/*
* 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 <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>
#include <stropts.h>
#include <door.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <auth_attr.h>
#include <secdb.h>
#include <fcntl.h>
#include <string.h>
#include <alloca.h>
#include <pthread.h>
#include <ucred.h>
#include "isns_server.h"
#include "admintf.h"
#include "isns_mgmt.h"
#include "isns_utils.h"
#include "isns_protocol.h"
#include "isns_log.h"
#include "isns_provider.h"
/* door creation flag */
extern boolean_t door_created;
/* macro for allocating name buffers for the request */
(unsigned)(n+2) * sizeof (xmlChar *))
/* macro for allocating association pair buffers for the request */
(unsigned)(n+2) * sizeof (assoc_pair_t *))
(unsigned)(n+2) * sizeof (object_attrlist_t *))
#if LIBXML_VERSION >= 20904
#define XMLSTRING_CAST (const char *)
#else
#endif
/* operation table */
{NULL, 0}
};
/* object table */
{NODEOBJECT, Node},
{NULL, 0}
};
/*
* list to capture thread id and associated door return buffer
* the return buffer from the previous door return is freed
* when the same thread is invoked to take another request.
* While the server is running one buffer is outstanding
* to be freed.
*/
/*
* get_op_id_from_doc --
* extracts an operation id through the given context ptr.
*
* ctext: context ptr for the original doc
*
* Returns an operation id if found or -1 otherwise.
*/
static int
{
int i;
"xpath obj->nodesetval->nodeNr: %d",
}
}
return (-1);
}
/*
* process_get_request_from_doc --
* looks for the object through the context ptr and gets the object
* name. Possible object types are Node, DD, DD set and server-config.
*
* ctext: context ptr for the original doc to parse request info.
* req: request to be filled up.
*
* Returns 0 if successful or an error code otherwise.
*/
static int
{
int i, cnt;
int obj = 0;
/*
* To handle DiscoveryDomain and DiscoveryDomainSet
* searches isnsobject instead of the object directly.
*/
if (xmlStrncmp(
== 0) {
break;
}
}
}
if (obj == 0) {
/* check the server config request. */
strlen(ISNSSERVER)) == 0) {
break;
}
}
}
}
if (obj == 0) {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
}
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
switch (obj) {
/* using the same algorithm for isns object */
case Node:
case DiscoveryDomain:
case DiscoveryDomainSet:
for (i = 0; i < cnt; i++) {
if (xpath_obj)
return (ERR_MALLOC_FAILED);
}
}
}
}
break;
case ServerConfig:
/* indication the obj type is sufficient. */
break;
default:
return (ERR_XML_OP_FAILED);
}
return (0);
}
/*
* process_enumerate_request_from_doc --
* looks for the object through the context ptr and sets the
* request with object type.
*
* ctext: context ptr for the original doc to parse request info.
* req: request to be filled up.
*
* Returns 0 if successful or an error code otherwise.
*/
static int
{
int i;
int obj = 0;
if (xmlStrncmp(
== 0) {
break;
}
}
} else {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (obj == 0) {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
}
return (0);
}
/*
* process_getAssociated_request_from_doc --
* first looks for association type through the contexti and then
* find out the given object. That will indicate the direction of
* association, containter to member or vice versa.
* Lastly it extract the object name form the doc that assocation
* is requested.
*
* ctext: context ptr for the original doc to parse request info.
* req: request to be filled up.
*
* Returns 0 if successful or an error code otherwise.
*/
static int
{
if (xmlStrncmp(
== 0) {
break;
}
}
}
if (obj == 0) {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
}
switch (obj) {
/* using the same algorithm for isns object */
case DiscoveryDomainMember:
} else {
DDOBJECT);
} else {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
}
break;
case DiscoveryDomainSetMember:
} else {
DDOBJECT);
} else {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
}
break;
default:
return (ERR_XML_OP_FAILED);
}
/* now process the name attr */
/* for (i = cnt - 1; i >= 0; i--) { */
for (i = 0; i < cnt; i++) {
return (ERR_MALLOC_FAILED);
}
}
}
}
return (0);
}
/*
* process_delete_request_from_doc --
* first looks for the object through the context ptr and sets the
* request with additional data.
* For DD and DD set, the name is given.
* For DD and DD set membership, container and member pairs are given.
*
* ctext: context ptr for the original doc to parse request info.
* req: request to be filled up.
*
* Returns 0 if successful or an error code otherwise.
*/
static int
{
int i, cnt;
int obj = 0;
break;
}
}
if (obj == 0) {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
}
switch (obj) {
case DiscoveryDomainMember:
/* at least one object exists to get here. */
for (i = 0; i < cnt; i++) {
}
member =
}
}
return (ERR_MALLOC_FAILED);
}
malloc(sizeof (assoc_pair_t));
return (ERR_MALLOC_FAILED);
}
} else {
}
}
return (ERR_XML_OP_FAILED);
}
}
break;
case DiscoveryDomainSetMember:
/* at least one object exists to get here. */
for (i = 0; i < cnt; i++) {
}
member =
}
}
return (ERR_MALLOC_FAILED);
}
malloc(sizeof (assoc_pair_t));
return (ERR_MALLOC_FAILED);
}
} else {
}
}
return (ERR_XML_OP_FAILED);
}
}
break;
case DiscoveryDomain:
case DiscoveryDomainSet:
for (i = 0; i < cnt; i++) {
if (xpath_obj)
return (ERR_MALLOC_FAILED);
}
}
}
}
break;
default:
return (ERR_XML_OP_FAILED);
}
return (0);
}
/*
* process_createModify_request_from_doc --
* first looks for the object through the context ptr and sets the
* request with additional data.
* For DD and DD set, the name is given.
* For DD and DD set membership, container and member pairs are given.
*
* ctext: context ptr for the original doc to parse request info.
* req: request to be filled up.
*
* Returns 0 if successful or an error code otherwise.
*/
static int
{
int i, cnt;
int obj = 0;
break;
}
}
if (obj == 0) {
return (ERR_XML_VALID_OBJECT_NOT_FOUND);
}
if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
}
switch (obj) {
case DiscoveryDomainMember:
/* at least one object exists to get here. */
for (i = 0; i < cnt; i++) {
}
member =
}
}
return (ERR_MALLOC_FAILED);
}
malloc(sizeof (assoc_pair_t));
return (ERR_MALLOC_FAILED);
}
} else {
}
}
return (ERR_XML_OP_FAILED);
}
}
break;
case DiscoveryDomainSetMember:
/* at least one object exists to get here. */
for (i = 0; i < cnt; i++) {
}
member =
}
}
return (ERR_MALLOC_FAILED);
}
malloc(sizeof (assoc_pair_t));
return (ERR_MALLOC_FAILED);
}
} else {
}
}
return (ERR_XML_OP_FAILED);
}
}
break;
case DiscoveryDomain:
case DiscoveryDomainSet:
/* at least one object exists to get here. */
for (i = 0; i < cnt; i++) {
(object_attrlist_t **)NULL) {
return (ERR_MALLOC_FAILED);
}
malloc(sizeof (object_attrlist_t));
return (ERR_MALLOC_FAILED);
}
}
NULL) {
if (xpath_obj)
return (ERR_MALLOC_FAILED);
}
}
}
}
/*
* check the enabled element.
* Only one child element so check the children ptr.
*/
== NULL) {
return (ERR_MALLOC_FAILED);
}
/* value is children of enabled. */
if (xmlStrncmp(
== 0) {
= B_TRUE;
} else {
= B_FALSE;
}
}
}
break;
default:
return (ERR_XML_OP_FAILED);
}
return (0);
}
/*
* build_mgmt_request -- extracts the request info from the given XML doc.
*
* x_doc: ptr to the request XML doc
* req: ptr to the request struct to be filled up.
*
* Return value: ISNS_RSP_SUCCESSFUL if successful or an error code.
*/
static int
{
int op;
/* get the operation first. */
return (ERR_XML_FAILED_TO_SET_XPATH_CONTEXT);
}
if (op == -1) {
return (ERR_XML_VALID_OPERATION_NOT_FOUND);
}
if (ret != 0) {
return (ERR_DOOR_SERVER_DETECTED_INVALID_USER);
}
/* write operations are restricted. */
}
}
if (ISNS_MGMT_OPERATION_TYPE_ENABLED()) {
}
switch (op) {
case (get_op):
break;
case (getAssociated_op):
break;
case (enumerate_op):
break;
case (delete_op):
break;
case (createModify_op):
break;
default:
}
return (ret);
}
/*
* build_mgmt_response -- sets an XML doc with a root and calls a porper
* routine based on the request. If the called routine constructed
* the response doc with the result element, this routine fills up
* response buffer with raw XML doc.
*
* reponse: ptr to response buffer
* req: request to be processed.
* size: ptr to the response doc buffer
*/
static int
{
int ret;
NULL) {
return (ERR_XML_SETPROP_FAILED);
}
case get_op:
case Node:
break;
case DiscoveryDomain:
break;
case DiscoveryDomainSet:
break;
case ServerConfig:
break;
default:
}
break;
case enumerate_op:
case Node:
break;
case DiscoveryDomain:
break;
case DiscoveryDomainSet:
break;
default:
}
break;
case getAssociated_op:
case DiscoveryDomainMember:
} else {
}
break;
case DiscoveryDomainSetMember:
} else {
}
break;
default:
}
break;
case createModify_op:
case DiscoveryDomain:
case DiscoveryDomainSet:
break;
case DiscoveryDomainMember:
case DiscoveryDomainSetMember:
break;
default:
}
break;
case delete_op:
case DiscoveryDomainMember:
case DiscoveryDomainSetMember:
break;
case DiscoveryDomain:
case DiscoveryDomainSet:
break;
default:
}
break;
default:
}
/*
* if failed check to see the doc contains the result element.
* if not, the response is set with only an error code.
*/
if (ret != ISNS_RSP_SUCCESSFUL) {
"build_mgmt_response",
"returning repsonse only with error code %d\n", ret);
} else {
}
} else {
/* can't verify the xml doc. dump return the doc anyway. */
}
} else {
}
return (ret);
}
/*
* build_result_message -- construct a response doc with the given result.
* Result contains status code and message.
*
* reponse: ptr to response doc
* code: result code
* size: ptr to the response doc size
*/
static int
{
if (code == ISNS_RSP_SUCCESSFUL) {
}
} else {
}
}
}
return (ret);
}
/*
* cleanup_request -- deallocatate memory associated with the given request
* structure.
*/
static void
{
int i;
case (get_op):
}
break;
case (getAssociated_op):
}
break;
case (enumerate_op):
break;
case (delete_op):
}
} else {
}
}
break;
case (createModify_op):
}
}
}
break;
}
}
/*
* Find a matching entry for the given thread id.
*/
{
while (thr) {
return (thr);
}
}
return (NULL);
}
/*
* Add an entry to the thr_list for the given thread id.
*/
static int
{
return (ERR_MALLOC_FAILED);
}
} else {
}
}
return (ISNS_RSP_SUCCESSFUL);
}
/*
* door_server -- proecess the management request and send response back
* the client.
*
* In order to handle allocation after door_return,
* a global list, thr_list, is maintained to free the response buffer
* from the previous invocation of the server function on the same thread.
* Note: the door framework creates a thread and the same thread is used
* while a new thread is created for concurrent door_calls.
*
* If a thread is used once the buffer will be left allocated.
*/
/*ARGSUSED*/
static void
{
if (ISNS_MGMT_REQUEST_RECEIVED_ENABLED()) {
}
if (door_ucred(&uc) != 0) {
"door_ucred failed. errno: %d\n", errno);
if (ret == ISNS_RSP_SUCCESSFUL) {
/* Not reached */
} else {
/* Not reached */
}
}
} else {
}
} else {
}
/* free the ucred */
ucred_free(uc);
if (resp_buf) {
tid = pthread_self();
} else {
"free the previouly returned buffer %x on this thread\n",
"store the currently allocated buffer %x on this thread\n",
resp_buf);
}
"door_server", "exiting with response:\n %s\n",
(const char *)resp_buf);
if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) {
}
/* Not reached */
}
if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) {
}
}
/*
* setup_mgmt_door -- Create a door portal for management application requests
*
* First check to see if another daemon is already running by attempting
* to send an empty request to the door. If successful it means this
* daemon should exit.
*/
int
{
/* check if a door is already running. */
"<isnsRequest><get><isnsObject>"
"<DiscoveryDomain name=\"default\">"
"</DiscoveryDomain></isnsObject></get>"
"</isnsRequest>";
/* door already running. */
"management door is already runninng.");
}
return (0);
}
}
"Failed to create managment door");
exit(1);
}
exit(1);
}
}
/* make sure the file permission set to general access. */
(void) fdetach(ISNS_DOOR_NAME);
"fattach failed on %s errno=%d",
return (-1);
}
return (0);
}