10 #include <sys/types.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
19 #include <security/pam_appl.h>
29 #include <gio/gunixsocketaddress.h>
37 #define LOGIN_PROMPT "login:"
39 static int console_fd = -1;
41 static GList *user_entries = NULL;
42 static GList *getpwent_link = NULL;
44 static GList *group_entries = NULL;
46 static int active_vt = 7;
48 static gboolean status_connected = FALSE;
49 static GKeyFile *config;
51 static void connect_status (void)
55 status_connected = TRUE;
57 status_connect (NULL, NULL);
59 config = g_key_file_new ();
60 g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
72 struct pam_conv conversation;
88 initgroups (const char *user, gid_t group)
99 getgroups (int size, gid_t list[])
101 const gchar *group_list;
105 /* Get groups we are a member of */
106 group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
109 groups = g_strsplit (group_list, ",", -1);
110 groups_length = g_strv_length (groups);
116 if (groups_length > size)
121 for (i = 0; groups[i]; i++)
122 list[i] = atoi (groups[i]);
126 return groups_length;
130 setgroups (size_t size, const gid_t *list)
135 group_list = g_string_new ("");
136 for (i = 0; i < size; i++)
139 g_string_append (group_list, ",");
140 g_string_append_printf (group_list, "%d", list[i]);
142 g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
143 g_string_free (group_list, TRUE);
161 setresgid (gid_t rgid, gid_t ugid, gid_t sgid)
179 setresuid (uid_t ruid, uid_t uuid, uid_t suid)
185 redirect_path (const gchar *path)
187 /* Hide Xmir for legacy tests */
188 if (g_str_has_suffix (path, "/Xmir"))
191 if (g_key_file_get_boolean (config, "test-xmir", "hide", NULL))
195 // Don't redirect if inside the running directory
196 if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
197 return g_strdup (path);
199 if (g_str_has_prefix (path, SYSCONFDIR))
200 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
202 if (g_str_has_prefix (path, LOCALSTATEDIR))
203 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
205 if (g_str_has_prefix (path, DATADIR))
206 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
208 // Don't redirect if inside the build directory
209 if (g_str_has_prefix (path, BUILDDIR))
210 return g_strdup (path);
212 if (g_str_has_prefix (path, "/tmp"))
213 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
215 if (g_str_has_prefix (path, "/run"))
216 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "run", path + strlen ("/run"), NULL);
218 if (g_str_has_prefix (path, "/etc/xdg"))
219 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
221 if (g_str_has_prefix (path, "/usr/share/lightdm"))
222 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
224 return g_strdup (path);
229 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
231 int (*_open) (const char *pathname, int flags, mode_t mode);
232 gchar *new_path = NULL;
235 _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
237 if (strcmp (pathname, "/dev/console") == 0)
241 console_fd = _open ("/dev/null", flags, mode);
242 fcntl (console_fd, F_SETFD, FD_CLOEXEC);
247 new_path = redirect_path (pathname);
248 fd = _open (new_path, flags, mode);
255 open (const char *pathname, int flags, ...)
261 va_start (ap, flags);
262 mode = va_arg (ap, mode_t);
265 return open_wrapper ("open", pathname, flags, mode);
269 open64 (const char *pathname, int flags, ...)
275 va_start (ap, flags);
276 mode = va_arg (ap, mode_t);
279 return open_wrapper ("open64", pathname, flags, mode);
283 fopen (const char *path, const char *mode)
285 FILE *(*_fopen) (const char *pathname, const char *mode);
286 gchar *new_path = NULL;
289 _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
291 new_path = redirect_path (path);
292 result = _fopen (new_path, mode);
299 unlinkat (int dirfd, const char *pathname, int flags)
301 int (*_unlinkat) (int dirfd, const char *pathname, int flags);
302 gchar *new_path = NULL;
305 _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
307 new_path = redirect_path (pathname);
308 result = _unlinkat (dirfd, new_path, flags);
315 creat (const char *pathname, mode_t mode)
317 int (*_creat) (const char *pathname, mode_t mode);
318 gchar *new_path = NULL;
321 _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
323 new_path = redirect_path (pathname);
324 result = _creat (new_path, mode);
331 creat64 (const char *pathname, mode_t mode)
333 int (*_creat64) (const char *pathname, mode_t mode);
334 gchar *new_path = NULL;
337 _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
339 new_path = redirect_path (pathname);
340 result = _creat64 (new_path, mode);
347 access (const char *pathname, int mode)
349 int (*_access) (const char *pathname, int mode);
350 gchar *new_path = NULL;
353 _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
355 if (strcmp (pathname, "/dev/tty0") == 0)
357 if (strcmp (pathname, "/sys/class/tty/tty0/active") == 0)
360 new_path = redirect_path (pathname);
361 ret = _access (new_path, mode);
368 stat (const char *path, struct stat *buf)
370 int (*_stat) (const char *path, struct stat *buf);
371 gchar *new_path = NULL;
374 _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
376 new_path = redirect_path (path);
377 ret = _stat (new_path, buf);
384 stat64 (const char *path, struct stat64 *buf)
386 int (*_stat64) (const char *path, struct stat64 *buf);
387 gchar *new_path = NULL;
390 _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
392 new_path = redirect_path (path);
393 ret = _stat64 (new_path, buf);
400 __xstat (int version, const char *path, struct stat *buf)
402 int (*___xstat) (int version, const char *path, struct stat *buf);
403 gchar *new_path = NULL;
406 ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
408 new_path = redirect_path (path);
409 ret = ___xstat (version, new_path, buf);
416 __xstat64 (int version, const char *path, struct stat64 *buf)
418 int (*___xstat64) (int version, const char *path, struct stat64 *buf);
419 gchar *new_path = NULL;
422 ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
424 new_path = redirect_path (path);
425 ret = ___xstat64 (version, new_path, buf);
432 __fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
434 int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
435 gchar *new_path = NULL;
438 ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
440 new_path = redirect_path (pathname);
441 ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
448 __fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
450 int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
451 gchar *new_path = NULL;
454 ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
456 new_path = redirect_path (pathname);
457 ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
464 opendir (const char *name)
466 DIR *(*_opendir) (const char *name);
467 gchar *new_path = NULL;
470 _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
472 new_path = redirect_path (name);
473 result = _opendir (new_path);
480 mkdir (const char *pathname, mode_t mode)
482 int (*_mkdir) (const char *pathname, mode_t mode);
483 gchar *new_path = NULL;
486 _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
488 new_path = redirect_path (pathname);
489 result = _mkdir (new_path, mode);
496 chown (const char *pathname, uid_t owner, gid_t group)
498 /* Just fake it - we're not root */
503 chmod (const char *path, mode_t mode)
505 int (*_chmod) (const char *path, mode_t mode);
506 gchar *new_path = NULL;
509 _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
511 new_path = redirect_path (path);
512 result = _chmod (new_path, mode);
519 ioctl (int d, unsigned long request, ...)
521 int (*_ioctl) (int d, int request, ...);
523 _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
524 if (d > 0 && d == console_fd)
526 struct vt_stat *console_state;
533 va_start (ap, request);
534 console_state = va_arg (ap, struct vt_stat *);
536 console_state->v_active = active_vt;
539 va_start (ap, request);
540 vt = va_arg (ap, int);
546 status_notify ("VT ACTIVATE VT=%d", active_vt);
559 va_start (ap, request);
560 data = va_arg (ap, void *);
562 return _ioctl (d, request, data);
567 add_port_redirect (int requested_port, int redirected_port)
570 gchar *path, *name, *data;
572 file = g_key_file_new ();
573 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
574 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
576 name = g_strdup_printf ("%d", requested_port);
577 g_key_file_set_integer (file, name, "redirected", redirected_port);
580 data = g_key_file_to_data (file, NULL, NULL);
581 g_file_set_contents (path, data, -1, NULL);
585 g_key_file_free (file);
589 find_port_redirect (int port)
595 file = g_key_file_new ();
596 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
597 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
600 name = g_strdup_printf ("%d", port);
601 redirected_port = g_key_file_get_integer (file, name, "redirected", NULL);
603 g_key_file_free (file);
605 return redirected_port;
609 bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
611 int port = 0, redirected_port = 0;
612 int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
613 const struct sockaddr *modified_addr = addr;
614 struct sockaddr_in temp_addr;
615 struct sockaddr_in6 temp_addr6;
618 _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
620 switch (addr->sa_family)
623 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
624 redirected_port = find_port_redirect (port);
625 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
626 modified_addr = (struct sockaddr *) &temp_addr;
627 if (redirected_port != 0)
628 temp_addr.sin_port = htons (redirected_port);
630 temp_addr.sin_port = 0;
633 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
634 redirected_port = find_port_redirect (port);
635 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
636 modified_addr = (struct sockaddr *) &temp_addr6;
637 if (redirected_port != 0)
638 temp_addr6.sin6_port = htons (redirected_port);
640 temp_addr6.sin6_port = 0;
644 retval = _bind (sockfd, modified_addr, addrlen);
646 socklen_t temp_addr_len;
647 switch (addr->sa_family)
650 temp_addr_len = sizeof (temp_addr);
651 getsockname (sockfd, &temp_addr, &temp_addr_len);
652 if (redirected_port == 0)
654 redirected_port = ntohs (temp_addr.sin_port);
655 add_port_redirect (port, redirected_port);
659 temp_addr_len = sizeof (temp_addr6);
660 getsockname (sockfd, &temp_addr6, &temp_addr_len);
661 if (redirected_port == 0)
663 redirected_port = ntohs (temp_addr6.sin6_port);
664 add_port_redirect (port, redirected_port);
673 connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
675 int port, redirected_port;
676 const struct sockaddr *modified_addr = addr;
677 struct sockaddr_in temp_addr;
678 struct sockaddr_in6 temp_addr6;
679 int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
681 _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
683 switch (addr->sa_family)
686 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
687 redirected_port = find_port_redirect (port);
688 if (redirected_port != 0)
690 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
691 temp_addr.sin_port = htons (redirected_port);
692 modified_addr = (struct sockaddr *) &temp_addr;
696 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
697 redirected_port = find_port_redirect (port);
698 if (redirected_port != 0)
700 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
701 temp_addr6.sin6_port = htons (redirected_port);
702 modified_addr = (struct sockaddr *) &temp_addr6;
707 return _connect (sockfd, modified_addr, addrlen);
711 sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
713 int port, redirected_port;
714 const struct sockaddr *modified_addr = dest_addr;
715 struct sockaddr_in temp_addr;
716 struct sockaddr_in6 temp_addr6;
717 ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
719 _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");
721 switch (dest_addr->sa_family)
724 port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
725 redirected_port = find_port_redirect (port);
726 if (redirected_port != 0)
728 memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in));
729 temp_addr.sin_port = htons (redirected_port);
730 modified_addr = (struct sockaddr *) &temp_addr;
734 port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port);
735 redirected_port = find_port_redirect (port);
736 if (redirected_port != 0)
738 memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6));
739 temp_addr6.sin6_port = htons (redirected_port);
740 modified_addr = (struct sockaddr *) &temp_addr6;
745 return _sendto (sockfd, buf, len, flags, modified_addr, addrlen);
751 int (*_close) (int fd);
753 if (fd > 0 && fd == console_fd)
756 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
762 free_user (gpointer data)
764 struct passwd *entry = data;
766 g_free (entry->pw_name);
767 g_free (entry->pw_passwd);
768 g_free (entry->pw_gecos);
769 g_free (entry->pw_dir);
770 g_free (entry->pw_shell);
775 load_passwd_file (void)
777 gchar *path, *data = NULL, **lines;
779 GError *error = NULL;
781 g_list_free_full (user_entries, free_user);
783 getpwent_link = NULL;
785 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
786 g_file_get_contents (path, &data, NULL, &error);
789 g_warning ("Error loading passwd file: %s", error->message);
790 g_clear_error (&error);
795 lines = g_strsplit (data, "\n", -1);
798 for (i = 0; lines[i]; i++)
800 gchar *line, **fields;
802 line = g_strstrip (lines[i]);
803 fields = g_strsplit (line, ":", -1);
804 if (g_strv_length (fields) == 7)
806 struct passwd *entry = malloc (sizeof (struct passwd));
808 entry->pw_name = g_strdup (fields[0]);
809 entry->pw_passwd = g_strdup (fields[1]);
810 entry->pw_uid = atoi (fields[2]);
811 entry->pw_gid = atoi (fields[3]);
812 entry->pw_gecos = g_strdup (fields[4]);
813 entry->pw_dir = g_strdup (fields[5]);
814 entry->pw_shell = g_strdup (fields[6]);
815 user_entries = g_list_append (user_entries, entry);
825 if (getpwent_link == NULL)
828 if (user_entries == NULL)
830 getpwent_link = user_entries;
834 if (getpwent_link->next == NULL)
836 getpwent_link = getpwent_link->next;
839 return getpwent_link->data;
845 getpwent_link = NULL;
851 getpwent_link = NULL;
855 getpwnam (const char *name)
864 for (link = user_entries; link; link = link->next)
866 struct passwd *entry = link->data;
867 if (strcmp (entry->pw_name, name) == 0)
883 for (link = user_entries; link; link = link->next)
885 struct passwd *entry = link->data;
886 if (entry->pw_uid == uid)
896 free_group (gpointer data)
898 struct group *entry = data;
900 g_free (entry->gr_name);
901 g_free (entry->gr_passwd);
902 g_strfreev (entry->gr_mem);
907 load_group_file (void)
909 gchar *path, *data = NULL, **lines;
911 GError *error = NULL;
913 g_list_free_full (group_entries, free_group);
914 group_entries = NULL;
916 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
917 g_file_get_contents (path, &data, NULL, &error);
920 g_warning ("Error loading group file: %s", error->message);
921 g_clear_error (&error);
926 lines = g_strsplit (data, "\n", -1);
929 for (i = 0; lines[i]; i++)
931 gchar *line, **fields;
933 line = g_strstrip (lines[i]);
934 fields = g_strsplit (line, ":", -1);
935 if (g_strv_length (fields) == 4)
937 struct group *entry = malloc (sizeof (struct group));
939 entry->gr_name = g_strdup (fields[0]);
940 entry->gr_passwd = g_strdup (fields[1]);
941 entry->gr_gid = atoi (fields[2]);
942 entry->gr_mem = g_strsplit (fields[3], ",", -1);
943 group_entries = g_list_append (group_entries, entry);
951 getgrnam (const char *name)
957 for (link = group_entries; link; link = link->next)
959 struct group *entry = link->data;
960 if (strcmp (entry->gr_name, name) == 0)
976 for (link = group_entries; link; link = link->next)
978 struct group *entry = link->data;
979 if (entry->gr_gid == gid)
989 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
991 pam_handle_t *handle;
993 if (service_name == NULL || conversation == NULL || pamh == NULL)
994 return PAM_SYSTEM_ERR;
996 handle = *pamh = malloc (sizeof (pam_handle_t));
1001 handle->id = g_strdup_printf ("PAM-%s", user);
1003 handle->id = g_strdup ("PAM");
1006 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1010 status = g_string_new ("");
1011 g_string_append_printf (status, "%s START", handle->id);
1012 g_string_append_printf (status, " SERVICE=%s", service_name);
1014 g_string_append_printf (status, " USER=%s", user);
1015 status_notify ("%s", status->str);
1016 g_string_free (status, TRUE);
1019 handle->service_name = strdup (service_name);
1020 handle->user = user ? strdup (user) : NULL;
1021 handle->authtok = NULL;
1022 handle->ruser = NULL;
1024 handle->conversation.conv = conversation->conv;
1025 handle->conversation.appdata_ptr = conversation->appdata_ptr;
1026 handle->envlist = malloc (sizeof (char *) * 1);
1027 handle->envlist[0] = NULL;
1033 pam_authenticate (pam_handle_t *pamh, int flags)
1035 struct passwd *entry;
1036 gboolean password_matches = FALSE;
1039 return PAM_SYSTEM_ERR;
1042 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1046 status = g_string_new ("");
1047 g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
1048 if (flags & PAM_SILENT)
1049 g_string_append (status, " SILENT");
1050 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1051 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1053 status_notify ("%s", status->str);
1054 g_string_free (status, TRUE);
1057 if (strcmp (pamh->service_name, "test-remote") == 0)
1060 struct pam_message **msg;
1061 struct pam_response *resp = NULL;
1063 msg = malloc (sizeof (struct pam_message *) * 1);
1064 msg[0] = malloc (sizeof (struct pam_message));
1065 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1066 msg[0]->msg = "remote-login:";
1067 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1070 if (result != PAM_SUCCESS)
1074 return PAM_CONV_ERR;
1075 if (resp[0].resp == NULL)
1078 return PAM_CONV_ERR;
1083 pamh->ruser = strdup (resp[0].resp);
1084 free (resp[0].resp);
1087 msg = malloc (sizeof (struct pam_message *) * 1);
1088 msg[0] = malloc (sizeof (struct pam_message));
1089 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1090 msg[0]->msg = "remote-password:";
1091 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1094 if (result != PAM_SUCCESS)
1098 return PAM_CONV_ERR;
1099 if (resp[0].resp == NULL)
1102 return PAM_CONV_ERR;
1106 free (pamh->authtok);
1107 pamh->authtok = strdup (resp[0].resp);
1108 free (resp[0].resp);
1111 password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
1113 if (password_matches)
1116 return PAM_AUTH_ERR;
1119 /* Prompt for username */
1120 if (pamh->user == NULL)
1123 struct pam_message **msg;
1124 struct pam_response *resp = NULL;
1126 msg = malloc (sizeof (struct pam_message *) * 1);
1127 msg[0] = malloc (sizeof (struct pam_message));
1128 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1129 msg[0]->msg = LOGIN_PROMPT;
1130 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1133 if (result != PAM_SUCCESS)
1137 return PAM_CONV_ERR;
1138 if (resp[0].resp == NULL)
1141 return PAM_CONV_ERR;
1144 pamh->user = strdup (resp[0].resp);
1145 free (resp[0].resp);
1149 /* Crash on authenticate */
1150 if (strcmp (pamh->user, "crash-authenticate") == 0)
1151 kill (getpid (), SIGSEGV);
1153 /* Look up password database */
1154 entry = getpwnam (pamh->user);
1156 /* Prompt for password if required */
1157 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
1158 password_matches = TRUE;
1161 int i, n_messages = 0, password_index, result;
1162 struct pam_message **msg;
1163 struct pam_response *resp = NULL;
1165 msg = malloc (sizeof (struct pam_message *) * 5);
1166 if (strcmp (pamh->user, "info-prompt") == 0)
1168 msg[n_messages] = malloc (sizeof (struct pam_message));
1169 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1170 msg[n_messages]->msg = "Welcome to LightDM";
1173 if (strcmp (pamh->user, "multi-info-prompt") == 0)
1175 msg[n_messages] = malloc (sizeof (struct pam_message));
1176 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1177 msg[n_messages]->msg = "Welcome to LightDM";
1179 msg[n_messages] = malloc (sizeof (struct pam_message));
1180 msg[n_messages]->msg_style = PAM_ERROR_MSG;
1181 msg[n_messages]->msg = "This is an error";
1183 msg[n_messages] = malloc (sizeof (struct pam_message));
1184 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1185 msg[n_messages]->msg = "You should have seen three messages";
1188 if (strcmp (pamh->user, "multi-prompt") == 0)
1190 msg[n_messages] = malloc (sizeof (struct pam_message));
1191 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
1192 msg[n_messages]->msg = "Favorite Color:";
1195 msg[n_messages] = malloc (sizeof (struct pam_message));
1196 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
1197 msg[n_messages]->msg = "Password:";
1198 password_index = n_messages;
1200 result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1201 for (i = 0; i < n_messages; i++)
1204 if (result != PAM_SUCCESS)
1208 return PAM_CONV_ERR;
1209 if (resp[password_index].resp == NULL)
1212 return PAM_CONV_ERR;
1216 password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
1218 if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
1219 password_matches = strcmp ("blue", resp[0].resp) == 0;
1221 for (i = 0; i < n_messages; i++)
1224 free (resp[i].resp);
1228 /* Do two factor authentication */
1229 if (password_matches && strcmp (pamh->user, "two-factor") == 0)
1231 msg = malloc (sizeof (struct pam_message *) * 1);
1232 msg[0] = malloc (sizeof (struct pam_message));
1233 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1234 msg[0]->msg = "OTP:";
1236 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1239 if (result != PAM_SUCCESS)
1243 return PAM_CONV_ERR;
1244 if (resp[0].resp == NULL)
1247 return PAM_CONV_ERR;
1249 password_matches = strcmp (resp[0].resp, "otp") == 0;
1250 free (resp[0].resp);
1255 /* Special user has home directory created on login */
1256 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
1257 g_mkdir_with_parents (entry->pw_dir, 0755);
1259 /* Special user 'change-user1' changes user on authentication */
1260 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
1262 g_free (pamh->user);
1263 pamh->user = g_strdup ("change-user2");
1266 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
1267 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
1269 g_free (pamh->user);
1270 pamh->user = g_strdup ("invalid-user");
1273 if (password_matches)
1276 return PAM_AUTH_ERR;
1280 get_env_value (const char *name_value, const char *name)
1284 for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
1285 if (name[j] == '\0' && name_value[j] == '=')
1286 return &name_value[j + 1];
1292 pam_putenv (pam_handle_t *pamh, const char *name_value)
1297 if (pamh == NULL || name_value == NULL)
1298 return PAM_SYSTEM_ERR;
1300 name = strdup (name_value);
1301 for (i = 0; name[i]; i++)
1304 for (i = 0; pamh->envlist[i]; i++)
1306 if (get_env_value (pamh->envlist[i], name))
1311 if (pamh->envlist[i])
1313 free (pamh->envlist[i]);
1314 pamh->envlist[i] = strdup (name_value);
1318 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
1319 pamh->envlist[i] = strdup (name_value);
1320 pamh->envlist[i + 1] = NULL;
1327 pam_getenv (pam_handle_t *pamh, const char *name)
1331 if (pamh == NULL || name == NULL)
1334 for (i = 0; pamh->envlist[i]; i++)
1337 value = get_env_value (pamh->envlist[i], name);
1346 pam_getenvlist (pam_handle_t *pamh)
1351 return pamh->envlist;
1355 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
1357 if (pamh == NULL || item == NULL)
1358 return PAM_SYSTEM_ERR;
1365 pamh->tty = strdup ((const char *) item);
1369 return PAM_BAD_ITEM;
1374 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
1376 if (pamh == NULL || item == NULL)
1377 return PAM_SYSTEM_ERR;
1382 *item = pamh->service_name;
1390 *item = pamh->authtok;
1394 *item = pamh->ruser;
1397 case PAM_USER_PROMPT:
1398 *item = LOGIN_PROMPT;
1406 *item = &pamh->conversation;
1410 return PAM_BAD_ITEM;
1415 pam_open_session (pam_handle_t *pamh, int flags)
1418 GError *error = NULL;
1421 return PAM_SYSTEM_ERR;
1424 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1428 status = g_string_new ("");
1429 g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1430 if (flags & PAM_SILENT)
1431 g_string_append (status, " SILENT");
1433 status_notify ("%s", status->str);
1434 g_string_free (status, TRUE);
1437 if (strcmp (pamh->user, "session-error") == 0)
1438 return PAM_SESSION_ERR;
1440 if (strcmp (pamh->user, "make-home-dir") == 0)
1442 struct passwd *entry;
1443 entry = getpwnam (pamh->user);
1444 g_mkdir_with_parents (entry->pw_dir, 0755);
1447 /* Open logind session */
1448 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
1449 "org.freedesktop.login1",
1450 "/org/freedesktop/login1",
1451 "org.freedesktop.login1.Manager",
1453 g_variant_new ("()", ""),
1454 G_VARIANT_TYPE ("(so)"),
1455 G_DBUS_CALL_FLAGS_NONE,
1464 g_variant_get (result, "(&so)", &id, NULL);
1465 e = g_strdup_printf ("XDG_SESSION_ID=%s", id);
1466 pam_putenv (pamh, e);
1468 g_variant_unref (result);
1471 g_printerr ("Failed to create logind session: %s\n", error->message);
1472 g_clear_error (&error);
1478 pam_close_session (pam_handle_t *pamh, int flags)
1481 return PAM_SYSTEM_ERR;
1484 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1488 status = g_string_new ("");
1489 g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1490 if (flags & PAM_SILENT)
1491 g_string_append (status, " SILENT");
1493 status_notify ("%s", status->str);
1494 g_string_free (status, TRUE);
1501 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1504 return PAM_SYSTEM_ERR;
1507 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1511 status = g_string_new ("");
1512 g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1513 if (flags & PAM_SILENT)
1514 g_string_append (status, " SILENT");
1515 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1516 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1518 status_notify ("%s", status->str);
1519 g_string_free (status, TRUE);
1523 return PAM_USER_UNKNOWN;
1525 if (strcmp (pamh->user, "denied") == 0)
1526 return PAM_PERM_DENIED;
1527 if (strcmp (pamh->user, "expired") == 0)
1528 return PAM_ACCT_EXPIRED;
1529 if (strcmp (pamh->user, "new-authtok") == 0)
1530 return PAM_NEW_AUTHTOK_REQD;
1536 pam_chauthtok (pam_handle_t *pamh, int flags)
1538 struct passwd *entry;
1540 struct pam_message **msg;
1541 struct pam_response *resp = NULL;
1544 return PAM_SYSTEM_ERR;
1547 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1551 status = g_string_new ("");
1552 g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1553 if (flags & PAM_SILENT)
1554 g_string_append (status, " SILENT");
1555 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1556 g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1558 status_notify ("%s", status->str);
1559 g_string_free (status, TRUE);
1562 msg = malloc (sizeof (struct pam_message *) * 1);
1563 msg[0] = malloc (sizeof (struct pam_message));
1564 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1565 if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1566 msg[0]->msg = "Enter new password (expired):";
1568 msg[0]->msg = "Enter new password:";
1569 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1572 if (result != PAM_SUCCESS)
1576 return PAM_CONV_ERR;
1577 if (resp[0].resp == NULL)
1580 return PAM_CONV_ERR;
1583 /* Update password database */
1584 entry = getpwnam (pamh->user);
1585 free (entry->pw_passwd);
1586 entry->pw_passwd = resp[0].resp;
1593 pam_setcred (pam_handle_t *pamh, int flags)
1598 return PAM_SYSTEM_ERR;
1601 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1605 status = g_string_new ("");
1606 g_string_append_printf (status, "%s SETCRED", pamh->id);
1607 if (flags & PAM_SILENT)
1608 g_string_append (status, " SILENT");
1609 if (flags & PAM_ESTABLISH_CRED)
1610 g_string_append (status, " ESTABLISH_CRED");
1611 if (flags & PAM_DELETE_CRED)
1612 g_string_append (status, " DELETE_CRED");
1613 if (flags & PAM_REINITIALIZE_CRED)
1614 g_string_append (status, " REINITIALIZE_CRED");
1615 if (flags & PAM_REFRESH_CRED)
1616 g_string_append (status, " REFRESH_CRED");
1618 status_notify ("%s", status->str);
1619 g_string_free (status, TRUE);
1622 /* Put the test directories into the path */
1623 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"));
1624 pam_putenv (pamh, e);
1627 if (strcmp (pamh->user, "cred-error") == 0)
1628 return PAM_CRED_ERR;
1629 if (strcmp (pamh->user, "cred-expired") == 0)
1630 return PAM_CRED_EXPIRED;
1631 if (strcmp (pamh->user, "cred-unavail") == 0)
1632 return PAM_CRED_UNAVAIL;
1634 /* Join special groups if requested */
1635 if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1637 struct group *group;
1641 group = getgrnam ("test-group");
1644 groups_length = getgroups (0, NULL);
1645 if (groups_length < 0)
1646 return PAM_SYSTEM_ERR;
1647 groups = malloc (sizeof (gid_t) * (groups_length + 1));
1648 groups_length = getgroups (groups_length, groups);
1649 if (groups_length < 0)
1650 return PAM_SYSTEM_ERR;
1651 groups[groups_length] = group->gr_gid;
1653 setgroups (groups_length, groups);
1657 /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1658 pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1665 pam_end (pam_handle_t *pamh, int pam_status)
1668 return PAM_SYSTEM_ERR;
1671 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1675 status = g_string_new ("");
1676 g_string_append_printf (status, "%s END", pamh->id);
1677 status_notify ("%s", status->str);
1678 g_string_free (status, TRUE);
1682 free (pamh->service_name);
1686 free (pamh->authtok);
1697 pam_strerror (pam_handle_t *pamh, int errnum)
1707 return "Critical error - immediate abort";
1709 return "Failed to load module";
1710 case PAM_SYMBOL_ERR:
1711 return "Symbol not found";
1712 case PAM_SERVICE_ERR:
1713 return "Error in service module";
1714 case PAM_SYSTEM_ERR:
1715 return "System error";
1717 return "Memory buffer error";
1718 case PAM_PERM_DENIED:
1719 return "Permission denied";
1721 return "Authentication failure";
1722 case PAM_CRED_INSUFFICIENT:
1723 return "Insufficient credentials to access authentication data";
1724 case PAM_AUTHINFO_UNAVAIL:
1725 return "Authentication service cannot retrieve authentication info";
1726 case PAM_USER_UNKNOWN:
1727 return "User not known to the underlying authentication module";
1729 return "Have exhausted maximum number of retries for service";
1730 case PAM_NEW_AUTHTOK_REQD:
1731 return "Authentication token is no longer valid; new one required";
1732 case PAM_ACCT_EXPIRED:
1733 return "User account has expired";
1734 case PAM_SESSION_ERR:
1735 return "Cannot make/remove an entry for the specified session";
1736 case PAM_CRED_UNAVAIL:
1737 return "Authentication service cannot retrieve user credentials";
1738 case PAM_CRED_EXPIRED:
1739 return "User credentials expired";
1741 return "Failure setting user credentials";
1742 case PAM_NO_MODULE_DATA:
1743 return "No module specific data is present";
1745 return "Bad item passed to pam_*_item()";
1747 return "Conversation error";
1748 case PAM_AUTHTOK_ERR:
1749 return "Authentication token manipulation error";
1750 case PAM_AUTHTOK_RECOVERY_ERR:
1751 return "Authentication information cannot be recovered";
1752 case PAM_AUTHTOK_LOCK_BUSY:
1753 return "Authentication token lock busy";
1754 case PAM_AUTHTOK_DISABLE_AGING:
1755 return "Authentication token aging disabled";
1757 return "Failed preliminary check by password service";
1759 return "The return value should be ignored by PAM dispatch";
1760 case PAM_MODULE_UNKNOWN:
1761 return "Module is unknown";
1762 case PAM_AUTHTOK_EXPIRED:
1763 return "Authentication token expired";
1764 case PAM_CONV_AGAIN:
1765 return "Conversation is waiting for event";
1766 case PAM_INCOMPLETE:
1767 return "Application needs to call libpam again";
1769 return "Unknown PAM error";
1779 pututxline (const struct utmpx *ut)
1782 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1786 status = g_string_new ("UTMP");
1787 switch (ut->ut_type)
1790 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1793 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1796 g_string_append_printf (status, " TYPE=USER_PROCESS");
1799 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1802 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1805 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1807 g_string_append_printf (status, " ID=%s", ut->ut_id);
1809 g_string_append_printf (status, " USER=%s", ut->ut_user);
1811 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1812 status_notify ("%s", status->str);
1813 g_string_free (status, TRUE);
1816 return (struct utmpx *)ut;
1825 updwtmp (const char *wtmp_file, const struct utmp *ut)
1828 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1832 status = g_string_new ("WTMP");
1833 g_string_append_printf (status, " FILE=%s", wtmp_file);
1834 switch (ut->ut_type)
1837 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1840 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1843 g_string_append_printf (status, " TYPE=USER_PROCESS");
1846 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1849 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1852 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1854 g_string_append_printf (status, " ID=%s", ut->ut_id);
1856 g_string_append_printf (status, " USER=%s", ut->ut_user);
1858 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1859 status_notify ("%s", status->str);
1860 g_string_free (status, TRUE);
1864 struct xcb_connection_t
1872 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1874 xcb_connection_t *c;
1876 GError *error = NULL;
1878 c = malloc (sizeof (xcb_connection_t));
1879 c->display = g_strdup (display);
1882 if (display == NULL)
1883 display = getenv ("DISPLAY");
1884 if (display == NULL)
1885 c->error = XCB_CONN_CLOSED_PARSE_ERR;
1889 c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1891 g_printerr ("%s\n", error->message);
1892 g_clear_error (&error);
1893 if (c->socket == NULL)
1894 c->error = XCB_CONN_ERROR;
1900 GSocketAddress *address;
1902 /* Skip the hostname, we'll assume it's localhost */
1903 d = g_strdup_printf (".x%s", strchr (display, ':'));
1905 socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1907 address = g_unix_socket_address_new (socket_path);
1908 if (!g_socket_connect (c->socket, address, NULL, &error))
1909 c->error = XCB_CONN_ERROR;
1910 g_object_unref (address);
1912 g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1913 g_free (socket_path);
1914 g_clear_error (&error);
1917 // FIXME: Send auth info
1926 xcb_connect (const char *displayname, int *screenp)
1928 return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1932 xcb_connection_has_error (xcb_connection_t *c)
1938 xcb_disconnect (xcb_connection_t *c)
1942 g_object_unref (c->socket);
1951 if (g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1952 status_notify ("AUDIT OPEN");
1954 return dup (STDOUT_FILENO);
1958 audit_log_acct_message (int audit_fd, int type, const char *pgname,
1959 const char *op, const char *name, unsigned int id,
1960 const char *host, const char *addr, const char *tty, int result)
1965 if (!g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1970 case AUDIT_USER_LOGIN:
1971 type_string = g_strdup ("USER_LOGIN");
1973 case AUDIT_USER_LOGOUT:
1974 type_string = g_strdup ("USER_LOGOUT");
1977 type_string = g_strdup_printf ("%d", type);
1981 status_notify ("AUDIT LOG-ACCT TYPE=%s PGNAME=%s OP=%s NAME=%s ID=%u HOST=%s ADDR=%s TTY=%s RESULT=%d",
1982 type_string, pgname ? pgname : "", op ? op : "", name ? name : "", id, host ? host : "", addr ? addr : "", tty ? tty : "", result);
1984 g_free (type_string);