902 lines
19 KiB
C
902 lines
19 KiB
C
/* Copyright (c) 2008, 2009
|
|
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
|
|
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
|
|
* Micah Cowan (micah@cowan.name)
|
|
* Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
|
|
* Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
|
|
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
|
|
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
|
|
* Copyright (c) 1987 Oliver Laumann
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING); if not, see
|
|
* https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
|
*
|
|
****************************************************************
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "config.h"
|
|
#include "screen.h"
|
|
#include "extern.h"
|
|
|
|
#ifdef HAVE_UTEMPTER
|
|
#include <utempter.h>
|
|
#endif
|
|
|
|
|
|
extern struct display *display;
|
|
#ifdef CAREFULUTMP
|
|
extern struct win *windows;
|
|
#endif
|
|
extern struct win *fore;
|
|
extern char *LoginName;
|
|
extern int real_uid, eff_uid;
|
|
|
|
|
|
/*
|
|
* UTNOKEEP: A (ugly) hack for apollo that does two things:
|
|
* 1) Always close and reopen the utmp file descriptor. (I don't know
|
|
* for what reason this is done...)
|
|
* 2) Implement an unsorted utmp file much like GETUTENT.
|
|
* (split into UT_CLOSE and UT_UNSORTED)
|
|
*/
|
|
|
|
|
|
#ifdef UTNOKEEP
|
|
# define UT_CLOSE
|
|
# define UT_UNSORTED
|
|
#endif
|
|
|
|
#ifdef UT_CLOSE
|
|
# undef UT_CLOSE
|
|
# define UT_CLOSE endutent()
|
|
#else
|
|
# define UT_CLOSE
|
|
#endif
|
|
|
|
|
|
/*
|
|
* we have a suid-root helper app that changes the utmp for us
|
|
* (won't work for login-slots)
|
|
*/
|
|
#if (defined(sun) && defined(SVR4) && defined(GETUTENT)) || defined(HAVE_UTEMPTER)
|
|
# define UTMP_HELPER
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UTMPOK
|
|
|
|
|
|
static slot_t TtyNameSlot __P((char *));
|
|
static void makeuser __P((struct utmp *, char *, char *, int));
|
|
static void makedead __P((struct utmp *));
|
|
static int pututslot __P((slot_t, struct utmp *, char *, struct win *));
|
|
static struct utmp *getutslot __P((slot_t));
|
|
#ifndef GETUTENT
|
|
static struct utmp *getutent __P((void));
|
|
static void endutent __P((void));
|
|
static int initutmp __P((void));
|
|
static void setutent __P((void));
|
|
#endif
|
|
#if defined(linux) && defined(GETUTENT)
|
|
static struct utmp *xpututline __P((struct utmp *utmp));
|
|
# define pututline xpututline
|
|
#endif
|
|
|
|
|
|
static int utmpok;
|
|
static char UtmpName[] = UTMPFILE;
|
|
#ifndef UTMP_HELPER
|
|
static int utmpfd = -1;
|
|
#endif
|
|
|
|
|
|
# if defined(GETUTENT) && (!defined(SVR4) || defined(__hpux)) && ! defined(__CYGWIN__)
|
|
# if defined(hpux) /* cruel hpux release 8.0 */
|
|
# define pututline _pututline
|
|
# endif /* hpux */
|
|
extern struct utmp *getutline(), *pututline();
|
|
# if defined(_SEQUENT_)
|
|
extern struct utmp *ut_add_user(), *ut_delete_user();
|
|
extern char *ut_find_host();
|
|
# ifndef UTHOST
|
|
# define UTHOST /* _SEQUENT_ has ut_find_host() */
|
|
# endif
|
|
# endif /* _SEQUENT_ */
|
|
# endif /* GETUTENT && !SVR4 */
|
|
|
|
# if !defined(GETUTENT) && !defined(UT_UNSORTED)
|
|
# ifdef GETTTYENT
|
|
# include <ttyent.h>
|
|
# else
|
|
struct ttyent { char *ty_name; };
|
|
static void setttyent __P((void));
|
|
static struct ttyent *getttyent __P((void));
|
|
# endif
|
|
# endif /* !GETUTENT && !UT_UNSORTED */
|
|
|
|
#ifndef _SEQUENT_
|
|
# undef D_loginhost
|
|
# define D_loginhost D_utmp_logintty.ut_host
|
|
#endif
|
|
#ifndef UTHOST
|
|
# undef D_loginhost
|
|
# define D_loginhost ((char *)0)
|
|
#endif
|
|
|
|
|
|
#endif /* UTMPOK */
|
|
|
|
|
|
/*
|
|
* SlotToggle - modify the utmp slot of the fore window.
|
|
*
|
|
* how > 0 do try to set a utmp slot.
|
|
* how = 0 try to withdraw a utmp slot.
|
|
*
|
|
* w_slot = -1 window not logged in.
|
|
* w_slot = 0 window not logged in, but should be logged in.
|
|
* (unable to write utmp, or detached).
|
|
*/
|
|
|
|
#ifndef UTMPOK
|
|
void
|
|
SlotToggle(how)
|
|
int how;
|
|
{
|
|
debug1("SlotToggle (!UTMPOK) %d\n", how);
|
|
# ifdef UTMPFILE
|
|
Msg(0, "Unable to modify %s.\n", UTMPFILE);
|
|
# else
|
|
Msg(0, "Unable to modify utmp-database.\n");
|
|
# endif
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef UTMPOK
|
|
|
|
void
|
|
SlotToggle(how)
|
|
int how;
|
|
{
|
|
debug1("SlotToggle %d\n", how);
|
|
if (fore->w_type != W_TYPE_PTY)
|
|
{
|
|
Msg(0, "Can only work with normal windows.\n");
|
|
return;
|
|
}
|
|
if (how)
|
|
{
|
|
debug(" try to log in\n");
|
|
if ((fore->w_slot == (slot_t) -1) || (fore->w_slot == (slot_t) 0))
|
|
{
|
|
#ifdef USRLIMIT
|
|
if (CountUsers() >= USRLIMIT)
|
|
{
|
|
Msg(0, "User limit reached.");
|
|
return;
|
|
}
|
|
#endif
|
|
if (SetUtmp(fore) == 0)
|
|
Msg(0, "This window is now logged in.");
|
|
else
|
|
Msg(0, "This window should now be logged in.");
|
|
WindowChanged(fore, 'f');
|
|
}
|
|
else
|
|
Msg(0, "This window is already logged in.");
|
|
}
|
|
else
|
|
{
|
|
debug(" try to log out\n");
|
|
if (fore->w_slot == (slot_t) -1)
|
|
Msg(0, "This window is already logged out\n");
|
|
else if (fore->w_slot == (slot_t) 0)
|
|
{
|
|
debug("What a relief! In fact, it was not logged in\n");
|
|
Msg(0, "This window is not logged in.");
|
|
fore->w_slot = (slot_t) -1;
|
|
}
|
|
else
|
|
{
|
|
RemoveUtmp(fore);
|
|
if (fore->w_slot != (slot_t) -1)
|
|
Msg(0, "What? Cannot remove Utmp slot?");
|
|
else
|
|
Msg(0, "This window is no longer logged in.");
|
|
#ifdef CAREFULUTMP
|
|
CarefulUtmp();
|
|
#endif
|
|
WindowChanged(fore, 'f');
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CAREFULUTMP
|
|
|
|
/* CAREFULUTMP: goodie for paranoid sysadmins: always leave one
|
|
* window logged in
|
|
*/
|
|
void
|
|
CarefulUtmp()
|
|
{
|
|
struct win *p;
|
|
|
|
if (!windows) /* hopeless */
|
|
return;
|
|
debug("CarefulUtmp counting slots\n");
|
|
for (p = windows; p; p = p->w_next)
|
|
if (p->w_ptyfd >= 0 && p->w_slot != (slot_t)-1)
|
|
return; /* found one, nothing to do */
|
|
|
|
debug("CarefulUtmp: no slots, log one in again.\n");
|
|
for (p = windows; p; p = p->w_next)
|
|
if (p->w_ptyfd >= 0) /* no zombies please */
|
|
break;
|
|
if (!p)
|
|
return; /* really hopeless */
|
|
SetUtmp(p);
|
|
Msg(0, "Window %d is now logged in.\n", p->w_number);
|
|
}
|
|
#endif /* CAREFULUTMP */
|
|
|
|
|
|
void
|
|
InitUtmp()
|
|
{
|
|
debug1("InitUtmp testing '%s'...\n", UtmpName);
|
|
#ifndef UTMP_HELPER
|
|
if ((utmpfd = open(UtmpName, O_RDWR)) == -1)
|
|
{
|
|
if (errno != EACCES)
|
|
Msg(errno, "%s", UtmpName);
|
|
debug("InitUtmp failed.\n");
|
|
utmpok = 0;
|
|
return;
|
|
}
|
|
# ifdef GETUTENT
|
|
close(utmpfd); /* it was just a test */
|
|
utmpfd = -1;
|
|
# endif /* GETUTENT */
|
|
#endif /* UTMP_HELPER */
|
|
utmpok = 1;
|
|
}
|
|
|
|
|
|
#ifdef USRLIMIT
|
|
int
|
|
CountUsers()
|
|
{
|
|
struct utmp *ut;
|
|
int UserCount;
|
|
|
|
debug1("CountUsers() - utmpok=%d\n", utmpok);
|
|
if (!utmpok)
|
|
return 0;
|
|
UserCount = 0;
|
|
setutent();
|
|
while (ut = getutent())
|
|
if (SLOT_USED(ut))
|
|
UserCount++;
|
|
UT_CLOSE;
|
|
return UserCount;
|
|
}
|
|
#endif /* USRLIMIT */
|
|
|
|
|
|
|
|
/*
|
|
* the utmp entry for tty is located and removed.
|
|
* it is stored in D_utmp_logintty.
|
|
*/
|
|
void
|
|
RemoveLoginSlot()
|
|
{
|
|
struct utmp u, *uu;
|
|
|
|
ASSERT(display);
|
|
debug("RemoveLoginSlot: removing your logintty\n");
|
|
D_loginslot = TtyNameSlot(D_usertty);
|
|
if (D_loginslot == (slot_t)0 || D_loginslot == (slot_t)-1)
|
|
return;
|
|
#ifdef UTMP_HELPER
|
|
if (eff_uid) /* helpers can't do login slots. sigh. */
|
|
#else
|
|
if (!utmpok)
|
|
#endif
|
|
{
|
|
D_loginslot = 0;
|
|
debug("RemoveLoginSlot: utmpok == 0\n");
|
|
}
|
|
else
|
|
{
|
|
#ifdef _SEQUENT_
|
|
{
|
|
char *p;
|
|
if ((p = ut_find_host(D_loginslot)) != 0)
|
|
strncpy(D_loginhost, p, sizeof(D_loginhost) - 1);
|
|
D_loginhost[sizeof(D_loginhost) - 1] = 0;
|
|
}
|
|
#endif /* _SEQUENT_ */
|
|
|
|
if ((uu = getutslot(D_loginslot)) == 0)
|
|
{
|
|
debug("Utmp slot not found -> not removed");
|
|
D_loginslot = 0;
|
|
}
|
|
else
|
|
{
|
|
D_utmp_logintty = *uu;
|
|
u = *uu;
|
|
makedead(&u);
|
|
if (pututslot(D_loginslot, &u, (char *)0, (struct win *)0) == 0)
|
|
D_loginslot = 0;
|
|
}
|
|
UT_CLOSE;
|
|
}
|
|
debug1(" slot %ld zapped\n", (long)D_loginslot);
|
|
if (D_loginslot == (slot_t)0)
|
|
{
|
|
/* couldn't remove slot, do a 'mesg n' at least. */
|
|
struct stat stb;
|
|
char *tty;
|
|
debug("couln't zap slot -> do mesg n\n");
|
|
D_loginttymode = 0;
|
|
if ((tty = GetPtsPathOrSymlink(D_userfd)) && stat(tty, &stb) == 0 && (int)stb.st_uid == real_uid && !CheckTtyname(tty) && ((int)stb.st_mode & 0777) != 0666)
|
|
{
|
|
D_loginttymode = (int)stb.st_mode & 0777;
|
|
chmod(D_usertty, stb.st_mode & 0600);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* D_utmp_logintty is reinserted into utmp
|
|
*/
|
|
void
|
|
RestoreLoginSlot()
|
|
{
|
|
char *tty;
|
|
|
|
debug("RestoreLoginSlot()\n");
|
|
ASSERT(display);
|
|
if (utmpok && D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1)
|
|
{
|
|
debug1(" logging you in again (slot %#lx)\n", (long)D_loginslot);
|
|
if (pututslot(D_loginslot, &D_utmp_logintty, D_loginhost, (struct win *)0) == 0)
|
|
Msg(errno,"Could not write %s", UtmpName);
|
|
}
|
|
UT_CLOSE;
|
|
D_loginslot = (slot_t)0;
|
|
if (D_loginttymode && (tty = GetPtsPathOrSymlink(D_userfd)) && !CheckTtyname(tty))
|
|
chmod(tty, D_loginttymode);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Construct a utmp entry for window wi.
|
|
* the hostname field reflects what we know about the user (display)
|
|
* location. If d_loginhost is not set, then he is local and we write
|
|
* down the name of his terminal line; else he is remote and we keep
|
|
* the hostname here. The letter S and the window id will be appended.
|
|
* A saved utmp entry in wi->w_savut serves as a template, usually.
|
|
*/
|
|
|
|
int
|
|
SetUtmp(wi)
|
|
struct win *wi;
|
|
{
|
|
register slot_t slot;
|
|
struct utmp u;
|
|
int saved_ut;
|
|
#ifdef UTHOST
|
|
char *p;
|
|
char host[sizeof(D_loginhost) + 15];
|
|
#else
|
|
char *host = 0;
|
|
#endif /* UTHOST */
|
|
|
|
wi->w_slot = (slot_t)0;
|
|
if (!utmpok || wi->w_type != W_TYPE_PTY)
|
|
return -1;
|
|
if ((slot = TtyNameSlot(wi->w_tty)) == (slot_t)0)
|
|
{
|
|
debug1("SetUtmp failed (tty %s).\n",wi->w_tty);
|
|
return -1;
|
|
}
|
|
debug2("SetUtmp %d will get slot %ld...\n", wi->w_number, (long)slot);
|
|
|
|
bzero((char *)&u, sizeof(u));
|
|
if ((saved_ut = bcmp((char *) &wi->w_savut, (char *)&u, sizeof(u))))
|
|
/* restore original, of which we will adopt all fields but ut_host */
|
|
bcopy((char *)&wi->w_savut, (char *) &u, sizeof(u));
|
|
|
|
if (!saved_ut)
|
|
makeuser(&u, stripdev(wi->w_tty), LoginName, wi->w_pid);
|
|
|
|
#ifdef UTHOST
|
|
host[sizeof(host) - 15] = '\0';
|
|
if (display)
|
|
{
|
|
strncpy(host, D_loginhost, sizeof(host) - 15);
|
|
if (D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1 && host[0] != '\0')
|
|
{
|
|
/*
|
|
* we want to set our ut_host field to something like
|
|
* ":ttyhf:s.0" or
|
|
* "faui45:s.0" or
|
|
* "132.199.81.4:s.0" (even this may hurt..), but not
|
|
* "faui45.informati"......:s.0
|
|
* HPUX uses host:0.0, so chop at "." and ":" (Eric Backus)
|
|
*/
|
|
for (p = host; *p; p++)
|
|
if ((*p < '0' || *p > '9') && (*p != '.'))
|
|
break;
|
|
if (*p)
|
|
{
|
|
for (p = host; *p; p++)
|
|
if (*p == '.' || (*p == ':' && p != host))
|
|
{
|
|
*p = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strncpy(host + 1, stripdev(D_usertty), sizeof(host) - 15 - 1);
|
|
host[0] = ':';
|
|
}
|
|
}
|
|
else
|
|
strncpy(host, "local", sizeof(host) - 15);
|
|
|
|
sprintf(host + strlen(host), ":S.%d", wi->w_number);
|
|
debug1("rlogin hostname: '%s'\n", host);
|
|
|
|
# if !defined(_SEQUENT_) && !defined(sequent)
|
|
strncpy(u.ut_host, host, sizeof(u.ut_host));
|
|
# endif
|
|
#endif /* UTHOST */
|
|
|
|
if (pututslot(slot, &u, host, wi) == 0)
|
|
{
|
|
Msg(errno,"Could not write %s", UtmpName);
|
|
UT_CLOSE;
|
|
return -1;
|
|
}
|
|
debug("SetUtmp successful\n");
|
|
wi->w_slot = slot;
|
|
bcopy((char *)&u, (char *)&wi->w_savut, sizeof(u));
|
|
UT_CLOSE;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* if slot could be removed or was 0, wi->w_slot = -1;
|
|
* else not changed.
|
|
*/
|
|
|
|
int
|
|
RemoveUtmp(wi)
|
|
struct win *wi;
|
|
{
|
|
struct utmp u, *uu;
|
|
slot_t slot;
|
|
|
|
slot = wi->w_slot;
|
|
debug1("RemoveUtmp slot=%#lx\n", (long)slot);
|
|
if (!utmpok)
|
|
return -1;
|
|
if (slot == (slot_t)0 || slot == (slot_t)-1)
|
|
{
|
|
wi->w_slot = (slot_t)-1;
|
|
return 0;
|
|
}
|
|
bzero((char *) &u, sizeof(u));
|
|
#ifdef sgi
|
|
bcopy((char *)&wi->w_savut, (char *)&u, sizeof(u));
|
|
uu = &u;
|
|
#else
|
|
if ((uu = getutslot(slot)) == 0)
|
|
{
|
|
Msg(0, "Utmp slot not found -> not removed");
|
|
return -1;
|
|
}
|
|
bcopy((char *)uu, (char *)&wi->w_savut, sizeof(wi->w_savut));
|
|
#endif
|
|
u = *uu;
|
|
makedead(&u);
|
|
if (pututslot(slot, &u, (char *)0, wi) == 0)
|
|
{
|
|
Msg(errno,"Could not write %s", UtmpName);
|
|
UT_CLOSE;
|
|
return -1;
|
|
}
|
|
debug("RemoveUtmp successfull\n");
|
|
wi->w_slot = (slot_t)-1;
|
|
UT_CLOSE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
*
|
|
* routines using the getut* api
|
|
*/
|
|
|
|
#ifdef GETUTENT
|
|
|
|
#define SLOT_USED(u) (u->ut_type == USER_PROCESS)
|
|
|
|
static struct utmp *
|
|
getutslot(slot)
|
|
slot_t slot;
|
|
{
|
|
struct utmp u;
|
|
bzero((char *)&u, sizeof(u));
|
|
strncpy(u.ut_line, slot, sizeof(u.ut_line));
|
|
setutent();
|
|
return getutline(&u);
|
|
}
|
|
|
|
static int
|
|
pututslot(slot, u, host, wi)
|
|
slot_t slot;
|
|
struct utmp *u;
|
|
char *host;
|
|
struct win *wi;
|
|
{
|
|
#ifdef _SEQUENT_
|
|
if (SLOT_USED(u) && host && *host)
|
|
return ut_add_user(u.ut_name, slot, u.ut_pid, host) != 0;
|
|
if (!SLOT_USED(u))
|
|
return ut_delete_user(slot, u.ut_pid, 0, 0) != 0;
|
|
#endif
|
|
#ifdef HAVE_UTEMPTER
|
|
if (eff_uid && wi && wi->w_ptyfd != -1)
|
|
{
|
|
/* sigh, linux hackers made the helper functions void */
|
|
if (SLOT_USED(u))
|
|
addToUtmp(wi->w_tty, host, wi->w_ptyfd);
|
|
else
|
|
removeLineFromUtmp(wi->w_tty, wi->w_ptyfd);
|
|
/*
|
|
* As documented in libutempter: "During execution of the privileged
|
|
* process spawned by these functions, SIGCHLD signal handler will be
|
|
* temporarily set to the default action."
|
|
* Thus in case a SIGCHLD has been lost, we send a SIGCHLD to oneself
|
|
* in order to avoid zombies: https://savannah.gnu.org/bugs/?25089
|
|
*/
|
|
kill(getpid(), SIGCHLD);
|
|
|
|
return 1; /* pray for success */
|
|
}
|
|
#endif
|
|
setutent();
|
|
#ifndef __CYGWIN__
|
|
return pututline(u) != 0;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
makedead(u)
|
|
struct utmp *u;
|
|
{
|
|
u->ut_type = DEAD_PROCESS;
|
|
#if (!defined(linux) || defined(EMPTY)) && !defined(__CYGWIN__)
|
|
u->ut_exit.e_termination = 0;
|
|
u->ut_exit.e_exit = 0;
|
|
#endif
|
|
#if !defined(sun) || !defined(SVR4)
|
|
u->ut_user[0] = 0; /* for Digital UNIX, kilbi@rad.rwth-aachen.de */
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
makeuser(u, line, user, pid)
|
|
struct utmp *u;
|
|
char *line, *user;
|
|
int pid;
|
|
{
|
|
time_t now;
|
|
u->ut_type = USER_PROCESS;
|
|
strncpy(u->ut_user, user, sizeof(u->ut_user));
|
|
/* Now the tricky part... guess ut_id */
|
|
#if defined(sgi) || defined(linux)
|
|
strncpy(u->ut_id, line + 3, sizeof(u->ut_id));
|
|
#else /* sgi */
|
|
# ifdef _IBMR2
|
|
strncpy(u->ut_id, line, sizeof(u->ut_id));
|
|
# else
|
|
strncpy(u->ut_id, line + strlen(line) - 2, sizeof(u->ut_id));
|
|
# endif
|
|
#endif /* sgi */
|
|
strncpy(u->ut_line, line, sizeof(u->ut_line));
|
|
u->ut_pid = pid;
|
|
/* must use temp variable because of NetBSD/sparc64, where
|
|
* ut_xtime is long(64) but time_t is int(32) */
|
|
(void)time(&now);
|
|
u->ut_time = now;
|
|
}
|
|
|
|
static slot_t
|
|
TtyNameSlot(nam)
|
|
char *nam;
|
|
{
|
|
return stripdev(nam);
|
|
}
|
|
|
|
|
|
#else /* GETUTENT */
|
|
|
|
/*********************************************************************
|
|
*
|
|
* getut emulation for systems lacking the api
|
|
*/
|
|
|
|
static struct utmp uent;
|
|
|
|
#define SLOT_USED(u) (u.ut_name[0] != 0)
|
|
|
|
static int
|
|
initutmp()
|
|
{
|
|
if (utmpfd >= 0)
|
|
return 1;
|
|
return (utmpfd = open(UtmpName, O_RDWR)) >= 0;
|
|
}
|
|
|
|
static void
|
|
setutent()
|
|
{
|
|
if (utmpfd >= 0)
|
|
(void)lseek(utmpfd, (off_t)0, 0);
|
|
}
|
|
|
|
static void
|
|
endutent()
|
|
{
|
|
if (utmpfd >= 0)
|
|
close(utmpfd);
|
|
utmpfd = -1;
|
|
}
|
|
|
|
static struct utmp *
|
|
getutent()
|
|
{
|
|
if (utmpfd < 0 && !initutmp())
|
|
return 0;
|
|
if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent))
|
|
return 0;
|
|
return &uent;
|
|
}
|
|
|
|
static struct utmp *
|
|
getutslot(slot)
|
|
slot_t slot;
|
|
{
|
|
if (utmpfd < 0 && !initutmp())
|
|
return 0;
|
|
lseek(utmpfd, (off_t)(slot * sizeof(struct utmp)), 0);
|
|
if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent))
|
|
return 0;
|
|
return &uent;
|
|
}
|
|
|
|
static int
|
|
pututslot(slot, u, host, wi)
|
|
slot_t slot;
|
|
struct utmp *u;
|
|
char *host;
|
|
struct win *wi;
|
|
{
|
|
#ifdef sequent
|
|
if (SLOT_USED(u))
|
|
return add_utmp(slot, u) != -1;
|
|
#endif
|
|
if (utmpfd < 0 && !initutmp())
|
|
return 0;
|
|
lseek(utmpfd, (off_t)(slot * sizeof(*u)), 0);
|
|
if (write(utmpfd, u, sizeof(*u)) != sizeof(*u))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static void
|
|
makedead(u)
|
|
struct utmp *u;
|
|
{
|
|
#ifdef UT_UNSORTED
|
|
bzero(u->ut_name, sizeof(u->ut_name));
|
|
# ifdef UTHOST
|
|
bzero(u->ut_host, sizeof(u->ut_host));
|
|
# endif
|
|
#else
|
|
bzero((char *)u, sizeof(*u));
|
|
#endif
|
|
}
|
|
|
|
|
|
static void
|
|
makeuser(u, line, user, pid)
|
|
struct utmp *u;
|
|
char *line, *user;
|
|
int pid;
|
|
{
|
|
time_t now;
|
|
strncpy(u->ut_line, line, sizeof(u->ut_line));
|
|
strncpy(u->ut_name, user, sizeof(u->ut_name));
|
|
(void)time(&now);
|
|
u->ut_time = now;
|
|
}
|
|
|
|
static slot_t
|
|
TtyNameSlot(nam)
|
|
char *nam;
|
|
{
|
|
slot_t slot;
|
|
char *line;
|
|
#ifndef UT_UNSORTED
|
|
struct ttyent *tp;
|
|
#endif
|
|
|
|
line = stripdev(nam);
|
|
#ifdef UT_UNSORTED
|
|
setutent();
|
|
if (utmpfd < 0)
|
|
return -1;
|
|
for (slot = 0; getutent(); slot++)
|
|
if (strcmp(uent.ut_line, line) == 0)
|
|
break;
|
|
UT_CLOSE;
|
|
#else
|
|
slot = 1;
|
|
setttyent();
|
|
while ((tp = getttyent()) != 0 && strcmp(line, tp->ty_name) != 0)
|
|
slot++;
|
|
#endif
|
|
return slot;
|
|
}
|
|
|
|
#endif /* GETUTENT */
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Cheap plastic imitation of ttyent routines.
|
|
*/
|
|
|
|
#if !defined(GETTTYENT) && !defined(GETUTENT) && !defined(UT_UNSORTED)
|
|
|
|
|
|
static char *tt, *ttnext;
|
|
static char ttys[] = "/etc/ttys";
|
|
|
|
static void
|
|
setttyent()
|
|
{
|
|
if (ttnext == 0)
|
|
{
|
|
struct stat s;
|
|
register int f;
|
|
register char *p, *ep;
|
|
|
|
if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
|
|
Panic(errno, ttys);
|
|
if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
|
|
Panic(0, strnomem);
|
|
if (read(f, tt, s.st_size) != s.st_size)
|
|
Panic(errno, ttys);
|
|
close(f);
|
|
for (p = tt, ep = p + s.st_size; p < ep; p++)
|
|
if (*p == '\n')
|
|
*p = '\0';
|
|
*p = '\0';
|
|
}
|
|
ttnext = tt;
|
|
}
|
|
|
|
static struct ttyent *
|
|
getttyent()
|
|
{
|
|
static struct ttyent t;
|
|
|
|
if (*ttnext == '\0')
|
|
return NULL;
|
|
t.ty_name = ttnext + 2;
|
|
ttnext += strlen(ttnext) + 1;
|
|
return &t;
|
|
}
|
|
|
|
#endif /* !GETTTYENT && !GETUTENT && !UT_UNSORTED*/
|
|
|
|
|
|
|
|
#endif /* UTMPOK */
|
|
|
|
|
|
|
|
|
|
/*********************************************************************
|
|
*
|
|
* getlogin() replacement (for SVR4 machines)
|
|
*/
|
|
|
|
# if defined(BUGGYGETLOGIN) && defined(UTMP_FILE)
|
|
char *
|
|
getlogin()
|
|
{
|
|
char *tty = NULL;
|
|
#ifdef utmp
|
|
# undef utmp
|
|
#endif
|
|
struct utmp u;
|
|
static char retbuf[sizeof(u.ut_user)+1];
|
|
int fd;
|
|
|
|
for (fd = 0; fd <= 2 && (tty = GetPtsPathOrSymlink(fd)) == NULL; fd++)
|
|
;
|
|
if ((tty == NULL) || CheckTtyname(tty) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0))
|
|
return NULL;
|
|
tty = stripdev(tty);
|
|
retbuf[0] = '\0';
|
|
while (read(fd, (char *)&u, sizeof(struct utmp)) == sizeof(struct utmp))
|
|
{
|
|
if (!strncmp(tty, u.ut_line, sizeof(u.ut_line)))
|
|
{
|
|
strncpy(retbuf, u.ut_user, sizeof(u.ut_user));
|
|
retbuf[sizeof(u.ut_user)] = '\0';
|
|
if (u.ut_type == USER_PROCESS)
|
|
break;
|
|
}
|
|
}
|
|
close(fd);
|
|
|
|
return *retbuf ? retbuf : NULL;
|
|
}
|
|
# endif /* BUGGYGETLOGIN */
|
|
|
|
#if defined(linux) && defined(GETUTENT)
|
|
# undef pututline
|
|
|
|
/* aargh, linux' pututline returns void! */
|
|
struct utmp *
|
|
xpututline(u)
|
|
struct utmp *u;
|
|
{
|
|
struct utmp *u2;
|
|
pututline(u);
|
|
setutent();
|
|
u2 = getutline(u);
|
|
if (u2 == 0)
|
|
return u->ut_type == DEAD_PROCESS ? u : 0;
|
|
return u->ut_type == u2->ut_type ? u : 0;
|
|
}
|
|
#endif
|
|
|