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