]> andersk Git - moira.git/blame - incremental/winad/ldap_adgssapi_bind.c
Support incrementals on the mcntmap table.
[moira.git] / incremental / winad / ldap_adgssapi_bind.c
CommitLineData
5d0a7127 1/*
2 * Copyright (C) 1998-2000 Luke Howard. All rights reserved.
3 * CONFIDENTIAL
4 * $Id$
5 *
6 * Implementation of GSS-API client side binding for SASL
7 */
8
9#ifdef _WIN32
10#include <windows.h>
11#endif
12#include <stdio.h>
13#include <string.h>
14#include <sys/types.h>
15#ifndef _WIN32
16#include <sys/uio.h>
cd9e6b16 17#include <sys/socket.h>
5d0a7127 18#include <netinet/in.h>
19#endif
20
cd9e6b16 21#include <arpa/nameser.h>
22#include <resolv.h>
23#include <lber.h>
5d0a7127 24#include <krb5.h>
25#include "ldap-int.h"
26#include "gssldap-int.h"
27
28#ifndef _WIN32
29typedef gss_uint32 OM_uint32;
30#endif
31
cd9e6b16 32char ldap_domain_name[128];
33
34#ifndef T_SRV
35#define T_SRV 33
36#endif
37#define LDAP_SERVICE "_ldap"
38#define TCP_PROTOCOL "_tcp"
39
40int locate_ldap_server(char *domain, char **server_name);
5d0a7127 41int ldap_delete_tickets(LDAP *ld, char *service_name);
cd9e6b16 42static int negotiate_security_options(gssldap_client_state_t state,
43 int layer);
5d0a7127 44int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name);
cd9e6b16 45unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
46 gsssasl_security_negotiation_t inmask,
47 size_t masklength, gss_buffer_t wrapped_tok);
48
5d0a7127 49int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
cd9e6b16 50 gss_buffer_t wrapped_tok,
51 gsssasl_security_negotiation_t *outmask,
52 size_t *masklength);
5d0a7127 53
54#ifdef GSSSASL_DEBUG
55static int debug_ = 1;
56#define TRACE(x) do { if (debug_) fprintf(stderr, "%s\n", x); fflush(stderr); } while (0);
57#define LDAP_PERROR(ld, x) do { if (debug_) ldap_perror(ld, x); } while (0);
58#define LOG_STATUS(msg, min, maj) log_status(msg, min, maj)
59#else
60#define TRACE(x)
61#define LDAP_PERROR(ld, x)
62#define LOG_STATUS(msg, min, maj)
cd9e6b16 63#endif /* GSSSASL_DEBUG */
5d0a7127 64
65#ifdef HACK_SERVICE_NAME
66char *__service = NULL;
67#endif
68
69/*
70 * The read and write fns need to access the context in here and
71 * there doesn't appear to be a way to pass this info to them.
72 */
73static gss_ctx_id_t security_context;
74static int security_layer = 0;
75static int security_token_size = 0;
76
cd9e6b16 77LDAP_CALLBACK int LDAP_C ldap_gssapi_read(LBER_SOCKET sock, void *data,
78 int len)
79{
80 OM_uint32 maj_stat;
81 OM_uint32 min_stat;
82 OM_uint32 rc;
83 OM_uint32 pdulen;
84 gss_buffer_desc recv_tok;
85 gss_buffer_desc wrapped_tok;
86
87 if (security_layer &
88 (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION))
89 {
90 if (recv(sock, (char *)&pdulen, sizeof(pdulen), 0) != sizeof(pdulen))
91 return (0);
92 wrapped_tok.length = ntohl(pdulen);
93#ifdef GSSSASL_DEBUG
94 if (debug_)
95 {
96 fprintf(stderr, "Reading data of %d octets\n",
97 wrapped_tok.length);
98 }
99#endif /* GSSSASL_DEBUG */
100 if ((int)wrapped_tok.length > security_token_size)
101 return (0);
102 wrapped_tok.value = malloc(wrapped_tok.length);
103 if (wrapped_tok.value == NULL)
104 return (0);
105 if (recv(sock, wrapped_tok.value, wrapped_tok.length, 0)
106 != (int)wrapped_tok.length)
107 {
108 gss_release_buffer(&rc, &wrapped_tok);
109 return (0);
110 }
111 maj_stat = gss_unwrap(&min_stat,
112 security_context,
113 &wrapped_tok,
114 &recv_tok,
115 &rc,
116 (gss_qop_t *) NULL);
117 if (maj_stat != GSS_S_COMPLETE)
118 {
119 gss_release_buffer(&rc, &wrapped_tok);
120 return maj_stat;
121 }
122#ifdef GSSSASL_DEBUG
123 if (debug_)
124 {
125 fprintf(stderr, "Got %d bytes of %s data\n",
126 recv_tok.length, rc ? "private" : "signed");
127 }
128#endif /* GSSSASL_DEBUG */
129 if ((int)recv_tok.length > len)
130 {
131 gss_release_buffer(&rc, &recv_tok);
132 gss_release_buffer(&rc, &wrapped_tok);
133 return GSS_S_FAILURE;
134 }
135 memcpy(data, recv_tok.value, recv_tok.length);
136 pdulen = recv_tok.length;
137 gss_release_buffer(&rc, &recv_tok);
138 gss_release_buffer(&rc, &wrapped_tok);
139
140 return pdulen;
141 }
142 else
143 return read(sock, data, len);
144}
145
146LDAP_CALLBACK int LDAP_C ldap_gssapi_write(LBER_SOCKET sock, const void *data,
147 int len)
148{
149 OM_uint32 maj_stat;
150 OM_uint32 min_stat;
151 OM_uint32 pdulen;
152 OM_uint32 rc;
153 gss_buffer_desc send_tok;
154 gss_buffer_desc wrapped_tok;
155 unsigned char *ptr;
156
157 if (security_layer &
158 (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION))
159 {
160 send_tok.length = len;
161 send_tok.value = (void *) data;
162#ifdef GSSSASL_DEBUG
163 if (debug_)
164 {
165 fprintf(stderr, "Sending %d bytes of data\n",
166 len);
167 }
168#endif /* GSSSASL_DEBUG */
169 maj_stat = gss_wrap(&min_stat,
170 security_context,
171 (security_layer & GSSSASL_PRIVACY_PROTECTION) ? 1 : 0,
172 GSS_C_QOP_DEFAULT,
173 &send_tok,
174 &rc,
175 &wrapped_tok);
176 if (maj_stat != GSS_S_COMPLETE)
177 return maj_stat;
178#ifdef GSSSASL_DEBUG
179 if (debug_)
180 {
181 fprintf(stderr, "Sent %d bytes of %s data\n",
182 wrapped_tok.length, rc ? "private" : "signed");
183 }
184#endif /* GSSSASL_DEBUG */
185 pdulen = htonl(wrapped_tok.length);
186 ptr = calloc(1, sizeof(pdulen) + wrapped_tok.length);
187 memcpy(ptr, &pdulen, sizeof(pdulen));
188 memcpy(&ptr[sizeof(pdulen)], wrapped_tok.value, wrapped_tok.length);
189 rc = send(sock, ptr, sizeof(pdulen) + wrapped_tok.length, 0);
190 free(ptr);
191 if (rc == (wrapped_tok.length + sizeof(pdulen)))
192 rc = len;
193 gss_release_buffer(&maj_stat, &wrapped_tok);
194 return rc;
195 }
196 else
197 return send(sock, data, len, 0);
198}
199
5d0a7127 200#ifdef GSSSASL_DEBUG
201/*
202 * Dump the token to stderr
203 */
204static void print_token(gss_buffer_t tok)
205{
206 int i;
207 unsigned char *p = tok->value;
cd9e6b16 208
5d0a7127 209 for (i = 0; i < (int)tok->length; i++, p++)
210 {
211 fprintf(stderr, "%02x ", *p);
212 if ((i % 16) == 15)
cd9e6b16 213 {
214 fprintf(stderr, "\n");
215 }
5d0a7127 216 }
217 fprintf(stderr, "\n");
218 fflush(stderr);
219 return;
220}
221
222/*
223 * Handle a GSS-API error
224 */
225static void log_status_impl(const char *reason, OM_uint32 res, int type)
226{
227 OM_uint32 maj_stat, min_stat;
228 gss_buffer_desc msg;
229 OM_uint32 msg_ctx;
230
231 msg_ctx = 0;
232 while (1)
233 {
cd9e6b16 234 maj_stat = gss_display_status(&min_stat,
235 res,
236 type,
237 GSS_C_NULL_OID,
238 &msg_ctx,
239 &msg);
5d0a7127 240
241 if (debug_)
cd9e6b16 242 {
243 fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n",
244 (char *) msg.value,
245 reason);
246 }
5d0a7127 247 (void) gss_release_buffer(&min_stat, &msg);
248 if (!msg_ctx)
cd9e6b16 249 break;
5d0a7127 250 }
251 return;
252}
253
254/*
255 * Cover function to handle a GSS-API error
256 */
cd9e6b16 257static void log_status(const char *reason, OM_uint32 maj_stat,
258 OM_uint32 min_stat)
5d0a7127 259{
260 log_status_impl(reason, maj_stat, GSS_C_GSS_CODE);
261 log_status_impl(reason, min_stat, GSS_C_MECH_CODE);
262 return;
263}
cd9e6b16 264#endif /* GSSSASL_DEBUG */
5d0a7127 265
266/*
267 * Send a GSS-API token as part of a SASL BindRequest
268 */
269static int send_token(gssldap_client_state_t state, gss_buffer_t send_tok)
270{
271 struct berval cred;
272
273 TRACE("==> send_token");
274
275 cred.bv_val = send_tok->value;
276 cred.bv_len = send_tok->length;
277
cd9e6b16 278 if (ldap_sasl_bind(state->ld,
279 state->binddn,
280 GSSAPI_SASL_NAME,
281 &cred,
282 NULL,
283 NULL,
284 &state->msgid) != LDAP_SUCCESS)
285 {
5d0a7127 286 LDAP_PERROR(state->ld, "send_token");
287 TRACE("<== send_token");
288 return -1;
289 }
290 TRACE("<== send_token");
291 return 0;
292}
293
294/*
295 * Parse the final result sent back from the server.
296 */
297static int parse_bind_result(gssldap_client_state_t state)
298{
299 LDAPMessage *res = NULL, *msg = NULL;
300 int rc;
301
302 TRACE("==> parse_bind_result");
303
cd9e6b16 304 if (ldap_result(state->ld,
305 state->msgid,
306 LDAP_MSG_ALL,
307 NULL,
308 &res) <= 0)
5d0a7127 309 {
310 LDAP_PERROR(state->ld, "ldap_result");
311 TRACE("<== parse_bind_result");
312 return -1;
313 }
cd9e6b16 314 for (msg = ldap_first_message(state->ld, res);
315 msg != NULL;
316 msg = ldap_next_message(state->ld, msg))
5d0a7127 317 {
318 if (ldap_msgtype(msg) == LDAP_RES_BIND)
cd9e6b16 319 {
320 ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0);
321 break;
322 }
323 }
5d0a7127 324
325 ldap_msgfree(res);
326 state->msgid = -1;
cd9e6b16 327
5d0a7127 328 TRACE("<== parse_bind_result");
cd9e6b16 329
5d0a7127 330 if (rc == LDAP_SUCCESS)
cd9e6b16 331 {
332 return 0;
333 }
5d0a7127 334 state->rc = rc;
335 return -1;
336}
337
338/*
339 * Receive a GSS-API token from a SASL BindResponse
340 * The contents of recv_tok must be freed by the
341 * caller.
342 */
343static int recv_token(gssldap_client_state_t state, gss_buffer_t recv_tok)
344{
345 struct berval *servercred = NULL;
346 LDAPMessage *res = NULL, *msg = NULL;
347 int rc;
348
349 TRACE("==> recv_token");
350
351 if (ldap_result(state->ld, state->msgid, LDAP_MSG_ALL, NULL, &res) <= 0)
352 {
353 LDAP_PERROR(state->ld, "ldap_result");
354 TRACE("<== recv_token");
355 return -1;
356 }
357 recv_tok->value = NULL;
358 recv_tok->length = 0;
359
cd9e6b16 360 for (msg = ldap_first_message(state->ld, res);
361 msg != NULL;
362 msg = ldap_next_message(state->ld, msg))
5d0a7127 363 {
cd9e6b16 364 if (ldap_msgtype(msg) == LDAP_RES_BIND && servercred == NULL)
365 {
366 rc = ldap_parse_sasl_bind_result(state->ld,
367 msg,
368 &servercred,
369 0);
370 if (rc == LDAP_SUCCESS && servercred != NULL)
371 {
372 recv_tok->value = malloc(servercred->bv_len);
373 if (recv_tok->value != NULL)
374 {
375 memcpy(recv_tok->value, servercred->bv_val, servercred->bv_len);
376 recv_tok->length = servercred->bv_len;
377 }
378 break;
379 }
380 else
381 {
382 state->rc = rc;
383 }
384 }
385 }
5d0a7127 386
387 ldap_msgfree(res);
388 state->msgid = -1;
389 TRACE("<== recv_token");
390 if (servercred != NULL)
391 {
cd9e6b16 392 nslberi_free(servercred);
5d0a7127 393 TRACE("<== recv_token");
394 return 0;
cd9e6b16 395 }
5d0a7127 396 if (state->rc == LDAP_SUCCESS)
cd9e6b16 397 {
398 state->rc = LDAP_OPERATIONS_ERROR;
399 }
5d0a7127 400 else
cd9e6b16 401 {
402 LDAP_PERROR(state->ld, "recv_token");
403 }
404
5d0a7127 405 TRACE("<== recv_token");
406 return -1;
407}
408
409/*
410 * The client calls GSS_Init_sec_context, passing in 0 for
411 * input_context_handle (initially) and a targ_name equal to output_name
412 * from GSS_Import_Name called with input_name_type of
413 * GSS_C_NT_HOSTBASED_SERVICE and input_name_string of
414 * "service@hostname" where "service" is the service name specified in
415 * the protocol's profile, and "hostname" is the fully qualified host
416 * name of the server. The client then responds with the resulting
417 * output_token. If GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED,
418 * then the client should expect the server to issue a token in a
419 * subsequent challenge. The client must pass the token to another call
420 * to GSS_Init_sec_context, repeating the actions in this paragraph.
421 */
422static int client_establish_context(LDAP *ld, gssldap_client_state_t state,
cd9e6b16 423 char *service_name)
5d0a7127 424{
425 gss_buffer_desc send_tok;
426 gss_buffer_desc recv_tok;
427 gss_buffer_desc *token_ptr;
cd9e6b16 428 gss_name_t target_name;
429 OM_uint32 maj_stat;
430 OM_uint32 min_stat;
431 gss_OID oid = GSS_C_NULL_OID;
432 OM_uint32 ret_flags;
5d0a7127 433
434 TRACE("==> client_establish_context");
435
436 memset(&recv_tok, '\0', sizeof(recv_tok));
437 send_tok.value = service_name;
438 send_tok.length = strlen(send_tok.value) + 1;
439
cd9e6b16 440 maj_stat = gss_import_name(&min_stat,
441 &send_tok,
442 (gss_OID) gss_nt_service_name,
443 &target_name);
5d0a7127 444 if (ldap_reset_principal(ld, service_name, target_name))
445 {
446 TRACE("<== client_establish_context");
447 return -1;
448 }
449
450 token_ptr = GSS_C_NO_BUFFER;
451 state->context = GSS_C_NO_CONTEXT;
cd9e6b16 452
5d0a7127 453 do
454 {
cd9e6b16 455 maj_stat = gss_init_sec_context(&min_stat,
456 GSS_C_NO_CREDENTIAL,
457 &state->context,
458 target_name,
459 oid,
460 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
461 0,
462 NULL,
463 token_ptr,
464 NULL,
465 &send_tok,
466 &ret_flags,
467 NULL);
5d0a7127 468
469 if (token_ptr != GSS_C_NO_BUFFER)
cd9e6b16 470 (void) gss_release_buffer(&min_stat, &recv_tok);
5d0a7127 471
472 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
cd9e6b16 473 {
474 LOG_STATUS("initializing context", maj_stat, min_stat);
475 (void) gss_release_name(&min_stat, &target_name);
476 TRACE("<== client_establish_context");
477 return -1;
478 }
5d0a7127 479#ifdef GSSSASL_DEBUG
480 if (debug_)
cd9e6b16 481 {
482 fprintf(stderr, "Sending init_sec_context token (size=%d)...\n",
483 send_tok.length);
484 fflush(stderr);
485 print_token(&send_tok);
486 }
5d0a7127 487#endif
488 if (send_token(state, &send_tok) < 0)
cd9e6b16 489 {
490 TRACE("Send_token failed");
491 (void) gss_release_buffer(&min_stat, &send_tok);
492 (void) gss_release_name(&min_stat, &target_name);
493 TRACE("<== client_establish_context");
494 return -1;
495 }
5d0a7127 496 (void) gss_release_buffer(&min_stat, &send_tok);
497 if (maj_stat == GSS_S_CONTINUE_NEEDED)
cd9e6b16 498 {
499 TRACE("continue needed...");
500 if (recv_token(state, &recv_tok) < 0)
501 {
502 TRACE("recv_token failed");
503 (void) gss_release_name(&min_stat, &target_name);
504 TRACE("<== client_establish_context");
505 return -1;
506 }
5d0a7127 507#ifdef GSSSASL_DEBUG
cd9e6b16 508 if (debug_)
509 {
510 fprintf(stderr, "Received token (size=%d)...\n",
511 recv_tok.length);
512 fflush(stderr);
513 print_token(&recv_tok);
514 }
5d0a7127 515#endif
cd9e6b16 516 token_ptr = &recv_tok;
517 }
5d0a7127 518 } while (maj_stat == GSS_S_CONTINUE_NEEDED);
519
520 (void) gss_release_name(&min_stat, &target_name);
cd9e6b16 521
5d0a7127 522 TRACE("<== client_establish_context");
523 return 0;
524}
525
526/*
527 * When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes
528 * the following actions: If the last call to GSS_Init_sec_context
529 * returned an output_token, then the client responds with the
530 * output_token, otherwise the client responds with no data. The client
531 * should then expect the server to issue a token in a subsequent
532 * challenge. The client passes this token to GSS_Unwrap and interprets
533 * the first octet of resulting cleartext as a bit-mask specifying the
534 * security layers supported by the server and the second through fourth
535 * octets as the maximum size output_message to send to the server. The
536 * client then constructs data, with the first octet containing the
537 * bit-mask specifying the selected security layer, the second through
538 * fourth octets containing in network byte order the maximum size
539 * output_message the client is able to receive, and the remaining
540 * octets containing the authorization identity. The client passes the
541 * data to GSS_Wrap with conf_flag set to FALSE, and responds with the
542 * generated output_message. The client can then consider the server
543 * authenticated.
544 */
cd9e6b16 545static int negotiate_security_options(gssldap_client_state_t state,
546 int layer)
5d0a7127 547{
cd9e6b16 548 OM_uint32 maj_stat;
549 OM_uint32 min_stat;
5d0a7127 550 gss_buffer_desc recv_tok;
551 gss_buffer_desc send_tok;
cd9e6b16 552 OM_uint32 rc;
553 size_t mask_length;
554 gsssasl_security_negotiation_t send_mask;
555 gsssasl_security_negotiation_t recv_mask;
556
5d0a7127 557 TRACE("==> negotiate_security_options");
cd9e6b16 558
5d0a7127 559 memset(&send_tok, '\0', sizeof(send_tok));
560 memset(&recv_tok, '\0', sizeof(recv_tok));
561 if ((rc = recv_token(state, &recv_tok)) < 0)
562 {
563 TRACE("<== negotiate_security_options (recv_token failed)");
564 return rc;
565 }
566#ifdef GSSSASL_DEBUG
567 if (debug_)
cd9e6b16 568 {
569 fprintf(stderr, "Received token (size=%d)...\n",
570 recv_tok.length);
571 fflush(stderr);
572 print_token(&recv_tok);
5d0a7127 573 }
cd9e6b16 574#endif /* GSSSASL_DEBUG */
575
576 maj_stat = gsssasl_unpack_security_token(&min_stat,
577 state->context,
578 &recv_tok,
579 &recv_mask,
580 &mask_length);
581
582 if (maj_stat != GSS_S_COMPLETE)
583 {
584 LOG_STATUS("unpacking security negotiation token",
585 maj_stat,
586 min_stat);
587 TRACE("<== negotiate_security_options (unpack failed)");
588 return -1;
589 }
5d0a7127 590#ifdef GSSSASL_DEBUG
cd9e6b16 591 if (debug_)
592 {
593 fprintf(stderr, "Received security token level %d size %d\n",
594 recv_mask->security_layer,
595 recv_mask->token_size);
5d0a7127 596 }
597#endif
cd9e6b16 598 if ((~recv_mask->security_layer) & layer)
599 {
600 free(recv_mask);
601 TRACE("<== negotiate_security_options (unsupported security layer)");
602 return -1;
5d0a7127 603 }
cd9e6b16 604 mask_length = sizeof(recv_mask) +
605 GSSAPI_LDAP_DN_PREFIX_LEN + strlen(state->binddn);
606 send_mask = NSLDAPI_MALLOC(mask_length);
607 if (send_mask == NULL)
608 {
609 free(recv_mask);
610 TRACE("<== negotiate_security_options (malloc failed)");
611 return -1;
612 }
613 send_mask->security_layer = layer;
614 send_mask->token_size = recv_mask->token_size;
615 memcpy(send_mask->identity, GSSAPI_LDAP_DN_PREFIX, GSSAPI_LDAP_DN_PREFIX_LEN);
616 memcpy(send_mask->identity + GSSAPI_LDAP_DN_PREFIX_LEN,
617 state->binddn,
618 mask_length - sizeof(recv_mask) - GSSAPI_LDAP_DN_PREFIX_LEN);
619 free(recv_mask);
620
5d0a7127 621#ifdef GSSSASL_DEBUG
cd9e6b16 622 if (debug_)
623 {
624 fprintf(stderr, "Sending security token level %d size %d\n",
625 send_mask->security_layer,
626 send_mask->token_size);
627 }
5d0a7127 628#endif
cd9e6b16 629 maj_stat = gsssasl_pack_security_token(&min_stat,
630 state->context,
631 send_mask,
632 mask_length,
633 &send_tok);
634 if (maj_stat != GSS_S_COMPLETE)
635 {
636 LOG_STATUS("packing security negotiation token", maj_stat, min_stat);
637 NSLDAPI_FREE(send_mask);
638 TRACE("<== negotiate_security_options (pack failed)");
639 return -1;
640 }
641 if ((rc = send_token(state, &send_tok)) < 0)
642 {
643 NSLDAPI_FREE(send_mask);
644 TRACE("<== negotiate_security_options (send_token failed)");
645 return rc;
646 }
647 rc = parse_bind_result(state);
648
649 if (rc == 0)
650 {
651 security_context = state->context;
652 security_layer = layer;
653 security_token_size = send_mask->token_size;
5d0a7127 654 }
5d0a7127 655
cd9e6b16 656 NSLDAPI_FREE(send_mask);
657 if (send_tok.value != NULL)
658 gss_release_buffer(&rc, &send_tok);
659 if (recv_tok.value != NULL)
660 gss_release_buffer(&rc, &recv_tok);
661 TRACE("<== negotiate_security_options");
662 return rc;
5d0a7127 663}
664
665#ifdef GSSSASL_DEBUG
666/*
667 * Temporary function to enable debugging
668 */
669LDAP_API(int)
670LDAP_CALL ldap_gssapi_debug(int on)
671{
672 int old = debug_;
673 debug_ = on;
674 return old;
675}
cd9e6b16 676#endif /* GSSSASL_DEBUG */
5d0a7127 677
678/*
679 * Public function for doing a GSS-API SASL bind
680 */
681LDAP_API(int)
682LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer)
683{
684 gssldap_client_state_desc state;
cd9e6b16 685 char *service_name;
686 OM_uint32 min_stat;
687 int rc;
688 int i;
689 struct ldap_io_fns iofns;
5d0a7127 690
691 if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL)
cd9e6b16 692 {
693 return -1;
694 }
695
5d0a7127 696 for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
697 ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
698
cd9e6b16 699 service_name =
700 NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + strlen(ld->ld_defhost));
5d0a7127 701 if (service_name == NULL)
cd9e6b16 702 {
703 return -1;
704 }
5d0a7127 705 strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@");
706 strcat(service_name, ld->ld_defhost);
707
708#ifdef GSSSASL_DEBUG
cd9e6b16 709 if (debug_)
710 {
711 fprintf(stderr, "LDAP service name: %s\n", service_name);
712 fflush(stderr);
713 }
5d0a7127 714#endif
715
cd9e6b16 716 state.msgid = -1;
717 state.ld = ld;
718 state.binddn = who;
719 state.context = GSS_C_NO_CONTEXT;
720 state.rc = LDAP_OPERATIONS_ERROR;
5d0a7127 721
cd9e6b16 722 rc = client_establish_context(ld, &state, service_name);
723 if (rc == 0)
724 {
5d0a7127 725 rc = negotiate_security_options(&state, layer);
cd9e6b16 726 }
727 if (rc == 0)
728 {
5d0a7127 729#ifdef GSSSASL_DEBUG
cd9e6b16 730 gss_buffer_desc tname;
731 gss_buffer_desc sname;
732 gss_name_t targ_name;
733 gss_name_t src_name;
734 OM_uint32 context_flags;
735 OM_uint32 lifetime;
736 OM_uint32 maj_stat;
737 int is_open;
738 int is_local;
739 gss_OID mechanism;
740 gss_OID name_type;
741
742 maj_stat = gss_inquire_context(&min_stat,
743 state.context,
744 &src_name,
745 &targ_name,
746 &lifetime,
747 &mechanism,
748 &context_flags,
749 &is_local,
750 &is_open);
751 if (maj_stat != GSS_S_COMPLETE)
752 {
753 LOG_STATUS("inquiring context", maj_stat, min_stat);
754 return LDAP_OPERATIONS_ERROR;
755 }
756 maj_stat = gss_display_name(&min_stat,
757 src_name,
758 &sname,
759 &name_type);
760 if (maj_stat != GSS_S_COMPLETE)
761 {
762 LOG_STATUS("displaying source name", maj_stat, min_stat);
763 return LDAP_OPERATIONS_ERROR;
764 }
765 maj_stat = gss_display_name(&min_stat,
766 targ_name,
767 &tname,
768 (gss_OID *) NULL);
769 if (maj_stat != GSS_S_COMPLETE)
770 {
771 LOG_STATUS("displaying target name", maj_stat, min_stat);
772 return LDAP_OPERATIONS_ERROR;
773 }
774 if (debug_)
775 {
776 fprintf(stderr,
777 "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
778 (int) sname.length, (char *) sname.value,
779 (int) tname.length, (char *) tname.value, lifetime,
780 context_flags,
781 (is_local) ? "locally initiated" : "remotely initiated",
782 (is_open) ? "open" : "closed");
783 fflush(stderr);
784 }
785 (void) gss_release_name(&min_stat, &src_name);
786 (void) gss_release_name(&min_stat, &targ_name);
787 (void) gss_release_buffer(&min_stat, &sname);
788 (void) gss_release_buffer(&min_stat, &tname);
5d0a7127 789#endif
cd9e6b16 790 state.rc = LDAP_SUCCESS;
791 }
5d0a7127 792
cd9e6b16 793 if (state.rc == LDAP_SUCCESS)
794 {
b9fa546a 795 if (layer == GSSSASL_PRIVACY_PROTECTION)
cd9e6b16 796 {
797 memset(&iofns, 0, sizeof(iofns));
798 iofns.liof_read = ldap_gssapi_read;
799 iofns.liof_write = ldap_gssapi_write;
800 state.rc = ldap_set_option(ld, LDAP_OPT_IO_FN_PTRS, &iofns);
801 }
802 }
803
804 NSLDAPI_FREE(service_name);
805 LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL);
806
807 return state.rc;
5d0a7127 808}
809
810/* Wrap and encode a security negotiation token */
cd9e6b16 811unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat,
812 gss_ctx_id_t context,
813 gsssasl_security_negotiation_t inmask,
814 size_t masklength, gss_buffer_t wrapped_tok)
5d0a7127 815{
cd9e6b16 816 OM_uint32 maj_stat;
817 OM_uint32 rc;
5d0a7127 818 gss_buffer_desc send_tok;
819
820 wrapped_tok->length = 0;
821 wrapped_tok->value = NULL;
822
823 if (masklength < sizeof(gsssasl_security_negotiation_desc))
824 return GSS_S_FAILURE;
825
826 inmask->token_size = htonl(inmask->token_size);
827
828 send_tok.length = masklength;
829 send_tok.value = inmask;
830
cd9e6b16 831 maj_stat = gss_wrap(min_stat,
832 context,
833 0,
834 GSS_C_QOP_DEFAULT,
835 &send_tok,
836 (int *)&rc,
837 wrapped_tok);
5d0a7127 838
839 inmask->token_size = ntohl(inmask->token_size);
840
841 return maj_stat;
842}
843
844/* Unwrap and decode a security negotiation token. */
cd9e6b16 845int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
846 gss_buffer_t wrapped_tok,
847 gsssasl_security_negotiation_t *outmask,
848 size_t *masklength)
5d0a7127 849{
cd9e6b16 850 OM_uint32 maj_stat;
851 OM_uint32 rc;
5d0a7127 852 gss_buffer_desc recv_tok;
853
854 *masklength = 0;
855 *outmask = NULL;
856 memset(&recv_tok, '\0', sizeof(recv_tok));
857
cd9e6b16 858 maj_stat = gss_unwrap(min_stat,
859 context,
860 wrapped_tok,
861 &recv_tok,
862 (int *)&rc,
863 (gss_qop_t *) NULL);
5d0a7127 864 if (maj_stat != GSS_S_COMPLETE)
865 return maj_stat;
866
cd9e6b16 867/*
5d0a7127 868#ifdef _WIN32
869 if (recv_tok.length < sizeof(gsssasl_security_negotiation_desc))
870 {
871 gss_release_buffer(&rc, &recv_tok);
872 return GSS_S_FAILURE;
873 }
cd9e6b16 874#endif
875*/
5d0a7127 876
cd9e6b16 877 /*
878 * we're lazy and don't copy the token. This could cause
879 * problems if libgssapi uses a different malloc!
880 */
5d0a7127 881 *masklength = recv_tok.length;
882 *outmask = (gsssasl_security_negotiation_t) recv_tok.value;
883 if (*outmask == NULL)
884 {
885 gss_release_buffer(&rc, &recv_tok);
886 return GSS_S_FAILURE;
887 }
888 return GSS_S_COMPLETE;
889}
890
891int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name)
892{
cd9e6b16 893 krb5_context context = NULL;
894 krb5_principal princ;
895 krb5_principal princ1;
896 krb5_principal temp_princ;
897 char *realm;
898 char *server_name = NULL;
899 int i;
5d0a7127 900
5d0a7127 901 princ = (krb5_principal)(target_name);
cd9e6b16 902
5d0a7127 903 if (krb5_init_context(&context))
cd9e6b16 904 return(-1);
905
906 realm = strdup(ldap_domain_name);
907 for (i = 0; i < (int)strlen(realm); i++)
908 realm[i] = toupper(realm[i]);
909 server_name = strdup(ld->ld_defhost);
910 for (i = 0; i < (int)strlen(server_name); i++)
911 server_name[i] = tolower(server_name[i]);
5d0a7127 912
5d0a7127 913 temp_princ = malloc(sizeof(*princ));
914 memcpy(temp_princ, princ, sizeof(*princ));
915
cd9e6b16 916 krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap",
917 server_name, ldap_domain_name, 0);
5d0a7127 918
919 memcpy(princ, princ1, sizeof(*princ1));
920 free(princ1);
921 krb5_free_principal(context, temp_princ);
cd9e6b16 922
923 if (realm != NULL)
924 free(realm);
925 if (server_name != NULL)
926 free(server_name);
5d0a7127 927 if (context != NULL)
928 krb5_free_context(context);
cd9e6b16 929 return(0);
5d0a7127 930}
931
932int ldap_delete_tickets(LDAP *ld, char *service_name)
933{
cd9e6b16 934 int i;
935 int rc;
936 krb5_context context = NULL;
937 krb5_ccache v5Cache = NULL;
938 krb5_creds creds;
939 krb5_cc_cursor v5Cursor;
5d0a7127 940 krb5_error_code code;
cd9e6b16 941 char *sServerName;
5d0a7127 942
943 if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL)
cd9e6b16 944 {
945 return -1;
946 }
5d0a7127 947
948 for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
949 ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
950
951 rc = -1;
952
953 if (krb5_init_context(&context))
954 return(rc);
955
956 if (krb5_cc_default(context, &v5Cache))
957 goto cleanup;
958 if (krb5_cc_start_seq_get(context, v5Cache, &v5Cursor))
959 goto cleanup;
960
961 memset(&creds, '\0', sizeof(creds));
962
963 while (!(code = krb5_cc_next_cred(context, v5Cache, &v5Cursor, &creds)))
964 {
965 if (krb5_unparse_name(context, creds.server, &sServerName))
cd9e6b16 966 {
967 krb5_free_cred_contents(context, &creds);
968 continue;
969 }
5d0a7127 970 if (!memcmp(sServerName, service_name, strlen(service_name)))
cd9e6b16 971 {
972 krb5_cc_remove_cred(context, v5Cache, 0, &creds);
973 }
5d0a7127 974 continue;
975 }
cd9e6b16 976
5d0a7127 977 if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))
cd9e6b16 978 {
979 krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
980 }
5d0a7127 981 rc = 0;
982
983cleanup:
984 if ((v5Cache != NULL) && (context != NULL))
985 krb5_cc_close(context, v5Cache);
986 if (context != NULL)
987 krb5_free_context(context);
988 return(rc);
989}
cd9e6b16 990
991int locate_ldap_server(char *domain, char **server_name)
992{
993 char service[128];
994 char host[128];
995 int location_type;
996 int length;
997 int rc;
998 int return_code;
999 int entry_length;
1000 int server_count;
1001 unsigned char reply[1024];
1002 unsigned char *ptr;
1003
1004 strcpy(ldap_domain_name, domain);
1005 sprintf(service, "%s.%s.%s.", LDAP_SERVICE, TCP_PROTOCOL, domain);
1006
1007 return_code = -1;
1008 server_count = 0;
1009 memset(reply, '\0', sizeof(reply));
1010 length = res_search(service, C_IN, T_SRV, reply, sizeof(reply));
1011 if (length >= 0)
1012 {
1013 ptr = reply;
1014 ptr += sizeof(HEADER);
1015 if ((rc = dn_expand(reply, reply + length, ptr, host,
1016 sizeof(host))) < 0)
1017 return(-1);
1018 ptr += (rc + 4);
1019
1020 while (ptr < reply + length)
1021 {
1022 if ((rc = dn_expand(reply, reply + length, ptr, host,
1023 sizeof(host))) < 0)
1024 break;
1025 ptr += rc;
1026 location_type = (ptr[0] << 8) | ptr[1];
1027 ptr += 8;
1028 entry_length = (ptr[0] << 8) | ptr[1];
1029 ptr += 2;
1030 if (location_type == T_SRV)
1031 {
1032 if ((rc = dn_expand(reply, reply + length, ptr + 6, host,
1033 sizeof(host))) < 0)
1034 return -1;
1035
1036 (*server_name) = strdup(host);
1037 ++server_name;
1038 return_code = 1;
1039 server_count++;
1040 }
1041 ptr += entry_length;
1042 }
1043 }
1044 return(return_code);
1045}
This page took 0.216429 seconds and 5 git commands to generate.