5 #include <security/pam_appl.h>
14 #define LOGIN_PROMPT "login:"
16 static int console_fd = -1;
18 static GList *user_entries = NULL;
19 static GList *getpwent_link = NULL;
27 struct pam_conv conversation;
43 initgroups (const char *user, gid_t group)
62 open (const char *pathname, int flags, mode_t mode)
64 int (*_open) (const char * pathname, int flags, mode_t mode);
66 _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open");
67 if (strcmp (pathname, "/dev/console") == 0)
70 console_fd = _open ("/dev/null", 0, 0);
74 return _open(pathname, flags, mode);
78 ioctl (int d, int request, void *data)
80 int (*_ioctl) (int d, int request, void *data);
82 _ioctl = (int (*)(int d, int request, void *data)) dlsym (RTLD_NEXT, "ioctl");
83 if (d > 0 && d == console_fd)
85 struct vt_stat *console_state;
91 console_state->v_active = 7;
99 return _ioctl (d, request, data);
105 int (*_close) (int fd);
107 if (fd > 0 && fd == console_fd)
110 _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
116 free_user (gpointer data)
118 struct passwd *entry = data;
120 g_free (entry->pw_name);
121 g_free (entry->pw_passwd);
122 g_free (entry->pw_gecos);
123 g_free (entry->pw_dir);
124 g_free (entry->pw_shell);
131 gchar *data = NULL, **lines;
133 GError *error = NULL;
135 g_list_free_full (user_entries, free_user);
137 getpwent_link = NULL;
139 g_file_get_contents (g_getenv ("LIGHTDM_TEST_PASSWD_FILE"), &data, NULL, &error);
141 g_warning ("Error loading passwd file: %s", error->message);
142 g_clear_error (&error);
147 lines = g_strsplit (data, "\n", -1);
150 for (i = 0; lines[i]; i++)
152 gchar *line, **fields;
154 line = g_strstrip (lines[i]);
155 fields = g_strsplit (line, ":", -1);
156 if (g_strv_length (fields) == 7)
158 struct passwd *entry = malloc (sizeof (struct passwd));
160 entry->pw_name = g_strdup (fields[0]);
161 entry->pw_passwd = g_strdup (fields[1]);
162 entry->pw_uid = atoi (fields[2]);
163 entry->pw_gid = atoi (fields[3]);
164 entry->pw_gecos = g_strdup (fields[4]);
165 entry->pw_dir = g_strdup (fields[5]);
166 entry->pw_shell = g_strdup (fields[6]);
167 user_entries = g_list_append (user_entries, entry);
177 if (getpwent_link == NULL)
180 if (user_entries == NULL)
182 getpwent_link = user_entries;
186 if (getpwent_link->next == NULL)
188 getpwent_link = getpwent_link->next;
191 return getpwent_link->data;
197 getpwent_link = NULL;
203 getpwent_link = NULL;
207 getpwnam (const char *name)
216 for (link = user_entries; link; link = link->next)
218 struct passwd *entry = link->data;
219 if (strcmp (entry->pw_name, name) == 0)
235 for (link = user_entries; link; link = link->next)
237 struct passwd *entry = link->data;
238 if (entry->pw_uid == uid)
248 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
250 pam_handle_t *handle;
252 if (service_name == NULL || conversation == NULL || pamh == NULL)
253 return PAM_SYSTEM_ERR;
255 handle = *pamh = malloc (sizeof (pam_handle_t));
259 handle->service_name = strdup (service_name);
260 handle->user = user ? strdup (user) : NULL;
262 handle->conversation.conv = conversation->conv;
263 handle->conversation.appdata_ptr = conversation->appdata_ptr;
264 handle->envlist = malloc (sizeof (char *) * 1);
265 handle->envlist[0] = NULL;
271 pam_authenticate (pam_handle_t *pamh, int flags)
273 struct passwd *entry;
274 gboolean password_matches = FALSE;
277 return PAM_SYSTEM_ERR;
279 /* Prompt for username */
280 if (pamh->user == NULL)
283 struct pam_message **msg;
284 struct pam_response *resp = NULL;
286 msg = malloc (sizeof (struct pam_message *) * 1);
287 msg[0] = malloc (sizeof (struct pam_message));
288 msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
289 msg[0]->msg = LOGIN_PROMPT;
290 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
293 if (result != PAM_SUCCESS)
298 if (resp[0].resp == NULL)
304 pamh->user = strdup (resp[0].resp);
309 /* Crash on authenticate */
310 if (strcmp (pamh->user, "crash-authenticate") == 0)
311 kill (getpid (), SIGSEGV);
313 /* Look up password database */
314 entry = getpwnam (pamh->user);
316 /* Prompt for password if required */
317 if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
318 password_matches = TRUE;
322 struct pam_message **msg;
323 struct pam_response *resp = NULL;
325 msg = malloc (sizeof (struct pam_message *) * 1);
326 msg[0] = malloc (sizeof (struct pam_message));
327 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
328 msg[0]->msg = "Password:";
329 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
332 if (result != PAM_SUCCESS)
337 if (resp[0].resp == NULL)
344 password_matches = strcmp (entry->pw_passwd, resp[0].resp) == 0;
349 /* Special user has home directory created on login */
350 if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
351 g_mkdir_with_parents (entry->pw_dir, 0755);
353 /* Special user 'change-user1' changes user on authentication */
354 if (password_matches && strcmp (pamh->user, "change-user1") == 0)
357 pamh->user = g_strdup ("change-user2");
360 /* Special user 'change-user-invalid' changes to an invalid user on authentication */
361 if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
364 pamh->user = g_strdup ("invalid-user");
367 if (password_matches)
374 get_env_value (const char *name_value, const char *name)
378 for (j = 0; name[j] && name[j] != '=' && name[j] == name_value[j]; j++);
379 if (name_value[j] == '=')
380 return &name_value[j + 1];
386 pam_putenv (pam_handle_t *pamh, const char *name_value)
390 if (pamh == NULL || name_value == NULL)
391 return PAM_SYSTEM_ERR;
393 for (i = 0; pamh->envlist[i]; i++)
395 if (get_env_value (pamh->envlist[i], name_value))
399 if (pamh->envlist[i])
401 free (pamh->envlist[i]);
402 pamh->envlist[i] = strdup (name_value);
406 pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
407 pamh->envlist[i] = strdup (name_value);
408 pamh->envlist[i + 1] = NULL;
415 pam_getenv (pam_handle_t *pamh, const char *name)
419 if (pamh == NULL || name == NULL)
422 for (i = 0; pamh->envlist[i]; i++)
425 value = get_env_value (pamh->envlist[i], name);
434 pam_getenvlist (pam_handle_t *pamh)
439 return pamh->envlist;
443 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
445 if (pamh == NULL || item == NULL)
446 return PAM_SYSTEM_ERR;
453 pamh->tty = strdup ((const char *) item);
462 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
464 if (pamh == NULL || item == NULL)
465 return PAM_SYSTEM_ERR;
470 *item = pamh->service_name;
477 case PAM_USER_PROMPT:
478 *item = LOGIN_PROMPT;
486 *item = &pamh->conversation;
495 pam_open_session (pam_handle_t *pamh, int flags)
498 return PAM_SYSTEM_ERR;
504 pam_close_session (pam_handle_t *pamh, int flags)
507 return PAM_SYSTEM_ERR;
513 pam_acct_mgmt (pam_handle_t *pamh, int flags)
516 return PAM_SYSTEM_ERR;
519 return PAM_USER_UNKNOWN;
521 if (strcmp (pamh->user, "denied") == 0)
522 return PAM_PERM_DENIED;
523 if (strcmp (pamh->user, "expired") == 0)
524 return PAM_ACCT_EXPIRED;
525 if (strcmp (pamh->user, "new-authtok") == 0)
526 return PAM_NEW_AUTHTOK_REQD;
532 pam_chauthtok (pam_handle_t *pamh, int flags)
534 struct passwd *entry;
536 struct pam_message **msg;
537 struct pam_response *resp = NULL;
540 return PAM_SYSTEM_ERR;
542 msg = malloc (sizeof (struct pam_message *) * 1);
543 msg[0] = malloc (sizeof (struct pam_message));
544 msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
545 msg[0]->msg = "Enter new password:";
546 result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
549 if (result != PAM_SUCCESS)
554 if (resp[0].resp == NULL)
560 /* Update password database */
561 entry = getpwnam (pamh->user);
562 free (entry->pw_passwd);
563 entry->pw_passwd = resp[0].resp;
570 pam_setcred (pam_handle_t *pamh, int flags)
573 return PAM_SYSTEM_ERR;
579 pam_end (pam_handle_t *pamh, int pam_status)
582 return PAM_SYSTEM_ERR;
584 free (pamh->service_name);
595 pam_strerror (pam_handle_t *pamh, int errnum)
605 return "Critical error - immediate abort";
607 return "Failed to load module";
609 return "Symbol not found";
610 case PAM_SERVICE_ERR:
611 return "Error in service module";
613 return "System error";
615 return "Memory buffer error";
616 case PAM_PERM_DENIED:
617 return "Permission denied";
619 return "Authentication failure";
620 case PAM_CRED_INSUFFICIENT:
621 return "Insufficient credentials to access authentication data";
622 case PAM_AUTHINFO_UNAVAIL:
623 return "Authentication service cannot retrieve authentication info";
624 case PAM_USER_UNKNOWN:
625 return "User not known to the underlying authentication module";
627 return "Have exhausted maximum number of retries for service";
628 case PAM_NEW_AUTHTOK_REQD:
629 return "Authentication token is no longer valid; new one required";
630 case PAM_ACCT_EXPIRED:
631 return "User account has expired";
632 case PAM_SESSION_ERR:
633 return "Cannot make/remove an entry for the specified session";
634 case PAM_CRED_UNAVAIL:
635 return "Authentication service cannot retrieve user credentials";
636 case PAM_CRED_EXPIRED:
637 return "User credentials expired";
639 return "Failure setting user credentials";
640 case PAM_NO_MODULE_DATA:
641 return "No module specific data is present";
643 return "Bad item passed to pam_*_item()";
645 return "Conversation error";
646 case PAM_AUTHTOK_ERR:
647 return "Authentication token manipulation error";
648 case PAM_AUTHTOK_RECOVERY_ERR:
649 return "Authentication information cannot be recovered";
650 case PAM_AUTHTOK_LOCK_BUSY:
651 return "Authentication token lock busy";
652 case PAM_AUTHTOK_DISABLE_AGING:
653 return "Authentication token aging disabled";
655 return "Failed preliminary check by password service";
657 return "The return value should be ignored by PAM dispatch";
658 case PAM_MODULE_UNKNOWN:
659 return "Module is unknown";
660 case PAM_AUTHTOK_EXPIRED:
661 return "Authentication token expired";
663 return "Conversation is waiting for event";
665 return "Application needs to call libpam again";
667 return "Unknown PAM error";