10Sstevel@tonic-gate /*
2*11415SSurya.Prakki@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
30Sstevel@tonic-gate * Use is subject to license terms.
40Sstevel@tonic-gate */
50Sstevel@tonic-gate
60Sstevel@tonic-gate /* Copyright(c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
70Sstevel@tonic-gate /* All Rights Reserved */
80Sstevel@tonic-gate
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate * Copyright (c) 1983 The Regents of the University of California.
110Sstevel@tonic-gate * All rights reserved.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted
140Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are
150Sstevel@tonic-gate * duplicated in all such forms and that any documentation,
160Sstevel@tonic-gate * advertising materials, and other materials related to such
170Sstevel@tonic-gate * distribution and use acknowledge that the software was developed
180Sstevel@tonic-gate * by the University of California, Berkeley. The name of the
190Sstevel@tonic-gate * University may not be used to endorse or promote products derived
200Sstevel@tonic-gate * from this software without specific prior written permission.
210Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
220Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
230Sstevel@tonic-gate * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * remote login server:
280Sstevel@tonic-gate * remuser\0
290Sstevel@tonic-gate * locuser\0
300Sstevel@tonic-gate * terminal info\0
310Sstevel@tonic-gate * data
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <time.h>
350Sstevel@tonic-gate #include <sys/types.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/socket.h>
380Sstevel@tonic-gate #include <sys/wait.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <netinet/in.h>
410Sstevel@tonic-gate
420Sstevel@tonic-gate #include <errno.h>
430Sstevel@tonic-gate #include <signal.h>
440Sstevel@tonic-gate #include <fcntl.h>
450Sstevel@tonic-gate #include <stdio.h>
460Sstevel@tonic-gate #include <netdb.h>
470Sstevel@tonic-gate #include <syslog.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <unistd.h>
500Sstevel@tonic-gate #include <stdlib.h>
510Sstevel@tonic-gate #include <alloca.h>
520Sstevel@tonic-gate #include <stropts.h>
530Sstevel@tonic-gate #include <sac.h> /* for SC_WILDC */
540Sstevel@tonic-gate #include <utmpx.h>
550Sstevel@tonic-gate #include <sys/filio.h>
560Sstevel@tonic-gate #include <sys/logindmux.h>
570Sstevel@tonic-gate #include <sys/rlioctl.h>
580Sstevel@tonic-gate #include <sys/termios.h>
590Sstevel@tonic-gate #include <sys/tihdr.h>
600Sstevel@tonic-gate #include <arpa/inet.h>
610Sstevel@tonic-gate #include <security/pam_appl.h>
620Sstevel@tonic-gate #include <strings.h>
630Sstevel@tonic-gate #include <com_err.h>
640Sstevel@tonic-gate #include <k5-int.h>
650Sstevel@tonic-gate #include <kcmd.h>
660Sstevel@tonic-gate #include <krb5_repository.h>
670Sstevel@tonic-gate #include <sys/cryptmod.h>
680Sstevel@tonic-gate #include <bsm/adt.h>
693011Sjbeck #include <addr_match.h>
706536Sgtb #include <store_forw_creds.h>
710Sstevel@tonic-gate
720Sstevel@tonic-gate #define KRB5_RECVAUTH_V5 5
730Sstevel@tonic-gate #define UT_NAMESIZE sizeof (((struct utmpx *)0)->ut_name)
740Sstevel@tonic-gate
750Sstevel@tonic-gate static char lusername[UT_NAMESIZE+1];
760Sstevel@tonic-gate static char rusername[UT_NAMESIZE+1];
770Sstevel@tonic-gate static char *krusername = NULL;
780Sstevel@tonic-gate static char term[64];
790Sstevel@tonic-gate
800Sstevel@tonic-gate static krb5_ccache ccache = NULL;
810Sstevel@tonic-gate static krb5_keyblock *session_key = NULL;
820Sstevel@tonic-gate static int chksum_flag = 0;
830Sstevel@tonic-gate static int use_auth = 0;
840Sstevel@tonic-gate static enum kcmd_proto kcmd_protocol;
850Sstevel@tonic-gate #ifdef ALLOW_KCMD_V2
860Sstevel@tonic-gate static krb5_data encr_iv = { NULL, 0 };
870Sstevel@tonic-gate static krb5_data decr_iv = { NULL, 0 };
880Sstevel@tonic-gate #endif /* ALLOW_KCMD_V2 */
890Sstevel@tonic-gate
900Sstevel@tonic-gate #define CHKSUM_REQUIRED 0x01
910Sstevel@tonic-gate #define CHKSUM_IGNORED 0x02
920Sstevel@tonic-gate #define VALID_CHKSUM(x) ((x) == 0 || (x) == CHKSUM_REQUIRED ||\
930Sstevel@tonic-gate (x) == CHKSUM_IGNORED)
940Sstevel@tonic-gate
950Sstevel@tonic-gate #define PWD_IF_FAIL 0x01
960Sstevel@tonic-gate #define PWD_REQUIRED 0x02
970Sstevel@tonic-gate
980Sstevel@tonic-gate #define AUTH_NONE 0x00
990Sstevel@tonic-gate
1000Sstevel@tonic-gate #define ARGSTR "k5exEXciM:s:S:D:"
1010Sstevel@tonic-gate #define DEFAULT_TOS 16
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate #define KRB5_PROG_NAME "krlogin"
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate #define SECURE_MSG "This rlogin session is using encryption " \
1060Sstevel@tonic-gate "for all data transmissions.\r\n"
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate #define KRB_V5_SENDAUTH_VERS "KRB5_SENDAUTH_V1.0"
1090Sstevel@tonic-gate #define KRB5_RECVAUTH_V5 5
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate static krb5_error_code krb5_compat_recvauth(krb5_context context,
1120Sstevel@tonic-gate krb5_auth_context *auth_context,
1130Sstevel@tonic-gate krb5_pointer fdp,
1140Sstevel@tonic-gate krb5_principal server,
1150Sstevel@tonic-gate krb5_int32 flags,
1160Sstevel@tonic-gate krb5_keytab keytab,
1170Sstevel@tonic-gate krb5_ticket **ticket,
1180Sstevel@tonic-gate krb5_int32 *auth_sys,
1190Sstevel@tonic-gate krb5_data *version);
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static void do_krb_login(int, char *, char *, krb5_context, int, krb5_keytab);
1220Sstevel@tonic-gate static int configure_stream(int, krb5_keyblock *, int, krb5_data *, uint_t);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate extern krb5_error_code krb5_read_message(krb5_context, krb5_pointer,
1250Sstevel@tonic-gate krb5_data *);
1260Sstevel@tonic-gate extern krb5_error_code krb5_net_read(krb5_context, int, char *, int);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate #define LOGIN_PROGRAM "/bin/login"
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate #define DEFAULT_PROG_NAME "rlogin"
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate static const char *pam_prog_name = DEFAULT_PROG_NAME;
1330Sstevel@tonic-gate static void rmut(void);
1340Sstevel@tonic-gate static void doit(int, struct sockaddr_storage *, krb5_context, int,
1350Sstevel@tonic-gate krb5_keytab);
1360Sstevel@tonic-gate static void protocol(int, int, int);
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate static int readstream(int, char *, int);
1390Sstevel@tonic-gate static void fatal(int, const char *);
1400Sstevel@tonic-gate static void fatalperror(int, const char *);
1410Sstevel@tonic-gate static int send_oob(int fd, void *ptr, size_t count);
1420Sstevel@tonic-gate static int removemod(int f, char *modname);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate static int
issock(int fd)1450Sstevel@tonic-gate issock(int fd)
1460Sstevel@tonic-gate {
1470Sstevel@tonic-gate struct stat stats;
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate if (fstat(fd, &stats) == -1)
1500Sstevel@tonic-gate return (0);
1510Sstevel@tonic-gate return (S_ISSOCK(stats.st_mode));
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * audit_rlogin_settid stores the terminal id while it is still
1560Sstevel@tonic-gate * available. Subsequent calls to adt_load_hostname() return
1570Sstevel@tonic-gate * the id which is stored here.
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate static int
audit_rlogin_settid(int fd)1600Sstevel@tonic-gate audit_rlogin_settid(int fd) {
1610Sstevel@tonic-gate adt_session_data_t *ah;
1620Sstevel@tonic-gate adt_termid_t *termid;
1630Sstevel@tonic-gate int rc;
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate if ((rc = adt_start_session(&ah, NULL, 0)) == 0) {
1660Sstevel@tonic-gate if ((rc = adt_load_termid(fd, &termid)) == 0) {
1670Sstevel@tonic-gate if ((rc = adt_set_user(ah, ADT_NO_AUDIT,
1680Sstevel@tonic-gate ADT_NO_AUDIT, 0, ADT_NO_AUDIT,
1690Sstevel@tonic-gate termid, ADT_SETTID)) == 0)
1700Sstevel@tonic-gate (void) adt_set_proc(ah);
1710Sstevel@tonic-gate free(termid);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate (void) adt_end_session(ah);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate return (rc);
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* ARGSUSED */
180473Sbw int
main(int argc,char * argv[])1810Sstevel@tonic-gate main(int argc, char *argv[])
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate int on = 1;
1840Sstevel@tonic-gate socklen_t fromlen;
1850Sstevel@tonic-gate struct sockaddr_storage from;
1860Sstevel@tonic-gate int fd = -1;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate extern char *optarg;
1890Sstevel@tonic-gate char c;
1900Sstevel@tonic-gate int tos = -1;
1910Sstevel@tonic-gate krb5_context krb_context;
1920Sstevel@tonic-gate krb5_keytab keytab = NULL;
1930Sstevel@tonic-gate krb5_error_code status;
1940Sstevel@tonic-gate char *realm = NULL;
1950Sstevel@tonic-gate char *keytab_file = NULL;
1960Sstevel@tonic-gate int encr_flag = 0;
1970Sstevel@tonic-gate struct sockaddr_storage ouraddr;
1980Sstevel@tonic-gate socklen_t ourlen;
1990Sstevel@tonic-gate #ifdef DEBUG
2000Sstevel@tonic-gate int debug_port = 0;
2010Sstevel@tonic-gate #endif /* DEBUG */
2020Sstevel@tonic-gate openlog("rlogind", LOG_PID | LOG_ODELAY, LOG_DAEMON);
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate while ((c = getopt(argc, argv, ARGSTR)) != -1) {
2050Sstevel@tonic-gate switch (c) {
2060Sstevel@tonic-gate case 'k':
2070Sstevel@tonic-gate case '5':
2080Sstevel@tonic-gate use_auth = KRB5_RECVAUTH_V5;
2090Sstevel@tonic-gate break;
2100Sstevel@tonic-gate case 'e':
2110Sstevel@tonic-gate case 'E':
2120Sstevel@tonic-gate case 'x':
2130Sstevel@tonic-gate case 'X':
2140Sstevel@tonic-gate encr_flag = 1;
2150Sstevel@tonic-gate break;
2160Sstevel@tonic-gate case 'M':
2170Sstevel@tonic-gate realm = (char *)strdup(optarg);
2180Sstevel@tonic-gate break;
2190Sstevel@tonic-gate case 'S':
2200Sstevel@tonic-gate keytab_file = (char *)strdup(optarg);
2210Sstevel@tonic-gate break;
2220Sstevel@tonic-gate case 'c':
2230Sstevel@tonic-gate chksum_flag |= CHKSUM_REQUIRED;
2240Sstevel@tonic-gate break;
2250Sstevel@tonic-gate case 'i':
2260Sstevel@tonic-gate chksum_flag |= CHKSUM_IGNORED;
2270Sstevel@tonic-gate break;
2280Sstevel@tonic-gate case 's':
2290Sstevel@tonic-gate if (optarg == NULL || (tos = atoi(optarg)) < 0 ||
2300Sstevel@tonic-gate tos > 255) {
2310Sstevel@tonic-gate syslog(LOG_ERR, "%s: illegal tos value: "
2320Sstevel@tonic-gate "%s\n", argv[0], optarg);
2330Sstevel@tonic-gate } else {
2340Sstevel@tonic-gate if (tos < 0)
2350Sstevel@tonic-gate tos = DEFAULT_TOS;
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate break;
2380Sstevel@tonic-gate #ifdef DEBUG
2390Sstevel@tonic-gate case 'D':
2400Sstevel@tonic-gate debug_port = atoi(optarg);
2410Sstevel@tonic-gate break;
2420Sstevel@tonic-gate #endif /* DEBUG */
2430Sstevel@tonic-gate default:
2440Sstevel@tonic-gate syslog(LOG_ERR, "Unrecognized command line option "
2457727SRameshkumar.Ramasamy@Sun.COM "(-%c), exiting", optopt);
2460Sstevel@tonic-gate exit(EXIT_FAILURE);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5) {
2500Sstevel@tonic-gate status = krb5_init_context(&krb_context);
2510Sstevel@tonic-gate if (status) {
2520Sstevel@tonic-gate syslog(LOG_ERR, "Error initializing krb5: %s",
2530Sstevel@tonic-gate error_message(status));
2540Sstevel@tonic-gate exit(EXIT_FAILURE);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate if (realm != NULL)
257*11415SSurya.Prakki@Sun.COM (void) krb5_set_default_realm(krb_context, realm);
2580Sstevel@tonic-gate if (keytab_file != NULL) {
2590Sstevel@tonic-gate if ((status = krb5_kt_resolve(krb_context,
2600Sstevel@tonic-gate keytab_file,
2610Sstevel@tonic-gate &keytab))) {
2620Sstevel@tonic-gate com_err(argv[0],
2630Sstevel@tonic-gate status,
2640Sstevel@tonic-gate "while resolving srvtab file %s",
2650Sstevel@tonic-gate keytab_file);
2660Sstevel@tonic-gate exit(EXIT_FAILURE);
2670Sstevel@tonic-gate }
2680Sstevel@tonic-gate }
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate #ifdef DEBUG
2720Sstevel@tonic-gate if (debug_port) {
2730Sstevel@tonic-gate int s;
2740Sstevel@tonic-gate struct sockaddr_in sin;
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
2770Sstevel@tonic-gate fatalperror(STDERR_FILENO, "Error in socket");
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate
2800Sstevel@tonic-gate (void) memset((char *)&sin, 0, sizeof (sin));
2810Sstevel@tonic-gate sin.sin_family = AF_INET;
2820Sstevel@tonic-gate sin.sin_port = htons(debug_port);
2830Sstevel@tonic-gate sin.sin_addr.s_addr = INADDR_ANY;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
2860Sstevel@tonic-gate (char *)&on, sizeof (on));
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
2890Sstevel@tonic-gate fatalperror(STDERR_FILENO, "bind error");
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate if ((listen(s, 5)) < 0) {
2930Sstevel@tonic-gate fatalperror(STDERR_FILENO, "listen error");
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate fromlen = sizeof (from);
2970Sstevel@tonic-gate if ((fd = accept(s, (struct sockaddr *)&from, &fromlen)) < 0) {
2980Sstevel@tonic-gate fatalperror(STDERR_FILENO, "accept error");
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate
3010Sstevel@tonic-gate (void) close(s);
3020Sstevel@tonic-gate } else
3030Sstevel@tonic-gate #endif /* DEBUG */
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate if (!issock(STDIN_FILENO))
3060Sstevel@tonic-gate fatal(STDIN_FILENO,
3070Sstevel@tonic-gate "stdin is not a socket file descriptor");
3080Sstevel@tonic-gate fd = STDIN_FILENO;
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate fromlen = sizeof (from);
3120Sstevel@tonic-gate if (getpeername(fd, (struct sockaddr *)&from, &fromlen) < 0)
3130Sstevel@tonic-gate fatalperror(STDERR_FILENO, "getpeername");
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate if (audit_rlogin_settid(fd)) /* set terminal ID */
3160Sstevel@tonic-gate fatalperror(STDERR_FILENO, "audit");
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
3190Sstevel@tonic-gate sizeof (on)) < 0)
3200Sstevel@tonic-gate syslog(LOG_WARNING, "setsockopt(SO_KEEPALIVE): %m");
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate if (!VALID_CHKSUM(chksum_flag)) {
3230Sstevel@tonic-gate syslog(LOG_ERR, "Configuration error: mutually exclusive "
3240Sstevel@tonic-gate "options specified (-c and -i)");
3250Sstevel@tonic-gate fatal(fd, "Checksums are required and ignored (-c and -i);"
3260Sstevel@tonic-gate "these options are mutually exclusive - check "
3270Sstevel@tonic-gate "the documentation.");
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate ourlen = sizeof (ouraddr);
3300Sstevel@tonic-gate if (getsockname(fd, (struct sockaddr *)&ouraddr, &ourlen) == -1) {
3310Sstevel@tonic-gate syslog(LOG_ERR, "getsockname error: %m");
3320Sstevel@tonic-gate exit(EXIT_FAILURE);
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate if (tos != -1 &&
3360Sstevel@tonic-gate ouraddr.ss_family != AF_INET6 &&
3370Sstevel@tonic-gate setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos,
3380Sstevel@tonic-gate sizeof (tos)) < 0 &&
3390Sstevel@tonic-gate errno != ENOPROTOOPT) {
3400Sstevel@tonic-gate syslog(LOG_ERR, "setsockopt(IP_TOS %d): %m", tos);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate doit(fd, &from, krb_context, encr_flag, keytab);
343473Sbw return (0);
3440Sstevel@tonic-gate }
3450Sstevel@tonic-gate
3460Sstevel@tonic-gate static void cleanup(int);
3470Sstevel@tonic-gate static int nsize = 0; /* bytes read prior to pushing rlmod */
3480Sstevel@tonic-gate static char *rlbuf; /* buffer where nbytes are read to */
3490Sstevel@tonic-gate static char *line;
3500Sstevel@tonic-gate
3510Sstevel@tonic-gate static struct winsize win = { 0, 0, 0, 0 };
3520Sstevel@tonic-gate static pid_t pid;
3530Sstevel@tonic-gate static char hostname[MAXHOSTNAMELEN + 1];
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate static void
getstr(int f,char * buf,int cnt,char * err)3560Sstevel@tonic-gate getstr(int f, char *buf, int cnt, char *err)
3570Sstevel@tonic-gate {
3580Sstevel@tonic-gate char c;
3590Sstevel@tonic-gate do {
3600Sstevel@tonic-gate if (read(f, &c, 1) != 1 || (--cnt < 0)) {
3610Sstevel@tonic-gate syslog(LOG_ERR, "Error reading \'%s\' field", err);
3620Sstevel@tonic-gate exit(EXIT_FAILURE);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate *buf++ = c;
3650Sstevel@tonic-gate } while (c != '\0');
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate static krb5_error_code
recvauth(int f,krb5_context krb_context,unsigned int * valid_checksum,krb5_ticket ** ticket,int * auth_type,krb5_principal * client,int encr_flag,krb5_keytab keytab)3690Sstevel@tonic-gate recvauth(int f,
3700Sstevel@tonic-gate krb5_context krb_context,
3710Sstevel@tonic-gate unsigned int *valid_checksum,
3720Sstevel@tonic-gate krb5_ticket **ticket,
3730Sstevel@tonic-gate int *auth_type,
3740Sstevel@tonic-gate krb5_principal *client,
3750Sstevel@tonic-gate int encr_flag,
3760Sstevel@tonic-gate krb5_keytab keytab)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate krb5_error_code status = 0;
3790Sstevel@tonic-gate krb5_auth_context auth_context = NULL;
3800Sstevel@tonic-gate krb5_rcache rcache;
3810Sstevel@tonic-gate krb5_authenticator *authenticator;
3820Sstevel@tonic-gate krb5_data inbuf;
3830Sstevel@tonic-gate krb5_data auth_version;
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate *valid_checksum = 0;
3860Sstevel@tonic-gate
3870Sstevel@tonic-gate if ((status = krb5_auth_con_init(krb_context, &auth_context)))
3880Sstevel@tonic-gate return (status);
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /* Only need remote address for rd_cred() to verify client */
3910Sstevel@tonic-gate if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
3920Sstevel@tonic-gate KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
3930Sstevel@tonic-gate return (status);
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
3960Sstevel@tonic-gate if (status)
3970Sstevel@tonic-gate return (status);
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (!rcache) {
4000Sstevel@tonic-gate krb5_principal server;
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate status = krb5_sname_to_principal(krb_context, 0, 0,
4030Sstevel@tonic-gate KRB5_NT_SRV_HST, &server);
4040Sstevel@tonic-gate if (status)
4050Sstevel@tonic-gate return (status);
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate status = krb5_get_server_rcache(krb_context,
4080Sstevel@tonic-gate krb5_princ_component(krb_context, server, 0),
4090Sstevel@tonic-gate &rcache);
4100Sstevel@tonic-gate krb5_free_principal(krb_context, server);
4110Sstevel@tonic-gate if (status)
4120Sstevel@tonic-gate return (status);
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate status = krb5_auth_con_setrcache(krb_context, auth_context,
4150Sstevel@tonic-gate rcache);
4160Sstevel@tonic-gate if (status)
4170Sstevel@tonic-gate return (status);
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate if ((status = krb5_compat_recvauth(krb_context,
4200Sstevel@tonic-gate &auth_context,
4210Sstevel@tonic-gate &f,
4220Sstevel@tonic-gate NULL, /* Specify daemon principal */
4230Sstevel@tonic-gate 0, /* no flags */
4240Sstevel@tonic-gate keytab, /* NULL to use v5srvtab */
4250Sstevel@tonic-gate ticket, /* return ticket */
4260Sstevel@tonic-gate auth_type, /* authentication system */
4270Sstevel@tonic-gate &auth_version))) {
4280Sstevel@tonic-gate if (*auth_type == KRB5_RECVAUTH_V5) {
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate * clean up before exiting
4310Sstevel@tonic-gate */
4320Sstevel@tonic-gate getstr(f, rusername, sizeof (rusername), "remuser");
4330Sstevel@tonic-gate getstr(f, lusername, sizeof (lusername), "locuser");
4340Sstevel@tonic-gate getstr(f, term, sizeof (term), "Terminal type");
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate return (status);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate getstr(f, lusername, sizeof (lusername), "locuser");
4400Sstevel@tonic-gate getstr(f, term, sizeof (term), "Terminal type");
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
4430Sstevel@tonic-gate if (auth_version.length != 9 || auth_version.data == NULL) {
4440Sstevel@tonic-gate syslog(LOG_ERR, "Bad application protocol version length in "
4450Sstevel@tonic-gate "KRB5 exchange, exiting");
4460Sstevel@tonic-gate fatal(f, "Bad application version length, exiting.");
4470Sstevel@tonic-gate }
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate * Determine which Kerberos CMD protocol was used.
4500Sstevel@tonic-gate */
4510Sstevel@tonic-gate if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
4520Sstevel@tonic-gate kcmd_protocol = KCMD_OLD_PROTOCOL;
4530Sstevel@tonic-gate } else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
4540Sstevel@tonic-gate kcmd_protocol = KCMD_NEW_PROTOCOL;
4550Sstevel@tonic-gate } else {
4560Sstevel@tonic-gate syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
4570Sstevel@tonic-gate (char *)auth_version.data);
4580Sstevel@tonic-gate fatal(f, "Unrecognized KCMD protocol, exiting");
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
4620Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL) {
4630Sstevel@tonic-gate if ((status = krb5_auth_con_getauthenticator(krb_context,
4640Sstevel@tonic-gate auth_context,
4650Sstevel@tonic-gate &authenticator)))
4660Sstevel@tonic-gate return (status);
4670Sstevel@tonic-gate if (authenticator->checksum) {
4680Sstevel@tonic-gate struct sockaddr_storage adr;
4690Sstevel@tonic-gate int adr_length = sizeof (adr);
4700Sstevel@tonic-gate int buflen;
4710Sstevel@tonic-gate krb5_data input;
4720Sstevel@tonic-gate krb5_keyblock key;
4730Sstevel@tonic-gate char *chksumbuf;
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate /*
4760Sstevel@tonic-gate * Define the lenght of the chksum buffer.
4770Sstevel@tonic-gate * chksum string = "[portnum]:termstr:username"
4780Sstevel@tonic-gate * The extra 32 is to hold a integer string for
4790Sstevel@tonic-gate * the portnumber.
4800Sstevel@tonic-gate */
4810Sstevel@tonic-gate buflen = strlen(term) + strlen(lusername) + 32;
4820Sstevel@tonic-gate chksumbuf = (char *)malloc(buflen);
4830Sstevel@tonic-gate if (chksumbuf == 0) {
4840Sstevel@tonic-gate krb5_free_authenticator(krb_context,
4850Sstevel@tonic-gate authenticator);
4860Sstevel@tonic-gate fatal(f, "Out of memory error");
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate if (getsockname(f, (struct sockaddr *)&adr,
4900Sstevel@tonic-gate &adr_length) != 0) {
4910Sstevel@tonic-gate krb5_free_authenticator(krb_context,
4920Sstevel@tonic-gate authenticator);
4930Sstevel@tonic-gate fatal(f, "getsockname error");
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate (void) snprintf(chksumbuf, buflen,
4970Sstevel@tonic-gate "%u:%s%s",
4980Sstevel@tonic-gate ntohs(SOCK_PORT(adr)),
4990Sstevel@tonic-gate term, lusername);
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate input.data = chksumbuf;
5020Sstevel@tonic-gate input.length = strlen(chksumbuf);
5030Sstevel@tonic-gate key.contents = (*ticket)->enc_part2->session->contents;
5040Sstevel@tonic-gate key.length = (*ticket)->enc_part2->session->length;
5050Sstevel@tonic-gate status = krb5_c_verify_checksum(krb_context,
5060Sstevel@tonic-gate &key, 0,
5070Sstevel@tonic-gate &input,
5080Sstevel@tonic-gate authenticator->checksum,
5090Sstevel@tonic-gate valid_checksum);
5100Sstevel@tonic-gate
5110Sstevel@tonic-gate if (status == 0 && *valid_checksum == 0)
5120Sstevel@tonic-gate status = KRB5KRB_AP_ERR_BAD_INTEGRITY;
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate if (chksumbuf)
5150Sstevel@tonic-gate krb5_xfree(chksumbuf);
5160Sstevel@tonic-gate if (status) {
5170Sstevel@tonic-gate krb5_free_authenticator(krb_context,
5180Sstevel@tonic-gate authenticator);
5190Sstevel@tonic-gate return (status);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate }
5220Sstevel@tonic-gate krb5_free_authenticator(krb_context, authenticator);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate if ((status = krb5_copy_principal(krb_context,
5260Sstevel@tonic-gate (*ticket)->enc_part2->client,
5270Sstevel@tonic-gate client)))
5280Sstevel@tonic-gate return (status);
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /* Get the Unix username of the remote user */
5310Sstevel@tonic-gate getstr(f, rusername, sizeof (rusername), "remuser");
5320Sstevel@tonic-gate
5330Sstevel@tonic-gate /* Get the Kerberos principal name string of the remote user */
5340Sstevel@tonic-gate if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
5350Sstevel@tonic-gate return (status);
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate #ifdef DEBUG
5380Sstevel@tonic-gate syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
5390Sstevel@tonic-gate (krusername != NULL ? krusername : "<unknown>"));
5400Sstevel@tonic-gate #endif
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate if (encr_flag) {
5430Sstevel@tonic-gate status = krb5_auth_con_getremotesubkey(krb_context,
5440Sstevel@tonic-gate auth_context,
5450Sstevel@tonic-gate &session_key);
5460Sstevel@tonic-gate if (status) {
5470Sstevel@tonic-gate syslog(LOG_ERR, "Error getting KRB5 session "
5480Sstevel@tonic-gate "subkey, exiting");
5490Sstevel@tonic-gate fatal(f, "Error getting KRB5 session subkey, exiting");
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate /*
5520Sstevel@tonic-gate * The "new" protocol requires that a subkey be sent.
5530Sstevel@tonic-gate */
5540Sstevel@tonic-gate if (session_key == NULL &&
5550Sstevel@tonic-gate kcmd_protocol == KCMD_NEW_PROTOCOL) {
5560Sstevel@tonic-gate syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
5570Sstevel@tonic-gate fatal(f, "No KRB5 session subkey sent, exiting");
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate /*
5600Sstevel@tonic-gate * The "old" protocol does not permit an authenticator subkey.
5610Sstevel@tonic-gate * The key is taken from the ticket instead (see below).
5620Sstevel@tonic-gate */
5630Sstevel@tonic-gate if (session_key != NULL &&
5640Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL) {
5650Sstevel@tonic-gate syslog(LOG_ERR, "KRB5 session subkey not permitted "
5660Sstevel@tonic-gate "with old KCMD protocol, exiting");
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate fatal(f, "KRB5 session subkey not permitted "
5690Sstevel@tonic-gate "with old KCMD protocol, exiting");
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate /*
5720Sstevel@tonic-gate * If no key at this point, use the session key from
5730Sstevel@tonic-gate * the ticket.
5740Sstevel@tonic-gate */
5750Sstevel@tonic-gate if (session_key == NULL) {
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate * Save the session key so we can configure the crypto
5780Sstevel@tonic-gate * module later.
5790Sstevel@tonic-gate */
5800Sstevel@tonic-gate status = krb5_copy_keyblock(krb_context,
5810Sstevel@tonic-gate (*ticket)->enc_part2->session,
5820Sstevel@tonic-gate &session_key);
5830Sstevel@tonic-gate if (status) {
5840Sstevel@tonic-gate syslog(LOG_ERR, "krb5_copy_keyblock failed");
5850Sstevel@tonic-gate fatal(f, "krb5_copy_keyblock failed");
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate /*
5890Sstevel@tonic-gate * If session key still cannot be found, we must
5900Sstevel@tonic-gate * exit because encryption is required here
5910Sstevel@tonic-gate * when encr_flag (-x) is set.
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate if (session_key == NULL) {
5940Sstevel@tonic-gate syslog(LOG_ERR, "Could not find an encryption key,"
5950Sstevel@tonic-gate "exiting");
5960Sstevel@tonic-gate fatal(f, "Encryption required but key not found, "
5970Sstevel@tonic-gate "exiting");
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate * Use krb5_read_message to read the principal stuff.
6020Sstevel@tonic-gate */
6030Sstevel@tonic-gate if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
6040Sstevel@tonic-gate &inbuf)))
6050Sstevel@tonic-gate fatal(f, "Error reading krb5 message");
6060Sstevel@tonic-gate
6076536Sgtb if (inbuf.length) { /* Forwarding being done, read creds */
6086536Sgtb krb5_creds **creds = NULL;
6096536Sgtb
6106536Sgtb if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
6116536Sgtb &creds, NULL)) {
6126536Sgtb if (rcache)
6136536Sgtb (void) krb5_rc_close(krb_context, rcache);
6146536Sgtb krb5_free_creds(krb_context, *creds);
6156536Sgtb fatal(f, "Can't get forwarded credentials");
6166536Sgtb }
6176536Sgtb
6186536Sgtb /* Store the forwarded creds in the ccache */
6196536Sgtb if (status = store_forw_creds(krb_context,
6206536Sgtb creds, *ticket, lusername,
6216536Sgtb &ccache)) {
6226536Sgtb if (rcache)
6236536Sgtb (void) krb5_rc_close(krb_context, rcache);
6246536Sgtb krb5_free_creds(krb_context, *creds);
6256536Sgtb fatal(f, "Can't store forwarded credentials");
6266536Sgtb }
6276536Sgtb krb5_free_creds(krb_context, *creds);
6280Sstevel@tonic-gate }
6296536Sgtb
6300Sstevel@tonic-gate if (rcache)
6310Sstevel@tonic-gate (void) krb5_rc_close(krb_context, rcache);
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate return (status);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate
6360Sstevel@tonic-gate static void
do_krb_login(int f,char * host_addr,char * hostname,krb5_context krb_context,int encr_flag,krb5_keytab keytab)6370Sstevel@tonic-gate do_krb_login(int f, char *host_addr, char *hostname,
6380Sstevel@tonic-gate krb5_context krb_context, int encr_flag,
6390Sstevel@tonic-gate krb5_keytab keytab)
6400Sstevel@tonic-gate {
6410Sstevel@tonic-gate krb5_error_code status;
6420Sstevel@tonic-gate uint_t valid_checksum;
6430Sstevel@tonic-gate krb5_ticket *ticket = NULL;
6440Sstevel@tonic-gate int auth_sys = 0;
6450Sstevel@tonic-gate int auth_sent = 0;
6460Sstevel@tonic-gate krb5_principal client = NULL;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate if (getuid())
6490Sstevel@tonic-gate fatal(f, "Error authorizing KRB5 connection, "
6500Sstevel@tonic-gate "server lacks privilege");
6510Sstevel@tonic-gate
6520Sstevel@tonic-gate status = recvauth(f, krb_context, &valid_checksum, &ticket,
6530Sstevel@tonic-gate &auth_sys, &client, encr_flag, keytab);
6540Sstevel@tonic-gate if (status) {
6550Sstevel@tonic-gate if (ticket)
6560Sstevel@tonic-gate krb5_free_ticket(krb_context, ticket);
6570Sstevel@tonic-gate if (status != 255)
6580Sstevel@tonic-gate syslog(LOG_ERR,
6590Sstevel@tonic-gate "Authentication failed from %s(%s): %s\n",
6600Sstevel@tonic-gate host_addr, hostname, error_message(status));
6610Sstevel@tonic-gate fatal(f, "Kerberos authentication failed, exiting");
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate
6640Sstevel@tonic-gate if (auth_sys != KRB5_RECVAUTH_V5) {
6650Sstevel@tonic-gate fatal(f, "This server only supports Kerberos V5");
6660Sstevel@tonic-gate } else {
6670Sstevel@tonic-gate /*
6680Sstevel@tonic-gate * Authenticated OK, now check authorization.
6690Sstevel@tonic-gate */
6700Sstevel@tonic-gate if (client && krb5_kuserok(krb_context, client, lusername))
6710Sstevel@tonic-gate auth_sent = KRB5_RECVAUTH_V5;
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate if (auth_sent == KRB5_RECVAUTH_V5 &&
6750Sstevel@tonic-gate kcmd_protocol == KCMD_OLD_PROTOCOL &&
6760Sstevel@tonic-gate chksum_flag == CHKSUM_REQUIRED && !valid_checksum) {
6770Sstevel@tonic-gate syslog(LOG_ERR, "Client did not supply required checksum, "
6780Sstevel@tonic-gate "connection rejected.");
6790Sstevel@tonic-gate fatal(f, "Client did not supply required checksum, "
6800Sstevel@tonic-gate "connection rejected.");
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate if (auth_sys != auth_sent) {
6840Sstevel@tonic-gate char *msg_fail = NULL;
6850Sstevel@tonic-gate int msgsize = 0;
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate if (ticket)
6880Sstevel@tonic-gate krb5_free_ticket(krb_context, ticket);
6890Sstevel@tonic-gate
6900Sstevel@tonic-gate if (krusername != NULL) {
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * msgsize must be enough to hold
6930Sstevel@tonic-gate * krusername, lusername and a brief
6940Sstevel@tonic-gate * message describing the failure.
6950Sstevel@tonic-gate */
6960Sstevel@tonic-gate msgsize = strlen(krusername) +
6970Sstevel@tonic-gate strlen(lusername) + 80;
6980Sstevel@tonic-gate msg_fail = (char *)malloc(msgsize);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate if (msg_fail == NULL) {
7010Sstevel@tonic-gate syslog(LOG_ERR, "User is not authorized to login to "
7020Sstevel@tonic-gate "specified account");
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate fatal(f, "User is not authorized to login to "
7050Sstevel@tonic-gate "specified account");
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate if (auth_sent != 0)
7080Sstevel@tonic-gate (void) snprintf(msg_fail, msgsize,
7090Sstevel@tonic-gate "Access denied because of improper "
7100Sstevel@tonic-gate "KRB5 credentials");
7110Sstevel@tonic-gate else
7120Sstevel@tonic-gate (void) snprintf(msg_fail, msgsize,
7130Sstevel@tonic-gate "User %s is not authorized to login "
7140Sstevel@tonic-gate "to account %s",
7150Sstevel@tonic-gate krusername, lusername);
7160Sstevel@tonic-gate syslog(LOG_ERR, "%s", msg_fail);
7170Sstevel@tonic-gate fatal(f, msg_fail);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate /*
7220Sstevel@tonic-gate * stop_stream
7230Sstevel@tonic-gate *
7240Sstevel@tonic-gate * Utility routine to send a CRYPTIOCSTOP ioctl to the
7250Sstevel@tonic-gate * crypto module(cryptmod).
7260Sstevel@tonic-gate */
7270Sstevel@tonic-gate static void
stop_stream(int fd,int dir)7280Sstevel@tonic-gate stop_stream(int fd, int dir)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate struct strioctl crioc;
7310Sstevel@tonic-gate uint32_t stopdir = dir;
7320Sstevel@tonic-gate
7330Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSTOP;
7340Sstevel@tonic-gate crioc.ic_timout = -1;
7350Sstevel@tonic-gate crioc.ic_len = sizeof (stopdir);
7360Sstevel@tonic-gate crioc.ic_dp = (char *)&stopdir;
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc))
7390Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTOP ioctl: %m");
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate
7420Sstevel@tonic-gate /*
7430Sstevel@tonic-gate * start_stream
7440Sstevel@tonic-gate *
7450Sstevel@tonic-gate * Utility routine to send a CRYPTIOCSTART ioctl to the
7460Sstevel@tonic-gate * crypto module(cryptmod). This routine may contain optional
7470Sstevel@tonic-gate * payload data that the cryptmod will interpret as bytes that
7480Sstevel@tonic-gate * need to be decrypted and sent back up to the application
7490Sstevel@tonic-gate * via the data stream.
7500Sstevel@tonic-gate */
7510Sstevel@tonic-gate static void
start_stream(int fd,int dir)7520Sstevel@tonic-gate start_stream(int fd, int dir)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate struct strioctl crioc;
7550Sstevel@tonic-gate uint32_t iocval;
7560Sstevel@tonic-gate size_t datalen = 0;
7570Sstevel@tonic-gate char *data = NULL;
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate if (dir == CRYPT_DECRYPT) {
7600Sstevel@tonic-gate iocval = CRYPTIOCSTARTDEC;
7610Sstevel@tonic-gate
7620Sstevel@tonic-gate /* Look for data not yet processed */
7630Sstevel@tonic-gate if (ioctl(fd, I_NREAD, &datalen) < 0) {
7640Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m");
7650Sstevel@tonic-gate datalen = 0;
7660Sstevel@tonic-gate } else {
7670Sstevel@tonic-gate if (datalen > 0) {
7680Sstevel@tonic-gate data = malloc(datalen);
7690Sstevel@tonic-gate if (data != NULL) {
7700Sstevel@tonic-gate int nbytes = read(fd, data, datalen);
7710Sstevel@tonic-gate datalen = nbytes;
7720Sstevel@tonic-gate } else {
7730Sstevel@tonic-gate syslog(LOG_ERR,
7740Sstevel@tonic-gate "malloc error (%d bytes)",
7750Sstevel@tonic-gate datalen);
7760Sstevel@tonic-gate datalen = 0;
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate } else {
7790Sstevel@tonic-gate datalen = 0;
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate } else {
7830Sstevel@tonic-gate iocval = CRYPTIOCSTARTENC;
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate
7860Sstevel@tonic-gate crioc.ic_cmd = iocval;
7870Sstevel@tonic-gate crioc.ic_timout = -1;
7880Sstevel@tonic-gate crioc.ic_len = datalen;
7890Sstevel@tonic-gate crioc.ic_dp = data;
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc))
7920Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSTART ioctl: %m");
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate if (data != NULL)
7950Sstevel@tonic-gate free(data);
7960Sstevel@tonic-gate }
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate static int
configure_stream(int fd,krb5_keyblock * skey,int dir,krb5_data * ivec,uint_t iv_usage)7990Sstevel@tonic-gate configure_stream(int fd, krb5_keyblock *skey, int dir, krb5_data *ivec,
8000Sstevel@tonic-gate uint_t iv_usage)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate struct cr_info_t setup_info;
8030Sstevel@tonic-gate struct strioctl crioc;
8040Sstevel@tonic-gate int retval = 0;
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate switch (skey->enctype) {
8070Sstevel@tonic-gate case ENCTYPE_DES_CBC_CRC:
8080Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_CRC;
8090Sstevel@tonic-gate break;
8100Sstevel@tonic-gate case ENCTYPE_DES_CBC_MD5:
8110Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_MD5;
8120Sstevel@tonic-gate break;
8130Sstevel@tonic-gate case ENCTYPE_DES_CBC_RAW:
8140Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES_CBC_NULL;
8150Sstevel@tonic-gate break;
8160Sstevel@tonic-gate case ENCTYPE_DES3_CBC_SHA1:
8170Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_DES3_CBC_SHA1;
8180Sstevel@tonic-gate break;
8190Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC:
8200Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5;
8210Sstevel@tonic-gate break;
8220Sstevel@tonic-gate case ENCTYPE_ARCFOUR_HMAC_EXP:
8230Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_ARCFOUR_HMAC_MD5_EXP;
8240Sstevel@tonic-gate break;
8250Sstevel@tonic-gate case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
8260Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_AES128;
8270Sstevel@tonic-gate break;
8280Sstevel@tonic-gate case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
8290Sstevel@tonic-gate setup_info.crypto_method = CRYPT_METHOD_AES256;
8300Sstevel@tonic-gate break;
8310Sstevel@tonic-gate default:
8320Sstevel@tonic-gate syslog(LOG_ERR, "Enctype in kerberos session key "
8330Sstevel@tonic-gate "is not supported by crypto module(%d)",
8340Sstevel@tonic-gate skey->enctype);
8350Sstevel@tonic-gate return (-1);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate if (ivec == NULL || ivec->length == 0) {
8380Sstevel@tonic-gate (void) memset(&setup_info.ivec, 0, sizeof (setup_info.ivec));
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate if (skey->enctype != ENCTYPE_ARCFOUR_HMAC &&
8410Sstevel@tonic-gate skey->enctype != ENCTYPE_ARCFOUR_HMAC_EXP)
8420Sstevel@tonic-gate /* Kerberos IVs are 8 bytes long for DES keys */
8430Sstevel@tonic-gate setup_info.iveclen = KRB5_MIT_DES_KEYSIZE;
8440Sstevel@tonic-gate else
8450Sstevel@tonic-gate setup_info.iveclen = 0;
8460Sstevel@tonic-gate } else {
8470Sstevel@tonic-gate (void) memcpy(&setup_info.ivec, ivec->data, ivec->length);
8480Sstevel@tonic-gate setup_info.iveclen = ivec->length;
8490Sstevel@tonic-gate }
8500Sstevel@tonic-gate
8510Sstevel@tonic-gate setup_info.ivec_usage = iv_usage;
8520Sstevel@tonic-gate (void) memcpy(&setup_info.key, skey->contents, skey->length);
8530Sstevel@tonic-gate
8540Sstevel@tonic-gate setup_info.keylen = skey->length;
8550Sstevel@tonic-gate setup_info.direction_mask = dir;
8560Sstevel@tonic-gate /*
8570Sstevel@tonic-gate * R* commands get special handling by crypto module -
8580Sstevel@tonic-gate * 4 byte length field is used before each encrypted block
8590Sstevel@tonic-gate * of data.
8600Sstevel@tonic-gate */
8610Sstevel@tonic-gate setup_info.option_mask = (kcmd_protocol == KCMD_OLD_PROTOCOL ?
8620Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V1 :
8630Sstevel@tonic-gate CRYPTOPT_RCMD_MODE_V2);
8640Sstevel@tonic-gate
8650Sstevel@tonic-gate crioc.ic_cmd = CRYPTIOCSETUP;
8660Sstevel@tonic-gate crioc.ic_timout = -1;
8670Sstevel@tonic-gate crioc.ic_len = sizeof (setup_info);
8680Sstevel@tonic-gate crioc.ic_dp = (char *)&setup_info;
8690Sstevel@tonic-gate
8700Sstevel@tonic-gate if (ioctl(fd, I_STR, &crioc)) {
8710Sstevel@tonic-gate syslog(LOG_ERR, "Error sending CRYPTIOCSETUP ioctl: %m");
8720Sstevel@tonic-gate retval = -1;
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate return (retval);
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate static krb5_error_code
krb5_compat_recvauth(krb5_context context,krb5_auth_context * auth_context,krb5_pointer fdp,krb5_principal server,krb5_int32 flags,krb5_keytab keytab,krb5_ticket ** ticket,krb5_int32 * auth_sys,krb5_data * version)8780Sstevel@tonic-gate krb5_compat_recvauth(krb5_context context,
8790Sstevel@tonic-gate krb5_auth_context *auth_context,
8800Sstevel@tonic-gate krb5_pointer fdp, /* IN */
8810Sstevel@tonic-gate krb5_principal server, /* IN */
8820Sstevel@tonic-gate krb5_int32 flags, /* IN */
8830Sstevel@tonic-gate krb5_keytab keytab, /* IN */
8840Sstevel@tonic-gate krb5_ticket **ticket, /* OUT */
8850Sstevel@tonic-gate krb5_int32 *auth_sys, /* OUT */
8860Sstevel@tonic-gate krb5_data *version) /* OUT */
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate krb5_int32 vlen;
8890Sstevel@tonic-gate char *buf;
8900Sstevel@tonic-gate int len, length;
8910Sstevel@tonic-gate krb5_int32 retval;
8920Sstevel@tonic-gate int fd = *((int *)fdp);
8930Sstevel@tonic-gate
8940Sstevel@tonic-gate if ((retval = krb5_net_read(context, fd, (char *)&vlen, 4)) != 4)
8950Sstevel@tonic-gate return ((retval < 0) ? errno : ECONNABORTED);
8960Sstevel@tonic-gate
8970Sstevel@tonic-gate /*
8980Sstevel@tonic-gate * Assume that we're talking to a V5 recvauth; read in the
8990Sstevel@tonic-gate * the version string, and make sure it matches.
9000Sstevel@tonic-gate */
9010Sstevel@tonic-gate len = (int)ntohl(vlen);
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate if (len < 0 || len > 255)
9040Sstevel@tonic-gate return (KRB5_SENDAUTH_BADAUTHVERS);
9050Sstevel@tonic-gate
9060Sstevel@tonic-gate buf = malloc(len);
9070Sstevel@tonic-gate if (buf == NULL)
9080Sstevel@tonic-gate return (ENOMEM);
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate length = krb5_net_read(context, fd, buf, len);
9110Sstevel@tonic-gate if (len != length) {
9120Sstevel@tonic-gate krb5_xfree(buf);
9130Sstevel@tonic-gate return ((len < 0) ? errno : ECONNABORTED);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate if (strcmp(buf, KRB_V5_SENDAUTH_VERS) != 0) {
9170Sstevel@tonic-gate krb5_xfree(buf);
9180Sstevel@tonic-gate return (KRB5_SENDAUTH_BADAUTHVERS);
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate krb5_xfree(buf);
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate *auth_sys = KRB5_RECVAUTH_V5;
9230Sstevel@tonic-gate
9240Sstevel@tonic-gate retval = krb5_recvauth_version(context, auth_context, fdp,
9250Sstevel@tonic-gate server, flags | KRB5_RECVAUTH_SKIP_VERSION,
9260Sstevel@tonic-gate keytab, ticket, version);
9270Sstevel@tonic-gate
9280Sstevel@tonic-gate return (retval);
9290Sstevel@tonic-gate }
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate static void
doit(int f,struct sockaddr_storage * fromp,krb5_context krb_context,int encr_flag,krb5_keytab keytab)9330Sstevel@tonic-gate doit(int f,
9340Sstevel@tonic-gate struct sockaddr_storage *fromp,
9350Sstevel@tonic-gate krb5_context krb_context,
9360Sstevel@tonic-gate int encr_flag,
9370Sstevel@tonic-gate krb5_keytab keytab)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate int p, t, on = 1;
9400Sstevel@tonic-gate char c;
9410Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
9420Sstevel@tonic-gate struct sockaddr_in *sin;
9430Sstevel@tonic-gate struct sockaddr_in6 *sin6;
9440Sstevel@tonic-gate int fromplen;
9450Sstevel@tonic-gate in_port_t port;
9460Sstevel@tonic-gate struct termios tp;
9470Sstevel@tonic-gate boolean_t bad_port;
9480Sstevel@tonic-gate boolean_t no_name;
9490Sstevel@tonic-gate char rhost_addra[INET6_ADDRSTRLEN];
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate if (!(rlbuf = malloc(BUFSIZ))) {
9520Sstevel@tonic-gate syslog(LOG_ERR, "rlbuf malloc failed\n");
9530Sstevel@tonic-gate exit(EXIT_FAILURE);
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate (void) alarm(60);
9560Sstevel@tonic-gate if (read(f, &c, 1) != 1 || c != 0) {
9570Sstevel@tonic-gate syslog(LOG_ERR, "failed to receive protocol zero byte\n");
9580Sstevel@tonic-gate exit(EXIT_FAILURE);
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate (void) alarm(0);
9610Sstevel@tonic-gate if (fromp->ss_family == AF_INET) {
9620Sstevel@tonic-gate sin = (struct sockaddr_in *)fromp;
9630Sstevel@tonic-gate port = sin->sin_port = ntohs((ushort_t)sin->sin_port);
9640Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in);
9650Sstevel@tonic-gate
9660Sstevel@tonic-gate if (!inet_ntop(AF_INET, &sin->sin_addr,
9670Sstevel@tonic-gate rhost_addra, sizeof (rhost_addra)))
9680Sstevel@tonic-gate goto badconversion;
9690Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) {
9700Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)fromp;
9710Sstevel@tonic-gate port = sin6->sin6_port = ntohs((ushort_t)sin6->sin6_port);
9720Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in6);
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
9750Sstevel@tonic-gate struct in_addr ipv4_addr;
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr,
9780Sstevel@tonic-gate &ipv4_addr);
9790Sstevel@tonic-gate if (!inet_ntop(AF_INET, &ipv4_addr, rhost_addra,
9800Sstevel@tonic-gate sizeof (rhost_addra)))
9810Sstevel@tonic-gate goto badconversion;
9820Sstevel@tonic-gate } else {
9830Sstevel@tonic-gate if (!inet_ntop(AF_INET6, &sin6->sin6_addr,
9840Sstevel@tonic-gate rhost_addra, sizeof (rhost_addra)))
9850Sstevel@tonic-gate goto badconversion;
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate } else {
9880Sstevel@tonic-gate syslog(LOG_ERR, "unknown address family %d\n",
9890Sstevel@tonic-gate fromp->ss_family);
9900Sstevel@tonic-gate fatal(f, "Permission denied");
9910Sstevel@tonic-gate }
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate /*
9940Sstevel@tonic-gate * Allow connections only from the "ephemeral" reserved
9950Sstevel@tonic-gate * ports(ports 512 - 1023) by checking the remote port
9960Sstevel@tonic-gate * because other utilities(e.g. in.ftpd) can be used to
9970Sstevel@tonic-gate * allow a unprivileged user to originate a connection
9980Sstevel@tonic-gate * from a privileged port and provide untrustworthy
9990Sstevel@tonic-gate * authentication.
10000Sstevel@tonic-gate */
10010Sstevel@tonic-gate bad_port = (use_auth != KRB5_RECVAUTH_V5 &&
10020Sstevel@tonic-gate (port >= (in_port_t)IPPORT_RESERVED) ||
10030Sstevel@tonic-gate (port < (in_port_t)(IPPORT_RESERVED/2)));
10040Sstevel@tonic-gate no_name = getnameinfo((const struct sockaddr *) fromp,
10050Sstevel@tonic-gate fromplen, hostname, sizeof (hostname),
10060Sstevel@tonic-gate NULL, 0, 0) != 0;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate if (no_name || bad_port) {
10090Sstevel@tonic-gate (void) strlcpy(abuf, rhost_addra, sizeof (abuf));
10100Sstevel@tonic-gate /* If no host name, use IP address for name later on. */
10110Sstevel@tonic-gate if (no_name)
10120Sstevel@tonic-gate (void) strlcpy(hostname, abuf, sizeof (hostname));
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate
10153011Sjbeck if (!no_name) {
10163011Sjbeck /*
10173011Sjbeck * Even if getnameinfo() succeeded, we still have to check
10183011Sjbeck * for spoofing.
10193011Sjbeck */
10203011Sjbeck check_address("rlogind", fromp, sin, sin6, rhost_addra,
10213011Sjbeck hostname, sizeof (hostname));
10223011Sjbeck }
10233011Sjbeck
10240Sstevel@tonic-gate if (bad_port) {
10250Sstevel@tonic-gate if (no_name)
10260Sstevel@tonic-gate syslog(LOG_NOTICE,
10270Sstevel@tonic-gate "connection from %s - bad port\n",
10280Sstevel@tonic-gate abuf);
10290Sstevel@tonic-gate else
10300Sstevel@tonic-gate syslog(LOG_NOTICE,
10310Sstevel@tonic-gate "connection from %s(%s) - bad port\n",
10320Sstevel@tonic-gate hostname, abuf);
10330Sstevel@tonic-gate fatal(f, "Permission denied");
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate
10360Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5) {
10370Sstevel@tonic-gate do_krb_login(f, rhost_addra, hostname,
10380Sstevel@tonic-gate krb_context, encr_flag, keytab);
10390Sstevel@tonic-gate if (krusername != NULL && strlen(krusername)) {
10400Sstevel@tonic-gate /*
10410Sstevel@tonic-gate * Kerberos Authentication succeeded,
10420Sstevel@tonic-gate * so set the proper program name to use
10430Sstevel@tonic-gate * with pam (important during 'cleanup'
10440Sstevel@tonic-gate * routine later).
10450Sstevel@tonic-gate */
10460Sstevel@tonic-gate pam_prog_name = KRB5_PROG_NAME;
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate if (write(f, "", 1) != 1) {
10510Sstevel@tonic-gate syslog(LOG_NOTICE,
10520Sstevel@tonic-gate "send of the zero byte(to %s) failed:"
10530Sstevel@tonic-gate " cannot start data transfer mode\n",
10540Sstevel@tonic-gate (no_name ? abuf : hostname));
10550Sstevel@tonic-gate exit(EXIT_FAILURE);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate if ((p = open("/dev/ptmx", O_RDWR)) == -1)
10580Sstevel@tonic-gate fatalperror(f, "cannot open /dev/ptmx");
10590Sstevel@tonic-gate if (grantpt(p) == -1)
10600Sstevel@tonic-gate fatal(f, "could not grant slave pty");
10610Sstevel@tonic-gate if (unlockpt(p) == -1)
10620Sstevel@tonic-gate fatal(f, "could not unlock slave pty");
10630Sstevel@tonic-gate if ((line = ptsname(p)) == NULL)
10640Sstevel@tonic-gate fatal(f, "could not enable slave pty");
10650Sstevel@tonic-gate if ((t = open(line, O_RDWR)) == -1)
10660Sstevel@tonic-gate fatal(f, "could not open slave pty");
10670Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ptem") == -1)
10680Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ptem");
10690Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ldterm") == -1)
10700Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ldterm");
10710Sstevel@tonic-gate if (ioctl(t, I_PUSH, "ttcompat") == -1)
10720Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH ttcompat");
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * POP the sockmod and push the rlmod module.
10750Sstevel@tonic-gate *
10760Sstevel@tonic-gate * Note that sockmod has to be removed since readstream assumes
10770Sstevel@tonic-gate * a "raw" TPI endpoint(e.g. it uses getmsg).
10780Sstevel@tonic-gate */
10790Sstevel@tonic-gate if (removemod(f, "sockmod") < 0)
10800Sstevel@tonic-gate fatalperror(f, "couldn't remove sockmod");
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate if (encr_flag) {
10830Sstevel@tonic-gate if (ioctl(f, I_PUSH, "cryptmod") < 0)
10840Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH rlmod");
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate if (ioctl(f, I_PUSH, "rlmod") < 0)
10890Sstevel@tonic-gate fatalperror(f, "ioctl I_PUSH rlmod");
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate if (encr_flag) {
10920Sstevel@tonic-gate /*
10930Sstevel@tonic-gate * Make sure rlmod will pass unrecognized IOCTLs to cryptmod
10940Sstevel@tonic-gate */
10950Sstevel@tonic-gate uchar_t passthru = 1;
10960Sstevel@tonic-gate struct strioctl rlmodctl;
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate rlmodctl.ic_cmd = CRYPTPASSTHRU;
10990Sstevel@tonic-gate rlmodctl.ic_timout = -1;
11000Sstevel@tonic-gate rlmodctl.ic_len = sizeof (uchar_t);
11010Sstevel@tonic-gate rlmodctl.ic_dp = (char *)&passthru;
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate if (ioctl(f, I_STR, &rlmodctl) < 0)
11040Sstevel@tonic-gate fatal(f, "ioctl CRYPTPASSTHRU failed\n");
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate /*
11080Sstevel@tonic-gate * readstream will do a getmsg till it receives
11090Sstevel@tonic-gate * M_PROTO type T_DATA_REQ from rloginmodopen()
11100Sstevel@tonic-gate * indicating all data on the stream prior to pushing rlmod has
11110Sstevel@tonic-gate * been drained at the stream head.
11120Sstevel@tonic-gate */
11130Sstevel@tonic-gate if ((nsize = readstream(f, rlbuf, BUFSIZ)) < 0)
11140Sstevel@tonic-gate fatalperror(f, "readstream failed");
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate * Make sure the pty doesn't modify the strings passed
11170Sstevel@tonic-gate * to login as part of the "rlogin protocol." The login
11180Sstevel@tonic-gate * program should set these flags to apropriate values
11190Sstevel@tonic-gate * after it has read the strings.
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate if (ioctl(t, TCGETS, &tp) == -1)
11220Sstevel@tonic-gate fatalperror(f, "ioctl TCGETS");
11230Sstevel@tonic-gate tp.c_lflag &= ~(ECHO|ICANON);
11240Sstevel@tonic-gate tp.c_oflag &= ~(XTABS|OCRNL);
11250Sstevel@tonic-gate tp.c_iflag &= ~(IGNPAR|ICRNL);
11260Sstevel@tonic-gate if (ioctl(t, TCSETS, &tp) == -1)
11270Sstevel@tonic-gate fatalperror(f, "ioctl TCSETS");
11280Sstevel@tonic-gate
11290Sstevel@tonic-gate /*
11300Sstevel@tonic-gate * System V ptys allow the TIOC{SG}WINSZ ioctl to be
11310Sstevel@tonic-gate * issued on the master side of the pty. Luckily, that's
11320Sstevel@tonic-gate * the only tty ioctl we need to do do, so we can close the
11330Sstevel@tonic-gate * slave side in the parent process after the fork.
11340Sstevel@tonic-gate */
11350Sstevel@tonic-gate (void) ioctl(p, TIOCSWINSZ, &win);
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate pid = fork();
11380Sstevel@tonic-gate if (pid < 0)
11390Sstevel@tonic-gate fatalperror(f, "fork");
11400Sstevel@tonic-gate if (pid == 0) {
11410Sstevel@tonic-gate int tt;
11420Sstevel@tonic-gate struct utmpx ut;
11430Sstevel@tonic-gate
11440Sstevel@tonic-gate /* System V login expects a utmp entry to already be there */
11450Sstevel@tonic-gate (void) memset(&ut, 0, sizeof (ut));
11460Sstevel@tonic-gate (void) strncpy(ut.ut_user, ".rlogin", sizeof (ut.ut_user));
11470Sstevel@tonic-gate (void) strncpy(ut.ut_line, line, sizeof (ut.ut_line));
11480Sstevel@tonic-gate ut.ut_pid = getpid();
11490Sstevel@tonic-gate ut.ut_id[0] = 'r';
11500Sstevel@tonic-gate ut.ut_id[1] = (char)SC_WILDC;
11510Sstevel@tonic-gate ut.ut_id[2] = (char)SC_WILDC;
11520Sstevel@tonic-gate ut.ut_id[3] = (char)SC_WILDC;
11530Sstevel@tonic-gate ut.ut_type = LOGIN_PROCESS;
11540Sstevel@tonic-gate ut.ut_exit.e_termination = 0;
11550Sstevel@tonic-gate ut.ut_exit.e_exit = 0;
11560Sstevel@tonic-gate (void) time(&ut.ut_tv.tv_sec);
11570Sstevel@tonic-gate if (makeutx(&ut) == NULL)
11580Sstevel@tonic-gate syslog(LOG_INFO, "in.rlogind:\tmakeutx failed");
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate /* controlling tty */
11610Sstevel@tonic-gate if (setsid() == -1)
11620Sstevel@tonic-gate fatalperror(f, "setsid");
11630Sstevel@tonic-gate if ((tt = open(line, O_RDWR)) == -1)
11640Sstevel@tonic-gate fatalperror(f, "could not re-open slave pty");
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate if (close(p) == -1)
11670Sstevel@tonic-gate fatalperror(f, "error closing pty master");
11680Sstevel@tonic-gate if (close(t) == -1)
11690Sstevel@tonic-gate fatalperror(f, "error closing pty slave"
11700Sstevel@tonic-gate " opened before session established");
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate * If this fails we may or may not be able to output an
11730Sstevel@tonic-gate * error message.
11740Sstevel@tonic-gate */
11750Sstevel@tonic-gate if (close(f) == -1)
11760Sstevel@tonic-gate fatalperror(f, "error closing deamon stdout");
11770Sstevel@tonic-gate if (dup2(tt, STDIN_FILENO) == -1 ||
11780Sstevel@tonic-gate dup2(tt, STDOUT_FILENO) == -1 ||
11790Sstevel@tonic-gate dup2(tt, STDERR_FILENO) == -1)
11800Sstevel@tonic-gate exit(EXIT_FAILURE); /* Disaster! No stderr! */
11810Sstevel@tonic-gate
11820Sstevel@tonic-gate (void) close(tt);
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate if (use_auth == KRB5_RECVAUTH_V5 &&
11850Sstevel@tonic-gate krusername != NULL && strlen(krusername)) {
11860Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login",
11870Sstevel@tonic-gate "-d", line,
11880Sstevel@tonic-gate "-r", hostname,
11890Sstevel@tonic-gate "-u", krusername, /* KRB5 principal name */
11900Sstevel@tonic-gate "-s", pam_prog_name,
11910Sstevel@tonic-gate "-t", term, /* Remote Terminal */
11920Sstevel@tonic-gate "-U", rusername, /* Remote User */
11930Sstevel@tonic-gate "-R", KRB5_REPOSITORY_NAME,
11940Sstevel@tonic-gate lusername, /* local user */
11950Sstevel@tonic-gate NULL);
11960Sstevel@tonic-gate } else {
11970Sstevel@tonic-gate (void) execl(LOGIN_PROGRAM, "login",
11980Sstevel@tonic-gate "-d", line,
11990Sstevel@tonic-gate "-r", hostname,
12000Sstevel@tonic-gate NULL);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate fatalperror(STDERR_FILENO, "/bin/login");
12040Sstevel@tonic-gate /*NOTREACHED*/
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate (void) close(t);
12070Sstevel@tonic-gate (void) ioctl(f, FIONBIO, &on);
12080Sstevel@tonic-gate (void) ioctl(p, FIONBIO, &on);
12090Sstevel@tonic-gate
12100Sstevel@tonic-gate /*
12110Sstevel@tonic-gate * Must ignore SIGTTOU, otherwise we'll stop
12120Sstevel@tonic-gate * when we try and set slave pty's window shape
12130Sstevel@tonic-gate * (our controlling tty is the master pty).
12140Sstevel@tonic-gate * Likewise, we don't want any of the tty-generated
12150Sstevel@tonic-gate * signals from chars passing through.
12160Sstevel@tonic-gate */
12170Sstevel@tonic-gate (void) sigset(SIGTSTP, SIG_IGN);
12180Sstevel@tonic-gate (void) sigset(SIGINT, SIG_IGN);
12190Sstevel@tonic-gate (void) sigset(SIGQUIT, SIG_IGN);
12200Sstevel@tonic-gate (void) sigset(SIGTTOU, SIG_IGN);
12210Sstevel@tonic-gate (void) sigset(SIGTTIN, SIG_IGN);
12220Sstevel@tonic-gate (void) sigset(SIGCHLD, cleanup);
12230Sstevel@tonic-gate (void) setpgrp();
12240Sstevel@tonic-gate
12250Sstevel@tonic-gate if (encr_flag) {
12260Sstevel@tonic-gate krb5_data ivec, *ivptr;
12270Sstevel@tonic-gate uint_t ivec_usage;
12280Sstevel@tonic-gate stop_stream(f, CRYPT_ENCRYPT|CRYPT_DECRYPT);
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /*
12310Sstevel@tonic-gate * Configure the STREAMS crypto module. For now,
12320Sstevel@tonic-gate * don't use any IV parameter. KCMDV0.2 support
12330Sstevel@tonic-gate * will require the use of Initialization Vectors
12340Sstevel@tonic-gate * for both encrypt and decrypt modes.
12350Sstevel@tonic-gate */
12360Sstevel@tonic-gate if (kcmd_protocol == KCMD_OLD_PROTOCOL) {
12370Sstevel@tonic-gate if (session_key->enctype == ENCTYPE_DES_CBC_CRC) {
12380Sstevel@tonic-gate /*
12390Sstevel@tonic-gate * This is gross but necessary for MIT compat.
12400Sstevel@tonic-gate */
12410Sstevel@tonic-gate ivec.length = session_key->length;
12420Sstevel@tonic-gate ivec.data = (char *)session_key->contents;
12430Sstevel@tonic-gate ivec_usage = IVEC_REUSE;
12440Sstevel@tonic-gate ivptr = &ivec;
12450Sstevel@tonic-gate } else {
12460Sstevel@tonic-gate ivptr = NULL; /* defaults to all 0's */
12470Sstevel@tonic-gate ivec_usage = IVEC_NEVER;
12480Sstevel@tonic-gate }
12490Sstevel@tonic-gate /*
12500Sstevel@tonic-gate * configure both sides of stream together
12510Sstevel@tonic-gate * since they share the same IV.
12520Sstevel@tonic-gate * This is what makes the OLD KCMD protocol
12530Sstevel@tonic-gate * less secure than the newer one - Bad ivecs.
12540Sstevel@tonic-gate */
12550Sstevel@tonic-gate if (configure_stream(f, session_key,
12560Sstevel@tonic-gate CRYPT_ENCRYPT|CRYPT_DECRYPT,
12570Sstevel@tonic-gate ivptr, ivec_usage) != 0)
12580Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -"
12590Sstevel@tonic-gate " exiting.\n");
12600Sstevel@tonic-gate } else {
12610Sstevel@tonic-gate size_t blocksize;
12620Sstevel@tonic-gate if (session_key->enctype == ENCTYPE_ARCFOUR_HMAC ||
12630Sstevel@tonic-gate session_key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
12640Sstevel@tonic-gate if (configure_stream(f, session_key,
12650Sstevel@tonic-gate CRYPT_ENCRYPT|CRYPT_DECRYPT,
12660Sstevel@tonic-gate NULL, IVEC_NEVER) != 0)
12670Sstevel@tonic-gate fatal(f,
12680Sstevel@tonic-gate "Cannot initialize encryption -"
12690Sstevel@tonic-gate " exiting.\n");
12700Sstevel@tonic-gate goto startcrypto;
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate if (krb5_c_block_size(krb_context,
12730Sstevel@tonic-gate session_key->enctype,
12740Sstevel@tonic-gate &blocksize)) {
12750Sstevel@tonic-gate syslog(LOG_ERR, "Cannot determine blocksize "
12760Sstevel@tonic-gate "for encryption type %d",
12770Sstevel@tonic-gate session_key->enctype);
12780Sstevel@tonic-gate fatal(f, "Cannot determine blocksize "
12790Sstevel@tonic-gate "for encryption - exiting.\n");
12800Sstevel@tonic-gate }
12810Sstevel@tonic-gate ivec.data = (char *)malloc(blocksize);
12820Sstevel@tonic-gate ivec.length = blocksize;
12830Sstevel@tonic-gate if (ivec.data == NULL)
12840Sstevel@tonic-gate fatal(f, "memory error - exiting\n");
12850Sstevel@tonic-gate /*
12860Sstevel@tonic-gate * Following MIT convention -
12870Sstevel@tonic-gate * encrypt IV = 0x01 x blocksize
12880Sstevel@tonic-gate * decrypt IV = 0x00 x blocksize
12890Sstevel@tonic-gate * ivec_usage = IVEC_ONETIME
12900Sstevel@tonic-gate *
12910Sstevel@tonic-gate * configure_stream separately for encrypt and
12920Sstevel@tonic-gate * decrypt because there are 2 different IVs.
12930Sstevel@tonic-gate *
12940Sstevel@tonic-gate * AES uses 0's for IV.
12950Sstevel@tonic-gate */
12960Sstevel@tonic-gate if (session_key->enctype ==
12970Sstevel@tonic-gate ENCTYPE_AES128_CTS_HMAC_SHA1_96 ||
12980Sstevel@tonic-gate session_key->enctype ==
12990Sstevel@tonic-gate ENCTYPE_AES256_CTS_HMAC_SHA1_96)
13000Sstevel@tonic-gate (void) memset(ivec.data, 0x00, blocksize);
13010Sstevel@tonic-gate else
13020Sstevel@tonic-gate (void) memset(ivec.data, 0x01, blocksize);
13030Sstevel@tonic-gate if (configure_stream(f, session_key, CRYPT_ENCRYPT,
13040Sstevel@tonic-gate &ivec, IVEC_ONETIME) != 0)
13050Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -"
13060Sstevel@tonic-gate " exiting.\n");
13070Sstevel@tonic-gate (void) memset(ivec.data, 0x00, blocksize);
13080Sstevel@tonic-gate if (configure_stream(f, session_key, CRYPT_DECRYPT,
13090Sstevel@tonic-gate &ivec, IVEC_ONETIME) != 0)
13100Sstevel@tonic-gate fatal(f, "Cannot initialize encryption -"
13110Sstevel@tonic-gate " exiting.\n");
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate (void) free(ivec.data);
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate startcrypto:
13160Sstevel@tonic-gate start_stream(f, CRYPT_ENCRYPT);
13170Sstevel@tonic-gate start_stream(f, CRYPT_DECRYPT);
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate protocol(f, p, encr_flag);
13200Sstevel@tonic-gate cleanup(0);
13210Sstevel@tonic-gate /*NOTREACHED*/
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate badconversion:
13240Sstevel@tonic-gate fatalperror(f, "address conversion");
13250Sstevel@tonic-gate /*NOTREACHED*/
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate /*
13290Sstevel@tonic-gate * rlogin "protocol" machine.
13300Sstevel@tonic-gate */
13310Sstevel@tonic-gate static void
protocol(int f,int p,int encr_flag)13320Sstevel@tonic-gate protocol(int f, int p, int encr_flag)
13330Sstevel@tonic-gate {
13340Sstevel@tonic-gate struct stat buf;
13350Sstevel@tonic-gate struct protocol_arg rloginp;
13360Sstevel@tonic-gate struct strioctl rloginmod;
13370Sstevel@tonic-gate int ptmfd; /* fd of logindmux coneected to ptmx */
13380Sstevel@tonic-gate int netfd; /* fd of logindmux connected to netf */
13390Sstevel@tonic-gate static uchar_t oobdata[] = {TIOCPKT_WINDOW};
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate /* indicate new rlogin */
13420Sstevel@tonic-gate if (send_oob(f, oobdata, 1) < 0)
13430Sstevel@tonic-gate fatalperror(f, "send_oob");
13440Sstevel@tonic-gate /*
13450Sstevel@tonic-gate * We cannot send the SECURE_MSG until after the
13460Sstevel@tonic-gate * client has been signaled with the oobdata (above).
13470Sstevel@tonic-gate */
13480Sstevel@tonic-gate if (encr_flag) {
13490Sstevel@tonic-gate if (write(f, SECURE_MSG, strlen(SECURE_MSG)) < 0)
13500Sstevel@tonic-gate fatalperror(f, "Error writing SECURE message");
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate
13530Sstevel@tonic-gate /*
13540Sstevel@tonic-gate * Open logindmux driver and link netf and ptmx
13550Sstevel@tonic-gate * underneath logindmux.
13560Sstevel@tonic-gate */
13570Sstevel@tonic-gate if ((ptmfd = open("/dev/logindmux", O_RDWR)) == -1)
13580Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux");
13590Sstevel@tonic-gate
13600Sstevel@tonic-gate if ((netfd = open("/dev/logindmux", O_RDWR)) == -1)
13610Sstevel@tonic-gate fatalperror(f, "open /dev/logindmux");
13620Sstevel@tonic-gate
13630Sstevel@tonic-gate if (ioctl(ptmfd, I_LINK, p) < 0)
13640Sstevel@tonic-gate fatal(f, "ioctl I_LINK of /dev/ptmx failed\n");
13650Sstevel@tonic-gate
13660Sstevel@tonic-gate if (ioctl(netfd, I_LINK, f) < 0)
13670Sstevel@tonic-gate fatal(f, "ioctl I_LINK of tcp connection failed\n");
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate * Figure out the device number of the ptm's mux fd, and pass that
13710Sstevel@tonic-gate * to the net's mux.
13720Sstevel@tonic-gate */
13730Sstevel@tonic-gate if (fstat(ptmfd, &buf) < 0)
13740Sstevel@tonic-gate fatalperror(f, "cannot determine device number"
13750Sstevel@tonic-gate " of pty side of /dev/logindmux");
13760Sstevel@tonic-gate rloginp.dev = buf.st_rdev;
13770Sstevel@tonic-gate rloginp.flag = 0;
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
13800Sstevel@tonic-gate rloginmod.ic_timout = -1;
13810Sstevel@tonic-gate rloginmod.ic_len = sizeof (struct protocol_arg);
13820Sstevel@tonic-gate rloginmod.ic_dp = (char *)&rloginp;
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate if (ioctl(netfd, I_STR, &rloginmod) < 0)
13850Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMX_IOC_QEXCHANGE of netfd failed\n");
13860Sstevel@tonic-gate
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate * Figure out the device number of the net's mux fd, and pass that
13890Sstevel@tonic-gate * to the ptm's mux.
13900Sstevel@tonic-gate */
13910Sstevel@tonic-gate if (fstat(netfd, &buf))
13920Sstevel@tonic-gate fatalperror(f, "cannot determine device number"
13930Sstevel@tonic-gate " of network side of /dev/logindmux");
13940Sstevel@tonic-gate rloginp.dev = buf.st_rdev;
13950Sstevel@tonic-gate rloginp.flag = 1;
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate rloginmod.ic_cmd = LOGDMX_IOC_QEXCHANGE;
13980Sstevel@tonic-gate rloginmod.ic_timout = -1;
13990Sstevel@tonic-gate rloginmod.ic_len = sizeof (struct protocol_arg);
14000Sstevel@tonic-gate rloginmod.ic_dp = (char *)&rloginp;
14010Sstevel@tonic-gate
14020Sstevel@tonic-gate if (ioctl(ptmfd, I_STR, &rloginmod) < 0)
14030Sstevel@tonic-gate fatal(netfd, "ioctl LOGDMXZ_IOC_QEXCHANGE of ptmfd failed\n");
14040Sstevel@tonic-gate /*
14050Sstevel@tonic-gate * Send an ioctl type RL_IOC_ENABLE to reenable the
14060Sstevel@tonic-gate * message queue and reinsert the data read from streamhead
14070Sstevel@tonic-gate * at the time of pushing rloginmod module.
14080Sstevel@tonic-gate * We need to send this ioctl even if no data was read earlier
14090Sstevel@tonic-gate * since we need to reenable the message queue of rloginmod module.
14100Sstevel@tonic-gate */
14110Sstevel@tonic-gate rloginmod.ic_cmd = RL_IOC_ENABLE;
14120Sstevel@tonic-gate rloginmod.ic_timout = -1;
14130Sstevel@tonic-gate if (nsize) {
14140Sstevel@tonic-gate rloginmod.ic_len = nsize;
14150Sstevel@tonic-gate rloginmod.ic_dp = rlbuf;
14160Sstevel@tonic-gate } else {
14170Sstevel@tonic-gate rloginmod.ic_len = 0;
14180Sstevel@tonic-gate rloginmod.ic_dp = NULL;
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate
14210Sstevel@tonic-gate if (ioctl(netfd, I_STR, &rloginmod) < 0)
14220Sstevel@tonic-gate fatal(netfd, "ioctl RL_IOC_ENABLE of netfd failed\n");
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate /*
14250Sstevel@tonic-gate * User level daemon now pauses till the shell exits.
14260Sstevel@tonic-gate */
14270Sstevel@tonic-gate (void) pause();
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate /* This is a signal handler, hence the dummy argument */
14310Sstevel@tonic-gate /*ARGSUSED*/
14320Sstevel@tonic-gate static void
cleanup(int dummy)14330Sstevel@tonic-gate cleanup(int dummy)
14340Sstevel@tonic-gate {
14350Sstevel@tonic-gate rmut();
14360Sstevel@tonic-gate exit(EXIT_FAILURE);
14370Sstevel@tonic-gate /*NOTREACHED*/
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate
14400Sstevel@tonic-gate /*
14410Sstevel@tonic-gate * TPI style replacement for socket send() primitive, so we don't require
14420Sstevel@tonic-gate * sockmod to be on the stream.
14430Sstevel@tonic-gate */
14440Sstevel@tonic-gate static int
send_oob(int fd,void * ptr,size_t count)14450Sstevel@tonic-gate send_oob(int fd, void *ptr, size_t count)
14460Sstevel@tonic-gate {
14470Sstevel@tonic-gate struct T_exdata_req exd_req;
14480Sstevel@tonic-gate struct strbuf hdr, dat;
14490Sstevel@tonic-gate int ret;
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate exd_req.PRIM_type = T_EXDATA_REQ;
14520Sstevel@tonic-gate exd_req.MORE_flag = 0;
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate hdr.buf = (char *)&exd_req;
14550Sstevel@tonic-gate hdr.len = sizeof (exd_req);
14560Sstevel@tonic-gate
14570Sstevel@tonic-gate dat.buf = ptr;
14580Sstevel@tonic-gate dat.len = count;
14590Sstevel@tonic-gate
14600Sstevel@tonic-gate ret = putmsg(fd, &hdr, &dat, 0);
14610Sstevel@tonic-gate if (ret == 0)
14620Sstevel@tonic-gate ret = count;
14630Sstevel@tonic-gate return (ret);
14640Sstevel@tonic-gate }
14650Sstevel@tonic-gate
14660Sstevel@tonic-gate static void
fatal(int fd,const char * msg)14670Sstevel@tonic-gate fatal(int fd, const char *msg)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate char *bufp;
14700Sstevel@tonic-gate size_t len = strlen(msg) + 16; /* enough for our wrapper */
14710Sstevel@tonic-gate
14720Sstevel@tonic-gate bufp = alloca(len);
14730Sstevel@tonic-gate /* ASCII 001 is the error indicator */
14740Sstevel@tonic-gate len = snprintf(bufp, len, "\01rlogind: %s.\r\n", msg);
14750Sstevel@tonic-gate (void) write(fd, bufp, len);
14760Sstevel@tonic-gate exit(EXIT_FAILURE);
14770Sstevel@tonic-gate /*NOTREACHED*/
14780Sstevel@tonic-gate }
14790Sstevel@tonic-gate
14800Sstevel@tonic-gate /*PRINTFLIKE2*/
14810Sstevel@tonic-gate static void
fatalperror(int fd,const char * msg)14820Sstevel@tonic-gate fatalperror(int fd, const char *msg)
14830Sstevel@tonic-gate {
14840Sstevel@tonic-gate char *bufp;
14850Sstevel@tonic-gate const char *errstr;
14860Sstevel@tonic-gate int save_errno = errno;
14870Sstevel@tonic-gate size_t len = strlen(msg);
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate if ((errstr = strerror(save_errno))) {
14900Sstevel@tonic-gate len += strlen(errstr) + 3; /* 3 for ": " and \0 below */
14910Sstevel@tonic-gate bufp = alloca(len);
14920Sstevel@tonic-gate (void) snprintf(bufp, len, "%s: %s", msg, errstr);
14930Sstevel@tonic-gate } else {
14940Sstevel@tonic-gate const char fmt[] = "%s: Error %d";
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate /* -4 for %s & %d. "*8/3" is bytes->decimal, pessimistically */
14970Sstevel@tonic-gate len += sizeof (fmt) -4 + (sizeof (save_errno) *8 /3);
14980Sstevel@tonic-gate bufp = alloca(len);
14990Sstevel@tonic-gate (void) snprintf(bufp, len, fmt, msg, save_errno);
15000Sstevel@tonic-gate }
15010Sstevel@tonic-gate fatal(fd, bufp);
15020Sstevel@tonic-gate /*NOTREACHED*/
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate
15050Sstevel@tonic-gate static void
rmut(void)15060Sstevel@tonic-gate rmut(void)
15070Sstevel@tonic-gate {
15080Sstevel@tonic-gate pam_handle_t *pamh;
15090Sstevel@tonic-gate struct utmpx *up;
15100Sstevel@tonic-gate char user[sizeof (up->ut_user) + 1];
15110Sstevel@tonic-gate char ttyn[sizeof (up->ut_line) + 1];
15120Sstevel@tonic-gate char rhost[sizeof (up->ut_host) + 1];
15130Sstevel@tonic-gate
15140Sstevel@tonic-gate /* while cleaning up dont allow disruption */
15150Sstevel@tonic-gate (void) sigset(SIGCHLD, SIG_IGN);
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate setutxent();
15180Sstevel@tonic-gate while (up = getutxent()) {
15190Sstevel@tonic-gate if (up->ut_pid == pid) {
15200Sstevel@tonic-gate if (up->ut_type == DEAD_PROCESS)
15210Sstevel@tonic-gate break; /* Cleaned up elsewhere. */
15220Sstevel@tonic-gate
15230Sstevel@tonic-gate /*
15240Sstevel@tonic-gate * call pam_close_session if login changed
15250Sstevel@tonic-gate * the utmpx user entry from type LOGIN_PROCESS
15260Sstevel@tonic-gate * to type USER_PROCESS, which happens
15270Sstevel@tonic-gate * after pam_open_session is called.
15280Sstevel@tonic-gate */
15290Sstevel@tonic-gate if (up->ut_type == USER_PROCESS) {
15300Sstevel@tonic-gate (void) strlcpy(user, up->ut_user,
15310Sstevel@tonic-gate sizeof (user));
15320Sstevel@tonic-gate (void) strlcpy(ttyn, up->ut_line,
15330Sstevel@tonic-gate sizeof (ttyn));
15340Sstevel@tonic-gate (void) strlcpy(rhost, up->ut_host,
15350Sstevel@tonic-gate sizeof (rhost));
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate /*
15380Sstevel@tonic-gate * Use the same pam_prog_name that
15390Sstevel@tonic-gate * 'login' used.
15400Sstevel@tonic-gate */
15410Sstevel@tonic-gate if ((pam_start(pam_prog_name, user, NULL,
15420Sstevel@tonic-gate &pamh))
15430Sstevel@tonic-gate == PAM_SUCCESS) {
15440Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_TTY,
15450Sstevel@tonic-gate ttyn);
15460Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RHOST,
15470Sstevel@tonic-gate rhost);
15480Sstevel@tonic-gate (void) pam_close_session(pamh, 0);
15490Sstevel@tonic-gate (void) pam_end(pamh, PAM_SUCCESS);
15500Sstevel@tonic-gate }
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate
15530Sstevel@tonic-gate up->ut_type = DEAD_PROCESS;
15540Sstevel@tonic-gate up->ut_exit.e_termination = WTERMSIG(0);
15550Sstevel@tonic-gate up->ut_exit.e_exit = WEXITSTATUS(0);
15560Sstevel@tonic-gate (void) time(&up->ut_tv.tv_sec);
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate if (modutx(up) == NULL) {
15590Sstevel@tonic-gate /*
15600Sstevel@tonic-gate * Since modutx failed we'll
15610Sstevel@tonic-gate * write out the new entry
15620Sstevel@tonic-gate * ourselves.
15630Sstevel@tonic-gate */
15640Sstevel@tonic-gate (void) pututxline(up);
15650Sstevel@tonic-gate updwtmpx("wtmpx", up);
15660Sstevel@tonic-gate }
15670Sstevel@tonic-gate break;
15680Sstevel@tonic-gate }
15690Sstevel@tonic-gate }
15700Sstevel@tonic-gate
15710Sstevel@tonic-gate endutxent();
15720Sstevel@tonic-gate
15730Sstevel@tonic-gate (void) sigset(SIGCHLD, cleanup);
15740Sstevel@tonic-gate }
15750Sstevel@tonic-gate
15760Sstevel@tonic-gate static int
readstream(int fd,char * buf,int size)15770Sstevel@tonic-gate readstream(int fd, char *buf, int size)
15780Sstevel@tonic-gate {
15790Sstevel@tonic-gate struct strbuf ctlbuf, datbuf;
15800Sstevel@tonic-gate union T_primitives tpi;
15810Sstevel@tonic-gate int nbytes = 0;
15820Sstevel@tonic-gate int ret = 0;
15830Sstevel@tonic-gate int flags = 0;
15840Sstevel@tonic-gate int bufsize = size;
15850Sstevel@tonic-gate int nread;
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate (void) memset(&ctlbuf, 0, sizeof (ctlbuf));
15880Sstevel@tonic-gate (void) memset(&datbuf, 0, sizeof (datbuf));
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate ctlbuf.buf = (char *)&tpi;
15910Sstevel@tonic-gate ctlbuf.maxlen = sizeof (tpi);
15920Sstevel@tonic-gate datbuf.buf = buf;
15930Sstevel@tonic-gate datbuf.maxlen = size;
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate for (;;) {
15960Sstevel@tonic-gate if (ioctl(fd, I_NREAD, &nread) < 0) {
15970Sstevel@tonic-gate syslog(LOG_ERR, "I_NREAD returned error %m");
15980Sstevel@tonic-gate return (-1);
15990Sstevel@tonic-gate }
16000Sstevel@tonic-gate if (nread + nbytes > bufsize) {
16010Sstevel@tonic-gate buf = (char *)realloc(buf, (unsigned)(bufsize + nread));
16020Sstevel@tonic-gate if (buf == NULL) {
16030Sstevel@tonic-gate syslog(LOG_WARNING,
16040Sstevel@tonic-gate "buffer allocation failed\n");
16050Sstevel@tonic-gate return (-1);
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate bufsize += nread;
16080Sstevel@tonic-gate rlbuf = buf;
16090Sstevel@tonic-gate datbuf.buf = buf + nbytes;
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate datbuf.maxlen = bufsize - nbytes;
16120Sstevel@tonic-gate ret = getmsg(fd, &ctlbuf, &datbuf, &flags);
16130Sstevel@tonic-gate if (ret < 0) {
16140Sstevel@tonic-gate syslog(LOG_ERR, "getmsg failed error %m");
16150Sstevel@tonic-gate return (-1);
16160Sstevel@tonic-gate }
16170Sstevel@tonic-gate if ((ctlbuf.len == 0) && (datbuf.len == 0)) {
16180Sstevel@tonic-gate /*
16190Sstevel@tonic-gate * getmsg() returned no data - this indicates
16200Sstevel@tonic-gate * that the connection is closing down.
16210Sstevel@tonic-gate */
16220Sstevel@tonic-gate cleanup(0);
16230Sstevel@tonic-gate }
16240Sstevel@tonic-gate if (ctlbuf.len <= 0) {
16250Sstevel@tonic-gate nbytes += datbuf.len;
16260Sstevel@tonic-gate datbuf.buf += datbuf.len;
16270Sstevel@tonic-gate continue;
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate if (tpi.type == T_DATA_REQ) {
16300Sstevel@tonic-gate return (nbytes);
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate if ((tpi.type == T_ORDREL_IND) || (tpi.type == T_DISCON_IND))
16330Sstevel@tonic-gate cleanup(0);
16340Sstevel@tonic-gate }
16350Sstevel@tonic-gate }
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate /*
16380Sstevel@tonic-gate * Verify that the named module is at the top of the stream
16390Sstevel@tonic-gate * and then pop it off.
16400Sstevel@tonic-gate */
16410Sstevel@tonic-gate static int
removemod(int f,char * modname)16420Sstevel@tonic-gate removemod(int f, char *modname)
16430Sstevel@tonic-gate {
16440Sstevel@tonic-gate char topmodname[BUFSIZ];
16450Sstevel@tonic-gate
16460Sstevel@tonic-gate if (ioctl(f, I_LOOK, topmodname) < 0)
16470Sstevel@tonic-gate return (-1);
16480Sstevel@tonic-gate if (strcmp(modname, topmodname) != 0) {
16490Sstevel@tonic-gate errno = ENXIO;
16500Sstevel@tonic-gate return (-1);
16510Sstevel@tonic-gate }
16520Sstevel@tonic-gate if (ioctl(f, I_POP, 0) < 0)
16530Sstevel@tonic-gate return (-1);
16540Sstevel@tonic-gate return (0);
16550Sstevel@tonic-gate }
1656