Annotation of src/usr.bin/ftp/ruserpass.c, Revision 1.22
1.22 ! moritz 1: /* $OpenBSD: ruserpass.c,v 1.21 2007/03/22 11:35:02 moritz Exp $ */
1.9 millert 2: /* $NetBSD: ruserpass.c,v 1.14 1997/07/20 09:46:01 lukem Exp $ */
1.1 deraadt 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.
1.16 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 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
1.4 millert 34: #if 0
1.1 deraadt 35: static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95";
1.4 millert 36: #else
1.17 deraadt 37: #ifndef SMALL
1.22 ! moritz 38: static const char rcsid[] = "$OpenBSD: ruserpass.c,v 1.21 2007/03/22 11:35:02 moritz Exp $";
1.17 deraadt 39: #endif /* SMALL */
1.4 millert 40: #endif
1.1 deraadt 41: #endif /* not lint */
42:
43: #include <sys/types.h>
44: #include <sys/stat.h>
45:
46: #include <ctype.h>
47: #include <err.h>
48: #include <errno.h>
49: #include <stdio.h>
50: #include <stdlib.h>
51: #include <string.h>
52: #include <unistd.h>
53:
54: #include "ftp_var.h"
55:
1.13 millert 56: static int token(void);
1.1 deraadt 57: static FILE *cfile;
58:
59: #define DEFAULT 1
60: #define LOGIN 2
61: #define PASSWD 3
62: #define ACCOUNT 4
63: #define MACDEF 5
64: #define ID 10
65: #define MACH 11
66:
67: static char tokval[100];
68:
69: static struct toktab {
70: char *tokstr;
71: int tval;
72: } toktab[]= {
73: { "default", DEFAULT },
74: { "login", LOGIN },
75: { "password", PASSWD },
76: { "passwd", PASSWD },
77: { "account", ACCOUNT },
78: { "machine", MACH },
79: { "macdef", MACDEF },
80: { NULL, 0 }
81: };
82:
83: int
1.18 deraadt 84: ruserpass(const char *host, char **aname, char **apass, char **aacct)
1.1 deraadt 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");
1.14 millert 92: if (hdir == NULL || *hdir == '\0')
1.12 millert 93: return (0);
1.22 ! moritz 94: i = snprintf(buf, sizeof(buf), "%s/.netrc", hdir);
! 95: if (i < 0 || i >= sizeof(buf)) {
1.3 millert 96: warnx("%s/.netrc: %s", hdir, strerror(ENAMETOOLONG));
97: return (0);
98: }
1.1 deraadt 99: cfile = fopen(buf, "r");
100: if (cfile == NULL) {
101: if (errno != ENOENT)
102: warn("%s", buf);
103: return (0);
104: }
105: if (gethostname(myname, sizeof(myname)) < 0)
106: myname[0] = '\0';
107: if ((mydomain = strchr(myname, '.')) == NULL)
108: mydomain = "";
109: next:
1.21 moritz 110: while ((t = token()) > 0) switch(t) {
1.1 deraadt 111:
112: case DEFAULT:
113: usedefault = 1;
1.20 ray 114: /* FALLTHROUGH */
1.1 deraadt 115:
116: case MACH:
117: if (!usedefault) {
1.21 moritz 118: if ((t = token()) == -1)
119: goto bad;
120: if (t != ID)
1.1 deraadt 121: continue;
122: /*
123: * Allow match either for user's input host name
1.4 millert 124: * or official hostname. Also allow match of
1.1 deraadt 125: * incompletely-specified host in local domain.
126: */
127: if (strcasecmp(host, tokval) == 0)
128: goto match;
129: if (strcasecmp(hostname, tokval) == 0)
130: goto match;
131: if ((tmp = strchr(hostname, '.')) != NULL &&
132: strcasecmp(tmp, mydomain) == 0 &&
1.9 millert 133: strncasecmp(hostname, tokval,
134: (size_t)(tmp - hostname)) == 0 &&
1.1 deraadt 135: tokval[tmp - hostname] == '\0')
136: goto match;
137: if ((tmp = strchr(host, '.')) != NULL &&
138: strcasecmp(tmp, mydomain) == 0 &&
1.9 millert 139: strncasecmp(host, tokval,
140: (size_t)(tmp - host)) == 0 &&
1.1 deraadt 141: tokval[tmp - host] == '\0')
142: goto match;
143: continue;
144: }
145: match:
1.21 moritz 146: while ((t = token()) > 0 &&
147: t != MACH && t != DEFAULT) switch(t) {
1.1 deraadt 148:
149: case LOGIN:
1.21 moritz 150: if ((t = token()) == -1)
151: goto bad;
152: if (t) {
1.15 deraadt 153: if (*aname == 0)
154: *aname = strdup(tokval);
155: else {
1.1 deraadt 156: if (strcmp(*aname, tokval))
157: goto next;
158: }
1.11 deraadt 159: }
1.1 deraadt 160: break;
161: case PASSWD:
162: if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
163: fstat(fileno(cfile), &stb) >= 0 &&
164: (stb.st_mode & 077) != 0) {
165: warnx("Error: .netrc file is readable by others.");
166: warnx("Remove password or make file unreadable by others.");
167: goto bad;
168: }
1.21 moritz 169: if ((t = token()) == -1)
170: goto bad;
171: if (t && *apass == 0)
1.15 deraadt 172: *apass = strdup(tokval);
1.1 deraadt 173: break;
174: case ACCOUNT:
175: if (fstat(fileno(cfile), &stb) >= 0
176: && (stb.st_mode & 077) != 0) {
177: warnx("Error: .netrc file is readable by others.");
178: warnx("Remove account or make file unreadable by others.");
179: goto bad;
180: }
1.21 moritz 181: if ((t = token()) == -1)
182: goto bad;
183: if (t && *aacct == 0)
1.15 deraadt 184: *aacct = strdup(tokval);
1.1 deraadt 185: break;
186: case MACDEF:
187: if (proxy) {
1.5 millert 188: (void)fclose(cfile);
1.1 deraadt 189: return (0);
190: }
1.10 millert 191: while ((c = fgetc(cfile)) != EOF)
1.4 millert 192: if (c != ' ' && c != '\t')
193: break;
1.1 deraadt 194: if (c == EOF || c == '\n') {
1.8 deraadt 195: fputs("Missing macdef name argument.\n", ttyout);
1.1 deraadt 196: goto bad;
197: }
198: if (macnum == 16) {
1.8 deraadt 199: fputs(
200: "Limit of 16 macros have already been defined.\n", ttyout);
1.1 deraadt 201: goto bad;
202: }
203: tmp = macros[macnum].mac_name;
204: *tmp++ = c;
1.10 millert 205: for (i=0; i < 8 && (c = fgetc(cfile)) != EOF &&
1.1 deraadt 206: !isspace(c); ++i) {
207: *tmp++ = c;
208: }
209: if (c == EOF) {
1.8 deraadt 210: fputs(
211: "Macro definition missing null line terminator.\n", ttyout);
1.1 deraadt 212: goto bad;
213: }
214: *tmp = '\0';
215: if (c != '\n') {
1.10 millert 216: while ((c = fgetc(cfile)) != EOF && c != '\n');
1.1 deraadt 217: }
218: if (c == EOF) {
1.8 deraadt 219: fputs(
220: "Macro definition missing null line terminator.\n", ttyout);
1.1 deraadt 221: goto bad;
222: }
223: if (macnum == 0) {
224: macros[macnum].mac_start = macbuf;
225: }
226: else {
1.4 millert 227: macros[macnum].mac_start =
228: macros[macnum-1].mac_end + 1;
1.1 deraadt 229: }
230: tmp = macros[macnum].mac_start;
231: while (tmp != macbuf + 4096) {
1.10 millert 232: if ((c = fgetc(cfile)) == EOF) {
1.8 deraadt 233: fputs(
234: "Macro definition missing null line terminator.\n", ttyout);
1.1 deraadt 235: goto bad;
236: }
237: *tmp = c;
238: if (*tmp == '\n') {
239: if (*(tmp-1) == '\0') {
240: macros[macnum++].mac_end = tmp - 1;
241: break;
242: }
243: *tmp = '\0';
244: }
245: tmp++;
246: }
247: if (tmp == macbuf + 4096) {
1.8 deraadt 248: fputs("4K macro buffer exceeded.\n", ttyout);
1.1 deraadt 249: goto bad;
250: }
251: break;
252: default:
253: warnx("Unknown .netrc keyword %s", tokval);
254: break;
255: }
256: goto done;
257: }
258: done:
1.21 moritz 259: if (t == -1)
260: goto bad;
1.5 millert 261: (void)fclose(cfile);
1.1 deraadt 262: return (0);
263: bad:
1.5 millert 264: (void)fclose(cfile);
1.1 deraadt 265: return (-1);
266: }
267:
268: static int
1.18 deraadt 269: token(void)
1.1 deraadt 270: {
271: char *cp;
272: int c;
273: struct toktab *t;
274:
275: if (feof(cfile) || ferror(cfile))
276: return (0);
1.10 millert 277: while ((c = fgetc(cfile)) != EOF &&
1.1 deraadt 278: (c == '\n' || c == '\t' || c == ' ' || c == ','))
279: continue;
280: if (c == EOF)
281: return (0);
282: cp = tokval;
283: if (c == '"') {
1.10 millert 284: while ((c = fgetc(cfile)) != EOF && c != '"') {
1.1 deraadt 285: if (c == '\\')
1.10 millert 286: c = fgetc(cfile);
1.1 deraadt 287: *cp++ = c;
1.21 moritz 288: if (cp == tokval + sizeof(tokval)) {
289: warnx("Token in .netrc too long");
290: return (-1);
291: }
1.1 deraadt 292: }
293: } else {
294: *cp++ = c;
1.10 millert 295: while ((c = fgetc(cfile)) != EOF
1.1 deraadt 296: && c != '\n' && c != '\t' && c != ' ' && c != ',') {
297: if (c == '\\')
1.10 millert 298: c = fgetc(cfile);
1.1 deraadt 299: *cp++ = c;
1.21 moritz 300: if (cp == tokval + sizeof(tokval)) {
301: warnx("Token in .netrc too long");
302: return (-1);
303: }
1.1 deraadt 304: }
305: }
306: *cp = 0;
307: if (tokval[0] == 0)
308: return (0);
309: for (t = toktab; t->tokstr; t++)
310: if (!strcmp(t->tokstr, tokval))
311: return (t->tval);
312: return (ID);
313: }