Xreset.src: Do not hardcode /usr/dt.
[oweals/cde.git] / cde / programs / dtlogin / solaris.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: solaris.c /main/4 1995/10/27 16:15:38 rswiston $ */
24 /*******************************************************************************
25 **
26 **  solaris.c 1.15 95/09/10
27 **
28 **  Copyright 1993, 1994, 1995 Sun Microsystems, Inc.  All rights reserved.
29 **  
30 **  This file contains procedures specific to Sun Solaris login
31 **
32 *******************************************************************************/
33 /*                                                                      *
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.                                *
38  */
39 /*******************************************************************************
40 **
41 **  RESTRICTED CONFIDENTIAL INFORMATION:
42 **
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
49 **  Sun's request.
50 **
51 **  Copyright 1994 Sun Microsystems, Inc.  All rights reserved.
52 **
53 *******************************************************************************/
54
55
56 /*
57  * Header Files
58  */
59
60 #include <sys/types.h>
61 #include <utmpx.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <dirent.h>
66 #include <sys/param.h>
67 #include <pwd.h>
68 #include "solaris.h"
69
70 #ifdef SUNAUTH
71 #include <security/ia_appl.h>
72 #endif
73
74
75 /*
76  * Local function declarations, structures, and variables
77  */
78
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 *);
83
84 #ifdef SUNAUTH
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();
88
89 static struct ia_conv ia_conv = {login_conv, login_conv, end_conv, NULL};
90 static char *saved_user_passwd;
91 #endif SUNAUTH
92
93
94 /****************************************************************************
95  * solaris_setdevperm
96  *
97  * Modify permission of devices as specified in Solaris /etc/logindevperm file
98  ****************************************************************************/
99
100 int 
101 solaris_setdevperm(char* gettyLine, uid_t uid, gid_t gid) 
102 {
103         char *devname = create_devname(gettyLine);
104
105         if (devname == NULL) { 
106             Debug ("solaris_setdevperm:  NULL devname\n");
107             return(0);
108         };
109
110         logindevperm(devname, uid, gid);
111         free(devname);
112         return(1);
113 }
114
115
116 /****************************************************************************
117  * solaris_resetdevperm
118  *
119  * Reset permission on devices specified in /etc/logindevperm file 
120  ****************************************************************************/
121
122 int 
123 solaris_resetdevperm(char* gettyLine) 
124 {
125         char *devname = create_devname(gettyLine);
126
127         if (devname == NULL) {
128             Debug ("solaris_resetdevperm:  NULL devname\n");
129             return(0);
130         }
131
132         resetdevperm(devname);
133         free(devname);
134         return(1);
135 }
136
137
138 #ifdef SUNAUTH 
139 /****************************************************************************
140  * solaris_authentication
141  *
142  * Authenticate that user / password combination is legal for this system
143  *
144  ****************************************************************************/
145
146 int
147 solaris_authenticate ( char*   prog_name,
148                        char*   display_name,
149                        char*   user_passwd,
150                        char*   user, 
151                        char*   line )
152 {
153         int status;
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);  
159
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);
165
166         if (user_passwd) {
167             if (strlen(user_passwd) == 0) {
168                 Debug("solaris_authenticate: user passwd empty\n"); 
169             } else {
170                 Debug("solaris_authenticate: user passwd present\n"); 
171             }
172         }
173         else {
174             Debug("solaris_authenticate: user passwd NULL\n");
175
176             /* Password challenge required for solaris authentication */
177             return(IA_AUTHTEST_FAIL);
178         }
179         
180         /* Solaris BSM Audit trail */
181
182         audit_login_save_host(display_name);
183         audit_login_save_ttyn(line_dev);
184         audit_login_save_port();
185
186         /* Open Solaris PAM (Plugable Authentication module ) connection */
187
188         status = ia_start( prog_name, user, line_dev, 
189                            display_name, &ia_conv, &iah );
190
191         if (status == 0) {
192            int flags = AU_CHECK_PASSWD | AU_CONTINUE;
193            struct passwd *pwd;
194
195            saved_user_passwd = user_passwd;
196            status = ia_auth_user( iah, flags, &pwd, &out );
197                  
198            audit_login_save_pw(pwd);
199
200            if (status != 0) {
201               audit_login_bad_pw();
202               if (status == IA_MAXTRYS) {
203                  audit_login_maxtrys();
204               }
205            }
206         }
207
208         if (status != 0) {
209             Debug("solaris_authenticate: PAM error=%d\n", status);
210         }  
211
212         ia_end(iah);
213
214         return(status);
215 }
216
217
218
219
220 /****************************************************************************
221  * solaris_accounting
222  *
223  * Updates "utmp/utmpx: and "wtmp/wtmpx" system accounting entries
224  *
225  ****************************************************************************/
226
227 int
228 solaris_accounting( char*   prog_name,
229                     char*   display_name,
230                     char*   entry_id,
231                     char*   user, 
232                     char*   line, 
233                     pid_t   pid,
234                     int     entry_type,
235                     int     exitcode )
236 {
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);  
243
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);
254
255
256         /* Open Solaris PAM (Plugable Authentication module ) connection */
257
258         if (entry_type == ACCOUNTING) {
259             status = ia_start(prog_name, user, line, 
260                               display_name, &ia_conv, &iah);
261         }
262         else {
263             status = ia_start(prog_name, user, line_dev, 
264                               display_name, &ia_conv, &iah);
265         }
266
267
268         /* Session accounting */
269
270         if (status != IA_SUCCESS) {
271             Debug("solaris_accounting: PAM error=%d)\n", status);
272         } 
273         else {
274             switch(entry_type) {
275
276             case USER_PROCESS:
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();
282                 break;
283
284
285             case ACCOUNTING:
286                 /* 
287                  * User session has terminated, mark it DEAD and close 
288                  * the sessions accounting logs. 
289                  */
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", 
296                            status);
297                 }
298                 /* Intentional fall thru */
299
300
301             case DEAD_PROCESS:
302                 /* Cleanup account files for dead processes */
303                 status = ia_close_session(iah, 0, pid, 
304                                           exitcode, entry_id, &out); 
305                 break;
306
307
308             case LOGIN_PROCESS:
309             default:    
310                 session_type = 0;
311                 status = ia_open_session(iah, session_type, 
312                                          entry_type, entry_id, &out); 
313                 break;
314             }
315         }
316
317         if (status != IA_SUCCESS) {
318             Debug("solaris_accounting: PAM session error=%d\n", status);
319         }
320
321         ia_end(iah);
322         free(line_dev);
323         return(status);
324 }
325
326
327
328 /****************************************************************************
329  * solaris_setcred
330  *
331  * Set Users login credentials: uid, gid, and group lists 
332  ****************************************************************************/
333
334 int
335 solaris_setcred(char* prog_name, char* user, uid_t uid, gid_t gid) 
336 {
337         int cred_type, status;
338         struct ia_status out;
339         void *iah;              /* PAM authentication handle */
340         char* user_str = user ? user : "NULL";
341
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);
346
347
348         /* Open PAM connection */       
349
350         status = ia_start(prog_name, user, NULL, NULL, &ia_conv, &iah);
351         if (status != 0) {
352             Debug("solaris_setcred: PAM start error=%d\n", status);
353             return(status);
354         }
355
356         /* Set users credentials */
357
358         ia_set_item(iah, IA_AUTHTOK, saved_user_passwd);
359
360         cred_type = SC_INITGPS|SC_SETRID;
361         status = ia_setcred(iah, cred_type, uid, gid, 0, NULL, &out);
362
363         if (status != 0) {
364             Debug("solaris_setcred: user=%s, err=%d)\n", user, status);
365         }
366
367         ia_end(iah);
368
369         Debug("solaris_setcred: return status =%d\n", status);
370
371         return(status);
372 }
373 #endif SUNAUTH 
374
375
376 /***************************************************************************
377  * create_devname
378  *
379  * A utility function.  Takes short device name like "console" and returns 
380  * a long device name like "/dev/console"
381  ***************************************************************************/
382
383 static char* 
384 create_devname(char* short_devname)
385 {
386        char* long_devname;
387
388        if (short_devname == NULL)
389           short_devname = "";
390
391        long_devname = (char *) malloc (strlen(short_devname) + 5);
392
393        if (long_devname == NULL)
394           return(NULL); 
395
396        strcpy(long_devname,"/dev/");
397        strcat(long_devname, short_devname);
398         
399        return(long_devname);
400 }
401
402
403 /****************************************************************************
404  * logindevperm 
405  *
406  * change owner/group/permissions of devices list in /etc/logindevperm.
407  *
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  ***************************************************************************/
411
412 #define LOGINDEVPERM    "/etc/logindevperm"
413 #define DIRWILD         "/*"                    /* directory wildcard */
414 #define DIRWLDLEN       2                       /* strlen(DIRWILD) */
415
416
417 static void
418 logindevperm(char *ttyn, uid_t uid, gid_t gid)
419 {
420         char *field_delims = " \t\n";
421         char *permfile = LOGINDEVPERM;
422         char line[MAXPATHLEN];
423         char *console;
424         char *mode_str;
425         char *dev_list;
426         char *device;
427         char *ptr;
428         int mode;
429         FILE *fp;
430         size_t l;
431         int lineno;
432
433         if ((fp = fopen(permfile, "r")) == NULL)
434                 return;
435
436         lineno = 0;
437         while (fgets(line, MAXPATHLEN, fp) != NULL) {
438                 lineno++;
439
440                 if ((ptr = strchr(line, '#')) != NULL)
441                         *ptr = '\0';    /* handle comments */
442
443                 if ((console = strtok(line, field_delims)) == NULL)
444                         continue;       /* ignore blank lines */
445
446                 if (strcmp(console, ttyn) != 0)
447                         continue;       /* not our tty, skip */
448
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,
453                             lineno, line);
454                         continue;
455                 }
456
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,
462                             lineno, mode_str);
463                         continue;
464                 }
465
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);
471                         continue;
472                 }
473
474                 device = strtok(dev_list, ":");
475                 while (device != NULL) {
476                         l = strlen(device);
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);
481                         } else {
482                                 /*
483                                  * change the owner/group/permission;
484                                  * nonexistent devices are ignored
485                                  */
486                                 if (chown(device, uid, gid) == -1) {
487                                         if (errno != ENOENT) {
488                                                 (void) fprintf(stderr, "%s: ",
489                                                     permfile);
490                                                 perror(device);
491                                         }
492                                 } else {
493                                         if ((chmod(device, mode) == -1) &&
494                                             (errno != ENOENT)) {
495                                                 (void) fprintf(stderr, "%s: ",
496                                                     permfile);
497                                                 perror(device);
498                                         }
499                                 }
500                         }
501                         device = strtok((char *)NULL, ":");
502                 }
503         }
504         (void) fclose(fp);
505 }
506
507 /***************************************************************************
508  * dir_dev_acc
509  *
510  * Apply owner/group/perms to all files (except "." and "..") in a directory.
511  *
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  ***************************************************************************/
515
516 static void
517 dir_dev_acc(char *dir, uid_t uid, gid_t gid, mode_t mode, char *permfile)
518 {
519         DIR *dirp;
520         struct dirent *direntp;
521         char *name, path[MAXPATHLEN];
522
523         dirp = opendir(dir);
524         if (dirp == NULL)
525                 return;
526
527         while ((direntp = readdir(dirp)) != NULL) {
528                 name = direntp->d_name;
529                 if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
530                         continue;
531
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);
536                                 perror(path);
537                         }
538                 } else {
539                         if ((chmod(path, mode) == -1) && (errno != ENOENT)) {
540                                 (void) fprintf(stderr, "%s: ", permfile);
541                                 perror(path);
542                         }
543                 }
544         }
545         (void) closedir(dirp);
546 }
547
548 /*****************************************************************************
549  * resetdevperm
550  *
551  * Clean up access of devices in /etc/logindevperm by resetting the
552  * owner/group/permissions back to the login pseudo user.
553  *
554  *****************************************************************************/
555
556 extern struct passwd   puser;   /* pseudo_user password entry   */
557
558 static void
559 resetdevperm(char *ttyn)
560 {
561         logindevperm(ttyn, puser.pw_uid, puser.pw_gid);
562 }
563
564 #ifdef SUNAUTH 
565 /*****************************************************************************
566  * login_conv():
567  *
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
571  * messages.
572  *****************************************************************************/
573
574 static int
575 login_conv(int conv_id, int num_msg, struct ia_message **msg,
576            struct ia_response **response, void *appdata_ptr)
577 {
578         struct ia_message       *m;
579         struct ia_response      *r;
580         char                    *temp;
581         int                     k;
582
583 #ifdef lint
584         conv_id = conv_id;
585 #endif
586         if (num_msg <= 0)
587                 return (IA_CONV_FAILURE);
588
589         *response = (struct ia_response*) 
590                                 calloc(num_msg, sizeof (struct ia_response));
591         if (*response == NULL)
592                 return (IA_CONV_FAILURE);
593
594         (void) memset(*response, 0, sizeof (struct ia_response));
595
596         k = num_msg;
597         m = *msg;
598         r = *response;
599         while (k--) {
600
601                 switch (m->msg_style) {
602
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);
608                             *response = NULL;
609                             return (IA_CONV_FAILURE);
610                         }
611                         (void) strcpy(r->resp, saved_user_passwd);
612                         r->resp_len = strlen(r->resp);
613                     }
614
615                     m++;
616                     r++;
617                     break;
618
619
620                 case IA_ERROR_MSG:
621                         if (m->msg != NULL) { 
622                             Debug ("login_conv: %s\n", m->msg); 
623                         }
624                         m++;
625                         r++;
626                         break;
627
628                 default:
629                         Debug ("login_conv: Unexpected case %d\n", 
630                                 m->msg_style);
631                         break;
632                 }
633         }
634         return (IA_SUCCESS);
635 }
636
637
638 /*****************************************************************************
639  * end_conv():
640  *
641  * End of conversation function.  Called from PAM.  
642  * Currently a noop for dtlogin.
643  *****************************************************************************/
644
645 static void
646 end_conv()
647 {}
648 #endif SUNAUTH 
649
650 #ifdef PAM
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  ***************************************************************************/
657
658 #define INIT_PROC_PID   1
659 #define PAMTXD          "SUNW_OST_SYSOSPAM"
660 #define SCPYN(a, b)     (void) strncpy(a, b, sizeof (a))
661
662 /* utility function to do UTMP/WTMP management */
663 int
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 */
671 );
672
673 /*
674  * solaris_reset_utmp_mgmt 
675  *              a utility function which terminates UTMP/WTMP mgmt
676  */
677 int
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) */
685 );
686
687 /* flags for the flags field */
688 #define __NOOP  8       /* No utmp action desired */
689
690 /* __setproc_cred is a utility function to set process credentials */
691 int
692 __setproc_cred(
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 */
699 );
700
701 /* flags indicates specific set credential actions */
702
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 */
711
712 /*
713  * solaris_setutmp_mgmt - A utility function used to do UTMP/WTMP management.
714  *
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:
719  *
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
725  *
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
730  *      utmp).
731  *
732  *      Upon successful completion, SOLARIS_SUCCESS is returned.
733  *      Error values may include:
734  *
735  *      SOLARIS_NOENTRY     An entry for the specified process was not found
736  *      SOLARIS_ENTRYFAIL   Could not make/remove entry for specified process
737  */
738
739 int
740 solaris_setutmp_mgmt(
741         char    *user,
742         char    *ttyn,
743         char    *rhost,
744         int     flags,
745         int     type,
746         char    id[])
747 {
748         int                     tmplen;
749         struct utmpx            *u = (struct utmpx *)0;
750         struct utmpx            utmp;
751         char                    *ttyntail;
752         int                     err = PAM_SUCCESS;
753
754         Debug("Enter: solaris_setutmp_mgmt()\n");
755
756         (void) memset((void *)&utmp, 0, sizeof (utmp));
757
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;
765                 else
766                         utmp.ut_syslen = sizeof (utmp.ut_host);
767         } else {
768                 (void) memset(utmp.ut_host, 0, sizeof (utmp.ut_host));
769                 utmp.ut_syslen = 0;
770         }
771
772         (void) strcpy(utmp.ut_user, user);
773         /*
774          * Copy in the name of the tty minus the "/dev/" if a /dev/ is
775          * in the path name.
776          */
777
778         if (!(flags&SOLARIS_LOGIN))
779                 SCPYN(utmp.ut_line, ttyn);
780
781         ttyntail = ttyn;
782
783         utmp.ut_type = type;
784
785         if (id != NULL)
786                 (void) memcpy(utmp.ut_id, id, sizeof (utmp.ut_id));
787
788         if ((flags & SOLARIS_NOLOG) == SOLARIS_NOLOG) {
789                 updwtmpx(WTMPX_FILE, &utmp);
790         } else {
791                 /*
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.
798                  */
799
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)) {
809                                 if (ttyn)
810                                         SCPYN(utmp.ut_line,
811                                             (ttyn + sizeof ("/dev/") - 1));
812                                 if (id == NULL) {
813                                         (void) memcpy(utmp.ut_id, u->ut_id,
814                                                     sizeof (utmp.ut_id));
815                                 }
816                                 (void) pututxline(&utmp);
817                                 break;
818                         }
819                     }      /* end while */
820                     endutxent();                /* Close utmp file */
821                 }
822
823                 if (u == (struct utmpx *)NULL) {
824                         /* audit_login_main11(); */
825                         if (flags & SOLARIS_UPDATE_ENTRY)
826                                 err =  SOLARIS_NOENTRY;
827                         else
828                                 (void) makeutx(&utmp);
829                 }
830                 else
831                         updwtmpx(WTMPX_FILE, &utmp);
832         }
833         return (err);
834 }
835
836 /*
837  * solaris_reset_utmp_mgmt 
838  *              A utility function used to terminate  UTMP/WTMP mgmt.
839  *
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:
844  *
845  *      SOLARIS_NOLOG           Write a wtmp/wtmpx entry only
846  *      SOLARIS_NOOP            Ignore utmp/wtmp processing
847  *
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
851  *      utmp).
852  *
853  *      Upon successful completion, PAM_SUCCESS is returned.
854  *      Error values may include:
855  *
856  *      SOLARIS_NOENTRY    An entry for the specified process was not found
857  *      SOLARIS_ENTRYFAIL  Could not make/remove entry for specified process
858  */
859
860 int
861 solaris_reset_utmp_mgmt(
862         char    **user,
863         char    **ttyn,
864         char    **rhost,
865         int     flags,
866         int     status,
867         char    id[])
868 {
869         struct utmpx            *up;
870         struct utmpx            ut;
871         int                     err = 0;
872         int                     pid;
873
874         Debug("Enter: solaris_reset_utmp_mgmt()\n");
875
876
877         pid = (int) getpid();
878
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));
883
884                 if (id != NULL)
885                         (void) memcpy(ut.ut_id, id, sizeof (ut.ut_id));
886
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));
891                         else
892                                 (void) strncpy(ut.ut_line, *ttyn,
893                                                         sizeof (ut.ut_line));
894                 }
895                 ut.ut_pid  = pid;
896                 ut.ut_type = DEAD_PROCESS;
897                 ut.ut_exit.e_termination = 0;
898                 ut.ut_exit.e_exit = 0;
899                 ut.ut_syslen = 1;
900                 (void) gettimeofday(&ut.ut_tv, NULL);
901                 updwtmpx(WTMPX_FILE, &ut);
902
903                 return (PAM_SUCCESS);
904         } else {
905                 setutxent();
906                 while (up = getutxent()) {
907                         if (up->ut_pid == pid) {
908                                 if (up->ut_type == DEAD_PROCESS) {
909                                         /*
910                                          * Cleaned up elsewhere.
911                                          */
912                                         endutxent();
913                                         return (0);
914                                 }
915                                 if ((*user = (char *) strdup (up->ut_user))
916                                                         == NULL ||
917                                     (*ttyn = (char *) strdup (up->ut_line))
918                                                         == NULL ||
919                                     (*rhost = (char *) strdup (up->ut_host))
920                                                         == NULL)
921                                         return (PAM_BUF_ERR);
922
923                                 up->ut_type = DEAD_PROCESS;
924                                 up->ut_exit.e_termination = status & 0xff;
925                                 up->ut_exit.e_exit = (status >> 8) & 0xff;
926                                 if (id != NULL)
927                                         (void) memcpy(up->ut_id, id,
928                                                 sizeof (up->ut_id));
929                                 (void) time(&up->ut_tv.tv_sec);
930
931                                 /*
932                                  * For init (Process ID 1) we don't write to
933                                  * init's pipe, since we are init.
934                                  */
935                                 if (getpid() == INIT_PROC_PID) {
936                                         (void) pututxline(up);
937                                         /*
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.
941                                          */
942                                         updwtmpx("wtmpx", up);
943                                 } else {
944                                         if (modutx(up) == NULL) {
945                                                 Debug("modutx failed\n");
946                                                 /*
947                                                  * Since modutx failed we'll
948                                                  * write out the new entry
949                                                  * ourselves.
950                                                  */
951                                                 (void) pututxline(up);
952                                                 updwtmpx("wtmpx", up);
953                                         }
954                                 }
955
956                                 endutxent();
957
958                                 return (PAM_SUCCESS);
959                         }
960                 }
961
962                 endutxent();
963                 return (SOLARIS_NOENTRY);
964         }
965
966 }
967
968 #endif PAM