gdm_session_worker_initialize_pam (GdmSessionWorker   *worker,
                                   const char         *service,
                                   const char * const *extensions,
                                   const char         *username,
                                   const char         *hostname,
                                   gboolean            display_is_local,
                                   const char         *x11_display_name,
                                   const char         *x11_authority_file,
                                   const char         *display_device,
                                   const char         *seat_id,
                                   GError            **error)
{
        struct pam_conv        pam_conversation;
        int                    error_code;
        char tty_string[256];

        g_assert (worker->priv->pam_handle == NULL);

        g_debug ("GdmSessionWorker: initializing PAM; service=%s username=%s seat=%s",
                 service ? service : "(null)",
                 username ? username : "(null)",
                 seat_id ? seat_id : "(null)");

#ifdef SUPPORTS_PAM_EXTENSIONS
        if (extensions != NULL) {
                GDM_PAM_EXTENSION_ADVERTISE_SUPPORTED_EXTENSIONS (gdm_pam_extension_environment_block, extensions);
        }
#endif

        pam_conversation.conv = (GdmSessionWorkerPamNewMessagesFunc) gdm_session_worker_pam_new_messages_handler;
        pam_conversation.appdata_ptr = worker;

        gdm_session_worker_start_auditor (worker);
        error_code = pam_start (service,
                                username,
                                &pam_conversation,
                                &worker->priv->pam_handle);
        if (error_code != PAM_SUCCESS) {
                g_debug ("GdmSessionWorker: could not initialize PAM: (error code %d)", error_code);
                /* we don't use pam_strerror here because it requires a valid
                 * pam handle, and if pam_start fails pam_handle is undefined
                 */
                g_set_error (error,
                             GDM_SESSION_WORKER_ERROR,
                             GDM_SESSION_WORKER_ERROR_SERVICE_UNAVAILABLE,
                             "%s", "");

                goto out;
        }

        /* set USER PROMPT */
        if (username == NULL) {
                error_code = pam_set_item (worker->priv->pam_handle, PAM_USER_PROMPT, _("Username:"));

                if (error_code != PAM_SUCCESS) {
                        g_debug ("GdmSessionWorker: error informing authentication system of preferred username prompt: %s",
                                pam_strerror (worker->priv->pam_handle, error_code));
                        g_set_error (error,
                                     GDM_SESSION_WORKER_ERROR,
                                     GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
                                     "%s", "");
                        goto out;
                }
        }

        /* set RHOST */
        if (hostname != NULL && hostname[0] != '\0') {
                error_code = pam_set_item (worker->priv->pam_handle, PAM_RHOST, hostname);
                g_debug ("error informing authentication system of user's hostname %s: %s",
                         hostname,
                         pam_strerror (worker->priv->pam_handle, error_code));

                if (error_code != PAM_SUCCESS) {
                        g_set_error (error,
                                     GDM_SESSION_WORKER_ERROR,
                                     GDM_SESSION_WORKER_ERROR_AUTHENTICATING,
                                     "%s", "");
                        goto out;
                }
        }

        /* set seat ID */
        if (seat_id != NULL && seat_id[0] != '\0') {
                gdm_session_worker_set_environment_variable (worker, "XDG_SEAT", seat_id);
        }

        if (strcmp (service, "gdm-launch-environment") == 0) {
                gdm_session_worker_set_environment_variable (worker, "XDG_SESSION_CLASS", "greeter");
        }

        g_debug ("GdmSessionWorker: state SETUP_COMPLETE");
        gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SETUP_COMPLETE);

        /* Temporarily set PAM_TTY with the login VT,
           PAM_TTY will be reset with the users VT right before the user session is opened */
        g_snprintf (tty_string, 256, "/dev/tty%d", GDM_INITIAL_VT);
        pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
        if (!display_is_local)
                worker->priv->password_is_required = TRUE;

 out:
        if (error_code != PAM_SUCCESS) {
                gdm_session_worker_uninitialize_pam (worker, error_code);
                return FALSE;
        }

        return TRUE;
}