1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * lib/kdb/kdb_ldap/kdb_ldap.h
8  *
9  * Copyright (c) 2004-2005, Novell, Inc.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions are met:
14  *
15  *   * Redistributions of source code must retain the above copyright notice,
16  *       this list of conditions and the following disclaimer.
17  *   * Redistributions in binary form must reproduce the above copyright
18  *       notice, this list of conditions and the following disclaimer in the
19  *       documentation and/or other materials provided with the distribution.
20  *   * The copyright holder's name is not used to endorse or promote products
21  *       derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /* */
37 #ifndef _KDB_LDAP_H
38 #define _KDB_LDAP_H 1
39 
40 /* We want the interfaces marked "deprecated" in OpenLDAP.  */
41 #define LDAP_DEPRECATED 1
42 #include <ldap.h>
43 
44 /* Check for acceptable versions.
45 
46    OpenLDAP version 2.2.6 is known to have some kind of problem that
47    is tickled by the use of multiple handles in this code.  Version
48    2.2.19 in Mac OS 10.4.7 seems to be buggy as well.  Version 2.2.24
49    doesn't have this problem.  Other in-between versions have not been
50    tested.  */
51 #ifndef BUILD_WITH_BROKEN_LDAP
52 # if defined(LDAP_API_FEATURE_X_OPENLDAP)
53 #  if LDAP_VENDOR_VERSION < 20224
54 #   error This code triggers bugs in old OpenLDAP implementations.  Please update to 2.2.24 or later.
55 #  endif
56 # endif
57 #endif /* BUILD_WITH_BROKEN_LDAP */
58 
59 #include <k5-thread.h>
60 #include <k5-platform.h> /* Solaris Kerberos */
61 #include <k5-platform-store_16.h>
62 #include <k5-platform-store_32.h>
63 #include <k5-platform-load_16.h>
64 #include <k5-platform-load_32.h>
65 
66 #include <kdb5.h>
67 #include "k5-int.h"
68 #include "ldap_krbcontainer.h"
69 #include "ldap_realm.h"
70 
71 extern struct timeval timelimit;
72 
73 /* Solaris Kerberos: need this define to get around sccs keyword expansion */
74 #define  DATE_FORMAT "%Y" "%m" "%d" "%H" "%M" "%SZ"
75 
76 #define  SERV_COUNT                  100
77 #define  DEFAULT_CONNS_PER_SERVER    5
78 #define  REALM_READ_REFRESH_INTERVAL (5 * 60)
79 
80 #ifdef HAVE_EDIRECTORY
81 #define  SECURITY_CONTAINER "cn=Security"
82 #define  KERBEROS_CONTAINER "cn=Kerberos,cn=Security"
83 #endif
84 
85 #if !defined(LDAP_OPT_RESULT_CODE) && defined(LDAP_OPT_ERROR_NUMBER)
86 #define LDAP_OPT_RESULT_CODE LDAP_OPT_ERROR_NUMBER
87 #endif
88 
89 #define NEG(val)   (val <0) ? abs(val) : -val ;
90 #define MAXINTLEN  10
91 
92 #define IGNORE_STATUS              0
93 #define CHECK_STATUS               1
94 
95 #define SETUP_CONTEXT() if (context == NULL || context->db_context == NULL \
96             || ((kdb5_dal_handle *)context->db_context)->db_context == NULL) { \
97         return EINVAL; \
98     } \
99     dal_handle = (kdb5_dal_handle *)context->db_context; \
100     ldap_context = (krb5_ldap_context *) dal_handle->db_context; \
101     if (ldap_context == NULL || ldap_context->server_info_list == NULL) \
102         return KRB5_KDB_DBNOTINITED;
103 
104 #define GET_HANDLE()  ld = NULL; \
105     st = krb5_ldap_request_handle_from_pool(ldap_context, &ldap_server_handle); \
106     if (st != 0) { \
107         prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \
108         st = KRB5_KDB_ACCESS_ERROR; \
109         goto cleanup; \
110     } \
111     ld = ldap_server_handle->ldap_handle;
112 
113 extern int set_ldap_error (krb5_context ctx, int st, int op);
114 extern void prepend_err_str (krb5_context ctx, const char *s, krb5_error_code err, krb5_error_code oerr);
115 
116 #define LDAP_SEARCH(base, scope, filter, attrs)   LDAP_SEARCH_1(base, scope, filter, attrs, CHECK_STATUS)
117 
118 #define LDAP_SEARCH_1(base, scope, filter, attrs, status_check)        \
119       do { \
120 	  st = ldap_search_ext_s(ld, base, scope, filter, attrs, 0, NULL, NULL, &timelimit, LDAP_NO_LIMIT, &result); \
121 	  if (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR) { \
122               tempst = krb5_ldap_rebind(ldap_context, &ldap_server_handle); \
123 	      if (ldap_server_handle) \
124 		  ld = ldap_server_handle->ldap_handle; \
125 	  } \
126       }while (translate_ldap_error(st, OP_SEARCH) == KRB5_KDB_ACCESS_ERROR && tempst == 0); \
127       \
128       if (status_check != IGNORE_STATUS) { \
129         if (tempst != 0) { \
130             prepend_err_str(context, "LDAP handle unavailable: ", KRB5_KDB_ACCESS_ERROR, st); \
131             st = KRB5_KDB_ACCESS_ERROR; \
132             goto cleanup; \
133         } \
134         if (st != LDAP_SUCCESS) { \
135 	     st = set_ldap_error(context, st, OP_SEARCH); \
136 	     goto cleanup; \
137         } \
138       }
139 
140 
141 #define CHECK_CLASS_VALIDITY(st, mask, str) \
142 	if (st != 0 || mask == 0) { \
143 	    if (st == 0 && mask == 0) { \
144 	       st = set_ldap_error(context, LDAP_OBJECT_CLASS_VIOLATION, OP_SEARCH); \
145 	    } \
146 	    prepend_err_str(context, str, st, st); \
147 	    goto cleanup; \
148 	 }
149 
150 #define CHECK_NULL(ptr) if (ptr == NULL) { \
151                             st = ENOMEM; \
152                             goto cleanup; \
153                         }
154 
155 #define  STORE16_INT(ptr, val)	store_16_be(val, ptr)
156 #define  STORE32_INT(ptr, val)  store_32_be(val, ptr)
157 #define UNSTORE16_INT(ptr, val) (val = load_16_be(ptr))
158 #define UNSTORE32_INT(ptr, val) (val = load_32_be(ptr))
159 
160 #define KRB5_CONF_KDC_BIND_DN "ldap_kdc_dn"
161 #define KRB5_CONF_ADMIN_BIND_DN "ldap_kadmind_dn"
162 #define KRB5_CONF_PWD_BIND_DN "ldap_passwd_dn"
163 
164 #define  KDB_TL_USER_INFO      0x7ffe
165 
166 #define KDB_TL_PRINCTYPE          0x01
167 #define KDB_TL_PRINCCOUNT         0x02
168 #define KDB_TL_USERDN             0x03
169 #define KDB_TL_KEYINFO            0x04
170 #define KDB_TL_MASK               0x05
171 #define KDB_TL_CONTAINERDN        0x06
172 #define KDB_TL_LINKDN             0x07
173 
174 
175 #define CHECK_LDAP_HANDLE(lcontext)     if (!(ldap_context \
176 					      && ldap_context->server_info_list)) { \
177 					  return KRB5_KDB_DBNOTINITED; \
178 					}
179 
180 #define HNDL_LOCK(lcontext) k5_mutex_lock(&lcontext->hndl_lock)
181 #define HNDL_UNLOCK(lcontext) k5_mutex_unlock(&lcontext->hndl_lock)
182 
183 /* To be used later */
184 typedef struct _krb5_ldap_certificates{
185     char *certificate;
186     int  certtype;
187 }krb5_ldap_certificates;
188 
189 /* ldap server info structure */
190 
191 typedef enum _server_type {PRIMARY, SECONDARY} krb5_ldap_server_type;
192 
193 typedef enum _server_status {OFF, ON, NOTSET} krb5_ldap_server_status;
194 
195 typedef struct _krb5_ldap_server_info krb5_ldap_server_info;
196 
197 typedef struct  _krb5_ldap_server_handle {
198     int                              msgid;
199     LDAP                             *ldap_handle;
200     krb5_boolean                     server_info_update_pending;
201     krb5_ldap_server_info            *server_info;
202     struct _krb5_ldap_server_handle  *next;
203 } krb5_ldap_server_handle;
204 
205 struct _krb5_ldap_server_info {
206     krb5_ldap_server_type	 server_type;
207     krb5_ldap_server_status      server_status;
208     krb5_ui_4                    num_conns;
209     krb5_ldap_server_handle      *ldap_server_handles;
210     time_t                       downtime;
211     char			*server_name;
212 #ifdef HAVE_EDIRECTORY
213     char			*root_certificate_file;
214 #endif
215     struct _krb5_ldap_server_info *next;
216 };
217 
218 
219 /* ldap server structure */
220 
221 typedef enum {SERVICE_DN_TYPE_SERVER, SERVICE_DN_TYPE_CLIENT} krb5_ldap_servicetype;
222 
223 typedef struct _krb5_ldap_context {
224   krb5_ldap_servicetype         service_type;
225   krb5_ldap_server_info         **server_info_list;
226   krb5_ui_4                     max_server_conns;
227   char                          *conf_section;
228   char 		                *bind_dn;
229   char                          *bind_pwd;
230   char 		                *service_password_file;
231   char 		                *root_certificate_file;
232   char                          *service_cert_path;
233   char                          *service_cert_pass;
234   krb5_ldap_certificates        **certificates;
235   krb5_ui_4                     cert_count; /* certificate count */
236   k5_mutex_t                    hndl_lock;
237   krb5_ldap_krbcontainer_params *krbcontainer;
238   krb5_ldap_realm_params        *lrparams;
239   krb5_context                  kcontext;   /* to set the error code and message */
240 } krb5_ldap_context;
241 
242 
243 typedef struct {
244   int           nkey;
245   struct berval **keys;
246 }KEY;
247 
248 #define k5ldap_inited(c) (c && c->db_context \
249                          && ((kdb5_dal_handle*)c->db_context)->db_context \
250                          && ((krb5_ldap_context *) ((kdb5_dal_handle*)c->db_context)->db_context))
251 
252 
253 /* misc functions */
254 
255 krb5_error_code
256 krb5_ldap_db_init(krb5_context, krb5_ldap_context *);
257 
258 krb5_error_code
259 krb5_ldap_db_single_init(krb5_ldap_context *);
260 
261 krb5_error_code
262 krb5_ldap_rebind(krb5_ldap_context *, krb5_ldap_server_handle **);
263 
264 krb5_error_code
265 krb5_ldap_db_get_age(krb5_context, char *, time_t *);
266 
267 krb5_error_code
268 krb5_ldap_lib_init(void);
269 
270 krb5_error_code
271 krb5_ldap_lib_cleanup(void);
272 
273 void *
274 krb5_ldap_alloc( krb5_context kcontext,  void *ptr, size_t size );
275 
276 void
277 krb5_ldap_free( krb5_context kcontext, void *ptr );
278 krb5_error_code
279 krb5_ldap_get_mkey(krb5_context, krb5_keyblock **);
280 
281 krb5_error_code
282 krb5_ldap_set_mkey(krb5_context, char *, krb5_keyblock *);
283 
284 krb5_error_code
285 krb5_ldap_create(krb5_context , char *, char **);
286 
287 krb5_error_code
288 krb5_ldap_open( krb5_context , char *,
289 		char **db_args,
290 		int mode );
291 krb5_error_code
292 krb5_ldap_close( krb5_context );
293 
294 krb5_error_code
295 krb5_ldap_free_ldap_context(krb5_ldap_context *);
296 
297 krb5_error_code
298 krb5_ldap_read_startup_information(krb5_context );
299 
300 int
301 has_sasl_external_mech(krb5_context, char *);
302 
303 /* DAL functions */
304 
305 
306 krb5_error_code
307 krb5_ldap_set_option( krb5_context, int, void * );
308 
309 krb5_error_code
310 krb5_ldap_lock( krb5_context, int );
311 
312 krb5_error_code
313 krb5_ldap_unlock( krb5_context );
314 
315 krb5_error_code
316 krb5_ldap_supported_realms( krb5_context, char ** );
317 
318 krb5_error_code
319 krb5_ldap_free_supported_realms( krb5_context, char ** );
320 
321 const char *
322 krb5_ldap_errcode_2_string( krb5_context, long );
323 
324 void
325 krb5_ldap_release_errcode_string (krb5_context, const char *);
326 
327 #ifndef HAVE_LDAP_INITIALIZE
328 /* Solaris Kerberos: added a use_SSL parameter */
329 int
330 ldap_initialize(LDAP **, char *, int, char **);
331 #endif
332 #ifndef HAVE_LDAP_UNBIND_EXT_S
333 int
334 ldap_unbind_ext_s(LDAP *, LDAPControl **, LDAPControl **);
335 #endif
336 
337 #endif
338