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