]> git.sur5r.net Git - openldap/blob - libraries/libldap/init.c
c8a15f157bd6fef987b0a3089430c42ab87fb442
[openldap] / libraries / libldap / init.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1998-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in the file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15
16 #include "portable.h"
17
18 #include <stdio.h>
19 #include <ac/stdlib.h>
20
21 #include <ac/socket.h>
22 #include <ac/string.h>
23 #include <ac/ctype.h>
24 #include <ac/time.h>
25
26 #ifdef HAVE_LIMITS_H
27 #include <limits.h>
28 #endif
29
30 #include "ldap-int.h"
31 #include "ldap_defaults.h"
32 #include "lutil.h"
33
34 struct ldapoptions ldap_int_global_options =
35         { LDAP_UNINITIALIZED, LDAP_DEBUG_NONE };  
36
37 #define ATTR_NONE       0
38 #define ATTR_BOOL       1
39 #define ATTR_INT        2
40 #define ATTR_KV         3
41 #define ATTR_STRING     4
42 #define ATTR_OPTION     5
43
44 #define ATTR_SASL       6
45 #define ATTR_TLS        7
46
47 #define ATTR_OPT_TV     8
48 #define ATTR_OPT_INT    9
49
50 struct ol_keyvalue {
51         const char *            key;
52         int                     value;
53 };
54
55 static const struct ol_keyvalue deref_kv[] = {
56         {"never", LDAP_DEREF_NEVER},
57         {"searching", LDAP_DEREF_SEARCHING},
58         {"finding", LDAP_DEREF_FINDING},
59         {"always", LDAP_DEREF_ALWAYS},
60         {NULL, 0}
61 };
62
63 static const struct ol_attribute {
64         int                     useronly;
65         int                     type;
66         const char *    name;
67         const void *    data;
68         size_t          offset;
69 } attrs[] = {
70         {0, ATTR_OPT_TV,        "TIMEOUT",              NULL,   LDAP_OPT_TIMEOUT},
71         {0, ATTR_OPT_TV,        "NETWORK_TIMEOUT",      NULL,   LDAP_OPT_NETWORK_TIMEOUT},
72         {0, ATTR_OPT_INT,       "VERSION",              NULL,   LDAP_OPT_PROTOCOL_VERSION},
73         {0, ATTR_KV,            "DEREF",        deref_kv, /* or &deref_kv[0] */
74                 offsetof(struct ldapoptions, ldo_deref)},
75         {0, ATTR_INT,           "SIZELIMIT",    NULL,
76                 offsetof(struct ldapoptions, ldo_sizelimit)},
77         {0, ATTR_INT,           "TIMELIMIT",    NULL,
78                 offsetof(struct ldapoptions, ldo_timelimit)},
79         {1, ATTR_STRING,        "BINDDN",               NULL,
80                 offsetof(struct ldapoptions, ldo_defbinddn)},
81         {0, ATTR_STRING,        "BASE",                 NULL,
82                 offsetof(struct ldapoptions, ldo_defbase)},
83         {0, ATTR_INT,           "PORT",                 NULL,           /* deprecated */
84                 offsetof(struct ldapoptions, ldo_defport)},
85         {0, ATTR_OPTION,        "HOST",                 NULL,   LDAP_OPT_HOST_NAME}, /* deprecated */
86         {0, ATTR_OPTION,        "URI",                  NULL,   LDAP_OPT_URI}, /* replaces HOST/PORT */
87         {0, ATTR_BOOL,          "REFERRALS",    NULL,   LDAP_BOOL_REFERRALS},
88         {0, ATTR_BOOL,          "RESTART",              NULL,   LDAP_BOOL_RESTART},
89
90 #ifdef HAVE_CYRUS_SASL
91         {0, ATTR_STRING,        "SASL_MECH",            NULL,
92                 offsetof(struct ldapoptions, ldo_def_sasl_mech)},
93         {0, ATTR_STRING,        "SASL_REALM",           NULL,
94                 offsetof(struct ldapoptions, ldo_def_sasl_realm)},
95         {1, ATTR_STRING,        "SASL_AUTHCID",         NULL,
96                 offsetof(struct ldapoptions, ldo_def_sasl_authcid)},
97         {1, ATTR_STRING,        "SASL_AUTHZID",         NULL,
98                 offsetof(struct ldapoptions, ldo_def_sasl_authzid)},
99         {0, ATTR_SASL,          "SASL_SECPROPS",        NULL,   LDAP_OPT_X_SASL_SECPROPS},
100 #endif
101
102 #ifdef HAVE_TLS
103         {1, ATTR_TLS,   "TLS_CERT",                     NULL,   LDAP_OPT_X_TLS_CERTFILE},
104         {1, ATTR_TLS,   "TLS_KEY",                      NULL,   LDAP_OPT_X_TLS_KEYFILE},
105         {0, ATTR_TLS,   "TLS_CACERT",           NULL,   LDAP_OPT_X_TLS_CACERTFILE},
106         {0, ATTR_TLS,   "TLS_CACERTDIR",        NULL,   LDAP_OPT_X_TLS_CACERTDIR},
107         {0, ATTR_TLS,   "TLS_REQCERT",          NULL,   LDAP_OPT_X_TLS_REQUIRE_CERT},
108         {0, ATTR_TLS,   "TLS_RANDFILE",         NULL,   LDAP_OPT_X_TLS_RANDOM_FILE},
109         {0, ATTR_TLS,   "TLS_CIPHER_SUITE",     NULL,   LDAP_OPT_X_TLS_CIPHER_SUITE},
110
111 #ifdef HAVE_OPENSSL_CRL
112         {0, ATTR_TLS,   "TLS_CRLCHECK",         NULL,   LDAP_OPT_X_TLS_CRLCHECK},
113 #endif
114         
115 #endif
116
117         {0, ATTR_NONE,          NULL,           NULL,   0}
118 };
119
120 #define MAX_LDAP_ATTR_LEN  sizeof("TLS_CIPHER_SUITE")
121 #define MAX_LDAP_ENV_PREFIX_LEN 8
122
123 static void openldap_ldap_init_w_conf(
124         const char *file, int userconf )
125 {
126         char linebuf[ AC_LINE_MAX ];
127         FILE *fp;
128         int i;
129         char *cmd, *opt;
130         char *start, *end;
131         struct ldapoptions *gopts;
132
133         if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
134                 return;                 /* Could not allocate mem for global options */
135         }
136
137         if (file == NULL) {
138                 /* no file name */
139                 return;
140         }
141
142         Debug(LDAP_DEBUG_TRACE, "ldap_init: trying %s\n", file, 0, 0);
143
144         fp = fopen(file, "r");
145         if(fp == NULL) {
146                 /* could not open file */
147                 return;
148         }
149
150         Debug(LDAP_DEBUG_TRACE, "ldap_init: using %s\n", file, 0, 0);
151
152         while((start = fgets(linebuf, sizeof(linebuf), fp)) != NULL) {
153                 /* skip lines starting with '#' */
154                 if(*start == '#') continue;
155
156                 /* trim leading white space */
157                 while((*start != '\0') && isspace((unsigned char) *start))
158                         start++;
159
160                 /* anything left? */
161                 if(*start == '\0') continue;
162
163                 /* trim trailing white space */
164                 end = &start[strlen(start)-1];
165                 while(isspace((unsigned char)*end)) end--;
166                 end[1] = '\0';
167
168                 /* anything left? */
169                 if(*start == '\0') continue;
170                 
171
172                 /* parse the command */
173                 cmd=start;
174                 while((*start != '\0') && !isspace((unsigned char)*start)) {
175                         start++;
176                 }
177                 if(*start == '\0') {
178                         /* command has no argument */
179                         continue;
180                 } 
181
182                 *start++ = '\0';
183
184                 /* we must have some whitespace to skip */
185                 while(isspace((unsigned char)*start)) start++;
186                 opt = start;
187
188                 for(i=0; attrs[i].type != ATTR_NONE; i++) {
189                         void *p;
190
191                         if( !userconf && attrs[i].useronly ) {
192                                 continue;
193                         }
194
195                         if(strcasecmp(cmd, attrs[i].name) != 0) {
196                                 continue;
197                         }
198
199                         switch(attrs[i].type) {
200                         case ATTR_BOOL:
201                                 if((strcasecmp(opt, "on") == 0) 
202                                         || (strcasecmp(opt, "yes") == 0)
203                                         || (strcasecmp(opt, "true") == 0))
204                                 {
205                                         LDAP_BOOL_SET(gopts, attrs[i].offset);
206
207                                 } else {
208                                         LDAP_BOOL_CLR(gopts, attrs[i].offset);
209                                 }
210
211                                 break;
212
213                         case ATTR_INT:
214                                 p = &((char *) gopts)[attrs[i].offset];
215                                 (void)lutil_atoi( (int*) p, opt );
216                                 break;
217
218                         case ATTR_KV: {
219                                         const struct ol_keyvalue *kv;
220
221                                         for(kv = attrs[i].data;
222                                                 kv->key != NULL;
223                                                 kv++) {
224
225                                                 if(strcasecmp(opt, kv->key) == 0) {
226                                                         p = &((char *) gopts)[attrs[i].offset];
227                                                         * (int*) p = kv->value;
228                                                         break;
229                                                 }
230                                         }
231                                 } break;
232
233                         case ATTR_STRING:
234                                 p = &((char *) gopts)[attrs[i].offset];
235                                 if (* (char**) p != NULL) LDAP_FREE(* (char**) p);
236                                 * (char**) p = LDAP_STRDUP(opt);
237                                 break;
238                         case ATTR_OPTION:
239                                 ldap_set_option( NULL, attrs[i].offset, opt );
240                                 break;
241                         case ATTR_SASL:
242 #ifdef HAVE_CYRUS_SASL
243                                 ldap_int_sasl_config( gopts, attrs[i].offset, opt );
244 #endif
245                                 break;
246                         case ATTR_TLS:
247 #ifdef HAVE_TLS
248                                 ldap_int_tls_config( NULL, attrs[i].offset, opt );
249 #endif
250                                 break;
251                         case ATTR_OPT_TV: {
252                                 struct timeval tv;
253                                 tv.tv_sec = -1;
254                                 tv.tv_usec = 0;
255                                 (void)lutil_atol( &tv.tv_sec, opt );
256                                 if ( tv.tv_sec > 0 ) {
257                                         (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&tv);
258                                 }
259                                 } break;
260                         case ATTR_OPT_INT: {
261                                 int v = -1;
262                                 (void)lutil_atoi( &v, opt );
263                                 if ( v > 0 ) {
264                                         (void)ldap_set_option( NULL, attrs[i].offset, (const void *)&v);
265                                 }
266                                 } break;
267                         }
268
269                         break;
270                 }
271         }
272
273         fclose(fp);
274 }
275
276 static void openldap_ldap_init_w_sysconf(const char *file)
277 {
278         openldap_ldap_init_w_conf( file, 0 );
279 }
280
281 static void openldap_ldap_init_w_userconf(const char *file)
282 {
283         char *home;
284         char *path = NULL;
285
286         if (file == NULL) {
287                 /* no file name */
288                 return;
289         }
290
291         home = getenv("HOME");
292
293         if (home != NULL) {
294                 Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is %s\n",
295                       home, 0, 0);
296                 path = LDAP_MALLOC(strlen(home) + strlen(file) + sizeof( LDAP_DIRSEP "."));
297         } else {
298                 Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is NULL\n",
299                       0, 0, 0);
300         }
301
302         if(home != NULL && path != NULL) {
303                 /* we assume UNIX path syntax is used... */
304
305                 /* try ~/file */
306                 sprintf(path, "%s" LDAP_DIRSEP "%s", home, file);
307                 openldap_ldap_init_w_conf(path, 1);
308
309                 /* try ~/.file */
310                 sprintf(path, "%s" LDAP_DIRSEP ".%s", home, file);
311                 openldap_ldap_init_w_conf(path, 1);
312         }
313
314         if(path != NULL) {
315                 LDAP_FREE(path);
316         }
317
318         /* try file */
319         openldap_ldap_init_w_conf(file, 1);
320 }
321
322 static void openldap_ldap_init_w_env(
323                 struct ldapoptions *gopts,
324                 const char *prefix)
325 {
326         char buf[MAX_LDAP_ATTR_LEN+MAX_LDAP_ENV_PREFIX_LEN];
327         int len;
328         int i;
329         void *p;
330         char *value;
331
332         if (prefix == NULL) {
333                 prefix = LDAP_ENV_PREFIX;
334         }
335
336         strncpy(buf, prefix, MAX_LDAP_ENV_PREFIX_LEN);
337         buf[MAX_LDAP_ENV_PREFIX_LEN] = '\0';
338         len = strlen(buf);
339
340         for(i=0; attrs[i].type != ATTR_NONE; i++) {
341                 strcpy(&buf[len], attrs[i].name);
342                 value = getenv(buf);
343
344                 if(value == NULL) {
345                         continue;
346                 }
347
348                 switch(attrs[i].type) {
349                 case ATTR_BOOL:
350                         if((strcasecmp(value, "on") == 0) 
351                                 || (strcasecmp(value, "yes") == 0)
352                                 || (strcasecmp(value, "true") == 0))
353                         {
354                                 LDAP_BOOL_SET(gopts, attrs[i].offset);
355
356                         } else {
357                                 LDAP_BOOL_CLR(gopts, attrs[i].offset);
358                         }
359                         break;
360
361                 case ATTR_INT:
362                         p = &((char *) gopts)[attrs[i].offset];
363                         * (int*) p = atoi(value);
364                         break;
365
366                 case ATTR_KV: {
367                                 const struct ol_keyvalue *kv;
368
369                                 for(kv = attrs[i].data;
370                                         kv->key != NULL;
371                                         kv++) {
372
373                                         if(strcasecmp(value, kv->key) == 0) {
374                                                 p = &((char *) gopts)[attrs[i].offset];
375                                                 * (int*) p = kv->value;
376                                                 break;
377                                         }
378                                 }
379                         } break;
380
381                 case ATTR_STRING:
382                         p = &((char *) gopts)[attrs[i].offset];
383                         if (* (char**) p != NULL) LDAP_FREE(* (char**) p);
384                         if (*value == '\0') {
385                                 * (char**) p = NULL;
386                         } else {
387                                 * (char**) p = LDAP_STRDUP(value);
388                         }
389                         break;
390                 case ATTR_OPTION:
391                         ldap_set_option( NULL, attrs[i].offset, value );
392                         break;
393                 case ATTR_SASL:
394 #ifdef HAVE_CYRUS_SASL
395                         ldap_int_sasl_config( gopts, attrs[i].offset, value );
396 #endif                          
397                         break;
398                 case ATTR_TLS:
399 #ifdef HAVE_TLS
400                         ldap_int_tls_config( NULL, attrs[i].offset, value );
401 #endif                          
402                         break;
403                 }
404         }
405 }
406
407 #if defined(__GNUC__)
408 /* Declare this function as a destructor so that it will automatically be
409  * invoked either at program exit (if libldap is a static library) or
410  * at unload time (if libldap is a dynamic library).
411  *
412  * Sorry, don't know how to handle this for non-GCC environments.
413  */
414 static void ldap_int_destroy_global_options(void)
415         __attribute__ ((destructor));
416 #endif
417
418 static void
419 ldap_int_destroy_global_options(void)
420 {
421         struct ldapoptions *gopts = LDAP_INT_GLOBAL_OPT();
422
423         if ( gopts == NULL )
424                 return;
425
426         gopts->ldo_valid = LDAP_UNINITIALIZED;
427
428         if ( gopts->ldo_defludp ) {
429                 ldap_free_urllist( gopts->ldo_defludp );
430                 gopts->ldo_defludp = NULL;
431         }
432 #if defined(HAVE_WINSOCK) || defined(HAVE_WINSOCK2)
433         WSACleanup( );
434 #endif
435
436 #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \
437         || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
438         if ( ldap_int_hostname ) {
439                 LDAP_FREE( ldap_int_hostname );
440                 ldap_int_hostname = NULL;
441         }
442 #endif
443 #ifdef HAVE_CYRUS_SASL
444         if ( gopts->ldo_def_sasl_authcid ) {
445                 LDAP_FREE( gopts->ldo_def_sasl_authcid );
446                 gopts->ldo_def_sasl_authcid = NULL;
447         }
448 #endif
449 #ifdef HAVE_TLS
450         ldap_int_tls_destroy( gopts );
451 #endif
452 }
453
454 /* 
455  * Initialize the global options structure with default values.
456  */
457 void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl )
458 {
459         if (dbglvl)
460             gopts->ldo_debug = *dbglvl;
461         else
462                 gopts->ldo_debug = 0;
463
464         gopts->ldo_version   = LDAP_VERSION2;
465         gopts->ldo_deref     = LDAP_DEREF_NEVER;
466         gopts->ldo_timelimit = LDAP_NO_LIMIT;
467         gopts->ldo_sizelimit = LDAP_NO_LIMIT;
468
469         gopts->ldo_tm_api = (struct timeval *)NULL;
470         gopts->ldo_tm_net = (struct timeval *)NULL;
471
472         /* ldo_defludp will be freed by the termination handler
473          */
474         ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/");
475         gopts->ldo_defport = LDAP_PORT;
476 #if !defined(__GNUC__) && !defined(PIC)
477         /* Do this only for a static library, and only if we can't
478          * arrange for it to be executed as a library destructor
479          */
480         atexit(ldap_int_destroy_global_options);
481 #endif
482
483         gopts->ldo_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
484         gopts->ldo_rebind_proc = NULL;
485         gopts->ldo_rebind_params = NULL;
486
487         LDAP_BOOL_ZERO(gopts);
488
489         LDAP_BOOL_SET(gopts, LDAP_BOOL_REFERRALS);
490
491 #ifdef LDAP_CONNECTIONLESS
492         gopts->ldo_peer = NULL;
493         gopts->ldo_cldapdn = NULL;
494         gopts->ldo_is_udp = 0;
495 #endif
496
497 #ifdef HAVE_CYRUS_SASL
498         gopts->ldo_def_sasl_mech = NULL;
499         gopts->ldo_def_sasl_realm = NULL;
500         gopts->ldo_def_sasl_authcid = NULL;
501         gopts->ldo_def_sasl_authzid = NULL;
502
503         memset( &gopts->ldo_sasl_secprops,
504                 '\0', sizeof(gopts->ldo_sasl_secprops) );
505
506         gopts->ldo_sasl_secprops.max_ssf = INT_MAX;
507         gopts->ldo_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
508         gopts->ldo_sasl_secprops.security_flags =
509                 SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
510 #endif
511
512 #ifdef HAVE_TLS
513         gopts->ldo_tls_connect_cb = NULL;
514         gopts->ldo_tls_connect_arg = NULL;
515 #endif
516
517         gopts->ldo_valid = LDAP_INITIALIZED;
518         return;
519 }
520
521 #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \
522         || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
523 char * ldap_int_hostname = NULL;
524 #endif
525
526 void ldap_int_initialize( struct ldapoptions *gopts, int *dbglvl )
527 {
528         if ( gopts->ldo_valid == LDAP_INITIALIZED ) {
529                 return;
530         }
531
532         ldap_int_error_init();
533
534         ldap_int_utils_init();
535
536 #ifdef HAVE_WINSOCK2
537 {       WORD wVersionRequested;
538         WSADATA wsaData;
539  
540         wVersionRequested = MAKEWORD( 2, 0 );
541         if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
542                 /* Tell the user that we couldn't find a usable */
543                 /* WinSock DLL.                                  */
544                 return;
545         }
546  
547         /* Confirm that the WinSock DLL supports 2.0.*/
548         /* Note that if the DLL supports versions greater    */
549         /* than 2.0 in addition to 2.0, it will still return */
550         /* 2.0 in wVersion since that is the version we      */
551         /* requested.                                        */
552  
553         if ( LOBYTE( wsaData.wVersion ) != 2 ||
554                 HIBYTE( wsaData.wVersion ) != 0 )
555         {
556             /* Tell the user that we couldn't find a usable */
557             /* WinSock DLL.                                  */
558             WSACleanup( );
559             return; 
560         }
561 }       /* The WinSock DLL is acceptable. Proceed. */
562 #elif HAVE_WINSOCK
563 {       WSADATA wsaData;
564         if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
565             return;
566         }
567 }
568 #endif
569
570 #if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \
571         || defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
572         {
573                 char    *name = ldap_int_hostname;
574
575                 ldap_int_hostname = ldap_pvt_get_fqdn( name );
576
577                 if ( name != NULL && name != ldap_int_hostname ) {
578                         LDAP_FREE( name );
579                 }
580         }
581 #endif
582
583 #ifndef HAVE_POLL
584         if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
585 #endif
586
587         ldap_int_initialize_global_options(gopts, NULL);
588
589         if( getenv("LDAPNOINIT") != NULL ) {
590                 return;
591         }
592
593 #ifdef HAVE_CYRUS_SASL
594         {
595                 /* set authentication identity to current user name */
596                 char *user = getenv("USER");
597
598                 if( user == NULL ) user = getenv("USERNAME");
599                 if( user == NULL ) user = getenv("LOGNAME");
600
601                 if( user != NULL ) {
602                         gopts->ldo_def_sasl_authcid = LDAP_STRDUP( user );
603                 }
604     }
605 #endif
606
607         openldap_ldap_init_w_sysconf(LDAP_CONF_FILE);
608         openldap_ldap_init_w_userconf(LDAP_USERRC_FILE);
609
610         {
611                 char *altfile = getenv(LDAP_ENV_PREFIX "CONF");
612
613                 if( altfile != NULL ) {
614                         Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n",
615                               LDAP_ENV_PREFIX "CONF", altfile, 0);
616                         openldap_ldap_init_w_sysconf( altfile );
617                 }
618                 else
619                         Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n",
620                               LDAP_ENV_PREFIX "CONF", 0, 0);
621         }
622
623         {
624                 char *altfile = getenv(LDAP_ENV_PREFIX "RC");
625
626                 if( altfile != NULL ) {
627                         Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n",
628                               LDAP_ENV_PREFIX "RC", altfile, 0);
629                         openldap_ldap_init_w_userconf( altfile );
630                 }
631                 else
632                         Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n",
633                               LDAP_ENV_PREFIX "RC", 0, 0);
634         }
635
636         openldap_ldap_init_w_env(gopts, NULL);
637 }