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