void auth_request_handler_reply(struct auth_request *request, enum auth_client_result result, const void *auth_reply, size_t reply_size) { struct auth_request_handler *handler = request->handler; string_t *str; int ret; if (handler->destroyed) { /* the client connection was already closed. we can't do anything but abort this request */ request->internal_failure = TRUE; result = AUTH_CLIENT_RESULT_FAILURE; /* make sure this request is set to finished state (it's not with result=continue) */ auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); } switch (result) { case AUTH_CLIENT_RESULT_CONTINUE: str = t_str_new(16 + MAX_BASE64_ENCODED_SIZE(reply_size)); str_printfa(str, "CONT\t%u\t", request->id); base64_encode(auth_reply, reply_size, str); request->accept_cont_input = TRUE; handler->callback(str_c(str), handler->context); break; case AUTH_CLIENT_RESULT_SUCCESS: if (reply_size > 0) { str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size)); base64_encode(auth_reply, reply_size, str); auth_fields_add(request->extra_fields, "resp", str_c(str), 0); } ret = auth_request_proxy_finish(request, auth_request_handler_proxy_callback); if (ret < 0) auth_request_handler_reply_failure_finish(request); else if (ret > 0) auth_request_handler_reply_success_finish(request); else return; break; case AUTH_CLIENT_RESULT_FAILURE: auth_request_proxy_finish_failure(request); auth_request_handler_reply_failure_finish(request); break; } /* NOTE: request may be destroyed now */ auth_request_handler_unref(&handler); }
static bool postfix_input_user(struct auth_postfix_connection *conn, const char *username) { struct auth_request *auth_request; const char *error; io_remove(&conn->io); if (!postfix_input_auth_request(conn, username, &auth_request, &error)) { auth_request_log_info(auth_request, "postfix", "%s", error); user_callback(USERDB_RESULT_USER_UNKNOWN, auth_request); } else { auth_request_set_state(auth_request, AUTH_REQUEST_STATE_USERDB); auth_request_lookup_user(auth_request, user_callback); } return TRUE; }
static bool master_input_user(struct auth_master_connection *conn, const char *args) { struct auth_request *auth_request; const char *error; int ret; ret = master_input_auth_request(conn, args, "USER", &auth_request, &error); if (ret <= 0) { if (ret < 0) return FALSE; auth_request_log_info(auth_request, "userdb", "%s", error); user_callback(USERDB_RESULT_USER_UNKNOWN, auth_request); } else { auth_request_set_state(auth_request, AUTH_REQUEST_STATE_USERDB); auth_request_lookup_user(auth_request, user_callback); } return TRUE; }
static void userdb_callback(enum userdb_result result, struct auth_request *request) { struct auth_request_handler *handler = request->handler; string_t *str; const char *value; i_assert(request->state == AUTH_REQUEST_STATE_USERDB); auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED); if (request->userdb_lookup_tempfailed) result = USERDB_RESULT_INTERNAL_FAILURE; str = t_str_new(128); switch (result) { case USERDB_RESULT_INTERNAL_FAILURE: str_printfa(str, "FAIL\t%u", request->id); if (request->userdb_lookup_tempfailed) { value = auth_fields_find(request->userdb_reply, "reason"); if (value != NULL) auth_str_add_keyvalue(str, "reason", value); } break; case USERDB_RESULT_USER_UNKNOWN: str_printfa(str, "NOTFOUND\t%u", request->id); break; case USERDB_RESULT_OK: str_printfa(str, "USER\t%u\t", request->id); str_append_tabescaped(str, request->user); auth_str_append_userdb_extra_fields(request, str); break; } handler->master_callback(str_c(str), request->master); auth_master_connection_unref(&request->master); auth_request_unref(&request); auth_request_handler_unref(&handler); }
bool auth_request_handler_master_request(struct auth_request_handler *handler, struct auth_master_connection *master, unsigned int id, unsigned int client_id, const char *const *params) { struct auth_request *request; struct net_unix_cred cred; request = hash_table_lookup(handler->requests, POINTER_CAST(client_id)); if (request == NULL) { i_error("Master request %u.%u not found", handler->client_pid, client_id); return auth_master_request_failed(handler, master, id); } auth_request_ref(request); auth_request_handler_remove(handler, request); for (; *params != NULL; params++) { const char *name, *param = strchr(*params, '='); if (param == NULL) { name = *params; param = ""; } else { name = t_strdup_until(*params, param); param++; } (void)auth_request_import_master(request, name, param); } /* verify session pid if specified and possible */ if (request->session_pid != (pid_t)-1 && net_getunixcred(master->fd, &cred) == 0 && cred.pid != (pid_t)-1 && request->session_pid != cred.pid) { i_error("Session pid %ld provided by master for request %u.%u " "did not match peer credentials (pid=%ld, uid=%ld)", (long)request->session_pid, handler->client_pid, client_id, (long)cred.pid, (long)cred.uid); return auth_master_request_failed(handler, master, id); } if (request->state != AUTH_REQUEST_STATE_FINISHED || !request->successful) { i_error("Master requested unfinished authentication request " "%u.%u", handler->client_pid, client_id); handler->master_callback(t_strdup_printf("FAIL\t%u", id), master); auth_request_unref(&request); } else { /* the request isn't being referenced anywhere anymore, so we can do a bit of kludging.. replace the request's old client_id with master's id. */ auth_request_set_state(request, AUTH_REQUEST_STATE_USERDB); request->id = id; request->master = master; /* master and handler are referenced until userdb_callback i s called. */ auth_master_connection_ref(master); handler->refcount++; auth_request_lookup_user(request, userdb_callback); } return TRUE; }