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