xref: /illumos-gate/usr/src/cmd/isns/isnsd/door.c (revision 0687de4f0b1d84cc87ddf92c49ceaec0f551670e)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include    <libxml/xmlreader.h>
27 #include    <libxml/xmlwriter.h>
28 #include    <libxml/tree.h>
29 #include    <libxml/parser.h>
30 #include    <libxml/xpath.h>
31 #include    <stropts.h>
32 #include    <door.h>
33 #include    <errno.h>
34 #include    <sys/types.h>
35 #include    <unistd.h>
36 #include    <pwd.h>
37 #include    <auth_attr.h>
38 #include    <secdb.h>
39 #include    <sys/stat.h>
40 #include    <fcntl.h>
41 #include    <sys/stat.h>
42 #include    <sys/mman.h>
43 #include    <string.h>
44 #include    <alloca.h>
45 #include    <pthread.h>
46 #include    <ucred.h>
47 #include    "isns_server.h"
48 #include    "admintf.h"
49 #include    "isns_mgmt.h"
50 #include    "isns_utils.h"
51 #include    "isns_protocol.h"
52 #include    "isns_log.h"
53 #include    "isns_provider.h"
54 
55 /* door creation flag */
56 extern boolean_t door_created;
57 
58 /* macro for allocating name buffers for the request */
59 #define	NEW_REQARGV(old, n) (xmlChar **)realloc((xmlChar *)old, \
60 	(unsigned)(n+2) * sizeof (xmlChar *))
61 
62 /* macro for allocating association pair buffers for the request */
63 #define	NEW_REQPAIRARGV(old, n) (assoc_pair_t **)realloc((assoc_pair_t *)old, \
64 	(unsigned)(n+2) * sizeof (assoc_pair_t *))
65 
66 /* macro for allocating DD/DD set attribute list buffers for the request */
67 #define	NEW_REQATTRLISTARGV(old, n)\
68 	(object_attrlist_t **)realloc((object_attrlist_t *)old, \
69 	(unsigned)(n+2) * sizeof (object_attrlist_t *))
70 
71 #if LIBXML_VERSION >= 20904
72 #define	XMLSTRING_CAST (const char *)
73 #else
74 #define	XMLSTRING_CAST (const xmlChar *)
75 #endif
76 
77 /* operation table */
78 static op_table_entry_t op_table[] = {
79 	{GET, get_op},
80 	{GETASSOCIATED, getAssociated_op},
81 	{ENUMERATE, enumerate_op},
82 	{CREATEMODIFY, createModify_op},
83 	{DELETE, delete_op},
84 	{NULL, 0}
85 };
86 
87 /* object table */
88 static obj_table_entry_t obj_table[] = {
89 	{NODEOBJECT, Node},
90 	{DDOBJECT, DiscoveryDomain},
91 	{DDSETOBJECT, DiscoveryDomainSet},
92 	{DDOBJECTMEMBER, DiscoveryDomainMember},
93 	{DDSETOBJECTMEMBER, DiscoveryDomainSetMember},
94 	{ISNSSERVER, ServerConfig},
95 	{NULL, 0}
96 };
97 
98 /*
99  * list to capture thread id and associated door return buffer
100  * the return buffer from the previous door return is freed
101  * when the same thread is invoked to take another request.
102  * While the server is running one buffer is outstanding
103  * to be freed.
104  */
105 static thr_elem_t *thr_list = NULL;
106 
107 /*
108  * get_op_id_from_doc --
109  *	    extracts an operation id through the given context ptr.
110  *
111  * ctext: context ptr for the original doc
112  *
113  * Returns an operation id if found or -1 otherwise.
114  */
115 static int
116 get_op_id_from_doc(xmlXPathContextPtr ctext)
117 {
118 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
119 	xmlXPathObjectPtr xpath_obj = NULL;
120 	int i;
121 
122 	for (i = 0; op_table[i].op_str != NULL; i++) {
123 	    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
124 		XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
125 		op_table[i].op_str);
126 	    xpath_obj = xmlXPathEvalExpression(expr, ctext);
127 	    if ((xpath_obj) && (xpath_obj->nodesetval) &&
128 		(xpath_obj->nodesetval->nodeNr > 0) &&
129 		(xpath_obj->nodesetval->nodeTab)) {
130 		isnslog(LOG_DEBUG, "get_op_id_from_doc ",
131 		"xpath obj->nodesetval->nodeNr: %d",
132 		xpath_obj->nodesetval->nodeNr);
133 		isnslog(LOG_DEBUG, "get_op_id_from_doc", "operation: %s id: %d",
134 		    op_table[i].op_str, op_table[i].op_id);
135 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
136 		return (op_table[i].op_id);
137 	    }
138 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
139 	}
140 
141 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
142 	return (-1);
143 }
144 
145 /*
146  * process_get_request_from_doc --
147  *	    looks for the object through the context ptr and gets the object
148  *	    name.  Possible object types are Node, DD, DD set and server-config.
149  *
150  * ctext: context ptr for the original doc to parse request info.
151  * req: request to be filled up.
152  *
153  * Returns 0 if successful or an error code otherwise.
154  */
155 static int
156 process_get_request_from_doc(xmlXPathContextPtr ctext, request_t *req)
157 {
158 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
159 	xmlXPathObjectPtr xpath_obj = NULL;
160 	xmlNodeSetPtr r_nodes = NULL;
161 	xmlAttrPtr attr = NULL;
162 	int i, cnt;
163 
164 	int obj = 0;
165 
166 	isnslog(LOG_DEBUG, "process_get_request_from_doc", "entered");
167 	(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
168 	    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSOBJECT);
169 	xpath_obj = xmlXPathEvalExpression(expr, ctext);
170 	if ((xpath_obj) && (xpath_obj->nodesetval) &&
171 	    (xpath_obj->nodesetval->nodeTab) &&
172 	    (xpath_obj->nodesetval->nodeNr > 0) &&
173 	    (xpath_obj->nodesetval->nodeTab[0]->children) &&
174 	    (xpath_obj->nodesetval->nodeTab[0]->children->name)) {
175 	    for (i = 0; obj_table[i].obj_str != NULL; i++) {
176 		/*
177 		 * To handle DiscoveryDomain and DiscoveryDomainSet
178 		 * searches isnsobject instead of the object directly.
179 		 */
180 		if (xmlStrncmp(
181 		    xpath_obj->nodesetval->nodeTab[0]->children->name,
182 		    (xmlChar *)obj_table[i].obj_str, xmlStrlen(
183 		    xpath_obj->nodesetval->nodeTab[0]->children->name))
184 		    == 0) {
185 			obj = obj_table[i].obj_id;
186 			break;
187 		}
188 	    }
189 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
190 	}
191 
192 	if (obj == 0) {
193 	    /* check the server config request. */
194 	    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
195 	    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSSERVER);
196 	    xpath_obj = xmlXPathEvalExpression(expr, ctext);
197 	    if ((xpath_obj) && (xpath_obj->nodesetval) &&
198 		(xpath_obj->nodesetval->nodeNr > 0) &&
199 		(xpath_obj->nodesetval->nodeTab)) {
200 		for (i = 0; obj_table[i].obj_str != NULL; i++) {
201 		    if (strncmp(ISNSSERVER, obj_table[i].obj_str,
202 			strlen(ISNSSERVER)) == 0) {
203 			obj = obj_table[i].obj_id;
204 			break;
205 		    }
206 		}
207 	    }
208 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
209 	}
210 
211 	if (obj == 0) {
212 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
213 	}
214 
215 	req->op_info.obj = obj;
216 
217 	if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
218 	    ISNS_MGMT_OBJECT_TYPE(obj);
219 	}
220 
221 	(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 12,
222 	    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
223 	    obj_table[i].obj_str);
224 	xpath_obj = xmlXPathEvalExpression(expr, ctext);
225 	if (((xpath_obj == NULL) || (xpath_obj->nodesetval == NULL) ||
226 	    (xpath_obj->nodesetval->nodeNr <= 0) ||
227 	    (xpath_obj->nodesetval->nodeTab == NULL))) {
228 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
229 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
230 	}
231 
232 	switch (obj) {
233 	    /* using the same algorithm for isns object */
234 	    case Node:
235 	    case DiscoveryDomain:
236 	    case DiscoveryDomainSet:
237 		r_nodes = xpath_obj->nodesetval;
238 		cnt = r_nodes->nodeNr;
239 		req->count = 0;
240 		req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *));
241 		for (i = 0; i < cnt; i++) {
242 		    attr = r_nodes->nodeTab[i]->properties;
243 		    for (; attr != NULL; attr = attr->next) {
244 			if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR,
245 			    xmlStrlen((xmlChar *)NAMEATTR)) == 0) {
246 				req->req_data.data =
247 				    NEW_REQARGV(req->req_data.data, req->count);
248 				if (req->req_data.data == (xmlChar **)NULL) {
249 				    if (xpath_obj)
250 					xmlXPathFreeObject(xpath_obj);
251 				    return (ERR_MALLOC_FAILED);
252 				}
253 				req->req_data.data[req->count] =
254 				    xmlNodeGetContent(attr->children);
255 				req->req_data.data[++req->count] = NULL;
256 			}
257 		    }
258 		}
259 		break;
260 	    case ServerConfig:
261 		/* indication the obj type is sufficient. */
262 		break;
263 	    default:
264 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
265 		return (ERR_XML_OP_FAILED);
266 	}
267 
268 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
269 	return (0);
270 }
271 
272 /*
273  * process_enumerate_request_from_doc --
274  *	    looks for the object through the context ptr and sets the
275  *	    request with object type.
276  *
277  * ctext: context ptr for the original doc to parse request info.
278  * req: request to be filled up.
279  *
280  * Returns 0 if successful or an error code otherwise.
281  */
282 static int
283 process_enumerate_request_from_doc(xmlXPathContextPtr ctext, request_t *req)
284 {
285 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
286 	xmlXPathObjectPtr xpath_obj = NULL;
287 	int i;
288 
289 	int obj = 0;
290 
291 	isnslog(LOG_DEBUG, "process_enumerate_request_from_doc", "entered");
292 	(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
293 	    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ISNSOBJECTTYPE);
294 	xpath_obj = xmlXPathEvalExpression(expr, ctext);
295 	isnslog(LOG_DEBUG, "process_enumerate_request_from_doc",
296 	"xpath obj->nodesetval->nodeNR: %d", xpath_obj->nodesetval->nodeNr);
297 	if ((xpath_obj) && (xpath_obj->nodesetval) &&
298 	    (xpath_obj->nodesetval->nodeNr > 0) &&
299 	    (xpath_obj->nodesetval->nodeTab)) {
300 	    for (i = 0; obj_table[i].obj_str != NULL; i++) {
301 		if (xmlStrncmp(
302 		    xpath_obj->nodesetval->nodeTab[0]->children->content,
303 		    (xmlChar *)obj_table[i].obj_str, xmlStrlen((xmlChar *)
304 		    xpath_obj->nodesetval->nodeTab[0]->children->content))
305 		    == 0) {
306 		    obj = obj_table[i].obj_id;
307 		    break;
308 		}
309 	    }
310 	} else {
311 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
312 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
313 	}
314 
315 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
316 
317 	if (obj == 0) {
318 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
319 	}
320 
321 	req->op_info.obj = obj;
322 
323 	if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
324 	    ISNS_MGMT_OBJECT_TYPE(obj);
325 	}
326 
327 	return (0);
328 }
329 
330 /*
331  * process_getAssociated_request_from_doc --
332  *	    first looks for association type through the contexti and then
333  *	    find out the given object.  That will indicate the direction of
334  *	    association, containter to member or vice versa.
335  *	    Lastly it extract the object name form the doc that assocation
336  *	    is requested.
337  *
338  * ctext: context ptr for the original doc to parse request info.
339  * req: request to be filled up.
340  *
341  * Returns 0 if successful or an error code otherwise.
342  */
343 static int
344 process_getAssociated_request_from_doc(xmlXPathContextPtr ctext, request_t *req)
345 {
346 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
347 	xmlXPathObjectPtr xpath_obj = NULL;
348 	xmlNodeSetPtr r_nodes = NULL;
349 	xmlAttrPtr attr = NULL;
350 	int i, cnt, obj = 0;
351 
352 	isnslog(LOG_DEBUG, "process_getAssociated_request_from_doc", "entered");
353 	(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
354 	    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", ASSOCIATIONTYPE);
355 	xpath_obj = xmlXPathEvalExpression(expr, ctext);
356 	if ((xpath_obj) && (xpath_obj->nodesetval) &&
357 		(xpath_obj->nodesetval->nodeNr > 0) &&
358 		(xpath_obj->nodesetval->nodeTab)) {
359 	    for (i = 0; obj_table[i].obj_str != NULL; i++) {
360 		if (xmlStrncmp(
361 		    xpath_obj->nodesetval->nodeTab[0]->children->content,
362 		    (xmlChar *)obj_table[i].obj_str, xmlStrlen(
363 		    xpath_obj->nodesetval->nodeTab[0]->children->content))
364 		    == 0) {
365 		    obj = obj_table[i].obj_id;
366 		    break;
367 		}
368 	    }
369 	}
370 
371 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
372 
373 	if (obj == 0) {
374 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
375 	}
376 
377 	req->op_info.obj = obj;
378 
379 	if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
380 	    ISNS_MGMT_OBJECT_TYPE(obj);
381 	}
382 
383 	switch (obj) {
384 	    /* using the same algorithm for isns object */
385 	    case DiscoveryDomainMember:
386 		(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
387 		XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", NODEOBJECT);
388 		xpath_obj = xmlXPathEvalExpression(expr, ctext);
389 		r_nodes = xpath_obj->nodesetval;
390 		if ((xpath_obj) && (xpath_obj->nodesetval) &&
391 		    (xpath_obj->nodesetval->nodeNr > 0) &&
392 		    (xpath_obj->nodesetval->nodeTab)) {
393 		    req->assoc_req = member_to_container;
394 		} else {
395 		    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
396 		    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
397 		    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
398 		    DDOBJECT);
399 		    xpath_obj = xmlXPathEvalExpression(expr, ctext);
400 		    r_nodes = xpath_obj->nodesetval;
401 		    if ((xpath_obj) && (xpath_obj->nodesetval) &&
402 			(xpath_obj->nodesetval->nodeNr > 0) &&
403 			(xpath_obj->nodesetval->nodeTab)) {
404 			req->assoc_req = container_to_member;
405 		    } else {
406 			if (xpath_obj) xmlXPathFreeObject(xpath_obj);
407 			return (ERR_XML_VALID_OBJECT_NOT_FOUND);
408 		    }
409 		}
410 		break;
411 	    case DiscoveryDomainSetMember:
412 		(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
413 		XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", DDSETOBJECT);
414 		xpath_obj = xmlXPathEvalExpression(expr, ctext);
415 		r_nodes = xpath_obj->nodesetval;
416 		if ((xpath_obj) && (xpath_obj->nodesetval) &&
417 		    (xpath_obj->nodesetval->nodeNr > 0) &&
418 		    (xpath_obj->nodesetval->nodeTab)) {
419 		    req->assoc_req = container_to_member;
420 		} else {
421 		    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
422 		    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
423 		    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
424 			DDOBJECT);
425 		    xpath_obj = xmlXPathEvalExpression(expr, ctext);
426 		    r_nodes = xpath_obj->nodesetval;
427 		    if ((xpath_obj) && (xpath_obj->nodesetval) &&
428 			(xpath_obj->nodesetval->nodeNr > 0) &&
429 			(xpath_obj->nodesetval->nodeTab)) {
430 			req->assoc_req = member_to_container;
431 		    } else {
432 			if (xpath_obj) xmlXPathFreeObject(xpath_obj);
433 			return (ERR_XML_VALID_OBJECT_NOT_FOUND);
434 		    }
435 		}
436 		break;
437 	    default:
438 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
439 		return (ERR_XML_OP_FAILED);
440 	}
441 
442 	/* now process the name attr */
443 	cnt = r_nodes->nodeNr;
444 	req->count = 0;
445 	req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *));
446 	/* for (i = cnt - 1; i >= 0; i--) { */
447 	for (i = 0; i < cnt; i++) {
448 	    attr = r_nodes->nodeTab[i]->properties;
449 	    for (; attr != NULL; attr = attr->next) {
450 		if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR,
451 		    xmlStrlen((xmlChar *)NAMEATTR)) == 0) {
452 			req->req_data.data =
453 			    NEW_REQARGV(req->req_data.data, req->count);
454 			if (req->req_data.data == (xmlChar **)NULL) {
455 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
456 			    return (ERR_MALLOC_FAILED);
457 			}
458 			req->req_data.data[req->count++] =
459 			xmlNodeGetContent(attr->children);
460 			req->req_data.data[req->count] = NULL;
461 		}
462 	    }
463 	}
464 
465 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
466 	return (0);
467 }
468 
469 /*
470  * process_delete_request_from_doc --
471  *	    first looks for the object through the context ptr and sets the
472  *	    request with additional data.
473  *	    For DD and DD set, the name is given.
474  *	    For DD and DD set membership, container and member pairs are given.
475  *
476  * ctext: context ptr for the original doc to parse request info.
477  * req: request to be filled up.
478  *
479  * Returns 0 if successful or an error code otherwise.
480  */
481 static int
482 process_delete_request_from_doc(xmlXPathContextPtr ctext, request_t *req)
483 {
484 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
485 	xmlXPathObjectPtr xpath_obj = NULL;
486 	xmlNodeSetPtr r_nodes = NULL;
487 	xmlAttrPtr attr = NULL;
488 	xmlChar *container = NULL, *member = NULL;
489 	int i, cnt;
490 
491 	int obj = 0;
492 
493 	isnslog(LOG_DEBUG, "process_delete_request_from_doc", "entered");
494 	for (i = 0; obj_table[i].obj_str != NULL; i++) {
495 	    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
496 		XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
497 		obj_table[i].obj_str);
498 	    xpath_obj = xmlXPathEvalExpression(expr, ctext);
499 	    if ((xpath_obj) && (xpath_obj->nodesetval) &&
500 		(xpath_obj->nodesetval->nodeNr > 0) &&
501 		(xpath_obj->nodesetval->nodeTab)) {
502 		obj = obj_table[i].obj_id;
503 		break;
504 	    }
505 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
506 	}
507 
508 	if (obj == 0) {
509 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
510 	}
511 
512 	req->op_info.obj = obj;
513 
514 	if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
515 	    ISNS_MGMT_OBJECT_TYPE(obj);
516 	}
517 
518 	switch (obj) {
519 	    case DiscoveryDomainMember:
520 		/* at least one object exists to get here. */
521 		r_nodes = xpath_obj->nodesetval;
522 		cnt = r_nodes->nodeNr;
523 		req->count = 0;
524 		req->req_data.pair =
525 		(assoc_pair_t **)malloc(sizeof (assoc_pair_t *));
526 		for (i = 0; i < cnt; i++) {
527 		    attr = r_nodes->nodeTab[i]->properties;
528 		    for (; attr != NULL; attr = attr->next) {
529 			if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR,
530 			    xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) {
531 				container =
532 				xmlNodeGetContent(attr->children);
533 			}
534 			if (xmlStrncmp(attr->name, (xmlChar *)NODENAMEATTR,
535 			    xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) {
536 				member =
537 				xmlNodeGetContent(attr->children);
538 			}
539 		    }
540 		    if (container != NULL && member != NULL) {
541 			    req->req_data.pair =
542 			    NEW_REQPAIRARGV(req->req_data.pair, req->count);
543 			    if (req->req_data.pair == (assoc_pair_t **)NULL) {
544 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
545 				return (ERR_MALLOC_FAILED);
546 			    }
547 			    req->req_data.pair[req->count] = (assoc_pair_t *)
548 				malloc(sizeof (assoc_pair_t));
549 			    if (req->req_data.pair[req->count] == NULL) {
550 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
551 				return (ERR_MALLOC_FAILED);
552 			    }
553 			    req->req_data.pair[req->count]->container =
554 				container;
555 			    req->req_data.pair[req->count]->member =
556 				member;
557 			    req->req_data.data[++req->count] = NULL;
558 		    } else {
559 			    if (container != NULL) {
560 				xmlFree(container);
561 			    }
562 			    if (member != NULL) {
563 				xmlFree(member);
564 			    }
565 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
566 			    return (ERR_XML_OP_FAILED);
567 		    }
568 		    container = NULL;
569 		    member = NULL;
570 		}
571 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
572 		break;
573 	    case DiscoveryDomainSetMember:
574 		/* at least one object exists to get here. */
575 		r_nodes = xpath_obj->nodesetval;
576 		cnt = r_nodes->nodeNr;
577 		req->count = 0;
578 		req->req_data.pair =
579 		(assoc_pair_t **)malloc(sizeof (assoc_pair_t *));
580 		for (i = 0; i < cnt; i++) {
581 		    attr = r_nodes->nodeTab[i]->properties;
582 		    for (; attr != NULL; attr = attr->next) {
583 			if (xmlStrncmp(attr->name, (xmlChar *)DDSETNAMEATTR,
584 			    xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) {
585 				container =
586 				xmlNodeGetContent(attr->children);
587 			}
588 			if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR,
589 			    xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) {
590 				member =
591 				xmlNodeGetContent(attr->children);
592 			}
593 		    }
594 		    if (container != NULL && member != NULL) {
595 			    req->req_data.pair =
596 			    NEW_REQPAIRARGV(req->req_data.pair, req->count);
597 			    if (req->req_data.pair == (assoc_pair_t **)NULL) {
598 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
599 				return (ERR_MALLOC_FAILED);
600 			    }
601 			    req->req_data.pair[req->count] = (assoc_pair_t *)
602 				malloc(sizeof (assoc_pair_t));
603 			    if (req->req_data.pair[req->count] == NULL) {
604 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
605 				return (ERR_MALLOC_FAILED);
606 			    }
607 			    req->req_data.pair[req->count]->container =
608 				container;
609 			    req->req_data.pair[req->count++]->member =
610 				member;
611 			    req->req_data.data[req->count] = NULL;
612 		    } else {
613 			    if (container != NULL) {
614 				xmlFree(container);
615 			    }
616 			    if (member != NULL) {
617 				xmlFree(member);
618 			    }
619 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
620 			    return (ERR_XML_OP_FAILED);
621 		    }
622 		}
623 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
624 		break;
625 	    case DiscoveryDomain:
626 	    case DiscoveryDomainSet:
627 		r_nodes = xpath_obj->nodesetval;
628 		cnt = r_nodes->nodeNr;
629 		req->count = 0;
630 		req->req_data.data = (xmlChar **) malloc(sizeof (xmlChar *));
631 		for (i = 0; i < cnt; i++) {
632 		    attr = r_nodes->nodeTab[i]->properties;
633 		    for (; attr != NULL; attr = attr->next) {
634 			if (xmlStrncmp(attr->name, (xmlChar *)NAMEATTR,
635 			    xmlStrlen((xmlChar *)NAMEATTR)) == 0) {
636 				req->req_data.data =
637 				    NEW_REQARGV(req->req_data.data, req->count);
638 				if (req->req_data.data == (xmlChar **)NULL) {
639 				    if (xpath_obj)
640 					xmlXPathFreeObject(xpath_obj);
641 				    return (ERR_MALLOC_FAILED);
642 				}
643 				req->req_data.data[req->count] =
644 				xmlNodeGetContent(attr->children);
645 				req->req_data.data[++req->count] = NULL;
646 			}
647 		    }
648 		}
649 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
650 		break;
651 	    default:
652 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
653 		return (ERR_XML_OP_FAILED);
654 	}
655 
656 	return (0);
657 }
658 
659 /*
660  * process_createModify_request_from_doc --
661  *	    first looks for the object through the context ptr and sets the
662  *	    request with additional data.
663  *	    For DD and DD set, the name is given.
664  *	    For DD and DD set membership, container and member pairs are given.
665  *
666  * ctext: context ptr for the original doc to parse request info.
667  * req: request to be filled up.
668  *
669  * Returns 0 if successful or an error code otherwise.
670  */
671 static int
672 process_createModify_request_from_doc(xmlXPathContextPtr ctext, request_t *req)
673 {
674 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
675 	xmlXPathObjectPtr xpath_obj = NULL;
676 	xmlNodeSetPtr r_nodes = NULL;
677 	xmlAttrPtr attr = NULL;
678 	xmlChar *container = NULL, *member = NULL, *xml_id;
679 	int i, cnt;
680 
681 	int obj = 0;
682 
683 	isnslog(LOG_DEBUG, "process_createModify_request_from_doc", "entered");
684 	for (i = 0; obj_table[i].obj_str != NULL; i++) {
685 	    (void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
686 		XMLSTRING_CAST "%s\"%s\"]", "//*[name()=",
687 		obj_table[i].obj_str);
688 	    xpath_obj = xmlXPathEvalExpression(expr, ctext);
689 	    if ((xpath_obj) && (xpath_obj->nodesetval) &&
690 		(xpath_obj->nodesetval->nodeNr > 0) &&
691 		(xpath_obj->nodesetval->nodeTab)) {
692 		obj = obj_table[i].obj_id;
693 		break;
694 	    }
695 	    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
696 	}
697 
698 	if (obj == 0) {
699 	    return (ERR_XML_VALID_OBJECT_NOT_FOUND);
700 	}
701 
702 	req->op_info.obj = obj;
703 
704 	if (ISNS_MGMT_OBJECT_TYPE_ENABLED()) {
705 	    ISNS_MGMT_OBJECT_TYPE(obj);
706 	}
707 
708 	switch (obj) {
709 	    case DiscoveryDomainMember:
710 		/* at least one object exists to get here. */
711 		r_nodes = xpath_obj->nodesetval;
712 		cnt = r_nodes->nodeNr;
713 		req->count = 0;
714 		req->req_data.pair =
715 		(assoc_pair_t **)malloc(sizeof (assoc_pair_t *));
716 		for (i = 0; i < cnt; i++) {
717 		    attr = r_nodes->nodeTab[i]->properties;
718 		    for (; attr != NULL; attr = attr->next) {
719 			if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR,
720 			    xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) {
721 				container =
722 				xmlNodeGetContent(attr->children);
723 			}
724 			if (xmlStrncmp(attr->name, (xmlChar *)NODENAMEATTR,
725 			    xmlStrlen((xmlChar *)NODENAMEATTR)) == 0) {
726 				member =
727 				xmlNodeGetContent(attr->children);
728 			}
729 		    }
730 		    if (container != NULL && member != NULL) {
731 			    req->req_data.pair =
732 			    NEW_REQPAIRARGV(req->req_data.pair, req->count);
733 			    if (req->req_data.pair == (assoc_pair_t **)NULL) {
734 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
735 				return (ERR_MALLOC_FAILED);
736 			    }
737 			    req->req_data.pair[req->count] = (assoc_pair_t *)
738 				malloc(sizeof (assoc_pair_t));
739 			    if (req->req_data.pair[req->count] == NULL) {
740 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
741 				return (ERR_MALLOC_FAILED);
742 			    }
743 			    req->req_data.pair[req->count]->container =
744 				container;
745 			    req->req_data.pair[req->count]->member =
746 				member;
747 			    req->req_data.data[++req->count] = NULL;
748 		    } else {
749 			    if (container != NULL) {
750 				xmlFree(container);
751 			    }
752 			    if (member != NULL) {
753 				xmlFree(member);
754 			    }
755 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
756 			    return (ERR_XML_OP_FAILED);
757 		    }
758 		    container = member = NULL;
759 		}
760 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
761 		break;
762 	    case DiscoveryDomainSetMember:
763 		/* at least one object exists to get here. */
764 		r_nodes = xpath_obj->nodesetval;
765 		cnt = r_nodes->nodeNr;
766 		req->count = 0;
767 		req->req_data.pair =
768 		(assoc_pair_t **)malloc(sizeof (assoc_pair_t *));
769 		for (i = 0; i < cnt; i++) {
770 		    attr = r_nodes->nodeTab[i]->properties;
771 		    for (; attr != NULL; attr = attr->next) {
772 			if (xmlStrncmp(attr->name, (xmlChar *)DDSETNAMEATTR,
773 			    xmlStrlen((xmlChar *)DDSETNAMEATTR)) == 0) {
774 				container =
775 				xmlNodeGetContent(attr->children);
776 			}
777 			if (xmlStrncmp(attr->name, (xmlChar *)DDNAMEATTR,
778 			    xmlStrlen((xmlChar *)DDNAMEATTR)) == 0) {
779 				member =
780 				xmlNodeGetContent(attr->children);
781 			}
782 		    }
783 		    if (container != NULL && member != NULL) {
784 			    req->req_data.pair =
785 			    NEW_REQPAIRARGV(req->req_data.pair, req->count);
786 			    if (req->req_data.pair == (assoc_pair_t **)NULL) {
787 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
788 				return (ERR_MALLOC_FAILED);
789 			    }
790 			    req->req_data.pair[req->count] = (assoc_pair_t *)
791 				malloc(sizeof (assoc_pair_t));
792 			    if (req->req_data.pair[req->count] == NULL) {
793 				if (xpath_obj) xmlXPathFreeObject(xpath_obj);
794 				return (ERR_MALLOC_FAILED);
795 			    }
796 			    req->req_data.pair[req->count]->container =
797 				container;
798 			    req->req_data.pair[req->count]->member =
799 				member;
800 			    req->req_data.data[++req->count] = NULL;
801 		    } else {
802 			    if (container != NULL) {
803 				xmlFree(container);
804 			    }
805 			    if (member != NULL) {
806 				xmlFree(member);
807 			    }
808 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
809 			    return (ERR_XML_OP_FAILED);
810 		    }
811 		    container = member = NULL;
812 		}
813 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
814 		break;
815 	    case DiscoveryDomain:
816 	    case DiscoveryDomainSet:
817 		/* at least one object exists to get here. */
818 		r_nodes = xpath_obj->nodesetval;
819 		cnt = r_nodes->nodeNr;
820 		req->count = 0;
821 		req->req_data.attrlist =
822 		(object_attrlist_t **)malloc(sizeof (object_attrlist_t *));
823 		for (i = 0; i < cnt; i++) {
824 		    req->req_data.attrlist =
825 			NEW_REQATTRLISTARGV(req->req_data.attrlist, req->count);
826 		    if (req->req_data.attrlist ==
827 			(object_attrlist_t **)NULL) {
828 			if (xpath_obj) xmlXPathFreeObject(xpath_obj);
829 			return (ERR_MALLOC_FAILED);
830 		    }
831 		    req->req_data.attrlist[req->count] = (object_attrlist_t *)
832 			malloc(sizeof (object_attrlist_t));
833 		    if (req->req_data.attrlist[req->count] == NULL) {
834 			if (xpath_obj) xmlXPathFreeObject(xpath_obj);
835 			return (ERR_MALLOC_FAILED);
836 		    }
837 		    req->req_data.attrlist[req->count]->name = NULL;
838 		    req->req_data.attrlist[req->count]->id = NULL;
839 		    req->req_data.attrlist[req->count]->enabled = NULL;
840 		    attr = r_nodes->nodeTab[i]->properties;
841 		    for (; attr != NULL; attr = attr->next) {
842 			if ((xmlStrncmp(attr->name, (xmlChar *)NAMEATTR,
843 			    xmlStrlen((xmlChar *)NAMEATTR))) == 0) {
844 				req->req_data.attrlist[req->count]->name =
845 				xmlNodeGetContent(attr->children);
846 			}
847 			if ((xmlStrncmp(attr->name, (xmlChar *)IDATTR,
848 			    xmlStrlen((xmlChar *)IDATTR))) == 0) {
849 				req->req_data.attrlist[req->count]->id =
850 				    (uint32_t *)calloc(1, sizeof (uint32_t));
851 				if (req->req_data.attrlist[req->count]->id ==
852 				    NULL) {
853 				    if (xpath_obj)
854 					xmlXPathFreeObject(xpath_obj);
855 				    return (ERR_MALLOC_FAILED);
856 				}
857 				xml_id = xmlNodeGetContent(attr->children);
858 				if (xml_id != NULL) {
859 				    *(req->req_data.attrlist[req->count]->id) =
860 					atoi((const char *)xml_id);
861 				    xmlFree(xml_id);
862 				}
863 			}
864 		    }
865 			/*
866 			 * check the enabled element.
867 			 * Only one child element so check the children ptr.
868 			 */
869 		    if (r_nodes->nodeTab[i]->children) {
870 			req->req_data.attrlist[req->count]->enabled =
871 			    (boolean_t *)malloc(sizeof (boolean_t));
872 			if (req->req_data.attrlist[req->count]->enabled
873 			    == NULL) {
874 			    if (xpath_obj) xmlXPathFreeObject(xpath_obj);
875 			    return (ERR_MALLOC_FAILED);
876 			}
877 			/* value is children of enabled. */
878 			if (xmlStrncmp(
879 			    r_nodes->nodeTab[i]->children->children->content,
880 			    (xmlChar *)XMLTRUE, xmlStrlen((xmlChar *)XMLTRUE))
881 			    == 0) {
882 			    *(req->req_data.attrlist[req->count]->enabled)
883 				= B_TRUE;
884 			} else {
885 			    *(req->req_data.attrlist[req->count]->enabled)
886 				= B_FALSE;
887 			}
888 		    }
889 		    req->req_data.attrlist[++req->count] = NULL;
890 		}
891 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
892 		break;
893 	    default:
894 		if (xpath_obj) xmlXPathFreeObject(xpath_obj);
895 		return (ERR_XML_OP_FAILED);
896 	}
897 
898 	return (0);
899 }
900 
901 /*
902  * build_mgmt_request -- extracts the request info from the given XML doc.
903  *
904  * x_doc: ptr to the request XML doc
905  * req: ptr to the request struct to be filled up.
906  *
907  * Return value: ISNS_RSP_SUCCESSFUL if successful or an error code.
908  */
909 static int
910 process_mgmt_request(xmlDocPtr x_doc, request_t *req, ucred_t *uc)
911 {
912 	result_code_t   ret;
913 	int		op;
914 	xmlXPathContextPtr ctext = NULL;
915 	uid_t			user;
916 	struct passwd		pwds, *pwd;
917 	char			buf_pwd[1024];
918 
919 
920 	isnslog(LOG_DEBUG, "process_mgmt_request", "entered");
921 	(void) memset(req, 0, sizeof (request_t));
922 	/* get the operation first. */
923 	ctext = xmlXPathNewContext(x_doc);
924 	if (ctext == NULL) {
925 	    return (ERR_XML_FAILED_TO_SET_XPATH_CONTEXT);
926 	}
927 
928 	isnslog(LOG_DEBUG, "process_mgmt_request", "xpath context succeeded");
929 	op = get_op_id_from_doc(ctext);
930 	if (op == -1) {
931 	    if (ctext) xmlXPathFreeContext(ctext);
932 	    return (ERR_XML_VALID_OPERATION_NOT_FOUND);
933 	}
934 
935 	user = ucred_getruid(uc);
936 	ret = getpwuid_r(user, &pwds, buf_pwd, sizeof (buf_pwd), &pwd);
937 	if (ret != 0) {
938 	    if (ctext) xmlXPathFreeContext(ctext);
939 	    return (ERR_DOOR_SERVER_DETECTED_INVALID_USER);
940 	}
941 
942 	/* write operations are restricted. */
943 	if ((op == delete_op) || (op == createModify_op)) {
944 	    if (!chkauthattr(ISNS_ADMIN_WRITE_AUTH, pwd->pw_name)) {
945 		if (ctext) xmlXPathFreeContext(ctext);
946 		return (ERR_DOOR_SERVER_DETECTED_NOT_AUTHORIZED_USER);
947 	    }
948 	}
949 
950 	req->op_info.op = op;
951 
952 	if (ISNS_MGMT_OPERATION_TYPE_ENABLED()) {
953 	    ISNS_MGMT_OPERATION_TYPE(op);
954 	}
955 
956 	switch (op) {
957 	    case (get_op):
958 		ret = process_get_request_from_doc(ctext, req);
959 		break;
960 	    case (getAssociated_op):
961 		ret = process_getAssociated_request_from_doc(ctext, req);
962 		break;
963 	    case (enumerate_op):
964 		ret = process_enumerate_request_from_doc(ctext, req);
965 		break;
966 	    case (delete_op):
967 		ret = process_delete_request_from_doc(ctext, req);
968 		break;
969 	    case (createModify_op):
970 		ret = process_createModify_request_from_doc(ctext, req);
971 		break;
972 	    default:
973 		ret = ERR_XML_VALID_OPERATION_NOT_FOUND;
974 	}
975 
976 	if (ctext) xmlXPathFreeContext(ctext);
977 	return (ret);
978 }
979 
980 /*
981  * build_mgmt_response -- sets an XML doc with a root and calls a porper
982  *	    routine based on the request.  If the called routine constructed
983  *	    the response doc with the result element, this routine fills up
984  *	    response buffer with raw XML doc.
985  *
986  * reponse: ptr to response buffer
987  * req: request to be processed.
988  * size: ptr to the response doc buffer
989  */
990 static int
991 build_mgmt_response(xmlChar **response, request_t req, int *size)
992 {
993 
994 	int ret;
995 	xmlDocPtr	doc;
996 	xmlNodePtr	root;
997 	xmlXPathContextPtr ctext = NULL;
998 	xmlChar expr[ISNS_MAX_LABEL_LEN + 13];
999 	xmlXPathObjectPtr xpath_obj = NULL;
1000 
1001 	isnslog(LOG_DEBUG, "build_mgmt_response", "entered");
1002 
1003 	doc = xmlNewDoc((uchar_t *)"1.0");
1004 	root = xmlNewNode(NULL, (xmlChar *)ISNSRESPONSE);
1005 	(void) xmlDocSetRootElement(doc, root);
1006 	if (xmlSetProp(root, (xmlChar *)XMLNSATTR, (xmlChar *)XMLNSATTRVAL) ==
1007 	    NULL) {
1008 	    return (ERR_XML_SETPROP_FAILED);
1009 	}
1010 
1011 	switch (req.op_info.op) {
1012 	    case get_op:
1013 		switch (req.op_info.obj) {
1014 		    case Node:
1015 			ret = get_node_op(&req, doc);
1016 			break;
1017 		    case DiscoveryDomain:
1018 			ret = get_dd_op(&req, doc);
1019 			break;
1020 		    case DiscoveryDomainSet:
1021 			ret = get_ddset_op(&req, doc);
1022 			break;
1023 		    case ServerConfig:
1024 			ret = get_serverconfig_op(doc);
1025 			break;
1026 		    default:
1027 			ret = ERR_INVALID_MGMT_REQUEST;
1028 		}
1029 		break;
1030 	    case enumerate_op:
1031 		isnslog(LOG_DEBUG, "build_mgmt_response", "enumerate_op");
1032 		switch (req.op_info.obj) {
1033 		    case Node:
1034 			ret = enumerate_node_op(doc);
1035 			break;
1036 		    case DiscoveryDomain:
1037 			ret = enumerate_dd_op(doc);
1038 			break;
1039 		    case DiscoveryDomainSet:
1040 			ret = enumerate_ddset_op(doc);
1041 			break;
1042 		    default:
1043 			ret = ERR_INVALID_MGMT_REQUEST;
1044 		}
1045 		break;
1046 	    case getAssociated_op:
1047 		switch (req.op_info.obj) {
1048 		    case DiscoveryDomainMember:
1049 			if (req.assoc_req == container_to_member) {
1050 			    ret = getAssociated_dd_to_node_op(&req, doc);
1051 			} else {
1052 			    ret = getAssociated_node_to_dd_op(&req, doc);
1053 			}
1054 			break;
1055 		    case DiscoveryDomainSetMember:
1056 			if (req.assoc_req == container_to_member) {
1057 			    ret = getAssociated_ddset_to_dd_op(&req, doc);
1058 			} else {
1059 			    ret = getAssociated_dd_to_ddset_op(&req, doc);
1060 			}
1061 			break;
1062 		    default:
1063 			ret = ERR_INVALID_MGMT_REQUEST;
1064 		}
1065 		break;
1066 	    case createModify_op:
1067 		switch (req.op_info.obj) {
1068 		    case DiscoveryDomain:
1069 		    case DiscoveryDomainSet:
1070 			ret = createModify_dd_ddset_op(&req, doc);
1071 			break;
1072 		    case DiscoveryDomainMember:
1073 		    case DiscoveryDomainSetMember:
1074 			ret = create_ddmember_ddsetmember_op(&req, doc,
1075 			    req.op_info.obj);
1076 			break;
1077 		    default:
1078 			ret = ERR_INVALID_MGMT_REQUEST;
1079 		}
1080 		break;
1081 	    case delete_op:
1082 		switch (req.op_info.obj) {
1083 		    case DiscoveryDomainMember:
1084 		    case DiscoveryDomainSetMember:
1085 			ret = delete_ddmember_ddsetmember_op(&req, doc,
1086 			    req.op_info.obj);
1087 			break;
1088 		    case DiscoveryDomain:
1089 		    case DiscoveryDomainSet:
1090 			ret = delete_dd_ddset_op(&req, doc, req.op_info.obj);
1091 			break;
1092 		    default:
1093 			ret = ERR_INVALID_MGMT_REQUEST;
1094 		}
1095 		break;
1096 	    default:
1097 		ret = ERR_INVALID_MGMT_REQUEST;
1098 	}
1099 
1100 	/*
1101 	 * if failed check to see the doc contains the result element.
1102 	 * if not, the response is set with only an error code.
1103 	 */
1104 	if (ret != ISNS_RSP_SUCCESSFUL) {
1105 	    ctext = xmlXPathNewContext(doc);
1106 	    if (ctext != NULL) {
1107 		(void) xmlStrPrintf(expr, ISNS_MAX_LABEL_LEN + 13,
1108 		    XMLSTRING_CAST "%s\"%s\"]", "//*[name()=", RESULT);
1109 		xpath_obj = xmlXPathEvalExpression(expr, ctext);
1110 		if ((xpath_obj == NULL) || (xpath_obj->nodesetval == NULL) ||
1111 		    (xpath_obj->nodesetval->nodeNr <= 0) ||
1112 		    (xpath_obj->nodesetval->nodeTab == NULL)) {
1113 		    isnslog(LOG_DEBUG,
1114 			"build_mgmt_response",
1115 			"returning repsonse only with error code %d\n", ret);
1116 			*response = malloc(sizeof (ret));
1117 			if (*response) **response = ret;
1118 			*size = sizeof (ret);
1119 		} else {
1120 		    xmlDocDumpMemory(doc, response, size);
1121 		}
1122 	    } else {
1123 		/* can't verify the xml doc. dump return the doc anyway. */
1124 		xmlDocDumpMemory(doc, response, size);
1125 	    }
1126 	} else {
1127 	    xmlDocDumpMemory(doc, response, size);
1128 	}
1129 
1130 	if (xpath_obj) xmlXPathFreeObject(xpath_obj);
1131 	if (ctext) xmlXPathFreeContext(ctext);
1132 	if (doc) xmlFreeDoc(doc);
1133 	return (ret);
1134 }
1135 
1136 /*
1137  * build_result_message -- construct a response doc with the given result.
1138  *	    Result contains status code and message.
1139  *
1140  * reponse: ptr to response doc
1141  * code: result code
1142  * size: ptr to the response doc size
1143  */
1144 static int
1145 build_result_message(xmlChar **response, result_code_t code, int *size)
1146 {
1147 	int ret = ISNS_RSP_SUCCESSFUL;
1148 	xmlDocPtr	doc;
1149 	xmlNodePtr	root, n_obj;
1150 	char		numbuf[32];
1151 
1152 	isnslog(LOG_DEBUG, "build_result_response", "entered");
1153 
1154 	doc = xmlNewDoc((uchar_t *)"1.0");
1155 	root = xmlNewNode(NULL, (xmlChar *)ISNSRESPONSE);
1156 	(void) xmlDocSetRootElement(doc, root);
1157 
1158 	n_obj = xmlNewChild(root, NULL, (xmlChar *)RESULT, NULL);
1159 
1160 	if (code == ISNS_RSP_SUCCESSFUL) {
1161 	    (void) sprintf(numbuf, "%d", ISNS_RSP_SUCCESSFUL);
1162 	    if (xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT,
1163 		(xmlChar *)numbuf) == NULL) {
1164 		ret = ERR_XML_NEWCHILD_FAILED;
1165 	    }
1166 	} else {
1167 	    (void) sprintf(numbuf, "%d", code);
1168 	    if (xmlNewChild(n_obj, NULL, (xmlChar *)STATUSELEMENT,
1169 		(xmlChar *)numbuf) == NULL) {
1170 		ret = ERR_XML_NEWCHILD_FAILED;
1171 	    }
1172 	    if (xmlNewChild(n_obj, NULL, (xmlChar *)MESSAGEELEMENT,
1173 		(xmlChar *)result_code_to_str(code)) == NULL) {
1174 		ret = ERR_XML_NEWCHILD_FAILED;
1175 	    }
1176 	}
1177 
1178 	xmlDocDumpMemory(doc, response, size);
1179 
1180 	if (doc) xmlFreeDoc(doc);
1181 	return (ret);
1182 }
1183 
1184 /*
1185  * cleanup_request -- deallocatate memory associated with the given request
1186  *	    structure.
1187  */
1188 static void
1189 cleanup_request(request_t req)
1190 {
1191 	int i;
1192 
1193 	isnslog(LOG_DEBUG, "cleanup_request", "entered");
1194 	switch (req.op_info.op) {
1195 	    case (get_op):
1196 		for (i = 0; i < req.count; i++) {
1197 		    if (req.req_data.data[i])
1198 			xmlFree(req.req_data.data[i]);
1199 		}
1200 		if (req.req_data.data) free(req.req_data.data);
1201 		break;
1202 	    case (getAssociated_op):
1203 		for (i = 0; i < req.count; i++) {
1204 		    if (req.req_data.data[i])
1205 			xmlFree(req.req_data.data[i]);
1206 		}
1207 		if (req.req_data.data) free(req.req_data.data);
1208 		break;
1209 	    case (enumerate_op):
1210 		break;
1211 	    case (delete_op):
1212 		if ((req.op_info.obj == DiscoveryDomainMember) ||
1213 		    (req.op_info.obj == DiscoveryDomainSetMember)) {
1214 		    for (i = 0; i < req.count; i++) {
1215 			if (req.req_data.pair[i]->container)
1216 			    xmlFree(req.req_data.pair[i]->container);
1217 			if (req.req_data.pair[i]->member)
1218 			    xmlFree(req.req_data.pair[i]->member);
1219 			if (req.req_data.pair[i])
1220 			    free(req.req_data.pair[i]);
1221 		    }
1222 		    if (req.req_data.pair) free(req.req_data.pair);
1223 		} else {
1224 		    for (i = 0; i < req.count; i++) {
1225 			if (req.req_data.data[i])
1226 			    xmlFree(req.req_data.data[i]);
1227 		    }
1228 		    if (req.req_data.data) free(req.req_data.data);
1229 		}
1230 		break;
1231 	    case (createModify_op):
1232 		if ((req.op_info.obj == DiscoveryDomainMember) ||
1233 		    (req.op_info.obj == DiscoveryDomainSetMember)) {
1234 		    for (i = 0; i < req.count; i++) {
1235 			if (req.req_data.pair[i]->container)
1236 			    xmlFree(req.req_data.pair[i]->container);
1237 			if (req.req_data.pair[i]->member)
1238 			    xmlFree(req.req_data.pair[i]->member);
1239 			if (req.req_data.pair[i])
1240 			    free(req.req_data.pair[i]);
1241 		    }
1242 		    if (req.req_data.pair) free(req.req_data.pair);
1243 		} else if ((req.op_info.obj == DiscoveryDomain) ||
1244 		    (req.op_info.obj == DiscoveryDomainSet)) {
1245 		    for (i = 0; i < req.count; i++) {
1246 			if (req.req_data.attrlist[i]->name)
1247 			    xmlFree(req.req_data.attrlist[i]->name);
1248 			if (req.req_data.attrlist[i]->id)
1249 			    free(req.req_data.attrlist[i]->id);
1250 			if (req.req_data.attrlist[i]->enabled)
1251 			    free(req.req_data.attrlist[i]->enabled);
1252 			if (req.req_data.pair[i])
1253 			    free(req.req_data.pair[i]);
1254 		    }
1255 		    if (req.req_data.attrlist) free(req.req_data.attrlist);
1256 		}
1257 		break;
1258 	}
1259 }
1260 
1261 /*
1262  * Find a matching entry for the given thread id.
1263  */
1264 static thr_elem_t *match_entry(pthread_t tid)
1265 {
1266 
1267 	thr_elem_t *thr = thr_list;
1268 
1269 	while (thr) {
1270 	    if (pthread_equal(thr->thr_id, tid)) {
1271 		return (thr);
1272 	    }
1273 	    thr = thr->next;
1274 	}
1275 
1276 	return (NULL);
1277 }
1278 
1279 /*
1280  * Add an entry to the thr_list for the given thread id.
1281  */
1282 static int
1283 add_entry(pthread_t tid, xmlChar *doc)
1284 {
1285 
1286 	thr_elem_t *new_e;
1287 	thr_elem_t *thr = thr_list;
1288 
1289 	if ((new_e = malloc(sizeof (thr_elem_t))) == NULL) {
1290 	    return (ERR_MALLOC_FAILED);
1291 	}
1292 	new_e->thr_id = tid;
1293 	new_e->doc = doc;
1294 	new_e->next = NULL;
1295 
1296 	if (thr_list == NULL) {
1297 	    thr_list = new_e;
1298 	} else {
1299 	    while (thr->next) {
1300 		thr = thr->next;
1301 	    }
1302 	    thr->next = new_e;
1303 	}
1304 
1305 	return (ISNS_RSP_SUCCESSFUL);
1306 }
1307 
1308 /*
1309  * door_server -- proecess the management request and send response back
1310  *		the client.
1311  *
1312  * In order to handle allocation after door_return,
1313  * a global list, thr_list, is maintained to free the response buffer
1314  * from the previous invocation of the server function on the same thread.
1315  * Note:  the door framework creates a thread and the same thread is used
1316  * while a new thread is created for concurrent door_calls.
1317  *
1318  * If a thread is used once the buffer will be left allocated.
1319  */
1320 /*ARGSUSED*/
1321 static void
1322 door_server(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
1323     uint_t n_desc)
1324 {
1325 	request_t		req;
1326 	xmlDocPtr		x_doc;
1327 	xmlChar			*resp_buf = NULL;
1328 	int			ret, size = 0;
1329 	pthread_t		tid;
1330 	thr_elem_t		*thr;
1331 	ucred_t			*uc = NULL;
1332 
1333 	if (ISNS_MGMT_REQUEST_RECEIVED_ENABLED()) {
1334 	    ISNS_MGMT_REQUEST_RECEIVED();
1335 	}
1336 
1337 	if (door_ucred(&uc) != 0) {
1338 	    isnslog(LOG_DEBUG, "door_server",
1339 		"door_ucred failed. errno: %d\n", errno);
1340 	    ret = build_result_message(&resp_buf,
1341 		ERR_DOOR_UCRED_FAILED, &size);
1342 	    if (ret == ISNS_RSP_SUCCESSFUL) {
1343 		(void) door_return((char *)resp_buf, size + 1,  NULL, 0);
1344 		/* Not reached */
1345 	    } else {
1346 		ret = ERR_DOOR_UCRED_FAILED;
1347 		(void) door_return((void *)&ret, sizeof (ret),  NULL, 0);
1348 		/* Not reached */
1349 	    }
1350 	}
1351 
1352 	isnslog(LOG_DEBUG, "door_server", "entered with request:\n %s\n", argp);
1353 	if ((x_doc = xmlParseMemory(argp, arg_size)) != NULL) {
1354 		isnslog(LOG_DEBUG, "door_server", "ParseMemory succeeded");
1355 		if ((ret = process_mgmt_request(x_doc, &req, uc)) == 0) {
1356 		    ret = build_mgmt_response(&resp_buf, req, &size);
1357 		} else {
1358 		    ret = build_result_message(&resp_buf, ret, &size);
1359 		}
1360 		xmlFreeDoc(x_doc);
1361 		cleanup_request(req);
1362 	} else {
1363 		ret = build_result_message(&resp_buf,
1364 		    ERR_XML_PARSE_MEMORY_FAILED, &size);
1365 	}
1366 
1367 	/* free the ucred */
1368 	ucred_free(uc);
1369 
1370 	if (resp_buf) {
1371 	    tid = pthread_self();
1372 	    if ((thr = match_entry(tid)) == NULL) {
1373 		(void) add_entry(tid, resp_buf);
1374 	    } else {
1375 		isnslog(LOG_DEBUG, "door_server",
1376 		    "free the previouly returned buffer %x on this thread\n",
1377 		    thr->doc);
1378 		xmlFree(thr->doc);
1379 		isnslog(LOG_DEBUG, "door_server",
1380 		    "store the currently allocated buffer %x on this thread\n",
1381 		    resp_buf);
1382 		thr->doc = resp_buf;
1383 	    }
1384 	    isnslog(LOG_DEBUG,
1385 		"door_server", "exiting with response:\n %s\n",
1386 		    (const char *)resp_buf);
1387 
1388 	    if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) {
1389 		ISNS_MGMT_REQUEST_RESPONDED();
1390 	    }
1391 
1392 	    (void) door_return((char *)resp_buf, size + 1,  NULL, 0);
1393 		/* Not reached */
1394 	}
1395 
1396 	isnslog(LOG_DEBUG,
1397 	    "door_server", "exiting only with error code %d\n", ret);
1398 
1399 	if (ISNS_MGMT_REQUEST_RESPONDED_ENABLED()) {
1400 	    ISNS_MGMT_REQUEST_RESPONDED();
1401 	}
1402 
1403 	(void) door_return((void *)&ret, sizeof (ret),  NULL, 0);
1404 
1405 }
1406 
1407 /*
1408  * setup_mgmt_door -- Create a door portal for management application requests
1409  *
1410  * First check to see if another daemon is already running by attempting
1411  * to send an empty request to the door. If successful it means this
1412  * daemon should exit.
1413  */
1414 int
1415 setup_mgmt_door(msg_queue_t *sys_q)
1416 {
1417 	int fd, door_id;
1418 	struct stat buf;
1419 	door_arg_t darg;
1420 
1421 	isnslog(LOG_DEBUG, "setup_mgmt_door", "entered");
1422 	/* check if a door is already running. */
1423 	if ((fd = open(ISNS_DOOR_NAME, 0)) >= 0) {
1424 		darg.data_ptr = "<?xml version='1.0' encoding='UTF-8'?>"
1425 				"<isnsRequest><get><isnsObject>"
1426 				"<DiscoveryDomain name=\"default\">"
1427 				"</DiscoveryDomain></isnsObject></get>"
1428 				"</isnsRequest>";
1429 		darg.data_size = xmlStrlen((xmlChar *)darg.data_ptr) + 1;
1430 		darg.desc_ptr = NULL;
1431 		darg.desc_num = 0;
1432 		darg.rbuf = NULL;
1433 		darg.rsize = 0;
1434 
1435 		if (door_call(fd, &darg) == 0) {
1436 			/* door already running. */
1437 			(void) close(fd);
1438 			isnslog(LOG_DEBUG, "setup_mgmt_door",
1439 			    "management door is already runninng.");
1440 			if (darg.rsize > darg.data_size) {
1441 			    (void) munmap(darg.rbuf, darg.rsize);
1442 			}
1443 			door_created = B_FALSE;
1444 			return (0);
1445 		}
1446 		(void) close(fd);
1447 	}
1448 
1449 	if ((door_id = door_create(door_server, (void *)sys_q, 0)) < 0) {
1450 		isnslog(LOG_DEBUG, "setup_mgmt_door",
1451 			"Failed to create managment door");
1452 		exit(1);
1453 	}
1454 
1455 	if (stat(ISNS_DOOR_NAME, &buf) < 0) {
1456 	    if ((fd = creat(ISNS_DOOR_NAME, 0666)) < 0) {
1457 		isnslog(LOG_DEBUG, "setup_mgmt_door",
1458 		    "open failed on %s errno = %d", ISNS_DOOR_NAME, errno);
1459 		exit(1);
1460 	    }
1461 	    (void) close(fd);
1462 	}
1463 
1464 	/* make sure the file permission set to general access. */
1465 	(void) chmod(ISNS_DOOR_NAME, 0666);
1466 	(void) fdetach(ISNS_DOOR_NAME);
1467 
1468 	if (fattach(door_id, ISNS_DOOR_NAME) < 0) {
1469 		syslog(LOG_DEBUG, "setup_mgmt_door",
1470 		    "fattach failed on %s errno=%d",
1471 		    ISNS_DOOR_NAME, errno);
1472 		return (-1);
1473 	}
1474 
1475 	door_created = B_TRUE;
1476 
1477 	return (0);
1478 }
1479