10 #include <sys/ioctl.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
17 #include <security/pam_appl.h>
27 #include <gio/gunixsocketaddress.h>
31 #define LOGIN_PROMPT "login:"
33 static int console_fd = -1;
35 static GList *user_entries = NULL;
36 static GList *getpwent_link = NULL;
38 static GList *group_entries = NULL;
40 static int active_vt = 7;
42 static gboolean status_connected = FALSE;
43 static GKeyFile *config;
45 static void connect_status (void)
49 status_connected = TRUE;
51 status_connect (NULL, NULL);
53 config = g_key_file_new ();
54 g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
66 struct pam_conv conversation;
82 initgroups (const char *user, gid_t group)
93 getgroups (int size, gid_t list[])
95 const gchar *group_list;
99 /* Get groups we are a member of */
100 group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
103 groups = g_strsplit (group_list, ",", -1);
104 groups_length = g_strv_length (groups);
110 if (groups_length > size)
115 for (i = 0; groups[i]; i++)
116 list[i] = atoi (groups[i]);
120 return groups_length;
124 setgroups (size_t size, const gid_t *list)
129 group_list = g_string_new ("");
130 for (i = 0; i < size; i++)
133 g_string_append (group_list, ",");
134 g_string_append_printf (group_list, "%d", list[i]);
136 g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
137 g_string_free (group_list, TRUE);
155 setresgid (gid_t rgid, gid_t ugid, gid_t sgid)
173 setresuid (uid_t ruid, uid_t uuid, uid_t suid)
179 redirect_path (const gchar *path)
181 // Don't redirect if inside the running directory
182 if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
183 return g_strdup (path);
185 if (g_str_has_prefix (path, SYSCONFDIR))
186 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
188 if (g_str_has_prefix (path, LOCALSTATEDIR))
189 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
191 if (g_str_has_prefix (path, DATADIR))
192 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
194 // Don't redirect if inside the build directory
195 if (g_str_has_prefix (path, BUILDDIR))
196 return g_strdup (path);
198 if (g_str_has_prefix (path, "/tmp"))
199 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
201 if (g_str_has_prefix (path, "/run"))
202 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "run", path + strlen ("/run"), NULL);
204 if (g_str_has_prefix (path, "/etc/xdg"))
205 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
207 if (g_str_has_prefix (path, "/usr/share/lightdm"))
208 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
210 return g_strdup (path);
215 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
217 int (*_open) (const char *pathname, int flags, mode_t mode);
218 gchar *new_path = NULL;
221 _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
223 if (strcmp (pathname, "/dev/console") == 0)
227 console_fd = _open ("/dev/null", flags, mode);
228 fcntl (console_fd, F_SETFD, FD_CLOEXEC);
233 new_path = redirect_path (pathname);
234 fd = _open (new_path, flags, mode);
241 open (const char *pathname, int flags, ...)
247 va_start (ap, flags);
248 mode = va_arg (ap, mode_t);
251 return open_wrapper ("open", pathname, flags, mode);
255 open64 (const char *pathname, int flags, ...)
261 va_start (ap, flags);
262 mode = va_arg (ap, mode_t);
265 return open_wrapper ("open64", pathname, flags, mode);
269 fopen (const char *path, const char *mode)
271 FILE *(*_fopen) (const char *pathname, const char *mode);
272 gchar *new_path = NULL;
275 _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
277 new_path = redirect_path (path);
278 result = _fopen (new_path, mode);
285 unlinkat (int dirfd, const char *pathname, int flags)
287 int (*_unlinkat) (int dirfd, const char *pathname, int flags);
288 gchar *new_path = NULL;
291 _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
293 new_path = redirect_path (pathname);
294 result = _unlinkat (dirfd, new_path, flags);
301 creat (const char *pathname, mode_t mode)
303 int (*_creat) (const char *pathname, mode_t mode);
304 gchar *new_path = NULL;
307 _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
309 new_path = redirect_path (pathname);
310 result = _creat (new_path, mode);
317 creat64 (const char *pathname, mode_t mode)
319 int (*_creat64) (const char *pathname, mode_t mode);
320 gchar *new_path = NULL;
323 _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
325 new_path = redirect_path (pathname);
326 result = _creat64 (new_path, mode);
333 access (const char *pathname, int mode)
335 int (*_access) (const char *pathname, int mode);
336 gchar *new_path = NULL;
339 _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
341 new_path = redirect_path (pathname);
342 ret = _access (new_path, mode);
349 stat (const char *path, struct stat *buf)
351 int (*_stat) (const char *path, struct stat *buf);
352 gchar *new_path = NULL;
355 _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
357 new_path = redirect_path (path);
358 ret = _stat (new_path, buf);
365 stat64 (const char *path, struct stat64 *buf)
367 int (*_stat64) (const char *path, struct stat64 *buf);
368 gchar *new_path = NULL;
371 _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
373 new_path = redirect_path (path);
374 ret = _stat64 (new_path, buf);
381 __xstat (int version, const char *path, struct stat *buf)
383 int (*___xstat) (int version, const char *path, struct stat *buf);
384 gchar *new_path = NULL;
387 ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
389 new_path = redirect_path (path);
390 ret = ___xstat (version, new_path, buf);
397 __xstat64 (int version, const char *path, struct stat64 *buf)
399 int (*___xstat64) (int version, const char *path, struct stat64 *buf);
400 gchar *new_path = NULL;
403 ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
405 new_path = redirect_path (path);
406 ret = ___xstat64 (version, new_path, buf);
413 __fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
415 int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
416 gchar *new_path = NULL;
419 ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
421 new_path = redirect_path (pathname);
422 ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
429 __fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
431 int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
432 gchar *new_path = NULL;
435 ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
437 new_path = redirect_path (pathname);
438 ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
445 opendir (const char *name)
447 DIR *(*_opendir) (const char *name);
448 gchar *new_path = NULL;
451 _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
453 new_path = redirect_path (name);
454 result = _opendir (new_path);
461 mkdir (const char *pathname, mode_t mode)
463 int (*_mkdir) (const char *pathname, mode_t mode);
464 gchar *new_path = NULL;
467 _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
469 new_path = redirect_path (pathname);
470 result = _mkdir (new_path, mode);
477 chown (const char *pathname, uid_t owner, gid_t group)
479 /* Just fake it - we're not root */
484 chmod (const char *path, mode_t mode)
486 int (*_chmod) (const char *path, mode_t mode);
487 gchar *new_path = NULL;
490 _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
492 new_path = redirect_path (path);
493 result = _chmod (new_path, mode);
500 ioctl (int d, unsigned long request, ...)
502 int (*_ioctl) (int d, int request, ...);
504 _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
505 if (d > 0 && d == console_fd)
507 struct vt_stat *console_state;
514 va_start (ap, request);
515 console_state = va_arg (ap, struct vt_stat *);
517 console_state->v_active = active_vt;
520 va_start (ap, request);
521 vt = va_arg (ap, int);
527 status_notify ("VT ACTIVATE VT=%d", active_vt);
540 va_start (ap, request);
541 data = va_arg (ap, void *);
543 return _ioctl (d, request, data);
548 add_port_redirect (int requested_port, int redirected_port)
551 gchar *path, *name, *data;
553 file = g_key_file_new ();
554 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
555 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
557 name = g_strdup_printf ("%d", requested_port);
558 g_key_file_set_integer (file, name, "redirected", redirected_port);
561 data = g_key_file_to_data (file, NULL, NULL);
562 g_file_set_contents (path, data, -1, NULL);
566 g_key_file_free (file);
570 find_port_redirect (int port)
576 file = g_key_file_new ();
577 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
578 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
581 name = g_strdup_printf ("%d", port);
582 redirected_port = g_key_file_get_integer (file, name, "redirected", NULL);
584 g_key_file_free (file);
586 return redirected_port;
590 bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
592 int port = 0, redirected_port = 0;
593 int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
594 const struct sockaddr *modified_addr = addr;
595 struct sockaddr_in temp_addr;
596 struct sockaddr_in6 temp_addr6;
599 _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
601 switch (addr->sa_family)
604 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
605 redirected_port = find_port_redirect (port);
606 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
607 modified_addr = (struct sockaddr *) &temp_addr;
608 if (redirected_port != 0)
609 temp_addr.sin_port = htons (redirected_port);
611 temp_addr.sin_port = 0;
614 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
615 redirected_port = find_port_redirect (port);
616 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
617 modified_addr = (struct sockaddr *) &temp_addr6;
618 if (redirected_port != 0)
619 temp_addr6.sin6_port = htons (redirected_port);
621 temp_addr6.sin6_port = 0;
625 retval = _bind (sockfd, modified_addr, addrlen);
627 socklen_t temp_addr_len;
628 switch (addr->sa_family)
631 temp_addr_len = sizeof (temp_addr);
632 getsockname (sockfd, &temp_addr, &temp_addr_len);
633 if (redirected_port == 0)
635 redirected_port = ntohs (temp_addr.sin_port);
636 add_port_redirect (port, redirected_port);
640 temp_addr_len = sizeof (temp_addr6);
641 getsockname (sockfd, &temp_addr6, &temp_addr_len);
642 if (redirected_port == 0)
644 redirected_port = ntohs (temp_addr6.sin6_port);
645 add_port_redirect (port, redirected_port);
654 connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
656 int port, redirected_port;
657 const struct sockaddr *modified_addr = addr;
658 struct sockaddr_in temp_addr;
659 struct sockaddr_in6 temp_addr6;
660 int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
662 _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
664 switch (addr->sa_family)
667 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
668 redirected_port = find_port_redirect (port);
669 if (redirected_port != 0)
671 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
672 temp_addr.sin_port = htons (redirected_port);
673 modified_addr = (struct sockaddr *) &temp_addr;
677 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
678 redirected_port = find_port_redirect (port);
679 if (redirected_port != 0)
681 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
682 temp_addr6.sin6_port = htons (redirected_port);
683 modified_addr = (struct sockaddr *) &temp_addr6;
688 return _connect (sockfd, modified_addr, addrlen);
692 sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
694 int port, redirected_port;
695 const struct sockaddr *modified_addr = dest_addr;
696 struct sockaddr_in temp_addr;
697 struct sockaddr_in6 temp_addr6;
698 ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
700 _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");
702 switch (dest_addr->sa_family)
705 port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
706 redirected_port = find_port_redirect (port);
707 if (redirected_port != 0)
709 memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in));
710 temp_addr.sin_port = htons (redirected_port);
711 modified_addr = (struct sockaddr *) &temp_addr;
715 port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port);
716 redirected_port = find_port_redirect (port);
717 if (redirected_port != 0)
719 memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6));
720 temp_addr6.sin6_port = htons (redirected_port);
721 modified_addr = (struct sockaddr *) &temp_addr6;
726 return _sendto (sockfd, buf, len, flags, modified_addr, addrlen);
732 int (*_close) (int fd);
734 if (fd > 0 && fd == console_fd)
737 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
743 free_user (gpointer data)
745 struct passwd *entry = data;
747 g_free (entry->pw_name);
748 g_free (entry->pw_passwd);
749 g_free (entry->pw_gecos);
750 g_free (entry->pw_dir);
751 g_free (entry->pw_shell);
756 load_passwd_file (void)
758 gchar *path, *data = NULL, **lines;
760 GError *error = NULL;
762 g_list_free_full (user_entries, free_user);
764 getpwent_link = NULL;
766 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
767 g_file_get_contents (path, &data, NULL, &error);
770 g_warning ("Error loading passwd file: %s", error->message);
771 g_clear_error (&error);
776 lines = g_strsplit (data, "\n", -1);
779 for (i = 0; lines[i]; i++)
781 gchar *line, **fields;
783 line = g_strstrip (lines[i]);
784 fields = g_strsplit (line, ":", -1);
785 if (g_strv_length (fields) == 7)
787 struct passwd *entry = malloc (sizeof (struct passwd));
789 entry->pw_name = g_strdup (fields[0]);
790 entry->pw_passwd = g_strdup (fields[1]);
791 entry->pw_uid = atoi (fields[2]);
792 entry->pw_gid = atoi (fields[3]);
793 entry->pw_gecos = g_strdup (fields[4]);
794 entry->pw_dir = g_strdup (fields[5]);
795 entry->pw_shell = g_strdup (fields[6]);
796 user_entries = g_list_append (user_entries, entry);
806 if (getpwent_link == NULL)
809 if (user_entries == NULL)
811 getpwent_link = user_entries;
815 if (getpwent_link->next == NULL)
817 getpwent_link = getpwent_link->next;
820 return getpwent_link->data;
826 getpwent_link = NULL;
832 getpwent_link = NULL;
836 getpwnam (const char *name)
845 for (link = user_entries; link; link = link->next)
847 struct passwd *entry = link->data;
848 if (strcmp (entry->pw_name, name) == 0)
864 for (link = user_entries; link; link = link->next)
866 struct passwd *entry = link->data;
867 if (entry->pw_uid == uid)
877 free_group (gpointer data)
879 struct group *entry = data;
881 g_free (entry->gr_name);
882 g_free (entry->gr_passwd);
883 g_strfreev (entry->gr_mem);
888 load_group_file (void)
890 gchar *path, *data = NULL, **lines;
892 GError *error = NULL;
894 g_list_free_full (group_entries, free_group);
895 group_entries = NULL;
897 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
898 g_file_get_contents (path, &data, NULL, &error);
901 g_warning ("Error loading group file: %s", error->message);
902 g_clear_error (&error);
907 lines = g_strsplit (data, "\n", -1);
910 for (i = 0; lines[i]; i++)
912 gchar *line, **fields;
914 line = g_strstrip (lines[i]);
915 fields = g_strsplit (line, ":", -1);
916 if (g_strv_length (fields) == 4)
918 struct group *entry = malloc (sizeof (struct group));
920 entry->gr_name = g_strdup (fields[0]);
921 entry->gr_passwd = g_strdup (fields[1]);
922 entry->gr_gid = atoi (fields[2]);
923 entry->gr_mem = g_strsplit (fields[3], ",", -1);
924 group_entries = g_list_append (group_entries, entry);
932 getgrnam (const char *name)
938 for (link = group_entries; link; link = link->next)
940 struct group *entry = link->data;
941 if (strcmp (entry->gr_name, name) == 0)
957 for (link = group_entries; link; link = link->next)
959 struct group *entry = link->data;
960 if (entry->gr_gid == gid)
970 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
972 pam_handle_t *handle;
974 if (service_name == NULL || conversation == NULL || pamh == NULL)
975 return PAM_SYSTEM_ERR;
977 handle = *pamh = malloc (sizeof (pam_handle_t));
982 handle->id = g_strdup_printf ("PAM-%s", user);
984 handle->id = g_strdup ("PAM");
987 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
991 status = g_string_new ("");
992 g_string_append_printf (status, "%s START", handle->id);
993 g_string_append_printf (status, " SERVICE=%s", service_name);
995 g_string_append_printf (status, " USER=%s", user);
996 status_notify ("%s", status->str);
997 g_string_free (status, TRUE);
1000 handle->service_name = strdup (service_name);
1001 handle->user = user ? strdup (user) : NULL;
1002 handle->authtok = NULL;
1003 handle->ruser = NULL;
1005 handle->conversation.conv = conversation->conv;
1006 handle->conversation.appdata_ptr = conversation->appdata_ptr;
1007 handle->envlist = malloc (sizeof (char *) * 1);
1008 handle->envlist[0] = NULL;
1014 pam_authenticate (pam_handle_t *pamh, int flags)
1016 struct passwd *entry;
1017 gboolean password_matches = FALSE;
1020 return PAM_SYSTEM_ERR;
1023 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1027 status = g_string_new ("");
1028 g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
1029 if (flags & PAM_SILENT)
1030 g_string_append (status, " SILENT");
1031 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1032 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1034 status_notify ("%s", status->str);
1035 g_string_free (status, TRUE);
1038 if (strcmp (pamh->service_name, "test-remote") == 0)
1041 struct pam_message **msg;
1042 struct pam_response *resp = NULL;
1044 msg = malloc (sizeof (struct pam_message *) * 1);
1045 msg[0] = malloc (sizeof (struct pam_message));
1046 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1047 msg[0]->msg = "remote-login:";
1048 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1051 if (result != PAM_SUCCESS)
1055 return PAM_CONV_ERR;
1056 if (resp[0].resp == NULL)
1059 return PAM_CONV_ERR;
1064 pamh->ruser = strdup (resp[0].resp);
1065 free (resp[0].resp);
1068 msg = malloc (sizeof (struct pam_message *) * 1);
1069 msg[0] = malloc (sizeof (struct pam_message));
1070 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1071 msg[0]->msg = "remote-password:";
1072 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1075 if (result != PAM_SUCCESS)
1079 return PAM_CONV_ERR;
1080 if (resp[0].resp == NULL)
1083 return PAM_CONV_ERR;
1087 free (pamh->authtok);
1088 pamh->authtok = strdup (resp[0].resp);
1089 free (resp[0].resp);
1092 password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
1094 if (password_matches)
1097 return PAM_AUTH_ERR;
1100 /* Prompt for username */
1101 if (pamh->user == NULL)
1104 struct pam_message **msg;
1105 struct pam_response *resp = NULL;
1107 msg = malloc (sizeof (struct pam_message *) * 1);
1108 msg[0] = malloc (sizeof (struct pam_message));
1109 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1110 msg[0]->msg = LOGIN_PROMPT;
1111 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1114 if (result != PAM_SUCCESS)
1118 return PAM_CONV_ERR;
1119 if (resp[0].resp == NULL)
1122 return PAM_CONV_ERR;
1125 pamh->user = strdup (resp[0].resp);
1126 free (resp[0].resp);
1130 /* Crash on authenticate */
1131 if (strcmp (pamh->user, "crash-authenticate") == 0)
1132 kill (getpid (), SIGSEGV);
1134 /* Look up password database */
1135 entry = getpwnam (pamh->user);
1137 /* Prompt for password if required */
1138 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
1139 password_matches = TRUE;
1142 int i, n_messages = 0, password_index, result;
1143 struct pam_message **msg;
1144 struct pam_response *resp = NULL;
1146 msg = malloc (sizeof (struct pam_message *) * 5);
1147 if (strcmp (pamh->user, "info-prompt") == 0)
1149 msg[n_messages] = malloc (sizeof (struct pam_message));
1150 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1151 msg[n_messages]->msg = "Welcome to LightDM";
1154 if (strcmp (pamh->user, "multi-info-prompt") == 0)
1156 msg[n_messages] = malloc (sizeof (struct pam_message));
1157 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1158 msg[n_messages]->msg = "Welcome to LightDM";
1160 msg[n_messages] = malloc (sizeof (struct pam_message));
1161 msg[n_messages]->msg_style = PAM_ERROR_MSG;
1162 msg[n_messages]->msg = "This is an error";
1164 msg[n_messages] = malloc (sizeof (struct pam_message));
1165 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1166 msg[n_messages]->msg = "You should have seen three messages";
1169 if (strcmp (pamh->user, "multi-prompt") == 0)
1171 msg[n_messages] = malloc (sizeof (struct pam_message));
1172 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
1173 msg[n_messages]->msg = "Favorite Color:";
1176 msg[n_messages] = malloc (sizeof (struct pam_message));
1177 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
1178 msg[n_messages]->msg = "Password:";
1179 password_index = n_messages;
1181 result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1182 for (i = 0; i < n_messages; i++)
1185 if (result != PAM_SUCCESS)
1189 return PAM_CONV_ERR;
1190 if (resp[password_index].resp == NULL)
1193 return PAM_CONV_ERR;
1197 password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
1199 if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
1200 password_matches = strcmp ("blue", resp[0].resp) == 0;
1202 for (i = 0; i < n_messages; i++)
1205 free (resp[i].resp);
1209 /* Do two factor authentication */
1210 if (password_matches && strcmp (pamh->user, "two-factor") == 0)
1212 msg = malloc (sizeof (struct pam_message *) * 1);
1213 msg[0] = malloc (sizeof (struct pam_message));
1214 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1215 msg[0]->msg = "OTP:";
1217 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1222 return PAM_CONV_ERR;
1223 if (resp[0].resp == NULL)
1226 return PAM_CONV_ERR;
1228 password_matches = strcmp (resp[0].resp, "otp") == 0;
1229 free (resp[0].resp);
1234 /* Special user has home directory created on login */
1235 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
1236 g_mkdir_with_parents (entry->pw_dir, 0755);
1238 /* Special user 'change-user1' changes user on authentication */
1239 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
1241 g_free (pamh->user);
1242 pamh->user = g_strdup ("change-user2");
1245 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
1246 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
1248 g_free (pamh->user);
1249 pamh->user = g_strdup ("invalid-user");
1252 if (password_matches)
1255 return PAM_AUTH_ERR;
1259 get_env_value (const char *name_value, const char *name)
1263 for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
1264 if (name[j] == '\0' && name_value[j] == '=')
1265 return &name_value[j + 1];
1271 pam_putenv (pam_handle_t *pamh, const char *name_value)
1276 if (pamh == NULL || name_value == NULL)
1277 return PAM_SYSTEM_ERR;
1279 name = strdup (name_value);
1280 for (i = 0; name[i]; i++)
1283 for (i = 0; pamh->envlist[i]; i++)
1285 if (get_env_value (pamh->envlist[i], name))
1290 if (pamh->envlist[i])
1292 free (pamh->envlist[i]);
1293 pamh->envlist[i] = strdup (name_value);
1297 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
1298 pamh->envlist[i] = strdup (name_value);
1299 pamh->envlist[i + 1] = NULL;
1306 pam_getenv (pam_handle_t *pamh, const char *name)
1310 if (pamh == NULL || name == NULL)
1313 for (i = 0; pamh->envlist[i]; i++)
1316 value = get_env_value (pamh->envlist[i], name);
1325 pam_getenvlist (pam_handle_t *pamh)
1330 return pamh->envlist;
1334 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
1336 if (pamh == NULL || item == NULL)
1337 return PAM_SYSTEM_ERR;
1344 pamh->tty = strdup ((const char *) item);
1348 return PAM_BAD_ITEM;
1353 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
1355 if (pamh == NULL || item == NULL)
1356 return PAM_SYSTEM_ERR;
1361 *item = pamh->service_name;
1369 *item = pamh->authtok;
1373 *item = pamh->ruser;
1376 case PAM_USER_PROMPT:
1377 *item = LOGIN_PROMPT;
1385 *item = &pamh->conversation;
1389 return PAM_BAD_ITEM;
1394 pam_open_session (pam_handle_t *pamh, int flags)
1397 GError *error = NULL;
1400 return PAM_SYSTEM_ERR;
1403 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1407 status = g_string_new ("");
1408 g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1409 if (flags & PAM_SILENT)
1410 g_string_append (status, " SILENT");
1412 status_notify ("%s", status->str);
1413 g_string_free (status, TRUE);
1416 if (strcmp (pamh->user, "session-error") == 0)
1417 return PAM_SESSION_ERR;
1419 if (strcmp (pamh->user, "make-home-dir") == 0)
1421 struct passwd *entry;
1422 entry = getpwnam (pamh->user);
1423 g_mkdir_with_parents (entry->pw_dir, 0755);
1426 /* Open logind session */
1427 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
1428 "org.freedesktop.login1",
1429 "/org/freedesktop/login1",
1430 "org.freedesktop.login1.Manager",
1432 g_variant_new ("()", ""),
1433 G_VARIANT_TYPE ("(so)"),
1434 G_DBUS_CALL_FLAGS_NONE,
1443 g_variant_get (result, "(&so)", &id, NULL);
1444 e = g_strdup_printf ("XDG_SESSION_ID=%s", id);
1445 pam_putenv (pamh, e);
1447 g_variant_unref (result);
1450 g_printerr ("Failed to create logind session: %s\n", error->message);
1451 g_clear_error (&error);
1457 pam_close_session (pam_handle_t *pamh, int flags)
1460 return PAM_SYSTEM_ERR;
1463 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1467 status = g_string_new ("");
1468 g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1469 if (flags & PAM_SILENT)
1470 g_string_append (status, " SILENT");
1472 status_notify ("%s", status->str);
1473 g_string_free (status, TRUE);
1480 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1483 return PAM_SYSTEM_ERR;
1486 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1490 status = g_string_new ("");
1491 g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1492 if (flags & PAM_SILENT)
1493 g_string_append (status, " SILENT");
1494 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1495 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1497 status_notify ("%s", status->str);
1498 g_string_free (status, TRUE);
1502 return PAM_USER_UNKNOWN;
1504 if (strcmp (pamh->user, "denied") == 0)
1505 return PAM_PERM_DENIED;
1506 if (strcmp (pamh->user, "expired") == 0)
1507 return PAM_ACCT_EXPIRED;
1508 if (strcmp (pamh->user, "new-authtok") == 0)
1509 return PAM_NEW_AUTHTOK_REQD;
1515 pam_chauthtok (pam_handle_t *pamh, int flags)
1517 struct passwd *entry;
1519 struct pam_message **msg;
1520 struct pam_response *resp = NULL;
1523 return PAM_SYSTEM_ERR;
1526 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1530 status = g_string_new ("");
1531 g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1532 if (flags & PAM_SILENT)
1533 g_string_append (status, " SILENT");
1534 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1535 g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1537 status_notify ("%s", status->str);
1538 g_string_free (status, TRUE);
1541 msg = malloc (sizeof (struct pam_message *) * 1);
1542 msg[0] = malloc (sizeof (struct pam_message));
1543 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1544 if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1545 msg[0]->msg = "Enter new password (expired):";
1547 msg[0]->msg = "Enter new password:";
1548 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1551 if (result != PAM_SUCCESS)
1555 return PAM_CONV_ERR;
1556 if (resp[0].resp == NULL)
1559 return PAM_CONV_ERR;
1562 /* Update password database */
1563 entry = getpwnam (pamh->user);
1564 free (entry->pw_passwd);
1565 entry->pw_passwd = resp[0].resp;
1572 pam_setcred (pam_handle_t *pamh, int flags)
1577 return PAM_SYSTEM_ERR;
1580 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1584 status = g_string_new ("");
1585 g_string_append_printf (status, "%s SETCRED", pamh->id);
1586 if (flags & PAM_SILENT)
1587 g_string_append (status, " SILENT");
1588 if (flags & PAM_ESTABLISH_CRED)
1589 g_string_append (status, " ESTABLISH_CRED");
1590 if (flags & PAM_DELETE_CRED)
1591 g_string_append (status, " DELETE_CRED");
1592 if (flags & PAM_REINITIALIZE_CRED)
1593 g_string_append (status, " REINITIALIZE_CRED");
1594 if (flags & PAM_REFRESH_CRED)
1595 g_string_append (status, " REFRESH_CRED");
1597 status_notify ("%s", status->str);
1598 g_string_free (status, TRUE);
1601 /* Put the test directories into the path */
1602 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"));
1603 pam_putenv (pamh, e);
1606 if (strcmp (pamh->user, "cred-error") == 0)
1607 return PAM_CRED_ERR;
1608 if (strcmp (pamh->user, "cred-expired") == 0)
1609 return PAM_CRED_EXPIRED;
1610 if (strcmp (pamh->user, "cred-unavail") == 0)
1611 return PAM_CRED_UNAVAIL;
1613 /* Join special groups if requested */
1614 if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1616 struct group *group;
1620 group = getgrnam ("test-group");
1623 groups_length = getgroups (0, NULL);
1624 if (groups_length < 0)
1625 return PAM_SYSTEM_ERR;
1626 groups = malloc (sizeof (gid_t) * (groups_length + 1));
1627 groups_length = getgroups (groups_length, groups);
1628 if (groups_length < 0)
1629 return PAM_SYSTEM_ERR;
1630 groups[groups_length] = group->gr_gid;
1632 setgroups (groups_length, groups);
1636 /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1637 pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1644 pam_end (pam_handle_t *pamh, int pam_status)
1647 return PAM_SYSTEM_ERR;
1650 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1654 status = g_string_new ("");
1655 g_string_append_printf (status, "%s END", pamh->id);
1656 status_notify ("%s", status->str);
1657 g_string_free (status, TRUE);
1661 free (pamh->service_name);
1665 free (pamh->authtok);
1676 pam_strerror (pam_handle_t *pamh, int errnum)
1686 return "Critical error - immediate abort";
1688 return "Failed to load module";
1689 case PAM_SYMBOL_ERR:
1690 return "Symbol not found";
1691 case PAM_SERVICE_ERR:
1692 return "Error in service module";
1693 case PAM_SYSTEM_ERR:
1694 return "System error";
1696 return "Memory buffer error";
1697 case PAM_PERM_DENIED:
1698 return "Permission denied";
1700 return "Authentication failure";
1701 case PAM_CRED_INSUFFICIENT:
1702 return "Insufficient credentials to access authentication data";
1703 case PAM_AUTHINFO_UNAVAIL:
1704 return "Authentication service cannot retrieve authentication info";
1705 case PAM_USER_UNKNOWN:
1706 return "User not known to the underlying authentication module";
1708 return "Have exhausted maximum number of retries for service";
1709 case PAM_NEW_AUTHTOK_REQD:
1710 return "Authentication token is no longer valid; new one required";
1711 case PAM_ACCT_EXPIRED:
1712 return "User account has expired";
1713 case PAM_SESSION_ERR:
1714 return "Cannot make/remove an entry for the specified session";
1715 case PAM_CRED_UNAVAIL:
1716 return "Authentication service cannot retrieve user credentials";
1717 case PAM_CRED_EXPIRED:
1718 return "User credentials expired";
1720 return "Failure setting user credentials";
1721 case PAM_NO_MODULE_DATA:
1722 return "No module specific data is present";
1724 return "Bad item passed to pam_*_item()";
1726 return "Conversation error";
1727 case PAM_AUTHTOK_ERR:
1728 return "Authentication token manipulation error";
1729 case PAM_AUTHTOK_RECOVERY_ERR:
1730 return "Authentication information cannot be recovered";
1731 case PAM_AUTHTOK_LOCK_BUSY:
1732 return "Authentication token lock busy";
1733 case PAM_AUTHTOK_DISABLE_AGING:
1734 return "Authentication token aging disabled";
1736 return "Failed preliminary check by password service";
1738 return "The return value should be ignored by PAM dispatch";
1739 case PAM_MODULE_UNKNOWN:
1740 return "Module is unknown";
1741 case PAM_AUTHTOK_EXPIRED:
1742 return "Authentication token expired";
1743 case PAM_CONV_AGAIN:
1744 return "Conversation is waiting for event";
1745 case PAM_INCOMPLETE:
1746 return "Application needs to call libpam again";
1748 return "Unknown PAM error";
1758 pututxline (const struct utmpx *ut)
1761 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1765 status = g_string_new ("UTMP");
1766 switch (ut->ut_type)
1769 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1772 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1775 g_string_append_printf (status, " TYPE=USER_PROCESS");
1778 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1781 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1784 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1786 g_string_append_printf (status, " ID=%s", ut->ut_id);
1788 g_string_append_printf (status, " USER=%s", ut->ut_user);
1790 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1791 status_notify ("%s", status->str);
1792 g_string_free (status, TRUE);
1795 return (struct utmpx *)ut;
1804 updwtmp (const char *wtmp_file, const struct utmp *ut)
1807 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1811 status = g_string_new ("WTMP");
1812 g_string_append_printf (status, " FILE=%s", wtmp_file);
1813 switch (ut->ut_type)
1816 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1819 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1822 g_string_append_printf (status, " TYPE=USER_PROCESS");
1825 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1828 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1831 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1833 g_string_append_printf (status, " ID=%s", ut->ut_id);
1835 g_string_append_printf (status, " USER=%s", ut->ut_user);
1837 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1838 status_notify ("%s", status->str);
1839 g_string_free (status, TRUE);
1843 struct xcb_connection_t
1851 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1853 xcb_connection_t *c;
1855 GError *error = NULL;
1857 c = malloc (sizeof (xcb_connection_t));
1858 c->display = g_strdup (display);
1861 if (display == NULL)
1862 display = getenv ("DISPLAY");
1863 if (display == NULL)
1864 c->error = XCB_CONN_CLOSED_PARSE_ERR;
1868 c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1870 g_printerr ("%s\n", error->message);
1871 g_clear_error (&error);
1872 if (c->socket == NULL)
1873 c->error = XCB_CONN_ERROR;
1879 GSocketAddress *address;
1881 /* Skip the hostname, we'll assume it's localhost */
1882 d = g_strdup_printf (".x%s", strchr (display, ':'));
1884 socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1886 address = g_unix_socket_address_new (socket_path);
1887 if (!g_socket_connect (c->socket, address, NULL, &error))
1888 c->error = XCB_CONN_ERROR;
1889 g_object_unref (address);
1891 g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1892 g_free (socket_path);
1893 g_clear_error (&error);
1896 // FIXME: Send auth info
1905 xcb_connect (const char *displayname, int *screenp)
1907 return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1911 xcb_connection_has_error (xcb_connection_t *c)
1917 xcb_disconnect (xcb_connection_t *c)
1921 g_object_unref (c->socket);