test/integration/test-ubuntu-bug-346386-apt-get-update-paywall: use downloadfile()
[apt.git] / apt-pkg / contrib / netrc.cc
CommitLineData
592b7800
MV
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 /*}}}*/
ea542140 14#include <config.h>
592b7800 15
f1c081b6 16#include <apt-pkg/configuration.h>
472ff00e 17#include <apt-pkg/strutl.h>
472ff00e 18
592b7800
MV
19#include <iostream>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
453b82a3 24#include <stddef.h>
592b7800
MV
25#include <pwd.h>
26
27#include "netrc.h"
28
8f3ba4e8 29using std::string;
592b7800
MV
30
31/* Get user and password from .netrc when given a machine name */
32
33enum {
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: */
7735ad05
MV
42#define LOGINSIZE 256
43#define PASSWORDSIZE 256
592b7800
MV
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 */
b8c50bd0 47static int parsenetrc_string (char *host, std::string &login, std::string &password, char *netrcfile = NULL)
592b7800
MV
48{
49 FILE *file;
50 int retcode = 1;
b8c50bd0 51 int specific_login = (login.empty() == false);
592b7800 52 bool netrc_alloc = false;
592b7800 53
592b7800 54 if (!netrcfile) {
69c2ecbd 55 char const * home = getenv ("HOME"); /* portable environment reader */
592b7800
MV
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
31bda500 67 if (asprintf (&netrcfile, "%s%s%s", home, DIR_CHAR, NETRC) == -1 || netrcfile == NULL)
592b7800
MV
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;
7f18595b
DK
78 char *netrcbuffer = NULL;
79 size_t netrcbuffer_size = 0;
592b7800 80
91c03d37
DK
81 int state = NOTHING;
82 char state_login = 0; /* Found a login keyword */
83 char state_password = 0; /* Found a password keyword */
69c2ecbd
DK
84 int state_our_login = false; /* With specific_login,
85 found *our* login name */
91c03d37 86
7f18595b 87 while (!done && getline(&netrcbuffer, &netrcbuffer_size, file) != -1) {
592b7800
MV
88 tok = strtok_r (netrcbuffer, " \t\n", &tok_buf);
89 while (!done && tok) {
b8c50bd0 90 if(login.empty() == false && password.empty() == false) {
592b7800
MV
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:
278835da
MV
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))) {
592b7800
MV
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)
b8c50bd0 122 state_our_login = !strcasecmp (login.c_str(), tok);
592b7800 123 else
b8c50bd0 124 login = tok;
592b7800
MV
125 state_login = 0;
126 } else if (state_password) {
127 if (state_our_login || !specific_login)
b8c50bd0 128 password = tok;
592b7800
MV
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) */
7f18595b 144 } /* while getline() */
592b7800 145
7f18595b 146 free(netrcbuffer);
592b7800
MV
147 fclose(file);
148 }
149
150 if (netrc_alloc)
151 free(netrcfile);
152
153 return retcode;
154}
b8c50bd0
DK
155// for some unknown reason this method is exported so keep a compatible interface for now …
156int 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
592b7800
MV
167
168void maybe_add_auth (URI &Uri, string NetRCFile)
169{
f1c081b6 170 if (_config->FindB("Debug::Acquire::netrc", false) == true)
01fc8930
MV
171 std::clog << "maybe_add_auth: " << (string)Uri
172 << " " << NetRCFile << std::endl;
f1c081b6 173 if (Uri.Password.empty () == true || Uri.User.empty () == true)
592b7800
MV
174 {
175 if (NetRCFile.empty () == false)
176 {
b8c50bd0 177 std::string login, password;
fc3eb5b2 178 char *netrcfile = strdup(NetRCFile.c_str());
592b7800 179
01fc8930 180 // first check for a generic host based netrc entry
fc3eb5b2 181 char *host = strdup(Uri.Host.c_str());
b8c50bd0 182 if (host && parsenetrc_string(host, login, password, netrcfile) == 0)
592b7800 183 {
01fc8930
MV
184 if (_config->FindB("Debug::Acquire::netrc", false) == true)
185 std::clog << "host: " << host
186 << " user: " << login
b8c50bd0 187 << " pass-size: " << password.size()
01fc8930 188 << std::endl;
b8c50bd0
DK
189 Uri.User = login;
190 Uri.Password = password;
fc3eb5b2
DK
191 free(netrcfile);
192 free(host);
01fc8930 193 return;
592b7800 194 }
fc3eb5b2 195 free(host);
592b7800 196
278835da
MV
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 "/"
e788a834 200 char *hostpath = strdup((Uri.Host + Uri.Path).c_str());
b8c50bd0 201 if (hostpath && parsenetrc_string(hostpath, login, password, netrcfile) == 0)
01fc8930
MV
202 {
203 if (_config->FindB("Debug::Acquire::netrc", false) == true)
204 std::clog << "hostpath: " << hostpath
205 << " user: " << login
b8c50bd0 206 << " pass-size: " << password.size()
01fc8930 207 << std::endl;
b8c50bd0
DK
208 Uri.User = login;
209 Uri.Password = password;
01fc8930 210 }
fc3eb5b2
DK
211 free(netrcfile);
212 free(hostpath);
592b7800
MV
213 }
214 }
215}
216
217#ifdef DEBUG
218int 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