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 #include <lastlog.h>
52
53 #include <security/pam_appl.h>
54
55 static int uucp_conv();
56 struct pam_conv conv = {uucp_conv, NULL };
57 pam_handle_t *pamh;
58
59 #if !defined(BSD4_2) && !defined(BSD2_9) && !defined(ATTSVR4)
60 --- You must have either BSD4_2, BSD2_9, or ATTSVR4 defined for this to work
61 #endif /* !BSD4_2 && !BSD2_9 */
62 #if defined(BSD4_2) && defined(BSD2_9)
63 --- You may not have both BSD4_2 and BSD2_9 defined for this to work
64 #endif /* check for stupidity */
65
66 char lastlog[] = "/var/adm/lastlog";
67 struct passwd nouser = {
68 "", "nope", (uid_t)-1, (gid_t)-1, "", "", "", "", "" };
69 #ifdef ATTSVR4
70 struct spwd noupass = { "", "nope" };
71 #endif
72 struct sockaddr_in hisctladdr;
73 socklen_t hisaddrlen = (socklen_t)sizeof (hisctladdr);
74 struct sockaddr_in myctladdr;
75 int nolog; /* don't log in utmp or wtmp */
76
77 char Username[64];
78 char Loginname[64];
79 char *nenv[] = {
80 Username,
81 Loginname,
82 NULL,
83 };
84 extern char **environ;
85
86 static void doit(struct sockaddr_in *);
87 static void dologout(void);
88
89 int
main(argc,argv)90 main(argc, argv)
91 int argc;
92 char **argv;
93 {
94 #ifndef BSDINETD
95 int s, tcp_socket;
96 struct servent *sp;
97 #endif /* !BSDINETD */
98 extern int errno;
99
100 if (argc > 1 && strcmp(argv[1], "-n") == 0)
101 nolog = 1;
102 environ = nenv;
103 #ifdef BSDINETD
104 close(1); close(2);
105 dup(0); dup(0);
106 hisaddrlen = (socklen_t)sizeof (hisctladdr);
107 if (getpeername(0, (struct sockaddr *)&hisctladdr, &hisaddrlen) < 0) {
108 fprintf(stderr, "%s: ", argv[0]);
109 perror("getpeername");
110 _exit(1);
111 }
112 if (fork() == 0)
113 doit(&hisctladdr);
114 dologout();
115 exit(1);
116 #else /* !BSDINETD */
117 sp = getservbyname("uucp", "tcp");
118 if (sp == NULL) {
119 perror("uucpd: getservbyname");
120 exit(1);
121 }
122 if (fork())
123 exit(0);
124 #ifdef ATTSVR4
125 setsid();
126 #else
127 if ((s = open("/dev/tty", 2)) >= 0) {
128 ioctl(s, TIOCNOTTY, (char *)0);
129 close(s);
130 }
131 #endif
132
133 #ifdef ATTSVR4
134 memset((void *)&myctladdr, 0, sizeof (myctladdr));
135 #else
136 bzero((char *)&myctladdr, sizeof (myctladdr));
137 #endif
138 myctladdr.sin_family = AF_INET;
139 myctladdr.sin_port = sp->s_port;
140 #if defined(BSD4_2) || defined(ATTSVR4)
141 tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
142 if (tcp_socket < 0) {
143 perror("uucpd: socket");
144 exit(1);
145 }
146 if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) {
147 perror("uucpd: bind");
148 exit(1);
149 }
150 listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */
151 signal(SIGCHLD, dologout);
152
153 for (;;) {
154 s = accept(tcp_socket, &hisctladdr, &hisaddrlen);
155 if (s < 0) {
156 if (errno == EINTR)
157 continue;
158 perror("uucpd: accept");
159 exit(1);
160 }
161 if (fork() == 0) {
162 close(0); close(1); close(2);
163 dup(s); dup(s); dup(s);
164 close(tcp_socket); close(s);
165 doit(&hisctladdr);
166 exit(1);
167 }
168 close(s);
169 }
170 #endif /* BSD4_2 */
171
172 #ifdef BSD2_9
173 for (;;) {
174 signal(SIGCHLD, dologout);
175 s = socket(SOCK_STREAM, 0, &myctladdr,
176 SO_ACCEPTCONN|SO_KEEPALIVE);
177 if (s < 0) {
178 perror("uucpd: socket");
179 exit(1);
180 }
181 if (accept(s, &hisctladdr) < 0) {
182 if (errno == EINTR) {
183 close(s);
184 continue;
185 }
186 perror("uucpd: accept");
187 exit(1);
188 }
189 if (fork() == 0) {
190 close(0); close(1); close(2);
191 dup(s); dup(s); dup(s);
192 close(s);
193 doit(&hisctladdr);
194 exit(1);
195 }
196 }
197 #endif /* BSD2_9 */
198 #endif /* !BSDINETD */
199
200 /* NOTREACHED */
201 }
202
203 static void
doit(sinp)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 int
readline(p,n)316 readline(p, n)
317 char *p;
318 int n;
319 {
320 char c;
321
322 while (n-- > 0) {
323 if (read(0, &c, 1) <= 0)
324 return (-1);
325 c &= 0177;
326 if (c == '\n' || c == '\r') {
327 *p = '\0';
328 return (0);
329 }
330 *p++ = c;
331 }
332 return (-1);
333 }
334
335 #ifdef ATTSVR4
336 #include <sac.h> /* for SC_WILDC */
337 #include <utmpx.h>
338 #else /* !ATTSVR4 */
339 #include <utmp.h>
340 #endif /* !ATTSVR4 */
341 #if defined(BSD4_2) || defined(ATTSVR4)
342 #include <fcntl.h>
343 #endif /* BSD4_2 */
344
345 #ifdef BSD2_9
346 #define O_APPEND 0 /* kludge */
347 #define wait3(a, b, c) wait2(a, b)
348 #endif /* BSD2_9 */
349
350 #define SCPYN(a, b) strncpy(a, b, sizeof (a))
351
352 #ifdef ATTSVR4
353 struct utmpx utmp;
354 #else /* !ATTSVR4 */
355 struct utmp utmp;
356 #endif /* !ATTSVR4 */
357
358 static void
dologout(void)359 dologout(void)
360 {
361 #ifdef ATTSVR4
362 int status;
363 #else /* !ATTSVR4 */
364 union wait status;
365 #endif /* !ATSVR4 */
366 int pid, wtmp;
367 /* the following 2 variables are needed for utmp mgmt */
368 struct utmpx ut;
369
370 #ifdef BSDINETD
371 while ((pid = wait(&status)) > 0) {
372 #else /* !BSDINETD */
373 while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
374 #endif /* !BSDINETD */
375 if (nolog)
376 continue;
377 #ifdef ATTSVR4
378 /* clear out any residue from utmpx buffer */
379 (void) memset((char *)&ut, 0, sizeof (ut));
380
381 SCPYN(utmp.ut_user, "");
382 ut.ut_id[0] = 'u';
383 ut.ut_id[1] = 'u';
384 ut.ut_id[2] = SC_WILDC;
385 ut.ut_id[3] = SC_WILDC;
386 sprintf(ut.ut_line, "uucp%.4d", pid);
387 ut.ut_pid = getpid();
388 ut.ut_type = DEAD_PROCESS;
389 ut.ut_exit.e_termination = status & 0xFF;
390 ut.ut_exit.e_exit = WEXITSTATUS(status);
391 SCPYN(ut.ut_host, "");
392 ut.ut_syslen = 1;
393 (void) gettimeofday(&ut.ut_tv, NULL);
394
395 /*
396 * XXX: UUCPD does not do any pam session management.
397 * There is no way for the parent process to close
398 * the pam session after a child has exited.
399 */
400
401 updwtmpx(WTMPX_FILE, &ut);
402 #else /* !ATTSVR4 */
403 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
404 if (wtmp >= 0) {
405 sprintf(utmp.ut_line, "uucp%.4d", pid);
406 SCPYN(utmp.ut_name, "");
407 SCPYN(utmp.ut_host, "");
408 (void) time(&utmp.ut_time);
409 #ifdef BSD2_9
410 (void) lseek(wtmp, 0L, 2);
411 #endif /* BSD2_9 */
412 (void) write(wtmp, (char *)&utmp, sizeof (utmp));
413 (void) close(wtmp);
414 }
415 #endif /* !ATTSVR4 */
416 }
417 }
418
419 /*
420 * Record login in wtmp file.
421 */
422 int
423 dologin(pw, sin)
424 struct passwd *pw;
425 struct sockaddr_in *sin;
426 {
427 char line[32];
428 char remotehost[32];
429 int wtmp;
430 struct hostent *hp = gethostbyaddr((const char *)&sin->sin_addr,
431 sizeof (struct in_addr), AF_INET);
432 struct utmpx ut;
433
434 if (hp) {
435 strncpy(remotehost, hp->h_name, sizeof (remotehost));
436 endhostent();
437 } else
438 strncpy(remotehost, (char *)inet_ntoa(sin->sin_addr),
439 sizeof (remotehost));
440 #ifdef ATTSVR4
441 /* clear wtmpx entry */
442 (void) memset((void *)&ut, 0, sizeof (ut));
443
444 SCPYN(ut.ut_user, pw->pw_name);
445 ut.ut_id[0] = 'u';
446 ut.ut_id[1] = 'u';
447 ut.ut_id[2] = SC_WILDC;
448 ut.ut_id[3] = SC_WILDC;
449 /* hack, but must be unique and no tty line */
450 sprintf(line, "uucp%.4d", getpid());
451 SCPYN(ut.ut_line, line);
452 ut.ut_pid = getpid();
453 ut.ut_type = USER_PROCESS;
454 ut.ut_exit.e_termination = 0;
455 ut.ut_exit.e_exit = 0;
456 SCPYN(ut.ut_host, remotehost);
457 ut.ut_syslen = strlen(remotehost) + 1;
458 (void) gettimeofday(&ut.ut_tv, 0);
459 updwtmpx(WTMPX_FILE, &ut);
460
461 /*
462 * XXX:
463 * We no longer do session management in uucpd because
464 * there is no way to do the "pam_close_session()".
465 *
466 * Processes like "init" can do a pam_close_session()
467 * because they can use the utmp entry to retrieve
468 * the proper username, ttyname, etc. --
469 * uucpd only writes to the wtmp file.
470 *
471 * ftpd (which also only writes to the wtmp file)
472 * can do a pam_close_session() because it doesn't fork().
473 *
474 * if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS)
475 * return (1);
476 * if (pam_set_item(pamh, PAM_TTY, line) != PAM_SUCCESS)
477 * return (1);
478 * if (pam_open_session(pamh, 0) != PAM_SUCCESS) {
479 * return (1);
480 * }
481 */
482
483 #else /* !ATTSVR4 */
484 wtmp = open("/usr/adm/wtmp", O_WRONLY|O_APPEND);
485 if (wtmp >= 0) {
486 /* hack, but must be unique and no tty line */
487 sprintf(line, "uucp%.4d", getpid());
488 SCPYN(utmp.ut_line, line);
489 SCPYN(utmp.ut_name, pw->pw_name);
490 SCPYN(utmp.ut_host, remotehost);
491 time(&utmp.ut_time);
492 #ifdef BSD2_9
493 (void) lseek(wtmp, 0L, 2);
494 #endif /* BSD2_9 */
495 (void) write(wtmp, (char *)&utmp, sizeof (utmp));
496 (void) close(wtmp);
497 }
498 #endif /* !ATTSVR4 */
499
500 return (0);
501 }
502
503 /*
504 * uucp_conv - This is the conv (conversation) function called from
505 * a PAM authentication module to print error messages
506 * or garner information from the user.
507 */
508
509 static int
510 uucp_conv(num_msg, msg, response, appdata_ptr)
511 int num_msg;
512 struct pam_message **msg;
513 struct pam_response **response;
514 void *appdata_ptr;
515 {
516 struct pam_message *m;
517 struct pam_response *r;
518 char *temp;
519 static char passwd[64];
520 int k, i;
521
522 if (num_msg <= 0)
523 return (PAM_CONV_ERR);
524
525 *response = (struct pam_response *)calloc(num_msg,
526 sizeof (struct pam_response));
527 if (*response == NULL)
528 return (PAM_BUF_ERR);
529
530 k = num_msg;
531 m = *msg;
532 r = *response;
533 while (k--) {
534
535 switch (m->msg_style) {
536
537 case PAM_PROMPT_ECHO_OFF:
538 /*
539 * we do this instead of using passed in message
540 * to prevent possible breakage of uucp protocol.
541 */
542 printf("Password: "); fflush(stdout);
543 if (readline(passwd, sizeof (passwd)) < 0) {
544 fprintf(stderr, "passwd read\n");
545 return (PAM_SUCCESS);
546 }
547 temp = passwd;
548 if (temp != NULL) {
549 r->resp = strdup(temp);
550 if (r->resp == NULL) {
551 /* free responses */
552 r = *response;
553 for (i = 0; i < num_msg; i++, r++) {
554 if (r->resp)
555 free(r->resp);
556 }
557 free(*response);
558 *response = NULL;
559 return (PAM_BUF_ERR);
560 }
561 }
562
563 m++;
564 r++;
565 break;
566
567 case PAM_PROMPT_ECHO_ON:
568 if (m->msg != NULL) {
569 fputs(m->msg, stdout);
570 fflush(stdout);
571 }
572 r->resp = (char *)malloc(PAM_MAX_RESP_SIZE);
573 if (r->resp == NULL) {
574 /* free the response */
575 r = *response;
576 for (i = 0; i < num_msg; i++, r++) {
577 if (r->resp)
578 free(r->resp);
579 }
580 free(*response);
581 *response = NULL;
582 return (PAM_BUF_ERR);
583 }
584 (void) fgets(r->resp, PAM_MAX_RESP_SIZE, stdin);
585 m++;
586 r++;
587 break;
588
589 case PAM_ERROR_MSG:
590 if (m->msg != NULL) {
591 fputs(m->msg, stderr);
592 fputs("\n", stderr);
593 }
594 m++;
595 r++;
596 break;
597 case PAM_TEXT_INFO:
598 if (m->msg != NULL) {
599 fputs(m->msg, stdout);
600 fputs("\n", stdout);
601 }
602 m++;
603 r++;
604 break;
605
606 default:
607 break;
608 }
609 }
610 return (PAM_SUCCESS);
611 }
612