|
|
1.1 root 1: /*
2: * Copyright (c) 1983, 1988, 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1983, 1988, 1089 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)rshd.c 5.36.1.1 (Berkeley) 10/21/90";
28: #endif /* not lint */
29:
30: /* From:
31: * $Source: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v $
32: * $Header: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v 5.2 89/07/31 19:30:04 kfall Exp $
33: */
34:
35:
36: /*
37: * remote shell server:
38: * [port]\0
39: * remuser\0
40: * locuser\0
41: * command\0
42: * data
43: */
44: #include <sys/param.h>
45: #include <sys/ioctl.h>
46: #include <sys/socket.h>
47: #include <sys/file.h>
48: #include <sys/signal.h>
49: #include <sys/time.h>
50:
51: #include <netinet/in.h>
52:
53: #include <arpa/inet.h>
54:
55: #include <stdio.h>
56: #include <errno.h>
57: #include <pwd.h>
58: #include <netdb.h>
59: #include <syslog.h>
60: #include "pathnames.h"
61:
62: int errno;
63: int keepalive = 1;
64: int check_all = 0;
65: char *index(), *rindex(), *strncat();
66: /*VARARGS1*/
67: int error();
68: int sent_null;
69:
70: #ifdef KERBEROS
71: #include <kerberosIV/des.h>
72: #include <kerberosIV/krb.h>
73: #define VERSION_SIZE 9
74: #define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n"
75: #define OPTIONS "alknvx"
76: char authbuf[sizeof(AUTH_DAT)];
77: char tickbuf[sizeof(KTEXT_ST)];
78: int use_kerberos = 0, vacuous = 0;
79: int encrypt = 0;
80: Key_schedule schedule;
81: #else
82: #define OPTIONS "aln"
83: #endif
84:
85: /*ARGSUSED*/
86: main(argc, argv)
87: int argc;
88: char **argv;
89: {
90: extern int opterr, optind;
91: extern int _check_rhosts_file;
92: struct linger linger;
93: int ch, on = 1, fromlen;
94: struct sockaddr_in from;
95:
96: openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
97:
98: opterr = 0;
99: while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
100: switch (ch) {
101: case 'a':
102: check_all = 1;
103: break;
104: case 'l':
105: _check_rhosts_file = 0;
106: break;
107: case 'n':
108: keepalive = 0;
109: break;
110: #ifdef KERBEROS
111: case 'k':
112: use_kerberos = 1;
113: break;
114:
115: case 'v':
116: vacuous = 1;
117: break;
118:
119: #endif
120: case '?':
121: default:
122: usage();
123: exit(2);
124: }
125:
126: argc -= optind;
127: argv += optind;
128:
129: #ifdef KERBEROS
130: if (use_kerberos && vacuous) {
131: syslog(LOG_ERR, "only one of -k and -v allowed");
132: exit(2);
133: }
134: #endif
135:
136: fromlen = sizeof (from);
137: if (getpeername(0, &from, &fromlen) < 0) {
138: syslog(LOG_ERR, "getpeername: %m");
139: _exit(1);
140: }
141: if (keepalive &&
142: setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
143: sizeof(on)) < 0)
144: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
145: linger.l_onoff = 1;
146: linger.l_linger = 60; /* XXX */
147: if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
148: sizeof (linger)) < 0)
149: syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
150: doit(&from);
151: }
152:
153: char username[20] = "USER=";
154: char homedir[64] = "HOME=";
155: char shell[64] = "SHELL=";
156: char *envinit[] =
157: {homedir, shell, _PATH_DEFPATH, username, 0};
158: char **environ;
159:
160: doit(fromp)
161: struct sockaddr_in *fromp;
162: {
163: char cmdbuf[NCARGS+1], *cp;
164: char locuser[16], remuser[16];
165: struct passwd *pwd;
166: int s;
167: struct hostent *hp;
168: char *hostname, *errorstr = NULL, *errorhost;
169: u_short port;
170: int pv[2], pid, cc;
171: int nfd;
172: fd_set ready, readfrom;
173: char buf[BUFSIZ], sig;
174: int one = 1;
175: char remotehost[2 * MAXHOSTNAMELEN + 1];
176:
177: #ifdef KERBEROS
178: AUTH_DAT *kdata = (AUTH_DAT *) NULL;
179: KTEXT ticket = (KTEXT) NULL;
180: char instance[INST_SZ], version[VERSION_SIZE];
181: struct sockaddr_in fromaddr;
182: int rc;
183: long authopts;
184: int pv1[2], pv2[2];
185: fd_set wready, writeto;
186:
187: fromaddr = *fromp;
188: #endif
189:
190: (void) signal(SIGINT, SIG_DFL);
191: (void) signal(SIGQUIT, SIG_DFL);
192: (void) signal(SIGTERM, SIG_DFL);
193: #ifdef DEBUG
194: { int t = open(_PATH_TTY, 2);
195: if (t >= 0) {
196: ioctl(t, TIOCNOTTY, (char *)0);
197: (void) close(t);
198: }
199: }
200: #endif
201: fromp->sin_port = ntohs((u_short)fromp->sin_port);
202: if (fromp->sin_family != AF_INET) {
203: syslog(LOG_ERR, "malformed \"from\" address (af %d)\n",
204: fromp->sin_family);
205: exit(1);
206: }
207: #ifdef IP_OPTIONS
208: {
209: u_char optbuf[BUFSIZ/3], *cp;
210: char lbuf[BUFSIZ], *lp;
211: int optsize = sizeof(optbuf), ipproto;
212: struct protoent *ip;
213:
214: if ((ip = getprotobyname("ip")) != NULL)
215: ipproto = ip->p_proto;
216: else
217: ipproto = IPPROTO_IP;
218: if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
219: optsize != 0) {
220: lp = lbuf;
221: for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
222: sprintf(lp, " %2.2x", *cp);
223: syslog(LOG_NOTICE,
224: "Connection received from %s using IP options (ignored):%s",
225: inet_ntoa(fromp->sin_addr), lbuf);
226: if (setsockopt(0, ipproto, IP_OPTIONS,
227: (char *)NULL, &optsize) != 0) {
228: syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
229: exit(1);
230: }
231: }
232: }
233: #endif
234:
235: #ifdef KERBEROS
236: if (!use_kerberos)
237: #endif
238: if (fromp->sin_port >= IPPORT_RESERVED ||
239: fromp->sin_port < IPPORT_RESERVED/2) {
240: syslog(LOG_NOTICE|LOG_AUTH,
241: "Connection from %s on illegal port",
242: inet_ntoa(fromp->sin_addr));
243: exit(1);
244: }
245:
246: (void) alarm(60);
247: port = 0;
248: for (;;) {
249: char c;
250: if ((cc = read(0, &c, 1)) != 1) {
251: if (cc < 0)
252: syslog(LOG_NOTICE, "read: %m");
253: shutdown(0, 1+1);
254: exit(1);
255: }
256: if (c== 0)
257: break;
258: port = port * 10 + c - '0';
259: }
260:
261: (void) alarm(0);
262: if (port != 0) {
263: int lport = IPPORT_RESERVED - 1;
264: s = rresvport(&lport);
265: if (s < 0) {
266: syslog(LOG_ERR, "can't get stderr port: %m");
267: exit(1);
268: }
269: #ifdef KERBEROS
270: if (!use_kerberos)
271: #endif
272: if (port >= IPPORT_RESERVED) {
273: syslog(LOG_ERR, "2nd port not reserved\n");
274: exit(1);
275: }
276: fromp->sin_port = htons(port);
277: if (connect(s, fromp, sizeof (*fromp)) < 0) {
278: syslog(LOG_INFO, "connect second port: %m");
279: exit(1);
280: }
281: }
282:
283: #ifdef KERBEROS
284: if (vacuous) {
285: error("rshd: remote host requires Kerberos authentication\n");
286: exit(1);
287: }
288: #endif
289:
290: #ifdef notdef
291: /* from inetd, socket is already on 0, 1, 2 */
292: dup2(f, 0);
293: dup2(f, 1);
294: dup2(f, 2);
295: #endif
296: hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
297: fromp->sin_family);
298: if (hp) {
299: /*
300: * If name returned by gethostbyaddr is in our domain,
301: * attempt to verify that we haven't been fooled by someone
302: * in a remote net; look up the name and check that this
303: * address corresponds to the name.
304: */
305: hostname = hp->h_name;
306: #ifdef KERBEROS
307: if (!use_kerberos)
308: #endif
309: if (check_all || local_domain(hp->h_name)) {
310: strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1);
311: remotehost[sizeof(remotehost) - 1] = 0;
312: errorhost = remotehost;
313: hp = gethostbyname(remotehost);
314: if (hp == NULL) {
315: syslog(LOG_INFO,
316: "Couldn't look up address for %s",
317: remotehost);
318: errorstr =
319: "Couldn't look up address for your host (%s)\n";
320: hostname = inet_ntoa(fromp->sin_addr);
321: } else for (; ; hp->h_addr_list++) {
322: if (hp->h_addr_list[0] == NULL) {
323: syslog(LOG_NOTICE,
324: "Host addr %s not listed for host %s",
325: inet_ntoa(fromp->sin_addr),
326: hp->h_name);
327: errorstr =
328: "Host address mismatch for %s\n";
329: hostname = inet_ntoa(fromp->sin_addr);
330: break;
331: }
332: if (!bcmp(hp->h_addr_list[0],
333: (caddr_t)&fromp->sin_addr,
334: sizeof(fromp->sin_addr))) {
335: hostname = hp->h_name;
336: break;
337: }
338: }
339: }
340: } else
341: errorhost = hostname = inet_ntoa(fromp->sin_addr);
342:
343: #ifdef KERBEROS
344: if (use_kerberos) {
345: kdata = (AUTH_DAT *) authbuf;
346: ticket = (KTEXT) tickbuf;
347: authopts = 0L;
348: strcpy(instance, "*");
349: version[VERSION_SIZE - 1] = '\0';
350: rc = krb_recvauth(authopts, 0, ticket, "rcmd",
351: instance, &fromaddr,
352: (struct sockaddr_in *) 0,
353: kdata, "", (bit_64 *) 0, version);
354: if (rc != KSUCCESS) {
355: error("Kerberos authentication failure: %s\n",
356: krb_err_txt[rc]);
357: exit(1);
358: }
359: } else
360: #endif
361: getstr(remuser, sizeof(remuser), "remuser");
362:
363: getstr(locuser, sizeof(locuser), "locuser");
364: getstr(cmdbuf, sizeof(cmdbuf), "command");
365: setpwent();
366: pwd = getpwnam(locuser);
367: if (pwd == NULL) {
368: if (errorstr == NULL)
369: errorstr = "Login incorrect.\n";
370: goto fail;
371: }
372: if (chdir(pwd->pw_dir) < 0) {
373: (void) chdir("/");
374: #ifdef notdef
375: error("No remote directory.\n");
376: exit(1);
377: #endif
378: }
379:
380: #ifdef KERBEROS
381: if (use_kerberos) {
382: if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
383: if (kuserok(kdata, locuser) != 0) {
384: syslog(LOG_NOTICE|LOG_AUTH,
385: "Kerberos rsh denied to %s.%s@%s",
386: kdata->pname, kdata->pinst, kdata->prealm);
387: error("Permission denied.\n");
388: exit(1);
389: }
390: }
391: } else
392: #endif
393:
394: if (errorstr ||
395: pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
396: ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
397: fail:
398: if (errorstr == NULL)
399: errorstr = "Permission denied.\n";
400: error(errorstr, errorhost);
401: exit(1);
402: }
403:
404: if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) {
405: error("Logins currently disabled.\n");
406: exit(1);
407: }
408:
409: (void) write(2, "\0", 1);
410: sent_null = 1;
411:
412: if (port) {
413: if (pipe(pv) < 0) {
414: error("Can't make pipe.\n");
415: exit(1);
416: }
417: pid = fork();
418: if (pid == -1) {
419: error("Can't fork; try again.\n");
420: exit(1);
421: }
422: if (pid) {
423: {
424: (void) close(0); (void) close(1);
425: }
426: (void) close(2); (void) close(pv[1]);
427:
428: FD_ZERO(&readfrom);
429: FD_SET(s, &readfrom);
430: FD_SET(pv[0], &readfrom);
431: if (pv[0] > s)
432: nfd = pv[0];
433: else
434: nfd = s;
435: ioctl(pv[0], FIONBIO, (char *)&one);
436:
437: /* should set s nbio! */
438: nfd++;
439: do {
440: ready = readfrom;
441: if (select(nfd, &ready, (fd_set *)0,
442: (fd_set *)0, (struct timeval *)0) < 0)
443: break;
444: if (FD_ISSET(s, &ready)) {
445: int ret;
446: ret = read(s, &sig, 1);
447: if (ret <= 0)
448: FD_CLR(s, &readfrom);
449: else
450: killpg(pid, sig);
451: }
452: if (FD_ISSET(pv[0], &ready)) {
453: errno = 0;
454: cc = read(pv[0], buf, sizeof(buf));
455: if (cc <= 0) {
456: shutdown(s, 1+1);
457: FD_CLR(pv[0], &readfrom);
458: } else {
459: (void)
460: write(s, buf, cc);
461: }
462: }
463:
464: } while (FD_ISSET(s, &readfrom) ||
465: FD_ISSET(pv[0], &readfrom));
466: exit(0);
467: }
468: setpgrp(0, getpid());
469: (void) close(s); (void) close(pv[0]);
470: dup2(pv[1], 2);
471: close(pv[1]);
472: }
473: if (*pwd->pw_shell == '\0')
474: pwd->pw_shell = _PATH_BSHELL;
475: #if BSD > 43
476: if (setlogin(pwd->pw_name) < 0)
477: syslog(LOG_ERR, "setlogin() failed: %m");
478: #endif
479: (void) setgid((gid_t)pwd->pw_gid);
480: initgroups(pwd->pw_name, pwd->pw_gid);
481: (void) setuid((uid_t)pwd->pw_uid);
482: environ = envinit;
483: strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
484: strncat(shell, pwd->pw_shell, sizeof(shell)-7);
485: strncat(username, pwd->pw_name, sizeof(username)-6);
486: cp = rindex(pwd->pw_shell, '/');
487: if (cp)
488: cp++;
489: else
490: cp = pwd->pw_shell;
491: endpwent();
492: if (pwd->pw_uid == 0) {
493: #ifdef KERBEROS
494: if (use_kerberos)
495: syslog(LOG_INFO|LOG_AUTH,
496: "ROOT Kerberos shell from %s.%s@%s on %s, comm: %s\n",
497: kdata->pname, kdata->pinst, kdata->prealm,
498: hostname, cmdbuf);
499: else
500: #endif
501: syslog(LOG_INFO|LOG_AUTH,
502: "ROOT shell from %s@%s, comm: %s\n",
503: remuser, hostname, cmdbuf);
504: }
505: execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
506: perror(pwd->pw_shell);
507: exit(1);
508: }
509:
510: /*
511: * Report error to client.
512: * Note: can't be used until second socket has connected
513: * to client, or older clients will hang waiting
514: * for that connection first.
515: */
516: /*VARARGS1*/
517: error(fmt, a1, a2, a3)
518: char *fmt;
519: int a1, a2, a3;
520: {
521: char buf[BUFSIZ], *bp = buf;
522:
523: if (sent_null == 0)
524: *bp++ = 1;
525: (void) sprintf(bp, fmt, a1, a2, a3);
526: (void) write(2, buf, strlen(buf));
527: }
528:
529: getstr(buf, cnt, err)
530: char *buf;
531: int cnt;
532: char *err;
533: {
534: char c;
535:
536: do {
537: if (read(0, &c, 1) != 1)
538: exit(1);
539: *buf++ = c;
540: if (--cnt == 0) {
541: error("%s too long\n", err);
542: exit(1);
543: }
544: } while (c != 0);
545: }
546:
547: /*
548: * Check whether host h is in our local domain,
549: * defined as sharing the last two components of the domain part,
550: * or the entire domain part if the local domain has only one component.
551: * If either name is unqualified (contains no '.'),
552: * assume that the host is local, as it will be
553: * interpreted as such.
554: */
555: local_domain(h)
556: char *h;
557: {
558: char localhost[MAXHOSTNAMELEN];
559: char *p1, *p2, *topdomain();
560:
561: localhost[0] = 0;
562: (void) gethostname(localhost, sizeof(localhost));
563: p1 = topdomain(localhost);
564: p2 = topdomain(h);
565: if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
566: return(1);
567: return(0);
568: }
569:
570: char *
571: topdomain(h)
572: char *h;
573: {
574: register char *p;
575: char *maybe = NULL;
576: int dots = 0;
577:
578: for (p = h + strlen(h); p >= h; p--) {
579: if (*p == '.') {
580: if (++dots == 2)
581: return (p);
582: maybe = p;
583: }
584: }
585: return (maybe);
586: }
587:
588: usage()
589: {
590: syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
591: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.