Skip to content
Permalink
Browse files

feat(sspi): introduce client initialization for SSPI

  • Loading branch information
mbroadst committed Jul 12, 2018
1 parent 2ede690 commit 6a403014ec4b83e9730e17527a222b483a3c648e
Showing with 227 additions and 11 deletions.
  1. +3 −3 src/kerberos_server.cc
  2. +172 −0 src/win32/kerberos_sspi.c
  3. +52 −8 src/win32/kerberos_sspi.h
@@ -41,21 +41,21 @@ NAN_GETTER(KerberosServer::UserNameGetter) {
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
(server->_state->username == NULL)
? info.GetReturnValue().Set(Nan::Null())
: info.GetReturnValue().Set(Nan::New(server->_state->username).ToLocalChecked());
: info.GetReturnValue().Set(Nan::New((char*)server->_state->username).ToLocalChecked());
}

NAN_GETTER(KerberosServer::ResponseGetter) {
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
(server->_state->response == NULL)
? info.GetReturnValue().Set(Nan::Null())
: info.GetReturnValue().Set(Nan::New(server->_state->response).ToLocalChecked());
: info.GetReturnValue().Set(Nan::New((char*)server->_state->response).ToLocalChecked());
}

NAN_GETTER(KerberosServer::TargetNameGetter) {
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
(server->_state->targetname == NULL)
? info.GetReturnValue().Set(Nan::Null())
: info.GetReturnValue().Set(Nan::New(server->_state->targetname).ToLocalChecked());
: info.GetReturnValue().Set(Nan::New((char*)server->_state->targetname).ToLocalChecked());
}

NAN_GETTER(KerberosServer::ContextCompleteGetter) {
@@ -0,0 +1,172 @@
#include "kerberos_sspi.h"

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(WCHAR* message);
static sspi_result* sspi_error_result_with_message_and_code(WCHAR* mesage, INT code);

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

// sspi_server_state* sspi_server_state_new() {
// sspi_server_state* state = (sspi_server_state*)malloc(sizeof(sspi_server_state));
// state->username = NULL;
// state->response = NULL;
// state->targetname = NULL;
// state->context_complete = false;

// return state;
// }

VOID
auth_sspi_client_clean(sspi_client_state* state) {
if (state->haveCtx) {
DeleteSecurityContext(&state->ctx);
state->haveCtx = 0;
}
if (state->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;
}
}

sspi_result*
auth_sspi_client_init(WCHAR* service,
ULONG flags,
WCHAR* user,
ULONG ulen,
WCHAR* domain,
ULONG dlen,
WCHAR* password,
ULONG plen,
WCHAR* mechoid,
sspi_client_state* state) {
SECURITY_STATUS status;
SEC_WINNT_AUTH_IDENTITY_W authIdentity;
TimeStamp ignored;

state->response = NULL;
state->username = NULL;
state->qop = SECQOP_WRAP_NO_ENCRYPT;
state->flags = flags;
state->haveCred = 0;
state->haveCtx = 0;
state->spn = _wcsdup(service);
if (state->spn == NULL) {
return sspi_error_result_with_message("Ran out of memory assigning service");
}

/* Convert RFC-2078 format to SPN */
if (!wcschr(state->spn, L'/')) {
WCHAR* ptr = wcschr(state->spn, L'@');
if (ptr) {
*ptr = L'/';
}
}

if (user) {
authIdentity.User = user;
authIdentity.UserLength = ulen;
authIdentity.Domain = domain;
authIdentity.DomainLength = dlen;
authIdentity.Password = password;
authIdentity.PasswordLength = plen;
authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
}

/* Note that the first paramater, pszPrincipal, appears to be
* completely ignored in the Kerberos SSP. For more details see
* https://github.com/mongodb-labs/winkerberos/issues/11.
* */
status = AcquireCredentialsHandleW(/* Principal */
NULL,
/* Security package name */
mechoid,
/* Credentials Use */
SECPKG_CRED_OUTBOUND,
/* LogonID (We don't use this) */
NULL,
/* AuthData */
user ? &authIdentity : NULL,
/* Always NULL */
NULL,
/* Always NULL */
NULL,
/* CredHandle */
&state->cred,
/* Expiry (Required but unused by us) */
&ignored);
if (status != SEC_E_OK) {
return sspi_error_result(status, "AcquireCredentialsHandle");
}

state->haveCred = 1;
return sspi_success_result(AUTH_SSPI_COMPLETE);
}

static sspi_result* sspi_success_result(int ret) {
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
result->code = ret;
result->message = NULL;
return result;
}

static sspi_result* sspi_error_result(DWORD errCode, const SEC_CHAR* msg) {
SEC_CHAR* err;
DWORD status;
DWORD flags = (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS);
status = FormatMessageA(flags,
NULL,
errCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&err,
0,
NULL);

sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
result->code = AUTH_SSPI_ERROR;
result->message = (WCHAR*)malloc(sizeof(WCHAR) * 1024 + 2);
if (status) {
swprintf(result->message, "%s: %s", msg, err);
} else {
swprintf(result->message, "%s", msg);
}

return result;
}

static sspi_result* sspi_error_result_with_message(WCHAR* message) {
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
result->code = AUTH_SSPI_ERROR;
result->message = _wcsdup(message);
return result;
}

static sspi_result* sspi_error_result_with_message_and_code(WCHAR* message, INT code) {
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
result->code = AUTH_SSPI_ERROR;
result->message = (WCHAR*)malloc(wcslen(message) + 20);
swprintf(result->message, "%s (%d)", message, code);
return result;
}
@@ -13,23 +13,67 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/


#define SECURITY_WIN32 1 /* Required for SSPI */

#include <windef.h>
#include <windows.h>
#include <sspi.h>

#define AUTH_SSPI_ERROR -1
#define AUTH_SSPI_COMPLETE 1
#define AUTH_SSPI_CONTINUE 0

#define GSS_MECH_OID_KRB5 L"Kerberos"
#define GSS_MECH_OID_SPNEGO L"Negotiate"

typedef struct {
INT code;
WCHAR* message;
WCHAR* data;
} sspi_result;

typedef struct {
char* username;
char* response;
int responseConf;
bool context_complete;
CredHandle cred;
CtxtHandle ctx;
WCHAR* spn;
SEC_CHAR* response;
SEC_CHAR* username;
ULONG flags;
UCHAR haveCred;
UCHAR haveCtx;
ULONG qop;

INT responseConf;
BOOL context_complete;
} sspi_client_state;

typedef struct {
char* username;
WCHAR* username;
WCHAR* response;
BOOL context_complete;
char* targetname;
char* response;
bool context_complete;
} sspi_server_state;

sspi_client_state* sspi_client_state_new();
// sspi_server_state* sspi_server_state_new();

VOID auth_sspi_client_clean(sspi_client_state* state);
sspi_result* auth_sspi_client_init(WCHAR* service,
ULONG flags,
WCHAR* user,
ULONG ulen,
WCHAR* domain,
ULONG dlen,
WCHAR* password,
ULONG plen,
WCHAR* mechoid,
sspi_client_state* state);

sspi_result* auth_sspi_client_step(sspi_client_state* state, SEC_CHAR* challenge, SecPkgContext_Bindings* sec_pkg_context_bindings);
// INT auth_sspi_client_unwrap(sspi_client_state* state, SEC_CHAR* challenge);
// INT auth_sspi_client_wrap(sspi_client_state* state,
// SEC_CHAR* data,
// SEC_CHAR* user,
// ULONG ulen,
// INT protect);

0 comments on commit 6a40301

Please sign in to comment.
You can’t perform that action at this time.