static gboolean
gs_auth_queued_message_handler (GsAuthMessageHandlerData *data)
{
        gboolean res;

        if (gs_auth_get_verbose ()) {
                g_message ("Waiting for lock");
        }

        g_mutex_lock (message_handler_mutex);

        if (gs_auth_get_verbose ()) {
                g_message ("Waiting for response");
        }

        res = data->closure->cb_func (data->style,
                                      data->msg,
                                      data->resp,
                                      data->closure->cb_data);

        data->should_interrupt_stack = res == FALSE;

        g_cond_signal (message_handled_condition);
        g_mutex_unlock (message_handler_mutex);

        if (gs_auth_get_verbose ()) {
                g_message ("Got response");
        }

        return FALSE;
}
Пример #2
0
/* Initializations that potentially take place as a priveleged user:
   If the executable is setuid root, then these initializations
   are run as root, before discarding privileges.
*/
static gboolean
privileged_initialization (void)
{
	gboolean ret;
	char    *nolock_reason;
	char    *orig_uid;
	char    *uid_message;

#ifndef NO_LOCKING
	/* before hack_uid () for proper permissions */
	gs_auth_priv_init ();
#endif /* NO_LOCKING */

	ret = hack_uid (&nolock_reason,
	                &orig_uid,
	                &uid_message);
	if (nolock_reason)
	{
		g_warning ("Locking disabled: %s", nolock_reason);
	}
	if (uid_message && gs_auth_get_verbose ())
	{
		g_print ("Modified UID: %s", uid_message);
	}

	g_free (nolock_reason);
	g_free (orig_uid);
	g_free (uid_message);

	return ret;
}
static gboolean
close_pam_handle (int status)
{

        if (pam_handle != NULL) {
                int status2;

                status2 = pam_end (pam_handle, status);
                pam_handle = NULL;

                if (gs_auth_get_verbose ()) {
                        g_message (" pam_end (...) ==> %d (%s)",
                                   status2,
                                   (status2 == PAM_SUCCESS ? "Success" : "Failure"));
                }
        }

        if (message_handled_condition != NULL) {
                g_cond_free (message_handled_condition);
                message_handled_condition = NULL;
        }

        if (message_handler_mutex != NULL) {
                g_mutex_free (message_handler_mutex);
                message_handler_mutex = NULL;
        }

        return TRUE;
}
static gboolean
gs_auth_run_message_handler (struct pam_closure *c,
                             GSAuthMessageStyle  style,
                             const char         *msg,
                             char              **resp)
{
        GsAuthMessageHandlerData data;

        data.closure = c;
        data.style = style;
        data.msg = msg;
        data.resp = resp;
        data.should_interrupt_stack = TRUE;

        g_mutex_lock (message_handler_mutex);

        /* Queue the callback in the gui (the main) thread
         */
        g_idle_add ((GSourceFunc) gs_auth_queued_message_handler, &data);

        if (gs_auth_get_verbose ()) {
                g_message ("Waiting for respose to message style %d: '%s'", style, msg);
        }

        /* Wait for the response
         */
        g_cond_wait (message_handled_condition,
                     message_handler_mutex);
        g_mutex_unlock (message_handler_mutex);

        if (gs_auth_get_verbose ()) {
                g_message ("Got respose to message style %d: interrupt:%d", style, data.should_interrupt_stack);
        }

        return data.should_interrupt_stack == FALSE;
}
static int
gs_auth_thread_func (int auth_operation_fd)
{
        static const int flags = 0;
        int              status;
        int              status2;
        struct timespec  timeout;
        sigset_t         set;
        const void      *p;

        timeout.tv_sec = 0;
        timeout.tv_nsec = 1;

        set = block_sigchld ();

        status = pam_authenticate (pam_handle, flags);

        sigtimedwait (&set, NULL, &timeout);
        unblock_sigchld ();

        if (gs_auth_get_verbose ()) {
                g_message ("   pam_authenticate (...) ==> %d (%s)",
                           status,
                           PAM_STRERROR (pam_handle, status));
        }

        if (status != PAM_SUCCESS) {
                goto done;
        }

        if ((status = pam_get_item (pam_handle, PAM_USER, &p)) != PAM_SUCCESS) {
                /* is not really an auth problem, but it will
                   pretty much look as such, it shouldn't really
                   happen */
                goto done;
        }

        /* We don't actually care if the account modules fail or succeed,
         * but we need to run them anyway because certain pam modules
         * depend on side effects of the account modules getting run.
         */
        status2 = pam_acct_mgmt (pam_handle, 0);

        if (gs_auth_get_verbose ()) {
                g_message ("pam_acct_mgmt (...) ==> %d (%s)\n",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
        }

        /* FIXME: should we handle these? */
        switch (status2) {
        case PAM_SUCCESS:
                break;
        case PAM_NEW_AUTHTOK_REQD:
                status2 = pam_chauthtok (pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);

                if (status2 != PAM_SUCCESS) {
                    g_message ("pam_acct_mgmt (...) ==> %d (%s)\n",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
		    status = status2;
                }
                break;
        case PAM_AUTHINFO_UNAVAIL:
                break;
        case PAM_ACCT_EXPIRED:
                break;
        case PAM_PERM_DENIED:
                break;
        default :
                break;
        }

        /* Each time we successfully authenticate, refresh credentials,
           for Kerberos/AFS/DCE/etc.  If this fails, just ignore that
           failure and blunder along; it shouldn't matter.

           Note: this used to be PAM_REFRESH_CRED instead of
           PAM_REINITIALIZE_CRED, but Jason Heiss <*****@*****.**>
           says that the Linux PAM library ignores that one, and only refreshes
           credentials when using PAM_REINITIALIZE_CRED.
        */
        status2 = pam_setcred (pam_handle, PAM_REINITIALIZE_CRED);
        if (gs_auth_get_verbose ()) {
                g_message ("   pam_setcred (...) ==> %d (%s)",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
        }

 done:
        /* we're done, close the fd and wake up the main
         * loop
         */
        close (auth_operation_fd);

        return status;
}
static gboolean
create_pam_handle (const char      *username,
                   const char      *display,
                   struct pam_conv *conv,
                   int             *status_code)
{
        int         status;
        const char *service = PAM_SERVICE_NAME;
        char       *disp;
        gboolean    ret;

	if (pam_handle != NULL) {
		g_warning ("create_pam_handle: Stale pam handle around, cleaning up");
                close_pam_handle (PAM_SUCCESS);
	}

	/* init things */
	pam_handle = NULL;
        status = -1;
        disp = NULL;
        ret = TRUE;

	/* Initialize a PAM session for the user */
	if ((status = pam_start (service, username, conv, &pam_handle)) != PAM_SUCCESS) {
		pam_handle = NULL;
                g_warning (_("Unable to establish service %s: %s\n"),
                           service,
                           PAM_STRERROR (NULL, status));

                if (status_code != NULL) {
                        *status_code = status;
                }

                ret = FALSE;
                goto out;
	}

        if (gs_auth_get_verbose ()) {
                g_message ("pam_start (\"%s\", \"%s\", ...) ==> %d (%s)",
                           service,
                           username,
                           status,
                           PAM_STRERROR (pam_handle, status));
        }

        disp = g_strdup (display);
        if (disp == NULL) {
                disp = g_strdup (":0.0");
        }

	if ((status = pam_set_item (pam_handle, PAM_TTY, disp)) != PAM_SUCCESS) {
                g_warning (_("Can't set PAM_TTY=%s"), display);

                if (status_code != NULL) {
                        *status_code = status;
                }

                ret = FALSE;
                goto out;
	}

        ret = TRUE;
	message_handled_condition = g_cond_new ();
	message_handler_mutex = g_mutex_new ();

 out:
        if (status_code != NULL) {
                *status_code = status;
        }

        g_free (disp);

        return ret;
}
static int
pam_conversation (int                        nmsgs,
                  const struct pam_message **msg,
                  struct pam_response      **resp,
                  void                      *closure)
{
        int                  replies = 0;
        struct pam_response *reply = NULL;
        struct pam_closure  *c = (struct pam_closure *) closure;
        gboolean             res;
        int                  ret;

        reply = (struct pam_response *) calloc (nmsgs, sizeof (*reply));

        if (reply == NULL) {
                return PAM_CONV_ERR;
        }

        res = TRUE;
        ret = PAM_SUCCESS;

        for (replies = 0; replies < nmsgs && ret == PAM_SUCCESS; replies++) {
                GSAuthMessageStyle style;
                char              *utf8_msg;

                style = pam_style_to_gs_style (msg [replies]->msg_style);

                utf8_msg = g_locale_to_utf8 (msg [replies]->msg,
                                             -1,
                                             NULL,
                                             NULL,
                                             NULL);

                /* if we couldn't convert text from locale then
                 * assume utf-8 and hope for the best */
                if (utf8_msg == NULL) {
                        char *p;
                        char *q;

                        utf8_msg = g_strdup (msg [replies]->msg);

                        p = utf8_msg;
                        while (*p != '\0' && !g_utf8_validate ((const char *)p, -1, (const char **)&q)) {
                                *q = '?';
                                p = q + 1;
                        }
                }

                /* handle message locally first */
                auth_message_handler (style,
                                      utf8_msg,
                                      &reply [replies].resp,
                                      NULL);

                if (c->cb_func != NULL) {
                        if (gs_auth_get_verbose ()) {
                                g_message ("Handling message style %d: '%s'", style, utf8_msg);
                        }

 			/* blocks until the gui responds
  			 */
  			res = gs_auth_run_message_handler (c,
                                                           style,
  							   utf8_msg,
  							   &reply [replies].resp);

                        if (gs_auth_get_verbose ()) {
                                g_message ("Msg handler returned %d", res);
                        }

                        /* If the handler returns FALSE - interrupt the PAM stack */
                        if (res) {
                                reply [replies].resp_retcode = PAM_SUCCESS;
                        } else {
                                int i;
                                for (i = 0; i <= replies; i++) {
                                        free (reply [i].resp);
                                }
                                free (reply);
                                reply = NULL;
                                ret = PAM_CONV_ERR;
                        }
                }

                g_free (utf8_msg);
        }

        *resp = reply;

        return ret;
}