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