xref: /freebsd/crypto/heimdal/appl/rsh/rshd.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1 /*
2  * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute 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.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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.
32  */
33 
34 #include "rsh_locl.h"
35 RCSID("$Id: rshd.c,v 1.29 1999/12/02 17:04:56 joda Exp $");
36 
37 enum auth_method auth_method;
38 
39 krb5_context context;
40 krb5_keyblock *keyblock;
41 krb5_crypto crypto;
42 des_key_schedule schedule;
43 des_cblock iv;
44 
45 krb5_ccache ccache, ccache2;
46 int kerberos_status = 0;
47 
48 int do_encrypt = 0;
49 
50 static int do_unique_tkfile           = 0;
51 static char tkfile[MAXPATHLEN] = "";
52 
53 static int do_inetd = 1;
54 static char *port_str;
55 static int do_rhosts;
56 static int do_kerberos = 0;
57 static int do_vacuous = 0;
58 static int do_log = 1;
59 static int do_newpag = 1;
60 static int do_version;
61 static int do_help = 0;
62 
63 static void
64 syslog_and_die (const char *m, ...)
65 {
66     va_list args;
67 
68     va_start(args, m);
69     vsyslog (LOG_ERR, m, args);
70     va_end(args);
71     exit (1);
72 }
73 
74 static void
75 fatal (int sock, const char *m, ...)
76 {
77     va_list args;
78     char buf[BUFSIZ];
79     size_t len;
80 
81     *buf = 1;
82     va_start(args, m);
83     len = vsnprintf (buf + 1, sizeof(buf) - 1, m, args);
84     va_end(args);
85     syslog (LOG_ERR, buf + 1);
86     net_write (sock, buf, len + 1);
87     exit (1);
88 }
89 
90 static void
91 read_str (int s, char *str, size_t sz, char *expl)
92 {
93     while (sz > 0) {
94 	if (net_read (s, str, 1) != 1)
95 	    syslog_and_die ("read: %m");
96 	if (*str == '\0')
97 	    return;
98 	--sz;
99 	++str;
100     }
101     fatal (s, "%s too long", expl);
102 }
103 
104 static int
105 recv_bsd_auth (int s, u_char *buf,
106 	       struct sockaddr_in *thisaddr,
107 	       struct sockaddr_in *thataddr,
108 	       char *client_username,
109 	       char *server_username,
110 	       char *cmd)
111 {
112     struct passwd *pwd;
113 
114     read_str (s, client_username, USERNAME_SZ, "local username");
115     read_str (s, server_username, USERNAME_SZ, "remote username");
116     read_str (s, cmd, COMMAND_SZ, "command");
117     pwd = getpwnam(server_username);
118     if (pwd == NULL)
119 	fatal(s, "Login incorrect.");
120     if (iruserok(thataddr->sin_addr.s_addr, pwd->pw_uid == 0,
121 		 client_username, server_username))
122 	fatal(s, "Login incorrect.");
123     return 0;
124 }
125 
126 #ifdef KRB4
127 static int
128 recv_krb4_auth (int s, u_char *buf,
129 		struct sockaddr *thisaddr,
130 		struct sockaddr *thataddr,
131 		char *client_username,
132 		char *server_username,
133 		char *cmd)
134 {
135     int status;
136     int32_t options;
137     KTEXT_ST ticket;
138     AUTH_DAT auth;
139     char instance[INST_SZ + 1];
140     char version[KRB_SENDAUTH_VLEN + 1];
141 
142     if (memcmp (buf, KRB_SENDAUTH_VERS, 4) != 0)
143 	return -1;
144     if (net_read (s, buf + 4, KRB_SENDAUTH_VLEN - 4) !=
145 	KRB_SENDAUTH_VLEN - 4)
146 	syslog_and_die ("reading auth info: %m");
147     if (memcmp (buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN) != 0)
148 	syslog_and_die("unrecognized auth protocol: %.8s", buf);
149 
150     options = KOPT_IGNORE_PROTOCOL;
151     if (do_encrypt)
152 	options |= KOPT_DO_MUTUAL;
153     k_getsockinst (s, instance, sizeof(instance));
154     status = krb_recvauth (options,
155 			   s,
156 			   &ticket,
157 			   "rcmd",
158 			   instance,
159 			   (struct sockaddr_in *)thataddr,
160 			   (struct sockaddr_in *)thisaddr,
161 			   &auth,
162 			   "",
163 			   schedule,
164 			   version);
165     if (status != KSUCCESS)
166 	syslog_and_die ("recvauth: %s", krb_get_err_text(status));
167     if (strncmp (version, KCMD_VERSION, KRB_SENDAUTH_VLEN) != 0)
168 	syslog_and_die ("bad version: %s", version);
169 
170     read_str (s, server_username, USERNAME_SZ, "remote username");
171     if (kuserok (&auth, server_username) != 0)
172 	fatal (s, "Permission denied");
173     read_str (s, cmd, COMMAND_SZ, "command");
174 
175     syslog(LOG_INFO|LOG_AUTH,
176 	   "kerberos v4 shell from %s on %s as %s, cmd '%.80s'",
177 	   krb_unparse_name_long(auth.pname, auth.pinst, auth.prealm),
178 
179 	   inet_ntoa(((struct sockaddr_in *)thataddr)->sin_addr),
180 	   server_username,
181 	   cmd);
182 
183     memcpy (iv, auth.session, sizeof(iv));
184 
185     return 0;
186 }
187 
188 #endif /* KRB4 */
189 
190 static int
191 save_krb5_creds (int s,
192                  krb5_auth_context auth_context,
193                  krb5_principal client)
194 
195 {
196     int ret;
197     krb5_data remote_cred;
198 
199     krb5_data_zero (&remote_cred);
200     ret= krb5_read_message (context, (void *)&s, &remote_cred);
201     if (ret) {
202 	krb5_data_free(&remote_cred);
203 	return 0;
204     }
205     if (remote_cred.length == 0)
206 	return 0;
207 
208     ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
209     if (ret) {
210 	krb5_data_free(&remote_cred);
211 	return 0;
212     }
213 
214     krb5_cc_initialize(context,ccache,client);
215     ret = krb5_rd_cred(context, auth_context, ccache,&remote_cred);
216     krb5_data_free (&remote_cred);
217     if (ret)
218 	return 0;
219     return 1;
220 }
221 
222 static void
223 krb5_start_session (void)
224 {
225     krb5_error_code ret;
226 
227     ret = krb5_cc_resolve (context, tkfile, &ccache2);
228     if (ret) {
229 	krb5_cc_destroy(context, ccache);
230 	return;
231     }
232 
233     ret = krb5_cc_copy_cache (context, ccache, ccache2);
234     if (ret) {
235 	krb5_cc_destroy(context, ccache);
236 	return ;
237     }
238 
239     krb5_cc_close(context, ccache2);
240     krb5_cc_destroy(context, ccache);
241     return;
242 }
243 
244 static int
245 recv_krb5_auth (int s, u_char *buf,
246 		struct sockaddr *thisaddr,
247 		struct sockaddr *thataddr,
248 		char *client_username,
249 		char *server_username,
250 		char *cmd)
251 {
252     u_int32_t len;
253     krb5_auth_context auth_context = NULL;
254     krb5_ticket *ticket;
255     krb5_error_code status;
256     krb5_data cksum_data;
257     krb5_principal server;
258 
259     if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
260 	return -1;
261     len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
262 
263     if (net_read(s, buf, len) != len)
264 	syslog_and_die ("reading auth info: %m");
265     if (len != sizeof(KRB5_SENDAUTH_VERSION)
266 	|| memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
267 	syslog_and_die ("bad sendauth version: %.8s", buf);
268 
269     status = krb5_sock_to_principal (context,
270 				     s,
271 				     "host",
272 				     KRB5_NT_SRV_HST,
273 				     &server);
274     if (status)
275 	syslog_and_die ("krb5_sock_to_principal: %s",
276 			krb5_get_err_text(context, status));
277 
278     status = krb5_recvauth(context,
279 			   &auth_context,
280 			   &s,
281 			   KCMD_VERSION,
282 			   server,
283 			   KRB5_RECVAUTH_IGNORE_VERSION,
284 			   NULL,
285 			   &ticket);
286     krb5_free_principal (context, server);
287     if (status)
288 	syslog_and_die ("krb5_recvauth: %s",
289 			krb5_get_err_text(context, status));
290 
291     read_str (s, server_username, USERNAME_SZ, "remote username");
292     read_str (s, cmd, COMMAND_SZ, "command");
293     read_str (s, client_username, COMMAND_SZ, "local username");
294 
295     status = krb5_auth_con_getkey (context, auth_context, &keyblock);
296     if (status)
297        syslog_and_die ("krb5_auth_con_getkey: %s",
298                        krb5_get_err_text(context, status));
299 
300     status = krb5_crypto_init(context, keyblock, 0, &crypto);
301     if(status)
302 	syslog_and_die("krb5_crypto_init: %s",
303 		       krb5_get_err_text(context, status));
304 
305 
306     cksum_data.length = asprintf ((char **)&cksum_data.data,
307 				  "%u:%s%s",
308 				  ntohs(socket_get_port (thisaddr)),
309 				  cmd,
310 				  server_username);
311 
312     status = krb5_verify_authenticator_checksum(context,
313 						auth_context,
314 						cksum_data.data,
315 						cksum_data.length);
316 
317     if (status)
318 	syslog_and_die ("krb5_verify_authenticator_checksum: %s",
319 			krb5_get_err_text(context, status));
320 
321     free (cksum_data.data);
322 
323     if (strncmp (client_username, "-u ", 3) == 0) {
324 	do_unique_tkfile = 1;
325 	memmove (client_username, client_username + 3,
326 		 strlen(client_username) - 2);
327     }
328 
329     if (strncmp (client_username, "-U ", 3) == 0) {
330 	char *end, *temp_tkfile;
331 
332 	do_unique_tkfile = 1;
333 	if (strncmp (server_username + 3, "FILE:", 5) == 0) {
334 	    temp_tkfile = tkfile;
335 	} else {
336 	    strcpy (tkfile, "FILE:");
337 	    temp_tkfile = tkfile + 5;
338 	}
339 	end = strchr(client_username + 3,' ');
340 	strncpy(temp_tkfile, client_username + 3, end - client_username - 3);
341 	temp_tkfile[end - client_username - 3] = '\0';
342 	memmove (client_username, end +1, strlen(end+1)+1);
343     }
344 
345     kerberos_status = save_krb5_creds (s, auth_context, ticket->client);
346 
347     if(!krb5_kuserok (context,
348 		     ticket->client,
349 		     server_username))
350 	fatal (s, "Permission denied");
351 
352     if (strncmp (cmd, "-x ", 3) == 0) {
353 	do_encrypt = 1;
354 	memmove (cmd, cmd + 3, strlen(cmd) - 2);
355     } else {
356 	do_encrypt = 0;
357     }
358 
359     {
360 	char *name;
361 
362 	if (krb5_unparse_name (context, ticket->client, &name) == 0) {
363 	    char addr_str[256];
364 
365 	    if (inet_ntop (thataddr->sa_family,
366 			   socket_get_address (thataddr),
367 			   addr_str, sizeof(addr_str)) == NULL)
368 		strlcpy (addr_str, "unknown address",
369 				 sizeof(addr_str));
370 
371 	    syslog(LOG_INFO|LOG_AUTH,
372 		   "kerberos v5 shell from %s on %s as %s, cmd '%.80s'",
373 		   name,
374 		   addr_str,
375 		   server_username,
376 		   cmd);
377 	    free (name);
378 	}
379     }
380 
381     return 0;
382 }
383 
384 static void
385 loop (int from0, int to0,
386       int to1,   int from1,
387       int to2,   int from2)
388 {
389     fd_set real_readset;
390     int max_fd;
391     int count = 2;
392 
393     FD_ZERO(&real_readset);
394     FD_SET(from0, &real_readset);
395     FD_SET(from1, &real_readset);
396     FD_SET(from2, &real_readset);
397     max_fd = max(from0, max(from1, from2)) + 1;
398     for (;;) {
399 	int ret;
400 	fd_set readset = real_readset;
401 	char buf[RSH_BUFSIZ];
402 
403 	ret = select (max_fd, &readset, NULL, NULL, NULL);
404 	if (ret < 0) {
405 	    if (errno == EINTR)
406 		continue;
407 	    else
408 		syslog_and_die ("select: %m");
409 	}
410 	if (FD_ISSET(from0, &readset)) {
411 	    ret = do_read (from0, buf, sizeof(buf));
412 	    if (ret < 0)
413 		syslog_and_die ("read: %m");
414 	    else if (ret == 0) {
415 		close (from0);
416 		close (to0);
417 		FD_CLR(from0, &real_readset);
418 	    } else
419 		net_write (to0, buf, ret);
420 	}
421 	if (FD_ISSET(from1, &readset)) {
422 	    ret = read (from1, buf, sizeof(buf));
423 	    if (ret < 0)
424 		syslog_and_die ("read: %m");
425 	    else if (ret == 0) {
426 		close (from1);
427 		close (to1);
428 		FD_CLR(from1, &real_readset);
429 		if (--count == 0)
430 		    exit (0);
431 	    } else
432 		do_write (to1, buf, ret);
433 	}
434 	if (FD_ISSET(from2, &readset)) {
435 	    ret = read (from2, buf, sizeof(buf));
436 	    if (ret < 0)
437 		syslog_and_die ("read: %m");
438 	    else if (ret == 0) {
439 		close (from2);
440 		close (to2);
441 		FD_CLR(from2, &real_readset);
442 		if (--count == 0)
443 		    exit (0);
444 	    } else
445 		do_write (to2, buf, ret);
446 	}
447    }
448 }
449 
450 /*
451  * Used by `setup_copier' to create some pipe-like means of
452  * communcation.  Real pipes would probably be the best thing, but
453  * then the shell doesn't understand it's talking to rshd.  If
454  * socketpair doesn't work everywhere, some autoconf magic would have
455  * to be added here.
456  *
457  * If it fails creating the `pipe', it aborts by calling fatal.
458  */
459 
460 static void
461 pipe_a_like (int fd[2])
462 {
463     if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) < 0)
464 	fatal (STDOUT_FILENO, "socketpair: %m");
465 }
466 
467 /*
468  * Start a child process and leave the parent copying data to and from it.  */
469 
470 static void
471 setup_copier (void)
472 {
473     int p0[2], p1[2], p2[2];
474     pid_t pid;
475 
476     pipe_a_like(p0);
477     pipe_a_like(p1);
478     pipe_a_like(p2);
479     pid = fork ();
480     if (pid < 0)
481 	fatal (STDOUT_FILENO, "fork: %m");
482     if (pid == 0) { /* child */
483 	close (p0[1]);
484 	close (p1[0]);
485 	close (p2[0]);
486 	dup2 (p0[0], STDIN_FILENO);
487 	dup2 (p1[1], STDOUT_FILENO);
488 	dup2 (p2[1], STDERR_FILENO);
489 	close (p0[0]);
490 	close (p1[1]);
491 	close (p2[1]);
492     } else { /* parent */
493 	close (p0[0]);
494 	close (p1[1]);
495 	close (p2[1]);
496 
497 	if (net_write (STDOUT_FILENO, "", 1) != 1)
498 	    fatal (STDOUT_FILENO, "write failed");
499 
500 	loop (STDIN_FILENO, p0[1],
501 	      STDOUT_FILENO, p1[0],
502 	      STDERR_FILENO, p2[0]);
503     }
504 }
505 
506 /*
507  * Is `port' a ``reserverd'' port?
508  */
509 
510 static int
511 is_reserved(u_short port)
512 {
513     return ntohs(port) < IPPORT_RESERVED;
514 }
515 
516 /*
517  * Set the necessary part of the environment in `env'.
518  */
519 
520 static void
521 setup_environment (char *env[7], struct passwd *pwd)
522 {
523     asprintf (&env[0], "USER=%s",  pwd->pw_name);
524     asprintf (&env[1], "HOME=%s",  pwd->pw_dir);
525     asprintf (&env[2], "SHELL=%s", pwd->pw_shell);
526     asprintf (&env[3], "PATH=%s",  _PATH_DEFPATH);
527     asprintf (&env[4], "SSH_CLIENT=only_to_make_bash_happy");
528     if (do_unique_tkfile)
529        asprintf (&env[5], "KRB5CCNAME=%s", tkfile);
530        else env[5] = NULL;
531     env[6] = NULL;
532 }
533 
534 static void
535 doit (int do_kerberos, int check_rhosts)
536 {
537     u_char buf[BUFSIZ];
538     u_char *p;
539     struct sockaddr_storage thisaddr_ss;
540     struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
541     struct sockaddr_storage thataddr_ss;
542     struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
543     struct sockaddr_storage erraddr_ss;
544     struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
545     int addrlen;
546     int port;
547     int errsock = -1;
548     char client_user[COMMAND_SZ], server_user[USERNAME_SZ];
549     char cmd[COMMAND_SZ];
550     struct passwd *pwd;
551     int s = STDIN_FILENO;
552     char *env[7];
553 
554     addrlen = sizeof(thisaddr_ss);
555     if (getsockname (s, thisaddr, &addrlen) < 0)
556 	syslog_and_die("getsockname: %m");
557     addrlen = sizeof(thataddr_ss);
558     if (getpeername (s, thataddr, &addrlen) < 0)
559 	syslog_and_die ("getpeername: %m");
560 
561     if (!do_kerberos && !is_reserved(socket_get_port(thataddr)))
562 	fatal(s, "Permission denied");
563 
564     p = buf;
565     port = 0;
566     for(;;) {
567 	if (net_read (s, p, 1) != 1)
568 	    syslog_and_die ("reading port number: %m");
569 	if (*p == '\0')
570 	    break;
571 	else if (isdigit(*p))
572 	    port = port * 10 + *p - '0';
573 	else
574 	    syslog_and_die ("non-digit in port number: %c", *p);
575     }
576 
577     if (!do_kerberos && !is_reserved(htons(port)))
578 	fatal(s, "Permission denied");
579 
580     if (port) {
581 	int priv_port = IPPORT_RESERVED - 1;
582 
583 	/*
584 	 * There's no reason to require a ``privileged'' port number
585 	 * here, but for some reason the brain dead rsh clients
586 	 * do... :-(
587 	 */
588 
589 	erraddr->sa_family = thataddr->sa_family;
590 	socket_set_address_and_port (erraddr,
591 				     socket_get_address (thataddr),
592 				     htons(port));
593 
594 	/*
595 	 * we only do reserved port for IPv4
596 	 */
597 
598 	if (erraddr->sa_family == AF_INET)
599 	    errsock = rresvport (&priv_port);
600 	else
601 	    errsock = socket (erraddr->sa_family, SOCK_STREAM, 0);
602 	if (errsock < 0)
603 	    syslog_and_die ("socket: %m");
604 	if (connect (errsock,
605 		     erraddr,
606 		     socket_sockaddr_size (erraddr)) < 0)
607 	    syslog_and_die ("connect: %m");
608     }
609 
610     if(do_kerberos) {
611 	if (net_read (s, buf, 4) != 4)
612 	    syslog_and_die ("reading auth info: %m");
613 
614 #ifdef KRB4
615 	if (recv_krb4_auth (s, buf, thisaddr, thataddr,
616 			    client_user,
617 			    server_user,
618 			    cmd) == 0)
619 	    auth_method = AUTH_KRB4;
620 	else
621 #endif /* KRB4 */
622 	    if(recv_krb5_auth (s, buf, thisaddr, thataddr,
623 			       client_user,
624 			       server_user,
625 			       cmd) == 0)
626 		auth_method = AUTH_KRB5;
627 	    else
628 		syslog_and_die ("unrecognized auth protocol: %x %x %x %x",
629 				buf[0], buf[1], buf[2], buf[3]);
630     } else {
631 	if(recv_bsd_auth (s, buf,
632 			  (struct sockaddr_in *)thisaddr,
633 			  (struct sockaddr_in *)thataddr,
634 			  client_user,
635 			  server_user,
636 			  cmd) == 0) {
637 	    auth_method = AUTH_BROKEN;
638 	    if(do_vacuous) {
639 		printf("Remote host requires Kerberos authentication\n");
640 		exit(0);
641 	    }
642 	} else
643 	    syslog_and_die("recv_bsd_auth failed");
644     }
645 
646     pwd = getpwnam (server_user);
647     if (pwd == NULL)
648 	fatal (s, "Login incorrect.");
649 
650     if (*pwd->pw_shell == '\0')
651 	pwd->pw_shell = _PATH_BSHELL;
652 
653     if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0)
654 	fatal (s, "Login disabled.");
655 
656 #ifdef HAVE_GETSPNAM
657     {
658 	struct spwd *sp;
659 	long    today;
660 
661 	sp = getspnam(server_user);
662 	today = time(0)/(24L * 60 * 60);
663 	if (sp->sp_expire > 0)
664 	    if (today > sp->sp_expire)
665 		fatal(s, "Account has expired.");
666     }
667 #endif
668 
669 #ifdef HAVE_SETLOGIN
670     if (setlogin(pwd->pw_name) < 0)
671 	syslog(LOG_ERR, "setlogin() failed: %m");
672 #endif
673 
674 #ifdef HAVE_SETPCRED
675     if (setpcred (pwd->pw_name, NULL) == -1)
676 	syslog(LOG_ERR, "setpcred() failure: %m");
677 #endif /* HAVE_SETPCRED */
678     if (initgroups (pwd->pw_name, pwd->pw_gid) < 0)
679 	fatal (s, "Login incorrect.");
680 
681     if (setgid(pwd->pw_gid) < 0)
682 	fatal (s, "Login incorrect.");
683 
684     if (setuid (pwd->pw_uid) < 0)
685 	fatal (s, "Login incorrect.");
686 
687 #ifdef KRB5
688     {
689 	int fd;
690 
691 	if (!do_unique_tkfile)
692 	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%u",pwd->pw_uid);
693 	else if (*tkfile=='\0') {
694 	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX");
695 	    fd = mkstemp(tkfile+5);
696 	    close(fd);
697 	    unlink(tkfile+5);
698 	}
699 
700 	if (kerberos_status)
701 	    krb5_start_session();
702     }
703 #endif
704 
705     if (chdir (pwd->pw_dir) < 0)
706 	fatal (s, "Remote directory.");
707 
708     if (errsock >= 0) {
709 	if (dup2 (errsock, STDERR_FILENO) < 0)
710 	    fatal (s, "Dup2 failed.");
711 	close (errsock);
712     }
713 
714     setup_environment (env, pwd);
715 
716     if (do_encrypt) {
717 	setup_copier ();
718     } else {
719 	if (net_write (s, "", 1) != 1)
720 	    fatal (s, "write failed");
721     }
722 
723 #ifdef KRB4
724     if(k_hasafs()) {
725 	char cell[64];
726 
727 	if(do_newpag)
728 	    k_setpag();
729 	if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0)
730 	    krb_afslog_uid_home (cell, NULL, pwd->pw_uid, pwd->pw_dir);
731 
732 	krb_afslog_uid_home(NULL, NULL, pwd->pw_uid, pwd->pw_dir);
733 
734 #ifdef KRB5
735 	/* XXX */
736        {
737 	   krb5_ccache ccache;
738 	   krb5_error_code status;
739 
740 	   status = krb5_cc_resolve (context, tkfile, &ccache);
741 	   if (!status) {
742 	       krb5_afslog_uid_home(context,ccache,NULL,NULL,
743 				    pwd->pw_uid, pwd->pw_dir);
744 	       krb5_cc_close (context, ccache);
745 	   }
746        }
747 #endif /* KRB5 */
748     }
749 #endif /* KRB4 */
750     execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env);
751     err(1, "exec %s", pwd->pw_shell);
752 }
753 
754 struct getargs args[] = {
755     { "inetd",		'i',	arg_negative_flag,	&do_inetd,
756       "Not started from inetd" },
757     { "kerberos",	'k',	arg_flag,	&do_kerberos,
758       "Implement kerberised services" },
759     { "encrypt",	'x',	arg_flag,		&do_encrypt,
760       "Implement encrypted service" },
761     { "rhosts",		'l',	arg_flag, &do_rhosts,
762       "Check users .rhosts" },
763     { "port",		'p',	arg_string,	&port_str,	"Use this port",
764       "port" },
765     { "vacuous",	'v',	arg_flag, &do_vacuous,
766       "Don't accept non-kerberised connections" },
767     { NULL,		'P',	arg_negative_flag, &do_newpag,
768       "Don't put process in new PAG" },
769     /* compatibility flag: */
770     { NULL,		'L',	arg_flag, &do_log },
771     { "version",	0, 	arg_flag,		&do_version },
772     { "help",		0, 	arg_flag,		&do_help }
773 };
774 
775 static void
776 usage (int ret)
777 {
778     if(isatty(STDIN_FILENO))
779 	arg_printusage (args,
780 			sizeof(args) / sizeof(args[0]),
781 			NULL,
782 			"");
783     else
784 	syslog (LOG_ERR, "Usage: %s [-ikxlvPL] [-p port]", __progname);
785     exit (ret);
786 }
787 
788 
789 int
790 main(int argc, char **argv)
791 {
792     int optind = 0;
793     int port = 0;
794 
795     set_progname (argv[0]);
796     roken_openlog ("rshd", LOG_ODELAY | LOG_PID, LOG_AUTH);
797 
798     if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv,
799 	       &optind))
800 	usage(1);
801 
802     if(do_help)
803 	usage (0);
804 
805     if (do_version) {
806 	print_version(NULL);
807 	exit(0);
808     }
809 
810 #ifdef KRB5
811     krb5_init_context (&context);
812 #endif
813 
814     if(port_str) {
815 	struct servent *s = roken_getservbyname (port_str, "tcp");
816 
817 	if (s)
818 	    port = s->s_port;
819 	else {
820 	    char *ptr;
821 
822 	    port = strtol (port_str, &ptr, 10);
823 	    if (port == 0 && ptr == port_str)
824 		syslog_and_die("Bad port `%s'", port_str);
825 	    port = htons(port);
826 	}
827     }
828 
829     if (do_encrypt)
830 	do_kerberos = 1;
831 
832     if (!do_inetd) {
833 	if (port == 0) {
834 	    if (do_kerberos) {
835 		if (do_encrypt)
836 		    port = krb5_getportbyname (context, "ekshell", "tcp", 545);
837 		else
838 		    port = krb5_getportbyname (context, "kshell",  "tcp", 544);
839 	    } else {
840 		port = krb5_getportbyname(context, "shell", "tcp", 514);
841 	    }
842 	}
843 	mini_inetd (port);
844     }
845 
846     signal (SIGPIPE, SIG_IGN);
847 
848     doit (do_kerberos, do_rhosts);
849     return 0;
850 }
851