xref: /illumos-gate/usr/src/cmd/bnu/in.uucpd.c (revision 7c478bd9)
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