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