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;
76 gethostname (char *name, size_t len)
78 snprintf (name, len, "lightdm-test");
95 initgroups (const char *user, gid_t group)
106 getgroups (int size, gid_t list[])
108 const gchar *group_list;
112 /* Get groups we are a member of */
113 group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
116 groups = g_strsplit (group_list, ",", -1);
117 groups_length = g_strv_length (groups);
123 if (groups_length > size)
128 for (i = 0; groups[i]; i++)
129 list[i] = atoi (groups[i]);
133 return groups_length;
137 setgroups (size_t size, const gid_t *list)
142 group_list = g_string_new ("");
143 for (i = 0; i < size; i++)
146 g_string_append (group_list, ",");
147 g_string_append_printf (group_list, "%d", list[i]);
149 g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
150 g_string_free (group_list, TRUE);
168 setresgid (gid_t rgid, gid_t ugid, gid_t sgid)
186 setresuid (uid_t ruid, uid_t uuid, uid_t suid)
192 redirect_path (const gchar *path)
194 // Don't redirect if inside the running directory
195 if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
196 return g_strdup (path);
198 if (g_str_has_prefix (path, SYSCONFDIR))
199 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
201 if (g_str_has_prefix (path, LOCALSTATEDIR))
202 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
204 if (g_str_has_prefix (path, DATADIR))
205 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
207 // Don't redirect if inside the build directory
208 if (g_str_has_prefix (path, BUILDDIR))
209 return g_strdup (path);
211 if (g_str_has_prefix (path, "/tmp"))
212 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
214 if (g_str_has_prefix (path, "/run"))
215 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "run", path + strlen ("/run"), NULL);
217 if (g_str_has_prefix (path, "/etc/xdg"))
218 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
220 if (g_str_has_prefix (path, "/usr/share/lightdm"))
221 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
223 return g_strdup (path);
228 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
230 int (*_open) (const char *pathname, int flags, mode_t mode);
231 gchar *new_path = NULL;
234 _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
236 if (strcmp (pathname, "/dev/tty0") == 0)
240 tty_fd = _open ("/dev/null", flags, mode);
241 fcntl (tty_fd, F_SETFD, FD_CLOEXEC);
246 new_path = redirect_path (pathname);
247 fd = _open (new_path, flags, mode);
254 open (const char *pathname, int flags, ...)
260 va_start (ap, flags);
261 mode = va_arg (ap, mode_t);
264 return open_wrapper ("open", pathname, flags, mode);
268 open64 (const char *pathname, int flags, ...)
274 va_start (ap, flags);
275 mode = va_arg (ap, mode_t);
278 return open_wrapper ("open64", pathname, flags, mode);
282 fopen (const char *path, const char *mode)
284 FILE *(*_fopen) (const char *pathname, const char *mode);
285 gchar *new_path = NULL;
288 _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
290 new_path = redirect_path (path);
291 result = _fopen (new_path, mode);
298 unlinkat (int dirfd, const char *pathname, int flags)
300 int (*_unlinkat) (int dirfd, const char *pathname, int flags);
301 gchar *new_path = NULL;
304 _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
306 new_path = redirect_path (pathname);
307 result = _unlinkat (dirfd, new_path, flags);
314 creat (const char *pathname, mode_t mode)
316 int (*_creat) (const char *pathname, mode_t mode);
317 gchar *new_path = NULL;
320 _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
322 new_path = redirect_path (pathname);
323 result = _creat (new_path, mode);
330 creat64 (const char *pathname, mode_t mode)
332 int (*_creat64) (const char *pathname, mode_t mode);
333 gchar *new_path = NULL;
336 _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
338 new_path = redirect_path (pathname);
339 result = _creat64 (new_path, mode);
346 access (const char *pathname, int mode)
348 int (*_access) (const char *pathname, int mode);
349 gchar *new_path = NULL;
352 _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
354 if (strcmp (pathname, "/dev/tty0") == 0)
356 if (strcmp (pathname, "/sys/class/tty/tty0/active") == 0)
359 new_path = redirect_path (pathname);
360 ret = _access (new_path, mode);
367 stat (const char *path, struct stat *buf)
369 int (*_stat) (const char *path, struct stat *buf);
370 gchar *new_path = NULL;
373 _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
375 new_path = redirect_path (path);
376 ret = _stat (new_path, buf);
383 stat64 (const char *path, struct stat64 *buf)
385 int (*_stat64) (const char *path, struct stat64 *buf);
386 gchar *new_path = NULL;
389 _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
391 new_path = redirect_path (path);
392 ret = _stat64 (new_path, buf);
399 __xstat (int version, const char *path, struct stat *buf)
401 int (*___xstat) (int version, const char *path, struct stat *buf);
402 gchar *new_path = NULL;
405 ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
407 new_path = redirect_path (path);
408 ret = ___xstat (version, new_path, buf);
415 __xstat64 (int version, const char *path, struct stat64 *buf)
417 int (*___xstat64) (int version, const char *path, struct stat64 *buf);
418 gchar *new_path = NULL;
421 ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
423 new_path = redirect_path (path);
424 ret = ___xstat64 (version, new_path, buf);
431 __fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
433 int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
434 gchar *new_path = NULL;
437 ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
439 new_path = redirect_path (pathname);
440 ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
447 __fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
449 int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
450 gchar *new_path = NULL;
453 ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
455 new_path = redirect_path (pathname);
456 ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
463 opendir (const char *name)
465 DIR *(*_opendir) (const char *name);
466 gchar *new_path = NULL;
469 _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
471 new_path = redirect_path (name);
472 result = _opendir (new_path);
479 mkdir (const char *pathname, mode_t mode)
481 int (*_mkdir) (const char *pathname, mode_t mode);
482 gchar *new_path = NULL;
485 _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
487 new_path = redirect_path (pathname);
488 result = _mkdir (new_path, mode);
495 chown (const char *pathname, uid_t owner, gid_t group)
497 /* Just fake it - we're not root */
502 chmod (const char *path, mode_t mode)
504 int (*_chmod) (const char *path, mode_t mode);
505 gchar *new_path = NULL;
508 _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
510 new_path = redirect_path (path);
511 result = _chmod (new_path, mode);
518 ioctl (int d, unsigned long request, ...)
520 int (*_ioctl) (int d, int request, ...);
522 _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
523 if (d > 0 && d == tty_fd)
525 struct vt_stat *vt_state;
532 va_start (ap, request);
533 vt_state = va_arg (ap, struct vt_stat *);
535 vt_state->v_active = active_vt;
538 va_start (ap, request);
539 vt = va_arg (ap, int);
545 status_notify ("VT ACTIVATE VT=%d", active_vt);
558 va_start (ap, request);
559 data = va_arg (ap, void *);
561 return _ioctl (d, request, data);
566 add_port_redirect (int requested_port, int redirected_port)
569 gchar *path, *name, *data;
571 file = g_key_file_new ();
572 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
573 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
575 name = g_strdup_printf ("%d", requested_port);
576 g_key_file_set_integer (file, name, "redirected", redirected_port);
579 data = g_key_file_to_data (file, NULL, NULL);
580 g_file_set_contents (path, data, -1, NULL);
584 g_key_file_free (file);
588 find_port_redirect (int port)
594 file = g_key_file_new ();
595 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), ".port-redirects", NULL);
596 g_key_file_load_from_file (file, path, G_KEY_FILE_NONE, NULL);
599 name = g_strdup_printf ("%d", port);
600 redirected_port = g_key_file_get_integer (file, name, "redirected", NULL);
602 g_key_file_free (file);
604 return redirected_port;
608 bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
610 int port = 0, redirected_port = 0;
611 int (*_bind) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
612 const struct sockaddr *modified_addr = addr;
613 struct sockaddr_in temp_addr;
614 struct sockaddr_in6 temp_addr6;
617 _bind = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "bind");
619 switch (addr->sa_family)
622 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
623 redirected_port = find_port_redirect (port);
624 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
625 modified_addr = (struct sockaddr *) &temp_addr;
626 if (redirected_port != 0)
627 temp_addr.sin_port = htons (redirected_port);
629 temp_addr.sin_port = 0;
632 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
633 redirected_port = find_port_redirect (port);
634 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
635 modified_addr = (struct sockaddr *) &temp_addr6;
636 if (redirected_port != 0)
637 temp_addr6.sin6_port = htons (redirected_port);
639 temp_addr6.sin6_port = 0;
643 retval = _bind (sockfd, modified_addr, addrlen);
645 socklen_t temp_addr_len;
646 switch (addr->sa_family)
649 temp_addr_len = sizeof (temp_addr);
650 getsockname (sockfd, &temp_addr, &temp_addr_len);
651 if (redirected_port == 0)
653 redirected_port = ntohs (temp_addr.sin_port);
654 add_port_redirect (port, redirected_port);
658 temp_addr_len = sizeof (temp_addr6);
659 getsockname (sockfd, &temp_addr6, &temp_addr_len);
660 if (redirected_port == 0)
662 redirected_port = ntohs (temp_addr6.sin6_port);
663 add_port_redirect (port, redirected_port);
672 connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
674 int port, redirected_port;
675 const struct sockaddr *modified_addr = addr;
676 struct sockaddr_in temp_addr;
677 struct sockaddr_in6 temp_addr6;
678 int (*_connect) (int sockfd, const struct sockaddr *addr, socklen_t addrlen);
680 _connect = (int (*)(int sockfd, const struct sockaddr *addr, socklen_t addrlen)) dlsym (RTLD_NEXT, "connect");
682 switch (addr->sa_family)
685 port = ntohs (((const struct sockaddr_in *) addr)->sin_port);
686 redirected_port = find_port_redirect (port);
687 if (redirected_port != 0)
689 memcpy (&temp_addr, addr, sizeof (struct sockaddr_in));
690 temp_addr.sin_port = htons (redirected_port);
691 modified_addr = (struct sockaddr *) &temp_addr;
695 port = ntohs (((const struct sockaddr_in6 *) addr)->sin6_port);
696 redirected_port = find_port_redirect (port);
697 if (redirected_port != 0)
699 memcpy (&temp_addr6, addr, sizeof (struct sockaddr_in6));
700 temp_addr6.sin6_port = htons (redirected_port);
701 modified_addr = (struct sockaddr *) &temp_addr6;
706 return _connect (sockfd, modified_addr, addrlen);
710 sendto (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
712 int port, redirected_port;
713 const struct sockaddr *modified_addr = dest_addr;
714 struct sockaddr_in temp_addr;
715 struct sockaddr_in6 temp_addr6;
716 ssize_t (*_sendto) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
718 _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");
720 switch (dest_addr->sa_family)
723 port = ntohs (((const struct sockaddr_in *) dest_addr)->sin_port);
724 redirected_port = find_port_redirect (port);
725 if (redirected_port != 0)
727 memcpy (&temp_addr, dest_addr, sizeof (struct sockaddr_in));
728 temp_addr.sin_port = htons (redirected_port);
729 modified_addr = (struct sockaddr *) &temp_addr;
733 port = ntohs (((const struct sockaddr_in6 *) dest_addr)->sin6_port);
734 redirected_port = find_port_redirect (port);
735 if (redirected_port != 0)
737 memcpy (&temp_addr6, dest_addr, sizeof (struct sockaddr_in6));
738 temp_addr6.sin6_port = htons (redirected_port);
739 modified_addr = (struct sockaddr *) &temp_addr6;
744 return _sendto (sockfd, buf, len, flags, modified_addr, addrlen);
750 int (*_close) (int fd);
752 if (fd > 0 && fd == tty_fd)
755 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
761 free_user (gpointer data)
763 struct passwd *entry = data;
765 g_free (entry->pw_name);
766 g_free (entry->pw_passwd);
767 g_free (entry->pw_gecos);
768 g_free (entry->pw_dir);
769 g_free (entry->pw_shell);
774 load_passwd_file (void)
776 gchar *path, *data = NULL, **lines;
778 GError *error = NULL;
780 g_list_free_full (user_entries, free_user);
782 getpwent_link = NULL;
784 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
785 g_file_get_contents (path, &data, NULL, &error);
788 g_warning ("Error loading passwd file: %s", error->message);
789 g_clear_error (&error);
794 lines = g_strsplit (data, "\n", -1);
797 for (i = 0; lines[i]; i++)
799 gchar *line, **fields;
801 line = g_strstrip (lines[i]);
802 fields = g_strsplit (line, ":", -1);
803 if (g_strv_length (fields) == 7)
805 struct passwd *entry = malloc (sizeof (struct passwd));
807 entry->pw_name = g_strdup (fields[0]);
808 entry->pw_passwd = g_strdup (fields[1]);
809 entry->pw_uid = atoi (fields[2]);
810 entry->pw_gid = atoi (fields[3]);
811 entry->pw_gecos = g_strdup (fields[4]);
812 entry->pw_dir = g_strdup (fields[5]);
813 entry->pw_shell = g_strdup (fields[6]);
814 user_entries = g_list_append (user_entries, entry);
824 if (getpwent_link == NULL)
827 if (user_entries == NULL)
829 getpwent_link = user_entries;
833 if (getpwent_link->next == NULL)
835 getpwent_link = getpwent_link->next;
838 return getpwent_link->data;
844 getpwent_link = NULL;
850 getpwent_link = NULL;
854 getpwnam (const char *name)
863 for (link = user_entries; link; link = link->next)
865 struct passwd *entry = link->data;
866 if (strcmp (entry->pw_name, name) == 0)
882 for (link = user_entries; link; link = link->next)
884 struct passwd *entry = link->data;
885 if (entry->pw_uid == uid)
895 free_group (gpointer data)
897 struct group *entry = data;
899 g_free (entry->gr_name);
900 g_free (entry->gr_passwd);
901 g_strfreev (entry->gr_mem);
906 load_group_file (void)
908 gchar *path, *data = NULL, **lines;
910 GError *error = NULL;
912 g_list_free_full (group_entries, free_group);
913 group_entries = NULL;
915 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
916 g_file_get_contents (path, &data, NULL, &error);
919 g_warning ("Error loading group file: %s", error->message);
920 g_clear_error (&error);
925 lines = g_strsplit (data, "\n", -1);
928 for (i = 0; lines[i]; i++)
930 gchar *line, **fields;
932 line = g_strstrip (lines[i]);
933 fields = g_strsplit (line, ":", -1);
934 if (g_strv_length (fields) == 4)
936 struct group *entry = malloc (sizeof (struct group));
938 entry->gr_name = g_strdup (fields[0]);
939 entry->gr_passwd = g_strdup (fields[1]);
940 entry->gr_gid = atoi (fields[2]);
941 entry->gr_mem = g_strsplit (fields[3], ",", -1);
942 group_entries = g_list_append (group_entries, entry);
950 getgrnam (const char *name)
956 for (link = group_entries; link; link = link->next)
958 struct group *entry = link->data;
959 if (strcmp (entry->gr_name, name) == 0)
975 for (link = group_entries; link; link = link->next)
977 struct group *entry = link->data;
978 if (entry->gr_gid == gid)
988 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
990 pam_handle_t *handle;
992 if (service_name == NULL || conversation == NULL || pamh == NULL)
993 return PAM_SYSTEM_ERR;
995 handle = *pamh = malloc (sizeof (pam_handle_t));
1000 handle->id = g_strdup_printf ("PAM-%s", user);
1002 handle->id = g_strdup ("PAM");
1005 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1009 status = g_string_new ("");
1010 g_string_append_printf (status, "%s START", handle->id);
1011 g_string_append_printf (status, " SERVICE=%s", service_name);
1013 g_string_append_printf (status, " USER=%s", user);
1014 status_notify ("%s", status->str);
1015 g_string_free (status, TRUE);
1018 handle->service_name = strdup (service_name);
1019 handle->user = user ? strdup (user) : NULL;
1020 handle->authtok = NULL;
1021 handle->ruser = NULL;
1023 handle->conversation.conv = conversation->conv;
1024 handle->conversation.appdata_ptr = conversation->appdata_ptr;
1025 handle->envlist = malloc (sizeof (char *) * 1);
1026 handle->envlist[0] = NULL;
1032 pam_authenticate (pam_handle_t *pamh, int flags)
1034 struct passwd *entry;
1035 gboolean password_matches = FALSE;
1038 return PAM_SYSTEM_ERR;
1041 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1045 status = g_string_new ("");
1046 g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
1047 if (flags & PAM_SILENT)
1048 g_string_append (status, " SILENT");
1049 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1050 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1052 status_notify ("%s", status->str);
1053 g_string_free (status, TRUE);
1056 if (strcmp (pamh->service_name, "test-remote") == 0)
1059 struct pam_message **msg;
1060 struct pam_response *resp = NULL;
1062 msg = malloc (sizeof (struct pam_message *) * 1);
1063 msg[0] = malloc (sizeof (struct pam_message));
1064 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1065 msg[0]->msg = "remote-login:";
1066 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1069 if (result != PAM_SUCCESS)
1073 return PAM_CONV_ERR;
1074 if (resp[0].resp == NULL)
1077 return PAM_CONV_ERR;
1082 pamh->ruser = strdup (resp[0].resp);
1083 free (resp[0].resp);
1086 msg = malloc (sizeof (struct pam_message *) * 1);
1087 msg[0] = malloc (sizeof (struct pam_message));
1088 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1089 msg[0]->msg = "remote-password:";
1090 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1093 if (result != PAM_SUCCESS)
1097 return PAM_CONV_ERR;
1098 if (resp[0].resp == NULL)
1101 return PAM_CONV_ERR;
1105 free (pamh->authtok);
1106 pamh->authtok = strdup (resp[0].resp);
1107 free (resp[0].resp);
1110 password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
1112 if (password_matches)
1115 return PAM_AUTH_ERR;
1118 /* Prompt for username */
1119 if (pamh->user == NULL)
1122 struct pam_message **msg;
1123 struct pam_response *resp = NULL;
1125 msg = malloc (sizeof (struct pam_message *) * 1);
1126 msg[0] = malloc (sizeof (struct pam_message));
1127 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1128 msg[0]->msg = LOGIN_PROMPT;
1129 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1132 if (result != PAM_SUCCESS)
1136 return PAM_CONV_ERR;
1137 if (resp[0].resp == NULL)
1140 return PAM_CONV_ERR;
1143 pamh->user = strdup (resp[0].resp);
1144 free (resp[0].resp);
1148 /* Crash on authenticate */
1149 if (strcmp (pamh->user, "crash-authenticate") == 0)
1150 kill (getpid (), SIGSEGV);
1152 /* Look up password database */
1153 entry = getpwnam (pamh->user);
1155 /* Prompt for password if required */
1156 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
1157 password_matches = TRUE;
1160 int i, n_messages = 0, password_index, result;
1161 struct pam_message **msg;
1162 struct pam_response *resp = NULL;
1164 msg = malloc (sizeof (struct pam_message *) * 5);
1165 if (strcmp (pamh->user, "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";
1172 if (strcmp (pamh->user, "multi-info-prompt") == 0)
1174 msg[n_messages] = malloc (sizeof (struct pam_message));
1175 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1176 msg[n_messages]->msg = "Welcome to LightDM";
1178 msg[n_messages] = malloc (sizeof (struct pam_message));
1179 msg[n_messages]->msg_style = PAM_ERROR_MSG;
1180 msg[n_messages]->msg = "This is an error";
1182 msg[n_messages] = malloc (sizeof (struct pam_message));
1183 msg[n_messages]->msg_style = PAM_TEXT_INFO;
1184 msg[n_messages]->msg = "You should have seen three messages";
1187 if (strcmp (pamh->user, "multi-prompt") == 0)
1189 msg[n_messages] = malloc (sizeof (struct pam_message));
1190 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
1191 msg[n_messages]->msg = "Favorite Color:";
1194 msg[n_messages] = malloc (sizeof (struct pam_message));
1195 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
1196 msg[n_messages]->msg = "Password:";
1197 password_index = n_messages;
1199 result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1200 for (i = 0; i < n_messages; i++)
1203 if (result != PAM_SUCCESS)
1207 return PAM_CONV_ERR;
1208 if (resp[password_index].resp == NULL)
1211 return PAM_CONV_ERR;
1215 password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
1217 if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
1218 password_matches = strcmp ("blue", resp[0].resp) == 0;
1220 for (i = 0; i < n_messages; i++)
1223 free (resp[i].resp);
1227 /* Do two factor authentication */
1228 if (password_matches && strcmp (pamh->user, "two-factor") == 0)
1230 msg = malloc (sizeof (struct pam_message *) * 1);
1231 msg[0] = malloc (sizeof (struct pam_message));
1232 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1233 msg[0]->msg = "OTP:";
1235 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1238 if (result != PAM_SUCCESS)
1242 return PAM_CONV_ERR;
1243 if (resp[0].resp == NULL)
1246 return PAM_CONV_ERR;
1248 password_matches = strcmp (resp[0].resp, "otp") == 0;
1249 free (resp[0].resp);
1254 /* Special user has home directory created on login */
1255 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
1256 g_mkdir_with_parents (entry->pw_dir, 0755);
1258 /* Special user 'change-user1' changes user on authentication */
1259 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
1261 g_free (pamh->user);
1262 pamh->user = g_strdup ("change-user2");
1265 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
1266 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
1268 g_free (pamh->user);
1269 pamh->user = g_strdup ("invalid-user");
1272 if (password_matches)
1275 return PAM_AUTH_ERR;
1279 get_env_value (const char *name_value, const char *name)
1283 for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
1284 if (name[j] == '\0' && name_value[j] == '=')
1285 return &name_value[j + 1];
1291 pam_putenv (pam_handle_t *pamh, const char *name_value)
1296 if (pamh == NULL || name_value == NULL)
1297 return PAM_SYSTEM_ERR;
1299 name = strdup (name_value);
1300 for (i = 0; name[i]; i++)
1303 for (i = 0; pamh->envlist[i]; i++)
1305 if (get_env_value (pamh->envlist[i], name))
1310 if (pamh->envlist[i])
1312 free (pamh->envlist[i]);
1313 pamh->envlist[i] = strdup (name_value);
1317 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
1318 pamh->envlist[i] = strdup (name_value);
1319 pamh->envlist[i + 1] = NULL;
1326 pam_getenv (pam_handle_t *pamh, const char *name)
1330 if (pamh == NULL || name == NULL)
1333 for (i = 0; pamh->envlist[i]; i++)
1336 value = get_env_value (pamh->envlist[i], name);
1345 pam_getenvlist (pam_handle_t *pamh)
1350 return pamh->envlist;
1354 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
1356 if (pamh == NULL || item == NULL)
1357 return PAM_SYSTEM_ERR;
1364 pamh->tty = strdup ((const char *) item);
1368 return PAM_BAD_ITEM;
1373 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
1375 if (pamh == NULL || item == NULL)
1376 return PAM_SYSTEM_ERR;
1381 *item = pamh->service_name;
1389 *item = pamh->authtok;
1393 *item = pamh->ruser;
1396 case PAM_USER_PROMPT:
1397 *item = LOGIN_PROMPT;
1405 *item = &pamh->conversation;
1409 return PAM_BAD_ITEM;
1414 pam_open_session (pam_handle_t *pamh, int flags)
1417 GError *error = NULL;
1420 return PAM_SYSTEM_ERR;
1423 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1427 status = g_string_new ("");
1428 g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1429 if (flags & PAM_SILENT)
1430 g_string_append (status, " SILENT");
1432 status_notify ("%s", status->str);
1433 g_string_free (status, TRUE);
1436 if (strcmp (pamh->user, "session-error") == 0)
1437 return PAM_SESSION_ERR;
1439 if (strcmp (pamh->user, "make-home-dir") == 0)
1441 struct passwd *entry;
1442 entry = getpwnam (pamh->user);
1443 g_mkdir_with_parents (entry->pw_dir, 0755);
1446 /* Open logind session */
1447 result = g_dbus_connection_call_sync (g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL),
1448 "org.freedesktop.login1",
1449 "/org/freedesktop/login1",
1450 "org.freedesktop.login1.Manager",
1452 g_variant_new ("()", ""),
1453 G_VARIANT_TYPE ("(so)"),
1454 G_DBUS_CALL_FLAGS_NONE,
1463 g_variant_get (result, "(&so)", &id, NULL);
1464 e = g_strdup_printf ("XDG_SESSION_ID=%s", id);
1465 pam_putenv (pamh, e);
1467 g_variant_unref (result);
1470 g_printerr ("Failed to create logind session: %s\n", error->message);
1471 g_clear_error (&error);
1477 pam_close_session (pam_handle_t *pamh, int flags)
1480 return PAM_SYSTEM_ERR;
1483 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1487 status = g_string_new ("");
1488 g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1489 if (flags & PAM_SILENT)
1490 g_string_append (status, " SILENT");
1492 status_notify ("%s", status->str);
1493 g_string_free (status, TRUE);
1500 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1503 return PAM_SYSTEM_ERR;
1506 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1510 status = g_string_new ("");
1511 g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1512 if (flags & PAM_SILENT)
1513 g_string_append (status, " SILENT");
1514 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1515 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1517 status_notify ("%s", status->str);
1518 g_string_free (status, TRUE);
1522 return PAM_USER_UNKNOWN;
1524 if (strcmp (pamh->user, "denied") == 0)
1525 return PAM_PERM_DENIED;
1526 if (strcmp (pamh->user, "expired") == 0)
1527 return PAM_ACCT_EXPIRED;
1528 if (strcmp (pamh->user, "new-authtok") == 0)
1529 return PAM_NEW_AUTHTOK_REQD;
1535 pam_chauthtok (pam_handle_t *pamh, int flags)
1537 struct passwd *entry;
1539 struct pam_message **msg;
1540 struct pam_response *resp = NULL;
1543 return PAM_SYSTEM_ERR;
1546 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1550 status = g_string_new ("");
1551 g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1552 if (flags & PAM_SILENT)
1553 g_string_append (status, " SILENT");
1554 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1555 g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1557 status_notify ("%s", status->str);
1558 g_string_free (status, TRUE);
1561 msg = malloc (sizeof (struct pam_message *) * 1);
1562 msg[0] = malloc (sizeof (struct pam_message));
1563 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1564 if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1565 msg[0]->msg = "Enter new password (expired):";
1567 msg[0]->msg = "Enter new password:";
1568 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1571 if (result != PAM_SUCCESS)
1575 return PAM_CONV_ERR;
1576 if (resp[0].resp == NULL)
1579 return PAM_CONV_ERR;
1582 /* Update password database */
1583 entry = getpwnam (pamh->user);
1584 free (entry->pw_passwd);
1585 entry->pw_passwd = resp[0].resp;
1592 pam_setcred (pam_handle_t *pamh, int flags)
1597 return PAM_SYSTEM_ERR;
1600 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1604 status = g_string_new ("");
1605 g_string_append_printf (status, "%s SETCRED", pamh->id);
1606 if (flags & PAM_SILENT)
1607 g_string_append (status, " SILENT");
1608 if (flags & PAM_ESTABLISH_CRED)
1609 g_string_append (status, " ESTABLISH_CRED");
1610 if (flags & PAM_DELETE_CRED)
1611 g_string_append (status, " DELETE_CRED");
1612 if (flags & PAM_REINITIALIZE_CRED)
1613 g_string_append (status, " REINITIALIZE_CRED");
1614 if (flags & PAM_REFRESH_CRED)
1615 g_string_append (status, " REFRESH_CRED");
1617 status_notify ("%s", status->str);
1618 g_string_free (status, TRUE);
1621 /* Put the test directories into the path */
1622 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"));
1623 pam_putenv (pamh, e);
1626 if (strcmp (pamh->user, "cred-error") == 0)
1627 return PAM_CRED_ERR;
1628 if (strcmp (pamh->user, "cred-expired") == 0)
1629 return PAM_CRED_EXPIRED;
1630 if (strcmp (pamh->user, "cred-unavail") == 0)
1631 return PAM_CRED_UNAVAIL;
1633 /* Join special groups if requested */
1634 if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1636 struct group *group;
1640 group = getgrnam ("test-group");
1643 groups_length = getgroups (0, NULL);
1644 if (groups_length < 0)
1645 return PAM_SYSTEM_ERR;
1646 groups = malloc (sizeof (gid_t) * (groups_length + 1));
1647 groups_length = getgroups (groups_length, groups);
1648 if (groups_length < 0)
1649 return PAM_SYSTEM_ERR;
1650 groups[groups_length] = group->gr_gid;
1652 setgroups (groups_length, groups);
1656 /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1657 pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1664 pam_end (pam_handle_t *pamh, int pam_status)
1667 return PAM_SYSTEM_ERR;
1670 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1674 status = g_string_new ("");
1675 g_string_append_printf (status, "%s END", pamh->id);
1676 status_notify ("%s", status->str);
1677 g_string_free (status, TRUE);
1681 free (pamh->service_name);
1685 free (pamh->authtok);
1696 pam_strerror (pam_handle_t *pamh, int errnum)
1706 return "Critical error - immediate abort";
1708 return "Failed to load module";
1709 case PAM_SYMBOL_ERR:
1710 return "Symbol not found";
1711 case PAM_SERVICE_ERR:
1712 return "Error in service module";
1713 case PAM_SYSTEM_ERR:
1714 return "System error";
1716 return "Memory buffer error";
1717 case PAM_PERM_DENIED:
1718 return "Permission denied";
1720 return "Authentication failure";
1721 case PAM_CRED_INSUFFICIENT:
1722 return "Insufficient credentials to access authentication data";
1723 case PAM_AUTHINFO_UNAVAIL:
1724 return "Authentication service cannot retrieve authentication info";
1725 case PAM_USER_UNKNOWN:
1726 return "User not known to the underlying authentication module";
1728 return "Have exhausted maximum number of retries for service";
1729 case PAM_NEW_AUTHTOK_REQD:
1730 return "Authentication token is no longer valid; new one required";
1731 case PAM_ACCT_EXPIRED:
1732 return "User account has expired";
1733 case PAM_SESSION_ERR:
1734 return "Cannot make/remove an entry for the specified session";
1735 case PAM_CRED_UNAVAIL:
1736 return "Authentication service cannot retrieve user credentials";
1737 case PAM_CRED_EXPIRED:
1738 return "User credentials expired";
1740 return "Failure setting user credentials";
1741 case PAM_NO_MODULE_DATA:
1742 return "No module specific data is present";
1744 return "Bad item passed to pam_*_item()";
1746 return "Conversation error";
1747 case PAM_AUTHTOK_ERR:
1748 return "Authentication token manipulation error";
1749 case PAM_AUTHTOK_RECOVERY_ERR:
1750 return "Authentication information cannot be recovered";
1751 case PAM_AUTHTOK_LOCK_BUSY:
1752 return "Authentication token lock busy";
1753 case PAM_AUTHTOK_DISABLE_AGING:
1754 return "Authentication token aging disabled";
1756 return "Failed preliminary check by password service";
1758 return "The return value should be ignored by PAM dispatch";
1759 case PAM_MODULE_UNKNOWN:
1760 return "Module is unknown";
1761 case PAM_AUTHTOK_EXPIRED:
1762 return "Authentication token expired";
1763 case PAM_CONV_AGAIN:
1764 return "Conversation is waiting for event";
1765 case PAM_INCOMPLETE:
1766 return "Application needs to call libpam again";
1768 return "Unknown PAM error";
1778 pututxline (const struct utmpx *ut)
1781 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1785 status = g_string_new ("UTMP");
1786 switch (ut->ut_type)
1789 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1792 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1795 g_string_append_printf (status, " TYPE=USER_PROCESS");
1798 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1801 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1804 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1806 g_string_append_printf (status, " ID=%s", ut->ut_id);
1808 g_string_append_printf (status, " USER=%s", ut->ut_user);
1810 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1811 status_notify ("%s", status->str);
1812 g_string_free (status, TRUE);
1815 return (struct utmpx *)ut;
1824 updwtmp (const char *wtmp_file, const struct utmp *ut)
1827 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1831 status = g_string_new ("WTMP");
1832 g_string_append_printf (status, " FILE=%s", wtmp_file);
1833 switch (ut->ut_type)
1836 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1839 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1842 g_string_append_printf (status, " TYPE=USER_PROCESS");
1845 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1848 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1851 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1853 g_string_append_printf (status, " ID=%s", ut->ut_id);
1855 g_string_append_printf (status, " USER=%s", ut->ut_user);
1857 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1858 status_notify ("%s", status->str);
1859 g_string_free (status, TRUE);
1863 struct xcb_connection_t
1871 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1873 xcb_connection_t *c;
1875 GError *error = NULL;
1877 c = malloc (sizeof (xcb_connection_t));
1878 c->display = g_strdup (display);
1881 if (display == NULL)
1882 display = getenv ("DISPLAY");
1883 if (display == NULL)
1884 c->error = XCB_CONN_CLOSED_PARSE_ERR;
1888 c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1890 g_printerr ("%s\n", error->message);
1891 g_clear_error (&error);
1892 if (c->socket == NULL)
1893 c->error = XCB_CONN_ERROR;
1899 GSocketAddress *address;
1901 /* Skip the hostname, we'll assume it's localhost */
1902 d = g_strdup_printf (".x%s", strchr (display, ':'));
1904 socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1906 address = g_unix_socket_address_new (socket_path);
1907 if (!g_socket_connect (c->socket, address, NULL, &error))
1908 c->error = XCB_CONN_ERROR;
1909 g_object_unref (address);
1911 g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1912 g_free (socket_path);
1913 g_clear_error (&error);
1916 // FIXME: Send auth info
1925 xcb_connect (const char *displayname, int *screenp)
1927 return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1931 xcb_connection_has_error (xcb_connection_t *c)
1937 xcb_disconnect (xcb_connection_t *c)
1941 g_object_unref (c->socket);
1950 if (g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1951 status_notify ("AUDIT OPEN");
1953 return dup (STDOUT_FILENO);
1957 audit_log_acct_message (int audit_fd, int type, const char *pgname,
1958 const char *op, const char *name, unsigned int id,
1959 const char *host, const char *addr, const char *tty, int result)
1964 if (!g_key_file_get_boolean (config, "test-audit-config", "check-events", NULL))
1969 case AUDIT_USER_LOGIN:
1970 type_string = g_strdup ("USER_LOGIN");
1972 case AUDIT_USER_LOGOUT:
1973 type_string = g_strdup ("USER_LOGOUT");
1976 type_string = g_strdup_printf ("%d", type);
1980 status_notify ("AUDIT LOG-ACCT TYPE=%s PGNAME=%s OP=%s NAME=%s ID=%u HOST=%s ADDR=%s TTY=%s RESULT=%d",
1981 type_string, pgname ? pgname : "", op ? op : "", name ? name : "", id, host ? host : "", addr ? addr : "", tty ? tty : "", result);
1983 g_free (type_string);