s3-librpc Remove special case for spnego session key
[Samba.git] / source3 / librpc / crypto / cli_spnego.c
blobe676703c6b05d3a0858d0f160519a64bb6e739b5
1 /*
2 * SPNEGO Encapsulation
3 * Client functions
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/>.
21 #include "includes.h"
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);
37 if (!sp_ctx) {
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;
45 *spnego_ctx = sp_ctx;
46 return NT_STATUS_OK;
49 NTSTATUS spnego_generic_init_client(TALLOC_CTX *mem_ctx,
50 const char *oid,
51 bool do_sign, bool do_seal,
52 bool is_dcerpc,
53 const char *server,
54 const char *target_service,
55 const char *domain,
56 const char *username,
57 const char *password,
58 struct spnego_context **spnego_ctx)
60 struct spnego_context *sp_ctx = NULL;
61 struct auth_generic_state *auth_generic_state;
62 NTSTATUS status;
64 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
65 if (!NT_STATUS_IS_OK(status)) {
66 return 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;
72 } else {
73 return NT_STATUS_INVALID_PARAMETER;
76 status = auth_generic_client_prepare(sp_ctx,
77 &auth_generic_state);
78 if (!NT_STATUS_IS_OK(status)) {
79 TALLOC_FREE(sp_ctx);
80 return status;
83 status = auth_generic_set_username(auth_generic_state,
84 username);
85 if (!NT_STATUS_IS_OK(status)) {
86 TALLOC_FREE(sp_ctx);
87 return status;
90 status = auth_generic_set_domain(auth_generic_state,
91 domain);
92 if (!NT_STATUS_IS_OK(status)) {
93 TALLOC_FREE(sp_ctx);
94 return status;
97 status = auth_generic_set_password(auth_generic_state,
98 password);
99 if (!NT_STATUS_IS_OK(status)) {
100 TALLOC_FREE(sp_ctx);
101 return status;
104 if (do_sign) {
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);
112 if (is_dcerpc) {
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)) {
119 TALLOC_FREE(sp_ctx);
120 return status;
123 status = gensec_set_target_hostname(auth_generic_state->gensec_security, server);
124 if (!NT_STATUS_IS_OK(status)) {
125 TALLOC_FREE(sp_ctx);
126 return status;
129 status = auth_generic_client_start(auth_generic_state, oid);
130 if (!NT_STATUS_IS_OK(status)) {
131 TALLOC_FREE(sp_ctx);
132 return 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;
138 return NT_STATUS_OK;
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;
152 ssize_t len_in = 0;
153 ssize_t len_out = 0;
154 NTSTATUS status;
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;
161 } else {
162 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
163 if (len_in == -1) {
164 status = NT_STATUS_INVALID_PARAMETER;
165 goto done;
167 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
168 status = NT_STATUS_INVALID_PARAMETER;
169 goto done;
171 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
172 status = NT_STATUS_ACCESS_DENIED;
173 goto done;
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;
183 } else {
184 status = NT_STATUS_ACCESS_DENIED;
186 goto done;
189 switch (sp_ctx->mech) {
190 case SPNEGO_KRB5:
191 mech_oids[0] = OID_KERBEROS5;
192 break;
194 case SPNEGO_NTLMSSP:
195 mech_oids[0] = OID_NTLMSSP;
196 break;
198 default:
199 status = NT_STATUS_INTERNAL_ERROR;
200 goto done;
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)) {
211 goto done;
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;
220 goto done;
222 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
223 break;
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;
230 goto done;
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);
240 if (len_out == -1) {
241 status = NT_STATUS_INTERNAL_ERROR;
242 goto done;
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;
250 break;
252 default:
253 status = NT_STATUS_INTERNAL_ERROR;
254 goto done;
257 status = NT_STATUS_OK;
259 done:
260 if (len_in > 0) {
261 spnego_free_data(&sp_in);
263 data_blob_free(&token_out);
264 return status;
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) {
273 return true;
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;
283 return NT_STATUS_OK;
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,
293 mem_ctx,
294 data->data, data->length,
295 full_data->data, full_data->length,
296 signature);
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,
308 signature);
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,
318 mem_ctx,
319 data->data, data->length,
320 full_data->data, full_data->length,
321 signature);
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,
333 signature);