5 #include <security/pam_appl.h>
15 #define LOGIN_PROMPT "login:"
17 static int console_fd = -1;
19 static GList *user_entries = NULL;
20 static GList *getpwent_link = NULL;
28 struct pam_conv conversation;
44 initgroups (const char *user, gid_t group)
63 open (const char *pathname, int flags, ...)
65 int (*_open) (const char * pathname, int flags, mode_t mode);
72 mode = va_arg (ap, int);
76 _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open");
77 if (strcmp (pathname, "/dev/console") == 0)
81 console_fd = _open ("/dev/null", flags, mode);
82 fcntl (console_fd, F_SETFD, FD_CLOEXEC);
87 return _open (pathname, flags, mode);
91 ioctl (int d, int request, void *data)
93 int (*_ioctl) (int d, int request, void *data);
95 _ioctl = (int (*)(int d, int request, void *data)) dlsym (RTLD_NEXT, "ioctl");
96 if (d > 0 && d == console_fd)
98 struct vt_stat *console_state;
103 console_state = data;
104 console_state->v_active = 7;
112 return _ioctl (d, request, data);
118 int (*_close) (int fd);
120 if (fd > 0 && fd == console_fd)
123 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
129 free_user (gpointer data)
131 struct passwd *entry = data;
133 g_free (entry->pw_name);
134 g_free (entry->pw_passwd);
135 g_free (entry->pw_gecos);
136 g_free (entry->pw_dir);
137 g_free (entry->pw_shell);
144 gchar *data = NULL, **lines;
146 GError *error = NULL;
148 g_list_free_full (user_entries, free_user);
150 getpwent_link = NULL;
152 g_file_get_contents (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), &data, NULL, &error);
154 g_warning ("Error loading passwd file: %s", error->message);
155 g_clear_error (&error);
160 lines = g_strsplit (data, "\n", -1);
163 for (i = 0; lines[i]; i++)
165 gchar *line, **fields;
167 line = g_strstrip (lines[i]);
168 fields = g_strsplit (line, ":", -1);
169 if (g_strv_length (fields) == 7)
171 struct passwd *entry = malloc (sizeof (struct passwd));
173 entry->pw_name = g_strdup (fields[0]);
174 entry->pw_passwd = g_strdup (fields[1]);
175 entry->pw_uid = atoi (fields[2]);
176 entry->pw_gid = atoi (fields[3]);
177 entry->pw_gecos = g_strdup (fields[4]);
178 entry->pw_dir = g_strdup (fields[5]);
179 entry->pw_shell = g_strdup (fields[6]);
180 user_entries = g_list_append (user_entries, entry);
190 if (getpwent_link == NULL)
193 if (user_entries == NULL)
195 getpwent_link = user_entries;
199 if (getpwent_link->next == NULL)
201 getpwent_link = getpwent_link->next;
204 return getpwent_link->data;
210 getpwent_link = NULL;
216 getpwent_link = NULL;
220 getpwnam (const char *name)
229 for (link = user_entries; link; link = link->next)
231 struct passwd *entry = link->data;
232 if (strcmp (entry->pw_name, name) == 0)
248 for (link = user_entries; link; link = link->next)
250 struct passwd *entry = link->data;
251 if (entry->pw_uid == uid)
261 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
263 pam_handle_t *handle;
265 if (service_name == NULL || conversation == NULL || pamh == NULL)
266 return PAM_SYSTEM_ERR;
268 handle = *pamh = malloc (sizeof (pam_handle_t));
272 handle->service_name = strdup (service_name);
273 handle->user = user ? strdup (user) : NULL;
275 handle->conversation.conv = conversation->conv;
276 handle->conversation.appdata_ptr = conversation->appdata_ptr;
277 handle->envlist = malloc (sizeof (char *) * 1);
278 handle->envlist[0] = NULL;
284 pam_authenticate (pam_handle_t *pamh, int flags)
286 struct passwd *entry;
287 gboolean password_matches = FALSE;
290 return PAM_SYSTEM_ERR;
292 /* Prompt for username */
293 if (pamh->user == NULL)
296 struct pam_message **msg;
297 struct pam_response *resp = NULL;
299 msg = malloc (sizeof (struct pam_message *) * 1);
300 msg[0] = malloc (sizeof (struct pam_message));
301 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
302 msg[0]->msg = LOGIN_PROMPT;
303 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
306 if (result != PAM_SUCCESS)
311 if (resp[0].resp == NULL)
317 pamh->user = strdup (resp[0].resp);
322 /* Crash on authenticate */
323 if (strcmp (pamh->user, "crash-authenticate") == 0)
324 kill (getpid (), SIGSEGV);
326 /* Look up password database */
327 entry = getpwnam (pamh->user);
329 /* Prompt for password if required */
330 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
331 password_matches = TRUE;
335 struct pam_message **msg;
336 struct pam_response *resp = NULL;
338 msg = malloc (sizeof (struct pam_message *) * 1);
339 msg[0] = malloc (sizeof (struct pam_message));
340 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
341 msg[0]->msg = "Password:";
342 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
345 if (result != PAM_SUCCESS)
350 if (resp[0].resp == NULL)
357 password_matches = strcmp (entry->pw_passwd, resp[0].resp) == 0;
362 /* Special user has home directory created on login */
363 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
364 g_mkdir_with_parents (entry->pw_dir, 0755);
366 /* Special user 'change-user1' changes user on authentication */
367 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
370 pamh->user = g_strdup ("change-user2");
373 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
374 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
377 pamh->user = g_strdup ("invalid-user");
380 if (password_matches)
387 get_env_value (const char *name_value, const char *name)
391 for (j = 0; name[j] && name[j] != '=' && name[j] == name_value[j]; j++);
392 if (name_value[j] == '=')
393 return &name_value[j + 1];
399 pam_putenv (pam_handle_t *pamh, const char *name_value)
403 if (pamh == NULL || name_value == NULL)
404 return PAM_SYSTEM_ERR;
406 for (i = 0; pamh->envlist[i]; i++)
408 if (get_env_value (pamh->envlist[i], name_value))
412 if (pamh->envlist[i])
414 free (pamh->envlist[i]);
415 pamh->envlist[i] = strdup (name_value);
419 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
420 pamh->envlist[i] = strdup (name_value);
421 pamh->envlist[i + 1] = NULL;
428 pam_getenv (pam_handle_t *pamh, const char *name)
432 if (pamh == NULL || name == NULL)
435 for (i = 0; pamh->envlist[i]; i++)
438 value = get_env_value (pamh->envlist[i], name);
447 pam_getenvlist (pam_handle_t *pamh)
452 return pamh->envlist;
456 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
458 if (pamh == NULL || item == NULL)
459 return PAM_SYSTEM_ERR;
466 pamh->tty = strdup ((const char *) item);
475 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
477 if (pamh == NULL || item == NULL)
478 return PAM_SYSTEM_ERR;
483 *item = pamh->service_name;
490 case PAM_USER_PROMPT:
491 *item = LOGIN_PROMPT;
499 *item = &pamh->conversation;
508 pam_open_session (pam_handle_t *pamh, int flags)
511 return PAM_SYSTEM_ERR;
517 pam_close_session (pam_handle_t *pamh, int flags)
520 return PAM_SYSTEM_ERR;
526 pam_acct_mgmt (pam_handle_t *pamh, int flags)
529 return PAM_SYSTEM_ERR;
532 return PAM_USER_UNKNOWN;
534 if (strcmp (pamh->user, "denied") == 0)
535 return PAM_PERM_DENIED;
536 if (strcmp (pamh->user, "expired") == 0)
537 return PAM_ACCT_EXPIRED;
538 if (strcmp (pamh->user, "new-authtok") == 0)
539 return PAM_NEW_AUTHTOK_REQD;
545 pam_chauthtok (pam_handle_t *pamh, int flags)
547 struct passwd *entry;
549 struct pam_message **msg;
550 struct pam_response *resp = NULL;
553 return PAM_SYSTEM_ERR;
555 msg = malloc (sizeof (struct pam_message *) * 1);
556 msg[0] = malloc (sizeof (struct pam_message));
557 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
558 msg[0]->msg = "Enter new password:";
559 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
562 if (result != PAM_SUCCESS)
567 if (resp[0].resp == NULL)
573 /* Update password database */
574 entry = getpwnam (pamh->user);
575 free (entry->pw_passwd);
576 entry->pw_passwd = resp[0].resp;
583 pam_setcred (pam_handle_t *pamh, int flags)
588 return PAM_SYSTEM_ERR;
590 /* Put the test directories into the path */
591 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"));
592 pam_putenv (pamh, e);
599 pam_end (pam_handle_t *pamh, int pam_status)
602 return PAM_SYSTEM_ERR;
604 free (pamh->service_name);
615 pam_strerror (pam_handle_t *pamh, int errnum)
625 return "Critical error - immediate abort";
627 return "Failed to load module";
629 return "Symbol not found";
630 case PAM_SERVICE_ERR:
631 return "Error in service module";
633 return "System error";
635 return "Memory buffer error";
636 case PAM_PERM_DENIED:
637 return "Permission denied";
639 return "Authentication failure";
640 case PAM_CRED_INSUFFICIENT:
641 return "Insufficient credentials to access authentication data";
642 case PAM_AUTHINFO_UNAVAIL:
643 return "Authentication service cannot retrieve authentication info";
644 case PAM_USER_UNKNOWN:
645 return "User not known to the underlying authentication module";
647 return "Have exhausted maximum number of retries for service";
648 case PAM_NEW_AUTHTOK_REQD:
649 return "Authentication token is no longer valid; new one required";
650 case PAM_ACCT_EXPIRED:
651 return "User account has expired";
652 case PAM_SESSION_ERR:
653 return "Cannot make/remove an entry for the specified session";
654 case PAM_CRED_UNAVAIL:
655 return "Authentication service cannot retrieve user credentials";
656 case PAM_CRED_EXPIRED:
657 return "User credentials expired";
659 return "Failure setting user credentials";
660 case PAM_NO_MODULE_DATA:
661 return "No module specific data is present";
663 return "Bad item passed to pam_*_item()";
665 return "Conversation error";
666 case PAM_AUTHTOK_ERR:
667 return "Authentication token manipulation error";
668 case PAM_AUTHTOK_RECOVERY_ERR:
669 return "Authentication information cannot be recovered";
670 case PAM_AUTHTOK_LOCK_BUSY:
671 return "Authentication token lock busy";
672 case PAM_AUTHTOK_DISABLE_AGING:
673 return "Authentication token aging disabled";
675 return "Failed preliminary check by password service";
677 return "The return value should be ignored by PAM dispatch";
678 case PAM_MODULE_UNKNOWN:
679 return "Module is unknown";
680 case PAM_AUTHTOK_EXPIRED:
681 return "Authentication token expired";
683 return "Conversation is waiting for event";
685 return "Application needs to call libpam again";
687 return "Unknown PAM error";