]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/netrc.cc
Merge remote-tracking branch 'upstream/debian/sid' into feature/apt-manpage
[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/strutl.h>
18
19 #include <iostream>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <stddef.h>
25 #include <pwd.h>
26
27 #include "netrc.h"
28
29 using std::string;
30
31 /* Get user and password from .netrc when given a machine name */
32
33 enum {
34 NOTHING,
35 HOSTFOUND, /* the 'machine' keyword was found */
36 HOSTCOMPLETE, /* the machine name following the keyword was found too */
37 HOSTVALID, /* this is "our" machine! */
38 HOSTEND /* LAST enum */
39 };
40
41 /* make sure we have room for at least this size: */
42 #define LOGINSIZE 256
43 #define PASSWORDSIZE 256
44 #define NETRC DOT_CHAR "netrc"
45
46 /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
47 static int parsenetrc_string (char *host, std::string &login, std::string &password, char *netrcfile = NULL)
48 {
49 FILE *file;
50 int retcode = 1;
51 int specific_login = (login.empty() == false);
52 bool netrc_alloc = false;
53
54 if (!netrcfile) {
55 char const * home = getenv ("HOME"); /* portable environment reader */
56
57 if (!home) {
58 struct passwd *pw;
59 pw = getpwuid (geteuid ());
60 if(pw)
61 home = pw->pw_dir;
62 }
63
64 if (!home)
65 return -1;
66
67 if (asprintf (&netrcfile, "%s%s%s", home, DIR_CHAR, NETRC) == -1 || netrcfile == NULL)
68 return -1;
69 else
70 netrc_alloc = true;
71 }
72
73 file = fopen (netrcfile, "r");
74 if(file) {
75 char *tok;
76 char *tok_buf;
77 bool done = false;
78 char *netrcbuffer = NULL;
79 size_t netrcbuffer_size = 0;
80
81 int state = NOTHING;
82 char state_login = 0; /* Found a login keyword */
83 char state_password = 0; /* Found a password keyword */
84 int state_our_login = false; /* With specific_login,
85 found *our* login name */
86
87 while (!done && getline(&netrcbuffer, &netrcbuffer_size, file) != -1) {
88 tok = strtok_r (netrcbuffer, " \t\n", &tok_buf);
89 while (!done && tok) {
90 if(login.empty() == false && password.empty() == false) {
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.c_str(), tok);
123 else
124 login = tok;
125 state_login = 0;
126 } else if (state_password) {
127 if (state_our_login || !specific_login)
128 password = tok;
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 getline() */
145
146 free(netrcbuffer);
147 fclose(file);
148 }
149
150 if (netrc_alloc)
151 free(netrcfile);
152
153 return retcode;
154 }
155 // for some unknown reason this method is exported so keep a compatible interface for now …
156 int parsenetrc (char *host, char *login, char *password, char *netrcfile = NULL)
157 {
158 std::string login_string, password_string;
159 int const ret = parsenetrc_string(host, login_string, password_string, netrcfile);
160 if (ret < 0)
161 return ret;
162 strncpy(login, login_string.c_str(), LOGINSIZE - 1);
163 strncpy(password, password_string.c_str(), PASSWORDSIZE - 1);
164 return ret;
165 }
166
167
168 void maybe_add_auth (URI &Uri, string NetRCFile)
169 {
170 if (_config->FindB("Debug::Acquire::netrc", false) == true)
171 std::clog << "maybe_add_auth: " << (string)Uri
172 << " " << NetRCFile << std::endl;
173 if (Uri.Password.empty () == true || Uri.User.empty () == true)
174 {
175 if (NetRCFile.empty () == false)
176 {
177 std::string login, password;
178 char *netrcfile = strdup(NetRCFile.c_str());
179
180 // first check for a generic host based netrc entry
181 char *host = strdup(Uri.Host.c_str());
182 if (host && parsenetrc_string(host, login, password, netrcfile) == 0)
183 {
184 if (_config->FindB("Debug::Acquire::netrc", false) == true)
185 std::clog << "host: " << host
186 << " user: " << login
187 << " pass-size: " << password.size()
188 << std::endl;
189 Uri.User = login;
190 Uri.Password = password;
191 free(netrcfile);
192 free(host);
193 return;
194 }
195 free(host);
196
197 // if host did not work, try Host+Path next, this will trigger
198 // a lookup uri.startswith(host) in the netrc file parser (because
199 // of the "/"
200 char *hostpath = strdup((Uri.Host + Uri.Path).c_str());
201 if (hostpath && parsenetrc_string(hostpath, login, password, netrcfile) == 0)
202 {
203 if (_config->FindB("Debug::Acquire::netrc", false) == true)
204 std::clog << "hostpath: " << hostpath
205 << " user: " << login
206 << " pass-size: " << password.size()
207 << std::endl;
208 Uri.User = login;
209 Uri.Password = password;
210 }
211 free(netrcfile);
212 free(hostpath);
213 }
214 }
215 }
216
217 #ifdef DEBUG
218 int main(int argc, char* argv[])
219 {
220 char login[64] = "";
221 char password[64] = "";
222
223 if(argc < 2)
224 return -1;
225
226 if(0 == parsenetrc (argv[1], login, password, argv[2])) {
227 printf("HOST: %s LOGIN: %s PASSWORD: %s\n", argv[1], login, password);
228 }
229 }
230 #endif