| /* | 
 |  * Copyright (c) 1985, 1993, 1994 | 
 |  *	The Regents of the University of California.  All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * 4. Neither the name of the University nor the names of its contributors | 
 |  *    may be used to endorse or promote products derived from this software | 
 |  *    without specific prior written permission. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 
 |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 
 |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
 |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
 |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 |  * SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | #if defined(LIBC_SCCS) && !defined(lint) | 
 | static char sccsid[] = "@(#)ruserpass.c	8.3 (Berkeley) 4/2/94"; | 
 | #endif /* not lint */ | 
 |  | 
 | #include <sys/types.h> | 
 | #include <sys/stat.h> | 
 |  | 
 | #include <ctype.h> | 
 | #include <err.h> | 
 | #include <errno.h> | 
 | #include <netdb.h> | 
 | #include <stdio.h> | 
 | #include <stdio_ext.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 | #include <unistd.h> | 
 | #include <libintl.h> | 
 |  | 
 | /* #include "ftp_var.h" */ | 
 |  | 
 | static	int token (void); | 
 | static	FILE *cfile; | 
 |  | 
 | #define	DEFAULT	1 | 
 | #define	LOGIN	2 | 
 | #define	PASSWD	3 | 
 | #define	ACCOUNT 4 | 
 | #define MACDEF  5 | 
 | #define	ID	10 | 
 | #define	MACHINE	11 | 
 |  | 
 | static char tokval[100]; | 
 |  | 
 | static const char tokstr[] = | 
 | { | 
 | #define TOK_DEFAULT_IDX	0 | 
 |   "default\0" | 
 | #define TOK_LOGIN_IDX	(TOK_DEFAULT_IDX + sizeof "default") | 
 |   "login\0" | 
 | #define TOK_PASSWORD_IDX (TOK_LOGIN_IDX + sizeof "login") | 
 |   "password\0" | 
 | #define TOK_PASSWD_IDX	(TOK_PASSWORD_IDX + sizeof "password") | 
 |   "passwd\0" | 
 | #define TOK_ACCOUNT_IDX	(TOK_PASSWD_IDX + sizeof "passwd") | 
 |   "account\0" | 
 | #define TOK_MACHINE_IDX	(TOK_ACCOUNT_IDX + sizeof "account") | 
 |   "machine\0" | 
 | #define TOK_MACDEF_IDX	(TOK_MACHINE_IDX + sizeof "machine") | 
 |   "macdef" | 
 | }; | 
 |  | 
 | static const struct toktab { | 
 | 	int tokstr_off; | 
 | 	int tval; | 
 | } toktab[]= { | 
 | 	{ TOK_DEFAULT_IDX,	DEFAULT }, | 
 | 	{ TOK_LOGIN_IDX,	LOGIN }, | 
 | 	{ TOK_PASSWORD_IDX,	PASSWD }, | 
 | 	{ TOK_PASSWD_IDX,	PASSWD }, | 
 | 	{ TOK_ACCOUNT_IDX,	ACCOUNT }, | 
 | 	{ TOK_MACHINE_IDX,	MACHINE }, | 
 | 	{ TOK_MACDEF_IDX,	MACDEF } | 
 | }; | 
 |  | 
 |  | 
 |  | 
 | int | 
 | ruserpass (const char *host, const char **aname, const char **apass) | 
 | { | 
 | 	char *hdir, *buf, *tmp; | 
 | 	char myname[1024], *mydomain; | 
 | 	int t, usedefault = 0; | 
 | 	struct stat64 stb; | 
 |  | 
 | 	hdir = __libc_secure_getenv("HOME"); | 
 | 	if (hdir == NULL) { | 
 | 		/* If we can't get HOME, fail instead of trying ".", | 
 | 		   which is no improvement. This really should call | 
 | 		   getpwuid(getuid()).  */ | 
 | 		/*hdir = ".";*/ | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	buf = alloca (strlen (hdir) + 8); | 
 |  | 
 | 	__stpcpy (__stpcpy (buf, hdir), "/.netrc"); | 
 | 	cfile = fopen(buf, "rce"); | 
 | 	if (cfile == NULL) { | 
 | 		if (errno != ENOENT) | 
 | 			warn("%s", buf); | 
 | 		return (0); | 
 | 	} | 
 | 	/* No threads use this stream.  */ | 
 | 	__fsetlocking (cfile, FSETLOCKING_BYCALLER); | 
 | 	if (__gethostname(myname, sizeof(myname)) < 0) | 
 | 		myname[0] = '\0'; | 
 | 	mydomain = __strchrnul(myname, '.'); | 
 | next: | 
 | 	while ((t = token())) switch(t) { | 
 |  | 
 | 	case DEFAULT: | 
 | 		usedefault = 1; | 
 | 		/* FALL THROUGH */ | 
 |  | 
 | 	case MACHINE: | 
 | 		if (!usedefault) { | 
 | 			if (token() != ID) | 
 | 				continue; | 
 | 			/* | 
 | 			 * Allow match either for user's input host name | 
 | 			 * or official hostname.  Also allow match of | 
 | 			 * incompletely-specified host in local domain. | 
 | 			 */ | 
 | 			if (__strcasecmp(host, tokval) == 0) | 
 | 				goto match; | 
 | /*			if (__strcasecmp(hostname, tokval) == 0) | 
 | 				goto match; | 
 | 			if ((tmp = strchr(hostname, '.')) != NULL && | 
 | 			    __strcasecmp(tmp, mydomain) == 0 && | 
 | 			    __strncasecmp(hostname, tokval, tmp-hostname) == 0 && | 
 | 			    tokval[tmp - hostname] == '\0') | 
 | 				goto match; */ | 
 | 			if ((tmp = strchr(host, '.')) != NULL && | 
 | 			    __strcasecmp(tmp, mydomain) == 0 && | 
 | 			    __strncasecmp(host, tokval, tmp - host) == 0 && | 
 | 			    tokval[tmp - host] == '\0') | 
 | 				goto match; | 
 | 			continue; | 
 | 		} | 
 | 	match: | 
 | 		while ((t = token()) && t != MACHINE && t != DEFAULT) switch(t) { | 
 |  | 
 | 		case LOGIN: | 
 | 			if (token()) { | 
 | 				if (*aname == 0) { | 
 | 				  char *newp; | 
 | 				  newp = malloc((unsigned) strlen(tokval) + 1); | 
 | 				  if (newp == NULL) | 
 | 				    { | 
 | 				      warnx(_("out of memory")); | 
 | 				      goto bad; | 
 | 				    } | 
 | 				  *aname = strcpy(newp, tokval); | 
 | 				} else { | 
 | 					if (strcmp(*aname, tokval)) | 
 | 						goto next; | 
 | 				} | 
 | 			} | 
 | 			break; | 
 | 		case PASSWD: | 
 | 			if (strcmp(*aname, "anonymous") && | 
 | 			    fstat64(fileno(cfile), &stb) >= 0 && | 
 | 			    (stb.st_mode & 077) != 0) { | 
 | 	warnx(_("Error: .netrc file is readable by others.")); | 
 | 	warnx(_("Remove password or make file unreadable by others.")); | 
 | 				goto bad; | 
 | 			} | 
 | 			if (token() && *apass == 0) { | 
 | 				char *newp; | 
 | 				newp = malloc((unsigned) strlen(tokval) + 1); | 
 | 				if (newp == NULL) | 
 | 				  { | 
 | 				    warnx(_("out of memory")); | 
 | 				    goto bad; | 
 | 				  } | 
 | 				*apass = strcpy(newp, tokval); | 
 | 			} | 
 | 			break; | 
 | 		case ACCOUNT: | 
 | #if 0 | 
 | 			if (fstat64(fileno(cfile), &stb) >= 0 | 
 | 			    && (stb.st_mode & 077) != 0) { | 
 | 	warnx("Error: .netrc file is readable by others."); | 
 | 	warnx("Remove account or make file unreadable by others."); | 
 | 				goto bad; | 
 | 			} | 
 | 			if (token() && *aacct == 0) { | 
 | 				*aacct = malloc((unsigned) strlen(tokval) + 1); | 
 | 				(void) strcpy(*aacct, tokval); | 
 | 			} | 
 | #endif | 
 | 			break; | 
 | 		case MACDEF: | 
 | #if 0 | 
 | 			if (proxy) { | 
 | 				(void) fclose(cfile); | 
 | 				return (0); | 
 | 			} | 
 | 			while ((c=getc_unlocked(cfile)) != EOF && c == ' ' | 
 | 			       || c == '\t'); | 
 | 			if (c == EOF || c == '\n') { | 
 | 				printf("Missing macdef name argument.\n"); | 
 | 				goto bad; | 
 | 			} | 
 | 			if (macnum == 16) { | 
 | 				printf("Limit of 16 macros have already been defined\n"); | 
 | 				goto bad; | 
 | 			} | 
 | 			tmp = macros[macnum].mac_name; | 
 | 			*tmp++ = c; | 
 | 			for (i=0; i < 8 && (c=getc_unlocked(cfile)) != EOF && | 
 | 			    !isspace(c); ++i) { | 
 | 				*tmp++ = c; | 
 | 			} | 
 | 			if (c == EOF) { | 
 | 				printf("Macro definition missing null line terminator.\n"); | 
 | 				goto bad; | 
 | 			} | 
 | 			*tmp = '\0'; | 
 | 			if (c != '\n') { | 
 | 				while ((c=getc_unlocked(cfile)) != EOF | 
 | 				       && c != '\n'); | 
 | 			} | 
 | 			if (c == EOF) { | 
 | 				printf("Macro definition missing null line terminator.\n"); | 
 | 				goto bad; | 
 | 			} | 
 | 			if (macnum == 0) { | 
 | 				macros[macnum].mac_start = macbuf; | 
 | 			} | 
 | 			else { | 
 | 				macros[macnum].mac_start = macros[macnum-1].mac_end + 1; | 
 | 			} | 
 | 			tmp = macros[macnum].mac_start; | 
 | 			while (tmp != macbuf + 4096) { | 
 | 				if ((c=getc_unlocked(cfile)) == EOF) { | 
 | 				printf("Macro definition missing null line terminator.\n"); | 
 | 					goto bad; | 
 | 				} | 
 | 				*tmp = c; | 
 | 				if (*tmp == '\n') { | 
 | 					if (*(tmp-1) == '\0') { | 
 | 					   macros[macnum++].mac_end = tmp - 1; | 
 | 					   break; | 
 | 					} | 
 | 					*tmp = '\0'; | 
 | 				} | 
 | 				tmp++; | 
 | 			} | 
 | 			if (tmp == macbuf + 4096) { | 
 | 				printf("4K macro buffer exceeded\n"); | 
 | 				goto bad; | 
 | 			} | 
 | #endif | 
 | 			break; | 
 | 		default: | 
 | 			warnx(_("Unknown .netrc keyword %s"), tokval); | 
 | 			break; | 
 | 		} | 
 | 		goto done; | 
 | 	} | 
 | done: | 
 | 	(void) fclose(cfile); | 
 | 	return (0); | 
 | bad: | 
 | 	(void) fclose(cfile); | 
 | 	return (-1); | 
 | } | 
 | libc_hidden_def (ruserpass) | 
 |  | 
 | static int | 
 | token (void) | 
 | { | 
 | 	char *cp; | 
 | 	int c; | 
 | 	int i; | 
 |  | 
 | 	if (feof_unlocked(cfile) || ferror_unlocked(cfile)) | 
 | 		return (0); | 
 | 	while ((c = getc_unlocked(cfile)) != EOF && | 
 | 	    (c == '\n' || c == '\t' || c == ' ' || c == ',')) | 
 | 		continue; | 
 | 	if (c == EOF) | 
 | 		return (0); | 
 | 	cp = tokval; | 
 | 	if (c == '"') { | 
 | 		while ((c = getc_unlocked(cfile)) != EOF && c != '"') { | 
 | 			if (c == '\\') | 
 | 				c = getc_unlocked(cfile); | 
 | 			*cp++ = c; | 
 | 		} | 
 | 	} else { | 
 | 		*cp++ = c; | 
 | 		while ((c = getc_unlocked(cfile)) != EOF | 
 | 		    && c != '\n' && c != '\t' && c != ' ' && c != ',') { | 
 | 			if (c == '\\') | 
 | 				c = getc_unlocked(cfile); | 
 | 			*cp++ = c; | 
 | 		} | 
 | 	} | 
 | 	*cp = 0; | 
 | 	if (tokval[0] == 0) | 
 | 		return (0); | 
 | 	for (i = 0; i < (int) (sizeof (toktab) / sizeof (toktab[0])); ++i) | 
 | 		if (!strcmp(&tokstr[toktab[i].tokstr_off], tokval)) | 
 | 			return toktab[i].tval; | 
 | 	return (ID); | 
 | } |