269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Buffer management for results.
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic pthread_mutex_t buffer_lock = PTHREAD_MUTEX_INITIALIZER;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Door file descriptor.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Function prototypes.
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void door_server(void *, char *, size_t, door_desc_t *, uint_t);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int cmd_changestate(nvlist_t *, nvlist_t **);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int cmd_private(hp_cmd_t, nvlist_t *, nvlist_t **);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic char *state_str(int);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic int audit_session(ucred_t *, adt_session_data_t **);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void audit_changestate(ucred_t *, char *, char *, char *, int, int,
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void audit_setprivate(ucred_t *, char *, char *, char *, char *,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * door_server_init()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Create the door file, and initialize the door server.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Create the door file */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((fd = open(HOTPLUGD_DOOR, O_CREAT|O_EXCL|O_RDONLY, 0644)) == -1) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Initialize the door service */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot create door service: %s\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Cleanup stale door associations */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Associate door service with door file */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot attach to door file '%s': %s\n", HOTPLUGD_DOOR,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * door_server_fini()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Terminate and cleanup the door server.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * door_server()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * This routine is the handler which responds to each door call.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Each incoming door call is expected to send a packed nvlist
269473047d747f7815af570197e4ef7322d3632cEvan Yan * of arguments which describe the requested action. And each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * response is sent back as a packed nvlist of results.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Results are always allocated on the heap. A global list of
269473047d747f7815af570197e4ef7322d3632cEvan Yan * allocated result buffers is managed, and each one is tracked
269473047d747f7815af570197e4ef7322d3632cEvan Yan * by a unique sequence number. The final step in the protocol
269473047d747f7815af570197e4ef7322d3632cEvan Yan * is for the caller to send a short response using the sequence
269473047d747f7815af570197e4ef7322d3632cEvan Yan * number when the buffer can be released.
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*ARGSUSED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yandoor_server(void *cookie, char *argp, size_t sz, door_desc_t *dp, uint_t ndesc)
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("Door call: cookie=%p, argp=%p, sz=%d\n", cookie, (void *)argp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Special case to free a results buffer */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Unpack the arguments nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Extract the requested command */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_int32(args, HPD_CMD, (int32_t *)&cmd) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Implement the command */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The arguments nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If an nvlist was constructed for the results,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * then pack the results nvlist and return it.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add a sequence number to the results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_add_uint64(results, HPD_SEQNUM, seqnum) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack the results nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Link results buffer into list */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The results nvlist is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Return the results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Return result code (when no nvlist) */
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) door_return((char *)&rv, sizeof (int), NULL, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) door_return((char *)&rv, sizeof (int), NULL, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * check_auth()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Perform an RBAC authorization check.
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((getpwuid_r(euid, &pwd, buf, sizeof (buf)) == NULL) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * cmd_getinfo()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implements the door command to get a hotplug information snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_string(args, HPD_PATH, &path) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_uint32(args, HPD_FLAGS, (uint32_t *)&flags) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get and pack the requested snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((rv = getinfo(path, connection, flags, &root)) == 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_getinfo: getinfo(): rv = %d, buf = %p.\n", rv,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If the above failed or there is no snapshot,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * then only return a status code.
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate nvlist for results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add snapshot and successful status to results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_add_int32(results, HPD_STATUS, 0) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Packed snapshot no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Success */
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * cmd_changestate()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implements the door command to initate a state change operation.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: requires 'modify' authorization.
269473047d747f7815af570197e4ef7322d3632cEvan Yancmd_changestate(nvlist_t *args, nvlist_t **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_lookup_string(args, HPD_PATH, &path) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_lookup_int32(args, HPD_STATE, &state) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_lookup_uint32(args, HPD_FLAGS, (uint32_t *)&flags) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get caller's credentials */
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot get door credentials (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check authorization */
269473047d747f7815af570197e4ef7322d3632cEvan Yan audit_changestate(uc, HP_MODIFY_AUTH, path, connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Perform the state change operation */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = changestate(path, connection, state, flags, &old_state, &root);
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_changestate: changestate() == %d\n", status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Audit the operation */
269473047d747f7815af570197e4ef7322d3632cEvan Yan audit_changestate(uc, HP_MODIFY_AUTH, path, connection, state,
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Caller's credentials no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Pack the results into an nvlist if there is an error snapshot.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If any error occurs while packing the results, the original
269473047d747f7815af570197e4ef7322d3632cEvan Yan * error code from changestate() above is still returned.
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_changestate: results nvlist required.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Pack and discard the error snapshot */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (rv != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_changestate: hp_pack() failed (%s).\n",
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate nvlist for results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_changestate: nvlist_alloc() failed.\n");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add the results into the nvlist */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_add_int32(results, HPD_STATUS, status) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_byte_array(results, HPD_INFO, (uchar_t *)buf,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * cmd_private()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Implementation of the door command to set or get bus private options.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: requires 'modify' authorization for the 'set' command.
269473047d747f7815af570197e4ef7322d3632cEvan Yancmd_private(hp_cmd_t cmd, nvlist_t *args, nvlist_t **resultsp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get caller's credentials */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((cmd == HP_CMD_SETPRIVATE) && (door_ucred(&uc) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan log_err("Cannot get door credentials (%s)\n", strerror(errno));
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Get arguments */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_lookup_string(args, HPD_PATH, &path) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_lookup_string(args, HPD_CONNECTION, &connection) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_lookup_string(args, HPD_OPTIONS, &options) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Check authorization */
269473047d747f7815af570197e4ef7322d3632cEvan Yan audit_setprivate(uc, HP_MODIFY_AUTH, path, connection, options,
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Perform the operation */
269473047d747f7815af570197e4ef7322d3632cEvan Yan status = private_options(path, connection, cmd, options, &values);
269473047d747f7815af570197e4ef7322d3632cEvan Yan dprintf("cmd_private: private_options() == %d\n", status);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Audit the operation */
269473047d747f7815af570197e4ef7322d3632cEvan Yan audit_setprivate(uc, HP_MODIFY_AUTH, path, connection, options,
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Construct an nvlist if values were returned */
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Allocate nvlist for results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvlist_alloc(&results, NV_UNIQUE_NAME_TYPE, 0) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Add values and status to the results */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((nvlist_add_int32(results, HPD_STATUS, status) != 0) ||
269473047d747f7815af570197e4ef7322d3632cEvan Yan (nvlist_add_string(results, HPD_OPTIONS, values) != 0)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The values string is no longer needed */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * get_seqnum()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Allocate the next unique sequence number for a results buffer.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * add_buffer()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Link a results buffer into the list containing all buffers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((node = (i_buffer_t *)malloc(sizeof (i_buffer_t))) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The consequence is a memory leak. */
269473047d747f7815af570197e4ef7322d3632cEvan Yan * free_buffer()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Remove a results buffer from the list containing all buffers.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * audit_session()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize an audit session.
269473047d747f7815af570197e4ef7322d3632cEvan Yanaudit_session(ucred_t *ucred, adt_session_data_t **sessionp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (adt_set_from_ucred(session, ucred, ADT_NEW) != 0) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (-1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan * audit_changestate()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Audit a 'changestate' door command.
269473047d747f7815af570197e4ef7322d3632cEvan Yanaudit_changestate(ucred_t *ucred, char *auth, char *path, char *connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((event = adt_alloc_event(session, ADT_hotplug_state)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan event->adt_hotplug_state.new_state = state_str(new_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan event->adt_hotplug_state.old_state = state_str(old_state);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Put the event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (adt_put_event(event, pass_fail, fail_reason) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * audit_setprivate()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Audit a 'set private' door command.
269473047d747f7815af570197e4ef7322d3632cEvan Yanaudit_setprivate(ucred_t *ucred, char *auth, char *path, char *connection,
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((event = adt_alloc_event(session, ADT_hotplug_set)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Put the event */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (adt_put_event(event, pass_fail, fail_reason) != 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * state_str()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Convert a state from integer to string.
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic char *
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("EMPTY");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("PRESENT");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("POWERED");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("ENABLED");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("PORT-EMPTY");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("PORT-PRESENT");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("OFFLINE");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("ATTACHED");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("MAINTENANCE");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("ONLINE");
269473047d747f7815af570197e4ef7322d3632cEvan Yan return ("UNKNOWN");