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 52 #include <security/pam_appl.h> 53 54 static int uucp_conv(); 55 struct pam_conv conv = {uucp_conv, NULL }; 56 pam_handle_t *pamh; 57 58 #if !defined(BSD4_2) && !defined(BSD2_9) && !defined(ATTSVR4) 59 --- You must have either BSD4_2, BSD2_9, or ATTSVR4 defined for this to work 60 #endif /* !BSD4_2 && !BSD2_9 */ 61 #if defined(BSD4_2) && defined(BSD2_9) 62 --- You may not have both BSD4_2 and BSD2_9 defined for this to work 63 #endif /* check for stupidity */ 64 65 struct passwd nouser = { 66 "", "nope", (uid_t)-1, (gid_t)-1, "", "", "", "", "" }; 67 #ifdef ATTSVR4 68 struct spwd noupass = { "", "nope" }; 69 #endif 70 struct sockaddr_in hisctladdr; 71 socklen_t hisaddrlen = (socklen_t)sizeof (hisctladdr); 72 struct sockaddr_in myctladdr; 73 int nolog; /* don't log in utmp or wtmp */ 74 75 char Username[64]; 76 char Loginname[64]; 77 char *nenv[] = { 78 Username, 79 Loginname, 80 NULL, 81 }; 82 extern char **environ; 83 84 static void doit(struct sockaddr_in *); 85 static void dologout(void); 86 87 int 88 main(argc, argv) 89 int argc; 90 char **argv; 91 { 92 #ifndef BSDINETD 93 int s, tcp_socket; 94 struct servent *sp; 95 #endif /* !BSDINETD */ 96 extern int errno; 97 98 if (argc > 1 && strcmp(argv[1], "-n") == 0) 99 nolog = 1; 100 environ = nenv; 101 #ifdef BSDINETD 102 close(1); close(2); 103 dup(0); dup(0); 104 hisaddrlen = (socklen_t)sizeof (hisctladdr); 105 if (getpeername(0, (struct sockaddr *)&hisctladdr, &hisaddrlen) < 0) { 106 fprintf(stderr, "%s: ", argv[0]); 107 perror("getpeername"); 108 _exit(1); 109 } 110 if (fork() == 0) 111 doit(&hisctladdr); 112 dologout(); 113 exit(1); 114 #else /* !BSDINETD */ 115 sp = getservbyname("uucp", "tcp"); 116 if (sp == NULL) { 117 perror("uucpd: getservbyname"); 118 exit(1); 119 } 120 if (fork()) 121 exit(0); 122 #ifdef ATTSVR4 123 setsid(); 124 #else 125 if ((s = open("/dev/tty", 2)) >= 0) { 126 ioctl(s, TIOCNOTTY, (char *)0); 127 close(s); 128 } 129 #endif 130 131 #ifdef ATTSVR4 132 memset((void *)&myctladdr, 0, sizeof (myctladdr)); 133 #else 134 bzero((char *)&myctladdr, sizeof (myctladdr)); 135 #endif 136 myctladdr.sin_family = AF_INET; 137 myctladdr.sin_port = sp->s_port; 138 #if defined(BSD4_2) || defined(ATTSVR4) 139 tcp_socket = socket(AF_INET, SOCK_STREAM, 0); 140 if (tcp_socket < 0) { 141 perror("uucpd: socket"); 142 exit(1); 143 } 144 if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) { 145 perror("uucpd: bind"); 146 exit(1); 147 } 148 listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */ 149 signal(SIGCHLD, dologout); 150 151 for (;;) { 152 s = accept(tcp_socket, &hisctladdr, &hisaddrlen); 153 if (s < 0) { 154 if (errno == EINTR) 155 continue; 156 perror("uucpd: accept"); 157 exit(1); 158 } 159 if (fork() == 0) { 160 close(0); close(1); close(2); 161 dup(s); dup(s); dup(s); 162 close(tcp_socket); close(s); 163 doit(&hisctladdr); 164 exit(1); 165 } 166 close(s); 167 } 168 #endif /* BSD4_2 */ 169 170 #ifdef BSD2_9 171 for (;;) { 172 signal(SIGCHLD, dologout); 173 s = socket(SOCK_STREAM, 0, &myctladdr, 174 SO_ACCEPTCONN|SO_KEEPALIVE); 175 if (s < 0) { 176 perror("uucpd: socket"); 177 exit(1); 178 } 179 if (accept(s, &hisctladdr) < 0) { 180 if (errno == EINTR) { 181 close(s); 182 continue; 183 } 184 perror("uucpd: accept"); 185 exit(1); 186 } 187 if (fork() == 0) { 188 close(0); close(1); close(2); 189 dup(s); dup(s); dup(s); 190 close(s); 191 doit(&hisctladdr); 192 exit(1); 193 } 194 } 195 #endif /* BSD2_9 */ 196 #endif /* !BSDINETD */ 197 198 /* NOTREACHED */ 199 } 200 201 static void 202 doit(sinp) 203 struct sockaddr_in *sinp; 204 { 205 char user[64], passwd[64]; 206 struct passwd *pw, *getpwnam(); 207 int error; 208 209 alarm(60); 210 printf("login: "); fflush(stdout); 211 if (readline(user, sizeof (user)) < 0) { 212 fprintf(stderr, "user read\n"); 213 return; 214 } 215 216 /* 217 * Call pam_start to initiate a PAM authentication operation 218 */ 219 220 if ((pam_start("uucp", user, &conv, &pamh)) != PAM_SUCCESS) 221 return; 222 if ((pam_set_item(pamh, PAM_TTY, ttyname(0))) != PAM_SUCCESS) 223 return; 224 225 if (pam_authenticate(pamh, PAM_SILENT) != PAM_SUCCESS) { 226 /* force a delay if passwd bad */ 227 sleep(4); 228 fprintf(stderr, "Login incorrect."); 229 pam_end(pamh, PAM_ABORT); 230 return; 231 } 232 233 if ((error = pam_acct_mgmt(pamh, PAM_SILENT)) != PAM_SUCCESS) { 234 switch (error) { 235 case PAM_NEW_AUTHTOK_REQD: 236 fprintf(stderr, "Password Expired."); 237 break; 238 case PAM_PERM_DENIED: 239 fprintf(stderr, "Account Expired."); 240 break; 241 case PAM_AUTHTOK_EXPIRED: 242 fprintf(stderr, "Password Expired."); 243 break; 244 default: 245 fprintf(stderr, "Login incorrect."); 246 break; 247 } 248 pam_end(pamh, PAM_ABORT); 249 return; 250 } 251 252 if ((pw = getpwnam(user)) == NULL || strcmp(pw->pw_shell, UUCICO)) { 253 /* force a delay if user bad */ 254 sleep(4); 255 fprintf(stderr, "Login incorrect."); 256 pam_end(pamh, PAM_USER_UNKNOWN); 257 return; 258 } 259 260 alarm(0); 261 262 sprintf(Username, "USER=%s", user); 263 sprintf(Loginname, "LOGNAME=%s", user); 264 if (!nolog) 265 if (dologin(pw, sinp)) { 266 pam_end(pamh, PAM_ABORT); 267 _exit(1); 268 } 269 270 /* set the real (and effective) GID */ 271 if (setgid(pw->pw_gid) == -1) { 272 fprintf(stderr, "Login incorrect."); 273 pam_end(pamh, PAM_PERM_DENIED); 274 return; 275 } 276 277 /* 278 * Initialize the supplementary group access list. 279 */ 280 if (initgroups(user, pw->pw_gid) == -1) { 281 fprintf(stderr, "Login incorrect."); 282 pam_end(pamh, PAM_PERM_DENIED); 283 return; 284 } 285 286 if (pam_setcred(pamh, PAM_ESTABLISH_CRED) != PAM_SUCCESS) { 287 fprintf(stderr, "Login incorrect."); 288 pam_end(pamh, PAM_CRED_INSUFFICIENT); 289 return; 290 } 291 292 /* set the real (and effective) UID */ 293 if (setuid(pw->pw_uid) == -1) { 294 fprintf(stderr, "Login incorrect."); 295 pam_end(pamh, PAM_CRED_ERR); 296 return; 297 } 298 299 chdir(pw->pw_dir); 300 301 pam_end(pamh, PAM_SUCCESS); 302 303 #if defined(BSD4_2) || defined(ATTSVR4) 304 execl(UUCICO, "uucico", "-u", user, (char *)0); 305 #endif /* BSD4_2 */ 306 #ifdef BSD2_9 307 sprintf(passwd, "-h%s", inet_ntoa(sinp->sin_addr)); 308 execl(UUCICO, "uucico", passwd, (char *)0); 309 #endif /* BSD2_9 */ 310 perror("uucico server: execl"); 311 } 312 313 int 314 readline(p, n) 315 char *p; 316 int n; 317 { 318 char c; 319 320 while (n-- > 0) { 321 if (read(0, &c, 1) <= 0) 322 return (-1); 323 c &= 0177; 324 if (c == '\n' || c == '\r') { 325 *p = '\0'; 326 return (0); 327 } 328 *p++ = c; 329 } 330 return (-1); 331 } 332 333 #ifdef ATTSVR4 334 #include <sac.h> /* for SC_WILDC */ 335 #include <utmpx.h> 336 #else /* !ATTSVR4 */ 337 #include <utmp.h> 338 #endif /* !ATTSVR4 */ 339 #if defined(BSD4_2) || defined(ATTSVR4) 340 #include <fcntl.h> 341 #endif /* BSD4_2 */ 342 343 #ifdef BSD2_9 344 #define O_APPEND 0 /* kludge */ 345 #define wait3(a, b, c) wait2(a, b) 346 #endif /* BSD2_9 */ 347 348 #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 349 350 #ifdef ATTSVR4 351 struct utmpx utmp; 352 #else /* !ATTSVR4 */ 353 struct utmp utmp; 354 #endif /* !ATTSVR4 */ 355 356 static void 357 dologout(void) 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 int 421 dologin(pw, sin) 422 struct passwd *pw; 423 struct sockaddr_in *sin; 424 { 425 char line[32]; 426 char remotehost[32]; 427 int wtmp; 428 struct hostent *hp = gethostbyaddr((const char *)&sin->sin_addr, 429 sizeof (struct in_addr), AF_INET); 430 struct utmpx ut; 431 432 if (hp) { 433 strncpy(remotehost, hp->h_name, sizeof (remotehost)); 434 endhostent(); 435 } else 436 strncpy(remotehost, (char *)inet_ntoa(sin->sin_addr), 437 sizeof (remotehost)); 438 #ifdef ATTSVR4 439 /* clear wtmpx entry */ 440 (void) memset((void *)&ut, 0, sizeof (ut)); 441 442 SCPYN(ut.ut_user, pw->pw_name); 443 ut.ut_id[0] = 'u'; 444 ut.ut_id[1] = 'u'; 445 ut.ut_id[2] = SC_WILDC; 446 ut.ut_id[3] = SC_WILDC; 447 /* hack, but must be unique and no tty line */ 448 sprintf(line, "uucp%.4d", getpid()); 449 SCPYN(ut.ut_line, line); 450 ut.ut_pid = getpid(); 451 ut.ut_type = USER_PROCESS; 452 ut.ut_exit.e_termination = 0; 453 ut.ut_exit.e_exit = 0; 454 SCPYN(ut.ut_host, remotehost); 455 ut.ut_syslen = strlen(remotehost) + 1; 456 (void) gettimeofday(&ut.ut_tv, 0); 457 updwtmpx(WTMPX_FILE, &ut); 458 459 /* 460 * XXX: 461 * We no longer do session management in uucpd because 462 * there is no way to do the "pam_close_session()". 463 * 464 * Processes like "init" can do a pam_close_session() 465 * because they can use the utmp entry to retrieve 466 * the proper username, ttyname, etc. -- 467 * uucpd only writes to the wtmp file. 468 * 469 * ftpd (which also only writes to the wtmp file) 470 * can do a pam_close_session() because it doesn't fork(). 471 * 472 * if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS) 473 * return (1); 474 * if (pam_set_item(pamh, PAM_TTY, line) != PAM_SUCCESS) 475 * return (1); 476 * if (pam_open_session(pamh, 0) != PAM_SUCCESS) { 477 * return (1); 478 * } 479 */ 480 481 #else /* !ATTSVR4 */ 482 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND); 483 if (wtmp >= 0) { 484 /* hack, but must be unique and no tty line */ 485 sprintf(line, "uucp%.4d", getpid()); 486 SCPYN(utmp.ut_line, line); 487 SCPYN(utmp.ut_name, pw->pw_name); 488 SCPYN(utmp.ut_host, remotehost); 489 time(&utmp.ut_time); 490 #ifdef BSD2_9 491 (void) lseek(wtmp, 0L, 2); 492 #endif /* BSD2_9 */ 493 (void) write(wtmp, (char *)&utmp, sizeof (utmp)); 494 (void) close(wtmp); 495 } 496 #endif /* !ATTSVR4 */ 497 498 return (0); 499 } 500 501 /* 502 * uucp_conv - This is the conv (conversation) function called from 503 * a PAM authentication module to print error messages 504 * or garner information from the user. 505 */ 506 507 static int 508 uucp_conv(num_msg, msg, response, appdata_ptr) 509 int num_msg; 510 struct pam_message **msg; 511 struct pam_response **response; 512 void *appdata_ptr; 513 { 514 struct pam_message *m; 515 struct pam_response *r; 516 char *temp; 517 static char passwd[64]; 518 int k, i; 519 520 if (num_msg <= 0) 521 return (PAM_CONV_ERR); 522 523 *response = (struct pam_response *)calloc(num_msg, 524 sizeof (struct pam_response)); 525 if (*response == NULL) 526 return (PAM_BUF_ERR); 527 528 k = num_msg; 529 m = *msg; 530 r = *response; 531 while (k--) { 532 533 switch (m->msg_style) { 534 535 case PAM_PROMPT_ECHO_OFF: 536 /* 537 * we do this instead of using passed in message 538 * to prevent possible breakage of uucp protocol. 539 */ 540 printf("Password: "); fflush(stdout); 541 if (readline(passwd, sizeof (passwd)) < 0) { 542 fprintf(stderr, "passwd read\n"); 543 return (PAM_SUCCESS); 544 } 545 temp = passwd; 546 if (temp != NULL) { 547 r->resp = strdup(temp); 548 if (r->resp == NULL) { 549 /* free responses */ 550 r = *response; 551 for (i = 0; i < num_msg; i++, r++) { 552 if (r->resp) 553 free(r->resp); 554 } 555 free(*response); 556 *response = NULL; 557 return (PAM_BUF_ERR); 558 } 559 } 560 561 m++; 562 r++; 563 break; 564 565 case PAM_PROMPT_ECHO_ON: 566 if (m->msg != NULL) { 567 fputs(m->msg, stdout); 568 fflush(stdout); 569 } 570 r->resp = (char *)malloc(PAM_MAX_RESP_SIZE); 571 if (r->resp == NULL) { 572 /* free the response */ 573 r = *response; 574 for (i = 0; i < num_msg; i++, r++) { 575 if (r->resp) 576 free(r->resp); 577 } 578 free(*response); 579 *response = NULL; 580 return (PAM_BUF_ERR); 581 } 582 (void) fgets(r->resp, PAM_MAX_RESP_SIZE, stdin); 583 m++; 584 r++; 585 break; 586 587 case PAM_ERROR_MSG: 588 if (m->msg != NULL) { 589 fputs(m->msg, stderr); 590 fputs("\n", stderr); 591 } 592 m++; 593 r++; 594 break; 595 case PAM_TEXT_INFO: 596 if (m->msg != NULL) { 597 fputs(m->msg, stdout); 598 fputs("\n", stdout); 599 } 600 m++; 601 r++; 602 break; 603 604 default: 605 break; 606 } 607 } 608 return (PAM_SUCCESS); 609 } 610