Home | History | Annotate | Line # | Download | only in ftp
      1 /*	$NetBSD: ruserpass.c,v 1.35 2024/10/04 18:04:06 christos 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.35 2024/10/04 18:04:06 christos 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