Home | History | Annotate | Download | only in bnu
      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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     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 	struct pam_message **msg;
    515 	struct pam_response **response;
    516 	void *appdata_ptr;
    517 {
    518 	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