r3115: Bugfixes and extra debug in our kerberos verify code.
[Samba/gebeck_regimport.git] / source4 / libcli / auth / gensec_krb5.c
blob14e2f586c39ee96b8aa9f7e53e127bbbfbe587aa
1 /*
2 Unix SMB/CIFS implementation.
4 Kerberos backend for GENSEC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
7 Copyright (C) Andrew Tridgell 2001
8 Copyright (C) Luke Howard 2002-2003
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "includes.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_AUTH
31 enum GENSEC_KRB5_STATE {
32 GENSEC_KRB5_SERVER_START,
33 GENSEC_KRB5_CLIENT_START,
34 GENSEC_KRB5_CLIENT_MUTUAL_AUTH,
35 GENSEC_KRB5_DONE
38 struct gensec_krb5_state {
39 DATA_BLOB session_key;
40 struct PAC_LOGON_INFO *logon_info;
41 enum GENSEC_KRB5_STATE state_position;
42 krb5_context krb5_context;
43 krb5_auth_context krb5_auth_context;
44 krb5_ccache krb5_ccache;
45 krb5_data ticket;
46 krb5_keyblock krb5_keyblock;
47 char *peer_principal;
50 #ifdef KRB5_DO_VERIFY_PAC
51 static NTSTATUS gensec_krb5_pac_checksum(DATA_BLOB pac_data,
52 struct PAC_SIGNATURE_DATA *sig,
53 struct gensec_krb5_state *gensec_krb5_state,
54 uint32 keyusage)
56 krb5_error_code ret;
57 krb5_crypto crypto;
58 Checksum cksum;
59 int i;
61 cksum.cksumtype = (CKSUMTYPE)sig->type;
62 cksum.checksum.length = sizeof(sig->signature);
63 cksum.checksum.data = sig->signature;
66 ret = krb5_crypto_init(gensec_krb5_state->krb5_context,
67 &gensec_krb5_state->krb5_keyblock,
69 &crypto);
70 if (ret) {
71 DEBUG(0,("krb5_crypto_init() failed\n"));
72 return NT_STATUS_FOOBAR;
74 for (i=0; i < 40; i++) {
75 keyusage = i;
76 ret = krb5_verify_checksum(gensec_krb5_state->krb5_context,
77 crypto,
78 keyusage,
79 pac_data.data,
80 pac_data.length,
81 &cksum);
82 if (!ret) {
83 DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
84 break;
87 krb5_crypto_destroy(gensec_krb5_state->krb5_context, crypto);
89 if (ret) {
90 DEBUG(0,("NOT verifying PAC checksums yet!\n"));
91 //return NT_STATUS_LOGON_FAILURE;
92 } else {
93 DEBUG(0,("PAC checksums verified!\n"));
96 return NT_STATUS_OK;
98 #endif
100 static NTSTATUS gensec_krb5_decode_pac(TALLOC_CTX *mem_ctx,
101 struct PAC_LOGON_INFO **logon_info_out,
102 DATA_BLOB blob,
103 struct gensec_krb5_state *gensec_krb5_state)
105 NTSTATUS status;
106 struct PAC_SIGNATURE_DATA srv_sig;
107 struct PAC_SIGNATURE_DATA *srv_sig_ptr;
108 struct PAC_SIGNATURE_DATA kdc_sig;
109 struct PAC_SIGNATURE_DATA *kdc_sig_ptr;
110 struct PAC_LOGON_INFO *logon_info = NULL;
111 struct PAC_DATA pac_data;
112 #ifdef KRB5_DO_VERIFY_PAC
113 DATA_BLOB tmp_blob = data_blob(NULL, 0);
114 #endif
115 int i;
117 status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data,
118 (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
119 if (!NT_STATUS_IS_OK(status)) {
120 DEBUG(0,("can't parse the PAC\n"));
121 return status;
123 NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
125 if (pac_data.num_buffers < 3) {
126 /* we need logon_ingo, service_key and kdc_key */
127 DEBUG(0,("less than 3 PAC buffers\n"));
128 return NT_STATUS_FOOBAR;
131 for (i=0; i < pac_data.num_buffers; i++) {
132 switch (pac_data.buffers[i].type) {
133 case PAC_TYPE_LOGON_INFO:
134 if (!pac_data.buffers[i].info) {
135 break;
137 logon_info = &pac_data.buffers[i].info->logon_info;
138 break;
139 case PAC_TYPE_SRV_CHECKSUM:
140 if (!pac_data.buffers[i].info) {
141 break;
143 srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum;
144 srv_sig = pac_data.buffers[i].info->srv_cksum;
145 break;
146 case PAC_TYPE_KDC_CHECKSUM:
147 if (!pac_data.buffers[i].info) {
148 break;
150 kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum;
151 kdc_sig = pac_data.buffers[i].info->kdc_cksum;
152 break;
153 case PAC_TYPE_UNKNOWN_10:
154 break;
155 default:
156 break;
160 if (!logon_info) {
161 DEBUG(0,("PAC no logon_info\n"));
162 return NT_STATUS_FOOBAR;
165 if (!srv_sig_ptr) {
166 DEBUG(0,("PAC no srv_key\n"));
167 return NT_STATUS_FOOBAR;
170 if (!kdc_sig_ptr) {
171 DEBUG(0,("PAC no kdc_key\n"));
172 return NT_STATUS_FOOBAR;
174 #ifdef KRB5_DO_VERIFY_PAC
175 /* clear the kdc_key */
176 /* memset((void *)kdc_sig_ptr , '\0', sizeof(*kdc_sig_ptr));*/
178 status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
179 (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
180 if (!NT_STATUS_IS_OK(status)) {
181 return status;
183 status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
184 (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
185 if (!NT_STATUS_IS_OK(status)) {
186 DEBUG(0,("can't parse the PAC\n"));
187 return status;
189 /*NDR_PRINT_DEBUG(PAC_DATA, &pac_data);*/
191 /* verify by kdc_key */
192 status = gensec_krb5_pac_checksum(tmp_blob, &kdc_sig, gensec_krb5_state, 0);
194 if (!NT_STATUS_IS_OK(status)) {
195 return status;
198 /* clear the service_key */
199 /* memset((void *)srv_sig_ptr , '\0', sizeof(*srv_sig_ptr));*/
201 status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
202 (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
203 if (!NT_STATUS_IS_OK(status)) {
204 return status;
206 status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
207 (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
208 if (!NT_STATUS_IS_OK(status)) {
209 DEBUG(0,("can't parse the PAC\n"));
210 return status;
212 NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
214 /* verify by servie_key */
215 status = gensec_krb5_pac_checksum(tmp_blob, &srv_sig, gensec_krb5_state, 0);
217 if (!NT_STATUS_IS_OK(status)) {
218 return status;
220 #endif
221 DEBUG(0,("account_name: %s [%s]\n",logon_info->account_name.string, logon_info->full_name.string));
222 *logon_info_out = logon_info;
224 return status;
227 static void gensec_krb5_end(struct gensec_security *gensec_security)
229 struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
231 if (gensec_krb5_state->ticket.length) {
232 /* Hmm, early heimdal dooesn't have this - correct call would be krb5_data_free */
233 #ifdef HAVE_KRB5_FREE_DATA_CONTENTS
234 krb5_free_data_contents(gensec_krb5_state->krb5_context, &gensec_krb5_state->ticket);
235 #endif
237 if (gensec_krb5_state->krb5_ccache) {
238 /* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
239 krb5_cc_close(gensec_krb5_state->krb5_context, gensec_krb5_state->krb5_ccache);
242 krb5_free_keyblock_contents(gensec_krb5_state->krb5_context,
243 &gensec_krb5_state->krb5_keyblock);
245 if (gensec_krb5_state->krb5_auth_context) {
246 krb5_auth_con_free(gensec_krb5_state->krb5_context,
247 gensec_krb5_state->krb5_auth_context);
250 if (gensec_krb5_state->krb5_context) {
251 krb5_free_context(gensec_krb5_state->krb5_context);
254 talloc_free(gensec_krb5_state);
255 gensec_security->private_data = NULL;
259 static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
261 struct gensec_krb5_state *gensec_krb5_state;
262 krb5_error_code ret = 0;
264 gensec_krb5_state = talloc_p(gensec_security, struct gensec_krb5_state);
265 if (!gensec_krb5_state) {
266 return NT_STATUS_NO_MEMORY;
269 gensec_security->private_data = gensec_krb5_state;
271 initialize_krb5_error_table();
272 gensec_krb5_state->krb5_context = NULL;
273 gensec_krb5_state->krb5_auth_context = NULL;
274 gensec_krb5_state->krb5_ccache = NULL;
275 ZERO_STRUCT(gensec_krb5_state->ticket);
276 ZERO_STRUCT(gensec_krb5_state->krb5_keyblock);
277 gensec_krb5_state->session_key = data_blob(NULL, 0);
279 ret = krb5_init_context(&gensec_krb5_state->krb5_context);
280 if (ret) {
281 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n", error_message(ret)));
282 return NT_STATUS_INTERNAL_ERROR;
285 if (lp_realm() && *lp_realm()) {
286 ret = krb5_set_default_realm(gensec_krb5_state->krb5_context, lp_realm());
287 if (ret) {
288 DEBUG(1,("gensec_krb5_start: krb5_set_default_realm failed (%s)\n", error_message(ret)));
289 return NT_STATUS_INTERNAL_ERROR;
293 ret = krb5_auth_con_init(gensec_krb5_state->krb5_context, &gensec_krb5_state->krb5_auth_context);
294 if (ret) {
295 DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", error_message(ret)));
296 return NT_STATUS_INTERNAL_ERROR;
299 return NT_STATUS_OK;
302 static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security)
304 NTSTATUS nt_status;
305 struct gensec_krb5_state *gensec_krb5_state;
307 nt_status = gensec_krb5_start(gensec_security);
308 if (!NT_STATUS_IS_OK(nt_status)) {
309 return nt_status;
312 gensec_krb5_state = gensec_security->private_data;
313 gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START;
315 return NT_STATUS_OK;
318 static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security)
320 struct gensec_krb5_state *gensec_krb5_state;
321 krb5_error_code ret;
322 NTSTATUS nt_status;
324 nt_status = gensec_krb5_start(gensec_security);
325 if (!NT_STATUS_IS_OK(nt_status)) {
326 return nt_status;
329 gensec_krb5_state = gensec_security->private_data;
330 gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START;
332 /* TODO: This is effecivly a static/global variable... */
333 ret = krb5_cc_default(gensec_krb5_state->krb5_context, &gensec_krb5_state->krb5_ccache);
334 if (ret) {
335 DEBUG(1,("krb5_cc_default failed (%s)\n",
336 error_message(ret)));
337 return NT_STATUS_INTERNAL_ERROR;
340 while (1) {
341 if (gensec_security->target.principal) {
342 DEBUG(5, ("Finding ticket for target [%s]\n", gensec_security->target.principal));
343 ret = ads_krb5_mk_req(gensec_krb5_state->krb5_context,
344 &gensec_krb5_state->krb5_auth_context,
345 AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
346 gensec_security->target.principal,
347 gensec_krb5_state->krb5_ccache,
348 &gensec_krb5_state->ticket);
349 if (ret) {
350 DEBUG(1,("ads_krb5_mk_req failed (%s)\n",
351 error_message(ret)));
353 } else {
354 krb5_data in_data;
355 const char *hostname = gensec_get_target_hostname(gensec_security);
356 if (!hostname) {
357 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
358 return NT_STATUS_ACCESS_DENIED;
361 in_data.length = 0;
363 ret = krb5_mk_req(gensec_krb5_state->krb5_context,
364 &gensec_krb5_state->krb5_auth_context,
365 AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
366 gensec_get_target_service(gensec_security),
367 hostname,
368 &in_data, gensec_krb5_state->krb5_ccache,
369 &gensec_krb5_state->ticket);
370 if (ret) {
371 DEBUG(1,("krb5_mk_req failed (%s)\n",
372 error_message(ret)));
376 switch (ret) {
377 case 0:
378 return NT_STATUS_OK;
379 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
380 DEBUG(3, ("Server is not registered with our KDC: %s\n",
381 error_message(ret)));
382 return NT_STATUS_ACCESS_DENIED;
383 case KRB5KDC_ERR_PREAUTH_FAILED:
384 case KRB5KRB_AP_ERR_TKT_EXPIRED:
385 case KRB5_CC_END:
387 DEBUG(3, ("kerberos: %s\n",
388 error_message(ret)));
389 /* fall down to remaining code */
391 /* just don't print a message for these really ordinary messages */
392 case KRB5_FCC_NOFILE:
393 case KRB5_CC_NOTFOUND:
395 char *password;
396 time_t kdc_time = 0;
397 nt_status = gensec_get_password(gensec_security,
398 gensec_security,
399 &password);
400 if (!NT_STATUS_IS_OK(nt_status)) {
401 return nt_status;
404 ret = kerberos_kinit_password_cc(gensec_krb5_state->krb5_context, gensec_krb5_state->krb5_ccache,
405 gensec_get_client_principal(gensec_security, gensec_security),
406 password, NULL, &kdc_time);
408 /* cope with ticket being in the future due to clock skew */
409 if ((unsigned)kdc_time > time(NULL)) {
410 time_t t = time(NULL);
411 int time_offset =(unsigned)kdc_time-t;
412 DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
413 krb5_set_real_time(gensec_krb5_state->krb5_context, t + time_offset + 1, 0);
416 if (ret) {
417 DEBUG(1,("kinit failed (%s)\n",
418 error_message(ret)));
419 return NT_STATUS_WRONG_PASSWORD;
421 break;
423 default:
424 DEBUG(0, ("kerberos: %s\n",
425 error_message(ret)));
426 return NT_STATUS_UNSUCCESSFUL;
433 * Next state function for the Krb5 GENSEC mechanism
435 * @param gensec_krb5_state KRB5 State
436 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
437 * @param in The request, as a DATA_BLOB
438 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
439 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
440 * or NT_STATUS_OK if the user is authenticated.
443 static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
444 const DATA_BLOB in, DATA_BLOB *out)
446 struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
447 krb5_error_code ret = 0;
448 DATA_BLOB pac;
449 NTSTATUS nt_status;
451 switch (gensec_krb5_state->state_position) {
452 case GENSEC_KRB5_CLIENT_START:
454 if (ret) {
455 DEBUG(1,("ads_krb5_mk_req (request ticket) failed (%s)\n",
456 error_message(ret)));
457 nt_status = NT_STATUS_LOGON_FAILURE;
458 } else {
459 DATA_BLOB unwrapped_out;
461 #ifndef GENSEC_SEND_UNWRAPPED_KRB5 /* This should be a switch for the torture code to set */
462 unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
464 /* wrap that up in a nice GSS-API wrapping */
465 *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
466 #else
467 *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->ticket.data, gensec_krb5_state->ticket.length);
468 #endif
469 gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
470 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
473 return nt_status;
476 case GENSEC_KRB5_CLIENT_MUTUAL_AUTH:
478 krb5_data inbuf;
479 krb5_ap_rep_enc_part *repl = NULL;
480 uint8 tok_id[2];
481 DATA_BLOB unwrapped_in;
483 if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
484 DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n"));
485 dump_data_pw("Mutual authentication message:\n", in.data, in.length);
486 return NT_STATUS_INVALID_PARAMETER;
488 /* TODO: check the tok_id */
490 inbuf.data = unwrapped_in.data;
491 inbuf.length = unwrapped_in.length;
492 ret = krb5_rd_rep(gensec_krb5_state->krb5_context,
493 gensec_krb5_state->krb5_auth_context,
494 &inbuf, &repl);
495 if (ret) {
496 DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n",
497 error_message(ret)));
498 dump_data_pw("Mutual authentication message:\n", inbuf.data, inbuf.length);
499 nt_status = NT_STATUS_ACCESS_DENIED;
500 } else {
501 *out = data_blob(NULL, 0);
502 nt_status = NT_STATUS_OK;
503 gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
505 if (repl) {
506 krb5_free_ap_rep_enc_part(gensec_krb5_state->krb5_context, repl);
508 return nt_status;
511 case GENSEC_KRB5_SERVER_START:
513 char *principal;
514 DATA_BLOB unwrapped_in;
515 DATA_BLOB unwrapped_out;
516 uint8 tok_id[2];
518 /* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */
519 if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
520 nt_status = ads_verify_ticket(out_mem_ctx,
521 gensec_krb5_state->krb5_context,
522 gensec_krb5_state->krb5_auth_context,
523 lp_realm(), &in,
524 &principal, &pac, &unwrapped_out,
525 &gensec_krb5_state->krb5_keyblock);
526 } else {
527 /* TODO: check the tok_id */
528 nt_status = ads_verify_ticket(out_mem_ctx,
529 gensec_krb5_state->krb5_context,
530 gensec_krb5_state->krb5_auth_context,
531 lp_realm(), &unwrapped_in,
532 &principal, &pac, &unwrapped_out,
533 &gensec_krb5_state->krb5_keyblock);
536 if (!NT_STATUS_IS_OK(nt_status)) {
537 return nt_status;
540 if (pac.data) {
541 /* decode and verify the pac */
542 nt_status = gensec_krb5_decode_pac(gensec_krb5_state, &gensec_krb5_state->logon_info, pac,
543 gensec_krb5_state);
544 } else {
545 /* NULL PAC, we might need to figure this information out the hard way */
546 gensec_krb5_state->logon_info = NULL;
549 if (NT_STATUS_IS_OK(nt_status)) {
550 gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
551 /* wrap that up in a nice GSS-API wrapping */
552 *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP);
554 gensec_krb5_state->peer_principal = talloc_steal(gensec_krb5_state, principal);
556 return nt_status;
558 case GENSEC_KRB5_DONE:
559 return NT_STATUS_OK;
562 return NT_STATUS_INVALID_PARAMETER;
565 static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security,
566 DATA_BLOB *session_key)
568 struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
569 krb5_context context = gensec_krb5_state->krb5_context;
570 krb5_auth_context auth_context = gensec_krb5_state->krb5_auth_context;
571 krb5_keyblock *skey;
572 krb5_error_code err;
574 if (gensec_krb5_state->session_key.data) {
575 *session_key = gensec_krb5_state->session_key;
576 return NT_STATUS_OK;
579 switch (gensec_security->gensec_role) {
580 case GENSEC_CLIENT:
581 err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
582 break;
583 case GENSEC_SERVER:
584 err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
585 break;
587 if (err == 0 && skey != NULL) {
588 DEBUG(10, ("Got KRB5 session key of length %d\n", KRB5_KEY_LENGTH(skey)));
589 gensec_krb5_state->session_key = data_blob_talloc(gensec_krb5_state,
590 KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
591 *session_key = gensec_krb5_state->session_key;
592 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
594 krb5_free_keyblock(context, skey);
595 return NT_STATUS_OK;
596 } else {
597 DEBUG(10, ("KRB5 error getting session key %d\n", err));
598 return NT_STATUS_NO_USER_SESSION_KEY;
602 static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
603 struct auth_session_info **session_info_out)
605 NTSTATUS nt_status;
606 struct gensec_krb5_state *gensec_krb5_state = gensec_security->private_data;
607 struct auth_serversupplied_info *server_info = NULL;
608 struct auth_session_info *session_info = NULL;
609 struct PAC_LOGON_INFO *logon_info = gensec_krb5_state->logon_info;
610 struct nt_user_token *ptoken;
611 struct dom_sid *sid;
612 char *p;
613 char *principal;
615 *session_info_out = NULL;
617 nt_status = make_server_info(gensec_security, &server_info, gensec_krb5_state->peer_principal);
618 if (!NT_STATUS_IS_OK(nt_status)) {
619 return nt_status;
622 server_info->guest = False;
624 principal = talloc_strdup(server_info, gensec_krb5_state->peer_principal);
625 p = strchr(principal, '@');
626 if (p) {
627 *p = '\0';
629 server_info->account_name = principal;
630 server_info->domain = talloc_strdup(server_info, p++);
631 if (!server_info->domain) {
632 free_server_info(&server_info);
633 return NT_STATUS_NO_MEMORY;
636 nt_status = make_session_info(server_info, &session_info);
637 if (!NT_STATUS_IS_OK(nt_status)) {
638 free_server_info(&server_info);
639 return nt_status;
642 /* IF we have the PAC - otherwise (TODO) we need to get this
643 * data from elsewere - local ldb, or lookup of some
644 * kind... */
646 if (logon_info) {
647 ptoken = talloc_p(session_info, struct nt_user_token);
648 if (!ptoken) {
649 return NT_STATUS_NO_MEMORY;
652 ptoken->num_sids = 0;
654 ptoken->user_sids = talloc_array_p(ptoken, struct dom_sid*, logon_info->groups_count + 2);
655 if (!ptoken->user_sids) {
656 return NT_STATUS_NO_MEMORY;
660 sid = dom_sid_dup(session_info, logon_info->dom_sid);
661 ptoken->user_sids[0] = dom_sid_add_rid(session_info, sid, logon_info->user_rid);
662 ptoken->num_sids++;
663 sid = dom_sid_dup(session_info, logon_info->dom_sid);
664 ptoken->user_sids[1] = dom_sid_add_rid(session_info, sid, logon_info->group_rid);
665 ptoken->num_sids++;
667 for (;ptoken->num_sids < logon_info->groups_count; ptoken->num_sids++) {
668 sid = dom_sid_dup(session_info, logon_info->dom_sid);
669 ptoken->user_sids[ptoken->num_sids] = dom_sid_add_rid(session_info, sid, logon_info->groups[ptoken->num_sids - 2].rid);
672 debug_nt_user_token(DBGC_AUTH, 0, ptoken);
674 session_info->nt_user_token = ptoken;
675 } else {
676 session_info->nt_user_token = NULL;
679 nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key);
681 session_info->workstation = NULL;
683 *session_info_out = session_info;
685 return nt_status;
689 static const struct gensec_security_ops gensec_krb5_security_ops = {
690 .name = "krb5",
691 .auth_type = DCERPC_AUTH_TYPE_KRB5,
692 .oid = OID_KERBEROS5,
693 .client_start = gensec_krb5_client_start,
694 .server_start = gensec_krb5_server_start,
695 .update = gensec_krb5_update,
696 .session_key = gensec_krb5_session_key,
697 .session_info = gensec_krb5_session_info,
698 .end = gensec_krb5_end
701 static const struct gensec_security_ops gensec_ms_krb5_security_ops = {
702 .name = "ms_krb5",
703 .auth_type = DCERPC_AUTH_TYPE_KRB5,
704 .oid = OID_KERBEROS5_OLD,
705 .client_start = gensec_krb5_client_start,
706 .server_start = gensec_krb5_server_start,
707 .update = gensec_krb5_update,
708 .session_key = gensec_krb5_session_key,
709 .session_info = gensec_krb5_session_info,
710 .end = gensec_krb5_end
714 NTSTATUS gensec_krb5_init(void)
716 NTSTATUS ret;
718 ret = register_backend("gensec", &gensec_krb5_security_ops);
719 if (!NT_STATUS_IS_OK(ret)) {
720 DEBUG(0,("Failed to register '%s' gensec backend!\n",
721 gensec_krb5_security_ops.name));
722 return ret;
725 ret = register_backend("gensec", &gensec_ms_krb5_security_ops);
726 if (!NT_STATUS_IS_OK(ret)) {
727 DEBUG(0,("Failed to register '%s' gensec backend!\n",
728 gensec_krb5_security_ops.name));
729 return ret;
732 return ret;