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