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