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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
38 #include <sac.h> /* for SC_WILDC */
43 #include <sys/filio.h>
44 #include <sys/ioctl.h>
45 #include <sys/signal.h>
47 #include <sys/types.h>
51 * # include <sys/label.h>
52 * # include <sys/audit.h>
56 * # include <pwdadj.h>
59 #include <sys/ttold.h>
61 #include <sys/stream.h>
67 #include <security/pam_appl.h>
70 #define NTTYDISC 2 /* New ttydiscipline: stolen from ttold.h */
73 * unix_login - hairy junk to simulate logins for Unix
76 int Master
, Slave
; /* sides of the pty */
77 int Slave_is_closed_on_master_side
;
79 static char *slavename
;
80 extern char *ptsname();
83 int InputSocket
, /* Network sockets */
85 int Helper1
, /* pids of the helpers */
87 char UserName
[256]; /* saves the user name for loging */
88 char HostName
[256]; /* saves the host name for loging */
90 static int TtySlot
; /* slot number in Utmpx */
93 * pseudo-xprts used to add pty fds to svc_pollfd[]. This allows the
94 * polling for all i/o in one poll().
98 #define INPUTSOCKET 0 /* InputSocket xprt */
99 #define MASTER 1 /* Master xprt */
102 extern int child
; /* pid of the executed process */
103 extern int ChildDied
; /* flag */
104 extern int HasHelper
; /* flag */
106 extern void setproctitle(char *user
, char *host
);
109 extern void audit_rexd_fail(char *, char *, char *, uid_t
, gid_t
,
112 #define bzero(s, n) memset((s), 0, (n))
113 #define bcopy(a, b, c) memcpy((b), (a), (c))
115 static void LogoutUser(void);
118 * Check for user being able to run on this machine.
119 * returns 0 if OK, TRUE if problem, error message in "error"
120 * copies name of shell and home directory if user is valid.
123 ValidUser(host
, uid
, gid
, error
, shell
, dir
, rst
)
124 char *host
; /* passed in */
127 char *error
; /* filled in on return */
128 char *shell
; /* filled in on return */
129 char *dir
; /* filled in on return */
130 struct rex_start
*rst
; /* passed in */
132 struct passwd
*pw
, *getpwuid();
136 if (pw
== NULL
|| pw
->pw_name
== NULL
)
138 errprintf(error
, "rexd: User id %d not valid\n", uid
);
139 audit_rexd_fail("user id is not valid",
145 rst
->rst_cmd
); /* BSM */
148 strncpy(UserName
, pw
->pw_name
, sizeof (UserName
) - 1);
149 strncpy(HostName
, host
, sizeof (HostName
) - 1);
150 strcpy(shell
, pw
->pw_shell
);
151 strcpy(dir
, pw
->pw_dir
);
152 setproctitle(pw
->pw_name
, host
);
154 if (pam_start("rexd", pw
->pw_name
, NULL
, &pamh
) != PAM_SUCCESS
||
155 pam_set_item(pamh
, PAM_RHOST
, host
) != PAM_SUCCESS
) {
156 audit_rexd_fail("user id is not valid",
162 rst
->rst_cmd
); /* BSM */
163 errprintf(error
, "rexd: User id %d not valid\n", uid
);
165 pam_end(pamh
, PAM_ABORT
);
171 if ((v
= pam_acct_mgmt(pamh
, 0)) != PAM_SUCCESS
) {
173 case PAM_NEW_AUTHTOK_REQD
:
175 "rexd: User id %d Password Expired\n", uid
);
177 case PAM_PERM_DENIED
:
179 "rexd: User id %d Account Expired\n", uid
);
181 case PAM_AUTHTOK_EXPIRED
:
183 "rexd: User id %d Password Expired\n", uid
);
187 "rexd: User id %d not valid\n", uid
);
190 pam_end(pamh
, PAM_ABORT
);
193 audit_rexd_fail("user account expired",
199 rst
->rst_cmd
); /* BSM */
207 * Add an audit record with argv that was pre-set, plus the given string
211 * Allocate a pseudo-terminal
212 * sets the global variables Master and Slave.
213 * returns 1 on error, 0 if OK
216 AllocatePty(socket0
, socket1
)
217 int socket0
, socket1
;
222 sigset(SIGHUP
, SIG_IGN
);
223 sigset(SIGTTOU
, SIG_IGN
);
224 sigset(SIGTTIN
, SIG_IGN
);
226 if ((Master
= open("/dev/ptmx", O_RDWR
)) == -1) {
228 printf("open-ptmx-failure\n");
229 perror("AloocatePtyMaster fails");
230 return (1); /* error could not open /dev/ptmx */
233 printf("open-ptmx success Master =%d\n", Master
);
235 printf("Before grantpt...Master=%d\n", Master
);
237 if (grantpt(Master
) == -1) {
238 perror("could not grant slave pty");
241 if (unlockpt(Master
) == -1) {
242 perror("could not unlock slave pty");
245 if ((slavename
= ptsname(Master
)) == NULL
) {
246 perror("could not enable slave pty");
249 if ((Slave
= open(slavename
, O_RDWR
)) == -1) {
250 perror("could not open slave pty");
253 if (ioctl(Slave
, I_PUSH
, "ptem") == -1) {
254 perror("ioctl I_PUSH ptem");
257 if (ioctl(Slave
, I_PUSH
, "ldterm") == -1) {
258 perror("ioctl I_PUSH ldterm");
261 if (ioctl(Slave
, I_PUSH
, "ttcompat") == -1) {
262 perror("ioctl I_PUSH ttcompat");
266 Slave_is_closed_on_master_side
= FALSE
;
267 setsid(); /* get rid of controlling terminal */
270 InputSocket
= socket0
;
271 OutputSocket
= socket1
;
272 ioctl(Master
, FIONBIO
, &on
);
273 uxprt
[INPUTSOCKET
].xp_fd
= InputSocket
;
274 xprt_register(&uxprt
[INPUTSOCKET
]);
275 uxprt
[MASTER
].xp_fd
= Master
;
276 xprt_register(&uxprt
[MASTER
]);
285 Slave
= open(slavename
, O_RDWR
);
295 * Special processing for interactive operation.
296 * Given pointers to three standard file descriptors,
297 * which get set to point to the pty.
300 DoHelper(pfd0
, pfd1
, pfd2
)
301 int *pfd0
, *pfd1
, *pfd2
;
306 sigset(SIGINT
, SIG_IGN
);
318 * destroy the helpers when the executing process dies
324 printf("Enter KillHelper\n");
326 xprt_unregister(&uxprt
[MASTER
]);
328 xprt_unregister(&uxprt
[INPUTSOCKET
]);
333 kill((-grp
), SIGKILL
);
338 * edit the Unix traditional data files that tell who is logged
341 unsigned char utid
[] = {'o', 'n', SC_WILDC
, SC_WILDC
};
349 /* the next 4 variables are needed for utmpx mgmt */
351 struct utmpx
*u
= NULL
;
352 struct utmpx set_utmp
;
355 /* We're pretty drastic here, exiting if an error is detected */
356 if (pam_set_item(pamh
, PAM_TTY
, slavename
) != PAM_SUCCESS
||
357 pam_get_item(pamh
, PAM_USER
, (void **) &user
) != PAM_SUCCESS
||
358 pam_get_item(pamh
, PAM_RHOST
, (void **) &rhost
) != PAM_SUCCESS
||
359 pam_open_session(pamh
, 0) != PAM_SUCCESS
) {
361 * XXX should print something but for now we exit
366 (void) memset((void *)&set_utmp
, 0, sizeof (set_utmp
));
367 (void) time(&set_utmp
.ut_tv
.tv_sec
);
368 set_utmp
.ut_pid
= getpid();
369 if (rhost
!= NULL
&& rhost
[0] != '\0') {
370 (void) strcpy(set_utmp
.ut_host
, rhost
);
371 tmplen
= strlen(rhost
) + 1;
372 if (tmplen
< sizeof (set_utmp
.ut_host
))
373 set_utmp
.ut_syslen
= tmplen
;
375 set_utmp
.ut_syslen
= sizeof (set_utmp
.ut_host
);
377 (void) memset(set_utmp
.ut_host
, 0, sizeof (set_utmp
.ut_host
));
378 set_utmp
.ut_syslen
= 0;
380 (void) strcpy(set_utmp
.ut_user
, user
);
383 * Copy in the name of the tty minus the "/dev/" if a /dev/ is
386 ttyntail
= slavename
;
387 if (strstr(ttyntail
, "/dev/") != 0)
388 ttyntail
= ttyntail
+ strlen("/dev/");
389 (void) strcpy(set_utmp
.ut_line
, ttyntail
);
391 set_utmp
.ut_type
= USER_PROCESS
;
393 (void) memcpy(set_utmp
.ut_id
, utid
, sizeof (set_utmp
.ut_id
));
395 * Go through each entry one by one, looking only at INIT,
396 * LOGIN or USER Processes. Use the entry found if flags == 0
397 * and the line name matches, or if the process ID matches if
398 * the UPDATE_ENTRY flag is set. The UPDATE_ENTRY flag is mainly
399 * for login which normally only wants to update an entry if
400 * the pid fields matches.
403 if (u
== (struct utmpx
*)NULL
) {
404 (void) makeutx(&set_utmp
);
406 updwtmpx(WTMPX_FILE
, &set_utmp
);
411 * edit the Unix traditional data files that tell who is logged
420 char user
[sizeof (ut
.ut_user
) + 1];
421 char ttyn
[sizeof (ut
.ut_line
) + 1];
422 char rhost
[sizeof (ut
.ut_host
) + 1];
424 sighold(SIGCHLD
); /* no disruption during cleanup */
427 pam_end(pamh
, PAM_SUCCESS
);
431 /* BEGIN RESET UTMP */
434 while (up
= getutxent()) {
435 if (up
->ut_pid
== pid
) {
436 if (up
->ut_type
== DEAD_PROCESS
) {
438 * Cleaned up elsewhere.
443 strncpy(user
, up
->ut_user
, sizeof (up
->ut_user
));
444 user
[sizeof (up
->ut_user
)] = '\0';
445 strncpy(ttyn
, up
->ut_line
, sizeof (up
->ut_line
));
446 ttyn
[sizeof (up
->ut_line
)] = '\0';
447 strncpy(rhost
, up
->ut_host
, sizeof (up
->ut_host
));
448 rhost
[sizeof (up
->ut_host
)] = '\0';
450 if ((pam_start("rexd", user
, NULL
, &pamh
))
452 (void) pam_set_item(pamh
, PAM_TTY
, ttyn
);
453 (void) pam_set_item(pamh
, PAM_RHOST
, rhost
);
454 (void) pam_close_session(pamh
, 0);
455 (void) pam_end(pamh
, PAM_SUCCESS
);
459 up
->ut_type
= DEAD_PROCESS
;
460 up
->ut_exit
.e_termination
= WTERMSIG(0);
461 up
->ut_exit
.e_exit
= WEXITSTATUS(0);
462 (void) time(&up
->ut_tv
.tv_sec
);
463 if (modutx(up
) == NULL
) {
465 * Since modutx failed we'll
466 * write out the new entry
469 (void) pututxline(up
);
470 updwtmpx("wtmpx", up
);
481 * set the pty modes to the given values
485 struct rex_ttymode
*mode
;
487 struct sgttyb svr4_sgttyb_var
;
488 int ldisc
= NTTYDISC
;
491 printf("Enter SetPtyMode\n");
493 printf("SetPtyMode:opened slave\n");
494 ioctl(Slave
, TIOCSETD
, &ldisc
);
496 printf("SetPtyMode:Slave TIOCSETD done\n");
499 * Copy from over-the-net(bsd) to SVR4 format
501 svr4_sgttyb_var
.sg_ispeed
= mode
->basic
.sg_ispeed
;
502 svr4_sgttyb_var
.sg_ospeed
= mode
->basic
.sg_ospeed
;
503 svr4_sgttyb_var
.sg_erase
= mode
->basic
.sg_erase
;
504 svr4_sgttyb_var
.sg_kill
= mode
->basic
.sg_kill
;
505 svr4_sgttyb_var
.sg_flags
= (int)mode
->basic
.sg_flags
;
507 * Clear any possible sign extension caused by (int)
510 svr4_sgttyb_var
.sg_flags
&= 0xFFFF;
512 ioctl(Slave
, TIOCSETN
, &svr4_sgttyb_var
);
514 printf("SetPtyMode:Slave TIOCSETN done\n");
515 ioctl(Slave
, TIOCSETC
, &mode
->more
);
517 printf("SetPtyMode:Slave TIOCSETC done\n");
518 ioctl(Slave
, TIOCSLTC
, &mode
->yetmore
);
520 printf("SetPtyMode:Slave TIOCSLTC done\n");
521 ioctl(Slave
, TIOCLSET
, &mode
->andmore
);
523 printf("SetPtyMode:Slave TIOCSET done\n");
525 /* Opened in AllocPty for parent, still open in child */
526 if (Slave_is_closed_on_master_side
== FALSE
) {
528 Slave_is_closed_on_master_side
= TRUE
;
533 * set the pty window size to the given value
536 SetPtySize(struct rex_ttysize
*sizep
)
538 struct winsize newsize
;
540 /* if size has changed, this ioctl changes it */
541 /* *and* sends SIGWINCH to process group */
543 newsize
.ws_row
= (unsigned short) sizep
->ts_lines
;
544 newsize
.ws_col
= (unsigned short) sizep
->ts_cols
;
546 (void) ioctl(Master
, TIOCSWINSZ
, &newsize
);
547 if (Slave_is_closed_on_master_side
== FALSE
) {
549 Slave_is_closed_on_master_side
= TRUE
;
555 * send the given signal to the group controlling the terminal
562 pgrp
= getpgid(child
);
563 if (pgrp
!= (pid_t
)-1)
564 (void) kill((-pgrp
), sig
);
568 * called when the main select loop detects that we might want to
572 HelperRead(pollfd_t
*fdp
, int nfds
, int *pollretval
)
579 int inputsocket
= -1;
582 * fdp pollset may be compressed. Search for Master and
586 for (i
= 0; i
< nfds
; i
++) {
587 if (fdp
[i
].fd
== Master
&& fdp
[i
].revents
!= 0)
589 if (fdp
[i
].fd
== InputSocket
&& fdp
[i
].revents
!= 0)
593 /* mask = sigsetmask (sigmask (SIGCHLD)); */
594 mask
= sighold(SIGCHLD
);
597 if (!(fdp
[master
].revents
& (POLLERR
| POLLHUP
| POLLNVAL
))) {
598 retval
= read(Master
, buf
, sizeof (buf
));
600 (void) write(OutputSocket
, buf
, retval
);
602 if (errno
!= EINTR
&& errno
!= EIO
&&
603 errno
!= EWOULDBLOCK
)
605 /* 1 => further sends disallowed */
606 shutdown(OutputSocket
, 1);
607 xprt_unregister(&uxprt
[MASTER
]);
611 /* clear this event for svc_getreq_poll */
612 fdp
[master
].revents
= 0;
613 *pollretval
= *pollretval
- 1;
615 if (retval
<= 0 && ChildDied
) {
618 if (inputsocket
!= -1) {
619 fdp
[inputsocket
].revents
= 0;
620 *pollretval
= *pollretval
- 1;
626 if (inputsocket
!= -1) {
627 if (!(fdp
[inputsocket
].revents
& (POLLERR
| POLLHUP
|
629 retval
= read(InputSocket
, buf
, sizeof (buf
));
631 (void) write(Master
, buf
, retval
);
633 if (errno
!= EINTR
&& errno
!= EWOULDBLOCK
)
634 perror("socket read");
635 xprt_unregister(&uxprt
[INPUTSOCKET
]);
639 /* clear this event for svc_getreq_poll */
640 fdp
[inputsocket
].revents
= 0;
641 *pollretval
= *pollretval
- 1;
645 /* sigsetmask (mask); */