2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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 */
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. *
40 #include <TermPrimP.h>
41 #include <TermPrimSetUtmp.h>
42 #include <TermPrimUtil.h>
43 #include "TermPrimDebug.h"
44 #include "TermHeader.h"
46 /* for sigprocmask... */
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>
60 #define UT_NO_pututline
64 #if OSMAJORVERSION > 8
67 #define UT_HOST ut_host
68 #define UT_NO_pututline
73 #define UT_HOST ut_host
74 #define UT_HOST_LEN ut_syslen
75 #define UT_NO_pututline
79 #define UT_HOST ut_host
80 #define UT_ADDR ut_addr
84 #define UT_HOST ut_host
85 #define UT_NO_pututline
89 #define UT_HOST ut_host
90 #define UT_NO_pututline
94 /* /etc/utmp include files... */
97 #define getutent getutxent
98 #define getutid getutxid
99 #define getutline getutxline
101 #define pututline(entry) updwtmpx(UTMPX_FILE, entry)
103 #define pututline pututxline
104 #define setutent setutxent
105 #define endutent endutxent
109 #define ut_time ut_tv.tv_sec
112 #endif /* UT_UTMPX */
114 /* gethostbyname include files... */
115 #include <sys/socket.h>
116 #include <netinet/in.h>
118 typedef struct _utmpInfo {
120 struct _utmpInfo *next;
121 struct _utmpInfo *prev;
124 static utmpInfo _utmpInfoHead;
125 static utmpInfo *utmpInfoHead = &_utmpInfoHead;
128 _DtTermPrimUtmpAddEntry
133 utmpInfo *utmpInfoTmp;
137 /* malloc a new entry... */
138 utmpInfoTmp = (utmpInfo *) XtMalloc(sizeof(utmpInfo));
139 (void) memset(utmpInfoTmp, '\0', sizeof(utmpInfo));
141 /* fill in the structure... */
142 utmpInfoTmp->utmpLine = (char *) XtMalloc(strlen(utmpLine) + 1);
143 (void) strcpy(utmpInfoTmp->utmpLine, utmpLine);
145 /* insert it after the head of the list...
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;
159 _DtTermProcessUnlock();
160 /* restore signals... */
161 (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
170 utmpInfo *utmpInfoTmp;
174 _DtTermProcessLock();
176 /* find the entry... */
177 for (utmpInfoTmp = utmpInfoHead->next; utmpInfoTmp;
178 utmpInfoTmp = utmpInfoTmp->next) {
179 if (!strcmp(utmpInfoTmp->utmpLine, utmpLine)) {
184 /* did we find anything... */
187 _DtTermProcessUnlock();
191 /* delete entry from the list...
193 /* block all signals... */
194 (void) sigfillset(&newSigs);
195 (void) sigemptyset(&oldSigs);
196 (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
198 utmpInfoTmp->prev->next = utmpInfoTmp->next;
199 if (utmpInfoTmp->next) {
200 utmpInfoTmp->next->prev = utmpInfoTmp->prev;
202 /* restore signals... */
203 (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
205 /* free up the data... */
206 if (utmpInfoTmp->utmpLine) {
207 (void) XtFree(utmpInfoTmp->utmpLine);
208 utmpInfoTmp->utmpLine = (char *) 0;
210 (void) XtFree((char *) utmpInfoTmp);
211 _DtTermProcessUnlock();
214 static char *userName = (char *) 0;
215 Atom _DtTermPrim_XA_UtmpLine = (Atom) 0;
217 static char *localHostname = (char *) 0;
220 #ifdef UT_NO_pututline
222 _pututline(struct utmp *ut)
224 (void) pututline(ut);
227 #endif /* UT_NO_pututline */
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...
235 _DtTermPrimUtmpInit(Widget w)
239 struct passwd * pw_ret;
240 _Xgetpwparams pw_buf;
243 _Xgetloginparams login_buf;
246 struct hostent * name_ret;
247 _Xgethostbynameparams name_buf;
250 _DtTermProcessLock();
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
259 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
260 if ((c = getenv("USER")) == NULL) {
262 /* get the user's name from:
263 * -/etc/utmp if possible,
264 * -/etc/passwd if not.
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);
275 #if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
278 userName = XtMalloc(strlen(c) + 1);
279 (void) strcpy(userName, c);
284 if (!_DtTermPrim_XA_UtmpLine) {
285 _DtTermPrim_XA_UtmpLine = XInternAtom(XtDisplay(w), TermUtmpIdString, False);
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);
295 _DtTermProcessUnlock();
299 _DtTermPrimUtmpGetUtLine(int pty, char *ptyName)
301 Boolean closePty = False;
305 /* use the same pty name that everyone else will use (the one
306 * returned by ttyname())...
308 _Xttynameparams tty_buf;
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...
314 if ((pty < 0) && ((pty = open(ptyName, O_RDWR | O_NOCTTY, 0)) >= 0)) {
318 /* if we have a pty, use ttyname to get it's "canonical" name... */
319 if ((pty >= 0) && (c = _XTtyname(pty, tty_buf))) {
323 /* close the pty if we opened it... */
330 if (!strncmp(ptyName, "/dev/", strlen("/dev/"))) {
331 ptyName = ptyName + strlen("/dev/");
334 c = XtMalloc(strlen(ptyName) + 1);
335 (void) strcpy(c, ptyName);
341 UtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
343 #if !defined(CSRG_BASED) /* XXX */
344 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
345 struct termData *tpd = tw->term.tpd;
351 Boolean closePty = False;
356 struct sockaddr_in from;
360 /* initialize utmp stuff, just incase... */
361 (void) _DtTermPrimUtmpInit(w);
363 /* set up the entry to search for...
366 /* create the ut_line... */
367 (void) strncpy(ut.ut_line, utmpLine, sizeof(ut.ut_line));
369 ut.ut_type = DEAD_PROCESS;
371 /* position to entry in utmp file... */
373 if (NULL == (utPtr = getutline(&ut))) {
374 /* build a base utmp entry... */
377 if (c = strstr(utmpLine, "tty")) {
379 } else if (c = strstr(utmpLine, "pts")) {
383 if (strlen(utmpLine) > sizeof(utPtr->ut_id)) {
384 c += strlen(utmpLine) - sizeof(utPtr->ut_id);
387 (void) strncpy(utPtr->ut_id, c, sizeof(utPtr->ut_id));
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)
394 if (c = strchr(utmpLine, '/')) {
399 (void) strncpy(utPtr->ut_id, c, sizeof(utPtr->ut_id));
400 #else /* linux || sun */
401 error out -- missing code for utPtr->ut_id
403 #endif /* __AIX || __osf__ */
407 /* set up the new entry... */
408 utPtr->ut_type = USER_PROCESS;
410 utPtr->ut_exit.e_termination = 0;
411 utPtr->ut_exit.e_exit = 2;
414 snprintf(utPtr->ut_user, sizeof(utPtr->ut_user),
415 "%s", (userName && *userName) ? userName : "????");
416 (void) strncpy(utPtr->ut_line, utmpLine, sizeof(utPtr->ut_line));
419 utPtr->ut_time = now;
421 /* clear and set the host and addr fields... */
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...
429 displayName = DisplayString(XtDisplay(w));
430 (void) strncpy(utPtr->UT_HOST, displayName, sizeof(utPtr->UT_HOST));
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...
442 if (seat - displayName < sizeof(utPtr->UT_HOST)) {
443 c = utPtr->UT_HOST + (seat - displayName) - 1;
445 c = utPtr->UT_HOST + sizeof(utPtr->UT_HOST) - 1;
447 for (; c >= utPtr->UT_HOST; c--) {
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!... */
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';
463 utPtr->UT_HOST_LEN = c - utPtr->UT_HOST + strlen(seat) + 1;
464 #endif /* UT_HOST_LEN */
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.
471 (void) strncpy(utPtr->UT_HOST - strlen(seat), seat,
474 utPtr->UT_HOST_LEN = strlen(seat);
475 #endif /* UT_HOST_LEN */
481 (void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
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;
491 /* write it out... */
492 if (_pututline(utPtr)) {
501 #else /* __OpenBSD__ */
506 /* this is a public wrapper around the previous function that runs the
507 * previous function setuid root...
510 _DtTermPrimUtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
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);
524 UtmpEntryDestroy(Widget w, char *utmpLine)
526 #if !defined(CSRG_BASED)
531 ut.ut_type = USER_PROCESS;
532 snprintf(ut.ut_line, sizeof(ut.ut_line), "%s", utmpLine);
534 if (utPtr = getutline(&ut)) {
535 utPtr->ut_type = DEAD_PROCESS;
537 utPtr->ut_exit.e_termination = 0;
538 utPtr->ut_exit.e_exit = 0;
541 utPtr->ut_time = now;
543 (void) memset(utPtr->ut_host, '\0', sizeof(utPtr->ut_host));
546 (void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
548 (void) pututline(utPtr);
552 (void) DeleteUtmpInfo(utmpLine);
553 #endif /* !__OpenBSD__ */
556 /* this is a public wrapper around the previous function that runs the
557 * previous function setuid root...
560 _DtTermPrimUtmpEntryDestroy(Widget w, char *utmpLine)
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);
570 _DtTermPrimUtmpCleanup()
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);
580 _DtTermProcessUnlock();
581 DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimUtmpCleanup() finished\n"));