1*d1063cbfSchristos /* $NetBSD: ruserpass.c,v 1.35 2024/10/04 18:04:06 christos Exp $ */ 2917ef72dStls 361f28255Scgd /* 4dea9ded2Scgd * Copyright (c) 1985, 1993, 1994 5dea9ded2Scgd * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * Redistribution and use in source and binary forms, with or without 861f28255Scgd * modification, are permitted provided that the following conditions 961f28255Scgd * are met: 1061f28255Scgd * 1. Redistributions of source code must retain the above copyright 1161f28255Scgd * notice, this list of conditions and the following disclaimer. 1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1361f28255Scgd * notice, this list of conditions and the following disclaimer in the 1461f28255Scgd * documentation and/or other materials provided with the distribution. 1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors 1661f28255Scgd * may be used to endorse or promote products derived from this software 1761f28255Scgd * without specific prior written permission. 1861f28255Scgd * 1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2961f28255Scgd * SUCH DAMAGE. 3061f28255Scgd */ 3161f28255Scgd 32b9d5554dSlukem #include <sys/cdefs.h> 3361f28255Scgd #ifndef lint 347a7fa807Slukem #if 0 35917ef72dStls static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95"; 367a7fa807Slukem #else 37*d1063cbfSchristos __RCSID("$NetBSD: ruserpass.c,v 1.35 2024/10/04 18:04:06 christos Exp $"); 387a7fa807Slukem #endif 3961f28255Scgd #endif /* not lint */ 4061f28255Scgd 4161f28255Scgd #include <sys/types.h> 4261f28255Scgd #include <sys/stat.h> 43dea9ded2Scgd 44dea9ded2Scgd #include <ctype.h> 45dea9ded2Scgd #include <err.h> 4661f28255Scgd #include <errno.h> 470a0b6ed3Slukem #include <netdb.h> 48dea9ded2Scgd #include <stdio.h> 49dea9ded2Scgd #include <stdlib.h> 50dea9ded2Scgd #include <string.h> 51dea9ded2Scgd #include <unistd.h> 52dea9ded2Scgd 5361f28255Scgd #include "ftp_var.h" 5461f28255Scgd 552c9a4cf5Slukem static int token(void); 5661f28255Scgd static FILE *cfile; 5761f28255Scgd 5861f28255Scgd #define DEFAULT 1 5961f28255Scgd #define LOGIN 2 6061f28255Scgd #define PASSWD 3 6161f28255Scgd #define ACCOUNT 4 6261f28255Scgd #define MACDEF 5 6361f28255Scgd #define ID 10 6461f28255Scgd #define MACH 11 6561f28255Scgd 6661f28255Scgd static char tokval[100]; 6761f28255Scgd 6861f28255Scgd static struct toktab { 69ddc3d4caSlukem const char *tokstr; 7061f28255Scgd int tval; 7161f28255Scgd } toktab[] = { 72dea9ded2Scgd { "default", DEFAULT }, 73dea9ded2Scgd { "login", LOGIN }, 74dea9ded2Scgd { "password", PASSWD }, 75dea9ded2Scgd { "passwd", PASSWD }, 76dea9ded2Scgd { "account", ACCOUNT }, 77dea9ded2Scgd { "machine", MACH }, 78dea9ded2Scgd { "macdef", MACDEF }, 79dea9ded2Scgd { NULL, 0 } 8061f28255Scgd }; 8161f28255Scgd 82*d1063cbfSchristos static int 83*d1063cbfSchristos match_host_domain(const char *host, const char *domain, const char *tokv) 84*d1063cbfSchristos { 85*d1063cbfSchristos const char *tmp; 86*d1063cbfSchristos 87*d1063cbfSchristos if (strcasecmp(host, tokval) == 0) 88*d1063cbfSchristos return 1; 89*d1063cbfSchristos 90*d1063cbfSchristos return (tmp = strchr(host, '.')) != NULL && 91*d1063cbfSchristos strcasecmp(tmp, domain) == 0 && 92*d1063cbfSchristos strncasecmp(host, tokv, tmp - host) == 0 && 93*d1063cbfSchristos tokv[tmp - host] == '\0'; 94*d1063cbfSchristos } 95*d1063cbfSchristos 96dea9ded2Scgd int 97ddc3d4caSlukem ruserpass(const char *host, char **aname, char **apass, char **aacct) 9861f28255Scgd { 99ecd3d780Slukem char *tmp; 100ddc3d4caSlukem const char *mydomain; 101ddc3d4caSlukem char myname[MAXHOSTNAMELEN + 1]; 10261f28255Scgd int t, i, c, usedefault = 0; 10361f28255Scgd struct stat stb; 10461f28255Scgd 105ecd3d780Slukem if (netrc[0] == '\0') 1068ef5f804Slukem return (0); 107ecd3d780Slukem cfile = fopen(netrc, "r"); 10861f28255Scgd if (cfile == NULL) { 10961f28255Scgd if (errno != ENOENT) 1108a06b9bfSlukem warn("Can't read `%s'", netrc); 11161f28255Scgd return (0); 11261f28255Scgd } 11361f28255Scgd if (gethostname(myname, sizeof(myname)) < 0) 11461f28255Scgd myname[0] = '\0'; 1152beab49aSmrg myname[sizeof(myname) - 1] = '\0'; 116dea9ded2Scgd if ((mydomain = strchr(myname, '.')) == NULL) 11761f28255Scgd mydomain = ""; 11861f28255Scgd next: 119b1e08b00Slukem while ((t = token()) > 0) switch(t) { 12061f28255Scgd 12161f28255Scgd case DEFAULT: 12261f28255Scgd usedefault = 1; 12361f28255Scgd /* FALL THROUGH */ 12461f28255Scgd 12561f28255Scgd case MACH: 12661f28255Scgd if (!usedefault) { 127b1e08b00Slukem if ((t = token()) == -1) 128b1e08b00Slukem goto bad; 129b1e08b00Slukem if (t != ID) 13061f28255Scgd continue; 13161f28255Scgd /* 13261f28255Scgd * Allow match either for user's input host name 13361f28255Scgd * or official hostname. Also allow match of 13461f28255Scgd * incompletely-specified host in local domain. 13561f28255Scgd */ 136*d1063cbfSchristos if (match_host_domain(hostname, mydomain, tokval)) 13761f28255Scgd goto match; 138*d1063cbfSchristos if (match_host_domain(host, mydomain, tokval)) 13961f28255Scgd goto match; 14061f28255Scgd continue; 14161f28255Scgd } 14261f28255Scgd match: 143b1e08b00Slukem while ((t = token()) > 0 && 144b1e08b00Slukem t != MACH && t != DEFAULT) switch(t) { 14561f28255Scgd 14661f28255Scgd case LOGIN: 147b1e08b00Slukem if ((t = token()) == -1) 148b1e08b00Slukem goto bad; 149b1e08b00Slukem if (t) { 150d067f3bbSlukem if (*aname == NULL) 151e2279410Schristos *aname = ftp_strdup(tokval); 1524a8ec549Slukem else { 15361f28255Scgd if (strcmp(*aname, tokval)) 15461f28255Scgd goto next; 15561f28255Scgd } 156a0a2de67Schristos } 15761f28255Scgd break; 15861f28255Scgd case PASSWD: 159917ef72dStls if ((*aname == NULL || strcmp(*aname, "anonymous")) && 16061f28255Scgd fstat(fileno(cfile), &stb) >= 0 && 16161f28255Scgd (stb.st_mode & 077) != 0) { 1628a06b9bfSlukem warnx("Error: .netrc file is readable by others"); 1638a06b9bfSlukem warnx("Remove password or make file unreadable by others"); 16461f28255Scgd goto bad; 16561f28255Scgd } 166b1e08b00Slukem if ((t = token()) == -1) 167b1e08b00Slukem goto bad; 168b1e08b00Slukem if (t && *apass == NULL) 169e2279410Schristos *apass = ftp_strdup(tokval); 17061f28255Scgd break; 17161f28255Scgd case ACCOUNT: 17261f28255Scgd if (fstat(fileno(cfile), &stb) >= 0 17361f28255Scgd && (stb.st_mode & 077) != 0) { 1748a06b9bfSlukem warnx("Error: .netrc file is readable by others"); 1758a06b9bfSlukem warnx("Remove account or make file unreadable by others"); 17661f28255Scgd goto bad; 17761f28255Scgd } 178b1e08b00Slukem if ((t = token()) == -1) 179b1e08b00Slukem goto bad; 180b1e08b00Slukem if (t && *aacct == NULL) 181e2279410Schristos *aacct = ftp_strdup(tokval); 18261f28255Scgd break; 18361f28255Scgd case MACDEF: 18461f28255Scgd if (proxy) { 18561f28255Scgd (void)fclose(cfile); 18661f28255Scgd return (0); 18761f28255Scgd } 1887a7fa807Slukem while ((c = getc(cfile)) != EOF) 1897a7fa807Slukem if (c != ' ' && c != '\t') 1907a7fa807Slukem break; 19161f28255Scgd if (c == EOF || c == '\n') { 1929a6e9b2cSlukem fputs("Missing macdef name argument.\n", 1939a6e9b2cSlukem ttyout); 19461f28255Scgd goto bad; 19561f28255Scgd } 19661f28255Scgd if (macnum == 16) { 1979a6e9b2cSlukem fputs( 1989a6e9b2cSlukem "Limit of 16 macros have already been defined.\n", 1999a6e9b2cSlukem ttyout); 20061f28255Scgd goto bad; 20161f28255Scgd } 20261f28255Scgd tmp = macros[macnum].mac_name; 20361f28255Scgd *tmp++ = c; 20461f28255Scgd for (i = 0; i < 8 && (c = getc(cfile)) != EOF && 20561f28255Scgd !isspace(c); ++i) { 20661f28255Scgd *tmp++ = c; 20761f28255Scgd } 20861f28255Scgd if (c == EOF) { 2099a6e9b2cSlukem fputs( 2109a6e9b2cSlukem "Macro definition missing null line terminator.\n", 2119a6e9b2cSlukem ttyout); 21261f28255Scgd goto bad; 21361f28255Scgd } 21461f28255Scgd *tmp = '\0'; 21561f28255Scgd if (c != '\n') { 21661f28255Scgd while ((c = getc(cfile)) != EOF && c != '\n'); 21761f28255Scgd } 21861f28255Scgd if (c == EOF) { 2199a6e9b2cSlukem fputs( 2209a6e9b2cSlukem "Macro definition missing null line terminator.\n", 2219a6e9b2cSlukem ttyout); 22261f28255Scgd goto bad; 22361f28255Scgd } 22461f28255Scgd if (macnum == 0) { 22561f28255Scgd macros[macnum].mac_start = macbuf; 22661f28255Scgd } 22761f28255Scgd else { 228b6df1b3dSlukem macros[macnum].mac_start = 229b6df1b3dSlukem macros[macnum-1].mac_end + 1; 23061f28255Scgd } 23161f28255Scgd tmp = macros[macnum].mac_start; 23261f28255Scgd while (tmp != macbuf + 4096) { 23361f28255Scgd if ((c = getc(cfile)) == EOF) { 2349a6e9b2cSlukem fputs( 2359a6e9b2cSlukem "Macro definition missing null line terminator.\n", 2369a6e9b2cSlukem ttyout); 23761f28255Scgd goto bad; 23861f28255Scgd } 23961f28255Scgd *tmp = c; 24061f28255Scgd if (*tmp == '\n') { 241b1e08b00Slukem if (tmp == macros[macnum].mac_start) { 242b1e08b00Slukem macros[macnum++].mac_end = tmp; 243b1e08b00Slukem break; 244b1e08b00Slukem } else if (*(tmp - 1) == '\0') { 245b1e08b00Slukem macros[macnum++].mac_end = 246b1e08b00Slukem tmp - 1; 24761f28255Scgd break; 24861f28255Scgd } 24961f28255Scgd *tmp = '\0'; 25061f28255Scgd } 25161f28255Scgd tmp++; 25261f28255Scgd } 25361f28255Scgd if (tmp == macbuf + 4096) { 254e83274d0Slukem fputs("4 KiB macro buffer exceeded.\n", 2559a6e9b2cSlukem ttyout); 25661f28255Scgd goto bad; 25761f28255Scgd } 25861f28255Scgd break; 25961f28255Scgd default: 2608a06b9bfSlukem warnx("Unknown .netrc keyword `%s'", tokval); 26161f28255Scgd break; 26261f28255Scgd } 26361f28255Scgd goto done; 26461f28255Scgd } 26561f28255Scgd done: 266b1e08b00Slukem if (t == -1) 267b1e08b00Slukem goto bad; 26861f28255Scgd (void)fclose(cfile); 26961f28255Scgd return (0); 27061f28255Scgd bad: 27161f28255Scgd (void)fclose(cfile); 27261f28255Scgd return (-1); 27361f28255Scgd } 27461f28255Scgd 275dea9ded2Scgd static int 2762c9a4cf5Slukem token(void) 27761f28255Scgd { 27861f28255Scgd char *cp; 27961f28255Scgd int c; 28061f28255Scgd struct toktab *t; 28161f28255Scgd 282dea9ded2Scgd if (feof(cfile) || ferror(cfile)) 28361f28255Scgd return (0); 28461f28255Scgd while ((c = getc(cfile)) != EOF && 28561f28255Scgd (c == '\n' || c == '\t' || c == ' ' || c == ',')) 28661f28255Scgd continue; 28761f28255Scgd if (c == EOF) 28861f28255Scgd return (0); 28961f28255Scgd cp = tokval; 29061f28255Scgd if (c == '"') { 29161f28255Scgd while ((c = getc(cfile)) != EOF && c != '"') { 29261f28255Scgd if (c == '\\') 293b1e08b00Slukem if ((c = getc(cfile)) == EOF) 294b1e08b00Slukem break; 29561f28255Scgd *cp++ = c; 296b1e08b00Slukem if (cp == tokval + sizeof(tokval)) { 297b1e08b00Slukem warnx("Token in .netrc too long"); 298b1e08b00Slukem return (-1); 299b1e08b00Slukem } 30061f28255Scgd } 30161f28255Scgd } else { 30261f28255Scgd *cp++ = c; 30361f28255Scgd while ((c = getc(cfile)) != EOF 30461f28255Scgd && c != '\n' && c != '\t' && c != ' ' && c != ',') { 30561f28255Scgd if (c == '\\') 306b1e08b00Slukem if ((c = getc(cfile)) == EOF) 307b1e08b00Slukem break; 30861f28255Scgd *cp++ = c; 309b1e08b00Slukem if (cp == tokval + sizeof(tokval)) { 310b1e08b00Slukem warnx("Token in .netrc too long"); 311b1e08b00Slukem return (-1); 312b1e08b00Slukem } 31361f28255Scgd } 31461f28255Scgd } 31561f28255Scgd *cp = 0; 31661f28255Scgd if (tokval[0] == 0) 31761f28255Scgd return (0); 31861f28255Scgd for (t = toktab; t->tokstr; t++) 31961f28255Scgd if (!strcmp(t->tokstr, tokval)) 32061f28255Scgd return (t->tval); 32161f28255Scgd return (ID); 32261f28255Scgd } 323