4 * Copyright (C) Simo Sorce 2010.
5 * Copyright (C) Andrew Bartlett 2011.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "../libcli/auth/spnego.h"
23 #include "include/auth_generic.h"
24 #include "librpc/gen_ndr/ntlmssp.h"
25 #include "auth/ntlmssp/ntlmssp.h"
26 #include "librpc/crypto/gse.h"
27 #include "librpc/crypto/spnego.h"
28 #include "auth/gensec/gensec.h"
30 static NTSTATUS
spnego_context_init(TALLOC_CTX
*mem_ctx
,
31 bool do_sign
, bool do_seal
,
32 struct spnego_context
**spnego_ctx
)
34 struct spnego_context
*sp_ctx
;
36 sp_ctx
= talloc_zero(mem_ctx
, struct spnego_context
);
38 return NT_STATUS_NO_MEMORY
;
41 sp_ctx
->do_sign
= do_sign
;
42 sp_ctx
->do_seal
= do_seal
;
43 sp_ctx
->state
= SPNEGO_CONV_INIT
;
49 NTSTATUS
spnego_generic_init_client(TALLOC_CTX
*mem_ctx
,
51 bool do_sign
, bool do_seal
,
54 const char *target_service
,
58 struct spnego_context
**spnego_ctx
)
60 struct spnego_context
*sp_ctx
= NULL
;
61 struct auth_generic_state
*auth_generic_state
;
64 status
= spnego_context_init(mem_ctx
, do_sign
, do_seal
, &sp_ctx
);
65 if (!NT_STATUS_IS_OK(status
)) {
68 if (strcmp(oid
, GENSEC_OID_NTLMSSP
) == 0) {
69 sp_ctx
->mech
= SPNEGO_NTLMSSP
;
70 } else if (strcmp(oid
, GENSEC_OID_KERBEROS5
) == 0) {
71 sp_ctx
->mech
= SPNEGO_KRB5
;
73 return NT_STATUS_INVALID_PARAMETER
;
76 status
= auth_generic_client_prepare(sp_ctx
,
78 if (!NT_STATUS_IS_OK(status
)) {
83 status
= auth_generic_set_username(auth_generic_state
,
85 if (!NT_STATUS_IS_OK(status
)) {
90 status
= auth_generic_set_domain(auth_generic_state
,
92 if (!NT_STATUS_IS_OK(status
)) {
97 status
= auth_generic_set_password(auth_generic_state
,
99 if (!NT_STATUS_IS_OK(status
)) {
105 gensec_want_feature(auth_generic_state
->gensec_security
,
106 GENSEC_FEATURE_SIGN
);
107 } else if (do_seal
) {
108 gensec_want_feature(auth_generic_state
->gensec_security
,
109 GENSEC_FEATURE_SEAL
);
113 gensec_want_feature(auth_generic_state
->gensec_security
,
114 GENSEC_FEATURE_DCE_STYLE
);
117 status
= gensec_set_target_service(auth_generic_state
->gensec_security
, target_service
);
118 if (!NT_STATUS_IS_OK(status
)) {
123 status
= gensec_set_target_hostname(auth_generic_state
->gensec_security
, server
);
124 if (!NT_STATUS_IS_OK(status
)) {
129 status
= auth_generic_client_start(auth_generic_state
, oid
);
130 if (!NT_STATUS_IS_OK(status
)) {
135 sp_ctx
->gensec_security
= talloc_move(sp_ctx
, &auth_generic_state
->gensec_security
);
136 TALLOC_FREE(auth_generic_state
);
137 *spnego_ctx
= sp_ctx
;
141 NTSTATUS
spnego_get_client_auth_token(TALLOC_CTX
*mem_ctx
,
142 struct spnego_context
*sp_ctx
,
143 DATA_BLOB
*spnego_in
,
144 DATA_BLOB
*spnego_out
)
146 struct gensec_security
*gensec_security
;
147 struct spnego_data sp_in
, sp_out
;
148 DATA_BLOB token_in
= data_blob_null
;
149 DATA_BLOB token_out
= data_blob_null
;
150 const char *mech_oids
[2] = { NULL
, NULL
};
151 char *principal
= NULL
;
156 if (!spnego_in
->length
) {
157 /* server didn't send anything, is init ? */
158 if (sp_ctx
->state
!= SPNEGO_CONV_INIT
) {
159 return NT_STATUS_INVALID_PARAMETER
;
162 len_in
= spnego_read_data(mem_ctx
, *spnego_in
, &sp_in
);
164 status
= NT_STATUS_INVALID_PARAMETER
;
167 if (sp_in
.type
!= SPNEGO_NEG_TOKEN_TARG
) {
168 status
= NT_STATUS_INVALID_PARAMETER
;
171 if (sp_in
.negTokenTarg
.negResult
== SPNEGO_REJECT
) {
172 status
= NT_STATUS_ACCESS_DENIED
;
175 token_in
= sp_in
.negTokenTarg
.responseToken
;
178 if (sp_ctx
->state
== SPNEGO_CONV_AUTH_CONFIRM
) {
179 if (sp_in
.negTokenTarg
.negResult
== SPNEGO_ACCEPT_COMPLETED
) {
180 sp_ctx
->state
= SPNEGO_CONV_AUTH_DONE
;
181 *spnego_out
= data_blob_null
;
182 status
= NT_STATUS_OK
;
184 status
= NT_STATUS_ACCESS_DENIED
;
189 switch (sp_ctx
->mech
) {
191 mech_oids
[0] = OID_KERBEROS5
;
195 mech_oids
[0] = OID_NTLMSSP
;
199 status
= NT_STATUS_INTERNAL_ERROR
;
203 gensec_security
= sp_ctx
->gensec_security
;
204 status
= gensec_update(gensec_security
, mem_ctx
, NULL
,
205 token_in
, &token_out
);
206 sp_ctx
->more_processing
= false;
207 if (NT_STATUS_EQUAL(status
,
208 NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
209 sp_ctx
->more_processing
= true;
210 } else if (!NT_STATUS_IS_OK(status
)) {
214 switch (sp_ctx
->state
) {
215 case SPNEGO_CONV_INIT
:
216 *spnego_out
= spnego_gen_negTokenInit(mem_ctx
, mech_oids
,
217 &token_out
, principal
);
218 if (!spnego_out
->data
) {
219 status
= NT_STATUS_INTERNAL_ERROR
;
222 sp_ctx
->state
= SPNEGO_CONV_AUTH_MORE
;
225 case SPNEGO_CONV_AUTH_MORE
:
226 /* server says it's done and we do not seem to agree */
227 if (sp_in
.negTokenTarg
.negResult
==
228 SPNEGO_ACCEPT_COMPLETED
) {
229 status
= NT_STATUS_INVALID_PARAMETER
;
233 sp_out
.type
= SPNEGO_NEG_TOKEN_TARG
;
234 sp_out
.negTokenTarg
.negResult
= SPNEGO_NONE_RESULT
;
235 sp_out
.negTokenTarg
.supportedMech
= NULL
;
236 sp_out
.negTokenTarg
.responseToken
= token_out
;
237 sp_out
.negTokenTarg
.mechListMIC
= data_blob_null
;
239 len_out
= spnego_write_data(mem_ctx
, spnego_out
, &sp_out
);
241 status
= NT_STATUS_INTERNAL_ERROR
;
245 if (!sp_ctx
->more_processing
) {
246 /* we still need to get an ack from the server */
247 sp_ctx
->state
= SPNEGO_CONV_AUTH_CONFIRM
;
253 status
= NT_STATUS_INTERNAL_ERROR
;
257 status
= NT_STATUS_OK
;
261 spnego_free_data(&sp_in
);
263 data_blob_free(&token_out
);
267 bool spnego_require_more_processing(struct spnego_context
*sp_ctx
)
270 /* see if spnego processing itself requires more */
271 if (sp_ctx
->state
== SPNEGO_CONV_AUTH_MORE
||
272 sp_ctx
->state
== SPNEGO_CONV_AUTH_CONFIRM
) {
276 return sp_ctx
->more_processing
;
279 NTSTATUS
spnego_get_negotiated_mech(struct spnego_context
*sp_ctx
,
280 struct gensec_security
**auth_context
)
282 *auth_context
= sp_ctx
->gensec_security
;
286 NTSTATUS
spnego_sign(TALLOC_CTX
*mem_ctx
,
287 struct spnego_context
*sp_ctx
,
288 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
289 DATA_BLOB
*signature
)
291 return gensec_sign_packet(
292 sp_ctx
->gensec_security
,
294 data
->data
, data
->length
,
295 full_data
->data
, full_data
->length
,
299 NTSTATUS
spnego_sigcheck(TALLOC_CTX
*mem_ctx
,
300 struct spnego_context
*sp_ctx
,
301 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
302 DATA_BLOB
*signature
)
304 return gensec_check_packet(
305 sp_ctx
->gensec_security
,
306 data
->data
, data
->length
,
307 full_data
->data
, full_data
->length
,
311 NTSTATUS
spnego_seal(TALLOC_CTX
*mem_ctx
,
312 struct spnego_context
*sp_ctx
,
313 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
314 DATA_BLOB
*signature
)
316 return gensec_seal_packet(
317 sp_ctx
->gensec_security
,
319 data
->data
, data
->length
,
320 full_data
->data
, full_data
->length
,
324 NTSTATUS
spnego_unseal(TALLOC_CTX
*mem_ctx
,
325 struct spnego_context
*sp_ctx
,
326 DATA_BLOB
*data
, DATA_BLOB
*full_data
,
327 DATA_BLOB
*signature
)
329 return gensec_unseal_packet(
330 sp_ctx
->gensec_security
,
331 data
->data
, data
->length
,
332 full_data
->data
, full_data
->length
,