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