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