r20860: Adding some small tweaks. When we have no sitename, there is no need to
[samba.git] / source / libads / kerberos.c
1 /* 
2    Unix SMB/CIFS implementation.
3    kerberos utility library
4    Copyright (C) Andrew Tridgell 2001
5    Copyright (C) Remus Koos 2001
6    Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
7    Copyright (C) Jeremy Allison 2004.
8    Copyright (C) Gerald Carter 2006.
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26
27 #ifdef HAVE_KRB5
28
29 #define LIBADS_CCACHE_NAME "MEMORY:libads"
30
31 /*
32   we use a prompter to avoid a crash bug in the kerberos libs when 
33   dealing with empty passwords
34   this prompter is just a string copy ...
35 */
36 static krb5_error_code 
37 kerb_prompter(krb5_context ctx, void *data,
38                const char *name,
39                const char *banner,
40                int num_prompts,
41                krb5_prompt prompts[])
42 {
43         if (num_prompts == 0) return 0;
44
45         memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
46         if (prompts[0].reply->length > 0) {
47                 if (data) {
48                         strncpy(prompts[0].reply->data, (const char *)data,
49                                 prompts[0].reply->length-1);
50                         prompts[0].reply->length = strlen(prompts[0].reply->data);
51                 } else {
52                         prompts[0].reply->length = 0;
53                 }
54         }
55         return 0;
56 }
57
58 /*
59   simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
60   place in default cache location.
61   remus@snapserver.com
62 */
63 int kerberos_kinit_password_ext(const char *principal,
64                                 const char *password,
65                                 int time_offset,
66                                 time_t *expire_time,
67                                 time_t *renew_till_time,
68                                 const char *cache_name,
69                                 BOOL request_pac,
70                                 BOOL add_netbios_addr,
71                                 time_t renewable_time)
72 {
73         krb5_context ctx = NULL;
74         krb5_error_code code = 0;
75         krb5_ccache cc = NULL;
76         krb5_principal me;
77         krb5_creds my_creds;
78         krb5_get_init_creds_opt opt;
79         smb_krb5_addresses *addr = NULL;
80
81         initialize_krb5_error_table();
82         if ((code = krb5_init_context(&ctx)))
83                 return code;
84
85         if (time_offset != 0) {
86                 krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
87         }
88
89         DEBUG(10,("kerberos_kinit_password: using [%s] as ccache and config [%s]\n",
90                         cache_name ? cache_name: krb5_cc_default_name(ctx),
91                         getenv("KRB5_CONFIG")));
92
93         if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
94                 krb5_free_context(ctx);
95                 return code;
96         }
97         
98         if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
99                 krb5_free_context(ctx); 
100                 return code;
101         }
102
103         krb5_get_init_creds_opt_init(&opt);
104         krb5_get_init_creds_opt_set_renew_life(&opt, renewable_time);
105         krb5_get_init_creds_opt_set_forwardable(&opt, 1);
106         
107         if (request_pac) {
108 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
109                 code = krb5_get_init_creds_opt_set_pac_request(ctx, &opt, True);
110                 if (code) {
111                         krb5_free_principal(ctx, me);
112                         krb5_free_context(ctx);
113                         return code;
114                 }
115 #endif
116         }
117
118         if (add_netbios_addr) {
119                 code = smb_krb5_gen_netbios_krb5_address(&addr);
120                 if (code) {
121                         krb5_free_principal(ctx, me);
122                         krb5_free_context(ctx);         
123                         return code;    
124                 }
125                 krb5_get_init_creds_opt_set_address_list(&opt, addr->addrs);
126         }
127
128         if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
129                                                  kerb_prompter, NULL, 0, NULL, &opt)))
130         {
131                 smb_krb5_free_addresses(ctx, addr);
132                 krb5_free_principal(ctx, me);
133                 krb5_free_context(ctx);         
134                 return code;
135         }
136         
137         if ((code = krb5_cc_initialize(ctx, cc, me))) {
138                 smb_krb5_free_addresses(ctx, addr);
139                 krb5_free_cred_contents(ctx, &my_creds);
140                 krb5_free_principal(ctx, me);
141                 krb5_free_context(ctx);         
142                 return code;
143         }
144         
145         if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
146                 krb5_cc_close(ctx, cc);
147                 smb_krb5_free_addresses(ctx, addr);
148                 krb5_free_cred_contents(ctx, &my_creds);
149                 krb5_free_principal(ctx, me);
150                 krb5_free_context(ctx);         
151                 return code;
152         }
153
154         if (expire_time) {
155                 *expire_time = (time_t) my_creds.times.endtime;
156         }
157
158         if (renew_till_time) {
159                 *renew_till_time = (time_t) my_creds.times.renew_till;
160         }
161
162         krb5_cc_close(ctx, cc);
163         smb_krb5_free_addresses(ctx, addr);
164         krb5_free_cred_contents(ctx, &my_creds);
165         krb5_free_principal(ctx, me);
166         krb5_free_context(ctx);         
167         
168         return 0;
169 }
170
171
172
173 /* run kinit to setup our ccache */
174 int ads_kinit_password(ADS_STRUCT *ads)
175 {
176         char *s;
177         int ret;
178         const char *account_name;
179         fstring acct_name;
180
181         if ( IS_DC ) {
182                 /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
183                 account_name = lp_workgroup();
184         } else {
185                 /* always use the sAMAccountName for security = domain */
186                 /* global_myname()$@REA.LM */
187                 if ( lp_security() == SEC_DOMAIN ) {
188                         fstr_sprintf( acct_name, "%s$", global_myname() );
189                         account_name = acct_name;
190                 }
191                 else 
192                         /* This looks like host/global_myname()@REA.LM */
193                         account_name = ads->auth.user_name;
194         }
195
196         if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
197                 return KRB5_CC_NOMEM;
198         }
199
200         if (!ads->auth.password) {
201                 SAFE_FREE(s);
202                 return KRB5_LIBOS_CANTREADPWD;
203         }
204         
205         ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
206                         &ads->auth.expire, NULL, NULL, False, False, ads->auth.renewable);
207
208         if (ret) {
209                 DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
210                          s, error_message(ret)));
211         }
212         SAFE_FREE(s);
213         return ret;
214 }
215
216 int ads_kdestroy(const char *cc_name)
217 {
218         krb5_error_code code;
219         krb5_context ctx = NULL;
220         krb5_ccache cc = NULL;
221
222         initialize_krb5_error_table();
223         if ((code = krb5_init_context (&ctx))) {
224                 DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
225                         error_message(code)));
226                 return code;
227         }
228   
229         if (!cc_name) {
230                 if ((code = krb5_cc_default(ctx, &cc))) {
231                         krb5_free_context(ctx);
232                         return code;
233                 }
234         } else {
235                 if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
236                         DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
237                                   error_message(code)));
238                         krb5_free_context(ctx);
239                         return code;
240                 }
241         }
242
243         if ((code = krb5_cc_destroy (ctx, cc))) {
244                 DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
245                         error_message(code)));
246         }
247
248         krb5_free_context (ctx);
249         return code;
250 }
251
252 /************************************************************************
253  Routine to fetch the salting principal for a service.  Active
254  Directory may use a non-obvious principal name to generate the salt
255  when it determines the key to use for encrypting tickets for a service,
256  and hopefully we detected that when we joined the domain.
257  ************************************************************************/
258
259 static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
260 {
261         char *key = NULL;
262         char *ret = NULL;
263
264         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
265         if (!key) {
266                 return NULL;
267         }
268         ret = (char *)secrets_fetch(key, NULL);
269         SAFE_FREE(key);
270         return ret;
271 }
272
273 /************************************************************************
274  Return the standard DES salt key
275 ************************************************************************/
276
277 char* kerberos_standard_des_salt( void )
278 {
279         fstring salt;
280
281         fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
282         strlower_m( salt );
283         fstrcat( salt, lp_realm() );
284
285         return SMB_STRDUP( salt );
286 }
287
288 /************************************************************************
289 ************************************************************************/
290
291 static char* des_salt_key( void )
292 {
293         char *key;
294
295         asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL, lp_realm());
296
297         return key;
298 }
299
300 /************************************************************************
301 ************************************************************************/
302
303 BOOL kerberos_secrets_store_des_salt( const char* salt )
304 {
305         char* key;
306         BOOL ret;
307
308         if ( (key = des_salt_key()) == NULL ) {
309                 DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
310                 return False;
311         }
312
313         if ( !salt ) {
314                 DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
315                 secrets_delete( key );
316                 return True;
317         }
318
319         DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
320
321         ret = secrets_store( key, salt, strlen(salt)+1 );
322
323         SAFE_FREE( key );
324
325         return ret;
326 }
327
328 /************************************************************************
329 ************************************************************************/
330
331 char* kerberos_secrets_fetch_des_salt( void )
332 {
333         char *salt, *key;
334
335         if ( (key = des_salt_key()) == NULL ) {
336                 DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
337                 return False;
338         }
339
340         salt = (char*)secrets_fetch( key, NULL );
341
342         SAFE_FREE( key );
343
344         return salt;
345 }
346
347
348 /************************************************************************
349  Routine to get the salting principal for this service.  This is 
350  maintained for backwards compatibilty with releases prior to 3.0.24.
351  Since we store the salting principal string only at join, we may have 
352  to look for the older tdb keys.  Caller must free if return is not null.
353  ************************************************************************/
354
355 krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
356                                                         krb5_principal host_princ,
357                                                         int enctype)
358 {
359         char *unparsed_name = NULL, *salt_princ_s = NULL;
360         krb5_principal ret_princ = NULL;
361         
362         /* lookup new key first */
363
364         if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
365         
366                 /* look under the old key.  If this fails, just use the standard key */
367
368                 if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
369                         return (krb5_principal)NULL;
370                 }
371                 if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
372                         /* fall back to host/machine.realm@REALM */
373                         salt_princ_s = kerberos_standard_des_salt();
374                 }
375         }
376
377         if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
378                 ret_princ = NULL;
379         }
380         
381         SAFE_FREE(unparsed_name);
382         SAFE_FREE(salt_princ_s);
383         
384         return ret_princ;
385 }
386
387 /************************************************************************
388  Routine to set the salting principal for this service.  Active
389  Directory may use a non-obvious principal name to generate the salt
390  when it determines the key to use for encrypting tickets for a service,
391  and hopefully we detected that when we joined the domain.
392  Setting principal to NULL deletes this entry.
393  ************************************************************************/
394
395 BOOL kerberos_secrets_store_salting_principal(const char *service,
396                                               int enctype,
397                                               const char *principal)
398 {
399         char *key = NULL;
400         BOOL ret = False;
401         krb5_context context = NULL;
402         krb5_principal princ = NULL;
403         char *princ_s = NULL;
404         char *unparsed_name = NULL;
405
406         krb5_init_context(&context);
407         if (!context) {
408                 return False;
409         }
410         if (strchr_m(service, '@')) {
411                 asprintf(&princ_s, "%s", service);
412         } else {
413                 asprintf(&princ_s, "%s@%s", service, lp_realm());
414         }
415
416         if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
417                 goto out;
418                 
419         }
420         if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) {
421                 goto out;
422         }
423
424         asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
425         if (!key)  {
426                 goto out;
427         }
428
429         if ((principal != NULL) && (strlen(principal) > 0)) {
430                 ret = secrets_store(key, principal, strlen(principal) + 1);
431         } else {
432                 ret = secrets_delete(key);
433         }
434
435  out:
436
437         SAFE_FREE(key);
438         SAFE_FREE(princ_s);
439         SAFE_FREE(unparsed_name);
440
441         if (context) {
442                 krb5_free_context(context);
443         }
444
445         return ret;
446 }
447
448
449 /************************************************************************
450 ************************************************************************/
451
452 int kerberos_kinit_password(const char *principal,
453                             const char *password,
454                             int time_offset,
455                             const char *cache_name)
456 {
457         return kerberos_kinit_password_ext(principal, 
458                                            password, 
459                                            time_offset, 
460                                            0, 
461                                            0,
462                                            cache_name,
463                                            False,
464                                            False,
465                                            0);
466 }
467
468 /************************************************************************
469  Create a string list of available kdc's, possibly searching by sitename.
470  Does DNS queries.
471 ************************************************************************/
472
473 static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
474 {
475         struct ip_service *ip_srv_site;
476         struct ip_service *ip_srv_nonsite;
477         int count_site, count_nonsite, i;
478         char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
479                                         inet_ntoa(primary_ip));
480
481         if (kdc_str == NULL) {
482                 return NULL;
483         }
484
485         /* Get the KDC's only in this site. */
486
487         if (sitename) {
488
489                 get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
490
491                 for (i = 0; i < count_site; i++) {
492                         if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
493                                 continue;
494                         }
495                         /* Append to the string - inefficient but not done often. */
496                         kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
497                                 kdc_str, inet_ntoa(ip_srv_site[i].ip));
498                         if (!kdc_str) {
499                                 SAFE_FREE(ip_srv_site);
500                                 return NULL;
501                         }
502                 }
503         }
504
505         /* Get all KDC's. */
506
507         get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
508
509         for (i = 0; i < count_nonsite; i++) {
510                 int j;
511
512                 if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
513                         continue;
514                 }
515
516                 /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
517                 for (j = 0; j < count_site; j++) {
518                         if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
519                                 break;
520                         }
521                         /* As the lists are sorted we can break early if nonsite > site. */
522                         if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
523                                 break;
524                         }
525                 }
526                 if (j != i) {
527                         continue;
528                 }
529
530                 /* Append to the string - inefficient but not done often. */
531                 kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
532                         kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
533                 if (!kdc_str) {
534                         SAFE_FREE(ip_srv_site);
535                         SAFE_FREE(ip_srv_nonsite);
536                         return NULL;
537                 }
538         }
539
540
541         SAFE_FREE(ip_srv_site);
542         SAFE_FREE(ip_srv_nonsite);
543
544         DEBUG(10,("get_kdc_ip_string: Returning %s\n",
545                 kdc_str ));
546
547         return kdc_str;
548 }
549
550 /************************************************************************
551  Create  a specific krb5.conf file in the private directory pointing
552  at a specific kdc for a realm. Keyed off domain name. Sets
553  KRB5_CONFIG environment variable to point to this file. Must be
554  run as root or will fail (which is a good thing :-).
555 ************************************************************************/
556
557 BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
558                                         const char *sitename, struct in_addr ip)
559 {
560         char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
561         char *tmpname = NULL;
562         char *fname = NULL;
563         char *file_contents = NULL;
564         char *kdc_ip_string = NULL;
565         size_t flen = 0;
566         ssize_t ret;
567         int fd;
568         char *realm_upper = NULL;
569
570         if (!dname) {
571                 return False;
572         }
573         if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
574                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
575                         "failed to create directory %s. Error was %s\n",
576                         dname, strerror(errno) ));
577                 TALLOC_FREE(dname);
578                 return False;
579         }
580
581         tmpname = talloc_asprintf(dname, "%s/smb_tmp_krb5.XXXXXX", lp_lockdir());
582         if (!tmpname) {
583                 TALLOC_FREE(dname);
584                 return False;
585         }
586
587         fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
588         if (!fname) {
589                 TALLOC_FREE(dname);
590                 return False;
591         }
592
593         DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
594                 fname, realm, domain ));
595
596         realm_upper = talloc_strdup(fname, realm);
597         strupper_m(realm_upper);
598
599         kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
600         if (!kdc_ip_string) {
601                 TALLOC_FREE(dname);
602                 return False;
603         }
604                 
605         file_contents = talloc_asprintf(fname, "[libdefaults]\n\tdefault_realm = %s\n\n"
606                                 "[realms]\n\t%s = {\n"
607                                 "\t\t%s\t}\n",
608                                 realm_upper, realm_upper, kdc_ip_string);
609
610         if (!file_contents) {
611                 TALLOC_FREE(dname);
612                 return False;
613         }
614
615         flen = strlen(file_contents);
616
617         fd = smb_mkstemp(tmpname);
618         if (fd == -1) {
619                 DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
620                         " for file %s. Errno %s\n",
621                         tmpname, strerror(errno) ));
622         }
623
624         if (fchmod(fd, 0644)==-1) {
625                 DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
626                         " Errno %s\n",
627                         tmpname, strerror(errno) ));
628                 unlink(tmpname);
629                 close(fd);
630                 TALLOC_FREE(dname);
631                 return False;
632         }
633
634         ret = write(fd, file_contents, flen);
635         if (flen != ret) {
636                 DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
637                         " returned %d (should be %u). Errno %s\n",
638                         (int)ret, (unsigned int)flen, strerror(errno) ));
639                 unlink(tmpname);
640                 close(fd);
641                 TALLOC_FREE(dname);
642                 return False;
643         }
644         if (close(fd)==-1) {
645                 DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
646                         " Errno %s\n", strerror(errno) ));
647                 unlink(tmpname);
648                 TALLOC_FREE(dname);
649                 return False;
650         }
651
652         if (rename(tmpname, fname) == -1) {
653                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
654                         "of %s to %s failed. Errno %s\n",
655                         tmpname, fname, strerror(errno) ));
656                 unlink(tmpname);
657                 TALLOC_FREE(dname);
658                 return False;
659         }
660
661         DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
662                 "file %s with realm %s KDC = %s\n",
663                 fname, realm_upper, inet_ntoa(ip) ));
664
665         /* Set the environment variable to this file. */
666         setenv("KRB5_CONFIG", fname, 1);
667
668 #if defined(OVERWRITE_SYSTEM_KRB5_CONF)
669
670 #define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
671         /* Insanity, sheer insanity..... */
672
673         if (strequal(realm, lp_realm())) {
674                 pstring linkpath;
675                 int lret;
676
677                 lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
678                 linkpath[sizeof(pstring)-1] = '\0';
679
680                 if (lret == 0 || strcmp(linkpath, fname) == 0) {
681                         /* Symlink already exists. */
682                         TALLOC_FREE(dname);
683                         return True;
684                 }
685
686                 /* Try and replace with a symlink. */
687                 if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
688                         if (errno != EEXIST) {
689                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
690                                         "of %s to %s failed. Errno %s\n",
691                                         fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
692                                 TALLOC_FREE(dname);
693                                 return True; /* Not a fatal error. */
694                         }
695
696                         pstrcpy(linkpath, SYSTEM_KRB5_CONF_PATH);
697                         pstrcat(linkpath, ".saved");
698
699                         /* Yes, this is a race conditon... too bad. */
700                         if (rename(SYSTEM_KRB5_CONF_PATH, linkpath) == -1) {
701                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
702                                         "of %s to %s failed. Errno %s\n",
703                                         SYSTEM_KRB5_CONF_PATH, linkpath,
704                                         strerror(errno) ));
705                                 TALLOC_FREE(dname);
706                                 return True; /* Not a fatal error. */
707                         }
708
709                         if (symlink(fname, "/etc/krb5.conf") == -1) {
710                                 DEBUG(0,("create_local_private_krb5_conf_for_domain: "
711                                         "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
712                                         fname, strerror(errno) ));
713                                 TALLOC_FREE(dname);
714                                 return True; /* Not a fatal error. */
715                         }
716                 }
717         }
718 #endif
719
720         TALLOC_FREE(dname);
721
722         return True;
723 }
724 #endif