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; }
/* 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; }