155682Smarkm/*
255682Smarkm * Copyright (c) 1985, 1993, 1994
355682Smarkm *	The Regents of the University of California.  All rights reserved.
455682Smarkm *
555682Smarkm * Redistribution and use in source and binary forms, with or without
655682Smarkm * modification, are permitted provided that the following conditions
755682Smarkm * are met:
855682Smarkm * 1. Redistributions of source code must retain the above copyright
955682Smarkm *    notice, this list of conditions and the following disclaimer.
1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer in the
1255682Smarkm *    documentation and/or other materials provided with the distribution.
1355682Smarkm * 3. All advertising materials mentioning features or use of this software
1455682Smarkm *    must display the following acknowledgement:
1555682Smarkm *	This product includes software developed by the University of
1655682Smarkm *	California, Berkeley and its contributors.
1755682Smarkm * 4. Neither the name of the University nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "ftp_locl.h"
35178825SdfrRCSID("$Id: ruserpass.c 16161 2005-10-12 09:44:24Z joda $");
3655682Smarkm
3755682Smarkmstatic	int token (void);
3855682Smarkmstatic	FILE *cfile;
3955682Smarkm
4055682Smarkm#define	DEFAULT	1
4155682Smarkm#define	LOGIN	2
4255682Smarkm#define	PASSWD	3
4355682Smarkm#define	ACCOUNT 4
4455682Smarkm#define MACDEF  5
4555682Smarkm#define PROT	6
4655682Smarkm#define	ID	10
4755682Smarkm#define	MACH	11
4855682Smarkm
4955682Smarkmstatic char tokval[100];
5055682Smarkm
5155682Smarkmstatic struct toktab {
5255682Smarkm	char *tokstr;
5355682Smarkm	int tval;
5455682Smarkm} toktab[]= {
5555682Smarkm	{ "default",	DEFAULT },
5655682Smarkm	{ "login",	LOGIN },
5755682Smarkm	{ "password",	PASSWD },
5855682Smarkm	{ "passwd",	PASSWD },
5955682Smarkm	{ "account",	ACCOUNT },
6055682Smarkm	{ "machine",	MACH },
6155682Smarkm	{ "macdef",	MACDEF },
6255682Smarkm	{ "prot", 	PROT },
6355682Smarkm	{ NULL,		0 }
6455682Smarkm};
6555682Smarkm
6655682Smarkm/*
6755682Smarkm * Write a copy of the hostname into `hostname, sz' and return a guess
6855682Smarkm * as to the `domain' of that hostname.
6955682Smarkm */
7055682Smarkm
7155682Smarkmstatic char *
72178825Sdfrguess_domain (char *hostname_str, size_t sz)
7355682Smarkm{
7455682Smarkm    struct addrinfo *ai, *a;
7555682Smarkm    struct addrinfo hints;
7655682Smarkm    int error;
7755682Smarkm    char *dot;
7855682Smarkm
79178825Sdfr    if (gethostname (hostname_str, sz) < 0) {
80178825Sdfr	strlcpy (hostname_str, "", sz);
8155682Smarkm	return "";
8255682Smarkm    }
83178825Sdfr    dot = strchr (hostname_str, '.');
8455682Smarkm    if (dot != NULL)
8555682Smarkm	return dot + 1;
8655682Smarkm
8755682Smarkm    memset (&hints, 0, sizeof(hints));
8855682Smarkm    hints.ai_flags = AI_CANONNAME;
8955682Smarkm
90178825Sdfr    error = getaddrinfo (hostname_str, NULL, &hints, &ai);
9155682Smarkm    if (error)
92178825Sdfr	return hostname_str;
9355682Smarkm
9455682Smarkm    for (a = ai; a != NULL; a = a->ai_next)
9555682Smarkm	if (a->ai_canonname != NULL) {
96178825Sdfr	    strlcpy (hostname_str, ai->ai_canonname, sz);
9755682Smarkm	    break;
9855682Smarkm	}
9955682Smarkm    freeaddrinfo (ai);
100178825Sdfr    dot = strchr (hostname_str, '.');
10155682Smarkm    if (dot != NULL)
10255682Smarkm	return dot + 1;
10355682Smarkm    else
104178825Sdfr	return hostname_str;
10555682Smarkm}
10655682Smarkm
10755682Smarkmint
10855682Smarkmruserpass(char *host, char **aname, char **apass, char **aacct)
10955682Smarkm{
11055682Smarkm    char *hdir, buf[BUFSIZ], *tmp;
11155682Smarkm    int t, i, c, usedefault = 0;
11255682Smarkm    struct stat stb;
11355682Smarkm
11455682Smarkm    mydomain = guess_domain (myhostname, MaxHostNameLen);
11555682Smarkm
11655682Smarkm    hdir = getenv("HOME");
11755682Smarkm    if (hdir == NULL)
11855682Smarkm	hdir = ".";
11955682Smarkm    snprintf(buf, sizeof(buf), "%s/.netrc", hdir);
12055682Smarkm    cfile = fopen(buf, "r");
12155682Smarkm    if (cfile == NULL) {
12255682Smarkm	if (errno != ENOENT)
12355682Smarkm	    warn("%s", buf);
12455682Smarkm	return (0);
12555682Smarkm    }
12655682Smarkm
12755682Smarkmnext:
12855682Smarkm    while ((t = token())) switch(t) {
12955682Smarkm
13055682Smarkm    case DEFAULT:
13155682Smarkm	usedefault = 1;
13255682Smarkm	/* FALL THROUGH */
13355682Smarkm
13455682Smarkm    case MACH:
13555682Smarkm	if (!usedefault) {
13655682Smarkm	    if (token() != ID)
13755682Smarkm		continue;
13855682Smarkm	    /*
13955682Smarkm	     * Allow match either for user's input host name
14055682Smarkm	     * or official hostname.  Also allow match of
14155682Smarkm	     * incompletely-specified host in local domain.
14255682Smarkm	     */
14355682Smarkm	    if (strcasecmp(host, tokval) == 0)
14455682Smarkm		goto match;
14555682Smarkm	    if (strcasecmp(hostname, tokval) == 0)
14655682Smarkm		goto match;
14755682Smarkm	    if ((tmp = strchr(hostname, '.')) != NULL &&
14855682Smarkm		tmp++ &&
14955682Smarkm		strcasecmp(tmp, mydomain) == 0 &&
15055682Smarkm		strncasecmp(hostname, tokval, tmp-hostname) == 0 &&
15155682Smarkm		tokval[tmp - hostname] == '\0')
15255682Smarkm		goto match;
15355682Smarkm	    if ((tmp = strchr(host, '.')) != NULL &&
15455682Smarkm		tmp++ &&
15555682Smarkm		strcasecmp(tmp, mydomain) == 0 &&
15655682Smarkm		strncasecmp(host, tokval, tmp - host) == 0 &&
15755682Smarkm		tokval[tmp - host] == '\0')
15855682Smarkm		goto match;
15955682Smarkm	    continue;
16055682Smarkm	}
16155682Smarkm    match:
16255682Smarkm	while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
16355682Smarkm
16455682Smarkm	case LOGIN:
16555682Smarkm	    if (token()) {
16655682Smarkm		if (*aname == 0) {
16755682Smarkm		    *aname = strdup(tokval);
16855682Smarkm		} else {
16955682Smarkm		    if (strcmp(*aname, tokval))
17055682Smarkm			goto next;
17155682Smarkm		}
17255682Smarkm	    }
17355682Smarkm	    break;
17455682Smarkm	case PASSWD:
17555682Smarkm	    if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
17655682Smarkm		fstat(fileno(cfile), &stb) >= 0 &&
17755682Smarkm		(stb.st_mode & 077) != 0) {
17855682Smarkm		warnx("Error: .netrc file is readable by others.");
17955682Smarkm		warnx("Remove password or make file unreadable by others.");
18055682Smarkm		goto bad;
18155682Smarkm	    }
18255682Smarkm	    if (token() && *apass == 0) {
18355682Smarkm		*apass = strdup(tokval);
18455682Smarkm	    }
18555682Smarkm	    break;
18655682Smarkm	case ACCOUNT:
18755682Smarkm	    if (fstat(fileno(cfile), &stb) >= 0
18855682Smarkm		&& (stb.st_mode & 077) != 0) {
18955682Smarkm		warnx("Error: .netrc file is readable by others.");
19055682Smarkm		warnx("Remove account or make file unreadable by others.");
19155682Smarkm		goto bad;
19255682Smarkm	    }
19355682Smarkm	    if (token() && *aacct == 0) {
19455682Smarkm		*aacct = strdup(tokval);
19555682Smarkm	    }
19655682Smarkm	    break;
19755682Smarkm	case MACDEF:
19855682Smarkm	    if (proxy) {
19955682Smarkm		fclose(cfile);
20055682Smarkm		return (0);
20155682Smarkm	    }
20255682Smarkm	    while ((c=getc(cfile)) != EOF &&
20355682Smarkm		   (c == ' ' || c == '\t'));
20455682Smarkm	    if (c == EOF || c == '\n') {
20555682Smarkm		printf("Missing macdef name argument.\n");
20655682Smarkm		goto bad;
20755682Smarkm	    }
20855682Smarkm	    if (macnum == 16) {
20955682Smarkm		printf("Limit of 16 macros have already been defined\n");
21055682Smarkm		goto bad;
21155682Smarkm	    }
21255682Smarkm	    tmp = macros[macnum].mac_name;
21355682Smarkm	    *tmp++ = c;
21455682Smarkm	    for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
21555682Smarkm		     !isspace(c); ++i) {
21655682Smarkm		*tmp++ = c;
21755682Smarkm	    }
21855682Smarkm	    if (c == EOF) {
21955682Smarkm		printf("Macro definition missing null line terminator.\n");
22055682Smarkm		goto bad;
22155682Smarkm	    }
22255682Smarkm	    *tmp = '\0';
22355682Smarkm	    if (c != '\n') {
22455682Smarkm		while ((c=getc(cfile)) != EOF && c != '\n');
22555682Smarkm	    }
22655682Smarkm	    if (c == EOF) {
22755682Smarkm		printf("Macro definition missing null line terminator.\n");
22855682Smarkm		goto bad;
22955682Smarkm	    }
23055682Smarkm	    if (macnum == 0) {
23155682Smarkm		macros[macnum].mac_start = macbuf;
23255682Smarkm	    }
23355682Smarkm	    else {
23455682Smarkm		macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
23555682Smarkm	    }
23655682Smarkm	    tmp = macros[macnum].mac_start;
23755682Smarkm	    while (tmp != macbuf + 4096) {
23855682Smarkm		if ((c=getc(cfile)) == EOF) {
23955682Smarkm		    printf("Macro definition missing null line terminator.\n");
24055682Smarkm		    goto bad;
24155682Smarkm		}
24255682Smarkm		*tmp = c;
24355682Smarkm		if (*tmp == '\n') {
24455682Smarkm		    if (*(tmp-1) == '\0') {
24555682Smarkm			macros[macnum++].mac_end = tmp - 1;
24655682Smarkm			break;
24755682Smarkm		    }
24855682Smarkm		    *tmp = '\0';
24955682Smarkm		}
25055682Smarkm		tmp++;
25155682Smarkm	    }
25255682Smarkm	    if (tmp == macbuf + 4096) {
25355682Smarkm		printf("4K macro buffer exceeded\n");
25455682Smarkm		goto bad;
25555682Smarkm	    }
25655682Smarkm	    break;
25755682Smarkm	case PROT:
25855682Smarkm	    token();
259178825Sdfr	    if(doencrypt == 0 && sec_request_prot(tokval) < 0)
26055682Smarkm		warnx("Unknown protection level \"%s\"", tokval);
26155682Smarkm	    break;
26255682Smarkm	default:
26355682Smarkm	    warnx("Unknown .netrc keyword %s", tokval);
26455682Smarkm	    break;
26555682Smarkm	}
26655682Smarkm	goto done;
26755682Smarkm    }
26855682Smarkmdone:
26955682Smarkm    fclose(cfile);
27055682Smarkm    return (0);
27155682Smarkmbad:
27255682Smarkm    fclose(cfile);
27355682Smarkm    return (-1);
27455682Smarkm}
27555682Smarkm
27655682Smarkmstatic int
27755682Smarkmtoken(void)
27855682Smarkm{
27955682Smarkm	char *cp;
28055682Smarkm	int c;
28155682Smarkm	struct toktab *t;
28255682Smarkm
28355682Smarkm	if (feof(cfile) || ferror(cfile))
28455682Smarkm		return (0);
28555682Smarkm	while ((c = getc(cfile)) != EOF &&
28655682Smarkm	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
28755682Smarkm		continue;
28855682Smarkm	if (c == EOF)
28955682Smarkm		return (0);
29055682Smarkm	cp = tokval;
29155682Smarkm	if (c == '"') {
29255682Smarkm		while ((c = getc(cfile)) != EOF && c != '"') {
29355682Smarkm			if (c == '\\')
29455682Smarkm				c = getc(cfile);
29555682Smarkm			*cp++ = c;
29655682Smarkm		}
29755682Smarkm	} else {
29855682Smarkm		*cp++ = c;
29955682Smarkm		while ((c = getc(cfile)) != EOF
30055682Smarkm		    && c != '\n' && c != '\t' && c != ' ' && c != ',') {
30155682Smarkm			if (c == '\\')
30255682Smarkm				c = getc(cfile);
30355682Smarkm			*cp++ = c;
30455682Smarkm		}
30555682Smarkm	}
30655682Smarkm	*cp = 0;
30755682Smarkm	if (tokval[0] == 0)
30855682Smarkm		return (0);
30955682Smarkm	for (t = toktab; t->tokstr; t++)
31055682Smarkm		if (!strcmp(t->tokstr, tokval))
31155682Smarkm			return (t->tval);
31255682Smarkm	return (ID);
31355682Smarkm}
314