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