2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: solaris.c /main/4 1995/10/27 16:15:38 rswiston $ */
24 /*******************************************************************************
26 ** solaris.c 1.15 95/09/10
28 ** Copyright 1993, 1994, 1995 Sun Microsystems, Inc. All rights reserved.
30 ** This file contains procedures specific to Sun Solaris login
32 *******************************************************************************/
34 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
35 * (c) Copyright 1993, 1994 International Business Machines Corp. *
36 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
37 * (c) Copyright 1993, 1994 Novell, Inc. *
39 /*******************************************************************************
41 ** RESTRICTED CONFIDENTIAL INFORMATION:
43 ** The information in this document is subject to special
44 ** restrictions in a confidential disclosure agreement between
45 ** HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
46 ** document outside HP, IBM, Sun, USL, SCO, or Univel without
47 ** Sun's specific written approval. This document and all copies
48 ** and derivative works thereof must be returned or destroyed at
51 ** Copyright 1994 Sun Microsystems, Inc. All rights reserved.
53 *******************************************************************************/
60 #include <sys/types.h>
66 #include <sys/param.h>
71 #include <security/ia_appl.h>
76 * Local function declarations, structures, and variables
79 static char* create_devname(char* short_devname);
80 static void dir_dev_acc(char *, uid_t, gid_t, mode_t, char *);
81 static void logindevperm(char *, uid_t, gid_t);
82 static void resetdevperm(char *);
85 static int login_conv(int conv_id, int num_msg, struct ia_message **msg,
86 struct ia_response **response, void *appdata_ptr);
87 static void end_conv();
89 static struct ia_conv ia_conv = {login_conv, login_conv, end_conv, NULL};
90 static char *saved_user_passwd;
94 /****************************************************************************
97 * Modify permission of devices as specified in Solaris /etc/logindevperm file
98 ****************************************************************************/
101 solaris_setdevperm(char* gettyLine, uid_t uid, gid_t gid)
103 char *devname = create_devname(gettyLine);
105 if (devname == NULL) {
106 Debug ("solaris_setdevperm: NULL devname\n");
110 logindevperm(devname, uid, gid);
116 /****************************************************************************
117 * solaris_resetdevperm
119 * Reset permission on devices specified in /etc/logindevperm file
120 ****************************************************************************/
123 solaris_resetdevperm(char* gettyLine)
125 char *devname = create_devname(gettyLine);
127 if (devname == NULL) {
128 Debug ("solaris_resetdevperm: NULL devname\n");
132 resetdevperm(devname);
139 /****************************************************************************
140 * solaris_authentication
142 * Authenticate that user / password combination is legal for this system
144 ****************************************************************************/
147 solaris_authenticate ( char* prog_name,
154 struct ia_status out;
155 void *iah; /* PAM authentication handle */
156 char* user_str = user ? user : "NULL";
157 char* line_str = line ? line : "NULL";
158 char *line_dev = create_devname(line_str);
160 Debug("solaris_authenticate: prog_name=%s\n", prog_name);
161 Debug("solaris_authenticate: display_name=%s\n", display_name);
162 Debug("solaris_authenticate: user=%s\n", user_str);
163 Debug("solaris_authenticate: line=%s\n", line_str);
164 Debug("solaris_authenticate: line_dev=%s\n", line_dev);
167 if (strlen(user_passwd) == 0) {
168 Debug("solaris_authenticate: user passwd empty\n");
170 Debug("solaris_authenticate: user passwd present\n");
174 Debug("solaris_authenticate: user passwd NULL\n");
176 /* Password challenge required for solaris authentication */
177 return(IA_AUTHTEST_FAIL);
180 /* Solaris BSM Audit trail */
182 audit_login_save_host(display_name);
183 audit_login_save_ttyn(line_dev);
184 audit_login_save_port();
186 /* Open Solaris PAM (Plugable Authentication module ) connection */
188 status = ia_start( prog_name, user, line_dev,
189 display_name, &ia_conv, &iah );
192 int flags = AU_CHECK_PASSWD | AU_CONTINUE;
195 saved_user_passwd = user_passwd;
196 status = ia_auth_user( iah, flags, &pwd, &out );
198 audit_login_save_pw(pwd);
201 audit_login_bad_pw();
202 if (status == IA_MAXTRYS) {
203 audit_login_maxtrys();
209 Debug("solaris_authenticate: PAM error=%d\n", status);
220 /****************************************************************************
223 * Updates "utmp/utmpx: and "wtmp/wtmpx" system accounting entries
225 ****************************************************************************/
228 solaris_accounting( char* prog_name,
237 int session_type, status;
238 struct ia_status out;
239 void *iah; /* PAM authentication handle */
240 char* user_str = user ? user : "NULL";
241 char* line_str = line ? line : "NULL";
242 char *line_dev = create_devname(line_str);
244 Debug("solaris_accounting: prog_name=%s\n", prog_name);
245 Debug("solaris_accounting: display_name=%s\n", display_name);
246 Debug("solaris_accounting: entry_id=%c %c %c %c\n", entry_id[0],
247 entry_id[1], entry_id[2], entry_id[3]);
248 Debug("solaris_accounting: user=%s\n", user_str);
249 Debug("solaris_accounting: line=%s\n", line_str);
250 Debug("solaris_accounting: line_dev=%s\n", line_dev);
251 Debug("solaris_accounting: pid=%d\n", pid);
252 Debug("solaris_accounting: entry_type=%d\n", entry_type);
253 Debug("solaris_accounting: exitcode=%d\n", exitcode);
256 /* Open Solaris PAM (Plugable Authentication module ) connection */
258 if (entry_type == ACCOUNTING) {
259 status = ia_start(prog_name, user, line,
260 display_name, &ia_conv, &iah);
263 status = ia_start(prog_name, user, line_dev,
264 display_name, &ia_conv, &iah);
268 /* Session accounting */
270 if (status != IA_SUCCESS) {
271 Debug("solaris_accounting: PAM error=%d)\n", status);
277 /* New user session, open session accounting logs */
278 session_type = IS_LOGIN;
279 status = ia_open_session(iah, session_type,
280 entry_type, entry_id, &out);
281 if (status == IA_SUCCESS) audit_login_success();
287 * User session has terminated, mark it DEAD and close
288 * the sessions accounting logs.
290 entry_type = DEAD_PROCESS;
291 session_type = IS_NOLOG;
292 status = ia_open_session(iah, session_type,
293 entry_type, entry_id, &out);
294 if (status != IA_SUCCESS) {
295 Debug("solaris_accounting: PAM check seuser error=%d\n",
298 /* Intentional fall thru */
302 /* Cleanup account files for dead processes */
303 status = ia_close_session(iah, 0, pid,
304 exitcode, entry_id, &out);
311 status = ia_open_session(iah, session_type,
312 entry_type, entry_id, &out);
317 if (status != IA_SUCCESS) {
318 Debug("solaris_accounting: PAM session error=%d\n", status);
328 /****************************************************************************
331 * Set Users login credentials: uid, gid, and group lists
332 ****************************************************************************/
335 solaris_setcred(char* prog_name, char* user, uid_t uid, gid_t gid)
337 int cred_type, status;
338 struct ia_status out;
339 void *iah; /* PAM authentication handle */
340 char* user_str = user ? user : "NULL";
342 Debug("solaris_setcred: prog_name=%s\n", prog_name);
343 Debug("solaris_setcred: user=%s\n", user_str);
344 Debug("solaris_setcred: uid=%d\n", uid);
345 Debug("solaris_setcred: gid=%d\n", gid);
348 /* Open PAM connection */
350 status = ia_start(prog_name, user, NULL, NULL, &ia_conv, &iah);
352 Debug("solaris_setcred: PAM start error=%d\n", status);
356 /* Set users credentials */
358 ia_set_item(iah, IA_AUTHTOK, saved_user_passwd);
360 cred_type = SC_INITGPS|SC_SETRID;
361 status = ia_setcred(iah, cred_type, uid, gid, 0, NULL, &out);
364 Debug("solaris_setcred: user=%s, err=%d)\n", user, status);
369 Debug("solaris_setcred: return status =%d\n", status);
376 /***************************************************************************
379 * A utility function. Takes short device name like "console" and returns
380 * a long device name like "/dev/console"
381 ***************************************************************************/
384 create_devname(char* short_devname)
388 if (short_devname == NULL)
391 long_devname = (char *) malloc (strlen(short_devname) + 5);
393 if (long_devname == NULL)
396 strcpy(long_devname,"/dev/");
397 strcat(long_devname, short_devname);
399 return(long_devname);
403 /****************************************************************************
406 * change owner/group/permissions of devices list in /etc/logindevperm.
408 * This code is directly from Sun Solaris 5.3 login. Eventually this will
409 * be a fuction in a Solaris library. Till then, this is duplicate copy.
410 ***************************************************************************/
412 #define LOGINDEVPERM "/etc/logindevperm"
413 #define DIRWILD "/*" /* directory wildcard */
414 #define DIRWLDLEN 2 /* strlen(DIRWILD) */
418 logindevperm(char *ttyn, uid_t uid, gid_t gid)
420 char *field_delims = " \t\n";
421 char *permfile = LOGINDEVPERM;
422 char line[MAXPATHLEN];
433 if ((fp = fopen(permfile, "r")) == NULL)
437 while (fgets(line, MAXPATHLEN, fp) != NULL) {
440 if ((ptr = strchr(line, '#')) != NULL)
441 *ptr = '\0'; /* handle comments */
443 if ((console = strtok(line, field_delims)) == NULL)
444 continue; /* ignore blank lines */
446 if (strcmp(console, ttyn) != 0)
447 continue; /* not our tty, skip */
449 mode_str = strtok((char *)NULL, field_delims);
450 if (mode_str == NULL) {
451 (void) fprintf(stderr,
452 "%s: line %d, invalid entry -- %s\n", permfile,
457 /* convert string to octal value */
458 mode = strtol(mode_str, &ptr, 8);
459 if (mode < 0 || mode > 0777 || *ptr != '\0') {
460 (void) fprintf(stderr,
461 "%s: line %d, invalid mode -- %s\n", permfile,
466 dev_list = strtok((char *)NULL, field_delims);
467 if (dev_list == NULL) {
468 (void) fprintf(stderr,
469 "%s: line %d, %s -- empty device list\n",
470 permfile, lineno, console);
474 device = strtok(dev_list, ":");
475 while (device != NULL) {
477 ptr = &device[l - DIRWLDLEN];
478 if ((l > DIRWLDLEN) && (strcmp(ptr, DIRWILD) == 0)) {
479 *ptr = '\0'; /* chop off wildcard */
480 dir_dev_acc(device, uid, gid, mode, permfile);
483 * change the owner/group/permission;
484 * nonexistent devices are ignored
486 if (chown(device, uid, gid) == -1) {
487 if (errno != ENOENT) {
488 (void) fprintf(stderr, "%s: ",
493 if ((chmod(device, mode) == -1) &&
495 (void) fprintf(stderr, "%s: ",
501 device = strtok((char *)NULL, ":");
507 /***************************************************************************
510 * Apply owner/group/perms to all files (except "." and "..") in a directory.
512 * This code is directly Sun Solaris 5.3 login. Eventually this will
513 * be internal to a Solaris library. Till then, this is a duplicate copy.
514 ***************************************************************************/
517 dir_dev_acc(char *dir, uid_t uid, gid_t gid, mode_t mode, char *permfile)
520 struct dirent *direntp;
521 char *name, path[MAXPATHLEN];
527 while ((direntp = readdir(dirp)) != NULL) {
528 name = direntp->d_name;
529 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
532 (void) sprintf(path, "%s/%s", dir, name);
533 if (chown(path, uid, gid) == -1) {
534 if (errno != ENOENT) {
535 (void) fprintf(stderr, "%s: ", permfile);
539 if ((chmod(path, mode) == -1) && (errno != ENOENT)) {
540 (void) fprintf(stderr, "%s: ", permfile);
545 (void) closedir(dirp);
548 /*****************************************************************************
551 * Clean up access of devices in /etc/logindevperm by resetting the
552 * owner/group/permissions back to the login pseudo user.
554 *****************************************************************************/
556 extern struct passwd puser; /* pseudo_user password entry */
559 resetdevperm(char *ttyn)
561 logindevperm(ttyn, puser.pw_uid, puser.pw_gid);
565 /*****************************************************************************
568 * This is a conv (conversation) function called from the PAM
569 * authentication scheme. It returns the user's password when requested by
570 * internal PAM authentication modules and also logs any internal PAM error
572 *****************************************************************************/
575 login_conv(int conv_id, int num_msg, struct ia_message **msg,
576 struct ia_response **response, void *appdata_ptr)
578 struct ia_message *m;
579 struct ia_response *r;
587 return (IA_CONV_FAILURE);
589 *response = (struct ia_response*)
590 calloc(num_msg, sizeof (struct ia_response));
591 if (*response == NULL)
592 return (IA_CONV_FAILURE);
594 (void) memset(*response, 0, sizeof (struct ia_response));
601 switch (m->msg_style) {
603 case IA_PROMPT_ECHO_OFF:
604 if (saved_user_passwd != NULL) {
605 r->resp = (char *) malloc(strlen(saved_user_passwd)+1);
606 if (r->resp == NULL) {
607 free_resp(num_msg, *response);
609 return (IA_CONV_FAILURE);
611 (void) strcpy(r->resp, saved_user_passwd);
612 r->resp_len = strlen(r->resp);
621 if (m->msg != NULL) {
622 Debug ("login_conv: %s\n", m->msg);
629 Debug ("login_conv: Unexpected case %d\n",
638 /*****************************************************************************
641 * End of conversation function. Called from PAM.
642 * Currently a noop for dtlogin.
643 *****************************************************************************/
651 /****************************************************************************
652 * Following Solaris utmp management code was taken from portions of the
653 * private libauth open and close session code. There are no equivalent calls
654 * in libpam that replaces it, so the code is copied to here. Eventually this
655 * code may become functions in either PAM or other appropriate libraries.
656 ***************************************************************************/
658 #define INIT_PROC_PID 1
659 #define PAMTXD "SUNW_OST_SYSOSPAM"
660 #define SCPYN(a, b) (void) strncpy(a, b, sizeof (a))
662 /* utility function to do UTMP/WTMP management */
664 solaris_setutmp_mgmt(
665 char *user, /* user */
666 char *ttyn, /* ttyn */
667 char *rhost, /* remote hostname */
668 int flags, /* Flags - see below */
669 int type, /* type of utmp/wtmp entry */
670 char id[] /* 4 byte id field for utmp */
674 * solaris_reset_utmp_mgmt
675 * a utility function which terminates UTMP/WTMP mgmt
678 solaris_reset_utmp_mgmt(
679 char **user, /* user */
680 char **ttyn, /* tty name */
681 char **rhost, /* remote host */
682 int flags, /* flags - see below */
683 int status, /* logout process status */
684 char id[] /* logout ut_id (/etc/inittab id) */
687 /* flags for the flags field */
688 #define __NOOP 8 /* No utmp action desired */
690 /* __setproc_cred is a utility function to set process credentials */
693 char *user, /* user */
694 int flags, /* flags - see below */
695 uid_t uid, /* User ID to set for this process */
696 gid_t gid, /* Group ID */
697 int ngroups, /* Number of groups */
698 gid_t *grouplist /* Group list */
701 /* flags indicates specific set credential actions */
703 #define __INITGROUPS 0x00000001 /* Request to initgroups() */
704 #define __SETGROUPS 0x00000002 /* Request to setgroups() */
705 #define __SETEGID 0x00000004 /* Set effective gid only */
706 #define __SETGID 0x00000008 /* Set real gid */
707 #define __SETEUID 0x00000010 /* Set effective uid only */
708 #define __SETUID 0x00000020 /* Set real uid */
709 #define __SETEID (__SETEGID|__SETEUID) /* Set effective ids only */
710 #define __SETRID (__SETGID|__SETUID) /* Set real ids */
713 * solaris_setutmp_mgmt - A utility function used to do UTMP/WTMP management.
715 * "user" is the current username.
716 * "ttyn" is the tty name.
717 * "rhost" is the remote hostname.
718 * The following flags may be set in the "flags" field:
720 * SOLARIS_UPDATE_ENTRY No new entry will be created if utmp
721 * entry not found - return __NOENTRY
722 * SOLARIS_NOLOG Generate a wtmp/wtmpx entry only
723 * SOLARIS_LOGIN Caller is a login application - update
724 * utmp entry accordingly
726 * "type" is used to indicate the type of utmp/wtmp entry written
727 * (see also utmp.h and utmpx.h)
728 * "id is an optional application-defined 4 byte array that represents
729 * the /sbin/inittab id (created by the process that puts an entry in
732 * Upon successful completion, SOLARIS_SUCCESS is returned.
733 * Error values may include:
735 * SOLARIS_NOENTRY An entry for the specified process was not found
736 * SOLARIS_ENTRYFAIL Could not make/remove entry for specified process
740 solaris_setutmp_mgmt(
749 struct utmpx *u = (struct utmpx *)0;
752 int err = PAM_SUCCESS;
754 Debug("Enter: solaris_setutmp_mgmt()\n");
756 (void) memset((void *)&utmp, 0, sizeof (utmp));
758 (void) time(&utmp.ut_tv.tv_sec);
759 utmp.ut_pid = getpid();
760 if (rhost != NULL && rhost[0] != '\0') {
761 (void) strcpy(utmp.ut_host, rhost);
762 tmplen = strlen(rhost) + 1;
763 if (tmplen < sizeof (utmp.ut_host))
764 utmp.ut_syslen = tmplen;
766 utmp.ut_syslen = sizeof (utmp.ut_host);
768 (void) memset(utmp.ut_host, 0, sizeof (utmp.ut_host));
772 (void) strcpy(utmp.ut_user, user);
774 * Copy in the name of the tty minus the "/dev/" if a /dev/ is
778 if (!(flags&SOLARIS_LOGIN))
779 SCPYN(utmp.ut_line, ttyn);
786 (void) memcpy(utmp.ut_id, id, sizeof (utmp.ut_id));
788 if ((flags & SOLARIS_NOLOG) == SOLARIS_NOLOG) {
789 updwtmpx(WTMPX_FILE, &utmp);
792 * Go through each entry one by one, looking only at INIT,
793 * LOGIN or USER Processes. Use the entry found if flags == 0
794 * and the line name matches, or if the process ID matches if
795 * the UPDATE_ENTRY flag is set. The UPDATE_ENTRY flag is
796 * mainly for login which normally only wants to update an
797 * entry if the pid fields matches.
800 if (flags & SOLARIS_LOGIN) {
801 while ((u = getutxent()) != NULL) {
802 if ((u->ut_type == INIT_PROCESS ||
803 u->ut_type == LOGIN_PROCESS ||
804 u->ut_type == USER_PROCESS) &&
805 ((flags == SOLARIS_LOGIN && ttyn != NULL &&
806 strncmp(u->ut_line, ttyntail,
807 sizeof (u->ut_line)) == 0) ||
808 u->ut_pid == utmp.ut_pid)) {
811 (ttyn + sizeof ("/dev/") - 1));
813 (void) memcpy(utmp.ut_id, u->ut_id,
814 sizeof (utmp.ut_id));
816 (void) pututxline(&utmp);
820 endutxent(); /* Close utmp file */
823 if (u == (struct utmpx *)NULL) {
824 /* audit_login_main11(); */
825 if (flags & SOLARIS_UPDATE_ENTRY)
826 err = SOLARIS_NOENTRY;
828 (void) makeutx(&utmp);
831 updwtmpx(WTMPX_FILE, &utmp);
837 * solaris_reset_utmp_mgmt
838 * A utility function used to terminate UTMP/WTMP mgmt.
840 * "user" is the current username.
841 * "ttyn" is the tty name.
842 * "rhost" is the remote hostname.
843 * The following flags may be set in the "flags" field:
845 * SOLARIS_NOLOG Write a wtmp/wtmpx entry only
846 * SOLARIS_NOOP Ignore utmp/wtmp processing
848 * "status" is the logout process status.
849 * "id is an optional application-defined 4 byte array that represents
850 * the /sbin/inittab id (created by the process that puts an entry in
853 * Upon successful completion, PAM_SUCCESS is returned.
854 * Error values may include:
856 * SOLARIS_NOENTRY An entry for the specified process was not found
857 * SOLARIS_ENTRYFAIL Could not make/remove entry for specified process
861 solaris_reset_utmp_mgmt(
874 Debug("Enter: solaris_reset_utmp_mgmt()\n");
877 pid = (int) getpid();
879 if ((flags & SOLARIS_NOLOG) == SOLARIS_NOLOG) {
880 /* only write to wtmp files */
881 /* clear utmpx entry */
882 (void) memset((char *)&ut, 0, sizeof (ut));
885 (void) memcpy(ut.ut_id, id, sizeof (ut.ut_id));
887 if (*ttyn != NULL && **ttyn != '\0') {
888 if (strstr(*ttyn, "/dev/") != NULL)
889 (void) strncpy(ut.ut_line, (*ttyn+sizeof ("/dev/")-1),
890 sizeof (ut.ut_line));
892 (void) strncpy(ut.ut_line, *ttyn,
893 sizeof (ut.ut_line));
896 ut.ut_type = DEAD_PROCESS;
897 ut.ut_exit.e_termination = 0;
898 ut.ut_exit.e_exit = 0;
900 (void) gettimeofday(&ut.ut_tv, NULL);
901 updwtmpx(WTMPX_FILE, &ut);
903 return (PAM_SUCCESS);
906 while (up = getutxent()) {
907 if (up->ut_pid == pid) {
908 if (up->ut_type == DEAD_PROCESS) {
910 * Cleaned up elsewhere.
915 if ((*user = (char *) strdup (up->ut_user))
917 (*ttyn = (char *) strdup (up->ut_line))
919 (*rhost = (char *) strdup (up->ut_host))
921 return (PAM_BUF_ERR);
923 up->ut_type = DEAD_PROCESS;
924 up->ut_exit.e_termination = status & 0xff;
925 up->ut_exit.e_exit = (status >> 8) & 0xff;
927 (void) memcpy(up->ut_id, id,
929 (void) time(&up->ut_tv.tv_sec);
932 * For init (Process ID 1) we don't write to
933 * init's pipe, since we are init.
935 if (getpid() == INIT_PROC_PID) {
936 (void) pututxline(up);
938 * Now attempt to add to the end of the
939 * wtmp and wtmpx files. Do not create
940 * if they don't already exist.
942 updwtmpx("wtmpx", up);
944 if (modutx(up) == NULL) {
945 Debug("modutx failed\n");
947 * Since modutx failed we'll
948 * write out the new entry
951 (void) pututxline(up);
952 updwtmpx("wtmpx", up);
958 return (PAM_SUCCESS);
963 return (SOLARIS_NOENTRY);