2783e22f25e4600c2882015abd6a6cb30e29c364
[oweals/cde.git] / cde / programs / dtlogin / account.c
1 /* $XConsortium: account.c /main/6 1996/10/30 11:12:13 drk $ */
2 /*                                                                      *
3  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
4  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
5  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
6  * (c) Copyright 1993, 1994 Novell, Inc.                                *
7  */
8 /*
9  *  account.c
10  *
11  *    routines for handling accounting
12  *
13  *    ex. utmp/wtmp/btmp, user-license restrictions,
14  *
15  */
16
17
18 /***************************************************************************
19  *
20  *  Includes
21  *
22  ***************************************************************************/
23
24
25 #ifdef __apollo
26 #include <X11/apollosys.h>        /* for pid_t struct in hp-ux sys/types.h */
27 #include        <sys/types.h>
28 #else
29 #include        <sys/types.h>
30 #include        <sys/stat.h>
31 #endif
32
33 #ifdef AIXV3
34 #include        <usersec.h>
35 #endif
36
37 #include        <fcntl.h>
38 #include        <utmp.h>
39 #include        <time.h>
40 #include        "dm.h"
41
42 #ifdef __PASSWD_ETC
43 #include        "rgy_base.h"
44 #endif
45
46
47 /***************************************************************************
48  *
49  *  External declarations
50  *
51  ***************************************************************************/
52 #if defined(AIXV3) && !defined(_POWER)
53 extern void
54 GetLoginInfo(struct display *d, int *loginType, char *ttyName, char **hostname);
55 #endif
56
57
58
59 /***************************************************************************
60  *
61  *  Procedure declarations
62  *
63  ***************************************************************************/
64 #if defined(AIXV3) && !defined(_POWER)
65 void dt_lastlogin ( char * user, struct lastlogin * llogin);
66 #endif
67
68
69
70
71 /***************************************************************************
72  *
73  *  Global variables
74  *
75  ***************************************************************************/
76
77 #ifdef __PASSWD_ETC
78 struct rtmp {
79          char              rt_line[8];       /* tty name */
80          rgy_$login_name_t rt_name;          /* user id (full SID) */
81          char              rt_host[16];      /* hostname, if remote */
82          long              rt_time;          /* time on */
83 };
84 #endif
85
86 #ifdef AIXV3
87 struct  lastlogin {
88         time_t  ftime;
89         time_t  stime;
90         int     fcount;
91         char    user[32];
92         char    *stty;
93         char    *ftty;
94         char    *shost;
95         char    *fhost;
96 };
97
98
99 static struct lastlogin last_login;
100 #endif
101
102
103
104 /***************************************************************************
105  *
106  *  Account
107  *
108  *  update utmp/wtmp files.  
109  ***************************************************************************/
110 void 
111 Account( struct display *d, char *user, char *line, pid_t pid,
112 #if NeedWidePrototypes
113         int type,
114 #else
115         short type,
116 #endif /* NeedWidePrototypes */
117         waitType exitcode )
118 {
119     struct utmp utmp;           /* local struct for new entry              */
120     struct utmp *u;             /* pointer to entry in utmp file           */
121     int fd;
122     char        buf[32];
123     char* user_str = user ? user : "NULL";
124     char* line_str = line ? line : "NULL";
125             
126 #ifdef __PASSWD_ETC
127     struct rtmp rtmp;
128     struct rtmp *r;
129     int tty_slot;
130     int rtmp_fd;
131 #endif
132
133     if (d->utmpId == NULL) return;
134     
135     switch (type) {
136     
137     case INIT_PROCESS:  strcpy(buf, "INIT_PROCESS");    break;
138     case LOGIN_PROCESS: strcpy(buf, "LOGIN_PROCESS");   break;
139     case USER_PROCESS:  strcpy(buf, "USER_PROCESS");    break;
140     case DEAD_PROCESS:  strcpy(buf, "DEAD_PROCESS");    break;
141     default:            strcpy(buf, "UNKNOWN");         break;
142     }
143
144     Debug("Account: id=%s, user=%s, line=%s, pid=%d, type=%s\n",
145            d->utmpId, user_str, line_str, pid, buf);
146
147 #ifdef PAM
148     PamAccounting("dtlogin", d->name, d->utmpId, user, 
149                         line, pid, type, exitcode);
150 #else
151 #   ifdef SUNAUTH
152        solaris_accounting("dtlogin", d->name, d->utmpId, user, 
153                            line, pid, type, exitcode);
154 #   endif
155 #endif
156
157 #ifdef sun
158     return;
159 #else
160     bzero(&utmp, sizeof(struct utmp));
161
162     strncpy(utmp.ut_id, d->utmpId, sizeof(u->ut_id));
163     utmp.ut_type = LOGIN_PROCESS;
164     
165     setutent();
166     if ( (u = getutid(&utmp)) == NULL ) u = &utmp;
167
168     /*
169      *  make sure process ID's match if this is DEAD_PROCESS...
170      *  don't update an already DEAD_PROCESS...
171      */
172
173     if ((type == DEAD_PROCESS && pid != 0 && u->ut_pid != pid) ||
174         (type == DEAD_PROCESS && u->ut_type == DEAD_PROCESS)    ) {
175
176         endutent();
177         return;
178     }
179
180
181     /*
182      *  fill in required fields of utmp structure...
183      *
184      *  Note: for USER_PRCESS the "e_exit" field is overloaded to contain
185      *        the method for counting this user. This is used later to
186      *        determine if restricted user licenses have been exceeded.
187      *        Currently, an unlimited number of foreign displays can log in.
188      */
189      
190     if (user) strncpy(u->ut_user, user, sizeof(u->ut_user));
191     if (line) {
192 #ifdef _AIX
193 /*
194       For AIX the Init process writes the exact mapped device name for console
195       to the utmp file (like hft/0), if a getty on /dev/console record exists
196       in the Inittab file.Hitherto, we need to have a similar logic to make
197       sure for having the correct entry in the utmp file in order for the correct
198       operation of the GettyRunning function. It should be noted that by having
199       the correct value in the d->gettyLine field, the utmp file eventuallly
200       updated by the Account function in dm.c will have the right value. And
201       thus the GettyRunning function returns the appropriate value. So, it
202       is important that the following logic be included here for AIX platform
203       only.
204       Raghu Krovvidi         07.06.93
205  */
206
207         if (!strcmp(line,"console")) {
208              char *ttynm;
209              int fd=0;
210
211              fd = open("/dev/console",O_RDONLY);
212              ttynm = ttyname(fd);
213              ttynm += 5;
214              strcpy(u->ut_line,ttynm);
215              close(fd);
216         }
217         else
218              strncpy(u->ut_line, line, sizeof(u->ut_line));
219              
220 #else
221              strncpy(u->ut_line, line, sizeof(u->ut_line));
222 #endif
223     }
224     if (pid ) u->ut_pid = pid;
225     if (type) {
226         u->ut_type = type;
227         if (type == DEAD_PROCESS) {
228             u->ut_exit.e_termination = waitSig(exitcode);
229             u->ut_exit.e_exit = waitCode(exitcode);
230 #ifndef SVR4
231             (void) memset((char *) u->ut_host, '\0', sizeof(u->ut_host));
232 #endif
233         }
234
235         if (type == LOGIN_PROCESS && d->displayType.location != Local ) {
236 #ifndef SVR4
237             strncpy(u->ut_host, d->name, sizeof(u->ut_host));
238 #endif
239 #ifdef __hpux
240             u->ut_addr = 0;
241 #endif
242         }
243                     
244         if (type == USER_PROCESS)
245             u->ut_exit.e_exit = (d->displayType.location == Local ? 1 : 0 );
246     }   
247
248     (void) time(&u->ut_time);
249
250     /* 
251      * write to utmp...  
252      *
253      * (Do not close utmp yet. If "u" points to the static structure, it is
254      *  cleared upon close. This does not bode well for the following write
255      *  to wtmp!)
256      */
257
258     pututline(u);
259
260
261     /*
262      *  write the same entry to wtmp...
263      */
264
265     if ((fd = open(WTMP_FILE, O_WRONLY | O_APPEND)) >= 0) {
266         write(fd, u, sizeof(utmp));
267         close(fd);
268     }
269
270
271     /*
272      *  close utmp...
273      */
274      
275     endutent();
276
277 #ifdef __PASSWD_ETC
278     /* Now fill in the "rgy utmp" struct */
279     if (line) strncpy(rtmp.rt_line, u->ut_line, sizeof(u->ut_line));
280     bzero(rtmp.rt_host, sizeof(rtmp.rt_host));
281     rtmp.rt_time = u->ut_time;
282     r = &rtmp;
283
284     /* Write entry to rtmp */
285     tty_slot = ttyslot();
286
287     if (tty_slot > 0 && (rtmp_fd = open("/etc/rtmp", O_WRONLY|O_CREAT, 0644)) >= 0) {
288          lseek(rtmp_fd, (long) (tty_slot * sizeof(struct rtmp)), 0);
289          write(rtmp_fd, (char *) r, sizeof(struct rtmp));
290          close(rtmp_fd);
291     }
292 #endif
293 #if defined(AIXV3) && !defined(_POWER)
294         /* Log the lastlogin data ..    RK  09.13.93  */
295         /** in AIX 4.1 this is taken care of during authentication **/
296     if(type == USER_PROCESS) {
297         int loginType;
298         char tempTtyName[128];
299         char *hostname;
300
301         GetLoginInfo(d, &loginType, tempTtyName, &hostname);
302         time(&last_login.stime);
303
304         if(line) {
305                 Debug("tty_last_login is (line=%s)\n",line);
306                 last_login.stty = (char *)malloc(strlen(line) + 1);
307                 strcpy(last_login.stty,line);
308         } else {
309             last_login.stty = (char *)malloc(strlen(tempTtyName) + 1);
310             strcpy(last_login.stty,tempTtyName);
311         }
312
313         last_login.shost = (char *) malloc (MAXHOSTNAMELEN);
314         if (hostname == NULL) {
315             gethostname (last_login.shost , MAXHOSTNAMELEN);
316         } else {
317             strncpy(last_login.shost, hostname, MAXHOSTNAMELEN);
318             last_login.shost[MAXHOSTNAMELEN -1] = '\0';
319         }
320
321         Debug("logging lastlogin entry (user=%s)\n",user);
322         dt_lastlogin(user,&last_login); 
323         free(last_login.stty);
324         free(last_login.shost);
325     }
326 #endif
327
328 #endif /* !sun */
329 }
330
331
332
333
334 /***************************************************************************
335  *
336  *  UtmpIdOpen
337  *
338  *  see if a particular utmp ID is available
339  *
340  * return codes:  0 = ID is in use
341  *                1 = ID is open 
342  ***************************************************************************/
343
344 int 
345 UtmpIdOpen( char *utmpId )
346 {
347     struct utmp *u;             /* pointer to entry in utmp file           */
348     int    status = 1;          /* return code                             */
349
350     while ( (u = getutent()) != NULL ) {
351
352         if ( (strncmp(u->ut_id, utmpId, 4) == 0 ) &&
353              u->ut_type != DEAD_PROCESS ) {
354
355             status = 0;
356             break;
357         }
358     }
359     
360     endutent();
361     return (status);
362 }
363
364
365
366 #if defined(AIXV3) && !defined(_POWER)
367 void dt_lastlogin ( user, llogin)
368 char * user;
369 struct lastlogin * llogin;
370 {
371         char *tmp_char;
372         char *tmp_int;
373         /*
374          * We are loading all the lastlogin info into a struct and then dealing 
375          * with that so if the technique of storing the values is redone it 
376          * will be easy
377          */
378         /* set id back to root */
379         seteuid(0);
380                 /*
381                  * Open up the user data base
382                  */
383                 setuserdb(S_READ | S_WRITE);
384
385                 /*
386                  * setting new unsuccessful login attempts times
387                  */
388                 if (llogin->ftime) {
389                         /*
390                          * Get the old Failure count and increment it
391                          */
392                         if (getuserattr(user, S_ULOGCNT, &tmp_int, SEC_INT) != 0)
393                                 llogin->fcount = 0;
394                         else
395                                 llogin->fcount = (int)tmp_int;
396
397                         /*
398                          * put all the new data
399                          */
400                         putuserattr(user, S_ULASTTTY, llogin->ftty, SEC_CHAR);
401                         llogin->fcount++;
402                         putuserattr(user, S_ULOGCNT, (void *)llogin->fcount,
403                                     SEC_INT);
404                         putuserattr(user, S_ULASTTIME, (void *)llogin->ftime,
405                                     SEC_INT);
406                         putuserattr(user, S_ULASTHOST, llogin->fhost, SEC_CHAR);
407                         putuserattr(user, NULL, NULL, SEC_COMMIT);
408
409                         /*
410                          * Close data base and zero out indicator fields
411                          */
412                         llogin->ftime = 0;
413                         llogin->fcount = 0;
414                 }
415
416                 /*
417                  * New Successful login data
418                  */
419                 if (llogin->stime) {
420                         putuserattr(user, S_LASTTIME, (void *)llogin->stime,
421                                     SEC_INT);
422                         putuserattr(user, S_LASTTTY, llogin->stty, SEC_CHAR);
423                         Debug("hostname logged is %s\n",llogin->shost);
424                         putuserattr(user, S_LASTHOST, llogin->shost, SEC_CHAR);
425                         putuserattr(user, S_ULOGCNT, 0, SEC_INT);
426                         putuserattr(user, NULL, NULL, SEC_COMMIT);
427                 }
428         enduserdb();
429 }
430 #endif
431