1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  *	Use is subject to license terms.
24  */
25 
26 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	All Rights Reserved  	*/
28 
29 /*
30  *	University Copyright- Copyright (c) 1982, 1986, 1988
31  *	The Regents of the University of California
32  *	All Rights Reserved
33  *
34  *	University Acknowledgment- Portions of this document are derived from
35  *	software developed by the University of California, Berkeley, and its
36  *	contributors.
37  */
38 
39 #pragma ident	"%Z%%M%	%I%	%E% SMI"
40 
41 #include "ftp_var.h"
42 
43 static	FILE *cfile;
44 
45 static int rnetrc(char *host, char **aname, char **apass, char **aacct);
46 static int token(void);
47 
48 int
49 ruserpass(char *host, char **aname, char **apass, char **aacct)
50 {
51 #if 0
52 	renv(host, aname, apass, aacct);
53 	if (*aname == 0 || *apass == 0)
54 #endif
55 		return (rnetrc(host, aname, apass, aacct));
56 }
57 
58 #define	DEFAULT	1
59 #define	LOGIN	2
60 #define	PASSWD	3
61 #define	ACCOUNT 4
62 #define	MACDEF	5
63 #define	SKIPSYST	6
64 #define	ID	10
65 #define	MACHINE	11
66 
67 static char tokval[100];
68 
69 static struct toktab {
70 	char *tokstr;
71 	int tval;
72 } toktab[] = {
73 	"default",	DEFAULT,
74 	"login",	LOGIN,
75 	"password",	PASSWD,
76 	"account",	ACCOUNT,
77 	"machine",	MACHINE,
78 	"macdef",	MACDEF,
79 	"skipsyst",	SKIPSYST,
80 	0,		0
81 };
82 
83 static int
84 rnetrc(char *host, char **aname, char **apass, char **aacct)
85 {
86 	char *hdir, buf[PATH_MAX+1], *tmp;
87 	int t, i, c;
88 	struct stat stb;
89 	extern int errno;
90 
91 	hdir = getenv("HOME");
92 	if (hdir == NULL)
93 		hdir = ".";
94 	if (snprintf(buf, sizeof (buf), "%s/.netrc", hdir) >= sizeof (buf)) {
95 		fprintf(stderr, ".netrc: %s\n", strerror(ENAMETOOLONG));
96 		exit(1);
97 	}
98 
99 	cfile = fopen(buf, "r");
100 	if (cfile == NULL) {
101 		if (errno != ENOENT)
102 			perror(buf);
103 		return (0);
104 	}
105 next:
106 	while ((t = token()))
107 		switch (t) {
108 
109 	case MACHINE:
110 		if (token() != ID || strcmp(host, tokval))
111 			continue;
112 		/* "machine name" matches host */
113 		/* FALLTHROUGH */
114 
115 	case DEFAULT:
116 		/* "default" matches any host */
117 		while (((t = token()) != 0) && t != MACHINE && t != DEFAULT)
118 			switch (t) {
119 
120 		case LOGIN:
121 			if (token())
122 				if (*aname == 0) {
123 					*aname = malloc((unsigned)
124 					    strlen(tokval) + 1);
125 					if (*aname == NULL) {
126 						fprintf(stderr,
127 						    "Error - out of VM\n");
128 						exit(1);
129 					}
130 					(void) strcpy(*aname, tokval);
131 				} else {
132 					if (strcmp(*aname, tokval))
133 						goto next;
134 				}
135 			break;
136 		case PASSWD:
137 			if (fstat(fileno(cfile), &stb) >= 0 &&
138 			    (stb.st_mode & 077) != 0) {
139 				fprintf(stderr, "Error - .netrc file not "
140 				    "correct mode.\n");
141 				fprintf(stderr, "Remove password or correct "
142 				    "mode.\n");
143 				return (-1);
144 			}
145 			if (token() && *apass == 0) {
146 				*apass = malloc((unsigned)strlen(tokval) + 1);
147 				if (*apass == NULL) {
148 					fprintf(stderr, "Error - out of VM\n");
149 					exit(1);
150 				}
151 				(void) strcpy(*apass, tokval);
152 			}
153 			break;
154 		case ACCOUNT:
155 			if (fstat(fileno(cfile), &stb) >= 0 &&
156 			    (stb.st_mode & 077) != 0) {
157 				fprintf(stderr, "Error - .netrc file not "
158 				    "correct mode.\n");
159 				fprintf(stderr, "Remove account or correct "
160 				    "mode.\n");
161 				return (-1);
162 			}
163 			if (token() && *aacct == 0) {
164 				*aacct = malloc((unsigned)strlen(tokval) + 1);
165 				if (*aacct == NULL) {
166 					fprintf(stderr, "Error - out of VM\n");
167 					exit(1);
168 				}
169 				(void) strcpy(*aacct, tokval);
170 			}
171 			break;
172 		case MACDEF:
173 			if (proxy) {
174 				return (0);
175 			}
176 			while ((c = getc(cfile)) != EOF && c == ' ' ||
177 			    c == '\t');
178 			if (c == EOF || c == '\n') {
179 				printf("Missing macdef name argument.\n");
180 				return (-1);
181 			}
182 			if (macnum == 16) {
183 				printf("Limit of 16 macros have already "
184 				    "been defined\n");
185 				return (-1);
186 			}
187 			tmp = macros[macnum].mac_name;
188 			*tmp++ = c;
189 			for (i = 0; i < 8 && (c = getc(cfile)) != EOF &&
190 			    !isspace(c); ++i) {
191 				*tmp++ = c;
192 			}
193 			if (c == EOF) {
194 				printf("Macro definition for `%s` missing "
195 				    "null line terminator.\n",
196 				    macros[macnum].mac_name);
197 				return (-1);
198 			}
199 			*tmp = '\0';
200 			if (c != '\n') {
201 				while ((c = getc(cfile)) != EOF && c != '\n');
202 			}
203 			if (c == EOF) {
204 				printf("Macro definition for `%s` missing "
205 				    "null line terminator.\n",
206 				    macros[macnum].mac_name);
207 				return (-1);
208 			}
209 			if (macnum == 0) {
210 				macros[macnum].mac_start = macbuf;
211 			} else {
212 				macros[macnum].mac_start =
213 				    macros[macnum-1].mac_end + 1;
214 			}
215 			tmp = macros[macnum].mac_start;
216 			while (tmp != macbuf + 4096) {
217 				if ((c = getc(cfile)) == EOF) {
218 				printf("Macro definition for `%s` missing "
219 				    "null line terminator.\n",
220 				    macros[macnum].mac_name);
221 					return (-1);
222 				}
223 				*tmp = c;
224 				if (*tmp == '\n') {
225 					if (*(tmp-1) == '\0') {
226 						macros[macnum++].mac_end =
227 						    tmp - 1;
228 						break;
229 					}
230 					*tmp = '\0';
231 				}
232 				tmp++;
233 			}
234 			if (tmp == macbuf + 4096) {
235 				printf("4K macro buffer exceeded\n");
236 				return (-1);
237 			}
238 			if (*macros[macnum - 1].mac_start == '\n') {
239 				printf("Macro definition for `%s` is empty, "
240 				    "macro not stored.\n",
241 					macros[--macnum].mac_name);
242 			}
243 			break;
244 		case SKIPSYST:
245 			skipsyst = 1;
246 			break;
247 		default:
248 			fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
249 			break;
250 		}
251 		goto done;
252 	}
253 done:
254 	(void) fclose(cfile);
255 	return (0);
256 }
257 
258 static int
259 token(void)
260 {
261 	char *cp;
262 	int c;
263 	struct toktab *t;
264 	int	len;
265 
266 	if (feof(cfile))
267 		return (0);
268 	while ((c = fgetwc(cfile)) != EOF &&
269 	    (c == '\n' || c == '\t' || c == ' ' || c == ','))
270 		continue;
271 	if (c == EOF)
272 		return (0);
273 	cp = tokval;
274 	if (c == '"') {
275 		while ((c = fgetwc(cfile)) != EOF && c != '"') {
276 			if (c == '\\')
277 				c = fgetwc(cfile);
278 			if ((len = wctomb(cp, c)) <= 0) {
279 				len = 1;
280 				*cp = (unsigned char)c;
281 			}
282 			cp += len;
283 		}
284 	} else {
285 		if ((len = wctomb(cp, c)) <= 0) {
286 			*cp = (unsigned char)c;
287 			len = 1;
288 		}
289 		cp += len;
290 		while ((c = fgetwc(cfile)) != EOF && c != '\n' && c != '\t' &&
291 		    c != ' ' && c != ',') {
292 			if (c == '\\')
293 				c = fgetwc(cfile);
294 			if ((len = wctomb(cp, c)) <= 0) {
295 				len = 1;
296 				*cp = (unsigned char)c;
297 			}
298 			cp += len;
299 		}
300 	}
301 	*cp = 0;
302 	if (tokval[0] == 0)
303 		return (0);
304 	for (t = toktab; t->tokstr; t++)
305 		if (strcmp(t->tokstr, tokval) == 0)
306 			return (t->tval);
307 	return (ID);
308 }
309