This has meant very little for a long time as configure.ac just hardcoded these values depending on the current OS versions at the time. The only place where this is really 'needed' is XlationSvc.c in DtSvc so that differences between locale specifications on various versions of an OS can be accounted for. So for now, we just define those when building DtSvc. We could probably safely remove them as well with an update to the Xlate locale DB to remove ancient cruft we don't care about anymore. For various other modules, like dtlogin, dtsession, etc we just use the code that was already being used due to the hardcoded values we've had for the last 10-ish years.
549 lines
15 KiB
C
549 lines
15 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* *
|
|
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
|
|
* (c) Copyright 1996 Digital Equipment Corporation. *
|
|
* (c) Copyright 1996 FUJITSU LIMITED. *
|
|
* (c) Copyright 1996 Hitachi. *
|
|
*/
|
|
|
|
#include <Xm/Xm.h>
|
|
#include <TermPrimP.h>
|
|
#include <TermPrimSetUtmp.h>
|
|
#include <TermPrimUtil.h>
|
|
#include "TermPrimDebug.h"
|
|
#include "TermHeader.h"
|
|
|
|
/* for sigprocmask... */
|
|
#include <signal.h>
|
|
|
|
/* for open... */
|
|
#include <fcntl.h>
|
|
|
|
/* for getpw*() and getlogin() calls... */
|
|
#define X_INCLUDE_PWD_H
|
|
#define X_INCLUDE_NETDB_H
|
|
#define X_INCLUDE_UNISTD_H
|
|
#define XOS_USE_XT_LOCKING
|
|
#include <X11/Xos_r.h>
|
|
|
|
#ifdef __linux__
|
|
#define UT_NO_pututline
|
|
#endif /* sun */
|
|
|
|
#ifdef __FreeBSD__
|
|
#define UT_UTMPX
|
|
#define UT_HOST ut_host
|
|
#define UT_NO_pututline
|
|
#endif
|
|
|
|
#ifdef sun
|
|
#define UT_UTMPX
|
|
#define UT_HOST ut_host
|
|
#define UT_HOST_LEN ut_syslen
|
|
#define UT_NO_pututline
|
|
#endif /* sun */
|
|
|
|
#ifdef __AIX
|
|
#define UT_HOST ut_host
|
|
#define UT_NO_pututline
|
|
#endif /* __AIX */
|
|
|
|
|
|
/* /etc/utmp include files... */
|
|
#ifdef UT_UTMPX
|
|
#include <utmpx.h>
|
|
#define getutent getutxent
|
|
#define getutid getutxid
|
|
#define getutline getutxline
|
|
#ifdef NOTDEF
|
|
#define pututline(entry) updwtmpx(UTMPX_FILE, entry)
|
|
#endif /* NOTDEF */
|
|
#define pututline pututxline
|
|
#define setutent setutxent
|
|
#define endutent endutxent
|
|
|
|
#define utmp utmpx
|
|
|
|
#define ut_time ut_tv.tv_sec
|
|
#else /* UT_UTMPX */
|
|
#include <utmp.h>
|
|
#endif /* UT_UTMPX */
|
|
|
|
/* gethostbyname include files... */
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
|
|
typedef struct _utmpInfo {
|
|
char *utmpLine;
|
|
struct _utmpInfo *next;
|
|
struct _utmpInfo *prev;
|
|
} utmpInfo;
|
|
|
|
static utmpInfo _utmpInfoHead;
|
|
static utmpInfo *utmpInfoHead = &_utmpInfoHead;
|
|
|
|
void
|
|
_DtTermPrimUtmpAddEntry
|
|
(
|
|
char *utmpLine
|
|
)
|
|
{
|
|
utmpInfo *utmpInfoTmp;
|
|
sigset_t newSigs;
|
|
sigset_t oldSigs;
|
|
|
|
/* malloc a new entry... */
|
|
utmpInfoTmp = (utmpInfo *) XtMalloc(sizeof(utmpInfo));
|
|
(void) memset(utmpInfoTmp, '\0', sizeof(utmpInfo));
|
|
|
|
/* fill in the structure... */
|
|
utmpInfoTmp->utmpLine = (char *) XtMalloc(strlen(utmpLine) + 1);
|
|
(void) strcpy(utmpInfoTmp->utmpLine, utmpLine);
|
|
|
|
/* insert it after the head of the list...
|
|
*/
|
|
/* block all signals... */
|
|
(void) sigfillset(&newSigs);
|
|
(void) sigemptyset(&oldSigs);
|
|
(void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
|
|
/* insert the entry into the list... */
|
|
_DtTermProcessLock();
|
|
utmpInfoTmp->prev = utmpInfoHead;
|
|
utmpInfoTmp->next = utmpInfoHead->next;
|
|
utmpInfoHead->next = utmpInfoTmp;
|
|
if (utmpInfoTmp->next) {
|
|
utmpInfoTmp->next->prev = utmpInfoTmp;
|
|
}
|
|
_DtTermProcessUnlock();
|
|
/* restore signals... */
|
|
(void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
|
|
}
|
|
|
|
static void
|
|
DeleteUtmpInfo
|
|
(
|
|
char *utmpLine
|
|
)
|
|
{
|
|
utmpInfo *utmpInfoTmp;
|
|
sigset_t newSigs;
|
|
sigset_t oldSigs;
|
|
|
|
_DtTermProcessLock();
|
|
|
|
/* find the entry... */
|
|
for (utmpInfoTmp = utmpInfoHead->next; utmpInfoTmp;
|
|
utmpInfoTmp = utmpInfoTmp->next) {
|
|
if (!strcmp(utmpInfoTmp->utmpLine, utmpLine)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* did we find anything... */
|
|
if (!utmpInfoTmp) {
|
|
/* not found... */
|
|
_DtTermProcessUnlock();
|
|
return;
|
|
}
|
|
|
|
/* delete entry from the list...
|
|
*/
|
|
/* block all signals... */
|
|
(void) sigfillset(&newSigs);
|
|
(void) sigemptyset(&oldSigs);
|
|
(void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
|
|
/* remove it... */
|
|
utmpInfoTmp->prev->next = utmpInfoTmp->next;
|
|
if (utmpInfoTmp->next) {
|
|
utmpInfoTmp->next->prev = utmpInfoTmp->prev;
|
|
}
|
|
/* restore signals... */
|
|
(void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
|
|
|
|
/* free up the data... */
|
|
if (utmpInfoTmp->utmpLine) {
|
|
(void) XtFree(utmpInfoTmp->utmpLine);
|
|
utmpInfoTmp->utmpLine = (char *) 0;
|
|
}
|
|
(void) XtFree((char *) utmpInfoTmp);
|
|
_DtTermProcessUnlock();
|
|
}
|
|
|
|
static char *userName = (char *) 0;
|
|
Atom _DtTermPrim_XA_UtmpLine = (Atom) 0;
|
|
#ifdef UT_ADDR
|
|
static char *localHostname = (char *) 0;
|
|
#endif /* UT_ADDR */
|
|
|
|
#ifdef UT_NO_pututline
|
|
static struct utmp *
|
|
_pututline(struct utmp *ut)
|
|
{
|
|
(void) pututline(ut);
|
|
return(ut);
|
|
}
|
|
#endif /* UT_NO_pututline */
|
|
|
|
/* the following things should be done in the parent so that they will
|
|
* be available to all utmp entry creates which are done in the child.
|
|
* If we wait until we do the create, the info will not be passed back
|
|
* to the parent, and we will have to do it each and every time...
|
|
*/
|
|
void
|
|
_DtTermPrimUtmpInit(Widget w)
|
|
{
|
|
char buffer[BUFSIZ];
|
|
char *c;
|
|
struct passwd * pw_ret;
|
|
_Xgetpwparams pw_buf;
|
|
|
|
char *namebuf;
|
|
_Xgetloginparams login_buf;
|
|
|
|
#ifdef UT_ADDR
|
|
struct hostent * name_ret;
|
|
_Xgethostbynameparams name_buf;
|
|
#endif
|
|
|
|
_DtTermProcessLock();
|
|
|
|
if (!userName) {
|
|
/* getpw{uid,nam}_r routines fail on IBM when searching passwd info via NIS.
|
|
The AIX specific code could be removed after IBM fixes the problem. Note
|
|
that there could still be a failure on IBM platform if "USER" env variable
|
|
is not defined. In any case, we would really not want to rely on the env
|
|
variable.
|
|
*/
|
|
#if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
|
|
if ((c = getenv("USER")) == NULL) {
|
|
#endif
|
|
/* get the user's name from:
|
|
* -/etc/utmp if possible,
|
|
* -/etc/passwd if not.
|
|
*/
|
|
if ((((namebuf = _XGetlogin(login_buf))) != NULL)
|
|
&& (((pw_ret = _XGetpwnam(namebuf, pw_buf))) != NULL)
|
|
&& (pw_ret->pw_uid == getuid())) {
|
|
userName = XtMalloc(strlen(namebuf) + 1);
|
|
(void) strcpy(userName, namebuf);
|
|
} else if (((pw_ret = _XGetpwuid(getuid(), pw_buf))) != NULL) {
|
|
userName = XtMalloc(strlen(pw_ret->pw_name) + 1);
|
|
(void) strcpy(userName, pw_ret->pw_name);
|
|
}
|
|
#if defined(XTHREADS) && defined(XUSE_MTSAFE_API) && defined(AIXV3)
|
|
}
|
|
else {
|
|
userName = XtMalloc(strlen(c) + 1);
|
|
(void) strcpy(userName, c);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (!_DtTermPrim_XA_UtmpLine) {
|
|
_DtTermPrim_XA_UtmpLine = XInternAtom(XtDisplay(w), TermUtmpIdString, False);
|
|
}
|
|
|
|
#ifdef UT_ADDR
|
|
if (!localHostname && !gethostname(buffer, sizeof(buffer)) &&
|
|
(name_ret = _XGethostbyname(buffer, name_buf)) != NULL) {
|
|
localHostname = XtMalloc(strlen(buffer) + 1);
|
|
(void) strcpy(localHostname, buffer);
|
|
}
|
|
#endif /* UT_ADDR */
|
|
_DtTermProcessUnlock();
|
|
}
|
|
|
|
char *
|
|
_DtTermPrimUtmpGetUtLine(int pty, char *ptyName)
|
|
{
|
|
Boolean closePty = False;
|
|
char *c;
|
|
|
|
#ifdef DKS
|
|
/* use the same pty name that everyone else will use (the one
|
|
* returned by ttyname())...
|
|
*/
|
|
_Xttynameparams tty_buf;
|
|
|
|
/* if we weren't passed a pty, let's try opening ptyName. By using
|
|
* O_NOCTTY we are able to open the pty without accidentally becoming
|
|
* the session leader for it...
|
|
*/
|
|
if ((pty < 0) && ((pty = open(ptyName, O_RDWR | O_NOCTTY, 0)) >= 0)) {
|
|
closePty = True;
|
|
}
|
|
|
|
/* if we have a pty, use ttyname to get it's "canonical" name... */
|
|
if ((pty >= 0) && (c = _XTtyname(pty, tty_buf))) {
|
|
ptyName = c;
|
|
}
|
|
|
|
/* close the pty if we opened it... */
|
|
if (closePty) {
|
|
(void) close(pty);
|
|
pty = -1;
|
|
}
|
|
#endif /* DKS */
|
|
|
|
if (!strncmp(ptyName, "/dev/", strlen("/dev/"))) {
|
|
ptyName = ptyName + strlen("/dev/");
|
|
}
|
|
|
|
c = XtMalloc(strlen(ptyName) + 1);
|
|
(void) strcpy(c, ptyName);
|
|
|
|
return(c);
|
|
}
|
|
|
|
static char *
|
|
UtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
|
|
{
|
|
#if !defined(CSRG_BASED) /* XXX */
|
|
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
|
|
struct termData *tpd = tw->term.tpd;
|
|
struct utmp ut;
|
|
struct utmp *utPtr;
|
|
char *c;
|
|
char *displayName;
|
|
time_t now;
|
|
Boolean closePty = False;
|
|
#ifdef UT_HOST
|
|
char *seat;
|
|
#endif /* UT_HOST */
|
|
#ifdef UT_ADDR
|
|
struct sockaddr_in from;
|
|
int fromLen;
|
|
#endif /* UT_ADDR */
|
|
|
|
/* initialize utmp stuff, just incase... */
|
|
(void) _DtTermPrimUtmpInit(w);
|
|
|
|
/* set up the entry to search for...
|
|
*/
|
|
|
|
/* create the ut_line... */
|
|
(void) strncpy(ut.ut_line, utmpLine, sizeof(ut.ut_line));
|
|
|
|
ut.ut_type = DEAD_PROCESS;
|
|
|
|
/* position to entry in utmp file... */
|
|
(void) setutent();
|
|
if (NULL == (utPtr = getutline(&ut))) {
|
|
/* build a base utmp entry... */
|
|
utPtr = &ut;
|
|
#if defined(__AIX)
|
|
(void) strncpy(utPtr->ut_id, utmpLine,
|
|
sizeof(utPtr->ut_id));
|
|
#elif defined(__linux__) || defined(sun)
|
|
if (c = strchr(utmpLine, '/')) {
|
|
c++;
|
|
} else {
|
|
c = utmpLine;
|
|
}
|
|
(void) strncpy(utPtr->ut_id, c, sizeof(utPtr->ut_id));
|
|
#else /* linux || sun */
|
|
error out -- missing code for utPtr->ut_id
|
|
#endif /* sun */
|
|
}
|
|
|
|
/* set up the new entry... */
|
|
utPtr->ut_type = USER_PROCESS;
|
|
#if !defined(__linux__)
|
|
utPtr->ut_exit.e_termination = 0;
|
|
utPtr->ut_exit.e_exit = 2;
|
|
#endif
|
|
|
|
snprintf(utPtr->ut_user, sizeof(utPtr->ut_user),
|
|
"%s", (userName && *userName) ? userName : "????");
|
|
(void) strncpy(utPtr->ut_line, utmpLine, sizeof(utPtr->ut_line));
|
|
utPtr->ut_pid = pid;
|
|
(void) time(&now);
|
|
utPtr->ut_time = now;
|
|
|
|
/* clear and set the host and addr fields... */
|
|
#ifdef UT_HOST
|
|
(void) memset(utPtr->UT_HOST, '\0', sizeof(utPtr->UT_HOST));
|
|
/* stuff the display name into ut_host. We will stuff as much as
|
|
* will fit dropping domain chunks as necessary to make it fit. If
|
|
* we still can't fit with the entire domain removed, we will truncate
|
|
* the display name...
|
|
*/
|
|
displayName = DisplayString(XtDisplay(w));
|
|
(void) strncpy(utPtr->UT_HOST, displayName, sizeof(utPtr->UT_HOST));
|
|
#ifdef UT_HOST_LEN
|
|
utPtr->UT_HOST_LEN = strlen(displayName + 1);
|
|
#endif /* UT_HOST_LEN */
|
|
if (sizeof(utPtr->UT_HOST) < strlen(displayName)) {
|
|
/* pull off the seat number... */
|
|
seat = strchr(displayName, ':');
|
|
/* back up through the display name. Each time we hit a '.' that
|
|
* signals the start of a new domain chunk, see if we can fit
|
|
* the display name (less these domain chunks) plus the seat number
|
|
* into the structure...
|
|
*/
|
|
if (seat - displayName < sizeof(utPtr->UT_HOST)) {
|
|
c = utPtr->UT_HOST + (seat - displayName) - 1;
|
|
} else {
|
|
c = utPtr->UT_HOST + sizeof(utPtr->UT_HOST) - 1;
|
|
}
|
|
for (; c >= utPtr->UT_HOST; c--) {
|
|
/* hit a '.'... */
|
|
if ((*c == '.') && (c - utPtr->UT_HOST + strlen(seat) <
|
|
sizeof(utPtr->UT_HOST))) {
|
|
/* everything left of the dot plus the seat will fit!... */
|
|
break;
|
|
}
|
|
}
|
|
if (c >= utPtr->UT_HOST) {
|
|
/* we can perform a fit with some domains stripped... */
|
|
(void) strncpy(c, seat, sizeof(utPtr->UT_HOST) -
|
|
(c - utPtr->UT_HOST));
|
|
if ((c - utPtr->UT_HOST) + strlen(seat) < sizeof(utPtr->UT_HOST)) {
|
|
/* null out the end of the host name... */
|
|
utPtr->UT_HOST[c - utPtr->UT_HOST + strlen(seat)] = '\0';
|
|
#ifdef UT_HOST_LEN
|
|
utPtr->UT_HOST_LEN = c - utPtr->UT_HOST + strlen(seat) + 1;
|
|
#endif /* UT_HOST_LEN */
|
|
}
|
|
} else {
|
|
/* we can't fit even a single full chunk from the domain.
|
|
* since it is more important to get the seat number in (the
|
|
* host can be obtained from the addr), truncate the host.
|
|
*/
|
|
(void) strncpy(utPtr->UT_HOST - strlen(seat), seat,
|
|
strlen(seat));
|
|
#ifdef UT_HOST_LEN
|
|
utPtr->UT_HOST_LEN = strlen(seat);
|
|
#endif /* UT_HOST_LEN */
|
|
}
|
|
}
|
|
#endif /* UT_HOST */
|
|
|
|
#ifdef UT_ADDR
|
|
(void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
|
|
|
|
/* get the canonical host of the X socket... */
|
|
fromLen = sizeof(from);
|
|
if (!getpeername(ConnectionNumber(XtDisplay(w)), &from, &fromLen) &&
|
|
(from.sin_family == AF_INET)) {
|
|
utPtr->ut_addr = from.sin_addr.s_addr;
|
|
}
|
|
#endif /* UT_ADDR */
|
|
|
|
/* write it out... */
|
|
if (_pututline(utPtr)) {
|
|
/* success...
|
|
*/
|
|
(void) endutent();
|
|
return(utmpLine);
|
|
}
|
|
/* failure... */
|
|
(void) endutent();
|
|
return((char *) 0);
|
|
#else /* __OpenBSD__ */
|
|
return(utmpLine);
|
|
#endif
|
|
}
|
|
|
|
/* this is a public wrapper around the previous function that runs the
|
|
* previous function setuid root...
|
|
*/
|
|
char *
|
|
_DtTermPrimUtmpEntryCreate(Widget w, pid_t pid, char *utmpLine)
|
|
{
|
|
char *retValue;
|
|
|
|
/* this function needs to be suid root... */
|
|
(void) _DtTermPrimToggleSuidRoot(True);
|
|
retValue = UtmpEntryCreate(w, pid, utmpLine);
|
|
/* we now need to turn off setuid root... */
|
|
(void) _DtTermPrimToggleSuidRoot(False);
|
|
|
|
return(retValue);
|
|
}
|
|
|
|
static void
|
|
UtmpEntryDestroy(Widget w, char *utmpLine)
|
|
{
|
|
#if !defined(CSRG_BASED)
|
|
struct utmp ut;
|
|
struct utmp *utPtr;
|
|
time_t now;
|
|
|
|
ut.ut_type = USER_PROCESS;
|
|
snprintf(ut.ut_line, sizeof(ut.ut_line), "%s", utmpLine);
|
|
(void) setutent();
|
|
if (utPtr = getutline(&ut)) {
|
|
utPtr->ut_type = DEAD_PROCESS;
|
|
#if !defined(__linux__)
|
|
utPtr->ut_exit.e_termination = 0;
|
|
utPtr->ut_exit.e_exit = 0;
|
|
#endif
|
|
(void) time(&now);
|
|
utPtr->ut_time = now;
|
|
#ifdef UT_HOST
|
|
(void) memset(utPtr->ut_host, '\0', sizeof(utPtr->ut_host));
|
|
#endif /* UT_HOST */
|
|
#ifdef UT_ADDR
|
|
(void) memset(&utPtr->ut_addr, '\0', sizeof(utPtr->ut_addr));
|
|
#endif /* UT_ADDR */
|
|
(void) pututline(utPtr);
|
|
}
|
|
(void) endutent();
|
|
|
|
(void) DeleteUtmpInfo(utmpLine);
|
|
#endif /* !__OpenBSD__ */
|
|
}
|
|
|
|
/* this is a public wrapper around the previous function that runs the
|
|
* previous function setuid root...
|
|
*/
|
|
void
|
|
_DtTermPrimUtmpEntryDestroy(Widget w, char *utmpLine)
|
|
{
|
|
/* this function needs to be suid root... */
|
|
(void) _DtTermPrimToggleSuidRoot(True);
|
|
(void) UtmpEntryDestroy(w, utmpLine);
|
|
/* we now need to turn off setuid root... */
|
|
(void) _DtTermPrimToggleSuidRoot(False);
|
|
}
|
|
|
|
void
|
|
_DtTermPrimUtmpCleanup(void)
|
|
{
|
|
DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimUtmpCleanup() starting\n"));
|
|
_DtTermProcessLock();
|
|
while (utmpInfoHead->next && utmpInfoHead->next->utmpLine) {
|
|
DebugF('s', 10, fprintf(stderr, ">>resetting utmp for id \"%s\"\n",
|
|
utmpInfoHead->next->utmpLine));
|
|
(void) _DtTermPrimUtmpEntryDestroy((Widget) 0,
|
|
utmpInfoHead->next->utmpLine);
|
|
}
|
|
_DtTermProcessUnlock();
|
|
DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimUtmpCleanup() finished\n"));
|
|
}
|