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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * This is the main file for the Domain Configuration Server (DCS).
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.
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.
52 #include <config_admin.h>
53 #include <sys/param.h>
56 #include <sys/socket.h>
60 #include "remote_cfg.h"
61 #include "rdr_param_types.h"
62 #include "rdr_messages.h"
63 #include "rsrc_info.h"
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);
77 /* message processing functions */
78 static int invalid_msg(rdr_msg_hdr_t
*hdr
);
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
);
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
);
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);
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.
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.
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 */
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 }.
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.
147 dcs_ver_t ver_supp
[] = {
152 #define DCS_CURR_VER ver_supp[0]
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 */
168 * Array of acceptable -a, -e and -u arguments.
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 */
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 */
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.
191 main(int argc
, char **argv
)
195 struct pollfd dcs_rcv
;
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
;
203 /* initialize globals */
204 dcs_debug
= DBG_NONE
;
205 cmdname
= basename(argv
[0]);
207 /* open log file with unique prefix */
208 openlog(cmdname
, LOG_CONS
| LOG_NDELAY
, LOG_DAEMON
);
211 * Process command line args
213 opterr
= 0; /* disable getopt error messages */
214 while ((opt
= getopt(argc
, argv
, OPT_STR
)) != EOF
) {
222 usr_debug
= strtol(optarg
, &err_str
, 0);
225 * The err_str parameter will be an
226 * empty string if successful.
228 if (*err_str
!= '\0') {
229 dcs_log_msg(LOG_ERR
, DCS_BAD_OPT_ARG
, optopt
,
231 (void) rdr_reject(dcsfd
);
235 dcs_debug
= usr_debug
;
247 usr_ses
= strtol(optarg
, &err_str
, 0);
250 max_sessions
= usr_ses
;
252 char behavior_str
[MAX_MSG_LEN
];
254 snprintf(behavior_str
, MAX_MSG_LEN
,
255 "using default value (%d)", max_sessions
);
257 dcs_log_msg(LOG_NOTICE
, DCS_BAD_OPT_ARG
, optopt
,
258 optarg
, behavior_str
);
267 ah_auth_alg
= dcs_get_alg(auth_algs_array
,
269 else /* opt == 'u' */
270 esp_auth_alg
= dcs_get_alg(auth_algs_array
,
273 if (alg_ec
== DCS_BAD_OPT_ARG
) {
274 dcs_log_bad_alg(optopt
, optarg
);
275 (void) rdr_reject(dcsfd
);
282 esp_encr_alg
= dcs_get_alg(esp_algs_array
, optarg
,
285 if (alg_ec
== DCS_BAD_OPT_ARG
) {
286 dcs_log_bad_alg(optopt
, optarg
);
287 (void) rdr_reject(dcsfd
);
295 use_family
= AF_INET
;
299 if (optopt
== 'a' || optopt
== 'e' || optopt
== 'u')
300 dcs_log_bad_alg(optopt
, optarg
);
302 dcs_log_msg(LOG_ERR
, DCS_BAD_OPT
, optopt
);
303 (void) rdr_reject(dcsfd
);
312 * In the future if inetd supports per-socket IPsec dcs can be run
314 * Daemonize if we were not started by inetd unless running standalone.
316 inetd
= is_socket(STDIN_FILENO
);
317 if (inetd
== B_FALSE
&& standalone
== 0) {
327 /* open log again after all files were closed */
328 openlog(cmdname
, LOG_CONS
| LOG_NDELAY
, LOG_DAEMON
);
331 DCS_DBG(DBG_ALL
, "initializing %s...", cmdname
);
336 if (geteuid() != 0) {
337 dcs_log_msg(LOG_ERR
, DCS_NO_PRIV
);
338 (void) rdr_reject(dcsfd
);
343 * Seed the random number generator for
344 * generating random session identifiers.
346 gettimeofday(&tv
, NULL
);
349 /* initialize our transport endpoint */
350 if (init_server(&dcs_rcv
, ah_auth_alg
, esp_encr_alg
, esp_auth_alg
) ==
352 dcs_log_msg(LOG_ERR
, DCS_INIT_ERR
);
353 (void) rdr_reject(dcsfd
);
358 DCS_DBG(DBG_ALL
, "%s initialized, debug level = 0x%X, "
359 "max sessions = %d", cmdname
, dcs_debug
, max_sessions
);
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",
375 /* attempt to connect */
376 newfd
= rdr_connect_srv(dcs_rcv
.fd
);
378 if ((newfd
== RDR_ERROR
) || (newfd
== RDR_NET_ERR
)) {
379 dcs_log_msg(LOG_ERR
, DCS_CONNECT_ERR
);
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
);
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.
407 dcs_get_alg(dcs_alg_t
*algs
, char *arg
, dcs_err_code
*error
)
413 for (alg
= algs
; alg
->arg_name
!= NULL
&& arg
!= NULL
; alg
++) {
414 if (strncmp(alg
->arg_name
, arg
, strlen(alg
->arg_name
) + 1)
416 return (alg
->alg_id
);
420 *error
= DCS_BAD_OPT_ARG
;
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
436 dcs_log_bad_alg(char optopt
, char *optarg
)
438 if (optarg
== NULL
) {
439 dcs_log_msg(LOG_ERR
, DCS_BAD_OPT_ARG
, optopt
,
440 "empty string", "an argument is required, exiting");
442 dcs_log_msg(LOG_ERR
, DCS_BAD_OPT_ARG
, optopt
,
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
457 init_server(struct pollfd
*pfd
, uint8_t ah_auth_alg
, uint8_t esp_encr_alg
,
458 uint8_t esp_auth_alg
)
461 struct sockaddr_storage ss
;
462 struct sockaddr_in
*sin
;
463 struct sockaddr_in6
*sin6
;
465 ipsec_req_t ipsec_req
;
470 int sock_opts
[] = { SO_REUSEADDR
};
475 pfd
->events
= POLLIN
| POLLPRI
;
480 * In standalone mode, we have to initialize the transport
481 * endpoint for our reserved port. In daemon mode, inetd
482 * starts the DCS and hands off STDIN_FILENO connected to
486 if (inetd
== B_FALSE
|| standalone
) {
487 /* in standalone mode, init fd for reserved port */
488 if ((dcsfd
= rdr_open(use_family
)) == -1) {
489 DCS_DBG(DBG_ALL
, "rdr_open failed");
495 * Enable per-socket IPsec if the user specified an
496 * AH or ESP algorithm to use and global policy is not in
499 if (!dcs_global_policy() &&
500 (ah_auth_alg
!= SADB_AALG_NONE
||
501 esp_encr_alg
!= SADB_EALG_NONE
||
502 esp_auth_alg
!= SADB_AALG_NONE
)) {
505 bzero(&ipsec_req
, sizeof (ipsec_req
));
507 /* Hardcoded values */
508 ipsec_req
.ipsr_self_encap_req
= SELF_ENCAP_REQ
;
510 ipsec_req
.ipsr_auth_alg
= ah_auth_alg
;
511 ipsec_req
.ipsr_esp_alg
= esp_encr_alg
;
512 if (ah_auth_alg
!= SADB_AALG_NONE
)
513 ipsec_req
.ipsr_ah_req
= AH_REQ
;
514 if (esp_encr_alg
!= SADB_EALG_NONE
||
515 esp_auth_alg
!= SADB_AALG_NONE
) {
516 ipsec_req
.ipsr_esp_req
= ESP_REQ
;
517 ipsec_req
.ipsr_esp_auth_alg
= esp_auth_alg
;
520 err
= rdr_setsockopt(pfd
->fd
, IPPROTO_IPV6
,
521 IPV6_SEC_OPT
, (void *)&ipsec_req
,
525 DCS_DBG(DBG_ALL
, "rdr_setsockopt failed");
532 * Look up our service to get the reserved port number
534 if ((se
= getservbyname(DCS_SERVICE
, "tcp")) == NULL
) {
535 dcs_log_msg(LOG_NOTICE
, DCS_NO_SERV
, DCS_SERVICE
);
537 /* use the known port if service wasn't found */
538 req_port
= SUN_DR_PORT
;
540 req_port
= se
->s_port
;
543 (void) memset(&ss
, 0, sizeof (ss
));
544 if (use_family
== AF_INET
) {
545 /* initialize our local address */
546 sin
= (struct sockaddr_in
*)&ss
;
547 sin
->sin_family
= AF_INET
;
548 sin
->sin_port
= htons(req_port
);
549 sin
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
551 /* initialize our local address */
552 sin6
= (struct sockaddr_in6
*)&ss
;
553 sin6
->sin6_family
= AF_INET6
;
554 sin6
->sin6_port
= htons(req_port
);
555 sin6
->sin6_addr
= in6addr_any
;
558 num_sock_opts
= sizeof (sock_opts
) / sizeof (*sock_opts
);
560 init_status
= rdr_init(pfd
->fd
, (struct sockaddr
*)&ss
,
561 sock_opts
, num_sock_opts
, DCS_BACKLOG
);
563 if (init_status
!= RDR_OK
) {
568 * Set the SO_LINGER socket option so that TCP aborts the connection
569 * when the socket is closed. This avoids encountering a TIME_WAIT
570 * state if the daemon ever crashes and is instantly restarted.
574 if (setsockopt(pfd
->fd
, SOL_SOCKET
, SO_LINGER
, &ling
, sizeof (ling
))) {
578 switch (ss
.ss_family
) {
580 DCS_DBG(DBG_ALL
, "using AF_INET socket");
581 sin
= (struct sockaddr_in
*)&ss
;
582 act_port
= ntohs(sin
->sin_port
);
585 DCS_DBG(DBG_ALL
, "using AF_INET6 socket");
586 /* sin6 already set correctly */
587 act_port
= ntohs(sin6
->sin6_port
);
590 DCS_DBG(DBG_ALL
, "unknown socket type");
594 /* check that we got the requested port */
595 if (req_port
!= act_port
) {
596 dcs_log_msg(LOG_ERR
, DCS_NO_PORT
, req_port
);
607 * Initialize signals for the current session. All signals will be
608 * blocked with two possible exceptions. SIGINT is not blocked in
609 * standalone mode, and ses_init_signals() is called to selectively
610 * unblock any signals required to handle concurrent sessions.
618 /* block all signals */
621 /* in standalone, allow user to abort */
623 sigdelset(&mask
, SIGINT
);
626 ses_init_signals(&mask
);
628 (void) sigprocmask(SIG_BLOCK
, &mask
, NULL
);
633 * dcs_dispatch_message:
635 * This function dispatches a message to the correct function. The
636 * correct handler is determined by the opcode field of the message
640 dcs_dispatch_message(rdr_msg_hdr_t
*hdr
, cfga_params_t
*params
)
648 /* get the current session information */
649 if ((sp
= curr_ses()) == NULL
) {
650 ses_close(DCS_ERROR
);
654 /* check the message */
655 if (invalid_msg(hdr
)) {
656 dcs_log_msg(LOG_ERR
, DCS_MSG_INVAL
);
657 ses_close(DCS_MSG_INVAL
);
661 /* save the current message */
662 sp
->curr_msg
.hdr
= hdr
;
663 sp
->curr_msg
.params
= params
;
666 * hdr->message_opcode is unsigned so don't need
667 * to check for values less than zero
669 if (hdr
->message_opcode
>= RDR_NUM_OPS
) {
670 dcs_unknown_op(hdr
, params
);
671 ses_close(DCS_MSG_INVAL
);
675 PRINT_MSG_DBG(DCS_RECEIVE
, hdr
);
677 /* dispatch the message */
678 if ((*dcs_cmd
[hdr
->message_opcode
])(hdr
, params
) == -1) {
679 dcs_log_msg(LOG_ERR
, DCS_OP_FAILED
);
680 ses_close(DCS_ERROR
);
691 * Initialize the message header with information from the current
692 * session. Fields not set directly are initialized to zero.
695 init_msg(rdr_msg_hdr_t
*hdr
)
702 /* get the current session information */
703 if ((sp
= curr_ses()) == NULL
) {
704 ses_close(DCS_ERROR
);
708 (void) memset(hdr
, 0, sizeof (rdr_msg_hdr_t
));
710 /* set the session information */
711 hdr
->random_req
= sp
->random_req
;
712 hdr
->random_resp
= sp
->random_resp
;
714 /* set the version being used */
715 hdr
->major_version
= sp
->major_version
;
716 hdr
->minor_version
= sp
->minor_version
;
723 * Check if the message is valid for the current session. This
724 * is accomplished by checking various information in the header
725 * against the information for the current session.
728 invalid_msg(rdr_msg_hdr_t
*hdr
)
735 /* get the current session information */
736 if ((sp
= curr_ses()) == NULL
) {
737 ses_close(DCS_ERROR
);
742 * Only perform the following checks if the message
743 * is not a session request. The information to check
744 * will not be set at the time a session request is
747 if (hdr
->message_opcode
!= RDR_SES_REQ
) {
749 /* check major and minor version */
750 if ((sp
->major_version
!= hdr
->major_version
) ||
751 (sp
->minor_version
!= hdr
->minor_version
)) {
752 DCS_DBG(DBG_MSG
, "unsupported version %d.%d",
753 hdr
->major_version
, hdr
->minor_version
);
757 /* check session identifiers */
758 if ((sp
->random_req
!= hdr
->random_req
) ||
759 (sp
->random_resp
!= hdr
->random_resp
)) {
760 DCS_DBG(DBG_MSG
, "invalid session identifiers: "
761 "<%d, %d>", hdr
->random_req
, hdr
->random_resp
);
773 * Handle a session request message (RDR_SES_REQ).
776 dcs_ses_req(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
779 rdr_msg_hdr_t reply_hdr
;
780 cfga_params_t reply_param
;
783 static char *op_name
= "session request";
789 /* get the current session information */
790 if ((sp
= curr_ses()) == NULL
) {
791 ses_close(DCS_ERROR
);
795 /* make sure that a session hasn't been requested yet */
796 if (sp
->state
!= DCS_CONNECTED
) {
797 dcs_log_msg(LOG_ERR
, DCS_SES_SEQ_INVAL
);
798 ses_close(DCS_SES_SEQ_INVAL
);
802 ses_setlocale(param
->req
.locale_str
);
804 /* get the best matching version supported */
805 act_ver
= resolve_version(hdr
->major_version
, hdr
->minor_version
);
807 /* initialize session information */
808 sp
->random_req
= hdr
->random_req
;
809 sp
->major_version
= act_ver
.major
;
810 sp
->minor_version
= act_ver
.minor
;
812 /* prepare header information */
813 init_msg(&reply_hdr
);
814 reply_hdr
.message_opcode
= RDR_SES_REQ
;
815 reply_hdr
.data_type
= RDR_REPLY
;
816 reply_hdr
.status
= DCS_OK
;
818 /* prepare session request specific data */
819 (void) memset(&reply_param
, 0, sizeof (cfga_params_t
));
820 reply_param
.req
.session_id
= sp
->id
;
822 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
824 /* send the message */
825 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, &reply_param
,
828 if (snd_status
== RDR_ABORTED
) {
832 if (snd_status
!= RDR_OK
) {
833 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
837 sp
->state
= DCS_SES_REQ
;
845 * Handle a session establishment message (RDR_SES_ESTBL).
849 dcs_ses_estbl(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
858 /* get the current session information */
859 if ((sp
= curr_ses()) == NULL
) {
860 ses_close(DCS_ERROR
);
865 * Make sure that a session has not been
866 * established yet, and that a session
867 * request has already been processed.
869 if (sp
->state
!= DCS_SES_REQ
) {
870 dcs_log_msg(LOG_ERR
, DCS_SES_SEQ_INVAL
);
871 ses_close(DCS_SES_SEQ_INVAL
);
875 /* get the best matching version supported */
876 act_ver
= resolve_version(hdr
->major_version
, hdr
->minor_version
);
878 if ((act_ver
.major
!= hdr
->major_version
) ||
879 (act_ver
.minor
!= hdr
->minor_version
)) {
881 /* end the session because protocol not supported */
882 dcs_log_msg(LOG_ERR
, DCS_VER_INVAL
, hdr
->major_version
,
884 ses_close(DCS_VER_INVAL
);
888 DCS_DBG(DBG_SES
, "Session Established");
889 sp
->state
= DCS_SES_ESTBL
;
898 * Handle a session end message (RDR_SES_END).
901 dcs_ses_end(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
904 rdr_msg_hdr_t reply_hdr
;
905 cfga_params_t reply_param
;
907 static char *op_name
= "session end";
913 /* get the current session information */
914 if ((sp
= curr_ses()) == NULL
) {
915 ses_close(DCS_ERROR
);
920 * Session end is valid from any state. However, only
921 * send back a reply if the error code is zero. A non-zero
922 * error code indicates that the session is being terminated
923 * under an error condition, and no acknowledgement is
926 if (param
->end
.error_code
== 0) {
928 /* prepare header information */
929 init_msg(&reply_hdr
);
930 reply_hdr
.message_opcode
= RDR_SES_END
;
931 reply_hdr
.data_type
= RDR_REPLY
;
932 reply_hdr
.status
= DCS_OK
;
934 /* return empty data - no information needed in reply */
935 (void) memset(&reply_param
, 0, sizeof (cfga_params_t
));
937 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
939 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, &reply_param
,
942 if (snd_status
== RDR_ABORTED
) {
946 if (snd_status
!= RDR_OK
) {
947 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
951 sp
->state
= DCS_SES_END
;
953 return ((snd_status
!= RDR_OK
) ? -1 : 0);
960 * Handle a change state request message (RDR_CONF_CHANGE_STATE).
963 dcs_change_state(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
966 rdr_msg_hdr_t reply_hdr
;
967 change_state_params_t
*op_data
;
968 struct cfga_confirm local_conf_cb
;
969 struct cfga_msg local_msg_cb
;
973 unsigned int curr_attempt
;
974 unsigned int num_attempts
;
975 char retry_msg
[MAX_MSG_LEN
];
976 static char *op_name
= "config_change_state";
982 /* get the current session information */
983 if ((sp
= curr_ses()) == NULL
) {
984 ses_close(DCS_ERROR
);
988 op_data
= ¶m
->change
;
990 /* make sure we have a session established */
991 if (sp
->state
!= DCS_SES_ESTBL
) {
992 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
993 ses_close(DCS_NO_SES_ERR
);
997 /* initialize local confirm callback */
998 local_conf_cb
.confirm
= dcs_confirm_callback
;
999 local_conf_cb
.appdata_ptr
= (void *)op_data
->confp
;
1001 /* initialize local message callback */
1002 local_msg_cb
.message_routine
= dcs_message_callback
;
1003 local_msg_cb
.appdata_ptr
= (void *)op_data
->msgp
;
1005 /* verify retry value */
1006 if (op_data
->retries
< 0) {
1007 dcs_log_msg(LOG_NOTICE
, DCS_BAD_RETRY_VAL
, op_data
->retries
);
1008 op_data
->retries
= 0;
1011 /* verify timeout value */
1012 if (op_data
->timeval
< 0) {
1013 dcs_log_msg(LOG_NOTICE
, DCS_BAD_TIME_VAL
, op_data
->timeval
);
1014 op_data
->timeval
= 0;
1017 num_attempts
= 1 + op_data
->retries
;
1020 while (curr_attempt
< num_attempts
) {
1022 /* don't sleep the first time around */
1023 if (curr_attempt
!= 0) {
1025 /* log the error message and alert the user */
1026 err_str
= dcs_cfga_str(op_data
->errstring
, cfga_status
);
1028 dcs_log_msg(LOG_ERR
, DCS_CFGA_ERR
, op_name
,
1030 dcs_message_callback((void *)op_data
->msgp
,
1032 free((void *)err_str
);
1034 dcs_log_msg(LOG_ERR
, DCS_CFGA_UNKNOWN
);
1035 dcs_message_callback((void *)op_data
->msgp
,
1036 dcs_strerror(DCS_CFGA_UNKNOWN
));
1039 if (op_data
->errstring
&& *op_data
->errstring
) {
1040 free((void *)*op_data
->errstring
);
1041 *op_data
->errstring
= NULL
;
1044 /* sleep with abort enabled */
1045 ses_sleep(op_data
->timeval
);
1047 /* log the retry attempt and alert the user */
1048 dcs_log_msg(LOG_INFO
, DCS_RETRY
, curr_attempt
);
1049 snprintf(retry_msg
, MAX_MSG_LEN
,
1050 dcs_strerror(DCS_RETRY
), curr_attempt
);
1051 dcs_message_callback((void *)op_data
->msgp
, retry_msg
);
1054 sp
->state
= DCS_CONF_PENDING
;
1057 * Call into libcfgadm
1061 cfga_status
= config_change_state(op_data
->state_change
,
1062 op_data
->num_ap_ids
, op_data
->ap_ids
, op_data
->options
,
1063 &local_conf_cb
, &local_msg_cb
, op_data
->errstring
,
1066 ses_abort_disable();
1069 * Retry only the operations that have a chance to
1070 * succeed if retried. All libcfgadm errors not
1071 * included below will always fail, regardless of
1074 if ((cfga_status
!= CFGA_BUSY
) &&
1075 (cfga_status
!= CFGA_SYSTEM_BUSY
) &&
1076 (cfga_status
!= CFGA_ERROR
)) {
1080 /* prepare for another attempt */
1084 sp
->state
= DCS_CONF_DONE
;
1086 /* log any libcfgadm errors */
1087 if (cfga_status
!= CFGA_OK
) {
1088 err_str
= dcs_cfga_str(op_data
->errstring
, cfga_status
);
1090 dcs_log_msg(LOG_ERR
, DCS_CFGA_ERR
, op_name
, err_str
);
1091 free((void *)err_str
);
1095 /* prepare header information */
1096 init_msg(&reply_hdr
);
1097 reply_hdr
.message_opcode
= RDR_CONF_CHANGE_STATE
;
1098 reply_hdr
.data_type
= RDR_REPLY
;
1099 reply_hdr
.status
= cfga_status
;
1101 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1103 /* send the message */
1104 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1106 if (snd_status
== RDR_ABORTED
) {
1110 if (snd_status
!= RDR_OK
) {
1111 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1115 if (op_data
->errstring
&& *op_data
->errstring
) {
1116 free((void *)*op_data
->errstring
);
1117 *op_data
->errstring
= NULL
;
1120 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1127 * Handle a private function request message (RDR_CONF_PRIVATE_FUNC).
1130 dcs_private_func(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1133 rdr_msg_hdr_t reply_hdr
;
1134 private_func_params_t
*op_data
;
1135 struct cfga_confirm local_conf_cb
;
1136 struct cfga_msg local_msg_cb
;
1140 static char *op_name
= "config_private_func";
1146 /* get the current session information */
1147 if ((sp
= curr_ses()) == NULL
) {
1148 ses_close(DCS_ERROR
);
1152 op_data
= ¶m
->priv
;
1154 /* make sure we have a session established */
1155 if (sp
->state
!= DCS_SES_ESTBL
) {
1156 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1157 ses_close(DCS_NO_SES_ERR
);
1161 /* initialize local confirm callback */
1162 local_conf_cb
.confirm
= dcs_confirm_callback
;
1163 local_conf_cb
.appdata_ptr
= (void *)op_data
->confp
;
1165 /* initialize local message callback */
1166 local_msg_cb
.message_routine
= dcs_message_callback
;
1167 local_msg_cb
.appdata_ptr
= (void *)op_data
->msgp
;
1169 sp
->state
= DCS_CONF_PENDING
;
1172 * Call into libcfgadm
1176 cfga_status
= config_private_func(op_data
->function
,
1177 op_data
->num_ap_ids
, op_data
->ap_ids
, op_data
->options
,
1178 &local_conf_cb
, &local_msg_cb
, op_data
->errstring
, op_data
->flags
);
1180 ses_abort_disable();
1182 sp
->state
= DCS_CONF_DONE
;
1184 /* log any libcfgadm errors */
1185 if (cfga_status
!= CFGA_OK
) {
1186 err_str
= dcs_cfga_str(op_data
->errstring
, cfga_status
);
1188 dcs_log_msg(LOG_ERR
, DCS_CFGA_ERR
, op_name
, err_str
);
1189 free((void *)err_str
);
1193 /* prepare header information */
1194 init_msg(&reply_hdr
);
1195 reply_hdr
.message_opcode
= RDR_CONF_PRIVATE_FUNC
;
1196 reply_hdr
.data_type
= RDR_REPLY
;
1197 reply_hdr
.status
= cfga_status
;
1199 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1201 /* send the message */
1202 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1204 if (snd_status
== RDR_ABORTED
) {
1208 if (snd_status
!= RDR_OK
) {
1209 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1212 if (op_data
->errstring
&& *op_data
->errstring
) {
1213 free((void *)*op_data
->errstring
);
1214 *op_data
->errstring
= NULL
;
1217 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1224 * Handle a test request message (RDR_CONF_TEST).
1227 dcs_test(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1230 rdr_msg_hdr_t reply_hdr
;
1231 test_params_t
*op_data
;
1232 struct cfga_msg local_msg_cb
;
1236 static char *op_name
= "config_test";
1242 /* get the current session information */
1243 if ((sp
= curr_ses()) == NULL
) {
1244 ses_close(DCS_ERROR
);
1248 op_data
= ¶m
->test
;
1250 /* make sure we have a session established */
1251 if (sp
->state
!= DCS_SES_ESTBL
) {
1252 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1253 ses_close(DCS_NO_SES_ERR
);
1257 /* initialize local message callback */
1258 local_msg_cb
.message_routine
= dcs_message_callback
;
1259 local_msg_cb
.appdata_ptr
= op_data
->msgp
;
1261 sp
->state
= DCS_CONF_PENDING
;
1264 * Call into libcfgadm
1268 cfga_status
= config_test(op_data
->num_ap_ids
, op_data
->ap_ids
,
1269 op_data
->options
, &local_msg_cb
, op_data
->errstring
,
1272 ses_abort_disable();
1274 sp
->state
= DCS_CONF_DONE
;
1276 /* log any libcfgadm errors */
1277 if (cfga_status
!= CFGA_OK
) {
1278 err_str
= dcs_cfga_str(op_data
->errstring
, cfga_status
);
1280 dcs_log_msg(LOG_ERR
, DCS_CFGA_ERR
, op_name
, err_str
);
1281 free((void *)err_str
);
1285 /* prepare header information */
1286 init_msg(&reply_hdr
);
1287 reply_hdr
.message_opcode
= RDR_CONF_TEST
;
1288 reply_hdr
.data_type
= RDR_REPLY
;
1289 reply_hdr
.status
= cfga_status
;
1291 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1293 /* send the message */
1294 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1296 if (snd_status
== RDR_ABORTED
) {
1300 if (snd_status
!= RDR_OK
) {
1301 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1304 if (op_data
->errstring
&& *op_data
->errstring
) {
1305 free((void *)*op_data
->errstring
);
1306 *op_data
->errstring
= NULL
;
1309 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1316 * Handle a list request message (RDR_CONF_LIST_EXT).
1319 dcs_list_ext(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1322 rdr_msg_hdr_t reply_hdr
;
1323 list_ext_params_t
*op_data
;
1327 static char *op_name
= "config_list_ext";
1328 cfga_list_data_t
*ap_ids
;
1334 /* get the current session information */
1335 if ((sp
= curr_ses()) == NULL
) {
1336 ses_close(DCS_ERROR
);
1340 op_data
= ¶m
->list_ext
;
1342 /* make sure we have a session established */
1343 if (sp
->state
!= DCS_SES_ESTBL
) {
1344 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1345 ses_close(DCS_NO_SES_ERR
);
1350 * Make sure that we can retrieve the data
1351 * from libcfgadm. If not, report the error.
1353 if (op_data
->ap_id_list
== NULL
) {
1354 dcs_log_msg(LOG_ERR
, DCS_MSG_INVAL
);
1355 ses_close(DCS_MSG_INVAL
);
1359 sp
->state
= DCS_CONF_PENDING
;
1362 * Call into libcfgadm
1366 cfga_status
= config_list_ext(op_data
->num_ap_ids
, op_data
->ap_ids
,
1367 &ap_ids
, op_data
->nlist
, op_data
->options
, op_data
->listopts
,
1368 op_data
->errstring
, op_data
->flags
);
1370 ses_abort_disable();
1372 sp
->state
= DCS_CONF_DONE
;
1375 * Log any libcfgadm errors at a low priority level.
1376 * Since a status request does not modify the system
1377 * in any way, we do not need to worry about these
1378 * errors here on the host.
1380 if (cfga_status
!= CFGA_OK
) {
1381 err_str
= dcs_cfga_str(op_data
->errstring
, cfga_status
);
1383 dcs_log_msg(LOG_INFO
, DCS_CFGA_ERR
, op_name
, err_str
);
1384 free((void *)err_str
);
1389 * Filter ap ids to return only appropriate information
1391 filter_list_data(op_data
->permissions
, op_data
->nlist
, ap_ids
);
1393 /* if all aps were filtered out, return an error */
1394 if ((cfga_status
== CFGA_OK
) && (*op_data
->nlist
== 0)) {
1395 cfga_status
= CFGA_APID_NOEXIST
;
1398 /* calculate the sort order */
1399 if (cfga_status
== CFGA_OK
) {
1401 *op_data
->ap_id_list
= generate_sort_order(ap_ids
,
1404 if (*op_data
->ap_id_list
== NULL
) {
1405 cfga_status
= CFGA_LIB_ERROR
;
1409 /* ensure that nlist is 0 for errors */
1410 if (cfga_status
!= CFGA_OK
) {
1411 *op_data
->nlist
= 0;
1414 /* prepare header information */
1415 init_msg(&reply_hdr
);
1416 reply_hdr
.message_opcode
= RDR_CONF_LIST_EXT
;
1417 reply_hdr
.data_type
= RDR_REPLY
;
1418 reply_hdr
.status
= cfga_status
;
1420 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1422 /* send the message */
1423 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1425 if (snd_status
== RDR_ABORTED
) {
1429 if (snd_status
!= RDR_OK
) {
1430 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1433 if (op_data
->errstring
&& *op_data
->errstring
) {
1434 free((void *)*op_data
->errstring
);
1435 *op_data
->errstring
= NULL
;
1438 if (ap_ids
!= NULL
) {
1439 free((void *)ap_ids
);
1442 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1449 * Handle a help request message (RDR_CONF_HELP).
1452 dcs_help(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1455 rdr_msg_hdr_t reply_hdr
;
1456 help_params_t
*op_data
;
1457 struct cfga_msg local_msg_cb
;
1461 static char *op_name
= "config_help";
1467 /* get the current session information */
1468 if ((sp
= curr_ses()) == NULL
) {
1469 ses_close(DCS_ERROR
);
1473 op_data
= ¶m
->help
;
1475 /* make sure we have a session established */
1476 if (sp
->state
!= DCS_SES_ESTBL
) {
1477 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1478 ses_close(DCS_NO_SES_ERR
);
1482 /* initialize local message callback */
1483 local_msg_cb
.message_routine
= dcs_message_callback
;
1484 local_msg_cb
.appdata_ptr
= op_data
->msgp
;
1486 sp
->state
= DCS_CONF_PENDING
;
1489 * Call into libcfgadm
1493 cfga_status
= config_help(op_data
->num_ap_ids
, op_data
->ap_ids
,
1494 &local_msg_cb
, op_data
->options
, op_data
->flags
);
1496 ses_abort_disable();
1498 sp
->state
= DCS_CONF_DONE
;
1501 * Log any libcfgadm errors at a low priority level.
1502 * Since a help request does not modify the system
1503 * in any way, we do not need to worry about these
1504 * errors here on the host.
1506 if (cfga_status
!= CFGA_OK
) {
1507 err_str
= dcs_cfga_str(NULL
, cfga_status
);
1509 dcs_log_msg(LOG_INFO
, DCS_CFGA_ERR
, op_name
, err_str
);
1510 free((void *)err_str
);
1514 /* prepare header information */
1515 init_msg(&reply_hdr
);
1516 reply_hdr
.message_opcode
= RDR_CONF_HELP
;
1517 reply_hdr
.data_type
= RDR_REPLY
;
1518 reply_hdr
.status
= cfga_status
;
1520 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1522 /* send the message */
1523 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1525 if (snd_status
== RDR_ABORTED
) {
1529 if (snd_status
!= RDR_OK
) {
1530 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1533 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1540 * Handle an attachment point comparison request message (RDR_AP_ID_CMP).
1543 dcs_ap_id_cmp(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1546 rdr_msg_hdr_t reply_hdr
;
1547 ap_id_cmp_params_t
*op_data
;
1550 static char *op_name
= "config_ap_id_cmp";
1556 /* get the current session information */
1557 if ((sp
= curr_ses()) == NULL
) {
1558 ses_close(DCS_ERROR
);
1562 op_data
= ¶m
->cmp
;
1564 /* make sure we have a session established */
1565 if (sp
->state
!= DCS_SES_ESTBL
) {
1566 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1567 ses_close(DCS_NO_SES_ERR
);
1571 sp
->state
= DCS_CONF_PENDING
;
1574 * Call into libcfgadm
1578 cmp_result
= config_ap_id_cmp(op_data
->ap_log_id1
, op_data
->ap_log_id2
);
1580 ses_abort_disable();
1582 sp
->state
= DCS_CONF_DONE
;
1584 /* prepare header information */
1585 init_msg(&reply_hdr
);
1586 reply_hdr
.message_opcode
= RDR_CONF_AP_ID_CMP
;
1587 reply_hdr
.data_type
= RDR_REPLY
;
1590 * Return result of comparison as error code.
1591 * Since all values are valid, it is impossible
1592 * to report an error.
1594 reply_hdr
.status
= cmp_result
;
1596 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1598 /* send the message */
1599 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1601 if (snd_status
== RDR_ABORTED
) {
1605 if (snd_status
!= RDR_OK
) {
1606 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1609 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1616 * Handle an abort request message (RDR_CONF_ABORT_CMD).
1620 dcs_abort_cmd(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1623 rdr_msg_hdr_t reply_hdr
;
1624 abort_cmd_params_t
*op_data
;
1625 int op_status
= RDR_SUCCESS
;
1627 static char *op_name
= "abort command";
1633 /* get the current session information */
1634 if ((sp
= curr_ses()) == NULL
) {
1635 ses_close(DCS_ERROR
);
1639 op_data
= (abort_cmd_params_t
*)param
;
1641 op_status
= ses_abort(op_data
->session_id
);
1643 if (op_status
== -1) {
1644 dcs_log_msg(LOG_ERR
, DCS_ABORT_ERR
, op_data
->session_id
);
1647 /* prepare header information */
1648 init_msg(&reply_hdr
);
1649 reply_hdr
.message_opcode
= RDR_CONF_ABORT_CMD
;
1650 reply_hdr
.data_type
= RDR_REPLY
;
1651 reply_hdr
.status
= op_status
;
1653 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1655 /* send the message */
1656 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1658 if (snd_status
== RDR_ABORTED
) {
1662 if (snd_status
!= RDR_OK
) {
1663 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1666 sp
->state
= DCS_CONF_DONE
;
1668 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1675 * Handle a resource info request message (RDR_RSRC_INFO).
1678 dcs_rsrc_info(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1681 rdr_msg_hdr_t reply_hdr
;
1682 rsrc_info_params_t
*op_data
;
1685 static char *op_name
= "resource info init";
1690 /* get the current session information */
1691 if ((sp
= curr_ses()) == NULL
) {
1692 ses_close(DCS_ERROR
);
1696 op_data
= (rsrc_info_params_t
*)¶m
->rsrc_info
;
1698 /* make sure we have a session established */
1699 if (sp
->state
!= DCS_SES_ESTBL
) {
1700 dcs_log_msg(LOG_ERR
, DCS_NO_SES_ESTBL
, op_name
);
1701 ses_close(DCS_NO_SES_ERR
);
1705 sp
->state
= DCS_CONF_PENDING
;
1708 * Request resource info data.
1712 rsrc_status
= ri_init(op_data
->num_ap_ids
, op_data
->ap_ids
,
1713 op_data
->flags
, &op_data
->hdl
);
1715 ses_abort_disable();
1717 sp
->state
= DCS_CONF_DONE
;
1720 if (rsrc_status
!= RI_SUCCESS
) {
1721 dcs_log_msg(LOG_ERR
, DCS_RSRC_ERR
, rsrc_status
);
1724 /* prepare header information */
1725 init_msg(&reply_hdr
);
1726 reply_hdr
.message_opcode
= RDR_RSRC_INFO
;
1727 reply_hdr
.data_type
= RDR_REPLY
;
1728 reply_hdr
.status
= rsrc_status
;
1730 PRINT_MSG_DBG(DCS_SEND
, &reply_hdr
);
1732 /* send the message */
1733 snd_status
= rdr_snd_msg(sp
->fd
, &reply_hdr
, param
, DCS_SND_TIMEOUT
);
1735 if (snd_status
== RDR_ABORTED
) {
1739 if (snd_status
!= RDR_OK
) {
1740 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1743 ri_fini(op_data
->hdl
);
1745 return ((snd_status
!= RDR_OK
) ? -1 : 0);
1752 * Handle all unknown requests.
1756 dcs_unknown_op(rdr_msg_hdr_t
*hdr
, cfga_params_t
*param
)
1766 /* get the current session information */
1767 if ((sp
= curr_ses()) == NULL
) {
1768 ses_close(DCS_ERROR
);
1772 dcs_log_msg(LOG_ERR
, DCS_UNKNOWN_OP
, hdr
->message_opcode
);
1774 sp
->state
= DCS_CONF_DONE
;
1781 * dcs_confirm_callback:
1783 * Perform a confirm callback and wait for the reply. As defined
1784 * in the config_admin(3CFGADM) man page, 1 is returned if the
1785 * operation should be allowed to continue and 0 otherwise.
1788 dcs_confirm_callback(void *appdata_ptr
, const char *message
)
1791 rdr_msg_hdr_t req_hdr
;
1792 cfga_params_t req_data
;
1793 struct cfga_confirm
*cb_data
;
1794 rdr_msg_hdr_t reply_hdr
;
1795 cfga_params_t reply_data
;
1798 static char *op_name
= "confirm callback";
1802 if (appdata_ptr
== NULL
) {
1803 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1807 /* get the current session information */
1808 if ((sp
= curr_ses()) == NULL
) {
1809 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1813 cb_data
= (struct cfga_confirm
*)appdata_ptr
;
1815 /* prepare header information */
1817 req_hdr
.message_opcode
= RDR_CONF_CONFIRM_CALLBACK
;
1818 req_hdr
.data_type
= RDR_REQUEST
;
1820 /* prepare confirm callback specific data */
1821 (void) memset(&req_data
, 0, sizeof (req_data
));
1822 req_data
.conf_cb
.confp
= cb_data
;
1823 req_data
.conf_cb
.message
= (char *)message
;
1825 PRINT_MSG_DBG(DCS_SEND
, &req_hdr
);
1827 /* send the message */
1828 snd_status
= rdr_snd_msg(sp
->fd
, &req_hdr
, &req_data
, DCS_SND_TIMEOUT
);
1830 if (snd_status
== RDR_ABORTED
) {
1834 if (snd_status
!= RDR_OK
) {
1835 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1842 rcv_status
= rdr_rcv_msg(sp
->fd
, &reply_hdr
, &reply_data
,
1843 DCS_RCV_CB_TIMEOUT
);
1845 if (rcv_status
!= RDR_OK
) {
1846 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1847 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1852 * Perform several checks to see if we have a
1853 * valid response to the confirm callback.
1855 if (invalid_msg(&reply_hdr
)) {
1856 dcs_log_msg(LOG_ERR
, DCS_MSG_INVAL
);
1857 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1861 /* check the opcode and type */
1862 if ((reply_hdr
.message_opcode
!= RDR_CONF_CONFIRM_CALLBACK
) ||
1863 (reply_hdr
.data_type
!= RDR_REPLY
)) {
1864 DCS_DBG(DBG_MSG
, "bad opcode or message type");
1865 dcs_log_msg(LOG_ERR
, DCS_MSG_INVAL
);
1866 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1870 PRINT_MSG_DBG(DCS_RECEIVE
, &reply_hdr
);
1872 /* check for incorrect callback id */
1873 if (reply_data
.conf_cb
.confp
->confirm
!= cb_data
->confirm
) {
1874 dcs_log_msg(LOG_ERR
, DCS_MSG_INVAL
);
1875 dcs_log_msg(LOG_NOTICE
, DCS_CONF_CB_ERR
);
1880 * Got back valid response: return the user's answer
1882 return (reply_data
.conf_cb
.response
);
1887 * dcs_message_callback:
1889 * Perform a message callback to display a string to the user.
1891 * Note: There is no documentation about possible return values
1892 * for the message callback. It is assumed that the value returned
1893 * is ignored, so 0 is returned for all cases.
1896 dcs_message_callback(void *appdata_ptr
, const char *message
)
1899 rdr_msg_hdr_t req_hdr
;
1900 cfga_params_t req_data
;
1901 struct cfga_msg
*cb_data
;
1903 static char *op_name
= "message callback";
1907 if (appdata_ptr
== NULL
) {
1908 dcs_log_msg(LOG_NOTICE
, DCS_MSG_CB_ERR
);
1912 /* get the current session information */
1913 if ((sp
= curr_ses()) == NULL
) {
1914 dcs_log_msg(LOG_NOTICE
, DCS_MSG_CB_ERR
);
1918 cb_data
= (struct cfga_msg
*)appdata_ptr
;
1920 /* prepare header information */
1922 req_hdr
.message_opcode
= RDR_CONF_MSG_CALLBACK
;
1923 req_hdr
.data_type
= RDR_REQUEST
;
1925 /* prepare message callback specific data */
1926 (void) memset(&req_data
, 0, sizeof (req_data
));
1927 req_data
.msg_cb
.msgp
= cb_data
;
1928 req_data
.msg_cb
.message
= (char *)message
;
1930 PRINT_MSG_DBG(DCS_SEND
, &req_hdr
);
1932 /* send the message */
1933 snd_status
= rdr_snd_msg(sp
->fd
, &req_hdr
, (cfga_params_t
*)&req_data
,
1936 if (snd_status
== RDR_ABORTED
) {
1940 if (snd_status
!= RDR_OK
) {
1941 dcs_log_msg(LOG_ERR
, DCS_OP_REPLY_ERR
, op_name
);
1942 dcs_log_msg(LOG_NOTICE
, DCS_MSG_CB_ERR
);
1952 * Consult the list of supported versions and find the highest supported
1953 * version that is less than or equal to the version requested in the
1954 * parameters. This assumes that the list of supported versions is ordered
1955 * so that the highest supported version is the first element, and that
1956 * the versions are strictly decreasing.
1959 resolve_version(ushort_t req_major
, ushort_t req_minor
)
1966 num_vers
= sizeof (ver_supp
) / sizeof (*ver_supp
);
1968 /* default to the lowest version */
1969 act_ver
= ver_supp
[num_vers
- 1];
1971 for (i
= 0; i
< num_vers
; i
++) {
1973 if (req_major
== ver_supp
[i
].major
) {
1975 if (req_minor
>= ver_supp
[i
].minor
) {
1977 * The major version matches and the
1978 * minor version either matches, or
1979 * is the best match that we have.
1981 act_ver
= ver_supp
[i
];
1985 } else if (req_major
> ver_supp
[i
].major
) {
1987 * The requested major version is larger than
1988 * the current version we are checking. There
1989 * is not going to be a better match.
1991 act_ver
= ver_supp
[i
];
1996 DCS_DBG(DBG_SES
, "requested ver: %d.%d, closest match: %d.%d",
1997 req_major
, req_minor
, act_ver
.major
, act_ver
.minor
);
2006 * Check a list of cfga_list_data_t structures to filter out the ones
2007 * that don't have other-read permissions. All valid entries are placed
2008 * at the beginning of the array and the count of entries is updated.
2011 filter_list_data(int perm
, int *nlistp
, cfga_list_data_t
*linfo
)
2019 struct stat ap_info
;
2022 DCS_DBG(DBG_MSG
, "list access = %s", (perm
== RDR_PRIVILEGED
) ?
2023 "RDR_PRIVILEGED" : "RDR_NOT_PRIVILEGED");
2026 * Check if the user has priviledged access
2027 * to view all attachment points
2029 if (perm
== RDR_PRIVILEGED
) {
2038 * No priviledged access, check each attachment point to
2039 * see if the user has access (other:read) to view it.
2047 * Use a simple algorithm to compact the array so that
2048 * all attachment points that can be viewed are at the
2049 * beginning of the array. Adjust the count of the
2050 * attachment points accordingly.
2052 while (curr_ap
< num_aps
) {
2054 stat(linfo
[curr_ap
].ap_phys_id
, &ap_info
);
2056 /* check for unrestricted read permission */
2057 if (ap_info
.st_mode
& S_IROTH
) {
2059 end_block
= curr_ap
+ 1;
2062 * Check if this is the beginning of a
2063 * block of consecutive ap ids that can
2066 while (end_block
< num_aps
) {
2068 stat(linfo
[end_block
].ap_phys_id
, &ap_info
);
2070 /* search until the end of the block */
2071 if (ap_info
.st_mode
& S_IROTH
) {
2078 block_size
= end_block
- curr_ap
;
2080 /* make sure a copy is necessary */
2081 if (curr_ap
!= next_aval
) {
2083 /* copy the block of ap ids all at once */
2084 (void) memmove(&linfo
[next_aval
],
2086 block_size
* sizeof (cfga_list_data_t
));
2089 /* move past the copied block */
2090 next_aval
+= block_size
;
2091 curr_ap
= end_block
;
2093 num_aps_ret
+= block_size
;
2099 DCS_DBG(DBG_ALL
, "filtered %d of %d ap ids", (*nlistp
- num_aps_ret
),
2103 * return the number of aps that have the correct
2104 * access permissions.
2106 *nlistp
= num_aps_ret
;
2111 * generate_sort_order:
2113 * Determine the sort order of an array of cfga_list_data_t structures
2114 * and create an array of rdr_list_t structures that contain the original
2115 * elements tagged with the sort order.
2117 * This function is used to eliminate unnecessary network traffic that
2118 * might occur if the client needs the output of config_list_ext(3CFGADM)
2119 * sorted. Since a comparison is performed in a platform specific manner
2120 * using config_ap_id_cmp(3CFGADM), a client must establish a new session
2121 * for each comparison. For a long lists of attachment points, this can
2122 * slow down a simple list_ext operation significantly. With the sort
2123 * information included in the array of rdr_list_t structures, the client
2124 * can perform the sort operation locally, thus eliminating a great deal
2125 * of network traffic.
2128 generate_sort_order(cfga_list_data_t
*listp
, int nlist
)
2132 cfga_list_data_t
*sortlp
;
2133 cfga_list_data_t
*match
;
2142 /* create our new array */
2143 datalp
= (rdr_list_t
*)malloc(nlist
* sizeof (rdr_list_t
));
2145 if (datalp
== NULL
) {
2150 /* copy over the elements, preserving the original order */
2151 for (curr_ap
= 0; curr_ap
< nlist
; curr_ap
++) {
2152 datalp
[curr_ap
].ap_id_info
= listp
[curr_ap
];
2155 /* handle a one element list */
2157 datalp
[0].sort_order
= 0;
2161 /* sort the cfga_list_data_t array */
2162 qsort(listp
, nlist
, sizeof (listp
[0]), ldata_compare
);
2166 /* process each item in the original list */
2167 for (curr_ap
= 0; curr_ap
< nlist
; curr_ap
++) {
2169 /* look up the sort order in the sorted list */
2170 match
= bsearch(&datalp
[curr_ap
].ap_id_info
, sortlp
,
2171 nlist
, sizeof (cfga_list_data_t
), ldata_compare
);
2174 if (match
!= NULL
) {
2175 datalp
[curr_ap
].sort_order
= match
- sortlp
;
2178 * Should never get here. Since we did a
2179 * direct copy of the array, we should always
2180 * be able to find the ap id that we were
2183 DCS_DBG(DBG_ALL
, "could not find a matching "
2184 "ap id in the sorted list");
2185 datalp
[curr_ap
].sort_order
= 0;
2196 * Compare the two inputs to produce a strcmp(3C) style result. It uses
2197 * config_ap_id_cmp(3CFGADM) to perform the comparison.
2199 * This function is passed to qsort(3C) in generate_sort_order() to sort a
2200 * list of attachment points.
2203 ldata_compare(const void *ap1
, const void *ap2
)
2205 cfga_list_data_t
*ap_id1
;
2206 cfga_list_data_t
*ap_id2
;
2208 ap_id1
= (cfga_list_data_t
*)ap1
;
2209 ap_id2
= (cfga_list_data_t
*)ap2
;
2211 return (config_ap_id_cmp(ap_id1
->ap_log_id
, ap_id2
->ap_log_id
));
2218 * Find short path name of a full path name. If a short path name
2219 * is passed in, the original pointer is returned.
2226 if ((sp
= strrchr(cp
, '/')) != NULL
) {
2236 * determine if fd represents a socket file type.
2242 if (fstat(fd
, &statb
) < 0) {
2245 return (S_ISSOCK(statb
.st_mode
));
2251 * Look for "?port [sun-dr|665]" in input buf.
2252 * Assume only a single thread calls here.
2255 has_dcs_token(char *buf
)
2258 char *delims
= "{} \t\n";
2259 boolean_t port
= B_FALSE
;
2261 while ((token
= strtok(buf
, delims
)) != NULL
) {
2263 if (port
== B_TRUE
) {
2264 if (strcmp(token
, "sun-dr") == 0 ||
2265 strcmp(token
, "665") == 0) {
2271 if (strlen(token
) == 5) {
2273 if (strcmp(token
, "port") == 0) {
2285 * Check global policy file for dcs entry. Just covers common cases.
2292 boolean_t rv
= B_FALSE
;
2294 fp
= fopen("/etc/inet/ipsecinit.conf", "r");
2297 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
2300 if (has_dcs_token(buf
)) {
2302 syslog(LOG_NOTICE
, "dcs using global policy");