1 /* $OpenBSD: ruserpass.c,v 1.26 2008/06/25 21:15:19 martynas 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 SMALL 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95"; 37 #else 38 static const char rcsid[] = "$OpenBSD: ruserpass.c,v 1.26 2008/06/25 21:15:19 martynas Exp $"; 39 #endif 40 #endif /* not lint */ 41 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 45 #include <ctype.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "ftp_var.h" 54 55 static int token(void); 56 static FILE *cfile; 57 58 #define DEFAULT 1 59 #define LOGIN 2 60 #define PASSWD 3 61 #define ACCOUNT 4 62 #define MACDEF 5 63 #define ID 10 64 #define MACH 11 65 66 static char tokval[100]; 67 68 static struct toktab { 69 char *tokstr; 70 int tval; 71 } toktab[]= { 72 { "default", DEFAULT }, 73 { "login", LOGIN }, 74 { "password", PASSWD }, 75 { "passwd", PASSWD }, 76 { "account", ACCOUNT }, 77 { "machine", MACH }, 78 { "macdef", MACDEF }, 79 { NULL, 0 } 80 }; 81 82 int 83 ruserpass(const char *host, char **aname, char **apass, char **aacct) 84 { 85 char *hdir, buf[MAXPATHLEN], *tmp; 86 char myname[MAXHOSTNAMELEN], *mydomain; 87 int t, i, c, usedefault = 0; 88 struct stat stb; 89 90 hdir = getenv("HOME"); 91 if (hdir == NULL || *hdir == '\0') 92 return (0); 93 i = snprintf(buf, sizeof(buf), "%s/.netrc", hdir); 94 if (i < 0 || i >= sizeof(buf)) { 95 warnx("%s/.netrc: %s", hdir, strerror(ENAMETOOLONG)); 96 return (0); 97 } 98 cfile = fopen(buf, "r"); 99 if (cfile == NULL) { 100 if (errno != ENOENT) 101 warn("%s", buf); 102 return (0); 103 } 104 if (gethostname(myname, sizeof(myname)) < 0) 105 myname[0] = '\0'; 106 if ((mydomain = strchr(myname, '.')) == NULL) 107 mydomain = ""; 108 next: 109 while ((t = token()) > 0) switch(t) { 110 111 case DEFAULT: 112 usedefault = 1; 113 /* FALLTHROUGH */ 114 115 case MACH: 116 if (!usedefault) { 117 if ((t = token()) == -1) 118 goto bad; 119 if (t != 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()) > 0 && 146 t != MACH && t != DEFAULT) switch(t) { 147 148 case LOGIN: 149 if ((t = token()) == -1) 150 goto bad; 151 if (t) { 152 if (*aname == 0) { 153 if ((*aname = strdup(tokval)) == NULL) 154 err(1, "strdup"); 155 } else { 156 if (strcmp(*aname, tokval)) 157 goto next; 158 } 159 } 160 break; 161 case PASSWD: 162 if ((*aname == NULL || strcmp(*aname, "anonymous")) && 163 fstat(fileno(cfile), &stb) >= 0 && 164 (stb.st_mode & 077) != 0) { 165 warnx("Error: .netrc file is readable by others."); 166 warnx("Remove password or make file unreadable by others."); 167 goto bad; 168 } 169 if ((t = token()) == -1) 170 goto bad; 171 if (t && *apass == 0) { 172 if ((*apass = strdup(tokval)) == NULL) 173 err(1, "strdup"); 174 } 175 break; 176 case ACCOUNT: 177 if (fstat(fileno(cfile), &stb) >= 0 178 && (stb.st_mode & 077) != 0) { 179 warnx("Error: .netrc file is readable by others."); 180 warnx("Remove account or make file unreadable by others."); 181 goto bad; 182 } 183 if ((t = token()) == -1) 184 goto bad; 185 if (t && *aacct == 0) { 186 if ((*aacct = strdup(tokval)) == NULL) 187 err(1, "strdup"); 188 } 189 break; 190 case MACDEF: 191 if (proxy) { 192 (void)fclose(cfile); 193 return (0); 194 } 195 while ((c = fgetc(cfile)) != EOF) 196 if (c != ' ' && c != '\t') 197 break; 198 if (c == EOF || c == '\n') { 199 fputs("Missing macdef name argument.\n", ttyout); 200 goto bad; 201 } 202 if (macnum == 16) { 203 fputs( 204 "Limit of 16 macros have already been defined.\n", ttyout); 205 goto bad; 206 } 207 tmp = macros[macnum].mac_name; 208 *tmp++ = c; 209 for (i=0; i < 8 && (c = fgetc(cfile)) != EOF && 210 !isspace(c); ++i) { 211 *tmp++ = c; 212 } 213 if (c == EOF) { 214 fputs( 215 "Macro definition missing null line terminator.\n", ttyout); 216 goto bad; 217 } 218 *tmp = '\0'; 219 if (c != '\n') { 220 while ((c = fgetc(cfile)) != EOF && c != '\n'); 221 } 222 if (c == EOF) { 223 fputs( 224 "Macro definition missing null line terminator.\n", ttyout); 225 goto bad; 226 } 227 if (macnum == 0) { 228 macros[macnum].mac_start = macbuf; 229 } 230 else { 231 macros[macnum].mac_start = 232 macros[macnum-1].mac_end + 1; 233 } 234 tmp = macros[macnum].mac_start; 235 while (tmp != macbuf + 4096) { 236 if ((c = fgetc(cfile)) == EOF) { 237 fputs( 238 "Macro definition missing null line terminator.\n", ttyout); 239 goto bad; 240 } 241 *tmp = c; 242 if (*tmp == '\n') { 243 if (tmp == macros[macnum].mac_start) { 244 macros[macnum++].mac_end = tmp; 245 break; 246 } else if (*(tmp-1) == '\0') { 247 macros[macnum++].mac_end = 248 tmp - 1; 249 break; 250 } 251 *tmp = '\0'; 252 } 253 tmp++; 254 } 255 if (tmp == macbuf + 4096) { 256 fputs("4K macro buffer exceeded.\n", ttyout); 257 goto bad; 258 } 259 break; 260 default: 261 warnx("Unknown .netrc keyword %s", tokval); 262 break; 263 } 264 goto done; 265 } 266 done: 267 if (t == -1) 268 goto bad; 269 (void)fclose(cfile); 270 return (0); 271 bad: 272 (void)fclose(cfile); 273 return (-1); 274 } 275 276 static int 277 token(void) 278 { 279 char *cp; 280 int c; 281 struct toktab *t; 282 283 if (feof(cfile) || ferror(cfile)) 284 return (0); 285 while ((c = fgetc(cfile)) != EOF && 286 (c == '\n' || c == '\t' || c == ' ' || c == ',')) 287 continue; 288 if (c == EOF) 289 return (0); 290 cp = tokval; 291 if (c == '"') { 292 while ((c = fgetc(cfile)) != EOF && c != '"') { 293 if (c == '\\' && (c = fgetc(cfile)) == EOF) 294 break; 295 *cp++ = c; 296 if (cp == tokval + sizeof(tokval)) { 297 warnx("Token in .netrc too long"); 298 return (-1); 299 } 300 } 301 } else { 302 *cp++ = c; 303 while ((c = fgetc(cfile)) != EOF 304 && c != '\n' && c != '\t' && c != ' ' && c != ',') { 305 if (c == '\\' && (c = fgetc(cfile)) == EOF) 306 break; 307 *cp++ = c; 308 if (cp == tokval + sizeof(tokval)) { 309 warnx("Token in .netrc too long"); 310 return (-1); 311 } 312 } 313 } 314 *cp = 0; 315 if (tokval[0] == 0) 316 return (0); 317 for (t = toktab; t->tokstr; t++) 318 if (!strcmp(t->tokstr, tokval)) 319 return (t->tval); 320 return (ID); 321 } 322 #endif /* !SMALL */ 323