10 #include <sys/ioctl.h>
15 #include <security/pam_appl.h>
25 #include <gio/gunixsocketaddress.h>
29 #define LOGIN_PROMPT "login:"
31 static int console_fd = -1;
33 static GList *user_entries = NULL;
34 static GList *getpwent_link = NULL;
36 static GList *group_entries = NULL;
38 static int active_vt = 7;
40 static gboolean status_connected = FALSE;
41 static GKeyFile *config;
43 static void connect_status (void)
47 status_connected = TRUE;
49 status_connect (NULL, NULL);
51 config = g_key_file_new ();
52 g_key_file_load_from_file (config, g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "script", NULL), G_KEY_FILE_NONE, NULL);
64 struct pam_conv conversation;
80 initgroups (const char *user, gid_t group)
91 getgroups (int size, gid_t list[])
93 const gchar *group_list;
97 /* Get groups we are a member of */
98 group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
101 groups = g_strsplit (group_list, ",", -1);
102 groups_length = g_strv_length (groups);
108 if (groups_length > size)
113 for (i = 0; groups[i]; i++)
114 list[i] = atoi (groups[i]);
118 return groups_length;
122 setgroups (size_t size, const gid_t *list)
127 group_list = g_string_new ("");
128 for (i = 0; i < size; i++)
131 g_string_append (group_list, ",");
132 g_string_append_printf (group_list, "%d", list[i]);
134 g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
135 g_string_free (group_list, TRUE);
153 setresgid (gid_t rgid, gid_t ugid, gid_t sgid)
171 setresuid (uid_t ruid, uid_t uuid, uid_t suid)
177 redirect_path (const gchar *path)
179 // Don't redirect if inside the running directory
180 if (g_str_has_prefix (path, g_getenv ("LIGHTDM_TEST_ROOT")))
181 return g_strdup (path);
183 if (g_str_has_prefix (path, SYSCONFDIR))
184 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", path + strlen (SYSCONFDIR), NULL);
186 if (g_str_has_prefix (path, LOCALSTATEDIR))
187 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "var", path + strlen (LOCALSTATEDIR), NULL);
189 if (g_str_has_prefix (path, DATADIR))
190 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", path + strlen (DATADIR), NULL);
192 // Don't redirect if inside the build directory
193 if (g_str_has_prefix (path, BUILDDIR))
194 return g_strdup (path);
196 if (g_str_has_prefix (path, "/tmp"))
197 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "tmp", path + strlen ("/tmp"), NULL);
199 if (g_str_has_prefix (path, "/etc/xdg"))
200 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "xdg", path + strlen ("/etc/xdg"), NULL);
202 if (g_str_has_prefix (path, "/usr/share/lightdm"))
203 return g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "usr", "share", "lightdm", path + strlen ("/usr/share/lightdm"), NULL);
205 return g_strdup (path);
210 open_wrapper (const char *func, const char *pathname, int flags, mode_t mode)
212 int (*_open) (const char *pathname, int flags, mode_t mode);
213 gchar *new_path = NULL;
216 _open = (int (*)(const char *pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, func);
218 if (strcmp (pathname, "/dev/console") == 0)
222 console_fd = _open ("/dev/null", flags, mode);
223 fcntl (console_fd, F_SETFD, FD_CLOEXEC);
228 new_path = redirect_path (pathname);
229 fd = _open (new_path, flags, mode);
236 open (const char *pathname, int flags, ...)
242 va_start (ap, flags);
243 mode = va_arg (ap, mode_t);
246 return open_wrapper ("open", pathname, flags, mode);
250 open64 (const char *pathname, int flags, ...)
256 va_start (ap, flags);
257 mode = va_arg (ap, mode_t);
260 return open_wrapper ("open64", pathname, flags, mode);
264 fopen (const char *path, const char *mode)
266 FILE *(*_fopen) (const char *pathname, const char *mode);
267 gchar *new_path = NULL;
270 _fopen = (FILE *(*)(const char *pathname, const char *mode)) dlsym (RTLD_NEXT, "fopen");
272 new_path = redirect_path (path);
273 result = _fopen (new_path, mode);
280 unlinkat (int dirfd, const char *pathname, int flags)
282 int (*_unlinkat) (int dirfd, const char *pathname, int flags);
283 gchar *new_path = NULL;
286 _unlinkat = (int (*)(int dirfd, const char *pathname, int flags)) dlsym (RTLD_NEXT, "unlinkat");
288 new_path = redirect_path (pathname);
289 result = _unlinkat (dirfd, new_path, flags);
296 creat (const char *pathname, mode_t mode)
298 int (*_creat) (const char *pathname, mode_t mode);
299 gchar *new_path = NULL;
302 _creat = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat");
304 new_path = redirect_path (pathname);
305 result = _creat (new_path, mode);
312 creat64 (const char *pathname, mode_t mode)
314 int (*_creat64) (const char *pathname, mode_t mode);
315 gchar *new_path = NULL;
318 _creat64 = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "creat64");
320 new_path = redirect_path (pathname);
321 result = _creat64 (new_path, mode);
328 access (const char *pathname, int mode)
330 int (*_access) (const char *pathname, int mode);
331 gchar *new_path = NULL;
334 _access = (int (*)(const char *pathname, int mode)) dlsym (RTLD_NEXT, "access");
336 new_path = redirect_path (pathname);
337 ret = _access (new_path, mode);
344 stat (const char *path, struct stat *buf)
346 int (*_stat) (const char *path, struct stat *buf);
347 gchar *new_path = NULL;
350 _stat = (int (*)(const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "stat");
352 new_path = redirect_path (path);
353 ret = _stat (new_path, buf);
360 stat64 (const char *path, struct stat64 *buf)
362 int (*_stat64) (const char *path, struct stat64 *buf);
363 gchar *new_path = NULL;
366 _stat64 = (int (*)(const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "stat64");
368 new_path = redirect_path (path);
369 ret = _stat64 (new_path, buf);
376 __xstat (int version, const char *path, struct stat *buf)
378 int (*___xstat) (int version, const char *path, struct stat *buf);
379 gchar *new_path = NULL;
382 ___xstat = (int (*)(int version, const char *path, struct stat *buf)) dlsym (RTLD_NEXT, "__xstat");
384 new_path = redirect_path (path);
385 ret = ___xstat (version, new_path, buf);
392 __xstat64 (int version, const char *path, struct stat64 *buf)
394 int (*___xstat64) (int version, const char *path, struct stat64 *buf);
395 gchar *new_path = NULL;
398 ___xstat64 = (int (*)(int version, const char *path, struct stat64 *buf)) dlsym (RTLD_NEXT, "__xstat64");
400 new_path = redirect_path (path);
401 ret = ___xstat64 (version, new_path, buf);
408 __fxstatat(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)
410 int (*___fxstatat) (int ver, int dirfd, const char *pathname, struct stat *buf, int flags);
411 gchar *new_path = NULL;
414 ___fxstatat = (int (*)(int ver, int dirfd, const char *pathname, struct stat *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat");
416 new_path = redirect_path (pathname);
417 ret = ___fxstatat (ver, dirfd, new_path, buf, flags);
424 __fxstatat64(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)
426 int (*___fxstatat64) (int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags);
427 gchar *new_path = NULL;
430 ___fxstatat64 = (int (*)(int ver, int dirfd, const char *pathname, struct stat64 *buf, int flags)) dlsym (RTLD_NEXT, "__fxstatat64");
432 new_path = redirect_path (pathname);
433 ret = ___fxstatat64 (ver, dirfd, new_path, buf, flags);
440 opendir (const char *name)
442 DIR *(*_opendir) (const char *name);
443 gchar *new_path = NULL;
446 _opendir = (DIR *(*)(const char *name)) dlsym (RTLD_NEXT, "opendir");
448 new_path = redirect_path (name);
449 result = _opendir (new_path);
456 mkdir (const char *pathname, mode_t mode)
458 int (*_mkdir) (const char *pathname, mode_t mode);
459 gchar *new_path = NULL;
462 _mkdir = (int (*)(const char *pathname, mode_t mode)) dlsym (RTLD_NEXT, "mkdir");
464 new_path = redirect_path (pathname);
465 result = _mkdir (new_path, mode);
472 chown (const char *pathname, uid_t owner, gid_t group)
474 /* Just fake it - we're not root */
479 chmod (const char *path, mode_t mode)
481 int (*_chmod) (const char *path, mode_t mode);
482 gchar *new_path = NULL;
485 _chmod = (int (*)(const char *path, mode_t mode)) dlsym (RTLD_NEXT, "chmod");
487 new_path = redirect_path (path);
488 result = _chmod (new_path, mode);
495 ioctl (int d, unsigned long request, ...)
497 int (*_ioctl) (int d, int request, ...);
499 _ioctl = (int (*)(int d, int request, ...)) dlsym (RTLD_NEXT, "ioctl");
500 if (d > 0 && d == console_fd)
502 struct vt_stat *console_state;
509 va_start (ap, request);
510 console_state = va_arg (ap, struct vt_stat *);
512 console_state->v_active = active_vt;
515 va_start (ap, request);
516 vt = va_arg (ap, int);
522 status_notify ("VT ACTIVATE VT=%d", active_vt);
535 va_start (ap, request);
536 data = va_arg (ap, void *);
538 return _ioctl (d, request, data);
545 int (*_close) (int fd);
547 if (fd > 0 && fd == console_fd)
550 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
556 free_user (gpointer data)
558 struct passwd *entry = data;
560 g_free (entry->pw_name);
561 g_free (entry->pw_passwd);
562 g_free (entry->pw_gecos);
563 g_free (entry->pw_dir);
564 g_free (entry->pw_shell);
569 load_passwd_file (void)
571 gchar *path, *data = NULL, **lines;
573 GError *error = NULL;
575 g_list_free_full (user_entries, free_user);
577 getpwent_link = NULL;
579 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
580 g_file_get_contents (path, &data, NULL, &error);
583 g_warning ("Error loading passwd file: %s", error->message);
584 g_clear_error (&error);
589 lines = g_strsplit (data, "\n", -1);
592 for (i = 0; lines[i]; i++)
594 gchar *line, **fields;
596 line = g_strstrip (lines[i]);
597 fields = g_strsplit (line, ":", -1);
598 if (g_strv_length (fields) == 7)
600 struct passwd *entry = malloc (sizeof (struct passwd));
602 entry->pw_name = g_strdup (fields[0]);
603 entry->pw_passwd = g_strdup (fields[1]);
604 entry->pw_uid = atoi (fields[2]);
605 entry->pw_gid = atoi (fields[3]);
606 entry->pw_gecos = g_strdup (fields[4]);
607 entry->pw_dir = g_strdup (fields[5]);
608 entry->pw_shell = g_strdup (fields[6]);
609 user_entries = g_list_append (user_entries, entry);
619 if (getpwent_link == NULL)
622 if (user_entries == NULL)
624 getpwent_link = user_entries;
628 if (getpwent_link->next == NULL)
630 getpwent_link = getpwent_link->next;
633 return getpwent_link->data;
639 getpwent_link = NULL;
645 getpwent_link = NULL;
649 getpwnam (const char *name)
658 for (link = user_entries; link; link = link->next)
660 struct passwd *entry = link->data;
661 if (strcmp (entry->pw_name, name) == 0)
677 for (link = user_entries; link; link = link->next)
679 struct passwd *entry = link->data;
680 if (entry->pw_uid == uid)
690 free_group (gpointer data)
692 struct group *entry = data;
694 g_free (entry->gr_name);
695 g_free (entry->gr_passwd);
696 g_strfreev (entry->gr_mem);
701 load_group_file (void)
703 gchar *path, *data = NULL, **lines;
705 GError *error = NULL;
707 g_list_free_full (group_entries, free_group);
708 group_entries = NULL;
710 path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
711 g_file_get_contents (path, &data, NULL, &error);
714 g_warning ("Error loading group file: %s", error->message);
715 g_clear_error (&error);
720 lines = g_strsplit (data, "\n", -1);
723 for (i = 0; lines[i]; i++)
725 gchar *line, **fields;
727 line = g_strstrip (lines[i]);
728 fields = g_strsplit (line, ":", -1);
729 if (g_strv_length (fields) == 4)
731 struct group *entry = malloc (sizeof (struct group));
733 entry->gr_name = g_strdup (fields[0]);
734 entry->gr_passwd = g_strdup (fields[1]);
735 entry->gr_gid = atoi (fields[2]);
736 entry->gr_mem = g_strsplit (fields[3], ",", -1);
737 group_entries = g_list_append (group_entries, entry);
745 getgrnam (const char *name)
751 for (link = group_entries; link; link = link->next)
753 struct group *entry = link->data;
754 if (strcmp (entry->gr_name, name) == 0)
770 for (link = group_entries; link; link = link->next)
772 struct group *entry = link->data;
773 if (entry->gr_gid == gid)
783 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
785 pam_handle_t *handle;
787 if (service_name == NULL || conversation == NULL || pamh == NULL)
788 return PAM_SYSTEM_ERR;
790 handle = *pamh = malloc (sizeof (pam_handle_t));
795 handle->id = g_strdup_printf ("PAM-%s", user);
797 handle->id = g_strdup ("PAM");
800 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
804 status = g_string_new ("");
805 g_string_append_printf (status, "%s START", handle->id);
806 g_string_append_printf (status, " SERVICE=%s", service_name);
808 g_string_append_printf (status, " USER=%s", user);
809 status_notify (status->str);
810 g_string_free (status, TRUE);
813 handle->service_name = strdup (service_name);
814 handle->user = user ? strdup (user) : NULL;
815 handle->authtok = NULL;
816 handle->ruser = NULL;
818 handle->conversation.conv = conversation->conv;
819 handle->conversation.appdata_ptr = conversation->appdata_ptr;
820 handle->envlist = malloc (sizeof (char *) * 1);
821 handle->envlist[0] = NULL;
827 pam_authenticate (pam_handle_t *pamh, int flags)
829 struct passwd *entry;
830 gboolean password_matches = FALSE;
833 return PAM_SYSTEM_ERR;
836 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
840 status = g_string_new ("");
841 g_string_append_printf (status, "%s AUTHENTICATE", pamh->id);
842 if (flags & PAM_SILENT)
843 g_string_append (status, " SILENT");
844 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
845 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
847 status_notify (status->str);
848 g_string_free (status, TRUE);
851 if (strcmp (pamh->service_name, "test-remote") == 0)
854 struct pam_message **msg;
855 struct pam_response *resp = NULL;
857 msg = malloc (sizeof (struct pam_message *) * 1);
858 msg[0] = malloc (sizeof (struct pam_message));
859 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
860 msg[0]->msg = "remote-login:";
861 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
864 if (result != PAM_SUCCESS)
869 if (resp[0].resp == NULL)
877 pamh->ruser = strdup (resp[0].resp);
881 msg = malloc (sizeof (struct pam_message *) * 1);
882 msg[0] = malloc (sizeof (struct pam_message));
883 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
884 msg[0]->msg = "remote-password:";
885 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
888 if (result != PAM_SUCCESS)
893 if (resp[0].resp == NULL)
900 free (pamh->authtok);
901 pamh->authtok = strdup (resp[0].resp);
905 password_matches = strcmp (pamh->ruser, "remote-user") == 0 && strcmp (pamh->authtok, "password") == 0;
907 if (password_matches)
913 /* Prompt for username */
914 if (pamh->user == NULL)
917 struct pam_message **msg;
918 struct pam_response *resp = NULL;
920 msg = malloc (sizeof (struct pam_message *) * 1);
921 msg[0] = malloc (sizeof (struct pam_message));
922 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
923 msg[0]->msg = LOGIN_PROMPT;
924 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
927 if (result != PAM_SUCCESS)
932 if (resp[0].resp == NULL)
938 pamh->user = strdup (resp[0].resp);
943 /* Crash on authenticate */
944 if (strcmp (pamh->user, "crash-authenticate") == 0)
945 kill (getpid (), SIGSEGV);
947 /* Look up password database */
948 entry = getpwnam (pamh->user);
950 /* Prompt for password if required */
951 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
952 password_matches = TRUE;
955 int i, n_messages = 0, password_index, result;
956 struct pam_message **msg;
957 struct pam_response *resp = NULL;
959 msg = malloc (sizeof (struct pam_message *) * 5);
960 if (strcmp (pamh->user, "info-prompt") == 0)
962 msg[n_messages] = malloc (sizeof (struct pam_message));
963 msg[n_messages]->msg_style = PAM_TEXT_INFO;
964 msg[n_messages]->msg = "Welcome to LightDM";
967 if (strcmp (pamh->user, "multi-info-prompt") == 0)
969 msg[n_messages] = malloc (sizeof (struct pam_message));
970 msg[n_messages]->msg_style = PAM_TEXT_INFO;
971 msg[n_messages]->msg = "Welcome to LightDM";
973 msg[n_messages] = malloc (sizeof (struct pam_message));
974 msg[n_messages]->msg_style = PAM_ERROR_MSG;
975 msg[n_messages]->msg = "This is an error";
977 msg[n_messages] = malloc (sizeof (struct pam_message));
978 msg[n_messages]->msg_style = PAM_TEXT_INFO;
979 msg[n_messages]->msg = "You should have seen three messages";
982 if (strcmp (pamh->user, "multi-prompt") == 0)
984 msg[n_messages] = malloc (sizeof (struct pam_message));
985 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_ON;
986 msg[n_messages]->msg = "Favorite Color:";
989 msg[n_messages] = malloc (sizeof (struct pam_message));
990 msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
991 msg[n_messages]->msg = "Password:";
992 password_index = n_messages;
994 result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
995 for (i = 0; i < n_messages; i++)
998 if (result != PAM_SUCCESS)
1002 return PAM_CONV_ERR;
1003 if (resp[password_index].resp == NULL)
1006 return PAM_CONV_ERR;
1010 password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
1012 if (password_matches && strcmp (pamh->user, "multi-prompt") == 0)
1013 password_matches = strcmp ("blue", resp[0].resp) == 0;
1015 for (i = 0; i < n_messages; i++)
1018 free (resp[i].resp);
1022 /* Do two factor authentication */
1023 if (password_matches && strcmp (pamh->user, "two-factor") == 0)
1025 msg = malloc (sizeof (struct pam_message *) * 1);
1026 msg[0] = malloc (sizeof (struct pam_message));
1027 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
1028 msg[0]->msg = "OTP:";
1030 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1035 return PAM_CONV_ERR;
1036 if (resp[0].resp == NULL)
1039 return PAM_CONV_ERR;
1041 password_matches = strcmp (resp[0].resp, "otp") == 0;
1042 free (resp[0].resp);
1047 /* Special user has home directory created on login */
1048 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
1049 g_mkdir_with_parents (entry->pw_dir, 0755);
1051 /* Special user 'change-user1' changes user on authentication */
1052 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
1054 g_free (pamh->user);
1055 pamh->user = g_strdup ("change-user2");
1058 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
1059 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
1061 g_free (pamh->user);
1062 pamh->user = g_strdup ("invalid-user");
1065 if (password_matches)
1068 return PAM_AUTH_ERR;
1072 get_env_value (const char *name_value, const char *name)
1076 for (j = 0; name[j] && name_value[j] && name[j] == name_value[j]; j++);
1077 if (name[j] == '\0' && name_value[j] == '=')
1078 return &name_value[j + 1];
1084 pam_putenv (pam_handle_t *pamh, const char *name_value)
1089 if (pamh == NULL || name_value == NULL)
1090 return PAM_SYSTEM_ERR;
1092 name = strdup (name_value);
1093 for (i = 0; name[i]; i++)
1096 for (i = 0; pamh->envlist[i]; i++)
1098 if (get_env_value (pamh->envlist[i], name))
1103 if (pamh->envlist[i])
1105 free (pamh->envlist[i]);
1106 pamh->envlist[i] = strdup (name_value);
1110 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
1111 pamh->envlist[i] = strdup (name_value);
1112 pamh->envlist[i + 1] = NULL;
1119 pam_getenv (pam_handle_t *pamh, const char *name)
1123 if (pamh == NULL || name == NULL)
1126 for (i = 0; pamh->envlist[i]; i++)
1129 value = get_env_value (pamh->envlist[i], name);
1138 pam_getenvlist (pam_handle_t *pamh)
1143 return pamh->envlist;
1147 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
1149 if (pamh == NULL || item == NULL)
1150 return PAM_SYSTEM_ERR;
1157 pamh->tty = strdup ((const char *) item);
1161 return PAM_BAD_ITEM;
1166 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
1168 if (pamh == NULL || item == NULL)
1169 return PAM_SYSTEM_ERR;
1174 *item = pamh->service_name;
1182 *item = pamh->authtok;
1186 *item = pamh->ruser;
1189 case PAM_USER_PROMPT:
1190 *item = LOGIN_PROMPT;
1198 *item = &pamh->conversation;
1202 return PAM_BAD_ITEM;
1207 pam_open_session (pam_handle_t *pamh, int flags)
1210 return PAM_SYSTEM_ERR;
1213 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1217 status = g_string_new ("");
1218 g_string_append_printf (status, "%s OPEN-SESSION", pamh->id);
1219 if (flags & PAM_SILENT)
1220 g_string_append (status, " SILENT");
1222 status_notify (status->str);
1223 g_string_free (status, TRUE);
1226 if (strcmp (pamh->user, "session-error") == 0)
1227 return PAM_SESSION_ERR;
1229 if (strcmp (pamh->user, "make-home-dir") == 0)
1231 struct passwd *entry;
1232 entry = getpwnam (pamh->user);
1233 g_mkdir_with_parents (entry->pw_dir, 0755);
1240 pam_close_session (pam_handle_t *pamh, int flags)
1243 return PAM_SYSTEM_ERR;
1246 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1250 status = g_string_new ("");
1251 g_string_append_printf (status, "%s CLOSE-SESSION", pamh->id);
1252 if (flags & PAM_SILENT)
1253 g_string_append (status, " SILENT");
1255 status_notify (status->str);
1256 g_string_free (status, TRUE);
1263 pam_acct_mgmt (pam_handle_t *pamh, int flags)
1266 return PAM_SYSTEM_ERR;
1269 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1273 status = g_string_new ("");
1274 g_string_append_printf (status, "%s ACCT-MGMT", pamh->id);
1275 if (flags & PAM_SILENT)
1276 g_string_append (status, " SILENT");
1277 if (flags & PAM_DISALLOW_NULL_AUTHTOK)
1278 g_string_append (status, " DISALLOW_NULL_AUTHTOK");
1280 status_notify (status->str);
1281 g_string_free (status, TRUE);
1285 return PAM_USER_UNKNOWN;
1287 if (strcmp (pamh->user, "denied") == 0)
1288 return PAM_PERM_DENIED;
1289 if (strcmp (pamh->user, "expired") == 0)
1290 return PAM_ACCT_EXPIRED;
1291 if (strcmp (pamh->user, "new-authtok") == 0)
1292 return PAM_NEW_AUTHTOK_REQD;
1298 pam_chauthtok (pam_handle_t *pamh, int flags)
1300 struct passwd *entry;
1302 struct pam_message **msg;
1303 struct pam_response *resp = NULL;
1306 return PAM_SYSTEM_ERR;
1309 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1313 status = g_string_new ("");
1314 g_string_append_printf (status, "%s CHAUTHTOK", pamh->id);
1315 if (flags & PAM_SILENT)
1316 g_string_append (status, " SILENT");
1317 if (flags & PAM_CHANGE_EXPIRED_AUTHTOK)
1318 g_string_append (status, " CHANGE_EXPIRED_AUTHTOK");
1320 status_notify (status->str);
1321 g_string_free (status, TRUE);
1324 msg = malloc (sizeof (struct pam_message *) * 1);
1325 msg[0] = malloc (sizeof (struct pam_message));
1326 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
1327 if ((flags & PAM_CHANGE_EXPIRED_AUTHTOK) != 0)
1328 msg[0]->msg = "Enter new password (expired):";
1330 msg[0]->msg = "Enter new password:";
1331 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
1334 if (result != PAM_SUCCESS)
1338 return PAM_CONV_ERR;
1339 if (resp[0].resp == NULL)
1342 return PAM_CONV_ERR;
1345 /* Update password database */
1346 entry = getpwnam (pamh->user);
1347 free (entry->pw_passwd);
1348 entry->pw_passwd = resp[0].resp;
1355 pam_setcred (pam_handle_t *pamh, int flags)
1360 return PAM_SYSTEM_ERR;
1363 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1367 status = g_string_new ("");
1368 g_string_append_printf (status, "%s SETCRED", pamh->id);
1369 if (flags & PAM_SILENT)
1370 g_string_append (status, " SILENT");
1371 if (flags & PAM_ESTABLISH_CRED)
1372 g_string_append (status, " ESTABLISH_CRED");
1373 if (flags & PAM_DELETE_CRED)
1374 g_string_append (status, " DELETE_CRED");
1375 if (flags & PAM_REINITIALIZE_CRED)
1376 g_string_append (status, " REINITIALIZE_CRED");
1377 if (flags & PAM_REFRESH_CRED)
1378 g_string_append (status, " REFRESH_CRED");
1380 status_notify (status->str);
1381 g_string_free (status, TRUE);
1384 /* Put the test directories into the path */
1385 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"));
1386 pam_putenv (pamh, e);
1389 if (strcmp (pamh->user, "cred-error") == 0)
1390 return PAM_CRED_ERR;
1391 if (strcmp (pamh->user, "cred-expired") == 0)
1392 return PAM_CRED_EXPIRED;
1393 if (strcmp (pamh->user, "cred-unavail") == 0)
1394 return PAM_CRED_UNAVAIL;
1396 /* Join special groups if requested */
1397 if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
1399 struct group *group;
1403 group = getgrnam ("test-group");
1406 groups_length = getgroups (0, NULL);
1407 if (groups_length < 0)
1408 return PAM_SYSTEM_ERR;
1409 groups = malloc (sizeof (gid_t) * (groups_length + 1));
1410 groups_length = getgroups (groups_length, groups);
1411 if (groups_length < 0)
1412 return PAM_SYSTEM_ERR;
1413 groups[groups_length] = group->gr_gid;
1415 setgroups (groups_length, groups);
1419 /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
1420 pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
1427 pam_end (pam_handle_t *pamh, int pam_status)
1430 return PAM_SYSTEM_ERR;
1433 if (g_key_file_get_boolean (config, "test-pam", "log-events", NULL))
1437 status = g_string_new ("");
1438 g_string_append_printf (status, "%s END", pamh->id);
1439 status_notify (status->str);
1440 g_string_free (status, TRUE);
1444 free (pamh->service_name);
1448 free (pamh->authtok);
1459 pam_strerror (pam_handle_t *pamh, int errnum)
1469 return "Critical error - immediate abort";
1471 return "Failed to load module";
1472 case PAM_SYMBOL_ERR:
1473 return "Symbol not found";
1474 case PAM_SERVICE_ERR:
1475 return "Error in service module";
1476 case PAM_SYSTEM_ERR:
1477 return "System error";
1479 return "Memory buffer error";
1480 case PAM_PERM_DENIED:
1481 return "Permission denied";
1483 return "Authentication failure";
1484 case PAM_CRED_INSUFFICIENT:
1485 return "Insufficient credentials to access authentication data";
1486 case PAM_AUTHINFO_UNAVAIL:
1487 return "Authentication service cannot retrieve authentication info";
1488 case PAM_USER_UNKNOWN:
1489 return "User not known to the underlying authentication module";
1491 return "Have exhausted maximum number of retries for service";
1492 case PAM_NEW_AUTHTOK_REQD:
1493 return "Authentication token is no longer valid; new one required";
1494 case PAM_ACCT_EXPIRED:
1495 return "User account has expired";
1496 case PAM_SESSION_ERR:
1497 return "Cannot make/remove an entry for the specified session";
1498 case PAM_CRED_UNAVAIL:
1499 return "Authentication service cannot retrieve user credentials";
1500 case PAM_CRED_EXPIRED:
1501 return "User credentials expired";
1503 return "Failure setting user credentials";
1504 case PAM_NO_MODULE_DATA:
1505 return "No module specific data is present";
1507 return "Bad item passed to pam_*_item()";
1509 return "Conversation error";
1510 case PAM_AUTHTOK_ERR:
1511 return "Authentication token manipulation error";
1512 case PAM_AUTHTOK_RECOVERY_ERR:
1513 return "Authentication information cannot be recovered";
1514 case PAM_AUTHTOK_LOCK_BUSY:
1515 return "Authentication token lock busy";
1516 case PAM_AUTHTOK_DISABLE_AGING:
1517 return "Authentication token aging disabled";
1519 return "Failed preliminary check by password service";
1521 return "The return value should be ignored by PAM dispatch";
1522 case PAM_MODULE_UNKNOWN:
1523 return "Module is unknown";
1524 case PAM_AUTHTOK_EXPIRED:
1525 return "Authentication token expired";
1526 case PAM_CONV_AGAIN:
1527 return "Conversation is waiting for event";
1528 case PAM_INCOMPLETE:
1529 return "Application needs to call libpam again";
1531 return "Unknown PAM error";
1541 pututxline (const struct utmpx *ut)
1544 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1548 status = g_string_new ("UTMP");
1549 switch (ut->ut_type)
1552 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1555 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1558 g_string_append_printf (status, " TYPE=USER_PROCESS");
1561 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1564 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1567 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1569 g_string_append_printf (status, " ID=%s", ut->ut_id);
1571 g_string_append_printf (status, " USER=%s", ut->ut_user);
1573 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1574 status_notify ("%s", status->str);
1575 g_string_free (status, TRUE);
1578 return (struct utmpx *)ut;
1587 updwtmp (const char *wtmp_file, const struct utmp *ut)
1590 if (g_key_file_get_boolean (config, "test-utmp-config", "check-events", NULL))
1594 status = g_string_new ("WTMP");
1595 g_string_append_printf (status, " FILE=%s", wtmp_file);
1596 switch (ut->ut_type)
1599 g_string_append_printf (status, " TYPE=INIT_PROCESS");
1602 g_string_append_printf (status, " TYPE=LOGIN_PROCESS");
1605 g_string_append_printf (status, " TYPE=USER_PROCESS");
1608 g_string_append_printf (status, " TYPE=DEAD_PROCESS");
1611 g_string_append_printf (status, " TYPE=%d", ut->ut_type);
1614 g_string_append_printf (status, " LINE=%s", ut->ut_line);
1616 g_string_append_printf (status, " ID=%s", ut->ut_id);
1618 g_string_append_printf (status, " USER=%s", ut->ut_user);
1620 g_string_append_printf (status, " HOST=%s", ut->ut_host);
1621 status_notify ("%s", status->str);
1622 g_string_free (status, TRUE);
1626 struct xcb_connection_t
1634 xcb_connect_to_display_with_auth_info (const char *display, xcb_auth_info_t *auth, int *screen)
1636 xcb_connection_t *c;
1638 GError *error = NULL;
1640 c = malloc (sizeof (xcb_connection_t));
1641 c->display = g_strdup (display);
1644 if (display == NULL)
1645 display = getenv ("DISPLAY");
1646 if (display == NULL)
1647 c->error = XCB_CONN_CLOSED_PARSE_ERR;
1651 c->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
1653 g_printerr ("%s\n", error->message);
1654 g_clear_error (&error);
1655 if (c->socket == NULL)
1656 c->error = XCB_CONN_ERROR;
1662 GSocketAddress *address;
1664 /* Skip the hostname, we'll assume it's localhost */
1665 d = g_strdup_printf (".x%s", strchr (display, ':'));
1667 socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), d, NULL);
1669 address = g_unix_socket_address_new (socket_path);
1670 if (!g_socket_connect (c->socket, address, NULL, &error))
1671 c->error = XCB_CONN_ERROR;
1672 g_object_unref (address);
1674 g_printerr ("Failed to connect to X socket %s: %s\n", socket_path, error->message);
1675 g_free (socket_path);
1676 g_clear_error (&error);
1679 // FIXME: Send auth info
1688 xcb_connect (const char *displayname, int *screenp)
1690 return xcb_connect_to_display_with_auth_info(displayname, NULL, screenp);
1694 xcb_connection_has_error (xcb_connection_t *c)
1700 xcb_disconnect (xcb_connection_t *c)
1704 g_object_unref (c->socket);