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