do not pollute namespace in the headers with using (Closes: #500198)
[ntk/apt.git] / apt-pkg / contrib / netrc.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: netrc.c,v 1.38 2007-11-07 09:21:35 bagder Exp $
4 /* ######################################################################
5
6 netrc file parser - returns the login and password of a give host in
7 a specified netrc-type file
8
9 Originally written by Daniel Stenberg, <daniel@haxx.se>, et al. and
10 placed into the Public Domain, do with it what you will.
11
12 ##################################################################### */
13 /*}}}*/
14 #include <config.h>
15
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/fileutl.h>
18 #include <iostream>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <pwd.h>
24
25 #include "netrc.h"
26
27 using std::string;
28
29 /* Get user and password from .netrc when given a machine name */
30
31 enum {
32 NOTHING,
33 HOSTFOUND, /* the 'machine' keyword was found */
34 HOSTCOMPLETE, /* the machine name following the keyword was found too */
35 HOSTVALID, /* this is "our" machine! */
36 HOSTEND /* LAST enum */
37 };
38
39 /* make sure we have room for at least this size: */
40 #define LOGINSIZE 64
41 #define PASSWORDSIZE 64
42 #define NETRC DOT_CHAR "netrc"
43
44 /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
45 int parsenetrc (char *host, char *login, char *password, char *netrcfile = NULL)
46 {
47 FILE *file;
48 int retcode = 1;
49 int specific_login = (login[0] != 0);
50 char *home = NULL;
51 bool netrc_alloc = false;
52
53 int state_our_login = false; /* With specific_login,
54 found *our* login name */
55
56 if (!netrcfile) {
57 home = getenv ("HOME"); /* portable environment reader */
58
59 if (!home) {
60 struct passwd *pw;
61 pw = getpwuid (geteuid ());
62 if(pw)
63 home = pw->pw_dir;
64 }
65
66 if (!home)
67 return -1;
68
69 asprintf (&netrcfile, "%s%s%s", home, DIR_CHAR, NETRC);
70 if(!netrcfile)
71 return -1;
72 else
73 netrc_alloc = true;
74 }
75
76 file = fopen (netrcfile, "r");
77 if(file) {
78 char *tok;
79 char *tok_buf;
80 bool done = false;
81 char netrcbuffer[256];
82
83 int state = NOTHING;
84 char state_login = 0; /* Found a login keyword */
85 char state_password = 0; /* Found a password keyword */
86
87 while (!done && fgets(netrcbuffer, sizeof (netrcbuffer), file)) {
88 tok = strtok_r (netrcbuffer, " \t\n", &tok_buf);
89 while (!done && tok) {
90 if(login[0] && password[0]) {
91 done = true;
92 break;
93 }
94
95 switch(state) {
96 case NOTHING:
97 if (!strcasecmp ("machine", tok)) {
98 /* the next tok is the machine name, this is in itself the
99 delimiter that starts the stuff entered for this machine,
100 after this we need to search for 'login' and
101 'password'. */
102 state = HOSTFOUND;
103 }
104 break;
105 case HOSTFOUND:
106 /* extended definition of a "machine" if we have a "/"
107 we match the start of the string (host.startswith(token) */
108 if ((strchr(host, '/') && strstr(host, tok) == host) ||
109 (!strcasecmp (host, tok))) {
110 /* and yes, this is our host! */
111 state = HOSTVALID;
112 retcode = 0; /* we did find our host */
113 }
114 else
115 /* not our host */
116 state = NOTHING;
117 break;
118 case HOSTVALID:
119 /* we are now parsing sub-keywords concerning "our" host */
120 if (state_login) {
121 if (specific_login)
122 state_our_login = !strcasecmp (login, tok);
123 else
124 strncpy (login, tok, LOGINSIZE - 1);
125 state_login = 0;
126 } else if (state_password) {
127 if (state_our_login || !specific_login)
128 strncpy (password, tok, PASSWORDSIZE - 1);
129 state_password = 0;
130 } else if (!strcasecmp ("login", tok))
131 state_login = 1;
132 else if (!strcasecmp ("password", tok))
133 state_password = 1;
134 else if(!strcasecmp ("machine", tok)) {
135 /* ok, there's machine here go => */
136 state = HOSTFOUND;
137 state_our_login = false;
138 }
139 break;
140 } /* switch (state) */
141
142 tok = strtok_r (NULL, " \t\n", &tok_buf);
143 } /* while(tok) */
144 } /* while fgets() */
145
146 fclose(file);
147 }
148
149 if (netrc_alloc)
150 free(netrcfile);
151
152 return retcode;
153 }
154
155 void maybe_add_auth (URI &Uri, string NetRCFile)
156 {
157 if (_config->FindB("Debug::Acquire::netrc", false) == true)
158 std::clog << "maybe_add_auth: " << (string)Uri
159 << " " << NetRCFile << std::endl;
160 if (Uri.Password.empty () == true || Uri.User.empty () == true)
161 {
162 if (NetRCFile.empty () == false)
163 {
164 char login[64] = "";
165 char password[64] = "";
166 char *netrcfile = strdup(NetRCFile.c_str());
167
168 // first check for a generic host based netrc entry
169 char *host = strdup(Uri.Host.c_str());
170 if (host && parsenetrc (host, login, password, netrcfile) == 0)
171 {
172 if (_config->FindB("Debug::Acquire::netrc", false) == true)
173 std::clog << "host: " << host
174 << " user: " << login
175 << " pass-size: " << strlen(password)
176 << std::endl;
177 Uri.User = string (login);
178 Uri.Password = string (password);
179 free(netrcfile);
180 free(host);
181 return;
182 }
183 free(host);
184
185 // if host did not work, try Host+Path next, this will trigger
186 // a lookup uri.startswith(host) in the netrc file parser (because
187 // of the "/"
188 char *hostpath = strdup(string(Uri.Host+Uri.Path).c_str());
189 if (hostpath && parsenetrc (hostpath, login, password, netrcfile) == 0)
190 {
191 if (_config->FindB("Debug::Acquire::netrc", false) == true)
192 std::clog << "hostpath: " << hostpath
193 << " user: " << login
194 << " pass-size: " << strlen(password)
195 << std::endl;
196 Uri.User = string (login);
197 Uri.Password = string (password);
198 }
199 free(netrcfile);
200 free(hostpath);
201 }
202 }
203 }
204
205 #ifdef DEBUG
206 int main(int argc, char* argv[])
207 {
208 char login[64] = "";
209 char password[64] = "";
210
211 if(argc < 2)
212 return -1;
213
214 if(0 == parsenetrc (argv[1], login, password, argv[2])) {
215 printf("HOST: %s LOGIN: %s PASSWORD: %s\n", argv[1], login, password);
216 }
217 }
218 #endif