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