]> git.ipfire.org Git - thirdparty/squid.git/blame - helpers/basic_auth/LDAP/squid_ldap_auth.c
Summary: Update release notes.
[thirdparty/squid.git] / helpers / basic_auth / LDAP / squid_ldap_auth.c
CommitLineData
94439e4e 1/*
94439e4e 2 * squid_ldap_auth: authentication via ldap for squid proxy server
3 *
d4ce3aef 4 * Authors:
5 * Henrik Nordstrom
6 * hno@squid-cache.org
05b7b723 7 *
d4ce3aef 8 * Glen Newton
94439e4e 9 * glen.newton@nrc.ca
10 * Advanced Services
11 * CISTI
12 * National Research Council
d4ce3aef 13 *
14 * with contributions from others mentioned in the Changes section below
94439e4e 15 *
7c2a6c51 16 * Usage: squid_ldap_auth -b basedn [-s searchscope]
b671cc68 17 * [-f searchfilter] [-D binddn -w bindpasswd]
20b6fc8e 18 * [-u attr] [-h host] [-p port] [-P] [-R] [ldap_server_name[:port]] ...
94439e4e 19 *
20 * Dependencies: You need to get the OpenLDAP libraries
d4ce3aef 21 * from http://www.openldap.org or another compatible LDAP C-API
22 * implementation.
8370dcf2 23 *
24 * If you want to make a TLS enabled connection you will also need the
25 * OpenSSL libraries linked into openldap. See http://www.openssl.org/
94439e4e 26 *
27 * License: squid_ldap_auth is free software; you can redistribute it
28 * and/or modify it under the terms of the GNU General Public License
29 * as published by the Free Software Foundation; either version 2,
30 * or (at your option) any later version.
efd2f308 31 *
32 * Changes:
653b264e 33 * 2003-03-01: David J N Begley
34 * - Support for Netscape API method of ldap over SSL
35 * connections
36 * - Timeout option for better recovery when using
37 * multiple LDAP servers
954a8513 38 * 2003-03-01: Christoph Lechleitner <lech@ibcl.at>
39 * - Added -W option to read bindpasswd from file
7ba68818 40 * 2003-03-01: Juerg Michel
41 * - Added support for ldap URI via the -H option
42 * (requires OpenLDAP)
8370dcf2 43 * 2001-12-12: Michael Cunningham <m.cunningham@xpedite.com>
2c10afe0 44 * - Added TLS support and partial ldap version 3 support.
49b97dc8 45 * 2001-10-04: Henrik Nordstrom <hno@squid-cache.org>
46 * - Be consistent with the other helpers in how
20b6fc8e 47 * spaces are managed. If there is space characters
48 * then these are assumed to be part of the password
49 * 2001-09-05: Henrik Nordstrom <hno@squid-cache.org>
50 * - Added ability to specify another default LDAP port to
51 * connect to. Persistent connections moved to -P
87f6d1e1 52 * 2001-05-02: Henrik Nordstrom <hno@squid-cache.org>
53 * - Support newer OpenLDAP 2.x libraries using the
b671cc68 54 * revised Internet Draft API which unfortunately
87f6d1e1 55 * is not backwards compatible with RFC1823..
efd2f308 56 * 2001-04-15: Henrik Nordstrom <hno@squid-cache.org>
57 * - Added command line option for basedn
58 * - Added the ability to search for the user DN
c4c1f30c 59 * 2001-04-16: Henrik Nordstrom <hno@squid-cache.org>
60 * - Added -D binddn -w bindpasswd.
50f87883 61 * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org>
62 * - Added -R to disable referrals
63 * - Added -a to control alias dereferencing
7c2a6c51 64 * 2001-04-17: Henrik Nordstrom <hno@squid-cache.org>
65 * - Added -u, DN username attribute name
c9acd551 66 * 2001-04-18: Henrik Nordstrom <hno@squid-cache.org>
67 * - Allow full filter specifications in -f
94439e4e 68 */
69
70#include <stdio.h>
71#include <string.h>
331ba756 72#include <stdlib.h>
94439e4e 73#include <lber.h>
94439e4e 74#include <ldap.h>
75
9bbd1655 76#include "util.h"
77
653b264e 78#define PROGRAM_NAME "squid_ldap_auth"
79
80/* Global options */
7c2a6c51 81static char *basedn;
331ba756 82static char *searchfilter = NULL;
c4c1f30c 83static char *binddn = NULL;
84static char *bindpasswd = NULL;
963b6afb 85static char *userattr = "uid";
331ba756 86static int searchscope = LDAP_SCOPE_SUBTREE;
c4c1f30c 87static int persistent = 0;
50f87883 88static int noreferrals = 0;
89static int aliasderef = LDAP_DEREF_NEVER;
653b264e 90#if defined(NETSCAPE_SSL)
91static char *sslpath = NULL;
92static int sslinit = 0;
93#endif
94static int connect_timeout = 0;
95static int timelimit = LDAP_NO_LIMIT;
94439e4e 96
8370dcf2 97/* Added for TLS support and version 3 */
98static int use_tls = 0;
99static int version = -1;
100
c4c1f30c 101static int checkLDAP(LDAP * ld, char *userid, char *password);
954a8513 102static int readSecret(char *filename);
94439e4e 103
87f6d1e1 104/* Yuck.. we need to glue to different versions of the API */
105
106#if defined(LDAP_API_VERSION) && LDAP_API_VERSION > 1823
9bea1d5b 107static int
b671cc68 108squid_ldap_errno(LDAP * ld)
87f6d1e1 109{
110 int err = 0;
111 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err);
112 return err;
113}
9bea1d5b 114static void
b671cc68 115squid_ldap_set_aliasderef(LDAP * ld, int deref)
87f6d1e1 116{
117 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
118}
9bea1d5b 119static void
b671cc68 120squid_ldap_set_referrals(LDAP * ld, int referrals)
87f6d1e1 121{
122 int *value = referrals ? LDAP_OPT_ON : LDAP_OPT_OFF;
123 ldap_set_option(ld, LDAP_OPT_REFERRALS, value);
124}
a9ce6538 125static void
653b264e 126squid_ldap_set_timelimit(LDAP *ld, int timelimit)
127{
128 ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
129}
130static void
131squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
132{
133#if defined(LDAP_OPT_NETWORK_TIMEOUT)
134 struct timeval tv;
135 tv.tv_sec = timelimit;
136 tv.tv_usec = 0;
137 ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv);
138#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT)
139 timelimit *= 1000;
140 ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timelimit);
141#endif
142}
143static void
a9ce6538 144squid_ldap_memfree(char *p)
145{
146 ldap_memfree(p);
147}
87f6d1e1 148#else
9bea1d5b 149static int
b671cc68 150squid_ldap_errno(LDAP * ld)
87f6d1e1 151{
152 return ld->ld_errno;
153}
9bea1d5b 154static void
b671cc68 155squid_ldap_set_aliasderef(LDAP * ld, int deref)
87f6d1e1 156{
157 ld->ld_deref = deref;
158}
9bea1d5b 159static void
b671cc68 160squid_ldap_set_referrals(LDAP * ld, int referrals)
87f6d1e1 161{
162 if (referrals)
163 ld->ld_options |= ~LDAP_OPT_REFERRALS;
164 else
165 ld->ld_options &= ~LDAP_OPT_REFERRALS;
166}
653b264e 167static void squid_ldap_set_timelimit(LDAP *ld, int timelimit)
168{
169 ld->ld_timelimit = timelimit;
170}
171static void
172squid_ldap_set_connect_timeout(LDAP *ld, int timelimit)
173{
174 fprintf(stderr, "Connect timeouts not supported in your LDAP library\n");
175}
a9ce6538 176static void
177squid_ldap_memfree(char *p)
178{
179 free(p);
180}
87f6d1e1 181#endif
182
7ba68818 183#ifdef LDAP_API_FEATURE_X_OPENLDAP
184 #if LDAP_VENDOR_VERSION > 194
185 #define HAS_URI_SUPPORT 1
186 #endif
187#endif
188
94439e4e 189int
190main(int argc, char **argv)
191{
192 char buf[256];
49b97dc8 193 char *user, *passwd;
20b6fc8e 194 char *ldapServer = NULL;
c4c1f30c 195 LDAP *ld = NULL;
c4c1f30c 196 int tryagain;
70c46401 197 int port = LDAP_PORT;
94439e4e 198
199 setbuf(stdout, NULL);
200
20b6fc8e 201 while (argc > 1 && argv[1][0] == '-') {
c4c1f30c 202 char *value = "";
331ba756 203 char option = argv[1][1];
b671cc68 204 switch (option) {
70c46401 205 case 'P':
50f87883 206 case 'R':
8370dcf2 207 case 'z':
2c10afe0 208 case 'Z':
c4c1f30c 209 break;
210 default:
2c10afe0 211 if (strlen(argv[1]) > 2) {
b671cc68 212 value = argv[1] + 2;
2c10afe0 213 } else if (argc > 2) {
c4c1f30c 214 value = argv[2];
215 argv++;
216 argc--;
2c10afe0 217 } else
218 value = "";
c4c1f30c 219 break;
331ba756 220 }
221 argv++;
222 argc--;
b671cc68 223 switch (option) {
7ba68818 224 case 'H':
225#if !HAS_URI_SUPPORT
226 fprintf(stderr, "ERROR: Your LDAP library does not have URI support\n");
227 exit(1);
228#endif
229 /* Fall thru to -h */
20b6fc8e 230 case 'h':
231 if (ldapServer) {
232 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
233 char *newhost = malloc(len);
234 snprintf(newhost, len, "%s %s", ldapServer, value);
235 free(ldapServer);
236 ldapServer = newhost;
237 } else {
238 ldapServer = strdup(value);
239 }
240 break;
331ba756 241 case 'b':
b671cc68 242 basedn = value;
243 break;
331ba756 244 case 'f':
b671cc68 245 searchfilter = value;
246 break;
7c2a6c51 247 case 'u':
b671cc68 248 userattr = value;
249 break;
331ba756 250 case 's':
b671cc68 251 if (strcmp(value, "base") == 0)
252 searchscope = LDAP_SCOPE_BASE;
253 else if (strcmp(value, "one") == 0)
254 searchscope = LDAP_SCOPE_ONELEVEL;
255 else if (strcmp(value, "sub") == 0)
256 searchscope = LDAP_SCOPE_SUBTREE;
257 else {
653b264e 258 fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown search scope '%s'\n", value);
b671cc68 259 exit(1);
260 }
261 break;
653b264e 262 case 'E':
263#if defined(NETSCAPE_SSL)
264 sslpath = value;
265 if (port == LDAP_PORT)
266 port = LDAPS_PORT;
267#else
268 fprintf(stderr, PROGRAM_NAME " ERROR: -E unsupported with this LDAP library\n");
269 exit(1);
270#endif
271 break;
272 case 'c':
273 connect_timeout = atoi(value);
274 break;
275 case 't':
276 timelimit = atoi(value);
277 break;
50f87883 278 case 'a':
b671cc68 279 if (strcmp(value, "never") == 0)
280 aliasderef = LDAP_DEREF_NEVER;
281 else if (strcmp(value, "always") == 0)
282 aliasderef = LDAP_DEREF_ALWAYS;
283 else if (strcmp(value, "search") == 0)
284 aliasderef = LDAP_DEREF_SEARCHING;
285 else if (strcmp(value, "find") == 0)
286 aliasderef = LDAP_DEREF_FINDING;
287 else {
653b264e 288 fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown alias dereference method '%s'\n", value);
b671cc68 289 exit(1);
290 }
291 break;
c4c1f30c 292 case 'D':
b671cc68 293 binddn = value;
294 break;
c4c1f30c 295 case 'w':
b671cc68 296 bindpasswd = value;
297 break;
954a8513 298 case 'W':
299 readSecret (value);
300 break;
70c46401 301 case 'P':
b671cc68 302 persistent = !persistent;
303 break;
70c46401 304 case 'p':
305 port = atoi(value);
306 break;
50f87883 307 case 'R':
b671cc68 308 noreferrals = !noreferrals;
309 break;
653b264e 310#ifdef LDAP_VERSION3
8370dcf2 311 case 'v':
312 switch( atoi(value) ) {
313 case 2:
314 version = LDAP_VERSION2;
315 break;
316 case 3:
317 version = LDAP_VERSION3;
318 break;
319 default:
320 fprintf( stderr, "Protocol version should be 2 or 3\n");
321 exit(1);
322 }
323 break;
324 case 'Z':
325 if ( version == LDAP_VERSION2 ) {
326 fprintf( stderr, "TLS (-Z) is incompatible with version %d\n",
327 version);
328 exit(1);
329 }
330 version = LDAP_VERSION3;
331 use_tls = 1;
332 break;
653b264e 333#endif
331ba756 334 default:
653b264e 335 fprintf(stderr, PROGRAM_NAME ": ERROR: Unknown command line option '%c'\n", option);
b671cc68 336 exit(1);
331ba756 337 }
338 }
7c2a6c51 339
2c10afe0 340 while (argc > 1) {
20b6fc8e 341 char *value = argv[1];
342 if (ldapServer) {
343 int len = strlen(ldapServer) + 1 + strlen(value) + 1;
344 char *newhost = malloc(len);
345 snprintf(newhost, len, "%s %s", ldapServer, value);
346 free(ldapServer);
347 ldapServer = newhost;
348 } else {
349 ldapServer = strdup(value);
350 }
351 argc--;
352 argv++;
353 }
354 if (!ldapServer)
355 ldapServer = "localhost";
356
357 if (!basedn) {
653b264e 358 fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn [options] [ldap_server_name[:port]]...\n\n");
7c2a6c51 359 fprintf(stderr, "\t-b basedn (REQUIRED)\tbase dn under which to search\n");
c4c1f30c 360 fprintf(stderr, "\t-f filter\t\tsearch filter to locate user DN\n");
7c2a6c51 361 fprintf(stderr, "\t-u userattr\t\tusername DN attribute\n");
c4c1f30c 362 fprintf(stderr, "\t-s base|one|sub\t\tsearch scope\n");
363 fprintf(stderr, "\t-D binddn\t\tDN to bind as to perform searches\n");
364 fprintf(stderr, "\t-w bindpasswd\t\tpassword for binddn\n");
954a8513 365 fprintf(stderr, "\t-W secretfile\t\tread password for binddn from file secretfile\n");
7ba68818 366#if HAS_URI_SUPPORT
367 fprintf(stderr, "\t-H URI\t\t\tLDAPURI (defaults to ldap://localhost)\n");
368#endif
20b6fc8e 369 fprintf(stderr, "\t-h server\t\tLDAP server (defaults to localhost)\n");
de896945 370 fprintf(stderr, "\t-p port\t\t\tLDAP server port\n");
20b6fc8e 371 fprintf(stderr, "\t-P\t\t\tpersistent LDAP connection\n");
653b264e 372#if defined(NETSCAPE_SSL)
373 fprintf(stderr, "\t-E sslcertpath\t\tenable LDAP over SSL\n");
374#endif
375 fprintf(stderr, "\t-c timeout\t\tconnect timeout\n");
376 fprintf(stderr, "\t-t timelimit\t\tsearch time limit\n");
50f87883 377 fprintf(stderr, "\t-R\t\t\tdo not follow referrals\n");
378 fprintf(stderr, "\t-a never|always|search|find\n\t\t\t\twhen to dereference aliases\n");
7ba68818 379#ifdef LDAP_VERSION3
380 fprintf(stderr, "\t-v 2|3\t\t\tLDAP version\n");
b3154cd7 381 fprintf(stderr, "\t-Z\t\t\tTLS encrypt the LDAP connection, requires LDAP version 3\n");
7ba68818 382#endif
c4c1f30c 383 fprintf(stderr, "\n");
7c2a6c51 384 fprintf(stderr, "\tIf no search filter is specified, then the dn <userattr>=user,basedn\n\twill be used (same as specifying a search filter of '<userattr>=',\n\tbut quicker as as there is no need to search for the user DN)\n\n");
954a8513 385 fprintf(stderr, "\tIf you need to bind as a user to perform searches then use the\n\t-D binddn -w bindpasswd or -D binddn -W secretfile options\n\n");
94439e4e 386 exit(1);
387 }
94439e4e 388 while (fgets(buf, 256, stdin) != NULL) {
49b97dc8 389 user = strtok(buf, " \r\n");
2542502f 390 passwd = strtok(NULL, "\r\n");
94439e4e 391
49b97dc8 392 if (!user || !passwd || !passwd[0]) {
94439e4e 393 printf("ERR\n");
394 continue;
395 }
9bbd1655 396 rfc1738_unescape(user);
397 rfc1738_unescape(passwd);
c4c1f30c 398 tryagain = 1;
b671cc68 399 recover:
c4c1f30c 400 if (ld == NULL) {
7ba68818 401#if HAS_URI_SUPPORT
402 if (strstr(ldapServer, "://") != NULL) {
653b264e 403 int rc = ldap_initialize( &ld, ldapServer );
7ba68818 404 if( rc != LDAP_SUCCESS ) {
405 fprintf(stderr, "\nUnable to connect to LDAPURI:%s\n", ldapServer);
406 break;
407 }
408 } else
653b264e 409#endif
410#if NETSCAPE_SSL
411 if (sslpath) {
412 if ( !sslinit && (ldapssl_client_init(sslpath, NULL) != LDAP_SUCCESS)) {
413 fprintf(stderr, "\nUnable to initialise SSL with cert path %s\n",
414 sslpath);
415 exit(1);
416 } else {
417 sslinit++;
418 }
419 if ((ld = ldapssl_init(ldapServer, port, 1)) == NULL) {
420 fprintf(stderr, "\nUnable to connect to SSL LDAP server: %s port:%d\n",
421 ldapServer, port);
422 exit(1);
423 }
424 } else
7ba68818 425#endif
70c46401 426 if ((ld = ldap_init(ldapServer, port)) == NULL) {
c4c1f30c 427 fprintf(stderr, "\nUnable to connect to LDAP server:%s port:%d\n",
70c46401 428 ldapServer, port);
c4c1f30c 429 exit(1);
430 }
8370dcf2 431
653b264e 432 if (connect_timeout)
433 squid_ldap_set_connect_timeout(ld, connect_timeout);
434
435#ifdef LDAP_VERSION3
436 if (version == -1 ) {
8370dcf2 437 version = LDAP_VERSION2;
653b264e 438 }
8370dcf2 439
653b264e 440 if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version )
441 != LDAP_OPT_SUCCESS )
442 {
8370dcf2 443 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n",
444 version );
445 exit(1);
653b264e 446 }
8370dcf2 447
653b264e 448 if ( use_tls && ( version == LDAP_VERSION3 ) && ( ldap_start_tls_s( ld, NULL, NULL ) == LDAP_SUCCESS )) {
8370dcf2 449 fprintf( stderr, "Could not Activate TLS connection\n");
450 exit(1);
653b264e 451 }
452#endif
453 squid_ldap_set_timelimit(ld, timelimit);
87f6d1e1 454 squid_ldap_set_referrals(ld, !noreferrals);
455 squid_ldap_set_aliasderef(ld, aliasderef);
94439e4e 456 }
6ee0ef8e 457 if (checkLDAP(ld, user, passwd) != 0) {
87f6d1e1 458 if (tryagain && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS) {
c4c1f30c 459 tryagain = 0;
460 ldap_unbind(ld);
461 ld = NULL;
462 goto recover;
463 }
94439e4e 464 printf("ERR\n");
94439e4e 465 } else {
466 printf("OK\n");
467 }
87f6d1e1 468 if (!persistent || (squid_ldap_errno(ld) != LDAP_SUCCESS && squid_ldap_errno(ld) != LDAP_INVALID_CREDENTIALS)) {
c4c1f30c 469 ldap_unbind(ld);
470 ld = NULL;
471 }
94439e4e 472 }
c4c1f30c 473 if (ld)
474 ldap_unbind(ld);
331ba756 475 return 0;
94439e4e 476}
477
c4c1f30c 478static int
94439e4e 479checkLDAP(LDAP * ld, char *userid, char *password)
480{
331ba756 481 char dn[256];
94439e4e 482
c4c1f30c 483 if (!*password) {
484 /* LDAP can't bind with a blank password. Seen as "anonymous"
485 * and always granted access
486 */
487 return 1;
488 }
331ba756 489 if (searchfilter) {
490 char filter[256];
491 LDAPMessage *res = NULL;
492 LDAPMessage *entry;
b671cc68 493 char *searchattr[] =
494 {NULL};
331ba756 495 char *userdn;
50f87883 496 int rc;
94439e4e 497
c4c1f30c 498 if (binddn) {
50f87883 499 rc = ldap_simple_bind_s(ld, binddn, bindpasswd);
500 if (rc != LDAP_SUCCESS) {
653b264e 501 fprintf(stderr, PROGRAM_NAME ": WARNING, could not bind to binddn '%s'\n", ldap_err2string(rc));
c4c1f30c 502 return 1;
503 }
504 }
c9acd551 505 snprintf(filter, sizeof(filter), searchfilter, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid, userid);
4e9ab9a6 506 rc = ldap_search_s(ld, basedn, searchscope, filter, searchattr, 1, &res);
507 if (rc != LDAP_SUCCESS) {
60ce38ae 508 if (noreferrals && rc == LDAP_PARTIAL_RESULTS) {
509 /* Everything is fine. This is expected when referrals
510 * are disabled.
50f87883 511 */
60ce38ae 512 } else {
653b264e 513 fprintf(stderr, PROGRAM_NAME ": WARNING, LDAP search error '%s'\n", ldap_err2string(rc));
514#if defined(NETSCAPE_SSL)
515 if (sslpath && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))) {
516 int sslerr = PORT_GetError();
517 fprintf(stderr, PROGRAM_NAME ": WARNING, SSL error %d (%s)\n", sslerr, ldapssl_err2string(sslerr));
518 }
519#endif
46412b38 520 ldap_msgfree(res);
521 return 1;
50f87883 522 }
523 }
331ba756 524 entry = ldap_first_entry(ld, res);
525 if (!entry) {
526 ldap_msgfree(res);
527 return 1;
528 }
529 userdn = ldap_get_dn(ld, entry);
530 if (!userdn) {
653b264e 531 fprintf(stderr, PROGRAM_NAME ": ERROR, could not get user DN for '%s'\n", userid);
331ba756 532 ldap_msgfree(res);
533 return 1;
534 }
535 snprintf(dn, sizeof(dn), "%s", userdn);
8f64c86a 536 squid_ldap_memfree(userdn);
331ba756 537 ldap_msgfree(res);
538 } else {
7c2a6c51 539 snprintf(dn, sizeof(dn), "%s=%s,%s", userattr, userid, basedn);
94439e4e 540 }
331ba756 541
c4c1f30c 542 if (ldap_simple_bind_s(ld, dn, password) != LDAP_SUCCESS)
543 return 1;
b671cc68 544
c4c1f30c 545 return 0;
94439e4e 546}
954a8513 547
548int readSecret(char *filename)
549{
550 char buf[BUFSIZ];
551 char *e=0;
552 FILE *f;
553
554 if(!(f=fopen(filename, "r"))) {
555 fprintf(stderr, PROGRAM_NAME " ERROR: Can not read secret file %s\n", filename);
556 return 1;
557 }
558
559 if( !fgets(buf, sizeof(buf)-1, f)) {
560 fprintf(stderr, PROGRAM_NAME " ERROR: Secret file %s is empty\n", filename);
561 fclose(f);
562 return 1;
563 }
564
565 /* strip whitespaces on end */
566 if((e = strrchr(buf, '\n'))) *e = 0;
567 if((e = strrchr(buf, '\r'))) *e = 0;
568
569 bindpasswd = (char *) calloc(sizeof(char), strlen(buf)+1);
570 if (bindpasswd) {
571 strcpy(bindpasswd, buf);
572 } else {
573 fprintf(stderr, PROGRAM_NAME " ERROR: can not allocate memory\n");
574 }
575
576 fclose(f);
577
578 return 0;
579}