fi
-for ac_header in malloc.h paths.h utime.h netgroup.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h
+for ac_header in malloc.h paths.h utime.h netgroup.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
fi
+if test $ac_cv_header_utmpx_h = "yes"; then
+ ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_id" "ac_cv_member_struct_utmpx_ut_id" "
+ #include <sys/types.h>
+ #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_id" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_ID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_pid" "ac_cv_member_struct_utmpx_ut_pid" "
+ #include <sys/types.h>
+ #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_pid" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_PID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_tv" "ac_cv_member_struct_utmpx_ut_tv" "
+ #include <sys/types.h>
+ #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_tv" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_TV 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_type" "ac_cv_member_struct_utmpx_ut_type" "
+ #include <sys/types.h>
+ #include <utmpx.h>
+
+"
+if test "x$ac_cv_member_struct_utmpx_ut_type" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMPX_UT_TYPE 1
+_ACEOF
+
+
+fi
+
+else
+ ac_fn_c_check_member "$LINENO" "struct utmp" "ut_id" "ac_cv_member_struct_utmp_ut_id" "
+ #include <sys/types.h>
+ #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_id" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_ID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_pid" "ac_cv_member_struct_utmp_ut_pid" "
+ #include <sys/types.h>
+ #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_pid" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_PID 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_tv" "ac_cv_member_struct_utmp_ut_tv" "
+ #include <sys/types.h>
+ #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_tv" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_TV 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_type" "ac_cv_member_struct_utmp_ut_type" "
+ #include <sys/types.h>
+ #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_type" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_TYPE 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_member "$LINENO" "struct utmp" "ut_user" "ac_cv_member_struct_utmp_ut_user" "
+ #include <sys/types.h>
+ #include <utmp.h>
+
+"
+if test "x$ac_cv_member_struct_utmp_ut_user" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STRUCT_UTMP_UT_USER 1
+_ACEOF
+
+
+fi
+
+fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5
$as_echo_n "checking type of array argument to getgroups... " >&6; }
if test "${ac_cv_type_getgroups+set}" = set; then :
done
if test "${utmp-NONE}" = "NONE"; then
- for ac_func in login
-do :
- ac_fn_c_check_func "$LINENO" "login" "ac_cv_func_login"
-if test "x$ac_cv_func_login" = x""yes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LOGIN 1
-_ACEOF
-
- UTMP=BSD
- for ac_header in util.h utmp.h
+ for ac_func in getttyent ttyslot
do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-eval as_val=\$$as_ac_Header
- if test "x$as_val" = x""yes; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
- break
-fi
-
-done
-
-
-else
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for login in -lutil" >&5
-$as_echo_n "checking for login in -lutil... " >&6; }
-if test "${ac_cv_lib_util_login+set}" = set; then :
- $as_echo_n "(cached) " >&6
-else
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lutil $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char login ();
-int
-main ()
-{
-return login ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_lib_util_login=yes
-else
- ac_cv_lib_util_login=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_login" >&5
-$as_echo "$ac_cv_lib_util_login" >&6; }
-if test "x$ac_cv_lib_util_login" = x""yes; then :
-
- UTMP=BSD
- for ac_header in util.h utmp.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-eval as_val=\$$as_ac_Header
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
if test "x$as_val" = x""yes; then :
cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
break
-fi
-
-done
-
- case "$SUDO_LIBS" in
- *-lutil*) ;;
- *) SUDO_LIBS="${SUDO_LIBS} -lutil";;
- esac
- $as_echo "#define HAVE_LOGIN 1" >>confdefs.h
-
-
-fi
-
-
fi
done
#if TIME_WITH_SYS_TIME
# include <time.h>
#endif
-#if defined(HAVE_GETUTXID)
+#ifdef HAVE_UTMPX_H
# include <utmpx.h>
-#elif defined(HAVE_GETUTID)
-# include <utmp.h>
-#elif defined(HAVE_UTIL_H)
-# include <util.h>
+#else
# include <utmp.h>
+#endif /* HAVE_UTMPX_H */
+#ifdef HAVE_GETTTYENT
+# include <ttyent.h>
#endif
+#include <fcntl.h>
#include "sudo.h"
#include "sudo_exec.h"
+/*
+ * Simplify handling of utmp vs. utmpx
+ */
+#if !defined(HAVE_GETUTXID) && defined(HAVE_GETUTID)
+# define getutxline(u) getutline(u)
+# define pututxline(u) pututline(u)
+# define setutxent setutent(u)
+# define endutxent endutent(u)
+#endif /* !HAVE_GETUTXID && HAVE_GETUTID */
+
+#ifdef HAVE_GETUTXID
+typedef struct utmpx sudo_utmp_t;
+#else
+typedef struct utmp sudo_utmp_t;
+/* Older systems have ut_name, not us_user */
+# if !defined(HAVE_STRUCT_UTMP_UT_USER) && !defined(ut_user)
+# define ut_user ut_name
+# endif
+#endif
+
#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
/*
- * Create ut_id from tty line and the id from the entry we are cloning.
+ * Create ut_id from the new ut_line and the old ut_id.
*/
static void
-utmp_setid(const char *line, const char *old_id, char *new_id, size_t idsize)
+utmp_setid(sudo_utmp_t *old, sudo_utmp_t *new)
{
+ const char *line = new->ut_line;
size_t idlen;
/* Skip over "tty" in the id if old entry did too. */
- if (strncmp(line, "tty", 3) == 0 &&
- strncmp(old_id, "tty", idsize < 3 ? idsize : 3) != 0)
- line += 3;
+ if (strncmp(line, "tty", 3) == 0) {
+ idlen = MIN(sizeof(old->ut_id), 3);
+ if (strncmp(old->ut_id, "tty", idlen) != 0)
+ line += 3;
+ }
/* Store as much as will fit, skipping parts of the beginning as needed. */
idlen = strlen(line);
- if (idlen > idsize) {
- line += (idlen - idsize);
- idlen = idsize;
+ if (idlen > sizeof(new->ut_id)) {
+ line += idlen - sizeof(new->ut_id);
+ idlen = sizeof(new->ut_id);
}
- strncpy(new_id, line, idlen);
+ strncpy(new->ut_id, line, idlen);
}
#endif /* HAVE_GETUTXID || HAVE_GETUTID */
/*
- * Clone a utmp entry, updating the line, id, pid and time.
- * XXX - if no existing entry, make a new one
+ * Store time in utmp structure.
*/
-static int
-utmp_doclone(const char *from_line, const char *to_line)
+static void
+utmp_settime(sudo_utmp_t *ut)
{
- int rval = FALSE;
-#ifdef HAVE_GETUTXID
- struct utmpx *ut_old, ut_new;
+ struct timeval tv;
- memset(&ut_new, 0, sizeof(ut_new));
- strncpy(ut_new.ut_line, from_line, sizeof(ut_new.ut_line));
- setutxent();
- if ((ut_old = getutxid(&ut_new)) != NULL) {
- if (ut_old != &ut_new)
- memcpy(&ut_new, ut_old, sizeof(ut_new));
- strncpy(ut_new.ut_line, to_line, sizeof(ut_new.ut_line));
- utmp_setid(to_line, ut_old->ut_id, ut_new.ut_id, sizeof(ut_new.ut_id));
- ut_new.ut_pid = getpid();
- gettimeofday(&ut_new.ut_tv, NULL);
- ut_new.ut_type = USER_PROCESS;
-
- if (pututxline(&ut_new) != NULL)
- rval = TRUE;
- }
- endutxent();
-#elif HAVE_GETUTID
- struct utmp *ut_old, ut_new;
-
- memset(&ut_new, 0, sizeof(ut_new));
- strncpy(ut_new.ut_line, from_line, sizeof(ut_new.ut_line));
- setutent();
- if ((ut_old = getutid(&ut_new)) != NULL) {
- if (ut_old != &ut_new)
- memcpy(&ut_new, ut_old, sizeof(ut_new));
- strncpy(ut_new.ut_line, to_line, sizeof(ut_new.ut_line));
- utmp_setid(to_line, ut_old->ut_id, ut_new.ut_id, sizeof(ut_new.ut_id));
- ut_new.ut_pid = getpid();
- ut_new.ut_time = time(NULL);
- ut_new.ut_type = USER_PROCESS;
-
- if (pututline(&ut_new) != NULL)
- rval = TRUE;
- }
- endutent();
-#elif HAVE_LOGIN
- FILE *fp;
- struct utmp ut;
-
- /* Find existing entry, update line and add as new. */
- if ((fp = fopen(_PATH_UTMP, "r")) != NULL) {
- while (fread(&ut, sizeof(ut), 1, fp) == 1) {
- if (ut.ut_name[0] &&
- strncmp(ut.ut_line, from_line, sizeof(ut.ut_line)) == 0) {
- strncpy(ut.ut_line, to_line, sizeof(ut.ut_line));
- login(&ut);
- rval = TRUE;
- break;
- }
- }
- fclose(fp);
+ gettimeofday(&tv, NULL);
+
+#if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV)
+ ut->ut_tv.tv_sec = tv.tv_sec;
+ ut->ut_tv.tv_usec = tv.tv_usec;
+#else
+ ut->ut_time = tv.tv_sec;
+#endif
+}
+
+/*
+ * Fill in a utmp entry, using an old entry as a template if there is one.
+ */
+static void
+utmp_fill(const char *line, sudo_utmp_t *ut_old, sudo_utmp_t *ut_new)
+{
+ if (ut_old == NULL) {
+ memset(ut_new, 0, sizeof(*ut_new));
+ strncpy(ut_new->ut_user, user_details.username, sizeof(ut_new->ut_user));
+ } else if (ut_old != ut_new) {
+ memcpy(ut_new, ut_old, sizeof(*ut_new));
}
+ strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line));
+#if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID)
+ utmp_setid(ut_old, ut_new);
+#endif
+#if defined(HAVE_STRUCT_UTMPX_UT_PID) || defined(HAVE_STRUCT_UTMP_UT_PID)
+ ut_new->ut_pid = getpid();
+#endif
+ utmp_settime(ut_new);
+#if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
+ ut_new->ut_type = USER_PROCESS;
#endif
- return rval;
}
+/*
+ * There are two basic utmp file types:
+ *
+ * POSIX: sequential access with new entries appended to the end.
+ * Manipulated via {get,put}utent()/{get,put}getutxent().
+ *
+ * Legacy: sparse file indexed by ttyslot() * sizeof(struct utmp)
+ */
+#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID)
int
-utmp_clone(const char *from_line, const char *to_line)
+utmp_login(const char *from_line, const char *to_line, int ttyfd)
{
- /* Strip off /dev/ prefix from to/from line as needed. */
- if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
- from_line += sizeof(_PATH_DEV) - 1;
+ sudo_utmp_t utbuf, *ut_old = NULL;
+ int rval = FALSE;
+
+ /* Strip off /dev/ prefix from line as needed. */
if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
to_line += sizeof(_PATH_DEV) - 1;
-
- return utmp_doclone(from_line, to_line);
+ setutxent();
+ if (from_line != NULL) {
+ if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ from_line += sizeof(_PATH_DEV) - 1;
+
+ /* Lookup old line. */
+ memset(&utbuf, 0, sizeof(utbuf));
+ strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line));
+ ut_old = getutxline(&utbuf);
+ }
+ utmp_fill(to_line, ut_old, &utbuf);
+ if (pututxline(&utbuf) != NULL)
+ rval = TRUE;
+ endutxent();
+
+ return rval;
}
-/*
- * Remove (zero out) the utmp entry for a line.
- */
-static int
-utmp_doremove(const char *line)
+int
+utmp_logout(const char *line)
{
int rval = FALSE;
-#ifdef HAVE_GETUTXID
- struct utmpx *ut, key;
+ sudo_utmp_t *ut, utbuf;
+
+ /* Strip off /dev/ prefix from line as needed. */
+ if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ line += sizeof(_PATH_DEV) - 1;
- memset(&key, 0, sizeof(key));
- strncpy(key.ut_line, line, sizeof(key.ut_line));
- setutxent();
- if ((ut = getutxid(&key)) != NULL) {
+ memset(&utbuf, 0, sizeof(utbuf));
+ strncpy(utbuf.ut_line, line, sizeof(utbuf.ut_line));
+ if ((ut = getutxline(&utbuf)) != NULL) {
+ memset(ut->ut_user, 0, sizeof(ut->ut_user));
+# if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE)
ut->ut_type = DEAD_PROCESS;
- (void)gettimeofday(&ut->ut_tv, NULL);
+# endif
+ utmp_settime(ut);
if (pututxline(ut) != NULL)
rval = TRUE;
}
- endutxent();
-#elif HAVE_GETUTID
- struct utmp *ut, key;
-
- memset(&key, 0, sizeof(key));
- strncpy(key.ut_line, line, sizeof(key.ut_line));
- setutent();
- if ((ut = getutid(&key)) != NULL) {
- ut->ut_type = DEAD_PROCESS;
- ut->ut_time = time(NULL);
- if (pututline(ut) != NULL)
+ return rval;
+}
+
+#else /* !HAVE_GETUTXID && !HAVE_GETUTID */
+
+/*
+ * Find the slot for the specified line (tty name and file descriptor).
+ * Returns a slot suitable for seeking into utmp on success or <= 0 on error.
+ * If getttyent() is available we can use that to compute the slot.
+ */
+# ifdef HAVE_GETTTYENT
+static int
+utmp_slot(const char *line, int ttyfd)
+{
+ int slot = 1;
+ struct ttyent *tty;
+
+ setttyent();
+ while ((tty = getttyent()) != NULL) {
+ if (strcmp(line, tty->ty_name) == 0)
+ break;
+ slot++;
+ }
+ endttyent();
+ return tty ? slot : 0;
+}
+# else
+static int
+utmp_slot(const char *line, int ttyfd)
+{
+ int sfd, slot;
+
+ /*
+ * Temporarily point stdin to the tty since ttyslot()
+ * doesn't take an argument.
+ */
+ if ((sfd = dup(STDIN_FILENO)) == -1)
+ error(1, "Can't save stdin");
+ if (dup2(ttyfd, STDIN_FILENO) == -1)
+ error(1, "Can't dup2 stdin");
+ slot = ttyslot();
+ if (dup2(sfd, STDIN_FILENO) == -1)
+ error(1, "Can't restore stdin");
+ close(sfd);
+
+ return slot;
+}
+# endif /* HAVE_GETTTYENT */
+
+int
+utmp_login(const char *from_line, const char *to_line, int ttyfd)
+{
+ sudo_utmp_t utbuf, *ut_old = NULL;
+ int slot, rval = FALSE;
+ FILE *fp;
+
+ /* Find slot for new entry. */
+ slot = utmp_slot(to_line, ttyfd);
+ if (slot <= 0)
+ goto done;
+
+ if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
+ goto done;
+
+ /* Strip off /dev/ prefix from line as needed. */
+ if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ to_line += sizeof(_PATH_DEV) - 1;
+ if (from_line != NULL) {
+ if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ from_line += sizeof(_PATH_DEV) - 1;
+
+ /* Lookup old line. */
+ while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
+# ifdef HAVE_STRUCT_UTMP_UT_ID
+ if (utbuf.ut_type != LOGIN_PROCESS && utbuf.ut_type != USER_PROCESS)
+ continue;
+# endif
+ if (utbuf.ut_user[0] &&
+ !strncmp(utbuf.ut_line, from_line, sizeof(utbuf.ut_line))) {
+ ut_old = &utbuf;
+ break;
+ }
+ }
+ }
+ utmp_fill(to_line, ut_old, &utbuf);
+ if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) {
+ if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
rval = TRUE;
}
- endutent();
-#elif HAVE_LOGIN
- if (logout(line) != 0)
- rval = TRUE;
-#endif /* HAVE_GETUTXID */
+ fclose(fp);
+
+done:
return rval;
}
int
-utmp_remove(const char *line)
+utmp_logout(const char *line)
{
- /* Strip off /dev/ prefix from to/from line as needed. */
+ sudo_utmp_t utbuf;
+ int rval = FALSE;
+ FILE *fp;
+
+ if ((fp = fopen(_PATH_UTMP, "r+")) == NULL)
+ return rval;
+
+ /* Strip off /dev/ prefix from line as needed. */
if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
line += sizeof(_PATH_DEV) - 1;
+
+ while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) {
+ if (!strncmp(utbuf.ut_line, line, sizeof(utbuf.ut_line))) {
+ memset(utbuf.ut_user, 0, sizeof(utbuf.ut_user));
+# if defined(HAVE_STRUCT_UTMP_UT_TYPE)
+ utbuf.ut_type = DEAD_PROCESS;
+# endif
+ utmp_settime(&utbuf);
+ /* Back up and overwrite record. */
+ if (fseek(fp, 0L - (long)sizeof(utbuf), SEEK_CUR) == 0) {
+ if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1)
+ rval = TRUE;
+ }
+ break;
+ }
+ }
+ fclose(fp);
- return utmp_doremove(line);
+ return rval;
}
+#endif /* HAVE_GETUTXID || HAVE_GETUTID */