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