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