source: trunk/server/source3/librpc/crypto/cli_spnego.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 11.0 KB
Line 
1/*
2 * SPNEGO Encapsulation
3 * Client functions
4 * Copyright (C) Simo Sorce 2010.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
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"
26
27static NTSTATUS spnego_context_init(TALLOC_CTX *mem_ctx,
28 bool do_sign, bool do_seal,
29 struct spnego_context **spnego_ctx)
30{
31 struct spnego_context *sp_ctx;
32
33 sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
34 if (!sp_ctx) {
35 return NT_STATUS_NO_MEMORY;
36 }
37
38 sp_ctx->do_sign = do_sign;
39 sp_ctx->do_seal = do_seal;
40 sp_ctx->state = SPNEGO_CONV_INIT;
41
42 *spnego_ctx = sp_ctx;
43 return NT_STATUS_OK;
44}
45
46NTSTATUS 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)
55{
56 struct spnego_context *sp_ctx = NULL;
57 uint32_t add_gss_c_flags = 0;
58 NTSTATUS status;
59
60 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
61 if (!NT_STATUS_IS_OK(status)) {
62 return status;
63 }
64 sp_ctx->mech = SPNEGO_KRB5;
65
66 if (is_dcerpc) {
67 add_gss_c_flags = GSS_C_DCE_STYLE;
68 }
69
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;
78 }
79
80 *spnego_ctx = sp_ctx;
81 return NT_STATUS_OK;
82}
83
84NTSTATUS 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)
91{
92 struct spnego_context *sp_ctx = NULL;
93 NTSTATUS status;
94
95 status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
96 if (!NT_STATUS_IS_OK(status)) {
97 return status;
98 }
99 sp_ctx->mech = SPNEGO_NTLMSSP;
100
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;
109 }
110
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;
116 }
117
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;
123 }
124
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;
130 }
131
132 /*
133 * Turn off sign+seal to allow selected auth level to turn it back on.
134 */
135 auth_ntlmssp_and_flags(sp_ctx->mech_ctx.ntlmssp_state,
136 ~(NTLMSSP_NEGOTIATE_SIGN |
137 NTLMSSP_NEGOTIATE_SEAL));
138
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);
146 }
147
148 *spnego_ctx = sp_ctx;
149 return NT_STATUS_OK;
150}
151
152NTSTATUS 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)
156{
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;
168
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;
173 }
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;
179 }
180 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
181 status = NT_STATUS_INVALID_PARAMETER;
182 goto done;
183 }
184 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
185 status = NT_STATUS_ACCESS_DENIED;
186 goto done;
187 }
188 token_in = sp_in.negTokenTarg.responseToken;
189 }
190
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;
198 }
199 goto done;
200 }
201
202 switch (sp_ctx->mech) {
203 case SPNEGO_KRB5:
204
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;
210 }
211
212 mech_oids[0] = OID_KERBEROS5;
213 mech_wants_more = gse_require_more_processing(gse_ctx);
214
215 break;
216
217 case SPNEGO_NTLMSSP:
218
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;
227 }
228
229 mech_oids[0] = OID_NTLMSSP;
230
231 break;
232
233 default:
234 status = NT_STATUS_INTERNAL_ERROR;
235 goto done;
236 }
237
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;
245 }
246 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
247 break;
248
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;
255 }
256
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;
262
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;
267 }
268
269 if (!mech_wants_more) {
270 /* we still need to get an ack from the server */
271 sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
272 }
273
274 break;
275
276 default:
277 status = NT_STATUS_INTERNAL_ERROR;
278 goto done;
279 }
280
281 status = NT_STATUS_OK;
282
283done:
284 if (len_in > 0) {
285 spnego_free_data(&sp_in);
286 }
287 data_blob_free(&token_out);
288 return status;
289}
290
291bool spnego_require_more_processing(struct spnego_context *sp_ctx)
292{
293 struct gse_context *gse_ctx;
294
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;
299 }
300
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;
311 }
312}
313
314NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
315 enum spnego_mech *type,
316 void **auth_context)
317{
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;
327 }
328
329 *type = sp_ctx->mech;
330 return NT_STATUS_OK;
331}
332
333DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
334 struct spnego_context *sp_ctx)
335{
336 DATA_BLOB sk;
337
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;
349 }
350}
351
352NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
353 struct spnego_context *sp_ctx,
354 DATA_BLOB *data, DATA_BLOB *full_data,
355 DATA_BLOB *signature)
356{
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;
371 }
372}
373
374NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
375 struct spnego_context *sp_ctx,
376 DATA_BLOB *data, DATA_BLOB *full_data,
377 DATA_BLOB *signature)
378{
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;
392 }
393}
394
395NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
396 struct spnego_context *sp_ctx,
397 DATA_BLOB *data, DATA_BLOB *full_data,
398 DATA_BLOB *signature)
399{
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;
414 }
415}
416
417NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
418 struct spnego_context *sp_ctx,
419 DATA_BLOB *data, DATA_BLOB *full_data,
420 DATA_BLOB *signature)
421{
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;
435 }
436}
Note: See TracBrowser for help on using the repository browser.