190075Sobrien/* $NetBSD: ruserpass.c,v 1.8 2007/08/06 04:33:24 lukem Exp $ */ 2169689Skan/* from NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp */ 3169689Skan 490075Sobrien/* 590075Sobrien * Copyright (c) 1985, 1993, 1994 690075Sobrien * The Regents of the University of California. All rights reserved. 790075Sobrien * 890075Sobrien * Redistribution and use in source and binary forms, with or without 990075Sobrien * modification, are permitted provided that the following conditions 1090075Sobrien * are met: 1190075Sobrien * 1. Redistributions of source code must retain the above copyright 1290075Sobrien * notice, this list of conditions and the following disclaimer. 1390075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1490075Sobrien * notice, this list of conditions and the following disclaimer in the 1590075Sobrien * documentation and/or other materials provided with the distribution. 1690075Sobrien * 3. Neither the name of the University nor the names of its contributors 1790075Sobrien * may be used to endorse or promote products derived from this software 1890075Sobrien * without specific prior written permission. 19169689Skan * 20169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2190075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2290075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2390075Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2490075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2590075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2690075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2790075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2890075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2990075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3090075Sobrien * SUCH DAMAGE. 3190075Sobrien */ 3290075Sobrien 3390075Sobrien#include "tnftp.h" 3490075Sobrien 3590075Sobrien#if 0 /* tnftp */ 3690075Sobrien 3790075Sobrien#include <sys/cdefs.h> 3890075Sobrien#ifndef lint 3990075Sobrien#if 0 4090075Sobrienstatic char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95"; 4190075Sobrien#else 42132718Skan__RCSID(" NetBSD: ruserpass.c,v 1.33 2007/04/17 05:52:04 lukem Exp "); 43132718Skan#endif 44132718Skan#endif /* not lint */ 45132718Skan 46132718Skan#include <sys/types.h> 47132718Skan#include <sys/stat.h> 48117395Skan 4990075Sobrien#include <ctype.h> 5090075Sobrien#include <err.h> 51132718Skan#include <errno.h> 52117395Skan#include <netdb.h> 53117395Skan#include <stdio.h> 5490075Sobrien#include <stdlib.h> 55132718Skan#include <string.h> 56132718Skan#include <unistd.h> 57132718Skan 58132718Skan#endif /* tnftp */ 59132718Skan 60132718Skan#include "ftp_var.h" 61132718Skan 62132718Skanstatic int token(void); 63132718Skanstatic FILE *cfile; 64132718Skan 6590075Sobrien#define DEFAULT 1 6690075Sobrien#define LOGIN 2 67132718Skan#define PASSWD 3 6890075Sobrien#define ACCOUNT 4 6990075Sobrien#define MACDEF 5 7090075Sobrien#define ID 10 7190075Sobrien#define MACH 11 7290075Sobrien 7390075Sobrienstatic char tokval[100]; 7490075Sobrien 7590075Sobrienstatic struct toktab { 7690075Sobrien const char *tokstr; 7790075Sobrien int tval; 7890075Sobrien} toktab[] = { 7990075Sobrien { "default", DEFAULT }, 8090075Sobrien { "login", LOGIN }, 8190075Sobrien { "password", PASSWD }, 8290075Sobrien { "passwd", PASSWD }, 8390075Sobrien { "account", ACCOUNT }, 8490075Sobrien { "machine", MACH }, 8590075Sobrien { "macdef", MACDEF }, 86169689Skan { NULL, 0 } 87169689Skan}; 8890075Sobrien 8990075Sobrienint 9090075Sobrienruserpass(const char *host, char **aname, char **apass, char **aacct) 9190075Sobrien{ 9290075Sobrien char *tmp; 9390075Sobrien const char *mydomain; 9490075Sobrien char myname[MAXHOSTNAMELEN + 1]; 9590075Sobrien int t, i, c, usedefault = 0; 9690075Sobrien struct stat stb; 9790075Sobrien 9890075Sobrien if (netrc[0] == '\0') 99169689Skan return (0); 100169689Skan cfile = fopen(netrc, "r"); 101169689Skan if (cfile == NULL) { 10290075Sobrien if (errno != ENOENT) 10390075Sobrien warn("Can't read `%s'", netrc); 10490075Sobrien return (0); 10590075Sobrien } 10690075Sobrien if (gethostname(myname, sizeof(myname)) < 0) 10790075Sobrien myname[0] = '\0'; 10890075Sobrien myname[sizeof(myname) - 1] = '\0'; 10990075Sobrien if ((mydomain = strchr(myname, '.')) == NULL) 11090075Sobrien mydomain = ""; 11190075Sobrien next: 11290075Sobrien while ((t = token()) > 0) switch(t) { 11390075Sobrien 11490075Sobrien case DEFAULT: 115132718Skan usedefault = 1; 11690075Sobrien /* FALL THROUGH */ 11790075Sobrien 11890075Sobrien case MACH: 11990075Sobrien if (!usedefault) { 12090075Sobrien if ((t = token()) == -1) 12190075Sobrien goto bad; 12290075Sobrien if (t != ID) 12390075Sobrien continue; 12490075Sobrien /* 12590075Sobrien * Allow match either for user's input host name 12690075Sobrien * or official hostname. Also allow match of 12790075Sobrien * incompletely-specified host in local domain. 12890075Sobrien */ 12990075Sobrien if (strcasecmp(host, tokval) == 0) 130132718Skan goto match; 131132718Skan if (strcasecmp(hostname, tokval) == 0) 132132718Skan goto match; 133132718Skan if ((tmp = strchr(hostname, '.')) != NULL && 13490075Sobrien strcasecmp(tmp, mydomain) == 0 && 13590075Sobrien strncasecmp(hostname, tokval, tmp-hostname) == 0 && 13690075Sobrien tokval[tmp - hostname] == '\0') 13790075Sobrien goto match; 13890075Sobrien if ((tmp = strchr(host, '.')) != NULL && 139169689Skan strcasecmp(tmp, mydomain) == 0 && 140169689Skan strncasecmp(host, tokval, tmp - host) == 0 && 14190075Sobrien tokval[tmp - host] == '\0') 14290075Sobrien goto match; 14390075Sobrien continue; 14490075Sobrien } 14590075Sobrien match: 14690075Sobrien while ((t = token()) > 0 && 14790075Sobrien t != MACH && t != DEFAULT) switch(t) { 14890075Sobrien 14990075Sobrien case LOGIN: 15090075Sobrien if ((t = token()) == -1) 151132718Skan goto bad; 15290075Sobrien if (t) { 153132718Skan if (*aname == NULL) 154132718Skan *aname = ftp_strdup(tokval); 155132718Skan else { 156132718Skan if (strcmp(*aname, tokval)) 15790075Sobrien goto next; 15890075Sobrien } 159169689Skan } 160169689Skan break; 16190075Sobrien case PASSWD: 16290075Sobrien if ((*aname == NULL || strcmp(*aname, "anonymous")) && 163169689Skan fstat(fileno(cfile), &stb) >= 0 && 164169689Skan (stb.st_mode & 077) != 0) { 16590075Sobrien warnx("Error: .netrc file is readable by others"); 16690075Sobrien warnx("Remove password or make file unreadable by others"); 167169689Skan goto bad; 168169689Skan } 169117395Skan if ((t = token()) == -1) 170117395Skan goto bad; 171169689Skan if (t && *apass == NULL) 172169689Skan *apass = ftp_strdup(tokval); 173169689Skan break; 174169689Skan case ACCOUNT: 175169689Skan if (fstat(fileno(cfile), &stb) >= 0 176169689Skan && (stb.st_mode & 077) != 0) { 177169689Skan warnx("Error: .netrc file is readable by others"); 178169689Skan warnx("Remove account or make file unreadable by others"); 179169689Skan goto bad; 180169689Skan } 181169689Skan if ((t = token()) == -1) 182117395Skan goto bad; 183117395Skan if (t && *aacct == NULL) 184169689Skan *aacct = ftp_strdup(tokval); 185169689Skan break; 186169689Skan case MACDEF: 187169689Skan if (proxy) { 188169689Skan (void)fclose(cfile); 189169689Skan return (0); 190132718Skan } 191132718Skan while ((c = getc(cfile)) != EOF) 192169689Skan if (c != ' ' && c != '\t') 193132718Skan break; 194169689Skan if (c == EOF || c == '\n') { 195169689Skan fputs("Missing macdef name argument.\n", 196132718Skan ttyout); 197132718Skan goto bad; 198169689Skan } 199169689Skan if (macnum == 16) { 200132718Skan fputs( 201132718Skan "Limit of 16 macros have already been defined.\n", 202132718Skan ttyout); 203132718Skan goto bad; 204169689Skan } 205169689Skan tmp = macros[macnum].mac_name; 20690075Sobrien *tmp++ = c; 20790075Sobrien for (i = 0; i < 8 && (c = getc(cfile)) != EOF && 20890075Sobrien !isspace(c); ++i) { 20990075Sobrien *tmp++ = c; 21090075Sobrien } 21190075Sobrien if (c == EOF) { 21290075Sobrien fputs( 21390075Sobrien "Macro definition missing null line terminator.\n", 214132718Skan ttyout); 215132718Skan goto bad; 216132718Skan } 217132718Skan *tmp = '\0'; 218132718Skan if (c != '\n') { 219132718Skan while ((c = getc(cfile)) != EOF && c != '\n'); 220132718Skan } 221132718Skan if (c == EOF) { 222132718Skan fputs( 22390075Sobrien "Macro definition missing null line terminator.\n", 22490075Sobrien ttyout); 22590075Sobrien goto bad; 22690075Sobrien } 22790075Sobrien if (macnum == 0) { 22890075Sobrien macros[macnum].mac_start = macbuf; 22990075Sobrien } 230132718Skan else { 23190075Sobrien macros[macnum].mac_start = 23290075Sobrien macros[macnum-1].mac_end + 1; 23390075Sobrien } 234132718Skan tmp = macros[macnum].mac_start; 235132718Skan while (tmp != macbuf + 4096) { 236132718Skan if ((c = getc(cfile)) == EOF) { 237169689Skan fputs( 238169689Skan "Macro definition missing null line terminator.\n", 239169689Skan ttyout); 240169689Skan goto bad; 241169689Skan } 242169689Skan *tmp = c; 243169689Skan if (*tmp == '\n') { 244169689Skan if (tmp == macros[macnum].mac_start) { 245169689Skan macros[macnum++].mac_end = tmp; 246169689Skan break; 247169689Skan } else if (*(tmp - 1) == '\0') { 248169689Skan macros[macnum++].mac_end = 249169689Skan tmp - 1; 250169689Skan break; 251169689Skan } 252169689Skan *tmp = '\0'; 253132718Skan } 254132718Skan tmp++; 255132718Skan } 256132718Skan if (tmp == macbuf + 4096) { 257132718Skan fputs("4K macro buffer exceeded.\n", 258132718Skan ttyout); 259169689Skan goto bad; 260169689Skan } 261169689Skan break; 262169689Skan default: 263169689Skan warnx("Unknown .netrc keyword `%s'", tokval); 264132718Skan break; 265169689Skan } 266169689Skan goto done; 267169689Skan } 26890075Sobrien done: 26990075Sobrien if (t == -1) 27090075Sobrien goto bad; 271117395Skan (void)fclose(cfile); 27290075Sobrien return (0); 27390075Sobrien bad: 27490075Sobrien (void)fclose(cfile); 27590075Sobrien return (-1); 27690075Sobrien} 27790075Sobrien 27890075Sobrienstatic int 27990075Sobrientoken(void) 28090075Sobrien{ 28190075Sobrien char *cp; 282169689Skan int c; 28390075Sobrien struct toktab *t; 28490075Sobrien 28590075Sobrien if (feof(cfile) || ferror(cfile)) 28690075Sobrien return (0); 28790075Sobrien while ((c = getc(cfile)) != EOF && 28890075Sobrien (c == '\n' || c == '\t' || c == ' ' || c == ',')) 28990075Sobrien continue; 29090075Sobrien if (c == EOF) 291169689Skan return (0); 292169689Skan cp = tokval; 29390075Sobrien if (c == '"') { 29490075Sobrien while ((c = getc(cfile)) != EOF && c != '"') { 29590075Sobrien if (c == '\\') 29690075Sobrien if ((c = getc(cfile)) == EOF) 29790075Sobrien break; 29890075Sobrien *cp++ = c; 29990075Sobrien if (cp == tokval + sizeof(tokval)) { 30090075Sobrien warnx("Token in .netrc too long"); 30190075Sobrien return (-1); 30290075Sobrien } 30390075Sobrien } 30490075Sobrien } else { 30590075Sobrien *cp++ = c; 306132718Skan while ((c = getc(cfile)) != EOF 307132718Skan && c != '\n' && c != '\t' && c != ' ' && c != ',') { 30890075Sobrien if (c == '\\') 30990075Sobrien if ((c = getc(cfile)) == EOF) 31090075Sobrien break; 311169689Skan *cp++ = c; 31290075Sobrien if (cp == tokval + sizeof(tokval)) { 31390075Sobrien warnx("Token in .netrc too long"); 31490075Sobrien return (-1); 31590075Sobrien } 31690075Sobrien } 31790075Sobrien } 31890075Sobrien *cp = 0; 319132718Skan if (tokval[0] == 0) 320132718Skan return (0); 321132718Skan for (t = toktab; t->tokstr; t++) 322132718Skan if (!strcmp(t->tokstr, tokval)) 32390075Sobrien return (t->tval); 324169689Skan return (ID); 32590075Sobrien} 326169689Skan