]> andersk Git - moira.git/blob - incremental/ldap/ldap_adgssapi_bind.c
New incremental code, existing side by side by winad.incr for now.
[moira.git] / incremental / ldap / 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 #ifndef T_SRV
33 #define T_SRV 33
34 #endif
35 #define LDAP_SERVICE    "_ldap"
36 #define TCP_PROTOCOL    "_tcp"
37
38 int locate_ldap_server(char *domain, char **server_name);
39 int ldap_delete_tickets(LDAP *ld, char *service_name);
40 static int negotiate_security_options(gssldap_client_state_t state, 
41                                       int layer);
42 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name, 
43                          char *ldap_realm_name);
44 unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
45                                           gsssasl_security_negotiation_t inmask,
46                                           size_t masklength, gss_buffer_t wrapped_tok);
47
48 int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context,
49                                   gss_buffer_t wrapped_tok,
50                                   gsssasl_security_negotiation_t *outmask,
51                                   size_t *masklength);
52
53 #ifdef GSSSASL_DEBUG
54 static int debug_ = 1;
55 #define TRACE(x) do { if (debug_) fprintf(stderr, "%s\n", x); fflush(stderr); } while (0);
56 #define LDAP_PERROR(ld, x) do { if (debug_) ldap_perror(ld, x); } while (0);
57 #define LOG_STATUS(msg, min, maj) log_status(msg, min, maj)
58 #else
59 #define TRACE(x)
60 #define LDAP_PERROR(ld, x)
61 #define LOG_STATUS(msg, min, maj)
62 #endif  /* GSSSASL_DEBUG */
63
64 #ifdef HACK_SERVICE_NAME
65 char *__service = NULL;
66 #endif
67
68 /*
69  * The read and write fns need to access the context in here and
70  * there doesn't appear to be a way to pass this info to them.
71  */
72 static gss_ctx_id_t security_context;
73 static int security_layer = 0;
74 static unsigned long security_token_size = 0;
75
76 LDAP_CALLBACK int LDAP_C ldap_gssapi_read(LBER_SOCKET sock, void *data,
77                                           int len)
78 {
79   OM_uint32   maj_stat;
80   OM_uint32   min_stat;
81   OM_uint32   rc;
82   OM_uint32   pdulen;
83   gss_buffer_desc recv_tok;
84   gss_buffer_desc wrapped_tok;
85   int         count;
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       count = recv(sock, wrapped_tok.value, wrapped_tok.length, 0);
106       if (count != (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
146 LDAP_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
200 #ifdef GSSSASL_DEBUG
201 /*
202  * Dump the token to stderr
203  */
204 static void print_token(gss_buffer_t tok)
205 {
206   int i;
207   unsigned char *p = tok->value;
208
209   for (i = 0; i < (int)tok->length; i++, p++)
210     {
211       fprintf(stderr, "%02x ", *p);
212       if ((i % 16) == 15)
213         {
214           fprintf(stderr, "\n");
215         }
216     }
217   fprintf(stderr, "\n");
218   fflush(stderr);
219   return;
220 }
221
222 /*
223  * Handle a GSS-API error
224  */
225 static 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     {
234       maj_stat = gss_display_status(&min_stat,
235                                     res,
236                                     type,
237                                     GSS_C_NULL_OID,
238                                     &msg_ctx,
239                                     &msg);
240
241       if (debug_)
242         {
243           fprintf(stderr, "ldap_adgssapi_bind: %s: %s\n",
244                   (char *) msg.value,
245                   reason);
246         }
247       (void) gss_release_buffer(&min_stat, &msg);
248       if (!msg_ctx)
249         break;
250     }
251   return;
252 }
253
254 /*
255  * Cover function to handle a GSS-API error
256  */
257 static void log_status(const char *reason, OM_uint32 maj_stat,
258                        OM_uint32 min_stat)
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 }
264 #endif  /* GSSSASL_DEBUG */
265
266 /*
267  * Send a GSS-API token as part of a SASL BindRequest
268  */
269 static 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
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         {
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  */
297 static 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
304   if (ldap_result(state->ld,
305                   state->msgid,
306                   LDAP_MSG_ALL,
307                   NULL,
308                   &res) <= 0) 
309     {
310       LDAP_PERROR(state->ld, "ldap_result");
311       TRACE("<== parse_bind_result");
312       return -1;
313     }
314   for (msg = ldap_first_message(state->ld, res);
315   msg != NULL;
316   msg = ldap_next_message(state->ld, msg)) 
317     {
318       if (ldap_msgtype(msg) == LDAP_RES_BIND)
319         {
320           ldap_parse_result(state->ld, msg, &rc, NULL, NULL, NULL, NULL, 0);
321           break;
322         }
323      }
324
325   ldap_msgfree(res);
326   state->msgid = -1;
327
328   TRACE("<== parse_bind_result");
329
330   if (rc == LDAP_SUCCESS) 
331     {
332       return 0;
333     }
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  */
343 static 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
360   for (msg = ldap_first_message(state->ld, res);
361   msg != NULL;
362   msg = ldap_next_message(state->ld, msg)) 
363     {
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   }
386
387   ldap_msgfree(res);
388   state->msgid = -1;
389   TRACE("<== recv_token");
390   if (servercred != NULL) 
391     {
392        nslberi_free(servercred);
393       TRACE("<== recv_token");
394       return 0;
395       }
396   if (state->rc == LDAP_SUCCESS) 
397     {
398       state->rc = LDAP_OPERATIONS_ERROR;
399     } 
400   else 
401     {
402       LDAP_PERROR(state->ld, "recv_token");
403     }
404
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  */
422 static int client_establish_context(LDAP *ld, gssldap_client_state_t state, 
423                                     char *service_name, char *ldap_realm_name)
424 {
425   gss_buffer_desc send_tok;
426   gss_buffer_desc recv_tok;
427   gss_buffer_desc *token_ptr;
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;
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
440   maj_stat = gss_import_name(&min_stat,
441                              &send_tok,
442                              (gss_OID) gss_nt_service_name,
443                              &target_name);
444   if (maj_stat)
445     return -1;
446   if (ldap_reset_principal(ld, service_name, target_name, ldap_realm_name))
447     {
448       TRACE("<== client_establish_context");
449       return -1;
450     }
451
452   token_ptr = GSS_C_NO_BUFFER;
453   state->context = GSS_C_NO_CONTEXT;
454
455   do 
456     {
457       maj_stat = gss_init_sec_context(&min_stat,
458                                         GSS_C_NO_CREDENTIAL,
459                                         &state->context,
460                                         target_name,
461                                         oid,
462                                         GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
463                                         0,
464                                         NULL,
465                                         token_ptr,
466                                         NULL,
467                                         &send_tok,
468                                         &ret_flags,
469                                         NULL);
470
471       if (token_ptr != GSS_C_NO_BUFFER)
472         (void) gss_release_buffer(&min_stat, &recv_tok);
473
474       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
475         {
476           LOG_STATUS("initializing context", maj_stat, min_stat);
477           (void) gss_release_name(&min_stat, &target_name);
478           TRACE("<== client_establish_context");
479           return -1;
480         }
481 #ifdef GSSSASL_DEBUG
482       if (debug_) 
483         {
484           fprintf(stderr, "Sending init_sec_context token (size=%d)...\n",
485           send_tok.length);
486           fflush(stderr);
487           print_token(&send_tok);
488         }
489 #endif
490       if (send_token(state, &send_tok) < 0)
491         {
492           TRACE("Send_token failed");
493           (void) gss_release_buffer(&min_stat, &send_tok);
494           (void) gss_release_name(&min_stat, &target_name);
495           TRACE("<== client_establish_context");
496           return -1;
497         }
498       (void) gss_release_buffer(&min_stat, &send_tok);
499       if (maj_stat == GSS_S_CONTINUE_NEEDED) 
500         {
501           TRACE("continue needed...");
502           if (recv_token(state, &recv_tok) < 0) 
503             {
504               TRACE("recv_token failed");
505               (void) gss_release_name(&min_stat, &target_name);
506               TRACE("<== client_establish_context");
507               return -1;
508             }
509 #ifdef GSSSASL_DEBUG
510           if (debug_)
511             {
512               fprintf(stderr, "Received token (size=%d)...\n",
513               recv_tok.length);
514               fflush(stderr);
515               print_token(&recv_tok);
516             }
517 #endif
518           token_ptr = &recv_tok;
519         }
520     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
521
522   (void) gss_release_name(&min_stat, &target_name);
523
524   TRACE("<== client_establish_context");
525   return 0;
526 }
527
528 /*
529  * When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes
530  * the following actions: If the last call to GSS_Init_sec_context
531  * returned an output_token, then the client responds with the
532  * output_token, otherwise the client responds with no data.  The client
533  * should then expect the server to issue a token in a subsequent
534  * challenge.  The client passes this token to GSS_Unwrap and interprets
535  * the first octet of resulting cleartext as a bit-mask specifying the
536  * security layers supported by the server and the second through fourth
537  * octets as the maximum size output_message to send to the server.  The
538  * client then constructs data, with the first octet containing the
539  * bit-mask specifying the selected security layer, the second through
540  * fourth octets containing in network byte order the maximum size
541  * output_message the client is able to receive, and the remaining
542  * octets containing the authorization identity.  The client passes the
543  * data to GSS_Wrap with conf_flag set to FALSE, and responds with the
544  * generated output_message.  The client can then consider the server
545  * authenticated.
546  */
547 static int negotiate_security_options(gssldap_client_state_t state, 
548                                       int layer)
549 {
550   OM_uint32       maj_stat;
551   OM_uint32       min_stat;
552   gss_buffer_desc recv_tok;
553   gss_buffer_desc send_tok;
554   OM_uint32       rc;
555   OM_uint32       ret;
556   size_t          mask_length;
557   gsssasl_security_negotiation_t  send_mask;
558   gsssasl_security_negotiation_t  recv_mask;
559
560   TRACE("==> negotiate_security_options");
561
562   memset(&send_tok, '\0', sizeof(send_tok));
563   memset(&recv_tok, '\0', sizeof(recv_tok));
564   if ((rc = recv_token(state, &recv_tok)) < 0)
565     {
566       TRACE("<== negotiate_security_options (recv_token failed)");
567       return rc;
568     }
569 #ifdef GSSSASL_DEBUG
570   if (debug_)
571     {
572       fprintf(stderr, "Received token (size=%d)...\n",
573       recv_tok.length);
574       fflush(stderr);
575       print_token(&recv_tok);
576       }
577 #endif  /* GSSSASL_DEBUG */
578
579   maj_stat = gsssasl_unpack_security_token(&min_stat,
580                                            state->context,
581                                            &recv_tok,
582                                            &recv_mask,
583                                            &mask_length);
584
585   if (maj_stat != GSS_S_COMPLETE)
586     {
587       LOG_STATUS("unpacking security negotiation token",
588                  maj_stat,
589                  min_stat);
590       TRACE("<== negotiate_security_options (unpack failed)");
591       return -1;
592     }
593 #ifdef GSSSASL_DEBUG
594   if (debug_) 
595     {
596       fprintf(stderr, "Received security token level %d size %d\n",
597       recv_mask->security_layer,
598       recv_mask->token_size);
599       }
600 #endif
601   if ((~recv_mask->security_layer) & layer) 
602     {
603       free(recv_mask);
604       TRACE("<== negotiate_security_options (unsupported security layer)");
605       return -1;
606       }
607   mask_length = sizeof(recv_mask);
608   send_mask = NSLDAPI_MALLOC(mask_length);
609   if (send_mask == NULL) 
610     {
611       free(recv_mask);
612       TRACE("<== negotiate_security_options (malloc failed)");
613       return -1;
614     }
615   memset(send_mask, '\0', mask_length);
616   send_mask->security_layer = layer;
617   send_mask->token_size = recv_mask->token_size;
618   memcpy(send_mask->identity, "", strlen(""));
619   free(recv_mask);
620
621 #ifdef GSSSASL_DEBUG
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     }
628 #endif
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   ret = rc;
650   if (rc == 0) 
651     {
652       security_context = state->context;
653       security_layer = layer;
654       security_token_size = ntohl(send_mask->token_size);
655 #ifdef _WIN32
656       security_token_size >>= 8;
657 #endif
658       }
659
660   NSLDAPI_FREE(send_mask);
661   if (send_tok.value != NULL)
662     gss_release_buffer(&rc, &send_tok);
663   if (recv_tok.value != NULL)
664     gss_release_buffer(&rc, &recv_tok);
665   TRACE("<== negotiate_security_options");
666   return ret;
667 }
668
669 #ifdef GSSSASL_DEBUG
670 /*
671  * Temporary function to enable debugging
672  */
673 LDAP_API(int)
674 LDAP_CALL ldap_gssapi_debug(int on)
675 {
676   int old = debug_;
677   debug_ = on;
678   return old;
679 }
680 #endif  /* GSSSASL_DEBUG */
681
682 /*
683  * Public function for doing a GSS-API SASL bind
684  */
685 LDAP_API(int)
686      LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer, 
687                                   char *ldap_domain_name, 
688                                   char *ldap_realm_name, char *server)
689 {
690   gssldap_client_state_desc state;
691   char        *service_name;
692   OM_uint32   min_stat;
693   int         rc;
694   int         i;
695   struct ldap_io_fns iofns;
696   char        *realm;
697
698   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
699     {
700       return -1;
701     }
702
703   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
704     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
705
706   service_name = 
707     NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + 
708                    strlen(server));
709   if (service_name == NULL) 
710     {
711       return -1;
712     }
713   strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@");
714   strcat(service_name, lowercase(server));
715   free(realm);
716
717 #ifdef GSSSASL_DEBUG
718   if (debug_) 
719     {
720       fprintf(stderr, "LDAP service name: %s\n", service_name);
721       fflush(stderr);
722     }
723 #endif
724
725   state.msgid = -1;
726   state.ld = ld;
727   state.binddn = who;
728   state.context = GSS_C_NO_CONTEXT;
729   state.rc = LDAP_OPERATIONS_ERROR;
730
731   rc = client_establish_context(ld, &state, service_name, ldap_realm_name);
732   if (rc == 0) 
733     {
734       rc = negotiate_security_options(&state, layer);
735     }
736   if (rc == 0) 
737     {
738 #ifdef GSSSASL_DEBUG
739       gss_buffer_desc tname;
740       gss_buffer_desc sname;
741       gss_name_t      targ_name;
742       gss_name_t      src_name;
743       OM_uint32       context_flags;
744       OM_uint32       lifetime;
745       OM_uint32       maj_stat;
746       int             is_open;
747       int             is_local;
748       gss_OID         mechanism;
749       gss_OID         name_type;
750
751       maj_stat = gss_inquire_context(&min_stat,
752                                       state.context,
753                                       &src_name,
754                                       &targ_name,
755                                       &lifetime,
756                                       &mechanism,
757                                       &context_flags,
758                                       &is_local,
759                                       &is_open);
760       if (maj_stat != GSS_S_COMPLETE) 
761         {
762           LOG_STATUS("inquiring context", maj_stat, min_stat);
763           return LDAP_OPERATIONS_ERROR;
764         }
765       maj_stat = gss_display_name(&min_stat,
766                                   src_name,
767                                   &sname,
768                                   &name_type);
769       if (maj_stat != GSS_S_COMPLETE) 
770         {
771           LOG_STATUS("displaying source name", maj_stat, min_stat);
772           return LDAP_OPERATIONS_ERROR;
773         }
774       maj_stat = gss_display_name(&min_stat,
775                                   targ_name,
776                                   &tname,
777                                   (gss_OID *) NULL);
778       if (maj_stat != GSS_S_COMPLETE) 
779         {
780           LOG_STATUS("displaying target name", maj_stat, min_stat);
781           return LDAP_OPERATIONS_ERROR;
782         }
783       if (debug_) 
784         {
785           fprintf(stderr, 
786                   "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
787                   (int) sname.length, (char *) sname.value,
788                   (int) tname.length, (char *) tname.value, lifetime,
789                   context_flags,
790                   (is_local) ? "locally initiated" : "remotely initiated",
791                   (is_open) ? "open" : "closed");
792           fflush(stderr);
793         }
794       (void) gss_release_name(&min_stat, &src_name);
795       (void) gss_release_name(&min_stat, &targ_name);
796       (void) gss_release_buffer(&min_stat, &sname);
797       (void) gss_release_buffer(&min_stat, &tname);
798 #endif
799       state.rc = LDAP_SUCCESS;
800     }
801
802   if (state.rc == LDAP_SUCCESS)
803     {
804       if (layer == GSSSASL_PRIVACY_PROTECTION)
805         {
806           memset(&iofns, 0, sizeof(iofns));
807           iofns.liof_read = ldap_gssapi_read;
808           iofns.liof_write = ldap_gssapi_write;
809           state.rc = ldap_set_option(ld, LDAP_OPT_IO_FN_PTRS, &iofns);
810         }
811     }
812
813   NSLDAPI_FREE(service_name);
814   LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL);
815
816   return state.rc;
817 }
818
819 /* Wrap and encode a security negotiation token */
820 unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, 
821                              gss_ctx_id_t context,
822                              gsssasl_security_negotiation_t inmask,
823                              size_t masklength, gss_buffer_t wrapped_tok)
824 {
825   OM_uint32       maj_stat;
826   OM_uint32       rc;
827   gss_buffer_desc send_tok;
828
829   wrapped_tok->length = 0;
830   wrapped_tok->value = NULL;
831
832 /*
833   if (masklength < sizeof(gsssasl_security_negotiation_desc))
834     return GSS_S_FAILURE;
835 */
836
837   inmask->token_size = inmask->token_size;
838
839   send_tok.length = masklength;
840   send_tok.value = inmask;
841
842   maj_stat = gss_wrap(min_stat,
843                       context,
844                       0,
845                       GSS_C_QOP_DEFAULT,
846                       &send_tok,
847                       (int *)&rc,
848                       wrapped_tok);
849
850 /*  inmask->token_size = ntohl(inmask->token_size);*/
851
852   return maj_stat;
853 }
854
855 /* Unwrap and decode a security negotiation token. */
856 int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, 
857                                   gss_buffer_t wrapped_tok,
858                                   gsssasl_security_negotiation_t *outmask, 
859                                   size_t *masklength)
860 {
861   OM_uint32       maj_stat;
862   OM_uint32       rc;
863   gss_buffer_desc recv_tok;
864
865   *masklength = 0;
866   *outmask = NULL;
867   memset(&recv_tok, '\0', sizeof(recv_tok));
868
869   maj_stat = gss_unwrap(min_stat,
870                         context,
871                         wrapped_tok,
872                         &recv_tok,
873                         (int *)&rc,
874                         (gss_qop_t *) NULL);
875   if (maj_stat != GSS_S_COMPLETE)
876     return maj_stat;
877
878 /*
879 #ifdef _WIN32
880   if (recv_tok.length < sizeof(gsssasl_security_negotiation_desc)) 
881     {
882       gss_release_buffer(&rc, &recv_tok);
883       return GSS_S_FAILURE;
884     }
885 #endif
886 */
887
888   /*
889    * we're lazy and don't copy the token. This could cause
890    * problems if libgssapi uses a different malloc!
891    */
892   *masklength = recv_tok.length;
893   *outmask = (gsssasl_security_negotiation_t) recv_tok.value;
894   if (*outmask == NULL) 
895     {
896       gss_release_buffer(&rc, &recv_tok);
897       return GSS_S_FAILURE;
898     }
899   return GSS_S_COMPLETE;
900 }
901
902 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name, 
903                          char *ldap_realm_name)
904 {
905   krb5_context    context = NULL;
906   krb5_principal  princ;
907   krb5_principal  princ1;
908   krb5_principal  temp_princ;
909   char            *realm;
910   char            *server_name = NULL;
911   int             i;
912
913   princ = (krb5_principal)(target_name);
914
915   if (krb5_init_context(&context))
916     return(-1);
917
918   realm = strdup(ldap_realm_name);
919   for (i = 0; i < (int)strlen(realm); i++)
920     realm[i] = toupper(realm[i]);
921   server_name = strdup(ld->ld_defhost);
922   for (i = 0; i < (int)strlen(server_name); i++)
923     server_name[i] = tolower(server_name[i]);
924
925   temp_princ = malloc(sizeof(*princ));
926   memcpy(temp_princ, princ, sizeof(*princ));
927
928   krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap", 
929                        server_name, NULL);
930
931   memcpy(princ, princ1, sizeof(*princ1));
932   free(princ1);
933   krb5_free_principal(context, temp_princ);
934
935   if (realm != NULL)
936     free(realm);
937   if (server_name != NULL)
938     free(server_name);
939   if (context != NULL)
940     krb5_free_context(context);
941   return(0);
942 }
943
944 int ldap_delete_tickets(LDAP *ld, char *service_name)
945 {
946   int             i;
947   int             rc;
948   krb5_context    context = NULL;
949   krb5_ccache     v5Cache = NULL;
950   krb5_creds      creds;
951   krb5_cc_cursor  v5Cursor;
952   krb5_error_code code;
953   char            *sServerName;
954
955   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
956     {
957       return -1;
958     }
959
960   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
961     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
962
963   rc = -1;
964
965   if (krb5_init_context(&context))
966     return(rc);
967
968   if (krb5_cc_default(context, &v5Cache))
969     goto cleanup;
970   if (krb5_cc_start_seq_get(context, v5Cache, &v5Cursor))
971     goto cleanup;
972
973   memset(&creds, '\0', sizeof(creds));
974
975   while (!(code = krb5_cc_next_cred(context, v5Cache, &v5Cursor, &creds))) 
976     {
977       if (krb5_unparse_name(context, creds.server, &sServerName))
978         {
979           krb5_free_cred_contents(context, &creds);
980           continue;
981         }
982       if (!memcmp(sServerName, service_name, strlen(service_name)))
983         {
984           krb5_cc_remove_cred(context, v5Cache, 0, &creds);
985         }
986       continue;
987     }
988
989   if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))
990     {
991       krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
992     }
993   rc = 0;
994
995 cleanup:
996   if ((v5Cache != NULL) && (context != NULL))
997     krb5_cc_close(context, v5Cache);
998   if (context != NULL)
999     krb5_free_context(context);
1000   return(rc);
1001 }
This page took 0.1221 seconds and 5 git commands to generate.