Back to index

lightdm  1.3.2
libsystem.c
Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <string.h>
00003 #include <errno.h>
00004 #include <sys/types.h>
00005 #include <pwd.h>
00006 #include <grp.h>
00007 #include <security/pam_appl.h>
00008 #include <fcntl.h>
00009 #define __USE_GNU
00010 #include <dlfcn.h>
00011 #ifdef __linux__
00012 #include <linux/vt.h>
00013 #endif
00014 #include <glib.h>
00015 
00016 #define LOGIN_PROMPT "login:"
00017 
00018 static int console_fd = -1;
00019 
00020 static GList *user_entries = NULL;
00021 static GList *getpwent_link = NULL;
00022 
00023 static GList *group_entries = NULL;
00024 
00025 struct pam_handle
00026 {
00027     char *service_name;
00028     char *user;
00029     char *tty;
00030     char **envlist;
00031     struct pam_conv conversation;
00032 };
00033 
00034 uid_t
00035 getuid (void)
00036 {
00037     return 0;
00038 }
00039 
00040 /*uid_t
00041 geteuid (void)
00042 {
00043     return 0;
00044 }*/
00045 
00046 int
00047 initgroups (const char *user, gid_t group)
00048 {
00049     gid_t g[1];
00050 
00051     g[0] = group;
00052     setgroups (1, g);
00053 
00054     return 0;
00055 }
00056 
00057 int
00058 getgroups (int size, gid_t list[])
00059 {
00060     const gchar *group_list;
00061     gchar **groups;
00062     gint groups_length;
00063 
00064     /* Get groups we are a member of */
00065     group_list = g_getenv ("LIGHTDM_TEST_GROUPS");
00066     if (!group_list)
00067         group_list = "";
00068     groups = g_strsplit (group_list, ",", -1);
00069     groups_length = g_strv_length (groups);
00070 
00071     if (size != 0)
00072     {
00073         int i;
00074 
00075         if (groups_length > size)
00076         {
00077             errno = EINVAL;
00078             return -1;
00079         }
00080         for (i = 0; groups[i]; i++)
00081             list[i] = atoi (groups[i]);
00082     }
00083     g_free (groups);
00084 
00085     return groups_length;
00086 }
00087 
00088 int
00089 setgroups (size_t size, const gid_t *list)
00090 {
00091     size_t i;
00092     GString *group_list;
00093 
00094     group_list = g_string_new ("");
00095     for (i = 0; i < size; i++)
00096     {
00097         if (i != 0)
00098             g_string_append (group_list, ",");
00099         g_string_append_printf (group_list, "%d", list[i]);
00100     }
00101     g_setenv ("LIGHTDM_TEST_GROUPS", group_list->str, TRUE);
00102     g_string_free (group_list, TRUE);
00103 
00104     return 0;
00105 }
00106 
00107 int
00108 setgid (gid_t gid)
00109 {
00110     return 0;
00111 }
00112 
00113 int
00114 setuid (uid_t uid)
00115 {
00116     return 0;
00117 }
00118 
00119 #ifdef __linux__
00120 int
00121 open (const char *pathname, int flags, ...)
00122 {
00123     int (*_open) (const char * pathname, int flags, mode_t mode);
00124     int mode = 0;
00125   
00126     if (flags & O_CREAT)
00127     {
00128         va_list ap;
00129         va_start (ap, flags);
00130         mode = va_arg (ap, int);
00131         va_end (ap);
00132     }
00133 
00134     _open = (int (*)(const char * pathname, int flags, mode_t mode)) dlsym (RTLD_NEXT, "open");
00135     if (strcmp (pathname, "/dev/console") == 0)
00136     {
00137         if (console_fd < 0)
00138         {
00139             console_fd = _open ("/dev/null", flags, mode);
00140             fcntl (console_fd, F_SETFD, FD_CLOEXEC);
00141         }
00142         return console_fd;
00143     }
00144     else if (strcmp (pathname, CONFIG_DIR "/lightdm.conf") == 0)
00145     {
00146         gchar *path;
00147         int fd;
00148 
00149         path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "lightdm", "lightdm.conf", NULL);
00150         fd = _open (path, flags, mode);
00151         g_free (path);
00152 
00153         return fd;
00154     }
00155     else
00156         return _open (pathname, flags, mode);
00157 }
00158 
00159 int
00160 ioctl (int d, int request, void *data)
00161 {
00162     int (*_ioctl) (int d, int request, void *data);
00163 
00164     _ioctl = (int (*)(int d, int request, void *data)) dlsym (RTLD_NEXT, "ioctl");
00165     if (d > 0 && d == console_fd)
00166     {
00167         struct vt_stat *console_state;
00168 
00169         switch (request)
00170         {
00171         case VT_GETSTATE:
00172             console_state = data;
00173             console_state->v_active = 7;
00174             break;          
00175         case VT_ACTIVATE:
00176             break;
00177         }
00178         return 0;
00179     }
00180     else
00181         return _ioctl (d, request, data);
00182 }
00183 
00184 int
00185 close (int fd)
00186 {
00187     int (*_close) (int fd);
00188 
00189     if (fd > 0 && fd == console_fd)
00190         return 0;
00191 
00192     _close = (int (*)(int fd)) dlsym (RTLD_NEXT, "close");
00193     return _close (fd);
00194 }
00195 #endif
00196 
00197 static void
00198 free_user (gpointer data)
00199 {
00200     struct passwd *entry = data;
00201   
00202     g_free (entry->pw_name);
00203     g_free (entry->pw_passwd);
00204     g_free (entry->pw_gecos);
00205     g_free (entry->pw_dir);
00206     g_free (entry->pw_shell);
00207     g_free (entry);
00208 }
00209 
00210 static void
00211 load_passwd_file ()
00212 {
00213     gchar *path, *data = NULL, **lines;
00214     gint i;
00215     GError *error = NULL;
00216 
00217     g_list_free_full (user_entries, free_user);
00218     user_entries = NULL;
00219     getpwent_link = NULL;
00220 
00221     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "passwd", NULL);
00222     g_file_get_contents (path, &data, NULL, &error);
00223     g_free (path);
00224     if (error)
00225         g_warning ("Error loading passwd file: %s", error->message);
00226     g_clear_error (&error);
00227 
00228     if (!data)
00229         return;
00230 
00231     lines = g_strsplit (data, "\n", -1);
00232     g_free (data);
00233 
00234     for (i = 0; lines[i]; i++)
00235     {
00236         gchar *line, **fields;
00237 
00238         line = g_strstrip (lines[i]);
00239         fields = g_strsplit (line, ":", -1);
00240         if (g_strv_length (fields) == 7)
00241         {
00242             struct passwd *entry = malloc (sizeof (struct passwd));
00243 
00244             entry->pw_name = g_strdup (fields[0]);
00245             entry->pw_passwd = g_strdup (fields[1]);
00246             entry->pw_uid = atoi (fields[2]);
00247             entry->pw_gid = atoi (fields[3]);
00248             entry->pw_gecos = g_strdup (fields[4]);
00249             entry->pw_dir = g_strdup (fields[5]);
00250             entry->pw_shell = g_strdup (fields[6]);
00251             user_entries = g_list_append (user_entries, entry);
00252         }
00253         g_strfreev (fields);
00254     }
00255     g_strfreev (lines);
00256 }
00257 
00258 struct passwd *
00259 getpwent (void)
00260 {
00261     if (getpwent_link == NULL)
00262     {
00263         load_passwd_file ();
00264         if (user_entries == NULL)
00265             return NULL;
00266         getpwent_link = user_entries;
00267     }
00268     else
00269     {
00270         if (getpwent_link->next == NULL)
00271             return NULL;
00272         getpwent_link = getpwent_link->next;
00273     }
00274 
00275     return getpwent_link->data;
00276 }
00277 
00278 void
00279 setpwent (void)
00280 {
00281     getpwent_link = NULL;
00282 }
00283 
00284 void
00285 endpwent (void)
00286 {
00287     getpwent_link = NULL;
00288 }
00289 
00290 struct passwd *
00291 getpwnam (const char *name)
00292 {
00293     GList *link;
00294   
00295     if (name == NULL)
00296         return NULL;
00297   
00298     load_passwd_file ();
00299 
00300     for (link = user_entries; link; link = link->next)
00301     {
00302         struct passwd *entry = link->data;
00303         if (strcmp (entry->pw_name, name) == 0)
00304             break;
00305     }
00306     if (!link)
00307         return NULL;
00308 
00309     return link->data;
00310 }
00311 
00312 struct passwd *
00313 getpwuid (uid_t uid)
00314 {
00315     GList *link;
00316 
00317     load_passwd_file ();
00318 
00319     for (link = user_entries; link; link = link->next)
00320     {
00321         struct passwd *entry = link->data;
00322         if (entry->pw_uid == uid)
00323             break;
00324     }
00325     if (!link)
00326         return NULL;
00327 
00328     return link->data;
00329 }
00330 
00331 static void
00332 free_group (gpointer data)
00333 {
00334     struct group *entry = data;
00335   
00336     g_free (entry->gr_name);
00337     g_free (entry->gr_passwd);
00338     g_strfreev (entry->gr_mem);
00339     g_free (entry);
00340 }
00341 
00342 static void
00343 load_group_file ()
00344 {
00345     gchar *path, *data = NULL, **lines;
00346     gint i;
00347     GError *error = NULL;
00348 
00349     g_list_free_full (group_entries, free_group);
00350     group_entries = NULL;
00351 
00352     path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), "etc", "group", NULL);
00353     g_file_get_contents (path, &data, NULL, &error);
00354     g_free (path);
00355     if (error)
00356         g_warning ("Error loading group file: %s", error->message);
00357     g_clear_error (&error);
00358 
00359     if (!data)
00360         return;
00361 
00362     lines = g_strsplit (data, "\n", -1);
00363     g_free (data);
00364 
00365     for (i = 0; lines[i]; i++)
00366     {
00367         gchar *line, **fields;
00368 
00369         line = g_strstrip (lines[i]);
00370         fields = g_strsplit (line, ":", -1);
00371         if (g_strv_length (fields) == 4)
00372         {
00373             struct group *entry = malloc (sizeof (struct group));
00374 
00375             entry->gr_name = g_strdup (fields[0]);
00376             entry->gr_passwd = g_strdup (fields[1]);
00377             entry->gr_gid = atoi (fields[2]);
00378             entry->gr_mem = g_strsplit (fields[3], ",", -1);
00379             group_entries = g_list_append (group_entries, entry);
00380         }
00381         g_strfreev (fields);
00382     }
00383     g_strfreev (lines);
00384 }
00385 
00386 struct group *
00387 getgrnam (const char *name)
00388 {
00389     GList *link;
00390 
00391     load_group_file ();
00392 
00393     for (link = group_entries; link; link = link->next)
00394     {
00395         struct group *entry = link->data;
00396         if (strcmp (entry->gr_name, name) == 0)
00397             break;
00398     }
00399     if (!link)
00400         return NULL;
00401 
00402     return link->data;
00403 }
00404 
00405 struct group *
00406 getgrgid (gid_t gid)
00407 {
00408     GList *link;
00409 
00410     load_group_file ();
00411 
00412     for (link = group_entries; link; link = link->next)
00413     {
00414         struct group *entry = link->data;
00415         if (entry->gr_gid == gid)
00416             break;
00417     }
00418     if (!link)
00419         return NULL;
00420 
00421     return link->data;
00422 }
00423 
00424 int
00425 pam_start (const char *service_name, const char *user, const struct pam_conv *conversation, pam_handle_t **pamh)
00426 {
00427     pam_handle_t *handle;
00428 
00429     if (service_name == NULL || conversation == NULL || pamh == NULL)
00430         return PAM_SYSTEM_ERR;
00431 
00432     handle = *pamh = malloc (sizeof (pam_handle_t));
00433     if (handle == NULL)
00434         return PAM_BUF_ERR;
00435 
00436     handle->service_name = strdup (service_name);
00437     handle->user = user ? strdup (user) : NULL;
00438     handle->tty = NULL;
00439     handle->conversation.conv = conversation->conv;
00440     handle->conversation.appdata_ptr = conversation->appdata_ptr;
00441     handle->envlist = malloc (sizeof (char *) * 1);
00442     handle->envlist[0] = NULL;
00443 
00444     return PAM_SUCCESS;
00445 }
00446 
00447 static void
00448 send_info (pam_handle_t *pamh, const char *message)
00449 {
00450     struct pam_message **msg;
00451     struct pam_response *resp = NULL;
00452 
00453     msg = calloc (1, sizeof (struct pam_message *));
00454     msg[0] = malloc (sizeof (struct pam_message));
00455     msg[0]->msg_style = PAM_TEXT_INFO;
00456     msg[0]->msg = message;
00457     pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
00458     free (msg[0]);
00459     free (msg);
00460     if (resp)
00461     {
00462         if (resp[0].resp)
00463             free (resp[0].resp);
00464         free (resp);
00465     }
00466 }
00467 
00468 int
00469 pam_authenticate (pam_handle_t *pamh, int flags)
00470 {
00471     struct passwd *entry;
00472     gboolean password_matches = FALSE;
00473 
00474     if (pamh == NULL)
00475         return PAM_SYSTEM_ERR;
00476 
00477     /* Prompt for username */
00478     if (pamh->user == NULL)
00479     {
00480         int result;
00481         struct pam_message **msg;
00482         struct pam_response *resp = NULL;
00483 
00484         msg = malloc (sizeof (struct pam_message *) * 1);
00485         msg[0] = malloc (sizeof (struct pam_message));
00486         msg[0]->msg_style = PAM_PROMPT_ECHO_ON; 
00487         msg[0]->msg = LOGIN_PROMPT;
00488         result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
00489         free (msg[0]);
00490         free (msg);
00491         if (result != PAM_SUCCESS)
00492             return result;
00493 
00494         if (resp == NULL)
00495             return PAM_CONV_ERR;
00496         if (resp[0].resp == NULL)
00497         {
00498             free (resp);
00499             return PAM_CONV_ERR;
00500         }
00501       
00502         pamh->user = strdup (resp[0].resp);
00503         free (resp[0].resp);
00504         free (resp);
00505     }
00506 
00507     if (strcmp (pamh->user, "log-pam") == 0)
00508         send_info (pamh, "pam_authenticate");
00509 
00510     /* Crash on authenticate */
00511     if (strcmp (pamh->user, "crash-authenticate") == 0)
00512         kill (getpid (), SIGSEGV);
00513 
00514     /* Look up password database */
00515     entry = getpwnam (pamh->user);
00516 
00517     /* Prompt for password if required */
00518     if (entry && strcmp (pamh->user, "always-password") != 0 && (strcmp (pamh->service_name, "lightdm-autologin") == 0 || strcmp (entry->pw_passwd, "") == 0))
00519         password_matches = TRUE;
00520     else
00521     {
00522         int i, n_messages = 0, password_index, result;
00523         struct pam_message **msg;
00524         struct pam_response *resp = NULL;
00525 
00526         msg = malloc (sizeof (struct pam_message *) * 5);
00527         if (strcmp (pamh->user, "info-prompt") == 0)
00528         {
00529             msg[n_messages] = malloc (sizeof (struct pam_message));
00530             msg[n_messages]->msg_style = PAM_TEXT_INFO;
00531             msg[n_messages]->msg = "Welcome to LightDM";
00532             n_messages++;
00533         }
00534         if (strcmp (pamh->user, "multi-info-prompt") == 0)
00535         {
00536             msg[n_messages] = malloc (sizeof (struct pam_message));
00537             msg[n_messages]->msg_style = PAM_TEXT_INFO;
00538             msg[n_messages]->msg = "Welcome to LightDM";
00539             n_messages++;
00540             msg[n_messages] = malloc (sizeof (struct pam_message));
00541             msg[n_messages]->msg_style = PAM_ERROR_MSG;
00542             msg[n_messages]->msg = "This is an error";
00543             n_messages++;
00544             msg[n_messages] = malloc (sizeof (struct pam_message));
00545             msg[n_messages]->msg_style = PAM_TEXT_INFO;
00546             msg[n_messages]->msg = "You should have seen three messages";
00547             n_messages++;
00548         }
00549         msg[n_messages] = malloc (sizeof (struct pam_message));
00550         msg[n_messages]->msg_style = PAM_PROMPT_ECHO_OFF;
00551         msg[n_messages]->msg = "Password:";
00552         password_index = n_messages;
00553         n_messages++;
00554         result = pamh->conversation.conv (n_messages, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
00555         for (i = 0; i < n_messages; i++)
00556             free (msg[i]);
00557         free (msg);
00558         if (result != PAM_SUCCESS)
00559             return result;
00560 
00561         if (resp == NULL)
00562             return PAM_CONV_ERR;
00563         if (resp[password_index].resp == NULL)
00564         {
00565             free (resp);
00566             return PAM_CONV_ERR;
00567         }
00568 
00569         if (entry)
00570             password_matches = strcmp (entry->pw_passwd, resp[password_index].resp) == 0;
00571         for (i = 0; i < n_messages; i++)
00572         {
00573             if (resp[i].resp)
00574                 free (resp[i].resp);
00575         }
00576         free (resp);
00577 
00578         /* Do two factor authentication */
00579         if (password_matches && strcmp (pamh->user, "two-factor") == 0)
00580         {
00581             msg = malloc (sizeof (struct pam_message *) * 1);
00582             msg[0] = malloc (sizeof (struct pam_message));
00583             msg[0]->msg_style = PAM_PROMPT_ECHO_ON;
00584             msg[0]->msg = "OTP:";
00585             resp = NULL;
00586             result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
00587             free (msg[0]);
00588             free (msg);
00589 
00590             if (resp == NULL)
00591                 return PAM_CONV_ERR;
00592             if (resp[0].resp == NULL)
00593             {
00594                 free (resp);
00595                 return PAM_CONV_ERR;
00596             }
00597             password_matches = strcmp (resp[0].resp, "otp") == 0;
00598             free (resp[0].resp);
00599             free (resp);
00600         }
00601     }
00602 
00603     /* Special user has home directory created on login */
00604     if (password_matches && strcmp (pamh->user, "mount-home-dir") == 0)
00605         g_mkdir_with_parents (entry->pw_dir, 0755);
00606 
00607     /* Special user 'change-user1' changes user on authentication */
00608     if (password_matches && strcmp (pamh->user, "change-user1") == 0)
00609     {
00610         g_free (pamh->user);
00611         pamh->user = g_strdup ("change-user2");
00612     }
00613 
00614     /* Special user 'change-user-invalid' changes to an invalid user on authentication */
00615     if (password_matches && strcmp (pamh->user, "change-user-invalid") == 0)
00616     {
00617         g_free (pamh->user);
00618         pamh->user = g_strdup ("invalid-user");
00619     }
00620 
00621     if (password_matches)
00622         return PAM_SUCCESS;
00623     else
00624         return PAM_AUTH_ERR;
00625 }
00626 
00627 static const char *
00628 get_env_value (const char *name_value, const char *name)
00629 {
00630     int j;
00631 
00632     for (j = 0; name[j] && name[j] != '=' && name[j] == name_value[j]; j++);
00633     if (name_value[j] == '=')
00634         return &name_value[j + 1];
00635 
00636     return NULL;
00637 }
00638 
00639 int
00640 pam_putenv (pam_handle_t *pamh, const char *name_value)
00641 {
00642     int i;
00643 
00644     if (pamh == NULL || name_value == NULL)
00645         return PAM_SYSTEM_ERR;
00646 
00647     for (i = 0; pamh->envlist[i]; i++)
00648     {
00649         if (get_env_value (pamh->envlist[i], name_value))
00650             break;
00651     }
00652 
00653     if (pamh->envlist[i])
00654     {
00655         free (pamh->envlist[i]);
00656         pamh->envlist[i] = strdup (name_value);
00657     }
00658     else
00659     {
00660         pamh->envlist = realloc (pamh->envlist, sizeof (char *) * (i + 2));
00661         pamh->envlist[i] = strdup (name_value);
00662         pamh->envlist[i + 1] = NULL;
00663     }
00664 
00665     return PAM_SUCCESS;
00666 }
00667 
00668 const char *
00669 pam_getenv (pam_handle_t *pamh, const char *name)
00670 {
00671     int i;
00672 
00673     if (pamh == NULL || name == NULL)
00674         return NULL;
00675 
00676     for (i = 0; pamh->envlist[i]; i++)
00677     {
00678         const char *value;
00679         value = get_env_value (pamh->envlist[i], name);
00680         if (value)
00681             return value;
00682     }
00683 
00684     return NULL;
00685 }
00686 
00687 char **
00688 pam_getenvlist (pam_handle_t *pamh)
00689 {
00690     if (pamh == NULL)
00691         return NULL;
00692 
00693     return pamh->envlist;
00694 }
00695 
00696 int
00697 pam_set_item (pam_handle_t *pamh, int item_type, const void *item)
00698 {
00699     if (pamh == NULL || item == NULL)
00700         return PAM_SYSTEM_ERR;
00701 
00702     switch (item_type)
00703     {
00704     case PAM_TTY:
00705         if (pamh->tty)
00706             free (pamh->tty);
00707         pamh->tty = strdup ((const char *) item);
00708         return PAM_SUCCESS;
00709 
00710     default:
00711         return PAM_BAD_ITEM;
00712     }
00713 }
00714 
00715 int
00716 pam_get_item (const pam_handle_t *pamh, int item_type, const void **item)
00717 {
00718     if (pamh == NULL || item == NULL)
00719         return PAM_SYSTEM_ERR;
00720   
00721     switch (item_type)
00722     {
00723     case PAM_SERVICE:
00724         *item = pamh->service_name;
00725         return PAM_SUCCESS;
00726       
00727     case PAM_USER:
00728         *item = pamh->user;
00729         return PAM_SUCCESS;
00730       
00731     case PAM_USER_PROMPT:
00732         *item = LOGIN_PROMPT;
00733         return PAM_SUCCESS;
00734       
00735     case PAM_TTY:
00736         *item = pamh->tty;
00737         return PAM_SUCCESS;
00738 
00739     case PAM_CONV:
00740         *item = &pamh->conversation;
00741         return PAM_SUCCESS;
00742 
00743     default:
00744         return PAM_BAD_ITEM;
00745     }
00746 }
00747 
00748 int
00749 pam_open_session (pam_handle_t *pamh, int flags)
00750 {
00751     if (pamh == NULL)
00752         return PAM_SYSTEM_ERR;
00753 
00754     if (strcmp (pamh->user, "session-error") == 0)
00755         return PAM_SESSION_ERR;
00756 
00757     if (strcmp (pamh->user, "log-pam") == 0)
00758         send_info (pamh, "pam_open_session");
00759 
00760     if (strcmp (pamh->user, "make-home-dir") == 0)
00761     {
00762         struct passwd *entry;
00763         entry = getpwnam (pamh->user);
00764         g_mkdir_with_parents (entry->pw_dir, 0755);
00765     }
00766 
00767     return PAM_SUCCESS;
00768 }
00769 
00770 int
00771 pam_close_session (pam_handle_t *pamh, int flags)
00772 {
00773     if (pamh == NULL)
00774         return PAM_SYSTEM_ERR;
00775 
00776     if (strcmp (pamh->user, "log-pam") == 0)
00777         send_info (pamh, "pam_close_session");
00778 
00779     return PAM_SUCCESS;
00780 }
00781 
00782 int
00783 pam_acct_mgmt (pam_handle_t *pamh, int flags)
00784 {
00785     if (pamh == NULL)
00786         return PAM_SYSTEM_ERR;
00787   
00788     if (!pamh->user)
00789         return PAM_USER_UNKNOWN;
00790 
00791     if (strcmp (pamh->user, "log-pam") == 0)
00792         send_info (pamh, "pam_acct_mgmt");
00793 
00794     if (strcmp (pamh->user, "denied") == 0)
00795         return PAM_PERM_DENIED;
00796     if (strcmp (pamh->user, "expired") == 0)
00797         return PAM_ACCT_EXPIRED;
00798     if (strcmp (pamh->user, "new-authtok") == 0)
00799         return PAM_NEW_AUTHTOK_REQD;
00800 
00801     return PAM_SUCCESS;
00802 }
00803 
00804 int
00805 pam_chauthtok (pam_handle_t *pamh, int flags)
00806 {
00807     struct passwd *entry;
00808     int result;
00809     struct pam_message **msg;
00810     struct pam_response *resp = NULL;
00811 
00812     if (pamh == NULL)
00813         return PAM_SYSTEM_ERR;
00814 
00815     if (strcmp (pamh->user, "log-pam") == 0)
00816         send_info (pamh, "pam_chauthtok");
00817 
00818     msg = malloc (sizeof (struct pam_message *) * 1);
00819     msg[0] = malloc (sizeof (struct pam_message));
00820     msg[0]->msg_style = PAM_PROMPT_ECHO_OFF;
00821     msg[0]->msg = "Enter new password:";
00822     result = pamh->conversation.conv (1, (const struct pam_message **) msg, &resp, pamh->conversation.appdata_ptr);
00823     free (msg[0]);
00824     free (msg);
00825     if (result != PAM_SUCCESS)
00826         return result;
00827 
00828     if (resp == NULL)
00829         return PAM_CONV_ERR;
00830     if (resp[0].resp == NULL)
00831     {
00832         free (resp);
00833         return PAM_CONV_ERR;
00834     }
00835 
00836     /* Update password database */
00837     entry = getpwnam (pamh->user);
00838     free (entry->pw_passwd);
00839     entry->pw_passwd = resp[0].resp;
00840     free (resp);
00841 
00842     return PAM_SUCCESS;
00843 }
00844 
00845 int
00846 pam_setcred (pam_handle_t *pamh, int flags)
00847 {
00848     gchar *e;
00849 
00850     if (pamh == NULL)
00851         return PAM_SYSTEM_ERR;
00852 
00853     if (strcmp (pamh->user, "log-pam") == 0)
00854         send_info (pamh, "pam_setcred");
00855 
00856     /* Put the test directories into the path */
00857     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"));
00858     pam_putenv (pamh, e);
00859     g_free (e);
00860 
00861     if (strcmp (pamh->user, "cred-error") == 0)
00862         return PAM_CRED_ERR;
00863     if (strcmp (pamh->user, "cred-expired") == 0)
00864         return PAM_CRED_EXPIRED;
00865     if (strcmp (pamh->user, "cred-unavail") == 0)
00866         return PAM_CRED_UNAVAIL;
00867 
00868     /* Join special groups if requested */
00869     if (strcmp (pamh->user, "group-member") == 0 && flags & PAM_ESTABLISH_CRED)
00870     {
00871         struct group *group;
00872         gid_t *groups;
00873         int groups_length;
00874 
00875         group = getgrnam ("test-group");
00876         if (group)
00877         {
00878             groups_length = getgroups (0, NULL);
00879             groups = malloc (sizeof (gid_t) * (groups_length + 1));
00880             groups_length = getgroups (groups_length, groups);
00881             groups[groups_length] = group->gr_gid;
00882             groups_length++;
00883             setgroups (groups_length, groups);
00884             free (groups);
00885         }
00886 
00887         /* We need to pass our group overrides down the child process - the environment via PAM seems the only way to do it easily */
00888         pam_putenv (pamh, g_strdup_printf ("LIGHTDM_TEST_GROUPS=%s", g_getenv ("LIGHTDM_TEST_GROUPS")));
00889     }
00890 
00891     return PAM_SUCCESS;
00892 }
00893 
00894 int
00895 pam_end (pam_handle_t *pamh, int pam_status)
00896 {
00897     if (pamh == NULL)
00898         return PAM_SYSTEM_ERR;
00899   
00900     free (pamh->service_name);
00901     if (pamh->user)
00902         free (pamh->user);
00903     if (pamh->tty)
00904         free (pamh->tty);
00905     free (pamh);
00906 
00907     return PAM_SUCCESS;
00908 }
00909 
00910 const char *
00911 pam_strerror (pam_handle_t *pamh, int errnum)
00912 {
00913     if (pamh == NULL)
00914         return NULL;
00915 
00916     switch (errnum)
00917     {
00918     case PAM_SUCCESS:
00919         return "Success";
00920     case PAM_ABORT:
00921         return "Critical error - immediate abort";
00922     case PAM_OPEN_ERR:
00923         return "Failed to load module";
00924     case PAM_SYMBOL_ERR:
00925         return "Symbol not found";
00926     case PAM_SERVICE_ERR:
00927         return "Error in service module";
00928     case PAM_SYSTEM_ERR:
00929         return "System error";
00930     case PAM_BUF_ERR:
00931         return "Memory buffer error";
00932     case PAM_PERM_DENIED:
00933         return "Permission denied";
00934     case PAM_AUTH_ERR:
00935         return "Authentication failure";
00936     case PAM_CRED_INSUFFICIENT:
00937         return "Insufficient credentials to access authentication data";
00938     case PAM_AUTHINFO_UNAVAIL:
00939         return "Authentication service cannot retrieve authentication info";
00940     case PAM_USER_UNKNOWN:
00941         return "User not known to the underlying authentication module";
00942     case PAM_MAXTRIES:
00943         return "Have exhausted maximum number of retries for service";
00944     case PAM_NEW_AUTHTOK_REQD:
00945         return "Authentication token is no longer valid; new one required";
00946     case PAM_ACCT_EXPIRED:
00947         return "User account has expired";
00948     case PAM_SESSION_ERR:
00949         return "Cannot make/remove an entry for the specified session";
00950     case PAM_CRED_UNAVAIL:
00951         return "Authentication service cannot retrieve user credentials";
00952     case PAM_CRED_EXPIRED:
00953         return "User credentials expired";
00954     case PAM_CRED_ERR:
00955         return "Failure setting user credentials";
00956     case PAM_NO_MODULE_DATA:
00957         return "No module specific data is present";
00958     case PAM_BAD_ITEM:
00959         return "Bad item passed to pam_*_item()";
00960     case PAM_CONV_ERR:
00961         return "Conversation error";
00962     case PAM_AUTHTOK_ERR:
00963         return "Authentication token manipulation error";
00964     case PAM_AUTHTOK_RECOVERY_ERR:
00965         return "Authentication information cannot be recovered";
00966     case PAM_AUTHTOK_LOCK_BUSY:
00967         return "Authentication token lock busy";
00968     case PAM_AUTHTOK_DISABLE_AGING:
00969         return "Authentication token aging disabled";
00970     case PAM_TRY_AGAIN:
00971         return "Failed preliminary check by password service";
00972     case PAM_IGNORE:
00973         return "The return value should be ignored by PAM dispatch";
00974     case PAM_MODULE_UNKNOWN:
00975         return "Module is unknown";
00976     case PAM_AUTHTOK_EXPIRED:
00977         return "Authentication token expired";
00978     case PAM_CONV_AGAIN:
00979         return "Conversation is waiting for event";
00980     case PAM_INCOMPLETE:
00981         return "Application needs to call libpam again";
00982     default:
00983         return "Unknown PAM error";
00984     }
00985 }
00986 
00987 void
00988 setutxent (void)
00989 {
00990 }
00991   
00992 struct utmp *
00993 pututxline (struct utmp *ut)
00994 {
00995     return ut;
00996 }
00997 
00998 void
00999 endutxent (void)
01000 {
01001 }