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"
27 #include "auth/gensec/gensec.h"
29 static NTSTATUS spnego_context_init(TALLOC_CTX *mem_ctx,
30 bool do_sign, bool do_seal,
31 struct spnego_context **spnego_ctx)
33 struct spnego_context *sp_ctx;
35 sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
37 return NT_STATUS_NO_MEMORY;
40 sp_ctx->do_sign = do_sign;
41 sp_ctx->do_seal = do_seal;
42 sp_ctx->state = SPNEGO_CONV_INIT;
48 NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx,
49 bool do_sign, bool do_seal,
51 const char *ccache_name,
56 struct spnego_context **spnego_ctx)
58 struct spnego_context *sp_ctx = NULL;
59 uint32_t add_gss_c_flags = 0;
62 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
63 if (!NT_STATUS_IS_OK(status)) {
66 sp_ctx->mech = SPNEGO_KRB5;
69 add_gss_c_flags = GSS_C_DCE_STYLE;
72 status = gse_init_client(sp_ctx,
74 ccache_name, server, service,
75 username, password, add_gss_c_flags,
76 &sp_ctx->mech_ctx.gssapi_state);
77 if (!NT_STATUS_IS_OK(status)) {
86 NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx,
87 bool do_sign, bool do_seal,
92 struct spnego_context **spnego_ctx)
94 struct spnego_context *sp_ctx = NULL;
97 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
98 if (!NT_STATUS_IS_OK(status)) {
101 sp_ctx->mech = SPNEGO_NTLMSSP;
103 status = auth_ntlmssp_client_prepare(sp_ctx,
104 &sp_ctx->mech_ctx.ntlmssp_state);
105 if (!NT_STATUS_IS_OK(status)) {
110 status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state,
112 if (!NT_STATUS_IS_OK(status)) {
117 status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state,
119 if (!NT_STATUS_IS_OK(status)) {
124 status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state,
126 if (!NT_STATUS_IS_OK(status)) {
132 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
133 NTLMSSP_FEATURE_SIGN);
134 } else if (do_seal) {
135 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
136 NTLMSSP_FEATURE_SEAL);
139 status = auth_ntlmssp_client_start(sp_ctx->mech_ctx.ntlmssp_state);
140 if (!NT_STATUS_IS_OK(status)) {
145 *spnego_ctx = sp_ctx;
149 NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
150 struct spnego_context *sp_ctx,
151 DATA_BLOB *spnego_in,
152 DATA_BLOB *spnego_out)
154 struct gse_context *gse_ctx;
155 struct auth_ntlmssp_state *ntlmssp_ctx;
156 struct spnego_data sp_in, sp_out;
157 DATA_BLOB token_in = data_blob_null;
158 DATA_BLOB token_out = data_blob_null;
159 const char *mech_oids[2] = { NULL, NULL };
160 char *principal = NULL;
163 bool mech_wants_more = false;
166 if (!spnego_in->length) {
167 /* server didn't send anything, is init ? */
168 if (sp_ctx->state != SPNEGO_CONV_INIT) {
169 return NT_STATUS_INVALID_PARAMETER;
172 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
174 status = NT_STATUS_INVALID_PARAMETER;
177 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
178 status = NT_STATUS_INVALID_PARAMETER;
181 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
182 status = NT_STATUS_ACCESS_DENIED;
185 token_in = sp_in.negTokenTarg.responseToken;
188 if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
189 if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
190 sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
191 *spnego_out = data_blob_null;
192 status = NT_STATUS_OK;
194 status = NT_STATUS_ACCESS_DENIED;
199 switch (sp_ctx->mech) {
202 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
203 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
204 &token_in, &token_out);
205 if (!NT_STATUS_IS_OK(status)) {
209 mech_oids[0] = OID_KERBEROS5;
210 mech_wants_more = gse_require_more_processing(gse_ctx);
216 ntlmssp_ctx = sp_ctx->mech_ctx.ntlmssp_state;
217 status = gensec_update(ntlmssp_ctx->gensec_security, mem_ctx, NULL,
218 token_in, &token_out);
219 if (NT_STATUS_EQUAL(status,
220 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
221 mech_wants_more = true;
222 } else if (!NT_STATUS_IS_OK(status)) {
226 mech_oids[0] = OID_NTLMSSP;
231 status = NT_STATUS_INTERNAL_ERROR;
235 switch (sp_ctx->state) {
236 case SPNEGO_CONV_INIT:
237 *spnego_out = spnego_gen_negTokenInit(mem_ctx, mech_oids,
238 &token_out, principal);
239 if (!spnego_out->data) {
240 status = NT_STATUS_INTERNAL_ERROR;
243 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
246 case SPNEGO_CONV_AUTH_MORE:
247 /* server says it's done and we do not seem to agree */
248 if (sp_in.negTokenTarg.negResult ==
249 SPNEGO_ACCEPT_COMPLETED) {
250 status = NT_STATUS_INVALID_PARAMETER;
254 sp_out.type = SPNEGO_NEG_TOKEN_TARG;
255 sp_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
256 sp_out.negTokenTarg.supportedMech = NULL;
257 sp_out.negTokenTarg.responseToken = token_out;
258 sp_out.negTokenTarg.mechListMIC = data_blob_null;
260 len_out = spnego_write_data(mem_ctx, spnego_out, &sp_out);
262 status = NT_STATUS_INTERNAL_ERROR;
266 if (!mech_wants_more) {
267 /* we still need to get an ack from the server */
268 sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
274 status = NT_STATUS_INTERNAL_ERROR;
278 status = NT_STATUS_OK;
282 spnego_free_data(&sp_in);
284 data_blob_free(&token_out);
288 bool spnego_require_more_processing(struct spnego_context *sp_ctx)
290 struct gse_context *gse_ctx;
292 /* see if spnego processing itself requires more */
293 if (sp_ctx->state == SPNEGO_CONV_AUTH_MORE ||
294 sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
298 /* otherwise see if underlying mechnism does */
299 switch (sp_ctx->mech) {
301 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
302 return gse_require_more_processing(gse_ctx);
306 DEBUG(0, ("Unsupported type in request!\n"));
311 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
312 enum spnego_mech *type,
315 switch (sp_ctx->mech) {
317 *auth_context = sp_ctx->mech_ctx.gssapi_state;
320 *auth_context = sp_ctx->mech_ctx.ntlmssp_state;
323 return NT_STATUS_INTERNAL_ERROR;
326 *type = sp_ctx->mech;
330 DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
331 struct spnego_context *sp_ctx)
333 switch (sp_ctx->mech) {
335 return gse_get_session_key(mem_ctx,
336 sp_ctx->mech_ctx.gssapi_state);
338 return auth_ntlmssp_get_session_key(
339 sp_ctx->mech_ctx.ntlmssp_state, mem_ctx);
341 DEBUG(0, ("Unsupported type in request!\n"));
342 return data_blob_null;
346 NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
347 struct spnego_context *sp_ctx,
348 DATA_BLOB *data, DATA_BLOB *full_data,
349 DATA_BLOB *signature)
351 switch(sp_ctx->mech) {
353 return gse_sign(mem_ctx,
354 sp_ctx->mech_ctx.gssapi_state,
357 return auth_ntlmssp_sign_packet(
358 sp_ctx->mech_ctx.ntlmssp_state,
360 data->data, data->length,
361 full_data->data, full_data->length,
364 return NT_STATUS_INVALID_PARAMETER;
368 NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
369 struct spnego_context *sp_ctx,
370 DATA_BLOB *data, DATA_BLOB *full_data,
371 DATA_BLOB *signature)
373 switch(sp_ctx->mech) {
375 return gse_sigcheck(mem_ctx,
376 sp_ctx->mech_ctx.gssapi_state,
379 return auth_ntlmssp_check_packet(
380 sp_ctx->mech_ctx.ntlmssp_state,
381 data->data, data->length,
382 full_data->data, full_data->length,
385 return NT_STATUS_INVALID_PARAMETER;
389 NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
390 struct spnego_context *sp_ctx,
391 DATA_BLOB *data, DATA_BLOB *full_data,
392 DATA_BLOB *signature)
394 switch(sp_ctx->mech) {
396 return gse_seal(mem_ctx,
397 sp_ctx->mech_ctx.gssapi_state,
400 return auth_ntlmssp_seal_packet(
401 sp_ctx->mech_ctx.ntlmssp_state,
403 data->data, data->length,
404 full_data->data, full_data->length,
407 return NT_STATUS_INVALID_PARAMETER;
411 NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
412 struct spnego_context *sp_ctx,
413 DATA_BLOB *data, DATA_BLOB *full_data,
414 DATA_BLOB *signature)
416 switch(sp_ctx->mech) {
418 return gse_unseal(mem_ctx,
419 sp_ctx->mech_ctx.gssapi_state,
422 return auth_ntlmssp_unseal_packet(
423 sp_ctx->mech_ctx.ntlmssp_state,
424 data->data, data->length,
425 full_data->data, full_data->length,
428 return NT_STATUS_INVALID_PARAMETER;