s3-rpc_server: Use the new endpoint register functions.
[Samba.git] / source3 / librpc / crypto / cli_spnego.c
blobbf58e25d9a87d2f0379663cea06d3ccb55d8adbb
1 /*
2 * SPNEGO Encapsulation
3 * Client functions
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/>.
20 #include "includes.h"
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);
34 if (!sp_ctx) {
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;
42 *spnego_ctx = sp_ctx;
43 return NT_STATUS_OK;
46 NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx,
47 bool do_sign, bool do_seal,
48 bool is_dcerpc,
49 const char *ccache_name,
50 const char *server,
51 const char *service,
52 const char *username,
53 const char *password,
54 struct spnego_context **spnego_ctx)
56 struct spnego_context *sp_ctx = NULL;
57 uint32_t add_gss_c_flags = 0;
58 NTSTATUS status;
60 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
61 if (!NT_STATUS_IS_OK(status)) {
62 return status;
64 sp_ctx->mech = SPNEGO_KRB5;
66 if (is_dcerpc) {
67 add_gss_c_flags = GSS_C_DCE_STYLE;
70 status = gse_init_client(sp_ctx,
71 do_sign, do_seal,
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)) {
76 TALLOC_FREE(sp_ctx);
77 return status;
80 *spnego_ctx = sp_ctx;
81 return NT_STATUS_OK;
84 NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx,
85 bool do_sign, bool do_seal,
86 bool is_dcerpc,
87 const char *domain,
88 const char *username,
89 const char *password,
90 struct spnego_context **spnego_ctx)
92 struct spnego_context *sp_ctx = NULL;
93 NTSTATUS status;
95 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
96 if (!NT_STATUS_IS_OK(status)) {
97 return status;
99 sp_ctx->mech = SPNEGO_NTLMSSP;
101 status = auth_ntlmssp_client_start(sp_ctx,
102 global_myname(),
103 lp_workgroup(),
104 lp_client_ntlmv2_auth(),
105 &sp_ctx->mech_ctx.ntlmssp_state);
106 if (!NT_STATUS_IS_OK(status)) {
107 TALLOC_FREE(sp_ctx);
108 return status;
111 status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state,
112 username);
113 if (!NT_STATUS_IS_OK(status)) {
114 TALLOC_FREE(sp_ctx);
115 return status;
118 status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state,
119 domain);
120 if (!NT_STATUS_IS_OK(status)) {
121 TALLOC_FREE(sp_ctx);
122 return status;
125 status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state,
126 password);
127 if (!NT_STATUS_IS_OK(status)) {
128 TALLOC_FREE(sp_ctx);
129 return 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));
139 if (do_sign) {
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;
149 return NT_STATUS_OK;
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;
164 ssize_t len_in = 0;
165 ssize_t len_out = 0;
166 bool mech_wants_more = false;
167 NTSTATUS status;
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;
174 } else {
175 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
176 if (len_in == -1) {
177 status = NT_STATUS_INVALID_PARAMETER;
178 goto done;
180 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
181 status = NT_STATUS_INVALID_PARAMETER;
182 goto done;
184 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
185 status = NT_STATUS_ACCESS_DENIED;
186 goto done;
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;
196 } else {
197 status = NT_STATUS_ACCESS_DENIED;
199 goto done;
202 switch (sp_ctx->mech) {
203 case SPNEGO_KRB5:
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)) {
209 goto done;
212 mech_oids[0] = OID_KERBEROS5;
213 mech_wants_more = gse_require_more_processing(gse_ctx);
215 break;
217 case SPNEGO_NTLMSSP:
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)) {
226 goto done;
229 mech_oids[0] = OID_NTLMSSP;
231 break;
233 default:
234 status = NT_STATUS_INTERNAL_ERROR;
235 goto done;
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;
244 goto done;
246 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
247 break;
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;
254 goto done;
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);
264 if (len_out == -1) {
265 status = NT_STATUS_INTERNAL_ERROR;
266 goto done;
269 if (!mech_wants_more) {
270 /* we still need to get an ack from the server */
271 sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
274 break;
276 default:
277 status = NT_STATUS_INTERNAL_ERROR;
278 goto done;
281 status = NT_STATUS_OK;
283 done:
284 if (len_in > 0) {
285 spnego_free_data(&sp_in);
287 data_blob_free(&token_out);
288 return status;
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) {
298 return true;
301 /* otherwise see if underlying mechnism does */
302 switch (sp_ctx->mech) {
303 case SPNEGO_KRB5:
304 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
305 return gse_require_more_processing(gse_ctx);
306 case SPNEGO_NTLMSSP:
307 return false;
308 default:
309 DEBUG(0, ("Unsupported type in request!\n"));
310 return false;
314 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
315 enum spnego_mech *type,
316 void **auth_context)
318 switch (sp_ctx->mech) {
319 case SPNEGO_KRB5:
320 *auth_context = sp_ctx->mech_ctx.gssapi_state;
321 break;
322 case SPNEGO_NTLMSSP:
323 *auth_context = sp_ctx->mech_ctx.ntlmssp_state;
324 break;
325 default:
326 return NT_STATUS_INTERNAL_ERROR;
329 *type = sp_ctx->mech;
330 return NT_STATUS_OK;
333 DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
334 struct spnego_context *sp_ctx)
336 DATA_BLOB sk;
338 switch (sp_ctx->mech) {
339 case SPNEGO_KRB5:
340 return gse_get_session_key(mem_ctx,
341 sp_ctx->mech_ctx.gssapi_state);
342 case SPNEGO_NTLMSSP:
343 sk = auth_ntlmssp_get_session_key(
344 sp_ctx->mech_ctx.ntlmssp_state);
345 return data_blob_dup_talloc(mem_ctx, &sk);
346 default:
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) {
358 case SPNEGO_KRB5:
359 return gse_sign(mem_ctx,
360 sp_ctx->mech_ctx.gssapi_state,
361 data, signature);
362 case SPNEGO_NTLMSSP:
363 return auth_ntlmssp_sign_packet(
364 sp_ctx->mech_ctx.ntlmssp_state,
365 mem_ctx,
366 data->data, data->length,
367 full_data->data, full_data->length,
368 signature);
369 default:
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) {
380 case SPNEGO_KRB5:
381 return gse_sigcheck(mem_ctx,
382 sp_ctx->mech_ctx.gssapi_state,
383 data, signature);
384 case SPNEGO_NTLMSSP:
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,
389 signature);
390 default:
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) {
401 case SPNEGO_KRB5:
402 return gse_seal(mem_ctx,
403 sp_ctx->mech_ctx.gssapi_state,
404 data, signature);
405 case SPNEGO_NTLMSSP:
406 return auth_ntlmssp_seal_packet(
407 sp_ctx->mech_ctx.ntlmssp_state,
408 mem_ctx,
409 data->data, data->length,
410 full_data->data, full_data->length,
411 signature);
412 default:
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) {
423 case SPNEGO_KRB5:
424 return gse_unseal(mem_ctx,
425 sp_ctx->mech_ctx.gssapi_state,
426 data, signature);
427 case SPNEGO_NTLMSSP:
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,
432 signature);
433 default:
434 return NT_STATUS_INVALID_PARAMETER;