try seeking on fds opened with OpenDescriptor before giving up
[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/strutl.h>
18 #include <apt-pkg/fileutl.h>
19
20 #include <iostream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.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 64
43 #define PASSWORDSIZE 64
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 int parsenetrc (char *host, char *login, char *password, char *netrcfile = NULL)
48 {
49 FILE *file;
50 int retcode = 1;
51 int specific_login = (login[0] != 0);
52 char *home = NULL;
53 bool netrc_alloc = false;
54
55 int state_our_login = false; /* With specific_login,
56 found *our* login name */
57
58 if (!netrcfile) {
59 home = getenv ("HOME"); /* portable environment reader */
60
61 if (!home) {
62 struct passwd *pw;
63 pw = getpwuid (geteuid ());
64 if(pw)
65 home = pw->pw_dir;
66 }
67
68 if (!home)
69 return -1;
70
71 asprintf (&netrcfile, "%s%s%s", home, DIR_CHAR, NETRC);
72 if(!netrcfile)
73 return -1;
74 else
75 netrc_alloc = true;
76 }
77
78 file = fopen (netrcfile, "r");
79 if(file) {
80 char *tok;
81 char *tok_buf;
82 bool done = false;
83 char netrcbuffer[256];
84
85 int state = NOTHING;
86 char state_login = 0; /* Found a login keyword */
87 char state_password = 0; /* Found a password keyword */
88
89 while (!done && fgets(netrcbuffer, sizeof (netrcbuffer), file)) {
90 tok = strtok_r (netrcbuffer, " \t\n", &tok_buf);
91 while (!done && tok) {
92 if(login[0] && password[0]) {
93 done = true;
94 break;
95 }
96
97 switch(state) {
98 case NOTHING:
99 if (!strcasecmp ("machine", tok)) {
100 /* the next tok is the machine name, this is in itself the
101 delimiter that starts the stuff entered for this machine,
102 after this we need to search for 'login' and
103 'password'. */
104 state = HOSTFOUND;
105 }
106 break;
107 case HOSTFOUND:
108 /* extended definition of a "machine" if we have a "/"
109 we match the start of the string (host.startswith(token) */
110 if ((strchr(host, '/') && strstr(host, tok) == host) ||
111 (!strcasecmp (host, tok))) {
112 /* and yes, this is our host! */
113 state = HOSTVALID;
114 retcode = 0; /* we did find our host */
115 }
116 else
117 /* not our host */
118 state = NOTHING;
119 break;
120 case HOSTVALID:
121 /* we are now parsing sub-keywords concerning "our" host */
122 if (state_login) {
123 if (specific_login)
124 state_our_login = !strcasecmp (login, tok);
125 else
126 strncpy (login, tok, LOGINSIZE - 1);
127 state_login = 0;
128 } else if (state_password) {
129 if (state_our_login || !specific_login)
130 strncpy (password, tok, PASSWORDSIZE - 1);
131 state_password = 0;
132 } else if (!strcasecmp ("login", tok))
133 state_login = 1;
134 else if (!strcasecmp ("password", tok))
135 state_password = 1;
136 else if(!strcasecmp ("machine", tok)) {
137 /* ok, there's machine here go => */
138 state = HOSTFOUND;
139 state_our_login = false;
140 }
141 break;
142 } /* switch (state) */
143
144 tok = strtok_r (NULL, " \t\n", &tok_buf);
145 } /* while(tok) */
146 } /* while fgets() */
147
148 fclose(file);
149 }
150
151 if (netrc_alloc)
152 free(netrcfile);
153
154 return retcode;
155 }
156
157 void maybe_add_auth (URI &Uri, string NetRCFile)
158 {
159 if (_config->FindB("Debug::Acquire::netrc", false) == true)
160 std::clog << "maybe_add_auth: " << (string)Uri
161 << " " << NetRCFile << std::endl;
162 if (Uri.Password.empty () == true || Uri.User.empty () == true)
163 {
164 if (NetRCFile.empty () == false)
165 {
166 char login[64] = "";
167 char password[64] = "";
168 char *netrcfile = strdup(NetRCFile.c_str());
169
170 // first check for a generic host based netrc entry
171 char *host = strdup(Uri.Host.c_str());
172 if (host && parsenetrc (host, login, password, netrcfile) == 0)
173 {
174 if (_config->FindB("Debug::Acquire::netrc", false) == true)
175 std::clog << "host: " << host
176 << " user: " << login
177 << " pass-size: " << strlen(password)
178 << std::endl;
179 Uri.User = string (login);
180 Uri.Password = string (password);
181 free(netrcfile);
182 free(host);
183 return;
184 }
185 free(host);
186
187 // if host did not work, try Host+Path next, this will trigger
188 // a lookup uri.startswith(host) in the netrc file parser (because
189 // of the "/"
190 char *hostpath = strdup(string(Uri.Host+Uri.Path).c_str());
191 if (hostpath && parsenetrc (hostpath, login, password, netrcfile) == 0)
192 {
193 if (_config->FindB("Debug::Acquire::netrc", false) == true)
194 std::clog << "hostpath: " << hostpath
195 << " user: " << login
196 << " pass-size: " << strlen(password)
197 << std::endl;
198 Uri.User = string (login);
199 Uri.Password = string (password);
200 }
201 free(netrcfile);
202 free(hostpath);
203 }
204 }
205 }
206
207 #ifdef DEBUG
208 int main(int argc, char* argv[])
209 {
210 char login[64] = "";
211 char password[64] = "";
212
213 if(argc < 2)
214 return -1;
215
216 if(0 == parsenetrc (argv[1], login, password, argv[2])) {
217 printf("HOST: %s LOGIN: %s PASSWORD: %s\n", argv[1], login, password);
218 }
219 }
220 #endif