4 * Copyright (C) Simo Sorce 2010.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "../libcli/auth/spnego.h"
22 #include "include/ntlmssp_wrap.h"
23 #include "librpc/gen_ndr/ntlmssp.h"
24 #include "auth/ntlmssp/ntlmssp.h"
25 #include "librpc/crypto/gse.h"
26 #include "librpc/crypto/spnego.h"
28 static NTSTATUS spnego_context_init(TALLOC_CTX *mem_ctx,
29 bool do_sign, bool do_seal,
30 struct spnego_context **spnego_ctx)
32 struct spnego_context *sp_ctx;
34 sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
36 return NT_STATUS_NO_MEMORY;
39 sp_ctx->do_sign = do_sign;
40 sp_ctx->do_seal = do_seal;
41 sp_ctx->state = SPNEGO_CONV_INIT;
47 NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx,
48 bool do_sign, bool do_seal,
50 const char *ccache_name,
55 struct spnego_context **spnego_ctx)
57 struct spnego_context *sp_ctx = NULL;
58 uint32_t add_gss_c_flags = 0;
61 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
62 if (!NT_STATUS_IS_OK(status)) {
65 sp_ctx->mech = SPNEGO_KRB5;
68 add_gss_c_flags = GSS_C_DCE_STYLE;
71 status = gse_init_client(sp_ctx,
73 ccache_name, server, service,
74 username, password, add_gss_c_flags,
75 &sp_ctx->mech_ctx.gssapi_state);
76 if (!NT_STATUS_IS_OK(status)) {
85 NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx,
86 bool do_sign, bool do_seal,
91 struct spnego_context **spnego_ctx)
93 struct spnego_context *sp_ctx = NULL;
96 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
97 if (!NT_STATUS_IS_OK(status)) {
100 sp_ctx->mech = SPNEGO_NTLMSSP;
102 status = auth_ntlmssp_client_start(sp_ctx,
105 lp_client_ntlmv2_auth(),
106 &sp_ctx->mech_ctx.ntlmssp_state);
107 if (!NT_STATUS_IS_OK(status)) {
112 status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state,
114 if (!NT_STATUS_IS_OK(status)) {
119 status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state,
121 if (!NT_STATUS_IS_OK(status)) {
126 status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state,
128 if (!NT_STATUS_IS_OK(status)) {
134 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
135 NTLMSSP_FEATURE_SIGN);
136 } else if (do_seal) {
137 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
138 NTLMSSP_FEATURE_SEAL);
141 *spnego_ctx = sp_ctx;
145 NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
146 struct spnego_context *sp_ctx,
147 DATA_BLOB *spnego_in,
148 DATA_BLOB *spnego_out)
150 struct gse_context *gse_ctx;
151 struct auth_ntlmssp_state *ntlmssp_ctx;
152 struct spnego_data sp_in, sp_out;
153 DATA_BLOB token_in = data_blob_null;
154 DATA_BLOB token_out = data_blob_null;
155 const char *mech_oids[2] = { NULL, NULL };
156 char *principal = NULL;
159 bool mech_wants_more = false;
162 if (!spnego_in->length) {
163 /* server didn't send anything, is init ? */
164 if (sp_ctx->state != SPNEGO_CONV_INIT) {
165 return NT_STATUS_INVALID_PARAMETER;
168 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
170 status = NT_STATUS_INVALID_PARAMETER;
173 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
174 status = NT_STATUS_INVALID_PARAMETER;
177 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
178 status = NT_STATUS_ACCESS_DENIED;
181 token_in = sp_in.negTokenTarg.responseToken;
184 if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
185 if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
186 sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
187 *spnego_out = data_blob_null;
188 status = NT_STATUS_OK;
190 status = NT_STATUS_ACCESS_DENIED;
195 switch (sp_ctx->mech) {
198 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
199 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
200 &token_in, &token_out);
201 if (!NT_STATUS_IS_OK(status)) {
205 mech_oids[0] = OID_KERBEROS5;
206 mech_wants_more = gse_require_more_processing(gse_ctx);
212 ntlmssp_ctx = sp_ctx->mech_ctx.ntlmssp_state;
213 status = auth_ntlmssp_update(ntlmssp_ctx, mem_ctx,
214 token_in, &token_out);
215 if (NT_STATUS_EQUAL(status,
216 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
217 mech_wants_more = true;
218 } else if (!NT_STATUS_IS_OK(status)) {
222 mech_oids[0] = OID_NTLMSSP;
227 status = NT_STATUS_INTERNAL_ERROR;
231 switch (sp_ctx->state) {
232 case SPNEGO_CONV_INIT:
233 *spnego_out = spnego_gen_negTokenInit(mem_ctx, mech_oids,
234 &token_out, principal);
235 if (!spnego_out->data) {
236 status = NT_STATUS_INTERNAL_ERROR;
239 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
242 case SPNEGO_CONV_AUTH_MORE:
243 /* server says it's done and we do not seem to agree */
244 if (sp_in.negTokenTarg.negResult ==
245 SPNEGO_ACCEPT_COMPLETED) {
246 status = NT_STATUS_INVALID_PARAMETER;
250 sp_out.type = SPNEGO_NEG_TOKEN_TARG;
251 sp_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
252 sp_out.negTokenTarg.supportedMech = NULL;
253 sp_out.negTokenTarg.responseToken = token_out;
254 sp_out.negTokenTarg.mechListMIC = data_blob_null;
256 len_out = spnego_write_data(mem_ctx, spnego_out, &sp_out);
258 status = NT_STATUS_INTERNAL_ERROR;
262 if (!mech_wants_more) {
263 /* we still need to get an ack from the server */
264 sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
270 status = NT_STATUS_INTERNAL_ERROR;
274 status = NT_STATUS_OK;
278 spnego_free_data(&sp_in);
280 data_blob_free(&token_out);
284 bool spnego_require_more_processing(struct spnego_context *sp_ctx)
286 struct gse_context *gse_ctx;
288 /* see if spnego processing itself requires more */
289 if (sp_ctx->state == SPNEGO_CONV_AUTH_MORE ||
290 sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
294 /* otherwise see if underlying mechnism does */
295 switch (sp_ctx->mech) {
297 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
298 return gse_require_more_processing(gse_ctx);
302 DEBUG(0, ("Unsupported type in request!\n"));
307 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
308 enum spnego_mech *type,
311 switch (sp_ctx->mech) {
313 *auth_context = sp_ctx->mech_ctx.gssapi_state;
316 *auth_context = sp_ctx->mech_ctx.ntlmssp_state;
319 return NT_STATUS_INTERNAL_ERROR;
322 *type = sp_ctx->mech;
326 DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
327 struct spnego_context *sp_ctx)
329 switch (sp_ctx->mech) {
331 return gse_get_session_key(mem_ctx,
332 sp_ctx->mech_ctx.gssapi_state);
334 return auth_ntlmssp_get_session_key(
335 sp_ctx->mech_ctx.ntlmssp_state, mem_ctx);
337 DEBUG(0, ("Unsupported type in request!\n"));
338 return data_blob_null;
342 NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
343 struct spnego_context *sp_ctx,
344 DATA_BLOB *data, DATA_BLOB *full_data,
345 DATA_BLOB *signature)
347 switch(sp_ctx->mech) {
349 return gse_sign(mem_ctx,
350 sp_ctx->mech_ctx.gssapi_state,
353 return auth_ntlmssp_sign_packet(
354 sp_ctx->mech_ctx.ntlmssp_state,
356 data->data, data->length,
357 full_data->data, full_data->length,
360 return NT_STATUS_INVALID_PARAMETER;
364 NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
365 struct spnego_context *sp_ctx,
366 DATA_BLOB *data, DATA_BLOB *full_data,
367 DATA_BLOB *signature)
369 switch(sp_ctx->mech) {
371 return gse_sigcheck(mem_ctx,
372 sp_ctx->mech_ctx.gssapi_state,
375 return auth_ntlmssp_check_packet(
376 sp_ctx->mech_ctx.ntlmssp_state,
377 data->data, data->length,
378 full_data->data, full_data->length,
381 return NT_STATUS_INVALID_PARAMETER;
385 NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
386 struct spnego_context *sp_ctx,
387 DATA_BLOB *data, DATA_BLOB *full_data,
388 DATA_BLOB *signature)
390 switch(sp_ctx->mech) {
392 return gse_seal(mem_ctx,
393 sp_ctx->mech_ctx.gssapi_state,
396 return auth_ntlmssp_seal_packet(
397 sp_ctx->mech_ctx.ntlmssp_state,
399 data->data, data->length,
400 full_data->data, full_data->length,
403 return NT_STATUS_INVALID_PARAMETER;
407 NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
408 struct spnego_context *sp_ctx,
409 DATA_BLOB *data, DATA_BLOB *full_data,
410 DATA_BLOB *signature)
412 switch(sp_ctx->mech) {
414 return gse_unseal(mem_ctx,
415 sp_ctx->mech_ctx.gssapi_state,
418 return auth_ntlmssp_unseal_packet(
419 sp_ctx->mech_ctx.ntlmssp_state,
420 data->data, data->length,
421 full_data->data, full_data->length,
424 return NT_STATUS_INVALID_PARAMETER;