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