1223328Sgavin/*	$NetBSD: ruserpass.c,v 1.8 2007/08/06 04:33:24 lukem Exp $	*/
2223328Sgavin/*	from	NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp	*/
379971Sobrien
479971Sobrien/*
579971Sobrien * Copyright (c) 1985, 1993, 1994
679971Sobrien *	The Regents of the University of California.  All rights reserved.
779971Sobrien *
879971Sobrien * Redistribution and use in source and binary forms, with or without
979971Sobrien * modification, are permitted provided that the following conditions
1079971Sobrien * are met:
1179971Sobrien * 1. Redistributions of source code must retain the above copyright
1279971Sobrien *    notice, this list of conditions and the following disclaimer.
1379971Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1479971Sobrien *    notice, this list of conditions and the following disclaimer in the
1579971Sobrien *    documentation and/or other materials provided with the distribution.
16121966Smikeh * 3. Neither the name of the University nor the names of its contributors
1779971Sobrien *    may be used to endorse or promote products derived from this software
1879971Sobrien *    without specific prior written permission.
1979971Sobrien *
2079971Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2179971Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2279971Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2379971Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2479971Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2579971Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2679971Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2779971Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2879971Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2979971Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3079971Sobrien * SUCH DAMAGE.
3179971Sobrien */
3279971Sobrien
33223328Sgavin#include "tnftp.h"
34223328Sgavin
35223328Sgavin#if 0	/* tnftp */
36223328Sgavin
37116424Smikeh#include <sys/cdefs.h>
38116424Smikeh#ifndef lint
39116424Smikeh#if 0
40116424Smikehstatic char sccsid[] = "@(#)ruserpass.c	8.4 (Berkeley) 4/27/95";
41116424Smikeh#else
42223328Sgavin__RCSID(" NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp  ");
43116424Smikeh#endif
44116424Smikeh#endif /* not lint */
4579971Sobrien
46116424Smikeh#include <sys/types.h>
47116424Smikeh#include <sys/stat.h>
48116424Smikeh
49116424Smikeh#include <ctype.h>
50116424Smikeh#include <err.h>
51116424Smikeh#include <errno.h>
52116424Smikeh#include <netdb.h>
53116424Smikeh#include <stdio.h>
54116424Smikeh#include <stdlib.h>
55116424Smikeh#include <string.h>
56116424Smikeh#include <unistd.h>
57116424Smikeh
58223328Sgavin#endif	/* tnftp */
59223328Sgavin
6079971Sobrien#include "ftp_var.h"
6179971Sobrien
6279971Sobrienstatic	int token(void);
6379971Sobrienstatic	FILE *cfile;
6479971Sobrien
6579971Sobrien#define	DEFAULT	1
6679971Sobrien#define	LOGIN	2
6779971Sobrien#define	PASSWD	3
6879971Sobrien#define	ACCOUNT	4
6979971Sobrien#define	MACDEF	5
7079971Sobrien#define	ID	10
7179971Sobrien#define	MACH	11
7279971Sobrien
7379971Sobrienstatic char tokval[100];
7479971Sobrien
7579971Sobrienstatic struct toktab {
76223328Sgavin	const char *tokstr;
7779971Sobrien	int tval;
7879971Sobrien} toktab[] = {
7979971Sobrien	{ "default",	DEFAULT },
8079971Sobrien	{ "login",	LOGIN },
8179971Sobrien	{ "password",	PASSWD },
8279971Sobrien	{ "passwd",	PASSWD },
8379971Sobrien	{ "account",	ACCOUNT },
8479971Sobrien	{ "machine",	MACH },
8579971Sobrien	{ "macdef",	MACDEF },
8679971Sobrien	{ NULL,		0 }
8779971Sobrien};
8879971Sobrien
8979971Sobrienint
90223328Sgavinruserpass(const char *host, char **aname, char **apass, char **aacct)
9179971Sobrien{
9298247Smikeh	char *tmp;
93223328Sgavin	const char *mydomain;
94223328Sgavin	char myname[MAXHOSTNAMELEN + 1];
9579971Sobrien	int t, i, c, usedefault = 0;
9679971Sobrien	struct stat stb;
9779971Sobrien
9898247Smikeh	if (netrc[0] == '\0')
9979971Sobrien		return (0);
10098247Smikeh	cfile = fopen(netrc, "r");
10179971Sobrien	if (cfile == NULL) {
10279971Sobrien		if (errno != ENOENT)
103223328Sgavin			warn("Can't read `%s'", netrc);
10479971Sobrien		return (0);
10579971Sobrien	}
10679971Sobrien	if (gethostname(myname, sizeof(myname)) < 0)
10779971Sobrien		myname[0] = '\0';
10879971Sobrien	myname[sizeof(myname) - 1] = '\0';
10979971Sobrien	if ((mydomain = strchr(myname, '.')) == NULL)
11079971Sobrien		mydomain = "";
11179971Sobrien next:
112223328Sgavin	while ((t = token()) > 0) switch(t) {
11379971Sobrien
11479971Sobrien	case DEFAULT:
11579971Sobrien		usedefault = 1;
11679971Sobrien		/* FALL THROUGH */
11779971Sobrien
11879971Sobrien	case MACH:
11979971Sobrien		if (!usedefault) {
120223328Sgavin			if ((t = token()) == -1)
121223328Sgavin				goto bad;
122223328Sgavin			if (t != ID)
12379971Sobrien				continue;
12479971Sobrien			/*
12579971Sobrien			 * Allow match either for user's input host name
12679971Sobrien			 * or official hostname.  Also allow match of
12779971Sobrien			 * incompletely-specified host in local domain.
12879971Sobrien			 */
12979971Sobrien			if (strcasecmp(host, tokval) == 0)
13079971Sobrien				goto match;
13179971Sobrien			if (strcasecmp(hostname, tokval) == 0)
13279971Sobrien				goto match;
13379971Sobrien			if ((tmp = strchr(hostname, '.')) != NULL &&
13479971Sobrien			    strcasecmp(tmp, mydomain) == 0 &&
13579971Sobrien			    strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
13679971Sobrien			    tokval[tmp - hostname] == '\0')
13779971Sobrien				goto match;
13879971Sobrien			if ((tmp = strchr(host, '.')) != NULL &&
13979971Sobrien			    strcasecmp(tmp, mydomain) == 0 &&
14079971Sobrien			    strncasecmp(host, tokval, tmp - host) == 0 &&
14179971Sobrien			    tokval[tmp - host] == '\0')
14279971Sobrien				goto match;
14379971Sobrien			continue;
14479971Sobrien		}
14579971Sobrien	match:
146223328Sgavin		while ((t = token()) > 0 &&
147223328Sgavin		    t != MACH && t != DEFAULT) switch(t) {
14879971Sobrien
14979971Sobrien		case LOGIN:
150223328Sgavin			if ((t = token()) == -1)
151223328Sgavin				goto bad;
152223328Sgavin			if (t) {
15379971Sobrien				if (*aname == NULL)
154223328Sgavin					*aname = ftp_strdup(tokval);
15579971Sobrien				else {
15679971Sobrien					if (strcmp(*aname, tokval))
15779971Sobrien						goto next;
15879971Sobrien				}
15979971Sobrien			}
16079971Sobrien			break;
16179971Sobrien		case PASSWD:
16279971Sobrien			if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
16379971Sobrien			    fstat(fileno(cfile), &stb) >= 0 &&
16479971Sobrien			    (stb.st_mode & 077) != 0) {
165223328Sgavin	warnx("Error: .netrc file is readable by others");
166223328Sgavin	warnx("Remove password or make file unreadable by others");
16779971Sobrien				goto bad;
16879971Sobrien			}
169223328Sgavin			if ((t = token()) == -1)
170223328Sgavin				goto bad;
171223328Sgavin			if (t && *apass == NULL)
172223328Sgavin				*apass = ftp_strdup(tokval);
17379971Sobrien			break;
17479971Sobrien		case ACCOUNT:
17579971Sobrien			if (fstat(fileno(cfile), &stb) >= 0
17679971Sobrien			    && (stb.st_mode & 077) != 0) {
177223328Sgavin	warnx("Error: .netrc file is readable by others");
178223328Sgavin	warnx("Remove account or make file unreadable by others");
17979971Sobrien				goto bad;
18079971Sobrien			}
181223328Sgavin			if ((t = token()) == -1)
182223328Sgavin				goto bad;
183223328Sgavin			if (t && *aacct == NULL)
184223328Sgavin				*aacct = ftp_strdup(tokval);
18579971Sobrien			break;
18679971Sobrien		case MACDEF:
18779971Sobrien			if (proxy) {
18879971Sobrien				(void)fclose(cfile);
18979971Sobrien				return (0);
19079971Sobrien			}
19179971Sobrien			while ((c = getc(cfile)) != EOF)
19279971Sobrien				if (c != ' ' && c != '\t')
19379971Sobrien					break;
19479971Sobrien			if (c == EOF || c == '\n') {
19579971Sobrien				fputs("Missing macdef name argument.\n",
19679971Sobrien				    ttyout);
19779971Sobrien				goto bad;
19879971Sobrien			}
19979971Sobrien			if (macnum == 16) {
20079971Sobrien				fputs(
20179971Sobrien			    "Limit of 16 macros have already been defined.\n",
20279971Sobrien				    ttyout);
20379971Sobrien				goto bad;
20479971Sobrien			}
20579971Sobrien			tmp = macros[macnum].mac_name;
20679971Sobrien			*tmp++ = c;
20779971Sobrien			for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
20879971Sobrien			    !isspace(c); ++i) {
20979971Sobrien				*tmp++ = c;
21079971Sobrien			}
21179971Sobrien			if (c == EOF) {
21279971Sobrien				fputs(
21379971Sobrien			    "Macro definition missing null line terminator.\n",
21479971Sobrien				    ttyout);
21579971Sobrien				goto bad;
21679971Sobrien			}
21779971Sobrien			*tmp = '\0';
21879971Sobrien			if (c != '\n') {
21979971Sobrien				while ((c = getc(cfile)) != EOF && c != '\n');
22079971Sobrien			}
22179971Sobrien			if (c == EOF) {
22279971Sobrien				fputs(
22379971Sobrien			    "Macro definition missing null line terminator.\n",
22479971Sobrien				    ttyout);
22579971Sobrien				goto bad;
22679971Sobrien			}
22779971Sobrien			if (macnum == 0) {
22879971Sobrien				macros[macnum].mac_start = macbuf;
22979971Sobrien			}
23079971Sobrien			else {
23179971Sobrien				macros[macnum].mac_start =
23279971Sobrien				    macros[macnum-1].mac_end + 1;
23379971Sobrien			}
23479971Sobrien			tmp = macros[macnum].mac_start;
23579971Sobrien			while (tmp != macbuf + 4096) {
23679971Sobrien				if ((c = getc(cfile)) == EOF) {
23779971Sobrien					fputs(
23879971Sobrien			    "Macro definition missing null line terminator.\n",
23979971Sobrien					    ttyout);
24079971Sobrien					goto bad;
24179971Sobrien				}
24279971Sobrien				*tmp = c;
24379971Sobrien				if (*tmp == '\n') {
244223328Sgavin					if (tmp == macros[macnum].mac_start) {
245223328Sgavin						macros[macnum++].mac_end = tmp;
246223328Sgavin						break;
247223328Sgavin					} else if (*(tmp - 1) == '\0') {
248223328Sgavin						macros[macnum++].mac_end =
249223328Sgavin						    tmp - 1;
250223328Sgavin						break;
25179971Sobrien					}
25279971Sobrien					*tmp = '\0';
25379971Sobrien				}
25479971Sobrien				tmp++;
25579971Sobrien			}
25679971Sobrien			if (tmp == macbuf + 4096) {
25779971Sobrien				fputs("4K macro buffer exceeded.\n",
25879971Sobrien				    ttyout);
25979971Sobrien				goto bad;
26079971Sobrien			}
26179971Sobrien			break;
26279971Sobrien		default:
263223328Sgavin			warnx("Unknown .netrc keyword `%s'", tokval);
26479971Sobrien			break;
26579971Sobrien		}
26679971Sobrien		goto done;
26779971Sobrien	}
26879971Sobrien done:
269223328Sgavin	if (t == -1)
270223328Sgavin		goto bad;
27179971Sobrien	(void)fclose(cfile);
27279971Sobrien	return (0);
27379971Sobrien bad:
27479971Sobrien	(void)fclose(cfile);
27579971Sobrien	return (-1);
27679971Sobrien}
27779971Sobrien
27879971Sobrienstatic int
27979971Sobrientoken(void)
28079971Sobrien{
28179971Sobrien	char *cp;
28279971Sobrien	int c;
28379971Sobrien	struct toktab *t;
28479971Sobrien
28579971Sobrien	if (feof(cfile) || ferror(cfile))
28679971Sobrien		return (0);
28779971Sobrien	while ((c = getc(cfile)) != EOF &&
28879971Sobrien	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
28979971Sobrien		continue;
29079971Sobrien	if (c == EOF)
29179971Sobrien		return (0);
29279971Sobrien	cp = tokval;
29379971Sobrien	if (c == '"') {
29479971Sobrien		while ((c = getc(cfile)) != EOF && c != '"') {
29579971Sobrien			if (c == '\\')
296223328Sgavin				if ((c = getc(cfile)) == EOF)
297223328Sgavin					break;
29879971Sobrien			*cp++ = c;
299223328Sgavin			if (cp == tokval + sizeof(tokval)) {
300223328Sgavin				warnx("Token in .netrc too long");
301223328Sgavin				return (-1);
302223328Sgavin			}
30379971Sobrien		}
30479971Sobrien	} else {
30579971Sobrien		*cp++ = c;
30679971Sobrien		while ((c = getc(cfile)) != EOF
30779971Sobrien		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
30879971Sobrien			if (c == '\\')
309223328Sgavin				if ((c = getc(cfile)) == EOF)
310223328Sgavin					break;
31179971Sobrien			*cp++ = c;
312223328Sgavin			if (cp == tokval + sizeof(tokval)) {
313223328Sgavin				warnx("Token in .netrc too long");
314223328Sgavin				return (-1);
315223328Sgavin			}
31679971Sobrien		}
31779971Sobrien	}
31879971Sobrien	*cp = 0;
31979971Sobrien	if (tokval[0] == 0)
32079971Sobrien		return (0);
32179971Sobrien	for (t = toktab; t->tokstr; t++)
32279971Sobrien		if (!strcmp(t->tokstr, tokval))
32379971Sobrien			return (t->tval);
32479971Sobrien	return (ID);
32579971Sobrien}
326