402 lines
11 KiB
C
402 lines
11 KiB
C
/*
|
|
* Copyright (C) 1997-2002, Michael Jennings
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
* and software packages that this Software was used.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
static const char cvs_ident[] = "$Id$";
|
|
|
|
#include "config.h"
|
|
#include "feature.h"
|
|
|
|
# include "eterm_utmp.h"
|
|
# include "command.h"
|
|
# include "screen.h"
|
|
|
|
#if defined(UTMP_SUPPORT) && !defined(HAVE_LIBUTEMPTER)
|
|
|
|
/* screen.h includes config.h again, so re-fix these. Pointed out by Sung-Hyun Nam <namsh@lgic.co.kr> */
|
|
# if defined(_HPUX_SOURCE) || defined(_AIX) || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1))
|
|
# undef HAVE_UTMPX_H
|
|
# endif
|
|
|
|
/* don't go off end of ut_id & remember if an entry has been made */
|
|
# if defined(USE_SYSV_UTMP) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)
|
|
static char ut_id[5]; /* remember if entry to utmp made */
|
|
# else
|
|
static int utmp_pos; /* BSD position of utmp-stamp */
|
|
# endif
|
|
|
|
# ifdef USE_SYSV_UTMP
|
|
|
|
# ifdef HAVE_UTMPX_H
|
|
# undef WTMP_FILENAME
|
|
# define WTMP_FILENAME WTMPX_FILE
|
|
# define update_wtmp updwtmpx
|
|
# else /* HAVE_UTMPX_H */
|
|
|
|
static void
|
|
update_wtmp(char *fname, struct utmp *putmp)
|
|
{
|
|
|
|
int fd, retry = 10; /* 10 attempts at locking */
|
|
struct flock lck; /* fcntl locking scheme */
|
|
|
|
if ((fd = open(fname, O_WRONLY | O_APPEND, 0)) < 0) {
|
|
D_UTMP(("Warning: Unable to open \"%s\" for writing -- %s\n", fname, strerror(errno)));
|
|
return;
|
|
}
|
|
lck.l_whence = SEEK_END; /* start lock at current eof */
|
|
lck.l_len = 0; /* end at ``largest possible eof'' */
|
|
lck.l_start = 0;
|
|
lck.l_type = F_WRLCK; /* we want a write lock */
|
|
|
|
/* attempt lock with F_SETLK - F_SETLKW would cause a deadlock! */
|
|
while (retry--) {
|
|
if ((fcntl(fd, F_SETLK, &lck) < 0) && errno != EACCESS) {
|
|
D_UTMP(("Warning: Unable to establish file lock on \"%s\" -- %s\n", fname, strerror(errno)));
|
|
close(fd);
|
|
return; /* failed for unknown reason: give up */
|
|
} else if (errno == EACCESS) {
|
|
D_UTMP(("Warning: Unable to establish file lock on \"%s\" -- %s\n", fname, strerror(errno)));
|
|
}
|
|
}
|
|
|
|
write(fd, putmp, sizeof(struct utmp));
|
|
|
|
/* unlocking the file */
|
|
lck.l_type = F_UNLCK;
|
|
fcntl(fd, F_SETLK, &lck);
|
|
|
|
close(fd);
|
|
}
|
|
# endif /* HAVE_UTMPX_H */
|
|
|
|
void
|
|
add_utmp_entry(const char *pty, const char *hostname, int fd)
|
|
{
|
|
struct passwd *pwent = getpwuid(my_ruid);
|
|
|
|
# ifdef HAVE_UTMPX_H
|
|
struct utmpx utmp;
|
|
struct utmp utmp2;
|
|
MEMSET(&utmp, 0, sizeof(struct utmpx));
|
|
# else
|
|
struct utmp utmp;
|
|
MEMSET(&utmp, 0, sizeof(struct utmp));
|
|
# endif
|
|
|
|
# ifdef WITH_DMALLOC
|
|
return;
|
|
# endif
|
|
|
|
if (!strncmp(pty, "/dev/", 5))
|
|
pty += 5; /* skip /dev/ prefix */
|
|
if (!strncmp(pty, "pty", 3) || !strncmp(pty, "tty", 3))
|
|
strncpy(ut_id, (pty + 3), sizeof(ut_id)); /* bsd naming */
|
|
else {
|
|
int n;
|
|
|
|
if (sscanf(pty, "pts/%d", &n) == 1)
|
|
sprintf(ut_id, "vt%02x", n); /* sysv naming */
|
|
else {
|
|
print_error("can't parse tty name \"%s\"\n", pty);
|
|
ut_id[0] = '\0'; /* entry not made */
|
|
return;
|
|
}
|
|
}
|
|
strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
|
|
utmp.ut_type = DEAD_PROCESS;
|
|
|
|
privileges(INVOKE);
|
|
# ifdef HAVE_UTMPX_H
|
|
getutmp(&utmp, &utmp2);
|
|
getutid(&utmp2); /* position to entry in utmp file */
|
|
# else
|
|
getutid(&utmp); /* position to entry in utmp file */
|
|
# endif
|
|
|
|
/* set up the new entry */
|
|
strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
|
|
strncpy(utmp.ut_line, pty, sizeof(utmp.ut_line));
|
|
strncpy(utmp.ut_name, pwent->pw_name, sizeof(utmp.ut_name));
|
|
strncpy(utmp.ut_user, pwent->pw_name, sizeof(utmp.ut_user));
|
|
strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
|
|
utmp.ut_type = USER_PROCESS;
|
|
utmp.ut_pid = getpid();
|
|
# ifdef HAVE_UTMPX_H
|
|
utmp.ut_session = getsid(0);
|
|
utmp.ut_xtime = time(NULL);
|
|
utmp.ut_tv.tv_usec = 0;
|
|
# else
|
|
utmp.ut_time = time(NULL);
|
|
# endif
|
|
|
|
/*
|
|
* write a utmp entry to the utmp file
|
|
*/
|
|
utmpname(UTMP_FILENAME);
|
|
# ifdef HAVE_UTMPX_H
|
|
getutmp(&utmp, &utmp2);
|
|
pututline(&utmp2);
|
|
pututxline(&utmp);
|
|
# else
|
|
pututline(&utmp);
|
|
# endif
|
|
update_wtmp(WTMP_FILENAME, &utmp);
|
|
endutent(); /* close the file */
|
|
privileges(REVERT);
|
|
return;
|
|
fd = 0;
|
|
}
|
|
|
|
void
|
|
remove_utmp_entry(void)
|
|
{
|
|
# ifdef HAVE_UTMPX_H
|
|
struct utmp utmp;
|
|
struct utmpx utmpx;
|
|
|
|
if (!ut_id[0])
|
|
return; /* entry not made */
|
|
|
|
utmpname(UTMP_FILENAME);
|
|
setutent();
|
|
strncpy(utmp.ut_id, ut_id, sizeof(utmp.ut_id));
|
|
utmp.ut_type = USER_PROCESS;
|
|
if (getutid(&utmp) == NULL) {
|
|
return;
|
|
}
|
|
utmp.ut_type = DEAD_PROCESS;
|
|
utmp.ut_time = time(NULL);
|
|
pututline(&utmp);
|
|
getutmpx(&utmp, &utmpx);
|
|
update_wtmp(WTMP_FILENAME, &utmpx);
|
|
endutent();
|
|
|
|
# else /* HAVE_UTMPX_H */
|
|
struct utmp *putmp;
|
|
pid_t pid = getpid();
|
|
|
|
if (!ut_id[0])
|
|
return; /* entry not made */
|
|
|
|
utmpname(UTMP_FILENAME);
|
|
setutent();
|
|
/*
|
|
* The following code waw copied from the poeigl-1.20 login/init package.
|
|
* Special thanks to poe for the code examples.
|
|
*/
|
|
while ((putmp = getutent()) != NULL) {
|
|
if (putmp->ut_pid == pid) {
|
|
putmp->ut_type = DEAD_PROCESS;
|
|
putmp->ut_pid = 0;
|
|
putmp->ut_user[0] = '\0';
|
|
putmp->ut_time = time(NULL);
|
|
pututline(putmp);
|
|
update_wtmp(WTMP_FILENAME, putmp);
|
|
break;
|
|
}
|
|
}
|
|
endutent();
|
|
# endif /* HAVE_UTMPX_H */
|
|
}
|
|
|
|
# else /* USE_SYSV_UTMP */
|
|
/* BSD utmp support */
|
|
|
|
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
|
|
|
|
/* used to hold the line we are using */
|
|
static char ut_line[32];
|
|
|
|
static int
|
|
get_tslot(const char *ttyname)
|
|
{
|
|
register struct ttyent *ttyp;
|
|
register int slot;
|
|
|
|
setttyent();
|
|
for (slot = 1; (ttyp = getttyent()); ++slot)
|
|
if (!strcmp(ttyp->ty_name, ttyname)) {
|
|
endttyent();
|
|
return (slot);
|
|
}
|
|
endttyent();
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
b_login(struct utmp *ut)
|
|
{
|
|
/*
|
|
** replacement for freebsd's login(), which uses ttyslot()
|
|
**
|
|
** like I shouldn't have just KNOWN that from the comment on get_tslot
|
|
** below...
|
|
** - brian
|
|
*/
|
|
register int fd;
|
|
int tty;
|
|
|
|
tty = get_tslot(ut->ut_line);
|
|
if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY | O_CREAT, 0644)) >= 0) {
|
|
(void) lseek(fd, (off_t) (tty * sizeof(struct utmp)), L_SET);
|
|
(void) write(fd, ut, sizeof(struct utmp));
|
|
|
|
(void) close(fd);
|
|
}
|
|
if ((fd = open(_PATH_WTMP, O_WRONLY | O_APPEND, 0)) >= 0) {
|
|
(void) write(fd, ut, sizeof(struct utmp));
|
|
|
|
(void) close(fd);
|
|
}
|
|
}
|
|
|
|
# else /* __FreeBSD__ || NetBSD || BSDI */
|
|
static int utmp_pos = 0; /* position of utmp-stamp */
|
|
|
|
/*----------------------------------------------------------------------*
|
|
* get_tslot() - grabbed from xvt-1.0 - modified by David Perry
|
|
*
|
|
* find ttyname in /etc/ttytab and return a slot number that can be used to
|
|
* access the utmp file. Can't use ttyslot() because the tty name is not
|
|
* that of fd 0.
|
|
*----------------------------------------------------------------------*/
|
|
static int
|
|
get_tslot(const char *ttyname)
|
|
{
|
|
char buf[256], name[256];
|
|
FILE *fd;
|
|
|
|
if ((fd = fopen(UTMP_FILENAME, "r")) != NULL) {
|
|
int i;
|
|
|
|
for (i = 1; fgets(buf, sizeof(buf), fd) != NULL; i++) {
|
|
if (*buf == '#' || sscanf(buf, "%s", name) != 1)
|
|
continue;
|
|
if (!strcmp(ttyname, name)) {
|
|
fclose(fd);
|
|
return i;
|
|
}
|
|
}
|
|
fclose(fd);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* write utmp entry to UTMP_FILENAME
|
|
*/
|
|
static int
|
|
write_utmp(struct utmp *putmp)
|
|
{
|
|
int rval = 0;
|
|
FILE *fd;
|
|
|
|
fprintf(stderr, "Utmp file is %s\n", UTMP_FILENAME);
|
|
privileges(INVOKE);
|
|
if ((fd = fopen(UTMP_FILENAME, "r+")) != NULL) {
|
|
utmp_pos = get_tslot(putmp->ut_line) * sizeof(struct utmp);
|
|
|
|
if (utmp_pos >= 0) {
|
|
fseek(fd, utmp_pos, 0);
|
|
fwrite(putmp, sizeof(struct utmp), 1, fd);
|
|
|
|
rval = 1;
|
|
}
|
|
fclose(fd);
|
|
}
|
|
privileges(REVERT);
|
|
return rval;
|
|
}
|
|
|
|
# endif /* __FreeBSD__ || NetBSD || BSDI */
|
|
|
|
void
|
|
add_utmp_entry(const char *pty, const char *hostname, int fd)
|
|
{
|
|
struct passwd *pwent = getpwuid(my_ruid);
|
|
struct utmp utmp;
|
|
|
|
MEMSET(&utmp, 0, sizeof(struct utmp));
|
|
|
|
if (!strncmp(pty, "/dev/", 5))
|
|
pty += 5; /* skip /dev/ prefix */
|
|
if (!strncmp(pty, "pty", 3) || !strncmp(pty, "tty", 3))
|
|
strncpy(ut_id, (pty + 3), sizeof(ut_id)); /* bsd naming */
|
|
else {
|
|
print_error("can't parse tty name \"%s\"\n", pty);
|
|
ut_id[0] = '\0'; /* entry not made */
|
|
return;
|
|
}
|
|
|
|
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
|
|
strncpy(ut_line, pty, 31);
|
|
|
|
strncpy(utmp.ut_line, pty, UT_LINESIZE);
|
|
strncpy(utmp.ut_name, pwent->pw_name, UT_NAMESIZE);
|
|
strncpy(utmp.ut_host, hostname, UT_HOSTSIZE);
|
|
utmp.ut_time = time(NULL);
|
|
|
|
b_login(&utmp);
|
|
# else /* __FreeBSD__ || NetBSD || BSDI */
|
|
strncpy(utmp.ut_line, ut_id, sizeof(utmp.ut_line));
|
|
strncpy(utmp.ut_name, pwent->pw_name, sizeof(utmp.ut_name));
|
|
strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
|
|
utmp.ut_time = time(NULL);
|
|
|
|
if (write_utmp(&utmp) < 0)
|
|
ut_id[0] = '\0'; /* entry not made */
|
|
# endif
|
|
return;
|
|
fd = 0;
|
|
}
|
|
|
|
/*
|
|
* remove a utmp entry
|
|
*/
|
|
void
|
|
remove_utmp_entry(void)
|
|
{
|
|
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
|
|
logout(ut_line);
|
|
logwtmp(ut_line, "", "");
|
|
# else /* __FreeBSD__ */
|
|
FILE *fd;
|
|
|
|
privileges(INVOKE);
|
|
if (!ut_id[0] && (fd = fopen(UTMP_FILENAME, "r+")) != NULL) {
|
|
struct utmp utmp;
|
|
MEMSET(&utmp, 0, sizeof(struct utmp));
|
|
|
|
fseek(fd, utmp_pos, 0);
|
|
fwrite(&utmp, sizeof(struct utmp), 1, fd);
|
|
|
|
fclose(fd);
|
|
}
|
|
privileges(REVERT);
|
|
# endif /* __FreeBSD__ || NetBSD || BSDI */
|
|
}
|
|
|
|
# endif /* USE_SYSV_UTMP */
|
|
|
|
#endif /* UTMP_SUPPORT */
|