]> andersk Git - moira.git/blob - incremental/winad/ldap_adgssapi_bind.c
Always reports email addresses of the form username@MIT.EDU, regardless
[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 int 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
87   if (security_layer & 
88     (GSSSASL_INTEGRITY_PROTECTION | GSSSASL_PRIVACY_PROTECTION))
89     {
90       if (recv(sock, (char *)&pdulen, sizeof(pdulen), 0) != sizeof(pdulen))
91         return (0);
92       wrapped_tok.length = ntohl(pdulen);
93 #ifdef GSSSASL_DEBUG
94       if (debug_)
95         {
96           fprintf(stderr, "Reading data of %d octets\n",
97                   wrapped_tok.length);
98         }
99 #endif  /* GSSSASL_DEBUG */
100       if ((int)wrapped_tok.length > security_token_size)
101         return (0);
102       wrapped_tok.value = malloc(wrapped_tok.length);
103       if (wrapped_tok.value == NULL)
104         return (0);
105       if (recv(sock, wrapped_tok.value, wrapped_tok.length, 0)
106           != (int)wrapped_tok.length)
107         {
108           gss_release_buffer(&rc, &wrapped_tok);
109           return (0);
110         }
111       maj_stat = gss_unwrap(&min_stat,
112                             security_context,
113                             &wrapped_tok,
114                             &recv_tok,
115                             &rc,
116                             (gss_qop_t *) NULL);
117       if (maj_stat != GSS_S_COMPLETE)
118         {
119           gss_release_buffer(&rc, &wrapped_tok);
120           return maj_stat;
121         }
122 #ifdef GSSSASL_DEBUG
123       if (debug_)
124         {
125           fprintf(stderr, "Got %d bytes of %s data\n",
126                   recv_tok.length, rc ? "private" : "signed");
127         }
128 #endif  /* GSSSASL_DEBUG */
129       if ((int)recv_tok.length > len)
130         {
131           gss_release_buffer(&rc, &recv_tok);
132           gss_release_buffer(&rc, &wrapped_tok);
133           return GSS_S_FAILURE;
134         }
135       memcpy(data, recv_tok.value, recv_tok.length);
136       pdulen = recv_tok.length;
137       gss_release_buffer(&rc, &recv_tok);
138       gss_release_buffer(&rc, &wrapped_tok);
139
140       return pdulen;
141     } 
142   else
143     return read(sock, data, len);
144 }
145
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)
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 (ldap_reset_principal(ld, service_name, target_name))
445     {
446       TRACE("<== client_establish_context");
447       return -1;
448     }
449
450   token_ptr = GSS_C_NO_BUFFER;
451   state->context = GSS_C_NO_CONTEXT;
452
453   do 
454     {
455       maj_stat = gss_init_sec_context(&min_stat,
456                                         GSS_C_NO_CREDENTIAL,
457                                         &state->context,
458                                         target_name,
459                                         oid,
460                                         GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
461                                         0,
462                                         NULL,
463                                         token_ptr,
464                                         NULL,
465                                         &send_tok,
466                                         &ret_flags,
467                                         NULL);
468
469       if (token_ptr != GSS_C_NO_BUFFER)
470         (void) gss_release_buffer(&min_stat, &recv_tok);
471
472       if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
473         {
474           LOG_STATUS("initializing context", maj_stat, min_stat);
475           (void) gss_release_name(&min_stat, &target_name);
476           TRACE("<== client_establish_context");
477           return -1;
478         }
479 #ifdef GSSSASL_DEBUG
480       if (debug_) 
481         {
482           fprintf(stderr, "Sending init_sec_context token (size=%d)...\n",
483           send_tok.length);
484           fflush(stderr);
485           print_token(&send_tok);
486         }
487 #endif
488       if (send_token(state, &send_tok) < 0)
489         {
490           TRACE("Send_token failed");
491           (void) gss_release_buffer(&min_stat, &send_tok);
492           (void) gss_release_name(&min_stat, &target_name);
493           TRACE("<== client_establish_context");
494           return -1;
495         }
496       (void) gss_release_buffer(&min_stat, &send_tok);
497       if (maj_stat == GSS_S_CONTINUE_NEEDED) 
498         {
499           TRACE("continue needed...");
500           if (recv_token(state, &recv_tok) < 0) 
501             {
502               TRACE("recv_token failed");
503               (void) gss_release_name(&min_stat, &target_name);
504               TRACE("<== client_establish_context");
505               return -1;
506             }
507 #ifdef GSSSASL_DEBUG
508           if (debug_)
509             {
510               fprintf(stderr, "Received token (size=%d)...\n",
511               recv_tok.length);
512               fflush(stderr);
513               print_token(&recv_tok);
514             }
515 #endif
516           token_ptr = &recv_tok;
517         }
518     } while (maj_stat == GSS_S_CONTINUE_NEEDED);
519
520   (void) gss_release_name(&min_stat, &target_name);
521
522   TRACE("<== client_establish_context");
523   return 0;
524 }
525
526 /*
527  * When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes
528  * the following actions: If the last call to GSS_Init_sec_context
529  * returned an output_token, then the client responds with the
530  * output_token, otherwise the client responds with no data.  The client
531  * should then expect the server to issue a token in a subsequent
532  * challenge.  The client passes this token to GSS_Unwrap and interprets
533  * the first octet of resulting cleartext as a bit-mask specifying the
534  * security layers supported by the server and the second through fourth
535  * octets as the maximum size output_message to send to the server.  The
536  * client then constructs data, with the first octet containing the
537  * bit-mask specifying the selected security layer, the second through
538  * fourth octets containing in network byte order the maximum size
539  * output_message the client is able to receive, and the remaining
540  * octets containing the authorization identity.  The client passes the
541  * data to GSS_Wrap with conf_flag set to FALSE, and responds with the
542  * generated output_message.  The client can then consider the server
543  * authenticated.
544  */
545 static int negotiate_security_options(gssldap_client_state_t state, 
546                                       int layer)
547 {
548   OM_uint32       maj_stat;
549   OM_uint32       min_stat;
550   gss_buffer_desc recv_tok;
551   gss_buffer_desc send_tok;
552   OM_uint32       rc;
553   size_t          mask_length;
554   gsssasl_security_negotiation_t  send_mask;
555   gsssasl_security_negotiation_t  recv_mask;
556
557   TRACE("==> negotiate_security_options");
558
559   memset(&send_tok, '\0', sizeof(send_tok));
560   memset(&recv_tok, '\0', sizeof(recv_tok));
561   if ((rc = recv_token(state, &recv_tok)) < 0)
562     {
563       TRACE("<== negotiate_security_options (recv_token failed)");
564       return rc;
565     }
566 #ifdef GSSSASL_DEBUG
567   if (debug_)
568     {
569       fprintf(stderr, "Received token (size=%d)...\n",
570       recv_tok.length);
571       fflush(stderr);
572       print_token(&recv_tok);
573       }
574 #endif  /* GSSSASL_DEBUG */
575
576   maj_stat = gsssasl_unpack_security_token(&min_stat,
577                                            state->context,
578                                            &recv_tok,
579                                            &recv_mask,
580                                            &mask_length);
581
582   if (maj_stat != GSS_S_COMPLETE)
583     {
584       LOG_STATUS("unpacking security negotiation token",
585                  maj_stat,
586                  min_stat);
587       TRACE("<== negotiate_security_options (unpack failed)");
588       return -1;
589     }
590 #ifdef GSSSASL_DEBUG
591   if (debug_) 
592     {
593       fprintf(stderr, "Received security token level %d size %d\n",
594       recv_mask->security_layer,
595       recv_mask->token_size);
596       }
597 #endif
598   if ((~recv_mask->security_layer) & layer) 
599     {
600       free(recv_mask);
601       TRACE("<== negotiate_security_options (unsupported security layer)");
602       return -1;
603       }
604   mask_length = sizeof(recv_mask) + 
605                        GSSAPI_LDAP_DN_PREFIX_LEN + strlen(state->binddn);
606   send_mask = NSLDAPI_MALLOC(mask_length);
607   if (send_mask == NULL) 
608     {
609       free(recv_mask);
610       TRACE("<== negotiate_security_options (malloc failed)");
611       return -1;
612     }
613   send_mask->security_layer = layer;
614   send_mask->token_size = recv_mask->token_size;
615   memcpy(send_mask->identity, GSSAPI_LDAP_DN_PREFIX, GSSAPI_LDAP_DN_PREFIX_LEN);
616   memcpy(send_mask->identity + GSSAPI_LDAP_DN_PREFIX_LEN,
617          state->binddn,
618          mask_length - sizeof(recv_mask) - GSSAPI_LDAP_DN_PREFIX_LEN);
619   free(recv_mask);
620
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   if (rc == 0) 
650     {
651       security_context = state->context;
652       security_layer = layer;
653       security_token_size = send_mask->token_size;
654       }
655
656   NSLDAPI_FREE(send_mask);
657   if (send_tok.value != NULL)
658     gss_release_buffer(&rc, &send_tok);
659   if (recv_tok.value != NULL)
660     gss_release_buffer(&rc, &recv_tok);
661   TRACE("<== negotiate_security_options");
662   return rc;
663 }
664
665 #ifdef GSSSASL_DEBUG
666 /*
667  * Temporary function to enable debugging
668  */
669 LDAP_API(int)
670 LDAP_CALL ldap_gssapi_debug(int on)
671 {
672   int old = debug_;
673   debug_ = on;
674   return old;
675 }
676 #endif  /* GSSSASL_DEBUG */
677
678 /*
679  * Public function for doing a GSS-API SASL bind
680  */
681 LDAP_API(int)
682 LDAP_CALL ldap_adgssapi_bind(LDAP *ld, const char *who, int layer)
683 {
684   gssldap_client_state_desc state;
685   char        *service_name;
686   OM_uint32   min_stat;
687   int         rc;
688   int         i;
689   struct ldap_io_fns iofns;
690
691   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
692     {
693       return -1;
694     }
695
696   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
697     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
698
699   service_name = 
700     NSLDAPI_MALLOC(sizeof(GSSAPI_LDAP_SERVICE_NAME "@") + strlen(ld->ld_defhost));
701   if (service_name == NULL) 
702     {
703       return -1;
704     }
705   strcpy(service_name, GSSAPI_LDAP_SERVICE_NAME "@");
706   strcat(service_name, ld->ld_defhost);
707
708 #ifdef GSSSASL_DEBUG
709   if (debug_) 
710     {
711       fprintf(stderr, "LDAP service name: %s\n", service_name);
712       fflush(stderr);
713     }
714 #endif
715
716   state.msgid = -1;
717   state.ld = ld;
718   state.binddn = who;
719   state.context = GSS_C_NO_CONTEXT;
720   state.rc = LDAP_OPERATIONS_ERROR;
721
722   rc = client_establish_context(ld, &state, service_name);
723   if (rc == 0) 
724     {
725       rc = negotiate_security_options(&state, layer);
726     }
727   if (rc == 0) 
728     {
729 #ifdef GSSSASL_DEBUG
730       gss_buffer_desc tname;
731       gss_buffer_desc sname;
732       gss_name_t      targ_name;
733       gss_name_t      src_name;
734       OM_uint32       context_flags;
735       OM_uint32       lifetime;
736       OM_uint32       maj_stat;
737       int             is_open;
738       int             is_local;
739       gss_OID         mechanism;
740       gss_OID         name_type;
741
742       maj_stat = gss_inquire_context(&min_stat,
743                                       state.context,
744                                       &src_name,
745                                       &targ_name,
746                                       &lifetime,
747                                       &mechanism,
748                                       &context_flags,
749                                       &is_local,
750                                       &is_open);
751       if (maj_stat != GSS_S_COMPLETE) 
752         {
753           LOG_STATUS("inquiring context", maj_stat, min_stat);
754           return LDAP_OPERATIONS_ERROR;
755         }
756       maj_stat = gss_display_name(&min_stat,
757                                   src_name,
758                                   &sname,
759                                   &name_type);
760       if (maj_stat != GSS_S_COMPLETE) 
761         {
762           LOG_STATUS("displaying source name", maj_stat, min_stat);
763           return LDAP_OPERATIONS_ERROR;
764         }
765       maj_stat = gss_display_name(&min_stat,
766                                   targ_name,
767                                   &tname,
768                                   (gss_OID *) NULL);
769       if (maj_stat != GSS_S_COMPLETE) 
770         {
771           LOG_STATUS("displaying target name", maj_stat, min_stat);
772           return LDAP_OPERATIONS_ERROR;
773         }
774       if (debug_) 
775         {
776           fprintf(stderr, 
777                   "\"%.*s\" to \"%.*s\", lifetime %d, flags %x, %s, %s\n",
778                   (int) sname.length, (char *) sname.value,
779                   (int) tname.length, (char *) tname.value, lifetime,
780                   context_flags,
781                   (is_local) ? "locally initiated" : "remotely initiated",
782                   (is_open) ? "open" : "closed");
783           fflush(stderr);
784         }
785       (void) gss_release_name(&min_stat, &src_name);
786       (void) gss_release_name(&min_stat, &targ_name);
787       (void) gss_release_buffer(&min_stat, &sname);
788       (void) gss_release_buffer(&min_stat, &tname);
789 #endif
790       state.rc = LDAP_SUCCESS;
791     }
792
793   if (state.rc == LDAP_SUCCESS)
794     {
795       if (layer == GSSSASL_PRIVACY_PROTECTION)
796         {
797           memset(&iofns, 0, sizeof(iofns));
798           iofns.liof_read = ldap_gssapi_read;
799           iofns.liof_write = ldap_gssapi_write;
800           state.rc = ldap_set_option(ld, LDAP_OPT_IO_FN_PTRS, &iofns);
801         }
802     }
803
804   NSLDAPI_FREE(service_name);
805   LDAP_SET_LDERRNO(ld, state.rc, NULL, NULL);
806
807   return state.rc;
808 }
809
810 /* Wrap and encode a security negotiation token */
811 unsigned long gsssasl_pack_security_token(OM_uint32 *min_stat, 
812                              gss_ctx_id_t context,
813                              gsssasl_security_negotiation_t inmask,
814                              size_t masklength, gss_buffer_t wrapped_tok)
815 {
816   OM_uint32       maj_stat;
817   OM_uint32       rc;
818   gss_buffer_desc send_tok;
819
820   wrapped_tok->length = 0;
821   wrapped_tok->value = NULL;
822
823   if (masklength < sizeof(gsssasl_security_negotiation_desc))
824     return GSS_S_FAILURE;
825
826   inmask->token_size = htonl(inmask->token_size);
827
828   send_tok.length = masklength;
829   send_tok.value = inmask;
830
831   maj_stat = gss_wrap(min_stat,
832                       context,
833                       0,
834                       GSS_C_QOP_DEFAULT,
835                       &send_tok,
836                       (int *)&rc,
837                       wrapped_tok);
838
839   inmask->token_size = ntohl(inmask->token_size);
840
841   return maj_stat;
842 }
843
844 /* Unwrap and decode a security negotiation token. */
845 int gsssasl_unpack_security_token(OM_uint32 *min_stat, gss_ctx_id_t context, 
846                                   gss_buffer_t wrapped_tok,
847                                   gsssasl_security_negotiation_t *outmask, 
848                                   size_t *masklength)
849 {
850   OM_uint32       maj_stat;
851   OM_uint32       rc;
852   gss_buffer_desc recv_tok;
853
854   *masklength = 0;
855   *outmask = NULL;
856   memset(&recv_tok, '\0', sizeof(recv_tok));
857
858   maj_stat = gss_unwrap(min_stat,
859                         context,
860                         wrapped_tok,
861                         &recv_tok,
862                         (int *)&rc,
863                         (gss_qop_t *) NULL);
864   if (maj_stat != GSS_S_COMPLETE)
865     return maj_stat;
866
867 /*
868 #ifdef _WIN32
869   if (recv_tok.length < sizeof(gsssasl_security_negotiation_desc)) 
870     {
871       gss_release_buffer(&rc, &recv_tok);
872       return GSS_S_FAILURE;
873     }
874 #endif
875 */
876
877   /*
878    * we're lazy and don't copy the token. This could cause
879    * problems if libgssapi uses a different malloc!
880    */
881   *masklength = recv_tok.length;
882   *outmask = (gsssasl_security_negotiation_t) recv_tok.value;
883   if (*outmask == NULL) 
884     {
885       gss_release_buffer(&rc, &recv_tok);
886       return GSS_S_FAILURE;
887     }
888   return GSS_S_COMPLETE;
889 }
890
891 int ldap_reset_principal(LDAP *ld, char *service_name, gss_name_t target_name)
892 {
893   krb5_context    context = NULL;
894   krb5_principal  princ;
895   krb5_principal  princ1;
896   krb5_principal  temp_princ;
897   char            *realm;
898   char            *server_name = NULL;
899   int             i;
900
901   princ = (krb5_principal)(target_name);
902
903   if (krb5_init_context(&context))
904     return(-1);
905
906   realm = strdup(ldap_domain_name);
907   for (i = 0; i < (int)strlen(realm); i++)
908     realm[i] = toupper(realm[i]);
909   server_name = strdup(ld->ld_defhost);
910   for (i = 0; i < (int)strlen(server_name); i++)
911     server_name[i] = tolower(server_name[i]);
912
913   temp_princ = malloc(sizeof(*princ));
914   memcpy(temp_princ, princ, sizeof(*princ));
915
916   krb5_build_principal(context, &princ1, strlen(realm), realm, "ldap", 
917                        server_name, ldap_domain_name, 0);
918
919   memcpy(princ, princ1, sizeof(*princ1));
920   free(princ1);
921   krb5_free_principal(context, temp_princ);
922
923   if (realm != NULL)
924     free(realm);
925   if (server_name != NULL)
926     free(server_name);
927   if (context != NULL)
928     krb5_free_context(context);
929   return(0);
930 }
931
932 int ldap_delete_tickets(LDAP *ld, char *service_name)
933 {
934   int             i;
935   int             rc;
936   krb5_context    context = NULL;
937   krb5_ccache     v5Cache = NULL;
938   krb5_creds      creds;
939   krb5_cc_cursor  v5Cursor;
940   krb5_error_code code;
941   char            *sServerName;
942
943   if (!NSLDAPI_VALID_LDAP_POINTER(ld) || ld->ld_defhost == NULL) 
944     {
945       return -1;
946     }
947
948   for (i = 0; i < (int)strlen(ld->ld_defhost); i++)
949     ld->ld_defhost[i] = toupper(ld->ld_defhost[i]);
950
951   rc = -1;
952
953   if (krb5_init_context(&context))
954     return(rc);
955
956   if (krb5_cc_default(context, &v5Cache))
957     goto cleanup;
958   if (krb5_cc_start_seq_get(context, v5Cache, &v5Cursor))
959     goto cleanup;
960
961   memset(&creds, '\0', sizeof(creds));
962
963   while (!(code = krb5_cc_next_cred(context, v5Cache, &v5Cursor, &creds))) 
964     {
965       if (krb5_unparse_name(context, creds.server, &sServerName))
966         {
967           krb5_free_cred_contents(context, &creds);
968           continue;
969         }
970       if (!memcmp(sServerName, service_name, strlen(service_name)))
971         {
972           krb5_cc_remove_cred(context, v5Cache, 0, &creds);
973         }
974       continue;
975     }
976
977   if ((code == KRB5_CC_END) || (code == KRB5_CC_NOTFOUND))
978     {
979       krb5_cc_end_seq_get(context, v5Cache, &v5Cursor);
980     }
981   rc = 0;
982
983 cleanup:
984   if ((v5Cache != NULL) && (context != NULL))
985     krb5_cc_close(context, v5Cache);
986   if (context != NULL)
987     krb5_free_context(context);
988   return(rc);
989 }
990
991 int locate_ldap_server(char *domain, char **server_name)
992 {
993   char  service[128];
994   char  host[128];
995   int   location_type;
996   int   length;
997   int   rc;
998   int   return_code;
999   int   entry_length;
1000   int   server_count;
1001   unsigned char   reply[1024];
1002   unsigned char   *ptr;
1003     
1004   strcpy(ldap_domain_name, domain);
1005   sprintf(service, "%s.%s.%s.", LDAP_SERVICE, TCP_PROTOCOL, domain);
1006
1007   return_code = -1;
1008   server_count = 0;
1009   memset(reply, '\0', sizeof(reply));
1010   length = res_search(service, C_IN, T_SRV, reply, sizeof(reply));
1011   if (length >= 0)
1012     {
1013       ptr = reply;
1014       ptr += sizeof(HEADER);
1015       if ((rc = dn_expand(reply, reply + length, ptr, host, 
1016                           sizeof(host))) < 0)
1017         return(-1);
1018       ptr += (rc + 4);
1019
1020       while (ptr < reply + length)
1021         {
1022           if ((rc = dn_expand(reply, reply + length, ptr, host, 
1023                               sizeof(host))) < 0)
1024             break;
1025           ptr += rc;
1026           location_type = (ptr[0] << 8) | ptr[1];
1027           ptr += 8;
1028                 entry_length = (ptr[0] << 8) | ptr[1];
1029           ptr += 2;
1030           if (location_type == T_SRV)
1031             {
1032               if ((rc = dn_expand(reply, reply + length, ptr + 6, host, 
1033                                   sizeof(host))) < 0)
1034                 return -1;
1035               
1036               (*server_name) = strdup(host);
1037               ++server_name;
1038               return_code = 1;
1039               server_count++;
1040             }
1041         ptr += entry_length;
1042         }
1043     }
1044   return(return_code);
1045 }
This page took 0.119758 seconds and 5 git commands to generate.