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