1/*
2 * Copyright (c) 1997-2007 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#include "login_locl.h"
36RCSID("$Id$");
37
38int
39login_access( struct passwd *user, char *from);
40int
41read_limits_conf(const char *file, const struct passwd *pwd);
42
43#ifdef NEED_IRUSEROK_PROTO
44int iruserok(uint32_t, int, const char *, const char *);
45#endif
46
47enum auth_method auth_method;
48
49#ifdef KRB5
50krb5_context context;
51krb5_keyblock *keyblock;
52krb5_crypto crypto;
53#endif
54
55#ifdef KRB5
56krb5_ccache ccache, ccache2;
57int kerberos_status = 0;
58#endif
59
60int do_encrypt = 0;
61
62static int do_unique_tkfile           = 0;
63static char tkfile[MAXPATHLEN] = "";
64
65static int do_inetd = 1;
66static char *port_str;
67static int do_rhosts = 1;
68static int do_kerberos = 0;
69#define DO_KRB5 4
70static int do_vacuous = 0;
71static int do_log = 1;
72static int do_newpag = 1;
73static int do_addr_verify = 0;
74static int do_keepalive = 1;
75static int do_version;
76static int do_help = 0;
77
78static void
79syslog_and_die (const char *m, ...)
80    __attribute__ ((format (printf, 1, 2)));
81
82static void
83syslog_and_die (const char *m, ...)
84{
85    va_list args;
86
87    va_start(args, m);
88    vsyslog (LOG_ERR, m, args);
89    va_end(args);
90    exit (1);
91}
92
93static void
94fatal (int, const char*, const char *, ...)
95    __attribute__ ((noreturn, format (printf, 3, 4)));
96
97static void
98fatal (int sock, const char *what, const char *m, ...)
99{
100    va_list args;
101    char buf[BUFSIZ];
102    size_t len;
103
104    *buf = 1;
105    va_start(args, m);
106    len = vsnprintf (buf + 1, sizeof(buf) - 1, m, args);
107    len = min(len, sizeof(buf) - 1);
108    va_end(args);
109    if(what != NULL)
110	syslog (LOG_ERR, "%s: %s: %s", what, strerror(errno), buf + 1);
111    else
112	syslog (LOG_ERR, "%s", buf + 1);
113    net_write (sock, buf, len + 1);
114    exit (1);
115}
116
117static char *
118read_str (int s, size_t sz, char *expl)
119{
120    char *str = malloc(sz);
121    char *p = str;
122    if(str == NULL)
123	fatal(s, NULL, "%s too long", expl);
124    while(p < str + sz) {
125	if(net_read(s, p, 1) != 1)
126	    syslog_and_die("read: %s", strerror(errno));
127	if(*p == '\0')
128	    return str;
129	p++;
130    }
131    fatal(s, NULL, "%s too long", expl);
132}
133
134static int
135recv_bsd_auth (int s, u_char *buf,
136	       struct sockaddr_in *thisaddr,
137	       struct sockaddr_in *thataddr,
138	       char **client_username,
139	       char **server_username,
140	       char **cmd)
141{
142    struct passwd *pwd;
143
144    *client_username = read_str (s, USERNAME_SZ, "local username");
145    *server_username = read_str (s, USERNAME_SZ, "remote username");
146    *cmd = read_str (s, ARG_MAX + 1, "command");
147    pwd = getpwnam(*server_username);
148    if (pwd == NULL)
149	fatal(s, NULL, "Login incorrect.");
150    if (iruserok(thataddr->sin_addr.s_addr, pwd->pw_uid == 0,
151		 *client_username, *server_username))
152	fatal(s, NULL, "Login incorrect.");
153    return 0;
154}
155
156#ifdef KRB5
157static int
158save_krb5_creds (int s,
159                 krb5_auth_context auth_context,
160                 krb5_principal client)
161
162{
163    int ret;
164    krb5_data remote_cred;
165
166    krb5_data_zero (&remote_cred);
167    ret= krb5_read_message (context, (void *)&s, &remote_cred);
168    if (ret) {
169	krb5_data_free(&remote_cred);
170	return 0;
171    }
172    if (remote_cred.length == 0)
173	return 0;
174
175    ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, &ccache);
176    if (ret) {
177	krb5_data_free(&remote_cred);
178	return 0;
179    }
180
181    krb5_cc_initialize(context,ccache,client);
182    ret = krb5_rd_cred2(context, auth_context, ccache, &remote_cred);
183    if(ret != 0)
184	syslog(LOG_INFO|LOG_AUTH,
185	       "reading creds: %s", krb5_get_err_text(context, ret));
186    krb5_data_free (&remote_cred);
187    if (ret)
188	return 0;
189    return 1;
190}
191
192static void
193krb5_start_session (void)
194{
195    krb5_error_code ret;
196    char *estr;
197
198    ret = krb5_cc_resolve (context, tkfile, &ccache2);
199    if (ret) {
200	estr = krb5_get_error_string(context);
201	syslog(LOG_WARNING, "resolve cred cache %s: %s",
202	       tkfile,
203	       estr ? estr : krb5_get_err_text(context, ret));
204	free(estr);
205	krb5_cc_destroy(context, ccache);
206	return;
207    }
208
209    ret = krb5_cc_copy_cache (context, ccache, ccache2);
210    if (ret) {
211	estr = krb5_get_error_string(context);
212	syslog(LOG_WARNING, "storing credentials: %s",
213	       estr ? estr : krb5_get_err_text(context, ret));
214	free(estr);
215	krb5_cc_destroy(context, ccache);
216	return ;
217    }
218
219    krb5_cc_close(context, ccache2);
220    krb5_cc_destroy(context, ccache);
221    return;
222}
223
224static int protocol_version;
225
226static krb5_boolean
227match_kcmd_version(const void *data, const char *version)
228{
229    if(strcmp(version, KCMD_NEW_VERSION) == 0) {
230	protocol_version = 2;
231	return TRUE;
232    }
233    if(strcmp(version, KCMD_OLD_VERSION) == 0) {
234	protocol_version = 1;
235	key_usage = KRB5_KU_OTHER_ENCRYPTED;
236	return TRUE;
237    }
238    return FALSE;
239}
240
241
242static int
243recv_krb5_auth (int s, u_char *buf,
244		struct sockaddr *thisaddr,
245		struct sockaddr *thataddr,
246		char **client_username,
247		char **server_username,
248		char **cmd)
249{
250    uint32_t len;
251    krb5_auth_context auth_context = NULL;
252    krb5_ticket *ticket;
253    krb5_error_code status;
254    krb5_data cksum_data;
255    krb5_principal server;
256    char *str;
257
258    if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
259	return -1;
260    len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
261
262    if (net_read(s, buf, len) != len)
263	syslog_and_die ("reading auth info: %s", strerror(errno));
264    if (len != sizeof(KRB5_SENDAUTH_VERSION)
265	|| memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
266	syslog_and_die ("bad sendauth version: %.8s", buf);
267
268    status = krb5_sock_to_principal (context,
269				     s,
270				     "host",
271				     KRB5_NT_SRV_HST,
272				     &server);
273    if (status)
274	syslog_and_die ("krb5_sock_to_principal: %s",
275			krb5_get_err_text(context, status));
276
277    status = krb5_recvauth_match_version(context,
278					 &auth_context,
279					 &s,
280					 match_kcmd_version,
281					 NULL,
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    *server_username = read_str (s, USERNAME_SZ, "remote username");
292    *cmd = read_str (s, ARG_MAX + 1, "command");
293    *client_username = read_str (s, ARG_MAX + 1, "local username");
294
295    if(protocol_version == 2) {
296	status = krb5_auth_con_getremotesubkey(context, auth_context,
297					       &keyblock);
298	if(status != 0 || keyblock == NULL)
299	    syslog_and_die("failed to get remote subkey");
300    } else if(protocol_version == 1) {
301	status = krb5_auth_con_getkey (context, auth_context, &keyblock);
302	if(status != 0 || keyblock == NULL)
303	    syslog_and_die("failed to get key");
304    }
305    if (status != 0 || keyblock == NULL)
306       syslog_and_die ("krb5_auth_con_getkey: %s",
307                       krb5_get_err_text(context, status));
308
309    status = krb5_crypto_init(context, keyblock, 0, &crypto);
310    if(status)
311	syslog_and_die("krb5_crypto_init: %s",
312		       krb5_get_err_text(context, status));
313
314
315    cksum_data.length = asprintf (&str,
316				  "%u:%s%s",
317				  ntohs(socket_get_port (thisaddr)),
318				  *cmd,
319				  *server_username);
320    if (str == NULL)
321	syslog_and_die ("asprintf: out of memory");
322    cksum_data.data = str;
323
324    status = krb5_verify_authenticator_checksum(context,
325						auth_context,
326						cksum_data.data,
327						cksum_data.length);
328
329    if (status)
330	syslog_and_die ("krb5_verify_authenticator_checksum: %s",
331			krb5_get_err_text(context, status));
332
333    free (cksum_data.data);
334
335    if (strncmp (*client_username, "-u ", 3) == 0) {
336	do_unique_tkfile = 1;
337	memmove (*client_username, *client_username + 3,
338		 strlen(*client_username) - 2);
339    }
340
341    if (strncmp (*client_username, "-U ", 3) == 0) {
342	char *end, *temp_tkfile;
343
344	do_unique_tkfile = 1;
345	if (strncmp (*client_username + 3, "FILE:", 5) == 0) {
346	    temp_tkfile = tkfile;
347	} else {
348	    strlcpy (tkfile, "FILE:", sizeof(tkfile));
349	    temp_tkfile = tkfile + 5;
350	}
351	end = strchr(*client_username + 3,' ');
352	if (end == NULL)
353	    syslog_and_die("missing argument after -U");
354	snprintf(temp_tkfile, sizeof(tkfile) - (temp_tkfile - tkfile),
355		 "%.*s",
356		 (int)(end - *client_username - 3),
357		 *client_username + 3);
358	memmove (*client_username, end + 1, strlen(end+1)+1);
359    }
360
361    kerberos_status = save_krb5_creds (s, auth_context, ticket->client);
362
363    if(!krb5_kuserok (context,
364		      ticket->client,
365		      *server_username))
366	fatal (s, NULL, "Permission denied.");
367
368    if (strncmp (*cmd, "-x ", 3) == 0) {
369	do_encrypt = 1;
370	memmove (*cmd, *cmd + 3, strlen(*cmd) - 2);
371    } else {
372	if(do_encrypt)
373	    fatal (s, NULL, "Encryption is required.");
374	do_encrypt = 0;
375    }
376
377    {
378	char *name;
379
380	if (krb5_unparse_name (context, ticket->client, &name) == 0) {
381	    char addr_str[256];
382
383	    if (inet_ntop (thataddr->sa_family,
384			   socket_get_address (thataddr),
385			   addr_str, sizeof(addr_str)) == NULL)
386		strlcpy (addr_str, "unknown address",
387				 sizeof(addr_str));
388
389	    syslog(LOG_INFO|LOG_AUTH,
390		   "kerberos v5 shell from %s on %s as %s, cmd '%.80s'",
391		   name,
392		   addr_str,
393		   *server_username,
394		   *cmd);
395	    free (name);
396	}
397    }
398
399    krb5_auth_con_free(context, auth_context);
400
401    return 0;
402}
403#endif /* KRB5 */
404
405static void
406rshd_loop (int from0, int to0,
407	   int to1,   int from1,
408	   int to2,   int from2,
409	   int have_errsock)
410{
411    fd_set real_readset;
412    int max_fd;
413    int count = 2;
414    char *buf;
415
416    if(from0 >= FD_SETSIZE || from1 >= FD_SETSIZE || from2 >= FD_SETSIZE)
417	errx (1, "fd too large");
418
419#ifdef KRB5
420    if(auth_method == AUTH_KRB5 && protocol_version == 2)
421	init_ivecs(0, have_errsock);
422#endif
423
424    FD_ZERO(&real_readset);
425    FD_SET(from0, &real_readset);
426    FD_SET(from1, &real_readset);
427    FD_SET(from2, &real_readset);
428    max_fd = max(from0, max(from1, from2)) + 1;
429
430    buf = malloc(max(RSHD_BUFSIZ, RSH_BUFSIZ));
431    if (buf == NULL)
432	syslog_and_die("out of memory");
433
434    for (;;) {
435	int ret;
436	fd_set readset = real_readset;
437
438	ret = select (max_fd, &readset, NULL, NULL, NULL);
439	if (ret < 0) {
440	    if (errno == EINTR)
441		continue;
442	    else
443		syslog_and_die ("select: %s", strerror(errno));
444	}
445	if (FD_ISSET(from0, &readset)) {
446	    ret = do_read (from0, buf, RSHD_BUFSIZ, ivec_in[0]);
447	    if (ret < 0)
448		syslog_and_die ("read: %s", strerror(errno));
449	    else if (ret == 0) {
450		close (from0);
451		close (to0);
452		FD_CLR(from0, &real_readset);
453	    } else
454		net_write (to0, buf, ret);
455	}
456	if (FD_ISSET(from1, &readset)) {
457	    ret = read (from1, buf, RSH_BUFSIZ);
458	    if (ret < 0)
459		syslog_and_die ("read: %s", strerror(errno));
460	    else if (ret == 0) {
461		close (from1);
462		close (to1);
463		FD_CLR(from1, &real_readset);
464		if (--count == 0)
465		    exit (0);
466	    } else
467		do_write (to1, buf, ret, ivec_out[0]);
468	}
469	if (FD_ISSET(from2, &readset)) {
470	    ret = read (from2, buf, RSH_BUFSIZ);
471	    if (ret < 0)
472		syslog_and_die ("read: %s", strerror(errno));
473	    else if (ret == 0) {
474		close (from2);
475		close (to2);
476		FD_CLR(from2, &real_readset);
477		if (--count == 0)
478		    exit (0);
479	    } else
480		do_write (to2, buf, ret, ivec_out[1]);
481	}
482   }
483}
484
485/*
486 * Used by `setup_copier' to create some pipe-like means of
487 * communcation.  Real pipes would probably be the best thing, but
488 * then the shell doesn't understand it's talking to rshd.  If
489 * socketpair doesn't work everywhere, some autoconf magic would have
490 * to be added here.
491 *
492 * If it fails creating the `pipe', it aborts by calling fatal.
493 */
494
495static void
496pipe_a_like (int fd[2])
497{
498    if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) < 0)
499	fatal (STDOUT_FILENO, "socketpair", "Pipe creation failed.");
500}
501
502/*
503 * Start a child process and leave the parent copying data to and from it.  */
504
505static void
506setup_copier (int have_errsock)
507{
508    int p0[2], p1[2], p2[2];
509    pid_t pid;
510
511    pipe_a_like(p0);
512    pipe_a_like(p1);
513    pipe_a_like(p2);
514    pid = fork ();
515    if (pid < 0)
516	fatal (STDOUT_FILENO, "fork", "Could not create child process.");
517    if (pid == 0) { /* child */
518	close (p0[1]);
519	close (p1[0]);
520	close (p2[0]);
521	dup2 (p0[0], STDIN_FILENO);
522	dup2 (p1[1], STDOUT_FILENO);
523	dup2 (p2[1], STDERR_FILENO);
524	close (p0[0]);
525	close (p1[1]);
526	close (p2[1]);
527    } else { /* parent */
528	close (p0[0]);
529	close (p1[1]);
530	close (p2[1]);
531
532	if (net_write (STDOUT_FILENO, "", 1) != 1)
533	    fatal (STDOUT_FILENO, "net_write", "Write failure.");
534
535	rshd_loop (STDIN_FILENO, p0[1],
536	      STDOUT_FILENO, p1[0],
537	      STDERR_FILENO, p2[0],
538	      have_errsock);
539    }
540}
541
542/*
543 * Is `port' a ``reserverd'' port?
544 */
545
546static int
547is_reserved(u_short port)
548{
549    return ntohs(port) < IPPORT_RESERVED;
550}
551
552/*
553 * Set the necessary part of the environment in `env'.
554 */
555
556static void
557setup_environment (char ***env, const struct passwd *pwd)
558{
559    int i, j, path;
560    char **e;
561
562    i = 0;
563    path = 0;
564    *env = NULL;
565
566    i = read_environment(_PATH_ETC_ENVIRONMENT, env);
567    e = *env;
568    for (j = 0; j < i; j++) {
569	if (!strncmp(e[j], "PATH=", 5)) {
570	    path = 1;
571	}
572    }
573
574    e = *env;
575    e = realloc(e, (i + 7) * sizeof(char *));
576
577    if (asprintf (&e[i++], "USER=%s",  pwd->pw_name) == -1)
578	syslog_and_die ("asprintf: out of memory");
579    if (asprintf (&e[i++], "HOME=%s",  pwd->pw_dir) == -1)
580	syslog_and_die ("asprintf: out of memory");
581    if (asprintf (&e[i++], "SHELL=%s", pwd->pw_shell) == -1)
582	syslog_and_die ("asprintf: out of memory");
583    if (! path) {
584	if (asprintf (&e[i++], "PATH=%s",  _PATH_DEFPATH) == -1)
585	    syslog_and_die ("asprintf: out of memory");
586    }
587    asprintf (&e[i++], "SSH_CLIENT=only_to_make_bash_happy");
588    if (do_unique_tkfile)
589	if (asprintf (&e[i++], "KRB5CCNAME=%s", tkfile) == -1)
590	    syslog_and_die ("asprintf: out of memory");
591    e[i++] = NULL;
592    *env = e;
593}
594
595static void
596doit (void)
597{
598    u_char buf[BUFSIZ];
599    u_char *p;
600    struct sockaddr_storage thisaddr_ss;
601    struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
602    struct sockaddr_storage thataddr_ss;
603    struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
604    struct sockaddr_storage erraddr_ss;
605    struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
606    socklen_t thisaddr_len, thataddr_len;
607    int port;
608    int errsock = -1;
609    char *client_user = NULL, *server_user = NULL, *cmd = NULL;
610    struct passwd *pwd;
611    int s = STDIN_FILENO;
612    char **env;
613    int ret;
614    char that_host[NI_MAXHOST];
615
616    thisaddr_len = sizeof(thisaddr_ss);
617    if (getsockname (s, thisaddr, &thisaddr_len) < 0)
618	syslog_and_die("getsockname: %s", strerror(errno));
619    thataddr_len = sizeof(thataddr_ss);
620    if (getpeername (s, thataddr, &thataddr_len) < 0)
621	syslog_and_die ("getpeername: %s", strerror(errno));
622
623    /* check for V4MAPPED addresses? */
624
625    if (do_kerberos == 0 && !is_reserved(socket_get_port(thataddr)))
626	fatal(s, NULL, "Permission denied.");
627
628    p = buf;
629    port = 0;
630    for(;;) {
631	if (net_read (s, p, 1) != 1)
632	    syslog_and_die ("reading port number: %s", strerror(errno));
633	if (*p == '\0')
634	    break;
635	else if (isdigit(*p))
636	    port = port * 10 + *p - '0';
637	else
638	    syslog_and_die ("non-digit in port number: %c", *p);
639    }
640
641    if (do_kerberos  == 0 && !is_reserved(htons(port)))
642	fatal(s, NULL, "Permission denied.");
643
644    if (port) {
645	int priv_port = IPPORT_RESERVED - 1;
646
647	/*
648	 * There's no reason to require a ``privileged'' port number
649	 * here, but for some reason the brain dead rsh clients
650	 * do... :-(
651	 */
652
653	erraddr->sa_family = thataddr->sa_family;
654	socket_set_address_and_port (erraddr,
655				     socket_get_address (thataddr),
656				     htons(port));
657
658	/*
659	 * we only do reserved port for IPv4
660	 */
661
662	if (erraddr->sa_family == AF_INET)
663	    errsock = rresvport (&priv_port);
664	else
665	    errsock = socket (erraddr->sa_family, SOCK_STREAM, 0);
666	if (errsock < 0)
667	    syslog_and_die ("socket: %s", strerror(errno));
668	if (connect (errsock,
669		     erraddr,
670		     socket_sockaddr_size (erraddr)) < 0) {
671	    syslog (LOG_WARNING, "connect: %s", strerror(errno));
672	    close (errsock);
673	}
674    }
675
676    if(do_kerberos) {
677	if (net_read (s, buf, 4) != 4)
678	    syslog_and_die ("reading auth info: %s", strerror(errno));
679
680#ifdef KRB5
681	    if((do_kerberos & DO_KRB5) &&
682	       recv_krb5_auth (s, buf, thisaddr, thataddr,
683			       &client_user,
684			       &server_user,
685			       &cmd) == 0)
686		auth_method = AUTH_KRB5;
687	    else
688#endif /* KRB5 */
689		syslog_and_die ("unrecognized auth protocol: %x %x %x %x",
690				buf[0], buf[1], buf[2], buf[3]);
691    } else {
692	if(recv_bsd_auth (s, buf,
693			  (struct sockaddr_in *)thisaddr,
694			  (struct sockaddr_in *)thataddr,
695			  &client_user,
696			  &server_user,
697			  &cmd) == 0) {
698	    auth_method = AUTH_BROKEN;
699	    if(do_vacuous) {
700		printf("Remote host requires Kerberos authentication\n");
701		exit(0);
702	    }
703	} else
704	    syslog_and_die("recv_bsd_auth failed");
705    }
706
707    if (client_user == NULL || server_user == NULL || cmd == NULL)
708	syslog_and_die("mising client/server/cmd");
709
710    pwd = getpwnam (server_user);
711    if (pwd == NULL)
712	fatal (s, NULL, "Login incorrect.");
713
714    if (*pwd->pw_shell == '\0')
715	pwd->pw_shell = _PATH_BSHELL;
716
717    if (pwd->pw_uid != 0 && access (_PATH_NOLOGIN, F_OK) == 0)
718	fatal (s, NULL, "Login disabled.");
719
720
721    ret = getnameinfo_verified (thataddr, thataddr_len,
722				that_host, sizeof(that_host),
723				NULL, 0, 0);
724    if (ret)
725	fatal (s, NULL, "getnameinfo: %s", gai_strerror(ret));
726
727    if (login_access(pwd, that_host) == 0) {
728	syslog(LOG_NOTICE, "Kerberos rsh denied to %s from %s",
729	       server_user, that_host);
730	fatal(s, NULL, "Permission denied.");
731    }
732
733#ifdef HAVE_GETSPNAM
734    {
735	struct spwd *sp;
736	long    today;
737
738	sp = getspnam(server_user);
739	if (sp != NULL) {
740	    today = time(0)/(24L * 60 * 60);
741	    if (sp->sp_expire > 0)
742		if (today > sp->sp_expire)
743		    fatal(s, NULL, "Account has expired.");
744	}
745    }
746#endif
747
748
749#ifdef HAVE_SETLOGIN
750    if (setlogin(pwd->pw_name) < 0)
751	syslog(LOG_ERR, "setlogin() failed: %s", strerror(errno));
752#endif
753
754#ifdef HAVE_SETPCRED
755    if (setpcred (pwd->pw_name, NULL) == -1)
756	syslog(LOG_ERR, "setpcred() failure: %s", strerror(errno));
757#endif /* HAVE_SETPCRED */
758
759    /* Apply limits if not root */
760    if(pwd->pw_uid != 0) {
761	 const char *file = _PATH_LIMITS_CONF;
762	 read_limits_conf(file, pwd);
763    }
764
765    if (initgroups (pwd->pw_name, pwd->pw_gid) < 0)
766	fatal (s, "initgroups", "Login incorrect.");
767
768    if (setgid(pwd->pw_gid) < 0)
769	fatal (s, "setgid", "Login incorrect.");
770
771    if (setuid (pwd->pw_uid) < 0)
772	fatal (s, "setuid", "Login incorrect.");
773
774    if (chdir (pwd->pw_dir) < 0)
775	fatal (s, "chdir", "Remote directory.");
776
777    if (errsock >= 0) {
778	if (dup2 (errsock, STDERR_FILENO) < 0)
779	    fatal (s, "dup2", "Cannot dup stderr.");
780	close (errsock);
781    } else {
782	if (dup2 (STDOUT_FILENO, STDERR_FILENO) < 0)
783	    fatal (s, "dup2", "Cannot dup stderr.");
784    }
785
786#ifdef KRB5
787    {
788	int fd;
789
790	if (!do_unique_tkfile)
791	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_%lu",
792		     (unsigned long)pwd->pw_uid);
793	else if (*tkfile=='\0') {
794	    snprintf(tkfile,sizeof(tkfile),"FILE:/tmp/krb5cc_XXXXXX");
795	    fd = mkstemp(tkfile+5);
796	    close(fd);
797	    unlink(tkfile+5);
798	}
799
800	if (kerberos_status)
801	    krb5_start_session();
802    }
803#endif
804
805    setup_environment (&env, pwd);
806
807    if (do_encrypt) {
808	setup_copier (errsock >= 0);
809    } else {
810	if (net_write (s, "", 1) != 1)
811	    fatal (s, "net_write", "write failed");
812    }
813
814#if defined(KRB5)
815    if(k_hasafs()) {
816	char cell[64];
817
818	if(do_newpag)
819	    k_setpag();
820
821	/* XXX */
822       if (kerberos_status) {
823	   krb5_ccache ccache;
824	   krb5_error_code status;
825
826	   status = krb5_cc_resolve (context, tkfile, &ccache);
827	   if (!status) {
828	       if (k_afs_cell_of_file (pwd->pw_dir, cell, sizeof(cell)) == 0)
829		   krb5_afslog_uid_home(context, ccache, cell, NULL,
830					pwd->pw_uid, pwd->pw_dir);
831	       krb5_afslog_uid_home(context, ccache, NULL, NULL,
832				    pwd->pw_uid, pwd->pw_dir);
833	       krb5_cc_close (context, ccache);
834	   }
835       }
836    }
837#endif /* KRB5 */
838    execle (pwd->pw_shell, pwd->pw_shell, "-c", cmd, NULL, env);
839    err(1, "exec %s", pwd->pw_shell);
840}
841
842struct getargs args[] = {
843    { NULL,		'a',	arg_flag,	&do_addr_verify },
844    { "keepalive",	'n',	arg_negative_flag,	&do_keepalive },
845    { "inetd",		'i',	arg_negative_flag,	&do_inetd,
846      "Not started from inetd" },
847#if defined(KRB5)
848    { "kerberos",	'k',	arg_flag,	&do_kerberos,
849      "Implement kerberised services" },
850    { "encrypt",	'x',	arg_flag,		&do_encrypt,
851      "Implement encrypted service" },
852#endif
853    { "rhosts",		'l',	arg_negative_flag, &do_rhosts,
854      "Don't check users .rhosts" },
855    { "port",		'p',	arg_string,	&port_str,	"Use this port",
856      "port" },
857    { "vacuous",	'v',	arg_flag, &do_vacuous,
858      "Don't accept non-kerberised connections" },
859#if defined(KRB5)
860    { NULL,		'P',	arg_negative_flag, &do_newpag,
861      "Don't put process in new PAG" },
862#endif
863    /* compatibility flag: */
864    { NULL,		'L',	arg_flag, &do_log },
865    { "version",	0, 	arg_flag,		&do_version },
866    { "help",		0, 	arg_flag,		&do_help }
867};
868
869static void
870usage (int ret)
871{
872    if(isatty(STDIN_FILENO))
873	arg_printusage (args,
874			sizeof(args) / sizeof(args[0]),
875			NULL,
876			"");
877    else
878	syslog (LOG_ERR, "Usage: %s [-ikxlvPL] [-p port]", getprogname());
879    exit (ret);
880}
881
882
883int
884main(int argc, char **argv)
885{
886    int optind = 0;
887    int on = 1;
888
889    setprogname (argv[0]);
890    roken_openlog ("rshd", LOG_ODELAY | LOG_PID, LOG_AUTH);
891
892    if (getarg(args, sizeof(args) / sizeof(args[0]), argc, argv,
893	       &optind))
894	usage(1);
895
896    if(do_help)
897	usage (0);
898
899    if (do_version) {
900	print_version(NULL);
901	exit(0);
902    }
903
904#if defined(KRB5)
905    if (do_encrypt)
906	do_kerberos = 1;
907
908    if(do_kerberos)
909	do_kerberos = DO_KRB5;
910#endif
911
912#ifdef KRB5
913    if((do_kerberos & DO_KRB5) && krb5_init_context (&context) != 0)
914	do_kerberos &= ~DO_KRB5;
915#endif
916
917    if (!do_inetd) {
918	int error;
919	struct addrinfo *ai = NULL, hints;
920	char portstr[NI_MAXSERV];
921
922	memset (&hints, 0, sizeof(hints));
923	hints.ai_flags    = AI_PASSIVE;
924	hints.ai_socktype = SOCK_STREAM;
925	hints.ai_family   = PF_UNSPEC;
926
927	if(port_str != NULL) {
928	    error = getaddrinfo (NULL, port_str, &hints, &ai);
929	    if (error)
930		errx (1, "getaddrinfo: %s", gai_strerror (error));
931	}
932	if (ai == NULL) {
933#if defined(KRB5)
934	    if (do_kerberos) {
935		if (do_encrypt) {
936		    error = getaddrinfo(NULL, "ekshell", &hints, &ai);
937		    if(error == EAI_NONAME) {
938			snprintf(portstr, sizeof(portstr), "%d", 545);
939			error = getaddrinfo(NULL, portstr, &hints, &ai);
940		    }
941		    if(error)
942			errx (1, "getaddrinfo: %s", gai_strerror (error));
943		} else {
944		    error = getaddrinfo(NULL, "kshell", &hints, &ai);
945		    if(error == EAI_NONAME) {
946			snprintf(portstr, sizeof(portstr), "%d", 544);
947			error = getaddrinfo(NULL, portstr, &hints, &ai);
948		    }
949		    if(error)
950			errx (1, "getaddrinfo: %s", gai_strerror (error));
951		}
952	    } else
953#endif
954		{
955		    error = getaddrinfo(NULL, "shell", &hints, &ai);
956		    if(error == EAI_NONAME) {
957			snprintf(portstr, sizeof(portstr), "%d", 514);
958			error = getaddrinfo(NULL, portstr, &hints, &ai);
959		    }
960		    if(error)
961			errx (1, "getaddrinfo: %s", gai_strerror (error));
962		}
963	}
964	mini_inetd_addrinfo (ai, NULL);
965	freeaddrinfo(ai);
966    }
967
968    if (do_keepalive &&
969	setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
970		   sizeof(on)) < 0)
971	syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %s", strerror(errno));
972
973    /* set SO_LINGER? */
974
975    signal (SIGPIPE, SIG_IGN);
976
977    doit ();
978    return 0;
979}
980