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" 35233294SstasRCSID("$Id$"); 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 }, 62233294Sstas { "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 108233294Sstasruserpassword(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 140233294Sstas * 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()) { 166233294Sstas 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 } 202233294Sstas 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