]> andersk Git - moira.git/blob - incremental/winad/ldap_adgssapi_bind.c
From dtanner, to deal with more recent Windows.
[moira.git] / incremental / winad / ldap_adgssapi_bind.c
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>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #endif
20
21 #include <arpa/nameser.h>
22 #include <resolv.h>
23 #include <lber.h>
24 #include <krb5.h>
25 #include "ldap-int.h"
26 #include "gssldap-int.h"
27
28 #ifndef _WIN32
29 typedef gss_uint32  OM_uint32;
30 #endif
31
32 char 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
40 int locate_ldap_server(char *domain, char **server_name);
41 int ldap_delete_tickets(LDAP *ld, char *service_name);
42 static int negotiate_security_options(gssldap_client_state_t state, 
43                                       int layer);
44 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name);
45 unsigned 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
49 int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
50                                   gss_buffer_t wrapped_tok,
51                                   gsssasl_security_negotiation_t *outmask,
52                                   size_t *masklength);
53
54 #ifdef GSSSASL_DEBUG
55 static 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)
63 #endif  /* GSSSASL_DEBUG */
64
65 #ifdef HACK_SERVICE_NAME
66 char *__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  */
73 static gss_ctx_id_t security_context;
74 static int security_layer = 0;
75 static unsigned long security_token_size = 0;
76
77 LDAP_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   int         count;
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);
106       count = recv(sock, wrapped_tok.value, wrapped_tok.length, 0);
107       if (count != (int)wrapped_tok.length)
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
147 LDAP_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
201 #ifdef GSSSASL_DEBUG
202 /*
203  * Dump the token to stderr
204  */
205 static void print_token(gss_buffer_t tok)
206 {
207   int i;
208   unsigned char *p = tok->value;
209
210   for (i = 0; i < (int)tok->length; i++, p++)
211     {
212       fprintf(stderr, "%02x ", *p);
213       if ((i % 16) == 15)
214         {
215           fprintf(stderr, "\n");
216         }
217     }
218   fprintf(stderr, "\n");
219   fflush(stderr);
220   return;
221 }
222
223 /*
224  * Handle a GSS-API error
225  */
226 static 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     {
235       maj_stat = gss_display_status(&min_stat,
236                                     res,
237                                     type,
238                                     GSS_C_NULL_OID,
239                                     &msg_ctx,
240                                     &msg);
241
242       if (debug_)
243         {
244           fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n",
245                   (char *) msg.value,
246                   reason);
247         }
248       (void) gss_release_buffer(&min_stat, &msg);
249       if (!msg_ctx)
250         break;
251     }
252   return;
253 }
254
255 /*
256  * Cover function to handle a GSS-API error
257  */
258 static void log_status(const char *reason, OM_uint32 maj_stat,
259                        OM_uint32 min_stat)
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 }
265 #endif  /* GSSSASL_DEBUG */
266
267 /*
268  * Send a GSS-API token as part of a SASL BindRequest
269  */
270 static 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
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         {
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  */
298 static 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
305   if (ldap_result(state->ld,
306                   state->msgid,
307                   LDAP_MSG_ALL,
308                   NULL,
309                   &res) <= 0) 
310     {
311       LDAP_PERROR(state->ld, "ldap_result");
312       TRACE("<== parse_bind_result");
313       return -1;
314     }
315   for (msg = ldap_first_message(state->ld, res);
316   msg != NULL;
317   msg = ldap_next_message(state->ld, msg)) 
318     {
319       if (ldap_msgtype(msg) == LDAP_RES_BIND)
320         {
321           ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0);
322           break;
323         }
324      }
325
326   ldap_msgfree(res);
327   state->msgid = -1;
328
329   TRACE("<== parse_bind_result");
330
331   if (rc == LDAP_SUCCESS) 
332     {
333       return 0;
334     }
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  */
344 static 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
361   for (msg = ldap_first_message(state->ld, res);
362   msg != NULL;
363   msg = ldap_next_message(state->ld, msg)) 
364     {
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   }
387
388   ldap_msgfree(res);
389   state->msgid = -1;
390   TRACE("<== recv_token");
391   if (servercred != NULL) 
392     {
393        nslberi_free(servercred);
394       TRACE("<== recv_token");
395       return 0;
396       }
397   if (state->rc == LDAP_SUCCESS) 
398     {
399       state->rc = LDAP_OPERATIONS_ERROR;
400     } 
401   else 
402     {
403       LDAP_PERROR(state->ld, "recv_token");
404     }
405
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  */
423 static int client_establish_context(LDAP *ld, gssldap_client_state_t state, 
424                                     char *service_name)
425 {
426   gss_buffer_desc send_tok;
427   gss_buffer_desc recv_tok;
428   gss_buffer_desc *token_ptr;
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;
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
441   maj_stat = gss_import_name(&min_stat,
442                              &send_tok,
443                              (gss_OID) gss_nt_service_name,
444                              &target_name);
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;
453
454   do 
455     {
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);
469
470       if (token_ptr != GSS_C_NO_BUFFER)
471         (void) gss_release_buffer(&min_stat, &recv_tok);
472
473       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
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         }
480 #ifdef GSSSASL_DEBUG
481       if (debug_) 
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         }
488 #endif
489       if (send_token(state, &send_tok) < 0)
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         }
497       (void) gss_release_buffer(&min_stat, &send_tok);
498       if (maj_stat == GSS_S_CONTINUE_NEEDED) 
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             }
508 #ifdef GSSSASL_DEBUG
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             }
516 #endif
517           token_ptr = &recv_tok;
518         }
519     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
520
521   (void) gss_release_name(&min_stat, &target_name);
522
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  */
546 static int negotiate_security_options(gssldap_client_state_t state, 
547                                       int layer)
548 {
549   OM_uint32       maj_stat;
550   OM_uint32       min_stat;
551   gss_buffer_desc recv_tok;
552   gss_buffer_desc send_tok;
553   OM_uint32       rc;
554   OM_uint32       ret;
555   size_t          mask_length;
556   gsssasl_security_negotiation_t  send_mask;
557   gsssasl_security_negotiation_t  recv_mask;
558
559   TRACE("==> negotiate_security_options");
560
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_)
570     {
571       fprintf(stderr, "Received token (size=%d)...\n",
572       recv_tok.length);
573       fflush(stderr);
574       print_token(&recv_tok);
575       }
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     }
592 #ifdef GSSSASL_DEBUG
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);
598       }
599 #endif
600   if ((~recv_mask->security_layer) & layer) 
601     {
602       free(recv_mask);
603       TRACE("<== negotiate_security_options (unsupported security layer)");
604       return -1;
605       }
606   mask_length = sizeof(recv_mask);
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     }
614   memset(send_mask, '\0', mask_length);
615   send_mask->security_layer = layer;
616   send_mask->token_size = recv_mask->token_size;
617   memcpy(send_mask->identity, "", strlen(""));
618   free(recv_mask);
619
620 #ifdef GSSSASL_DEBUG
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     }
627 #endif
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
648   ret = rc;
649   if (rc == 0) 
650     {
651       security_context = state->context;
652       security_layer = layer;
653       security_token_size = ntohl(send_mask->token_size);
654 #ifdef _WIN32
655       security_token_size >>= 8;
656 #endif
657       }
658
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");
665   return ret;
666 }
667
668 #ifdef GSSSASL_DEBUG
669 /*
670  * Temporary function to enable debugging
671  */
672 LDAP_API(int)
673 LDAP_CALL ldap_gssapi_debug(int on)
674 {
675   int old = debug_;
676   debug_ = on;
677   return old;
678 }
679 #endif  /* GSSSASL_DEBUG */
680
681 /*
682  * Public function for doing a GSS-API SASL bind
683  */
684 LDAP_API(int)
685 LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer)
686 {
687   gssldap_client_state_desc state;
688   char        *service_name;
689   OM_uint32   min_stat;
690   int         rc;
691   int         i;
692   struct ldap_io_fns iofns;
693   char        *realm;
694
695   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
696     {
697       return -1;
698     }
699
700   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
701     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
702
703   service_name = 
704     NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + strlen(ld->ld_defhost));
705   if (service_name == NULL) 
706     {
707       return -1;
708     }
709   strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@");
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);
715
716 #ifdef GSSSASL_DEBUG
717   if (debug_) 
718     {
719       fprintf(stderr, "LDAP service name: %s\n", service_name);
720       fflush(stderr);
721     }
722 #endif
723
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;
729
730   rc = client_establish_context(ld, &state, service_name);
731   if (rc == 0) 
732     {
733       rc = negotiate_security_options(&state, layer);
734     }
735   if (rc == 0) 
736     {
737 #ifdef GSSSASL_DEBUG
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);
797 #endif
798       state.rc = LDAP_SUCCESS;
799     }
800
801   if (state.rc == LDAP_SUCCESS)
802     {
803       if (layer == GSSSASL_PRIVACY_PROTECTION)
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;
816 }
817
818 /* Wrap and encode a security negotiation token */
819 unsigned 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)
823 {
824   OM_uint32       maj_stat;
825   OM_uint32       rc;
826   gss_buffer_desc send_tok;
827
828   wrapped_tok->length = 0;
829   wrapped_tok->value = NULL;
830
831 /*
832   if (masklength < sizeof(gsssasl_security_negotiation_desc))
833     return GSS_S_FAILURE;
834 */
835
836   inmask->token_size = inmask->token_size;
837
838   send_tok.length = masklength;
839   send_tok.value = inmask;
840
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);
848
849 /*  inmask->token_size = ntohl(inmask->token_size);*/
850
851   return maj_stat;
852 }
853
854 /* Unwrap and decode a security negotiation token. */
855 int 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)
859 {
860   OM_uint32       maj_stat;
861   OM_uint32       rc;
862   gss_buffer_desc recv_tok;
863
864   *masklength = 0;
865   *outmask = NULL;
866   memset(&recv_tok, '\0', sizeof(recv_tok));
867
868   maj_stat = gss_unwrap(min_stat,
869                         context,
870                         wrapped_tok,
871                         &recv_tok,
872                         (int *)&rc,
873                         (gss_qop_t *) NULL);
874   if (maj_stat != GSS_S_COMPLETE)
875     return maj_stat;
876
877 /*
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     }
884 #endif
885 */
886
887   /*
888    * we're lazy and don't copy the token. This could cause
889    * problems if libgssapi uses a different malloc!
890    */
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
901 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name)
902 {
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;
910
911   princ = (krb5_principal)(target_name);
912
913   if (krb5_init_context(&context))
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]);
922
923   temp_princ = malloc(sizeof(*princ));
924   memcpy(temp_princ, princ, sizeof(*princ));
925
926   krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap", 
927                        server_name, ldap_domain_name, 0);
928
929   memcpy(princ, princ1, sizeof(*princ1));
930   free(princ1);
931   krb5_free_principal(context, temp_princ);
932
933   if (realm != NULL)
934     free(realm);
935   if (server_name != NULL)
936     free(server_name);
937   if (context != NULL)
938     krb5_free_context(context);
939   return(0);
940 }
941
942 int ldap_delete_tickets(LDAP *ld, char *service_name)
943 {
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;
950   krb5_error_code code;
951   char            *sServerName;
952
953   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
954     {
955       return -1;
956     }
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))
976         {
977           krb5_free_cred_contents(context, &creds);
978           continue;
979         }
980       if (!memcmp(sServerName, service_name, strlen(service_name)))
981         {
982           krb5_cc_remove_cred(context, v5Cache, 0, &creds);
983         }
984       continue;
985     }
986
987   if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))
988     {
989       krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
990     }
991   rc = 0;
992
993 cleanup:
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 }
1000
1001 int 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 0.469713 seconds and 5 git commands to generate.