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