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