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