]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - tests/src/libsystem.c
Allow greeters to run in-session
[sojka/lightdm.git] / tests / src / libsystem.c
index 157bb993efe08e67606e2442a8d85a0c3454863c..d4ec11676b23d482684ac1509fa9971d27718ee1 100644 (file)
@@ -1,6 +1,8 @@
 #define _GNU_SOURCE
 #define __USE_GNU
 
+#include <config.h>
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -8,6 +10,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
 #include <pwd.h>
 #include <unistd.h>
 #include <dirent.h>
@@ -15,6 +20,7 @@
 #include <security/pam_appl.h>
 #include <fcntl.h>
 #include <dlfcn.h>
+#include <utmp.h>
 #include <utmpx.h>
 #ifdef __linux__
 #include <linux/vt.h>
 #include <xcb/xcb.h>
 #include <gio/gunixsocketaddress.h>
 
+#if HAVE_LIBAUDIT
+#include <libaudit.h>
+#endif
+
 #include "status.h"
 
 #define LOGIN_PROMPT "login:"
 
-static int console_fd = -1;
+static int tty_fd = -1;
 
 static GList *user_entries = NULL;
 static GList *getpwent_link = NULL;
@@ -37,9 +47,23 @@ static GList *group_entries = NULL;
 static int active_vt = 7;
 
 static gboolean status_connected = FALSE;
+static GKeyFile *config;
+
+static void connect_status (void)
+{
+    if (status_connected)
+        return;
+    status_connected = TRUE;
+
+    status_connect (NULL, NULL);
+
+    config = g_key_file_new ();
+    g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
+}
 
 struct pam_handle
 {
+    char *id;
     char *service_name;
     char *user;
     char *authtok;
@@ -49,6 +73,13 @@ struct pam_handle
     struct pam_conv conversation;
 };
 
+int
+gethostname (char *name, size_t len)
+{
+   snprintf (name, len, "lightdm-test");
+   return 0;
+}
+
 uid_t
 getuid (void)
 {
@@ -179,7 +210,16 @@ redirect_path (const gchar *path)
         return g_strdup (path);
 
     if (g_str_has_prefix (path, "/tmp"))
-        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("tmp"), NULL);
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
+
+    if (g_str_has_prefix (path, "/run"))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "run", path + strlen ("/run"), NULL);
+
+    if (g_str_has_prefix (path, "/etc/xdg"))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
+
+    if (g_str_has_prefix (path, "/usr/share/lightdm"))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
 
     return g_strdup (path);
 }
@@ -194,14 +234,14 @@ open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
 
     _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
 
-    if (strcmp (pathname, "/dev/console") == 0)
+    if (strcmp (pathname, "/dev/tty0") == 0)
     {
-        if (console_fd < 0)
+        if (tty_fd < 0)
         {
-            console_fd = _open ("/dev/null", flags, mode);
-            fcntl (console_fd, F_SETFD, FD_CLOEXEC);
+            tty_fd = _open ("/dev/null", flags, mode);
+            fcntl (tty_fd, F_SETFD, FD_CLOEXEC);
         }
-        return console_fd;
+        return tty_fd;
     }
 
     new_path = redirect_path (pathname);
@@ -255,6 +295,22 @@ fopen (const char *path, const char *mode)
     return result;
 }
 
+int
+unlinkat (int dirfd, const char *pathname, int flags)
+{
+    int (*_unlinkat) (int dirfd, const char *pathname, int flags);
+    gchar *new_path = NULL;
+    int result;
+
+    _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
+
+    new_path = redirect_path (pathname);
+    result = _unlinkat (dirfd, new_path, flags);
+    g_free (new_path);
+
+    return result;
+}
+
 int
 creat (const char *pathname, mode_t mode)
 {
@@ -294,12 +350,13 @@ access (const char *pathname, int mode)
     gchar *new_path = NULL;
     int ret;
 
-    /* Look like systemd is always running */
-    if (strcmp (pathname, "/run/systemd/seats/") == 0)
-        return 1;
-
     _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
 
+    if (strcmp (pathname, "/dev/tty0") == 0)
+        return F_OK;
+    if (strcmp (pathname, "/sys/class/tty/tty0/active") == 0)
+        return F_OK;
+
     new_path = redirect_path (pathname);
     ret = _access (new_path, mode);
     g_free (new_path);
@@ -313,7 +370,7 @@ stat (const char *path, struct stat *buf)
     int (*_stat) (const char *path, struct stat *buf);
     gchar *new_path = NULL;
     int ret;
-  
+
     _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
 
     new_path = redirect_path (path);
@@ -345,7 +402,7 @@ __xstat (int version, const char *path, struct stat *buf)
     int (*___xstat) (int version, const char *path, struct stat *buf);
     gchar *new_path = NULL;
     int ret;
-  
+
     ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
 
     new_path = redirect_path (path);
@@ -361,7 +418,7 @@ __xstat64 (int version, const char *path, struct stat64 *buf)
     int (*___xstat64) (int version, const char *path, struct stat64 *buf);
     gchar *new_path = NULL;
     int ret;
-  
+
     ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
 
     new_path = redirect_path (path);
@@ -371,6 +428,38 @@ __xstat64 (int version, const char *path, struct stat64 *buf)
     return ret;
 }
 
+int
+__fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
+{
+    int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
+    gchar *new_path = NULL;
+    int ret;
+
+    ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
+
+    new_path = redirect_path (pathname);
+    ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
+    g_free (new_path);
+
+    return ret;
+}
+
+int
+__fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
+{
+    int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
+    gchar *new_path = NULL;
+    int ret;
+
+    ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
+
+    new_path = redirect_path (pathname);
+    ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
+    g_free (new_path);
+
+    return ret;
+}
+
 DIR *
 opendir (const char *name)
 {
@@ -384,7 +473,7 @@ opendir (const char *name)
     result = _opendir (new_path);
     g_free (new_path);
 
-    return result; 
+    return result;
 }
 
 int
@@ -406,17 +495,8 @@ mkdir (const char *pathname, mode_t mode)
 int
 chown (const char *pathname, uid_t owner, gid_t group)
 {
-    int (*_chown) (const char *pathname, uid_t owner, gid_t group);
-    gchar *new_path = NULL;
-    int result;
-
-    _chown = (int (*)(const char *pathname, uid_t owner, gid_t group)) dlsym (RTLD_NEXT, "chown");
-
-    new_path = redirect_path (pathname);
-    result = _chown (new_path, owner, group);
-    g_free (new_path);
-
-    return result;
+    /* Just fake it - we're not root */
+    return 0;
 }
 
 int
@@ -441,9 +521,9 @@ ioctl (int d, unsigned long request, ...)
     int (*_ioctl) (int d, int request, ...);
 
     _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
-    if (d > 0 && d == console_fd)
+    if (d > 0 && d == tty_fd)
     {
-        struct vt_stat *console_state;
+        struct vt_stat *vt_state;
         int vt;
         va_list ap;
 
@@ -451,9 +531,9 @@ ioctl (int d, unsigned long request, ...)
         {
         case VT_GETSTATE:
             va_start (ap, request);
-            console_state = va_arg (ap, struct vt_stat *);
+            vt_state = va_arg (ap, struct vt_stat *);
             va_end (ap);
-            console_state->v_active = active_vt;
+            vt_state->v_active = active_vt;
             break;
         case VT_ACTIVATE:
             va_start (ap, request);
@@ -462,8 +542,7 @@ ioctl (int d, unsigned long request, ...)
             if (vt != active_vt)
             {
                 active_vt = vt;
-                if (!status_connected)
-                    status_connected = status_connect (NULL);
+                connect_status ();
                 status_notify ("VT ACTIVATE VT=%d", active_vt);
             }
             break;
@@ -484,12 +563,235 @@ ioctl (int d, unsigned long request, ...)
     }
 }
 
+static void
+add_port_redirect (int requested_port, int redirected_port)
+{
+    GKeyFile *file;
+    gchar *path, *name, *data;
+
+    file = g_key_file_new ();
+    path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
+    g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
+
+    name = g_strdup_printf ("%d", requested_port);
+    g_key_file_set_integer (file, name, "redirected", redirected_port);
+    g_free (name);
+  
+    data = g_key_file_to_data (file, NULL, NULL);
+    g_file_set_contents (path, data, -1, NULL);
+    g_free (data);
+    g_free (path);
+
+    g_key_file_free (file);
+}
+
+static int
+find_port_redirect (int port)
+{
+    GKeyFile *file;
+    gchar *path, *name;
+    int redirected_port;
+
+    file = g_key_file_new ();
+    path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
+    g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
+    g_free (path);
+
+    name = g_strdup_printf ("%d", port);
+    redirected_port = g_key_file_get_integer (file, name, "redirected", NULL);
+    g_free (name);
+    g_key_file_free (file);
+
+    return redirected_port;
+}
+
+int
+bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+    int port = 0, redirected_port = 0;
+    const char *path;
+    int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+    const struct sockaddr *modified_addr = addr;
+    struct sockaddr_in temp_addr_in;
+    struct sockaddr_in6 temp_addr_in6;
+    struct sockaddr_un temp_addr_un;
+    int retval;
+
+    _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
+
+    switch (addr->sa_family)
+    {
+    case AF_UNIX:
+        path = ((const struct sockaddr_un *) addr)->sun_path;
+        if (path[0] != '\0')
+        {
+            gchar *new_path = redirect_path (path);
+            memcpy (&temp_addr_un, addr, sizeof (struct sockaddr_un));
+            strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+            g_free (new_path);
+            modified_addr = (struct sockaddr *) &temp_addr_un;
+        }
+        break;
+    case AF_INET:
+        port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
+        redirected_port = find_port_redirect (port);
+        memcpy (&temp_addr_in, addr, sizeof (struct sockaddr_in));
+        modified_addr = (struct sockaddr *) &temp_addr_in;
+        if (redirected_port != 0)
+            temp_addr_in.sin_port = htons (redirected_port);
+        else
+            temp_addr_in.sin_port = 0;
+        break;
+    case AF_INET6:
+        port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
+        redirected_port = find_port_redirect (port);
+        memcpy (&temp_addr_in6, addr, sizeof (struct sockaddr_in6));
+        modified_addr = (struct sockaddr *) &temp_addr_in6;
+        if (redirected_port != 0)
+            temp_addr_in6.sin6_port = htons (redirected_port);
+        else
+            temp_addr_in6.sin6_port = 0;
+        break;
+    }
+
+    retval = _bind (sockfd, modified_addr, addrlen);
+
+    socklen_t temp_addr_len;
+    switch (addr->sa_family)
+    {
+    case AF_INET:
+        temp_addr_len = sizeof (temp_addr_in);
+        getsockname (sockfd, &temp_addr_in, &temp_addr_len);
+        if (redirected_port == 0)
+        {
+            redirected_port = ntohs (temp_addr_in.sin_port);
+            add_port_redirect (port, redirected_port);
+        }
+        break;
+    case AF_INET6:
+        temp_addr_len = sizeof (temp_addr_in6);
+        getsockname (sockfd, &temp_addr_in6, &temp_addr_len);
+        if (redirected_port == 0)
+        {
+            redirected_port = ntohs (temp_addr_in6.sin6_port);
+            add_port_redirect (port, redirected_port);
+        }
+        break;
+    }
+
+    return retval;
+}
+
+#include <ctype.h>
+
+int
+connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+    int port, redirected_port;
+    const char *path;
+    const struct sockaddr *modified_addr = addr;
+    struct sockaddr_in temp_addr_in;
+    struct sockaddr_in6 temp_addr_in6;
+    struct sockaddr_un temp_addr_un;
+    int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+    _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
+
+    switch (addr->sa_family)
+    {
+    case AF_UNIX:
+        path = ((const struct sockaddr_un *) addr)->sun_path;
+        if (path[0] != '\0') 
+        {
+            gchar *new_path = redirect_path (path);
+            memcpy (&temp_addr_un, addr, addrlen);
+            strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+            g_free (new_path);
+            modified_addr = (struct sockaddr *) &temp_addr_un;
+        }
+        break;
+    case AF_INET:
+        port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
+        redirected_port = find_port_redirect (port);
+        if (redirected_port != 0) 
+        {
+            memcpy (&temp_addr_in, addr, sizeof (struct sockaddr_in));
+            temp_addr_in.sin_port = htons (redirected_port);
+            modified_addr = (struct sockaddr *) &temp_addr_in;
+        }
+        break;
+    case AF_INET6:
+        port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
+        redirected_port = find_port_redirect (port);
+        if (redirected_port != 0) 
+        {
+            memcpy (&temp_addr_in6, addr, sizeof (struct sockaddr_in6));
+            temp_addr_in6.sin6_port = htons (redirected_port);
+            modified_addr = (struct sockaddr *) &temp_addr_in6;
+        }
+        break;
+    }
+
+    return _connect (sockfd, modified_addr, addrlen);
+}
+
+ssize_t
+sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
+{
+    int port, redirected_port;
+    const char *path;
+    const struct sockaddr *modified_addr = dest_addr;
+    struct sockaddr_in temp_addr_in;
+    struct sockaddr_in6 temp_addr_in6;
+    struct sockaddr_un temp_addr_un;  
+    ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
+
+    _sendto = (ssize_t (*)(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "sendto");
+
+    switch (dest_addr->sa_family)
+    {
+    case AF_UNIX:
+        path = ((const struct sockaddr_un *) dest_addr)->sun_path;
+        if (path[0] != '\0') 
+        {
+            gchar *new_path = redirect_path (path);
+            memcpy (&temp_addr_un, dest_addr, sizeof (struct sockaddr_un));
+            strncpy (temp_addr_un.sun_path, new_path, sizeof (temp_addr_un.sun_path) - 1);
+            g_free (new_path);
+            modified_addr = (struct sockaddr *) &temp_addr_un;
+        }
+        break;
+    case AF_INET:
+        port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
+        redirected_port = find_port_redirect (port);
+        if (redirected_port != 0) 
+        {
+            memcpy (&temp_addr_in, dest_addr, sizeof (struct sockaddr_in));
+            temp_addr_in.sin_port = htons (redirected_port);
+            modified_addr = (struct sockaddr *) &temp_addr_in;
+        }
+        break;
+    case AF_INET6:
+        port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port);
+        redirected_port = find_port_redirect (port);
+        if (redirected_port != 0) 
+        {
+            memcpy (&temp_addr_in6, dest_addr, sizeof (struct sockaddr_in6));
+            temp_addr_in6.sin6_port = htons (redirected_port);
+            modified_addr = (struct sockaddr *) &temp_addr_in6;
+        }
+        break;
+    }
+
+    return _sendto (sockfd, buf, len, flags, modified_addr, addrlen);
+}
+
 int
 close (int fd)
 {
     int (*_close) (int fd);
 
-    if (fd > 0 && fd == console_fd)
+    if (fd > 0 && fd == tty_fd)
         return 0;
 
     _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
@@ -501,7 +803,7 @@ static void
 free_user (gpointer data)
 {
     struct passwd *entry = data;
-  
+
     g_free (entry->pw_name);
     g_free (entry->pw_passwd);
     g_free (entry->pw_gecos);
@@ -594,10 +896,10 @@ struct passwd *
 getpwnam (const char *name)
 {
     GList *link;
-  
+
     if (name == NULL)
         return NULL;
-  
+
     load_passwd_file ();
 
     for (link = user_entries; link; link = link->next)
@@ -635,7 +937,7 @@ static void
 free_group (gpointer data)
 {
     struct group *entry = data;
-  
+
     g_free (entry->gr_name);
     g_free (entry->gr_passwd);
     g_strfreev (entry->gr_mem);
@@ -736,6 +1038,25 @@ pam_start (const char *service_name, const char *user, const struct pam_conv *co
     if (handle == NULL)
         return PAM_BUF_ERR;
 
+    if (user)
+        handle->id = g_strdup_printf ("PAM-%s", user);
+    else
+        handle->id = g_strdup ("PAM");
+
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s START", handle->id);
+        g_string_append_printf (status, " SERVICE=%s", service_name);
+        if (user)
+            g_string_append_printf (status, " USER=%s", user);
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
     handle->service_name = strdup (service_name);
     handle->user = user ? strdup (user) : NULL;
     handle->authtok = NULL;
@@ -749,27 +1070,6 @@ pam_start (const char *service_name, const char *user, const struct pam_conv *co
     return PAM_SUCCESS;
 }
 
-static void
-send_info (pam_handle_t *pamh, const char *message)
-{
-    struct pam_message **msg;
-    struct pam_response *resp = NULL;
-
-    msg = calloc (1, sizeof (struct pam_message *));
-    msg[0] = malloc (sizeof (struct pam_message));
-    msg[0]->msg_style = PAM_TEXT_INFO;
-    msg[0]->msg = message;
-    pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
-    free (msg[0]);
-    free (msg);
-    if (resp)
-    {
-        if (resp[0].resp)
-            free (resp[0].resp);
-        free (resp);
-    }
-}
-
 int
 pam_authenticate (pam_handle_t *pamh, int flags)
 {
@@ -778,7 +1078,23 @@ pam_authenticate (pam_handle_t *pamh, int flags)
 
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
-  
+
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+        if (flags & PAM_DISALLOW_NULL_AUTHTOK)
+            g_string_append (status, " DISALLOW_NULL_AUTHTOK");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
     if (strcmp (pamh->service_name, "test-remote") == 0)
     {
         int result;
@@ -787,7 +1103,7 @@ pam_authenticate (pam_handle_t *pamh, int flags)
 
         msg = malloc (sizeof (struct pam_message *) * 1);
         msg[0] = malloc (sizeof (struct pam_message));
-        msg[0]->msg_style = PAM_PROMPT_ECHO_ON; 
+        msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
         msg[0]->msg = "remote-login:";
         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
         free (msg[0]);
@@ -850,7 +1166,7 @@ pam_authenticate (pam_handle_t *pamh, int flags)
 
         msg = malloc (sizeof (struct pam_message *) * 1);
         msg[0] = malloc (sizeof (struct pam_message));
-        msg[0]->msg_style = PAM_PROMPT_ECHO_ON; 
+        msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
         msg[0]->msg = LOGIN_PROMPT;
         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
         free (msg[0]);
@@ -865,15 +1181,12 @@ pam_authenticate (pam_handle_t *pamh, int flags)
             free (resp);
             return PAM_CONV_ERR;
         }
-      
+
         pamh->user = strdup (resp[0].resp);
         free (resp[0].resp);
         free (resp);
     }
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_authenticate");
-
     /* Crash on authenticate */
     if (strcmp (pamh->user, "crash-authenticate") == 0)
         kill (getpid (), SIGSEGV);
@@ -964,6 +1277,8 @@ pam_authenticate (pam_handle_t *pamh, int flags)
             result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
             free (msg[0]);
             free (msg);
+            if (result != PAM_SUCCESS)
+                return result;
 
             if (resp == NULL)
                 return PAM_CONV_ERR;
@@ -1006,7 +1321,7 @@ static const char *
 get_env_value (const char *name_value, const char *name)
 {
     int j;
-  
+
     for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
     if (name[j] == '\0' && name_value[j] == '=')
         return &name_value[j + 1];
@@ -1101,13 +1416,13 @@ pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
 {
     if (pamh == NULL || item == NULL)
         return PAM_SYSTEM_ERR;
-  
+
     switch (item_type)
     {
     case PAM_SERVICE:
         *item = pamh->service_name;
         return PAM_SUCCESS;
-      
+
     case PAM_USER:
         *item = pamh->user;
         return PAM_SUCCESS;
@@ -1119,11 +1434,11 @@ pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
     case PAM_RUSER:
         *item = pamh->ruser;
         return PAM_SUCCESS;
-     
+
     case PAM_USER_PROMPT:
         *item = LOGIN_PROMPT;
         return PAM_SUCCESS;
-      
+
     case PAM_TTY:
         *item = pamh->tty;
         return PAM_SUCCESS;
@@ -1140,15 +1455,29 @@ pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
 int
 pam_open_session (pam_handle_t *pamh, int flags)
 {
+    GVariant *result;
+    GError *error = NULL;
+
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
 
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
     if (strcmp (pamh->user, "session-error") == 0)
         return PAM_SESSION_ERR;
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_open_session");
-
     if (strcmp (pamh->user, "make-home-dir") == 0)
     {
         struct passwd *entry;
@@ -1156,6 +1485,33 @@ pam_open_session (pam_handle_t *pamh, int flags)
         g_mkdir_with_parents (entry->pw_dir, 0755);
     }
 
+    /* Open logind session */
+    result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
+                                          "org.freedesktop.login1",
+                                          "/org/freedesktop/login1",
+                                          "org.freedesktop.login1.Manager",
+                                          "CreateSession",
+                                          g_variant_new ("()", ""),
+                                          G_VARIANT_TYPE ("(so)"),
+                                          G_DBUS_CALL_FLAGS_NONE,
+                                          G_MAXINT,
+                                          NULL,
+                                          &error);
+    if (result)
+    {
+        gchar *e;
+        const gchar *id;
+
+        g_variant_get (result, "(&so)", &id, NULL);
+        e = g_strdup_printf ("XDG_SESSION_ID=%s", id);
+        pam_putenv (pamh, e);
+        g_free (e);
+        g_variant_unref (result);
+    }
+    else
+        g_printerr ("Failed to create logind session: %s\n", error->message);
+    g_clear_error (&error);
+
     return PAM_SUCCESS;
 }
 
@@ -1165,8 +1521,19 @@ pam_close_session (pam_handle_t *pamh, int flags)
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_close_session");
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
 
     return PAM_SUCCESS;
 }
@@ -1176,13 +1543,26 @@ pam_acct_mgmt (pam_handle_t *pamh, int flags)
 {
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
-  
+
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+        if (flags & PAM_DISALLOW_NULL_AUTHTOK)
+            g_string_append (status, " DISALLOW_NULL_AUTHTOK");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
     if (!pamh->user)
         return PAM_USER_UNKNOWN;
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_acct_mgmt");
-
     if (strcmp (pamh->user, "denied") == 0)
         return PAM_PERM_DENIED;
     if (strcmp (pamh->user, "expired") == 0)
@@ -1204,8 +1584,21 @@ pam_chauthtok (pam_handle_t *pamh, int flags)
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_chauthtok");
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+        if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
+            g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
 
     msg = malloc (sizeof (struct pam_message *) * 1);
     msg[0] = malloc (sizeof (struct pam_message));
@@ -1245,8 +1638,27 @@ pam_setcred (pam_handle_t *pamh, int flags)
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
 
-    if (strcmp (pamh->user, "log-pam") == 0)
-        send_info (pamh, "pam_setcred");
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s SETCRED", pamh->id);
+        if (flags & PAM_SILENT)
+            g_string_append (status, " SILENT");
+        if (flags & PAM_ESTABLISH_CRED)
+            g_string_append (status, " ESTABLISH_CRED");
+        if (flags & PAM_DELETE_CRED)
+            g_string_append (status, " DELETE_CRED");
+        if (flags & PAM_REINITIALIZE_CRED)
+            g_string_append (status, " REINITIALIZE_CRED");
+        if (flags & PAM_REFRESH_CRED)
+            g_string_append (status, " REFRESH_CRED");
+
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
 
     /* Put the test directories into the path */
     e = g_strdup_printf ("PATH=%s/tests/src/.libs:%s/tests/src:%s/tests/src:%s/src:%s", BUILDDIR, BUILDDIR, SRCDIR, BUILDDIR, pam_getenv (pamh, "PATH"));
@@ -1295,7 +1707,19 @@ pam_end (pam_handle_t *pamh, int pam_status)
 {
     if (pamh == NULL)
         return PAM_SYSTEM_ERR;
-  
+
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("");
+        g_string_append_printf (status, "%s END", pamh->id);
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
+    free (pamh->id);
     free (pamh->service_name);
     if (pamh->user)
         free (pamh->user);
@@ -1391,10 +1815,45 @@ void
 setutxent (void)
 {
 }
-  
+
 struct utmpx *
 pututxline (const struct utmpx *ut)
 {
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("UTMP");
+        switch (ut->ut_type)
+        {
+        case INIT_PROCESS:
+            g_string_append_printf (status, " TYPE=INIT_PROCESS");
+            break;
+        case LOGIN_PROCESS:
+            g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
+            break;
+        case USER_PROCESS:
+            g_string_append_printf (status, " TYPE=USER_PROCESS");
+            break;
+        case DEAD_PROCESS:
+            g_string_append_printf (status, " TYPE=DEAD_PROCESS");
+            break;
+        default:
+            g_string_append_printf (status, " TYPE=%d", ut->ut_type);
+        }
+        if (ut->ut_line)
+            g_string_append_printf (status, " LINE=%s", ut->ut_line);
+        if (ut->ut_id)
+            g_string_append_printf (status, " ID=%s", ut->ut_id);
+        if (ut->ut_user)
+            g_string_append_printf (status, " USER=%s", ut->ut_user);
+        if (ut->ut_host)
+            g_string_append_printf (status, " HOST=%s", ut->ut_host);
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+
     return (struct utmpx *)ut;
 }
 
@@ -1403,6 +1862,46 @@ endutxent (void)
 {
 }
 
+void
+updwtmp (const char *wtmp_file, const struct utmp *ut)
+{
+    connect_status ();
+    if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
+    {
+        GString *status;
+
+        status = g_string_new ("WTMP");
+        g_string_append_printf (status, " FILE=%s", wtmp_file);
+        switch (ut->ut_type)
+        {
+        case INIT_PROCESS:
+            g_string_append_printf (status, " TYPE=INIT_PROCESS");
+            break;
+        case LOGIN_PROCESS:
+            g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
+            break;
+        case USER_PROCESS:
+            g_string_append_printf (status, " TYPE=USER_PROCESS");
+            break;
+        case DEAD_PROCESS:
+            g_string_append_printf (status, " TYPE=DEAD_PROCESS");
+            break;
+        default:
+            g_string_append_printf (status, " TYPE=%d", ut->ut_type);
+        }
+        if (ut->ut_line)
+            g_string_append_printf (status, " LINE=%s", ut->ut_line);
+        if (ut->ut_id)
+            g_string_append_printf (status, " ID=%s", ut->ut_id);
+        if (ut->ut_user)
+            g_string_append_printf (status, " USER=%s", ut->ut_user);
+        if (ut->ut_host)
+            g_string_append_printf (status, " HOST=%s", ut->ut_host);
+        status_notify ("%s", status->str);
+        g_string_free (status, TRUE);
+    }
+}
+
 struct xcb_connection_t
 {
     gchar *display;
@@ -1416,7 +1915,7 @@ xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *aut
     xcb_connection_t *c;
     gchar *socket_path;
     GError *error = NULL;
-  
+
     c = malloc (sizeof (xcb_connection_t));
     c->display = g_strdup (display);
     c->error = 0;
@@ -1484,3 +1983,48 @@ xcb_disconnect (xcb_connection_t *c)
         g_object_unref (c->socket);
     free (c);
 }
+
+#if HAVE_LIBAUDIT
+int
+audit_open (void)
+{
+    connect_status ();  
+    if (g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
+        status_notify ("AUDIT OPEN");
+
+    return dup (STDOUT_FILENO);
+}
+
+int
+audit_log_acct_message (int audit_fd, int type, const char *pgname,
+                        const char *op, const char *name, unsigned int id,
+                        const char *host, const char *addr, const char *tty, int result)
+{
+    gchar *type_string;
+
+    connect_status ();  
+    if (!g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
+        return 1;
+
+    switch (type)
+    {
+    case AUDIT_USER_LOGIN:
+        type_string = g_strdup ("USER_LOGIN");
+        break;      
+    case AUDIT_USER_LOGOUT:
+        type_string = g_strdup ("USER_LOGOUT");
+        break;
+    default:
+        type_string = g_strdup_printf ("%d", type);
+        break;
+    }
+  
+    status_notify ("AUDIT LOG-ACCT TYPE=%s PGNAME=%s OP=%s NAME=%s ID=%u HOST=%s ADDR=%s TTY=%s RESULT=%d",
+                   type_string, pgname ? pgname : "", op ? op : "", name ? name : "", id, host ? host : "", addr ? addr : "", tty ? tty : "", result);
+
+    g_free (type_string);
+
+    return 1;
+}
+
+#endif