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