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