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