FreeBSD 10 clang port
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimSetUtmp.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 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$TOG: TermPrimSetUtmp.c /main/10 1998/04/03 17:11:42 mgreess $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company               *
31  * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32  * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc.                *
33  * (c) Copyright 1993, 1994, 1996 Novell, Inc.                          *
34  * (c) Copyright 1996 Digital Equipment Corporation.                    *
35  * (c) Copyright 1996 FUJITSU LIMITED.                                  *
36  * (c) Copyright 1996 Hitachi.                                          *
37  */
38
39 #include <Xm/Xm.h>
40 #include <TermPrimP.h>
41 #include <TermPrimSetUtmp.h>
42 #include <TermPrimUtil.h>
43 #include "TermPrimDebug.h"
44 #include "TermHeader.h"
45
46 /* for sigprocmask... */
47 #include <signal.h>
48
49 /* for open... */
50 #include <fcntl.h>
51
52 /* for getpw*() and getlogin() calls... */
53 #define X_INCLUDE_PWD_H
54 #define X_INCLUDE_NETDB_H
55 #define X_INCLUDE_UNISTD_H
56 #define XOS_USE_XT_LOCKING
57 #include <X11/Xos_r.h>
58
59 #ifdef  linux
60 #define UT_NO_pututline
61 #endif  /* sun */
62
63 #ifdef  __FreeBSD__
64 #if OSMAJORVERSION > 8
65 #define UT_UTMPX
66 #endif
67 #define UT_HOST         ut_host
68 #define UT_NO_pututline
69 #endif
70
71 #ifdef  sun
72 #define UT_UTMPX
73 #define UT_HOST         ut_host
74 #define UT_HOST_LEN     ut_syslen
75 #define UT_NO_pututline
76 #endif  /* sun */
77
78 #ifdef  __hpux
79 #define UT_HOST         ut_host
80 #define UT_ADDR         ut_addr
81 #endif  /* __hpux */
82
83 #ifdef  __AIX
84 #define UT_HOST         ut_host
85 #define UT_NO_pututline
86 #endif  /* __AIX */
87
88 #ifdef __osf__
89 #define UT_HOST         ut_host
90 #define UT_NO_pututline
91 #endif /* __osf__ */
92
93
94 /* /etc/utmp include files... */
95 #ifdef  UT_UTMPX
96 #include <utmpx.h>
97 #define getutent                getutxent       
98 #define getutid                 getutxid
99 #define getutline               getutxline
100 #ifdef  NOTDEF
101 #define pututline(entry)        updwtmpx(UTMPX_FILE, entry)
102 #endif  /* NOTDEF */
103 #define pututline               pututxline
104 #define setutent                setutxent
105 #define endutent                endutxent
106
107 #define utmp                    utmpx
108
109 #define ut_time                 ut_tv.tv_sec
110 #else   /* UT_UTMPX */
111 #include <utmp.h>
112 #endif  /* UT_UTMPX */
113
114 /* gethostbyname include files... */
115 #include <sys/socket.h>
116 #include <netinet/in.h>
117
118 typedef struct _utmpInfo {
119     char *utmpLine;
120     struct _utmpInfo *next;
121     struct _utmpInfo *prev;
122 } utmpInfo;
123
124 static utmpInfo _utmpInfoHead;
125 static utmpInfo *utmpInfoHead = &_utmpInfoHead;
126
127 void
128 _DtTermPrimUtmpAddEntry
129 (
130     char                 *utmpLine
131 )
132 {
133     utmpInfo             *utmpInfoTmp;
134     sigset_t              newSigs;
135     sigset_t              oldSigs;
136
137     /* malloc a new entry... */
138     utmpInfoTmp = (utmpInfo *) XtMalloc(sizeof(utmpInfo));
139     (void) memset(utmpInfoTmp, '\0', sizeof(utmpInfo));
140
141     /* fill in the structure... */
142     utmpInfoTmp->utmpLine = (char *) XtMalloc(strlen(utmpLine) + 1);
143     (void) strcpy(utmpInfoTmp->utmpLine, utmpLine);
144
145     /* insert it after the head of the list...
146      */
147     /* block all signals... */
148     (void) sigfillset(&newSigs);
149     (void) sigemptyset(&oldSigs);
150     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
151     /* insert the entry into the list... */
152     _DtTermProcessLock();
153     utmpInfoTmp->prev = utmpInfoHead;
154     utmpInfoTmp->next = utmpInfoHead->next;
155     utmpInfoHead->next = utmpInfoTmp;
156     if (utmpInfoTmp->next) {
157         utmpInfoTmp->next->prev = utmpInfoTmp;
158     }
159     _DtTermProcessUnlock();
160     /* restore signals... */
161     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
162 }
163
164 static void
165 DeleteUtmpInfo
166 (
167     char                 *utmpLine
168 )
169 {
170     utmpInfo             *utmpInfoTmp;
171     sigset_t              newSigs;
172     sigset_t              oldSigs;
173
174     _DtTermProcessLock();
175
176     /* find the entry... */
177     for (utmpInfoTmp = utmpInfoHead->next; utmpInfoTmp;
178             utmpInfoTmp = utmpInfoTmp->next) {
179         if (!strcmp(utmpInfoTmp->utmpLine, utmpLine)) {
180             break;
181         }
182     }
183
184     /* did we find anything... */
185     if (!utmpInfoTmp) {
186         /* not found... */
187         _DtTermProcessUnlock();
188         return;
189     }
190
191     /* delete entry from the list...
192      */
193     /* block all signals... */
194     (void) sigfillset(&newSigs);
195     (void) sigemptyset(&oldSigs);
196     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
197     /* remove it... */
198     utmpInfoTmp->prev->next = utmpInfoTmp->next;
199     if (utmpInfoTmp->next) {
200         utmpInfoTmp->next->prev = utmpInfoTmp->prev;
201     }
202     /* restore signals... */
203     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
204
205     /* free up the data... */
206     if (utmpInfoTmp->utmpLine) {
207         (void) XtFree(utmpInfoTmp->utmpLine);
208         utmpInfoTmp->utmpLine = (char *) 0;
209     }
210     (void) XtFree((char *) utmpInfoTmp);
211     _DtTermProcessUnlock();
212 }
213
214 static char *userName = (char *) 0;
215 Atom _DtTermPrim_XA_UtmpLine = (Atom) 0;
216 #ifdef  UT_ADDR
217 static char *localHostname = (char *) 0;
218 #endif  /* UT_ADDR */
219
220 #ifdef  UT_NO_pututline
221 static struct utmp *
222 _pututline(struct utmp *ut)
223 {
224     (void) pututline(ut);
225     return(ut);
226 }
227 #endif  /* UT_NO_pututline */
228
229 /* the following things should be done in the parent so that they will
230  * be available to all utmp entry creates which are done in the child.
231  * If we wait until we do the create, the info will not be passed back
232  * to the parent, and we will have to do it each and every time...
233  */
234 void
235 _DtTermPrimUtmpInit(Widget w)
236 {
237     char buffer[BUFSIZ];
238     char *c;
239     struct passwd * pw_ret;
240     _Xgetpwparams pw_buf;
241
242     char *namebuf;
243     _Xgetloginparams login_buf;
244
245 #ifdef UT_ADDR
246     struct hostent *            name_ret;
247     _Xgethostbynameparams       name_buf;
248 #endif
249
250     _DtTermProcessLock();
251
252     if (!userName) {
253 /* getpw{uid,nam}_r routines fail on IBM when searching passwd info via NIS.
254    The AIX specific code could be removed after IBM fixes the problem. Note
255    that there could still be a failure on IBM platform if "USER" env variable
256    is not defined. In any case, we would really not want to rely on the env
257    variable.
258 */
259 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
260       if ((c = getenv("USER")) == NULL) {
261 #endif
262         /* get the user's name from:
263          *      -/etc/utmp if possible,
264          *      -/etc/passwd if not.
265          */
266         if ((((namebuf = _XGetlogin(login_buf))) != NULL)
267             && (((pw_ret = _XGetpwnam(namebuf, pw_buf))) != NULL) 
268             && (pw_ret->pw_uid == getuid())) {
269             userName = XtMalloc(strlen(namebuf) + 1);
270             (void) strcpy(userName, namebuf);
271         } else if (((pw_ret = _XGetpwuid(getuid(), pw_buf))) != NULL) {
272             userName = XtMalloc(strlen(pw_ret->pw_name) + 1);
273             (void) strcpy(userName, pw_ret->pw_name);
274         }
275 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
276       }
277       else {
278         userName = XtMalloc(strlen(c) + 1);
279         (void) strcpy(userName, c);
280       }
281 #endif
282     }
283
284     if (!_DtTermPrim_XA_UtmpLine) {
285         _DtTermPrim_XA_UtmpLine = XInternAtom(XtDisplay(w), TermUtmpIdString, False);
286     }
287         
288 #ifdef  UT_ADDR
289     if (!localHostname && !gethostname(buffer, sizeof(buffer)) &&
290         (name_ret = _XGethostbyname(buffer, name_buf)) != NULL) {
291         localHostname = XtMalloc(strlen(buffer) + 1);
292         (void) strcpy(localHostname, buffer);
293     }
294 #endif  /* UT_ADDR */
295     _DtTermProcessUnlock();
296 }
297
298 char *
299 _DtTermPrimUtmpGetUtLine(int pty, char *ptyName)
300 {
301     Boolean closePty = False;
302     char *c;
303
304 #ifdef  DKS
305     /* use the same pty name that everyone else will use (the one
306      * returned by ttyname())...
307      */
308     _Xttynameparams tty_buf;
309
310     /* if we weren't passed a pty, let's try opening ptyName.  By using
311      * O_NOCTTY we are able to open the pty without accidentally becoming
312      * the session leader for it...
313      */
314     if ((pty < 0) && ((pty = open(ptyName, O_RDWR | O_NOCTTY, 0)) >= 0)) {
315         closePty = True;
316     }
317
318     /* if we have a pty, use ttyname to get it's "canonical" name... */
319     if ((pty >= 0) && (c = _XTtyname(pty, tty_buf))) {
320         ptyName = c;
321     }
322
323     /* close the pty if we opened it... */
324     if (closePty) {
325         (void) close(pty);
326         pty = -1;
327     }
328 #endif  /* DKS */
329
330     if (!strncmp(ptyName, "/dev/", strlen("/dev/"))) {
331         ptyName = ptyName + strlen("/dev/");
332     }
333
334     c = XtMalloc(strlen(ptyName) + 1);
335     (void) strcpy(c, ptyName);
336
337     return(c);
338 }
339
340 static char *
341 UtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
342 {
343 #if !defined(CSRG_BASED) /* XXX */
344     DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
345     struct termData *tpd = tw->term.tpd;
346     struct utmp ut;
347     struct utmp *utPtr;
348     char *c;
349     char *displayName;
350     time_t now;
351     Boolean closePty = False;
352 #ifdef  UT_HOST
353     char *seat;
354 #endif  /* UT_HOST */
355 #ifdef  UT_ADDR
356     struct sockaddr_in from;
357     int fromLen;
358 #endif  /* UT_ADDR */
359
360     /* initialize utmp stuff, just incase... */
361     (void) _DtTermPrimUtmpInit(w);
362
363     /* set up the entry to search for...
364      */
365
366     /* create the ut_line... */
367     (void) strncpy(ut.ut_line, utmpLine, sizeof(ut.ut_line));
368
369     ut.ut_type = DEAD_PROCESS;
370
371     /* position to entry in utmp file... */
372     (void) setutent();
373     if (NULL == (utPtr = getutline(&ut))) {
374         /* build a base utmp entry... */
375         utPtr = &ut;
376 #ifdef  __hpux
377         if (c = strstr(utmpLine, "tty")) {
378             c += strlen("tty");
379         } else if (c = strstr(utmpLine, "pts")) {
380             c += strlen("pts");
381         } else {
382             c = utmpLine;
383             if (strlen(utmpLine) > sizeof(utPtr->ut_id)) {
384                 c += strlen(utmpLine) - sizeof(utPtr->ut_id);
385             }
386         }
387         (void) strncpy(utPtr->ut_id, c, sizeof(utPtr->ut_id));
388 #else   /* __hpux */
389 #if defined(__AIX) || defined(__osf__)
390         (void) strncpy(utPtr->ut_id, utmpLine,
391                 sizeof(utPtr->ut_id));
392 #else   /* __AIX || __osf__ */
393 #if defined(linux) || defined(sun) || defined(USL) || defined(__uxp__)
394         if (c = strchr(utmpLine, '/')) {
395             c++;
396         } else {
397             c = utmpLine;
398         }
399         (void) strncpy(utPtr->ut_id, c, sizeof(utPtr->ut_id));
400 #else   /* linux || sun  || USL || __uxp__ */
401         error out -- missing code for utPtr->ut_id
402 #endif  /* sun */
403 #endif  /* __AIX || __osf__ */
404 #endif  /* __hpux */
405     }
406
407     /* set up the new entry... */
408     utPtr->ut_type = USER_PROCESS;
409 #if !defined(linux)
410     utPtr->ut_exit.e_termination = 0;
411     utPtr->ut_exit.e_exit = 2;
412 #endif
413                 
414     (void) strncpy(utPtr->ut_user, (userName && *userName) ? userName : "????",
415             sizeof(utPtr->ut_user));
416     (void) strncpy(utPtr->ut_line, utmpLine, sizeof(utPtr->ut_line));
417     utPtr->ut_pid = pid;
418     (void) time(&now);
419     utPtr->ut_time = now;
420
421     /* clear and set the host and addr fields... */
422 #ifdef  UT_HOST
423     (void) memset(utPtr->UT_HOST, '\0', sizeof(utPtr->UT_HOST));
424     /* stuff the display name into ut_host.  We will stuff as much as
425      * will fit dropping domain chunks as necessary to make it fit.  If
426      * we still can't fit with the entire domain removed, we will truncate
427      * the display name...
428      */
429     displayName = DisplayString(XtDisplay(w));
430     (void) strncpy(utPtr->UT_HOST, displayName, sizeof(utPtr->UT_HOST));
431 #ifdef  UT_HOST_LEN
432     utPtr->UT_HOST_LEN = strlen(displayName + 1);
433 #endif  /* UT_HOST_LEN */
434     if (sizeof(utPtr->UT_HOST) < strlen(displayName)) {
435         /* pull off the seat number... */
436         seat = strchr(displayName, ':');
437         /* back up through the display name.  Each time we hit a '.' that
438          * signals the start of a new domain chunk, see if we can fit
439          * the display name (less these domain chunks) plus the seat number
440          * into the structure...
441          */
442         if (seat - displayName < sizeof(utPtr->UT_HOST)) {
443             c = utPtr->UT_HOST + (seat - displayName) - 1;
444         } else {
445             c = utPtr->UT_HOST + sizeof(utPtr->UT_HOST) - 1;
446         }
447         for (; c >= utPtr->UT_HOST; c--) {
448             /* hit a '.'... */
449             if ((*c == '.') && (c - utPtr->UT_HOST + strlen(seat) <
450                     sizeof(utPtr->UT_HOST))) {
451                 /* everything left of the dot plus the seat will fit!... */
452                 break;
453             }
454         }
455         if (c >= utPtr->UT_HOST) {
456             /* we can perform a fit with some domains stripped... */
457             (void) strncpy(c, seat, sizeof(utPtr->UT_HOST) -
458                     (c - utPtr->UT_HOST));
459             if ((c - utPtr->UT_HOST) + strlen(seat) < sizeof(utPtr->UT_HOST)) {
460                 /* null out the end of the host name... */
461                 utPtr->UT_HOST[c - utPtr->UT_HOST + strlen(seat)] = '\0';
462 #ifdef  UT_HOST_LEN
463                 utPtr->UT_HOST_LEN = c - utPtr->UT_HOST + strlen(seat) + 1;
464 #endif  /* UT_HOST_LEN */
465             }
466         } else {
467             /* we can't fit even a single full chunk from the domain.
468              * since it is more important to get the seat number in (the
469              * host can be obtained from the addr), truncate the host.
470              */
471             (void) strncpy(utPtr->UT_HOST - strlen(seat), seat,
472                     strlen(seat));
473 #ifdef  UT_HOST_LEN
474             utPtr->UT_HOST_LEN = strlen(seat);
475 #endif  /* UT_HOST_LEN */
476         }
477     }
478 #endif  /* UT_HOST */
479
480 #ifdef  UT_ADDR
481     (void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
482
483     /* get the canonical host of the X socket... */
484     fromLen = sizeof(from);
485     if (!getpeername(ConnectionNumber(XtDisplay(w)), &from, &fromLen) &&
486             (from.sin_family == AF_INET)) {
487         utPtr->ut_addr = from.sin_addr.s_addr;
488     }
489 #endif  /* UT_ADDR */
490
491     /* write it out... */
492     if (_pututline(utPtr)) {
493         /* success...
494          */
495         (void) endutent();
496         return(utmpLine);
497     }
498     /* failure... */
499     (void) endutent();
500     return((char *) 0);
501 #else /* __OpenBSD__ */
502     return(utmpLine);
503 #endif
504 }
505
506 /* this is a public wrapper around the previous function that runs the
507  * previous function setuid root...
508  */
509 char *
510 _DtTermPrimUtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
511 {
512     char *retValue;
513
514     /* this function needs to be suid root... */
515     (void) _DtTermPrimToggleSuidRoot(True);
516     retValue = UtmpEntryCreate(w, pid, utmpLine);
517     /* we now need to turn off setuid root... */
518     (void) _DtTermPrimToggleSuidRoot(False);
519
520     return(retValue);
521 }
522
523 static void
524 UtmpEntryDestroy(Widget w, char *utmpLine)
525 {
526 #if !defined(CSRG_BASED)
527     struct utmp ut;
528     struct utmp *utPtr;
529     time_t now;
530
531     ut.ut_type = USER_PROCESS;
532     (void) strncpy(ut.ut_line, utmpLine, sizeof(ut.ut_line));
533     (void) setutent();
534     if (utPtr = getutline(&ut)) {
535         utPtr->ut_type = DEAD_PROCESS;
536 #if !defined(linux)
537         utPtr->ut_exit.e_termination = 0;
538         utPtr->ut_exit.e_exit = 0;
539 #endif
540         (void) time(&now);
541         utPtr->ut_time = now;
542 #ifdef  UT_HOST
543         (void) memset(utPtr->ut_host, '\0', sizeof(utPtr->ut_host));
544 #endif  /* UT_HOST */
545 #ifdef  UT_ADDR
546         (void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
547 #endif  /* UT_ADDR */
548         (void) pututline(utPtr);
549     }
550     (void) endutent();
551
552     (void) DeleteUtmpInfo(utmpLine);
553 #endif /* !__OpenBSD__ */
554 }
555
556 /* this is a public wrapper around the previous function that runs the
557  * previous function setuid root...
558  */
559 void
560 _DtTermPrimUtmpEntryDestroy(Widget w, char *utmpLine)
561 {
562     /* this function needs to be suid root... */
563     (void) _DtTermPrimToggleSuidRoot(True);
564     (void) UtmpEntryDestroy(w, utmpLine);
565     /* we now need to turn off setuid root... */
566     (void) _DtTermPrimToggleSuidRoot(False);
567 }
568
569 void
570 _DtTermPrimUtmpCleanup()
571 {
572     DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimUtmpCleanup() starting\n"));
573     _DtTermProcessLock();
574     while (utmpInfoHead->next && utmpInfoHead->next->utmpLine) {
575         DebugF('s', 10, fprintf(stderr, ">>resetting utmp for id \"%s\"\n",
576                 utmpInfoHead->next->utmpLine));
577         (void) _DtTermPrimUtmpEntryDestroy((Widget) 0,
578                 utmpInfoHead->next->utmpLine);
579     }
580     _DtTermProcessUnlock();
581     DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimUtmpCleanup() finished\n"));
582 }