Print this page
8158 Want named threads API
9857 proc manpages should have LIBRARY section
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ldapcachemgr/cachemgr_discovery.c
+++ new/usr/src/cmd/ldapcachemgr/cachemgr_discovery.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + *
25 + * Copyright 2018 Joyent, Inc.
24 26 */
25 27
26 28 #ifdef SLP
27 29
28 30 /*
29 31 * This file contains all the dynamic server discovery functionality
30 32 * for ldap_cachemgr. SLP is used to query the network for any changes
31 33 * in the set of deployed LDAP servers.
32 34 *
33 35 * The algorithm used is outlined here:
34 36 *
35 37 * 1. Find all naming contexts with SLPFindAttrs. (See
36 38 * find_all_contexts())
37 39 * 2. For each context, find all servers which serve that context
38 40 * with SLPFindSrvs. (See foreach_context())
39 41 * 3. For each server, retrieve that server's attributes with
40 42 * SLPFindAttributes. (See foreach_server())
41 43 * 4. Aggregate the servers' attributes into a config object. There
42 44 * is one config object associated with each context found in
43 45 * step 1. (See aggregate_attrs())
44 46 * 5. Update the global config cache for each found context and its
45 47 * associated servers and attributes. (See update_config())
46 48 *
47 49 * The entry point for ldap_cachemgr is discover(). The actual entry
48 50 * point into the discovery routine is find_all_contexts(); the
49 51 * code thereafter is actually not specific to LDAP, and could also
50 52 * be used to discover YP, or any other server which conforms
51 53 * to the SLP Naming and Directory abstract service type.
52 54 *
53 55 * find_all_attributes() takes as parameters three callback routines
54 56 * which are used to report all information back to the caller. The
55 57 * signatures and synopses of these routines are:
56 58 *
57 59 * void *get_cfghandle(const char *domain);
58 60 *
59 61 * Returns an opaque handle to a configuration object specific
60 62 * to the 'domain' parameter. 'domain' will be a naming context
61 63 * string, i.e. foo.bar.sun.com ( i.e. a secure-RPC domain-
62 64 * name).
63 65 *
64 66 * void aggregate(void *handle, const char *tag, const char *value);
65 67 *
66 68 * Adds this tag / value pair to the set of aggregated attributes
67 69 * associated with the given handle.
68 70 *
69 71 * void set_cfghandle(void *handle);
70 72 *
71 73 * Sets and destroys the config object; SLP will no longer attempt
72 74 * to use this handle after this call. Thus, this call marks the
73 75 * end of configuration information for this handle.
74 76 */
75 77
76 78 #include <stdio.h>
77 79 #include <slp.h>
78 80 #include <stdlib.h>
79 81 #include <string.h>
80 82 #include <door.h>
81 83 #include <unistd.h>
82 84 #include "ns_sldap.h"
83 85 #include "ns_internal.h"
84 86 #include "cachemgr.h"
85 87
86 88 #define ABSTYPE "service:naming-directory"
87 89 #define CONTEXT_ATTR "naming-context"
88 90 #define LDAP_DOMAIN_ATTR "x-sun-rpcdomain"
89 91
90 92 /* The configuration cookie passed along through all SLP callbacks. */
91 93 struct config_cookie {
92 94 SLPHandle h; /* An open SLPHandle */
93 95 const char *type; /* The full service type to use */
94 96 char *scopes; /* A list of scopes to use */
95 97 const char *context_attr; /* Which attr to use for the ctx */
96 98 void *cache_cfg; /* caller-supplied config object */
97 99 void *(*get_cfghandle)(const char *);
98 100 void (*aggregate)(void *, const char *, const char *);
99 101 void (*set_cfghandle)(void *);
100 102 };
101 103
102 104 extern admin_t current_admin; /* ldap_cachemgr's admin struct */
103 105
104 106 /*
105 107 * Utility routine: getlocale():
106 108 * Returns the locale specified by the SLP locale property, or just
107 109 * returns the default SLP locale if the property was not set.
108 110 */
109 111 static const char *getlocale() {
110 112 const char *locale = SLPGetProperty("net.slp.locale");
111 113 return (locale ? locale : "en");
112 114 }
113 115
114 116 /*
115 117 * Utility routine: next_attr():
116 118 * Parses an SLP attribute string. On the first call, *type
117 119 * must be set to 0, and *s_inout must point to the beginning
118 120 * of the attr string. The following results are possible:
119 121 *
120 122 * If the term is of the form 'tag' only, *t_inout is set to tag,
121 123 * and *v_inout is set to NULL.
122 124 * If the term is of the form '(tag=val)', *t_inout and *v_inout
123 125 * are set to the tag and val strings, respectively.
124 126 * If the term is of the form '(tag=val1,val2,..,valN)', on each
125 127 * successive call, next_attr will return the next value. On the
126 128 * first invocation, tag is set to 'tag'; on successive invocations,
127 129 * tag is set to *t_inout.
128 130 *
129 131 * The string passed in *s_inout is destructively modified; all values
130 132 * returned simply point into the initial string. Hence the caller
131 133 * is responsible for all memory management. The type parameter is
132 134 * for internal use only and should be set to 0 by the caller only
133 135 * on the first invocation.
134 136 *
135 137 * If more attrs are available, returns SLP_TRUE, otherwise returns
136 138 * SLP_FALSE. If SLP_FALSE is returned, all value-result parameters
137 139 * will be undefined, and should not be used.
138 140 */
139 141 static SLPBoolean next_attr(char **t_inout, char **v_inout,
140 142 char **s_inout, int *type) {
141 143 char *end = NULL;
142 144 char *tag = NULL;
143 145 char *val = NULL;
144 146 char *state = NULL;
145 147
146 148 if (!t_inout || !v_inout)
147 149 return (SLP_FALSE);
148 150
149 151 if (!s_inout || !*s_inout || !**s_inout)
150 152 return (SLP_FALSE);
151 153
152 154 state = *s_inout;
153 155
154 156 /* type: 0 = start, 1 = '(tag=val)' type, 2 = 'tag' type */
155 157 switch (*type) {
156 158 case 0:
157 159 switch (*state) {
158 160 case '(':
159 161 *type = 1;
160 162 break;
161 163 case ',':
162 164 state++;
163 165 *type = 0;
164 166 break;
165 167 default:
166 168 *type = 2;
167 169 }
168 170 *s_inout = state;
169 171 return (next_attr(t_inout, v_inout, s_inout, type));
170 172 break;
171 173 case 1:
172 174 switch (*state) {
173 175 case '(':
174 176 /* start of attr of the form (tag=val[,val]) */
175 177 state++;
176 178 tag = state;
177 179 end = strchr(state, ')'); /* for sanity checking */
178 180 if (!end)
179 181 return (SLP_FALSE); /* fatal parse error */
180 182
181 183 state = strchr(tag, '=');
182 184 if (state) {
183 185 if (state > end)
184 186 return (SLP_FALSE); /* fatal parse err */
185 187 *state++ = 0;
186 188 } else {
187 189 return (SLP_FALSE); /* fatal parse error */
188 190 }
189 191 /* fallthru to default case, which handles multivals */
190 192 default:
191 193 /* somewhere in a multivalued attr */
192 194 if (!end) { /* did not fallthru from '(' case */
193 195 tag = *t_inout; /* leave tag as it was */
194 196 end = strchr(state, ')');
195 197 if (!end)
196 198 return (SLP_FALSE); /* fatal parse error */
197 199 }
198 200
199 201 val = state;
200 202 state = strchr(val, ','); /* is this attr multivalued? */
201 203 if (!state || state > end) {
202 204 /* no, so skip to the next attr */
203 205 state = end;
204 206 *type = 0;
205 207 } /* else attr is multivalued */
206 208 *state++ = 0;
207 209 break;
208 210 }
209 211 break;
210 212 case 2:
211 213 /* attr term with tag only */
212 214 tag = state;
213 215 state = strchr(tag, ',');
214 216 if (state) {
215 217 *state++ = 0;
216 218 }
217 219 val = NULL;
218 220 *type = 0;
219 221 break;
220 222 default:
221 223 return (SLP_FALSE);
222 224 }
223 225
224 226 *t_inout = tag;
225 227 *v_inout = val;
226 228 *s_inout = state;
227 229
228 230 return (SLP_TRUE);
229 231 }
230 232
231 233 /*
232 234 * The SLP callback routine for foreach_server(). Aggregates each
233 235 * server's attributes into the caller-specified config object.
234 236 */
235 237 /*ARGSUSED*/
236 238 static SLPBoolean aggregate_attrs(SLPHandle h, const char *attrs_in,
237 239 SLPError errin, void *cookie) {
238 240 char *tag, *val, *state;
239 241 char *unesc_tag, *unesc_val;
240 242 int type = 0;
241 243 char *attrs;
242 244 SLPError err;
243 245 struct config_cookie *cfg = (struct config_cookie *)cookie;
244 246
245 247 if (errin != SLP_OK) {
246 248 return (SLP_TRUE);
247 249 }
248 250
249 251 attrs = strdup(attrs_in);
250 252 state = attrs;
251 253
252 254 while (next_attr(&tag, &val, &state, &type)) {
253 255 unesc_tag = unesc_val = NULL;
254 256
255 257 if (tag) {
256 258 if ((err = SLPUnescape(tag, &unesc_tag, SLP_TRUE)) != SLP_OK) {
257 259 unesc_tag = NULL;
258 260 if (current_admin.debug_level >= DBG_ALL) {
259 261 (void) logit("aggregate_attrs: ",
260 262 "could not unescape attr tag %s:%s\n",
261 263 tag, slp_strerror(err));
262 264 }
263 265 }
264 266 }
265 267 if (val) {
266 268 if ((err = SLPUnescape(val, &unesc_val, SLP_FALSE))
267 269 != SLP_OK) {
268 270 unesc_val = NULL;
269 271 if (current_admin.debug_level >= DBG_ALL) {
270 272 (void) logit("aggregate_attrs: ",
271 273 "could not unescape attr val %s:%s\n",
272 274 val, slp_strerror(err));
273 275 }
274 276 }
275 277 }
276 278
277 279 if (current_admin.debug_level >= DBG_ALL) {
278 280 (void) logit("discovery:\t\t%s=%s\n",
279 281 (unesc_tag ? unesc_tag : "NULL"),
280 282 (unesc_val ? unesc_val : "NULL"));
281 283 }
282 284
283 285 cfg->aggregate(cfg->cache_cfg, unesc_tag, unesc_val);
284 286
285 287 if (unesc_tag) free(unesc_tag);
286 288 if (unesc_val) free(unesc_val);
287 289 }
288 290
289 291 if (attrs) free(attrs);
290 292
291 293 return (SLP_TRUE);
292 294 }
293 295
294 296 /*
295 297 * The SLP callback routine for update_config(). For each
296 298 * server found, retrieves that server's attributes.
297 299 */
298 300 /*ARGSUSED*/
299 301 static SLPBoolean foreach_server(SLPHandle hin, const char *u,
300 302 unsigned short life,
301 303 SLPError errin, void *cookie) {
302 304 SLPError err;
303 305 struct config_cookie *cfg = (struct config_cookie *)cookie;
304 306 SLPHandle h = cfg->h; /* an open handle */
305 307 SLPSrvURL *surl = NULL;
306 308 char *url = NULL;
307 309
308 310 if (errin != SLP_OK) {
309 311 return (SLP_TRUE);
310 312 }
311 313
312 314 /* dup url so we can slice 'n dice */
313 315 if (!(url = strdup(u))) {
314 316 (void) logit("foreach_server: no memory");
315 317 return (SLP_FALSE);
316 318 }
317 319
318 320 if ((err = SLPParseSrvURL(url, &surl)) != SLP_OK) {
319 321 free(url);
320 322 if (current_admin.debug_level >= DBG_NETLOOKUPS) {
321 323 (void) logit("foreach_server: ",
322 324 "dropping unparsable URL %s: %s\n",
323 325 url, slp_strerror(err));
324 326 return (SLP_TRUE);
325 327 }
326 328 }
327 329
328 330 if (current_admin.debug_level >= DBG_ALL) {
329 331 (void) logit("discovery:\tserver: %s\n", surl->s_pcHost);
330 332 }
331 333
332 334 /* retrieve all attrs for this server */
333 335 err = SLPFindAttrs(h, u, cfg->scopes, "", aggregate_attrs, cookie);
334 336 if (err != SLP_OK) {
335 337 if (current_admin.debug_level >= DBG_NETLOOKUPS) {
336 338 (void) logit("foreach_server: FindAttrs failed: %s\n",
337 339 slp_strerror(err));
338 340 }
339 341 goto cleanup;
340 342 }
341 343
342 344 /* add this server and its attrs to the config object */
343 345 cfg->aggregate(cfg->cache_cfg, "_,_xservers_,_", surl->s_pcHost);
344 346
345 347 cleanup:
346 348 if (url) free(url);
347 349 if (surl) SLPFree(surl);
348 350
349 351 return (SLP_TRUE);
350 352 }
351 353
352 354 /*
353 355 * This routine does the dirty work of finding all servers for a
354 356 * given domain and injecting this information into the caller's
355 357 * configuration namespace via callbacks.
356 358 */
357 359 static void update_config(const char *context, struct config_cookie *cookie) {
358 360 SLPHandle h = NULL;
359 361 SLPHandle persrv_h = NULL;
360 362 SLPError err;
361 363 char *search = NULL;
362 364 char *unesc_domain = NULL;
363 365
364 366 /* Unescape the naming context string */
365 367 if ((err = SLPUnescape(context, &unesc_domain, SLP_FALSE)) != SLP_OK) {
366 368 if (current_admin.debug_level >= DBG_ALL) {
367 369 (void) logit("update_config: ",
368 370 "dropping unparsable domain: %s: %s\n",
369 371 context, slp_strerror(err));
370 372 }
371 373 return;
372 374 }
373 375
374 376 cookie->cache_cfg = cookie->get_cfghandle(unesc_domain);
375 377
376 378 /* Open a handle which all attrs calls can use */
377 379 if ((err = SLPOpen(getlocale(), SLP_FALSE, &persrv_h)) != SLP_OK) {
378 380 if (current_admin.debug_level >= DBG_NETLOOKUPS) {
379 381 (void) logit("update_config: SLPOpen failed: %s\n",
380 382 slp_strerror(err));
381 383 }
382 384 goto cleanup;
383 385 }
384 386
385 387 cookie->h = persrv_h;
386 388
387 389 if (current_admin.debug_level >= DBG_ALL) {
388 390 (void) logit("discovery: found naming context %s\n", context);
389 391 }
390 392
391 393 /* (re)construct the search filter form the input context */
392 394 search = malloc(strlen(cookie->context_attr) +
393 395 strlen(context) +
394 396 strlen("(=)") + 1);
395 397 if (!search) {
396 398 (void) logit("update_config: no memory\n");
397 399 goto cleanup;
398 400 }
399 401 (void) sprintf(search, "(%s=%s)", cookie->context_attr, context);
400 402
401 403 /* Find all servers which serve this context */
402 404 if ((err = SLPOpen(getlocale(), SLP_FALSE, &h)) != SLP_OK) {
403 405 if (current_admin.debug_level >= DBG_NETLOOKUPS) {
404 406 (void) logit("upate_config: SLPOpen failed: %s\n",
405 407 slp_strerror(err));
406 408 }
407 409 goto cleanup;
408 410 }
409 411
410 412 err = SLPFindSrvs(h, cookie->type, cookie->scopes,
411 413 search, foreach_server, cookie);
412 414 if (err != SLP_OK) {
413 415 if (current_admin.debug_level >= DBG_NETLOOKUPS) {
414 416 (void) logit("update_config: SLPFindSrvs failed: %s\n",
415 417 slp_strerror(err));
416 418 }
417 419 goto cleanup;
418 420 }
419 421
420 422 /* update the config cache with the new info */
421 423 cookie->set_cfghandle(cookie->cache_cfg);
422 424
423 425 cleanup:
424 426 if (h) SLPClose(h);
425 427 if (persrv_h) SLPClose(persrv_h);
426 428 if (search) free(search);
427 429 if (unesc_domain) free(unesc_domain);
428 430 }
429 431
430 432 /*
431 433 * The SLP callback routine for find_all_contexts(). For each context
432 434 * found, finds all the servers and their attributes.
433 435 */
434 436 /*ARGSUSED*/
435 437 static SLPBoolean foreach_context(SLPHandle h, const char *attrs_in,
436 438 SLPError err, void *cookie) {
437 439 char *attrs, *tag, *val, *state;
438 440 int type = 0;
439 441
440 442 if (err != SLP_OK) {
441 443 return (SLP_TRUE);
442 444 }
443 445
444 446 /*
445 447 * Parse out each context. Attrs will be of the following form:
446 448 * (naming-context=dc\3deng\2c dc\3dsun\2c dc\3dcom)
447 449 * Note that ',' and '=' are reserved in SLP, so they are escaped.
448 450 */
449 451 attrs = strdup(attrs_in); /* so we can slice'n'dice */
450 452 if (!attrs) {
451 453 (void) logit("foreach_context: no memory\n");
452 454 return (SLP_FALSE);
453 455 }
454 456 state = attrs;
455 457
456 458 while (next_attr(&tag, &val, &state, &type)) {
457 459 update_config(val, cookie);
458 460 }
459 461
460 462 free(attrs);
461 463
462 464 return (SLP_TRUE);
463 465 }
464 466
465 467 /*
466 468 * Initiates server and attribute discovery for the concrete type
467 469 * 'type'. Currently the only useful type is "ldap", but perhaps
468 470 * "nis" and "nisplus" will also be useful in the future.
469 471 *
470 472 * get_cfghandle, aggregate, and set_cfghandle are callback routines
471 473 * used to pass any discovered configuration information back to the
472 474 * caller. See the introduction at the top of this file for more info.
473 475 */
474 476 static void find_all_contexts(const char *type,
475 477 void *(*get_cfghandle)(const char *),
476 478 void (*aggregate)(
477 479 void *, const char *, const char *),
478 480 void (*set_cfghandle)(void *)) {
479 481 SLPHandle h = NULL;
480 482 SLPError err;
481 483 struct config_cookie cookie[1];
482 484 char *fulltype = NULL;
483 485 char *scope = (char *)SLPGetProperty("net.slp.useScopes");
484 486
485 487 if (!scope || !*scope) {
486 488 scope = "default";
487 489 }
488 490
489 491 /* construct the full type from the partial type parameter */
490 492 fulltype = malloc(strlen(ABSTYPE) + strlen(type) + 2);
491 493 if (!fulltype) {
492 494 (void) logit("find_all_contexts: no memory");
493 495 goto done;
494 496 }
495 497 (void) sprintf(fulltype, "%s:%s", ABSTYPE, type);
496 498
497 499 /* set up the cookie for this discovery operation */
498 500 memset(cookie, 0, sizeof (*cookie));
499 501 cookie->type = fulltype;
500 502 cookie->scopes = scope;
501 503 if (strcasecmp(type, "ldap") == 0) {
502 504 /* Sun LDAP is special */
503 505 cookie->context_attr = LDAP_DOMAIN_ATTR;
504 506 } else {
505 507 cookie->context_attr = CONTEXT_ATTR;
506 508 }
507 509 cookie->get_cfghandle = get_cfghandle;
508 510 cookie->aggregate = aggregate;
509 511 cookie->set_cfghandle = set_cfghandle;
510 512
511 513 if ((err = SLPOpen(getlocale(), SLP_FALSE, &h)) != SLP_OK) {
512 514 if (current_admin.debug_level >= DBG_CANT_FIND) {
513 515 (void) logit("discover: %s",
514 516 "Aborting discovery: SLPOpen failed: %s\n",
515 517 slp_strerror(err));
516 518 }
517 519 goto done;
518 520 }
519 521
520 522 /* use find attrs to get a list of all available contexts */
521 523 err = SLPFindAttrs(h, fulltype, scope, cookie->context_attr,
522 524 foreach_context, cookie);
523 525 if (err != SLP_OK) {
524 526 if (current_admin.debug_level >= DBG_CANT_FIND) {
525 527 (void) logit(
526 528 "discover: Aborting discovery: SLPFindAttrs failed: %s\n",
527 529 slp_strerror(err));
528 530 }
529 531 goto done;
530 532 }
531 533
↓ open down ↓ |
498 lines elided |
↑ open up ↑ |
532 534 done:
533 535 if (h) SLPClose(h);
534 536 if (fulltype) free(fulltype);
535 537 }
536 538
537 539 /*
538 540 * This is the ldap_cachemgr entry point into SLP dynamic discovery. The
539 541 * parameter 'r' should be a pointer to an unsigned int containing
540 542 * the requested interval at which the network should be queried.
541 543 */
542 -void discover(void *r) {
544 +void
545 +discover(void *r) {
543 546 unsigned short reqrefresh = *((unsigned int *)r);
544 547
548 + (void) pthread_setname_np(pthread_self(), "discover");
549 +
545 550 for (;;) {
546 551 find_all_contexts("ldap",
547 552 __cache_get_cfghandle,
548 553 __cache_aggregate_params,
549 554 __cache_set_cfghandle);
550 555
551 556 if (current_admin.debug_level >= DBG_ALL) {
552 557 (void) logit(
553 558 "dynamic discovery: using refresh interval %d\n",
554 559 reqrefresh);
555 560 }
556 561
557 562 (void) sleep(reqrefresh);
558 563 }
559 564 }
560 565
561 566 #endif /* SLP */
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX