Print this page
5910 libnisdb won't build with modern GCC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libnisdb/yptol/shim.c
+++ new/usr/src/lib/libnisdb/yptol/shim.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.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
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 + * Copyright 2015 Gary Mills
22 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
24 25 */
25 26
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 27 /*
29 28 * DESCRIPTION: Contains the top level shim hook functions. These must have
30 29 * identical interfaces to the equivalent standard dbm calls.
31 30 *
32 31 * Unfortunately many of these will do a copy of a datum structure
33 32 * on return. This is a side effect of the original DBM function
34 33 * being written to pass structures rather than pointers.
35 34 *
36 35 * NOTE : There is a major bug/feature in dbm. A key obtained by
37 36 * dbm_nextkey() of dbm_firstkey() cannot be passed to dbm_store().
38 37 * When the store occurs dbm's internal memory get's reorganized
39 38 * and the static strings pointed to by the key are destroyed. The
40 39 * data is then stored in the wrong place. We attempt to get round
41 40 * this by dbm_firstkey() and dbm_nextkey() making a copy of the
42 41 * key data in malloced memory. This is freed when map_ctrl is
43 42 * freed.
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
44 43 */
45 44
46 45 #include <unistd.h>
47 46 #include <syslog.h>
48 47 #include <ndbm.h>
49 48 #include <strings.h>
50 49 #include "ypsym.h"
51 50 #include "ypdefs.h"
52 51 #include "shim.h"
53 52 #include "yptol.h"
53 +#include "stubs.h"
54 54 #include "../ldap_parse.h"
55 55 #include "../ldap_util.h"
56 56
57 57 /*
58 58 * Globals
59 59 */
60 60 bool_t yptol_mode = FALSE; /* Set if in N2L mode */
61 61 bool_t yptol_newlock = FALSE;
62 62 /*
63 63 * Set if in N2L mode and we want to use the new
64 64 * lock mapping mechanism
65 65 */
66 66 bool_t ypxfrd_flag = FALSE; /* Set if called from ypxfrd */
67 67 pid_t parent_pid; /* ID of calling parent process */
68 68
69 69
70 70 /*
71 71 * Decs
72 72 */
73 73 void check_old_map_date(map_ctrl *);
74 74
75 75 /*
76 76 * Constants
77 77 */
78 78 /* Number of times to try to update a map before giving up */
79 79 /* #define MAX_UPDATE_ATTEMPTS 3 */
80 80 #define MAX_UPDATE_ATTEMPTS 1
81 81
82 82 /*
83 83 * FUNCTION: shim_dbm_close();
84 84 *
85 85 * INPUTS: Identical to equivalent dbm call.
86 86 *
87 87 * OUTPUTS: Identical to equivalent dbm call.
88 88 *
89 89 */
90 90 void
91 91 shim_dbm_close(DBM *db)
92 92 {
93 93 map_ctrl *map;
94 94
95 95 /* Lock the map */
96 96 map = get_map_ctrl(db);
97 97 if (map == NULL)
98 98 return;
99 99
100 100 free_map_ctrl(map);
101 101 }
102 102
103 103 /*
104 104 * FUNCTION: shim_dbm_delete();
105 105 *
106 106 * DESCRIPTION: This function is currently unused but is present so that the
107 107 * set of shim_dbm_xxx() interfaces is complete if required in
108 108 * future.
109 109 *
110 110 * INPUTS: Identical to equivalent dbm call.
111 111 *
112 112 * OUTPUTS: Identical to equivalent dbm call.
113 113 *
114 114 */
115 115 int
116 116 shim_dbm_delete(DBM *db, datum key)
117 117 {
118 118 int ret;
119 119 map_ctrl *map;
120 120
121 121 /* Lock the map */
122 122 map = get_map_ctrl(db);
123 123 if (map == NULL)
124 124 return (FAILURE);
125 125 if (1 != lock_map_ctrl(map))
126 126 return (FAILURE);
127 127
128 128 if (yptol_mode) {
129 129 /* Delete from and ttl map. Not a huge disaster if it fails. */
130 130 dbm_delete(map->ttl, key);
131 131 }
132 132
133 133 ret = dbm_delete(map->entries, key);
134 134
135 135 unlock_map_ctrl(map);
136 136
137 137 return (ret);
138 138 }
139 139
140 140
141 141 /*
142 142 * FUNCTION: shim_dbm_fetch()
143 143 *
144 144 * DESCRIPTION: N2L function used to handle 'normal' dbm_fetch() operations.
145 145 *
146 146 * INPUTS: First two identical to equivalent dbm call.
147 147 *
148 148 * OUTPUTS: Identical to equivalent dbm call.
149 149 *
150 150 */
151 151 datum
152 152 shim_dbm_fetch(DBM *db, datum key)
153 153 {
154 154 datum ret = {0, NULL};
155 155 map_ctrl *map;
156 156
157 157 /* Lock the map */
158 158 map = get_map_ctrl(db);
159 159 if (map == NULL)
160 160 return (ret);
161 161 if (1 != lock_map_ctrl(map))
162 162 return (ret);
163 163
164 164 if (yptol_mode) {
165 165 if (SUCCESS == update_entry_if_required(map, &key)) {
166 166 /* Update thinks we should return something */
167 167 ret = dbm_fetch(map->entries, key);
168 168 }
169 169 } else {
170 170 /* Non yptol mode do a normal fetch */
171 171 ret = dbm_fetch(map->entries, key);
172 172 }
173 173
174 174 unlock_map_ctrl(map);
175 175
176 176 return (ret);
177 177 }
178 178
179 179 /*
180 180 * FUNCTION: shim_dbm_fetch_noupdate()
181 181 *
182 182 * DESCRIPTION: A special version of shim_dbm_fetch() that never checks TTLs
183 183 * or updates entries.
184 184 *
185 185 * INPUTS: Identical to equivalent dbm call.
186 186 *
187 187 * OUTPUTS: Identical to equivalent dbm call.
188 188 *
189 189 */
190 190 datum
191 191 shim_dbm_fetch_noupdate(DBM *db, datum key)
192 192 {
193 193 datum ret = {0, NULL};
194 194 map_ctrl *map;
195 195
196 196 /* Get the map control block */
197 197 map = get_map_ctrl(db);
198 198 if (map == NULL)
199 199 return (ret);
200 200
201 201 /* Not updating so no need to lock */
202 202 ret = dbm_fetch(map->entries, key);
203 203
204 204 return (ret);
205 205 }
206 206
207 207 /*
208 208 * FUNCTION: shim_dbm_firstkey()
209 209 *
210 210 * DESCRIPTION: Get firstkey in an enumeration. If the map is out of date then
211 211 * this is the time to scan it and see if any new entries have been
212 212 * created.
213 213 *
214 214 * INPUTS: Identical to equivalent dbm call.
215 215 *
216 216 * OUTPUTS: Identical to equivalent dbm call.
217 217 *
218 218 */
219 219 datum
220 220 shim_dbm_firstkey(DBM *db)
221 221 {
222 222 int count;
223 223 bool_t wait_flag;
224 224
225 225 datum ret = {0, NULL};
226 226 map_ctrl *map;
227 227
228 228 /* Lock the map */
229 229 map = get_map_ctrl(db);
230 230 if (map == NULL)
231 231 return (ret);
232 232 if (1 != lock_map_ctrl(map))
233 233 return (ret);
234 234
235 235 if (yptol_mode) {
236 236 /*
237 237 * Due to the limitations in the hashing algorithm ypxfrd
238 238 * may end up waiting on the wrong update. It must thus loop
239 239 * until the right map has been updated.
240 240 */
241 241 for (count = 0; has_map_expired(map) &&
242 242 (MAX_UPDATE_ATTEMPTS > count); count++) {
243 243 /*
244 244 * Ideally ypxfr should wait for the map update
245 245 * to complete i.e. pass ypxfrd_flag into
246 246 * update_map_if_required(). This cannot be done
247 247 * because if there is a large map update the client
248 248 * side, ypxfr, can time out while waiting.
249 249 */
250 250 wait_flag = FALSE;
251 251 update_map_if_required(map, wait_flag);
252 252
253 253 if (wait_flag) {
254 254 /*
255 255 * Because ypxfrd does weird things with DBMs
256 256 * internal structures it's a good idea to
257 257 * reopen here. (Code that uses the real DBM
258 258 * API appears not to need this.)
259 259 *
260 260 * This should not be necessary all we have
261 261 * done is 'mv' the new file over the old one.
262 262 * Open handles should get the old data but if
263 263 * these lines are removed the first ypxfrd
264 264 * read access fail with bad file handle.
265 265 *
266 266 * NOTE : If we don't wait, because of the
267 267 * ypxfr timeout problem, there is no point
268 268 * doing this.
269 269 */
270 270 dbm_close(map->entries);
271 271 dbm_close(map->ttl);
272 272 if (FAILURE == open_yptol_files(map)) {
273 273 logmsg(MSG_NOTIMECHECK, LOG_ERR,
274 274 "Could not reopen DBM files");
275 275 }
276 276 } else {
277 277 /* For daemons that don't wait just try once */
278 278 break;
279 279 }
280 280 }
281 281
282 282 if (MAX_UPDATE_ATTEMPTS < count)
283 283 logmsg(MSG_NOTIMECHECK, LOG_ERR,
284 284 "Cannot update map %s", map->map_name);
285 285 }
286 286
287 287 ret = dbm_firstkey(map->entries);
288 288
289 289 /* Move key data out of static memory. See NOTE in file header above */
290 290 if (yptol_mode) {
291 291 set_key_data(map, &ret);
292 292 }
293 293 unlock_map_ctrl(map);
294 294
295 295 return (ret);
296 296 }
297 297
298 298 /*
299 299 * FUNCTION: shim_dbm_nextkey()
300 300 *
301 301 * DESCRIPTION: Get next key in an enumeration. Since updating an entry would
302 302 * invalidate the enumeration we never do it.
303 303 *
304 304 * INPUTS: Identical to equivalent dbm call.
305 305 *
306 306 * OUTPUTS: Identical to equivalent dbm call.
307 307 *
308 308 */
309 309 datum
310 310 shim_dbm_nextkey(DBM *db)
311 311 {
312 312 datum ret;
313 313 map_ctrl *map;
314 314
315 315 /* Lock the map */
316 316 map = get_map_ctrl(db);
317 317 if (map == NULL)
318 318 return (ret);
319 319 if (1 != lock_map_ctrl(map))
320 320 return (ret);
321 321
322 322 ret = dbm_nextkey(map->entries);
323 323
324 324 /* Move key data out of static memory. See NOTE in file header above */
325 325 if (yptol_mode) {
326 326 set_key_data(map, &ret);
327 327 }
328 328
329 329 unlock_map_ctrl(map);
330 330
331 331 return (ret);
332 332 }
333 333
334 334 /*
335 335 * FUNCTION: shim_dbm_do_nextkey()
336 336 *
337 337 * DESCRIPTION: Get next key in an enumeration. Since updating an entry would
338 338 * invalidate the enumeration we never do it.
339 339 *
340 340 * NOTE : dbm_do_nextkey is not a documented or legal DBM API.
341 341 * Despite this the existing NIS code calls it. One gross hack
342 342 * deserves another so we have this extra shim function to handle
343 343 * the illegal call.
344 344 *
345 345 * INPUTS: Identical to equivalent dbm call.
346 346 *
347 347 * OUTPUTS: Identical to equivalent dbm call.
348 348 *
349 349 */
350 350 datum
351 351 shim_dbm_do_nextkey(DBM *db, datum inkey)
352 352 {
353 353 datum ret;
354 354 map_ctrl *map;
355 355
356 356 /* Lock the map */
357 357 map = get_map_ctrl(db);
358 358 if (map == NULL)
359 359 return (ret);
360 360 if (1 != lock_map_ctrl(map))
361 361 return (ret);
362 362
363 363 ret = dbm_do_nextkey(map->entries, inkey);
364 364
365 365 /* Move key data out of static memory. See NOTE in file header above */
366 366 if (yptol_mode) {
367 367 set_key_data(map, &ret);
368 368 }
369 369
370 370 unlock_map_ctrl(map);
371 371
372 372 return (ret);
373 373 }
374 374 /*
375 375 * FUNCTION: shim_dbm_open()
376 376 *
377 377 * INPUTS: Identical to equivalent dbm call.
378 378 *
379 379 * OUTPUTS: Identical to equivalent dbm call.
380 380 *
381 381 */
382 382 DBM *
383 383 shim_dbm_open(const char *file, int open_flags, mode_t file_mode)
384 384 {
385 385 map_ctrl *map;
386 386 suc_code ret = FAILURE;
387 387
388 388 /* Find or create map_ctrl for this map */
389 389 map = create_map_ctrl((char *)file);
390 390
391 391 if (map == NULL)
392 392 return (NULL);
393 393
394 394 /* Lock map */
395 395 if (1 != lock_map_ctrl(map))
396 396 return (NULL);
397 397
398 398 /* Remember flags and mode in case we have to reopen */
399 399 map->open_flags = open_flags;
400 400 map->open_mode = file_mode;
401 401
402 402 if (yptol_mode) {
403 403 ret = open_yptol_files(map);
404 404
405 405 /*
406 406 * This is a good place to check that the
407 407 * equivalent old style map file has not been
408 408 * updated.
409 409 */
410 410 if (SUCCESS == ret)
411 411 check_old_map_date(map);
412 412
413 413 } else {
414 414 /* Open entries map */
415 415 map->entries = dbm_open(map->map_path, map->open_flags,
416 416 map->open_mode);
417 417
418 418 if (NULL != map->entries)
419 419 ret = SUCCESS;
420 420 }
421 421
422 422 /* If we were not successful unravel what we have done so far */
423 423 if (ret != SUCCESS) {
424 424 unlock_map_ctrl(map);
425 425 free_map_ctrl(map);
426 426 return (NULL);
427 427 }
428 428
429 429 unlock_map_ctrl(map);
430 430
431 431 /* Return map_ctrl pointer as a DBM *. To the outside world it is */
432 432 /* opaque. */
433 433 return ((DBM *)map);
434 434 }
435 435
436 436 /*
437 437 * FUNCTION: shim_dbm_store()
438 438 *
439 439 * DESCRIPTION: Shim for dbm_store.
440 440 *
441 441 * In N2L mode if we are asked to store in DBM_INSERT mode
442 442 * then first an attempt is made to write to the DIT (in the same
443 443 * mode). If this is successful then the value is forced into DBM
444 444 * using DBM_REPLACE. This is because the DIT is authoritative.
445 445 * The success of failure of an 'insert' is determined by the
446 446 * presence or otherwise of an entry in the DIT not DBM.
447 447 *
448 448 * INPUTS: Identical to equivalent dbm call.
449 449 *
450 450 * OUTPUTS: Identical to equivalent dbm call.
451 451 *
452 452 */
453 453 int
454 454 shim_dbm_store(DBM *db, datum key, datum content, int store_mode)
455 455 {
456 456 int ret;
457 457 map_ctrl *map;
458 458
459 459 /* Get map name */
460 460 map = get_map_ctrl(db);
461 461 if (map == NULL)
462 462 return (FAILURE);
463 463
464 464 if (yptol_mode) {
465 465 /* Write to the DIT before doing anything else */
466 466 if (!write_to_dit(map->map_name, map->domain, key, content,
467 467 DBM_REPLACE == store_mode, FALSE))
468 468 return (FAILURE);
469 469 }
470 470
471 471 /* Lock the map */
472 472 if (1 != lock_map_ctrl(map))
473 473 return (FAILURE);
474 474
475 475 if (yptol_mode) {
476 476 if (!is_map_updating(map)) {
477 477 ret = dbm_store(map->entries, key, content,
478 478 DBM_REPLACE);
479 479
480 480 if (SUCCESS == ret)
481 481 /* Update TTL */
482 482 update_entry_ttl(map, &key, TTL_RAND);
483 483 }
484 484 } else {
485 485 ret = dbm_store(map->entries, key, content, store_mode);
486 486 }
487 487
488 488 unlock_map_ctrl(map);
489 489
490 490 return (ret);
491 491 }
492 492
493 493 /*
494 494 * FUNCTION : shim_exit()
495 495 *
496 496 * DESCRIPTION: Intercepts exit() calls made by N2L compatible NIS components.
497 497 * This is required because any call to the shim_dbm... series
498 498 * of functions may have started an update thread. If the process
499 499 * exits normally then this thread may be killed before it can
500 500 * complete its work. We thus wait here for the thread to complete.
501 501 *
502 502 * GIVEN : Same arg as exit()
503 503 *
504 504 * RETURNS : Never
505 505 */
506 506 void
507 507 shim_exit(int code)
508 508 {
509 509 thr_join(NULL, NULL, NULL);
510 510 exit(code);
511 511 }
512 512
513 513 /*
514 514 * FUNCTION : init_yptol_flag()
515 515 *
516 516 * DESCRIPTION: Initializes two flags these are similar but their function is
517 517 * subtly different.
518 518 *
519 519 * yp2ldap tells the mapping system if it is to work in NIS or
520 520 * NIS+ mode. For N2L this is always set to NIS mode.
521 521 *
522 522 * yptol tells the shim if it is to work in N2L or traditional
523 523 * NIS mode. For N2L this is turned on if the N2L mapping file
524 524 * is found to be present. In NIS+ mode it is meaningless.
525 525 */
526 526 void
527 527 init_yptol_flag()
528 528 {
529 529 /*
530 530 * yp2ldap is used to switch appropriate code in the
531 531 * common libnisdb library used by rpc.nisd and ypserv.
532 532 */
533 533 yp2ldap = 1;
534 534 yptol_mode = is_yptol_mode();
535 535 /*
536 536 * Use the new lock mapping mechanism
537 537 * if in N2L mode.
538 538 */
539 539 yptol_newlock = yptol_mode;
540 540 }
541 541
542 542 /*
543 543 * FUNCTION : set_yxfrd_flag()
544 544 */
545 545 void
546 546 set_ypxfrd_flag()
547 547 {
548 548 ypxfrd_flag = TRUE;
549 549 }
550 550
551 551 /*
552 552 * FUNCTION : check_old_map_date()
553 553 *
554 554 * DESCRIPTION: Checks that an old style map has not been updated. If it has
555 555 * then ypmake has probably erroneously been run and an error is
556 556 * logged.
557 557 *
558 558 * GIVEN : A map_ctrl containing details of the NEW STYLE map.
559 559 *
560 560 * RETURNS : Nothing
561 561 */
562 562 void
563 563 check_old_map_date(map_ctrl *map)
564 564 {
565 565 datum key;
566 566 datum value;
567 567 struct stat stats;
568 568 time_t old_time;
569 569
570 570 /* Get date of last update */
571 571 if (0 != stat(map->trad_map_path, &stats)) {
572 572 /*
573 573 * No problem. We have a new style map but no old style map
574 574 * this will occur if the original data came from native LDAP
575 575 * instead of NIS.
576 576 */
577 577 return;
578 578 }
579 579
580 580 /* Set up datum with key for recorded old map update time */
581 581 key.dsize = strlen(MAP_OLD_MAP_DATE_KEY);
582 582 key.dptr = MAP_OLD_MAP_DATE_KEY;
583 583 value = dbm_fetch(map->ttl, key);
584 584
585 585 if (NULL != value.dptr) {
586 586 /*
587 587 * Because dptr may not be int aligned need to build an int
588 588 * out of what it points to or will get a bus error.
589 589 */
590 590 bcopy(value.dptr, &old_time, sizeof (time_t));
591 591
592 592
593 593 /* Do the comparison */
594 594 if (stats.st_mtime <= old_time) {
595 595 /* All is well, has not been updated */
596 596 return;
597 597 }
598 598
599 599 /* If we get here the file has been updated */
600 600 logmsg(MSG_NOTIMECHECK, LOG_ERR,
601 601 "Caution. ypmake may have been run in N2L "
602 602 "mode. This will NOT initiate a NIS map push. In "
603 603 "this mode pushes should be initiated with yppush");
604 604 }
605 605
606 606 /*
607 607 * If we get here then either the file was updated or there was not
608 608 * a valid old map date (no problem, maybe this is the first time we
609 609 * checked). In either case the old map date entry must be update.
610 610 */
611 611 value.dptr = (char *)&(stats.st_mtime);
612 612 value.dsize = sizeof (time_t);
613 613 dbm_store(map->ttl, key, value, DBM_REPLACE);
614 614 }
615 615
616 616 /*
617 617 * FUNCTION : init_lock_system()
618 618 *
619 619 * DESCRIPTION: Initializes all the systems related to map locking. This must
620 620 * be called before any access to the shim functions.
621 621 *
622 622 * GIVEN : A flag indicating if we are being called from ypserv, which does
623 623 * not wait for map updates to complete, or other NIS components
624 624 * which do.
625 625 *
626 626 * RETURNS : TRUE = Everything worked
627 627 * FALSE = There were problems
628 628 */
629 629 bool_t
630 630 init_lock_system(bool_t ypxfrd)
631 631 {
632 632 /* Remember what called us */
633 633 if (ypxfrd)
634 634 set_ypxfrd_flag();
635 635
636 636 /*
637 637 * Remember PID of process which called us. This enables update threads
638 638 * created by YP children to be handled differently to those created
639 639 * by YP parents.
640 640 */
641 641 parent_pid = getpid();
642 642
643 643 /* Init map locks */
644 644 if (!init_lock_map()) {
645 645 logmsg(MSG_NOTIMECHECK, LOG_ERR,
646 646 "Failed to init process synchronization");
647 647 return (FALSE);
648 648 }
649 649
650 650 /* If we are in yptol mode set flag indicating the fact */
651 651 init_yptol_flag();
652 652
653 653 /*
654 654 * If boot random number system. For now go for reproducible
655 655 * random numbers.
656 656 */
657 657 srand48(0x12345678);
658 658
659 659 /*
660 660 * If not N2L mode then no error but do not bother initializing update
661 661 * flags.
662 662 */
663 663 if (yptol_mode) {
664 664 if (!init_update_lock_map()) {
665 665 logmsg(MSG_NOTIMECHECK, LOG_ERR,
666 666 "Failed to init update synchronization");
667 667 return (FALSE);
668 668 }
669 669 }
670 670
671 671 return (TRUE);
672 672 }
↓ open down ↓ |
609 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX