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 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <strings.h>
47 #include <stdlib.h>
48 #include <libintl.h>
49 #include <limits.h>
50 #include <err.h>
51
52 #ifdef SYSV
53 #define index strchr
54 #endif /* SYSV */
55
56 static void rnetrc(const char *host, char **aname, char **apass);
57 static int token(void);
58
59 #define DEFAULT 1
60 #define LOGIN 2
61 #define PASSWD 3
62 #define NOTIFY 4
63 #define WRITE 5
64 #define YES 6
65 #define NO 7
66 #define COMMAND 8
67 #define FORCE 9
68 #define ID 10
69 #define MACHINE 11
70
71 #define MAXTOKEN 11
72 #define NTOKENS (MAXTOKEN - 1 + 2 + 1) /* two duplicates and null, minus id */
73
74 static struct ruserdata {
75 char tokval[100];
76 struct toktab {
77 char *tokstr;
78 int tval;
79 } toktab[NTOKENS];
80 FILE *cfile;
81 } *ruserdata, *_ruserdata();
82
83
84 static struct ruserdata *
_ruserdata(void)85 _ruserdata(void)
86 {
87 struct ruserdata *d = ruserdata;
88 struct toktab *t;
89
90 if (d == 0) {
91 if ((d = (struct ruserdata *)
92 calloc(1, sizeof (struct ruserdata))) == NULL) {
93 return (NULL);
94 }
95 ruserdata = d;
96 t = d->toktab;
97 t->tokstr = "default"; t++->tval = DEFAULT;
98 t->tokstr = "login"; t++->tval = LOGIN;
99 t->tokstr = "password"; t++->tval = PASSWD;
100 t->tokstr = "notify"; t++->tval = NOTIFY;
101 t->tokstr = "write"; t++->tval = WRITE;
102 t->tokstr = "yes"; t++->tval = YES;
103 t->tokstr = "y"; t++->tval = YES;
104 t->tokstr = "no"; t++->tval = NO;
105 t->tokstr = "n"; t++->tval = NO;
106 t->tokstr = "command"; t++->tval = COMMAND;
107 t->tokstr = "force"; t++->tval = FORCE;
108 t->tokstr = "machine"; t++->tval = MACHINE;
109 t->tokstr = 0; t->tval = 0;
110 }
111 return (d);
112 }
113
114
115 #define MAXANAME 16
116
117 void
_ruserpass(const char * host,char ** aname,char ** apass)118 _ruserpass(const char *host, char **aname, char **apass)
119 {
120
121 if (*aname == 0 || *apass == 0)
122 rnetrc(host, aname, apass);
123 if (*aname == 0) {
124 char myname[L_cuserid];
125
126 *aname = malloc(MAXANAME + 1);
127 (void) cuserid(myname);
128 (void) printf(dgettext(TEXT_DOMAIN, "Name (%s:%s): "),
129 host, myname);
130 (void) fflush(stdout);
131 if (read(2, *aname, MAXANAME) <= 0)
132 exit(1);
133 aname[0][MAXANAME] = '\0';
134 if ((*aname)[0] == '\n')
135 (void) strcpy(*aname, myname);
136 else
137 if (index(*aname, '\n'))
138 *index(*aname, '\n') = 0;
139 }
140 if (*aname && *apass == 0) {
141 (void) printf(dgettext(TEXT_DOMAIN, "Password (%s:%s): "),
142 host, *aname);
143 (void) fflush(stdout);
144 *apass = getpass("");
145 }
146 }
147
148 static void
rnetrc(const char * host,char ** aname,char ** apass)149 rnetrc(const char *host, char **aname, char **apass)
150 {
151 struct ruserdata *d = _ruserdata();
152 char *hdir, buf[PATH_MAX];
153 int t;
154 struct stat64 stb;
155
156 if (d == 0)
157 return;
158
159 hdir = getenv("HOME");
160 if (hdir == NULL)
161 hdir = ".";
162 t = snprintf(buf, sizeof (buf), "%s/.netrc", hdir);
163 if (t < 0 || t >= sizeof (buf)) {
164 if (t < 0) {
165 perror(buf);
166 } else {
167 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
168 "HOME directory name is too long: %s\n"), hdir);
169 }
170 return;
171 }
172
173 d->cfile = fopen(buf, "rF");
174 if (d->cfile == NULL) {
175 if (errno != ENOENT)
176 perror(buf);
177 return;
178 }
179 next:
180 while ((t = token())) {
181 if (t == DEFAULT) {
182 (void) token();
183 continue;
184 } else if (t != MACHINE) {
185 continue;
186 }
187
188 if (token() != ID || strcmp(host, d->tokval))
189 continue;
190 while ((t = token()) != 0 && t != MACHINE) {
191 switch (t) {
192 case LOGIN:
193 if (token() == 0) {
194 break;
195 }
196 if (*aname == NULL) {
197 size_t len = strlen(d->tokval) + 1;
198 *aname = malloc(len);
199 if (*aname == NULL) {
200 /*
201 * There's no good recovery path
202 * here today, unfortunately.
203 */
204 err(EXIT_FAILURE, dgettext(
205 TEXT_DOMAIN, "Fatal Error "
206 "- failed to allocate "
207 "memory"));
208 }
209 (void) memcpy(*aname, d->tokval, len);
210 } else {
211 if (strcmp(*aname, d->tokval))
212 goto next;
213 }
214 break;
215 case PASSWD:
216 if (fstat64(fileno(d->cfile), &stb) >= 0 &&
217 (stb.st_mode & 077) != 0) {
218 (void) fprintf(stderr,
219 dgettext(TEXT_DOMAIN,
220 "Error - .netrc file not correct "
221 "mode.\n"));
222 (void) fprintf(stderr,
223 dgettext(TEXT_DOMAIN, "Remove "
224 "password or correct mode.\n"));
225 exit(1);
226 }
227 if (token() && *apass == NULL) {
228 size_t len = strlen(d->tokval) + 1;
229 *apass = malloc(len);
230 if (*apass == NULL) {
231 err(EXIT_FAILURE, dgettext(
232 TEXT_DOMAIN, "Fatal Error "
233 "- failed to allocate "
234 "memory"));
235 }
236 (void) memcpy(*apass, d->tokval, len);
237 }
238 break;
239 case COMMAND:
240 case NOTIFY:
241 case WRITE:
242 case FORCE:
243 (void) token();
244 break;
245 default:
246 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
247 "Unknown .netrc option %s\n"), d->tokval);
248 break;
249 }
250 }
251 goto done;
252 }
253 done:
254 (void) fclose(d->cfile);
255 }
256
257 static int
token(void)258 token(void)
259 {
260 struct ruserdata *d = _ruserdata();
261 char *cp;
262 int c;
263 struct toktab *t;
264
265 if (d == 0)
266 return (0);
267
268 if (feof(d->cfile))
269 return (0);
270 while ((c = getc(d->cfile)) != EOF &&
271 (c == '\n' || c == '\t' || c == ' ' || c == ','))
272 continue;
273 if (c == EOF)
274 return (0);
275 cp = d->tokval;
276 if (c == '"') {
277 while ((c = getc(d->cfile)) != EOF && c != '"') {
278 if (c == '\\')
279 c = getc(d->cfile);
280 *cp++ = (char)c;
281 }
282 } else {
283 *cp++ = (char)c;
284 while ((c = getc(d->cfile)) != EOF &&
285 c != '\n' && c != '\t' && c != ' ' && c != ',') {
286 if (c == '\\')
287 c = getc(d->cfile);
288 *cp++ = (char)c;
289 }
290 }
291 *cp = 0;
292 if (d->tokval[0] == 0)
293 return (0);
294 for (t = d->toktab; t->tokstr; t++)
295 if ((strcmp(t->tokstr, d->tokval) == 0))
296 return (t->tval);
297 return (ID);
298 }
299