1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1998-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* from UCB 5.4 6/23/85 */ 30 31 /* 32 * 4.2BSD, 2.9BSD, or ATTSVR4 TCP/IP server for uucico 33 * uucico's TCP channel causes this server to be run at the remote end. 34 */ 35 36 #include "uucp.h" 37 #include <netdb.h> 38 #ifdef BSD2_9 39 #include <sys/localopts.h> 40 #include <sys/file.h> 41 #endif BSD2_9 42 #include <signal.h> 43 #include <errno.h> 44 #include <sys/socket.h> 45 #include <netinet/in.h> 46 #include <sys/wait.h> 47 #ifdef ATTSVTTY 48 #include <sys/termio.h> 49 #else 50 #include <sys/ioctl.h> 51 #endif 52 #include <pwd.h> 53 #ifdef ATTSVR4 54 #include <shadow.h> 55 #endif 56 #include <lastlog.h> 57 58 #include <security/pam_appl.h> 59 60 static int uucp_conv(); 61 struct pam_conv conv = {uucp_conv, NULL }; 62 pam_handle_t *pamh; 63 64 #if !defined(BSD4_2) && !defined(BSD2_9) && !defined(ATTSVR4) 65 --- You must have either BSD4_2, BSD2_9, or ATTSVR4 defined for this to work 66 #endif !BSD4_2 && !BSD2_9 67 #if defined(BSD4_2) && defined(BSD2_9) 68 --- You may not have both BSD4_2 and BSD2_9 defined for this to work 69 #endif /* check for stupidity */ 70 71 char lastlog[] = "/var/adm/lastlog"; 72 struct passwd nouser = { "", "nope", -1, -1, "", "", "", "", "" }; 73 #ifdef ATTSVR4 74 struct spwd noupass = { "", "nope" }; 75 #endif 76 struct sockaddr_in hisctladdr; 77 socklen_t hisaddrlen = (socklen_t)sizeof (hisctladdr); 78 struct sockaddr_in myctladdr; 79 int nolog; /* don't log in utmp or wtmp */ 80 81 char Username[64]; 82 char Loginname[64]; 83 char *nenv[] = { 84 Username, 85 Loginname, 86 NULL, 87 }; 88 extern char **environ; 89 90 main(argc, argv) 91 int argc; 92 char **argv; 93 { 94 #ifndef BSDINETD 95 register int s, tcp_socket; 96 struct servent *sp; 97 #endif !BSDINETD 98 extern int errno; 99 int dologout(); 100 101 if (argc > 1 && strcmp(argv[1], "-n") == 0) 102 nolog = 1; 103 environ = nenv; 104 #ifdef BSDINETD 105 close(1); close(2); 106 dup(0); dup(0); 107 hisaddrlen = (socklen_t)sizeof (hisctladdr); 108 if (getpeername(0, (struct sockaddr *)&hisctladdr, &hisaddrlen) < 0) { 109 fprintf(stderr, "%s: ", argv[0]); 110 perror("getpeername"); 111 _exit(1); 112 } 113 if (fork() == 0) 114 doit(&hisctladdr); 115 dologout(); 116 exit(1); 117 #else !BSDINETD 118 sp = getservbyname("uucp", "tcp"); 119 if (sp == NULL) { 120 perror("uucpd: getservbyname"); 121 exit(1); 122 } 123 if (fork()) 124 exit(0); 125 #ifdef ATTSVR4 126 setsid(); 127 #else 128 if ((s = open("/dev/tty", 2)) >= 0) { 129 ioctl(s, TIOCNOTTY, (char *)0); 130 close(s); 131 } 132 #endif 133 134 #ifdef ATTSVR4 135 memset((void *)&myctladdr, 0, sizeof (myctladdr)); 136 #else 137 bzero((char *)&myctladdr, sizeof (myctladdr)); 138 #endif 139 myctladdr.sin_family = AF_INET; 140 myctladdr.sin_port = sp->s_port; 141 #if defined(BSD4_2) || defined(ATTSVR4) 142 tcp_socket = socket(AF_INET, SOCK_STREAM, 0); 143 if (tcp_socket < 0) { 144 perror("uucpd: socket"); 145 exit(1); 146 } 147 if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) { 148 perror("uucpd: bind"); 149 exit(1); 150 } 151 listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */ 152 signal(SIGCHLD, dologout); 153 154 for (;;) { 155 s = accept(tcp_socket, &hisctladdr, &hisaddrlen); 156 if (s < 0) { 157 if (errno == EINTR) 158 continue; 159 perror("uucpd: accept"); 160 exit(1); 161 } 162 if (fork() == 0) { 163 close(0); close(1); close(2); 164 dup(s); dup(s); dup(s); 165 close(tcp_socket); close(s); 166 doit(&hisctladdr); 167 exit(1); 168 } 169 close(s); 170 } 171 #endif BSD4_2 172 173 #ifdef BSD2_9 174 for (;;) { 175 signal(SIGCHLD, dologout); 176 s = socket(SOCK_STREAM, 0, &myctladdr, 177 SO_ACCEPTCONN|SO_KEEPALIVE); 178 if (s < 0) { 179 perror("uucpd: socket"); 180 exit(1); 181 } 182 if (accept(s, &hisctladdr) < 0) { 183 if (errno == EINTR) { 184 close(s); 185 continue; 186 } 187 perror("uucpd: accept"); 188 exit(1); 189 } 190 if (fork() == 0) { 191 close(0); close(1); close(2); 192 dup(s); dup(s); dup(s); 193 close(s); 194 doit(&hisctladdr); 195 exit(1); 196 } 197 } 198 #endif BSD2_9 199 #endif !BSDINETD 200 201 /* NOTREACHED */ 202 } 203 204 doit(sinp) 205 struct sockaddr_in *sinp; 206 { 207 char user[64], passwd[64]; 208 struct passwd *pw, *getpwnam(); 209 int error; 210 211 alarm(60); 212 printf("login: "); fflush(stdout); 213 if (readline(user, sizeof (user)) < 0) { 214 fprintf(stderr, "user read\n"); 215 return; 216 } 217 218 /* 219 * Call pam_start to initiate a PAM authentication operation 220 */ 221 222 if ((pam_start("uucp", user, &conv, &pamh)) != PAM_SUCCESS) 223 return; 224 if ((pam_set_item(pamh, PAM_TTY, ttyname(0))) != PAM_SUCCESS) 225 return; 226 227 if (pam_authenticate(pamh, PAM_SILENT) != PAM_SUCCESS) { 228 /* force a delay if passwd bad */ 229 sleep(4); 230 fprintf(stderr, "Login incorrect."); 231 pam_end(pamh, PAM_ABORT); 232 return; 233 } 234 235 if ((error = pam_acct_mgmt(pamh, PAM_SILENT)) != PAM_SUCCESS) { 236 switch (error) { 237 case PAM_NEW_AUTHTOK_REQD: 238 fprintf(stderr, "Password Expired."); 239 break; 240 case PAM_PERM_DENIED: 241 fprintf(stderr, "Account Expired."); 242 break; 243 case PAM_AUTHTOK_EXPIRED: 244 fprintf(stderr, "Password Expired."); 245 break; 246 default: 247 fprintf(stderr, "Login incorrect."); 248 break; 249 } 250 pam_end(pamh, PAM_ABORT); 251 return; 252 } 253 254 if ((pw = getpwnam(user)) == NULL || strcmp(pw->pw_shell, UUCICO)) { 255 /* force a delay if user bad */ 256 sleep(4); 257 fprintf(stderr, "Login incorrect."); 258 pam_end(pamh, PAM_USER_UNKNOWN); 259 return; 260 } 261 262 alarm(0); 263 264 sprintf(Username, "USER=%s", user); 265 sprintf(Loginname, "LOGNAME=%s", user); 266 if (!nolog) 267 if (dologin(pw, sinp)) { 268 pam_end(pamh, PAM_ABORT); 269 _exit(1); 270 } 271 272 /* set the real (and effective) GID */ 273 if (setgid(pw->pw_gid) == -1) { 274 fprintf(stderr, "Login incorrect."); 275 pam_end(pamh, PAM_PERM_DENIED); 276 return; 277 } 278 279 /* 280 * Initialize the supplementary group access list. 281 */ 282 if (initgroups(user, pw->pw_gid) == -1) { 283 fprintf(stderr, "Login incorrect."); 284 pam_end(pamh, PAM_PERM_DENIED); 285 return; 286 } 287 288 if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) { 289 fprintf(stderr, "Login incorrect."); 290 pam_end(pamh, PAM_CRED_INSUFFICIENT); 291 return; 292 } 293 294 /* set the real (and effective) UID */ 295 if (setuid(pw->pw_uid) == -1) { 296 fprintf(stderr, "Login incorrect."); 297 pam_end(pamh, PAM_CRED_ERR); 298 return; 299 } 300 301 chdir(pw->pw_dir); 302 303 pam_end(pamh, PAM_SUCCESS); 304 305 #if defined(BSD4_2) || defined(ATTSVR4) 306 execl(UUCICO, "uucico", "-u", user, (char *)0); 307 #endif BSD4_2 308 #ifdef BSD2_9 309 sprintf(passwd, "-h%s", inet_ntoa(sinp->sin_addr)); 310 execl(UUCICO, "uucico", passwd, (char *)0); 311 #endif BSD2_9 312 perror("uucico server: execl"); 313 } 314 315 readline(p, n) 316 register char *p; 317 register int n; 318 { 319 char c; 320 321 while (n-- > 0) { 322 if (read(0, &c, 1) <= 0) 323 return (-1); 324 c &= 0177; 325 if (c == '\n' || c == '\r') { 326 *p = '\0'; 327 return (0); 328 } 329 *p++ = c; 330 } 331 return (-1); 332 } 333 334 #ifdef ATTSVR4 335 #include <sac.h> /* for SC_WILDC */ 336 #include <utmpx.h> 337 #else !ATTSVR4 338 #include <utmp.h> 339 #endif !ATTSVR4 340 #if defined(BSD4_2) || defined(ATTSVR4) 341 #include <fcntl.h> 342 #endif BSD4_2 343 344 #ifdef BSD2_9 345 #define O_APPEND 0 /* kludge */ 346 #define wait3(a, b, c) wait2(a, b) 347 #endif BSD2_9 348 349 #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 350 351 #ifdef ATTSVR4 352 struct utmpx utmp; 353 #else !ATTSVR4 354 struct utmp utmp; 355 #endif !ATTSVR4 356 357 dologout() 358 { 359 #ifdef ATTSVR4 360 int status; 361 #else !ATTSVR4 362 union wait status; 363 #endif !ATSVR4 364 int pid, wtmp; 365 /* the following 2 variables are needed for utmp mgmt */ 366 struct utmpx ut; 367 368 #ifdef BSDINETD 369 while ((pid = wait(&status)) > 0) { 370 #else !BSDINETD 371 while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 372 #endif !BSDINETD 373 if (nolog) 374 continue; 375 #ifdef ATTSVR4 376 /* clear out any residue from utmpx buffer */ 377 (void) memset((char *)&ut, 0, sizeof (ut)); 378 379 SCPYN(utmp.ut_user, ""); 380 ut.ut_id[0] = 'u'; 381 ut.ut_id[1] = 'u'; 382 ut.ut_id[2] = SC_WILDC; 383 ut.ut_id[3] = SC_WILDC; 384 sprintf(ut.ut_line, "uucp%.4d", pid); 385 ut.ut_pid = getpid(); 386 ut.ut_type = DEAD_PROCESS; 387 ut.ut_exit.e_termination = status & 0xFF; 388 ut.ut_exit.e_exit = WEXITSTATUS(status); 389 SCPYN(ut.ut_host, ""); 390 ut.ut_syslen = 1; 391 (void) gettimeofday(&ut.ut_tv, NULL); 392 393 /* 394 * XXX: UUCPD does not do any pam session management. 395 * There is no way for the parent process to close 396 * the pam session after a child has exited. 397 */ 398 399 updwtmpx(WTMPX_FILE, &ut); 400 #else !ATTSVR4 401 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 402 if (wtmp >= 0) { 403 sprintf(utmp.ut_line, "uucp%.4d", pid); 404 SCPYN(utmp.ut_name, ""); 405 SCPYN(utmp.ut_host, ""); 406 (void) time(&utmp.ut_time); 407 #ifdef BSD2_9 408 (void) lseek(wtmp, 0L, 2); 409 #endif BSD2_9 410 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 411 (void) close(wtmp); 412 } 413 #endif !ATTSVR4 414 } 415 } 416 417 /* 418 * Record login in wtmp file. 419 */ 420 dologin(pw, sin) 421 struct passwd *pw; 422 struct sockaddr_in *sin; 423 { 424 char line[32]; 425 char remotehost[32]; 426 int wtmp; 427 struct hostent *hp = gethostbyaddr((const char *)&sin->sin_addr, 428 sizeof (struct in_addr), AF_INET); 429 struct utmpx ut; 430 431 if (hp) { 432 strncpy(remotehost, hp->h_name, sizeof (remotehost)); 433 endhostent(); 434 } else 435 strncpy(remotehost, (char *)inet_ntoa(sin->sin_addr), 436 sizeof (remotehost)); 437 #ifdef ATTSVR4 438 /* clear wtmpx entry */ 439 (void) memset((void *)&ut, 0, sizeof (ut)); 440 441 SCPYN(ut.ut_user, pw->pw_name); 442 ut.ut_id[0] = 'u'; 443 ut.ut_id[1] = 'u'; 444 ut.ut_id[2] = SC_WILDC; 445 ut.ut_id[3] = SC_WILDC; 446 /* hack, but must be unique and no tty line */ 447 sprintf(line, "uucp%.4d", getpid()); 448 SCPYN(ut.ut_line, line); 449 ut.ut_pid = getpid(); 450 ut.ut_type = USER_PROCESS; 451 ut.ut_exit.e_termination = 0; 452 ut.ut_exit.e_exit = 0; 453 SCPYN(ut.ut_host, remotehost); 454 ut.ut_syslen = strlen(remotehost) + 1; 455 (void) gettimeofday(&ut.ut_tv, 0); 456 updwtmpx(WTMPX_FILE, &ut); 457 458 /* 459 * XXX: 460 * We no longer do session management in uucpd because 461 * there is no way to do the "pam_close_session()". 462 * 463 * Processes like "init" can do a pam_close_session() 464 * because they can use the utmp entry to retrive 465 * the proper username, ttyname, etc. -- 466 * uucpd only writes to the wtmp file. 467 * 468 * ftpd (which also only writes to the wtmp file) 469 * can do a pam_close_session() because it doesn't fork(). 470 * 471 * if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS) 472 * return (1); 473 * if (pam_set_item(pamh, PAM_TTY, line) != PAM_SUCCESS) 474 * return (1); 475 * if (pam_open_session(pamh, 0) != PAM_SUCCESS) { 476 * return (1); 477 * } 478 */ 479 480 #else !ATTSVR4 481 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 482 if (wtmp >= 0) { 483 /* hack, but must be unique and no tty line */ 484 sprintf(line, "uucp%.4d", getpid()); 485 SCPYN(utmp.ut_line, line); 486 SCPYN(utmp.ut_name, pw->pw_name); 487 SCPYN(utmp.ut_host, remotehost); 488 time(&utmp.ut_time); 489 #ifdef BSD2_9 490 (void) lseek(wtmp, 0L, 2); 491 #endif BSD2_9 492 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 493 (void) close(wtmp); 494 } 495 #endif !ATTSVR4 496 497 return (0); 498 } 499 500 /* 501 * uucp_conv - This is the conv (conversation) function called from 502 * a PAM authentication module to print error messages 503 * or garner information from the user. 504 */ 505 506 static int 507 uucp_conv(num_msg, msg, response, appdata_ptr) 508 int num_msg; 509 struct pam_message **msg; 510 struct pam_response **response; 511 void *appdata_ptr; 512 { 513 struct pam_message *m; 514 struct pam_response *r; 515 char *temp; 516 static char passwd[64]; 517 int k, i; 518 519 if (num_msg <= 0) 520 return (PAM_CONV_ERR); 521 522 *response = (struct pam_response *)calloc(num_msg, 523 sizeof (struct pam_response)); 524 if (*response == NULL) 525 return (PAM_BUF_ERR); 526 527 k = num_msg; 528 m = *msg; 529 r = *response; 530 while (k--) { 531 532 switch (m->msg_style) { 533 534 case PAM_PROMPT_ECHO_OFF: 535 /* 536 * we do this instead of using passed in message 537 * to prevent possible breakage of uucp protocol. 538 */ 539 printf("Password: "); fflush(stdout); 540 if (readline(passwd, sizeof (passwd)) < 0) { 541 fprintf(stderr, "passwd read\n"); 542 return (PAM_SUCCESS); 543 } 544 temp = passwd; 545 if (temp != NULL) { 546 r->resp = strdup(temp); 547 if (r->resp == NULL) { 548 /* free responses */ 549 r = *response; 550 for (i = 0; i < num_msg; i++, r++) { 551 if (r->resp) 552 free(r->resp); 553 } 554 free(*response); 555 *response = NULL; 556 return (PAM_BUF_ERR); 557 } 558 } 559 560 m++; 561 r++; 562 break; 563 564 case PAM_PROMPT_ECHO_ON: 565 if (m->msg != NULL) { 566 fputs(m->msg, stdout); 567 fflush(stdout); 568 } 569 r->resp = (char *)malloc(PAM_MAX_RESP_SIZE); 570 if (r->resp == NULL) { 571 /* free the response */ 572 r = *response; 573 for (i = 0; i < num_msg; i++, r++) { 574 if (r->resp) 575 free(r->resp); 576 } 577 free(*response); 578 *response = NULL; 579 return (PAM_BUF_ERR); 580 } 581 (void) fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); 582 m++; 583 r++; 584 break; 585 586 case PAM_ERROR_MSG: 587 if (m->msg != NULL) { 588 fputs(m->msg, stderr); 589 fputs("\n", stderr); 590 } 591 m++; 592 r++; 593 break; 594 case PAM_TEXT_INFO: 595 if (m->msg != NULL) { 596 fputs(m->msg, stdout); 597 fputs("\n", stdout); 598 } 599 m++; 600 r++; 601 break; 602 603 default: 604 break; 605 } 606 } 607 return (PAM_SUCCESS); 608 } 609