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