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_prepare(sp_ctx,
103 &sp_ctx->mech_ctx.ntlmssp_state);
104 if (!NT_STATUS_IS_OK(status)) {
109 status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state,
111 if (!NT_STATUS_IS_OK(status)) {
116 status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state,
118 if (!NT_STATUS_IS_OK(status)) {
123 status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state,
125 if (!NT_STATUS_IS_OK(status)) {
131 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
132 NTLMSSP_FEATURE_SIGN);
133 } else if (do_seal) {
134 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
135 NTLMSSP_FEATURE_SEAL);
138 status = auth_ntlmssp_client_start(sp_ctx->mech_ctx.ntlmssp_state);
139 if (!NT_STATUS_IS_OK(status)) {
144 *spnego_ctx = sp_ctx;
148 NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
149 struct spnego_context *sp_ctx,
150 DATA_BLOB *spnego_in,
151 DATA_BLOB *spnego_out)
153 struct gse_context *gse_ctx;
154 struct auth_ntlmssp_state *ntlmssp_ctx;
155 struct spnego_data sp_in, sp_out;
156 DATA_BLOB token_in = data_blob_null;
157 DATA_BLOB token_out = data_blob_null;
158 const char *mech_oids[2] = { NULL, NULL };
159 char *principal = NULL;
162 bool mech_wants_more = false;
165 if (!spnego_in->length) {
166 /* server didn't send anything, is init ? */
167 if (sp_ctx->state != SPNEGO_CONV_INIT) {
168 return NT_STATUS_INVALID_PARAMETER;
171 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
173 status = NT_STATUS_INVALID_PARAMETER;
176 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
177 status = NT_STATUS_INVALID_PARAMETER;
180 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
181 status = NT_STATUS_ACCESS_DENIED;
184 token_in = sp_in.negTokenTarg.responseToken;
187 if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
188 if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
189 sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
190 *spnego_out = data_blob_null;
191 status = NT_STATUS_OK;
193 status = NT_STATUS_ACCESS_DENIED;
198 switch (sp_ctx->mech) {
201 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
202 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
203 &token_in, &token_out);
204 if (!NT_STATUS_IS_OK(status)) {
208 mech_oids[0] = OID_KERBEROS5;
209 mech_wants_more = gse_require_more_processing(gse_ctx);
215 ntlmssp_ctx = sp_ctx->mech_ctx.ntlmssp_state;
216 status = auth_ntlmssp_update(ntlmssp_ctx, mem_ctx,
217 token_in, &token_out);
218 if (NT_STATUS_EQUAL(status,
219 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
220 mech_wants_more = true;
221 } else if (!NT_STATUS_IS_OK(status)) {
225 mech_oids[0] = OID_NTLMSSP;
230 status = NT_STATUS_INTERNAL_ERROR;
234 switch (sp_ctx->state) {
235 case SPNEGO_CONV_INIT:
236 *spnego_out = spnego_gen_negTokenInit(mem_ctx, mech_oids,
237 &token_out, principal);
238 if (!spnego_out->data) {
239 status = NT_STATUS_INTERNAL_ERROR;
242 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
245 case SPNEGO_CONV_AUTH_MORE:
246 /* server says it's done and we do not seem to agree */
247 if (sp_in.negTokenTarg.negResult ==
248 SPNEGO_ACCEPT_COMPLETED) {
249 status = NT_STATUS_INVALID_PARAMETER;
253 sp_out.type = SPNEGO_NEG_TOKEN_TARG;
254 sp_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
255 sp_out.negTokenTarg.supportedMech = NULL;
256 sp_out.negTokenTarg.responseToken = token_out;
257 sp_out.negTokenTarg.mechListMIC = data_blob_null;
259 len_out = spnego_write_data(mem_ctx, spnego_out, &sp_out);
261 status = NT_STATUS_INTERNAL_ERROR;
265 if (!mech_wants_more) {
266 /* we still need to get an ack from the server */
267 sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
273 status = NT_STATUS_INTERNAL_ERROR;
277 status = NT_STATUS_OK;
281 spnego_free_data(&sp_in);
283 data_blob_free(&token_out);
287 bool spnego_require_more_processing(struct spnego_context *sp_ctx)
289 struct gse_context *gse_ctx;
291 /* see if spnego processing itself requires more */
292 if (sp_ctx->state == SPNEGO_CONV_AUTH_MORE ||
293 sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
297 /* otherwise see if underlying mechnism does */
298 switch (sp_ctx->mech) {
300 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
301 return gse_require_more_processing(gse_ctx);
305 DEBUG(0, ("Unsupported type in request!\n"));
310 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
311 enum spnego_mech *type,
314 switch (sp_ctx->mech) {
316 *auth_context = sp_ctx->mech_ctx.gssapi_state;
319 *auth_context = sp_ctx->mech_ctx.ntlmssp_state;
322 return NT_STATUS_INTERNAL_ERROR;
325 *type = sp_ctx->mech;
329 DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
330 struct spnego_context *sp_ctx)
332 switch (sp_ctx->mech) {
334 return gse_get_session_key(mem_ctx,
335 sp_ctx->mech_ctx.gssapi_state);
337 return auth_ntlmssp_get_session_key(
338 sp_ctx->mech_ctx.ntlmssp_state, mem_ctx);
340 DEBUG(0, ("Unsupported type in request!\n"));
341 return data_blob_null;
345 NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
346 struct spnego_context *sp_ctx,
347 DATA_BLOB *data, DATA_BLOB *full_data,
348 DATA_BLOB *signature)
350 switch(sp_ctx->mech) {
352 return gse_sign(mem_ctx,
353 sp_ctx->mech_ctx.gssapi_state,
356 return auth_ntlmssp_sign_packet(
357 sp_ctx->mech_ctx.ntlmssp_state,
359 data->data, data->length,
360 full_data->data, full_data->length,
363 return NT_STATUS_INVALID_PARAMETER;
367 NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
368 struct spnego_context *sp_ctx,
369 DATA_BLOB *data, DATA_BLOB *full_data,
370 DATA_BLOB *signature)
372 switch(sp_ctx->mech) {
374 return gse_sigcheck(mem_ctx,
375 sp_ctx->mech_ctx.gssapi_state,
378 return auth_ntlmssp_check_packet(
379 sp_ctx->mech_ctx.ntlmssp_state,
380 data->data, data->length,
381 full_data->data, full_data->length,
384 return NT_STATUS_INVALID_PARAMETER;
388 NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
389 struct spnego_context *sp_ctx,
390 DATA_BLOB *data, DATA_BLOB *full_data,
391 DATA_BLOB *signature)
393 switch(sp_ctx->mech) {
395 return gse_seal(mem_ctx,
396 sp_ctx->mech_ctx.gssapi_state,
399 return auth_ntlmssp_seal_packet(
400 sp_ctx->mech_ctx.ntlmssp_state,
402 data->data, data->length,
403 full_data->data, full_data->length,
406 return NT_STATUS_INVALID_PARAMETER;
410 NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
411 struct spnego_context *sp_ctx,
412 DATA_BLOB *data, DATA_BLOB *full_data,
413 DATA_BLOB *signature)
415 switch(sp_ctx->mech) {
417 return gse_unseal(mem_ctx,
418 sp_ctx->mech_ctx.gssapi_state,
421 return auth_ntlmssp_unseal_packet(
422 sp_ctx->mech_ctx.ntlmssp_state,
423 data->data, data->length,
424 full_data->data, full_data->length,
427 return NT_STATUS_INVALID_PARAMETER;