1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Joyent, Inc.
  26  */
  27 
  28 #include <strings.h>
  29 #include <stdlib.h>
  30 #include <syslog.h>
  31 #include <errno.h>
  32 #include <libintl.h>
  33 #include <door.h>
  34 #include <sys/types.h>
  35 #include <sys/stat.h>
  36 #include <fcntl.h>
  37 #include <procfs.h>
  38 #include <pthread.h>
  39 #include "cachemgr.h"
  40 
  41 extern admin_t  current_admin;
  42 
  43 #define CLEANUP_WAIT_TIME 60
  44 
  45 typedef enum cleanup_type {
  46         CLEANUP_ALL     = 1,
  47         CLEANUP_BY_PID  = 2
  48 } cleanup_type_t;
  49 
  50 typedef struct cleanup_op {
  51         pid_t           pid;
  52         cleanup_type_t  type;
  53 } cleanup_op_t;
  54 
  55 typedef struct main_nscd_struct {
  56         pid_t           pid;                    /* main nscd pid */
  57         thread_t        tid;                    /* main nscd tid */
  58         int             in_progress;            /* A main nscd thread is */
  59                                                 /* waiting for change or */
  60                                                 /* copying data */
  61         int             is_waiting_cleanup;     /* A main nscd thread is */
  62                                                 /* waiting for another main */
  63                                                 /* nscd thread to be cleaned */
  64                                                 /* up */
  65 } main_nscd_t;
  66 
  67 static chg_info_t chg = { DEFAULTMUTEX, DEFAULTCV, 0, NULL, NULL, NULL, 0 };
  68 
  69 static main_nscd_t chg_main_nscd = {0, 0, 0, 0};
  70 static mutex_t chg_main_nscd_lock = DEFAULTMUTEX;
  71 static cond_t chg_main_nscd_cv = DEFAULTCV;
  72 
  73 /*
  74  * The cookie of the configuration and its mutex
  75  */
  76 static ldap_get_chg_cookie_t config_cookie = {0, 0};
  77 static mutex_t config_cookie_lock = DEFAULTMUTEX;
  78 
  79 static void cleanup_thread_by_pid(pid_t pid);
  80 
  81 ldap_get_chg_cookie_t
  82 chg_config_cookie_get(void)
  83 {
  84         ldap_get_chg_cookie_t cookie;
  85         (void) mutex_lock(&config_cookie_lock);
  86         cookie = config_cookie;
  87         (void) mutex_unlock(&config_cookie_lock);
  88         return (cookie);
  89 }
  90 
  91 static void
  92 chg_config_cookie_increment_seq_num(void)
  93 {
  94         (void) mutex_lock(&config_cookie_lock);
  95         config_cookie.seq_num++;
  96         (void) mutex_unlock(&config_cookie_lock);
  97 }
  98 
  99 void
 100 chg_config_cookie_set(ldap_get_chg_cookie_t *cookie)
 101 {
 102         (void) mutex_lock(&config_cookie_lock);
 103         config_cookie.mgr_pid = cookie->mgr_pid;
 104         config_cookie.seq_num = cookie->seq_num;
 105         (void) mutex_unlock(&config_cookie_lock);
 106 }
 107 static boolean_t
 108 chg_cookie_equal(ldap_get_chg_cookie_t *c1, ldap_get_chg_cookie_t *c2)
 109 {
 110         if (c1->mgr_pid == c2->mgr_pid && c1->seq_num == c2->seq_num)
 111                 return (B_TRUE);
 112         else
 113                 return (B_FALSE);
 114 }
 115 /*
 116  * Create a node in the list and output the node. The caller can NOT free it.
 117  */
 118 static  int
 119 waiting_list_add(chg_info_t *info, pid_t pid, thread_t tid,
 120     waiting_list_t **wlp)
 121 {
 122 
 123         waiting_list_t  *wl;
 124 
 125         *wlp = NULL;
 126 
 127         if ((wl = (waiting_list_t *)calloc(1, sizeof (waiting_list_t)))
 128             == NULL) {
 129                 logit("waiting_list_add: No memory. pid %ld tid %d\n",
 130                     pid, tid);
 131                 return (CHG_NO_MEMORY);
 132         }
 133 
 134         wl->pid = pid;
 135         wl->tid = tid;
 136 
 137         if (info->chg_w_first == NULL) {
 138                 info->chg_w_first = wl;
 139                 info->chg_w_last = wl;
 140         } else {
 141                 info->chg_w_last->next = wl;
 142                 wl->prev = info->chg_w_last;
 143                 info->chg_w_last = wl;
 144         }
 145         *wlp = wl;
 146         return (CHG_SUCCESS);
 147 }
 148 
 149 /*
 150  * Find a node with matching tid in the list and remove it from the list.
 151  */
 152 static int
 153 waiting_list_delete(chg_info_t *info, thread_t tid)
 154 {
 155         waiting_list_t  *wl;
 156 
 157         for (wl = info->chg_w_first; wl != NULL; wl = wl->next) {
 158                 if (wl->tid == tid) {
 159                         if (wl->next == NULL) {
 160                                 if (wl->prev == NULL) {
 161                                         info->chg_w_first = NULL;
 162                                         info->chg_w_last = NULL;
 163                                 } else {
 164                                         wl->prev->next = NULL;
 165                                         info->chg_w_last =  wl->prev;
 166                                 }
 167                         } else {
 168                                 if (wl->prev == NULL) {
 169                                         wl->next->prev = NULL;
 170                                         info->chg_w_first = wl->next;
 171                                 } else {
 172                                         wl->prev->next = wl->next;
 173                                         wl->next->prev = wl->prev;
 174                                 }
 175                         }
 176                         free(wl);
 177                         return (CHG_SUCCESS);
 178                 }
 179         }
 180         return (CHG_NOT_FOUND_IN_WAITING_LIST);
 181 }
 182 
 183 /*
 184  * Delete the thread from the waiting list and remove data when the list
 185  * is empty.
 186  */
 187 static void
 188 waiting_list_cleanup(chg_info_t *chg, thread_t tid)
 189 {
 190         int     rc;
 191 
 192         rc = waiting_list_delete(chg, tid);
 193 
 194         if (rc == CHG_SUCCESS && chg->chg_w_first == NULL) {
 195                 free(chg->chg_data);
 196                 chg->chg_data = NULL;
 197                 chg->chg_wakeup = 0;
 198         }
 199 }
 200 
 201 /*
 202  * Set flag by pid so it can be cleaned up.
 203  */
 204 static void
 205 waiting_list_set_cleanup(chg_info_t *info, pid_t pid)
 206 {
 207         waiting_list_t  *wl;
 208 
 209         for (wl = info->chg_w_first; wl != NULL; wl = wl->next) {
 210                 if (wl->pid == pid) {
 211                         wl->cleanup = 1;
 212                         break;
 213                 }
 214         }
 215 }
 216 
 217 /*
 218  * Return: 1 - door client is dead, 0 - door client is alive
 219  */
 220 static int
 221 door_client_dead(void)
 222 {
 223         ucred_t *uc = NULL;
 224         int     rc;
 225 
 226         if (door_ucred(&uc) == -1 && errno == EINVAL) {
 227                 rc = 1;
 228         } else {
 229                 rc = 0;
 230         }
 231         if (uc)
 232                 ucred_free(uc);
 233 
 234         return (rc);
 235 }
 236 
 237 /*
 238  * This function handles GETSTATUSCHANGE call from main nscd.
 239  * The call can be a START op or STOP op. A cookie is sent from main nscd too.
 240  * The static global variable main_nscd keeps record of pid, tid and some flags.
 241  * If the thread is door_return(), main_nscd.pid, main_nscd.tid are set to 0.
 242  * When the call is START op, it checks if main_nscd.pid is 0. If it is, it
 243  * proceeds to wait for the change notification. If it's not, which means
 244  * another main nscd handling thread is still around. It sends broadcast to
 245  * clean up that thread and wait until the cleanup is done then proceeds to
 246  * wait for the change notification. If same main nscd sends START op
 247  * repeatedly, it'll be rejected.
 248  * It also checks the cookie from main nscd. If it's not the same as
 249  * ldap_cachemgr's cookie, door returns config change.
 250  * If the door call is STOP op, it creates a thread to clean up main nscd START
 251  * thread so it won't be blocking.
 252  * In waiting for the change notification phase, the thread is waken up by
 253  * the notification threads or by the cleanup threads.
 254  * If it's a notification, it copies data to the stack then door return.
 255  * If it's a cleanup, door_client_dead() is called to verify it then
 256  * door return.
 257  */
 258 int
 259 chg_get_statusChange(LineBuf *info, ldap_call_t *in, pid_t nscd_pid)
 260 {
 261         int     rc = CHG_SUCCESS, another_main_nscd_thread_alive = 0;
 262         int     len, return_now;
 263         thread_t this_tid = thr_self();
 264         waiting_list_t  *wl = NULL;
 265         ldap_get_change_out_t *cout;
 266         ldap_get_chg_cookie_t cookie;
 267 
 268         info->str = NULL;
 269         info->len = 0;
 270 
 271         if (in->ldap_u.get_change.op == NS_STATUS_CHANGE_OP_START) {
 272 
 273                 (void) mutex_lock(&chg_main_nscd_lock);
 274                 if (chg_main_nscd.pid != 0) {
 275                         if (nscd_pid != chg_main_nscd.pid) {
 276                                 /*
 277                                  * This is the case that nscd doesn't shut down
 278                                  * properly(e.g. core) and STOP op is not sent,
 279                                  * the thread handling it is still around and
 280                                  * not cleaned up yet.
 281                                  * Test if the thread is still alive.
 282                                  * If it is, clean it up.
 283                                  * For thr_kill, if sig is 0, a validity check
 284                                  * is done for the existence of the target
 285                                  * thread; no signal is sent.
 286                                  */
 287                                 if (thr_kill(chg_main_nscd.tid, 0) == 0) {
 288                                         another_main_nscd_thread_alive = 1;
 289                                         cleanup_thread_by_pid(
 290                                             chg_main_nscd.pid);
 291                                 }
 292                         } else if (chg_main_nscd.in_progress ||
 293                             chg_main_nscd.is_waiting_cleanup) {
 294                                 /*
 295                                  * Same nscd pid can only send door call
 296                                  * one at a time and wait for ldap_cachemgr to
 297                                  * return change data. If it's the same pid
 298                                  * again, it's an nscd error.
 299                                  */
 300                                 (void) mutex_unlock(&chg_main_nscd_lock);
 301                                 return (CHG_NSCD_REPEATED_CALL);
 302                         }
 303                 }
 304                 /*
 305                  * Wait for another thread to be cleaned up if it's alive.
 306                  * After that this cond var is waken up.
 307                  */
 308                 if (another_main_nscd_thread_alive) {
 309                         while (chg_main_nscd.in_progress) {
 310                                 chg_main_nscd.is_waiting_cleanup = 1;
 311                                 (void) cond_wait(&chg_main_nscd_cv,
 312                                     &chg_main_nscd_lock);
 313                         }
 314                 }
 315 
 316                 /*
 317                  * Replace pid and tid and set the flag.
 318                  */
 319                 chg_main_nscd.is_waiting_cleanup = 0;
 320                 chg_main_nscd.pid = nscd_pid;
 321                 chg_main_nscd.tid = this_tid;
 322                 chg_main_nscd.in_progress = 1;
 323                 (void) mutex_unlock(&chg_main_nscd_lock);
 324 
 325                 cookie = chg_config_cookie_get();
 326 
 327                 if (!chg_cookie_equal(&cookie, &in->ldap_u.get_change.cookie)) {
 328                         /*
 329                          * different cookie, set new cookie and
 330                          * return door call right away
 331                          */
 332                         len = sizeof (ldap_get_change_out_t);
 333                         if ((cout = calloc(1, len)) == NULL) {
 334                                 rc = CHG_NO_MEMORY;
 335                         } else {
 336                                 cout->type = NS_STATUS_CHANGE_TYPE_CONFIG;
 337                                 cout->cookie = cookie;
 338                                 info->str = (char *)cout;
 339                                 info->len = len;
 340                         }
 341 
 342                 } else {
 343                         (void) mutex_lock(&chg.chg_lock);
 344 
 345                         /* wait for the change notification */
 346                         rc = waiting_list_add(&chg, nscd_pid, this_tid, &wl);
 347                         if (rc == CHG_SUCCESS) {
 348                                 return_now = 0;
 349                                 while (!chg.chg_wakeup) {
 350                                         if (wl->cleanup ||
 351                                             door_client_dead()) {
 352                                                 return_now = 1;
 353                                                 break;
 354                                         }
 355                                         (void) cond_wait(&chg.chg_cv,
 356                                             &chg.chg_lock);
 357                                 }
 358                                 /* Check if door client is still alive again */
 359                                 if (!return_now && !wl->cleanup &&
 360                                     !door_client_dead()) {
 361                                         /* copy data to buffer */
 362                                         if ((info->str = malloc(
 363                                             chg.chg_data_size)) == NULL) {
 364                                                 rc = CHG_NO_MEMORY;
 365                                         } else {
 366                                                 (void) memcpy(info->str,
 367                                                     chg.chg_data,
 368                                                     chg.chg_data_size);
 369                                                 info->len = chg.chg_data_size;
 370                                         }
 371                                 }
 372                                 waiting_list_cleanup(&chg, this_tid);
 373                         }
 374                         (void) mutex_unlock(&chg.chg_lock);
 375                 }
 376 
 377 
 378                 /*
 379                  * Reset pid, tid and flag, send wakeup signal.
 380                  */
 381                 (void) mutex_lock(&chg_main_nscd_lock);
 382                 chg_main_nscd.pid = 0;
 383                 chg_main_nscd.tid = 0;
 384                 chg_main_nscd.in_progress = 0;
 385                 if (chg_main_nscd.is_waiting_cleanup)
 386                         (void) cond_broadcast(&chg_main_nscd_cv);
 387 
 388                 (void) mutex_unlock(&chg_main_nscd_lock);
 389 
 390         } else if (in->ldap_u.get_change.op == NS_STATUS_CHANGE_OP_STOP) {
 391 
 392                 cleanup_thread_by_pid(nscd_pid);
 393                 rc = CHG_SUCCESS;
 394 
 395         } else {
 396                 rc = CHG_INVALID_PARAM;
 397         }
 398         if (rc == CHG_EXCEED_MAX_THREADS)
 399                 cleanup_thread_by_pid(0);
 400 
 401         return (rc);
 402 }
 403 
 404 /*
 405  * This function copies the header and data stream to the buffer
 406  * then send broadcast to wake up the chg_get_statusChange() threads.
 407  */
 408 int
 409 chg_notify_statusChange(char *str)
 410 {
 411         ldap_get_change_out_t *cout = (ldap_get_change_out_t *)str;
 412 
 413         cout->cookie = chg_config_cookie_get();
 414 
 415         (void) mutex_lock(&chg.chg_lock);
 416         if (chg.chg_w_first != NULL && chg.chg_wakeup == 0) {
 417 
 418                 if (chg.chg_data) {
 419                         free(chg.chg_data);
 420                         chg.chg_data = NULL;
 421                 }
 422 
 423                 chg.chg_data = str;
 424 
 425                 if (cout->type == NS_STATUS_CHANGE_TYPE_CONFIG)
 426                         chg.chg_data_size = sizeof (ldap_get_change_out_t);
 427                 else
 428                         /* NS_STATUS_CHANGE_TYPE_SERVER */
 429                         chg.chg_data_size = sizeof (ldap_get_change_out_t) -
 430                             sizeof (int) + cout->data_size;
 431 
 432                 chg.chg_wakeup = 1;
 433                 (void) cond_broadcast(&chg.chg_cv);
 434         }
 435         (void) mutex_unlock(&chg.chg_lock);
 436 
 437         return (CHG_SUCCESS);
 438 }
 439 
 440 /*
 441  * This is called when the configuration is refreshed.
 442  * The new configuration is different from the current one, a notification
 443  * is sent tochg_get_statusChange() threads.
 444  */
 445 void
 446 chg_test_config_change(ns_config_t *new, int *change_status)
 447 {
 448         int     changed = 0;
 449         LineBuf new_cfg, cur_cfg;
 450         ns_ldap_error_t *errp = NULL;
 451         ldap_config_out_t *new_out, *cur_out;
 452         ldap_get_change_out_t   *cout;
 453 
 454         (void) memset(&new_cfg, 0, sizeof (LineBuf));
 455         (void) memset(&cur_cfg, 0, sizeof (LineBuf));
 456         /*
 457          * Flatten the config data of the newly downloaded config and
 458          * current default config and compare both.
 459          */
 460         if ((errp = __ns_ldap_LoadDoorInfo(&new_cfg, NULL, new, 0)) != NULL) {
 461                 __ns_ldap_freeError(&errp);
 462                 /* error, assume the config is changed */
 463                 changed = 1;
 464         } else if ((errp = __ns_ldap_LoadDoorInfo(&cur_cfg, NULL, NULL, 0))
 465             != NULL) {
 466                 __ns_ldap_freeError(&errp);
 467                 /* error, assume the config is changed */
 468                 changed = 1;
 469         }
 470         if (changed == 0) {
 471                 new_out = (ldap_config_out_t *)new_cfg.str;
 472                 cur_out = (ldap_config_out_t *)cur_cfg.str;
 473                 if (strcmp(new_out->config_str, cur_out->config_str) != 0) {
 474                         changed = 1;
 475                         if (current_admin.debug_level >= DBG_PROFILE_REFRESH) {
 476                                 logit("config changed.\n");
 477                         }
 478                 }
 479         }
 480         if (cur_cfg.str)
 481                 free(cur_cfg.str);
 482         if (new_cfg.str)
 483                 free(new_cfg.str);
 484 
 485         if (changed) {
 486 
 487                 if ((cout = calloc(1, sizeof (ldap_get_change_out_t)))
 488                     == NULL) {
 489                         logit("chg_test_config_change: No Memory\n");
 490                 } else {
 491                         /*
 492                          * Replace the currentdefault config with the new
 493                          * config
 494                          */
 495                         __s_api_init_config(new);
 496                         chg_config_cookie_increment_seq_num();
 497                         cout->type = NS_STATUS_CHANGE_TYPE_CONFIG;
 498                         /*
 499                          * cout->cookie is set by
 500                          * chg_notify_statusChange
 501                          */
 502                         (void) chg_notify_statusChange((char *)cout);
 503                 }
 504         } else {
 505                 __s_api_destroy_config(new);
 506         }
 507 
 508         *change_status = changed;
 509 }
 510 
 511 /*
 512  * Wake up chg_get_statusChange() threads to clean up the threads
 513  * that main nscd doesn't exist on the other of door anymore or
 514  * the thread is marked as cleanup.
 515  */
 516 static void
 517 cleanup_threads(chg_info_t *chg, pid_t pid, cleanup_type_t type)
 518 {
 519         (void) mutex_lock(&chg->chg_lock);
 520         if (type == CLEANUP_BY_PID)
 521                 waiting_list_set_cleanup(chg, pid);
 522         /*
 523          * wake up threads without setting chg.chg_wakeup.
 524          * It's for cleanup purpose, not for notifying changes.
 525          */
 526         (void) cond_broadcast(&chg->chg_cv);
 527         (void) mutex_unlock(&chg->chg_lock);
 528 }
 529 /*
 530  * If arg is NULL, it loops forever,
 531  * else it calls cleanup_threads once and exits.
 532  */
 533 void *
 534 chg_cleanup_waiting_threads(void *arg)
 535 {
 536         cleanup_op_t *op = (cleanup_op_t *)arg;
 537         cleanup_type_t type = 0;
 538         pid_t   pid;
 539         int     always = 1, waiting;
 540 
 541         (void) pthread_setname_np(pthread_self(), "chg_cleanup_thr");
 542 
 543         if (op == NULL) {
 544                 waiting = 1;
 545                 type = CLEANUP_ALL;
 546                 pid = 0;
 547         } else {
 548                 waiting = 0;
 549                 type = op->type;
 550                 pid = op->pid;
 551         }
 552 
 553         while (always) {
 554                 if (waiting)
 555                         (void) sleep(CLEANUP_WAIT_TIME);
 556                 cleanup_threads(&chg, pid, type);
 557                 if (!waiting)
 558                         break;
 559         }
 560 
 561         if (op)
 562                 free(op);
 563 
 564         thr_exit(NULL);
 565         return (NULL);
 566 }
 567 /*
 568  * The door server thead which has the door client pid will be marked
 569  * as to be clean up. If pid is 0, no marking and just clean up all.
 570  */
 571 static void
 572 cleanup_thread_by_pid(pid_t pid)
 573 {
 574         cleanup_op_t *op;
 575 
 576         if ((op = malloc(sizeof (cleanup_op_t))) == NULL)
 577                 return;
 578 
 579         op->pid = pid;
 580         /* clean up all if pid is 0 */
 581         if (pid == 0)
 582                 op->type = CLEANUP_ALL;
 583         else
 584                 op->type = CLEANUP_BY_PID;
 585 
 586         if (thr_create(NULL, 0, chg_cleanup_waiting_threads,
 587             (void *)op, THR_BOUND|THR_DETACHED, NULL) != 0) {
 588                 free(op);
 589                 logit("thr_create failed for cleanup_thread_by_pid(%ld)\n",
 590                     pid);
 591         }
 592 }
 593 
 594 /*
 595  * Output a psinfo of an nscd process with process id pid
 596  * Return: 0  - Can't find the process or it's not nscd
 597  *         1  - psinfo found
 598  * Note: If info is NULL, returns 0 or 1 only and no output from info.
 599  */
 600 static int
 601 get_nscd_psinfo(pid_t pid, psinfo_t *info)
 602 {
 603         psinfo_t        pinfo;
 604         char            fname[MAXPATHLEN];
 605         ssize_t         ret;
 606         int             fd;
 607 
 608         if (snprintf(fname, MAXPATHLEN, "/proc/%d/psinfo", pid) > 0) {
 609                 if ((fd = open(fname,  O_RDONLY)) >= 0) {
 610                         ret = read(fd, &pinfo, sizeof (psinfo_t));
 611                         (void) close(fd);
 612                         if ((ret == sizeof (psinfo_t)) &&
 613                             (strcmp(pinfo.pr_fname, "nscd") == 0)) {
 614                                 if (info)
 615                                         *info = pinfo;
 616                                 return (1);
 617                         }
 618                 }
 619         }
 620         return (0);
 621 }
 622 /*
 623  * If the parent process is nscd and euid is 0, it's a peruser nscd.
 624  */
 625 static int
 626 is_peruser_nscd(pid_t pid)
 627 {
 628         pid_t   ppid;
 629         psinfo_t pinfo;
 630 
 631         if (get_nscd_psinfo(pid, &pinfo)) {
 632                 ppid = pinfo.pr_ppid;
 633                 if (get_nscd_psinfo(ppid, &pinfo) && pinfo.pr_euid == 0)
 634                         /*
 635                          * get psinfo of parent forker nscd
 636                          */
 637                         return (1);
 638                 else
 639                         return (0);
 640         } else {
 641                 return (0);
 642         }
 643 }
 644 /*
 645  * Check if the door client making door call is a nscd or peruser nscd and
 646  * output door client's pid.
 647  */
 648 int
 649 chg_is_called_from_nscd_or_peruser_nscd(char *dc_str, pid_t *pidp)
 650 {
 651         int     rc;
 652         uid_t   euid;
 653         pid_t   pid;
 654         ucred_t *uc = NULL;
 655 
 656         if (door_ucred(&uc) != 0) {
 657                 rc = errno;
 658                 logit("door_ucred() call failed %s\n", strerror(rc));
 659                 return (0);
 660         }
 661         euid = ucred_geteuid(uc);
 662         pid = *pidp = ucred_getpid(uc);
 663 
 664         if ((euid == 0 && is_called_from_nscd(pid)) ||
 665             is_peruser_nscd(pid)) {
 666                 if (current_admin.debug_level >= DBG_ALL)
 667                         logit("ldap_cachemgr received %s call from pid %ld, "
 668                             "uid %u, euid %u\n", dc_str, pid,
 669                             ucred_getruid(uc), euid);
 670                 rc = 1;
 671         } else {
 672                 if (current_admin.debug_level >= DBG_CANT_FIND)
 673                         logit("%s call failed(cred): caller pid %ld, uid %u, "
 674                             "euid %u\n", dc_str, pid,
 675                             ucred_getruid(uc), euid);
 676 
 677                 rc = 0;
 678         }
 679 
 680         ucred_free(uc);
 681 
 682         return (rc);
 683 }