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