/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <strings.h>
#include <alloca.h>
#include <door.h>
#include <pthread.h>
#include <synch.h>
#include <pwd.h>
#include <auth_list.h>
#include <auth_attr.h>
#include <bsm/adt_event.h>
#include <libnvpair.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
#include "hotplugd_impl.h"
/*
* Buffer management for results.
*/
typedef struct i_buffer {
char *buffer;
} i_buffer_t;
/*
* Door file descriptor.
*/
/*
* Function prototypes.
*/
static int check_auth(ucred_t *, const char *);
static void add_buffer(uint64_t, char *);
static void free_buffer(uint64_t);
static uint64_t get_seqnum(void);
static char *state_str(int);
static void audit_changestate(ucred_t *, char *, char *, char *, int, int,
int);
static void audit_setprivate(ucred_t *, char *, char *, char *, char *,
int);
/*
* door_server_init()
*
* Create the door file, and initialize the door server.
*/
door_server_init(void)
{
int fd;
/* Create the door file */
log_err("Door service is already running.\n");
} else {
log_err("Cannot open door file '%s': %s\n",
}
return (B_FALSE);
}
/* Initialize the door service */
return (B_FALSE);
}
/* Cleanup stale door associations */
(void) fdetach(HOTPLUGD_DOOR);
/* Associate door service with door file */
(void) door_revoke(door_fd);
(void) fdetach(HOTPLUGD_DOOR);
door_fd = -1;
return (B_FALSE);
}
return (B_TRUE);
}
/*
* door_server_fini()
*
* Terminate and cleanup the door server.
*/
void
door_server_fini(void)
{
if (door_fd != -1) {
(void) door_revoke(door_fd);
(void) fdetach(HOTPLUGD_DOOR);
}
(void) unlink(HOTPLUGD_DOOR);
}
/*
* door_server()
*
* This routine is the handler which responds to each door call.
* Each incoming door call is expected to send a packed nvlist
* of arguments which describe the requested action. And each
* response is sent back as a packed nvlist of results.
*
* Results are always allocated on the heap. A global list of
* allocated result buffers is managed, and each one is tracked
* by a unique sequence number. The final step in the protocol
* is for the caller to send a short response using the sequence
* number when the buffer can be released.
*/
/*ARGSUSED*/
static void
{
int rv;
sz);
/* Special case to free a results buffer */
return;
}
/* Unpack the arguments nvlist */
log_err("Cannot unpack door arguments.\n");
goto fail;
}
/* Extract the requested command */
log_err("Cannot decode door command.\n");
goto fail;
}
/* Implement the command */
switch (cmd) {
case HP_CMD_GETINFO:
break;
case HP_CMD_CHANGESTATE:
break;
case HP_CMD_SETPRIVATE:
case HP_CMD_GETPRIVATE:
break;
default:
break;
}
/* The arguments nvlist is no longer needed */
/*
* If an nvlist was constructed for the results,
* then pack the results nvlist and return it.
*/
/* Add a sequence number to the results */
seqnum = get_seqnum();
log_err("Cannot add sequence number.\n");
goto fail;
}
/* Pack the results nvlist */
NV_ENCODE_NATIVE, 0) != 0) {
log_err("Cannot pack door results.\n");
goto fail;
}
/* Link results buffer into list */
/* The results nvlist is no longer needed */
/* Return the results */
return;
}
/* Return result code (when no nvlist) */
return;
fail:
}
/*
* check_auth()
*
* Perform an RBAC authorization check.
*/
static int
{
log_info("Unauthorized door call.\n");
return (-1);
}
return (0);
}
/*
* cmd_getinfo()
*
* Implements the door command to get a hotplug information snapshot.
*/
static int
{
char *path;
char *connection;
int rv;
dprintf("cmd_getinfo:\n");
/* Get arguments */
dprintf("cmd_getinfo: invalid arguments.\n");
return (EINVAL);
}
connection = NULL;
flags = 0;
/* Get and pack the requested snapshot */
}
(void *)buf);
/*
* If the above failed or there is no snapshot,
* then only return a status code.
*/
if (rv != 0)
return (rv);
return (EFAULT);
/* Allocate nvlist for results */
dprintf("cmd_getinfo: nvlist_alloc() failed.\n");
return (ENOMEM);
}
/* Add snapshot and successful status to results */
dprintf("cmd_getinfo: nvlist add failure.\n");
return (ENOMEM);
}
/* Packed snapshot no longer needed */
/* Success */
return (0);
}
/*
* cmd_changestate()
*
* Implements the door command to initate a state change operation.
*
* NOTE: requires 'modify' authorization.
*/
static int
{
dprintf("cmd_changestate:\n");
/* Get arguments */
dprintf("cmd_changestate: invalid arguments.\n");
return (EINVAL);
}
flags = 0;
/* Get caller's credentials */
if (door_ucred(&uc) != 0) {
return (EACCES);
}
/* Check authorization */
dprintf("cmd_changestate: access denied.\n");
ucred_free(uc);
return (EACCES);
}
/* Perform the state change operation */
/* Audit the operation */
/* Caller's credentials no longer needed */
ucred_free(uc);
/*
* Pack the results into an nvlist if there is an error snapshot.
*
* If any error occurs while packing the results, the original
* error code from changestate() above is still returned.
*/
dprintf("cmd_changestate: results nvlist required.\n");
/* Pack and discard the error snapshot */
if (rv != 0) {
dprintf("cmd_changestate: hp_pack() failed (%s).\n",
return (status);
}
/* Allocate nvlist for results */
dprintf("cmd_changestate: nvlist_alloc() failed.\n");
return (status);
}
/* Add the results into the nvlist */
len) != 0)) {
dprintf("cmd_changestate: nvlist add failed.\n");
return (status);
}
}
return (status);
}
/*
* cmd_private()
*
* Implementation of the door command to set or get bus private options.
*
* NOTE: requires 'modify' authorization for the 'set' command.
*/
static int
{
int status;
dprintf("cmd_private:\n");
/* Get caller's credentials */
return (EACCES);
}
/* Get arguments */
dprintf("cmd_private: invalid arguments.\n");
return (EINVAL);
}
/* Check authorization */
if ((cmd == HP_CMD_SETPRIVATE) &&
dprintf("cmd_private: access denied.\n");
ucred_free(uc);
return (EACCES);
}
/* Perform the operation */
/* Audit the operation */
if (cmd == HP_CMD_SETPRIVATE) {
status);
ucred_free(uc);
}
/* Construct an nvlist if values were returned */
/* Allocate nvlist for results */
dprintf("cmd_private: nvlist_alloc() failed.\n");
return (ENOMEM);
}
/* Add values and status to the results */
dprintf("cmd_private: nvlist add failed.\n");
return (ENOMEM);
}
/* The values string is no longer needed */
}
return (status);
}
/*
* get_seqnum()
*
* Allocate the next unique sequence number for a results buffer.
*/
static uint64_t
get_seqnum(void)
{
(void) pthread_mutex_lock(&buffer_lock);
seqnum = buffer_seqnum++;
(void) pthread_mutex_unlock(&buffer_lock);
return (seqnum);
}
/*
* add_buffer()
*
* Link a results buffer into the list containing all buffers.
*/
static void
{
/* The consequence is a memory leak. */
log_err("Cannot allocate results buffer: %s\n",
return;
}
(void) pthread_mutex_lock(&buffer_lock);
buffer_list = node;
(void) pthread_mutex_unlock(&buffer_lock);
}
/*
* free_buffer()
*
* Remove a results buffer from the list containing all buffers.
*/
static void
{
(void) pthread_mutex_lock(&buffer_lock);
node = buffer_list;
while (node) {
if (prev) {
} else {
}
break;
}
}
(void) pthread_mutex_unlock(&buffer_lock);
}
/*
* audit_session()
*
* Initialize an audit session.
*/
static int
{
log_err("Cannot start audit session.\n");
return (-1);
}
log_err("Cannot set audit session from ucred.\n");
(void) adt_end_session(session);
return (-1);
}
return (0);
}
/*
* audit_changestate()
*
* Audit a 'changestate' door command.
*/
static void
{
return;
(void) adt_end_session(session);
return;
}
if (result == 0) {
} else {
}
/* Put the event */
log_err("Cannot put audit event.\n");
(void) adt_end_session(session);
}
/*
* audit_setprivate()
*
* Audit a 'set private' door command.
*/
static void
{
return;
(void) adt_end_session(session);
return;
}
if (result == 0) {
} else {
}
/* Put the event */
log_err("Cannot put audit event.\n");
(void) adt_end_session(session);
}
/*
* state_str()
*
* Convert a state from integer to string.
*/
static char *
{
switch (state) {
case DDI_HP_CN_STATE_EMPTY:
return ("EMPTY");
case DDI_HP_CN_STATE_PRESENT:
return ("PRESENT");
case DDI_HP_CN_STATE_POWERED:
return ("POWERED");
case DDI_HP_CN_STATE_ENABLED:
return ("ENABLED");
return ("PORT-EMPTY");
return ("PORT-PRESENT");
case DDI_HP_CN_STATE_OFFLINE:
return ("OFFLINE");
case DDI_HP_CN_STATE_ATTACHED:
return ("ATTACHED");
return ("MAINTENANCE");
case DDI_HP_CN_STATE_ONLINE:
return ("ONLINE");
default:
return ("UNKNOWN");
}
}