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 26 /* 27 * 4.2BSD, 2.9BSD, or ATTSVR4 TCP/IP server for uucico 28 * uucico's TCP channel causes this server to be run at the remote end. 29 */ 30 31 #include "uucp.h" 32 #include <netdb.h> 33 #ifdef BSD2_9 34 #include <sys/localopts.h> 35 #include <sys/file.h> 36 #endif /* BSD2_9 */ 37 #include <signal.h> 38 #include <errno.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <sys/wait.h> 42 #ifdef ATTSVTTY 43 #include <sys/termio.h> 44 #else 45 #include <sys/ioctl.h> 46 #endif 47 #include <pwd.h> 48 #ifdef ATTSVR4 49 #include <shadow.h> 50 #endif 51 #include <lastlog.h> 52 53 #include <security/pam_appl.h> 54 55 static int uucp_conv(); 56 struct pam_conv conv = {uucp_conv, NULL }; 57 pam_handle_t *pamh; 58 59 #if !defined(BSD4_2) && !defined(BSD2_9) && !defined(ATTSVR4) 60 --- You must have either BSD4_2, BSD2_9, or ATTSVR4 defined for this to work 61 #endif /* !BSD4_2 && !BSD2_9 */ 62 #if defined(BSD4_2) && defined(BSD2_9) 63 --- You may not have both BSD4_2 and BSD2_9 defined for this to work 64 #endif /* check for stupidity */ 65 66 char lastlog[] = "/var/adm/lastlog"; 67 struct passwd nouser = { 68 "", "nope", (uid_t)-1, (gid_t)-1, "", "", "", "", "" }; 69 #ifdef ATTSVR4 70 struct spwd noupass = { "", "nope" }; 71 #endif 72 struct sockaddr_in hisctladdr; 73 socklen_t hisaddrlen = (socklen_t)sizeof (hisctladdr); 74 struct sockaddr_in myctladdr; 75 int nolog; /* don't log in utmp or wtmp */ 76 77 char Username[64]; 78 char Loginname[64]; 79 char *nenv[] = { 80 Username, 81 Loginname, 82 NULL, 83 }; 84 extern char **environ; 85 86 static void doit(struct sockaddr_in *); 87 static void dologout(void); 88 89 int 90 main(argc, argv) 91 int argc; 92 char **argv; 93 { 94 #ifndef BSDINETD 95 int s, tcp_socket; 96 struct servent *sp; 97 #endif /* !BSDINETD */ 98 extern int errno; 99 100 if (argc > 1 && strcmp(argv[1], "-n") == 0) 101 nolog = 1; 102 environ = nenv; 103 #ifdef BSDINETD 104 close(1); close(2); 105 dup(0); dup(0); 106 hisaddrlen = (socklen_t)sizeof (hisctladdr); 107 if (getpeername(0, (struct sockaddr *)&hisctladdr, &hisaddrlen) < 0) { 108 fprintf(stderr, "%s: ", argv[0]); 109 perror("getpeername"); 110 _exit(1); 111 } 112 if (fork() == 0) 113 doit(&hisctladdr); 114 dologout(); 115 exit(1); 116 #else /* !BSDINETD */ 117 sp = getservbyname("uucp", "tcp"); 118 if (sp == NULL) { 119 perror("uucpd: getservbyname"); 120 exit(1); 121 } 122 if (fork()) 123 exit(0); 124 #ifdef ATTSVR4 125 setsid(); 126 #else 127 if ((s = open("/dev/tty", 2)) >= 0) { 128 ioctl(s, TIOCNOTTY, (char *)0); 129 close(s); 130 } 131 #endif 132 133 #ifdef ATTSVR4 134 memset((void *)&myctladdr, 0, sizeof (myctladdr)); 135 #else 136 bzero((char *)&myctladdr, sizeof (myctladdr)); 137 #endif 138 myctladdr.sin_family = AF_INET; 139 myctladdr.sin_port = sp->s_port; 140 #if defined(BSD4_2) || defined(ATTSVR4) 141 tcp_socket = socket(AF_INET, SOCK_STREAM, 0); 142 if (tcp_socket < 0) { 143 perror("uucpd: socket"); 144 exit(1); 145 } 146 if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) { 147 perror("uucpd: bind"); 148 exit(1); 149 } 150 listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */ 151 signal(SIGCHLD, dologout); 152 153 for (;;) { 154 s = accept(tcp_socket, &hisctladdr, &hisaddrlen); 155 if (s < 0) { 156 if (errno == EINTR) 157 continue; 158 perror("uucpd: accept"); 159 exit(1); 160 } 161 if (fork() == 0) { 162 close(0); close(1); close(2); 163 dup(s); dup(s); dup(s); 164 close(tcp_socket); close(s); 165 doit(&hisctladdr); 166 exit(1); 167 } 168 close(s); 169 } 170 #endif /* BSD4_2 */ 171 172 #ifdef BSD2_9 173 for (;;) { 174 signal(SIGCHLD, dologout); 175 s = socket(SOCK_STREAM, 0, &myctladdr, 176 SO_ACCEPTCONN|SO_KEEPALIVE); 177 if (s < 0) { 178 perror("uucpd: socket"); 179 exit(1); 180 } 181 if (accept(s, &hisctladdr) < 0) { 182 if (errno == EINTR) { 183 close(s); 184 continue; 185 } 186 perror("uucpd: accept"); 187 exit(1); 188 } 189 if (fork() == 0) { 190 close(0); close(1); close(2); 191 dup(s); dup(s); dup(s); 192 close(s); 193 doit(&hisctladdr); 194 exit(1); 195 } 196 } 197 #endif /* BSD2_9 */ 198 #endif /* !BSDINETD */ 199 200 /* NOTREACHED */ 201 } 202 203 static void 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 int 316 readline(p, n) 317 char *p; 318 int n; 319 { 320 char c; 321 322 while (n-- > 0) { 323 if (read(0, &c, 1) <= 0) 324 return (-1); 325 c &= 0177; 326 if (c == '\n' || c == '\r') { 327 *p = '\0'; 328 return (0); 329 } 330 *p++ = c; 331 } 332 return (-1); 333 } 334 335 #ifdef ATTSVR4 336 #include <sac.h> /* for SC_WILDC */ 337 #include <utmpx.h> 338 #else /* !ATTSVR4 */ 339 #include <utmp.h> 340 #endif /* !ATTSVR4 */ 341 #if defined(BSD4_2) || defined(ATTSVR4) 342 #include <fcntl.h> 343 #endif /* BSD4_2 */ 344 345 #ifdef BSD2_9 346 #define O_APPEND 0 /* kludge */ 347 #define wait3(a, b, c) wait2(a, b) 348 #endif /* BSD2_9 */ 349 350 #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 351 352 #ifdef ATTSVR4 353 struct utmpx utmp; 354 #else /* !ATTSVR4 */ 355 struct utmp utmp; 356 #endif /* !ATTSVR4 */ 357 358 static void 359 dologout(void) 360 { 361 #ifdef ATTSVR4 362 int status; 363 #else /* !ATTSVR4 */ 364 union wait status; 365 #endif /* !ATSVR4 */ 366 int pid, wtmp; 367 /* the following 2 variables are needed for utmp mgmt */ 368 struct utmpx ut; 369 370 #ifdef BSDINETD 371 while ((pid = wait(&status)) > 0) { 372 #else /* !BSDINETD */ 373 while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 374 #endif /* !BSDINETD */ 375 if (nolog) 376 continue; 377 #ifdef ATTSVR4 378 /* clear out any residue from utmpx buffer */ 379 (void) memset((char *)&ut, 0, sizeof (ut)); 380 381 SCPYN(utmp.ut_user, ""); 382 ut.ut_id[0] = 'u'; 383 ut.ut_id[1] = 'u'; 384 ut.ut_id[2] = SC_WILDC; 385 ut.ut_id[3] = SC_WILDC; 386 sprintf(ut.ut_line, "uucp%.4d", pid); 387 ut.ut_pid = getpid(); 388 ut.ut_type = DEAD_PROCESS; 389 ut.ut_exit.e_termination = status & 0xFF; 390 ut.ut_exit.e_exit = WEXITSTATUS(status); 391 SCPYN(ut.ut_host, ""); 392 ut.ut_syslen = 1; 393 (void) gettimeofday(&ut.ut_tv, NULL); 394 395 /* 396 * XXX: UUCPD does not do any pam session management. 397 * There is no way for the parent process to close 398 * the pam session after a child has exited. 399 */ 400 401 updwtmpx(WTMPX_FILE, &ut); 402 #else /* !ATTSVR4 */ 403 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 404 if (wtmp >= 0) { 405 sprintf(utmp.ut_line, "uucp%.4d", pid); 406 SCPYN(utmp.ut_name, ""); 407 SCPYN(utmp.ut_host, ""); 408 (void) time(&utmp.ut_time); 409 #ifdef BSD2_9 410 (void) lseek(wtmp, 0L, 2); 411 #endif /* BSD2_9 */ 412 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 413 (void) close(wtmp); 414 } 415 #endif /* !ATTSVR4 */ 416 } 417 } 418 419 /* 420 * Record login in wtmp file. 421 */ 422 int 423 dologin(pw, sin) 424 struct passwd *pw; 425 struct sockaddr_in *sin; 426 { 427 char line[32]; 428 char remotehost[32]; 429 int wtmp; 430 struct hostent *hp = gethostbyaddr((const char *)&sin->sin_addr, 431 sizeof (struct in_addr), AF_INET); 432 struct utmpx ut; 433 434 if (hp) { 435 strncpy(remotehost, hp->h_name, sizeof (remotehost)); 436 endhostent(); 437 } else 438 strncpy(remotehost, (char *)inet_ntoa(sin->sin_addr), 439 sizeof (remotehost)); 440 #ifdef ATTSVR4 441 /* clear wtmpx entry */ 442 (void) memset((void *)&ut, 0, sizeof (ut)); 443 444 SCPYN(ut.ut_user, pw->pw_name); 445 ut.ut_id[0] = 'u'; 446 ut.ut_id[1] = 'u'; 447 ut.ut_id[2] = SC_WILDC; 448 ut.ut_id[3] = SC_WILDC; 449 /* hack, but must be unique and no tty line */ 450 sprintf(line, "uucp%.4d", getpid()); 451 SCPYN(ut.ut_line, line); 452 ut.ut_pid = getpid(); 453 ut.ut_type = USER_PROCESS; 454 ut.ut_exit.e_termination = 0; 455 ut.ut_exit.e_exit = 0; 456 SCPYN(ut.ut_host, remotehost); 457 ut.ut_syslen = strlen(remotehost) + 1; 458 (void) gettimeofday(&ut.ut_tv, 0); 459 updwtmpx(WTMPX_FILE, &ut); 460 461 /* 462 * XXX: 463 * We no longer do session management in uucpd because 464 * there is no way to do the "pam_close_session()". 465 * 466 * Processes like "init" can do a pam_close_session() 467 * because they can use the utmp entry to retrieve 468 * the proper username, ttyname, etc. -- 469 * uucpd only writes to the wtmp file. 470 * 471 * ftpd (which also only writes to the wtmp file) 472 * can do a pam_close_session() because it doesn't fork(). 473 * 474 * if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS) 475 * return (1); 476 * if (pam_set_item(pamh, PAM_TTY, line) != PAM_SUCCESS) 477 * return (1); 478 * if (pam_open_session(pamh, 0) != PAM_SUCCESS) { 479 * return (1); 480 * } 481 */ 482 483 #else /* !ATTSVR4 */ 484 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 485 if (wtmp >= 0) { 486 /* hack, but must be unique and no tty line */ 487 sprintf(line, "uucp%.4d", getpid()); 488 SCPYN(utmp.ut_line, line); 489 SCPYN(utmp.ut_name, pw->pw_name); 490 SCPYN(utmp.ut_host, remotehost); 491 time(&utmp.ut_time); 492 #ifdef BSD2_9 493 (void) lseek(wtmp, 0L, 2); 494 #endif /* BSD2_9 */ 495 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 496 (void) close(wtmp); 497 } 498 #endif /* !ATTSVR4 */ 499 500 return (0); 501 } 502 503 /* 504 * uucp_conv - This is the conv (conversation) function called from 505 * a PAM authentication module to print error messages 506 * or garner information from the user. 507 */ 508 509 static int 510 uucp_conv(num_msg, msg, response, appdata_ptr) 511 int num_msg; 512 struct pam_message **msg; 513 struct pam_response **response; 514 void *appdata_ptr; 515 { 516 struct pam_message *m; 517 struct pam_response *r; 518 char *temp; 519 static char passwd[64]; 520 int k, i; 521 522 if (num_msg <= 0) 523 return (PAM_CONV_ERR); 524 525 *response = (struct pam_response *)calloc(num_msg, 526 sizeof (struct pam_response)); 527 if (*response == NULL) 528 return (PAM_BUF_ERR); 529 530 k = num_msg; 531 m = *msg; 532 r = *response; 533 while (k--) { 534 535 switch (m->msg_style) { 536 537 case PAM_PROMPT_ECHO_OFF: 538 /* 539 * we do this instead of using passed in message 540 * to prevent possible breakage of uucp protocol. 541 */ 542 printf("Password: "); fflush(stdout); 543 if (readline(passwd, sizeof (passwd)) < 0) { 544 fprintf(stderr, "passwd read\n"); 545 return (PAM_SUCCESS); 546 } 547 temp = passwd; 548 if (temp != NULL) { 549 r->resp = strdup(temp); 550 if (r->resp == NULL) { 551 /* free responses */ 552 r = *response; 553 for (i = 0; i < num_msg; i++, r++) { 554 if (r->resp) 555 free(r->resp); 556 } 557 free(*response); 558 *response = NULL; 559 return (PAM_BUF_ERR); 560 } 561 } 562 563 m++; 564 r++; 565 break; 566 567 case PAM_PROMPT_ECHO_ON: 568 if (m->msg != NULL) { 569 fputs(m->msg, stdout); 570 fflush(stdout); 571 } 572 r->resp = (char *)malloc(PAM_MAX_RESP_SIZE); 573 if (r->resp == NULL) { 574 /* free the response */ 575 r = *response; 576 for (i = 0; i < num_msg; i++, r++) { 577 if (r->resp) 578 free(r->resp); 579 } 580 free(*response); 581 *response = NULL; 582 return (PAM_BUF_ERR); 583 } 584 (void) fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); 585 m++; 586 r++; 587 break; 588 589 case PAM_ERROR_MSG: 590 if (m->msg != NULL) { 591 fputs(m->msg, stderr); 592 fputs("\n", stderr); 593 } 594 m++; 595 r++; 596 break; 597 case PAM_TEXT_INFO: 598 if (m->msg != NULL) { 599 fputs(m->msg, stdout); 600 fputs("\n", stdout); 601 } 602 m++; 603 r++; 604 break; 605 606 default: 607 break; 608 } 609 } 610 return (PAM_SUCCESS); 611 } 612