]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - tests/src/libsystem.c
Add shared data manager and test
[sojka/lightdm.git] / tests / src / libsystem.c
index 287835a79a0812e67e45b1da61dbcd7e9b25173e..b4db0c35310bba952b2c1b0c8a2e6402c1a165e0 100644 (file)
@@ -1,17 +1,29 @@
+#define _GNU_SOURCE
+#define __USE_GNU
+
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
 #include <pwd.h>
+#include <unistd.h>
+#include <dirent.h>
 #include <grp.h>
 #include <security/pam_appl.h>
 #include <fcntl.h>
-#define __USE_GNU
 #include <dlfcn.h>
+#include <utmpx.h>
 #ifdef __linux__
 #include <linux/vt.h>
 #endif
 #include <glib.h>
+#include <xcb/xcb.h>
+#include <gio/gunixsocketaddress.h>
+
+#include "status.h"
 
 #define LOGIN_PROMPT "login:"
 
@@ -22,6 +34,10 @@ static GList *getpwent_link = NULL;
 
 static GList *group_entries = NULL;
 
+static int active_vt = 7;
+
+static gboolean status_connected = FALSE;
+
 struct pam_handle
 {
     char *service_name;
@@ -142,13 +158,42 @@ setresuid (uid_t ruid, uid_t uuid, uid_t suid)
     return 0;
 }
 
+static gchar *
+redirect_path (const gchar *path)
+{
+    // Don't redirect if inside the running directory
+    if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
+        return g_strdup (path);
+
+    if (g_str_has_prefix (path, SYSCONFDIR))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
+
+    if (g_str_has_prefix (path, LOCALSTATEDIR))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
+
+    if (g_str_has_prefix (path, DATADIR))
+        return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
+
+    // Don't redirect if inside the build directory
+    if (g_str_has_prefix (path, BUILDDIR))
+        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_strdup (path);
+}
+
 #ifdef __linux__
 static int
 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
 {
-    int (*_open) (const char * pathname, int flags, mode_t mode);
+    int (*_open) (const char *pathname, int flags, mode_t mode);
+    gchar *new_path = NULL;
+    int fd;
+
+    _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
 
-    _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
     if (strcmp (pathname, "/dev/console") == 0)
     {
         if (console_fd < 0)
@@ -158,19 +203,12 @@ open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
         }
         return console_fd;
     }
-    else if (strcmp (pathname, CONFIG_DIR "/lightdm.conf") == 0)
-    {
-        gchar *path;
-        int fd;
 
-        path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "lightdm", "lightdm.conf", NULL);
-        fd = _open (path, flags, mode);
-        g_free (path);
+    new_path = redirect_path (pathname);
+    fd = _open (new_path, flags, mode);
+    g_free (new_path);
 
-        return fd;
-    }
-    else
-        return _open (pathname, flags, mode);
+    return fd;
 }
 
 int
@@ -181,7 +219,7 @@ open (const char *pathname, int flags, ...)
     {
         va_list ap;
         va_start (ap, flags);
-        mode = va_arg (ap, int);
+        mode = va_arg (ap, mode_t);
         va_end (ap);
     }
     return open_wrapper ("open", pathname, flags, mode);
@@ -195,35 +233,303 @@ open64 (const char *pathname, int flags, ...)
     {
         va_list ap;
         va_start (ap, flags);
-        mode = va_arg (ap, int);
+        mode = va_arg (ap, mode_t);
         va_end (ap);
     }
     return open_wrapper ("open64", pathname, flags, mode);
 }
 
+FILE *
+fopen (const char *path, const char *mode)
+{
+    FILE *(*_fopen) (const char *pathname, const char *mode);
+    gchar *new_path = NULL;
+    FILE *result;
+
+    _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
+
+    new_path = redirect_path (path);
+    result = _fopen (new_path, mode);
+    g_free (new_path);
+
+    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)
+{
+    int (*_creat) (const char *pathname, mode_t mode);
+    gchar *new_path = NULL;
+    int result;
+
+    _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
+
+    new_path = redirect_path (pathname);
+    result = _creat (new_path, mode);
+    g_free (new_path);
+
+    return result;
+}
+
+int
+creat64 (const char *pathname, mode_t mode)
+{
+    int (*_creat64) (const char *pathname, mode_t mode);
+    gchar *new_path = NULL;
+    int result;
+
+    _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
+
+    new_path = redirect_path (pathname);
+    result = _creat64 (new_path, mode);
+    g_free (new_path);
+
+    return result;
+}
+
+int
+access (const char *pathname, int mode)
+{
+    int (*_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");
+
+    new_path = redirect_path (pathname);
+    ret = _access (new_path, mode);
+    g_free (new_path);
+
+    return ret;
+}
+
+int
+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);
+    ret = _stat (new_path, buf);
+    g_free (new_path);
+
+    return ret;
+}
+
+int
+stat64 (const char *path, struct stat64 *buf)
+{
+    int (*_stat64) (const char *path, struct stat64 *buf);
+    gchar *new_path = NULL;
+    int ret;
+
+    _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
+
+    new_path = redirect_path (path);
+    ret = _stat64 (new_path, buf);
+    g_free (new_path);
+
+    return ret;
+}
+
+int
+__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);
+    ret = ___xstat (version, new_path, buf);
+    g_free (new_path);
+
+    return ret;
+}
+
+int
+__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);
+    ret = ___xstat64 (version, new_path, buf);
+    g_free (new_path);
+
+    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)
+{
+    DIR *(*_opendir) (const char *name);
+    gchar *new_path = NULL;
+    DIR *result;
+
+    _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
+
+    new_path = redirect_path (name);
+    result = _opendir (new_path);
+    g_free (new_path);
+
+    return result; 
+}
+
+int
+mkdir (const char *pathname, mode_t mode)
+{
+    int (*_mkdir) (const char *pathname, mode_t mode);
+    gchar *new_path = NULL;
+    int result;
+
+    _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
+
+    new_path = redirect_path (pathname);
+    result = _mkdir (new_path, mode);
+    g_free (new_path);
+
+    return result;
+}
+
+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;
+}
+
+int
+chmod (const char *path, mode_t mode)
+{
+    int (*_chmod) (const char *path, mode_t mode);
+    gchar *new_path = NULL;
+    int result;
+
+    _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
+
+    new_path = redirect_path (path);
+    result = _chmod (new_path, mode);
+    g_free (new_path);
+
+    return result;
+}
+
 int
-ioctl (int d, int request, void *data)
+ioctl (int d, unsigned long request, ...)
 {
-    int (*_ioctl) (int d, int request, void *data);
+    int (*_ioctl) (int d, int request, ...);
 
-    _ioctl = (int (*)(int d, int request, void *data)) dlsym (RTLD_NEXT, "ioctl");
+    _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
     if (d > 0 && d == console_fd)
     {
         struct vt_stat *console_state;
+        int vt;
+        va_list ap;
 
         switch (request)
         {
         case VT_GETSTATE:
-            console_state = data;
-            console_state->v_active = 7;
-            break;          
+            va_start (ap, request);
+            console_state = va_arg (ap, struct vt_stat *);
+            va_end (ap);
+            console_state->v_active = active_vt;
+            break;
         case VT_ACTIVATE:
+            va_start (ap, request);
+            vt = va_arg (ap, int);
+            va_end (ap);
+            if (vt != active_vt)
+            {
+                active_vt = vt;
+                if (!status_connected)
+                    status_connected = status_connect (NULL);
+                status_notify ("VT ACTIVATE VT=%d", active_vt);
+            }
+            break;
+        case VT_WAITACTIVE:
             break;
         }
         return 0;
     }
     else
+    {
+        va_list ap;
+        void *data;
+
+        va_start (ap, request);
+        data = va_arg (ap, void *);
+        va_end (ap);
         return _ioctl (d, request, data);
+    }
 }
 
 int
@@ -253,7 +559,7 @@ free_user (gpointer data)
 }
 
 static void
-load_passwd_file ()
+load_passwd_file (void)
 {
     gchar *path, *data = NULL, **lines;
     gint i;
@@ -385,7 +691,7 @@ free_group (gpointer data)
 }
 
 static void
-load_group_file ()
+load_group_file (void)
 {
     gchar *path, *data = NULL, **lines;
     gint i;
@@ -748,9 +1054,9 @@ static const char *
 get_env_value (const char *name_value, const char *name)
 {
     int j;
-
-    for (j = 0; name[j] && name[j] != '=' && name[j] == name_value[j]; j++);
-    if (name_value[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];
 
     return NULL;
@@ -760,15 +1066,21 @@ int
 pam_putenv (pam_handle_t *pamh, const char *name_value)
 {
     int i;
+    gchar *name;
 
     if (pamh == NULL || name_value == NULL)
         return PAM_SYSTEM_ERR;
 
+    name = strdup (name_value);
+    for (i = 0; name[i]; i++)
+        if (name[i] == '=')
+            name[i] = '\0';
     for (i = 0; pamh->envlist[i]; i++)
     {
-        if (get_env_value (pamh->envlist[i], name_value))
+        if (get_env_value (pamh->envlist[i], name))
             break;
     }
+    free (name);
 
     if (pamh->envlist[i])
     {
@@ -946,7 +1258,10 @@ pam_chauthtok (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_OFF;
-    msg[0]->msg = "Enter new password:";
+    if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
+        msg[0]->msg = "Enter new password (expired):";
+    else
+        msg[0]->msg = "Enter new password:";
     result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
     free (msg[0]);
     free (msg);
@@ -1004,8 +1319,12 @@ pam_setcred (pam_handle_t *pamh, int flags)
         if (group)
         {
             groups_length = getgroups (0, NULL);
+            if (groups_length < 0)
+                return PAM_SYSTEM_ERR;
             groups = malloc (sizeof (gid_t) * (groups_length + 1));
             groups_length = getgroups (groups_length, groups);
+            if (groups_length < 0)
+                return PAM_SYSTEM_ERR;
             groups[groups_length] = group->gr_gid;
             groups_length++;
             setgroups (groups_length, groups);
@@ -1121,13 +1440,95 @@ setutxent (void)
 {
 }
   
-struct utmp *
-pututxline (struct utmp *ut)
+struct utmpx *
+pututxline (const struct utmpx *ut)
 {
-    return ut;
+    return (struct utmpx *)ut;
 }
 
 void
 endutxent (void)
 {
 }
+
+struct xcb_connection_t
+{
+    gchar *display;
+    int error;
+    GSocket *socket;
+};
+
+xcb_connection_t *
+xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
+{
+    xcb_connection_t *c;
+    gchar *socket_path;
+    GError *error = NULL;
+  
+    c = malloc (sizeof (xcb_connection_t));
+    c->display = g_strdup (display);
+    c->error = 0;
+
+    if (display == NULL)
+        display = getenv ("DISPLAY");
+    if (display == NULL)
+        c->error = XCB_CONN_CLOSED_PARSE_ERR;
+
+    if (c->error == 0)
+    {
+        c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
+        if (error)
+            g_printerr ("%s\n", error->message);
+        g_clear_error (&error);
+        if (c->socket == NULL)
+            c->error = XCB_CONN_ERROR;
+    }
+
+    if (c->error == 0)
+    {
+        gchar *d;
+        GSocketAddress *address;
+
+        /* Skip the hostname, we'll assume it's localhost */
+        d = g_strdup_printf (".x%s", strchr (display, ':'));
+
+        socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
+        g_free (d);
+        address = g_unix_socket_address_new (socket_path);
+        if (!g_socket_connect (c->socket, address, NULL, &error))
+            c->error = XCB_CONN_ERROR;
+        g_object_unref (address);
+        if (error)
+            g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
+        g_free (socket_path);
+        g_clear_error (&error);
+    }
+
+    // FIXME: Send auth info
+    if (c->error == 0)
+    {
+    }
+
+    return c;
+}
+
+xcb_connection_t *
+xcb_connect (const char *displayname, int *screenp)
+{
+    return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
+}
+
+int
+xcb_connection_has_error (xcb_connection_t *c)
+{
+    return c->error;
+}
+
+void
+xcb_disconnect (xcb_connection_t *c)
+{
+    free (c->display);
+    if (c->socket)
+        g_object_unref (c->socket);
+    free (c);
+}