1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2000-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This is the main file for the Domain Configuration Server (DCS). 31 * 32 * The DCS is a server that runs on a domain and communicates with 33 * a Domain Configuration Agent (DCA) running on a remote host. The 34 * DCA initiates DR requests that the DCS performs by calling the 35 * appropriate libcfgadm(3LIB) function. 36 * 37 * This file contains functions that receive and process the messages 38 * received from the DCA. It also handles the initialization of the 39 * server and is responsible for starting a concurrent session to 40 * handle each DR request. 41 */ 42 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <unistd.h> 46 #include <string.h> 47 #include <fcntl.h> 48 #include <errno.h> 49 #include <syslog.h> 50 #include <assert.h> 51 #include <signal.h> 52 #include <netdb.h> 53 #include <config_admin.h> 54 #include <sys/param.h> 55 #include <sys/time.h> 56 #include <sys/stat.h> 57 #include <sys/socket.h> 58 59 #include "dcs.h" 60 #include "remote_cfg.h" 61 #include "rdr_param_types.h" 62 #include "rdr_messages.h" 63 #include "rsrc_info.h" 64 65 66 typedef struct { 67 ushort_t major; 68 ushort_t minor; 69 } dcs_ver_t; 70 71 72 /* initialization functions */ 73 static int init_server(struct pollfd *pfd); 74 static void init_signals(void); 75 76 /* message processing functions */ 77 static int invalid_msg(rdr_msg_hdr_t *hdr); 78 79 /* message handling functions */ 80 static int dcs_ses_req(rdr_msg_hdr_t *hdr, cfga_params_t *param); 81 static int dcs_ses_estbl(rdr_msg_hdr_t *hdr, cfga_params_t *param); 82 static int dcs_ses_end(rdr_msg_hdr_t *hdr, cfga_params_t *param); 83 static int dcs_change_state(rdr_msg_hdr_t *hdr, cfga_params_t *param); 84 static int dcs_private_func(rdr_msg_hdr_t *hdr, cfga_params_t *param); 85 static int dcs_test(rdr_msg_hdr_t *hdr, cfga_params_t *param); 86 static int dcs_list_ext(rdr_msg_hdr_t *hdr, cfga_params_t *param); 87 static int dcs_help(rdr_msg_hdr_t *hdr, cfga_params_t *param); 88 static int dcs_ap_id_cmp(rdr_msg_hdr_t *hdr, cfga_params_t *param); 89 static int dcs_abort_cmd(rdr_msg_hdr_t *hdr, cfga_params_t *param); 90 static int dcs_rsrc_info(rdr_msg_hdr_t *hdr, cfga_params_t *param); 91 static int dcs_unknown_op(rdr_msg_hdr_t *hdr, cfga_params_t *param); 92 93 /* local callback functions */ 94 static int dcs_confirm_callback(void *appdata_ptr, const char *message); 95 static int dcs_message_callback(void *appdata_ptr, const char *message); 96 97 /* utility functions */ 98 static dcs_ver_t resolve_version(ushort_t req_major, ushort_t req_minor); 99 static void filter_list_data(int perm, int *nlistp, cfga_list_data_t *linfo); 100 static rdr_list_t *generate_sort_order(cfga_list_data_t *listp, int nlist); 101 static int ldata_compare(const void *ap1, const void *ap2); 102 static int invalid_msg(rdr_msg_hdr_t *hdr); 103 static char *basename(char *path); 104 105 106 /* 107 * Lookup table for handling different message types. This 108 * assumes the ordering of rdr_msg_opcode_t in remote_cfg.h. 109 * If this enum changes, the lookup table must be updated. 110 * 111 * The lookup table handles all _known_ opcodes >= 0. Unsupported 112 * opcodes, or opcodes that should not be received by the 113 * dispatcher are handled by the dcs_unknown_op() function. 114 */ 115 int (*dcs_cmd[])(rdr_msg_hdr_t *, cfga_params_t *) = { 116 dcs_unknown_op, /* 0 is an invalid opcode */ 117 dcs_ses_req, /* RDR_SES_REQ */ 118 dcs_ses_estbl, /* RDR_SES_ESTBL */ 119 dcs_ses_end, /* RDR_SES_END */ 120 dcs_change_state, /* RDR_CONF_CHANGE_STATE */ 121 dcs_private_func, /* RDR_CONF_PRIVATE_FUNC */ 122 dcs_test, /* RDR_CONF_TEST */ 123 dcs_list_ext, /* RDR_CONF_LIST_EXT */ 124 dcs_help, /* RDR_CONF_HELP */ 125 dcs_ap_id_cmp, /* RDR_CONF_AP_ID_CMP */ 126 dcs_abort_cmd, /* RDR_CONF_ABORT_CMD */ 127 dcs_unknown_op, /* RDR_CONF_CONFIRM_CALLBACK */ 128 dcs_unknown_op, /* RDR_CONF_MSG_CALLBACK */ 129 dcs_rsrc_info /* RDR_RSRC_INFO */ 130 }; 131 132 133 /* 134 * ver_supp[] is an array of the supported versions for the network 135 * transport protocol used by the DCA and DCS. Each item in the array 136 * is a pair: { major_version, minor_version }. 137 * 138 * The order of the array is significant. The first element should be 139 * the highest supported version and all successive elements should be 140 * strictly decreasing. 141 */ 142 dcs_ver_t ver_supp[] = { 143 { 1, 0 } 144 }; 145 146 #define DCS_CURR_VER ver_supp[0] 147 148 149 /* 150 * Global Data 151 */ 152 char *cmdname = NULL; /* the name of the executable */ 153 ulong_t dcs_debug = 0; /* control the amount of debugging */ 154 int standalone = 0; /* control standalone mode */ 155 ulong_t max_sessions = DCS_MAX_SESSIONS; /* control maximum active sessions */ 156 int dcsfd = STDIN_FILENO; /* fd for the DCS reserved port */ 157 158 159 /* 160 * main: 161 * 162 * Initialize the DCS and then enter an infinite loop. This loop waits 163 * for connection requests to come and then establishes a connection. 164 * It dispatches the connection to be handled in a concurrent session. 165 */ 166 int 167 main(int argc, char **argv) 168 { 169 int opt; 170 struct timeval tv; 171 struct pollfd dcs_rcv; 172 int newfd; 173 174 175 /* initialize globals */ 176 dcs_debug = DBG_NONE; 177 cmdname = basename(argv[0]); 178 179 /* open log file with unique prefix */ 180 openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON); 181 182 /* 183 * Process command line args 184 */ 185 opterr = 0; /* disable getopt error messages */ 186 while ((opt = getopt(argc, argv, OPT_STR)) != EOF) { 187 188 switch (opt) { 189 190 case 'd': { 191 int usr_debug; 192 char *err_str; 193 194 usr_debug = strtol(optarg, &err_str, 0); 195 196 /* 197 * The err_str parameter will be an 198 * empty string if successful. 199 */ 200 if (*err_str != '\0') { 201 dcs_log_msg(LOG_ERR, DCS_BAD_OPT_ARG, optopt, 202 optarg, "exiting"); 203 (void) rdr_reject(dcsfd); 204 exit(1); 205 } 206 207 dcs_debug = usr_debug; 208 break; 209 } 210 211 case 'S': 212 standalone++; 213 break; 214 215 case 's': { 216 int usr_ses; 217 char *err_str; 218 219 usr_ses = strtol(optarg, &err_str, 0); 220 221 if (usr_ses >= 1) { 222 max_sessions = usr_ses; 223 } else { 224 char behavior_str[MAX_MSG_LEN]; 225 226 snprintf(behavior_str, MAX_MSG_LEN, 227 "using default value (%d)", max_sessions); 228 229 dcs_log_msg(LOG_NOTICE, DCS_BAD_OPT_ARG, optopt, 230 optarg, behavior_str); 231 } 232 233 break; 234 } 235 236 default: 237 dcs_log_msg(LOG_ERR, DCS_BAD_OPT, optopt); 238 (void) rdr_reject(dcsfd); 239 exit(1); 240 241 /* NOTREACHED */ 242 break; 243 } 244 } 245 246 DCS_DBG(DBG_ALL, "initializing %s...", cmdname); 247 248 init_signals(); 249 250 /* must be root */ 251 if (geteuid() != 0) { 252 dcs_log_msg(LOG_ERR, DCS_NO_PRIV); 253 (void) rdr_reject(dcsfd); 254 exit(1); 255 } 256 257 /* 258 * Seed the random number generator for 259 * generating random session identifiers. 260 */ 261 gettimeofday(&tv, NULL); 262 srand48(tv.tv_usec); 263 264 /* initialize our transport endpoint */ 265 if (init_server(&dcs_rcv) == -1) { 266 dcs_log_msg(LOG_ERR, DCS_INIT_ERR); 267 (void) rdr_reject(dcsfd); 268 exit(1); 269 } 270 271 272 DCS_DBG(DBG_ALL, "%s initialized, debug level = 0x%X, " 273 "max sessions = %d", cmdname, dcs_debug, max_sessions); 274 275 /* 276 * Main service loop 277 */ 278 for (;;) { 279 280 /* wait for a connection request */ 281 if (ses_poll(&dcs_rcv, 1, BLOCKFOREVER) == -1) { 282 if (errno != EINTR) { 283 dcs_log_msg(LOG_ERR, DCS_INT_ERR, "poll", 284 strerror(errno)); 285 } 286 continue; 287 } 288 289 /* attempt to connect */ 290 newfd = rdr_connect_srv(dcs_rcv.fd); 291 292 if ((newfd == RDR_ERROR) || (newfd == RDR_NET_ERR)) { 293 dcs_log_msg(LOG_ERR, DCS_CONNECT_ERR); 294 continue; 295 } 296 297 298 /* process the session concurrently */ 299 if (ses_start(newfd) == -1) { 300 dcs_log_msg(LOG_ERR, DCS_SES_HAND_ERR); 301 (void) rdr_close(newfd); 302 break; 303 } 304 } 305 306 close(dcs_rcv.fd); 307 return (1); 308 } 309 310 311 /* 312 * init_server: 313 * 314 * Perform all the operations that are required to initialize the 315 * transport endpoint used by the DCS. After this routine succeeds, 316 * the DCS is ready to accept session requests on its well known 317 * port. 318 */ 319 static int 320 init_server(struct pollfd *pfd) 321 { 322 struct servent *se; 323 struct sockaddr_storage ss; 324 struct sockaddr_in *sin; 325 struct sockaddr_in6 *sin6; 326 int req_port; 327 int act_port; 328 int init_status; 329 int num_sock_opts; 330 int sock_opts[] = { SO_REUSEADDR }; 331 332 333 assert(pfd); 334 335 /* 336 * In standalone mode, we have to initialize the transport 337 * endpoint for our reserved port. In daemon mode, inetd 338 * starts the DCS and hands off STDIN_FILENO connected to 339 * our reserved port. 340 */ 341 342 if (standalone) { 343 /* in standalone mode, init fd for reserved port */ 344 if ((dcsfd = rdr_open(AF_INET6)) == -1) { 345 DCS_DBG(DBG_ALL, "rdr_open failed"); 346 } 347 } 348 349 pfd->fd = dcsfd; 350 pfd->events = POLLIN | POLLPRI; 351 pfd->revents = 0; 352 353 /* 354 * Look up our service to get the reserved port number 355 */ 356 if ((se = getservbyname(DCS_SERVICE, "tcp")) == NULL) { 357 dcs_log_msg(LOG_NOTICE, DCS_NO_SERV, DCS_SERVICE); 358 359 /* use the known port if service wasn't found */ 360 req_port = SUN_DR_PORT; 361 } else { 362 req_port = se->s_port; 363 } 364 365 /* initialize our local address */ 366 sin6 = (struct sockaddr_in6 *)&ss; 367 (void) memset(sin6, 0, sizeof (*sin6)); 368 sin6->sin6_family = AF_INET6; 369 sin6->sin6_port = htons(req_port); 370 sin6->sin6_addr = in6addr_any; 371 372 num_sock_opts = sizeof (sock_opts) / sizeof (*sock_opts); 373 374 init_status = rdr_init(pfd->fd, (struct sockaddr *)sin6, 375 sock_opts, num_sock_opts, DCS_BACKLOG); 376 377 if (init_status != RDR_OK) { 378 return (-1); 379 } 380 381 switch (ss.ss_family) { 382 case AF_INET: 383 DCS_DBG(DBG_ALL, "using AF_INET socket"); 384 sin = (struct sockaddr_in *)&ss; 385 act_port = ntohs(sin->sin_port); 386 break; 387 case AF_INET6: 388 DCS_DBG(DBG_ALL, "using AF_INET6 socket"); 389 /* sin6 already set correctly */ 390 act_port = ntohs(sin6->sin6_port); 391 break; 392 default: 393 DCS_DBG(DBG_ALL, "unknown socket type"); 394 return (-1); 395 } 396 397 /* check that we got the requested port */ 398 if (req_port != act_port) { 399 dcs_log_msg(LOG_ERR, DCS_NO_PORT, req_port); 400 return (-1); 401 } 402 403 return (0); 404 } 405 406 407 /* 408 * init_signals: 409 * 410 * Initialize signals for the current session. All signals will be 411 * blocked with two possible exceptions. SIGINT is not blocked in 412 * standalone mode, and ses_init_signals() is called to selectively 413 * unblock any signals required to handle concurrent sessions. 414 */ 415 static void 416 init_signals(void) 417 { 418 sigset_t mask; 419 420 421 /* block all signals */ 422 sigfillset(&mask); 423 424 /* in standalone, allow user to abort */ 425 if (standalone) { 426 sigdelset(&mask, SIGINT); 427 } 428 429 ses_init_signals(&mask); 430 431 (void) sigprocmask(SIG_BLOCK, &mask, NULL); 432 } 433 434 435 /* 436 * dcs_dispatch_message: 437 * 438 * This function dispatches a message to the correct function. The 439 * correct handler is determined by the opcode field of the message 440 * header. 441 */ 442 int 443 dcs_dispatch_message(rdr_msg_hdr_t *hdr, cfga_params_t *params) 444 { 445 session_t *sp; 446 447 448 assert(hdr); 449 assert(params); 450 451 /* get the current session information */ 452 if ((sp = curr_ses()) == NULL) { 453 ses_close(DCS_ERROR); 454 return (-1); 455 } 456 457 /* check the message */ 458 if (invalid_msg(hdr)) { 459 dcs_log_msg(LOG_ERR, DCS_MSG_INVAL); 460 ses_close(DCS_MSG_INVAL); 461 return (-1); 462 } 463 464 /* save the current message */ 465 sp->curr_msg.hdr = hdr; 466 sp->curr_msg.params = params; 467 468 /* 469 * hdr->message_opcode is unsigned so don't need 470 * to check for values less than zero 471 */ 472 if (hdr->message_opcode >= RDR_NUM_OPS) { 473 dcs_unknown_op(hdr, params); 474 ses_close(DCS_MSG_INVAL); 475 return (-1); 476 } 477 478 PRINT_MSG_DBG(DCS_RECEIVE, hdr); 479 480 /* dispatch the message */ 481 if ((*dcs_cmd[hdr->message_opcode])(hdr, params) == -1) { 482 dcs_log_msg(LOG_ERR, DCS_OP_FAILED); 483 ses_close(DCS_ERROR); 484 return (-1); 485 } 486 487 return (0); 488 } 489 490 491 /* 492 * init_msg: 493 * 494 * Initialize the message header with information from the current 495 * session. Fields not set directly are initialized to zero. 496 */ 497 void 498 init_msg(rdr_msg_hdr_t *hdr) 499 { 500 session_t *sp; 501 502 503 assert(hdr); 504 505 /* get the current session information */ 506 if ((sp = curr_ses()) == NULL) { 507 ses_close(DCS_ERROR); 508 return; 509 } 510 511 (void) memset(hdr, 0, sizeof (rdr_msg_hdr_t)); 512 513 /* set the session information */ 514 hdr->random_req = sp->random_req; 515 hdr->random_resp = sp->random_resp; 516 517 /* set the version being used */ 518 hdr->major_version = sp->major_version; 519 hdr->minor_version = sp->minor_version; 520 } 521 522 523 /* 524 * invalid_msg: 525 * 526 * Check if the message is valid for the current session. This 527 * is accomplished by checking various information in the header 528 * against the information for the current session. 529 */ 530 static int 531 invalid_msg(rdr_msg_hdr_t *hdr) 532 { 533 session_t *sp; 534 535 536 assert(hdr); 537 538 /* get the current session information */ 539 if ((sp = curr_ses()) == NULL) { 540 ses_close(DCS_ERROR); 541 return (-1); 542 } 543 544 /* 545 * Only perform the following checks if the message 546 * is not a session request. The information to check 547 * will not be set at the time a session request is 548 * received. 549 */ 550 if (hdr->message_opcode != RDR_SES_REQ) { 551 552 /* check major and minor version */ 553 if ((sp->major_version != hdr->major_version) || 554 (sp->minor_version != hdr->minor_version)) { 555 DCS_DBG(DBG_MSG, "unsupported version %d.%d", 556 hdr->major_version, hdr->minor_version); 557 return (-1); 558 } 559 560 /* check session identifiers */ 561 if ((sp->random_req != hdr->random_req) || 562 (sp->random_resp != hdr->random_resp)) { 563 DCS_DBG(DBG_MSG, "invalid session identifiers: " 564 "<%d, %d>", hdr->random_req, hdr->random_resp); 565 return (-1); 566 } 567 } 568 569 return (0); 570 } 571 572 573 /* 574 * dcs_ses_req: 575 * 576 * Handle a session request message (RDR_SES_REQ). 577 */ 578 static int 579 dcs_ses_req(rdr_msg_hdr_t *hdr, cfga_params_t *param) 580 { 581 session_t *sp; 582 rdr_msg_hdr_t reply_hdr; 583 cfga_params_t reply_param; 584 dcs_ver_t act_ver; 585 int snd_status; 586 static char *op_name = "session request"; 587 588 589 assert(hdr); 590 assert(param); 591 592 /* get the current session information */ 593 if ((sp = curr_ses()) == NULL) { 594 ses_close(DCS_ERROR); 595 return (-1); 596 } 597 598 /* make sure that a session hasn't been requested yet */ 599 if (sp->state != DCS_CONNECTED) { 600 dcs_log_msg(LOG_ERR, DCS_SES_SEQ_INVAL); 601 ses_close(DCS_SES_SEQ_INVAL); 602 return (-1); 603 } 604 605 ses_setlocale(param->req.locale_str); 606 607 /* get the best matching version supported */ 608 act_ver = resolve_version(hdr->major_version, hdr->minor_version); 609 610 /* initialize session information */ 611 sp->random_req = hdr->random_req; 612 sp->major_version = act_ver.major; 613 sp->minor_version = act_ver.minor; 614 615 /* prepare header information */ 616 init_msg(&reply_hdr); 617 reply_hdr.message_opcode = RDR_SES_REQ; 618 reply_hdr.data_type = RDR_REPLY; 619 reply_hdr.status = DCS_OK; 620 621 /* prepare session request specific data */ 622 (void) memset(&reply_param, 0, sizeof (cfga_params_t)); 623 reply_param.req.session_id = sp->id; 624 625 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 626 627 /* send the message */ 628 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, &reply_param, 629 DCS_SND_TIMEOUT); 630 631 if (snd_status == RDR_ABORTED) { 632 abort_handler(); 633 } 634 635 if (snd_status != RDR_OK) { 636 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 637 return (-1); 638 } 639 640 sp->state = DCS_SES_REQ; 641 return (0); 642 } 643 644 645 /* 646 * dcs_ses_estbl: 647 * 648 * Handle a session establishment message (RDR_SES_ESTBL). 649 */ 650 /* ARGSUSED */ 651 static int 652 dcs_ses_estbl(rdr_msg_hdr_t *hdr, cfga_params_t *param) 653 { 654 session_t *sp; 655 dcs_ver_t act_ver; 656 657 658 assert(hdr); 659 assert(param); 660 661 /* get the current session information */ 662 if ((sp = curr_ses()) == NULL) { 663 ses_close(DCS_ERROR); 664 return (-1); 665 } 666 667 /* 668 * Make sure that a session has not been 669 * established yet, and that a session 670 * request has already been processed. 671 */ 672 if (sp->state != DCS_SES_REQ) { 673 dcs_log_msg(LOG_ERR, DCS_SES_SEQ_INVAL); 674 ses_close(DCS_SES_SEQ_INVAL); 675 return (-1); 676 } 677 678 /* get the best matching version supported */ 679 act_ver = resolve_version(hdr->major_version, hdr->minor_version); 680 681 if ((act_ver.major != hdr->major_version) || 682 (act_ver.minor != hdr->minor_version)) { 683 684 /* end the session because protocol not supported */ 685 dcs_log_msg(LOG_ERR, DCS_VER_INVAL, hdr->major_version, 686 hdr->minor_version); 687 ses_close(DCS_VER_INVAL); 688 return (-1); 689 } 690 691 DCS_DBG(DBG_SES, "Session Established"); 692 sp->state = DCS_SES_ESTBL; 693 694 return (0); 695 } 696 697 698 /* 699 * dcs_ses_end: 700 * 701 * Handle a session end message (RDR_SES_END). 702 */ 703 static int 704 dcs_ses_end(rdr_msg_hdr_t *hdr, cfga_params_t *param) 705 { 706 session_t *sp; 707 rdr_msg_hdr_t reply_hdr; 708 cfga_params_t reply_param; 709 int snd_status; 710 static char *op_name = "session end"; 711 712 713 assert(hdr); 714 assert(param); 715 716 /* get the current session information */ 717 if ((sp = curr_ses()) == NULL) { 718 ses_close(DCS_ERROR); 719 return (-1); 720 } 721 722 /* 723 * Session end is valid from any state. However, only 724 * send back a reply if the error code is zero. A non-zero 725 * error code indicates that the session is being terminated 726 * under an error condition, and no acknowledgement is 727 * required. 728 */ 729 if (param->end.error_code == 0) { 730 731 /* prepare header information */ 732 init_msg(&reply_hdr); 733 reply_hdr.message_opcode = RDR_SES_END; 734 reply_hdr.data_type = RDR_REPLY; 735 reply_hdr.status = DCS_OK; 736 737 /* return empty data - no information needed in reply */ 738 (void) memset(&reply_param, 0, sizeof (cfga_params_t)); 739 740 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 741 742 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, &reply_param, 743 DCS_SND_TIMEOUT); 744 745 if (snd_status == RDR_ABORTED) { 746 abort_handler(); 747 } 748 749 if (snd_status != RDR_OK) { 750 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 751 } 752 } 753 754 sp->state = DCS_SES_END; 755 756 return ((snd_status != RDR_OK) ? -1 : 0); 757 } 758 759 760 /* 761 * dcs_change_state: 762 * 763 * Handle a change state request message (RDR_CONF_CHANGE_STATE). 764 */ 765 static int 766 dcs_change_state(rdr_msg_hdr_t *hdr, cfga_params_t *param) 767 { 768 session_t *sp; 769 rdr_msg_hdr_t reply_hdr; 770 change_state_params_t *op_data; 771 struct cfga_confirm local_conf_cb; 772 struct cfga_msg local_msg_cb; 773 int cfga_status = 0; 774 int snd_status; 775 char *err_str; 776 unsigned int curr_attempt; 777 unsigned int num_attempts; 778 char retry_msg[MAX_MSG_LEN]; 779 static char *op_name = "config_change_state"; 780 781 782 assert(hdr); 783 assert(param); 784 785 /* get the current session information */ 786 if ((sp = curr_ses()) == NULL) { 787 ses_close(DCS_ERROR); 788 return (-1); 789 } 790 791 op_data = ¶m->change; 792 793 /* make sure we have a session established */ 794 if (sp->state != DCS_SES_ESTBL) { 795 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 796 ses_close(DCS_NO_SES_ERR); 797 return (-1); 798 } 799 800 /* initialize local confirm callback */ 801 local_conf_cb.confirm = dcs_confirm_callback; 802 local_conf_cb.appdata_ptr = (void *)op_data->confp; 803 804 /* initialize local message callback */ 805 local_msg_cb.message_routine = dcs_message_callback; 806 local_msg_cb.appdata_ptr = (void *)op_data->msgp; 807 808 /* verify retry value */ 809 if (op_data->retries < 0) { 810 dcs_log_msg(LOG_NOTICE, DCS_BAD_RETRY_VAL, op_data->retries); 811 op_data->retries = 0; 812 } 813 814 /* verify timeout value */ 815 if (op_data->timeval < 0) { 816 dcs_log_msg(LOG_NOTICE, DCS_BAD_TIME_VAL, op_data->timeval); 817 op_data->timeval = 0; 818 } 819 820 num_attempts = 1 + op_data->retries; 821 curr_attempt = 0; 822 823 while (curr_attempt < num_attempts) { 824 825 /* don't sleep the first time around */ 826 if (curr_attempt != 0) { 827 828 /* log the error message and alert the user */ 829 err_str = dcs_cfga_str(op_data->errstring, cfga_status); 830 if (err_str) { 831 dcs_log_msg(LOG_ERR, DCS_CFGA_ERR, op_name, 832 err_str); 833 dcs_message_callback((void *)op_data->msgp, 834 err_str); 835 free((void *)err_str); 836 } else { 837 dcs_log_msg(LOG_ERR, DCS_CFGA_UNKNOWN); 838 dcs_message_callback((void *)op_data->msgp, 839 dcs_strerror(DCS_CFGA_UNKNOWN)); 840 } 841 842 if (op_data->errstring && *op_data->errstring) { 843 free((void *)*op_data->errstring); 844 *op_data->errstring = NULL; 845 } 846 847 /* sleep with abort enabled */ 848 ses_sleep(op_data->timeval); 849 850 /* log the retry attempt and alert the user */ 851 dcs_log_msg(LOG_INFO, DCS_RETRY, curr_attempt); 852 snprintf(retry_msg, MAX_MSG_LEN, 853 dcs_strerror(DCS_RETRY), curr_attempt); 854 dcs_message_callback((void *)op_data->msgp, retry_msg); 855 } 856 857 sp->state = DCS_CONF_PENDING; 858 859 /* 860 * Call into libcfgadm 861 */ 862 ses_abort_enable(); 863 864 cfga_status = config_change_state(op_data->state_change, 865 op_data->num_ap_ids, op_data->ap_ids, op_data->options, 866 &local_conf_cb, &local_msg_cb, op_data->errstring, 867 op_data->flags); 868 869 ses_abort_disable(); 870 871 /* 872 * Retry only the operations that have a chance to 873 * succeed if retried. All libcfgadm errors not 874 * included below will always fail, regardless of 875 * a retry. 876 */ 877 if ((cfga_status != CFGA_BUSY) && 878 (cfga_status != CFGA_SYSTEM_BUSY) && 879 (cfga_status != CFGA_ERROR)) { 880 break; 881 } 882 883 /* prepare for another attempt */ 884 ++curr_attempt; 885 } 886 887 sp->state = DCS_CONF_DONE; 888 889 /* log any libcfgadm errors */ 890 if (cfga_status != CFGA_OK) { 891 err_str = dcs_cfga_str(op_data->errstring, cfga_status); 892 if (err_str) { 893 dcs_log_msg(LOG_ERR, DCS_CFGA_ERR, op_name, err_str); 894 free((void *)err_str); 895 } 896 } 897 898 /* prepare header information */ 899 init_msg(&reply_hdr); 900 reply_hdr.message_opcode = RDR_CONF_CHANGE_STATE; 901 reply_hdr.data_type = RDR_REPLY; 902 reply_hdr.status = cfga_status; 903 904 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 905 906 /* send the message */ 907 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 908 909 if (snd_status == RDR_ABORTED) { 910 abort_handler(); 911 } 912 913 if (snd_status != RDR_OK) { 914 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 915 } 916 917 /* clean up */ 918 if (op_data->errstring && *op_data->errstring) { 919 free((void *)*op_data->errstring); 920 *op_data->errstring = NULL; 921 } 922 923 return ((snd_status != RDR_OK) ? -1 : 0); 924 } 925 926 927 /* 928 * dcs_private_func: 929 * 930 * Handle a private function request message (RDR_CONF_PRIVATE_FUNC). 931 */ 932 static int 933 dcs_private_func(rdr_msg_hdr_t *hdr, cfga_params_t *param) 934 { 935 session_t *sp; 936 rdr_msg_hdr_t reply_hdr; 937 private_func_params_t *op_data; 938 struct cfga_confirm local_conf_cb; 939 struct cfga_msg local_msg_cb; 940 int cfga_status; 941 int snd_status; 942 char *err_str; 943 static char *op_name = "config_private_func"; 944 945 946 assert(hdr); 947 assert(param); 948 949 /* get the current session information */ 950 if ((sp = curr_ses()) == NULL) { 951 ses_close(DCS_ERROR); 952 return (-1); 953 } 954 955 op_data = ¶m->priv; 956 957 /* make sure we have a session established */ 958 if (sp->state != DCS_SES_ESTBL) { 959 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 960 ses_close(DCS_NO_SES_ERR); 961 return (-1); 962 } 963 964 /* initialize local confirm callback */ 965 local_conf_cb.confirm = dcs_confirm_callback; 966 local_conf_cb.appdata_ptr = (void *)op_data->confp; 967 968 /* initialize local message callback */ 969 local_msg_cb.message_routine = dcs_message_callback; 970 local_msg_cb.appdata_ptr = (void *)op_data->msgp; 971 972 sp->state = DCS_CONF_PENDING; 973 974 /* 975 * Call into libcfgadm 976 */ 977 ses_abort_enable(); 978 979 cfga_status = config_private_func(op_data->function, 980 op_data->num_ap_ids, op_data->ap_ids, op_data->options, 981 &local_conf_cb, &local_msg_cb, op_data->errstring, op_data->flags); 982 983 ses_abort_disable(); 984 985 sp->state = DCS_CONF_DONE; 986 987 /* log any libcfgadm errors */ 988 if (cfga_status != CFGA_OK) { 989 err_str = dcs_cfga_str(op_data->errstring, cfga_status); 990 if (err_str) { 991 dcs_log_msg(LOG_ERR, DCS_CFGA_ERR, op_name, err_str); 992 free((void *)err_str); 993 } 994 } 995 996 /* prepare header information */ 997 init_msg(&reply_hdr); 998 reply_hdr.message_opcode = RDR_CONF_PRIVATE_FUNC; 999 reply_hdr.data_type = RDR_REPLY; 1000 reply_hdr.status = cfga_status; 1001 1002 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1003 1004 /* send the message */ 1005 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1006 1007 if (snd_status == RDR_ABORTED) { 1008 abort_handler(); 1009 } 1010 1011 if (snd_status != RDR_OK) { 1012 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1013 } 1014 1015 if (op_data->errstring && *op_data->errstring) { 1016 free((void *)*op_data->errstring); 1017 *op_data->errstring = NULL; 1018 } 1019 1020 return ((snd_status != RDR_OK) ? -1 : 0); 1021 } 1022 1023 1024 /* 1025 * dcs_test: 1026 * 1027 * Handle a test request message (RDR_CONF_TEST). 1028 */ 1029 static int 1030 dcs_test(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1031 { 1032 session_t *sp; 1033 rdr_msg_hdr_t reply_hdr; 1034 test_params_t *op_data; 1035 struct cfga_msg local_msg_cb; 1036 int cfga_status; 1037 int snd_status; 1038 char *err_str; 1039 static char *op_name = "config_test"; 1040 1041 1042 assert(hdr); 1043 assert(param); 1044 1045 /* get the current session information */ 1046 if ((sp = curr_ses()) == NULL) { 1047 ses_close(DCS_ERROR); 1048 return (-1); 1049 } 1050 1051 op_data = ¶m->test; 1052 1053 /* make sure we have a session established */ 1054 if (sp->state != DCS_SES_ESTBL) { 1055 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 1056 ses_close(DCS_NO_SES_ERR); 1057 return (-1); 1058 } 1059 1060 /* initialize local message callback */ 1061 local_msg_cb.message_routine = dcs_message_callback; 1062 local_msg_cb.appdata_ptr = op_data->msgp; 1063 1064 sp->state = DCS_CONF_PENDING; 1065 1066 /* 1067 * Call into libcfgadm 1068 */ 1069 ses_abort_enable(); 1070 1071 cfga_status = config_test(op_data->num_ap_ids, op_data->ap_ids, 1072 op_data->options, &local_msg_cb, op_data->errstring, 1073 op_data->flags); 1074 1075 ses_abort_disable(); 1076 1077 sp->state = DCS_CONF_DONE; 1078 1079 /* log any libcfgadm errors */ 1080 if (cfga_status != CFGA_OK) { 1081 err_str = dcs_cfga_str(op_data->errstring, cfga_status); 1082 if (err_str) { 1083 dcs_log_msg(LOG_ERR, DCS_CFGA_ERR, op_name, err_str); 1084 free((void *)err_str); 1085 } 1086 } 1087 1088 /* prepare header information */ 1089 init_msg(&reply_hdr); 1090 reply_hdr.message_opcode = RDR_CONF_TEST; 1091 reply_hdr.data_type = RDR_REPLY; 1092 reply_hdr.status = cfga_status; 1093 1094 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1095 1096 /* send the message */ 1097 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1098 1099 if (snd_status == RDR_ABORTED) { 1100 abort_handler(); 1101 } 1102 1103 if (snd_status != RDR_OK) { 1104 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1105 } 1106 1107 if (op_data->errstring && *op_data->errstring) { 1108 free((void *)*op_data->errstring); 1109 *op_data->errstring = NULL; 1110 } 1111 1112 return ((snd_status != RDR_OK) ? -1 : 0); 1113 } 1114 1115 1116 /* 1117 * dcs_list_ext: 1118 * 1119 * Handle a list request message (RDR_CONF_LIST_EXT). 1120 */ 1121 static int 1122 dcs_list_ext(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1123 { 1124 session_t *sp; 1125 rdr_msg_hdr_t reply_hdr; 1126 list_ext_params_t *op_data; 1127 int cfga_status; 1128 int snd_status; 1129 char *err_str; 1130 static char *op_name = "config_list_ext"; 1131 cfga_list_data_t *ap_ids; 1132 1133 1134 assert(hdr); 1135 assert(param); 1136 1137 /* get the current session information */ 1138 if ((sp = curr_ses()) == NULL) { 1139 ses_close(DCS_ERROR); 1140 return (-1); 1141 } 1142 1143 op_data = ¶m->list_ext; 1144 1145 /* make sure we have a session established */ 1146 if (sp->state != DCS_SES_ESTBL) { 1147 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 1148 ses_close(DCS_NO_SES_ERR); 1149 return (-1); 1150 } 1151 1152 /* 1153 * Make sure that we can retrieve the data 1154 * from libcfgadm. If not, report the error. 1155 */ 1156 if (op_data->ap_id_list == NULL) { 1157 dcs_log_msg(LOG_ERR, DCS_MSG_INVAL); 1158 ses_close(DCS_MSG_INVAL); 1159 return (-1); 1160 } 1161 1162 sp->state = DCS_CONF_PENDING; 1163 1164 /* 1165 * Call into libcfgadm 1166 */ 1167 ses_abort_enable(); 1168 1169 cfga_status = config_list_ext(op_data->num_ap_ids, op_data->ap_ids, 1170 &ap_ids, op_data->nlist, op_data->options, op_data->listopts, 1171 op_data->errstring, op_data->flags); 1172 1173 ses_abort_disable(); 1174 1175 sp->state = DCS_CONF_DONE; 1176 1177 /* 1178 * Log any libcfgadm errors at a low priority level. 1179 * Since a status request does not modify the system 1180 * in any way, we do not need to worry about these 1181 * errors here on the host. 1182 */ 1183 if (cfga_status != CFGA_OK) { 1184 err_str = dcs_cfga_str(op_data->errstring, cfga_status); 1185 if (err_str) { 1186 dcs_log_msg(LOG_INFO, DCS_CFGA_ERR, op_name, err_str); 1187 free((void *)err_str); 1188 } 1189 } 1190 1191 /* 1192 * Filter ap ids to return only appropriate information 1193 */ 1194 filter_list_data(op_data->permissions, op_data->nlist, ap_ids); 1195 1196 /* if all aps were filtered out, return an error */ 1197 if ((cfga_status == CFGA_OK) && (*op_data->nlist == 0)) { 1198 cfga_status = CFGA_APID_NOEXIST; 1199 } 1200 1201 /* calculate the sort order */ 1202 if (cfga_status == CFGA_OK) { 1203 1204 *op_data->ap_id_list = generate_sort_order(ap_ids, 1205 *op_data->nlist); 1206 1207 if (*op_data->ap_id_list == NULL) { 1208 cfga_status = CFGA_LIB_ERROR; 1209 } 1210 } 1211 1212 /* ensure that nlist is 0 for errors */ 1213 if (cfga_status != CFGA_OK) { 1214 *op_data->nlist = 0; 1215 } 1216 1217 /* prepare header information */ 1218 init_msg(&reply_hdr); 1219 reply_hdr.message_opcode = RDR_CONF_LIST_EXT; 1220 reply_hdr.data_type = RDR_REPLY; 1221 reply_hdr.status = cfga_status; 1222 1223 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1224 1225 /* send the message */ 1226 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1227 1228 if (snd_status == RDR_ABORTED) { 1229 abort_handler(); 1230 } 1231 1232 if (snd_status != RDR_OK) { 1233 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1234 } 1235 1236 if (op_data->errstring && *op_data->errstring) { 1237 free((void *)*op_data->errstring); 1238 *op_data->errstring = NULL; 1239 } 1240 1241 if (ap_ids != NULL) { 1242 free((void *)ap_ids); 1243 } 1244 1245 return ((snd_status != RDR_OK) ? -1 : 0); 1246 } 1247 1248 1249 /* 1250 * dcs_help: 1251 * 1252 * Handle a help request message (RDR_CONF_HELP). 1253 */ 1254 static int 1255 dcs_help(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1256 { 1257 session_t *sp; 1258 rdr_msg_hdr_t reply_hdr; 1259 help_params_t *op_data; 1260 struct cfga_msg local_msg_cb; 1261 int cfga_status; 1262 int snd_status; 1263 char *err_str; 1264 static char *op_name = "config_help"; 1265 1266 1267 assert(hdr); 1268 assert(param); 1269 1270 /* get the current session information */ 1271 if ((sp = curr_ses()) == NULL) { 1272 ses_close(DCS_ERROR); 1273 return (-1); 1274 } 1275 1276 op_data = ¶m->help; 1277 1278 /* make sure we have a session established */ 1279 if (sp->state != DCS_SES_ESTBL) { 1280 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 1281 ses_close(DCS_NO_SES_ERR); 1282 return (-1); 1283 } 1284 1285 /* initialize local message callback */ 1286 local_msg_cb.message_routine = dcs_message_callback; 1287 local_msg_cb.appdata_ptr = op_data->msgp; 1288 1289 sp->state = DCS_CONF_PENDING; 1290 1291 /* 1292 * Call into libcfgadm 1293 */ 1294 ses_abort_enable(); 1295 1296 cfga_status = config_help(op_data->num_ap_ids, op_data->ap_ids, 1297 &local_msg_cb, op_data->options, op_data->flags); 1298 1299 ses_abort_disable(); 1300 1301 sp->state = DCS_CONF_DONE; 1302 1303 /* 1304 * Log any libcfgadm errors at a low priority level. 1305 * Since a help request does not modify the system 1306 * in any way, we do not need to worry about these 1307 * errors here on the host. 1308 */ 1309 if (cfga_status != CFGA_OK) { 1310 err_str = dcs_cfga_str(NULL, cfga_status); 1311 if (err_str) { 1312 dcs_log_msg(LOG_INFO, DCS_CFGA_ERR, op_name, err_str); 1313 free((void *)err_str); 1314 } 1315 } 1316 1317 /* prepare header information */ 1318 init_msg(&reply_hdr); 1319 reply_hdr.message_opcode = RDR_CONF_HELP; 1320 reply_hdr.data_type = RDR_REPLY; 1321 reply_hdr.status = cfga_status; 1322 1323 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1324 1325 /* send the message */ 1326 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1327 1328 if (snd_status == RDR_ABORTED) { 1329 abort_handler(); 1330 } 1331 1332 if (snd_status != RDR_OK) { 1333 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1334 } 1335 1336 return ((snd_status != RDR_OK) ? -1 : 0); 1337 } 1338 1339 1340 /* 1341 * dcs_ap_id_cmp: 1342 * 1343 * Handle an attachment point comparison request message (RDR_AP_ID_CMP). 1344 */ 1345 static int 1346 dcs_ap_id_cmp(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1347 { 1348 session_t *sp; 1349 rdr_msg_hdr_t reply_hdr; 1350 ap_id_cmp_params_t *op_data; 1351 int snd_status; 1352 int cmp_result; 1353 static char *op_name = "config_ap_id_cmp"; 1354 1355 1356 assert(hdr); 1357 assert(param); 1358 1359 /* get the current session information */ 1360 if ((sp = curr_ses()) == NULL) { 1361 ses_close(DCS_ERROR); 1362 return (-1); 1363 } 1364 1365 op_data = ¶m->cmp; 1366 1367 /* make sure we have a session established */ 1368 if (sp->state != DCS_SES_ESTBL) { 1369 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 1370 ses_close(DCS_NO_SES_ERR); 1371 return (-1); 1372 } 1373 1374 sp->state = DCS_CONF_PENDING; 1375 1376 /* 1377 * Call into libcfgadm 1378 */ 1379 ses_abort_enable(); 1380 1381 cmp_result = config_ap_id_cmp(op_data->ap_log_id1, op_data->ap_log_id2); 1382 1383 ses_abort_disable(); 1384 1385 sp->state = DCS_CONF_DONE; 1386 1387 /* prepare header information */ 1388 init_msg(&reply_hdr); 1389 reply_hdr.message_opcode = RDR_CONF_AP_ID_CMP; 1390 reply_hdr.data_type = RDR_REPLY; 1391 1392 /* 1393 * Return result of comparison as error code. 1394 * Since all values are valid, it is impossible 1395 * to report an error. 1396 */ 1397 reply_hdr.status = cmp_result; 1398 1399 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1400 1401 /* send the message */ 1402 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1403 1404 if (snd_status == RDR_ABORTED) { 1405 abort_handler(); 1406 } 1407 1408 if (snd_status != RDR_OK) { 1409 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1410 } 1411 1412 return ((snd_status != RDR_OK) ? -1 : 0); 1413 } 1414 1415 1416 /* 1417 * dcs_abort_cmd: 1418 * 1419 * Handle an abort request message (RDR_CONF_ABORT_CMD). 1420 */ 1421 /* ARGSUSED */ 1422 static int 1423 dcs_abort_cmd(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1424 { 1425 session_t *sp; 1426 rdr_msg_hdr_t reply_hdr; 1427 abort_cmd_params_t *op_data; 1428 int op_status = RDR_SUCCESS; 1429 int snd_status; 1430 static char *op_name = "abort command"; 1431 1432 1433 assert(hdr); 1434 assert(param); 1435 1436 /* get the current session information */ 1437 if ((sp = curr_ses()) == NULL) { 1438 ses_close(DCS_ERROR); 1439 return (-1); 1440 } 1441 1442 op_data = (abort_cmd_params_t *)param; 1443 1444 op_status = ses_abort(op_data->session_id); 1445 1446 if (op_status == -1) { 1447 dcs_log_msg(LOG_ERR, DCS_ABORT_ERR, op_data->session_id); 1448 } 1449 1450 /* prepare header information */ 1451 init_msg(&reply_hdr); 1452 reply_hdr.message_opcode = RDR_CONF_ABORT_CMD; 1453 reply_hdr.data_type = RDR_REPLY; 1454 reply_hdr.status = op_status; 1455 1456 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1457 1458 /* send the message */ 1459 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1460 1461 if (snd_status == RDR_ABORTED) { 1462 abort_handler(); 1463 } 1464 1465 if (snd_status != RDR_OK) { 1466 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1467 } 1468 1469 sp->state = DCS_CONF_DONE; 1470 1471 return ((snd_status != RDR_OK) ? -1 : 0); 1472 } 1473 1474 1475 /* 1476 * dcs_rsrc_info: 1477 * 1478 * Handle a resource info request message (RDR_RSRC_INFO). 1479 */ 1480 static int 1481 dcs_rsrc_info(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1482 { 1483 session_t *sp; 1484 rdr_msg_hdr_t reply_hdr; 1485 rsrc_info_params_t *op_data; 1486 int rsrc_status; 1487 int snd_status; 1488 static char *op_name = "resource info init"; 1489 1490 assert(hdr); 1491 assert(param); 1492 1493 /* get the current session information */ 1494 if ((sp = curr_ses()) == NULL) { 1495 ses_close(DCS_ERROR); 1496 return (-1); 1497 } 1498 1499 op_data = (rsrc_info_params_t *)¶m->rsrc_info; 1500 1501 /* make sure we have a session established */ 1502 if (sp->state != DCS_SES_ESTBL) { 1503 dcs_log_msg(LOG_ERR, DCS_NO_SES_ESTBL, op_name); 1504 ses_close(DCS_NO_SES_ERR); 1505 return (-1); 1506 } 1507 1508 sp->state = DCS_CONF_PENDING; 1509 1510 /* 1511 * Request resource info data. 1512 */ 1513 ses_abort_enable(); 1514 1515 rsrc_status = ri_init(op_data->num_ap_ids, op_data->ap_ids, 1516 op_data->flags, &op_data->hdl); 1517 1518 ses_abort_disable(); 1519 1520 sp->state = DCS_CONF_DONE; 1521 1522 /* log errors */ 1523 if (rsrc_status != RI_SUCCESS) { 1524 dcs_log_msg(LOG_ERR, DCS_RSRC_ERR, rsrc_status); 1525 } 1526 1527 /* prepare header information */ 1528 init_msg(&reply_hdr); 1529 reply_hdr.message_opcode = RDR_RSRC_INFO; 1530 reply_hdr.data_type = RDR_REPLY; 1531 reply_hdr.status = rsrc_status; 1532 1533 PRINT_MSG_DBG(DCS_SEND, &reply_hdr); 1534 1535 /* send the message */ 1536 snd_status = rdr_snd_msg(sp->fd, &reply_hdr, param, DCS_SND_TIMEOUT); 1537 1538 if (snd_status == RDR_ABORTED) { 1539 abort_handler(); 1540 } 1541 1542 if (snd_status != RDR_OK) { 1543 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1544 } 1545 1546 ri_fini(op_data->hdl); 1547 1548 return ((snd_status != RDR_OK) ? -1 : 0); 1549 } 1550 1551 1552 /* 1553 * dcs_unknown_op: 1554 * 1555 * Handle all unknown requests. 1556 */ 1557 /* ARGSUSED */ 1558 static int 1559 dcs_unknown_op(rdr_msg_hdr_t *hdr, cfga_params_t *param) 1560 { 1561 session_t *sp; 1562 1563 1564 assert(hdr); 1565 assert(param); 1566 1567 assert(hdr); 1568 1569 /* get the current session information */ 1570 if ((sp = curr_ses()) == NULL) { 1571 ses_close(DCS_ERROR); 1572 return (-1); 1573 } 1574 1575 dcs_log_msg(LOG_ERR, DCS_UNKNOWN_OP, hdr->message_opcode); 1576 1577 sp->state = DCS_CONF_DONE; 1578 1579 return (-1); 1580 } 1581 1582 1583 /* 1584 * dcs_confirm_callback: 1585 * 1586 * Perform a confirm callback and wait for the reply. As defined 1587 * in the config_admin(3CFGADM) man page, 1 is returned if the 1588 * operation should be allowed to continue and 0 otherwise. 1589 */ 1590 static int 1591 dcs_confirm_callback(void *appdata_ptr, const char *message) 1592 { 1593 session_t *sp; 1594 rdr_msg_hdr_t req_hdr; 1595 cfga_params_t req_data; 1596 struct cfga_confirm *cb_data; 1597 rdr_msg_hdr_t reply_hdr; 1598 cfga_params_t reply_data; 1599 int snd_status; 1600 int rcv_status; 1601 static char *op_name = "confirm callback"; 1602 1603 1604 /* sanity check */ 1605 if (appdata_ptr == NULL) { 1606 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1607 return (0); 1608 } 1609 1610 /* get the current session information */ 1611 if ((sp = curr_ses()) == NULL) { 1612 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1613 return (0); 1614 } 1615 1616 cb_data = (struct cfga_confirm *)appdata_ptr; 1617 1618 /* prepare header information */ 1619 init_msg(&req_hdr); 1620 req_hdr.message_opcode = RDR_CONF_CONFIRM_CALLBACK; 1621 req_hdr.data_type = RDR_REQUEST; 1622 1623 /* prepare confirm callback specific data */ 1624 (void) memset(&req_data, 0, sizeof (req_data)); 1625 req_data.conf_cb.confp = cb_data; 1626 req_data.conf_cb.message = (char *)message; 1627 1628 PRINT_MSG_DBG(DCS_SEND, &req_hdr); 1629 1630 /* send the message */ 1631 snd_status = rdr_snd_msg(sp->fd, &req_hdr, &req_data, DCS_SND_TIMEOUT); 1632 1633 if (snd_status == RDR_ABORTED) { 1634 abort_handler(); 1635 } 1636 1637 if (snd_status != RDR_OK) { 1638 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1639 return (0); 1640 } 1641 1642 /* 1643 * Wait for response 1644 */ 1645 rcv_status = rdr_rcv_msg(sp->fd, &reply_hdr, &reply_data, 1646 DCS_RCV_CB_TIMEOUT); 1647 1648 if (rcv_status != RDR_OK) { 1649 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1650 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1651 return (0); 1652 } 1653 1654 /* 1655 * Perform several checks to see if we have a 1656 * valid response to the confirm callback. 1657 */ 1658 if (invalid_msg(&reply_hdr)) { 1659 dcs_log_msg(LOG_ERR, DCS_MSG_INVAL); 1660 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1661 return (0); 1662 } 1663 1664 /* check the opcode and type */ 1665 if ((reply_hdr.message_opcode != RDR_CONF_CONFIRM_CALLBACK) || 1666 (reply_hdr.data_type != RDR_REPLY)) { 1667 DCS_DBG(DBG_MSG, "bad opcode or message type"); 1668 dcs_log_msg(LOG_ERR, DCS_MSG_INVAL); 1669 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1670 return (0); 1671 } 1672 1673 PRINT_MSG_DBG(DCS_RECEIVE, &reply_hdr); 1674 1675 /* check for incorrect callback id */ 1676 if (reply_data.conf_cb.confp->confirm != cb_data->confirm) { 1677 dcs_log_msg(LOG_ERR, DCS_MSG_INVAL); 1678 dcs_log_msg(LOG_NOTICE, DCS_CONF_CB_ERR); 1679 return (0); 1680 } 1681 1682 /* 1683 * Got back valid response: return the user's answer 1684 */ 1685 return (reply_data.conf_cb.response); 1686 } 1687 1688 1689 /* 1690 * dcs_message_callback: 1691 * 1692 * Perform a message callback to display a string to the user. 1693 * 1694 * Note: There is no documentation about possible return values 1695 * for the message callback. It is assumed that the value returned 1696 * is ignored, so 0 is returned for all cases. 1697 */ 1698 static int 1699 dcs_message_callback(void *appdata_ptr, const char *message) 1700 { 1701 session_t *sp; 1702 rdr_msg_hdr_t req_hdr; 1703 cfga_params_t req_data; 1704 struct cfga_msg *cb_data; 1705 int snd_status; 1706 static char *op_name = "message callback"; 1707 1708 1709 /* sanity check */ 1710 if (appdata_ptr == NULL) { 1711 dcs_log_msg(LOG_NOTICE, DCS_MSG_CB_ERR); 1712 return (0); 1713 } 1714 1715 /* get the current session information */ 1716 if ((sp = curr_ses()) == NULL) { 1717 dcs_log_msg(LOG_NOTICE, DCS_MSG_CB_ERR); 1718 return (0); 1719 } 1720 1721 cb_data = (struct cfga_msg *)appdata_ptr; 1722 1723 /* prepare header information */ 1724 init_msg(&req_hdr); 1725 req_hdr.message_opcode = RDR_CONF_MSG_CALLBACK; 1726 req_hdr.data_type = RDR_REQUEST; 1727 1728 /* prepare message callback specific data */ 1729 (void) memset(&req_data, 0, sizeof (req_data)); 1730 req_data.msg_cb.msgp = cb_data; 1731 req_data.msg_cb.message = (char *)message; 1732 1733 PRINT_MSG_DBG(DCS_SEND, &req_hdr); 1734 1735 /* send the message */ 1736 snd_status = rdr_snd_msg(sp->fd, &req_hdr, (cfga_params_t *)&req_data, 1737 DCS_SND_TIMEOUT); 1738 1739 if (snd_status == RDR_ABORTED) { 1740 abort_handler(); 1741 } 1742 1743 if (snd_status != RDR_OK) { 1744 dcs_log_msg(LOG_ERR, DCS_OP_REPLY_ERR, op_name); 1745 dcs_log_msg(LOG_NOTICE, DCS_MSG_CB_ERR); 1746 } 1747 1748 return (0); 1749 } 1750 1751 1752 /* 1753 * resolve_version: 1754 * 1755 * Consult the list of supported versions and find the highest supported 1756 * version that is less than or equal to the version requested in the 1757 * parameters. This assumes that the list of supported versions is ordered 1758 * so that the highest supported version is the first element, and that 1759 * the versions are strictly decreasing. 1760 */ 1761 static dcs_ver_t 1762 resolve_version(ushort_t req_major, ushort_t req_minor) 1763 { 1764 int i; 1765 dcs_ver_t act_ver; 1766 int num_vers; 1767 1768 1769 num_vers = sizeof (ver_supp) / sizeof (*ver_supp); 1770 1771 /* default to the lowest version */ 1772 act_ver = ver_supp[num_vers - 1]; 1773 1774 for (i = 0; i < num_vers; i++) { 1775 1776 if (req_major == ver_supp[i].major) { 1777 1778 if (req_minor >= ver_supp[i].minor) { 1779 /* 1780 * The major version matches and the 1781 * minor version either matches, or 1782 * is the best match that we have. 1783 */ 1784 act_ver = ver_supp[i]; 1785 break; 1786 } 1787 1788 } else if (req_major > ver_supp[i].major) { 1789 /* 1790 * The requested major version is larger than 1791 * the current version we are checking. There 1792 * is not going to be a better match. 1793 */ 1794 act_ver = ver_supp[i]; 1795 break; 1796 } 1797 } 1798 1799 DCS_DBG(DBG_SES, "requested ver: %d.%d, closest match: %d.%d", 1800 req_major, req_minor, act_ver.major, act_ver.minor); 1801 1802 return (act_ver); 1803 } 1804 1805 1806 /* 1807 * filter_list_data: 1808 * 1809 * Check a list of cfga_list_data_t structures to filter out the ones 1810 * that don't have other-read permissions. All valid entries are placed 1811 * at the beginning of the array and the count of entries is updated. 1812 */ 1813 static void 1814 filter_list_data(int perm, int *nlistp, cfga_list_data_t *linfo) 1815 { 1816 int num_aps; 1817 int num_aps_ret; 1818 int curr_ap; 1819 int next_aval; 1820 int end_block; 1821 int block_size; 1822 struct stat ap_info; 1823 1824 1825 DCS_DBG(DBG_MSG, "list access = %s", (perm == RDR_PRIVILEGED) ? 1826 "RDR_PRIVILEGED" : "RDR_NOT_PRIVILEGED"); 1827 1828 /* 1829 * Check if the user has priviledged access 1830 * to view all attachment points 1831 */ 1832 if (perm == RDR_PRIVILEGED) { 1833 return; 1834 } 1835 1836 if (*nlistp < 0) { 1837 *nlistp = 0; 1838 } 1839 1840 /* 1841 * No priviledged access, check each attachment point to 1842 * see if the user has access (other:read) to view it. 1843 */ 1844 num_aps = *nlistp; 1845 next_aval = 0; 1846 num_aps_ret = 0; 1847 curr_ap = 0; 1848 1849 /* 1850 * Use a simple algorithm to compact the array so that 1851 * all attachment points that can be viewed are at the 1852 * beginning of the array. Adjust the count of the 1853 * attachment points accordingly. 1854 */ 1855 while (curr_ap < num_aps) { 1856 1857 stat(linfo[curr_ap].ap_phys_id, &ap_info); 1858 1859 /* check for unrestricted read permission */ 1860 if (ap_info.st_mode & S_IROTH) { 1861 1862 end_block = curr_ap + 1; 1863 1864 /* 1865 * Check if this is the beginning of a 1866 * block of consecutive ap ids that can 1867 * be returned. 1868 */ 1869 while (end_block < num_aps) { 1870 1871 stat(linfo[end_block].ap_phys_id, &ap_info); 1872 1873 /* search until the end of the block */ 1874 if (ap_info.st_mode & S_IROTH) { 1875 end_block++; 1876 } else { 1877 break; 1878 } 1879 } 1880 1881 block_size = end_block - curr_ap; 1882 1883 /* make sure a copy is necessary */ 1884 if (curr_ap != next_aval) { 1885 1886 /* copy the block of ap ids all at once */ 1887 (void) memmove(&linfo[next_aval], 1888 &linfo[curr_ap], 1889 block_size * sizeof (cfga_list_data_t)); 1890 } 1891 1892 /* move past the copied block */ 1893 next_aval += block_size; 1894 curr_ap = end_block; 1895 1896 num_aps_ret += block_size; 1897 } else { 1898 curr_ap++; 1899 } 1900 } 1901 1902 DCS_DBG(DBG_ALL, "filtered %d of %d ap ids", (*nlistp - num_aps_ret), 1903 *nlistp); 1904 1905 /* 1906 * return the number of aps that have the correct 1907 * access permissions. 1908 */ 1909 *nlistp = num_aps_ret; 1910 } 1911 1912 1913 /* 1914 * generate_sort_order: 1915 * 1916 * Determine the sort order of an array of cfga_list_data_t structures 1917 * and create an array of rdr_list_t structures that contain the original 1918 * elements tagged with the sort order. 1919 * 1920 * This function is used to eliminate unnecessary network traffic that 1921 * might occur if the client needs the output of config_list_ext(3CFGADM) 1922 * sorted. Since a comparison is performed in a platform specific manner 1923 * using config_ap_id_cmp(3CFGADM), a client must establish a new session 1924 * for each comparison. For a long lists of attachment points, this can 1925 * slow down a simple list_ext operation significantly. With the sort 1926 * information included in the array of rdr_list_t structures, the client 1927 * can perform the sort operation locally, thus eliminating a great deal 1928 * of network traffic. 1929 */ 1930 static rdr_list_t * 1931 generate_sort_order(cfga_list_data_t *listp, int nlist) 1932 { 1933 int curr_ap; 1934 rdr_list_t *datalp; 1935 cfga_list_data_t *sortlp; 1936 cfga_list_data_t *match; 1937 1938 1939 assert(listp); 1940 1941 if (nlist <= 0) { 1942 return (NULL); 1943 } 1944 1945 /* create our new array */ 1946 datalp = (rdr_list_t *)malloc(nlist * sizeof (rdr_list_t)); 1947 1948 if (datalp == NULL) { 1949 return (NULL); 1950 } 1951 1952 1953 /* copy over the elements, preserving the original order */ 1954 for (curr_ap = 0; curr_ap < nlist; curr_ap++) { 1955 datalp[curr_ap].ap_id_info = listp[curr_ap]; 1956 } 1957 1958 /* handle a one element list */ 1959 if (nlist == 1) { 1960 datalp[0].sort_order = 0; 1961 return (datalp); 1962 } 1963 1964 /* sort the cfga_list_data_t array */ 1965 qsort(listp, nlist, sizeof (listp[0]), ldata_compare); 1966 1967 sortlp = listp; 1968 1969 /* process each item in the original list */ 1970 for (curr_ap = 0; curr_ap < nlist; curr_ap++) { 1971 1972 /* look up the sort order in the sorted list */ 1973 match = bsearch(&datalp[curr_ap].ap_id_info, sortlp, 1974 nlist, sizeof (cfga_list_data_t), ldata_compare); 1975 1976 /* found a match */ 1977 if (match != NULL) { 1978 datalp[curr_ap].sort_order = match - sortlp; 1979 } else { 1980 /* 1981 * Should never get here. Since we did a 1982 * direct copy of the array, we should always 1983 * be able to find the ap id that we were 1984 * looking for. 1985 */ 1986 DCS_DBG(DBG_ALL, "could not find a matching " 1987 "ap id in the sorted list"); 1988 datalp[curr_ap].sort_order = 0; 1989 } 1990 } 1991 1992 return (datalp); 1993 } 1994 1995 1996 /* 1997 * ldata_compare: 1998 * 1999 * Compare the two inputs to produce a strcmp(3C) style result. It uses 2000 * config_ap_id_cmp(3CFGADM) to perform the comparison. 2001 * 2002 * This function is passed to qsort(3C) in generate_sort_order() to sort a 2003 * list of attachment points. 2004 */ 2005 static int 2006 ldata_compare(const void *ap1, const void *ap2) 2007 { 2008 cfga_list_data_t *ap_id1; 2009 cfga_list_data_t *ap_id2; 2010 2011 ap_id1 = (cfga_list_data_t *)ap1; 2012 ap_id2 = (cfga_list_data_t *)ap2; 2013 2014 return (config_ap_id_cmp(ap_id1->ap_log_id, ap_id2->ap_log_id)); 2015 } 2016 2017 2018 /* 2019 * basename: 2020 * 2021 * Find short path name of a full path name. If a short path name 2022 * is passed in, the original pointer is returned. 2023 */ 2024 static char * 2025 basename(char *cp) 2026 { 2027 char *sp; 2028 2029 if ((sp = strrchr(cp, '/')) != NULL) { 2030 return (sp + 1); 2031 } 2032 2033 return (cp); 2034 } 2035