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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <string.h>
29 #include "nscd_switch.h"
30 #include "nscd_log.h"
31
32 /*
33 * nscd_nsw_state_t list for each nss database. Protected
34 * by the readers/writer lock nscd_nsw_state_base_lock.
35 */
36 nscd_nsw_state_base_t **nscd_nsw_state_base;
37 static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK;
38
39 static void
_nscd_free_nsw_state(nscd_nsw_state_t * s)40 _nscd_free_nsw_state(
41 nscd_nsw_state_t *s)
42 {
43
44 int i;
45 char *me = "_nscd_free_nsw_state";
46
47 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
48 (me, "freeing nsw state = %p\n", s);
49
50 if (s == NULL)
51 return;
52
53 if (s->nsw_cfg_p != NULL)
54 /*
55 * an nsw state without base does not reference
56 * count the nsw config data (ie not using a
57 * shared one), so the one created for it should
58 * be freed
59 */
60 if ((*s->nsw_cfg_p)->nobase != 1)
61 _nscd_release((nscd_acc_data_t *)s->nsw_cfg_p);
62 else
63 (void) _nscd_set((nscd_acc_data_t *)s->nsw_cfg_p, NULL);
64
65 if (s->be_db_pp != NULL) {
66 for (i = 0; i < s->max_src; i++) {
67 if (s->be_db_pp[i] == NULL)
68 continue;
69 _nscd_release((nscd_acc_data_t *)s->be_db_pp[i]);
70 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
71 (me, "release db be ptr %p\n", s->be_db_pp[i]);
72 }
73 free(s->be_db_pp);
74 }
75
76 if (s->be != NULL) {
77 for (i = 0; i < s->max_src; i++) {
78 if (s->be[i] == NULL)
79 continue;
80 if (s->getent == 1)
81 (void) NSS_INVOKE_DBOP(s->be[i],
82 NSS_DBOP_ENDENT, 0);
83 (void) NSS_INVOKE_DBOP(s->be[i],
84 NSS_DBOP_DESTRUCTOR, 0);
85 }
86 free(s->be);
87 }
88
89 if (s->be_constr != NULL)
90 free(s->be_constr);
91
92 if (s->be_version_p != NULL)
93 free(s->be_version_p);
94
95 /* remove reference to the nsw state base */
96 if (s->base != NULL) {
97 _nscd_release((nscd_acc_data_t *)s->base);
98 s->base = NULL;
99 }
100
101 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
102 (me, "nsw state %p freed \n", s);
103
104 free(s);
105 }
106
107 static void
_nscd_free_nsw_state_base(nscd_acc_data_t * data)108 _nscd_free_nsw_state_base(
109 nscd_acc_data_t *data)
110 {
111 nscd_nsw_state_base_t *base = (nscd_nsw_state_base_t *)data;
112 nscd_nsw_state_t *s, *ts;
113 int i;
114 char *me = "_nscd_free_nsw_state_base";
115
116 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
117 (me, "freeing db state base %p\n", base);
118
119 if (base == NULL)
120 return;
121
122 for (i = 0; i < 2; i++) {
123 if (i == 1)
124 s = base->nsw_state.first;
125 else
126 s = base->nsw_state_thr.first;
127
128 while (s != NULL) {
129 ts = s->next;
130 _nscd_free_nsw_state(s);
131 s = ts;
132 }
133 }
134
135 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
136 (me, "nsw state base %p freed \n", base);
137 }
138
139 void
_nscd_free_all_nsw_state_base()140 _nscd_free_all_nsw_state_base()
141 {
142 nscd_nsw_state_base_t *base;
143 int i;
144 char *me = "_nscd_free_all_nsw_state_base";
145
146 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
147 (me, "freeing all db state base\n");
148
149 (void) rw_wrlock(&nscd_nsw_state_base_lock);
150 for (i = 0; i < NSCD_NUM_DB; i++) {
151
152 base = nscd_nsw_state_base[i];
153 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
154 NSCD_LOG_LEVEL_DEBUG)
155 (me, "freeing db state base (%d) %p \n", i, base);
156
157 if (base == NULL)
158 continue;
159
160 nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *)
161 _nscd_set((nscd_acc_data_t *)base, NULL);
162 }
163 (void) rw_unlock(&nscd_nsw_state_base_lock);
164 }
165
166 static nscd_nsw_state_t *
_nscd_create_nsw_state(nscd_nsw_params_t * params)167 _nscd_create_nsw_state(
168 nscd_nsw_params_t *params)
169 {
170 nscd_nsw_state_t *s;
171 nscd_nsw_config_t *nsw_cfg;
172 nscd_db_t **be_db_p, *be_db;
173 int i, nobe = 1;
174 char *me = "_nscd_create_nsw_state";
175
176
177 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
178 (me, "creating nsw state...\n");
179
180 s = calloc(1, sizeof (nscd_nsw_state_t));
181 if (s == NULL) {
182 if ((*s->nsw_cfg_p)->nobase != 1)
183 _nscd_release((nscd_acc_data_t *)params->nswcfg);
184 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
185 (me, "not able to allocate a nsw state\n");
186 return (NULL);
187 } else
188 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
189 (me, "nsw state %p allocated\n", s);
190
191 s->dbi = params->dbi;
192 s->next = NULL;
193
194 nsw_cfg = *params->nswcfg;
195
196 s->nsw_cfg_p = params->nswcfg;
197 s->config = nsw_cfg->nsw_config;
198 s->max_src = nsw_cfg->max_src;
199 s->p = params->p;
200
201 s->be = calloc(s->max_src, sizeof (nss_backend_t **));
202 if (s->be == NULL) {
203 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
204 (me, "not able to allocate s->be\n");
205
206 _nscd_free_nsw_state(s);
207 return (NULL);
208 } else {
209 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
210 (me, "db be array %p allocated\n", s->be);
211 }
212
213 s->be_constr = (nss_backend_constr_t *)calloc(s->max_src,
214 sizeof (nss_backend_constr_t));
215 if (s->be_constr == NULL) {
216 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
217 (me, "not able to allocate s->be_constr\n");
218
219 _nscd_free_nsw_state(s);
220 return (NULL);
221 } else {
222 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
223 (me, "db be constructor array %p allocated\n", s->be_constr);
224 }
225
226 s->be_version_p = (void **)calloc(s->max_src, sizeof (void *));
227 if (s->be_version_p == NULL) {
228 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
229 (me, "not able to allocate s->be_version_p\n");
230
231 _nscd_free_nsw_state(s);
232 return (NULL);
233 } else {
234 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
235 (me, "db be version ptr array %p allocated\n", s->be_version_p);
236 }
237
238 s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***));
239 if (s->be_db_pp == NULL) {
240 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
241 (me, "not able to allocate s->be_db_pp\n");
242 _nscd_free_nsw_state(s);
243 return (NULL);
244 } else {
245 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
246 (me, "be_db_pp array %p allocated\n", s->be_db_pp);
247 }
248
249 /* create the source:database backends */
250 for (i = 0; i < s->max_src; i++) {
251 nss_backend_t *be;
252 int srci;
253 char *srcn;
254 const char *dbn;
255 struct __nsw_lookup_v1 *lkp;
256 const nscd_db_entry_t *dbe;
257 nscd_be_info_t *be_info;
258
259 if (i == 0)
260 lkp = s->config->lookups;
261 else
262 lkp = lkp->next;
263 if (lkp == NULL) {
264 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
265 (me, "error: lkp is NULL\n");
266 _nscd_free_nsw_state(s);
267 return (NULL);
268 }
269
270 srci = nsw_cfg->src_idx[i];
271 srcn = lkp->service_name;
272 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
273 (me, "source name = %s, index = %d\n", srcn, srci);
274
275 be_db_p = (nscd_db_t **)_nscd_get(
276 (nscd_acc_data_t *)nscd_src_backend_db[srci]);
277 if (be_db_p == NULL) {
278 _nscd_free_nsw_state(s);
279 return (NULL);
280 }
281 be_db = *be_db_p;
282 s->be_db_pp[i] = be_db_p;
283 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
284 (me, "be db ptr array %p referenced\n", be_db_p);
285
286 be_info = NULL;
287 be = NULL;
288 dbn = params->p.name;
289 dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO,
290 (const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0);
291 if (dbe != NULL)
292 be_info = (nscd_be_info_t *)*(dbe->data_array);
293
294 if (be_info == NULL || be_info->be_constr == NULL) {
295 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
296 (me, "no backend info or be_constr is NULL "
297 "for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci),
298 dbn);
299 } else {
300 s->be_constr[i] = be_info->be_constr;
301 be = (be_info->be_constr)(dbn,
302 NSCD_NSW_SRC_NAME(srci), 0);
303 if (be == NULL)
304 s->recheck_be = nscd_true;
305 }
306
307 if (be == NULL) {
308 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
309 (me, "not able to init be for <%s : %s>\n",
310 NSCD_NSW_SRC_NAME(srci), dbn);
311
312 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
313 (me, "releasing db be ptr %p\n", be_db_p);
314
315 _nscd_release((nscd_acc_data_t *)be_db_p);
316 s->be_db_pp[i] = NULL;
317
318 continue;
319 }
320
321 s->be[i] = be;
322 s->be_version_p[i] = be_info->be_version;
323 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
324 (me, "backend version is %p\n", be_info->be_version);
325 nobe = 0;
326 }
327
328 if (nobe == 1) {
329 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
330 (me, "NO backend found, returning NULL\n");
331
332 _nscd_free_nsw_state(s);
333 return (NULL);
334 }
335
336 return (s);
337 }
338
339 /*
340 * Try to initialize the backend instances one more time
341 * in case the dependencies the backend libraries depend
342 * on are now available
343 */
344 static void
check_be_array(nscd_nsw_state_t * s)345 check_be_array(
346 nscd_nsw_state_t *s)
347 {
348 int i;
349 char *dbn;
350 char *srcn;
351 struct __nsw_lookup_v1 *lkp;
352
353 dbn = NSCD_NSW_DB_NAME(s->dbi);
354
355 s->recheck_be = nscd_false;
356 for (i = 0; i < s->max_src; i++) {
357
358 if (i == 0)
359 lkp = s->config->lookups;
360 else
361 lkp = lkp->next;
362 if (lkp == NULL)
363 return;
364
365 srcn = lkp->service_name;
366
367 /*
368 * it is possible that 's->be[i]' could not be
369 * initialized earlier due to a dependency not
370 * yet available (e.g., nis on domain name),
371 * try to initialize one more time
372 */
373 if (s->be[i] == NULL && s->be_constr[i] != NULL) {
374 s->be[i] = (s->be_constr[i])(dbn, srcn, 0);
375 if (s->be[i] == NULL)
376 s->recheck_be = nscd_true;
377 }
378 }
379 }
380
381 static nscd_rc_t
_get_nsw_state_int(nss_db_root_t * rootp,nscd_nsw_params_t * params,thread_t * tid)382 _get_nsw_state_int(
383 nss_db_root_t *rootp,
384 nscd_nsw_params_t *params,
385 thread_t *tid)
386 {
387
388 nscd_nsw_state_t *ret = NULL;
389 nscd_nsw_config_t **nswcfg;
390 nscd_nsw_state_base_t *base;
391 nscd_state_ctrl_t *ctrl_p;
392 int thread_only = 0, wait_cond = 0;
393 char *me = "_get_nsw_state_int";
394 int dbi;
395 nscd_rc_t rc;
396
397 dbi = params->dbi;
398
399 /*
400 * no nsw state will be reused, if asked to use
401 * default config. So create the new structures
402 * used by the switch engine and the new nsw state
403 */
404 if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
405 rc = _nscd_create_sw_struct(dbi, -1, (char *)params->p.name,
406 (char *)params->p.default_config, NULL, params);
407 if (rc != NSCD_SUCCESS)
408 return (rc);
409
410 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
411 (me, "no base nsw config created for %s (sources: %s)\n",
412 params->p.name, params->p.default_config);
413
414 ret = _nscd_create_nsw_state(params);
415 if (ret == NULL)
416 return (NSCD_CREATE_NSW_STATE_FAILED);
417 rootp->s = (struct nss_db_state *)ret;
418 return (NSCD_SUCCESS);
419 }
420
421 /*
422 * if getting a nsw state for a request from the compat
423 * backend, create the new switch structures if this
424 * is the first time around for a passwd, shadow, group,
425 * or user_attr database
426 */
427 if (params->compati != -1) {
428
429 nscd_nsw_config_t **nswcfg1, **nswcfg2;
430 int i = params->compati;
431
432 dbi = i;
433
434 /*
435 * retrieve the pointer space which contains a
436 * pointer pointing to the nsswitch config
437 * structure for the compat backend
438 */
439 nswcfg = (nscd_nsw_config_t **)_nscd_get(
440 (nscd_acc_data_t *)nscd_nsw_config[i]);
441
442 /*
443 * If nsswitch config structure not created yet,
444 * get the config string from the passwd_compat
445 * or group_compat DB and create the structure.
446 */
447 if (*nswcfg == NULL) {
448 /* Wait first if it's being created. */
449 nswcfg2 = (nscd_nsw_config_t **)_nscd_mutex_lock(
450 (nscd_acc_data_t *)nscd_nsw_config[i]);
451
452 /* still not created yet */
453 if (*nswcfg2 == NULL) {
454 /*
455 * get the nsswitch config string specified
456 * for passwd_compat or group_compat
457 */
458 nswcfg1 = (nscd_nsw_config_t **)_nscd_get(
459 (nscd_acc_data_t *)
460 nscd_nsw_config[params->cfgdbi]);
461 if (nswcfg1 == NULL) {
462 _NSCD_LOG(NSCD_LOG_NSW_STATE,
463 NSCD_LOG_LEVEL_ERROR)
464 (me, "no nsw config for %s\n",
465 params->p.name);
466
467 (void) _nscd_mutex_unlock(
468 (nscd_acc_data_t *)nswcfg2);
469 _nscd_release((nscd_acc_data_t *)
470 nswcfg);
471
472 return (NSCD_CREATE_NSW_STATE_FAILED);
473 }
474
475 rc = _nscd_create_sw_struct(i, params->cfgdbi,
476 params->p.name, (*nswcfg1)->nsw_cfg_str,
477 NULL, params);
478 _nscd_release((nscd_acc_data_t *)nswcfg1);
479
480 if (rc == NSCD_SUCCESS) {
481 _NSCD_LOG(NSCD_LOG_NSW_STATE,
482 NSCD_LOG_LEVEL_DEBUG)
483 (me, "nsw config created for %s (%s)\n",
484 params->p.name,
485 (*nswcfg1)->nsw_cfg_str);
486 } else {
487 (void) _nscd_mutex_unlock(
488 (nscd_acc_data_t *)nswcfg2);
489 _nscd_release((nscd_acc_data_t *)
490 nswcfg);
491 return (rc);
492 }
493 }
494 (void) _nscd_mutex_unlock((nscd_acc_data_t *)nswcfg2);
495 }
496 _nscd_release((nscd_acc_data_t *)nswcfg);
497 }
498
499 (void) rw_rdlock(&nscd_nsw_state_base_lock);
500 base = nscd_nsw_state_base[dbi];
501 (void) rw_unlock(&nscd_nsw_state_base_lock);
502 if (base == NULL)
503 assert(base != NULL);
504
505 /*
506 * If list is not empty, return the first one on list.
507 * Otherwise, create and return a new db state if the
508 * limit is not reached. if reacehed, wait for the 'one
509 * is available' signal.
510 */
511 assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock(
512 (nscd_acc_data_t *)base));
513
514 if (tid == NULL) {
515 ctrl_p = &base->nsw_state;
516 } else {
517 thread_only = 1;
518 ctrl_p = &base->nsw_state_thr;
519
520 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
521 _nscd_logit(me, "per thread nsw state info: \n");
522 _nscd_logit(me, "tid = %d\n", *tid);
523 _nscd_logit(me, "tid in base = %d\n", base->tid);
524 _nscd_logit(me, "number of free nsw_state = %d\n",
525 ctrl_p->free);
526 _nscd_logit(me, "number of nsw state allocated = %d\n",
527 ctrl_p->allocated);
528 _nscd_logit(me, "first nsw state on list = %p\n",
529 ctrl_p->first);
530 _nscd_logit(me, "number of waiter = %d\n",
531 ctrl_p->waiter);
532
533 }
534 }
535
536 if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max)
537 wait_cond = 1;
538 else if (thread_only && base->used_by_thr && base->tid != *tid)
539 wait_cond = 1;
540
541 if (wait_cond) {
542
543 ctrl_p->waiter++;
544
545 while (wait_cond) {
546 if (!thread_only)
547 _NSCD_LOG(NSCD_LOG_NSW_STATE,
548 NSCD_LOG_LEVEL_DEBUG)
549 (me, "waiting for nsw state signal\n");
550 else
551 _NSCD_LOG(NSCD_LOG_NSW_STATE,
552 NSCD_LOG_LEVEL_DEBUG)
553 (me, "waiting for per thread "
554 "nsw state signal\n");
555
556 if (thread_only) {
557 _nscd_cond_wait((nscd_acc_data_t *)base,
558 &base->thr_cond);
559
560 if (base->used_by_thr == 0 &&
561 ctrl_p->first != NULL)
562 wait_cond = 0;
563 } else {
564 _nscd_cond_wait((nscd_acc_data_t *)base, NULL);
565
566 if (ctrl_p->first != NULL)
567 wait_cond = 0;
568 }
569
570 if (!thread_only)
571 _NSCD_LOG(NSCD_LOG_NSW_STATE,
572 NSCD_LOG_LEVEL_DEBUG)
573 (me, "woke from cond wait ...wait_cond = %d\n",
574 wait_cond);
575 else
576
577 _NSCD_LOG(NSCD_LOG_NSW_STATE,
578 NSCD_LOG_LEVEL_DEBUG)
579 (me, "woke from cond wait (per thread) "
580 "...wait_cond = %d\n", wait_cond);
581
582 }
583
584 ctrl_p->waiter--;
585 }
586
587 if (ctrl_p->first == NULL) {
588 int geti;
589
590 /*
591 * for lookup calls from the compat backend
592 * uses the switch policy for passwd_compat
593 * or group_compat
594 */
595 if (params->compati != -1)
596 geti = params->compati;
597 else
598 geti = params->dbi;
599
600 params->nswcfg = (nscd_nsw_config_t **)_nscd_get(
601 (nscd_acc_data_t *)nscd_nsw_config[geti]);
602 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
603 (me, "got a nsw config %p for index %d\n",
604 params->nswcfg, geti);
605
606 ctrl_p->first = _nscd_create_nsw_state(params);
607 if (ctrl_p->first != NULL) {
608 if (tid == NULL) {
609 _NSCD_LOG(NSCD_LOG_NSW_STATE,
610 NSCD_LOG_LEVEL_DEBUG)
611 (me, "got a new nsw_state %p\n", ctrl_p->first);
612 } else {
613 _NSCD_LOG(NSCD_LOG_NSW_STATE,
614 NSCD_LOG_LEVEL_DEBUG)
615 (me, "got a new per thread nsw_state %p\n",
616 ctrl_p->first);
617 }
618 ctrl_p->allocated++;
619 ctrl_p->free++;
620 } else {
621 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
622 (me, "error: unable to obtain a nsw state\n");
623 _nscd_mutex_unlock((nscd_acc_data_t *)base);
624 return (NSCD_CREATE_NSW_STATE_FAILED);
625 }
626 }
627
628 ret = ctrl_p->first;
629 if (ret->recheck_be == nscd_true)
630 check_be_array(ret);
631 ctrl_p->first = ret->next;
632 ret->next = NULL;
633 ctrl_p->free--;
634 if (thread_only) {
635 base->tid = *tid;
636 base->used_by_thr = 1;
637
638 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
639 _nscd_logit(me, "\t\t\tgot a per thread nsw "
640 "state %p: \n", ret);
641 _nscd_logit(me, "tid = %d\n", *tid);
642 _nscd_logit(me, "tid in base = %d\n", base->tid);
643 _nscd_logit(me, "number of free nsw_state = %d\n",
644 ctrl_p->free);
645 _nscd_logit(me, "number od nsw state allocated = %d\n",
646 ctrl_p->allocated);
647 _nscd_logit(me, "first nsw state on list = %p\n",
648 ctrl_p->first);
649 _nscd_logit(me, "number of waiter = %d\n",
650 ctrl_p->waiter);
651 }
652 }
653 else
654 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
655 (me, "got old nsw state %p\n", ret);
656
657 /*
658 * reference count the nsswitch state base bfore handing out
659 * the nsswitch state
660 */
661 ret->base = (nscd_nsw_state_base_t *)
662 _nscd_get((nscd_acc_data_t *)base);
663
664 _nscd_mutex_unlock((nscd_acc_data_t *)base);
665
666 rootp->s = (struct nss_db_state *)ret;
667
668 return (NSCD_SUCCESS);
669 }
670
671 nscd_rc_t
_nscd_get_nsw_state(nss_db_root_t * rootp,nscd_nsw_params_t * params)672 _nscd_get_nsw_state(
673 nss_db_root_t *rootp,
674 nscd_nsw_params_t *params)
675 {
676 return (_get_nsw_state_int(rootp, params, NULL));
677 }
678
679 nscd_rc_t
_nscd_get_nsw_state_thread(nss_db_root_t * rootp,nscd_nsw_params_t * params)680 _nscd_get_nsw_state_thread(
681 nss_db_root_t *rootp,
682 nscd_nsw_params_t *params)
683 {
684 thread_t tid = thr_self();
685 return (_get_nsw_state_int(rootp, params, &tid));
686 }
687
688
689 static void
_put_nsw_state_int(nscd_nsw_state_t * s,thread_t * tid)690 _put_nsw_state_int(
691 nscd_nsw_state_t *s,
692 thread_t *tid)
693 {
694
695 nscd_nsw_state_base_t *base;
696 nscd_state_ctrl_t *ctrl_p;
697 int thread_only = 0;
698 char *me = "_put_nsw_state_int";
699
700 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
701 (me, "put back a nsw state\n");
702
703 if (s == NULL) {
704 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
705 (me, "nsw state is NULL, nothing to put back\n");
706 return;
707 }
708
709 /*
710 * no need to put back if the nsw state is not on any base
711 * but need to free the resources used
712 */
713 if ((*s->nsw_cfg_p)->nobase == 1) {
714 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
715 (me, "no base nsw state, freeing resources ...\n");
716
717 _nscd_free_nsw_state(s);
718 return;
719 }
720
721 if (tid != NULL)
722 thread_only = 1;
723
724 base = s->base;
725
726 if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) {
727 /* base has been freed or no longer valid, free the nsw state */
728 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
729 (me, "nsw state base gone or no longer valid, freeing %p\n", s);
730 _nscd_free_nsw_state(s);
731 return;
732 }
733
734 if (thread_only)
735 ctrl_p = &base->nsw_state_thr;
736 else
737 ctrl_p = &base->nsw_state;
738
739 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
740 _nscd_logit(me, "before returning the nsw state: \n");
741 _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
742 _nscd_logit(me, "tid in base = %d\n", base->tid);
743 _nscd_logit(me, "number of free nsw_state = %d\n",
744 ctrl_p->free);
745 _nscd_logit(me, "number od nsw state allocated = %d\n",
746 ctrl_p->allocated);
747 _nscd_logit(me, "first nsw state on list = %p\n",
748 ctrl_p->first);
749 _nscd_logit(me, "number of waiter = %d\n", ctrl_p->waiter);
750 }
751
752 if (ctrl_p->first != NULL) {
753 s->next = ctrl_p->first;
754 ctrl_p->first = s;
755 } else {
756 ctrl_p->first = s;
757 s->next = NULL;
758 }
759 ctrl_p->free++;
760
761 /*
762 * Remove reference to the nsswitch state base.
763 */
764 _nscd_release((nscd_acc_data_t *)base);
765 s->base = NULL;
766
767 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
768 (me, "signaling waiter thread_only = %d..\n", thread_only);
769
770 if (thread_only && ctrl_p->free == ctrl_p->allocated) {
771 assert(ctrl_p->first != NULL);
772 base->used_by_thr = 0;
773 if (ctrl_p->waiter > 0) {
774 (void) cond_signal(&base->thr_cond);
775 }
776 }
777
778 if (!thread_only && ctrl_p->waiter > 0) {
779
780 _nscd_cond_signal((nscd_acc_data_t *)base);
781 }
782
783 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
784 _nscd_logit(me, "after the nsw state is returned: \n");
785 _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
786 _nscd_logit(me, "tid in base = %d\n", base->tid);
787 _nscd_logit(me, "number of free nsw_state = %d\n",
788 ctrl_p->free);
789 _nscd_logit(me, "number od nsw state allocated = %d\n",
790 ctrl_p->allocated);
791 _nscd_logit(me, "first nsw state on list = %p\n",
792 ctrl_p->first);
793 _nscd_logit(me, "tnumber of waiter = %d\n", ctrl_p->waiter);
794 }
795
796 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
797 (me, "done putting back nsw state %p, thread_only = %d\n",
798 s, thread_only);
799
800 _nscd_mutex_unlock((nscd_acc_data_t *)base);
801
802 }
803
804 void
_nscd_put_nsw_state(nscd_nsw_state_t * s)805 _nscd_put_nsw_state(
806 nscd_nsw_state_t *s)
807 {
808 _put_nsw_state_int(s, NULL);
809 }
810
811 void
_nscd_put_nsw_state_thread(nscd_nsw_state_t * s)812 _nscd_put_nsw_state_thread(
813 nscd_nsw_state_t *s)
814 {
815 thread_t tid = thr_self();
816 _put_nsw_state_int(s, &tid);
817 }
818
819 nscd_rc_t
_nscd_init_nsw_state_base(int dbi,int compat_basei,int lock)820 _nscd_init_nsw_state_base(
821 int dbi,
822 int compat_basei,
823 int lock)
824 {
825 int cfgdbi;
826 nscd_nsw_state_base_t *base = NULL;
827 char *me = "_nscd_init_nsw_state_base";
828
829 if (lock)
830 (void) rw_rdlock(&nscd_nsw_state_base_lock);
831
832 base = (nscd_nsw_state_base_t *)_nscd_alloc(
833 NSCD_DATA_NSW_STATE_BASE,
834 sizeof (nscd_nsw_state_base_t),
835 _nscd_free_nsw_state_base,
836 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
837
838 if (base == NULL) {
839 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
840 NSCD_LOG_LEVEL_ERROR)
841 (me, "not able to allocate a nsw state base\n");
842 if (lock)
843 (void) rw_unlock(&nscd_nsw_state_base_lock);
844 return (NSCD_NO_MEMORY);
845 }
846 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
847 (me, "nsw state base %p allocated\n", base);
848
849 /*
850 * initialize and activate the new nss_nsw_state base
851 */
852 base->dbi = dbi;
853 if (compat_basei != -1)
854 cfgdbi = compat_basei;
855 else
856 cfgdbi = dbi;
857
858 base->nsw_state.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_db;
859 base->nsw_state_thr.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_thread;
860
861 nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set(
862 (nscd_acc_data_t *)nscd_nsw_state_base[dbi],
863 (nscd_acc_data_t *)base);
864
865 if (lock)
866 (void) rw_unlock(&nscd_nsw_state_base_lock);
867
868 return (NSCD_SUCCESS);
869 }
870
871 nscd_rc_t
_nscd_init_all_nsw_state_base()872 _nscd_init_all_nsw_state_base()
873 {
874 int i;
875 nscd_rc_t rc;
876 char *me = "_nscd_init_all_nsw_state_base";
877
878 (void) rw_rdlock(&nscd_nsw_state_base_lock);
879
880 for (i = 0; i < NSCD_NUM_DB; i++) {
881
882 rc = _nscd_init_nsw_state_base(i, -1, 0);
883
884 if (rc != NSCD_SUCCESS) {
885 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
886 NSCD_LOG_LEVEL_ERROR)
887 (me, "not able to initialize a nsw db state "
888 "base (%d)\n", i);
889
890 (void) rw_unlock(&nscd_nsw_state_base_lock);
891 return (rc);
892 }
893 }
894 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
895 (me, "all nsw state base initialized\n");
896
897 (void) rw_unlock(&nscd_nsw_state_base_lock);
898
899 return (NSCD_SUCCESS);
900 }
901
902 nscd_rc_t
_nscd_alloc_nsw_state_base()903 _nscd_alloc_nsw_state_base()
904 {
905
906 (void) rw_rdlock(&nscd_nsw_state_base_lock);
907
908 nscd_nsw_state_base = calloc(NSCD_NUM_DB,
909 sizeof (nscd_nsw_state_base_t *));
910 if (nscd_nsw_state_base == NULL) {
911 (void) rw_unlock(&nscd_nsw_state_base_lock);
912 return (NSCD_NO_MEMORY);
913 }
914
915 (void) rw_rdlock(&nscd_nsw_state_base_lock);
916
917 return (NSCD_SUCCESS);
918 }
919