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