ruserpass.c revision 302408
1/*
2 * Copyright (c) 1985, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "ftp_locl.h"
35RCSID("$Id$");
36
37static	int token (void);
38static	FILE *cfile;
39
40#define	DEFAULT	1
41#define	LOGIN	2
42#define	PASSWD	3
43#define	ACCOUNT 4
44#define MACDEF  5
45#define PROT	6
46#define	ID	10
47#define	MACH	11
48
49static char tokval[100];
50
51static struct toktab {
52	char *tokstr;
53	int tval;
54} toktab[]= {
55	{ "default",	DEFAULT },
56	{ "login",	LOGIN },
57	{ "password",	PASSWD },
58	{ "passwd",	PASSWD },
59	{ "account",	ACCOUNT },
60	{ "machine",	MACH },
61	{ "macdef",	MACDEF },
62	{ "prot", 	PROT },
63	{ NULL,		0 }
64};
65
66/*
67 * Write a copy of the hostname into `hostname, sz' and return a guess
68 * as to the `domain' of that hostname.
69 */
70
71static char *
72guess_domain (char *hostname_str, size_t sz)
73{
74    struct addrinfo *ai, *a;
75    struct addrinfo hints;
76    int error;
77    char *dot;
78
79    if (gethostname (hostname_str, sz) < 0) {
80	strlcpy (hostname_str, "", sz);
81	return "";
82    }
83    dot = strchr (hostname_str, '.');
84    if (dot != NULL)
85	return dot + 1;
86
87    memset (&hints, 0, sizeof(hints));
88    hints.ai_flags = AI_CANONNAME;
89
90    error = getaddrinfo (hostname_str, NULL, &hints, &ai);
91    if (error)
92	return hostname_str;
93
94    for (a = ai; a != NULL; a = a->ai_next)
95	if (a->ai_canonname != NULL) {
96	    strlcpy (hostname_str, ai->ai_canonname, sz);
97	    break;
98	}
99    freeaddrinfo (ai);
100    dot = strchr (hostname_str, '.');
101    if (dot != NULL)
102	return dot + 1;
103    else
104	return hostname_str;
105}
106
107int
108ruserpassword(char *host, char **aname, char **apass, char **aacct)
109{
110    char *hdir, buf[BUFSIZ], *tmp;
111    int t, i, c, usedefault = 0;
112    struct stat stb;
113
114    mydomain = guess_domain (myhostname, MaxHostNameLen);
115
116    hdir = getenv("HOME");
117    if (hdir == NULL)
118	hdir = ".";
119    snprintf(buf, sizeof(buf), "%s/.netrc", hdir);
120    cfile = fopen(buf, "r");
121    if (cfile == NULL) {
122	if (errno != ENOENT)
123	    warn("%s", buf);
124	return (0);
125    }
126
127next:
128    while ((t = token())) switch(t) {
129
130    case DEFAULT:
131	usedefault = 1;
132	/* FALL THROUGH */
133
134    case MACH:
135	if (!usedefault) {
136	    if (token() != ID)
137		continue;
138	    /*
139	     * Allow match either for user's input host name
140	     * or official hostname.  Also allow match of
141	     * incompletely-specified host in local domain.
142	     */
143	    if (strcasecmp(host, tokval) == 0)
144		goto match;
145	    if (strcasecmp(hostname, tokval) == 0)
146		goto match;
147	    if ((tmp = strchr(hostname, '.')) != NULL &&
148		tmp++ &&
149		strcasecmp(tmp, mydomain) == 0 &&
150		strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
151		tokval[tmp - hostname] == '\0')
152		goto match;
153	    if ((tmp = strchr(host, '.')) != NULL &&
154		tmp++ &&
155		strcasecmp(tmp, mydomain) == 0 &&
156		strncasecmp(host, tokval, tmp - host) == 0 &&
157		tokval[tmp - host] == '\0')
158		goto match;
159	    continue;
160	}
161    match:
162	while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
163
164	case LOGIN:
165	    if (token()) {
166		if (*aname == 0) {
167		    *aname = strdup(tokval);
168		} else {
169		    if (strcmp(*aname, tokval))
170			goto next;
171		}
172	    }
173	    break;
174	case PASSWD:
175	    if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
176		fstat(fileno(cfile), &stb) >= 0 &&
177		(stb.st_mode & 077) != 0) {
178		warnx("Error: .netrc file is readable by others.");
179		warnx("Remove password or make file unreadable by others.");
180		goto bad;
181	    }
182	    if (token() && *apass == 0) {
183		*apass = strdup(tokval);
184	    }
185	    break;
186	case ACCOUNT:
187	    if (fstat(fileno(cfile), &stb) >= 0
188		&& (stb.st_mode & 077) != 0) {
189		warnx("Error: .netrc file is readable by others.");
190		warnx("Remove account or make file unreadable by others.");
191		goto bad;
192	    }
193	    if (token() && *aacct == 0) {
194		*aacct = strdup(tokval);
195	    }
196	    break;
197	case MACDEF:
198	    if (proxy) {
199		fclose(cfile);
200		return (0);
201	    }
202	    while ((c=getc(cfile)) != EOF &&
203		   (c == ' ' || c == '\t'));
204	    if (c == EOF || c == '\n') {
205		printf("Missing macdef name argument.\n");
206		goto bad;
207	    }
208	    if (macnum == 16) {
209		printf("Limit of 16 macros have already been defined\n");
210		goto bad;
211	    }
212	    tmp = macros[macnum].mac_name;
213	    *tmp++ = c;
214	    for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
215		     !isspace(c); ++i) {
216		*tmp++ = c;
217	    }
218	    if (c == EOF) {
219		printf("Macro definition missing null line terminator.\n");
220		goto bad;
221	    }
222	    *tmp = '\0';
223	    if (c != '\n') {
224		while ((c=getc(cfile)) != EOF && c != '\n');
225	    }
226	    if (c == EOF) {
227		printf("Macro definition missing null line terminator.\n");
228		goto bad;
229	    }
230	    if (macnum == 0) {
231		macros[macnum].mac_start = macbuf;
232	    }
233	    else {
234		macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
235	    }
236	    tmp = macros[macnum].mac_start;
237	    while (tmp != macbuf + 4096) {
238		if ((c=getc(cfile)) == EOF) {
239		    printf("Macro definition missing null line terminator.\n");
240		    goto bad;
241		}
242		*tmp = c;
243		if (*tmp == '\n') {
244		    if (*(tmp-1) == '\0') {
245			macros[macnum++].mac_end = tmp - 1;
246			break;
247		    }
248		    *tmp = '\0';
249		}
250		tmp++;
251	    }
252	    if (tmp == macbuf + 4096) {
253		printf("4K macro buffer exceeded\n");
254		goto bad;
255	    }
256	    break;
257	case PROT:
258	    token();
259	    if(doencrypt == 0 && sec_request_prot(tokval) < 0)
260		warnx("Unknown protection level \"%s\"", tokval);
261	    break;
262	default:
263	    warnx("Unknown .netrc keyword %s", tokval);
264	    break;
265	}
266	goto done;
267    }
268done:
269    fclose(cfile);
270    return (0);
271bad:
272    fclose(cfile);
273    return (-1);
274}
275
276static int
277token(void)
278{
279	char *cp;
280	int c;
281	struct toktab *t;
282
283	if (feof(cfile) || ferror(cfile))
284		return (0);
285	while ((c = getc(cfile)) != EOF &&
286	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
287		continue;
288	if (c == EOF)
289		return (0);
290	cp = tokval;
291	if (c == '"') {
292		while ((c = getc(cfile)) != EOF && c != '"') {
293			if (c == '\\')
294				c = getc(cfile);
295			*cp++ = c;
296		}
297	} else {
298		*cp++ = c;
299		while ((c = getc(cfile)) != EOF
300		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
301			if (c == '\\')
302				c = getc(cfile);
303			*cp++ = c;
304		}
305	}
306	*cp = 0;
307	if (tokval[0] == 0)
308		return (0);
309	for (t = toktab; t->tokstr; t++)
310		if (!strcmp(t->tokstr, tokval))
311			return (t->tval);
312	return (ID);
313}
314