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 tty_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 // Don't redirect if inside the running directory
188 if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
189 return g_strdup (path);
191 if (g_str_has_prefix (path, SYSCONFDIR))
192 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
194 if (g_str_has_prefix (path, LOCALSTATEDIR))
195 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
197 if (g_str_has_prefix (path, DATADIR))
198 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
200 // Don't redirect if inside the build directory
201 if (g_str_has_prefix (path, BUILDDIR))
202 return g_strdup (path);
204 if (g_str_has_prefix (path, "/tmp"))
205 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
207 if (g_str_has_prefix (path, "/run"))
208 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "run", path + strlen ("/run"), NULL);
210 if (g_str_has_prefix (path, "/etc/xdg"))
211 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
213 if (g_str_has_prefix (path, "/usr/share/lightdm"))
214 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
216 return g_strdup (path);
221 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
223 int (*_open) (const char *pathname, int flags, mode_t mode);
224 gchar *new_path = NULL;
227 _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
229 if (strcmp (pathname, "/dev/tty0") == 0)
233 tty_fd = _open ("/dev/null", flags, mode);
234 fcntl (tty_fd, F_SETFD, FD_CLOEXEC);
239 new_path = redirect_path (pathname);
240 fd = _open (new_path, flags, mode);
247 open (const char *pathname, int flags, ...)
253 va_start (ap, flags);
254 mode = va_arg (ap, mode_t);
257 return open_wrapper ("open", pathname, flags, mode);
261 open64 (const char *pathname, int flags, ...)
267 va_start (ap, flags);
268 mode = va_arg (ap, mode_t);
271 return open_wrapper ("open64", pathname, flags, mode);
275 fopen (const char *path, const char *mode)
277 FILE *(*_fopen) (const char *pathname, const char *mode);
278 gchar *new_path = NULL;
281 _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
283 new_path = redirect_path (path);
284 result = _fopen (new_path, mode);
291 unlinkat (int dirfd, const char *pathname, int flags)
293 int (*_unlinkat) (int dirfd, const char *pathname, int flags);
294 gchar *new_path = NULL;
297 _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
299 new_path = redirect_path (pathname);
300 result = _unlinkat (dirfd, new_path, flags);
307 creat (const char *pathname, mode_t mode)
309 int (*_creat) (const char *pathname, mode_t mode);
310 gchar *new_path = NULL;
313 _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
315 new_path = redirect_path (pathname);
316 result = _creat (new_path, mode);
323 creat64 (const char *pathname, mode_t mode)
325 int (*_creat64) (const char *pathname, mode_t mode);
326 gchar *new_path = NULL;
329 _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
331 new_path = redirect_path (pathname);
332 result = _creat64 (new_path, mode);
339 access (const char *pathname, int mode)
341 int (*_access) (const char *pathname, int mode);
342 gchar *new_path = NULL;
345 _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
347 if (strcmp (pathname, "/dev/tty0") == 0)
349 if (strcmp (pathname, "/sys/class/tty/tty0/active") == 0)
352 new_path = redirect_path (pathname);
353 ret = _access (new_path, mode);
360 stat (const char *path, struct stat *buf)
362 int (*_stat) (const char *path, struct stat *buf);
363 gchar *new_path = NULL;
366 _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
368 new_path = redirect_path (path);
369 ret = _stat (new_path, buf);
376 stat64 (const char *path, struct stat64 *buf)
378 int (*_stat64) (const char *path, struct stat64 *buf);
379 gchar *new_path = NULL;
382 _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
384 new_path = redirect_path (path);
385 ret = _stat64 (new_path, buf);
392 __xstat (int version, const char *path, struct stat *buf)
394 int (*___xstat) (int version, const char *path, struct stat *buf);
395 gchar *new_path = NULL;
398 ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
400 new_path = redirect_path (path);
401 ret = ___xstat (version, new_path, buf);
408 __xstat64 (int version, const char *path, struct stat64 *buf)
410 int (*___xstat64) (int version, const char *path, struct stat64 *buf);
411 gchar *new_path = NULL;
414 ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
416 new_path = redirect_path (path);
417 ret = ___xstat64 (version, new_path, buf);
424 __fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
426 int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
427 gchar *new_path = NULL;
430 ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
432 new_path = redirect_path (pathname);
433 ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
440 __fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
442 int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
443 gchar *new_path = NULL;
446 ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
448 new_path = redirect_path (pathname);
449 ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
456 opendir (const char *name)
458 DIR *(*_opendir) (const char *name);
459 gchar *new_path = NULL;
462 _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
464 new_path = redirect_path (name);
465 result = _opendir (new_path);
472 mkdir (const char *pathname, mode_t mode)
474 int (*_mkdir) (const char *pathname, mode_t mode);
475 gchar *new_path = NULL;
478 _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
480 new_path = redirect_path (pathname);
481 result = _mkdir (new_path, mode);
488 chown (const char *pathname, uid_t owner, gid_t group)
490 /* Just fake it - we're not root */
495 chmod (const char *path, mode_t mode)
497 int (*_chmod) (const char *path, mode_t mode);
498 gchar *new_path = NULL;
501 _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
503 new_path = redirect_path (path);
504 result = _chmod (new_path, mode);
511 ioctl (int d, unsigned long request, ...)
513 int (*_ioctl) (int d, int request, ...);
515 _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
516 if (d > 0 && d == tty_fd)
518 struct vt_stat *vt_state;
525 va_start (ap, request);
526 vt_state = va_arg (ap, struct vt_stat *);
528 vt_state->v_active = active_vt;
531 va_start (ap, request);
532 vt = va_arg (ap, int);
538 status_notify ("VT ACTIVATE VT=%d", active_vt);
551 va_start (ap, request);
552 data = va_arg (ap, void *);
554 return _ioctl (d, request, data);
559 add_port_redirect (int requested_port, int redirected_port)
562 gchar *path, *name, *data;
564 file = g_key_file_new ();
565 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
566 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
568 name = g_strdup_printf ("%d", requested_port);
569 g_key_file_set_integer (file, name, "redirected", redirected_port);
572 data = g_key_file_to_data (file, NULL, NULL);
573 g_file_set_contents (path, data, -1, NULL);
577 g_key_file_free (file);
581 find_port_redirect (int port)
587 file = g_key_file_new ();
588 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
589 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
592 name = g_strdup_printf ("%d", port);
593 redirected_port = g_key_file_get_integer (file, name, "redirected", NULL);
595 g_key_file_free (file);
597 return redirected_port;
601 bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
603 int port = 0, redirected_port = 0;
604 int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
605 const struct sockaddr *modified_addr = addr;
606 struct sockaddr_in temp_addr;
607 struct sockaddr_in6 temp_addr6;
610 _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
612 switch (addr->sa_family)
615 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
616 redirected_port = find_port_redirect (port);
617 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
618 modified_addr = (struct sockaddr *) &temp_addr;
619 if (redirected_port != 0)
620 temp_addr.sin_port = htons (redirected_port);
622 temp_addr.sin_port = 0;
625 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
626 redirected_port = find_port_redirect (port);
627 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
628 modified_addr = (struct sockaddr *) &temp_addr6;
629 if (redirected_port != 0)
630 temp_addr6.sin6_port = htons (redirected_port);
632 temp_addr6.sin6_port = 0;
636 retval = _bind (sockfd, modified_addr, addrlen);
638 socklen_t temp_addr_len;
639 switch (addr->sa_family)
642 temp_addr_len = sizeof (temp_addr);
643 getsockname (sockfd, &temp_addr, &temp_addr_len);
644 if (redirected_port == 0)
646 redirected_port = ntohs (temp_addr.sin_port);
647 add_port_redirect (port, redirected_port);
651 temp_addr_len = sizeof (temp_addr6);
652 getsockname (sockfd, &temp_addr6, &temp_addr_len);
653 if (redirected_port == 0)
655 redirected_port = ntohs (temp_addr6.sin6_port);
656 add_port_redirect (port, redirected_port);
665 connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
667 int port, redirected_port;
668 const struct sockaddr *modified_addr = addr;
669 struct sockaddr_in temp_addr;
670 struct sockaddr_in6 temp_addr6;
671 int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
673 _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
675 switch (addr->sa_family)
678 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
679 redirected_port = find_port_redirect (port);
680 if (redirected_port != 0)
682 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
683 temp_addr.sin_port = htons (redirected_port);
684 modified_addr = (struct sockaddr *) &temp_addr;
688 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
689 redirected_port = find_port_redirect (port);
690 if (redirected_port != 0)
692 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
693 temp_addr6.sin6_port = htons (redirected_port);
694 modified_addr = (struct sockaddr *) &temp_addr6;
699 return _connect (sockfd, modified_addr, addrlen);
703 sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
705 int port, redirected_port;
706 const struct sockaddr *modified_addr = dest_addr;
707 struct sockaddr_in temp_addr;
708 struct sockaddr_in6 temp_addr6;
709 ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
711 _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");
713 switch (dest_addr->sa_family)
716 port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
717 redirected_port = find_port_redirect (port);
718 if (redirected_port != 0)
720 memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in));
721 temp_addr.sin_port = htons (redirected_port);
722 modified_addr = (struct sockaddr *) &temp_addr;
726 port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port);
727 redirected_port = find_port_redirect (port);
728 if (redirected_port != 0)
730 memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6));
731 temp_addr6.sin6_port = htons (redirected_port);
732 modified_addr = (struct sockaddr *) &temp_addr6;
737 return _sendto (sockfd, buf, len, flags, modified_addr, addrlen);
743 int (*_close) (int fd);
745 if (fd > 0 && fd == tty_fd)
748 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
754 free_user (gpointer data)
756 struct passwd *entry = data;
758 g_free (entry->pw_name);
759 g_free (entry->pw_passwd);
760 g_free (entry->pw_gecos);
761 g_free (entry->pw_dir);
762 g_free (entry->pw_shell);
767 load_passwd_file (void)
769 gchar *path, *data = NULL, **lines;
771 GError *error = NULL;
773 g_list_free_full (user_entries, free_user);
775 getpwent_link = NULL;
777 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
778 g_file_get_contents (path, &data, NULL, &error);
781 g_warning ("Error loading passwd file: %s", error->message);
782 g_clear_error (&error);
787 lines = g_strsplit (data, "\n", -1);
790 for (i = 0; lines[i]; i++)
792 gchar *line, **fields;
794 line = g_strstrip (lines[i]);
795 fields = g_strsplit (line, ":", -1);
796 if (g_strv_length (fields) == 7)
798 struct passwd *entry = malloc (sizeof (struct passwd));
800 entry->pw_name = g_strdup (fields[0]);
801 entry->pw_passwd = g_strdup (fields[1]);
802 entry->pw_uid = atoi (fields[2]);
803 entry->pw_gid = atoi (fields[3]);
804 entry->pw_gecos = g_strdup (fields[4]);
805 entry->pw_dir = g_strdup (fields[5]);
806 entry->pw_shell = g_strdup (fields[6]);
807 user_entries = g_list_append (user_entries, entry);
817 if (getpwent_link == NULL)
820 if (user_entries == NULL)
822 getpwent_link = user_entries;
826 if (getpwent_link->next == NULL)
828 getpwent_link = getpwent_link->next;
831 return getpwent_link->data;
837 getpwent_link = NULL;
843 getpwent_link = NULL;
847 getpwnam (const char *name)
856 for (link = user_entries; link; link = link->next)
858 struct passwd *entry = link->data;
859 if (strcmp (entry->pw_name, name) == 0)
875 for (link = user_entries; link; link = link->next)
877 struct passwd *entry = link->data;
878 if (entry->pw_uid == uid)
888 free_group (gpointer data)
890 struct group *entry = data;
892 g_free (entry->gr_name);
893 g_free (entry->gr_passwd);
894 g_strfreev (entry->gr_mem);
899 load_group_file (void)
901 gchar *path, *data = NULL, **lines;
903 GError *error = NULL;
905 g_list_free_full (group_entries, free_group);
906 group_entries = NULL;
908 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
909 g_file_get_contents (path, &data, NULL, &error);
912 g_warning ("Error loading group file: %s", error->message);
913 g_clear_error (&error);
918 lines = g_strsplit (data, "\n", -1);
921 for (i = 0; lines[i]; i++)
923 gchar *line, **fields;
925 line = g_strstrip (lines[i]);
926 fields = g_strsplit (line, ":", -1);
927 if (g_strv_length (fields) == 4)
929 struct group *entry = malloc (sizeof (struct group));
931 entry->gr_name = g_strdup (fields[0]);
932 entry->gr_passwd = g_strdup (fields[1]);
933 entry->gr_gid = atoi (fields[2]);
934 entry->gr_mem = g_strsplit (fields[3], ",", -1);
935 group_entries = g_list_append (group_entries, entry);
943 getgrnam (const char *name)
949 for (link = group_entries; link; link = link->next)
951 struct group *entry = link->data;
952 if (strcmp (entry->gr_name, name) == 0)
968 for (link = group_entries; link; link = link->next)
970 struct group *entry = link->data;
971 if (entry->gr_gid == gid)
981 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
983 pam_handle_t *handle;
985 if (service_name == NULL || conversation == NULL || pamh == NULL)
986 return PAM_SYSTEM_ERR;
988 handle = *pamh = malloc (sizeof (pam_handle_t));
993 handle->id = g_strdup_printf ("PAM-%s", user);
995 handle->id = g_strdup ("PAM");
998 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1002 status = g_string_new ("");
1003 g_string_append_printf (status, "%s START", handle->id);
1004 g_string_append_printf (status, " SERVICE=%s", service_name);
1006 g_string_append_printf (status, " USER=%s", user);
1007 status_notify ("%s", status->str);
1008 g_string_free (status, TRUE);
1011 handle->service_name = strdup (service_name);
1012 handle->user = user ? strdup (user) : NULL;
1013 handle->authtok = NULL;
1014 handle->ruser = NULL;
1016 handle->conversation.conv = conversation->conv;
1017 handle->conversation.appdata_ptr = conversation->appdata_ptr;
1018 handle->envlist = malloc (sizeof (char *) * 1);
1019 handle->envlist[0] = NULL;
1025 pam_authenticate (pam_handle_t *pamh, int flags)
1027 struct passwd *entry;
1028 gboolean password_matches = FALSE;
1031 return PAM_SYSTEM_ERR;
1034 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1038 status = g_string_new ("");
1039 g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
1040 if (flags & PAM_SILENT)
1041 g_string_append (status, " SILENT");
1042 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1043 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1045 status_notify ("%s", status->str);
1046 g_string_free (status, TRUE);
1049 if (strcmp (pamh->service_name, "test-remote") == 0)
1052 struct pam_message **msg;
1053 struct pam_response *resp = NULL;
1055 msg = malloc (sizeof (struct pam_message *) * 1);
1056 msg[0] = malloc (sizeof (struct pam_message));
1057 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1058 msg[0]->msg = "remote-login:";
1059 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1062 if (result != PAM_SUCCESS)
1066 return PAM_CONV_ERR;
1067 if (resp[0].resp == NULL)
1070 return PAM_CONV_ERR;
1075 pamh->ruser = strdup (resp[0].resp);
1076 free (resp[0].resp);
1079 msg = malloc (sizeof (struct pam_message *) * 1);
1080 msg[0] = malloc (sizeof (struct pam_message));
1081 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1082 msg[0]->msg = "remote-password:";
1083 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1086 if (result != PAM_SUCCESS)
1090 return PAM_CONV_ERR;
1091 if (resp[0].resp == NULL)
1094 return PAM_CONV_ERR;
1098 free (pamh->authtok);
1099 pamh->authtok = strdup (resp[0].resp);
1100 free (resp[0].resp);
1103 password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
1105 if (password_matches)
1108 return PAM_AUTH_ERR;
1111 /* Prompt for username */
1112 if (pamh->user == NULL)
1115 struct pam_message **msg;
1116 struct pam_response *resp = NULL;
1118 msg = malloc (sizeof (struct pam_message *) * 1);
1119 msg[0] = malloc (sizeof (struct pam_message));
1120 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1121 msg[0]->msg = LOGIN_PROMPT;
1122 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1125 if (result != PAM_SUCCESS)
1129 return PAM_CONV_ERR;
1130 if (resp[0].resp == NULL)
1133 return PAM_CONV_ERR;
1136 pamh->user = strdup (resp[0].resp);
1137 free (resp[0].resp);
1141 /* Crash on authenticate */
1142 if (strcmp (pamh->user, "crash-authenticate") == 0)
1143 kill (getpid (), SIGSEGV);
1145 /* Look up password database */
1146 entry = getpwnam (pamh->user);
1148 /* Prompt for password if required */
1149 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
1150 password_matches = TRUE;
1153 int i, n_messages = 0, password_index, result;
1154 struct pam_message **msg;
1155 struct pam_response *resp = NULL;
1157 msg = malloc (sizeof (struct pam_message *) * 5);
1158 if (strcmp (pamh->user, "info-prompt") == 0)
1160 msg[n_messages] = malloc (sizeof (struct pam_message));
1161 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1162 msg[n_messages]->msg = "Welcome to LightDM";
1165 if (strcmp (pamh->user, "multi-info-prompt") == 0)
1167 msg[n_messages] = malloc (sizeof (struct pam_message));
1168 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1169 msg[n_messages]->msg = "Welcome to LightDM";
1171 msg[n_messages] = malloc (sizeof (struct pam_message));
1172 msg[n_messages]->msg_style = PAM_ERROR_MSG;
1173 msg[n_messages]->msg = "This is an error";
1175 msg[n_messages] = malloc (sizeof (struct pam_message));
1176 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1177 msg[n_messages]->msg = "You should have seen three messages";
1180 if (strcmp (pamh->user, "multi-prompt") == 0)
1182 msg[n_messages] = malloc (sizeof (struct pam_message));
1183 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
1184 msg[n_messages]->msg = "Favorite Color:";
1187 msg[n_messages] = malloc (sizeof (struct pam_message));
1188 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
1189 msg[n_messages]->msg = "Password:";
1190 password_index = n_messages;
1192 result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1193 for (i = 0; i < n_messages; i++)
1196 if (result != PAM_SUCCESS)
1200 return PAM_CONV_ERR;
1201 if (resp[password_index].resp == NULL)
1204 return PAM_CONV_ERR;
1208 password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
1210 if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
1211 password_matches = strcmp ("blue", resp[0].resp) == 0;
1213 for (i = 0; i < n_messages; i++)
1216 free (resp[i].resp);
1220 /* Do two factor authentication */
1221 if (password_matches && strcmp (pamh->user, "two-factor") == 0)
1223 msg = malloc (sizeof (struct pam_message *) * 1);
1224 msg[0] = malloc (sizeof (struct pam_message));
1225 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1226 msg[0]->msg = "OTP:";
1228 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1231 if (result != PAM_SUCCESS)
1235 return PAM_CONV_ERR;
1236 if (resp[0].resp == NULL)
1239 return PAM_CONV_ERR;
1241 password_matches = strcmp (resp[0].resp, "otp") == 0;
1242 free (resp[0].resp);
1247 /* Special user has home directory created on login */
1248 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
1249 g_mkdir_with_parents (entry->pw_dir, 0755);
1251 /* Special user 'change-user1' changes user on authentication */
1252 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
1254 g_free (pamh->user);
1255 pamh->user = g_strdup ("change-user2");
1258 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
1259 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
1261 g_free (pamh->user);
1262 pamh->user = g_strdup ("invalid-user");
1265 if (password_matches)
1268 return PAM_AUTH_ERR;
1272 get_env_value (const char *name_value, const char *name)
1276 for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
1277 if (name[j] == '\0' && name_value[j] == '=')
1278 return &name_value[j + 1];
1284 pam_putenv (pam_handle_t *pamh, const char *name_value)
1289 if (pamh == NULL || name_value == NULL)
1290 return PAM_SYSTEM_ERR;
1292 name = strdup (name_value);
1293 for (i = 0; name[i]; i++)
1296 for (i = 0; pamh->envlist[i]; i++)
1298 if (get_env_value (pamh->envlist[i], name))
1303 if (pamh->envlist[i])
1305 free (pamh->envlist[i]);
1306 pamh->envlist[i] = strdup (name_value);
1310 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
1311 pamh->envlist[i] = strdup (name_value);
1312 pamh->envlist[i + 1] = NULL;
1319 pam_getenv (pam_handle_t *pamh, const char *name)
1323 if (pamh == NULL || name == NULL)
1326 for (i = 0; pamh->envlist[i]; i++)
1329 value = get_env_value (pamh->envlist[i], name);
1338 pam_getenvlist (pam_handle_t *pamh)
1343 return pamh->envlist;
1347 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
1349 if (pamh == NULL || item == NULL)
1350 return PAM_SYSTEM_ERR;
1357 pamh->tty = strdup ((const char *) item);
1361 return PAM_BAD_ITEM;
1366 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
1368 if (pamh == NULL || item == NULL)
1369 return PAM_SYSTEM_ERR;
1374 *item = pamh->service_name;
1382 *item = pamh->authtok;
1386 *item = pamh->ruser;
1389 case PAM_USER_PROMPT:
1390 *item = LOGIN_PROMPT;
1398 *item = &pamh->conversation;
1402 return PAM_BAD_ITEM;
1407 pam_open_session (pam_handle_t *pamh, int flags)
1410 GError *error = NULL;
1413 return PAM_SYSTEM_ERR;
1416 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1420 status = g_string_new ("");
1421 g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1422 if (flags & PAM_SILENT)
1423 g_string_append (status, " SILENT");
1425 status_notify ("%s", status->str);
1426 g_string_free (status, TRUE);
1429 if (strcmp (pamh->user, "session-error") == 0)
1430 return PAM_SESSION_ERR;
1432 if (strcmp (pamh->user, "make-home-dir") == 0)
1434 struct passwd *entry;
1435 entry = getpwnam (pamh->user);
1436 g_mkdir_with_parents (entry->pw_dir, 0755);
1439 /* Open logind session */
1440 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
1441 "org.freedesktop.login1",
1442 "/org/freedesktop/login1",
1443 "org.freedesktop.login1.Manager",
1445 g_variant_new ("()", ""),
1446 G_VARIANT_TYPE ("(so)"),
1447 G_DBUS_CALL_FLAGS_NONE,
1456 g_variant_get (result, "(&so)", &id, NULL);
1457 e = g_strdup_printf ("XDG_SESSION_ID=%s", id);
1458 pam_putenv (pamh, e);
1460 g_variant_unref (result);
1463 g_printerr ("Failed to create logind session: %s\n", error->message);
1464 g_clear_error (&error);
1470 pam_close_session (pam_handle_t *pamh, int flags)
1473 return PAM_SYSTEM_ERR;
1476 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1480 status = g_string_new ("");
1481 g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1482 if (flags & PAM_SILENT)
1483 g_string_append (status, " SILENT");
1485 status_notify ("%s", status->str);
1486 g_string_free (status, TRUE);
1493 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1496 return PAM_SYSTEM_ERR;
1499 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1503 status = g_string_new ("");
1504 g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1505 if (flags & PAM_SILENT)
1506 g_string_append (status, " SILENT");
1507 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1508 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1510 status_notify ("%s", status->str);
1511 g_string_free (status, TRUE);
1515 return PAM_USER_UNKNOWN;
1517 if (strcmp (pamh->user, "denied") == 0)
1518 return PAM_PERM_DENIED;
1519 if (strcmp (pamh->user, "expired") == 0)
1520 return PAM_ACCT_EXPIRED;
1521 if (strcmp (pamh->user, "new-authtok") == 0)
1522 return PAM_NEW_AUTHTOK_REQD;
1528 pam_chauthtok (pam_handle_t *pamh, int flags)
1530 struct passwd *entry;
1532 struct pam_message **msg;
1533 struct pam_response *resp = NULL;
1536 return PAM_SYSTEM_ERR;
1539 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1543 status = g_string_new ("");
1544 g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1545 if (flags & PAM_SILENT)
1546 g_string_append (status, " SILENT");
1547 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1548 g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1550 status_notify ("%s", status->str);
1551 g_string_free (status, TRUE);
1554 msg = malloc (sizeof (struct pam_message *) * 1);
1555 msg[0] = malloc (sizeof (struct pam_message));
1556 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1557 if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1558 msg[0]->msg = "Enter new password (expired):";
1560 msg[0]->msg = "Enter new password:";
1561 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1564 if (result != PAM_SUCCESS)
1568 return PAM_CONV_ERR;
1569 if (resp[0].resp == NULL)
1572 return PAM_CONV_ERR;
1575 /* Update password database */
1576 entry = getpwnam (pamh->user);
1577 free (entry->pw_passwd);
1578 entry->pw_passwd = resp[0].resp;
1585 pam_setcred (pam_handle_t *pamh, int flags)
1590 return PAM_SYSTEM_ERR;
1593 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1597 status = g_string_new ("");
1598 g_string_append_printf (status, "%s SETCRED", pamh->id);
1599 if (flags & PAM_SILENT)
1600 g_string_append (status, " SILENT");
1601 if (flags & PAM_ESTABLISH_CRED)
1602 g_string_append (status, " ESTABLISH_CRED");
1603 if (flags & PAM_DELETE_CRED)
1604 g_string_append (status, " DELETE_CRED");
1605 if (flags & PAM_REINITIALIZE_CRED)
1606 g_string_append (status, " REINITIALIZE_CRED");
1607 if (flags & PAM_REFRESH_CRED)
1608 g_string_append (status, " REFRESH_CRED");
1610 status_notify ("%s", status->str);
1611 g_string_free (status, TRUE);
1614 /* Put the test directories into the path */
1615 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"));
1616 pam_putenv (pamh, e);
1619 if (strcmp (pamh->user, "cred-error") == 0)
1620 return PAM_CRED_ERR;
1621 if (strcmp (pamh->user, "cred-expired") == 0)
1622 return PAM_CRED_EXPIRED;
1623 if (strcmp (pamh->user, "cred-unavail") == 0)
1624 return PAM_CRED_UNAVAIL;
1626 /* Join special groups if requested */
1627 if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1629 struct group *group;
1633 group = getgrnam ("test-group");
1636 groups_length = getgroups (0, NULL);
1637 if (groups_length < 0)
1638 return PAM_SYSTEM_ERR;
1639 groups = malloc (sizeof (gid_t) * (groups_length + 1));
1640 groups_length = getgroups (groups_length, groups);
1641 if (groups_length < 0)
1642 return PAM_SYSTEM_ERR;
1643 groups[groups_length] = group->gr_gid;
1645 setgroups (groups_length, groups);
1649 /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1650 pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1657 pam_end (pam_handle_t *pamh, int pam_status)
1660 return PAM_SYSTEM_ERR;
1663 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1667 status = g_string_new ("");
1668 g_string_append_printf (status, "%s END", pamh->id);
1669 status_notify ("%s", status->str);
1670 g_string_free (status, TRUE);
1674 free (pamh->service_name);
1678 free (pamh->authtok);
1689 pam_strerror (pam_handle_t *pamh, int errnum)
1699 return "Critical error - immediate abort";
1701 return "Failed to load module";
1702 case PAM_SYMBOL_ERR:
1703 return "Symbol not found";
1704 case PAM_SERVICE_ERR:
1705 return "Error in service module";
1706 case PAM_SYSTEM_ERR:
1707 return "System error";
1709 return "Memory buffer error";
1710 case PAM_PERM_DENIED:
1711 return "Permission denied";
1713 return "Authentication failure";
1714 case PAM_CRED_INSUFFICIENT:
1715 return "Insufficient credentials to access authentication data";
1716 case PAM_AUTHINFO_UNAVAIL:
1717 return "Authentication service cannot retrieve authentication info";
1718 case PAM_USER_UNKNOWN:
1719 return "User not known to the underlying authentication module";
1721 return "Have exhausted maximum number of retries for service";
1722 case PAM_NEW_AUTHTOK_REQD:
1723 return "Authentication token is no longer valid; new one required";
1724 case PAM_ACCT_EXPIRED:
1725 return "User account has expired";
1726 case PAM_SESSION_ERR:
1727 return "Cannot make/remove an entry for the specified session";
1728 case PAM_CRED_UNAVAIL:
1729 return "Authentication service cannot retrieve user credentials";
1730 case PAM_CRED_EXPIRED:
1731 return "User credentials expired";
1733 return "Failure setting user credentials";
1734 case PAM_NO_MODULE_DATA:
1735 return "No module specific data is present";
1737 return "Bad item passed to pam_*_item()";
1739 return "Conversation error";
1740 case PAM_AUTHTOK_ERR:
1741 return "Authentication token manipulation error";
1742 case PAM_AUTHTOK_RECOVERY_ERR:
1743 return "Authentication information cannot be recovered";
1744 case PAM_AUTHTOK_LOCK_BUSY:
1745 return "Authentication token lock busy";
1746 case PAM_AUTHTOK_DISABLE_AGING:
1747 return "Authentication token aging disabled";
1749 return "Failed preliminary check by password service";
1751 return "The return value should be ignored by PAM dispatch";
1752 case PAM_MODULE_UNKNOWN:
1753 return "Module is unknown";
1754 case PAM_AUTHTOK_EXPIRED:
1755 return "Authentication token expired";
1756 case PAM_CONV_AGAIN:
1757 return "Conversation is waiting for event";
1758 case PAM_INCOMPLETE:
1759 return "Application needs to call libpam again";
1761 return "Unknown PAM error";
1771 pututxline (const struct utmpx *ut)
1774 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1778 status = g_string_new ("UTMP");
1779 switch (ut->ut_type)
1782 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1785 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1788 g_string_append_printf (status, " TYPE=USER_PROCESS");
1791 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1794 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1797 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1799 g_string_append_printf (status, " ID=%s", ut->ut_id);
1801 g_string_append_printf (status, " USER=%s", ut->ut_user);
1803 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1804 status_notify ("%s", status->str);
1805 g_string_free (status, TRUE);
1808 return (struct utmpx *)ut;
1817 updwtmp (const char *wtmp_file, const struct utmp *ut)
1820 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1824 status = g_string_new ("WTMP");
1825 g_string_append_printf (status, " FILE=%s", wtmp_file);
1826 switch (ut->ut_type)
1829 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1832 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1835 g_string_append_printf (status, " TYPE=USER_PROCESS");
1838 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1841 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1844 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1846 g_string_append_printf (status, " ID=%s", ut->ut_id);
1848 g_string_append_printf (status, " USER=%s", ut->ut_user);
1850 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1851 status_notify ("%s", status->str);
1852 g_string_free (status, TRUE);
1856 struct xcb_connection_t
1864 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1866 xcb_connection_t *c;
1868 GError *error = NULL;
1870 c = malloc (sizeof (xcb_connection_t));
1871 c->display = g_strdup (display);
1874 if (display == NULL)
1875 display = getenv ("DISPLAY");
1876 if (display == NULL)
1877 c->error = XCB_CONN_CLOSED_PARSE_ERR;
1881 c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1883 g_printerr ("%s\n", error->message);
1884 g_clear_error (&error);
1885 if (c->socket == NULL)
1886 c->error = XCB_CONN_ERROR;
1892 GSocketAddress *address;
1894 /* Skip the hostname, we'll assume it's localhost */
1895 d = g_strdup_printf (".x%s", strchr (display, ':'));
1897 socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1899 address = g_unix_socket_address_new (socket_path);
1900 if (!g_socket_connect (c->socket, address, NULL, &error))
1901 c->error = XCB_CONN_ERROR;
1902 g_object_unref (address);
1904 g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1905 g_free (socket_path);
1906 g_clear_error (&error);
1909 // FIXME: Send auth info
1918 xcb_connect (const char *displayname, int *screenp)
1920 return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1924 xcb_connection_has_error (xcb_connection_t *c)
1930 xcb_disconnect (xcb_connection_t *c)
1934 g_object_unref (c->socket);
1943 if (g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1944 status_notify ("AUDIT OPEN");
1946 return dup (STDOUT_FILENO);
1950 audit_log_acct_message (int audit_fd, int type, const char *pgname,
1951 const char *op, const char *name, unsigned int id,
1952 const char *host, const char *addr, const char *tty, int result)
1957 if (!g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1962 case AUDIT_USER_LOGIN:
1963 type_string = g_strdup ("USER_LOGIN");
1965 case AUDIT_USER_LOGOUT:
1966 type_string = g_strdup ("USER_LOGOUT");
1969 type_string = g_strdup_printf ("%d", type);
1973 status_notify ("AUDIT LOG-ACCT TYPE=%s PGNAME=%s OP=%s NAME=%s ID=%u HOST=%s ADDR=%s TTY=%s RESULT=%d",
1974 type_string, pgname ? pgname : "", op ? op : "", name ? name : "", id, host ? host : "", addr ? addr : "", tty ? tty : "", result);
1976 g_free (type_string);