"Fossies" - the Fresh Open Source Software Archive 
Member "nss_ldap-265/ldap-init-krb5-cache.c" (6 Nov 2009, 32535 Bytes) of package /linux/privat/old/nss_ldap-265.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /* Copyright (C) 2007 Howard Wilkinson
2 Copyright (C) 2007 Markus Moeller
3 Copyright (C) 2007 Luke Howard
4 This file is part of the nss_ldap library
5 Contributed by Howard Wilkinson <howard@cohtech.com>, 2007.
6
7 Derived from original version by Markus Moeller <huaraz@moeller.plus.com>
8
9 The nss_ldap library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 The nss_ldap library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
18
19 You should have received a copy of the GNU Library General Public
20 License along with the nss_ldap library; see the file COPYING.LIB. If not,
21 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
23 */
24
25 static char rcsId[] =
26 "$Id: ldap-init-krb5-cache.c,v 2.1 2007/10/01 00:12:06 lukeh Exp $";
27
28 /*
29 * This file implementes the management of the Kerberos Credential Cache
30 * for SASL connections.
31 *
32 * The init function implements a finite state machine which is designed to
33 * manage the various configuration states that the Kerberos environment
34 * can be in.
35 */
36
37 /*
38 * INIT: Initial state when first called and also state after a reset.
39 * Calls krb5_cache_setup which populates the environment
40 * => REFRESH - Try to load some credentials first
41 * RUNNING: Credentials have been loaded and are current.
42 * => EXPIRED - Cached credentials have expired
43 * => REFRESH - Cached credentials are expiring
44 * => INIT - escape path for inconsistent data
45 * (should never happen)
46 * RENEW: Credentials are expiring and have not been externally refreshed
47 * => ERROR - Autorenew is not on so this is an error state
48 * => EXPIRED - Cached credentials expired during renewal
49 * => RUNNING - Cached credentials have been successfully renewed
50 * EXPIRED: Credentials have expired acquire new ones.
51 * This only works if a keytab is configured and useable.
52 * => ERROR - No available keytab or keytab is not useable
53 * => RUNNING - New credentials acquired
54 * REFRESH: Reload credentials from the configured credential cache
55 * => RUNNING - New credentials loaded and not expired
56 * => RENEW - New credentials loaded but are expiring
57 * (only happens if autorenew is on)
58 * => EXPIRED - New credentials loaded have expired
59 * or are expiring and autorenew is off
60 * => ERROR - Inconsistent credentials state
61 * => ACQUIRE - Cannot load any usable credentials from a cache
62 * Try for a keytab if one if configured
63 * ACQUIRE: No credentials loaded acquire new ones - (See EXPIRED)
64 * ERROR: Call reset and then return failure from this attempt
65 * => REFRESH
66 */
67
68 /*
69 * The code is written to allow and external program to supply credentials
70 * in the environment. This program can refresh/renew the credentials
71 * periodically and we will use these.
72 * As an alternative this code can renew externally provided credentials
73 * if necessary - autorenew must be turned on.
74 * Finally if provided with a keytab this code will acquire credentials
75 * from a KDC
76 */
77
78 /*
79 * 31st July 2007 - NO ATTEMPT HAS BEEN MADE TO MAKE
80 * THIS CODE THREAD SAFE AT THIS TIME
81 */
82
83 #include "config.h"
84 #ifdef HAVE_LBER_H
85 #include <lber.h>
86 #endif
87 #ifdef HAVE_LDAP_H
88 #include <ldap.h>
89 #endif
90 #include "ldap-nss.h"
91 #ifdef CONFIGURE_KRB5_KEYTAB
92 #include <krb5.h>
93 #include <unistd.h>
94 #include <stdlib.h>
95 #include <libgen.h>
96 #include <stdio.h>
97 #include <string.h>
98 #include <errno.h>
99 #include <syslog.h>
100 #include <time.h>
101 #ifndef HEIMDAL
102 #include <profile.h>
103 #endif
104 #ifdef HEIMDAL
105 #define error_message(code) krb5_get_err_text(context,code)
106 #endif
107 #include <sys/types.h>
108 #include <assert.h>
109 #include <gssapi/gssapi.h>
110 #include <gssapi/gssapi_krb5.h>
111
112 #define MAX_RENEW_TIME "365d"
113
114 #define KT_PATH_MAX 256
115
116 #ifndef HEIMDAL
117 typedef struct _profile_t *profile_t;
118 #endif
119
120 /* State machine items */
121 typedef enum
122 {
123 KRB5_CACHE_INIT = 0, /* First time through or has been reset */
124 KRB5_CACHE_RUNNING, /* Valid non-expired credentials loaded */
125 KRB5_CACHE_RENEW, /* Valid about to expire credentials loaded */
126 KRB5_CACHE_EXPIRED, /* Valid expired credentials loaded */
127 KRB5_CACHE_REFRESH, /* No credentials loaded */
128 KRB5_CACHE_ACQUIRE, /* Acquire new credentials from KDC */
129 KRB5_CACHE_ERROR /* Cannot get any credentials (this time) */
130 } krb5_cache_state;
131
132 /* Run the state machine from here */
133 static krb5_cache_state cache_state = KRB5_CACHE_INIT;
134
135 /* Track our Effective UID incase it is changing as we run */
136 static uid_t __euid = -1;
137 static uid_t euid = -1;
138
139 static krb5_context context = NULL;
140 static krb5_creds *creds = NULL;
141 #ifdef HEIMDAL
142 static krb5_creds creds2;
143 #endif
144 static krb5_principal principal = NULL;
145 static krb5_ccache cc = NULL;
146 static krb5_deltat skew = 0;
147 static char *ccname = NULL;
148 static char *ktname = NULL;
149 static char *saslid = NULL;
150 static int autorenew = 0;
151
152 #define credsOK(__c__) \
153 ((__c__ != NULL) && ((__c__->times.endtime - time(0)) > (2*skew)))
154
155 #define credsEXPIRING(__c__) \
156 ((__c__ != NULL) \
157 && (((__c__->times.endtime - time(0)) <= (2*skew)) \
158 && ((__c__->times.endtime - time(0)) > skew)))
159
160 #define credsEXPIRED(__c__) \
161 ((__c__ == NULL) \
162 || (((__c__->times.renew_till - time(0)) <= (2*skew)) \
163 || ((__c__->times.endtime - time(0)) <= skew)))
164
165 static int
166 krb5_cache_reset (ldap_config_t * config)
167 {
168 debug ("==> krb5_cache_reset");
169 if (creds != NULL)
170 {
171 free ((void *) creds);
172 creds = NULL;
173 }
174 if (context != NULL)
175 {
176 if (principal != NULL)
177 {
178 krb5_free_principal (context, principal);
179 principal = NULL;
180 }
181 if (cc != NULL)
182 {
183 krb5_cc_close (context, cc);
184 cc = NULL;
185 }
186 krb5_free_context (context);
187 context = NULL;
188 }
189 skew = 0;
190 autorenew = 0;
191 if (ccname != NULL)
192 {
193 free ((void *) ccname);
194 ccname = NULL;
195 }
196 if (ktname != NULL)
197 {
198 free ((void *) ktname);
199 ktname = NULL;
200 }
201 if (saslid != NULL)
202 {
203 free ((void *) saslid);
204 saslid = NULL;
205 }
206 cache_state = KRB5_CACHE_INIT;
207 debug ("<== krb5_cache_reset");
208 return (0);
209 }
210
211 static int
212 krb5_cache_kt_is_accessible (char *__ktname)
213 {
214 krb5_error_code code = 0;
215 krb5_keytab __keytab;
216
217 debug ("==> krb5_cache_kt_is_accessible: ktname %s", __ktname);
218 assert (context != NULL);
219 if (!(code = krb5_kt_resolve (context, __ktname, &__keytab)))
220 {
221 debug ("==> krb5_cache_kt_is_accessible: resolved ktname %s - %s",
222 __ktname, krb5_kt_get_type (context, __keytab));
223 if (strcmp ("FILE", krb5_kt_get_type (context, __keytab)) == 0)
224 {
225 debug ("==> krb5_cache_kt_is_accessible: kt type = FILE");
226 uid_t ruid = getuid ();
227 gid_t rgid = getgid ();
228 gid_t egid = getegid ();
229 char buf[KT_PATH_MAX];
230 if (ruid != euid)
231 {
232 setreuid (euid, ruid);
233 }
234 if (rgid != egid)
235 {
236 setregid (egid, rgid);
237 }
238 krb5_kt_get_name (context, __keytab, buf, KT_PATH_MAX);
239 debug ("==> krb5_cache_kt_is_accessible: kt_get_name gives %s",
240 buf);
241 code = access (buf, R_OK);
242 if (ruid != euid)
243 {
244 setreuid (ruid, euid);
245 }
246 if (rgid != rgid)
247 {
248 setregid (rgid, egid);
249 }
250 }
251 krb5_kt_close (context, __keytab);
252 }
253
254 debug ("<== krb5_cache_kt_is_accessible: returns %s(%d)",
255 error_message (code), (int) code);
256 return (code == 0);
257 }
258
259 static char *
260 krb5_cache_get_ktname (ldap_config_t * config)
261 {
262 char *__ktname = NULL;
263
264 debug ("==> krb5_cache_get_ktname");
265 {
266 char *rootktname = ((euid == 0 && config->ldc_krb5_rootusekeytab
267 && config->ldc_rootusesasl
268 && config->ldc_krb5_rootkeytabname)
269 ? config->ldc_krb5_rootkeytabname : NULL);
270 char *userktname = ((((config->ldc_usesasl && config->ldc_krb5_usekeytab)
271 || (euid == 0 && config->ldc_rootusesasl
272 && config->ldc_krb5_rootusekeytab))
273 && config->ldc_krb5_keytabname)
274 ? config->ldc_krb5_keytabname : NULL);
275 char *envktname = ((((config->ldc_usesasl && config->ldc_krb5_usekeytab)
276 || (euid == 0 && config->ldc_rootusesasl
277 && config->ldc_krb5_rootusekeytab))
278 && getenv ("KRB5_KTNAME"))
279 ? getenv ("KRB5_KTNAME") : NULL);
280 char *defktname = NULL;
281
282 if ((config->ldc_usesasl && config->ldc_krb5_usekeytab)
283 || (euid == 0 && config->ldc_rootusesasl
284 && config->ldc_krb5_rootusekeytab))
285 {
286 char buf[KT_PATH_MAX];
287 debug ("==> krb5_cache_get_ktname: get default keytab name");
288 krb5_kt_default_name (context, buf, KT_PATH_MAX);
289 defktname = strdup (buf);
290 }
291
292 debug
293 ("==> krb5_cache_get_ktname: rootktname = %s, userktname = %s, envktname = %s, defktname = %s",
294 (rootktname) ? rootktname : "NULL", (userktname) ? userktname : "NULL",
295 (envktname) ? envktname : "NULL", (defktname) ? defktname : "NULL");
296 __ktname =
297 ((rootktname
298 && krb5_cache_kt_is_accessible (rootktname)) ? rootktname
299 : (userktname
300 && krb5_cache_kt_is_accessible (userktname)) ? userktname
301 : (envktname
302 && krb5_cache_kt_is_accessible (envktname)) ? envktname : (defktname
303 &&
304 krb5_cache_kt_is_accessible
305 (defktname))
306 ? defktname : NULL);
307 }
308 debug ("<== krb5_cache_get_ktname: returns %s",
309 (__ktname) ? __ktname : "NULL");
310 return __ktname;
311 }
312
313 static int
314 krb5_cache_cc_is_accessible (char *__ccname, int writeable)
315 {
316 krb5_error_code code = 0;
317 krb5_ccache __cc;
318
319 debug ("==> krb5_cache_cc_is_accessible: ccname %s, writeable %d",
320 __ccname, writeable);
321 assert (context != NULL);
322 if (!(code = krb5_cc_resolve (context, __ccname, &__cc)))
323 {
324 debug ("==> krb5_cache_cc_is_accessible: resolved ccname %s - %s",
325 __ccname, krb5_cc_get_type (context, __cc));
326 if ((strcmp ("FILE", krb5_cc_get_type (context, __cc)) == 0)
327 || (strcmp ("WRFILE", krb5_cc_get_type (context, __cc)) == 0))
328 {
329 int mode = R_OK;
330 uid_t ruid = getuid ();
331 gid_t rgid = getgid ();
332 gid_t egid = getegid ();
333 if (writeable)
334 {
335 mode = mode | W_OK;
336 }
337 if (ruid != euid)
338 {
339 setreuid (euid, ruid);
340 }
341 if (rgid != egid)
342 {
343 setregid (egid, rgid);
344 }
345 if ((code = access (krb5_cc_get_name (context, __cc), F_OK)))
346 {
347 debug
348 ("==> krb5_cache_cc_is_accessible: cache file not accessible %s(%d)",
349 strerror (errno), errno);
350 if (errno == EACCES)
351 { /* File does not exist */
352 if (writeable)
353 {
354 /* Check that path exists */
355 char *x__ccname =
356 strdup (krb5_cc_get_name (context, cc));
357 char *x__ccdir = dirname (x__ccname);
358 code = access (x__ccdir, mode | X_OK);
359 free ((void *) x__ccname);
360 }
361 }
362 }
363 else
364 {
365 code = access (krb5_cc_get_name (context, __cc), mode);
366 }
367 if (ruid != euid)
368 {
369 setreuid (ruid, euid);
370 }
371 if (rgid != rgid)
372 {
373 setregid (rgid, egid);
374 }
375 }
376 krb5_cc_close (context, __cc);
377 }
378
379 debug ("<== krb5_cache_cc_is_accessible: returns %s(%d)",
380 error_message (code), code);
381 return (code == 0);
382 }
383
384 static char *
385 krb5_cache_get_ccname (ldap_config_t * config)
386 {
387 char *__ccname = NULL;
388
389 debug ("==> krb5_cache_get_ccname");
390 {
391 char *rootccname = ((euid == 0
392 && config->ldc_rootusesasl
393 && config->ldc_krb5_rootccname)
394 ? config->ldc_krb5_rootccname : NULL);
395 char *userccname = (((config->ldc_usesasl
396 || (euid == 0 && config->ldc_rootusesasl))
397 && config->ldc_krb5_ccname)
398 ? config->ldc_krb5_ccname : NULL);
399 char *envccname = (((config->ldc_usesasl
400 || (euid == 0 && config->ldc_rootusesasl))
401 && getenv ("KRB5CCNAME"))
402 ? getenv ("KRB5CCNAME") : NULL);
403 char *defccname = (((config->ldc_usesasl
404 || (euid == 0 && config->ldc_rootusesasl))
405 && (char *) krb5_cc_default_name (context))
406 ? (char *) krb5_cc_default_name (context) : NULL);
407
408 int writeable = (autorenew
409 || config->ldc_krb5_usekeytab
410 || (euid == 0 && config->ldc_krb5_rootusekeytab));
411
412 debug
413 ("==> krb5_cache_get_ccname: rootccname = %s, userccname = %s, envccname = %s, defccname = %s",
414 (rootccname) ? rootccname : "NULL", (userccname) ? userccname : "NULL",
415 (envccname) ? envccname : "NULL", (defccname) ? defccname : "NULL");
416 __ccname =
417 ((rootccname
418 && krb5_cache_cc_is_accessible (rootccname,
419 writeable)) ? rootccname : (userccname
420 &&
421 krb5_cache_cc_is_accessible
422 (userccname,
423 writeable))
424 ? userccname : (envccname
425 && krb5_cache_cc_is_accessible (envccname,
426 writeable)) ? envccname
427 : (defccname
428 && krb5_cache_cc_is_accessible (defccname,
429 writeable)) ? defccname : NULL);
430 if (__ccname == NULL
431 && (config->ldc_krb5_usekeytab
432 || (euid == 0 && config->ldc_krb5_rootusekeytab)))
433 __ccname = "MEMORY:store_creds";
434 }
435 debug ("<== krb5_cache_get_ccname: returns ccname = %s",
436 (__ccname) ? __ccname : "NULL");
437 return ((__ccname) ? strdup (__ccname) : "NULL");
438 }
439
440 static char *
441 krb5_cache_get_saslid (ldap_config_t * config)
442 {
443 char *__saslid = ((euid = 0 && config->ldc_rootusesasl
444 && config->ldc_rootsaslid)
445 ? config->ldc_rootsaslid
446 : (config->ldc_usesasl && config->ldc_saslid)
447 ? config->ldc_saslid : NULL);
448 if (__saslid == NULL)
449 {
450 int retval;
451 char hostname[HOST_NAME_MAX];
452
453 debug ("==> krb5_cache_get_saslid: get default principal name");
454 errno = 0;
455 retval = gethostname (hostname, HOST_NAME_MAX);
456 if (!retval)
457 {
458 hostname[HOST_NAME_MAX] = '\0';
459 __saslid = malloc (sizeof (hostname) + 6);
460 strcpy (__saslid, "host/");
461 strcat (__saslid, hostname);
462 debug ("==> krb5_cache_get_saslid: set principal name %s",
463 __saslid);
464 }
465 else
466 {
467 syslog (LOG_ERR, "nss_ldap: %s while resolving hostname",
468 strerror (errno));
469 debug ("==> krb5_cache_get_saslid: %s while resolving hostname",
470 strerror (errno));
471 }
472 }
473 else
474 {
475 __saslid = strdup (__saslid);
476 }
477 return __saslid;
478 }
479
480 static krb5_principal
481 krb5_cache_get_principal (ldap_config_t * config)
482 {
483 krb5_error_code code = 0;
484 krb5_principal __principal;
485
486 assert (saslid != NULL);
487 if ((code = krb5_parse_name (context, saslid, &__principal)))
488 {
489 syslog (LOG_ERR, "nss_ldap: %s(%d) while parsing principal name %s",
490 error_message (code), (int) code, saslid);
491 debug
492 ("==> krb5_cache_get_principal: %s(%d) while parsing principal name %s",
493 error_message (code), (int) code, saslid);
494 return (NULL);
495 }
496 return __principal;
497 }
498
499 /* Set up to manage the credentials cache */
500 static int
501 krb5_cache_setup (ldap_config_t * config)
502 {
503
504 krb5_error_code code = 0;
505
506 #ifndef HEIMDAL
507 profile_t profile;
508 #endif
509
510 debug ("==> krb5_cache_setup");
511 if (context == NULL)
512 {
513 if ((code = krb5_init_context (&context)))
514 {
515 syslog (LOG_ERR,
516 "nss_ldap: %s(%d) while initialising Kerberos library",
517 error_message (code), (int) code);
518 debug
519 ("<== krb5_cache_setup: %s(%d) while initialising Kerberos library",
520 error_message (code), (int) code);
521 return (code);
522 }
523 }
524 #ifndef HEIMDAL
525 if ((code = krb5_get_profile (context, &profile)))
526 {
527 syslog (LOG_ERR, "nss_ldap: %s(%d) while getting profile",
528 error_message (code), (int) code);
529 debug ("<== krb5_cache_setup: %s(%d) while getting profile",
530 error_message (code), (int) code);
531 return (code);
532 }
533 if ((code = profile_get_integer (profile,
534 "libdefaults",
535 "clockskew", 0, 5 * 60, &skew)))
536 {
537 syslog (LOG_ERR, "nss_ldap: %s(%d) while getting clockskew",
538 error_message (code), (int) code);
539 debug ("<== krb5_cache_setup: %s(%d) while getting clockskew",
540 error_message (code), (int) code);
541 return (code);
542 }
543 profile_release (profile);
544 #else
545 skew = context->max_skew;
546 #endif
547 ccname = krb5_cache_get_ccname (config);
548 debug ("==> krb5_cache_setup: credential cache name %s",
549 ccname ? ccname : "NULL");
550 cache_state = KRB5_CACHE_REFRESH;
551 autorenew = (config->ldc_krb5_autorenew
552 || (euid == 0 && config->ldc_krb5_rootautorenew));
553 debug ("<== krb5_cache_setup");
554 return (0);
555 }
556
557 static void
558 krb5_cache_setup_creds (ldap_config_t * context)
559 {
560 debug ("==> krb5_cache_setup_creds");
561 if (creds == NULL)
562 {
563 creds = malloc (sizeof (*creds));
564 assert (creds != NULL);
565 }
566 memset (creds, 0, sizeof (*creds));
567 debug ("<== krb5_cache_setup_creds");
568 }
569
570 /* (Re)load the credentials cache into our local data */
571 static int
572 krb5_cache_refresh (ldap_config_t * config)
573 {
574
575 krb5_error_code code = 0;
576
577 debug ("==> krb5_cache_refresh");
578 if ((code = krb5_cc_resolve (context, ccname, &cc)))
579 {
580 debug ("==> krb5_cache_refresh: cache %s cannot be resolved",
581 ccname ? ccname : "NULL");
582 }
583 else if ((code = krb5_cc_get_principal (context, cc, &principal)))
584 {
585 debug ("==> krb5_cache_refresh: cannot get principal from cache %s",
586 ccname ? ccname : "NULL");
587 }
588 else
589 {
590 debug ("==> krb5_cache_refresh: found existing cache %s",
591 ccname ? ccname : "NULL");
592 /* Use the principal name from the cache rather than preconfigured saslid */
593 char *principal_name = NULL;
594 if ((code = krb5_unparse_name (context, principal, &principal_name)))
595 {
596 debug
597 ("==> krb5_cache_refresh: cannot unparse principal from cache %s",
598 ccname ? ccname : "NULL");
599 }
600 else
601 {
602 krb5_cc_cursor cursor;
603
604 debug ("==> krb5_cache_refresh: cache %s principal %s",
605 ccname ? ccname : "NULL",
606 principal_name ? principal_name : "NULL");
607 if ((code = krb5_cc_start_seq_get (context, cc, &cursor)))
608 {
609 debug
610 ("==> krb5_cache_refresh: cache %s credentials not usable",
611 ccname ? ccname : "NULL");
612 }
613 else
614 {
615 krb5_cache_setup_creds (config);
616 do
617 {
618 if (!
619 (code =
620 krb5_cc_next_cred (context, cc, &cursor, creds)))
621 {
622 debug ("==> krb5_cache_refresh: retrieved creds");
623 if (credsOK (creds))
624 {
625 debug
626 ("==> krb5_cache_refresh: creds are OK --> RUNNING");
627 /* Reloaded cache is fine */
628 cache_state = KRB5_CACHE_RUNNING;
629 }
630 else
631 {
632 if (credsEXPIRING (creds))
633 {
634 debug
635 ("==> krb5_cache_refresh: creds are EXPIRING");
636 /* Reloaded cache will expire shortly */
637 if (autorenew)
638 {
639 debug ("==> krb5_cache_refresh: --> RENEW");
640 cache_state = KRB5_CACHE_RENEW;
641 }
642 else
643 {
644 debug
645 ("==> krb5_cache_refresh: --> EXPIRED");
646 cache_state = KRB5_CACHE_EXPIRED;
647 }
648 }
649 else if (credsEXPIRED (creds))
650 {
651 debug
652 ("==> krb5_cache_refresh: creds have EXPIRED --> EXPIRED");
653 /* Reload cache has expired */
654 cache_state = KRB5_CACHE_EXPIRED;
655 }
656 else
657 { /* Should never happen */
658 debug
659 ("==> krb5_cache_refresh: creds in weird state --> ERROR");
660 cache_state = KRB5_CACHE_ERROR;
661 }
662 krb5_free_cred_contents (context, creds);
663 }
664 }
665 }
666 while (!code && cache_state == KRB5_CACHE_REFRESH);
667 if ((code = krb5_cc_end_seq_get (context, cc, &cursor)))
668 {
669 debug
670 ("==> krb5_cache_refresh: cache %s scan failed to end cleanly",
671 ccname ? ccname : "NULL");
672 }
673 }
674 krb5_free_unparsed_name (context, principal_name);
675 }
676 }
677
678 if (principal != NULL)
679 {
680 krb5_free_principal (context, principal);
681 principal = NULL;
682 }
683 if (cc != NULL)
684 {
685 if ((code = krb5_cc_close (context, cc)))
686 {
687 debug ("==> krb5_cache_refresh: cache %s close failed",
688 ccname ? ccname : "NULL");
689 }
690 cc = NULL;
691 }
692 if (cache_state == KRB5_CACHE_REFRESH)
693 {
694 debug ("==> krb5_cache_refresh: stuck in refresh --> ACQUIRE");
695 cache_state = KRB5_CACHE_ACQUIRE; /* Try for a keytab */
696 }
697 debug ("<== krb5_cache_refresh");
698 return (code);
699 }
700
701 /* Renew an expired credentials cache */
702 static int
703 krb5_cache_renew (ldap_config_t * config)
704 {
705
706 krb5_error_code code = 0;
707
708 #ifdef HEIMDAL
709 krb5_kdc_flags flags;
710 krb5_realm *client_realm;
711 #endif
712
713 debug ("==> krb5_cache_renew");
714
715 if (!autorenew)
716 {
717 /*
718 * We should never get here
719 * as the refresh code should only enter renew
720 * if autorenew is true
721 */
722 debug
723 ("==> krb5_cache_renew: renew called with autorenew off --> ERROR");
724 cache_state = KRB5_CACHE_ERROR;
725 return (1);
726 }
727
728 assert (creds != NULL); /* Refresh or acquire will have set this up */
729 #ifndef HEIMDAL
730 /* renew ticket */
731 /* Overwrites contents of creds no storage allocation happening */
732 if ((code = krb5_get_renewed_creds (context, creds, principal, cc, NULL)))
733 {
734 debug ("==> krb5_cache_renew: failed to renew creds %s(%d)",
735 error_message (code), (int) code);
736 #else
737 /* renew ticket */
738 flags.i = 0;
739 flags.b.renewable = flags.b.renew = 1;
740 if ((code = krb5_cc_get_principal (context, cc, &creds2.client)))
741 {
742 syslog (LOG_ERR,
743 "nss_ldap: %s(%d) while getting principal from credential cache",
744 error_message (code), (int) code);
745 debug
746 ("==> krb5_cache_renew: %s(%d) while getting principal from credentials cache",
747 error_message (code), (int) code);
748 cache_state = KRB5_CACHE_REFRESH;
749 return (code);
750 }
751 client_realm = krb5_princ_realm (context, creds2.client);
752 if ((code = krb5_make_principal (context, &creds2.server, *client_realm,
753 KRB5_TGS_NAME, *client_realm, NULL)))
754 {
755 syslog (LOG_ERR, "nss_ldap: %s(%d) while getting krbtgt principal",
756 error_message (code), (int) code);
757 debug ("==> krb5_cache_renew: %s(%d) while getting krbtgt principal",
758 error_message (code), (int) code);
759 cache_state = KRB5_CACHE_REFRESH;
760 return (code);
761 }
762 /* I think there is a potential storage leak here as creds is written to */
763 /* Need to check Heimdal code to see if it will overwrite or replace memory */
764 if ((code = krb5_get_kdc_cred (context,
765 cc, flags, NULL, NULL, &creds2, &creds)))
766 {
767 debug ("==> krb5_cache_renew: failed to get creds from kdc %s(%d)",
768 error_message (code), (int) code);
769 #endif
770 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
771 {
772 /* this can happen because of clock skew */
773 debug
774 ("<== krb5_cache_renew: ticket has expired because of clock skey --> EXPIRED");
775 cache_state = KRB5_CACHE_EXPIRED;
776 return (0);
777 }
778 else
779 {
780 syslog (LOG_ERR, "nss_ldap: %s(%d) while renewing credentials",
781 error_message (code), (int) code);
782 debug ("==> krb5_cache_renew: %s(%d) while renewing credentials",
783 error_message (code), (int) code);
784 cache_state = KRB5_CACHE_REFRESH;
785 return (code);
786 }
787 }
788 cache_state = KRB5_CACHE_RUNNING;
789 debug ("<== krb5_cache_renew: renewed creds --> RUNNING");
790 return (0);
791 }
792
793 /* Initialise the credentials cache from a keytab */
794 static int
795 krb5_cache_acquire (ldap_config_t * config)
796 {
797
798 krb5_error_code code = 0;
799 krb5_keytab keytab = NULL;
800
801 debug ("==> krb5_cache_acquire");
802 /*
803 * We have not managed to find any credentials.
804 * If a keytab is configured then try using that
805 */
806 assert (context != NULL);
807 /* use keytab to fill cache */
808 if ((ktname == NULL) && ((ktname = krb5_cache_get_ktname (config)) == NULL))
809 {
810 debug ("==> krb5_cache_acquire: no usable keytab");
811 code = 1;
812 }
813 else if ((code = krb5_kt_resolve (context, ktname, &keytab)))
814 {
815 syslog (LOG_ERR, "nss_ldap: %s(%d) while resolving keytab filename %s",
816 error_message (code), (int) code, ktname);
817 debug
818 ("==> krb5_cache_acquire: %s(%d) while resolving keytab filename %s",
819 error_message (code), (int) code, ktname);
820 }
821 else
822 {
823 krb5_get_init_creds_opt options;
824 krb5_deltat rlife;
825 if (saslid == NULL)
826 {
827 saslid = krb5_cache_get_saslid (config);
828 }
829 debug ("==> krb5_cache_acquire: saslid = %s",
830 (saslid) ? saslid : "NULL");
831 if (saslid && principal == NULL)
832 {
833 principal = krb5_cache_get_principal (config);
834 if (principal == NULL)
835 {
836 debug ("<== krb5_cache_acquire: no valid principal --> ERROR");
837 cache_state = KRB5_CACHE_ERROR;
838 return (1);
839 }
840 }
841 krb5_get_init_creds_opt_init (&options);
842 if ((code = krb5_string_to_deltat (MAX_RENEW_TIME, &rlife))
843 || (rlife == 0))
844 {
845 syslog (LOG_ERR,
846 "nss_ldap: %s(%d) while setting renew lifetime value to %s",
847 error_message (code), (int) code, MAX_RENEW_TIME);
848 debug
849 ("==> krb5_cache_acquire: %s(%d) while setting renew lifetime value to %s",
850 error_message (code), (int) code, MAX_RENEW_TIME);
851 code = (code == 0) ? 1 : code;
852 }
853 else
854 {
855 krb5_get_init_creds_opt_set_renew_life (&options, rlife);
856 debug ("==> krb5_cache_acquire: get credentials from keytab");
857 krb5_cache_setup_creds (config);
858 if ((code = krb5_get_init_creds_keytab (context,
859 creds,
860 principal,
861 keytab,
862 0,
863 NULL,
864 &options))
865 && (code != EEXIST))
866 {
867 /* Failed to initialise credentials from keytab */
868 syslog (LOG_ERR,
869 "nss_ldap: %s(%d) while initialising credentials from keytab",
870 error_message (code), (int) code);
871 debug
872 ("==> krb5_cache_acquire get credentials from keytab failed %s(%d)",
873 error_message (code), (int) code);
874 debug
875 ("==> krb5_cache_acquire try refreshing from credential cache");
876 if ((code = krb5_cache_refresh (config)))
877 {
878 debug
879 ("==> krb5_cache_acquire: cache credentials not usable");
880 free ((void *) creds);
881 creds = NULL;
882 }
883 else if (cache_state == KRB5_CACHE_ACQUIRE)
884 code = 1;
885 }
886 else
887 {
888 /* We have a set of credentials we now need to save them */
889 if ((code = krb5_cc_resolve (context, ccname, &cc)))
890 {
891 syslog (LOG_ERR,
892 "nss_ldap: %s(%d) while resolving credential cache",
893 error_message (code), (int) code);
894 debug
895 ("==>krb5_cache_acquire: %s(%d) while resolving credential cache",
896 error_message (code), (int) code);
897 }
898 else if ((code = krb5_cc_initialize (context, cc, principal))
899 && (code != EEXIST))
900 {
901 /* Failed to initialize the cache try to use a default one instead */
902 syslog (LOG_ERR,
903 "nss_ldap: %s(%d) while initializing credential cache",
904 error_message (code), (int) code);
905 debug
906 ("==> krb5_cache_acquire: initializing credential cache failed %s(%d)",
907 error_message (code), (int) code);
908 }
909 else
910 {
911 debug
912 ("==> krb5_cache_acquire store credentials in cache file");
913 if ((code = krb5_cc_store_cred (context, cc, creds)))
914 {
915 syslog (LOG_ERR,
916 "nss_ldap: %s(%d) while storing credentials",
917 error_message (code), (int) code);
918 debug
919 ("==> krb5_cache_acquire: %s(%d) while storing credentials",
920 error_message (code), (int) code);
921 }
922 else
923 {
924 if (!creds->times.starttime)
925 creds->times.starttime = creds->times.authtime;
926 debug ("==> krb5_cache_acquire: got new credentials");
927 cache_state = KRB5_CACHE_RUNNING;
928 }
929 if (cc != NULL)
930 {
931 if ((code = krb5_cc_close (context, cc)))
932 {
933 debug
934 ("==> krb5_cache_acquire: cache %s close failed",
935 ccname ? ccname : "NULL");
936 }
937 }
938 }
939 }
940 }
941 if (keytab != NULL)
942 {
943 krb5_kt_close (context, keytab);
944 }
945 }
946 if (code)
947 {
948 debug ("<== krb5_cache_acquire: --> ERROR");
949 cache_state = KRB5_CACHE_ERROR;
950 }
951 else
952 {
953 debug ("<== krb5_cache_acquire");
954 }
955 return (code);
956 }
957
958 int
959 do_init_krb5_cache (ldap_config_t * config)
960 {
961 krb5_error_code code = 0;
962
963 debug ("==> do_init_krb5_cache %s %s %s",
964 config->ldc_krb5_keytabname ? config->ldc_krb5_keytabname : "NULL",
965 config->ldc_krb5_ccname ? config->ldc_krb5_ccname : "NULL",
966 config->ldc_saslid ? config->ldc_saslid : "NULL");
967
968 euid = geteuid ();
969
970 /* Check to see if we are using sasl, if not then return as nothing to do */
971 if (!(config->ldc_usesasl || (euid == 0 && config->ldc_rootusesasl)))
972 {
973 return (1); /* Should we signal success? */
974 }
975
976 /* Check to see if we have swapped user since we were last called */
977 if (__euid != euid)
978 { /* Could be first call but clear everything out anyway */
979 krb5_cache_reset (config);
980 __euid = euid;
981 }
982
983
984 /*
985 * If we do not have any credentials
986 * or they are expired or they are about to expire
987 * then try to load a new set from the credentials cache
988 * - this may have been renewed by
989 * some other process or thread so check this first.
990 */
991
992 do
993 {
994 switch (cache_state)
995 {
996
997 case KRB5_CACHE_INIT:
998 code = krb5_cache_setup (config);
999 debug
1000 ("==> do_init_krb5_cache ktname = %s, ccname = %s, saslid = %s, euid = %d",
1001 ktname ? ktname : "NULL", ccname ? ccname : "NULL",
1002 saslid ? saslid : "NULL", euid);
1003 break;
1004
1005 case KRB5_CACHE_RUNNING:
1006 /*
1007 * If we have credentials
1008 * and they are not expired or about to expire then OK!
1009 */
1010 if (credsOK (creds))
1011 {
1012 debug ("==> do_init_krb5_cache: return 0");
1013 return (0);
1014 }
1015
1016 if (credsEXPIRED (creds))
1017 {
1018 cache_state = KRB5_CACHE_EXPIRED;
1019 }
1020 else if (credsEXPIRING (creds))
1021 {
1022 cache_state = KRB5_CACHE_REFRESH;
1023 }
1024 else
1025 {
1026 /* Should not get here if things are OK so start again */
1027 code = krb5_cache_reset (config);
1028 cache_state = KRB5_CACHE_INIT;
1029 }
1030 break;
1031
1032 case KRB5_CACHE_RENEW:
1033 code = krb5_cache_renew (config);
1034 break;
1035
1036 case KRB5_CACHE_EXPIRED:
1037 code = krb5_cache_acquire (config);
1038 break;
1039
1040 case KRB5_CACHE_REFRESH:
1041 code = krb5_cache_refresh (config);
1042 break;
1043
1044 case KRB5_CACHE_ACQUIRE:
1045 code = krb5_cache_acquire (config);
1046 break;
1047
1048 case KRB5_CACHE_ERROR:
1049 /*
1050 * Can't do anything while in ERROR state.
1051 * ?? Wait for a few seconds to have passed and try again ??
1052 * Otherwise how do we break out of this loop
1053 * - reset will make same sequence happen if this is a hard problem
1054 */
1055 code = krb5_cache_reset (config);
1056 break;
1057
1058 default:
1059 break;
1060 }
1061 if (code)
1062 {
1063 debug ("==> do_init_krb5_cache: return %d", (int) code);
1064 return (code);
1065 }
1066 }
1067 while (1);
1068
1069 /*NOTREACHED*/
1070 debug ("==> do_init_krb5_cache: reinit ticket loop exit failure");
1071 return (1);
1072 }
1073
1074 static char *saveccname = NULL;
1075 /* This is shared into the environment so be careful */
1076 #ifdef CONFIGURE_KRB5_CCNAME_ENV
1077 static char envbuf[256];
1078 #endif
1079
1080 int
1081 do_select_krb5_cache (ldap_config_t * config)
1082 {
1083 int result = 0;
1084 if (cache_state != KRB5_CACHE_RUNNING)
1085 {
1086 result = do_init_krb5_cache (config);
1087 }
1088 if (ccname != NULL)
1089 {
1090 #ifdef CONFIGURE_KRB5_CCNAME_ENV
1091 char tmpbuf[256];
1092 char *oldccname = getenv ("KRB5CCNAME");
1093 if (saveccname != NULL)
1094 {
1095 free ((void *) saveccname);
1096 saveccname = NULL;
1097 }
1098 if (oldccname != NULL)
1099 {
1100 strncpy (tmpbuf, oldccname, sizeof (tmpbuf));
1101 tmpbuf[sizeof (tmpbuf) - 1] = '\0';
1102 saveccname = (char *) malloc (strlen (tmpbuf) + 1);
1103 strcpy (saveccname, tmpbuf);
1104 }
1105 snprintf (envbuf, sizeof (envbuf), "KRBCCNAME=%s", ccname);
1106 putenv (envbuf);
1107 #elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
1108 OM_uint32 retval = 0;
1109 if (gss_krb5_ccache_name (&retval,
1110 (const char *) ccname,
1111 (const char **) &saveccname) !=
1112 GSS_S_COMPLETE)
1113 {
1114 debug
1115 ("==> do_select_krb5_cache: unable to set default credential cache");
1116 result = -1;
1117 }
1118 #endif
1119 }
1120 return result;
1121 }
1122
1123 int
1124 do_restore_krb5_cache (ldap_config_t * config)
1125 {
1126 int result = 0;
1127 if (saveccname != NULL)
1128 {
1129 #ifdef CONFIGURE_KRB5_CCNAME_ENV
1130 snprintf (envbuf, sizeof (envbuf), "KRB5CCNAME=%s", saveccname);
1131 putenv (envbuf);
1132 free ((void *) saveccname);
1133 #elif defined(CONFIGURE_KRB5_CCNAME_GSSAPI)
1134 OM_uint32 retval = 0;
1135 if (gss_krb5_ccache_name (&retval, (const char *) saveccname, NULL) !=
1136 GSS_S_COMPLETE)
1137 {
1138 debug
1139 ("==> do_restore_krb5_cache: unable to restore default credential cache");
1140 result = -1;
1141 }
1142 #endif
1143 saveccname = NULL;
1144 }
1145 return result;
1146 }
1147 #endif /* CONFIGURE_KRB5_KEYTAB */