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