190075Sobrien/*	$NetBSD: ruserpass.c,v 1.8 2007/08/06 04:33:24 lukem Exp $	*/
2169689Skan/*	from	NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp	*/
3169689Skan
490075Sobrien/*
590075Sobrien * Copyright (c) 1985, 1993, 1994
690075Sobrien *	The Regents of the University of California.  All rights reserved.
790075Sobrien *
890075Sobrien * Redistribution and use in source and binary forms, with or without
990075Sobrien * modification, are permitted provided that the following conditions
1090075Sobrien * are met:
1190075Sobrien * 1. Redistributions of source code must retain the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer.
1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer in the
1590075Sobrien *    documentation and/or other materials provided with the distribution.
1690075Sobrien * 3. Neither the name of the University nor the names of its contributors
1790075Sobrien *    may be used to endorse or promote products derived from this software
1890075Sobrien *    without specific prior written permission.
19169689Skan *
20169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2190075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2290075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2390075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2490075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2590075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2690075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2790075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2890075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2990075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3090075Sobrien * SUCH DAMAGE.
3190075Sobrien */
3290075Sobrien
3390075Sobrien#include "tnftp.h"
3490075Sobrien
3590075Sobrien#if 0	/* tnftp */
3690075Sobrien
3790075Sobrien#include <sys/cdefs.h>
3890075Sobrien#ifndef lint
3990075Sobrien#if 0
4090075Sobrienstatic char sccsid[] = "@(#)ruserpass.c	8.4 (Berkeley) 4/27/95";
4190075Sobrien#else
42132718Skan__RCSID(" NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp  ");
43132718Skan#endif
44132718Skan#endif /* not lint */
45132718Skan
46132718Skan#include <sys/types.h>
47132718Skan#include <sys/stat.h>
48117395Skan
4990075Sobrien#include <ctype.h>
5090075Sobrien#include <err.h>
51132718Skan#include <errno.h>
52117395Skan#include <netdb.h>
53117395Skan#include <stdio.h>
5490075Sobrien#include <stdlib.h>
55132718Skan#include <string.h>
56132718Skan#include <unistd.h>
57132718Skan
58132718Skan#endif	/* tnftp */
59132718Skan
60132718Skan#include "ftp_var.h"
61132718Skan
62132718Skanstatic	int token(void);
63132718Skanstatic	FILE *cfile;
64132718Skan
6590075Sobrien#define	DEFAULT	1
6690075Sobrien#define	LOGIN	2
67132718Skan#define	PASSWD	3
6890075Sobrien#define	ACCOUNT	4
6990075Sobrien#define	MACDEF	5
7090075Sobrien#define	ID	10
7190075Sobrien#define	MACH	11
7290075Sobrien
7390075Sobrienstatic char tokval[100];
7490075Sobrien
7590075Sobrienstatic struct toktab {
7690075Sobrien	const char *tokstr;
7790075Sobrien	int tval;
7890075Sobrien} toktab[] = {
7990075Sobrien	{ "default",	DEFAULT },
8090075Sobrien	{ "login",	LOGIN },
8190075Sobrien	{ "password",	PASSWD },
8290075Sobrien	{ "passwd",	PASSWD },
8390075Sobrien	{ "account",	ACCOUNT },
8490075Sobrien	{ "machine",	MACH },
8590075Sobrien	{ "macdef",	MACDEF },
86169689Skan	{ NULL,		0 }
87169689Skan};
8890075Sobrien
8990075Sobrienint
9090075Sobrienruserpass(const char *host, char **aname, char **apass, char **aacct)
9190075Sobrien{
9290075Sobrien	char *tmp;
9390075Sobrien	const char *mydomain;
9490075Sobrien	char myname[MAXHOSTNAMELEN + 1];
9590075Sobrien	int t, i, c, usedefault = 0;
9690075Sobrien	struct stat stb;
9790075Sobrien
9890075Sobrien	if (netrc[0] == '\0')
99169689Skan		return (0);
100169689Skan	cfile = fopen(netrc, "r");
101169689Skan	if (cfile == NULL) {
10290075Sobrien		if (errno != ENOENT)
10390075Sobrien			warn("Can't read `%s'", netrc);
10490075Sobrien		return (0);
10590075Sobrien	}
10690075Sobrien	if (gethostname(myname, sizeof(myname)) < 0)
10790075Sobrien		myname[0] = '\0';
10890075Sobrien	myname[sizeof(myname) - 1] = '\0';
10990075Sobrien	if ((mydomain = strchr(myname, '.')) == NULL)
11090075Sobrien		mydomain = "";
11190075Sobrien next:
11290075Sobrien	while ((t = token()) > 0) switch(t) {
11390075Sobrien
11490075Sobrien	case DEFAULT:
115132718Skan		usedefault = 1;
11690075Sobrien		/* FALL THROUGH */
11790075Sobrien
11890075Sobrien	case MACH:
11990075Sobrien		if (!usedefault) {
12090075Sobrien			if ((t = token()) == -1)
12190075Sobrien				goto bad;
12290075Sobrien			if (t != ID)
12390075Sobrien				continue;
12490075Sobrien			/*
12590075Sobrien			 * Allow match either for user's input host name
12690075Sobrien			 * or official hostname.  Also allow match of
12790075Sobrien			 * incompletely-specified host in local domain.
12890075Sobrien			 */
12990075Sobrien			if (strcasecmp(host, tokval) == 0)
130132718Skan				goto match;
131132718Skan			if (strcasecmp(hostname, tokval) == 0)
132132718Skan				goto match;
133132718Skan			if ((tmp = strchr(hostname, '.')) != NULL &&
13490075Sobrien			    strcasecmp(tmp, mydomain) == 0 &&
13590075Sobrien			    strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
13690075Sobrien			    tokval[tmp - hostname] == '\0')
13790075Sobrien				goto match;
13890075Sobrien			if ((tmp = strchr(host, '.')) != NULL &&
139169689Skan			    strcasecmp(tmp, mydomain) == 0 &&
140169689Skan			    strncasecmp(host, tokval, tmp - host) == 0 &&
14190075Sobrien			    tokval[tmp - host] == '\0')
14290075Sobrien				goto match;
14390075Sobrien			continue;
14490075Sobrien		}
14590075Sobrien	match:
14690075Sobrien		while ((t = token()) > 0 &&
14790075Sobrien		    t != MACH && t != DEFAULT) switch(t) {
14890075Sobrien
14990075Sobrien		case LOGIN:
15090075Sobrien			if ((t = token()) == -1)
151132718Skan				goto bad;
15290075Sobrien			if (t) {
153132718Skan				if (*aname == NULL)
154132718Skan					*aname = ftp_strdup(tokval);
155132718Skan				else {
156132718Skan					if (strcmp(*aname, tokval))
15790075Sobrien						goto next;
15890075Sobrien				}
159169689Skan			}
160169689Skan			break;
16190075Sobrien		case PASSWD:
16290075Sobrien			if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
163169689Skan			    fstat(fileno(cfile), &stb) >= 0 &&
164169689Skan			    (stb.st_mode & 077) != 0) {
16590075Sobrien	warnx("Error: .netrc file is readable by others");
16690075Sobrien	warnx("Remove password or make file unreadable by others");
167169689Skan				goto bad;
168169689Skan			}
169117395Skan			if ((t = token()) == -1)
170117395Skan				goto bad;
171169689Skan			if (t && *apass == NULL)
172169689Skan				*apass = ftp_strdup(tokval);
173169689Skan			break;
174169689Skan		case ACCOUNT:
175169689Skan			if (fstat(fileno(cfile), &stb) >= 0
176169689Skan			    && (stb.st_mode & 077) != 0) {
177169689Skan	warnx("Error: .netrc file is readable by others");
178169689Skan	warnx("Remove account or make file unreadable by others");
179169689Skan				goto bad;
180169689Skan			}
181169689Skan			if ((t = token()) == -1)
182117395Skan				goto bad;
183117395Skan			if (t && *aacct == NULL)
184169689Skan				*aacct = ftp_strdup(tokval);
185169689Skan			break;
186169689Skan		case MACDEF:
187169689Skan			if (proxy) {
188169689Skan				(void)fclose(cfile);
189169689Skan				return (0);
190132718Skan			}
191132718Skan			while ((c = getc(cfile)) != EOF)
192169689Skan				if (c != ' ' && c != '\t')
193132718Skan					break;
194169689Skan			if (c == EOF || c == '\n') {
195169689Skan				fputs("Missing macdef name argument.\n",
196132718Skan				    ttyout);
197132718Skan				goto bad;
198169689Skan			}
199169689Skan			if (macnum == 16) {
200132718Skan				fputs(
201132718Skan			    "Limit of 16 macros have already been defined.\n",
202132718Skan				    ttyout);
203132718Skan				goto bad;
204169689Skan			}
205169689Skan			tmp = macros[macnum].mac_name;
20690075Sobrien			*tmp++ = c;
20790075Sobrien			for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
20890075Sobrien			    !isspace(c); ++i) {
20990075Sobrien				*tmp++ = c;
21090075Sobrien			}
21190075Sobrien			if (c == EOF) {
21290075Sobrien				fputs(
21390075Sobrien			    "Macro definition missing null line terminator.\n",
214132718Skan				    ttyout);
215132718Skan				goto bad;
216132718Skan			}
217132718Skan			*tmp = '\0';
218132718Skan			if (c != '\n') {
219132718Skan				while ((c = getc(cfile)) != EOF && c != '\n');
220132718Skan			}
221132718Skan			if (c == EOF) {
222132718Skan				fputs(
22390075Sobrien			    "Macro definition missing null line terminator.\n",
22490075Sobrien				    ttyout);
22590075Sobrien				goto bad;
22690075Sobrien			}
22790075Sobrien			if (macnum == 0) {
22890075Sobrien				macros[macnum].mac_start = macbuf;
22990075Sobrien			}
230132718Skan			else {
23190075Sobrien				macros[macnum].mac_start =
23290075Sobrien				    macros[macnum-1].mac_end + 1;
23390075Sobrien			}
234132718Skan			tmp = macros[macnum].mac_start;
235132718Skan			while (tmp != macbuf + 4096) {
236132718Skan				if ((c = getc(cfile)) == EOF) {
237169689Skan					fputs(
238169689Skan			    "Macro definition missing null line terminator.\n",
239169689Skan					    ttyout);
240169689Skan					goto bad;
241169689Skan				}
242169689Skan				*tmp = c;
243169689Skan				if (*tmp == '\n') {
244169689Skan					if (tmp == macros[macnum].mac_start) {
245169689Skan						macros[macnum++].mac_end = tmp;
246169689Skan						break;
247169689Skan					} else if (*(tmp - 1) == '\0') {
248169689Skan						macros[macnum++].mac_end =
249169689Skan						    tmp - 1;
250169689Skan						break;
251169689Skan					}
252169689Skan					*tmp = '\0';
253132718Skan				}
254132718Skan				tmp++;
255132718Skan			}
256132718Skan			if (tmp == macbuf + 4096) {
257132718Skan				fputs("4K macro buffer exceeded.\n",
258132718Skan				    ttyout);
259169689Skan				goto bad;
260169689Skan			}
261169689Skan			break;
262169689Skan		default:
263169689Skan			warnx("Unknown .netrc keyword `%s'", tokval);
264132718Skan			break;
265169689Skan		}
266169689Skan		goto done;
267169689Skan	}
26890075Sobrien done:
26990075Sobrien	if (t == -1)
27090075Sobrien		goto bad;
271117395Skan	(void)fclose(cfile);
27290075Sobrien	return (0);
27390075Sobrien bad:
27490075Sobrien	(void)fclose(cfile);
27590075Sobrien	return (-1);
27690075Sobrien}
27790075Sobrien
27890075Sobrienstatic int
27990075Sobrientoken(void)
28090075Sobrien{
28190075Sobrien	char *cp;
282169689Skan	int c;
28390075Sobrien	struct toktab *t;
28490075Sobrien
28590075Sobrien	if (feof(cfile) || ferror(cfile))
28690075Sobrien		return (0);
28790075Sobrien	while ((c = getc(cfile)) != EOF &&
28890075Sobrien	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
28990075Sobrien		continue;
29090075Sobrien	if (c == EOF)
291169689Skan		return (0);
292169689Skan	cp = tokval;
29390075Sobrien	if (c == '"') {
29490075Sobrien		while ((c = getc(cfile)) != EOF && c != '"') {
29590075Sobrien			if (c == '\\')
29690075Sobrien				if ((c = getc(cfile)) == EOF)
29790075Sobrien					break;
29890075Sobrien			*cp++ = c;
29990075Sobrien			if (cp == tokval + sizeof(tokval)) {
30090075Sobrien				warnx("Token in .netrc too long");
30190075Sobrien				return (-1);
30290075Sobrien			}
30390075Sobrien		}
30490075Sobrien	} else {
30590075Sobrien		*cp++ = c;
306132718Skan		while ((c = getc(cfile)) != EOF
307132718Skan		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
30890075Sobrien			if (c == '\\')
30990075Sobrien				if ((c = getc(cfile)) == EOF)
31090075Sobrien					break;
311169689Skan			*cp++ = c;
31290075Sobrien			if (cp == tokval + sizeof(tokval)) {
31390075Sobrien				warnx("Token in .netrc too long");
31490075Sobrien				return (-1);
31590075Sobrien			}
31690075Sobrien		}
31790075Sobrien	}
31890075Sobrien	*cp = 0;
319132718Skan	if (tokval[0] == 0)
320132718Skan		return (0);
321132718Skan	for (t = toktab; t->tokstr; t++)
322132718Skan		if (!strcmp(t->tokstr, tokval))
32390075Sobrien			return (t->tval);
324169689Skan	return (ID);
32590075Sobrien}
326169689Skan