Skip to content

Commit 6a40301

Browse files
committed
feat(sspi): introduce client initialization for SSPI
1 parent 2ede690 commit 6a40301

File tree

3 files changed

+227
-11
lines changed

3 files changed

+227
-11
lines changed

src/kerberos_server.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,21 @@ NAN_GETTER(KerberosServer::UserNameGetter) {
4141
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
4242
(server->_state->username == NULL)
4343
? info.GetReturnValue().Set(Nan::Null())
44-
: info.GetReturnValue().Set(Nan::New(server->_state->username).ToLocalChecked());
44+
: info.GetReturnValue().Set(Nan::New((char*)server->_state->username).ToLocalChecked());
4545
}
4646

4747
NAN_GETTER(KerberosServer::ResponseGetter) {
4848
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
4949
(server->_state->response == NULL)
5050
? info.GetReturnValue().Set(Nan::Null())
51-
: info.GetReturnValue().Set(Nan::New(server->_state->response).ToLocalChecked());
51+
: info.GetReturnValue().Set(Nan::New((char*)server->_state->response).ToLocalChecked());
5252
}
5353

5454
NAN_GETTER(KerberosServer::TargetNameGetter) {
5555
KerberosServer* server = Nan::ObjectWrap::Unwrap<KerberosServer>(info.This());
5656
(server->_state->targetname == NULL)
5757
? info.GetReturnValue().Set(Nan::Null())
58-
: info.GetReturnValue().Set(Nan::New(server->_state->targetname).ToLocalChecked());
58+
: info.GetReturnValue().Set(Nan::New((char*)server->_state->targetname).ToLocalChecked());
5959
}
6060

6161
NAN_GETTER(KerberosServer::ContextCompleteGetter) {

src/win32/kerberos_sspi.c

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include "kerberos_sspi.h"
2+
3+
static sspi_result* sspi_success_result(INT ret);
4+
static sspi_result* sspi_error_result(DWORD errCode, const SEC_CHAR* msg);
5+
static sspi_result* sspi_error_result_with_message(WCHAR* message);
6+
static sspi_result* sspi_error_result_with_message_and_code(WCHAR* mesage, INT code);
7+
8+
sspi_client_state* sspi_client_state_new() {
9+
sspi_client_state* state = (sspi_client_state*)malloc(sizeof(sspi_client_state));
10+
state->username = NULL;
11+
state->response = NULL;
12+
state->responseConf = 0;
13+
state->context_complete = FALSE;
14+
15+
return state;
16+
}
17+
18+
// sspi_server_state* sspi_server_state_new() {
19+
// sspi_server_state* state = (sspi_server_state*)malloc(sizeof(sspi_server_state));
20+
// state->username = NULL;
21+
// state->response = NULL;
22+
// state->targetname = NULL;
23+
// state->context_complete = false;
24+
25+
// return state;
26+
// }
27+
28+
VOID
29+
auth_sspi_client_clean(sspi_client_state* state) {
30+
if (state->haveCtx) {
31+
DeleteSecurityContext(&state->ctx);
32+
state->haveCtx = 0;
33+
}
34+
if (state->haveCred) {
35+
FreeCredentialsHandle(&state->cred);
36+
state->haveCred = 0;
37+
}
38+
if (state->spn != NULL) {
39+
free(state->spn);
40+
state->spn = NULL;
41+
}
42+
if (state->response != NULL) {
43+
free(state->response);
44+
state->response = NULL;
45+
}
46+
if (state->username != NULL) {
47+
free(state->username);
48+
state->username = NULL;
49+
}
50+
}
51+
52+
sspi_result*
53+
auth_sspi_client_init(WCHAR* service,
54+
ULONG flags,
55+
WCHAR* user,
56+
ULONG ulen,
57+
WCHAR* domain,
58+
ULONG dlen,
59+
WCHAR* password,
60+
ULONG plen,
61+
WCHAR* mechoid,
62+
sspi_client_state* state) {
63+
SECURITY_STATUS status;
64+
SEC_WINNT_AUTH_IDENTITY_W authIdentity;
65+
TimeStamp ignored;
66+
67+
state->response = NULL;
68+
state->username = NULL;
69+
state->qop = SECQOP_WRAP_NO_ENCRYPT;
70+
state->flags = flags;
71+
state->haveCred = 0;
72+
state->haveCtx = 0;
73+
state->spn = _wcsdup(service);
74+
if (state->spn == NULL) {
75+
return sspi_error_result_with_message("Ran out of memory assigning service");
76+
}
77+
78+
/* Convert RFC-2078 format to SPN */
79+
if (!wcschr(state->spn, L'/')) {
80+
WCHAR* ptr = wcschr(state->spn, L'@');
81+
if (ptr) {
82+
*ptr = L'/';
83+
}
84+
}
85+
86+
if (user) {
87+
authIdentity.User = user;
88+
authIdentity.UserLength = ulen;
89+
authIdentity.Domain = domain;
90+
authIdentity.DomainLength = dlen;
91+
authIdentity.Password = password;
92+
authIdentity.PasswordLength = plen;
93+
authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
94+
}
95+
96+
/* Note that the first paramater, pszPrincipal, appears to be
97+
* completely ignored in the Kerberos SSP. For more details see
98+
* https://github.com/mongodb-labs/winkerberos/issues/11.
99+
* */
100+
status = AcquireCredentialsHandleW(/* Principal */
101+
NULL,
102+
/* Security package name */
103+
mechoid,
104+
/* Credentials Use */
105+
SECPKG_CRED_OUTBOUND,
106+
/* LogonID (We don't use this) */
107+
NULL,
108+
/* AuthData */
109+
user ? &authIdentity : NULL,
110+
/* Always NULL */
111+
NULL,
112+
/* Always NULL */
113+
NULL,
114+
/* CredHandle */
115+
&state->cred,
116+
/* Expiry (Required but unused by us) */
117+
&ignored);
118+
if (status != SEC_E_OK) {
119+
return sspi_error_result(status, "AcquireCredentialsHandle");
120+
}
121+
122+
state->haveCred = 1;
123+
return sspi_success_result(AUTH_SSPI_COMPLETE);
124+
}
125+
126+
static sspi_result* sspi_success_result(int ret) {
127+
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
128+
result->code = ret;
129+
result->message = NULL;
130+
return result;
131+
}
132+
133+
static sspi_result* sspi_error_result(DWORD errCode, const SEC_CHAR* msg) {
134+
SEC_CHAR* err;
135+
DWORD status;
136+
DWORD flags = (FORMAT_MESSAGE_ALLOCATE_BUFFER |
137+
FORMAT_MESSAGE_FROM_SYSTEM |
138+
FORMAT_MESSAGE_IGNORE_INSERTS);
139+
status = FormatMessageA(flags,
140+
NULL,
141+
errCode,
142+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
143+
(LPTSTR)&err,
144+
0,
145+
NULL);
146+
147+
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
148+
result->code = AUTH_SSPI_ERROR;
149+
result->message = (WCHAR*)malloc(sizeof(WCHAR) * 1024 + 2);
150+
if (status) {
151+
swprintf(result->message, "%s: %s", msg, err);
152+
} else {
153+
swprintf(result->message, "%s", msg);
154+
}
155+
156+
return result;
157+
}
158+
159+
static sspi_result* sspi_error_result_with_message(WCHAR* message) {
160+
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
161+
result->code = AUTH_SSPI_ERROR;
162+
result->message = _wcsdup(message);
163+
return result;
164+
}
165+
166+
static sspi_result* sspi_error_result_with_message_and_code(WCHAR* message, INT code) {
167+
sspi_result* result = (sspi_result*)malloc(sizeof(sspi_result));
168+
result->code = AUTH_SSPI_ERROR;
169+
result->message = (WCHAR*)malloc(wcslen(message) + 20);
170+
swprintf(result->message, "%s (%d)", message, code);
171+
return result;
172+
}

src/win32/kerberos_sspi.h

+52-8
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,67 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
17+
#define SECURITY_WIN32 1 /* Required for SSPI */
18+
19+
#include <windef.h>
20+
#include <windows.h>
21+
#include <sspi.h>
22+
23+
#define AUTH_SSPI_ERROR -1
24+
#define AUTH_SSPI_COMPLETE 1
25+
#define AUTH_SSPI_CONTINUE 0
26+
27+
#define GSS_MECH_OID_KRB5 L"Kerberos"
28+
#define GSS_MECH_OID_SPNEGO L"Negotiate"
29+
1730
typedef struct {
1831
INT code;
1932
WCHAR* message;
2033
WCHAR* data;
2134
} sspi_result;
2235

2336
typedef struct {
24-
char* username;
25-
char* response;
26-
int responseConf;
27-
bool context_complete;
37+
CredHandle cred;
38+
CtxtHandle ctx;
39+
WCHAR* spn;
40+
SEC_CHAR* response;
41+
SEC_CHAR* username;
42+
ULONG flags;
43+
UCHAR haveCred;
44+
UCHAR haveCtx;
45+
ULONG qop;
46+
47+
INT responseConf;
48+
BOOL context_complete;
2849
} sspi_client_state;
2950

3051
typedef struct {
31-
char* username;
52+
WCHAR* username;
53+
WCHAR* response;
54+
BOOL context_complete;
3255
char* targetname;
33-
char* response;
34-
bool context_complete;
3556
} sspi_server_state;
57+
58+
sspi_client_state* sspi_client_state_new();
59+
// sspi_server_state* sspi_server_state_new();
60+
61+
VOID auth_sspi_client_clean(sspi_client_state* state);
62+
sspi_result* auth_sspi_client_init(WCHAR* service,
63+
ULONG flags,
64+
WCHAR* user,
65+
ULONG ulen,
66+
WCHAR* domain,
67+
ULONG dlen,
68+
WCHAR* password,
69+
ULONG plen,
70+
WCHAR* mechoid,
71+
sspi_client_state* state);
72+
73+
sspi_result* auth_sspi_client_step(sspi_client_state* state, SEC_CHAR* challenge, SecPkgContext_Bindings* sec_pkg_context_bindings);
74+
// INT auth_sspi_client_unwrap(sspi_client_state* state, SEC_CHAR* challenge);
75+
// INT auth_sspi_client_wrap(sspi_client_state* state,
76+
// SEC_CHAR* data,
77+
// SEC_CHAR* user,
78+
// ULONG ulen,
79+
// INT protect);

0 commit comments

Comments
 (0)