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 "librpc/crypto/gse.h"
25 #include "librpc/crypto/spnego.h"
27 static NTSTATUS
spnego_context_init(TALLOC_CTX
*mem_ctx
,
28 bool do_sign
, bool do_seal
,
29 struct spnego_context
**spnego_ctx
)
31 struct spnego_context
*sp_ctx
;
33 sp_ctx
= talloc_zero(mem_ctx
, struct spnego_context
);
35 return NT_STATUS_NO_MEMORY
;
38 sp_ctx
->do_sign
= do_sign
;
39 sp_ctx
->do_seal
= do_seal
;
40 sp_ctx
->state
= SPNEGO_CONV_INIT
;
46 NTSTATUS
spnego_gssapi_init_client(TALLOC_CTX
*mem_ctx
,
47 bool do_sign
, bool do_seal
,
49 const char *ccache_name
,
54 struct spnego_context
**spnego_ctx
)
56 struct spnego_context
*sp_ctx
= NULL
;
57 uint32_t add_gss_c_flags
= 0;
60 status
= spnego_context_init(mem_ctx
, do_sign
, do_seal
, &sp_ctx
);
61 if (!NT_STATUS_IS_OK(status
)) {
64 sp_ctx
->mech
= SPNEGO_KRB5
;
67 add_gss_c_flags
= GSS_C_DCE_STYLE
;
70 status
= gse_init_client(sp_ctx
,
72 ccache_name
, server
, service
,
73 username
, password
, add_gss_c_flags
,
74 &sp_ctx
->mech_ctx
.gssapi_state
);
75 if (!NT_STATUS_IS_OK(status
)) {
84 NTSTATUS
spnego_ntlmssp_init_client(TALLOC_CTX
*mem_ctx
,
85 bool do_sign
, bool do_seal
,
90 struct spnego_context
**spnego_ctx
)
92 struct spnego_context
*sp_ctx
= NULL
;
95 status
= spnego_context_init(mem_ctx
, do_sign
, do_seal
, &sp_ctx
);
96 if (!NT_STATUS_IS_OK(status
)) {
99 sp_ctx
->mech
= SPNEGO_NTLMSSP
;
101 status
= auth_ntlmssp_client_start(sp_ctx
,
104 lp_client_ntlmv2_auth(),
105 &sp_ctx
->mech_ctx
.ntlmssp_state
);
106 if (!NT_STATUS_IS_OK(status
)) {
111 status
= auth_ntlmssp_set_username(sp_ctx
->mech_ctx
.ntlmssp_state
,
113 if (!NT_STATUS_IS_OK(status
)) {
118 status
= auth_ntlmssp_set_domain(sp_ctx
->mech_ctx
.ntlmssp_state
,
120 if (!NT_STATUS_IS_OK(status
)) {
125 status
= auth_ntlmssp_set_password(sp_ctx
->mech_ctx
.ntlmssp_state
,
127 if (!NT_STATUS_IS_OK(status
)) {
133 * Turn off sign+seal to allow selected auth level to turn it back on.
135 auth_ntlmssp_and_flags(sp_ctx
->mech_ctx
.ntlmssp_state
,
136 ~(NTLMSSP_NEGOTIATE_SIGN
|
137 NTLMSSP_NEGOTIATE_SEAL
));
140 auth_ntlmssp_or_flags(sp_ctx
->mech_ctx
.ntlmssp_state
,
141 NTLMSSP_NEGOTIATE_SIGN
);
142 } else if (do_seal
) {
143 auth_ntlmssp_or_flags(sp_ctx
->mech_ctx
.ntlmssp_state
,
144 NTLMSSP_NEGOTIATE_SEAL
|
145 NTLMSSP_NEGOTIATE_SIGN
);
148 *spnego_ctx
= sp_ctx
;
152 NTSTATUS
spnego_get_client_auth_token(TALLOC_CTX
*mem_ctx
,
153 struct spnego_context
*sp_ctx
,
154 DATA_BLOB
*spnego_in
,
155 DATA_BLOB
*spnego_out
)
157 struct gse_context
*gse_ctx
;
158 struct auth_ntlmssp_state
*ntlmssp_ctx
;
159 struct spnego_data sp_in
, sp_out
;
160 DATA_BLOB token_in
= data_blob_null
;
161 DATA_BLOB token_out
= data_blob_null
;
162 const char *mech_oids
[2] = { NULL
, NULL
};
163 char *principal
= NULL
;
166 bool mech_wants_more
= false;
169 if (!spnego_in
->length
) {
170 /* server didn't send anything, is init ? */
171 if (sp_ctx
->state
!= SPNEGO_CONV_INIT
) {
172 return NT_STATUS_INVALID_PARAMETER
;
175 len_in
= spnego_read_data(mem_ctx
, *spnego_in
, &sp_in
);
177 status
= NT_STATUS_INVALID_PARAMETER
;
180 if (sp_in
.type
!= SPNEGO_NEG_TOKEN_TARG
) {
181 status
= NT_STATUS_INVALID_PARAMETER
;
184 if (sp_in
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
185 status
= NT_STATUS_ACCESS_DENIED
;
188 token_in
= sp_in
.negTokenTarg
.responseToken
;
191 if (sp_ctx
->state
== SPNEGO_CONV_AUTH_CONFIRM
) {
192 if (sp_in
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
193 sp_ctx
->state
= SPNEGO_CONV_AUTH_DONE
;
194 *spnego_out
= data_blob_null
;
195 status
= NT_STATUS_OK
;
197 status
= NT_STATUS_ACCESS_DENIED
;
202 switch (sp_ctx
->mech
) {
205 gse_ctx
= sp_ctx
->mech_ctx
.gssapi_state
;
206 status
= gse_get_client_auth_token(mem_ctx
, gse_ctx
,
207 &token_in
, &token_out
);
208 if (!NT_STATUS_IS_OK(status
)) {
212 mech_oids
[0] = OID_KERBEROS5
;
213 mech_wants_more
= gse_require_more_processing(gse_ctx
);
219 ntlmssp_ctx
= sp_ctx
->mech_ctx
.ntlmssp_state
;
220 status
= auth_ntlmssp_update(ntlmssp_ctx
,
221 token_in
, &token_out
);
222 if (NT_STATUS_EQUAL(status
,
223 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
224 mech_wants_more
= true;
225 } else if (!NT_STATUS_IS_OK(status
)) {
229 mech_oids
[0] = OID_NTLMSSP
;
234 status
= NT_STATUS_INTERNAL_ERROR
;
238 switch (sp_ctx
->state
) {
239 case SPNEGO_CONV_INIT
:
240 *spnego_out
= spnego_gen_negTokenInit(mem_ctx
, mech_oids
,
241 &token_out
, principal
);
242 if (!spnego_out
->data
) {
243 status
= NT_STATUS_INTERNAL_ERROR
;
246 sp_ctx
->state
= SPNEGO_CONV_AUTH_MORE
;
249 case SPNEGO_CONV_AUTH_MORE
:
250 /* server says it's done and we do not seem to agree */
251 if (sp_in
.negTokenTarg
.negResult
==
252 SPNEGO_ACCEPT_COMPLETED
) {
253 status
= NT_STATUS_INVALID_PARAMETER
;
257 sp_out
.type
= SPNEGO_NEG_TOKEN_TARG
;
258 sp_out
.negTokenTarg
.negResult
= SPNEGO_NONE_RESULT
;
259 sp_out
.negTokenTarg
.supportedMech
= NULL
;
260 sp_out
.negTokenTarg
.responseToken
= token_out
;
261 sp_out
.negTokenTarg
.mechListMIC
= data_blob_null
;
263 len_out
= spnego_write_data(mem_ctx
, spnego_out
, &sp_out
);
265 status
= NT_STATUS_INTERNAL_ERROR
;
269 if (!mech_wants_more
) {
270 /* we still need to get an ack from the server */
271 sp_ctx
->state
= SPNEGO_CONV_AUTH_CONFIRM
;
277 status
= NT_STATUS_INTERNAL_ERROR
;
281 status
= NT_STATUS_OK
;
285 spnego_free_data(&sp_in
);
287 data_blob_free(&token_out
);
291 bool spnego_require_more_processing(struct spnego_context
*sp_ctx
)
293 struct gse_context
*gse_ctx
;
295 /* see if spnego processing itself requires more */
296 if (sp_ctx
->state
== SPNEGO_CONV_AUTH_MORE
||
297 sp_ctx
->state
== SPNEGO_CONV_AUTH_CONFIRM
) {
301 /* otherwise see if underlying mechnism does */
302 switch (sp_ctx
->mech
) {
304 gse_ctx
= sp_ctx
->mech_ctx
.gssapi_state
;
305 return gse_require_more_processing(gse_ctx
);
309 DEBUG(0, ("Unsupported type in request!\n"));
314 NTSTATUS
spnego_get_negotiated_mech(struct spnego_context
*sp_ctx
,
315 enum spnego_mech
*type
,
318 switch (sp_ctx
->mech
) {
320 *auth_context
= sp_ctx
->mech_ctx
.gssapi_state
;
323 *auth_context
= sp_ctx
->mech_ctx
.ntlmssp_state
;
326 return NT_STATUS_INTERNAL_ERROR
;
329 *type
= sp_ctx
->mech
;
333 DATA_BLOB
spnego_get_session_key(TALLOC_CTX
*mem_ctx
,
334 struct spnego_context
*sp_ctx
)
338 switch (sp_ctx
->mech
) {
340 return gse_get_session_key(mem_ctx
,
341 sp_ctx
->mech_ctx
.gssapi_state
);
343 sk
= auth_ntlmssp_get_session_key(
344 sp_ctx
->mech_ctx
.ntlmssp_state
);
345 return data_blob_dup_talloc(mem_ctx
, &sk
);
347 DEBUG(0, ("Unsupported type in request!\n"));
348 return data_blob_null
;
352 NTSTATUS
spnego_sign(TALLOC_CTX
*mem_ctx
,
353 struct spnego_context
*sp_ctx
,
354 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
355 DATA_BLOB
*signature
)
357 switch(sp_ctx
->mech
) {
359 return gse_sign(mem_ctx
,
360 sp_ctx
->mech_ctx
.gssapi_state
,
363 return auth_ntlmssp_sign_packet(
364 sp_ctx
->mech_ctx
.ntlmssp_state
,
366 data
->data
, data
->length
,
367 full_data
->data
, full_data
->length
,
370 return NT_STATUS_INVALID_PARAMETER
;
374 NTSTATUS
spnego_sigcheck(TALLOC_CTX
*mem_ctx
,
375 struct spnego_context
*sp_ctx
,
376 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
377 DATA_BLOB
*signature
)
379 switch(sp_ctx
->mech
) {
381 return gse_sigcheck(mem_ctx
,
382 sp_ctx
->mech_ctx
.gssapi_state
,
385 return auth_ntlmssp_check_packet(
386 sp_ctx
->mech_ctx
.ntlmssp_state
,
387 data
->data
, data
->length
,
388 full_data
->data
, full_data
->length
,
391 return NT_STATUS_INVALID_PARAMETER
;
395 NTSTATUS
spnego_seal(TALLOC_CTX
*mem_ctx
,
396 struct spnego_context
*sp_ctx
,
397 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
398 DATA_BLOB
*signature
)
400 switch(sp_ctx
->mech
) {
402 return gse_seal(mem_ctx
,
403 sp_ctx
->mech_ctx
.gssapi_state
,
406 return auth_ntlmssp_seal_packet(
407 sp_ctx
->mech_ctx
.ntlmssp_state
,
409 data
->data
, data
->length
,
410 full_data
->data
, full_data
->length
,
413 return NT_STATUS_INVALID_PARAMETER
;
417 NTSTATUS
spnego_unseal(TALLOC_CTX
*mem_ctx
,
418 struct spnego_context
*sp_ctx
,
419 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
420 DATA_BLOB
*signature
)
422 switch(sp_ctx
->mech
) {
424 return gse_unseal(mem_ctx
,
425 sp_ctx
->mech_ctx
.gssapi_state
,
428 return auth_ntlmssp_unseal_packet(
429 sp_ctx
->mech_ctx
.ntlmssp_state
,
430 data
->data
, data
->length
,
431 full_data
->data
, full_data
->length
,
434 return NT_STATUS_INVALID_PARAMETER
;