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.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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.
36 #include <sys/localopts.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
45 #include <sys/termio.h>
47 #include <sys/ioctl.h>
55 #include <security/pam_appl.h>
57 static int uucp_conv();
58 struct pam_conv conv
= {uucp_conv
, NULL
};
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 */
68 char lastlog
[] = "/var/adm/lastlog";
69 struct passwd nouser
= {
70 "", "nope", (uid_t
)-1, (gid_t
)-1, "", "", "", "", "" };
72 struct spwd noupass
= { "", "nope" };
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 */
86 extern char **environ
;
88 static void doit(struct sockaddr_in
*);
89 static void dologout(void);
99 #endif /* !BSDINETD */
102 if (argc
> 1 && strcmp(argv
[1], "-n") == 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");
118 #else /* !BSDINETD */
119 sp
= getservbyname("uucp", "tcp");
121 perror("uucpd: getservbyname");
129 if ((s
= open("/dev/tty", 2)) >= 0) {
130 ioctl(s
, TIOCNOTTY
, (char *)0);
136 memset((void *)&myctladdr
, 0, sizeof (myctladdr
));
138 bzero((char *)&myctladdr
, sizeof (myctladdr
));
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");
148 if (bind(tcp_socket
, (char *)&myctladdr
, sizeof (myctladdr
)) < 0) {
149 perror("uucpd: bind");
152 listen(tcp_socket
, 3); /* at most 3 simultaneuos uucp connections */
153 signal(SIGCHLD
, dologout
);
156 s
= accept(tcp_socket
, &hisctladdr
, &hisaddrlen
);
160 perror("uucpd: accept");
164 close(0); close(1); close(2);
165 dup(s
); dup(s
); dup(s
);
166 close(tcp_socket
); close(s
);
176 signal(SIGCHLD
, dologout
);
177 s
= socket(SOCK_STREAM
, 0, &myctladdr
,
178 SO_ACCEPTCONN
|SO_KEEPALIVE
);
180 perror("uucpd: socket");
183 if (accept(s
, &hisctladdr
) < 0) {
184 if (errno
== EINTR
) {
188 perror("uucpd: accept");
192 close(0); close(1); close(2);
193 dup(s
); dup(s
); dup(s
);
200 #endif /* !BSDINETD */
207 struct sockaddr_in
*sinp
;
209 char user
[64], passwd
[64];
210 struct passwd
*pw
, *getpwnam();
214 printf("login: "); fflush(stdout
);
215 if (readline(user
, sizeof (user
)) < 0) {
216 fprintf(stderr
, "user read\n");
221 * Call pam_start to initiate a PAM authentication operation
224 if ((pam_start("uucp", user
, &conv
, &pamh
)) != PAM_SUCCESS
)
226 if ((pam_set_item(pamh
, PAM_TTY
, ttyname(0))) != PAM_SUCCESS
)
229 if (pam_authenticate(pamh
, PAM_SILENT
) != PAM_SUCCESS
) {
230 /* force a delay if passwd bad */
232 fprintf(stderr
, "Login incorrect.");
233 pam_end(pamh
, PAM_ABORT
);
237 if ((error
= pam_acct_mgmt(pamh
, PAM_SILENT
)) != PAM_SUCCESS
) {
239 case PAM_NEW_AUTHTOK_REQD
:
240 fprintf(stderr
, "Password Expired.");
242 case PAM_PERM_DENIED
:
243 fprintf(stderr
, "Account Expired.");
245 case PAM_AUTHTOK_EXPIRED
:
246 fprintf(stderr
, "Password Expired.");
249 fprintf(stderr
, "Login incorrect.");
252 pam_end(pamh
, PAM_ABORT
);
256 if ((pw
= getpwnam(user
)) == NULL
|| strcmp(pw
->pw_shell
, UUCICO
)) {
257 /* force a delay if user bad */
259 fprintf(stderr
, "Login incorrect.");
260 pam_end(pamh
, PAM_USER_UNKNOWN
);
266 sprintf(Username
, "USER=%s", user
);
267 sprintf(Loginname
, "LOGNAME=%s", user
);
269 if (dologin(pw
, sinp
)) {
270 pam_end(pamh
, PAM_ABORT
);
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
);
282 * Initialize the supplementary group access list.
284 if (initgroups(user
, pw
->pw_gid
) == -1) {
285 fprintf(stderr
, "Login incorrect.");
286 pam_end(pamh
, PAM_PERM_DENIED
);
290 if (pam_setcred(pamh
, PAM_ESTABLISH_CRED
) != PAM_SUCCESS
) {
291 fprintf(stderr
, "Login incorrect.");
292 pam_end(pamh
, PAM_CRED_INSUFFICIENT
);
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
);
305 pam_end(pamh
, PAM_SUCCESS
);
307 #if defined(BSD4_2) || defined(ATTSVR4)
308 execl(UUCICO
, "uucico", "-u", user
, (char *)0);
311 sprintf(passwd
, "-h%s", inet_ntoa(sinp
->sin_addr
));
312 execl(UUCICO
, "uucico", passwd
, (char *)0);
314 perror("uucico server: execl");
325 if (read(0, &c
, 1) <= 0)
328 if (c
== '\n' || c
== '\r') {
338 #include <sac.h> /* for SC_WILDC */
342 #endif /* !ATTSVR4 */
343 #if defined(BSD4_2) || defined(ATTSVR4)
348 #define O_APPEND 0 /* kludge */
349 #define wait3(a, b, c) wait2(a, b)
352 #define SCPYN(a, b) strncpy(a, b, sizeof (a))
358 #endif /* !ATTSVR4 */
369 /* the following 2 variables are needed for utmp mgmt */
373 while ((pid
= wait(&status
)) > 0) {
374 #else /* !BSDINETD */
375 while ((pid
= wait3(&status
, WNOHANG
, 0)) > 0) {
376 #endif /* !BSDINETD */
380 /* clear out any residue from utmpx buffer */
381 (void) memset((char *)&ut
, 0, sizeof (ut
));
383 SCPYN(utmp
.ut_user
, "");
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
, "");
395 (void) gettimeofday(&ut
.ut_tv
, NULL
);
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.
403 updwtmpx(WTMPX_FILE
, &ut
);
405 wtmp
= open("/usr/adm/wtmp", O_WRONLY
|O_APPEND
);
407 sprintf(utmp
.ut_line
, "uucp%.4d", pid
);
408 SCPYN(utmp
.ut_name
, "");
409 SCPYN(utmp
.ut_host
, "");
410 (void) time(&utmp
.ut_time
);
412 (void) lseek(wtmp
, 0L, 2);
414 (void) write(wtmp
, (char *)&utmp
, sizeof (utmp
));
417 #endif /* !ATTSVR4 */
422 * Record login in wtmp file.
427 struct sockaddr_in
*sin
;
432 struct hostent
*hp
= gethostbyaddr((const char *)&sin
->sin_addr
,
433 sizeof (struct in_addr
), AF_INET
);
437 strncpy(remotehost
, hp
->h_name
, sizeof (remotehost
));
440 strncpy(remotehost
, (char *)inet_ntoa(sin
->sin_addr
),
441 sizeof (remotehost
));
443 /* clear wtmpx entry */
444 (void) memset((void *)&ut
, 0, sizeof (ut
));
446 SCPYN(ut
.ut_user
, pw
->pw_name
);
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
);
465 * We no longer do session management in uucpd because
466 * there is no way to do the "pam_close_session()".
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.
473 * ftpd (which also only writes to the wtmp file)
474 * can do a pam_close_session() because it doesn't fork().
476 * if (pam_set_item(pamh, PAM_RHOST, remotehost) != PAM_SUCCESS)
478 * if (pam_set_item(pamh, PAM_TTY, line) != PAM_SUCCESS)
480 * if (pam_open_session(pamh, 0) != PAM_SUCCESS) {
486 wtmp
= open("/usr/adm/wtmp", O_WRONLY
|O_APPEND
);
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
);
495 (void) lseek(wtmp
, 0L, 2);
497 (void) write(wtmp
, (char *)&utmp
, sizeof (utmp
));
500 #endif /* !ATTSVR4 */
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.
512 uucp_conv(num_msg
, msg
, response
, appdata_ptr
)
514 struct pam_message
**msg
;
515 struct pam_response
**response
;
518 struct pam_message
*m
;
519 struct pam_response
*r
;
521 static char passwd
[64];
525 return (PAM_CONV_ERR
);
527 *response
= (struct pam_response
*)calloc(num_msg
,
528 sizeof (struct pam_response
));
529 if (*response
== NULL
)
530 return (PAM_BUF_ERR
);
537 switch (m
->msg_style
) {
539 case PAM_PROMPT_ECHO_OFF
:
541 * we do this instead of using passed in message
542 * to prevent possible breakage of uucp protocol.
544 printf("Password: "); fflush(stdout
);
545 if (readline(passwd
, sizeof (passwd
)) < 0) {
546 fprintf(stderr
, "passwd read\n");
547 return (PAM_SUCCESS
);
551 r
->resp
= strdup(temp
);
552 if (r
->resp
== NULL
) {
555 for (i
= 0; i
< num_msg
; i
++, r
++) {
561 return (PAM_BUF_ERR
);
569 case PAM_PROMPT_ECHO_ON
:
570 if (m
->msg
!= NULL
) {
571 fputs(m
->msg
, stdout
);
574 r
->resp
= (char *)malloc(PAM_MAX_RESP_SIZE
);
575 if (r
->resp
== NULL
) {
576 /* free the response */
578 for (i
= 0; i
< num_msg
; i
++, r
++) {
584 return (PAM_BUF_ERR
);
586 (void) fgets(r
->resp
, PAM_MAX_RESP_SIZE
, stdin
);
592 if (m
->msg
!= NULL
) {
593 fputs(m
->msg
, stderr
);
600 if (m
->msg
!= NULL
) {
601 fputs(m
->msg
, stdout
);
612 return (PAM_SUCCESS
);