#include <gsscon.h>
#include <tr_gss.h>
+/**
+ * tr_gss.c - GSS connection handler
+ *
+ * The chief entry point to this module is tr_gss_handle_connection(). This
+ * function accepts an incoming socket connection, runs the GSS authorization
+ * and authentication process, accepts a request, processes it, then sends
+ * the reply and returns without closing the connection.
+ *
+ * Callers need to provide two callbacks, each with a cookie for passing
+ * custom data to the callback.
+ *
+ * * TR_GSS_AUTH_FN auth_cb: Authorization callback
+ * - This callback is used during the GSS auth process to determine whether
+ * a credential should be authorized to connect.
+ *
+ * * TR_GSS_HANDLE_REQ_FN req_cb: Request handler callback
+ * - After auth, this callback is passed the string form of the incoming request.
+ * It should process the request and return a string form of the outgoing
+ * response, if any.
+ */
+
+typedef struct tr_gss_cookie {
+ TR_GSS_AUTH_FN *auth_cb;
+ void *auth_cookie;
+} TR_GSS_COOKIE;
+
+static int tr_gss_auth_cb(gss_name_t clientName, gss_buffer_t displayName, void *data)
+{
+ TR_GSS_COOKIE *cookie = talloc_get_type_abort(data, TR_GSS_COOKIE);
+ TR_NAME name ={(char *) displayName->value, (int) displayName->length};
+ int result=0;
+
+ if (cookie->auth_cb(clientName, &name, cookie->auth_cookie)) {
+ tr_debug("tr_gss_auth_cb: client '%.*s' denied authorization.", name.len, name.buf);
+ result=EACCES; /* denied */
+ }
+
+ return result;
+}
+
/**
- * Callback to handle GSS authentication and authorization
+ * Handle GSS authentication and authorization
*
* @param conn connection file descriptor
* @param acceptor_name name of acceptor to present to initiator
int rc = 0;
int auth, autherr = 0;
gss_buffer_desc nameBuffer = {0, NULL};
+ TR_GSS_COOKIE *cookie = NULL;
nameBuffer.value = talloc_asprintf(NULL, "%s@%s", acceptor_name, acceptor_realm);
if (nameBuffer.value == NULL) {
}
nameBuffer.length = strlen(nameBuffer.value);
- rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, auth_cb, auth_cookie);
+ /* Set up for the auth callback. There are two layers of callbacks here: we
+ * use our own, which handles gsscon interfacing and calls the auth_cb parameter
+ * to do the actual auth. Store the auth_cb information in a metacookie. */
+ cookie = talloc(NULL, TR_GSS_COOKIE);
+ cookie->auth_cb=auth_cb;
+ cookie->auth_cookie=auth_cookie;
+
+ /* Now call gsscon with *our* auth callback and cookie */
+ rc = gsscon_passive_authenticate(conn, nameBuffer, gssctx, tr_gss_auth_cb, cookie);
+ talloc_free(cookie);
talloc_free(nameBuffer.value);
if (rc) {
tr_debug("tr_gss_auth_connection: Error from gsscon_passive_authenticate(), rc = %d.", rc);
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
gss_ctx_id_t gssctx = GSS_C_NO_CONTEXT;
char *req_str = NULL;
+ size_t req_len = 0;
+ TR_MSG *req_msg = NULL;
+ TR_MSG *resp_msg = NULL;
char *resp_str = NULL;
if (tr_gss_auth_connection(conn,
tr_debug("tr_gss_handle_connection: Connection authorized");
// TODO: should there be a timeout on this?
- while (1) { /* continue until an error breaks us out */
+ do {
+ /* continue until an error breaks us out */
// try to read a request
req_str = tr_gss_read_req(tmp_ctx, conn, gssctx);
- if ( req_str == NULL) {
+ if (req_str == NULL) {
// an error occurred, give up
tr_notice("tr_gss_handle_connection: Error reading request");
goto cleanup;
- } else if (strlen(req_str) > 0) {
- // we got a request message, exit the loop and process it
- break;
}
- // no error, but no message, keep waiting for one
- talloc_free(req_str); // this would be cleaned up anyway, but may as well free it
+ req_len = strlen(req_str);
+
+ /* If we got no characters, we will loop again. Free the empty response for the next loop. */
+ if (req_len == 0)
+ talloc_free(req_str);
+
+ } while (req_len == 0);
+
+ /* Decode the request */
+ req_msg = tr_msg_decode(tmp_ctx, req_str, req_len);
+ if (req_msg == NULL) {
+ tr_notice("tr_gss_handle_connection: Error decoding response");
+ goto cleanup;
}
/* Hand off the request for processing and get the response */
- resp_str = req_cb(tmp_ctx, req_str, req_cookie);
+ resp_msg = req_cb(tmp_ctx, req_msg, req_cookie);
- if (resp_str == NULL) {
+ if (resp_msg == NULL) {
// no response, clean up
goto cleanup;
}
+ /* Encode the response */
+ resp_str = tr_msg_encode(tmp_ctx, resp_msg);
+ if (resp_str == NULL) {
+ /* We apparently can't encode a response, so just return */
+ tr_err("tr_gss_handle_connection: Error encoding response");
+ goto cleanup;
+ }
+
// send the response
if (tr_gss_write_resp(conn, gssctx, resp_str)) {
- tr_notice("tr_gss_handle_connection: Error writing response");
+ tr_err("tr_gss_handle_connection: Error writing response");
+ goto cleanup;
}
cleanup: