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