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