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