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