init.c 13 KB
Newer Older
1
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
6
7
8
#include "portable.h"

#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
9
#include <ac/stdlib.h>
10
11
12

#include <ac/socket.h>
#include <ac/string.h>
13
#include <ac/ctype.h>
14
15
#include <ac/time.h>

16
17
#include <limits.h>

18
#include "ldap-int.h"
19
#include "ldap_defaults.h"
20

21
22
struct ldapoptions ldap_int_global_options =
	{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE };  
23

24
25
26
27
28
#define ATTR_NONE	0
#define ATTR_BOOL	1
#define ATTR_INT	2
#define ATTR_KV		3
#define ATTR_STRING	4
29
#define ATTR_OPTION	5
30
31
32

#define ATTR_SASL	6
#define ATTR_TLS	7
33
34

struct ol_keyvalue {
35
	const char *		key;
36
37
38
	int			value;
};

39
static const struct ol_keyvalue deref_kv[] = {
40
41
42
43
44
45
46
	{"never", LDAP_DEREF_NEVER},
	{"searching", LDAP_DEREF_SEARCHING},
	{"finding", LDAP_DEREF_FINDING},
	{"always", LDAP_DEREF_ALWAYS},
	{NULL, 0}
};

47
static const struct ol_attribute {
48
	int			useronly;
49
	int			type;
50
51
	const char *	name;
	const void *	data;
52
53
	size_t		offset;
} attrs[] = {
54
	{0, ATTR_KV,		"DEREF",	deref_kv, /* or &deref_kv[0] */
55
		offsetof(struct ldapoptions, ldo_deref)},
56
	{0, ATTR_INT,		"SIZELIMIT",	NULL,
57
		offsetof(struct ldapoptions, ldo_sizelimit)},
58
	{0, ATTR_INT,		"TIMELIMIT",	NULL,
59
		offsetof(struct ldapoptions, ldo_timelimit)},
60
61
	{1, ATTR_STRING,	"BINDDN",		NULL,
		offsetof(struct ldapoptions, ldo_defbinddn)},
62
	{0, ATTR_STRING,	"BASE",			NULL,
63
		offsetof(struct ldapoptions, ldo_defbase)},
64
	{0, ATTR_INT,		"PORT",			NULL,		/* deprecated */
65
		offsetof(struct ldapoptions, ldo_defport)},
66
67
	{0, ATTR_OPTION,	"HOST",			NULL,	LDAP_OPT_HOST_NAME}, /* deprecated */
	{0, ATTR_OPTION,	"URI",			NULL,	LDAP_OPT_URI}, /* replaces HOST/PORT */
68
69
	{0, ATTR_BOOL,		"REFERRALS",	NULL,	LDAP_BOOL_REFERRALS},
	{0, ATTR_BOOL,		"RESTART",		NULL,	LDAP_BOOL_RESTART},
70

71
#ifdef HAVE_CYRUS_SASL
72
73
74
75
76
77
78
79
80
	{1, ATTR_STRING,	"SASL_MECH",		NULL,
		offsetof(struct ldapoptions, ldo_def_sasl_mech)},
	{1, ATTR_STRING,	"SASL_REALM",		NULL,
		offsetof(struct ldapoptions, ldo_def_sasl_realm)},
	{1, ATTR_STRING,	"SASL_AUTHCID",		NULL,
		offsetof(struct ldapoptions, ldo_def_sasl_authcid)},
	{1, ATTR_STRING,	"SASL_AUTHZID",		NULL,
		offsetof(struct ldapoptions, ldo_def_sasl_authzid)},
	{0, ATTR_SASL,		"SASL_SECPROPS",	NULL,	LDAP_OPT_X_SASL_SECPROPS},
81
82
#endif

83
#ifdef HAVE_TLS
84
  	{0, ATTR_TLS,		"TLS",			NULL,	LDAP_OPT_X_TLS},
85
86
	{1, ATTR_TLS,		"TLS_CERT",		NULL,	LDAP_OPT_X_TLS_CERTFILE},
	{1, ATTR_TLS,		"TLS_KEY",		NULL,	LDAP_OPT_X_TLS_KEYFILE},
87
88
  	{0, ATTR_TLS,		"TLS_CACERT",	NULL,	LDAP_OPT_X_TLS_CACERTFILE},
  	{0, ATTR_TLS,		"TLS_CACERTDIR",NULL,	LDAP_OPT_X_TLS_CACERTDIR},
89
90
  	{0, ATTR_TLS,		"TLS_REQCERT",	NULL,	LDAP_OPT_X_TLS_REQUIRE_CERT},
	{0, ATTR_TLS,		"TLS_RANDFILE",	NULL,	LDAP_OPT_X_TLS_RANDOM_FILE},
91
92
#endif

93
	{0, ATTR_NONE,		NULL,		NULL,	0}
94
95
};

96
#define MAX_LDAP_ATTR_LEN  sizeof("TLS_CACERTDIR")
97
98
#define MAX_LDAP_ENV_PREFIX_LEN 8

99
100
static void openldap_ldap_init_w_conf(
	const char *file, int userconf )
101
102
103
104
105
106
{
	char linebuf[128];
	FILE *fp;
	int i;
	char *cmd, *opt;
	char *start, *end;
107
108
109
110
111
	struct ldapoptions *gopts;

	if ((gopts = LDAP_INT_GLOBAL_OPT()) == NULL) {
		return;			/* Could not allocate mem for global options */
	}
112

113
114
115
116
117
	if (file == NULL) {
		/* no file name */
		return;
	}

118
119
	Debug(LDAP_DEBUG_TRACE, "ldap_init: trying %s\n", file, 0, 0);

120
121
122
123
124
125
	fp = fopen(file, "r");
	if(fp == NULL) {
		/* could not open file */
		return;
	}

126
127
	Debug(LDAP_DEBUG_TRACE, "ldap_init: using %s\n", file, 0, 0);

128
129
130
131
132
	while((start = fgets(linebuf, sizeof(linebuf), fp)) != NULL) {
		/* skip lines starting with '#' */
		if(*start == '#') continue;

		/* trim leading white space */
133
134
		while((*start != '\0') && isspace((unsigned char) *start))
			start++;
135
136
137
138
139
140

		/* anything left? */
		if(*start == '\0') continue;

		/* trim trailing white space */
		end = &start[strlen(start)-1];
141
		while(isspace((unsigned char)*end)) end--;
142
143
144
145
146
147
148
149
		end[1] = '\0';

		/* anything left? */
		if(*start == '\0') continue;
		

		/* parse the command */
		cmd=start;
150
		while((*start != '\0') && !isspace((unsigned char)*start)) {
151
152
153
154
155
156
157
158
159
			start++;
		}
		if(*start == '\0') {
			/* command has no argument */
			continue;
		} 

		*start++ = '\0';

160
		/* we must have some whitespace to skip */
161
		while(isspace((unsigned char)*start)) start++;
162
163
164
165
166
		opt = start;

		for(i=0; attrs[i].type != ATTR_NONE; i++) {
			void *p;

167
			if( !userconf && attrs[i].useronly ) {
168
169
170
				continue;
			}

171
172
173
174
175
176
177
178
179
180
			if(strcasecmp(cmd, attrs[i].name) != 0) {
				continue;
			}

			switch(attrs[i].type) {
			case ATTR_BOOL:
				if((strcasecmp(opt, "on") == 0) 
					|| (strcasecmp(opt, "yes") == 0)
					|| (strcasecmp(opt, "true") == 0))
				{
181
					LDAP_BOOL_SET(gopts, attrs[i].offset);
182
183

				} else {
184
					LDAP_BOOL_CLR(gopts, attrs[i].offset);
185
186
187
188
189
				}

				break;

			case ATTR_INT:
190
				p = &((char *) gopts)[attrs[i].offset];
191
192
193
194
				* (int*) p = atoi(opt);
				break;

			case ATTR_KV: {
195
					const struct ol_keyvalue *kv;
196

197
					for(kv = attrs[i].data;
198
199
200
201
						kv->key != NULL;
						kv++) {

						if(strcasecmp(opt, kv->key) == 0) {
202
							p = &((char *) gopts)[attrs[i].offset];
203
204
205
206
207
208
209
							* (int*) p = kv->value;
							break;
						}
					}
				} break;

			case ATTR_STRING:
210
				p = &((char *) gopts)[attrs[i].offset];
211
				if (* (char**) p != NULL) LDAP_FREE(* (char**) p);
212
				* (char**) p = LDAP_STRDUP(opt);
213
				break;
214
215
			case ATTR_OPTION:
				ldap_set_option( NULL, attrs[i].offset, opt );
216
				break;
217
218
219
220
221
222
223
			case ATTR_SASL:
#ifdef HAVE_CYRUS_SASL
			   	ldap_int_sasl_config( gopts, attrs[i].offset, opt );
#endif
				break;
			case ATTR_TLS:
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
224
			   	ldap_int_tls_config( NULL, attrs[i].offset, opt );
225
226
#endif
				break;
227
			}
228

229
			break;
230
231
		}
	}
232
233

	fclose(fp);
234
235
}

236
237
238
239
240
static void openldap_ldap_init_w_sysconf(const char *file)
{
	openldap_ldap_init_w_conf( file, 0 );
}

241
242
static void openldap_ldap_init_w_userconf(const char *file)
{
243
	char *home;
244
	char *path = NULL;
245
246
247
248
249
250
251
252

	if (file == NULL) {
		/* no file name */
		return;
	}

	home = getenv("HOME");

Kurt Zeilenga's avatar
Kurt Zeilenga committed
253
	if (home != NULL) {
254
255
		Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is %s\n",
		      home, 0, 0);
256
		path = LDAP_MALLOC(strlen(home) + strlen(file) + 3);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
	} else {
258
259
		Debug(LDAP_DEBUG_TRACE, "ldap_init: HOME env is NULL\n",
		      0, 0, 0);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
260
261
262
	}

	if(home != NULL && path != NULL) {
263
264
		/* we assume UNIX path syntax is used... */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
265
		/* try ~/file */
266
		sprintf(path, "%s%s%s", home, LDAP_DIRSEP, file);
267
		openldap_ldap_init_w_conf(path, 1);
268

Kurt Zeilenga's avatar
Kurt Zeilenga committed
269
		/* try ~/.file */
270
		sprintf(path, "%s%s.%s", home, LDAP_DIRSEP, file);
271
		openldap_ldap_init_w_conf(path, 1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
	}
273
274

	if(path != NULL) {
275
		LDAP_FREE(path);
276
	}
277
278

	/* try file */
279
	openldap_ldap_init_w_conf(file, 1);
280
281
}

282
283
284
static void openldap_ldap_init_w_env(
		struct ldapoptions *gopts,
		const char *prefix)
285
286
287
288
289
290
291
292
{
	char buf[MAX_LDAP_ATTR_LEN+MAX_LDAP_ENV_PREFIX_LEN];
	int len;
	int i;
	void *p;
	char *value;

	if (prefix == NULL) {
293
		prefix = LDAP_ENV_PREFIX;
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
	}

	strncpy(buf, prefix, MAX_LDAP_ENV_PREFIX_LEN);
	buf[MAX_LDAP_ENV_PREFIX_LEN] = '\0';
	len = strlen(buf);

	for(i=0; attrs[i].type != ATTR_NONE; i++) {
		strcpy(&buf[len], attrs[i].name);
		value = getenv(buf);

		if(value == NULL) {
			continue;
		}

		switch(attrs[i].type) {
		case ATTR_BOOL:
			if((strcasecmp(value, "on") == 0) 
				|| (strcasecmp(value, "yes") == 0)
				|| (strcasecmp(value, "true") == 0))
			{
314
				LDAP_BOOL_SET(gopts, attrs[i].offset);
315
316

			} else {
317
				LDAP_BOOL_CLR(gopts, attrs[i].offset);
318
319
320
321
			}
			break;

		case ATTR_INT:
322
			p = &((char *) gopts)[attrs[i].offset];
323
324
325
326
			* (int*) p = atoi(value);
			break;

		case ATTR_KV: {
327
				const struct ol_keyvalue *kv;
328

329
				for(kv = attrs[i].data;
330
331
332
333
					kv->key != NULL;
					kv++) {

					if(strcasecmp(value, kv->key) == 0) {
334
						p = &((char *) gopts)[attrs[i].offset];
335
336
337
338
339
340
341
						* (int*) p = kv->value;
						break;
					}
				}
			} break;

		case ATTR_STRING:
342
			p = &((char *) gopts)[attrs[i].offset];
343
			if (* (char**) p != NULL) LDAP_FREE(* (char**) p);
344
345
346
			if (*value == '\0') {
				* (char**) p = NULL;
			} else {
347
				* (char**) p = LDAP_STRDUP(value);
348
349
			}
			break;
350
351
		case ATTR_OPTION:
			ldap_set_option( NULL, attrs[i].offset, value );
352
			break;
353
354
355
356
357
358
359
		case ATTR_SASL:
#ifdef HAVE_CYRUS_SASL
		   	ldap_int_sasl_config( gopts, attrs[i].offset, value );
#endif			 	
		   	break;
		case ATTR_TLS:
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360
		   	ldap_int_tls_config( NULL, attrs[i].offset, value );
361
362
#endif			 	
		   	break;
363
364
365
366
		}
	}
}

367
368
369
370
371
372
373
374
375
376
377
#if defined(__GNUC__)
/* Declare this function as a destructor so that it will automatically be
 * invoked either at program exit (if libldap is a static library) or
 * at unload time (if libldap is a dynamic library).
 *
 * Sorry, don't know how to handle this for non-GCC environments.
 */
static void ldap_int_destroy_global_options(void)
	__attribute__ ((destructor));
#endif

378
static void
Howard Chu's avatar
Howard Chu committed
379
ldap_int_destroy_global_options(void)
380
381
382
383
384
385
386
{
	struct ldapoptions *gopts = LDAP_INT_GLOBAL_OPT();

	if ( gopts->ldo_defludp ) {
		ldap_free_urllist( gopts->ldo_defludp );
		gopts->ldo_defludp = NULL;
	}
387
388
389
#if defined(HAVE_WINSOCK) || defined(HAVE_WINSOCK2)
	WSACleanup( );
#endif
390
391
}

392
393
394
395
/* 
 * Initialize the global options structure with default values.
 */
void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl )
396
{
397
	if (dbglvl)
398
	    gopts->ldo_debug = *dbglvl;
399
	else
400
		gopts->ldo_debug = 0;
401

402
403
404
405
	gopts->ldo_version   = LDAP_VERSION2;
	gopts->ldo_deref     = LDAP_DEREF_NEVER;
	gopts->ldo_timelimit = LDAP_NO_LIMIT;
	gopts->ldo_sizelimit = LDAP_NO_LIMIT;
406

407
408
	gopts->ldo_tm_api = (struct timeval *)NULL;
	gopts->ldo_tm_net = (struct timeval *)NULL;
409

410
	/* ldo_defludp will be freed by the termination handler
411
	 */
412
413
	ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/");
	gopts->ldo_defport = LDAP_PORT;
414
415
416
417
#if !defined(__GNUC__) && !defined(PIC)
	/* Do this only for a static library, and only if we can't
	 * arrange for it to be executed as a library destructor
	 */
418
	atexit(ldap_int_destroy_global_options);
419
#endif
420

421
	gopts->ldo_refhoplimit = LDAP_DEFAULT_REFHOPLIMIT;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
422
423
	gopts->ldo_rebind_proc = NULL;
	gopts->ldo_rebind_params = NULL;
424

425
	LDAP_BOOL_ZERO(gopts);
426

427
	LDAP_BOOL_SET(gopts, LDAP_BOOL_REFERRALS);
428

429
430
431
#ifdef LDAP_CONNECTIONLESS
	gopts->ldo_peer = NULL;
	gopts->ldo_cldapdn = NULL;
Howard Chu's avatar
Howard Chu committed
432
	gopts->ldo_is_udp = 0;
433
434
#endif

435
#ifdef HAVE_CYRUS_SASL
436
437
438
439
440
	gopts->ldo_def_sasl_mech = NULL;
	gopts->ldo_def_sasl_realm = NULL;
	gopts->ldo_def_sasl_authcid = NULL;
	gopts->ldo_def_sasl_authzid = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
441
442
	memset( &gopts->ldo_sasl_secprops,
		'\0', sizeof(gopts->ldo_sasl_secprops) );
443
444

	gopts->ldo_sasl_secprops.max_ssf = INT_MAX;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
445
446
447
	gopts->ldo_sasl_secprops.maxbufsize = SASL_MAX_BUFF_SIZE;
	gopts->ldo_sasl_secprops.security_flags =
		SASL_SEC_NOPLAINTEXT | SASL_SEC_NOANONYMOUS;
448
#endif
449

450
451
452
453
	gopts->ldo_valid = LDAP_INITIALIZED;
   	return;
}

454
455
#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \
	|| defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
456
char * ldap_int_hostname = NULL;
457
458
#endif

459
460
461
462
463
464
void ldap_int_initialize( struct ldapoptions *gopts, int *dbglvl )
{
	if ( gopts->ldo_valid == LDAP_INITIALIZED ) {
		return;
	}

465
466
	ldap_int_error_init();

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
#ifdef HAVE_WINSOCK2
{	WORD wVersionRequested;
	WSADATA wsaData;
 
	wVersionRequested = MAKEWORD( 2, 0 );
	if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
		/* Tell the user that we couldn't find a usable */
		/* WinSock DLL.                                  */
		return;
	}
 
	/* Confirm that the WinSock DLL supports 2.0.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.0 in addition to 2.0, it will still return */
	/* 2.0 in wVersion since that is the version we      */
	/* requested.                                        */
 
	if ( LOBYTE( wsaData.wVersion ) != 2 ||
		HIBYTE( wsaData.wVersion ) != 0 )
	{
	    /* Tell the user that we couldn't find a usable */
	    /* WinSock DLL.                                  */
	    WSACleanup( );
	    return; 
	}
}	/* The WinSock DLL is acceptable. Proceed. */
#elif HAVE_WINSOCK
{	WSADATA wsaData;
	if ( WSAStartup( 0x0101, &wsaData ) != 0 ) {
	    return;
	}
}
499
500
501
502
503
#endif

#if defined(LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND) \
	|| defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
	ldap_int_hostname = ldap_pvt_get_fqdn( ldap_int_hostname );
504
#endif
505
506
507
508
509
510
	ldap_int_utils_init();

	if ( ldap_int_tblsize == 0 )
		ldap_int_ip_init();

	ldap_int_initialize_global_options(gopts, NULL);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511
512
513
514
515

	if( getenv("LDAPNOINIT") != NULL ) {
		return;
	}

516
517
518
519
520
521
522
523
524
#ifdef HAVE_CYRUS_SASL
	{
		/* set authentication identity to current user name */
		char *user = getenv("USER");

		if( user == NULL ) user = getenv("USERNAME");
		if( user == NULL ) user = getenv("LOGNAME");

		if( user != NULL ) {
525
			gopts->ldo_def_sasl_authcid = user;
526
527
528
529
		}
    }
#endif

530
	openldap_ldap_init_w_sysconf(LDAP_CONF_FILE);
531
	openldap_ldap_init_w_userconf(LDAP_USERRC_FILE);
532
533

	{
534
		char *altfile = getenv(LDAP_ENV_PREFIX "CONF");
535
536

		if( altfile != NULL ) {
537
538
			Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n",
			      LDAP_ENV_PREFIX "CONF", altfile, 0);
539
			openldap_ldap_init_w_sysconf( altfile );
540
		}
541
542
543
		else
			Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n",
			      LDAP_ENV_PREFIX "CONF", 0, 0);
544
545
	}

546
	{
547
		char *altfile = getenv(LDAP_ENV_PREFIX "RC");
548
549

		if( altfile != NULL ) {
550
551
			Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is %s\n",
			      LDAP_ENV_PREFIX "RC", altfile, 0);
552
553
			openldap_ldap_init_w_userconf( altfile );
		}
554
555
556
		else
			Debug(LDAP_DEBUG_TRACE, "ldap_init: %s env is NULL\n",
			      LDAP_ENV_PREFIX "RC", 0, 0);
557
558
	}

559
	openldap_ldap_init_w_env(gopts, NULL);
560
561

	ldap_int_sasl_init();
562
}