]> git.saurik.com Git - apt.git/blob - apt-pkg/contrib/netrc.cc
apt-key: change to / before find to satisfy its CWD needs
[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 regarding "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
156 void maybe_add_auth (URI &Uri, string NetRCFile)
157 {
158 if (_config->FindB("Debug::Acquire::netrc", false) == true)
159 std::clog << "maybe_add_auth: " << (string)Uri
160 << " " << NetRCFile << std::endl;
161 if (Uri.Password.empty () == true || Uri.User.empty () == true)
162 {
163 if (NetRCFile.empty () == false)
164 {
165 std::string login, password;
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_string(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: " << password.size()
176 << std::endl;
177 Uri.User = login;
178 Uri.Password = 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((Uri.Host + Uri.Path).c_str());
189 if (hostpath && parsenetrc_string(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: " << password.size()
195 << std::endl;
196 Uri.User = login;
197 Uri.Password = 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