1/*
2 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*	Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7/*	  All Rights Reserved  	*/
8
9/*
10 * Copyright (c) 1983 The Regents of the University of California.
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms are permitted
14 * provided that the above copyright notice and this paragraph are
15 * duplicated in all such forms and that any documentation,
16 * advertising materials, and other materials related to such
17 * distribution and use acknowledge that the software was developed
18 * by the University of California, Berkeley.  The name of the
19 * University may not be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
23 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 */
25
26/*
27 * remote login server:
28 *	remuser\0
29 *	locuser\0
30 *	terminal info\0
31 *	data
32 */
33
34#include <time.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/socket.h>
38#include <sys/wait.h>
39
40#include <netinet/in.h>
41
42#include <errno.h>
43#include <signal.h>
44#include <fcntl.h>
45#include <stdio.h>
46#include <netdb.h>
47#include <syslog.h>
48#include <string.h>
49#include <unistd.h>
50#include <stdlib.h>
51#include <alloca.h>
52#include <stropts.h>
53#include <sac.h>	/* for SC_WILDC */
54#include <utmpx.h>
55#include <sys/filio.h>
56#include <sys/logindmux.h>
57#include <sys/rlioctl.h>
58#include <sys/termios.h>
59#include <sys/tihdr.h>
60#include <arpa/inet.h>
61#include <security/pam_appl.h>
62#include <strings.h>
63#include <com_err.h>
64#include <k5-int.h>
65#include <kcmd.h>
66#include <krb5_repository.h>
67#include <sys/cryptmod.h>
68#include <bsm/adt.h>
69#include <addr_match.h>
70#include <store_forw_creds.h>
71
72#define	KRB5_RECVAUTH_V5 5
73#define	UT_NAMESIZE	sizeof (((struct utmpx *)0)->ut_name)
74
75static char lusername[UT_NAMESIZE+1];
76static char rusername[UT_NAMESIZE+1];
77static char *krusername = NULL;
78static char term[64];
79
80static krb5_ccache ccache = NULL;
81static krb5_keyblock *session_key = NULL;
82static int chksum_flag = 0;
83static int use_auth = 0;
84static enum kcmd_proto kcmd_protocol;
85#ifdef ALLOW_KCMD_V2
86static krb5_data encr_iv = { NULL, 0 };
87static krb5_data decr_iv = { NULL, 0 };
88#endif /* ALLOW_KCMD_V2 */
89
90#define	CHKSUM_REQUIRED 0x01
91#define	CHKSUM_IGNORED  0x02
92#define	VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\
93			(x) == CHKSUM_IGNORED)
94
95#define	PWD_IF_FAIL  0x01
96#define	PWD_REQUIRED 0x02
97
98#define	AUTH_NONE 0x00
99
100#define	ARGSTR "k5exEXciM:s:S:D:"
101#define	DEFAULT_TOS 16
102
103#define	KRB5_PROG_NAME "krlogin"
104
105#define	SECURE_MSG "This rlogin session is using encryption " \
106	"for all data transmissions.\r\n"
107
108#define	KRB_V5_SENDAUTH_VERS	"KRB5_SENDAUTH_V1.0"
109#define	KRB5_RECVAUTH_V5	5
110
111static krb5_error_code krb5_compat_recvauth(krb5_context context,
112					    krb5_auth_context *auth_context,
113					    krb5_pointer fdp,
114					    krb5_principal server,
115					    krb5_int32 flags,
116					    krb5_keytab keytab,
117					    krb5_ticket **ticket,
118					    krb5_int32 *auth_sys,
119					    krb5_data *version);
120
121static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab);
122static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t);
123
124extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer,
125					krb5_data *);
126extern krb5_error_code krb5_net_read(krb5_context, int, char *, int);
127
128#define	LOGIN_PROGRAM "/bin/login"
129
130#define	DEFAULT_PROG_NAME	"rlogin"
131
132static const char *pam_prog_name = DEFAULT_PROG_NAME;
133static void	rmut(void);
134static void	doit(int,  struct sockaddr_storage *, krb5_context, int,
135		    krb5_keytab);
136static void	protocol(int, int, int);
137
138static int	readstream(int, char *, int);
139static void	fatal(int, const char *);
140static void	fatalperror(int, const char *);
141static int	send_oob(int fd, void *ptr, size_t count);
142static int	removemod(int f, char *modname);
143
144static int
145issock(int fd)
146{
147	struct stat stats;
148
149	if (fstat(fd, &stats) == -1)
150		return (0);
151	return (S_ISSOCK(stats.st_mode));
152}
153
154/*
155 * audit_rlogin_settid stores the terminal id while it is still
156 * available.  Subsequent calls to adt_load_hostname() return
157 * the id which is stored here.
158 */
159static int
160audit_rlogin_settid(int fd) {
161	adt_session_data_t	*ah;
162	adt_termid_t		*termid;
163	int			rc;
164
165	if ((rc = adt_start_session(&ah, NULL, 0)) == 0) {
166		if ((rc = adt_load_termid(fd, &termid)) == 0) {
167			if ((rc = adt_set_user(ah, ADT_NO_AUDIT,
168			    ADT_NO_AUDIT, 0, ADT_NO_AUDIT,
169			    termid, ADT_SETTID)) == 0)
170				(void) adt_set_proc(ah);
171			free(termid);
172		}
173		(void) adt_end_session(ah);
174	}
175	return (rc);
176}
177
178
179/* ARGSUSED */
180int
181main(int argc, char *argv[])
182{
183	int on = 1;
184	socklen_t fromlen;
185	struct sockaddr_storage from;
186	int fd = -1;
187
188	extern char *optarg;
189	char c;
190	int tos = -1;
191	krb5_context krb_context;
192	krb5_keytab keytab = NULL;
193	krb5_error_code status;
194	char *realm = NULL;
195	char *keytab_file = NULL;
196	int encr_flag = 0;
197	struct sockaddr_storage ouraddr;
198	socklen_t ourlen;
199#ifdef DEBUG
200	int debug_port = 0;
201#endif /* DEBUG */
202	openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON);
203
204	while ((c = getopt(argc, argv, ARGSTR)) != -1) {
205		switch (c) {
206		case 'k':
207		case '5':
208			use_auth = KRB5_RECVAUTH_V5;
209			break;
210		case 'e':
211		case 'E':
212		case 'x':
213		case 'X':
214			encr_flag = 1;
215			break;
216		case 'M':
217			realm = (char *)strdup(optarg);
218			break;
219		case 'S':
220			keytab_file = (char *)strdup(optarg);
221			break;
222		case 'c':
223			chksum_flag |= CHKSUM_REQUIRED;
224			break;
225		case 'i':
226			chksum_flag |= CHKSUM_IGNORED;
227			break;
228		case 's':
229			if (optarg == NULL || (tos = atoi(optarg)) < 0 ||
230			    tos > 255) {
231				syslog(LOG_ERR, "%s: illegal tos value: "
232				    "%s\n", argv[0], optarg);
233			} else {
234				if (tos < 0)
235					tos = DEFAULT_TOS;
236			}
237			break;
238#ifdef DEBUG
239		case 'D':
240			debug_port = atoi(optarg);
241			break;
242#endif /* DEBUG */
243		default:
244			syslog(LOG_ERR, "Unrecognized command line option "
245			    "(-%c), exiting", optopt);
246			exit(EXIT_FAILURE);
247		}
248	}
249	if (use_auth == KRB5_RECVAUTH_V5) {
250		status = krb5_init_context(&krb_context);
251		if (status) {
252			syslog(LOG_ERR, "Error initializing krb5: %s",
253			    error_message(status));
254			exit(EXIT_FAILURE);
255		}
256		if (realm != NULL)
257			(void) krb5_set_default_realm(krb_context, realm);
258		if (keytab_file != NULL) {
259			if ((status = krb5_kt_resolve(krb_context,
260						    keytab_file,
261						    &keytab))) {
262				com_err(argv[0],
263					status,
264					"while resolving srvtab file %s",
265					keytab_file);
266				exit(EXIT_FAILURE);
267			}
268		}
269	}
270
271#ifdef DEBUG
272	if (debug_port) {
273		int s;
274		struct sockaddr_in sin;
275
276		if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
277			fatalperror(STDERR_FILENO, "Error in socket");
278		}
279
280		(void) memset((char *)&sin, 0, sizeof (sin));
281		sin.sin_family = AF_INET;
282		sin.sin_port = htons(debug_port);
283		sin.sin_addr.s_addr = INADDR_ANY;
284
285		(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
286					(char *)&on, sizeof (on));
287
288		if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
289			fatalperror(STDERR_FILENO, "bind error");
290		}
291
292		if ((listen(s, 5)) < 0) {
293			fatalperror(STDERR_FILENO, "listen error");
294		}
295
296		fromlen = sizeof (from);
297		if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) {
298			fatalperror(STDERR_FILENO, "accept error");
299		}
300
301		(void) close(s);
302	} else
303#endif /* DEBUG */
304	{
305		if (!issock(STDIN_FILENO))
306			fatal(STDIN_FILENO,
307				"stdin is not a socket file descriptor");
308		fd = STDIN_FILENO;
309	}
310
311	fromlen = sizeof (from);
312	if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0)
313		fatalperror(STDERR_FILENO, "getpeername");
314
315	if (audit_rlogin_settid(fd))	/* set terminal ID */
316		fatalperror(STDERR_FILENO, "audit");
317
318	if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
319	    sizeof (on)) < 0)
320		syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m");
321
322	if (!VALID_CHKSUM(chksum_flag)) {
323		syslog(LOG_ERR, "Configuration error: mutually exclusive "
324		    "options specified (-c and -i)");
325		fatal(fd, "Checksums are required and ignored (-c and -i);"
326		    "these options are mutually exclusive - check "
327		    "the documentation.");
328	}
329	ourlen = sizeof (ouraddr);
330	if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) {
331		syslog(LOG_ERR, "getsockname error: %m");
332		exit(EXIT_FAILURE);
333	}
334
335	if (tos != -1 &&
336	    ouraddr.ss_family != AF_INET6 &&
337	    setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos,
338					sizeof (tos)) < 0 &&
339					errno != ENOPROTOOPT) {
340		syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos);
341	}
342	doit(fd, &from, krb_context, encr_flag, keytab);
343	return (0);
344}
345
346static void	cleanup(int);
347static int	nsize = 0;	/* bytes read prior to pushing rlmod */
348static char	*rlbuf;		/* buffer where nbytes are read to */
349static char	*line;
350
351static struct winsize win = { 0, 0, 0, 0 };
352static pid_t pid;
353static char hostname[MAXHOSTNAMELEN + 1];
354
355static void
356getstr(int f, char *buf, int cnt, char *err)
357{
358	char c;
359	do {
360		if (read(f, &c, 1) != 1 || (--cnt < 0)) {
361			syslog(LOG_ERR, "Error reading \'%s\' field", err);
362			exit(EXIT_FAILURE);
363		}
364		*buf++ = c;
365	} while (c != '\0');
366}
367
368static krb5_error_code
369recvauth(int f,
370	krb5_context krb_context,
371	unsigned int *valid_checksum,
372	krb5_ticket **ticket,
373	int *auth_type,
374	krb5_principal *client,
375	int encr_flag,
376	krb5_keytab keytab)
377{
378	krb5_error_code status = 0;
379	krb5_auth_context auth_context = NULL;
380	krb5_rcache rcache;
381	krb5_authenticator *authenticator;
382	krb5_data inbuf;
383	krb5_data auth_version;
384
385	*valid_checksum = 0;
386
387	if ((status = krb5_auth_con_init(krb_context, &auth_context)))
388		return (status);
389
390	/* Only need remote address for rd_cred() to verify client */
391	if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
392			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
393		return (status);
394
395	status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
396	if (status)
397		return (status);
398
399	if (!rcache) {
400		krb5_principal server;
401
402		status = krb5_sname_to_principal(krb_context, 0, 0,
403						KRB5_NT_SRV_HST, &server);
404		if (status)
405			return (status);
406
407		status = krb5_get_server_rcache(krb_context,
408				krb5_princ_component(krb_context, server, 0),
409				&rcache);
410		krb5_free_principal(krb_context, server);
411		if (status)
412			return (status);
413
414		status = krb5_auth_con_setrcache(krb_context, auth_context,
415						rcache);
416		if (status)
417			return (status);
418	}
419	if ((status = krb5_compat_recvauth(krb_context,
420					&auth_context,
421					&f,
422					NULL,	/* Specify daemon principal */
423					0,	/* no flags */
424					keytab,	/* NULL to use v5srvtab */
425					ticket,	/* return ticket */
426					auth_type, /* authentication system */
427					&auth_version))) {
428		if (*auth_type == KRB5_RECVAUTH_V5) {
429			/*
430			 * clean up before exiting
431			 */
432			getstr(f, rusername, sizeof (rusername), "remuser");
433			getstr(f, lusername, sizeof (lusername), "locuser");
434			getstr(f, term, sizeof (term), "Terminal type");
435		}
436		return (status);
437	}
438
439	getstr(f, lusername, sizeof (lusername), "locuser");
440	getstr(f, term, sizeof (term), "Terminal type");
441
442	kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
443	if (auth_version.length != 9 || auth_version.data == NULL) {
444		syslog(LOG_ERR, "Bad application protocol version length in "
445		    "KRB5 exchange, exiting");
446		fatal(f, "Bad application version length, exiting.");
447	}
448	/*
449	 * Determine which Kerberos CMD protocol was used.
450	 */
451	if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
452		kcmd_protocol = KCMD_OLD_PROTOCOL;
453	} else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
454		kcmd_protocol = KCMD_NEW_PROTOCOL;
455	} else {
456		syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
457			(char *)auth_version.data);
458		fatal(f, "Unrecognized KCMD protocol, exiting");
459	}
460
461	if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
462		kcmd_protocol == KCMD_OLD_PROTOCOL) {
463		if ((status = krb5_auth_con_getauthenticator(krb_context,
464							    auth_context,
465							    &authenticator)))
466			return (status);
467		if (authenticator->checksum) {
468			struct sockaddr_storage adr;
469			int adr_length = sizeof (adr);
470			int buflen;
471			krb5_data input;
472			krb5_keyblock key;
473			char *chksumbuf;
474
475			/*
476			 * Define the lenght of the chksum buffer.
477			 * chksum string = "[portnum]:termstr:username"
478			 * The extra 32 is to hold a integer string for
479			 * the portnumber.
480			 */
481			buflen = strlen(term) + strlen(lusername) + 32;
482			chksumbuf = (char *)malloc(buflen);
483			if (chksumbuf == 0) {
484				krb5_free_authenticator(krb_context,
485							authenticator);
486				fatal(f, "Out of memory error");
487			}
488
489			if (getsockname(f, (struct sockaddr *)&adr,
490							&adr_length) != 0) {
491				krb5_free_authenticator(krb_context,
492							authenticator);
493				fatal(f, "getsockname error");
494			}
495
496			(void) snprintf(chksumbuf, buflen,
497					"%u:%s%s",
498					ntohs(SOCK_PORT(adr)),
499					term, lusername);
500
501			input.data = chksumbuf;
502			input.length = strlen(chksumbuf);
503			key.contents = (*ticket)->enc_part2->session->contents;
504			key.length = (*ticket)->enc_part2->session->length;
505			status = krb5_c_verify_checksum(krb_context,
506						&key, 0,
507						&input,
508						authenticator->checksum,
509						valid_checksum);
510
511			if (status == 0 && *valid_checksum == 0)
512				status = KRB5KRB_AP_ERR_BAD_INTEGRITY;
513
514			if (chksumbuf)
515				krb5_xfree(chksumbuf);
516			if (status) {
517				krb5_free_authenticator(krb_context,
518							authenticator);
519				return (status);
520			}
521		}
522		krb5_free_authenticator(krb_context, authenticator);
523	}
524
525	if ((status = krb5_copy_principal(krb_context,
526					(*ticket)->enc_part2->client,
527					client)))
528		return (status);
529
530	/* Get the Unix username of the remote user */
531	getstr(f, rusername, sizeof (rusername), "remuser");
532
533	/* Get the Kerberos principal name string of the remote user */
534	if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
535		return (status);
536
537#ifdef DEBUG
538	syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
539	    (krusername != NULL ? krusername : "<unknown>"));
540#endif
541
542	if (encr_flag) {
543		status = krb5_auth_con_getremotesubkey(krb_context,
544						    auth_context,
545						    &session_key);
546		if (status) {
547			syslog(LOG_ERR, "Error getting KRB5 session "
548			    "subkey, exiting");
549			fatal(f, "Error getting KRB5 session subkey, exiting");
550		}
551		/*
552		 * The "new" protocol requires that a subkey be sent.
553		 */
554		if (session_key == NULL &&
555		    kcmd_protocol == KCMD_NEW_PROTOCOL) {
556			syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
557			fatal(f, "No KRB5 session subkey sent, exiting");
558		}
559		/*
560		 * The "old" protocol does not permit an authenticator subkey.
561		 * The key is taken from the ticket instead (see below).
562		 */
563		if (session_key != NULL &&
564		    kcmd_protocol == KCMD_OLD_PROTOCOL) {
565			syslog(LOG_ERR, "KRB5 session subkey not permitted "
566			    "with old KCMD protocol, exiting");
567
568			fatal(f, "KRB5 session subkey not permitted "
569			    "with old KCMD protocol, exiting");
570		}
571		/*
572		 * If no key at this point, use the session key from
573		 * the ticket.
574		 */
575		if (session_key == NULL) {
576			/*
577			 * Save the session key so we can configure the crypto
578			 * module later.
579			 */
580			status = krb5_copy_keyblock(krb_context,
581					    (*ticket)->enc_part2->session,
582					    &session_key);
583			if (status) {
584				syslog(LOG_ERR, "krb5_copy_keyblock failed");
585				fatal(f, "krb5_copy_keyblock failed");
586			}
587		}
588		/*
589		 * If session key still cannot be found, we must
590		 * exit because encryption is required here
591		 * when encr_flag (-x) is set.
592		 */
593		if (session_key == NULL) {
594			syslog(LOG_ERR, "Could not find an encryption key,"
595				    "exiting");
596			fatal(f, "Encryption required but key not found, "
597			    "exiting");
598		}
599	}
600	/*
601	 * Use krb5_read_message to read the principal stuff.
602	 */
603	if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
604					&inbuf)))
605		fatal(f, "Error reading krb5 message");
606
607	if (inbuf.length) { /* Forwarding being done, read creds */
608		krb5_creds **creds = NULL;
609
610		if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
611					    &creds, NULL)) {
612			if (rcache)
613				(void) krb5_rc_close(krb_context, rcache);
614			krb5_free_creds(krb_context, *creds);
615			fatal(f, "Can't get forwarded credentials");
616		}
617
618		/* Store the forwarded creds in the ccache */
619		if (status = store_forw_creds(krb_context,
620					    creds, *ticket, lusername,
621					    &ccache)) {
622			if (rcache)
623				(void) krb5_rc_close(krb_context, rcache);
624			krb5_free_creds(krb_context, *creds);
625			fatal(f, "Can't store forwarded credentials");
626		}
627		krb5_free_creds(krb_context, *creds);
628	}
629
630	if (rcache)
631		(void) krb5_rc_close(krb_context, rcache);
632
633	return (status);
634}
635
636static void
637do_krb_login(int f, char *host_addr, char *hostname,
638	    krb5_context krb_context, int encr_flag,
639	    krb5_keytab keytab)
640{
641	krb5_error_code status;
642	uint_t valid_checksum;
643	krb5_ticket	*ticket = NULL;
644	int auth_sys = 0;
645	int auth_sent = 0;
646	krb5_principal client = NULL;
647
648	if (getuid())
649		fatal(f, "Error authorizing KRB5 connection, "
650			"server lacks privilege");
651
652	status = recvauth(f, krb_context, &valid_checksum, &ticket,
653			&auth_sys, &client, encr_flag, keytab);
654	if (status) {
655		if (ticket)
656			krb5_free_ticket(krb_context, ticket);
657		if (status != 255)
658			syslog(LOG_ERR,
659			    "Authentication failed from %s(%s): %s\n",
660			    host_addr, hostname, error_message(status));
661		fatal(f, "Kerberos authentication failed, exiting");
662	}
663
664	if (auth_sys != KRB5_RECVAUTH_V5) {
665		fatal(f, "This server only supports Kerberos V5");
666	} else {
667		/*
668		 * Authenticated OK, now check authorization.
669		 */
670		if (client && krb5_kuserok(krb_context, client, lusername))
671		    auth_sent = KRB5_RECVAUTH_V5;
672	}
673
674	if (auth_sent == KRB5_RECVAUTH_V5 &&
675	    kcmd_protocol == KCMD_OLD_PROTOCOL &&
676	    chksum_flag == CHKSUM_REQUIRED && !valid_checksum) {
677		syslog(LOG_ERR, "Client did not supply required checksum, "
678		    "connection rejected.");
679		fatal(f, "Client did not supply required checksum, "
680		    "connection rejected.");
681	}
682
683	if (auth_sys != auth_sent) {
684		char *msg_fail = NULL;
685		int msgsize = 0;
686
687		if (ticket)
688			krb5_free_ticket(krb_context, ticket);
689
690		if (krusername != NULL) {
691			/*
692			 * msgsize must be enough to hold
693			 * krusername, lusername and a brief
694			 * message describing the failure.
695			 */
696			msgsize = strlen(krusername) +
697				strlen(lusername) + 80;
698			msg_fail = (char *)malloc(msgsize);
699		}
700		if (msg_fail == NULL) {
701			syslog(LOG_ERR, "User is not authorized to login to "
702			    "specified account");
703
704			fatal(f, "User is not authorized to login to "
705			    "specified account");
706		}
707		if (auth_sent != 0)
708			(void) snprintf(msg_fail, msgsize,
709					"Access denied because of improper "
710					"KRB5 credentials");
711		else
712			(void) snprintf(msg_fail, msgsize,
713					"User %s is not authorized to login "
714					"to account %s",
715					krusername, lusername);
716		syslog(LOG_ERR, "%s", msg_fail);
717		fatal(f, msg_fail);
718	}
719}
720
721/*
722 * stop_stream
723 *
724 * Utility routine to send a CRYPTIOCSTOP ioctl to the
725 * crypto module(cryptmod).
726 */
727static void
728stop_stream(int fd, int dir)
729{
730	struct strioctl  crioc;
731	uint32_t stopdir = dir;
732
733	crioc.ic_cmd = CRYPTIOCSTOP;
734	crioc.ic_timout = -1;
735	crioc.ic_len = sizeof (stopdir);
736	crioc.ic_dp = (char *)&stopdir;
737
738	if (ioctl(fd, I_STR, &crioc))
739		syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m");
740}
741
742/*
743 * start_stream
744 *
745 * Utility routine to send a CRYPTIOCSTART ioctl to the
746 * crypto module(cryptmod).  This routine may contain optional
747 * payload data that the cryptmod will interpret as bytes that
748 * need to be decrypted and sent back up to the application
749 * via the data stream.
750 */
751static void
752start_stream(int fd, int dir)
753{
754	struct strioctl crioc;
755	uint32_t iocval;
756	size_t datalen = 0;
757	char *data = NULL;
758
759	if (dir == CRYPT_DECRYPT) {
760		iocval = CRYPTIOCSTARTDEC;
761
762		/* Look for data not yet processed */
763		if (ioctl(fd, I_NREAD, &datalen) < 0) {
764			syslog(LOG_ERR, "I_NREAD returned error %m");
765			datalen = 0;
766		} else {
767			if (datalen > 0) {
768				data = malloc(datalen);
769				if (data != NULL) {
770					int nbytes = read(fd, data, datalen);
771					datalen = nbytes;
772				} else {
773					syslog(LOG_ERR,
774						"malloc error (%d bytes)",
775						datalen);
776					datalen = 0;
777				}
778			} else {
779				datalen = 0;
780			}
781		}
782	} else {
783		iocval = CRYPTIOCSTARTENC;
784	}
785
786	crioc.ic_cmd = iocval;
787	crioc.ic_timout = -1;
788	crioc.ic_len = datalen;
789	crioc.ic_dp = data;
790
791	if (ioctl(fd, I_STR, &crioc))
792		syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m");
793
794	if (data != NULL)
795		free(data);
796}
797
798static int
799configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec,
800		uint_t iv_usage)
801{
802	struct cr_info_t setup_info;
803	struct strioctl crioc;
804	int retval = 0;
805
806	switch (skey->enctype) {
807	case ENCTYPE_DES_CBC_CRC:
808		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC;
809		break;
810	case ENCTYPE_DES_CBC_MD5:
811		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5;
812		break;
813	case ENCTYPE_DES_CBC_RAW:
814		setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL;
815		break;
816	case ENCTYPE_DES3_CBC_SHA1:
817		setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1;
818		break;
819	case ENCTYPE_ARCFOUR_HMAC:
820		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5;
821		break;
822	case ENCTYPE_ARCFOUR_HMAC_EXP:
823		setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP;
824		break;
825	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
826		setup_info.crypto_method = CRYPT_METHOD_AES128;
827		break;
828	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
829		setup_info.crypto_method = CRYPT_METHOD_AES256;
830		break;
831	default:
832		syslog(LOG_ERR, "Enctype in kerberos session key "
833		    "is not supported by crypto module(%d)",
834		    skey->enctype);
835		return (-1);
836	}
837	if (ivec == NULL || ivec->length == 0) {
838		(void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec));
839
840		if (skey->enctype != ENCTYPE_ARCFOUR_HMAC &&
841		    skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP)
842			/* Kerberos IVs are 8 bytes long for DES keys */
843			setup_info.iveclen = KRB5_MIT_DES_KEYSIZE;
844		else
845			setup_info.iveclen = 0;
846	} else {
847		(void) memcpy(&setup_info.ivec, ivec->data, ivec->length);
848		setup_info.iveclen = ivec->length;
849	}
850
851	setup_info.ivec_usage = iv_usage;
852	(void) memcpy(&setup_info.key, skey->contents, skey->length);
853
854	setup_info.keylen = skey->length;
855	setup_info.direction_mask = dir;
856	/*
857	 * R* commands get special handling by crypto module -
858	 * 4 byte length field is used before each encrypted block
859	 * of data.
860	 */
861	setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ?
862				CRYPTOPT_RCMD_MODE_V1 :
863				CRYPTOPT_RCMD_MODE_V2);
864
865	crioc.ic_cmd = CRYPTIOCSETUP;
866	crioc.ic_timout = -1;
867	crioc.ic_len = sizeof (setup_info);
868	crioc.ic_dp = (char *)&setup_info;
869
870	if (ioctl(fd, I_STR, &crioc)) {
871		syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m");
872		retval = -1;
873	}
874	return (retval);
875}
876
877static krb5_error_code
878krb5_compat_recvauth(krb5_context context,
879		    krb5_auth_context *auth_context,
880		    krb5_pointer fdp,	/* IN */
881		    krb5_principal server,	/* IN */
882		    krb5_int32 flags,	/* IN */
883		    krb5_keytab keytab,	/* IN */
884		    krb5_ticket **ticket, /* OUT */
885		    krb5_int32 *auth_sys, /* OUT */
886		    krb5_data *version)   /* OUT */
887{
888	krb5_int32 vlen;
889	char	*buf;
890	int	len, length;
891	krb5_int32	retval;
892	int		fd = *((int *)fdp);
893
894	if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4)
895		return ((retval < 0) ? errno : ECONNABORTED);
896
897	/*
898	 * Assume that we're talking to a V5 recvauth; read in the
899	 * the version string, and make sure it matches.
900	 */
901	len = (int)ntohl(vlen);
902
903	if (len < 0 || len > 255)
904		return (KRB5_SENDAUTH_BADAUTHVERS);
905
906	buf = malloc(len);
907	if (buf == NULL)
908		return (ENOMEM);
909
910	length = krb5_net_read(context, fd, buf, len);
911	if (len != length) {
912		krb5_xfree(buf);
913		return ((len < 0) ? errno : ECONNABORTED);
914	}
915
916	if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) {
917		krb5_xfree(buf);
918		return (KRB5_SENDAUTH_BADAUTHVERS);
919	}
920	krb5_xfree(buf);
921
922	*auth_sys = KRB5_RECVAUTH_V5;
923
924	retval = krb5_recvauth_version(context, auth_context, fdp,
925				    server, flags | KRB5_RECVAUTH_SKIP_VERSION,
926				    keytab, ticket, version);
927
928	return (retval);
929}
930
931
932static void
933doit(int f,
934	struct sockaddr_storage *fromp,
935	krb5_context krb_context,
936	int encr_flag,
937	krb5_keytab keytab)
938{
939	int p, t, on = 1;
940	char c;
941	char abuf[INET6_ADDRSTRLEN];
942	struct sockaddr_in *sin;
943	struct sockaddr_in6 *sin6;
944	int fromplen;
945	in_port_t port;
946	struct termios tp;
947	boolean_t bad_port;
948	boolean_t no_name;
949	char rhost_addra[INET6_ADDRSTRLEN];
950
951	if (!(rlbuf = malloc(BUFSIZ))) {
952		syslog(LOG_ERR, "rlbuf malloc failed\n");
953		exit(EXIT_FAILURE);
954	}
955	(void) alarm(60);
956	if (read(f, &c, 1) != 1 || c != 0) {
957		syslog(LOG_ERR, "failed to receive protocol zero byte\n");
958		exit(EXIT_FAILURE);
959	}
960	(void) alarm(0);
961	if (fromp->ss_family == AF_INET) {
962		sin = (struct sockaddr_in *)fromp;
963		port = sin->sin_port = ntohs((ushort_t)sin->sin_port);
964		fromplen = sizeof (struct sockaddr_in);
965
966		if (!inet_ntop(AF_INET, &sin->sin_addr,
967			    rhost_addra, sizeof (rhost_addra)))
968			goto badconversion;
969	} else if (fromp->ss_family == AF_INET6) {
970		sin6 = (struct sockaddr_in6 *)fromp;
971		port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port);
972		fromplen = sizeof (struct sockaddr_in6);
973
974		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
975			struct in_addr ipv4_addr;
976
977			IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
978					    &ipv4_addr);
979			if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra,
980				    sizeof (rhost_addra)))
981				goto badconversion;
982		} else {
983			if (!inet_ntop(AF_INET6, &sin6->sin6_addr,
984				    rhost_addra, sizeof (rhost_addra)))
985				goto badconversion;
986		}
987	} else {
988		syslog(LOG_ERR, "unknown address family %d\n",
989		    fromp->ss_family);
990		fatal(f, "Permission denied");
991	}
992
993	/*
994	 * Allow connections only from the "ephemeral" reserved
995	 * ports(ports 512 - 1023) by checking the remote port
996	 * because other utilities(e.g. in.ftpd) can be used to
997	 * allow a unprivileged user to originate a connection
998	 * from a privileged port and provide untrustworthy
999	 * authentication.
1000	 */
1001	bad_port = (use_auth != KRB5_RECVAUTH_V5 &&
1002		    (port >= (in_port_t)IPPORT_RESERVED) ||
1003		    (port < (in_port_t)(IPPORT_RESERVED/2)));
1004	no_name = getnameinfo((const struct sockaddr *) fromp,
1005			    fromplen, hostname, sizeof (hostname),
1006			    NULL, 0, 0) != 0;
1007
1008	if (no_name || bad_port) {
1009		(void) strlcpy(abuf, rhost_addra, sizeof (abuf));
1010		/* If no host name, use IP address for name later on. */
1011		if (no_name)
1012			(void) strlcpy(hostname, abuf, sizeof (hostname));
1013	}
1014
1015	if (!no_name) {
1016		/*
1017		 * Even if getnameinfo() succeeded, we still have to check
1018		 * for spoofing.
1019		 */
1020		check_address("rlogind", fromp, sin, sin6, rhost_addra,
1021		    hostname, sizeof (hostname));
1022	}
1023
1024	if (bad_port) {
1025		if (no_name)
1026			syslog(LOG_NOTICE,
1027			    "connection from %s - bad port\n",
1028			    abuf);
1029		else
1030			syslog(LOG_NOTICE,
1031			    "connection from %s(%s) - bad port\n",
1032			    hostname, abuf);
1033		fatal(f, "Permission denied");
1034	}
1035
1036	if (use_auth == KRB5_RECVAUTH_V5) {
1037		do_krb_login(f, rhost_addra, hostname,
1038			    krb_context, encr_flag, keytab);
1039		if (krusername != NULL && strlen(krusername)) {
1040			/*
1041			 * Kerberos Authentication succeeded,
1042			 * so set the proper program name to use
1043			 * with pam (important during 'cleanup'
1044			 * routine later).
1045			 */
1046			pam_prog_name = KRB5_PROG_NAME;
1047		}
1048	}
1049
1050	if (write(f, "", 1) != 1) {
1051		syslog(LOG_NOTICE,
1052		    "send of the zero byte(to %s) failed:"
1053		    " cannot start data transfer mode\n",
1054		    (no_name ? abuf : hostname));
1055		exit(EXIT_FAILURE);
1056	}
1057	if ((p = open("/dev/ptmx", O_RDWR)) == -1)
1058		fatalperror(f, "cannot open /dev/ptmx");
1059	if (grantpt(p) == -1)
1060		fatal(f, "could not grant slave pty");
1061	if (unlockpt(p) == -1)
1062		fatal(f, "could not unlock slave pty");
1063	if ((line = ptsname(p)) == NULL)
1064		fatal(f, "could not enable slave pty");
1065	if ((t = open(line, O_RDWR)) == -1)
1066		fatal(f, "could not open slave pty");
1067	if (ioctl(t, I_PUSH, "ptem") == -1)
1068		fatalperror(f, "ioctl I_PUSH ptem");
1069	if (ioctl(t, I_PUSH, "ldterm") == -1)
1070		fatalperror(f, "ioctl I_PUSH ldterm");
1071	if (ioctl(t, I_PUSH, "ttcompat") == -1)
1072		fatalperror(f, "ioctl I_PUSH ttcompat");
1073	/*
1074	 * POP the sockmod and push the rlmod module.
1075	 *
1076	 * Note that sockmod has to be removed since readstream assumes
1077	 * a "raw" TPI endpoint(e.g. it uses getmsg).
1078	 */
1079	if (removemod(f, "sockmod") < 0)
1080		fatalperror(f, "couldn't remove sockmod");
1081
1082	if (encr_flag) {
1083		if (ioctl(f, I_PUSH, "cryptmod") < 0)
1084		    fatalperror(f, "ioctl I_PUSH rlmod");
1085
1086	}
1087
1088	if (ioctl(f, I_PUSH, "rlmod") < 0)
1089		fatalperror(f, "ioctl I_PUSH rlmod");
1090
1091	if (encr_flag) {
1092		/*
1093		 * Make sure rlmod will pass unrecognized IOCTLs to cryptmod
1094		 */
1095		uchar_t passthru = 1;
1096		struct strioctl rlmodctl;
1097
1098		rlmodctl.ic_cmd = CRYPTPASSTHRU;
1099		rlmodctl.ic_timout = -1;
1100		rlmodctl.ic_len = sizeof (uchar_t);
1101		rlmodctl.ic_dp = (char *)&passthru;
1102
1103		if (ioctl(f, I_STR, &rlmodctl) < 0)
1104			fatal(f, "ioctl CRYPTPASSTHRU failed\n");
1105	}
1106
1107	/*
1108	 * readstream will do a getmsg till it receives
1109	 * M_PROTO type T_DATA_REQ from rloginmodopen()
1110	 * indicating all data on the stream prior to pushing rlmod has
1111	 * been drained at the stream head.
1112	 */
1113	if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0)
1114		fatalperror(f, "readstream failed");
1115	/*
1116	 * Make sure the pty doesn't modify the strings passed
1117	 * to login as part of the "rlogin protocol."  The login
1118	 * program should set these flags to apropriate values
1119	 * after it has read the strings.
1120	 */
1121	if (ioctl(t, TCGETS, &tp) == -1)
1122		fatalperror(f, "ioctl TCGETS");
1123	tp.c_lflag &= ~(ECHO|ICANON);
1124	tp.c_oflag &= ~(XTABS|OCRNL);
1125	tp.c_iflag &= ~(IGNPAR|ICRNL);
1126	if (ioctl(t, TCSETS, &tp) == -1)
1127		fatalperror(f, "ioctl TCSETS");
1128
1129	/*
1130	 * System V ptys allow the TIOC{SG}WINSZ ioctl to be
1131	 * issued on the master side of the pty.  Luckily, that's
1132	 * the only tty ioctl we need to do do, so we can close the
1133	 * slave side in the parent process after the fork.
1134	 */
1135	(void) ioctl(p, TIOCSWINSZ, &win);
1136
1137	pid = fork();
1138	if (pid < 0)
1139		fatalperror(f, "fork");
1140	if (pid == 0) {
1141		int tt;
1142		struct utmpx ut;
1143
1144		/* System V login expects a utmp entry to already be there */
1145		(void) memset(&ut, 0, sizeof (ut));
1146		(void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user));
1147		(void) strncpy(ut.ut_line, line, sizeof (ut.ut_line));
1148		ut.ut_pid = getpid();
1149		ut.ut_id[0] = 'r';
1150		ut.ut_id[1] = (char)SC_WILDC;
1151		ut.ut_id[2] = (char)SC_WILDC;
1152		ut.ut_id[3] = (char)SC_WILDC;
1153		ut.ut_type = LOGIN_PROCESS;
1154		ut.ut_exit.e_termination = 0;
1155		ut.ut_exit.e_exit = 0;
1156		(void) time(&ut.ut_tv.tv_sec);
1157		if (makeutx(&ut) == NULL)
1158			syslog(LOG_INFO, "in.rlogind:\tmakeutx failed");
1159
1160		/* controlling tty */
1161		if (setsid() == -1)
1162			fatalperror(f, "setsid");
1163		if ((tt = open(line, O_RDWR)) == -1)
1164			fatalperror(f, "could not re-open slave pty");
1165
1166		if (close(p) == -1)
1167			fatalperror(f, "error closing pty master");
1168		if (close(t) == -1)
1169			fatalperror(f, "error closing pty slave"
1170				    " opened before session established");
1171		/*
1172		 * If this fails we may or may not be able to output an
1173		 * error message.
1174		 */
1175		if (close(f) == -1)
1176			fatalperror(f, "error closing deamon stdout");
1177		if (dup2(tt, STDIN_FILENO) == -1 ||
1178		    dup2(tt, STDOUT_FILENO) == -1 ||
1179		    dup2(tt, STDERR_FILENO) == -1)
1180			exit(EXIT_FAILURE);	/* Disaster! No stderr! */
1181
1182		(void) close(tt);
1183
1184		if (use_auth == KRB5_RECVAUTH_V5 &&
1185		    krusername != NULL && strlen(krusername)) {
1186			(void) execl(LOGIN_PROGRAM, "login",
1187				    "-d", line,
1188				    "-r", hostname,
1189				    "-u", krusername, /* KRB5 principal name */
1190				    "-s", pam_prog_name,
1191				    "-t", term,	/* Remote Terminal */
1192				    "-U", rusername,	/* Remote User */
1193				    "-R", KRB5_REPOSITORY_NAME,
1194				    lusername,  /* local user */
1195				    NULL);
1196		} else {
1197			(void) execl(LOGIN_PROGRAM, "login",
1198				"-d", line,
1199				"-r", hostname,
1200				NULL);
1201		}
1202
1203		fatalperror(STDERR_FILENO, "/bin/login");
1204		/*NOTREACHED*/
1205	}
1206	(void) close(t);
1207	(void) ioctl(f, FIONBIO, &on);
1208	(void) ioctl(p, FIONBIO, &on);
1209
1210	/*
1211	 * Must ignore SIGTTOU, otherwise we'll stop
1212	 * when we try and set slave pty's window shape
1213	 * (our controlling tty is the master pty).
1214	 * Likewise, we don't want any of the tty-generated
1215	 * signals from chars passing through.
1216	 */
1217	(void) sigset(SIGTSTP, SIG_IGN);
1218	(void) sigset(SIGINT, SIG_IGN);
1219	(void) sigset(SIGQUIT, SIG_IGN);
1220	(void) sigset(SIGTTOU, SIG_IGN);
1221	(void) sigset(SIGTTIN, SIG_IGN);
1222	(void) sigset(SIGCHLD, cleanup);
1223	(void) setpgrp();
1224
1225	if (encr_flag) {
1226		krb5_data ivec, *ivptr;
1227		uint_t ivec_usage;
1228		stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT);
1229
1230		/*
1231		 * Configure the STREAMS crypto module.  For now,
1232		 * don't use any IV parameter.  KCMDV0.2 support
1233		 * will require the use of Initialization Vectors
1234		 * for both encrypt and decrypt modes.
1235		 */
1236		if (kcmd_protocol == KCMD_OLD_PROTOCOL) {
1237			if (session_key->enctype == ENCTYPE_DES_CBC_CRC) {
1238				/*
1239				 * This is gross but necessary for MIT compat.
1240				 */
1241				ivec.length = session_key->length;
1242				ivec.data = (char *)session_key->contents;
1243				ivec_usage = IVEC_REUSE;
1244				ivptr = &ivec;
1245			} else {
1246				ivptr = NULL; /* defaults to all 0's */
1247				ivec_usage = IVEC_NEVER;
1248			}
1249			/*
1250			 * configure both sides of stream together
1251			 * since they share the same IV.
1252			 * This is what makes the OLD KCMD protocol
1253			 * less secure than the newer one - Bad ivecs.
1254			 */
1255			if (configure_stream(f, session_key,
1256				CRYPT_ENCRYPT|CRYPT_DECRYPT,
1257				ivptr, ivec_usage) != 0)
1258				fatal(f, "Cannot initialize encryption -"
1259					" exiting.\n");
1260		} else {
1261			size_t blocksize;
1262			if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC ||
1263			    session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
1264				if (configure_stream(f, session_key,
1265					CRYPT_ENCRYPT|CRYPT_DECRYPT,
1266					NULL, IVEC_NEVER) != 0)
1267					fatal(f,
1268					"Cannot initialize encryption -"
1269					" exiting.\n");
1270				goto startcrypto;
1271			}
1272			if (krb5_c_block_size(krb_context,
1273					    session_key->enctype,
1274					    &blocksize)) {
1275				syslog(LOG_ERR, "Cannot determine blocksize "
1276				    "for encryption type %d",
1277				    session_key->enctype);
1278				fatal(f, "Cannot determine blocksize "
1279				    "for encryption - exiting.\n");
1280			}
1281			ivec.data = (char *)malloc(blocksize);
1282			ivec.length = blocksize;
1283			if (ivec.data == NULL)
1284				fatal(f, "memory error - exiting\n");
1285			/*
1286			 * Following MIT convention -
1287			 *   encrypt IV = 0x01 x blocksize
1288			 *   decrypt IV = 0x00 x blocksize
1289			 *   ivec_usage = IVEC_ONETIME
1290			 *
1291			 * configure_stream separately for encrypt and
1292			 * decrypt because there are 2 different IVs.
1293			 *
1294			 * AES uses 0's for IV.
1295			 */
1296			if (session_key->enctype ==
1297				ENCTYPE_AES128_CTS_HMAC_SHA1_96 ||
1298			    session_key->enctype ==
1299				ENCTYPE_AES256_CTS_HMAC_SHA1_96)
1300				(void) memset(ivec.data, 0x00, blocksize);
1301			else
1302				(void) memset(ivec.data, 0x01, blocksize);
1303			if (configure_stream(f, session_key, CRYPT_ENCRYPT,
1304				&ivec, IVEC_ONETIME) != 0)
1305				fatal(f, "Cannot initialize encryption -"
1306					" exiting.\n");
1307			(void) memset(ivec.data, 0x00, blocksize);
1308			if (configure_stream(f, session_key, CRYPT_DECRYPT,
1309				&ivec, IVEC_ONETIME) != 0)
1310				fatal(f, "Cannot initialize encryption -"
1311					" exiting.\n");
1312
1313			(void) free(ivec.data);
1314		}
1315startcrypto:
1316		start_stream(f, CRYPT_ENCRYPT);
1317		start_stream(f, CRYPT_DECRYPT);
1318	}
1319	protocol(f, p, encr_flag);
1320	cleanup(0);
1321	/*NOTREACHED*/
1322
1323badconversion:
1324	fatalperror(f, "address conversion");
1325	/*NOTREACHED*/
1326}
1327
1328/*
1329 * rlogin "protocol" machine.
1330 */
1331static void
1332protocol(int f, int p, int encr_flag)
1333{
1334	struct	stat	buf;
1335	struct 	protocol_arg	rloginp;
1336	struct	strioctl	rloginmod;
1337	int	ptmfd;	/* fd of logindmux coneected to ptmx */
1338	int	netfd;	/* fd of logindmux connected to netf */
1339	static uchar_t	oobdata[] = {TIOCPKT_WINDOW};
1340
1341	/* indicate new rlogin */
1342	if (send_oob(f, oobdata, 1) < 0)
1343		fatalperror(f, "send_oob");
1344	/*
1345	 * We cannot send the SECURE_MSG until after the
1346	 * client has been signaled with the oobdata (above).
1347	 */
1348	if (encr_flag) {
1349		if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0)
1350			fatalperror(f, "Error writing SECURE message");
1351	}
1352
1353	/*
1354	 * Open logindmux driver and link netf and ptmx
1355	 * underneath logindmux.
1356	 */
1357	if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1)
1358		fatalperror(f, "open /dev/logindmux");
1359
1360	if ((netfd = open("/dev/logindmux", O_RDWR)) == -1)
1361		fatalperror(f, "open /dev/logindmux");
1362
1363	if (ioctl(ptmfd, I_LINK, p) < 0)
1364		fatal(f, "ioctl I_LINK of /dev/ptmx failed\n");
1365
1366	if (ioctl(netfd, I_LINK, f) < 0)
1367		fatal(f, "ioctl I_LINK of tcp connection failed\n");
1368
1369	/*
1370	 * Figure out the device number of the ptm's mux fd, and pass that
1371	 * to the net's mux.
1372	 */
1373	if (fstat(ptmfd, &buf) < 0)
1374		fatalperror(f, "cannot determine device number"
1375		    " of pty side of /dev/logindmux");
1376	rloginp.dev = buf.st_rdev;
1377	rloginp.flag = 0;
1378
1379	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
1380	rloginmod.ic_timout = -1;
1381	rloginmod.ic_len = sizeof (struct protocol_arg);
1382	rloginmod.ic_dp = (char *)&rloginp;
1383
1384	if (ioctl(netfd, I_STR, &rloginmod) < 0)
1385		fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n");
1386
1387	/*
1388	 * Figure out the device number of the net's mux fd, and pass that
1389	 * to the ptm's mux.
1390	 */
1391	if (fstat(netfd, &buf))
1392		fatalperror(f, "cannot determine device number"
1393		    " of network side of /dev/logindmux");
1394	rloginp.dev = buf.st_rdev;
1395	rloginp.flag = 1;
1396
1397	rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
1398	rloginmod.ic_timout = -1;
1399	rloginmod.ic_len = sizeof (struct protocol_arg);
1400	rloginmod.ic_dp = (char *)&rloginp;
1401
1402	if (ioctl(ptmfd, I_STR, &rloginmod) < 0)
1403		fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n");
1404	/*
1405	 * Send an ioctl type RL_IOC_ENABLE to reenable the
1406	 * message queue and reinsert the data read from streamhead
1407	 * at the time of pushing rloginmod module.
1408	 * We need to send this ioctl even if no data was read earlier
1409	 * since we need to reenable the message queue of rloginmod module.
1410	 */
1411	rloginmod.ic_cmd = RL_IOC_ENABLE;
1412	rloginmod.ic_timout = -1;
1413	if (nsize) {
1414		rloginmod.ic_len = nsize;
1415		rloginmod.ic_dp = rlbuf;
1416	} else {
1417		rloginmod.ic_len = 0;
1418		rloginmod.ic_dp = NULL;
1419	}
1420
1421	if (ioctl(netfd, I_STR, &rloginmod) < 0)
1422		fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n");
1423
1424	/*
1425	 * User level daemon now pauses till the shell exits.
1426	 */
1427	(void) pause();
1428}
1429
1430/* This is a signal handler, hence the dummy argument */
1431/*ARGSUSED*/
1432static void
1433cleanup(int dummy)
1434{
1435	rmut();
1436	exit(EXIT_FAILURE);
1437	/*NOTREACHED*/
1438}
1439
1440/*
1441 * TPI style replacement for socket send() primitive, so we don't require
1442 * sockmod to be on the stream.
1443 */
1444static int
1445send_oob(int fd, void *ptr, size_t count)
1446{
1447	struct T_exdata_req exd_req;
1448	struct strbuf hdr, dat;
1449	int ret;
1450
1451	exd_req.PRIM_type = T_EXDATA_REQ;
1452	exd_req.MORE_flag = 0;
1453
1454	hdr.buf = (char *)&exd_req;
1455	hdr.len = sizeof (exd_req);
1456
1457	dat.buf = ptr;
1458	dat.len = count;
1459
1460	ret = putmsg(fd, &hdr, &dat, 0);
1461	if (ret == 0)
1462		ret = count;
1463	return (ret);
1464}
1465
1466static void
1467fatal(int fd, const char *msg)
1468{
1469	char *bufp;
1470	size_t len = strlen(msg) + 16;		/* enough for our wrapper */
1471
1472	bufp = alloca(len);
1473	/* ASCII 001 is the error indicator */
1474	len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg);
1475	(void) write(fd, bufp, len);
1476	exit(EXIT_FAILURE);
1477	/*NOTREACHED*/
1478}
1479
1480/*PRINTFLIKE2*/
1481static void
1482fatalperror(int fd, const char *msg)
1483{
1484	char *bufp;
1485	const char *errstr;
1486	int save_errno = errno;
1487	size_t len = strlen(msg);
1488
1489	if ((errstr = strerror(save_errno))) {
1490		len += strlen(errstr) + 3;	/* 3 for ": " and \0 below */
1491		bufp = alloca(len);
1492		(void) snprintf(bufp, len, "%s: %s", msg, errstr);
1493	} else {
1494		const char fmt[] = "%s: Error %d";
1495
1496		/* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */
1497		len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3);
1498		bufp = alloca(len);
1499		(void) snprintf(bufp, len, fmt, msg, save_errno);
1500	}
1501	fatal(fd, bufp);
1502	/*NOTREACHED*/
1503}
1504
1505static void
1506rmut(void)
1507{
1508	pam_handle_t *pamh;
1509	struct utmpx *up;
1510	char user[sizeof (up->ut_user) + 1];
1511	char ttyn[sizeof (up->ut_line) + 1];
1512	char rhost[sizeof (up->ut_host) + 1];
1513
1514	/* while cleaning up dont allow disruption */
1515	(void) sigset(SIGCHLD, SIG_IGN);
1516
1517	setutxent();
1518	while (up = getutxent()) {
1519		if (up->ut_pid == pid) {
1520			if (up->ut_type == DEAD_PROCESS)
1521				break;		/* Cleaned up elsewhere. */
1522
1523			/*
1524			 * call pam_close_session if login changed
1525			 * the utmpx user entry from type LOGIN_PROCESS
1526			 * to type USER_PROCESS, which happens
1527			 * after pam_open_session is called.
1528			 */
1529			if (up->ut_type == USER_PROCESS) {
1530				(void) strlcpy(user, up->ut_user,
1531					    sizeof (user));
1532				(void) strlcpy(ttyn, up->ut_line,
1533					    sizeof (ttyn));
1534				(void) strlcpy(rhost, up->ut_host,
1535					    sizeof (rhost));
1536
1537				/*
1538				 * Use the same pam_prog_name that
1539				 * 'login' used.
1540				 */
1541				if ((pam_start(pam_prog_name, user,  NULL,
1542					    &pamh))
1543				    == PAM_SUCCESS) {
1544					(void) pam_set_item(pamh, PAM_TTY,
1545							    ttyn);
1546					(void) pam_set_item(pamh, PAM_RHOST,
1547							    rhost);
1548					(void) pam_close_session(pamh, 0);
1549					(void) pam_end(pamh, PAM_SUCCESS);
1550				}
1551			}
1552
1553			up->ut_type = DEAD_PROCESS;
1554			up->ut_exit.e_termination = WTERMSIG(0);
1555			up->ut_exit.e_exit = WEXITSTATUS(0);
1556			(void) time(&up->ut_tv.tv_sec);
1557
1558			if (modutx(up) == NULL) {
1559				/*
1560				 * Since modutx failed we'll
1561				 * write out the new entry
1562				 * ourselves.
1563				 */
1564				(void) pututxline(up);
1565				updwtmpx("wtmpx", up);
1566			}
1567			break;
1568		}
1569	}
1570
1571	endutxent();
1572
1573	(void) sigset(SIGCHLD, cleanup);
1574}
1575
1576static int
1577readstream(int fd, char *buf, int size)
1578{
1579	struct strbuf ctlbuf, datbuf;
1580	union T_primitives tpi;
1581	int	nbytes = 0;
1582	int	ret = 0;
1583	int	flags = 0;
1584	int	bufsize = size;
1585	int	nread;
1586
1587	(void) memset(&ctlbuf, 0, sizeof (ctlbuf));
1588	(void) memset(&datbuf, 0, sizeof (datbuf));
1589
1590	ctlbuf.buf = (char *)&tpi;
1591	ctlbuf.maxlen = sizeof (tpi);
1592	datbuf.buf = buf;
1593	datbuf.maxlen = size;
1594
1595	for (;;) {
1596		if (ioctl(fd, I_NREAD, &nread) < 0) {
1597			syslog(LOG_ERR, "I_NREAD returned error %m");
1598			return (-1);
1599		}
1600		if (nread + nbytes > bufsize) {
1601			buf = (char *)realloc(buf, (unsigned)(bufsize + nread));
1602			if (buf == NULL) {
1603				syslog(LOG_WARNING,
1604				    "buffer allocation failed\n");
1605				return (-1);
1606			}
1607			bufsize += nread;
1608			rlbuf = buf;
1609			datbuf.buf = buf + nbytes;
1610		}
1611		datbuf.maxlen = bufsize - nbytes;
1612		ret = getmsg(fd, &ctlbuf, &datbuf, &flags);
1613		if (ret < 0) {
1614			syslog(LOG_ERR, "getmsg failed error %m");
1615			return (-1);
1616		}
1617		if ((ctlbuf.len == 0) && (datbuf.len == 0)) {
1618			/*
1619			 * getmsg() returned no data - this indicates
1620			 * that the connection is closing down.
1621			 */
1622			cleanup(0);
1623		}
1624		if (ctlbuf.len <= 0) {
1625			nbytes += datbuf.len;
1626			datbuf.buf += datbuf.len;
1627			continue;
1628		}
1629		if (tpi.type == T_DATA_REQ) {
1630			return (nbytes);
1631		}
1632		if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND))
1633			cleanup(0);
1634	}
1635}
1636
1637/*
1638 * Verify that the named module is at the top of the stream
1639 * and then pop it off.
1640 */
1641static int
1642removemod(int f, char *modname)
1643{
1644	char topmodname[BUFSIZ];
1645
1646	if (ioctl(f, I_LOOK, topmodname) < 0)
1647		return (-1);
1648	if (strcmp(modname, topmodname) != 0) {
1649		errno = ENXIO;
1650		return (-1);
1651	}
1652	if (ioctl(f, I_POP, 0) < 0)
1653		return (-1);
1654	return (0);
1655}
1656