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