xref: /illumos-gate/usr/src/cmd/bnu/in.uucpd.c (revision 2de0a7d6)
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
main(argc,argv)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
doit(sinp)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
readline(p,n)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
dologout(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