]>
Commit | Line | Data |
---|---|---|
b7080c8e A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
a2c93a76 A |
6 | * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 1.0 (the 'License'). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
b7080c8e A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
a2c93a76 A |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License." | |
b7080c8e A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /*- | |
25 | * Copyright (c) 1988, 1989, 1992, 1993, 1994 | |
26 | * The Regents of the University of California. All rights reserved. | |
27 | * | |
28 | * Redistribution and use in source and binary forms, with or without | |
29 | * modification, are permitted provided that the following conditions | |
30 | * are met: | |
31 | * 1. Redistributions of source code must retain the above copyright | |
32 | * notice, this list of conditions and the following disclaimer. | |
33 | * 2. Redistributions in binary form must reproduce the above copyright | |
34 | * notice, this list of conditions and the following disclaimer in the | |
35 | * documentation and/or other materials provided with the distribution. | |
36 | * 3. All advertising materials mentioning features or use of this software | |
37 | * must display the following acknowledgement: | |
38 | * This product includes software developed by the University of | |
39 | * California, Berkeley and its contributors. | |
40 | * 4. Neither the name of the University nor the names of its contributors | |
41 | * may be used to endorse or promote products derived from this software | |
42 | * without specific prior written permission. | |
43 | * | |
44 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
45 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
46 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
47 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
48 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
49 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
50 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
51 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
52 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
53 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
54 | * SUCH DAMAGE. | |
55 | */ | |
56 | ||
57 | #ifndef lint | |
58 | static char copyright[] = | |
59 | "@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\ | |
60 | The Regents of the University of California. All rights reserved.\n"; | |
61 | #endif /* not lint */ | |
62 | ||
63 | #ifndef lint | |
64 | static char sccsid[] = "@(#)rshd.c 8.2 (Berkeley) 4/6/94"; | |
65 | #endif /* not lint */ | |
66 | ||
67 | /* | |
68 | * remote shell server: | |
69 | * [port]\0 | |
70 | * remuser\0 | |
71 | * locuser\0 | |
72 | * command\0 | |
73 | * data | |
74 | */ | |
75 | #include <sys/param.h> | |
76 | #include <sys/ioctl.h> | |
77 | #include <sys/time.h> | |
78 | #include <sys/socket.h> | |
79 | ||
80 | #include <netinet/in.h> | |
81 | #include <arpa/inet.h> | |
82 | #include <netdb.h> | |
83 | ||
84 | #include <errno.h> | |
85 | #include <fcntl.h> | |
86 | #include <paths.h> | |
87 | #include <pwd.h> | |
88 | #include <signal.h> | |
89 | #include <stdio.h> | |
90 | #include <stdlib.h> | |
91 | #include <string.h> | |
92 | #include <syslog.h> | |
93 | #include <unistd.h> | |
94 | ||
95 | int keepalive = 1; | |
96 | int check_all; | |
97 | int log_success; /* If TRUE, log all successful accesses */ | |
98 | int sent_null; | |
99 | ||
100 | void doit __P((struct sockaddr_in *)); | |
101 | void error __P((const char *, ...)); | |
102 | void getstr __P((char *, int, char *)); | |
103 | int local_domain __P((char *)); | |
104 | char *topdomain __P((char *)); | |
105 | void usage __P((void)); | |
106 | ||
107 | #ifdef KERBEROS | |
108 | #include <kerberosIV/des.h> | |
109 | #include <kerberosIV/krb.h> | |
110 | #define VERSION_SIZE 9 | |
111 | #define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" | |
112 | #define OPTIONS "alnkvxL" | |
113 | char authbuf[sizeof(AUTH_DAT)]; | |
114 | char tickbuf[sizeof(KTEXT_ST)]; | |
115 | int doencrypt, use_kerberos, vacuous; | |
116 | Key_schedule schedule; | |
117 | #else | |
118 | #define OPTIONS "alnL" | |
119 | #endif | |
120 | ||
121 | int | |
122 | main(argc, argv) | |
123 | int argc; | |
124 | char *argv[]; | |
125 | { | |
126 | extern int __check_rhosts_file; | |
127 | struct linger linger; | |
128 | int ch, on = 1, fromlen; | |
129 | struct sockaddr_in from; | |
130 | ||
131 | openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); | |
132 | ||
133 | opterr = 0; | |
134 | while ((ch = getopt(argc, argv, OPTIONS)) != EOF) | |
135 | switch (ch) { | |
136 | case 'a': | |
137 | check_all = 1; | |
138 | break; | |
139 | case 'l': | |
140 | __check_rhosts_file = 0; | |
141 | break; | |
142 | case 'n': | |
143 | keepalive = 0; | |
144 | break; | |
145 | #ifdef KERBEROS | |
146 | case 'k': | |
147 | use_kerberos = 1; | |
148 | break; | |
149 | ||
150 | case 'v': | |
151 | vacuous = 1; | |
152 | break; | |
153 | ||
154 | #ifdef CRYPT | |
155 | case 'x': | |
156 | doencrypt = 1; | |
157 | break; | |
158 | #endif | |
159 | #endif | |
160 | case 'L': | |
161 | log_success = 1; | |
162 | break; | |
163 | case '?': | |
164 | default: | |
165 | usage(); | |
166 | break; | |
167 | } | |
168 | ||
169 | argc -= optind; | |
170 | argv += optind; | |
171 | ||
172 | #ifdef KERBEROS | |
173 | if (use_kerberos && vacuous) { | |
174 | syslog(LOG_ERR, "only one of -k and -v allowed"); | |
175 | exit(2); | |
176 | } | |
177 | #ifdef CRYPT | |
178 | if (doencrypt && !use_kerberos) { | |
179 | syslog(LOG_ERR, "-k is required for -x"); | |
180 | exit(2); | |
181 | } | |
182 | #endif | |
183 | #endif | |
184 | ||
185 | fromlen = sizeof (from); | |
186 | if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { | |
187 | syslog(LOG_ERR, "getpeername: %m"); | |
188 | _exit(1); | |
189 | } | |
190 | if (keepalive && | |
191 | setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, | |
192 | sizeof(on)) < 0) | |
193 | syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); | |
194 | linger.l_onoff = 1; | |
195 | linger.l_linger = 60; /* XXX */ | |
196 | if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, | |
197 | sizeof (linger)) < 0) | |
198 | syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); | |
199 | doit(&from); | |
200 | /* NOTREACHED */ | |
201 | } | |
202 | ||
203 | char username[20] = "USER="; | |
204 | char homedir[64] = "HOME="; | |
205 | char shell[64] = "SHELL="; | |
206 | char path[100] = "PATH="; | |
207 | char *envinit[] = | |
208 | {homedir, shell, path, username, 0}; | |
209 | #ifdef __APPLE__ | |
210 | extern | |
211 | #endif | |
212 | char **environ; | |
213 | ||
214 | void | |
215 | doit(fromp) | |
216 | struct sockaddr_in *fromp; | |
217 | { | |
218 | extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */ | |
219 | struct hostent *hp; | |
220 | struct passwd *pwd; | |
221 | u_short port; | |
222 | fd_set ready, readfrom; | |
223 | int cc, nfd, pv[2], pid, s; | |
224 | int one = 1; | |
225 | char *hostname, *errorstr, *errorhost; | |
226 | char *cp, sig, buf[BUFSIZ]; | |
227 | char cmdbuf[NCARGS+1], locuser[16], remuser[16]; | |
228 | char remotehost[2 * MAXHOSTNAMELEN + 1]; | |
229 | ||
230 | #ifdef KERBEROS | |
231 | AUTH_DAT *kdata = (AUTH_DAT *) NULL; | |
232 | KTEXT ticket = (KTEXT) NULL; | |
233 | char instance[INST_SZ], version[VERSION_SIZE]; | |
234 | struct sockaddr_in fromaddr; | |
235 | int rc; | |
236 | long authopts; | |
237 | int pv1[2], pv2[2]; | |
238 | fd_set wready, writeto; | |
239 | ||
240 | fromaddr = *fromp; | |
241 | #endif | |
242 | ||
243 | (void) signal(SIGINT, SIG_DFL); | |
244 | (void) signal(SIGQUIT, SIG_DFL); | |
245 | (void) signal(SIGTERM, SIG_DFL); | |
246 | #ifdef DEBUG | |
247 | { int t = open(_PATH_TTY, 2); | |
248 | if (t >= 0) { | |
249 | ioctl(t, TIOCNOTTY, (char *)0); | |
250 | (void) close(t); | |
251 | } | |
252 | } | |
253 | #endif | |
254 | fromp->sin_port = ntohs((u_short)fromp->sin_port); | |
255 | if (fromp->sin_family != AF_INET) { | |
256 | syslog(LOG_ERR, "malformed \"from\" address (af %d)", | |
257 | fromp->sin_family); | |
258 | exit(1); | |
259 | } | |
260 | #ifdef IP_OPTIONS | |
261 | { | |
262 | u_char optbuf[BUFSIZ/3], *cp; | |
263 | char lbuf[BUFSIZ], *lp; | |
264 | int optsize = sizeof(optbuf), ipproto; | |
265 | struct protoent *ip; | |
266 | ||
267 | if ((ip = getprotobyname("ip")) != NULL) | |
268 | ipproto = ip->p_proto; | |
269 | else | |
270 | ipproto = IPPROTO_IP; | |
271 | if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && | |
272 | optsize != 0) { | |
273 | lp = lbuf; | |
274 | for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) | |
275 | sprintf(lp, " %2.2x", *cp); | |
276 | syslog(LOG_NOTICE, | |
277 | "Connection received from %s using IP options (ignored):%s", | |
278 | inet_ntoa(fromp->sin_addr), lbuf); | |
279 | if (setsockopt(0, ipproto, IP_OPTIONS, | |
280 | (char *)NULL, optsize) != 0) { | |
281 | syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); | |
282 | exit(1); | |
283 | } | |
284 | } | |
285 | } | |
286 | #endif | |
287 | ||
288 | #ifdef KERBEROS | |
289 | if (!use_kerberos) | |
290 | #endif | |
291 | if (fromp->sin_port >= IPPORT_RESERVED || | |
292 | fromp->sin_port < IPPORT_RESERVED/2) { | |
293 | syslog(LOG_NOTICE|LOG_AUTH, | |
294 | "Connection from %s on illegal port %u", | |
295 | inet_ntoa(fromp->sin_addr), | |
296 | fromp->sin_port); | |
297 | exit(1); | |
298 | } | |
299 | ||
300 | (void) alarm(60); | |
301 | port = 0; | |
302 | for (;;) { | |
303 | char c; | |
304 | if ((cc = read(STDIN_FILENO, &c, 1)) != 1) { | |
305 | if (cc < 0) | |
306 | syslog(LOG_NOTICE, "read: %m"); | |
307 | shutdown(0, 1+1); | |
308 | exit(1); | |
309 | } | |
310 | if (c== 0) | |
311 | break; | |
312 | port = port * 10 + c - '0'; | |
313 | } | |
314 | ||
315 | (void) alarm(0); | |
316 | if (port != 0) { | |
317 | int lport = IPPORT_RESERVED - 1; | |
318 | s = rresvport(&lport); | |
319 | if (s < 0) { | |
320 | syslog(LOG_ERR, "can't get stderr port: %m"); | |
321 | exit(1); | |
322 | } | |
323 | #ifdef KERBEROS | |
324 | if (!use_kerberos) | |
325 | #endif | |
326 | if (port >= IPPORT_RESERVED) { | |
327 | syslog(LOG_ERR, "2nd port not reserved"); | |
328 | exit(1); | |
329 | } | |
330 | fromp->sin_port = htons(port); | |
331 | if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { | |
332 | syslog(LOG_INFO, "connect second port %d: %m", port); | |
333 | exit(1); | |
334 | } | |
335 | } | |
336 | ||
337 | #ifdef KERBEROS | |
338 | if (vacuous) { | |
339 | error("rshd: remote host requires Kerberos authentication\n"); | |
340 | exit(1); | |
341 | } | |
342 | #endif | |
343 | ||
344 | #ifdef notdef | |
345 | /* from inetd, socket is already on 0, 1, 2 */ | |
346 | dup2(f, 0); | |
347 | dup2(f, 1); | |
348 | dup2(f, 2); | |
349 | #endif | |
350 | errorstr = NULL; | |
351 | hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), | |
352 | fromp->sin_family); | |
353 | if (hp) { | |
354 | /* | |
355 | * If name returned by gethostbyaddr is in our domain, | |
356 | * attempt to verify that we haven't been fooled by someone | |
357 | * in a remote net; look up the name and check that this | |
358 | * address corresponds to the name. | |
359 | */ | |
360 | hostname = hp->h_name; | |
361 | #ifdef KERBEROS | |
362 | if (!use_kerberos) | |
363 | #endif | |
364 | if (check_all || local_domain(hp->h_name)) { | |
365 | strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); | |
366 | remotehost[sizeof(remotehost) - 1] = 0; | |
367 | errorhost = remotehost; | |
368 | hp = gethostbyname(remotehost); | |
369 | if (hp == NULL) { | |
370 | syslog(LOG_INFO, | |
371 | "Couldn't look up address for %s", | |
372 | remotehost); | |
373 | errorstr = | |
374 | "Couldn't look up address for your host (%s)\n"; | |
375 | hostname = inet_ntoa(fromp->sin_addr); | |
376 | } else for (; ; hp->h_addr_list++) { | |
377 | if (hp->h_addr_list[0] == NULL) { | |
378 | syslog(LOG_NOTICE, | |
379 | "Host addr %s not listed for host %s", | |
380 | inet_ntoa(fromp->sin_addr), | |
381 | hp->h_name); | |
382 | errorstr = | |
383 | "Host address mismatch for %s\n"; | |
384 | hostname = inet_ntoa(fromp->sin_addr); | |
385 | break; | |
386 | } | |
387 | if (!bcmp(hp->h_addr_list[0], | |
388 | (caddr_t)&fromp->sin_addr, | |
389 | sizeof(fromp->sin_addr))) { | |
390 | hostname = hp->h_name; | |
391 | break; | |
392 | } | |
393 | } | |
394 | } | |
395 | } else | |
396 | errorhost = hostname = inet_ntoa(fromp->sin_addr); | |
397 | ||
398 | #ifdef KERBEROS | |
399 | if (use_kerberos) { | |
400 | kdata = (AUTH_DAT *) authbuf; | |
401 | ticket = (KTEXT) tickbuf; | |
402 | authopts = 0L; | |
403 | strcpy(instance, "*"); | |
404 | version[VERSION_SIZE - 1] = '\0'; | |
405 | #ifdef CRYPT | |
406 | if (doencrypt) { | |
407 | struct sockaddr_in local_addr; | |
408 | rc = sizeof(local_addr); | |
409 | if (getsockname(0, (struct sockaddr *)&local_addr, | |
410 | &rc) < 0) { | |
411 | syslog(LOG_ERR, "getsockname: %m"); | |
412 | error("rshd: getsockname: %m"); | |
413 | exit(1); | |
414 | } | |
415 | authopts = KOPT_DO_MUTUAL; | |
416 | rc = krb_recvauth(authopts, 0, ticket, | |
417 | "rcmd", instance, &fromaddr, | |
418 | &local_addr, kdata, "", schedule, | |
419 | version); | |
420 | des_set_key(kdata->session, schedule); | |
421 | } else | |
422 | #endif | |
423 | rc = krb_recvauth(authopts, 0, ticket, "rcmd", | |
424 | instance, &fromaddr, | |
425 | (struct sockaddr_in *) 0, | |
426 | kdata, "", (bit_64 *) 0, version); | |
427 | if (rc != KSUCCESS) { | |
428 | error("Kerberos authentication failure: %s\n", | |
429 | krb_err_txt[rc]); | |
430 | exit(1); | |
431 | } | |
432 | } else | |
433 | #endif | |
434 | getstr(remuser, sizeof(remuser), "remuser"); | |
435 | ||
436 | getstr(locuser, sizeof(locuser), "locuser"); | |
437 | getstr(cmdbuf, sizeof(cmdbuf), "command"); | |
438 | setpwent(); | |
439 | pwd = getpwnam(locuser); | |
440 | if (pwd == NULL) { | |
441 | syslog(LOG_INFO|LOG_AUTH, | |
442 | "%s@%s as %s: unknown login. cmd='%.80s'", | |
443 | remuser, hostname, locuser, cmdbuf); | |
444 | if (errorstr == NULL) | |
445 | errorstr = "Login incorrect.\n"; | |
446 | goto fail; | |
447 | } | |
448 | if (chdir(pwd->pw_dir) < 0) { | |
449 | (void) chdir("/"); | |
450 | #ifdef notdef | |
451 | syslog(LOG_INFO|LOG_AUTH, | |
452 | "%s@%s as %s: no home directory. cmd='%.80s'", | |
453 | remuser, hostname, locuser, cmdbuf); | |
454 | error("No remote directory.\n"); | |
455 | exit(1); | |
456 | #endif | |
457 | } | |
458 | ||
459 | #ifdef KERBEROS | |
460 | if (use_kerberos) { | |
461 | if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { | |
462 | if (kuserok(kdata, locuser) != 0) { | |
463 | syslog(LOG_INFO|LOG_AUTH, | |
464 | "Kerberos rsh denied to %s.%s@%s", | |
465 | kdata->pname, kdata->pinst, kdata->prealm); | |
466 | error("Permission denied.\n"); | |
467 | exit(1); | |
468 | } | |
469 | } | |
470 | } else | |
471 | #endif | |
472 | ||
473 | if (errorstr || | |
474 | pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && | |
475 | iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0, | |
476 | remuser, locuser) < 0) { | |
477 | if (__rcmd_errstr) | |
478 | syslog(LOG_INFO|LOG_AUTH, | |
479 | "%s@%s as %s: permission denied (%s). cmd='%.80s'", | |
480 | remuser, hostname, locuser, __rcmd_errstr, | |
481 | cmdbuf); | |
482 | else | |
483 | syslog(LOG_INFO|LOG_AUTH, | |
484 | "%s@%s as %s: permission denied. cmd='%.80s'", | |
485 | remuser, hostname, locuser, cmdbuf); | |
486 | fail: | |
487 | if (errorstr == NULL) | |
488 | errorstr = "Permission denied.\n"; | |
489 | error(errorstr, errorhost); | |
490 | exit(1); | |
491 | } | |
492 | ||
493 | if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { | |
494 | error("Logins currently disabled.\n"); | |
495 | exit(1); | |
496 | } | |
497 | ||
498 | (void) write(STDERR_FILENO, "\0", 1); | |
499 | sent_null = 1; | |
500 | ||
501 | if (port) { | |
502 | if (pipe(pv) < 0) { | |
503 | error("Can't make pipe.\n"); | |
504 | exit(1); | |
505 | } | |
506 | #ifdef CRYPT | |
507 | #ifdef KERBEROS | |
508 | if (doencrypt) { | |
509 | if (pipe(pv1) < 0) { | |
510 | error("Can't make 2nd pipe.\n"); | |
511 | exit(1); | |
512 | } | |
513 | if (pipe(pv2) < 0) { | |
514 | error("Can't make 3rd pipe.\n"); | |
515 | exit(1); | |
516 | } | |
517 | } | |
518 | #endif | |
519 | #endif | |
520 | pid = fork(); | |
521 | if (pid == -1) { | |
522 | error("Can't fork; try again.\n"); | |
523 | exit(1); | |
524 | } | |
525 | if (pid) { | |
526 | #ifdef CRYPT | |
527 | #ifdef KERBEROS | |
528 | if (doencrypt) { | |
529 | static char msg[] = SECURE_MESSAGE; | |
530 | (void) close(pv1[1]); | |
531 | (void) close(pv2[1]); | |
532 | des_write(s, msg, sizeof(msg) - 1); | |
533 | ||
534 | } else | |
535 | #endif | |
536 | #endif | |
537 | { | |
538 | (void) close(0); | |
539 | (void) close(1); | |
540 | } | |
541 | (void) close(2); | |
542 | (void) close(pv[1]); | |
543 | ||
544 | FD_ZERO(&readfrom); | |
545 | FD_SET(s, &readfrom); | |
546 | FD_SET(pv[0], &readfrom); | |
547 | if (pv[0] > s) | |
548 | nfd = pv[0]; | |
549 | else | |
550 | nfd = s; | |
551 | #ifdef CRYPT | |
552 | #ifdef KERBEROS | |
553 | if (doencrypt) { | |
554 | FD_ZERO(&writeto); | |
555 | FD_SET(pv2[0], &writeto); | |
556 | FD_SET(pv1[0], &readfrom); | |
557 | ||
558 | nfd = MAX(nfd, pv2[0]); | |
559 | nfd = MAX(nfd, pv1[0]); | |
560 | } else | |
561 | #endif | |
562 | #endif | |
563 | ioctl(pv[0], FIONBIO, (char *)&one); | |
564 | ||
565 | /* should set s nbio! */ | |
566 | nfd++; | |
567 | do { | |
568 | ready = readfrom; | |
569 | #ifdef CRYPT | |
570 | #ifdef KERBEROS | |
571 | if (doencrypt) { | |
572 | wready = writeto; | |
573 | if (select(nfd, &ready, | |
574 | &wready, (fd_set *) 0, | |
575 | (struct timeval *) 0) < 0) | |
576 | break; | |
577 | } else | |
578 | #endif | |
579 | #endif | |
580 | if (select(nfd, &ready, (fd_set *)0, | |
581 | (fd_set *)0, (struct timeval *)0) < 0) | |
582 | break; | |
583 | if (FD_ISSET(s, &ready)) { | |
584 | int ret; | |
585 | #ifdef CRYPT | |
586 | #ifdef KERBEROS | |
587 | if (doencrypt) | |
588 | ret = des_read(s, &sig, 1); | |
589 | else | |
590 | #endif | |
591 | #endif | |
592 | ret = read(s, &sig, 1); | |
593 | if (ret <= 0) | |
594 | FD_CLR(s, &readfrom); | |
595 | else | |
596 | killpg(pid, sig); | |
597 | } | |
598 | if (FD_ISSET(pv[0], &ready)) { | |
599 | errno = 0; | |
600 | cc = read(pv[0], buf, sizeof(buf)); | |
601 | if (cc <= 0) { | |
602 | shutdown(s, 1+1); | |
603 | FD_CLR(pv[0], &readfrom); | |
604 | } else { | |
605 | #ifdef CRYPT | |
606 | #ifdef KERBEROS | |
607 | if (doencrypt) | |
608 | (void) | |
609 | des_write(s, buf, cc); | |
610 | else | |
611 | #endif | |
612 | #endif | |
613 | (void) | |
614 | write(s, buf, cc); | |
615 | } | |
616 | } | |
617 | #ifdef CRYPT | |
618 | #ifdef KERBEROS | |
619 | if (doencrypt && FD_ISSET(pv1[0], &ready)) { | |
620 | errno = 0; | |
621 | cc = read(pv1[0], buf, sizeof(buf)); | |
622 | if (cc <= 0) { | |
623 | shutdown(pv1[0], 1+1); | |
624 | FD_CLR(pv1[0], &readfrom); | |
625 | } else | |
626 | (void) des_write(STDOUT_FILENO, | |
627 | buf, cc); | |
628 | } | |
629 | ||
630 | if (doencrypt && FD_ISSET(pv2[0], &wready)) { | |
631 | errno = 0; | |
632 | cc = des_read(STDIN_FILENO, | |
633 | buf, sizeof(buf)); | |
634 | if (cc <= 0) { | |
635 | shutdown(pv2[0], 1+1); | |
636 | FD_CLR(pv2[0], &writeto); | |
637 | } else | |
638 | (void) write(pv2[0], buf, cc); | |
639 | } | |
640 | #endif | |
641 | #endif | |
642 | ||
643 | } while (FD_ISSET(s, &readfrom) || | |
644 | #ifdef CRYPT | |
645 | #ifdef KERBEROS | |
646 | (doencrypt && FD_ISSET(pv1[0], &readfrom)) || | |
647 | #endif | |
648 | #endif | |
649 | FD_ISSET(pv[0], &readfrom)); | |
650 | exit(0); | |
651 | } | |
652 | setpgrp(0, getpid()); | |
653 | (void) close(s); | |
654 | (void) close(pv[0]); | |
655 | #ifdef CRYPT | |
656 | #ifdef KERBEROS | |
657 | if (doencrypt) { | |
658 | close(pv1[0]); close(pv2[0]); | |
659 | dup2(pv1[1], 1); | |
660 | dup2(pv2[1], 0); | |
661 | close(pv1[1]); | |
662 | close(pv2[1]); | |
663 | } | |
664 | #endif | |
665 | #endif | |
666 | dup2(pv[1], 2); | |
667 | close(pv[1]); | |
668 | } | |
669 | if (*pwd->pw_shell == '\0') | |
670 | pwd->pw_shell = _PATH_BSHELL; | |
671 | #if BSD > 43 | |
672 | if (setlogin(pwd->pw_name) < 0) | |
673 | syslog(LOG_ERR, "setlogin() failed: %m"); | |
674 | #endif | |
675 | (void) setgid((gid_t)pwd->pw_gid); | |
676 | initgroups(pwd->pw_name, pwd->pw_gid); | |
677 | (void) setuid((uid_t)pwd->pw_uid); | |
678 | environ = envinit; | |
679 | strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); | |
680 | strcat(path, _PATH_DEFPATH); | |
681 | strncat(shell, pwd->pw_shell, sizeof(shell)-7); | |
682 | strncat(username, pwd->pw_name, sizeof(username)-6); | |
683 | cp = strrchr(pwd->pw_shell, '/'); | |
684 | if (cp) | |
685 | cp++; | |
686 | else | |
687 | cp = pwd->pw_shell; | |
688 | endpwent(); | |
689 | if (log_success || pwd->pw_uid == 0) { | |
690 | #ifdef KERBEROS | |
691 | if (use_kerberos) | |
692 | syslog(LOG_INFO|LOG_AUTH, | |
693 | "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'", | |
694 | kdata->pname, kdata->pinst, kdata->prealm, | |
695 | hostname, locuser, cmdbuf); | |
696 | else | |
697 | #endif | |
698 | syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'", | |
699 | remuser, hostname, locuser, cmdbuf); | |
700 | } | |
701 | execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); | |
702 | perror(pwd->pw_shell); | |
703 | exit(1); | |
704 | } | |
705 | ||
706 | /* | |
707 | * Report error to client. Note: can't be used until second socket has | |
708 | * connected to client, or older clients will hang waiting for that | |
709 | * connection first. | |
710 | */ | |
711 | #if __STDC__ | |
712 | #include <stdarg.h> | |
713 | #else | |
714 | #include <varargs.h> | |
715 | #endif | |
716 | ||
717 | void | |
718 | #if __STDC__ | |
719 | error(const char *fmt, ...) | |
720 | #else | |
721 | error(fmt, va_alist) | |
722 | char *fmt; | |
723 | va_dcl | |
724 | #endif | |
725 | { | |
726 | va_list ap; | |
727 | int len; | |
728 | char *bp, buf[BUFSIZ]; | |
729 | #if __STDC__ | |
730 | va_start(ap, fmt); | |
731 | #else | |
732 | va_start(ap); | |
733 | #endif | |
734 | bp = buf; | |
735 | if (sent_null == 0) { | |
736 | *bp++ = 1; | |
737 | len = 1; | |
738 | } else | |
739 | len = 0; | |
740 | (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap); | |
741 | (void)write(STDERR_FILENO, buf, len + strlen(bp)); | |
742 | } | |
743 | ||
744 | void | |
745 | getstr(buf, cnt, err) | |
746 | char *buf, *err; | |
747 | int cnt; | |
748 | { | |
749 | char c; | |
750 | ||
751 | do { | |
752 | if (read(STDIN_FILENO, &c, 1) != 1) | |
753 | exit(1); | |
754 | *buf++ = c; | |
755 | if (--cnt == 0) { | |
756 | error("%s too long\n", err); | |
757 | exit(1); | |
758 | } | |
759 | } while (c != 0); | |
760 | } | |
761 | ||
762 | /* | |
763 | * Check whether host h is in our local domain, | |
764 | * defined as sharing the last two components of the domain part, | |
765 | * or the entire domain part if the local domain has only one component. | |
766 | * If either name is unqualified (contains no '.'), | |
767 | * assume that the host is local, as it will be | |
768 | * interpreted as such. | |
769 | */ | |
770 | int | |
771 | local_domain(h) | |
772 | char *h; | |
773 | { | |
774 | char localhost[MAXHOSTNAMELEN]; | |
775 | char *p1, *p2; | |
776 | ||
777 | localhost[0] = 0; | |
778 | (void) gethostname(localhost, sizeof(localhost)); | |
779 | p1 = topdomain(localhost); | |
780 | p2 = topdomain(h); | |
781 | if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) | |
782 | return (1); | |
783 | return (0); | |
784 | } | |
785 | ||
786 | char * | |
787 | topdomain(h) | |
788 | char *h; | |
789 | { | |
790 | char *p, *maybe = NULL; | |
791 | int dots = 0; | |
792 | ||
793 | for (p = h + strlen(h); p >= h; p--) { | |
794 | if (*p == '.') { | |
795 | if (++dots == 2) | |
796 | return (p); | |
797 | maybe = p; | |
798 | } | |
799 | } | |
800 | return (maybe); | |
801 | } | |
802 | ||
803 | void | |
804 | usage() | |
805 | { | |
806 | ||
807 | syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); | |
808 | exit(2); | |
809 | } |