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