--- gdm-2.16.0/config/PreSession.in.wtmp 2006-04-26 21:06:05.000000000 -0400 +++ gdm-2.16.0/config/PreSession.in 2006-10-15 20:05:45.000000000 -0400 @@ -68,17 +68,4 @@ if [ "x$XSETROOT" != "x" ] ; then "$XSETROOT" -cursor_name left_ptr -solid "$BACKCOLOR" fi - -SESSREG=`gdmwhich sessreg` -if [ "x$SESSREG" != "x" ] ; then - # some output for easy debugging - echo "$0: Registering your session with wtmp and utmp" - echo "$0: running: $SESSREG -a -w /var/log/wtmp -u /var/run/utmp -x \"$X_SERVERS\" -h \"$REMOTE_HOST\" -l \"$DISPLAY\" \"$USER\"" - - exec "$SESSREG" -a -w /var/log/wtmp -u /var/run/utmp -x "$X_SERVERS" -h "$REMOTE_HOST" -l "$DISPLAY" "$USER" - # this is not reached -fi - -# some output for easy debugging -echo "$0: could not find the sessreg utility, cannot update wtmp and utmp" exit 0 --- gdm-2.16.0/daemon/slave.c.wtmp 2006-10-15 20:05:45.000000000 -0400 +++ gdm-2.16.0/daemon/slave.c 2006-10-15 20:05:45.000000000 -0400 @@ -4315,6 +4315,14 @@ gdm_slave_session_start (void) g_free (language); g_free (gnome_session); + gdm_verify_write_record (d, + GDM_VERIFY_RECORD_TYPE_LOGIN, + pwent->pw_name, + d->name, + !d->attached? d->hostname : NULL, + pid); + + gdm_slave_send_num (GDM_SOP_SESSPID, pid); gdm_sigchld_block_push (); @@ -4363,6 +4371,17 @@ gdm_slave_session_start (void) uid, gid); } + if ((pid != 0) && (d->last_sess_status != -1)) { + gdm_debug ("session '%d' exited with status '%d', recording logout", + pid, d->last_sess_status); + gdm_verify_write_record (d, + GDM_VERIFY_RECORD_TYPE_LOGOUT, + pwent->pw_name, + d->name, + !d->attached? d->hostname : NULL, + pid); + } + gdm_slave_session_stop (pid != 0 /* run_post_session */, FALSE /* no_shutdown_check */); @@ -4721,7 +4740,7 @@ gdm_slave_child_handler (int sig) } } else if (pid != 0 && pid == d->sesspid) { d->sesspid = 0; - if (WIFEXITED (status)) + if (WIFEXITED (status)) d->last_sess_status = WEXITSTATUS (status); else d->last_sess_status = -1; --- gdm-2.16.0/daemon/verify.h.wtmp 2005-11-03 19:51:21.000000000 -0500 +++ gdm-2.16.0/daemon/verify.h 2006-10-15 20:05:45.000000000 -0400 @@ -21,6 +21,12 @@ #include "gdm.h" +typedef enum { + GDM_VERIFY_RECORD_TYPE_LOGIN, + GDM_VERIFY_RECORD_TYPE_LOGOUT, + GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT +} GdmVerifyRecordType; + /* If username is NULL, we ask, if local is FALSE, don't start * the timed login timer */ gchar *gdm_verify_user (GdmDisplay *d, @@ -30,6 +36,13 @@ gchar *gdm_verify_user (GdmDisplay *d void gdm_verify_cleanup (GdmDisplay *d); void gdm_verify_check (void); void gdm_verify_select_user (const char *user); +void gdm_verify_write_record (GdmDisplay *d, + GdmVerifyRecordType record_type, + const gchar *username, + const gchar *console_name, + const gchar *host_name, + GPid pid); + /* used in pam */ gboolean gdm_verify_setup_env (GdmDisplay *d); gboolean gdm_verify_setup_user (GdmDisplay *d, --- gdm-2.16.0/daemon/verify-pam.c.wtmp 2006-10-15 20:05:45.000000000 -0400 +++ gdm-2.16.0/daemon/verify-pam.c 2006-10-15 20:08:48.000000000 -0400 @@ -29,6 +29,7 @@ #ifdef sun #include #endif +#include #include @@ -55,6 +56,14 @@ #define log_to_audit_system(l,h,d,s) do { ; } while (0) #endif +#ifndef GDM_BAD_RECORDS_FILE +#define GDM_BAD_RECORDS_FILE "/var/log/btmp" +#endif + +#ifndef GDM_NEW_RECORDS_FILE +#define GDM_NEW_RECORDS_FILE "/var/log/wtmp" +#endif + /* Evil, but this way these things are passed to the child session */ static pam_handle_t *pamh = NULL; @@ -417,6 +426,125 @@ gdm_verify_select_user (const char *user selected_user = g_strdup (user); } +void +gdm_verify_write_record (GdmDisplay *d, + GdmVerifyRecordType record_type, + const gchar *username, + const gchar *console_name, + const gchar *host_name, + GPid pid) +{ + struct utmp record = { 0 }; + GTimeVal now = { 0 }; + gchar *host; + + gdm_debug ("writing %s record", + record_type == GDM_VERIFY_RECORD_TYPE_LOGIN? "session" : + record_type == GDM_VERIFY_RECORD_TYPE_LOGOUT? "logout" : + "failed session attempt"); + + if (record_type != GDM_VERIFY_RECORD_TYPE_LOGOUT) + { + /* it's possible that PAM failed before + * it mapped the user input into a valid username + * so we fallback to try using "(unknown)" + */ + if (username != NULL) + strncpy (record.ut_user, + username, + sizeof (record.ut_user)); + else + strncpy (record.ut_user, + "(unknown)", + sizeof (record.ut_user)); + } + + gdm_debug ("using username %.*s", + sizeof (record.ut_user), + record.ut_user); + + strncpy (record.ut_id, + console_name + + strlen (console_name) - + sizeof (record.ut_id), + sizeof (record.ut_id)); + + gdm_debug ("using id %.*s", + sizeof (record.ut_id), + record.ut_id); + + if (g_str_has_prefix (console_name, "/dev/")) { + strncpy (record.ut_line, + console_name + strlen ("/dev/"), + sizeof (record.ut_line)); + } else if (g_str_has_prefix (console_name, ":")) { + strncpy (record.ut_line, + console_name, + sizeof (record.ut_line)); + } + + gdm_debug ("using line %.*s", + sizeof (record.ut_line), + record.ut_line); + + host = NULL; + if ((host_name != NULL) && + g_str_has_prefix (console_name, ":")) + host = g_strdup_printf ("%s%s", + host_name, + console_name); + else if ((host_name != NULL) && + !strstr (console_name, ":")) + host = g_strdup (host_name); + else if (!g_str_has_prefix (console_name, ":") && + strstr (console_name, ":")) + host = g_strdup (console_name); + + if (host) + { + strncpy (record.ut_host, host, sizeof (record.ut_host)); + g_free (host); + gdm_debug ("using hostname %.*s", + sizeof (record.ut_host), + record.ut_host); + } + + g_get_current_time (&now); + record.ut_tv.tv_sec = now.tv_sec; + record.ut_tv.tv_usec = now.tv_usec; + + gdm_debug ("using time %ld", (glong) record.ut_tv.tv_sec); + + record.ut_type = USER_PROCESS; + gdm_debug ("using type USER_PROCESS"); + + record.ut_pid = pid; + + gdm_debug ("using pid %d", (gint) record.ut_pid); + + switch (record_type) + { + case GDM_VERIFY_RECORD_TYPE_LOGIN: + gdm_debug ("writing session record to " + GDM_NEW_RECORDS_FILE); + updwtmp (GDM_NEW_RECORDS_FILE, &record); + break; + + case GDM_VERIFY_RECORD_TYPE_LOGOUT: + gdm_debug ("writing logout record to " + GDM_NEW_RECORDS_FILE); + updwtmp (GDM_NEW_RECORDS_FILE, &record); + break; + + case GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT: + gdm_debug ("writing failed session attempt record to " + GDM_BAD_RECORDS_FILE); + updwtmp (GDM_BAD_RECORDS_FILE, &record); + break; + } + +} + static const char * perhaps_translate_message (const char *msg) { @@ -1173,6 +1301,12 @@ authenticate_again: * message from the PAM subsystem */ if ( ! error_msg_given && gdm_slave_action_pending ()) { + + gdm_verify_write_record (d, GDM_VERIFY_RECORD_TYPE_FAILED_ATTEMPT, + login, display, + d->attached? NULL : d->hostname, + getpid ()); + /* I'm not sure yet if I should display this message for any other issues - heeten */ if (pamerr == PAM_AUTH_ERR || pamerr == PAM_USER_UNKNOWN) {