Print this page
7849 Disable auditing when building native svc.configd
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/configd/client.c
+++ new/usr/src/cmd/svc/configd/client.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 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 + * Copyright 2015 RackTop Systems.
24 25 */
25 26
26 27 /*
27 28 * This is the client layer for svc.configd. All direct protocol interactions
28 29 * are handled here.
29 30 *
30 31 * Essentially, the job of this layer is to turn the idempotent protocol
31 32 * into a series of non-idempotent calls into the object layer, while
32 33 * also handling the necessary locking.
33 34 */
34 35
35 36 #include <alloca.h>
36 37 #include <assert.h>
37 38 #include <bsm/adt_event.h>
38 39 #include <door.h>
39 40 #include <errno.h>
40 41 #include <libintl.h>
41 42 #include <limits.h>
42 43 #include <pthread.h>
43 44 #include <stdio.h>
44 45 #include <stdlib.h>
45 46 #include <string.h>
46 47 #include <syslog.h>
47 48 #include <ucred.h>
48 49 #include <unistd.h>
49 50
50 51 #include <libuutil.h>
51 52
52 53 #include "configd.h"
53 54 #include "repcache_protocol.h"
54 55
55 56 #define INVALID_CHANGEID (0)
56 57 #define INVALID_DOORID ((door_id_t)-1)
57 58 #define INVALID_RESULT ((rep_protocol_responseid_t)INT_MIN)
58 59
59 60 /*
60 61 * lint doesn't like constant assertions
61 62 */
62 63 #ifdef lint
63 64 #define assert_nolint(x) (void)0
64 65 #else
65 66 #define assert_nolint(x) assert(x)
66 67 #endif
67 68
68 69 /*
69 70 * Protects client linkage and the freelist
70 71 */
71 72 #define CLIENT_HASH_SIZE 64
72 73
73 74 #pragma align 64(client_hash)
74 75 static client_bucket_t client_hash[CLIENT_HASH_SIZE];
75 76
76 77 static uu_avl_pool_t *entity_pool;
77 78 static uu_avl_pool_t *iter_pool;
78 79 static uu_list_pool_t *client_pool;
79 80
80 81 #define CLIENT_HASH(id) (&client_hash[((id) & (CLIENT_HASH_SIZE - 1))])
81 82
82 83 uint_t request_log_size = 1024; /* tunable, before we start */
83 84
84 85 static pthread_mutex_t request_log_lock = PTHREAD_MUTEX_INITIALIZER;
85 86 static uint_t request_log_cur;
86 87 request_log_entry_t *request_log;
87 88
88 89 static uint32_t client_maxid;
89 90 static pthread_mutex_t client_lock; /* protects client_maxid */
90 91
91 92 static request_log_entry_t *
92 93 get_log(void)
93 94 {
94 95 thread_info_t *ti = thread_self();
95 96 return (&ti->ti_log);
96 97 }
97 98
98 99 void
99 100 log_enter(request_log_entry_t *rlp)
100 101 {
101 102 if (rlp->rl_start != 0 && request_log != NULL) {
102 103 request_log_entry_t *logrlp;
103 104
104 105 (void) pthread_mutex_lock(&request_log_lock);
105 106 assert(request_log_cur < request_log_size);
106 107 logrlp = &request_log[request_log_cur++];
107 108 if (request_log_cur == request_log_size)
108 109 request_log_cur = 0;
109 110 (void) memcpy(logrlp, rlp, sizeof (*rlp));
110 111 (void) pthread_mutex_unlock(&request_log_lock);
111 112 }
112 113 }
113 114
114 115 /*
115 116 * Note that the svc.configd dmod will join all of the per-thread log entries
116 117 * with the main log, so that even if the log is disabled, there is some
117 118 * information available.
118 119 */
119 120 static request_log_entry_t *
120 121 start_log(uint32_t clientid)
121 122 {
122 123 request_log_entry_t *rlp = get_log();
123 124
124 125 log_enter(rlp);
125 126
126 127 (void) memset(rlp, 0, sizeof (*rlp));
127 128 rlp->rl_start = gethrtime();
128 129 rlp->rl_tid = pthread_self();
129 130 rlp->rl_clientid = clientid;
130 131
131 132 return (rlp);
132 133 }
133 134
134 135 void
135 136 end_log(void)
136 137 {
137 138 request_log_entry_t *rlp = get_log();
138 139
139 140 rlp->rl_end = gethrtime();
140 141 }
141 142
142 143 static void
143 144 add_log_ptr(request_log_entry_t *rlp, enum rc_ptr_type type, uint32_t id,
144 145 void *ptr)
145 146 {
146 147 request_log_ptr_t *rpp;
147 148
148 149 if (rlp == NULL)
149 150 return;
150 151
151 152 if (rlp->rl_num_ptrs >= MAX_PTRS)
152 153 return;
153 154
154 155 rpp = &rlp->rl_ptrs[rlp->rl_num_ptrs++];
155 156 rpp->rlp_type = type;
156 157 rpp->rlp_id = id;
157 158 rpp->rlp_ptr = ptr;
158 159
159 160 /*
160 161 * For entities, it's useful to have the node pointer at the start
161 162 * of the request.
162 163 */
163 164 if (type == RC_PTR_TYPE_ENTITY && ptr != NULL)
164 165 rpp->rlp_data = ((repcache_entity_t *)ptr)->re_node.rnp_node;
165 166 }
166 167
167 168 int
168 169 client_is_privileged(void)
169 170 {
170 171 thread_info_t *ti = thread_self();
171 172
172 173 ucred_t *uc;
173 174
174 175 if (ti->ti_active_client != NULL &&
175 176 ti->ti_active_client->rc_all_auths)
176 177 return (1);
177 178
178 179 if ((uc = get_ucred()) == NULL)
179 180 return (0);
180 181
181 182 return (ucred_is_privileged(uc));
182 183 }
183 184
184 185 /*ARGSUSED*/
185 186 static int
186 187 client_compare(const void *lc_arg, const void *rc_arg, void *private)
187 188 {
188 189 uint32_t l_id = ((const repcache_client_t *)lc_arg)->rc_id;
189 190 uint32_t r_id = ((const repcache_client_t *)rc_arg)->rc_id;
190 191
191 192 if (l_id > r_id)
192 193 return (1);
193 194 if (l_id < r_id)
194 195 return (-1);
195 196 return (0);
196 197 }
197 198
198 199 /*ARGSUSED*/
199 200 static int
200 201 entity_compare(const void *lc_arg, const void *rc_arg, void *private)
201 202 {
202 203 uint32_t l_id = ((const repcache_entity_t *)lc_arg)->re_id;
203 204 uint32_t r_id = ((const repcache_entity_t *)rc_arg)->re_id;
204 205
205 206 if (l_id > r_id)
206 207 return (1);
207 208 if (l_id < r_id)
208 209 return (-1);
209 210 return (0);
210 211 }
211 212
212 213 /*ARGSUSED*/
213 214 static int
214 215 iter_compare(const void *lc_arg, const void *rc_arg, void *private)
215 216 {
216 217 uint32_t l_id = ((const repcache_iter_t *)lc_arg)->ri_id;
217 218 uint32_t r_id = ((const repcache_iter_t *)rc_arg)->ri_id;
218 219
219 220 if (l_id > r_id)
220 221 return (1);
221 222 if (l_id < r_id)
222 223 return (-1);
223 224 return (0);
224 225 }
225 226
226 227 static int
227 228 client_hash_init(void)
228 229 {
229 230 int x;
230 231
231 232 assert_nolint(offsetof(repcache_entity_t, re_id) == 0);
232 233 entity_pool = uu_avl_pool_create("repcache_entitys",
233 234 sizeof (repcache_entity_t), offsetof(repcache_entity_t, re_link),
234 235 entity_compare, UU_AVL_POOL_DEBUG);
235 236
236 237 assert_nolint(offsetof(repcache_iter_t, ri_id) == 0);
237 238 iter_pool = uu_avl_pool_create("repcache_iters",
238 239 sizeof (repcache_iter_t), offsetof(repcache_iter_t, ri_link),
239 240 iter_compare, UU_AVL_POOL_DEBUG);
240 241
241 242 assert_nolint(offsetof(repcache_client_t, rc_id) == 0);
242 243 client_pool = uu_list_pool_create("repcache_clients",
243 244 sizeof (repcache_client_t), offsetof(repcache_client_t, rc_link),
244 245 client_compare, UU_LIST_POOL_DEBUG);
245 246
246 247 if (entity_pool == NULL || iter_pool == NULL || client_pool == NULL)
247 248 return (0);
248 249
249 250 for (x = 0; x < CLIENT_HASH_SIZE; x++) {
250 251 uu_list_t *lp = uu_list_create(client_pool, &client_hash[x],
251 252 UU_LIST_SORTED);
252 253 if (lp == NULL)
253 254 return (0);
254 255
255 256 (void) pthread_mutex_init(&client_hash[x].cb_lock, NULL);
256 257 client_hash[x].cb_list = lp;
257 258 }
258 259
259 260 return (1);
260 261 }
261 262
262 263 static repcache_client_t *
263 264 client_alloc(void)
264 265 {
265 266 repcache_client_t *cp;
266 267 cp = uu_zalloc(sizeof (*cp));
267 268 if (cp == NULL)
268 269 return (NULL);
269 270
270 271 cp->rc_entities = uu_avl_create(entity_pool, cp, 0);
271 272 if (cp->rc_entities == NULL)
272 273 goto fail;
273 274
274 275 cp->rc_iters = uu_avl_create(iter_pool, cp, 0);
275 276 if (cp->rc_iters == NULL)
276 277 goto fail;
277 278
278 279 uu_list_node_init(cp, &cp->rc_link, client_pool);
279 280
280 281 cp->rc_doorfd = -1;
281 282 cp->rc_doorid = INVALID_DOORID;
282 283
283 284 (void) pthread_mutex_init(&cp->rc_lock, NULL);
284 285 (void) pthread_mutex_init(&cp->rc_annotate_lock, NULL);
285 286
286 287 rc_node_ptr_init(&cp->rc_notify_ptr);
287 288
288 289 return (cp);
289 290
290 291 fail:
291 292 if (cp->rc_iters != NULL)
292 293 uu_avl_destroy(cp->rc_iters);
293 294 if (cp->rc_entities != NULL)
294 295 uu_avl_destroy(cp->rc_entities);
295 296 uu_free(cp);
296 297 return (NULL);
297 298 }
298 299
299 300 static void
300 301 client_free(repcache_client_t *cp)
301 302 {
302 303 assert(cp->rc_insert_thr == 0);
303 304 assert(cp->rc_refcnt == 0);
304 305 assert(cp->rc_doorfd == -1);
305 306 assert(cp->rc_doorid == INVALID_DOORID);
306 307 assert(uu_avl_first(cp->rc_entities) == NULL);
307 308 assert(uu_avl_first(cp->rc_iters) == NULL);
308 309 uu_avl_destroy(cp->rc_entities);
309 310 uu_avl_destroy(cp->rc_iters);
310 311 uu_list_node_fini(cp, &cp->rc_link, client_pool);
311 312 (void) pthread_mutex_destroy(&cp->rc_lock);
312 313 (void) pthread_mutex_destroy(&cp->rc_annotate_lock);
313 314 rc_node_ptr_free_mem(&cp->rc_notify_ptr);
314 315 uu_free(cp);
315 316 }
316 317
317 318 static void
318 319 client_insert(repcache_client_t *cp)
319 320 {
320 321 client_bucket_t *bp = CLIENT_HASH(cp->rc_id);
321 322 uu_list_index_t idx;
322 323
323 324 assert(cp->rc_id > 0);
324 325
325 326 (void) pthread_mutex_lock(&bp->cb_lock);
326 327 /*
327 328 * We assume it does not already exist
328 329 */
329 330 (void) uu_list_find(bp->cb_list, cp, NULL, &idx);
330 331 uu_list_insert(bp->cb_list, cp, idx);
331 332
332 333 (void) pthread_mutex_unlock(&bp->cb_lock);
333 334 }
334 335
335 336 static repcache_client_t *
336 337 client_lookup(uint32_t id)
337 338 {
338 339 client_bucket_t *bp = CLIENT_HASH(id);
339 340 repcache_client_t *cp;
340 341
341 342 (void) pthread_mutex_lock(&bp->cb_lock);
342 343
343 344 cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
344 345
345 346 /*
346 347 * Bump the reference count
347 348 */
348 349 if (cp != NULL) {
349 350 (void) pthread_mutex_lock(&cp->rc_lock);
350 351 assert(!(cp->rc_flags & RC_CLIENT_DEAD));
351 352 cp->rc_refcnt++;
352 353 (void) pthread_mutex_unlock(&cp->rc_lock);
353 354 }
354 355 (void) pthread_mutex_unlock(&bp->cb_lock);
355 356
356 357 return (cp);
357 358 }
358 359
359 360 static void
360 361 client_release(repcache_client_t *cp)
361 362 {
362 363 (void) pthread_mutex_lock(&cp->rc_lock);
363 364 assert(cp->rc_refcnt > 0);
364 365 assert(cp->rc_insert_thr != pthread_self());
365 366
366 367 --cp->rc_refcnt;
367 368 (void) pthread_cond_broadcast(&cp->rc_cv);
368 369 (void) pthread_mutex_unlock(&cp->rc_lock);
369 370 }
370 371
371 372 /*
372 373 * We only allow one thread to be inserting at a time, to prevent
373 374 * insert/insert races.
374 375 */
375 376 static void
376 377 client_start_insert(repcache_client_t *cp)
377 378 {
378 379 (void) pthread_mutex_lock(&cp->rc_lock);
379 380 assert(cp->rc_refcnt > 0);
380 381
381 382 while (cp->rc_insert_thr != 0) {
382 383 assert(cp->rc_insert_thr != pthread_self());
383 384 (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
384 385 }
385 386 cp->rc_insert_thr = pthread_self();
386 387 (void) pthread_mutex_unlock(&cp->rc_lock);
387 388 }
388 389
389 390 static void
390 391 client_end_insert(repcache_client_t *cp)
391 392 {
392 393 (void) pthread_mutex_lock(&cp->rc_lock);
393 394 assert(cp->rc_insert_thr == pthread_self());
394 395 cp->rc_insert_thr = 0;
395 396 (void) pthread_cond_broadcast(&cp->rc_cv);
396 397 (void) pthread_mutex_unlock(&cp->rc_lock);
397 398 }
398 399
399 400 /*ARGSUSED*/
400 401 static repcache_entity_t *
401 402 entity_alloc(repcache_client_t *cp)
402 403 {
403 404 repcache_entity_t *ep = uu_zalloc(sizeof (repcache_entity_t));
404 405 if (ep != NULL) {
405 406 uu_avl_node_init(ep, &ep->re_link, entity_pool);
406 407 }
407 408 return (ep);
408 409 }
409 410
410 411 static void
411 412 entity_add(repcache_client_t *cp, repcache_entity_t *ep)
412 413 {
413 414 uu_avl_index_t idx;
414 415
415 416 (void) pthread_mutex_lock(&cp->rc_lock);
416 417 assert(cp->rc_insert_thr == pthread_self());
417 418
418 419 (void) uu_avl_find(cp->rc_entities, ep, NULL, &idx);
419 420 uu_avl_insert(cp->rc_entities, ep, idx);
420 421
421 422 (void) pthread_mutex_unlock(&cp->rc_lock);
422 423 }
423 424
424 425 static repcache_entity_t *
425 426 entity_find(repcache_client_t *cp, uint32_t id)
426 427 {
427 428 repcache_entity_t *ep;
428 429
429 430 (void) pthread_mutex_lock(&cp->rc_lock);
430 431 ep = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
431 432 if (ep != NULL) {
432 433 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, ep);
433 434 (void) pthread_mutex_lock(&ep->re_lock);
434 435 }
435 436 (void) pthread_mutex_unlock(&cp->rc_lock);
436 437
437 438 return (ep);
438 439 }
439 440
440 441 /*
441 442 * Fails with
442 443 * _DUPLICATE_ID - the ids are equal
443 444 * _UNKNOWN_ID - an id does not designate an active register
444 445 */
445 446 static int
446 447 entity_find2(repcache_client_t *cp, uint32_t id1, repcache_entity_t **out1,
447 448 uint32_t id2, repcache_entity_t **out2)
448 449 {
449 450 repcache_entity_t *e1, *e2;
450 451 request_log_entry_t *rlp;
451 452
452 453 if (id1 == id2)
453 454 return (REP_PROTOCOL_FAIL_DUPLICATE_ID);
454 455
455 456 (void) pthread_mutex_lock(&cp->rc_lock);
456 457 e1 = uu_avl_find(cp->rc_entities, &id1, NULL, NULL);
457 458 e2 = uu_avl_find(cp->rc_entities, &id2, NULL, NULL);
458 459 if (e1 == NULL || e2 == NULL) {
459 460 (void) pthread_mutex_unlock(&cp->rc_lock);
460 461 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
461 462 }
462 463
463 464 assert(e1 != e2);
464 465
465 466 /*
466 467 * locks are ordered by id number
467 468 */
468 469 if (id1 < id2) {
469 470 (void) pthread_mutex_lock(&e1->re_lock);
470 471 (void) pthread_mutex_lock(&e2->re_lock);
471 472 } else {
472 473 (void) pthread_mutex_lock(&e2->re_lock);
473 474 (void) pthread_mutex_lock(&e1->re_lock);
474 475 }
475 476 *out1 = e1;
476 477 *out2 = e2;
477 478
478 479 (void) pthread_mutex_unlock(&cp->rc_lock);
479 480
480 481 if ((rlp = get_log()) != NULL) {
481 482 add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id1, e1);
482 483 add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, id2, e2);
483 484 }
484 485
485 486 return (REP_PROTOCOL_SUCCESS);
486 487 }
487 488
488 489 static void
489 490 entity_release(repcache_entity_t *ep)
490 491 {
491 492 assert(ep->re_node.rnp_node == NULL ||
492 493 !MUTEX_HELD(&ep->re_node.rnp_node->rn_lock));
493 494 (void) pthread_mutex_unlock(&ep->re_lock);
494 495 }
495 496
496 497 static void
497 498 entity_destroy(repcache_entity_t *entity)
498 499 {
499 500 (void) pthread_mutex_lock(&entity->re_lock);
500 501 rc_node_clear(&entity->re_node, 0);
501 502 (void) pthread_mutex_unlock(&entity->re_lock);
502 503
503 504 uu_avl_node_fini(entity, &entity->re_link, entity_pool);
504 505 (void) pthread_mutex_destroy(&entity->re_lock);
505 506 rc_node_ptr_free_mem(&entity->re_node);
506 507 uu_free(entity);
507 508 }
508 509
509 510 static void
510 511 entity_remove(repcache_client_t *cp, uint32_t id)
511 512 {
512 513 repcache_entity_t *entity;
513 514
514 515 (void) pthread_mutex_lock(&cp->rc_lock);
515 516 entity = uu_avl_find(cp->rc_entities, &id, NULL, NULL);
516 517 if (entity != NULL) {
517 518 add_log_ptr(get_log(), RC_PTR_TYPE_ENTITY, id, entity);
518 519
519 520 uu_avl_remove(cp->rc_entities, entity);
520 521 }
521 522 (void) pthread_mutex_unlock(&cp->rc_lock);
522 523
523 524 if (entity != NULL)
524 525 entity_destroy(entity);
525 526 }
526 527
527 528 static void
528 529 entity_cleanup(repcache_client_t *cp)
529 530 {
530 531 repcache_entity_t *ep;
531 532 void *cookie = NULL;
532 533
533 534 (void) pthread_mutex_lock(&cp->rc_lock);
534 535 while ((ep = uu_avl_teardown(cp->rc_entities, &cookie)) != NULL) {
535 536 (void) pthread_mutex_unlock(&cp->rc_lock);
536 537 entity_destroy(ep);
537 538 (void) pthread_mutex_lock(&cp->rc_lock);
538 539 }
539 540 (void) pthread_mutex_unlock(&cp->rc_lock);
540 541 }
541 542
542 543 /*ARGSUSED*/
543 544 static repcache_iter_t *
544 545 iter_alloc(repcache_client_t *cp)
545 546 {
546 547 repcache_iter_t *iter;
547 548 iter = uu_zalloc(sizeof (repcache_iter_t));
548 549 if (iter != NULL)
549 550 uu_avl_node_init(iter, &iter->ri_link, iter_pool);
550 551 return (iter);
551 552 }
552 553
553 554 static void
554 555 iter_add(repcache_client_t *cp, repcache_iter_t *iter)
555 556 {
556 557 uu_list_index_t idx;
557 558
558 559 (void) pthread_mutex_lock(&cp->rc_lock);
559 560 assert(cp->rc_insert_thr == pthread_self());
560 561
561 562 (void) uu_avl_find(cp->rc_iters, iter, NULL, &idx);
562 563 uu_avl_insert(cp->rc_iters, iter, idx);
563 564
564 565 (void) pthread_mutex_unlock(&cp->rc_lock);
565 566 }
566 567
567 568 static repcache_iter_t *
568 569 iter_find(repcache_client_t *cp, uint32_t id)
569 570 {
570 571 repcache_iter_t *iter;
571 572
572 573 (void) pthread_mutex_lock(&cp->rc_lock);
573 574
574 575 iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
575 576 if (iter != NULL) {
576 577 add_log_ptr(get_log(), RC_PTR_TYPE_ITER, id, iter);
577 578 (void) pthread_mutex_lock(&iter->ri_lock);
578 579 }
579 580 (void) pthread_mutex_unlock(&cp->rc_lock);
580 581
581 582 return (iter);
582 583 }
583 584
584 585 /*
585 586 * Fails with
586 587 * _UNKNOWN_ID - iter_id or entity_id does not designate an active register
587 588 */
588 589 static int
589 590 iter_find_w_entity(repcache_client_t *cp, uint32_t iter_id,
590 591 repcache_iter_t **iterp, uint32_t entity_id, repcache_entity_t **epp)
591 592 {
592 593 repcache_iter_t *iter;
593 594 repcache_entity_t *ep;
594 595 request_log_entry_t *rlp;
595 596
596 597 (void) pthread_mutex_lock(&cp->rc_lock);
597 598 iter = uu_avl_find(cp->rc_iters, &iter_id, NULL, NULL);
598 599 ep = uu_avl_find(cp->rc_entities, &entity_id, NULL, NULL);
599 600
600 601 assert(iter == NULL || !MUTEX_HELD(&iter->ri_lock));
601 602 assert(ep == NULL || !MUTEX_HELD(&ep->re_lock));
602 603
603 604 if (iter == NULL || ep == NULL) {
604 605 (void) pthread_mutex_unlock(&cp->rc_lock);
605 606 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
606 607 }
607 608
608 609 (void) pthread_mutex_lock(&iter->ri_lock);
609 610 (void) pthread_mutex_lock(&ep->re_lock);
610 611
611 612 (void) pthread_mutex_unlock(&cp->rc_lock);
612 613
613 614 *iterp = iter;
614 615 *epp = ep;
615 616
616 617 if ((rlp = get_log()) != NULL) {
617 618 add_log_ptr(rlp, RC_PTR_TYPE_ENTITY, entity_id, ep);
618 619 add_log_ptr(rlp, RC_PTR_TYPE_ITER, iter_id, iter);
619 620 }
620 621
621 622 return (REP_PROTOCOL_SUCCESS);
622 623 }
623 624
624 625 static void
625 626 iter_release(repcache_iter_t *iter)
626 627 {
627 628 (void) pthread_mutex_unlock(&iter->ri_lock);
628 629 }
629 630
630 631 static void
631 632 iter_destroy(repcache_iter_t *iter)
632 633 {
633 634 (void) pthread_mutex_lock(&iter->ri_lock);
634 635 rc_iter_destroy(&iter->ri_iter);
635 636 (void) pthread_mutex_unlock(&iter->ri_lock);
636 637
637 638 uu_avl_node_fini(iter, &iter->ri_link, iter_pool);
638 639 (void) pthread_mutex_destroy(&iter->ri_lock);
639 640 uu_free(iter);
640 641 }
641 642
642 643 static void
643 644 iter_remove(repcache_client_t *cp, uint32_t id)
644 645 {
645 646 repcache_iter_t *iter;
646 647
647 648 (void) pthread_mutex_lock(&cp->rc_lock);
648 649 iter = uu_avl_find(cp->rc_iters, &id, NULL, NULL);
649 650 if (iter != NULL)
650 651 uu_avl_remove(cp->rc_iters, iter);
651 652 (void) pthread_mutex_unlock(&cp->rc_lock);
652 653
653 654 if (iter != NULL)
654 655 iter_destroy(iter);
655 656 }
656 657
657 658 static void
658 659 iter_cleanup(repcache_client_t *cp)
659 660 {
660 661 repcache_iter_t *iter;
661 662 void *cookie = NULL;
662 663
663 664 (void) pthread_mutex_lock(&cp->rc_lock);
664 665 while ((iter = uu_avl_teardown(cp->rc_iters, &cookie)) != NULL) {
665 666 (void) pthread_mutex_unlock(&cp->rc_lock);
666 667 iter_destroy(iter);
667 668 (void) pthread_mutex_lock(&cp->rc_lock);
668 669 }
669 670 (void) pthread_mutex_unlock(&cp->rc_lock);
670 671 }
671 672
672 673 /*
673 674 * Ensure that the passed client id is no longer usable, wait for any
674 675 * outstanding invocations to complete, then destroy the client
675 676 * structure.
676 677 */
677 678 static void
678 679 client_destroy(uint32_t id)
679 680 {
680 681 client_bucket_t *bp = CLIENT_HASH(id);
681 682 repcache_client_t *cp;
682 683
683 684 (void) pthread_mutex_lock(&bp->cb_lock);
684 685
685 686 cp = uu_list_find(bp->cb_list, &id, NULL, NULL);
686 687
687 688 if (cp == NULL) {
688 689 (void) pthread_mutex_unlock(&bp->cb_lock);
689 690 return;
690 691 }
691 692
692 693 uu_list_remove(bp->cb_list, cp);
693 694
694 695 (void) pthread_mutex_unlock(&bp->cb_lock);
695 696
696 697 /* kick the waiters out */
697 698 rc_notify_info_fini(&cp->rc_notify_info);
698 699
699 700 (void) pthread_mutex_lock(&cp->rc_lock);
700 701 assert(!(cp->rc_flags & RC_CLIENT_DEAD));
701 702 cp->rc_flags |= RC_CLIENT_DEAD;
702 703
703 704 if (cp->rc_doorfd != -1) {
704 705 if (door_revoke(cp->rc_doorfd) < 0)
705 706 perror("door_revoke");
706 707 cp->rc_doorfd = -1;
707 708 cp->rc_doorid = INVALID_DOORID;
708 709 }
709 710
710 711 while (cp->rc_refcnt > 0)
711 712 (void) pthread_cond_wait(&cp->rc_cv, &cp->rc_lock);
712 713
713 714 assert(cp->rc_insert_thr == 0 && cp->rc_notify_thr == 0);
714 715 (void) pthread_mutex_unlock(&cp->rc_lock);
715 716
716 717 /*
717 718 * destroy outstanding objects
718 719 */
719 720 entity_cleanup(cp);
720 721 iter_cleanup(cp);
721 722
722 723 /*
723 724 * clean up notifications
724 725 */
725 726 rc_pg_notify_fini(&cp->rc_pg_notify);
726 727
727 728 /*
↓ open down ↓ |
694 lines elided |
↑ open up ↑ |
728 729 * clean up annotations
729 730 */
730 731 if (cp->rc_operation != NULL)
731 732 free((void *)cp->rc_operation);
732 733 if (cp->rc_file != NULL)
733 734 free((void *)cp->rc_file);
734 735
735 736 /*
736 737 * End audit session.
737 738 */
739 +#ifndef NATIVE_BUILD
738 740 (void) adt_end_session(cp->rc_adt_session);
741 +#endif
739 742
740 743 client_free(cp);
741 744 }
742 745
743 746 /*
744 747 * Fails with
745 748 * _TYPE_MISMATCH - the entity is already set up with a different type
746 749 * _NO_RESOURCES - out of memory
747 750 */
748 751 static int
749 752 entity_setup(repcache_client_t *cp, struct rep_protocol_entity_setup *rpr)
750 753 {
751 754 repcache_entity_t *ep;
752 755 uint32_t type;
753 756
754 757 client_start_insert(cp);
755 758
756 759 if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
757 760 type = ep->re_type;
758 761 entity_release(ep);
759 762
760 763 client_end_insert(cp);
761 764
762 765 if (type != rpr->rpr_entitytype)
763 766 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH);
764 767 return (REP_PROTOCOL_SUCCESS);
765 768 }
766 769
767 770 switch (type = rpr->rpr_entitytype) {
768 771 case REP_PROTOCOL_ENTITY_SCOPE:
769 772 case REP_PROTOCOL_ENTITY_SERVICE:
770 773 case REP_PROTOCOL_ENTITY_INSTANCE:
771 774 case REP_PROTOCOL_ENTITY_SNAPSHOT:
772 775 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
773 776 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
774 777 case REP_PROTOCOL_ENTITY_PROPERTY:
775 778 break;
776 779 default:
777 780 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
778 781 }
779 782
780 783 ep = entity_alloc(cp);
781 784 if (ep == NULL) {
782 785 client_end_insert(cp);
783 786 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
784 787 }
785 788
786 789 ep->re_id = rpr->rpr_entityid;
787 790 ep->re_changeid = INVALID_CHANGEID;
788 791
789 792 ep->re_type = type;
790 793 rc_node_ptr_init(&ep->re_node);
791 794
792 795 entity_add(cp, ep);
793 796 client_end_insert(cp);
794 797 return (REP_PROTOCOL_SUCCESS);
795 798 }
796 799
797 800 /*ARGSUSED*/
798 801 static void
799 802 entity_name(repcache_client_t *cp, const void *in, size_t insz, void *out_arg,
800 803 size_t *outsz, void *arg)
801 804 {
802 805 const struct rep_protocol_entity_name *rpr = in;
803 806 struct rep_protocol_name_response *out = out_arg;
804 807 repcache_entity_t *ep;
805 808 size_t sz = sizeof (out->rpr_name);
806 809
807 810 assert(*outsz == sizeof (*out));
808 811
809 812 ep = entity_find(cp, rpr->rpr_entityid);
810 813
811 814 if (ep == NULL) {
812 815 out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
813 816 *outsz = sizeof (out->rpr_response);
814 817 return;
815 818 }
816 819 out->rpr_response = rc_node_name(&ep->re_node, out->rpr_name,
817 820 sz, rpr->rpr_answertype, &sz);
818 821 entity_release(ep);
819 822
820 823 /*
821 824 * If we fail, we only return the response code.
822 825 * If we succeed, we don't return anything after the '\0' in rpr_name.
823 826 */
824 827 if (out->rpr_response != REP_PROTOCOL_SUCCESS)
825 828 *outsz = sizeof (out->rpr_response);
826 829 else
827 830 *outsz = offsetof(struct rep_protocol_name_response,
828 831 rpr_name[sz + 1]);
829 832 }
830 833
831 834 /*ARGSUSED*/
832 835 static void
833 836 entity_parent_type(repcache_client_t *cp, const void *in, size_t insz,
834 837 void *out_arg, size_t *outsz, void *arg)
835 838 {
836 839 const struct rep_protocol_entity_name *rpr = in;
837 840 struct rep_protocol_integer_response *out = out_arg;
838 841 repcache_entity_t *ep;
839 842
840 843 assert(*outsz == sizeof (*out));
841 844
842 845 ep = entity_find(cp, rpr->rpr_entityid);
843 846
844 847 if (ep == NULL) {
845 848 out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
846 849 *outsz = sizeof (out->rpr_response);
847 850 return;
848 851 }
849 852
850 853 out->rpr_response = rc_node_parent_type(&ep->re_node, &out->rpr_value);
851 854 entity_release(ep);
852 855
853 856 if (out->rpr_response != REP_PROTOCOL_SUCCESS)
854 857 *outsz = sizeof (out->rpr_response);
855 858 }
856 859
857 860 /*
858 861 * Fails with
859 862 * _DUPLICATE_ID - the ids are equal
860 863 * _UNKNOWN_ID - an id does not designate an active register
861 864 * _INVALID_TYPE - type is invalid
862 865 * _TYPE_MISMATCH - np doesn't carry children of type type
863 866 * _DELETED - np has been deleted
864 867 * _NOT_FOUND - no child with that name/type combo found
865 868 * _NO_RESOURCES
866 869 * _BACKEND_ACCESS
867 870 */
868 871 static int
869 872 entity_get_child(repcache_client_t *cp,
870 873 struct rep_protocol_entity_get_child *rpr)
871 874 {
872 875 repcache_entity_t *parent, *child;
873 876 int result;
874 877
875 878 uint32_t parentid = rpr->rpr_entityid;
876 879 uint32_t childid = rpr->rpr_childid;
877 880
878 881 result = entity_find2(cp, childid, &child, parentid, &parent);
879 882 if (result != REP_PROTOCOL_SUCCESS)
880 883 return (result);
881 884
882 885 rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
883 886
884 887 result = rc_node_get_child(&parent->re_node, rpr->rpr_name,
885 888 child->re_type, &child->re_node);
886 889
887 890 entity_release(child);
888 891 entity_release(parent);
889 892
890 893 return (result);
891 894 }
892 895
893 896 /*
894 897 * Returns _FAIL_DUPLICATE_ID, _FAIL_UNKNOWN_ID, _FAIL_NOT_SET, _FAIL_DELETED,
895 898 * _FAIL_TYPE_MISMATCH, _FAIL_NOT_FOUND (scope has no parent), or _SUCCESS.
896 899 * Fails with
897 900 * _DUPLICATE_ID - the ids are equal
898 901 * _UNKNOWN_ID - an id does not designate an active register
899 902 * _NOT_SET - child is not set
900 903 * _DELETED - child has been deleted
901 904 * _TYPE_MISMATCH - child's parent does not match that of the parent register
902 905 * _NOT_FOUND - child has no parent (and is a scope)
903 906 */
904 907 static int
905 908 entity_get_parent(repcache_client_t *cp, struct rep_protocol_entity_parent *rpr)
906 909 {
907 910 repcache_entity_t *child, *parent;
908 911 int result;
909 912
910 913 uint32_t childid = rpr->rpr_entityid;
911 914 uint32_t outid = rpr->rpr_outid;
912 915
913 916 result = entity_find2(cp, childid, &child, outid, &parent);
914 917 if (result != REP_PROTOCOL_SUCCESS)
915 918 return (result);
916 919
917 920 result = rc_node_get_parent(&child->re_node, parent->re_type,
918 921 &parent->re_node);
919 922
920 923 entity_release(child);
921 924 entity_release(parent);
922 925
923 926 return (result);
924 927 }
925 928
926 929 static int
927 930 entity_get(repcache_client_t *cp, struct rep_protocol_entity_get *rpr)
928 931 {
929 932 repcache_entity_t *ep;
930 933 int result;
931 934
932 935 ep = entity_find(cp, rpr->rpr_entityid);
933 936
934 937 if (ep == NULL)
935 938 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
936 939
937 940 switch (rpr->rpr_object) {
938 941 case RP_ENTITY_GET_INVALIDATE:
939 942 rc_node_clear(&ep->re_node, 0);
940 943 result = REP_PROTOCOL_SUCCESS;
941 944 break;
942 945 case RP_ENTITY_GET_MOST_LOCAL_SCOPE:
943 946 result = rc_local_scope(ep->re_type, &ep->re_node);
944 947 break;
945 948 default:
946 949 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
947 950 break;
948 951 }
949 952
950 953 entity_release(ep);
951 954
952 955 return (result);
953 956 }
954 957
955 958 static int
956 959 entity_update(repcache_client_t *cp, struct rep_protocol_entity_update *rpr)
957 960 {
958 961 repcache_entity_t *ep;
959 962 int result;
960 963
961 964 if (rpr->rpr_changeid == INVALID_CHANGEID)
962 965 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
963 966
964 967 ep = entity_find(cp, rpr->rpr_entityid);
965 968
966 969 if (ep == NULL)
967 970 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
968 971
969 972 if (ep->re_changeid == rpr->rpr_changeid) {
970 973 result = REP_PROTOCOL_DONE;
971 974 } else {
972 975 result = rc_node_update(&ep->re_node);
973 976 if (result == REP_PROTOCOL_DONE)
974 977 ep->re_changeid = rpr->rpr_changeid;
975 978 }
976 979
977 980 entity_release(ep);
978 981
979 982 return (result);
980 983 }
981 984
982 985 static int
983 986 entity_reset(repcache_client_t *cp, struct rep_protocol_entity_reset *rpr)
984 987 {
985 988 repcache_entity_t *ep;
986 989
987 990 ep = entity_find(cp, rpr->rpr_entityid);
988 991 if (ep == NULL)
989 992 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
990 993
991 994 rc_node_clear(&ep->re_node, 0);
992 995 ep->re_txstate = REPCACHE_TX_INIT;
993 996
994 997 entity_release(ep);
995 998 return (REP_PROTOCOL_SUCCESS);
996 999 }
997 1000
998 1001 /*
999 1002 * Fails with
1000 1003 * _BAD_REQUEST - request has invalid changeid
1001 1004 * rpr_name is invalid
1002 1005 * cannot create children for parent's type of node
1003 1006 * _DUPLICATE_ID - request has duplicate ids
1004 1007 * _UNKNOWN_ID - request has unknown id
1005 1008 * _DELETED - parent has been deleted
1006 1009 * _NOT_SET - parent is reset
1007 1010 * _NOT_APPLICABLE - rpr_childtype is _PROPERTYGRP
1008 1011 * _INVALID_TYPE - parent is corrupt or rpr_childtype is invalid
1009 1012 * _TYPE_MISMATCH - parent cannot have children of type rpr_childtype
1010 1013 * _NO_RESOURCES
1011 1014 * _PERMISSION_DENIED
1012 1015 * _BACKEND_ACCESS
1013 1016 * _BACKEND_READONLY
1014 1017 * _EXISTS - child already exists
1015 1018 */
1016 1019 static int
1017 1020 entity_create_child(repcache_client_t *cp,
1018 1021 struct rep_protocol_entity_create_child *rpr)
1019 1022 {
1020 1023 repcache_entity_t *parent;
1021 1024 repcache_entity_t *child;
1022 1025
1023 1026 uint32_t parentid = rpr->rpr_entityid;
1024 1027 uint32_t childid = rpr->rpr_childid;
1025 1028
1026 1029 int result;
1027 1030
1028 1031 if (rpr->rpr_changeid == INVALID_CHANGEID)
1029 1032 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1030 1033
1031 1034 result = entity_find2(cp, parentid, &parent, childid, &child);
1032 1035 if (result != REP_PROTOCOL_SUCCESS)
1033 1036 return (result);
1034 1037
1035 1038 rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1036 1039
1037 1040 if (child->re_changeid == rpr->rpr_changeid) {
1038 1041 result = REP_PROTOCOL_SUCCESS;
1039 1042 } else {
1040 1043 result = rc_node_create_child(&parent->re_node,
1041 1044 rpr->rpr_childtype, rpr->rpr_name, &child->re_node);
1042 1045 if (result == REP_PROTOCOL_SUCCESS)
1043 1046 child->re_changeid = rpr->rpr_changeid;
1044 1047 }
1045 1048
1046 1049 entity_release(parent);
1047 1050 entity_release(child);
1048 1051
1049 1052 return (result);
1050 1053 }
1051 1054
1052 1055 static int
1053 1056 entity_create_pg(repcache_client_t *cp,
1054 1057 struct rep_protocol_entity_create_pg *rpr)
1055 1058 {
1056 1059 repcache_entity_t *parent;
1057 1060 repcache_entity_t *child;
1058 1061
1059 1062 uint32_t parentid = rpr->rpr_entityid;
1060 1063 uint32_t childid = rpr->rpr_childid;
1061 1064
1062 1065 int result;
1063 1066
1064 1067 if (rpr->rpr_changeid == INVALID_CHANGEID)
1065 1068 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1066 1069
1067 1070 result = entity_find2(cp, parentid, &parent, childid, &child);
1068 1071 if (result != REP_PROTOCOL_SUCCESS)
1069 1072 return (result);
1070 1073
1071 1074 rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1072 1075 rpr->rpr_type[sizeof (rpr->rpr_type) - 1] = 0;
1073 1076
1074 1077 if (child->re_changeid == rpr->rpr_changeid) {
1075 1078 result = REP_PROTOCOL_SUCCESS;
1076 1079 } else {
1077 1080 result = rc_node_create_child_pg(&parent->re_node,
1078 1081 child->re_type, rpr->rpr_name, rpr->rpr_type,
1079 1082 rpr->rpr_flags, &child->re_node);
1080 1083 if (result == REP_PROTOCOL_SUCCESS)
1081 1084 child->re_changeid = rpr->rpr_changeid;
1082 1085 }
1083 1086
1084 1087 entity_release(parent);
1085 1088 entity_release(child);
1086 1089
1087 1090 return (result);
1088 1091 }
1089 1092
1090 1093 static int
1091 1094 entity_delete(repcache_client_t *cp,
1092 1095 struct rep_protocol_entity_delete *rpr)
1093 1096 {
1094 1097 repcache_entity_t *entity;
1095 1098
1096 1099 uint32_t entityid = rpr->rpr_entityid;
1097 1100
1098 1101 int result;
1099 1102
1100 1103 if (rpr->rpr_changeid == INVALID_CHANGEID)
1101 1104 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1102 1105
1103 1106 entity = entity_find(cp, entityid);
1104 1107
1105 1108 if (entity == NULL)
1106 1109 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1107 1110
1108 1111 if (entity->re_changeid == rpr->rpr_changeid) {
1109 1112 result = REP_PROTOCOL_SUCCESS;
1110 1113 } else {
1111 1114 result = rc_node_delete(&entity->re_node);
1112 1115 if (result == REP_PROTOCOL_SUCCESS)
1113 1116 entity->re_changeid = rpr->rpr_changeid;
1114 1117 }
1115 1118
1116 1119 entity_release(entity);
1117 1120
1118 1121 return (result);
1119 1122 }
1120 1123
1121 1124 static rep_protocol_responseid_t
1122 1125 entity_teardown(repcache_client_t *cp, struct rep_protocol_entity_teardown *rpr)
1123 1126 {
1124 1127 entity_remove(cp, rpr->rpr_entityid);
1125 1128
1126 1129 return (REP_PROTOCOL_SUCCESS);
1127 1130 }
1128 1131
1129 1132 /*
1130 1133 * Fails with
1131 1134 * _MISORDERED - the iterator exists and is not reset
1132 1135 * _NO_RESOURCES - out of memory
1133 1136 */
1134 1137 static int
1135 1138 iter_setup(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1136 1139 {
1137 1140 repcache_iter_t *iter;
1138 1141 uint32_t sequence;
1139 1142
1140 1143 client_start_insert(cp);
1141 1144 /*
1142 1145 * If the iter already exists, and hasn't been read from,
1143 1146 * we assume the previous call succeeded.
1144 1147 */
1145 1148 if ((iter = iter_find(cp, rpr->rpr_iterid)) != NULL) {
1146 1149 sequence = iter->ri_sequence;
1147 1150 iter_release(iter);
1148 1151
1149 1152 client_end_insert(cp);
1150 1153
1151 1154 if (sequence != 0)
1152 1155 return (REP_PROTOCOL_FAIL_MISORDERED);
1153 1156 return (REP_PROTOCOL_SUCCESS);
1154 1157 }
1155 1158
1156 1159 iter = iter_alloc(cp);
1157 1160 if (iter == NULL) {
1158 1161 client_end_insert(cp);
1159 1162 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1160 1163 }
1161 1164
1162 1165 iter->ri_id = rpr->rpr_iterid;
1163 1166 iter->ri_type = REP_PROTOCOL_TYPE_INVALID;
1164 1167 iter->ri_sequence = 0;
1165 1168 iter_add(cp, iter);
1166 1169
1167 1170 client_end_insert(cp);
1168 1171 return (REP_PROTOCOL_SUCCESS);
1169 1172 }
1170 1173
1171 1174 /*
1172 1175 * Fails with
1173 1176 * _UNKNOWN_ID
1174 1177 * _MISORDERED - iterator has already been started
1175 1178 * _NOT_SET
1176 1179 * _DELETED
1177 1180 * _TYPE_MISMATCH - entity cannot have type children
1178 1181 * _BAD_REQUEST - rpr_flags is invalid
1179 1182 * rpr_pattern is invalid
1180 1183 * _NO_RESOURCES
1181 1184 * _INVALID_TYPE
1182 1185 * _BACKEND_ACCESS
1183 1186 */
1184 1187 static int
1185 1188 iter_start(repcache_client_t *cp, struct rep_protocol_iter_start *rpr)
1186 1189 {
1187 1190 int result;
1188 1191 repcache_iter_t *iter;
1189 1192 repcache_entity_t *ep;
1190 1193
1191 1194 result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
1192 1195 rpr->rpr_entity, &ep);
1193 1196
1194 1197 if (result != REP_PROTOCOL_SUCCESS)
1195 1198 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1196 1199
1197 1200 if (iter->ri_sequence > 1) {
1198 1201 result = REP_PROTOCOL_FAIL_MISORDERED;
1199 1202 goto end;
1200 1203 }
1201 1204
1202 1205 if (iter->ri_sequence == 1) {
1203 1206 result = REP_PROTOCOL_SUCCESS;
1204 1207 goto end;
1205 1208 }
1206 1209
1207 1210 rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
1208 1211
1209 1212 result = rc_node_setup_iter(&ep->re_node, &iter->ri_iter,
1210 1213 rpr->rpr_itertype, rpr->rpr_flags, rpr->rpr_pattern);
1211 1214
1212 1215 if (result == REP_PROTOCOL_SUCCESS)
1213 1216 iter->ri_sequence++;
1214 1217
1215 1218 end:
1216 1219 iter_release(iter);
1217 1220 entity_release(ep);
1218 1221 return (result);
1219 1222 }
1220 1223
1221 1224 /*
1222 1225 * Returns
1223 1226 * _UNKNOWN_ID
1224 1227 * _NOT_SET - iter has not been started
1225 1228 * _MISORDERED
1226 1229 * _BAD_REQUEST - iter walks values
1227 1230 * _TYPE_MISMATCH - iter does not walk type entities
1228 1231 * _DELETED - parent was deleted
1229 1232 * _NO_RESOURCES
1230 1233 * _INVALID_TYPE - type is invalid
1231 1234 * _DONE
1232 1235 * _SUCCESS
1233 1236 *
1234 1237 * For composed property group iterators, can also return
1235 1238 * _TYPE_MISMATCH - parent cannot have type children
1236 1239 * _BACKEND_ACCESS
1237 1240 */
1238 1241 static rep_protocol_responseid_t
1239 1242 iter_read(repcache_client_t *cp, struct rep_protocol_iter_read *rpr)
1240 1243 {
1241 1244 rep_protocol_responseid_t result;
1242 1245 repcache_iter_t *iter;
1243 1246 repcache_entity_t *ep;
1244 1247 uint32_t sequence;
1245 1248
1246 1249 result = iter_find_w_entity(cp, rpr->rpr_iterid, &iter,
1247 1250 rpr->rpr_entityid, &ep);
1248 1251
1249 1252 if (result != REP_PROTOCOL_SUCCESS)
1250 1253 return (result);
1251 1254
1252 1255 sequence = rpr->rpr_sequence;
1253 1256
1254 1257 if (iter->ri_sequence == 0) {
1255 1258 iter_release(iter);
1256 1259 entity_release(ep);
1257 1260 return (REP_PROTOCOL_FAIL_NOT_SET);
1258 1261 }
1259 1262
1260 1263 if (sequence == 1) {
1261 1264 iter_release(iter);
1262 1265 entity_release(ep);
1263 1266 return (REP_PROTOCOL_FAIL_MISORDERED);
1264 1267 }
1265 1268
1266 1269 if (sequence == iter->ri_sequence) {
1267 1270 iter_release(iter);
1268 1271 entity_release(ep);
1269 1272 return (REP_PROTOCOL_SUCCESS);
1270 1273 }
1271 1274
1272 1275 if (sequence == iter->ri_sequence + 1) {
1273 1276 result = rc_iter_next(iter->ri_iter, &ep->re_node,
1274 1277 ep->re_type);
1275 1278
1276 1279 if (result == REP_PROTOCOL_SUCCESS)
1277 1280 iter->ri_sequence++;
1278 1281
1279 1282 iter_release(iter);
1280 1283 entity_release(ep);
1281 1284
1282 1285 return (result);
1283 1286 }
1284 1287
1285 1288 iter_release(iter);
1286 1289 entity_release(ep);
1287 1290 return (REP_PROTOCOL_FAIL_MISORDERED);
1288 1291 }
1289 1292
1290 1293 /*ARGSUSED*/
1291 1294 static void
1292 1295 iter_read_value(repcache_client_t *cp, const void *in, size_t insz,
1293 1296 void *out_arg, size_t *outsz, void *arg)
1294 1297 {
1295 1298 const struct rep_protocol_iter_read_value *rpr = in;
1296 1299 struct rep_protocol_value_response *out = out_arg;
1297 1300 rep_protocol_responseid_t result;
1298 1301
1299 1302 repcache_iter_t *iter;
1300 1303 uint32_t sequence;
1301 1304 int repeat;
1302 1305
1303 1306 assert(*outsz == sizeof (*out));
1304 1307
1305 1308 iter = iter_find(cp, rpr->rpr_iterid);
1306 1309
1307 1310 if (iter == NULL) {
1308 1311 result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1309 1312 goto out;
1310 1313 }
1311 1314
1312 1315 sequence = rpr->rpr_sequence;
1313 1316
1314 1317 if (iter->ri_sequence == 0) {
1315 1318 iter_release(iter);
1316 1319 result = REP_PROTOCOL_FAIL_NOT_SET;
1317 1320 goto out;
1318 1321 }
1319 1322
1320 1323 repeat = (sequence == iter->ri_sequence);
1321 1324
1322 1325 if (sequence == 1 || (!repeat && sequence != iter->ri_sequence + 1)) {
1323 1326 iter_release(iter);
1324 1327 result = REP_PROTOCOL_FAIL_MISORDERED;
1325 1328 goto out;
1326 1329 }
1327 1330
1328 1331 result = rc_iter_next_value(iter->ri_iter, out, outsz, repeat);
1329 1332
1330 1333 if (!repeat && result == REP_PROTOCOL_SUCCESS)
1331 1334 iter->ri_sequence++;
1332 1335
1333 1336 iter_release(iter);
1334 1337
1335 1338 out:
1336 1339 /*
1337 1340 * If we fail, we only return the response code.
1338 1341 * If we succeed, rc_iter_next_value has shortened *outsz
1339 1342 * to only include the value bytes needed.
1340 1343 */
1341 1344 if (result != REP_PROTOCOL_SUCCESS && result != REP_PROTOCOL_DONE)
1342 1345 *outsz = sizeof (out->rpr_response);
1343 1346
1344 1347 out->rpr_response = result;
1345 1348 }
1346 1349
1347 1350 static int
1348 1351 iter_reset(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1349 1352 {
1350 1353 repcache_iter_t *iter = iter_find(cp, rpr->rpr_iterid);
1351 1354
1352 1355 if (iter == NULL)
1353 1356 return (REP_PROTOCOL_FAIL_UNKNOWN_ID);
1354 1357
1355 1358 if (iter->ri_sequence != 0) {
1356 1359 iter->ri_sequence = 0;
1357 1360 rc_iter_destroy(&iter->ri_iter);
1358 1361 }
1359 1362 iter_release(iter);
1360 1363 return (REP_PROTOCOL_SUCCESS);
1361 1364 }
1362 1365
1363 1366 static rep_protocol_responseid_t
1364 1367 iter_teardown(repcache_client_t *cp, struct rep_protocol_iter_request *rpr)
1365 1368 {
1366 1369 iter_remove(cp, rpr->rpr_iterid);
1367 1370
1368 1371 return (REP_PROTOCOL_SUCCESS);
1369 1372 }
1370 1373
1371 1374 static rep_protocol_responseid_t
1372 1375 tx_start(repcache_client_t *cp, struct rep_protocol_transaction_start *rpr)
1373 1376 {
1374 1377 repcache_entity_t *tx;
1375 1378 repcache_entity_t *ep;
1376 1379 rep_protocol_responseid_t result;
1377 1380
1378 1381 uint32_t txid = rpr->rpr_entityid_tx;
1379 1382 uint32_t epid = rpr->rpr_entityid;
1380 1383
1381 1384 result = entity_find2(cp, txid, &tx, epid, &ep);
1382 1385 if (result != REP_PROTOCOL_SUCCESS)
1383 1386 return (result);
1384 1387
1385 1388 if (tx->re_txstate == REPCACHE_TX_SETUP) {
1386 1389 result = REP_PROTOCOL_SUCCESS;
1387 1390 goto end;
1388 1391 }
1389 1392 if (tx->re_txstate != REPCACHE_TX_INIT) {
1390 1393 result = REP_PROTOCOL_FAIL_MISORDERED;
1391 1394 goto end;
1392 1395 }
1393 1396
1394 1397 result = rc_node_setup_tx(&ep->re_node, &tx->re_node);
1395 1398
1396 1399 end:
1397 1400 if (result == REP_PROTOCOL_SUCCESS)
1398 1401 tx->re_txstate = REPCACHE_TX_SETUP;
1399 1402 else
1400 1403 rc_node_clear(&tx->re_node, 0);
1401 1404
1402 1405 entity_release(ep);
1403 1406 entity_release(tx);
1404 1407 return (result);
1405 1408 }
1406 1409
1407 1410 /*ARGSUSED*/
1408 1411 static void
1409 1412 tx_commit(repcache_client_t *cp, const void *in, size_t insz,
1410 1413 void *out_arg, size_t *outsz, void *arg)
1411 1414 {
1412 1415 struct rep_protocol_response *out = out_arg;
1413 1416 const struct rep_protocol_transaction_commit *rpr = in;
1414 1417 repcache_entity_t *tx;
1415 1418
1416 1419 assert(*outsz == sizeof (*out));
1417 1420 assert(insz >= REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
1418 1421
1419 1422 if (rpr->rpr_size != insz) {
1420 1423 out->rpr_response = REP_PROTOCOL_FAIL_BAD_REQUEST;
1421 1424 return;
1422 1425 }
1423 1426
1424 1427 tx = entity_find(cp, rpr->rpr_entityid);
1425 1428
1426 1429 if (tx == NULL) {
1427 1430 out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1428 1431 return;
1429 1432 }
1430 1433
1431 1434 switch (tx->re_txstate) {
1432 1435 case REPCACHE_TX_INIT:
1433 1436 out->rpr_response = REP_PROTOCOL_FAIL_MISORDERED;
1434 1437 break;
1435 1438
1436 1439 case REPCACHE_TX_SETUP:
1437 1440 out->rpr_response = rc_tx_commit(&tx->re_node, rpr->rpr_cmd,
1438 1441 insz - REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE);
1439 1442
1440 1443 if (out->rpr_response == REP_PROTOCOL_SUCCESS) {
1441 1444 tx->re_txstate = REPCACHE_TX_COMMITTED;
1442 1445 rc_node_clear(&tx->re_node, 0);
1443 1446 }
1444 1447
1445 1448 break;
1446 1449 case REPCACHE_TX_COMMITTED:
1447 1450 out->rpr_response = REP_PROTOCOL_SUCCESS;
1448 1451 break;
1449 1452 default:
1450 1453 assert(0); /* CAN'T HAPPEN */
1451 1454 break;
1452 1455 }
1453 1456
1454 1457 entity_release(tx);
1455 1458 }
1456 1459
1457 1460 static rep_protocol_responseid_t
1458 1461 next_snaplevel(repcache_client_t *cp, struct rep_protocol_entity_pair *rpr)
1459 1462 {
1460 1463 repcache_entity_t *src;
1461 1464 repcache_entity_t *dest;
1462 1465
1463 1466 uint32_t srcid = rpr->rpr_entity_src;
1464 1467 uint32_t destid = rpr->rpr_entity_dst;
1465 1468
1466 1469 int result;
1467 1470
1468 1471 result = entity_find2(cp, srcid, &src, destid, &dest);
1469 1472 if (result != REP_PROTOCOL_SUCCESS)
1470 1473 return (result);
1471 1474
1472 1475 result = rc_node_next_snaplevel(&src->re_node, &dest->re_node);
1473 1476
1474 1477 entity_release(src);
1475 1478 entity_release(dest);
1476 1479
1477 1480 return (result);
1478 1481 }
1479 1482
1480 1483 static rep_protocol_responseid_t
1481 1484 snapshot_take(repcache_client_t *cp, struct rep_protocol_snapshot_take *rpr)
1482 1485 {
1483 1486 repcache_entity_t *src;
1484 1487 uint32_t srcid = rpr->rpr_entityid_src;
1485 1488 repcache_entity_t *dest;
1486 1489 uint32_t destid = rpr->rpr_entityid_dest;
1487 1490
1488 1491 int result;
1489 1492
1490 1493 result = entity_find2(cp, srcid, &src, destid, &dest);
1491 1494 if (result != REP_PROTOCOL_SUCCESS)
1492 1495 return (result);
1493 1496
1494 1497 if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
1495 1498 result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1496 1499 } else {
1497 1500 rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1498 1501
1499 1502 if (rpr->rpr_flags == REP_SNAPSHOT_NEW)
1500 1503 result = rc_snapshot_take_new(&src->re_node, NULL,
1501 1504 NULL, rpr->rpr_name, &dest->re_node);
1502 1505 else if (rpr->rpr_flags == REP_SNAPSHOT_ATTACH &&
1503 1506 rpr->rpr_name[0] == 0)
1504 1507 result = rc_snapshot_take_attach(&src->re_node,
1505 1508 &dest->re_node);
1506 1509 else
1507 1510 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
1508 1511 }
1509 1512 entity_release(src);
1510 1513 entity_release(dest);
1511 1514
1512 1515 return (result);
1513 1516 }
1514 1517
1515 1518 static rep_protocol_responseid_t
1516 1519 snapshot_take_named(repcache_client_t *cp,
1517 1520 struct rep_protocol_snapshot_take_named *rpr)
1518 1521 {
1519 1522 repcache_entity_t *src;
1520 1523 uint32_t srcid = rpr->rpr_entityid_src;
1521 1524 repcache_entity_t *dest;
1522 1525 uint32_t destid = rpr->rpr_entityid_dest;
1523 1526
1524 1527 int result;
1525 1528
1526 1529 result = entity_find2(cp, srcid, &src, destid, &dest);
1527 1530 if (result != REP_PROTOCOL_SUCCESS)
1528 1531 return (result);
1529 1532
1530 1533 if (dest->re_type != REP_PROTOCOL_ENTITY_SNAPSHOT) {
1531 1534 result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1532 1535 } else {
1533 1536 rpr->rpr_svcname[sizeof (rpr->rpr_svcname) - 1] = 0;
1534 1537 rpr->rpr_instname[sizeof (rpr->rpr_instname) - 1] = 0;
1535 1538 rpr->rpr_name[sizeof (rpr->rpr_name) - 1] = 0;
1536 1539
1537 1540 result = rc_snapshot_take_new(&src->re_node, rpr->rpr_svcname,
1538 1541 rpr->rpr_instname, rpr->rpr_name, &dest->re_node);
1539 1542 }
1540 1543 entity_release(src);
1541 1544 entity_release(dest);
1542 1545
1543 1546 return (result);
1544 1547 }
1545 1548
1546 1549 static rep_protocol_responseid_t
1547 1550 snapshot_attach(repcache_client_t *cp, struct rep_protocol_snapshot_attach *rpr)
1548 1551 {
1549 1552 repcache_entity_t *src;
1550 1553 uint32_t srcid = rpr->rpr_entityid_src;
1551 1554 repcache_entity_t *dest;
1552 1555 uint32_t destid = rpr->rpr_entityid_dest;
1553 1556
1554 1557 int result;
1555 1558
1556 1559 result = entity_find2(cp, srcid, &src, destid, &dest);
1557 1560 if (result != REP_PROTOCOL_SUCCESS)
1558 1561 return (result);
1559 1562
1560 1563 result = rc_snapshot_attach(&src->re_node, &dest->re_node);
1561 1564
1562 1565 entity_release(src);
1563 1566 entity_release(dest);
1564 1567
1565 1568 return (result);
1566 1569 }
1567 1570
1568 1571 /*ARGSUSED*/
1569 1572 static void
1570 1573 property_get_type(repcache_client_t *cp, const void *in, size_t insz,
1571 1574 void *out_arg, size_t *outsz, void *arg)
1572 1575 {
1573 1576 const struct rep_protocol_property_request *rpr = in;
1574 1577 struct rep_protocol_integer_response *out = out_arg;
1575 1578 repcache_entity_t *ep;
1576 1579 rep_protocol_value_type_t t = 0;
1577 1580
1578 1581 assert(*outsz == sizeof (*out));
1579 1582
1580 1583 ep = entity_find(cp, rpr->rpr_entityid);
1581 1584
1582 1585 if (ep == NULL) {
1583 1586 out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1584 1587 *outsz = sizeof (out->rpr_response);
1585 1588 return;
1586 1589 }
1587 1590
1588 1591 out->rpr_response = rc_node_get_property_type(&ep->re_node, &t);
1589 1592
1590 1593 entity_release(ep);
1591 1594
1592 1595 if (out->rpr_response != REP_PROTOCOL_SUCCESS)
1593 1596 *outsz = sizeof (out->rpr_response);
1594 1597 else
1595 1598 out->rpr_value = t;
1596 1599 }
1597 1600
1598 1601 /*
1599 1602 * Fails with:
1600 1603 * _UNKNOWN_ID - an id does not designate an active register
1601 1604 * _NOT_SET - The property is not set
1602 1605 * _DELETED - The property has been deleted
1603 1606 * _TYPE_MISMATCH - The object is not a property
1604 1607 * _NOT_FOUND - The property has no values.
1605 1608 *
1606 1609 * Succeeds with:
1607 1610 * _SUCCESS - The property has 1 value.
1608 1611 * _TRUNCATED - The property has >1 value.
1609 1612 */
1610 1613 /*ARGSUSED*/
1611 1614 static void
1612 1615 property_get_value(repcache_client_t *cp, const void *in, size_t insz,
1613 1616 void *out_arg, size_t *outsz, void *arg)
1614 1617 {
1615 1618 const struct rep_protocol_property_request *rpr = in;
1616 1619 struct rep_protocol_value_response *out = out_arg;
1617 1620 repcache_entity_t *ep;
1618 1621
1619 1622 assert(*outsz == sizeof (*out));
1620 1623
1621 1624 ep = entity_find(cp, rpr->rpr_entityid);
1622 1625 if (ep == NULL) {
1623 1626 out->rpr_response = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1624 1627 *outsz = sizeof (out->rpr_response);
1625 1628 return;
1626 1629 }
1627 1630
1628 1631 out->rpr_response = rc_node_get_property_value(&ep->re_node, out,
1629 1632 outsz);
1630 1633
1631 1634 entity_release(ep);
1632 1635
1633 1636 /*
1634 1637 * If we fail, we only return the response code.
1635 1638 * If we succeed, rc_node_get_property_value has shortened *outsz
1636 1639 * to only include the value bytes needed.
1637 1640 */
1638 1641 if (out->rpr_response != REP_PROTOCOL_SUCCESS &&
1639 1642 out->rpr_response != REP_PROTOCOL_FAIL_TRUNCATED)
1640 1643 *outsz = sizeof (out->rpr_response);
1641 1644 }
1642 1645
1643 1646 static rep_protocol_responseid_t
1644 1647 propertygrp_notify(repcache_client_t *cp,
1645 1648 struct rep_protocol_propertygrp_request *rpr, int *out_fd)
1646 1649 {
1647 1650 int fds[2];
1648 1651 int ours, theirs;
1649 1652
1650 1653 rep_protocol_responseid_t result;
1651 1654 repcache_entity_t *ep;
1652 1655
1653 1656 if (pipe(fds) < 0)
1654 1657 return (REP_PROTOCOL_FAIL_NO_RESOURCES);
1655 1658
1656 1659 ours = fds[0];
1657 1660 theirs = fds[1];
1658 1661
1659 1662 if ((ep = entity_find(cp, rpr->rpr_entityid)) == NULL) {
1660 1663 result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1661 1664 goto fail;
1662 1665 }
1663 1666
1664 1667 /*
1665 1668 * While the following can race with other threads setting up a
1666 1669 * notification, the worst that can happen is that our fd has
1667 1670 * already been closed before we return.
1668 1671 */
1669 1672 result = rc_pg_notify_setup(&cp->rc_pg_notify, &ep->re_node,
1670 1673 ours);
1671 1674
1672 1675 entity_release(ep);
1673 1676
1674 1677 if (result != REP_PROTOCOL_SUCCESS)
1675 1678 goto fail;
1676 1679
1677 1680 *out_fd = theirs;
1678 1681 return (REP_PROTOCOL_SUCCESS);
1679 1682
1680 1683 fail:
1681 1684 (void) close(ours);
1682 1685 (void) close(theirs);
1683 1686
1684 1687 return (result);
1685 1688 }
1686 1689
1687 1690 static rep_protocol_responseid_t
1688 1691 client_add_notify(repcache_client_t *cp,
1689 1692 struct rep_protocol_notify_request *rpr)
1690 1693 {
1691 1694 rpr->rpr_pattern[sizeof (rpr->rpr_pattern) - 1] = 0;
1692 1695
1693 1696 switch (rpr->rpr_type) {
1694 1697 case REP_PROTOCOL_NOTIFY_PGNAME:
1695 1698 return (rc_notify_info_add_name(&cp->rc_notify_info,
1696 1699 rpr->rpr_pattern));
1697 1700
1698 1701 case REP_PROTOCOL_NOTIFY_PGTYPE:
1699 1702 return (rc_notify_info_add_type(&cp->rc_notify_info,
1700 1703 rpr->rpr_pattern));
1701 1704
1702 1705 default:
1703 1706 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1704 1707 }
1705 1708 }
1706 1709
1707 1710 /*ARGSUSED*/
1708 1711 static void
1709 1712 client_wait(repcache_client_t *cp, const void *in, size_t insz,
1710 1713 void *out_arg, size_t *outsz, void *arg)
1711 1714 {
1712 1715 int result;
1713 1716 repcache_entity_t *ep;
1714 1717 const struct rep_protocol_wait_request *rpr = in;
1715 1718 struct rep_protocol_fmri_response *out = out_arg;
1716 1719
1717 1720 assert(*outsz == sizeof (*out));
1718 1721
1719 1722 (void) pthread_mutex_lock(&cp->rc_lock);
1720 1723 if (cp->rc_notify_thr != 0) {
1721 1724 (void) pthread_mutex_unlock(&cp->rc_lock);
1722 1725 out->rpr_response = REP_PROTOCOL_FAIL_EXISTS;
1723 1726 *outsz = sizeof (out->rpr_response);
1724 1727 return;
1725 1728 }
1726 1729 cp->rc_notify_thr = pthread_self();
1727 1730 (void) pthread_mutex_unlock(&cp->rc_lock);
1728 1731
1729 1732 result = rc_notify_info_wait(&cp->rc_notify_info, &cp->rc_notify_ptr,
1730 1733 out->rpr_fmri, sizeof (out->rpr_fmri));
1731 1734
1732 1735 if (result == REP_PROTOCOL_SUCCESS) {
1733 1736 if ((ep = entity_find(cp, rpr->rpr_entityid)) != NULL) {
1734 1737 if (ep->re_type == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
1735 1738 rc_node_ptr_assign(&ep->re_node,
1736 1739 &cp->rc_notify_ptr);
1737 1740 } else {
1738 1741 result = REP_PROTOCOL_FAIL_TYPE_MISMATCH;
1739 1742 }
1740 1743 entity_release(ep);
1741 1744 } else {
1742 1745 result = REP_PROTOCOL_FAIL_UNKNOWN_ID;
1743 1746 }
1744 1747 rc_node_clear(&cp->rc_notify_ptr, 0);
1745 1748 }
1746 1749
1747 1750 (void) pthread_mutex_lock(&cp->rc_lock);
1748 1751 assert(cp->rc_notify_thr == pthread_self());
1749 1752 cp->rc_notify_thr = 0;
1750 1753 (void) pthread_mutex_unlock(&cp->rc_lock);
1751 1754
1752 1755 out->rpr_response = result;
1753 1756 if (result != REP_PROTOCOL_SUCCESS)
1754 1757 *outsz = sizeof (out->rpr_response);
1755 1758 }
1756 1759
1757 1760 /*
1758 1761 * Can return:
1759 1762 * _PERMISSION_DENIED not enough privileges to do request.
1760 1763 * _BAD_REQUEST name is not valid or reserved
1761 1764 * _TRUNCATED name is too long for current repository path
1762 1765 * _UNKNOWN failed for unknown reason (details written to
1763 1766 * console)
1764 1767 * _BACKEND_READONLY backend is not writable
1765 1768 * _NO_RESOURCES out of memory
1766 1769 * _SUCCESS Backup completed successfully.
1767 1770 */
1768 1771 static rep_protocol_responseid_t
1769 1772 backup_repository(repcache_client_t *cp,
1770 1773 struct rep_protocol_backup_request *rpr)
1771 1774 {
1772 1775 rep_protocol_responseid_t result;
1773 1776 ucred_t *uc = get_ucred();
1774 1777
1775 1778 if (!client_is_privileged() && (uc == NULL || ucred_geteuid(uc) != 0))
1776 1779 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
1777 1780
1778 1781 rpr->rpr_name[REP_PROTOCOL_NAME_LEN - 1] = 0;
1779 1782 if (strcmp(rpr->rpr_name, REPOSITORY_BOOT_BACKUP) == 0)
1780 1783 return (REP_PROTOCOL_FAIL_BAD_REQUEST);
1781 1784
1782 1785 (void) pthread_mutex_lock(&cp->rc_lock);
1783 1786 if (rpr->rpr_changeid != cp->rc_changeid) {
1784 1787 result = backend_create_backup(rpr->rpr_name);
1785 1788 if (result == REP_PROTOCOL_SUCCESS)
1786 1789 cp->rc_changeid = rpr->rpr_changeid;
1787 1790 } else {
1788 1791 result = REP_PROTOCOL_SUCCESS;
1789 1792 }
1790 1793 (void) pthread_mutex_unlock(&cp->rc_lock);
1791 1794
1792 1795 return (result);
1793 1796 }
1794 1797
1795 1798 /*
1796 1799 * This function captures the information that will be used for an
1797 1800 * annotation audit event. Specifically, it captures the operation to be
1798 1801 * performed and the name of the file that is being used. These values are
1799 1802 * copied from the rep_protocol_annotation request at rpr to the client
1800 1803 * structure. If both these values are null, the client is turning
1801 1804 * annotation off.
1802 1805 *
1803 1806 * Fails with
1804 1807 * _NO_RESOURCES - unable to allocate memory
1805 1808 */
1806 1809 static rep_protocol_responseid_t
1807 1810 set_annotation(repcache_client_t *cp, struct rep_protocol_annotation *rpr)
1808 1811 {
1809 1812 au_id_t audit_uid;
1810 1813 const char *file = NULL;
1811 1814 const char *old_ptrs[2];
1812 1815 const char *operation = NULL;
1813 1816 rep_protocol_responseid_t rc = REP_PROTOCOL_FAIL_NO_RESOURCES;
1814 1817 au_asid_t sessionid;
1815 1818
1816 1819 (void) memset((void *)old_ptrs, 0, sizeof (old_ptrs));
1817 1820
1818 1821 /* Copy rpr_operation and rpr_file if they are not empty strings. */
1819 1822 if (rpr->rpr_operation[0] != 0) {
1820 1823 /*
1821 1824 * Make sure that client did not send us an unterminated buffer.
1822 1825 */
1823 1826 rpr->rpr_operation[sizeof (rpr->rpr_operation) - 1] = 0;
1824 1827 if ((operation = strdup(rpr->rpr_operation)) == NULL)
1825 1828 goto out;
1826 1829 }
1827 1830 if (rpr->rpr_file[0] != 0) {
1828 1831 /*
1829 1832 * Make sure that client did not send us an unterminated buffer.
1830 1833 */
1831 1834 rpr->rpr_file[sizeof (rpr->rpr_file) - 1] = 0;
1832 1835 if ((file = strdup(rpr->rpr_file)) == NULL)
1833 1836 goto out;
1834 1837 }
1835 1838
1836 1839 (void) pthread_mutex_lock(&cp->rc_annotate_lock);
1837 1840 /* Save addresses of memory to free when not locked */
1838 1841 old_ptrs[0] = cp->rc_operation;
1839 1842 old_ptrs[1] = cp->rc_file;
1840 1843
1841 1844 /* Save pointers to annotation strings. */
1842 1845 cp->rc_operation = operation;
1843 1846 cp->rc_file = file;
1844 1847
1845 1848 /*
1846 1849 * Set annotation flag. Annotations should be turned on if either
1847 1850 * operation or file are not NULL.
1848 1851 */
1849 1852 cp->rc_annotate = (operation != NULL) || (file != NULL);
1850 1853 (void) pthread_mutex_unlock(&cp->rc_annotate_lock);
1851 1854
1852 1855 /*
1853 1856 * operation and file pointers are saved in cp, so don't free them
1854 1857 * during cleanup.
1855 1858 */
1856 1859 operation = NULL;
1857 1860 file = NULL;
1858 1861 rc = REP_PROTOCOL_SUCCESS;
1859 1862
1860 1863 /*
1861 1864 * Native builds are done to create svc.configd-native. This
1862 1865 * program runs only on the Open Solaris build machines to create
1863 1866 * the seed repository. Until the SMF auditing code is distributed
1864 1867 * to the Open Solaris build machines, adt_get_unique_id() in the
1865 1868 * following code is not a global function in libbsm. Hence the
1866 1869 * following conditional compilation.
1867 1870 */
1868 1871 #ifndef NATIVE_BUILD
1869 1872 /*
1870 1873 * Set the appropriate audit session id.
1871 1874 */
1872 1875 if (cp->rc_annotate) {
1873 1876 /*
1874 1877 * We're starting a group of annotated audit events, so
1875 1878 * create and set an audit session ID for this annotation.
1876 1879 */
1877 1880 adt_get_auid(cp->rc_adt_session, &audit_uid);
1878 1881 sessionid = adt_get_unique_id(audit_uid);
1879 1882 } else {
1880 1883 /*
1881 1884 * Annotation is done so restore our client audit session
1882 1885 * id.
1883 1886 */
1884 1887 sessionid = cp->rc_adt_sessionid;
1885 1888 }
1886 1889 adt_set_asid(cp->rc_adt_session, sessionid);
1887 1890 #endif /* NATIVE_BUILD */
1888 1891
1889 1892 out:
1890 1893 if (operation != NULL)
1891 1894 free((void *)operation);
1892 1895 if (file != NULL)
1893 1896 free((void *)file);
1894 1897 free((void *)old_ptrs[0]);
1895 1898 free((void *)old_ptrs[1]);
1896 1899 return (rc);
1897 1900 }
1898 1901
1899 1902 /*
1900 1903 * Determine if an annotation event needs to be generated. If it does
1901 1904 * provide the operation and file name that should be used in the event.
1902 1905 *
1903 1906 * Can return:
1904 1907 * 0 No annotation event needed or buffers are not large
1905 1908 * enough. Either way an event should not be
1906 1909 * generated.
1907 1910 * 1 Generate annotation event.
1908 1911 */
1909 1912 int
1910 1913 client_annotation_needed(char *operation, size_t oper_sz,
1911 1914 char *file, size_t file_sz)
1912 1915 {
1913 1916 thread_info_t *ti = thread_self();
1914 1917 repcache_client_t *cp = ti->ti_active_client;
1915 1918 int rc = 0;
1916 1919
1917 1920 (void) pthread_mutex_lock(&cp->rc_annotate_lock);
1918 1921 if (cp->rc_annotate) {
1919 1922 rc = 1;
1920 1923 if (cp->rc_operation == NULL) {
1921 1924 if (oper_sz > 0)
1922 1925 operation[0] = 0;
1923 1926 } else {
1924 1927 if (strlcpy(operation, cp->rc_operation, oper_sz) >=
1925 1928 oper_sz) {
1926 1929 /* Buffer overflow, so do not generate event */
1927 1930 rc = 0;
1928 1931 }
1929 1932 }
1930 1933 if (cp->rc_file == NULL) {
1931 1934 if (file_sz > 0)
1932 1935 file[0] = 0;
1933 1936 } else if (rc == 1) {
1934 1937 if (strlcpy(file, cp->rc_file, file_sz) >= file_sz) {
1935 1938 /* Buffer overflow, so do not generate event */
1936 1939 rc = 0;
1937 1940 }
1938 1941 }
1939 1942 }
1940 1943 (void) pthread_mutex_unlock(&cp->rc_annotate_lock);
1941 1944 return (rc);
1942 1945 }
1943 1946
1944 1947 void
↓ open down ↓ |
1196 lines elided |
↑ open up ↑ |
1945 1948 client_annotation_finished()
1946 1949 {
1947 1950 thread_info_t *ti = thread_self();
1948 1951 repcache_client_t *cp = ti->ti_active_client;
1949 1952
1950 1953 (void) pthread_mutex_lock(&cp->rc_annotate_lock);
1951 1954 cp->rc_annotate = 0;
1952 1955 (void) pthread_mutex_unlock(&cp->rc_annotate_lock);
1953 1956 }
1954 1957
1958 +#ifndef NATIVE_BUILD
1955 1959 static void
1956 1960 start_audit_session(repcache_client_t *cp)
1957 1961 {
1958 1962 ucred_t *cred = NULL;
1959 1963 adt_session_data_t *session;
1960 1964
1961 1965 /*
1962 1966 * A NULL session pointer value can legally be used in all
1963 1967 * subsequent calls to adt_* functions.
1964 1968 */
1965 1969 cp->rc_adt_session = NULL;
1966 1970
1967 1971 if (!adt_audit_state(AUC_AUDITING))
1968 1972 return;
1969 1973
1970 1974 if (door_ucred(&cred) != 0) {
1971 1975 switch (errno) {
1972 1976 case EAGAIN:
1973 1977 case ENOMEM:
1974 1978 syslog(LOG_ERR, gettext("start_audit_session(): cannot "
1975 1979 "get ucred. %m\n"));
1976 1980 return;
1977 1981 case EINVAL:
1978 1982 /*
1979 1983 * Door client went away. This is a normal,
1980 1984 * although infrequent event, so there is no need
1981 1985 * to create a syslog message.
1982 1986 */
1983 1987 return;
1984 1988 case EFAULT:
1985 1989 default:
1986 1990 bad_error("door_ucred", errno);
1987 1991 return;
1988 1992 }
1989 1993 }
1990 1994 if (adt_start_session(&session, NULL, 0) != 0) {
1991 1995 syslog(LOG_ERR, gettext("start_audit_session(): could not "
1992 1996 "start audit session.\n"));
1993 1997 ucred_free(cred);
1994 1998 return;
1995 1999 }
1996 2000 if (adt_set_from_ucred(session, cred, ADT_NEW) != 0) {
1997 2001 syslog(LOG_ERR, gettext("start_audit_session(): cannot set "
1998 2002 "audit session data from ucred\n"));
1999 2003 /* Something went wrong. End the session. */
2000 2004 (void) adt_end_session(session);
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
2001 2005 ucred_free(cred);
2002 2006 return;
2003 2007 }
2004 2008
2005 2009 /* All went well. Save the session data and session ID */
2006 2010 cp->rc_adt_session = session;
2007 2011 adt_get_asid(session, &cp->rc_adt_sessionid);
2008 2012
2009 2013 ucred_free(cred);
2010 2014 }
2015 +#endif
2011 2016
2012 2017 /*
2013 2018 * Handle switch client request
2014 2019 *
2015 2020 * This routine can return:
2016 2021 *
2017 2022 * _PERMISSION_DENIED not enough privileges to do request.
2018 2023 * _UNKNOWN file operation error (details written to
2019 2024 * the console).
2020 2025 * _SUCCESS switch operation is completed.
2021 2026 * _BACKEND_ACCESS backend access fails.
2022 2027 * _NO_RESOURCES out of memory.
2023 2028 * _BACKEND_READONLY backend is not writable.
2024 2029 */
2025 2030 static rep_protocol_responseid_t
2026 2031 repository_switch(repcache_client_t *cp,
2027 2032 struct rep_protocol_switch_request *rpr)
2028 2033 {
2029 2034 rep_protocol_responseid_t result;
2030 2035 ucred_t *uc = get_ucred();
2031 2036
2032 2037 if (!client_is_privileged() && (uc == NULL ||
2033 2038 ucred_geteuid(uc) != 0)) {
2034 2039 return (REP_PROTOCOL_FAIL_PERMISSION_DENIED);
2035 2040 }
2036 2041
2037 2042 (void) pthread_mutex_lock(&cp->rc_lock);
2038 2043 if (rpr->rpr_changeid != cp->rc_changeid) {
2039 2044 if ((result = backend_switch(rpr->rpr_flag)) ==
2040 2045 REP_PROTOCOL_SUCCESS)
2041 2046 cp->rc_changeid = rpr->rpr_changeid;
2042 2047 } else {
2043 2048 result = REP_PROTOCOL_SUCCESS;
2044 2049 }
2045 2050 (void) pthread_mutex_unlock(&cp->rc_lock);
2046 2051
2047 2052 return (result);
2048 2053 }
2049 2054
2050 2055 typedef rep_protocol_responseid_t protocol_simple_f(repcache_client_t *cp,
2051 2056 const void *rpr);
2052 2057
2053 2058 /*ARGSUSED*/
2054 2059 static void
2055 2060 simple_handler(repcache_client_t *cp, const void *in, size_t insz,
2056 2061 void *out_arg, size_t *outsz, void *arg)
2057 2062 {
2058 2063 protocol_simple_f *f = (protocol_simple_f *)arg;
2059 2064 rep_protocol_response_t *out = out_arg;
2060 2065
2061 2066 assert(*outsz == sizeof (*out));
2062 2067 assert(f != NULL);
2063 2068
2064 2069 out->rpr_response = (*f)(cp, in);
2065 2070 }
2066 2071
2067 2072 typedef rep_protocol_responseid_t protocol_simple_fd_f(repcache_client_t *cp,
2068 2073 const void *rpr, int *out_fd);
2069 2074
2070 2075 /*ARGSUSED*/
2071 2076 static void
2072 2077 simple_fd_handler(repcache_client_t *cp, const void *in, size_t insz,
2073 2078 void *out_arg, size_t *outsz, void *arg, int *out_fd)
2074 2079 {
2075 2080 protocol_simple_fd_f *f = (protocol_simple_fd_f *)arg;
2076 2081 rep_protocol_response_t *out = out_arg;
2077 2082
2078 2083 assert(*outsz == sizeof (*out));
2079 2084 assert(f != NULL);
2080 2085
2081 2086 out->rpr_response = (*f)(cp, in, out_fd);
2082 2087 }
2083 2088
2084 2089 typedef void protocol_handler_f(repcache_client_t *, const void *in,
2085 2090 size_t insz, void *out, size_t *outsz, void *arg);
2086 2091
2087 2092 typedef void protocol_handler_fdret_f(repcache_client_t *, const void *in,
2088 2093 size_t insz, void *out, size_t *outsz, void *arg, int *fd_out);
2089 2094
2090 2095 #define PROTO(p, f, in) { \
2091 2096 p, #p, simple_handler, (void *)(&f), NULL, \
2092 2097 sizeof (in), sizeof (rep_protocol_response_t), 0 \
2093 2098 }
2094 2099
2095 2100 #define PROTO_FD_OUT(p, f, in) { \
2096 2101 p, #p, NULL, (void *)(&f), simple_fd_handler, \
2097 2102 sizeof (in), \
2098 2103 sizeof (rep_protocol_response_t), \
2099 2104 PROTO_FLAG_RETFD \
2100 2105 }
2101 2106
2102 2107 #define PROTO_VARIN(p, f, insz) { \
2103 2108 p, #p, &(f), NULL, NULL, \
2104 2109 insz, sizeof (rep_protocol_response_t), \
2105 2110 PROTO_FLAG_VARINPUT \
2106 2111 }
2107 2112
2108 2113 #define PROTO_UINT_OUT(p, f, in) { \
2109 2114 p, #p, &(f), NULL, NULL, \
2110 2115 sizeof (in), \
2111 2116 sizeof (struct rep_protocol_integer_response), 0 \
2112 2117 }
2113 2118
2114 2119 #define PROTO_NAME_OUT(p, f, in) { \
2115 2120 p, #p, &(f), NULL, NULL, \
2116 2121 sizeof (in), \
2117 2122 sizeof (struct rep_protocol_name_response), 0 \
2118 2123 }
2119 2124
2120 2125 #define PROTO_FMRI_OUT(p, f, in) { \
2121 2126 p, #p, &(f), NULL, NULL, \
2122 2127 sizeof (in), \
2123 2128 sizeof (struct rep_protocol_fmri_response), 0 \
2124 2129 }
2125 2130
2126 2131 #define PROTO_VALUE_OUT(p, f, in) { \
2127 2132 p, #p, &(f), NULL, NULL, \
2128 2133 sizeof (in), \
2129 2134 sizeof (struct rep_protocol_value_response), 0 \
2130 2135 }
2131 2136
2132 2137 #define PROTO_PANIC(p) { p, #p, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2133 2138 #define PROTO_END() { 0, NULL, NULL, NULL, NULL, 0, 0, PROTO_FLAG_PANIC }
2134 2139
2135 2140 #define PROTO_FLAG_PANIC 0x00000001 /* should never be called */
2136 2141 #define PROTO_FLAG_VARINPUT 0x00000004 /* in_size is minimum size */
2137 2142 #define PROTO_FLAG_RETFD 0x00000008 /* can also return an FD */
2138 2143
2139 2144 #define PROTO_ALL_FLAGS 0x0000000f /* all flags */
2140 2145
2141 2146 static struct protocol_entry {
2142 2147 enum rep_protocol_requestid pt_request;
2143 2148 const char *pt_name;
2144 2149 protocol_handler_f *pt_handler;
2145 2150 void *pt_arg;
2146 2151 protocol_handler_fdret_f *pt_fd_handler;
2147 2152 size_t pt_in_size;
2148 2153 size_t pt_out_max;
2149 2154 uint32_t pt_flags;
2150 2155 } protocol_table[] = {
2151 2156 PROTO_PANIC(REP_PROTOCOL_CLOSE), /* special case */
2152 2157
2153 2158 PROTO(REP_PROTOCOL_ENTITY_SETUP, entity_setup,
2154 2159 struct rep_protocol_entity_setup),
2155 2160 PROTO_NAME_OUT(REP_PROTOCOL_ENTITY_NAME, entity_name,
2156 2161 struct rep_protocol_entity_name),
2157 2162 PROTO_UINT_OUT(REP_PROTOCOL_ENTITY_PARENT_TYPE, entity_parent_type,
2158 2163 struct rep_protocol_entity_parent_type),
2159 2164 PROTO(REP_PROTOCOL_ENTITY_GET_CHILD, entity_get_child,
2160 2165 struct rep_protocol_entity_get_child),
2161 2166 PROTO(REP_PROTOCOL_ENTITY_GET_PARENT, entity_get_parent,
2162 2167 struct rep_protocol_entity_parent),
2163 2168 PROTO(REP_PROTOCOL_ENTITY_GET, entity_get,
2164 2169 struct rep_protocol_entity_get),
2165 2170 PROTO(REP_PROTOCOL_ENTITY_UPDATE, entity_update,
2166 2171 struct rep_protocol_entity_update),
2167 2172 PROTO(REP_PROTOCOL_ENTITY_CREATE_CHILD, entity_create_child,
2168 2173 struct rep_protocol_entity_create_child),
2169 2174 PROTO(REP_PROTOCOL_ENTITY_CREATE_PG, entity_create_pg,
2170 2175 struct rep_protocol_entity_create_pg),
2171 2176 PROTO(REP_PROTOCOL_ENTITY_DELETE, entity_delete,
2172 2177 struct rep_protocol_entity_delete),
2173 2178 PROTO(REP_PROTOCOL_ENTITY_RESET, entity_reset,
2174 2179 struct rep_protocol_entity_reset),
2175 2180 PROTO(REP_PROTOCOL_ENTITY_TEARDOWN, entity_teardown,
2176 2181 struct rep_protocol_entity_teardown),
2177 2182
2178 2183 PROTO(REP_PROTOCOL_ITER_SETUP, iter_setup,
2179 2184 struct rep_protocol_iter_request),
2180 2185 PROTO(REP_PROTOCOL_ITER_START, iter_start,
2181 2186 struct rep_protocol_iter_start),
2182 2187 PROTO(REP_PROTOCOL_ITER_READ, iter_read,
2183 2188 struct rep_protocol_iter_read),
2184 2189 PROTO_VALUE_OUT(REP_PROTOCOL_ITER_READ_VALUE, iter_read_value,
2185 2190 struct rep_protocol_iter_read_value),
2186 2191 PROTO(REP_PROTOCOL_ITER_RESET, iter_reset,
2187 2192 struct rep_protocol_iter_request),
2188 2193 PROTO(REP_PROTOCOL_ITER_TEARDOWN, iter_teardown,
2189 2194 struct rep_protocol_iter_request),
2190 2195
2191 2196 PROTO(REP_PROTOCOL_NEXT_SNAPLEVEL, next_snaplevel,
2192 2197 struct rep_protocol_entity_pair),
2193 2198
2194 2199 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE, snapshot_take,
2195 2200 struct rep_protocol_snapshot_take),
2196 2201 PROTO(REP_PROTOCOL_SNAPSHOT_TAKE_NAMED, snapshot_take_named,
2197 2202 struct rep_protocol_snapshot_take_named),
2198 2203 PROTO(REP_PROTOCOL_SNAPSHOT_ATTACH, snapshot_attach,
2199 2204 struct rep_protocol_snapshot_attach),
2200 2205
2201 2206 PROTO_UINT_OUT(REP_PROTOCOL_PROPERTY_GET_TYPE, property_get_type,
2202 2207 struct rep_protocol_property_request),
2203 2208 PROTO_VALUE_OUT(REP_PROTOCOL_PROPERTY_GET_VALUE, property_get_value,
2204 2209 struct rep_protocol_property_request),
2205 2210
2206 2211 PROTO_FD_OUT(REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT, propertygrp_notify,
2207 2212 struct rep_protocol_propertygrp_request),
2208 2213 PROTO(REP_PROTOCOL_PROPERTYGRP_TX_START, tx_start,
2209 2214 struct rep_protocol_transaction_start),
2210 2215 PROTO_VARIN(REP_PROTOCOL_PROPERTYGRP_TX_COMMIT, tx_commit,
2211 2216 REP_PROTOCOL_TRANSACTION_COMMIT_MIN_SIZE),
2212 2217
2213 2218 PROTO(REP_PROTOCOL_CLIENT_ADD_NOTIFY, client_add_notify,
2214 2219 struct rep_protocol_notify_request),
2215 2220 PROTO_FMRI_OUT(REP_PROTOCOL_CLIENT_WAIT, client_wait,
2216 2221 struct rep_protocol_wait_request),
2217 2222
2218 2223 PROTO(REP_PROTOCOL_BACKUP, backup_repository,
2219 2224 struct rep_protocol_backup_request),
2220 2225
2221 2226 PROTO(REP_PROTOCOL_SET_AUDIT_ANNOTATION, set_annotation,
2222 2227 struct rep_protocol_annotation),
2223 2228
2224 2229 PROTO(REP_PROTOCOL_SWITCH, repository_switch,
2225 2230 struct rep_protocol_switch_request),
2226 2231
2227 2232 PROTO_END()
2228 2233 };
2229 2234 #undef PROTO
2230 2235 #undef PROTO_FMRI_OUT
2231 2236 #undef PROTO_NAME_OUT
2232 2237 #undef PROTO_UINT_OUT
2233 2238 #undef PROTO_PANIC
2234 2239 #undef PROTO_END
2235 2240
2236 2241 /*
2237 2242 * The number of entries, sans PROTO_END()
2238 2243 */
2239 2244 #define PROTOCOL_ENTRIES \
2240 2245 (sizeof (protocol_table) / sizeof (*protocol_table) - 1)
2241 2246
2242 2247 #define PROTOCOL_PREFIX "REP_PROTOCOL_"
2243 2248
2244 2249 int
2245 2250 client_init(void)
2246 2251 {
2247 2252 int i;
2248 2253 struct protocol_entry *e;
2249 2254
2250 2255 if (!client_hash_init())
2251 2256 return (0);
2252 2257
2253 2258 if (request_log_size > 0) {
2254 2259 request_log = uu_zalloc(request_log_size *
2255 2260 sizeof (request_log_entry_t));
2256 2261 }
2257 2262
2258 2263 /*
2259 2264 * update the names to not include REP_PROTOCOL_
2260 2265 */
2261 2266 for (i = 0; i < PROTOCOL_ENTRIES; i++) {
2262 2267 e = &protocol_table[i];
2263 2268 assert(strncmp(e->pt_name, PROTOCOL_PREFIX,
2264 2269 strlen(PROTOCOL_PREFIX)) == 0);
2265 2270 e->pt_name += strlen(PROTOCOL_PREFIX);
2266 2271 }
2267 2272 /*
2268 2273 * verify the protocol table is consistent
2269 2274 */
2270 2275 for (i = 0; i < PROTOCOL_ENTRIES; i++) {
2271 2276 e = &protocol_table[i];
2272 2277 assert(e->pt_request == (REP_PROTOCOL_BASE + i));
2273 2278
2274 2279 assert((e->pt_flags & ~PROTO_ALL_FLAGS) == 0);
2275 2280
2276 2281 if (e->pt_flags & PROTO_FLAG_PANIC)
2277 2282 assert(e->pt_in_size == 0 && e->pt_out_max == 0 &&
2278 2283 e->pt_handler == NULL);
2279 2284 else
2280 2285 assert(e->pt_in_size != 0 && e->pt_out_max != 0 &&
2281 2286 (e->pt_handler != NULL ||
2282 2287 e->pt_fd_handler != NULL));
2283 2288 }
2284 2289 assert((REP_PROTOCOL_BASE + i) == REP_PROTOCOL_MAX_REQUEST);
2285 2290
2286 2291 assert(protocol_table[i].pt_request == 0);
2287 2292
2288 2293 return (1);
2289 2294 }
2290 2295
2291 2296 static void
2292 2297 client_switcher(void *cookie, char *argp, size_t arg_size, door_desc_t *desc_in,
2293 2298 uint_t n_desc)
2294 2299 {
2295 2300 thread_info_t *ti = thread_self();
2296 2301
2297 2302 repcache_client_t *cp;
2298 2303 uint32_t id = (uint32_t)cookie;
2299 2304 enum rep_protocol_requestid request_code;
2300 2305
2301 2306 rep_protocol_responseid_t result = INVALID_RESULT;
2302 2307
2303 2308 struct protocol_entry *e;
2304 2309
2305 2310 char *retval = NULL;
2306 2311 size_t retsize = 0;
2307 2312
2308 2313 int retfd = -1;
2309 2314 door_desc_t desc;
2310 2315 request_log_entry_t *rlp;
2311 2316
2312 2317 rlp = start_log(id);
2313 2318
2314 2319 if (n_desc != 0)
2315 2320 uu_die("can't happen: %d descriptors @%p (cookie %p)",
2316 2321 n_desc, desc_in, cookie);
2317 2322
2318 2323 if (argp == DOOR_UNREF_DATA) {
2319 2324 client_destroy(id);
2320 2325 goto bad_end;
2321 2326 }
2322 2327
2323 2328 thread_newstate(ti, TI_CLIENT_CALL);
2324 2329
2325 2330 /*
2326 2331 * To simplify returning just a result code, we set up for
2327 2332 * that case here.
2328 2333 */
2329 2334 retval = (char *)&result;
2330 2335 retsize = sizeof (result);
2331 2336
2332 2337 if (arg_size < sizeof (request_code)) {
2333 2338 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2334 2339 goto end_unheld;
2335 2340 }
2336 2341
2337 2342 ti->ti_client_request = (void *)argp;
2338 2343
2339 2344 /* LINTED alignment */
2340 2345 request_code = *(uint32_t *)argp;
2341 2346
2342 2347 if (rlp != NULL) {
2343 2348 rlp->rl_request = request_code;
2344 2349 }
2345 2350 /*
2346 2351 * In order to avoid locking problems on removal, we handle the
2347 2352 * "close" case before doing a lookup.
2348 2353 */
2349 2354 if (request_code == REP_PROTOCOL_CLOSE) {
2350 2355 client_destroy(id);
2351 2356 result = REP_PROTOCOL_SUCCESS;
2352 2357 goto end_unheld;
2353 2358 }
2354 2359
2355 2360 cp = client_lookup(id);
2356 2361 /*
2357 2362 * cp is held
2358 2363 */
2359 2364
2360 2365 if (cp == NULL)
2361 2366 goto bad_end;
2362 2367
2363 2368 if (rlp != NULL)
2364 2369 rlp->rl_client = cp;
2365 2370
2366 2371 ti->ti_active_client = cp;
2367 2372
2368 2373 if (request_code < REP_PROTOCOL_BASE ||
2369 2374 request_code >= REP_PROTOCOL_BASE + PROTOCOL_ENTRIES) {
2370 2375 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2371 2376 goto end;
2372 2377 }
2373 2378
2374 2379 e = &protocol_table[request_code - REP_PROTOCOL_BASE];
2375 2380
2376 2381 assert(!(e->pt_flags & PROTO_FLAG_PANIC));
2377 2382
2378 2383 if (e->pt_flags & PROTO_FLAG_VARINPUT) {
2379 2384 if (arg_size < e->pt_in_size) {
2380 2385 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2381 2386 goto end;
2382 2387 }
2383 2388 } else if (arg_size != e->pt_in_size) {
2384 2389 result = REP_PROTOCOL_FAIL_BAD_REQUEST;
2385 2390 goto end;
2386 2391 }
2387 2392
2388 2393 if (retsize != e->pt_out_max) {
2389 2394 retsize = e->pt_out_max;
2390 2395 retval = alloca(retsize);
2391 2396 }
2392 2397
2393 2398 if (e->pt_flags & PROTO_FLAG_RETFD)
2394 2399 e->pt_fd_handler(cp, argp, arg_size, retval, &retsize,
2395 2400 e->pt_arg, &retfd);
2396 2401 else
2397 2402 e->pt_handler(cp, argp, arg_size, retval, &retsize, e->pt_arg);
2398 2403
2399 2404 end:
2400 2405 ti->ti_active_client = NULL;
2401 2406 client_release(cp);
2402 2407
2403 2408 end_unheld:
2404 2409 if (rlp != NULL) {
2405 2410 /* LINTED alignment */
2406 2411 rlp->rl_response = *(uint32_t *)retval;
2407 2412 end_log();
2408 2413 rlp = NULL;
2409 2414 }
2410 2415 ti->ti_client_request = NULL;
2411 2416 thread_newstate(ti, TI_DOOR_RETURN);
2412 2417
2413 2418 if (retval == (char *)&result) {
2414 2419 assert(result != INVALID_RESULT && retsize == sizeof (result));
2415 2420 } else {
2416 2421 /* LINTED alignment */
2417 2422 result = *(uint32_t *)retval;
2418 2423 }
2419 2424 if (retfd != -1) {
2420 2425 desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
2421 2426 desc.d_data.d_desc.d_descriptor = retfd;
2422 2427 (void) door_return(retval, retsize, &desc, 1);
2423 2428 } else {
2424 2429 (void) door_return(retval, retsize, NULL, 0);
2425 2430 }
2426 2431 bad_end:
2427 2432 if (rlp != NULL) {
2428 2433 rlp->rl_response = -1;
2429 2434 end_log();
2430 2435 rlp = NULL;
2431 2436 }
2432 2437 (void) door_return(NULL, 0, NULL, 0);
2433 2438 }
2434 2439
2435 2440 int
2436 2441 create_client(pid_t pid, uint32_t debugflags, int privileged, int *out_fd)
2437 2442 {
2438 2443 int fd;
2439 2444
2440 2445 repcache_client_t *cp;
2441 2446
2442 2447 struct door_info info;
2443 2448
2444 2449 int door_flags = DOOR_UNREF | DOOR_REFUSE_DESC;
2445 2450 #ifdef DOOR_NO_CANCEL
2446 2451 door_flags |= DOOR_NO_CANCEL;
2447 2452 #endif
2448 2453
2449 2454 cp = client_alloc();
2450 2455 if (cp == NULL)
↓ open down ↓ |
430 lines elided |
↑ open up ↑ |
2451 2456 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2452 2457
2453 2458 (void) pthread_mutex_lock(&client_lock);
2454 2459 cp->rc_id = ++client_maxid;
2455 2460 (void) pthread_mutex_unlock(&client_lock);
2456 2461
2457 2462 cp->rc_all_auths = privileged;
2458 2463 cp->rc_pid = pid;
2459 2464 cp->rc_debug = debugflags;
2460 2465
2466 +#ifndef NATIVE_BUILD
2461 2467 start_audit_session(cp);
2468 +#endif
2462 2469
2463 2470 cp->rc_doorfd = door_create(client_switcher, (void *)cp->rc_id,
2464 2471 door_flags);
2465 2472
2466 2473 if (cp->rc_doorfd < 0) {
2467 2474 client_free(cp);
2468 2475 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2469 2476 }
2470 2477 #ifdef DOOR_PARAM_DATA_MIN
2471 2478 (void) door_setparam(cp->rc_doorfd, DOOR_PARAM_DATA_MIN,
2472 2479 sizeof (enum rep_protocol_requestid));
2473 2480 #endif
2474 2481
2475 2482 if ((fd = dup(cp->rc_doorfd)) < 0 ||
2476 2483 door_info(cp->rc_doorfd, &info) < 0) {
2477 2484 if (fd >= 0)
2478 2485 (void) close(fd);
2479 2486 (void) door_revoke(cp->rc_doorfd);
2480 2487 cp->rc_doorfd = -1;
2481 2488 client_free(cp);
2482 2489 return (REPOSITORY_DOOR_FAIL_NO_RESOURCES);
2483 2490 }
2484 2491
2485 2492 rc_pg_notify_init(&cp->rc_pg_notify);
2486 2493 rc_notify_info_init(&cp->rc_notify_info);
2487 2494
2488 2495 client_insert(cp);
2489 2496
2490 2497 cp->rc_doorid = info.di_uniquifier;
2491 2498 *out_fd = fd;
2492 2499
2493 2500 return (REPOSITORY_DOOR_SUCCESS);
2494 2501 }
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX