From 226cef5597d5958102e454c2ab31b2c03b852503 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 2 Feb 2022 21:36:45 +0200 Subject: [PATCH 1/3] doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8cce1a4..817a3d4 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,8 @@ async function kerberizedFetch(url, kdcproxy, user, pwd) Browser note: if the kdcproxy and / or the authenticated application are hosted on a different host or port than the JavaScript application, then you'd have to enable CORS -on these servers, or the browser will likely reject the request. +on these servers, or the browser will likely reject the request. For details, see: +https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS ## Installation From 1f5db6f6138694d3e2dd731f9dda9279bc377596 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 2 Feb 2022 22:06:40 +0200 Subject: [PATCH 2/3] cleanup around sendto_kdc --- webgss.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/webgss.js b/webgss.js index c6bebd2..44098b5 100644 --- a/webgss.js +++ b/webgss.js @@ -189,17 +189,19 @@ async function sendto_kdc(obj, kproxy, req) { let init = { method: 'POST', body: req, - //cache: 'no-cache', - //redirect: 'error', headers: { 'Content-type': 'application/kerberos' } } - let request = new obj.req(kproxy, init); - let response = await obj.fetch(request); + + let response = await obj.fetch(kproxy, init); + if (response.status != 200) throw 'KdcProxy request failed'; - return response; + + let res_data = await response.arrayBuffer(); + + return new Uint8Array(res_data); } async function kdc_exchange(obj, kdcproxy, handle) @@ -212,11 +214,7 @@ async function kdc_exchange(obj, kdcproxy, handle) let rep = await sendto_kdc(obj, kdcproxy, req); - let rep_data = await rep.arrayBuffer(); - - rep_data = new Uint8Array(rep_data); - - reply = handle.step(rep_data); + reply = handle.step(rep); } if (reply.status != 'ok') From 5cc314d95d0bd5295ade03a8c1909db2276347e1 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Sat, 12 Feb 2022 02:34:23 +0200 Subject: [PATCH 3/3] wip: try switch to use asyncify with gssapi instead of low level krb5 api --- Makefile | 10 +- k5drv.cpp | 62 -------- k5drv.h | 6 - k5lib.cpp | 425 +++++++++++++------------------------------------ krb5 | 2 +- node_test.js | 13 +- upstream.patch | 115 +++++++++++++ webgss.js | 74 +++------ 8 files changed, 264 insertions(+), 443 deletions(-) diff --git a/Makefile b/Makefile index 39d58bf..688ea1d 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ DEBUG_OPTIONS = SANIT_OPTIONS = K5_CONF = --disable-rpath --disable-thread-support --disable-shared --enable-static -K5_LIBS = -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lapputils -lkrb5support +K5_LIBS = -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lkrb5support # -s STRICT=1 -s EXPORTED_FUNCTIONS=_getenv,_setenv -s EXPORTED_RUNTIME_METHODS=ccall,cwrap EM_ARGS = -s MODULARIZE=1 -s EXPORTED_RUNTIME_METHODS=FS @@ -54,7 +54,7 @@ k5lib.o: krb5/src/lib/libkrb5.a k5lib.cpp lib/k5lib.js: krb5/src/lib/libkrb5.a utils.o k5drv.o k5lib.o mkdir -p lib - $(CC) $(CFLAGS) --bind utils.o k5drv.o k5lib.o $(K5_LIBS) $(LIBS) $(LDFLAGS) $(WGLDFLAGS) -o lib/k5lib.js -s EXPORT_ES6=1 -s EXPORT_NAME=createEmModule -s ENVIRONMENT=web $(EM_ARGS) $(SANIT_OPTIONS) $(DEBUG_OPTIONS) + $(CC) $(CFLAGS) --bind utils.o k5drv.o k5lib.o $(K5_LIBS) $(LIBS) $(LDFLAGS) $(WGLDFLAGS) -o lib/k5lib.js -s EXPORT_ES6=1 -s EXPORT_NAME=createEmModule -s ENVIRONMENT=web $(EM_ARGS) $(SANIT_OPTIONS) $(DEBUG_OPTIONS) -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 lib/webgss.js: lib/k5lib.js cat webgss.js > lib/webgss.js @@ -63,7 +63,7 @@ lib/webgss.js: lib/k5lib.js # node isn't happy with EXPORT_ES6 so let it have its own build for now lib/k5lib_node.js: krb5/src/lib/libkrb5.a utils.o k5drv.o k5lib.o mkdir -p lib - $(CC) $(CFLAGS) --bind utils.o k5drv.o k5lib.o $(K5_LIBS) $(LIBS) $(LDFLAGS) $(WGLDFLAGS) -o lib/k5lib_node.js -s ENVIRONMENT=node $(EM_ARGS) $(SANIT_OPTIONS) $(DEBUG_OPTIONS) + $(CC) $(CFLAGS) --bind utils.o k5drv.o k5lib.o $(K5_LIBS) $(LIBS) $(LDFLAGS) $(WGLDFLAGS) -o lib/k5lib_node.js -s ENVIRONMENT=node $(EM_ARGS) $(SANIT_OPTIONS) $(DEBUG_OPTIONS) -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 lib/webgss_node.js: lib/k5lib_node.js cat webgss.js > lib/webgss_node.js @@ -78,5 +78,5 @@ check: all clean: rm -rf utils.o k5drv.o k5lib.o lib testdir_wgss - cd krb5/src && emmake $(MAKE) clean - rm -f emwrap.o lib_emwrap.a + # cd krb5/src && emmake $(MAKE) clean + # rm -f emwrap.o lib_emwrap.a diff --git a/k5drv.cpp b/k5drv.cpp index 2dd64d1..97c345b 100644 --- a/k5drv.cpp +++ b/k5drv.cpp @@ -79,65 +79,3 @@ encode_kkdcp_message(krb5_context ctx, vector &in_data, return 0; } -krb5_error_code -ccache_to_buffer(string &ccache, string &out_buffer) -{ - OM_uint32 maj, min; - OM_uint32 time_rec; // XXX - gss_cred_id_t creds = GSS_C_NO_CREDENTIAL; - gss_key_value_element_desc element = { "ccache", ccache.c_str() }; - gss_key_value_set_desc store = { 1, &element }; - gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; - - - maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE, - GSS_C_NO_OID_SET, GSS_C_INITIATE, &store, - &creds, NULL, &time_rec); - if (GSS_ERROR(maj)) { - log_gsserr("gss_acquire_cred_from()", maj, min); - return ENOMEM; - } - - maj = gss_export_cred(&min, creds, &buffer); - gss_release_cred(&min, &creds); - if (GSS_ERROR(maj)) { - log_gsserr("gss_export_cred()", maj, min); - return ENOMEM; - } - - out_buffer = string((const char *) buffer.value, buffer.length); - gss_release_buffer(&min, &buffer); - - return 0; -} - -krb5_error_code -buffer_to_ccache(string &in_buffer, string &ccache) -{ - OM_uint32 maj, min; - gss_cred_id_t creds = GSS_C_NO_CREDENTIAL; - gss_key_value_element_desc store_elm = { "ccache", ccache.c_str() }; - gss_key_value_set_desc store = { 1, &store_elm }; - gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; - vector data; - - data.assign(in_buffer.begin(), in_buffer.end()); - buffer.value = (void *) data.data(); - buffer.length = data.size(); - - maj = gss_import_cred(&min, &buffer, &creds); - if (GSS_ERROR(maj)) { - log_gsserr("gss_import_cred()", maj, min); - return ENOMEM; - } - - maj = gss_store_cred_into(&min, creds, GSS_C_INITIATE, GSS_C_NO_OID, - 1, 1, &store, NULL, NULL); - gss_release_cred(&min, &creds); - if (GSS_ERROR(maj)) { - log_gsserr("gss_store_cred_into()", maj, min); - return ENOMEM; - } - - return 0; -} diff --git a/k5drv.h b/k5drv.h index 836d91b..f3398d5 100644 --- a/k5drv.h +++ b/k5drv.h @@ -52,12 +52,6 @@ krb5_error_code encode_kkdcp_message(krb5_context ctx, std::vector &in_data, std::vector &realm, std::string &out_data); -krb5_error_code -ccache_to_buffer(std::string &ccache, std::string &out_buffer); - -krb5_error_code -buffer_to_ccache(std::string &in_buffer, std::string &ccache); - } // extern "C" #endif // K5DRV_H_INCLUDED diff --git a/k5lib.cpp b/k5lib.cpp index d2cb693..76375e3 100644 --- a/k5lib.cpp +++ b/k5lib.cpp @@ -12,311 +12,11 @@ using namespace std; +krb5_context kctx = NULL; -struct k5libHandle -{ - virtual emscripten::val step(string msg) = 0; - - virtual ~k5libHandle() {} -}; - -struct kdcExchangeHandle : k5libHandle -{ - krb5_context kctx; - krb5_ccache ccache; - - kdcExchangeHandle(krb5_context ctx) : - kctx(ctx), ccache(NULL) {} - - virtual krb5_error_code libStep(krb5_data &reply, - krb5_data &request, - krb5_data &realm) = 0; - - emscripten::val step(string msg) { - krb5_error_code ret; - vector rep, req, rlm; - krb5_data reply = {}, request = {}, realm = {}; - emscripten::val obj = emscripten::val::object(); - - obj.set("status", "error"); - - ret = decode_kkdcp_message(kctx, msg, rep); - if (ret) { - log_k5err(kctx, "decode_kkdcp_message", ret); - return obj; - } - - reply.data = (char *) rep.data(); - reply.length = rep.size(); - - ret = libStep(reply, request, realm); - if (ret) { - log_k5err(kctx, "libStep", ret); - return obj; - } - - if (request.length == 0) { - const char *ccname = krb5_cc_get_name(kctx, ccache); - - if (ccname == NULL || *ccname == NULL) { - cerr << "failed to get ccache name" << endl; - return obj; - } - - string ccache_str = string("MEMORY:") + ccname; - - ret = ccache_to_buffer(ccache_str, msg); - krb5_cc_destroy(kctx, ccache); - ccache = NULL; - if (ret) { - log_k5err(kctx, "ccache_to_buffer", ret); - return obj; - } - - obj.set("status", "ok"); - obj.set("creds", emscripten::val::array(msg.begin(), msg.end())); - - return obj; - } - - req.assign(request.data, request.data + request.length); - rlm.assign(realm.data, realm.data + realm.length); - - krb5_free_data_contents(kctx, &request); - krb5_free_data_contents(kctx, &realm); - - ret = encode_kkdcp_message(kctx, req, rlm, msg); - if (ret) { - log_k5err(kctx, "encode_kkdcp_message", ret); - return obj; - } - - obj.set("status", "continue"); - obj.set("token", emscripten::val::array(msg.begin(), msg.end())); - - return obj; - } - - virtual ~kdcExchangeHandle() { - if (ccache != NULL) - krb5_cc_destroy(kctx, ccache); - krb5_free_context(kctx); - } -}; - -struct initCredsHandle : kdcExchangeHandle -{ - krb5_init_creds_context icc; - krb5_get_init_creds_opt *gic_opts; - - initCredsHandle(krb5_context ctx) : - kdcExchangeHandle(ctx), icc(NULL), gic_opts(NULL) {} - - krb5_error_code libStep(krb5_data &reply, - krb5_data &request, - krb5_data &realm) { - krb5_error_code ret; - unsigned int flags = 0; - - ret = krb5_init_creds_step(kctx, icc, &reply, &request, &realm, &flags); - if (ret) { - log_k5err(kctx, "krb5_init_creds_step", ret); - return ret; - } - - if ((flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0) - assert(request.length == 0 && realm.length == 0); - else - assert(request.length != 0 && realm.length != 0); - - return 0; - } - - ~initCredsHandle() { - krb5_init_creds_free(kctx, icc); - krb5_get_init_creds_opt_free(kctx, gic_opts); - } -}; - -k5libHandle* initCreds(string princ, string pwd) -{ - krb5_error_code ret; - krb5_context kctx; - krb5_principal p; - - ret = krb5_init_context(&kctx); - if (ret) { - fprintf(stderr, "initCreds: krb5_init_context() failed\n"); - return NULL; - } - - initCredsHandle *ctx = new initCredsHandle(kctx); - - ret = krb5_get_init_creds_opt_alloc(ctx->kctx, &ctx->gic_opts); - if (ret) { - log_k5err(ctx->kctx, "krb5_get_init_creds_opt_alloc", ret); - delete ctx; - return NULL; - } - - ret = krb5_cc_new_unique(ctx->kctx, "MEMORY", NULL, &ctx->ccache); - if (ret) { - log_k5err(ctx->kctx, "krb5_cc_new_unique", ret); - delete ctx; - return NULL; - } - - ret = krb5_parse_name(ctx->kctx, princ.c_str(), &p); - if (ret) { - log_k5err(ctx->kctx, "krb5_parse_name", ret); - delete ctx; - return NULL; - } - - ret = krb5_cc_initialize(ctx->kctx, ctx->ccache, p); - if (ret) { - log_k5err(ctx->kctx, "krb5_cc_initialize", ret); - krb5_free_principal(ctx->kctx, p); - delete ctx; - return NULL; - } - - ret = krb5_get_init_creds_opt_set_in_ccache(ctx->kctx, ctx->gic_opts, ctx->ccache); - if (ret) { - log_k5err(ctx->kctx, "krb5_get_init_creds_opt_set_in_ccache", ret); - krb5_free_principal(ctx->kctx, p); - delete ctx; - return NULL; - } - - ret = krb5_get_init_creds_opt_set_out_ccache(ctx->kctx, ctx->gic_opts, ctx->ccache); - if (ret) { - log_k5err(ctx->kctx, "krb5_get_init_creds_opt_set_out_ccache", ret); - krb5_free_principal(ctx->kctx, p); - delete ctx; - return NULL; - } - - ret = krb5_init_creds_init(ctx->kctx, p, NULL, NULL, 0, ctx->gic_opts, &ctx->icc); - krb5_free_principal(ctx->kctx, p); - if (ret) { - log_k5err(ctx->kctx, "krb5_init_creds_init", ret); - delete ctx; - return NULL; - } - - ret = krb5_init_creds_set_password(ctx->kctx, ctx->icc, pwd.c_str()); - if (ret) { - log_k5err(ctx->kctx, "krb5_init_creds_set_password", ret); - delete ctx; - return NULL; - } - - return ctx; -} +extern krb5_pre_send_fn em_send_to_realm_hook; -struct tktCredsHandle : kdcExchangeHandle -{ - krb5_tkt_creds_context tcc; - - tktCredsHandle(krb5_context ctx) : - kdcExchangeHandle(ctx), tcc(NULL) {} - - krb5_error_code libStep(krb5_data &reply, - krb5_data &request, - krb5_data &realm) { - krb5_error_code ret; - unsigned int flags = 0; - - ret = krb5_tkt_creds_step(kctx, tcc, &reply, &request, &realm, &flags); - if (ret) { - log_k5err(kctx, "krb5_init_creds_step", ret); - return ret; - } - - if ((flags & KRB5_TKT_CREDS_STEP_FLAG_CONTINUE) == 0) - assert(request.length == 0 && realm.length == 0); - else - assert(request.length != 0 && realm.length != 0); - - return 0; - } - - ~tktCredsHandle() { - krb5_tkt_creds_free(kctx, tcc); - } -}; - -k5libHandle* tktCreds(string gssCreds, string server) -{ - krb5_error_code ret; - krb5_context kctx; - krb5_creds creds = {}; - krb5_principal p, p2; - - ret = krb5_init_context(&kctx); - if (ret) { - fprintf(stderr, "initCreds: krb5_init_context() failed\n"); - return NULL; - } - - tktCredsHandle *ctx = new tktCredsHandle(kctx); - - ret = krb5_cc_new_unique(kctx, "MEMORY", NULL, &ctx->ccache); - if (ret) { - log_k5err(ctx->kctx, "krb5_cc_new_unique", ret); - delete ctx; - return NULL; - } - - const char *ccname = krb5_cc_get_name(kctx, ctx->ccache); - - if (ccname == NULL || *ccname == NULL) { - cerr << "failed to get ccache name" << endl; - delete ctx; - return NULL; - } - - string ccache_str = string("MEMORY:") + ccname; - - ret = buffer_to_ccache(gssCreds, ccache_str); - if (ret) { - fprintf(stderr, "initCreds: buffer_to_ccache() failed\n"); - delete ctx; - return NULL; - } - - ret = krb5_parse_name(ctx->kctx, server.c_str(), &p); - if (ret) { - log_k5err(ctx->kctx, "krb5_parse_name", ret); - delete ctx; - return NULL; - } - - ret = krb5_cc_get_principal(ctx->kctx, ctx->ccache, &p2); - if (ret) { - log_k5err(ctx->kctx, "krb5_cc_get_principal", ret); - krb5_free_principal(ctx->kctx, p); - delete ctx; - return NULL; - } - - creds.client = p2; - creds.server = p; - - ret = krb5_tkt_creds_init(ctx->kctx, ctx->ccache, &creds, 0, &ctx->tcc); - krb5_free_principal(ctx->kctx, p); - krb5_free_principal(ctx->kctx, p2); - if (ret) { - log_k5err(ctx->kctx, "krb5_tkt_creds_init", ret); - delete ctx; - return NULL; - } - - return ctx; -} - -struct gssCredsHandle : k5libHandle +struct gssCredsHandle { gss_cred_id_t gss_creds; gss_name_t target_name; @@ -379,7 +79,7 @@ struct gssCredsHandle : k5libHandle } }; -k5libHandle* gssCreds(string in_creds, string target) +gssCredsHandle* gssCreds(string in_creds, string target) { OM_uint32 minor, major; gss_name_t target_name; @@ -415,27 +115,128 @@ k5libHandle* gssCreds(string in_creds, string target) return ctx; } -static void set_krb5_trace(bool val) { - setenv("KRB5_TRACE", val ? "/dev/stderr" : "/dev/null", 1); +static void set_krb5_trace(bool enable) { + setenv("KRB5_TRACE", enable ? "/dev/stderr" : "/dev/null", 1); } static void leak_check() { -#if defined(__has_feature) -#if __has_feature(address_sanitizer) +#if defined(__has_feature) && __has_feature(address_sanitizer) __lsan_do_leak_check(); #endif -#endif +} + +static emscripten::val gssError(const char *func, OM_uint32 major, OM_uint32 minor) +{ + emscripten::val obj = emscripten::val::object(); + + obj.set("error", func); + + return obj; +} + +static krb5_error_code +em_fetch_send_hook(krb5_context context, void *data, const krb5_data *realm, + const krb5_data *message, krb5_data **new_message_out, + krb5_data **reply_out) +{ + vector msg, rlm, rep; + emscripten::val obj = emscripten::val::module_property("wgssEnv"); + krb5_data rep_data; + + msg.assign(message->data, message->data + message->length); + rlm.assign(realm->data, realm->data + realm->length); + + string encoded; + krb5_error_code ret = encode_kkdcp_message(kctx, msg, rlm, encoded); + if (ret) { + log_k5err(kctx, "encode_kkdcp_message", ret); + return ret; + } + + emscripten::val msgArray = emscripten::val::array(encoded.begin(), encoded.end()); + + emscripten::val retProm = obj.call("sendToRealm", obj, msgArray); + + emscripten::val retData = retProm.await(); + + rep = emscripten::vecFromJSArray(retData); + if (rep.empty()) { + fprintf(stderr, "sendToRealm failed in JS\n"); + return KRB5_KDC_UNREACH; + } + + ret = decode_kkdcp_message(kctx, string(rep.begin(), rep.end()), rep); + if (ret) { + log_k5err(kctx, "decode_kkdcp_message", ret); + return ret; + } + + rep_data.data = (char *) rep.data(); + rep_data.length = rep.size(); + + ret = krb5_copy_data(kctx, &rep_data, reply_out); + if (ret) { + log_k5err(kctx, "krb5_copy_data", ret); + return ret; + } + + fprintf(stderr, "IN_KDC_SEND_HOOK: OK\n"); + + return 0; +} + +static emscripten::val acquireCreds(string username, string pwd) +{ + OM_uint32 major, minor; + gss_name_t name; + gss_buffer_desc buffer; + gss_cred_id_t creds; + vector data; + gss_OID_set_desc mechlist; + + em_send_to_realm_hook = em_fetch_send_hook; + + mechlist.count = 1; + mechlist.elements = &mech_spnego; + + data.assign(username.begin(), username.end()); + buffer.value = data.data(); + buffer.length = data.size(); + + major = gss_import_name(&minor, &buffer, GSS_C_NT_USER_NAME, &name); + if (GSS_ERROR(major)) + return gssError("gss_import_name", major, minor); + + data.assign(pwd.begin(), pwd.end()); + buffer.value = data.data(); + buffer.length = data.size(); + + major = gss_acquire_cred_with_password(&minor, name, &buffer, + GSS_C_INDEFINITE, &mechlist, + GSS_C_INITIATE, &creds, NULL, NULL); + gss_release_name(&minor, &name); + if (GSS_ERROR(major)) + return gssError("gss_acquire_cred_with_password", major, minor); + + major = gss_export_cred(&minor, creds, &buffer); + gss_release_cred(&minor, &creds); + if (GSS_ERROR(major)) + return gssError("gss_export_cred", major, minor); + + data.assign((char*)buffer.value, (char*)buffer.value + buffer.length); + gss_release_buffer(&minor, &buffer); + + return emscripten::val::array(data.begin(), data.end()); } using namespace emscripten; EMSCRIPTEN_BINDINGS(k5lib_driver) { - class_("k5libHandle").function("step", &k5libHandle::step); - emscripten::function("initCreds", &initCreds, allow_raw_pointers()); - emscripten::function("tktCreds", &tktCreds, allow_raw_pointers()); + class_("gssCredsHandle").function("step", &gssCredsHandle::step); emscripten::function("gssCreds", &gssCreds, allow_raw_pointers()); emscripten::function("setKrb5Trace", &set_krb5_trace); emscripten::function("doLeakCheck", &leak_check); + emscripten::function("acquireCreds", &acquireCreds); } diff --git a/krb5 b/krb5 index 4b47981..1465dbd 160000 --- a/krb5 +++ b/krb5 @@ -1 +1 @@ -Subproject commit 4b479814747b69ec386d0e092f71678e6e193a75 +Subproject commit 1465dbd8fc88cf31af3579f09a3148da3b9e1c3e diff --git a/node_test.js b/node_test.js index 3a5ad17..f839e69 100644 --- a/node_test.js +++ b/node_test.js @@ -6,16 +6,22 @@ async function getAuthResource(user, pwd, realm, server) let webgss = require('.'); // Debug - webgss.setKrb5Trace(true); - webgss.leakCheck(); webgss.setDefaultRealm(realm); webgss.leakCheck(); + webgss.setKrb5Trace(true); + webgss.leakCheck(); + let client = await webgss.gssClient(server + '/KdcProxy', user, pwd); webgss.leakCheck(); let reply = await client.fetch(server + '/hello'); + + // TODO: doesn't work with asyncify + //let reply2 = client.fetch(server + '/hello'); + //let reply3 = client.fetch(server + '/hello'); + webgss.leakCheck(); let data = await reply.text(); @@ -27,7 +33,10 @@ async function getAuthResource(user, pwd, realm, server) let user = process.env.KUSER; let pwd = process.env.KUPWD; let realm = process.env.KRB5REALM; +user = user +'@'+realm let srv = 'http://' + process.env.HOSTNAME + ':' + process.env.HTTPDPORT; getAuthResource(user, pwd, realm, srv).then(data => console.log( data )); +// TODO: add parallel and failed tests + diff --git a/upstream.patch b/upstream.patch index 5ad15d9..96a2667 100644 --- a/upstream.patch +++ b/upstream.patch @@ -47,3 +47,118 @@ index 8f14e9bf2..31272f45e 100644 -- 2.31.1 +From 518af6af6773b11b2e40351fda564564d93fccf7 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Tue, 8 Feb 2022 00:11:00 +0200 +Subject: [PATCH 1/2] Try kdc_send_hook() before locating the KDC server + +--- + src/lib/krb5/os/sendto_kdc.c | 36 ++++++++++++++++++------------------ + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c +index 8620ffa45..dc29619db 100644 +--- a/src/lib/krb5/os/sendto_kdc.c ++++ b/src/lib/krb5/os/sendto_kdc.c +@@ -440,7 +440,7 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + int no_udp) + { + krb5_error_code retval, oldret, err; +- struct serverlist servers; ++ struct serverlist servers = {}; + int server_used; + k5_transport_strategy strategy; + krb5_data reply = empty_data(), *hook_message = NULL, *hook_reply = NULL; +@@ -462,6 +462,23 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + + TRACE_SENDTO_KDC(context, message->length, realm, *use_primary, no_udp); + ++ if (context->kdc_send_hook != NULL) { ++ retval = context->kdc_send_hook(context, context->kdc_send_hook_data, ++ realm, message, &hook_message, ++ &hook_reply); ++ if (retval) ++ goto cleanup; ++ ++ if (hook_reply != NULL) { ++ *reply_out = *hook_reply; ++ free(hook_reply); ++ goto cleanup; ++ } ++ ++ if (hook_message != NULL) ++ message = hook_message; ++ } ++ + if (!no_udp && context->udp_pref_limit < 0) { + int tmp; + retval = profile_get_integer(context->profile, +@@ -490,23 +507,6 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message, + if (retval) + return retval; + +- if (context->kdc_send_hook != NULL) { +- retval = context->kdc_send_hook(context, context->kdc_send_hook_data, +- realm, message, &hook_message, +- &hook_reply); +- if (retval) +- goto cleanup; +- +- if (hook_reply != NULL) { +- *reply_out = *hook_reply; +- free(hook_reply); +- goto cleanup; +- } +- +- if (hook_message != NULL) +- message = hook_message; +- } +- + err = 0; + retval = k5_sendto(context, message, realm, &servers, strategy, NULL, + &reply, NULL, NULL, &server_used, +-- +2.34.1 + + +From 277163bd27d662cf93b2906a23cce1884752fd29 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +Date: Mon, 7 Feb 2022 21:18:45 +0200 +Subject: [PATCH 2/2] em_fetch + +--- + src/lib/krb5/krb/init_ctx.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c +index 87b486c53..8fe1b23e4 100644 +--- a/src/lib/krb5/krb/init_ctx.c ++++ b/src/lib/krb5/krb/init_ctx.c +@@ -151,6 +151,12 @@ krb5int_init_context_kdc(krb5_context *context) + return krb5_init_context_profile(NULL, KRB5_INIT_CONTEXT_KDC, context); + } + ++#ifdef __EMSCRIPTEN__ ++ ++krb5_pre_send_fn em_send_to_realm_hook = NULL; ++ ++#endif ++ + krb5_error_code KRB5_CALLCONV + krb5_init_context_profile(profile_t profile, krb5_flags flags, + krb5_context *context_out) +@@ -277,6 +283,11 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags, + /* It's OK if this fails */ + (void)profile_get_string(ctx->profile, KRB5_CONF_LIBDEFAULTS, + KRB5_CONF_ERR_FMT, NULL, NULL, &ctx->err_fmt); ++ ++#ifdef __EMSCRIPTEN__ ++ krb5_set_kdc_send_hook(ctx, em_send_to_realm_hook, NULL); ++#endif ++ + *context_out = ctx; + ctx = NULL; + +-- +2.34.1 + diff --git a/webgss.js b/webgss.js index 44098b5..f86cb0f 100644 --- a/webgss.js +++ b/webgss.js @@ -11,24 +11,6 @@ class gssClient this.creds = initCreds; } - async #prepSecContext(target) - { - let tktHandle = this.i.module.tktCreds(this.creds, target); - let tktCreds; - - if (!tktHandle) - throw 'null tktHandle'; - - try { - tktCreds = await kdc_exchange(this.i, this.kdcp, tktHandle); - } finally { - tktHandle.delete(); - } - - /* XXX: this can rece and cause cache misses. */ - this.creds = tktCreds; - } - /* Fetch a resource protected with HTTP Negotiate authentication (SPNEGO). */ async fetch(resource, init = {}) { @@ -42,14 +24,12 @@ class gssClient let target = 'HTTP/' + hostname + '@'; - await this.#prepSecContext(target); - let gssHandle = this.i.module.gssCreds(this.creds, target); if (!gssHandle) throw 'null gssHandle'; try { - let gssReply = gssHandle.step(''); + let gssReply = await gssHandle.step(''); while (gssReply.status == 'continue') { @@ -70,7 +50,7 @@ class gssClient auth = auth.slice(prefix.length); auth = base64DecToArr(auth); - gssReply = gssHandle.step(auth); + gssReply = await gssHandle.step(auth); if (response.status != 401) break; @@ -102,6 +82,18 @@ function setKrb5Conf(module, default_realm=null) module.FS.writeFile('/etc/krb5.conf', conf); } +async function sendToRealm(obj, req) { + let data = new Uint8Array(req); + let reply; + try { + reply = await sendto_kdc(obj, obj.kdcproxy, data); + } catch (error) { + console.log(error); + reply = new Uint8Array(0); + } + return reply; +} + class webgss { static #instance = null; @@ -133,6 +125,8 @@ class webgss module.FS.mkdir('/etc'); setKrb5Conf(module); this.#instance = { module, fetch, req }; + module.wgssEnv = this.#instance; + module.wgssEnv.sendToRealm = sendToRealm; } // XXX @@ -160,7 +154,6 @@ class webgss { this.#getInstance().then(i => { i.module.setKrb5Trace(enable); - i.module.logReadFiles = true; // XXX }); } @@ -168,18 +161,9 @@ class webgss static async gssClient(kdcproxy, user, pwd) { let i = await this.#getInstance(); - let initHandle = i.module.initCreds(user, pwd); - let initCreds; - - if (!initHandle) - throw 'null initHandle'; - - try { - initCreds = await kdc_exchange(i, kdcproxy, initHandle); - } finally { - initHandle.delete(); - } - + i.module.wgssEnv.kdcproxy = kdcproxy; + let initCreds = await i.module.acquireCreds(user, pwd); + initCreds = new Uint8Array(initCreds); return new gssClient(i, kdcproxy, initCreds); } } @@ -204,26 +188,6 @@ async function sendto_kdc(obj, kproxy, req) { return new Uint8Array(res_data); } -async function kdc_exchange(obj, kdcproxy, handle) -{ - let reply = handle.step(''); - - while (reply.status == 'continue') { - - let req = new Uint8Array(reply.token); - - let rep = await sendto_kdc(obj, kdcproxy, req); - - reply = handle.step(rep); - } - - if (reply.status != 'ok') - throw 'exchange failed'; - - return new Uint8Array(reply.creds); -} - - /*\ |*|