From a32f3a05b845def7ad5e32aaf380d0aa2ae6d3fe Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 22 Sep 2021 12:11:13 +0200 Subject: [PATCH 1/3] chore: address TODO for managing state through smart pointers Address the TODOs asking for the state to be managed through smart pointers and as a proper class with destructors. This is helpful for the upcoming Node-API conversion, because the presence of C++ exceptions in Node-API (and the fact that Node-API support also comes with multithreading support) makes it important to use proper C++ RAII style in order to avoid memory leaks. --- src/kerberos.cc | 14 +++--- src/kerberos.h | 18 ++++---- src/unix/kerberos_gss.cc | 87 ++++++++++--------------------------- src/unix/kerberos_gss.h | 37 +++++++++------- src/unix/kerberos_unix.cc | 63 ++++++++------------------- src/win32/kerberos_sspi.cc | 35 +++------------ src/win32/kerberos_sspi.h | 34 +++++++++------ src/win32/kerberos_win32.cc | 46 +++++--------------- 8 files changed, 117 insertions(+), 217 deletions(-) diff --git a/src/kerberos.cc b/src/kerberos.cc index f68c761a..1a845eea 100644 --- a/src/kerberos.cc +++ b/src/kerberos.cc @@ -26,7 +26,7 @@ NAN_MODULE_INIT(KerberosClient::Init) { Nan::GetFunction(tpl).ToLocalChecked()); } -v8::Local KerberosClient::NewInstance(krb_client_state* state) { +v8::Local KerberosClient::NewInstance(std::shared_ptr state) { Nan::EscapableHandleScope scope; v8::Local ctor = Nan::New(KerberosClient::constructor); v8::Local object = Nan::NewInstance(ctor).ToLocalChecked(); @@ -35,9 +35,10 @@ v8::Local KerberosClient::NewInstance(krb_client_state* state) { return scope.Escape(object); } -KerberosClient::KerberosClient(krb_client_state* state) : _state(state) {} +KerberosClient::KerberosClient(std::shared_ptr state) + : _state(state) {} -krb_client_state* KerberosClient::state() const { +std::shared_ptr KerberosClient::state() const { return _state; } @@ -88,7 +89,7 @@ NAN_MODULE_INIT(KerberosServer::Init) { Nan::GetFunction(tpl).ToLocalChecked()); } -v8::Local KerberosServer::NewInstance(krb_server_state* state) { +v8::Local KerberosServer::NewInstance(std::shared_ptr state) { Nan::EscapableHandleScope scope; v8::Local ctor = Nan::New(KerberosServer::constructor); v8::Local object = Nan::NewInstance(ctor).ToLocalChecked(); @@ -97,9 +98,10 @@ v8::Local KerberosServer::NewInstance(krb_server_state* state) { return scope.Escape(object); } -KerberosServer::KerberosServer(krb_server_state* state) : _state(state) {} +KerberosServer::KerberosServer(std::shared_ptr state) + : _state(state) {} -krb_server_state* KerberosServer::state() const { +std::shared_ptr KerberosServer::state() const { return _state; } diff --git a/src/kerberos.h b/src/kerberos.h index d73eb3fa..c0510dfd 100644 --- a/src/kerberos.h +++ b/src/kerberos.h @@ -7,9 +7,9 @@ class KerberosServer : public Nan::ObjectWrap { public: static NAN_MODULE_INIT(Init); - static v8::Local NewInstance(krb_server_state* state); + static v8::Local NewInstance(std::shared_ptr state); - krb_server_state* state() const; + std::shared_ptr state() const; private: static Nan::Persistent constructor; @@ -22,18 +22,17 @@ class KerberosServer : public Nan::ObjectWrap { static NAN_METHOD(Step); private: - explicit KerberosServer(krb_server_state* server_state); - ~KerberosServer(); + explicit KerberosServer(std::shared_ptr server_state); - krb_server_state* _state; + std::shared_ptr _state; }; class KerberosClient : public Nan::ObjectWrap { public: static NAN_MODULE_INIT(Init); - static v8::Local NewInstance(krb_client_state* state); + static v8::Local NewInstance(std::shared_ptr state); - krb_client_state* state() const; + std::shared_ptr state() const; private: static Nan::Persistent constructor; @@ -48,10 +47,9 @@ class KerberosClient : public Nan::ObjectWrap { static NAN_METHOD(WrapData); private: - explicit KerberosClient(krb_client_state* client_state); - ~KerberosClient(); + explicit KerberosClient(std::shared_ptr client_state); - krb_client_state* _state; + std::shared_ptr _state; }; NAN_METHOD(PrincipalDetails); diff --git a/src/unix/kerberos_gss.cc b/src/unix/kerberos_gss.cc index e0d36fb9..4b2e93bb 100644 --- a/src/unix/kerberos_gss.cc +++ b/src/unix/kerberos_gss.cc @@ -33,26 +33,6 @@ static gss_result gss_error_result(OM_uint32 err_maj, OM_uint32 err_min); static gss_result gss_error_result_with_message(const char* message); static gss_result gss_error_result_with_message_and_code(const char* mesage, int code); -gss_client_state* gss_client_state_new() { - gss_client_state* state = (gss_client_state*)malloc(sizeof(gss_client_state)); - state->username = NULL; - state->response = NULL; - state->responseConf = 0; - state->context_complete = false; - - return state; -} - -gss_server_state* gss_server_state_new() { - gss_server_state* state = (gss_server_state*)malloc(sizeof(gss_server_state)); - state->username = NULL; - state->response = NULL; - state->targetname = NULL; - state->context_complete = false; - - return state; -} - gss_result server_principal_details(const char* service, const char* hostname) { char match[1024]; size_t match_len = 0; @@ -195,26 +175,17 @@ gss_result authenticate_gss_client_init(const char* service, return ret; } -int authenticate_gss_client_clean(gss_client_state* state) { +gss_client_state::~gss_client_state() { OM_uint32 min_stat; - int ret = AUTH_GSS_COMPLETE; - - if (state->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); - if (state->server_name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &state->server_name); - if (state->client_creds != GSS_C_NO_CREDENTIAL && !(state->gss_flags & GSS_C_DELEG_FLAG)) - gss_release_cred(&min_stat, &state->client_creds); - if (state->username != NULL) { - free(state->username); - state->username = NULL; - } - if (state->response != NULL) { - free(state->response); - state->response = NULL; - } - return ret; + if (context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + if (server_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &server_name); + if (client_creds != GSS_C_NO_CREDENTIAL && !(gss_flags & GSS_C_DELEG_FLAG)) + gss_release_cred(&min_stat, &client_creds); + free(username); + free(response); } gss_result authenticate_gss_client_step(gss_client_state* state, @@ -507,34 +478,22 @@ gss_result authenticate_gss_server_init(const char* service, gss_server_state* s return ret; } -int authenticate_gss_server_clean(gss_server_state* state) { +gss_server_state::~gss_server_state() { OM_uint32 min_stat; - int ret = AUTH_GSS_COMPLETE; - - if (state->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&min_stat, &state->context, GSS_C_NO_BUFFER); - if (state->server_name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &state->server_name); - if (state->client_name != GSS_C_NO_NAME) - gss_release_name(&min_stat, &state->client_name); - if (state->server_creds != GSS_C_NO_CREDENTIAL) - gss_release_cred(&min_stat, &state->server_creds); - if (state->client_creds != GSS_C_NO_CREDENTIAL) - gss_release_cred(&min_stat, &state->client_creds); - if (state->username != NULL) { - free(state->username); - state->username = NULL; - } - if (state->targetname != NULL) { - free(state->targetname); - state->targetname = NULL; - } - if (state->response != NULL) { - free(state->response); - state->response = NULL; - } - return ret; + if (context != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER); + if (server_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &server_name); + if (client_name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &client_name); + if (server_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &server_creds); + if (client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &client_creds); + free(username); + free(targetname); + free(response); } gss_result authenticate_gss_server_step(gss_server_state* state, const char* challenge) { diff --git a/src/unix/kerberos_gss.h b/src/unix/kerberos_gss.h index 652812ab..bea7df52 100644 --- a/src/unix/kerberos_gss.h +++ b/src/unix/kerberos_gss.h @@ -43,32 +43,39 @@ typedef struct { std::string data; } gss_result; -typedef struct { +struct gss_client_state { gss_ctx_id_t context; gss_name_t server_name; gss_OID mech_oid; long int gss_flags; gss_cred_id_t client_creds; - char* username; - char* response; - int responseConf; - bool context_complete; -} gss_client_state; + char* username = nullptr; + char* response = nullptr; + int responseConf = 0; + bool context_complete = false; -typedef struct { + gss_client_state() {} + gss_client_state(const gss_client_state&) = delete; + gss_client_state& operator=(const gss_client_state&) = delete; + ~gss_client_state(); +}; + +struct gss_server_state { gss_ctx_id_t context; gss_name_t server_name; gss_name_t client_name; gss_cred_id_t server_creds; gss_cred_id_t client_creds; - char* username; - char* targetname; - char* response; - bool context_complete; -} gss_server_state; + char* username = nullptr; + char* targetname = nullptr; + char* response = nullptr; + bool context_complete = false; -gss_client_state* gss_client_state_new(); -gss_server_state* gss_server_state_new(); + gss_server_state() {} + gss_server_state(const gss_server_state&) = delete; + gss_server_state& operator=(const gss_server_state&) = delete; + ~gss_server_state(); +}; gss_result server_principal_details(const char* service, const char* hostname); @@ -79,7 +86,6 @@ gss_result authenticate_gss_client_init(const char* service, gss_OID mech_oid, gss_client_state* state); -int authenticate_gss_client_clean(gss_client_state* state); gss_result authenticate_gss_client_step(gss_client_state* state, const char* challenge, struct gss_channel_bindings_struct* channel_bindings); @@ -89,7 +95,6 @@ gss_result authenticate_gss_client_wrap(gss_client_state* state, const char* user, int protect); gss_result authenticate_gss_server_init(const char* service, gss_server_state* state); -int authenticate_gss_server_clean(gss_server_state* state); gss_result authenticate_gss_server_step(gss_server_state* state, const char* challenge); gss_result authenticate_user_krb5pwd(const char* user, diff --git a/src/unix/kerberos_unix.cc b/src/unix/kerberos_unix.cc index 98f59654..b7990417 100644 --- a/src/unix/kerberos_unix.cc +++ b/src/unix/kerberos_unix.cc @@ -13,22 +13,14 @@ static char spnego_mech_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; gss_OID_desc spnego_mech_oid = {6, &spnego_mech_oid_bytes}; /// KerberosClient -KerberosClient::~KerberosClient() { - if (_state != NULL) { - authenticate_gss_client_clean(_state); - free(_state); - _state = NULL; - } -} - NAN_METHOD(KerberosClient::Step) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:ClientStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = - authenticate_gss_client_step(client->state(), challenge.c_str(), NULL); + authenticate_gss_client_step(state.get(), challenge.c_str(), NULL); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -39,8 +31,8 @@ NAN_METHOD(KerberosClient::Step) { } v8::Local response = Nan::Null(); - if (client->state()->response != NULL) { - response = Nan::New(client->state()->response).ToLocalChecked(); + if (state->response != NULL) { + response = Nan::New(state->response).ToLocalChecked(); } v8::Local argv[] = {Nan::Null(), response}; @@ -50,13 +42,13 @@ NAN_METHOD(KerberosClient::Step) { } NAN_METHOD(KerberosClient::UnwrapData) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:ClientUnwrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = - authenticate_gss_client_unwrap(client->state(), challenge.c_str()); + authenticate_gss_client_unwrap(state.get(), challenge.c_str()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -66,14 +58,14 @@ NAN_METHOD(KerberosClient::UnwrapData) { return; } - v8::Local argv[] = {Nan::Null(), Nan::New(client->state()->response).ToLocalChecked()}; + v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; worker->Call(2, argv); }); }); } NAN_METHOD(KerberosClient::WrapData) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); v8::Local options = Nan::To(info[1]).ToLocalChecked(); Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); @@ -83,7 +75,7 @@ NAN_METHOD(KerberosClient::WrapData) { KerberosWorker::Run(callback, "kerberos:ClientWrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = authenticate_gss_client_wrap( - client->state(), challenge.c_str(), user.c_str(), protect); + state.get(), challenge.c_str(), user.c_str(), protect); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -93,28 +85,21 @@ NAN_METHOD(KerberosClient::WrapData) { return; } - v8::Local argv[] = {Nan::Null(), Nan::New(client->state()->response).ToLocalChecked()}; + v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; worker->Call(2, argv); }); }); } /// KerberosServer -KerberosServer::~KerberosServer() { - if (_state != NULL) { - authenticate_gss_server_clean(_state); - _state = NULL; - } -} - NAN_METHOD(KerberosServer::Step) { - KerberosServer* server = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:ServerStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = - authenticate_gss_server_step(server->state(), challenge.c_str()); + authenticate_gss_server_step(state.get(), challenge.c_str()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -125,8 +110,8 @@ NAN_METHOD(KerberosServer::Step) { } v8::Local response = Nan::Null(); - if (server->state()->response != NULL) { - response = Nan::New(server->state()->response).ToLocalChecked(); + if (state->response != NULL) { + response = Nan::New(state->response).ToLocalChecked(); } v8::Local argv[] = {Nan::Null(), response}; @@ -153,15 +138,9 @@ NAN_METHOD(InitializeClient) { } KerberosWorker::Run(callback, "kerberos:InitializeClient", [=](KerberosWorker::SetOnFinishedHandler onFinished) { - // TODO: Manage client_state as a proper C++ class with a destructor + through shared pointers - gss_client_state* client_state = gss_client_state_new(); + auto client_state = std::make_shared(); gss_result result = authenticate_gss_client_init( - service.c_str(), principal.c_str(), gss_flags, NULL, mech_oid, client_state); - - if (result.code == AUTH_GSS_ERROR) { - authenticate_gss_client_clean(client_state); - free(client_state); - } + service.c_str(), principal.c_str(), gss_flags, NULL, mech_oid, client_state.get()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -182,15 +161,9 @@ NAN_METHOD(InitializeServer) { Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:InitializeServer", [=](KerberosWorker::SetOnFinishedHandler onFinished) { - // TODO: Manage server_state as a proper C++ class with a destructor + through shared pointers - gss_server_state* server_state = gss_server_state_new(); + auto server_state = std::make_shared(); gss_result result = - authenticate_gss_server_init(service.c_str(), server_state); - - if (result.code == AUTH_GSS_ERROR) { - authenticate_gss_server_clean(server_state); - free(server_state); - } + authenticate_gss_server_init(service.c_str(), server_state.get()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; diff --git a/src/win32/kerberos_sspi.cc b/src/win32/kerberos_sspi.cc index 520600f7..f000f4dd 100644 --- a/src/win32/kerberos_sspi.cc +++ b/src/win32/kerberos_sspi.cc @@ -9,37 +9,16 @@ static SEC_CHAR* base64_encode(const SEC_CHAR* value, DWORD vlen); static SEC_CHAR* base64_decode(const SEC_CHAR* value, DWORD* rlen); static CHAR* wide_to_utf8(WCHAR* value); -sspi_client_state* sspi_client_state_new() { - sspi_client_state* state = (sspi_client_state*)malloc(sizeof(sspi_client_state)); - state->username = NULL; - state->response = NULL; - state->responseConf = 0; - state->context_complete = FALSE; - return state; -} - -VOID -auth_sspi_client_clean(sspi_client_state* state) { - if (state->haveCtx) { - DeleteSecurityContext(&state->ctx); - state->haveCtx = 0; +sspi_client_state::~sspi_client_state() { + if (haveCtx) { + DeleteSecurityContext(&ctx); } - if (state->haveCred) { + if (haveCred) { FreeCredentialsHandle(&state->cred); - state->haveCred = 0; - } - if (state->spn != NULL) { - free(state->spn); - state->spn = NULL; - } - if (state->response != NULL) { - free(state->response); - state->response = NULL; - } - if (state->username != NULL) { - free(state->username); - state->username = NULL; } + free(state->spn); + free(state->response); + free(state->username); } sspi_result diff --git a/src/win32/kerberos_sspi.h b/src/win32/kerberos_sspi.h index 113f2c0f..680069e5 100644 --- a/src/win32/kerberos_sspi.h +++ b/src/win32/kerberos_sspi.h @@ -33,27 +33,33 @@ typedef struct { std::string data; } sspi_result; -typedef struct { +struct sspi_client_state { CredHandle cred; CtxtHandle ctx; - WCHAR* spn; - SEC_CHAR* response; - SEC_CHAR* username; + WCHAR* spn = nullptr; + SEC_CHAR* response = nullptr; + SEC_CHAR* username = nullptr; ULONG flags; - UCHAR haveCred; - UCHAR haveCtx; + UCHAR haveCred = 0; + UCHAR haveCtx = 0; ULONG qop; - INT responseConf; - BOOL context_complete; -} sspi_client_state; + INT responseConf = 0; + BOOL context_complete = FALSE; -typedef struct { - WCHAR* username; - WCHAR* response; - BOOL context_complete; + sspi_client_state() {} + sspi_client_state(const sspi_client_state&) = delete; + sspi_client_state& operator=(const sspi_client_state&) = delete; + ~sspi_client_state(); +}; + +struct sspi_server_state { + // This is unused currently + WCHAR* username = nullptr; + WCHAR* response = nullptr; + BOOL context_complete = FALSE; char* targetname; -} sspi_server_state; +}; sspi_client_state* sspi_client_state_new(); VOID auth_sspi_client_clean(sspi_client_state* state); diff --git a/src/win32/kerberos_win32.cc b/src/win32/kerberos_win32.cc index dc1febda..ebdee099 100644 --- a/src/win32/kerberos_win32.cc +++ b/src/win32/kerberos_win32.cc @@ -38,22 +38,14 @@ NAN_INLINE std::wstring WStringOptionValue(v8::Local options, const } /// KerberosClient -KerberosClient::~KerberosClient() { - if (_state != NULL) { - auth_sspi_client_clean(_state); - free(_state); - _state = NULL; - } -} - NAN_METHOD(KerberosClient::Step) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:ClientStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { sspi_result result = - auth_sspi_client_step(client->state(), (SEC_CHAR*)challenge.c_str(), NULL); + auth_sspi_client_step(state.get(), (SEC_CHAR*)challenge.c_str(), NULL); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -64,8 +56,8 @@ NAN_METHOD(KerberosClient::Step) { } v8::Local response = Nan::Null(); - if (client->state()->response != NULL) { - response = Nan::New(client->state()->response).ToLocalChecked(); + if (state->response != NULL) { + response = Nan::New(state->response).ToLocalChecked(); } v8::Local argv[] = {Nan::Null(), response}; @@ -75,13 +67,13 @@ NAN_METHOD(KerberosClient::Step) { } NAN_METHOD(KerberosClient::UnwrapData) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); KerberosWorker::Run(callback, "kerberos:ClientUnwrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { sspi_result result = - auth_sspi_client_unwrap(client->state(), (SEC_CHAR*)challenge.c_str()); + auth_sspi_client_unwrap(state.get(), (SEC_CHAR*)challenge.c_str()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -91,14 +83,14 @@ NAN_METHOD(KerberosClient::UnwrapData) { return; } - v8::Local argv[] = {Nan::Null(), Nan::New(client->state()->response).ToLocalChecked()}; + v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; worker->Call(2, argv); }); }); } NAN_METHOD(KerberosClient::WrapData) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); + auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); std::string challenge(*Nan::Utf8String(info[0])); v8::Local options = Nan::To(info[1]).ToLocalChecked(); Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); @@ -107,7 +99,7 @@ NAN_METHOD(KerberosClient::WrapData) { KerberosWorker::Run(callback, "kerberos:ClientWrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { sspi_result result = auth_sspi_client_wrap( - client->state(), (SEC_CHAR*)challenge.c_str(), (SEC_CHAR*)user.c_str(), user.length(), protect); + state.get(), (SEC_CHAR*)challenge.c_str(), (SEC_CHAR*)user.c_str(), user.length(), protect); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; @@ -118,21 +110,13 @@ NAN_METHOD(KerberosClient::WrapData) { return; } - v8::Local argv[] = {Nan::Null(), Nan::New(client->state()->response).ToLocalChecked()}; + v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; worker->Call(2, argv); }); }); } /// KerberosServer -KerberosServer::~KerberosServer() { - // if (_state != NULL) { - // authenticate_gss_server_clean(_state); - // free(_state); - // _state = NULL; - // } -} - NAN_METHOD(KerberosServer::Step) { Nan::ThrowError("`KerberosServer::Step` is not implemented yet for windows"); } @@ -154,17 +138,11 @@ NAN_METHOD(InitializeClient) { } KerberosWorker::Run(callback, "kerberos:InitializeClient", [=](KerberosWorker::SetOnFinishedHandler onFinished) { - // TODO: Manage server_state as a proper C++ class with a destructor + through shared pointers - sspi_client_state* client_state = sspi_client_state_new(); + auto client_state = std::make_shared(); sspi_result result = auth_sspi_client_init( (WCHAR*)service.c_str(), gss_flags, (WCHAR*)user.c_str(), user.length(), (WCHAR*)domain.c_str(), domain.length(), (WCHAR*)password.c_str(), password.length(), - (WCHAR*)mech_oid.c_str(), client_state); - - if (result.code == AUTH_GSS_ERROR) { - auth_sspi_client_clean(client_state); - free(client_state); - } + (WCHAR*)mech_oid.c_str(), client_state.get()); return onFinished([=](KerberosWorker* worker) { Nan::HandleScope scope; From 9df823ff3cc8e937e2969532b2b1945d43cae99f Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 22 Sep 2021 12:17:29 +0200 Subject: [PATCH 2/3] feat!(NODE-3472): convert to Node-API --- .evergreen/run-prebuild.sh | 3 +- binding.gyp | 17 ++- package-lock.json | 8 +- package.json | 15 +- src/kerberos.cc | 279 +++++++++++++++++++----------------- src/kerberos.h | 71 +++++---- src/kerberos_common.h | 39 +---- src/kerberos_worker.h | 40 +++--- src/unix/kerberos_gss.cc | 4 + src/unix/kerberos_gss.h | 4 + src/unix/kerberos_unix.cc | 185 ++++++++++++------------ src/win32/kerberos_sspi.cc | 12 +- src/win32/kerberos_sspi.h | 6 +- src/win32/kerberos_win32.cc | 153 ++++++++++---------- 14 files changed, 433 insertions(+), 403 deletions(-) diff --git a/.evergreen/run-prebuild.sh b/.evergreen/run-prebuild.sh index b852b9a8..c99500de 100755 --- a/.evergreen/run-prebuild.sh +++ b/.evergreen/run-prebuild.sh @@ -14,7 +14,6 @@ run_prebuild() { else echo "Github token detected. Running prebuild." npm run prebuild -- -u $NODE_GITHUB_TOKEN - npm run prebuild-legacy -- -u $NODE_GITHUB_TOKEN echo "Prebuild's successfully submitted" fi } @@ -49,4 +48,4 @@ else npm run prebuild echo "Local prebuild successful." ls ./prebuilds -fi \ No newline at end of file +fi diff --git a/binding.gyp b/binding.gyp index bd4b1401..f4954ea5 100644 --- a/binding.gyp +++ b/binding.gyp @@ -3,14 +3,27 @@ { 'target_name': 'kerberos', 'type': 'loadable_module', - 'include_dirs': [ ' README.md", "rebuild": "prebuild --compile", - "prebuild": "prebuild --strip --verbose --all", - "prebuild-legacy": "prebuild --strip --verbose --runtime node --target 4.0.0", + "prebuild": "prebuild --runtime napi --strip --verbose --all", "release": "standard-version -i HISTORY.md" }, + "engines": { + "node": ">=12.9.0" + }, + "binary": { + "napi_versions": [ + 4 + ] + }, "license": "Apache-2.0", "readmeFilename": "README.md" } diff --git a/src/kerberos.cc b/src/kerberos.cc index 1a845eea..00010ab8 100644 --- a/src/kerberos.cc +++ b/src/kerberos.cc @@ -2,182 +2,191 @@ #include "kerberos_worker.h" /// KerberosClient -Nan::Persistent KerberosClient::constructor; -NAN_MODULE_INIT(KerberosClient::Init) { - v8::Local tpl = Nan::New(); - tpl->SetClassName(Nan::New("KerberosClient").ToLocalChecked()); - Nan::SetPrototypeMethod(tpl, "step", Step); - Nan::SetPrototypeMethod(tpl, "wrap", WrapData); - Nan::SetPrototypeMethod(tpl, "unwrap", UnwrapData); - - v8::Local itpl = tpl->InstanceTemplate(); - itpl->SetInternalFieldCount(1); - - Nan::SetAccessor(itpl, Nan::New("username").ToLocalChecked(), KerberosClient::UserNameGetter); - Nan::SetAccessor(itpl, Nan::New("response").ToLocalChecked(), KerberosClient::ResponseGetter); - Nan::SetAccessor( - itpl, Nan::New("responseConf").ToLocalChecked(), KerberosClient::ResponseConfGetter); - Nan::SetAccessor( - itpl, Nan::New("contextComplete").ToLocalChecked(), KerberosClient::ContextCompleteGetter); - - constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked()); - Nan::Set(target, - Nan::New("KerberosClient").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); -} - -v8::Local KerberosClient::NewInstance(std::shared_ptr state) { - Nan::EscapableHandleScope scope; - v8::Local ctor = Nan::New(KerberosClient::constructor); - v8::Local object = Nan::NewInstance(ctor).ToLocalChecked(); - KerberosClient* class_instance = new KerberosClient(state); - class_instance->Wrap(object); - return scope.Escape(object); -} - -KerberosClient::KerberosClient(std::shared_ptr state) - : _state(state) {} +namespace node_kerberos { -std::shared_ptr KerberosClient::state() const { - return _state; -} +using namespace Napi; -NAN_GETTER(KerberosClient::UserNameGetter) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); - (client->state()->username == NULL) - ? info.GetReturnValue().Set(Nan::Null()) - : info.GetReturnValue().Set(Nan::New(client->state()->username).ToLocalChecked()); +namespace { +struct InstanceData { + Reference KerberosClientCtor; + Reference KerberosServerCtor; +}; + +static constexpr napi_property_attributes writable_and_configurable = + static_cast( + static_cast(napi_writable) | static_cast(napi_configurable)); + +inline String NewMaybeWideString(Env env, const char* str) { + return String::New(env, str); +} +#ifdef _WIN32 +inline String NewMaybeWideString(Env env, const WCHAR* str) { + static_assert(sizeof(std::wstring::value_type) == sizeof(std::u16string::value_type), + "wstring and u16string have the same value type on Windows"); + std::wstring wstr(str); + std::u16string u16(wstr.begin(), wstr.end()); + return String::New(env, u16); +} +#endif } -NAN_GETTER(KerberosClient::ResponseGetter) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); - (client->state()->response == NULL) - ? info.GetReturnValue().Set(Nan::Null()) - : info.GetReturnValue().Set(Nan::New(client->state()->response).ToLocalChecked()); +std::string ToStringWithNonStringAsEmpty(Napi::Value value) { + if (!value.IsString()) { + return std::string(); + } + return value.As(); } -NAN_GETTER(KerberosClient::ResponseConfGetter) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(Nan::New(client->state()->responseConf)); +Function KerberosClient::Init(Napi::Env env) { + return + DefineClass(env, + "KerberosClient", + { + InstanceMethod("step", &KerberosClient::Step, writable_and_configurable), + InstanceMethod("wrap", &KerberosClient::WrapData, writable_and_configurable), + InstanceMethod("unwrap", &KerberosClient::UnwrapData, writable_and_configurable), + InstanceAccessor("username", &KerberosClient::UserNameGetter, nullptr), + InstanceAccessor("response", &KerberosClient::ResponseGetter, nullptr), + InstanceAccessor("responseConf", &KerberosClient::ResponseConfGetter, nullptr), + InstanceAccessor("contextComplete", &KerberosClient::ContextCompleteGetter, nullptr) + }); } -NAN_GETTER(KerberosClient::ContextCompleteGetter) { - KerberosClient* client = Nan::ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(Nan::New(client->state()->context_complete)); +Object KerberosClient::NewInstance(Napi::Env env, std::shared_ptr state) { + InstanceData* instance_data = env.GetInstanceData(); + Object obj = instance_data->KerberosClientCtor.Value().New({}); + KerberosClient* instance = KerberosClient::Unwrap(obj); + instance->_state = std::move(state); + return obj; } -/// KerberosServer -Nan::Persistent KerberosServer::constructor; -NAN_MODULE_INIT(KerberosServer::Init) { - v8::Local tpl = Nan::New(); - tpl->SetClassName(Nan::New("KerberosServer").ToLocalChecked()); - Nan::SetPrototypeMethod(tpl, "step", Step); +KerberosClient::KerberosClient(const CallbackInfo& info) + : ObjectWrap(info) {} - v8::Local itpl = tpl->InstanceTemplate(); - itpl->SetInternalFieldCount(1); +std::shared_ptr KerberosClient::state() const { + return _state; +} - Nan::SetAccessor(itpl, Nan::New("username").ToLocalChecked(), KerberosServer::UserNameGetter); - Nan::SetAccessor(itpl, Nan::New("response").ToLocalChecked(), KerberosServer::ResponseGetter); - Nan::SetAccessor( - itpl, Nan::New("targetName").ToLocalChecked(), KerberosServer::TargetNameGetter); - Nan::SetAccessor( - itpl, Nan::New("contextComplete").ToLocalChecked(), KerberosServer::ContextCompleteGetter); +Value KerberosClient::UserNameGetter(const CallbackInfo& info) { + const auto* username = state()->username; + if (username == nullptr) + return Env().Null(); + return NewMaybeWideString(Env(), username); +} - constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked()); - Nan::Set(target, - Nan::New("KerberosServer").ToLocalChecked(), - Nan::GetFunction(tpl).ToLocalChecked()); +Value KerberosClient::ResponseGetter(const CallbackInfo& info) { + const auto* response = state()->response; + if (response == nullptr) + return Env().Null(); + return NewMaybeWideString(Env(), response); } -v8::Local KerberosServer::NewInstance(std::shared_ptr state) { - Nan::EscapableHandleScope scope; - v8::Local ctor = Nan::New(KerberosServer::constructor); - v8::Local object = Nan::NewInstance(ctor).ToLocalChecked(); - KerberosServer* class_instance = new KerberosServer(state); - class_instance->Wrap(object); - return scope.Escape(object); +Value KerberosClient::ResponseConfGetter(const CallbackInfo& info) { + return Number::New(Env(), state()->responseConf); } -KerberosServer::KerberosServer(std::shared_ptr state) - : _state(state) {} +Value KerberosClient::ContextCompleteGetter(const CallbackInfo& info) { + return Boolean::New(Env(), state()->context_complete); +} + +/// KerberosServer +Function KerberosServer::Init(Napi::Env env) { + return + DefineClass(env, + "KerberosServer", + { + InstanceMethod("step", &KerberosServer::Step, writable_and_configurable), + InstanceAccessor("username", &KerberosServer::UserNameGetter, nullptr), + InstanceAccessor("response", &KerberosServer::ResponseGetter, nullptr), + InstanceAccessor("targetName", &KerberosServer::TargetNameGetter, nullptr), + InstanceAccessor("contextComplete", &KerberosServer::ContextCompleteGetter, nullptr) + }); +} + +Object KerberosServer::NewInstance(Napi::Env env, std::shared_ptr state) { + InstanceData* instance_data = env.GetInstanceData(); + Object obj = instance_data->KerberosServerCtor.Value().New({}); + KerberosServer* instance = KerberosServer::Unwrap(obj); + instance->_state = std::move(state); + return obj; +} + +KerberosServer::KerberosServer(const CallbackInfo& info) + : ObjectWrap(info) {} std::shared_ptr KerberosServer::state() const { return _state; } -NAN_GETTER(KerberosServer::UserNameGetter) { - KerberosServer* server = Nan::ObjectWrap::Unwrap(info.This()); - (server->_state->username == NULL) - ? info.GetReturnValue().Set(Nan::Null()) - : info.GetReturnValue().Set(Nan::New((char*)server->_state->username).ToLocalChecked()); +Value KerberosServer::UserNameGetter(const CallbackInfo& info) { + const auto* username = state()->username; + if (username == nullptr) + return Env().Null(); + return NewMaybeWideString(Env(), username); } -NAN_GETTER(KerberosServer::ResponseGetter) { - KerberosServer* server = Nan::ObjectWrap::Unwrap(info.This()); - (server->_state->response == NULL) - ? info.GetReturnValue().Set(Nan::Null()) - : info.GetReturnValue().Set(Nan::New((char*)server->_state->response).ToLocalChecked()); +Value KerberosServer::ResponseGetter(const CallbackInfo& info) { + const auto* response = state()->response; + if (response == nullptr) + return Env().Null(); + return NewMaybeWideString(Env(), response); } -NAN_GETTER(KerberosServer::TargetNameGetter) { - KerberosServer* server = Nan::ObjectWrap::Unwrap(info.This()); - (server->_state->targetname == NULL) - ? info.GetReturnValue().Set(Nan::Null()) - : info.GetReturnValue().Set(Nan::New((char*)server->_state->targetname).ToLocalChecked()); +Value KerberosServer::TargetNameGetter(const CallbackInfo& info) { + const auto* targetname = state()->targetname; + if (targetname == nullptr) + return Env().Null(); + return NewMaybeWideString(Env(), targetname); } -NAN_GETTER(KerberosServer::ContextCompleteGetter) { - KerberosServer* server = Nan::ObjectWrap::Unwrap(info.This()); - info.GetReturnValue().Set(Nan::New(server->_state->context_complete)); +Value KerberosServer::ContextCompleteGetter(const CallbackInfo& info) { + return Boolean::New(Env(), state()->context_complete); } -NAN_METHOD(TestMethod) { - std::string string(*Nan::Utf8String(info[0])); - bool shouldError = Nan::To(info[1]).FromJust(); +void TestMethod(const CallbackInfo& info) { + std::string string = info[0].ToString(); + bool shouldError = info[1].ToBoolean(); std::string optionalString; - Nan::Callback* callback; - if (info[2]->IsFunction()) { - callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); + Function callback; + if (info[2].IsFunction()) { + callback = info[2].As(); } else { - optionalString = *Nan::Utf8String(info[2]); - callback = new Nan::Callback(Nan::To(info[3]).ToLocalChecked()); + optionalString = info[2].ToString(); + callback = info[3].As(); } KerberosWorker::Run(callback, "kerberos:TestMethod", [=](KerberosWorker::SetOnFinishedHandler onFinished) { return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (shouldError) { - v8::Local argv[] = {Nan::Error("an error occurred"), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env).Value(), env.Null() }); } else { - v8::Local argv[] = {Nan::Null(), Nan::New(optionalString.c_str()).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, optionalString) }); } }); }); } -static NAN_MODULE_INIT(Init) { - // Custom types - KerberosClient::Init(target); - KerberosServer::Init(target); - - Nan::Set(target, - Nan::New("initializeClient").ToLocalChecked(), - Nan::GetFunction(Nan::New(InitializeClient)).ToLocalChecked()); - Nan::Set(target, - Nan::New("initializeServer").ToLocalChecked(), - Nan::GetFunction(Nan::New(InitializeServer)).ToLocalChecked()); - Nan::Set(target, - Nan::New("principalDetails").ToLocalChecked(), - Nan::GetFunction(Nan::New(PrincipalDetails)).ToLocalChecked()); - Nan::Set(target, - Nan::New("checkPassword").ToLocalChecked(), - Nan::GetFunction(Nan::New(CheckPassword)).ToLocalChecked()); - Nan::Set(target, - Nan::New("_testMethod").ToLocalChecked(), - Nan::GetFunction(Nan::New(TestMethod)).ToLocalChecked()); -} - -NODE_MODULE(kerberos, Init) +static Object Init(Env env, Object exports) { + Function KerberosClientCtor = KerberosClient::Init(env); + Function KerberosServerCtor = KerberosServer::Init(env); + exports["KerberosClient"] = KerberosClientCtor; + exports["KerberosServer"] = KerberosServerCtor; + env.SetInstanceData(new InstanceData { + Reference::New(KerberosClientCtor, 1), + Reference::New(KerberosServerCtor, 1) + }); + exports["initializeClient"] = Function::New(env, InitializeClient); + exports["initializeServer"] = Function::New(env, InitializeServer); + exports["principalDetails"] = Function::New(env, PrincipalDetails); + exports["checkPassword"] = Function::New(env, CheckPassword); + exports["_testMethod"] = Function::New(env, TestMethod); + return exports; +} + +NODE_API_MODULE(kerberos, Init) + +} diff --git a/src/kerberos.h b/src/kerberos.h index c0510dfd..b0c1cdc5 100644 --- a/src/kerberos.h +++ b/src/kerberos.h @@ -1,63 +1,74 @@ #ifndef KERBEROS_NATIVE_EXTENSION_H #define KERBEROS_NATIVE_EXTENSION_H -#include +// We generally only target N-API version 4, but the instance data +// feature is only available in N-API version 6. However, it is +// available in all Node.js versions that have N-API version 4 +#define NAPI_VERSION 6 +// as an experimental feature (that has not been changed since then). +#define NAPI_EXPERIMENTAL + +#include #include "kerberos_common.h" -class KerberosServer : public Nan::ObjectWrap { +namespace node_kerberos { + +class KerberosServer : public Napi::ObjectWrap { public: - static NAN_MODULE_INIT(Init); - static v8::Local NewInstance(std::shared_ptr state); + static Napi::Function Init(Napi::Env env); + static Napi::Object NewInstance(Napi::Env env, std::shared_ptr state); std::shared_ptr state() const; private: - static Nan::Persistent constructor; - - static NAN_GETTER(UserNameGetter); - static NAN_GETTER(ResponseGetter); - static NAN_GETTER(TargetNameGetter); - static NAN_GETTER(ContextCompleteGetter); + Napi::Value UserNameGetter(const Napi::CallbackInfo& info); + Napi::Value ResponseGetter(const Napi::CallbackInfo& info); + Napi::Value TargetNameGetter(const Napi::CallbackInfo& info); + Napi::Value ContextCompleteGetter(const Napi::CallbackInfo& info); - static NAN_METHOD(Step); + void Step(const Napi::CallbackInfo& info); private: - explicit KerberosServer(std::shared_ptr server_state); + friend class Napi::ObjectWrap; + explicit KerberosServer(const Napi::CallbackInfo& info); std::shared_ptr _state; }; -class KerberosClient : public Nan::ObjectWrap { +class KerberosClient : public Napi::ObjectWrap { public: - static NAN_MODULE_INIT(Init); - static v8::Local NewInstance(std::shared_ptr state); + static Napi::Function Init(Napi::Env env); + static Napi::Object NewInstance(Napi::Env env, std::shared_ptr state); std::shared_ptr state() const; private: - static Nan::Persistent constructor; - - static NAN_GETTER(UserNameGetter); - static NAN_GETTER(ResponseGetter); - static NAN_GETTER(ResponseConfGetter); - static NAN_GETTER(ContextCompleteGetter); + Napi::Value UserNameGetter(const Napi::CallbackInfo& info); + Napi::Value ResponseGetter(const Napi::CallbackInfo& info); + Napi::Value ResponseConfGetter(const Napi::CallbackInfo& info); + Napi::Value ContextCompleteGetter(const Napi::CallbackInfo& info); - static NAN_METHOD(Step); - static NAN_METHOD(UnwrapData); - static NAN_METHOD(WrapData); + void Step(const Napi::CallbackInfo& info); + void UnwrapData(const Napi::CallbackInfo& info); + void WrapData(const Napi::CallbackInfo& info); private: - explicit KerberosClient(std::shared_ptr client_state); + friend class Napi::ObjectWrap; + explicit KerberosClient(const Napi::CallbackInfo& info); std::shared_ptr _state; }; -NAN_METHOD(PrincipalDetails); -NAN_METHOD(InitializeClient); -NAN_METHOD(InitializeServer); -NAN_METHOD(CheckPassword); +void PrincipalDetails(const Napi::CallbackInfo& info); +void InitializeClient(const Napi::CallbackInfo& info); +void InitializeServer(const Napi::CallbackInfo& info); +void CheckPassword(const Napi::CallbackInfo& info); // NOTE: explicitly used for unit testing `defineOperation`, not meant to be exported -NAN_METHOD(TestMethod); +void TestMethod(const Napi::CallbackInfo& info); + +std::string ToStringWithNonStringAsEmpty(Napi::Value value); + +} #endif // KERBEROS_NATIVE_EXTENSION_H diff --git a/src/kerberos_common.h b/src/kerberos_common.h index 51701482..6058f143 100644 --- a/src/kerberos_common.h +++ b/src/kerberos_common.h @@ -1,53 +1,22 @@ #ifndef KERBEROS_COMMON_H #define KERBEROS_COMMON_H -#include - #if defined(__linux__) || defined(__APPLE__) #include "unix/kerberos_gss.h" +namespace node_kerberos { typedef gss_client_state krb_client_state; typedef gss_server_state krb_server_state; typedef gss_result krb_result; +} #else #include "win32/kerberos_sspi.h" +namespace node_kerberos { typedef sspi_client_state krb_client_state; typedef sspi_server_state krb_server_state; typedef sspi_result krb_result; -#endif - -// Useful methods for optional value handling -NAN_INLINE std::string StringOptionValue(v8::Local options, const char* _key) { - Nan::HandleScope scope; - v8::Local key = Nan::New(_key).ToLocalChecked(); - if (options.IsEmpty() || !Nan::Has(options, key).FromMaybe(false)) { - return std::string(); - } - - v8::Local value = Nan::Get(options, key).ToLocalChecked(); - if (!value->IsString()) { - return std::string(); - } - - return std::string(*(Nan::Utf8String(value))); -} - -NAN_INLINE uint32_t UInt32OptionValue(v8::Local options, - const char* _key, - uint32_t def) { - Nan::HandleScope scope; - v8::Local key = Nan::New(_key).ToLocalChecked(); - if (options.IsEmpty() || !Nan::Has(options, key).FromMaybe(false)) { - return def; - } - - v8::Local value = Nan::Get(options, key).ToLocalChecked(); - if (!value->IsNumber()) { - return def; - } - - return value->Uint32Value(Nan::GetCurrentContext()).FromJust(); } +#endif #endif diff --git a/src/kerberos_worker.h b/src/kerberos_worker.h index 318e5587..f626cae1 100644 --- a/src/kerberos_worker.h +++ b/src/kerberos_worker.h @@ -2,47 +2,47 @@ #define KERBEROS_ASYNC_WORKER_H #include -#include +#include "kerberos.h" -class KerberosWorker : public Nan::AsyncWorker { +namespace node_kerberos { + +class KerberosWorker final : public Napi::AsyncWorker { public: + ~KerberosWorker() {} + typedef std::function OnFinishedHandler; typedef std::function SetOnFinishedHandler; typedef std::function ExecuteHandler; - explicit KerberosWorker(Nan::Callback *callback, const char* resource_name, ExecuteHandler handler) - : Nan::AsyncWorker(callback, resource_name), execute_handler(handler) {} - template void Call(T... t) { - callback->Call(t..., async_resource); + Callback().Call(t...); } - virtual void Execute() { + static void Run(Napi::Function callback, const char* resource_name, ExecuteHandler handler) { + auto worker = new KerberosWorker(callback, resource_name, handler); + worker->Queue(); + } + + protected: + void Execute() final { execute_handler([=] (OnFinishedHandler handler) { on_finished_handler = handler; }); } - static void Run(Nan::Callback *callback, const char* resource_name, ExecuteHandler handler) { - Nan::TryCatch tryCatch; - if (tryCatch.HasCaught()) { - tryCatch.ReThrow(); - return; // don't proceed in case there were any previous errors - } - - auto worker = new KerberosWorker(callback, resource_name, handler); - Nan::AsyncQueueWorker(worker); - } - - protected: - void HandleOKCallback() { + void OnOK() final { on_finished_handler(this); } private: + explicit KerberosWorker(Napi::Function callback, const char* resource_name, ExecuteHandler handler) + : Napi::AsyncWorker(callback, resource_name), execute_handler(handler) {} + ExecuteHandler execute_handler; OnFinishedHandler on_finished_handler; }; +} + #endif // ASYNC_WORKER_H diff --git a/src/unix/kerberos_gss.cc b/src/unix/kerberos_gss.cc index 4b2e93bb..0ddb14dd 100644 --- a/src/unix/kerberos_gss.cc +++ b/src/unix/kerberos_gss.cc @@ -28,6 +28,8 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif +namespace node_kerberos { + static gss_result gss_success_result(int ret); static gss_result gss_error_result(OM_uint32 err_maj, OM_uint32 err_min); static gss_result gss_error_result_with_message(const char* message); @@ -735,6 +737,8 @@ static gss_result gss_error_result_with_message_and_code(const char* message, in }; } +} + #if defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/src/unix/kerberos_gss.h b/src/unix/kerberos_gss.h index bea7df52..e7a62eda 100644 --- a/src/unix/kerberos_gss.h +++ b/src/unix/kerberos_gss.h @@ -25,6 +25,8 @@ extern "C" { #include +namespace node_kerberos { + inline const char* krb5_get_err_text(const krb5_context&, krb5_error_code code) { return error_message(code); } @@ -102,4 +104,6 @@ gss_result authenticate_user_krb5pwd(const char* user, const char* service, const char* default_realm); +} + #endif diff --git a/src/unix/kerberos_unix.cc b/src/unix/kerberos_unix.cc index b7990417..ba252a4d 100644 --- a/src/unix/kerberos_unix.cc +++ b/src/unix/kerberos_unix.cc @@ -3,6 +3,10 @@ #include "../kerberos.h" #include "../kerberos_worker.h" +namespace node_kerberos { + +using namespace Napi; + #define GSS_MECH_OID_KRB5 9 #define GSS_MECH_OID_SPNEGO 6 @@ -13,63 +17,63 @@ static char spnego_mech_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; gss_OID_desc spnego_mech_oid = {6, &spnego_mech_oid_bytes}; /// KerberosClient -NAN_METHOD(KerberosClient::Step) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void KerberosClient::Step(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:ClientStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = authenticate_gss_client_step(state.get(), challenge.c_str(), NULL); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local response = Nan::Null(); - if (state->response != NULL) { - response = Nan::New(state->response).ToLocalChecked(); + Napi::Value response = env.Null(); + if (state->response != nullptr) { + response = String::New(env, state->response); } - v8::Local argv[] = {Nan::Null(), response}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), response }); }); }); } -NAN_METHOD(KerberosClient::UnwrapData) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void KerberosClient::UnwrapData(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:ClientUnwrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = authenticate_gss_client_unwrap(state.get(), challenge.c_str()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, state->response) }); }); }); } -NAN_METHOD(KerberosClient::WrapData) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - v8::Local options = Nan::To(info[1]).ToLocalChecked(); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); - std::string user = StringOptionValue(options, "user"); +void KerberosClient::WrapData(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Object options = info[1].ToObject(); + Function callback = info[2].As(); + std::string user = ToStringWithNonStringAsEmpty(options["user"]); int protect = 0; // NOTE: this should be an option @@ -78,58 +82,59 @@ NAN_METHOD(KerberosClient::WrapData) { state.get(), challenge.c_str(), user.c_str(), protect); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, state->response) }); }); }); } /// KerberosServer -NAN_METHOD(KerberosServer::Step) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void KerberosServer::Step(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:ServerStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = authenticate_gss_server_step(state.get(), challenge.c_str()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local response = Nan::Null(); - if (state->response != NULL) { - response = Nan::New(state->response).ToLocalChecked(); + Napi::Value response = env.Null(); + if (state->response != nullptr) { + response = String::New(env, state->response); } - v8::Local argv[] = {Nan::Null(), response}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), response }); }); }); } /// Global Methods -NAN_METHOD(InitializeClient) { - std::string service(*Nan::Utf8String(info[0])); - v8::Local options = Nan::To(info[1]).ToLocalChecked(); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); - - std::string principal = StringOptionValue(options, "principal"); - uint32_t gss_flags = - UInt32OptionValue(options, "gssFlags", GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG); - uint32_t mech_oid_int = UInt32OptionValue(options, "mechOID", 0); +void InitializeClient(const CallbackInfo& info) { + std::string service = info[0].ToString(); + Object options = info[1].ToObject(); + Function callback = info[2].As(); + + std::string principal = ToStringWithNonStringAsEmpty(options["principal"]); + Value flags_v = options["flags"]; + uint32_t gss_flags = flags_v.IsNumber() ? flags_v.As().Uint32Value() : GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG; + Value mech_oid_v = options["mechOID"]; + uint32_t mech_oid_int = mech_oid_v.IsNumber() ? mech_oid_v.As().Uint32Value() : 0; gss_OID mech_oid = GSS_C_NO_OID; if (mech_oid_int == GSS_MECH_OID_KRB5) { mech_oid = &krb5_mech_oid; @@ -143,22 +148,22 @@ NAN_METHOD(InitializeClient) { service.c_str(), principal.c_str(), gss_flags, NULL, mech_oid, client_state.get()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), KerberosClient::NewInstance(client_state)}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), KerberosClient::NewInstance(env, client_state) }); }); }); } -NAN_METHOD(InitializeServer) { - std::string service(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void InitializeServer(const CallbackInfo& info) { + std::string service = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:InitializeServer", [=](KerberosWorker::SetOnFinishedHandler onFinished) { auto server_state = std::make_shared(); @@ -166,54 +171,54 @@ NAN_METHOD(InitializeServer) { authenticate_gss_server_init(service.c_str(), server_state.get()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), KerberosServer::NewInstance(server_state)}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), KerberosServer::NewInstance(env, server_state) }); }); }); } -NAN_METHOD(PrincipalDetails) { - std::string service(*Nan::Utf8String(info[0])); - std::string hostname(*Nan::Utf8String(info[1])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); +void PrincipalDetails(const CallbackInfo& info) { + std::string service = info[0].ToString(); + std::string hostname = info[1].ToString(); + Function callback = info[2].As(); KerberosWorker::Run(callback, "kerberos:PrincipalDetails", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = server_principal_details(service.c_str(), hostname.c_str()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), Nan::New(result.data.c_str()).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, result.data) }); }); }); } -NAN_METHOD(CheckPassword) { - std::string username(*Nan::Utf8String(info[0])); - std::string password(*Nan::Utf8String(info[1])); - std::string service(*Nan::Utf8String(info[2])); +void CheckPassword(const CallbackInfo& info) { + std::string username = info[0].ToString(); + std::string password = info[1].ToString(); + std::string service = info[2].ToString(); std::string defaultRealm; - Nan::Callback* callback; - if (info[3]->IsFunction()) { - callback = new Nan::Callback(Nan::To(info[3]).ToLocalChecked()); + Function callback; + if (info[3].IsFunction()) { + callback = info[3].As(); } else { - defaultRealm = *Nan::Utf8String(info[3]); - callback = new Nan::Callback(Nan::To(info[4]).ToLocalChecked()); + defaultRealm = info[3].ToString(); + callback = info[4].As(); } KerberosWorker::Run(callback, "kerberos:CheckPassword", [=](KerberosWorker::SetOnFinishedHandler onFinished) { @@ -221,14 +226,16 @@ NAN_METHOD(CheckPassword) { username.c_str(), password.c_str(), service.c_str(), defaultRealm.c_str()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); } else { - v8::Local argv[] = {Nan::Null(), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), env.Null() }); } }); }); } + +} diff --git a/src/win32/kerberos_sspi.cc b/src/win32/kerberos_sspi.cc index f000f4dd..5681efd6 100644 --- a/src/win32/kerberos_sspi.cc +++ b/src/win32/kerberos_sspi.cc @@ -2,6 +2,8 @@ #include #include "kerberos_sspi.h" +namespace node_kerberos { + static sspi_result sspi_success_result(INT ret); static sspi_result sspi_error_result(DWORD errCode, const SEC_CHAR* msg); static sspi_result sspi_error_result_with_message(const char* message); @@ -14,11 +16,11 @@ sspi_client_state::~sspi_client_state() { DeleteSecurityContext(&ctx); } if (haveCred) { - FreeCredentialsHandle(&state->cred); + FreeCredentialsHandle(&cred); } - free(state->spn); - free(state->response); - free(state->username); + free(spn); + free(response); + free(username); } sspi_result @@ -534,3 +536,5 @@ wide_to_utf8(WCHAR* value) { return NULL; } + +} diff --git a/src/win32/kerberos_sspi.h b/src/win32/kerberos_sspi.h index 680069e5..2683f278 100644 --- a/src/win32/kerberos_sspi.h +++ b/src/win32/kerberos_sspi.h @@ -23,6 +23,8 @@ #include #include +namespace node_kerberos { + #define AUTH_GSS_ERROR -1 #define AUTH_GSS_COMPLETE 1 #define AUTH_GSS_CONTINUE 0 @@ -58,7 +60,7 @@ struct sspi_server_state { WCHAR* username = nullptr; WCHAR* response = nullptr; BOOL context_complete = FALSE; - char* targetname; + char* targetname = nullptr; }; sspi_client_state* sspi_client_state_new(); @@ -78,4 +80,6 @@ sspi_result auth_sspi_client_step(sspi_client_state* state, SEC_CHAR* challenge, sspi_result auth_sspi_client_unwrap(sspi_client_state* state, SEC_CHAR* challenge); sspi_result auth_sspi_client_wrap(sspi_client_state* state, SEC_CHAR* data, SEC_CHAR* user, ULONG ulen, INT protect); +} + #endif diff --git a/src/win32/kerberos_win32.cc b/src/win32/kerberos_win32.cc index ebdee099..450ff1da 100644 --- a/src/win32/kerberos_win32.cc +++ b/src/win32/kerberos_win32.cc @@ -3,6 +3,20 @@ #include "../kerberos.h" #include "../kerberos_worker.h" +namespace node_kerberos { + +using namespace Napi; + +inline std::wstring ToWStringWithNonStringAsEmpty(Value value) { + static_assert(sizeof(std::wstring::value_type) == sizeof(std::u16string::value_type), + "wstring and u16string have the same value type on Windows"); + if (!value.IsString()) { + return std::wstring(); + } + std::u16string u16 = value.As(); + return std::wstring(u16.begin(), u16.end()); +} + #define GSS_MECH_OID_KRB5 9 #define GSS_MECH_OID_SPNEGO 6 #define GSS_MECH_OID_KRB5_STR L"Kerberos" @@ -12,89 +26,64 @@ #define GSS_C_REPLAY_FLAG 4 #define GSS_C_SEQUENCE_FLAG 8 -const std::wstring to_wstring(const char *bytes) { - DWORD sizeOfStr = MultiByteToWideChar(CP_UTF8, 0, bytes, -1, NULL, 0); - assert(sizeOfStr > 0); - std::wstring arg(sizeOfStr, '\0'); - DWORD result = MultiByteToWideChar(CP_UTF8, 0, bytes, -1, &arg[0], sizeOfStr); - assert(result > 0); - arg.resize(result - 1); - return arg; -} - -NAN_INLINE std::wstring WStringOptionValue(v8::Local options, const char* _key) { - Nan::HandleScope scope; - v8::Local key = Nan::New(_key).ToLocalChecked(); - if (options.IsEmpty() || !Nan::Has(options, key).FromMaybe(false)) { - return std::wstring(); - } - - v8::Local value = Nan::Get(options, key).ToLocalChecked(); - if (!value->IsString()) { - return std::wstring(); - } - - return to_wstring(*(Nan::Utf8String(value))); -} - /// KerberosClient -NAN_METHOD(KerberosClient::Step) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void KerberosClient::Step(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:ClientStep", [=](KerberosWorker::SetOnFinishedHandler onFinished) { sspi_result result = auth_sspi_client_step(state.get(), (SEC_CHAR*)challenge.c_str(), NULL); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local response = Nan::Null(); - if (state->response != NULL) { - response = Nan::New(state->response).ToLocalChecked(); + Napi::Value response = env.Null(); + if (state->response != nullptr) { + response = String::New(env, state->response); } - v8::Local argv[] = {Nan::Null(), response}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), response }); }); }); } -NAN_METHOD(KerberosClient::UnwrapData) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[1]).ToLocalChecked()); +void KerberosClient::UnwrapData(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Function callback = info[1].As(); KerberosWorker::Run(callback, "kerberos:ClientUnwrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { sspi_result result = auth_sspi_client_unwrap(state.get(), (SEC_CHAR*)challenge.c_str()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, state->response) }); }); }); } -NAN_METHOD(KerberosClient::WrapData) { - auto state = Nan::ObjectWrap::Unwrap(info.This())->state(); - std::string challenge(*Nan::Utf8String(info[0])); - v8::Local options = Nan::To(info[1]).ToLocalChecked(); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); - std::string user = StringOptionValue(options, "user"); +void KerberosClient::WrapData(const CallbackInfo& info) { + auto state = this->state(); + std::string challenge = info[0].ToString(); + Object options = info[1].ToObject(); + Function callback = info[2].As(); + std::string user = ToStringWithNonStringAsEmpty(options["user"]); int protect = 0; // NOTE: this should be an option KerberosWorker::Run(callback, "kerberos:ClientWrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { @@ -102,36 +91,38 @@ NAN_METHOD(KerberosClient::WrapData) { state.get(), (SEC_CHAR*)challenge.c_str(), (SEC_CHAR*)user.c_str(), user.length(), protect); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), Nan::New(state->response).ToLocalChecked()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), String::New(env, state->response) }); }); }); } /// KerberosServer -NAN_METHOD(KerberosServer::Step) { - Nan::ThrowError("`KerberosServer::Step` is not implemented yet for windows"); +void KerberosServer::Step(const CallbackInfo& info) { + throw Error::New(info.Env(), "`KerberosServer::Step` is not implemented yet for windows"); } /// Global Methods -NAN_METHOD(InitializeClient) { - std::wstring service = to_wstring(*(Nan::Utf8String(info[0]))); - v8::Local options = Nan::To(info[1]).ToLocalChecked(); - Nan::Callback* callback = new Nan::Callback(Nan::To(info[2]).ToLocalChecked()); - - std::wstring user = WStringOptionValue(options, "user"); - std::wstring domain = WStringOptionValue(options, "domain"); - std::wstring password = WStringOptionValue(options, "password"); - ULONG gss_flags = (ULONG)UInt32OptionValue(options, "flags", GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG); - uint32_t mech_oid_int = UInt32OptionValue(options, "mechOID", 0); +void InitializeClient(const CallbackInfo& info) { + std::wstring service = ToWStringWithNonStringAsEmpty(info[0]); + Object options = info[1].ToObject(); + Function callback = info[2].As(); + + std::wstring user = ToWStringWithNonStringAsEmpty(options["user"]); + std::wstring domain = ToWStringWithNonStringAsEmpty(options["domain"]); + std::wstring password = ToWStringWithNonStringAsEmpty(options["password"]); + Value flags_v = options["flags"]; + ULONG gss_flags = flags_v.IsNumber() ? flags_v.As().Uint32Value() : GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG; + Value mech_oid_v = options["mechOID"]; + uint32_t mech_oid_int = mech_oid_v.IsNumber() ? mech_oid_v.As().Uint32Value() : 0; std::wstring mech_oid = GSS_MECH_OID_KRB5_STR; if (mech_oid_int == GSS_MECH_OID_SPNEGO) { mech_oid = GSS_MECH_OID_SPNEGO_STR; @@ -145,27 +136,29 @@ NAN_METHOD(InitializeClient) { (WCHAR*)mech_oid.c_str(), client_state.get()); return onFinished([=](KerberosWorker* worker) { - Nan::HandleScope scope; + Napi::Env env = worker->Env(); if (result.code == AUTH_GSS_ERROR) { - v8::Local argv[] = {Nan::Error(result.message.c_str()), Nan::Null()}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { Error::New(env, result.message).Value(), env.Null() }); return; } - v8::Local argv[] = {Nan::Null(), KerberosClient::NewInstance(client_state)}; - worker->Call(2, argv); + worker->Call(std::initializer_list + { env.Null(), KerberosClient::NewInstance(env, client_state) }); }); }); } -NAN_METHOD(InitializeServer) { - Nan::ThrowError("`initializeServer` is not implemented yet for windows"); +void InitializeServer(const CallbackInfo& info) { + throw Error::New(info.Env(), "`initializeServer` is not implemented yet for windows"); +} + +void PrincipalDetails(const CallbackInfo& info) { + throw Error::New(info.Env(), "`principalDetails` is not implemented yet for windows"); } -NAN_METHOD(PrincipalDetails) { - Nan::ThrowError("`principalDetails` is not implemented yet for windows"); +void CheckPassword(const CallbackInfo& info) { + throw Error::New(info.Env(), "`checkPassword` is not implemented yet for windows"); } -NAN_METHOD(CheckPassword) { - Nan::ThrowError("`checkPassword` is not implemented yet for windows"); } From bf156e9c49ef96ed2a632aa292f7ffca6b280c54 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Thu, 30 Sep 2021 13:56:59 +0200 Subject: [PATCH 3/3] fixup: std::move() for NewInstance --- src/unix/kerberos_unix.cc | 4 ++-- src/win32/kerberos_win32.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unix/kerberos_unix.cc b/src/unix/kerberos_unix.cc index ba252a4d..57a67ae8 100644 --- a/src/unix/kerberos_unix.cc +++ b/src/unix/kerberos_unix.cc @@ -156,7 +156,7 @@ void InitializeClient(const CallbackInfo& info) { } worker->Call(std::initializer_list - { env.Null(), KerberosClient::NewInstance(env, client_state) }); + { env.Null(), KerberosClient::NewInstance(env, std::move(client_state)) }); }); }); } @@ -179,7 +179,7 @@ void InitializeServer(const CallbackInfo& info) { } worker->Call(std::initializer_list - { env.Null(), KerberosServer::NewInstance(env, server_state) }); + { env.Null(), KerberosServer::NewInstance(env, std::move(server_state)) }); }); }); } diff --git a/src/win32/kerberos_win32.cc b/src/win32/kerberos_win32.cc index 450ff1da..c37b7eb6 100644 --- a/src/win32/kerberos_win32.cc +++ b/src/win32/kerberos_win32.cc @@ -144,7 +144,7 @@ void InitializeClient(const CallbackInfo& info) { } worker->Call(std::initializer_list - { env.Null(), KerberosClient::NewInstance(env, client_state) }); + { env.Null(), KerberosClient::NewInstance(env, std::move(client_state)) }); }); }); }