xref: /onnv-gate/usr/src/cmd/cmd-crypto/kmfcfg/util.c (revision 3089:8ddeb2ace8aa)
1*3089Swyllys /*
2*3089Swyllys  * CDDL HEADER START
3*3089Swyllys  *
4*3089Swyllys  * The contents of this file are subject to the terms of the
5*3089Swyllys  * Common Development and Distribution License (the "License").
6*3089Swyllys  * You may not use this file except in compliance with the License.
7*3089Swyllys  *
8*3089Swyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3089Swyllys  * or http://www.opensolaris.org/os/licensing.
10*3089Swyllys  * See the License for the specific language governing permissions
11*3089Swyllys  * and limitations under the License.
12*3089Swyllys  *
13*3089Swyllys  * When distributing Covered Code, include this CDDL HEADER in each
14*3089Swyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3089Swyllys  * If applicable, add the following below this CDDL HEADER, with the
16*3089Swyllys  * fields enclosed by brackets "[]" replaced with your own identifying
17*3089Swyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3089Swyllys  *
19*3089Swyllys  * CDDL HEADER END
20*3089Swyllys  *
21*3089Swyllys  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
22*3089Swyllys  * Use is subject to license terms.
23*3089Swyllys  */
24*3089Swyllys 
25*3089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
26*3089Swyllys 
27*3089Swyllys #include <stdio.h>
28*3089Swyllys #include <strings.h>
29*3089Swyllys #include <ctype.h>
30*3089Swyllys #include <libgen.h>
31*3089Swyllys #include <libintl.h>
32*3089Swyllys 
33*3089Swyllys #include <libxml/tree.h>
34*3089Swyllys #include <libxml/parser.h>
35*3089Swyllys 
36*3089Swyllys #include <kmfapiP.h>
37*3089Swyllys 
38*3089Swyllys #include "util.h"
39*3089Swyllys 
40*3089Swyllys /* Supporting structures and global variables for getopt_av(). */
41*3089Swyllys typedef struct	av_opts_s {
42*3089Swyllys 	int		shortnm;	/* short name character */
43*3089Swyllys 	char		*longnm;	/* long name string, NOT terminated */
44*3089Swyllys 	int		longnm_len;	/* length of long name string */
45*3089Swyllys 	boolean_t	has_arg;	/* takes optional argument */
46*3089Swyllys } av_opts;
47*3089Swyllys 
48*3089Swyllys static av_opts		*opts_av = NULL;
49*3089Swyllys static const char	*_save_optstr = NULL;
50*3089Swyllys static int		_save_numopts = 0;
51*3089Swyllys int			optind_av = 1;
52*3089Swyllys char			*optarg_av = NULL;
53*3089Swyllys 
54*3089Swyllys void
55*3089Swyllys free_policy_list(POLICY_LIST *plist)
56*3089Swyllys {
57*3089Swyllys 	POLICY_LIST *n = plist, *old;
58*3089Swyllys 
59*3089Swyllys 	if (plist == NULL)
60*3089Swyllys 		return;
61*3089Swyllys 
62*3089Swyllys 	while (n != NULL) {
63*3089Swyllys 		old = n;
64*3089Swyllys 		KMF_FreePolicyRecord(&n->plc);
65*3089Swyllys 		n = n->next;
66*3089Swyllys 		free(old);
67*3089Swyllys 	}
68*3089Swyllys 	plist = NULL;
69*3089Swyllys }
70*3089Swyllys 
71*3089Swyllys int
72*3089Swyllys load_policies(char *file, POLICY_LIST **policy_list)
73*3089Swyllys {
74*3089Swyllys 	int rv = KC_OK;
75*3089Swyllys 	KMF_RETURN kmfrv = KMF_OK;
76*3089Swyllys 	POLICY_LIST *newitem, *plist = NULL;
77*3089Swyllys 	xmlParserCtxtPtr ctxt;
78*3089Swyllys 	xmlDocPtr doc = NULL;
79*3089Swyllys 	xmlNodePtr cur, node;
80*3089Swyllys 
81*3089Swyllys 	/* Create a parser context */
82*3089Swyllys 	ctxt = xmlNewParserCtxt();
83*3089Swyllys 	if (ctxt == NULL)
84*3089Swyllys 		return (KMF_ERR_POLICY_DB_FORMAT);
85*3089Swyllys 
86*3089Swyllys 	/* Read the policy DB and verify it against the schema. */
87*3089Swyllys 	doc = xmlCtxtReadFile(ctxt, file, NULL,
88*3089Swyllys 	    XML_PARSE_DTDVALID | XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
89*3089Swyllys 	if (doc == NULL || ctxt->valid == 0) {
90*3089Swyllys 		kmfrv = KMF_ERR_POLICY_DB_FORMAT;
91*3089Swyllys 		goto end;
92*3089Swyllys 	}
93*3089Swyllys 
94*3089Swyllys 	cur = xmlDocGetRootElement(doc);
95*3089Swyllys 	if (cur == NULL) {
96*3089Swyllys 		kmfrv = KMF_ERR_POLICY_DB_FORMAT;
97*3089Swyllys 		goto end;
98*3089Swyllys 	}
99*3089Swyllys 
100*3089Swyllys 	node = cur->xmlChildrenNode;
101*3089Swyllys 	while (node != NULL) {
102*3089Swyllys 		char *c;
103*3089Swyllys 		/*
104*3089Swyllys 		 * Search for the policy that matches the given name.
105*3089Swyllys 		 */
106*3089Swyllys 		if (!xmlStrcmp((const xmlChar *)node->name,
107*3089Swyllys 			(const xmlChar *)KMF_POLICY_ELEMENT)) {
108*3089Swyllys 			/* Check the name attribute */
109*3089Swyllys 			c = (char *)xmlGetProp(node,
110*3089Swyllys 				(const xmlChar *)KMF_POLICY_NAME_ATTR);
111*3089Swyllys 
112*3089Swyllys 			/* If a match, parse the rest of the data */
113*3089Swyllys 			if (c != NULL) {
114*3089Swyllys 				xmlFree(c);
115*3089Swyllys 				newitem = malloc(sizeof (POLICY_LIST));
116*3089Swyllys 				if (newitem != NULL) {
117*3089Swyllys 					(void) memset(newitem, 0,
118*3089Swyllys 						sizeof (POLICY_LIST));
119*3089Swyllys 					kmfrv = parsePolicyElement(node,
120*3089Swyllys 						&newitem->plc);
121*3089Swyllys 				} else {
122*3089Swyllys 					kmfrv = KMF_ERR_MEMORY;
123*3089Swyllys 					goto end;
124*3089Swyllys 				}
125*3089Swyllys 				/* add to linked list */
126*3089Swyllys 				if (plist == NULL) {
127*3089Swyllys 					plist = newitem;
128*3089Swyllys 				} else {
129*3089Swyllys 					POLICY_LIST *n = plist;
130*3089Swyllys 					while (n->next != NULL)
131*3089Swyllys 						n = n->next;
132*3089Swyllys 
133*3089Swyllys 					n->next = newitem;
134*3089Swyllys 					newitem->next = NULL;
135*3089Swyllys 				}
136*3089Swyllys 			}
137*3089Swyllys 		}
138*3089Swyllys 		node = node->next;
139*3089Swyllys 	}
140*3089Swyllys 
141*3089Swyllys end:
142*3089Swyllys 	if (ctxt != NULL)
143*3089Swyllys 		xmlFreeParserCtxt(ctxt);
144*3089Swyllys 
145*3089Swyllys 	if (doc != NULL)
146*3089Swyllys 		xmlFreeDoc(doc);
147*3089Swyllys 
148*3089Swyllys 	if (kmfrv != KMF_OK) {
149*3089Swyllys 		free_policy_list(plist);
150*3089Swyllys 		rv = KC_ERR_LOADDB;
151*3089Swyllys 	} else {
152*3089Swyllys 		*policy_list = plist;
153*3089Swyllys 	}
154*3089Swyllys 
155*3089Swyllys 	return (rv);
156*3089Swyllys }
157*3089Swyllys 
158*3089Swyllys /*
159*3089Swyllys  * Return 0 if there is any error in the input string.
160*3089Swyllys  */
161*3089Swyllys uint16_t
162*3089Swyllys parseKUlist(char *kustring)
163*3089Swyllys {
164*3089Swyllys 	uint16_t cur_bit;
165*3089Swyllys 	uint16_t kubits = 0;
166*3089Swyllys 	char *p;
167*3089Swyllys 
168*3089Swyllys 	p = strtok(kustring, ",");
169*3089Swyllys 	while (p != NULL) {
170*3089Swyllys 		cur_bit = KMF_StringToKeyUsage(p);
171*3089Swyllys 		if (cur_bit == 0) {
172*3089Swyllys 			kubits = 0;
173*3089Swyllys 			break;
174*3089Swyllys 		}
175*3089Swyllys 		kubits |= cur_bit;
176*3089Swyllys 		p = strtok(NULL, ",");
177*3089Swyllys 	}
178*3089Swyllys 
179*3089Swyllys 	return (kubits);
180*3089Swyllys }
181*3089Swyllys 
182*3089Swyllys static void
183*3089Swyllys addToEKUList(KMF_EKU_POLICY *ekus, KMF_OID *newoid)
184*3089Swyllys {
185*3089Swyllys 	if (newoid != NULL && ekus != NULL) {
186*3089Swyllys 		ekus->eku_count++;
187*3089Swyllys 		ekus->ekulist = realloc(
188*3089Swyllys 			ekus->ekulist,
189*3089Swyllys 			ekus->eku_count * sizeof (KMF_OID));
190*3089Swyllys 		if (ekus->ekulist != NULL) {
191*3089Swyllys 			ekus->ekulist[ekus->eku_count-1] = *newoid;
192*3089Swyllys 		}
193*3089Swyllys 	}
194*3089Swyllys }
195*3089Swyllys 
196*3089Swyllys int
197*3089Swyllys parseEKUNames(char *ekulist, KMF_POLICY_RECORD *plc)
198*3089Swyllys {
199*3089Swyllys 	int rv = KC_OK;
200*3089Swyllys 	char *p;
201*3089Swyllys 	KMF_OID *newoid;
202*3089Swyllys 	KMF_EKU_POLICY *ekus = &plc->eku_set;
203*3089Swyllys 
204*3089Swyllys 	if (ekulist == NULL || !strlen(ekulist))
205*3089Swyllys 		return (0);
206*3089Swyllys 
207*3089Swyllys 	/*
208*3089Swyllys 	 * The list should be comma separated list of EKU Names.
209*3089Swyllys 	 */
210*3089Swyllys 	p = strtok(ekulist, ",");
211*3089Swyllys 
212*3089Swyllys 	/* If no tokens found, then maybe its just a single EKU value */
213*3089Swyllys 	if (p == NULL) {
214*3089Swyllys 		newoid = kmf_ekuname2oid(ekulist);
215*3089Swyllys 		if (newoid != NULL) {
216*3089Swyllys 			addToEKUList(ekus, newoid);
217*3089Swyllys 			free(newoid);
218*3089Swyllys 		} else {
219*3089Swyllys 			rv = KC_ERR_USAGE;
220*3089Swyllys 		}
221*3089Swyllys 	}
222*3089Swyllys 
223*3089Swyllys 	while (p != NULL) {
224*3089Swyllys 		newoid = kmf_ekuname2oid(p);
225*3089Swyllys 		if (newoid != NULL) {
226*3089Swyllys 			addToEKUList(ekus, newoid);
227*3089Swyllys 			free(newoid);
228*3089Swyllys 		} else {
229*3089Swyllys 			rv = KC_ERR_USAGE;
230*3089Swyllys 			break;
231*3089Swyllys 		}
232*3089Swyllys 		p = strtok(NULL, ",");
233*3089Swyllys 	}
234*3089Swyllys 
235*3089Swyllys 	if (rv != KC_OK)
236*3089Swyllys 		KMF_FreeEKUPolicy(ekus);
237*3089Swyllys 
238*3089Swyllys 	return (rv);
239*3089Swyllys }
240*3089Swyllys 
241*3089Swyllys int
242*3089Swyllys parseEKUOIDs(char *ekulist, KMF_POLICY_RECORD *plc)
243*3089Swyllys {
244*3089Swyllys 	int rv = KC_OK;
245*3089Swyllys 	char *p;
246*3089Swyllys 	KMF_OID *newoid;
247*3089Swyllys 	KMF_EKU_POLICY *ekus = &plc->eku_set;
248*3089Swyllys 
249*3089Swyllys 	if (ekulist == NULL || !strlen(ekulist))
250*3089Swyllys 		return (0);
251*3089Swyllys 
252*3089Swyllys 	/*
253*3089Swyllys 	 * The list should be comma separated list of EKU Names.
254*3089Swyllys 	 */
255*3089Swyllys 	p = strtok(ekulist, ",");
256*3089Swyllys 	if (p == NULL) {
257*3089Swyllys 		newoid = kmf_string2oid(ekulist);
258*3089Swyllys 		if (newoid != NULL) {
259*3089Swyllys 			addToEKUList(ekus, newoid);
260*3089Swyllys 			free(newoid);
261*3089Swyllys 		} else {
262*3089Swyllys 			rv = KC_ERR_USAGE;
263*3089Swyllys 		}
264*3089Swyllys 	}
265*3089Swyllys 
266*3089Swyllys 	while (p != NULL && rv == 0) {
267*3089Swyllys 		newoid = kmf_string2oid(p);
268*3089Swyllys 		if (newoid != NULL) {
269*3089Swyllys 			addToEKUList(ekus, newoid);
270*3089Swyllys 			free(newoid);
271*3089Swyllys 		} else {
272*3089Swyllys 			rv = KC_ERR_USAGE;
273*3089Swyllys 			break;
274*3089Swyllys 		}
275*3089Swyllys 		p = strtok(NULL, ",");
276*3089Swyllys 	}
277*3089Swyllys 
278*3089Swyllys 	if (rv != KC_OK)
279*3089Swyllys 		KMF_FreeEKUPolicy(ekus);
280*3089Swyllys 
281*3089Swyllys 	return (rv);
282*3089Swyllys }
283*3089Swyllys 
284*3089Swyllys int
285*3089Swyllys get_boolean(char *arg)
286*3089Swyllys {
287*3089Swyllys 	if (arg == NULL)
288*3089Swyllys 		return (-1);
289*3089Swyllys 	if (strcasecmp(arg, "true") == 0)
290*3089Swyllys 		return (1);
291*3089Swyllys 	if (strcasecmp(arg, "false") == 0)
292*3089Swyllys 		return (0);
293*3089Swyllys 	return (-1);
294*3089Swyllys }
295*3089Swyllys 
296*3089Swyllys /*
297*3089Swyllys  * This function processes the input string.  It removes the beginning
298*3089Swyllys  * and ending blank's first, makes a copy of the resulting string and
299*3089Swyllys  * return it.
300*3089Swyllys  *
301*3089Swyllys  * This function returns NULL, if there is an error in the
302*3089Swyllys  * input string or when the system is out of memory.  The output
303*3089Swyllys  * "err_flag" argument will record the error code, if it is not NULL.
304*3089Swyllys  */
305*3089Swyllys char *
306*3089Swyllys get_string(char *str, int *err_flag)
307*3089Swyllys {
308*3089Swyllys 	char *p;
309*3089Swyllys 	int len, i;
310*3089Swyllys 	char *retstr = NULL;
311*3089Swyllys 
312*3089Swyllys 	if (str == NULL) {
313*3089Swyllys 		if (err_flag != NULL)
314*3089Swyllys 			*err_flag = KC_ERR_USAGE;
315*3089Swyllys 		return (NULL);
316*3089Swyllys 	}
317*3089Swyllys 
318*3089Swyllys 	/* Remove beginning whitespace */
319*3089Swyllys 	p = str;
320*3089Swyllys 	while (p != NULL && isspace(*p))
321*3089Swyllys 		p++;
322*3089Swyllys 
323*3089Swyllys 	if (p == NULL) {
324*3089Swyllys 		if (err_flag != NULL)
325*3089Swyllys 			*err_flag = KC_ERR_USAGE;
326*3089Swyllys 		return (NULL);
327*3089Swyllys 	}
328*3089Swyllys 
329*3089Swyllys 	/* Remove the trailing blanks */
330*3089Swyllys 	len = strlen(p);
331*3089Swyllys 	while (len > 0 && isspace(p[len-1]))
332*3089Swyllys 		len--;
333*3089Swyllys 
334*3089Swyllys 	if (len == 0) {
335*3089Swyllys 		if (err_flag != NULL)
336*3089Swyllys 			*err_flag = KC_ERR_USAGE;
337*3089Swyllys 		return (NULL);
338*3089Swyllys 	}
339*3089Swyllys 
340*3089Swyllys 	/* Check if there is any non-printable character */
341*3089Swyllys 	i = 0;
342*3089Swyllys 	while (i < len) {
343*3089Swyllys 		if (isprint(p[i]))
344*3089Swyllys 			i++;
345*3089Swyllys 		else {
346*3089Swyllys 			if (err_flag != NULL)
347*3089Swyllys 				*err_flag = KC_ERR_USAGE;
348*3089Swyllys 			return (NULL);
349*3089Swyllys 		}
350*3089Swyllys 	}
351*3089Swyllys 
352*3089Swyllys 	/* Make a copy of the string and return it */
353*3089Swyllys 	retstr = malloc(len + 1);
354*3089Swyllys 	if (retstr == NULL) {
355*3089Swyllys 		if (err_flag != NULL)
356*3089Swyllys 			*err_flag = KC_ERR_MEMORY;
357*3089Swyllys 		return (NULL);
358*3089Swyllys 	}
359*3089Swyllys 
360*3089Swyllys 	if (err_flag != NULL)
361*3089Swyllys 		*err_flag = KC_OK;
362*3089Swyllys 
363*3089Swyllys 	(void) strncpy(retstr, p, len);
364*3089Swyllys 	retstr[len] = '\0';
365*3089Swyllys 	return (retstr);
366*3089Swyllys }
367*3089Swyllys 
368*3089Swyllys /*
369*3089Swyllys  * Breaks out the getopt-style option string into a structure that can be
370*3089Swyllys  * traversed later for calls to getopt_av().  Option string is NOT altered,
371*3089Swyllys  * but the struct fields point to locations within option string.
372*3089Swyllys  */
373*3089Swyllys static int
374*3089Swyllys populate_opts(char *optstring)
375*3089Swyllys {
376*3089Swyllys 	int		i;
377*3089Swyllys 	av_opts		*temp;
378*3089Swyllys 	char		*marker;
379*3089Swyllys 
380*3089Swyllys 	if (optstring == NULL || *optstring == '\0')
381*3089Swyllys 		return (0);
382*3089Swyllys 
383*3089Swyllys 	/*
384*3089Swyllys 	 * This tries to imitate getopt(3c) Each option must conform to:
385*3089Swyllys 	 * <short name char> [ ':' ] [ '(' <long name string> ')' ]
386*3089Swyllys 	 * If long name is missing, the short name is used for long name.
387*3089Swyllys 	 */
388*3089Swyllys 	for (i = 0; *optstring != '\0'; i++) {
389*3089Swyllys 		if ((temp = (av_opts *)((i == 0) ? malloc(sizeof (av_opts)) :
390*3089Swyllys 		    realloc(opts_av, (i+1) * sizeof (av_opts)))) == NULL) {
391*3089Swyllys 			free(opts_av);
392*3089Swyllys 			opts_av = NULL;
393*3089Swyllys 			return (0);
394*3089Swyllys 		} else
395*3089Swyllys 			opts_av = (av_opts *)temp;
396*3089Swyllys 
397*3089Swyllys 		marker = optstring;		/* may need optstring later */
398*3089Swyllys 
399*3089Swyllys 		opts_av[i].shortnm = *marker++;	/* set short name */
400*3089Swyllys 
401*3089Swyllys 		if (*marker == ':') {		/* check for opt arg */
402*3089Swyllys 			marker++;
403*3089Swyllys 			opts_av[i].has_arg = B_TRUE;
404*3089Swyllys 		}
405*3089Swyllys 
406*3089Swyllys 		if (*marker == '(') {		/* check and set long name */
407*3089Swyllys 			marker++;
408*3089Swyllys 			opts_av[i].longnm = marker;
409*3089Swyllys 			opts_av[i].longnm_len = strcspn(marker, ")");
410*3089Swyllys 			optstring = marker + opts_av[i].longnm_len + 1;
411*3089Swyllys 		} else {
412*3089Swyllys 			/* use short name option character */
413*3089Swyllys 			opts_av[i].longnm = optstring;
414*3089Swyllys 			opts_av[i].longnm_len = 1;
415*3089Swyllys 			optstring = marker;
416*3089Swyllys 		}
417*3089Swyllys 	}
418*3089Swyllys 
419*3089Swyllys 	return (i);
420*3089Swyllys }
421*3089Swyllys 
422*3089Swyllys /*
423*3089Swyllys  * getopt_av() is very similar to getopt(3c) in that the takes an option
424*3089Swyllys  * string, compares command line arguments for matches, and returns a single
425*3089Swyllys  * letter option when a match is found.  However, getopt_av() differs from
426*3089Swyllys  * getopt(3c) by allowing both longname options and values be found
427*3089Swyllys  * on the command line.
428*3089Swyllys  */
429*3089Swyllys int
430*3089Swyllys getopt_av(int argc, char * const *argv, const char *optstring)
431*3089Swyllys {
432*3089Swyllys 	int	i;
433*3089Swyllys 	int	len;
434*3089Swyllys 
435*3089Swyllys 	if (optind_av >= argc)
436*3089Swyllys 		return (EOF);
437*3089Swyllys 
438*3089Swyllys 	/* First time or when optstring changes from previous one */
439*3089Swyllys 	if (_save_optstr != optstring) {
440*3089Swyllys 		if (opts_av != NULL)
441*3089Swyllys 		    free(opts_av);
442*3089Swyllys 		opts_av = NULL;
443*3089Swyllys 		_save_optstr = optstring;
444*3089Swyllys 		_save_numopts = populate_opts((char *)optstring);
445*3089Swyllys 	}
446*3089Swyllys 
447*3089Swyllys 	for (i = 0; i < _save_numopts; i++) {
448*3089Swyllys 		if (strcmp(argv[optind_av], "--") == 0) {
449*3089Swyllys 			optind_av++;
450*3089Swyllys 			break;
451*3089Swyllys 		}
452*3089Swyllys 
453*3089Swyllys 		len = strcspn(argv[optind_av], "=");
454*3089Swyllys 
455*3089Swyllys 		if (len == opts_av[i].longnm_len && strncmp(argv[optind_av],
456*3089Swyllys 		    opts_av[i].longnm, opts_av[i].longnm_len) == 0) {
457*3089Swyllys 			/* matched */
458*3089Swyllys 			if (!opts_av[i].has_arg) {
459*3089Swyllys 				optind_av++;
460*3089Swyllys 				return (opts_av[i].shortnm);
461*3089Swyllys 			}
462*3089Swyllys 
463*3089Swyllys 			/* needs optarg */
464*3089Swyllys 			if (argv[optind_av][len] == '=') {
465*3089Swyllys 				optarg_av = &(argv[optind_av][len+1]);
466*3089Swyllys 				optind_av++;
467*3089Swyllys 				return (opts_av[i].shortnm);
468*3089Swyllys 			}
469*3089Swyllys 
470*3089Swyllys 			optarg_av = NULL;
471*3089Swyllys 			optind_av++;
472*3089Swyllys 			return ((int)'?');
473*3089Swyllys 		}
474*3089Swyllys 	}
475*3089Swyllys 
476*3089Swyllys 	return (EOF);
477*3089Swyllys }
478*3089Swyllys 
479*3089Swyllys void
480*3089Swyllys print_sanity_error(KMF_RETURN ret)
481*3089Swyllys {
482*3089Swyllys 	switch (ret) {
483*3089Swyllys 	case KMF_ERR_POLICY_NAME:
484*3089Swyllys 		(void) fprintf(stderr, gettext("Error in the policy name\n"));
485*3089Swyllys 		break;
486*3089Swyllys 	case KMF_ERR_TA_POLICY:
487*3089Swyllys 		(void) fprintf(stderr,
488*3089Swyllys 		    gettext("Error in trust anchor attributes\n"));
489*3089Swyllys 		break;
490*3089Swyllys 	case KMF_ERR_OCSP_POLICY:
491*3089Swyllys 		(void) fprintf(stderr,
492*3089Swyllys 		    gettext("Error in OCSP policy attributes\n"));
493*3089Swyllys 		break;
494*3089Swyllys 	default:
495*3089Swyllys 		break;
496*3089Swyllys 	}
497*3089Swyllys }
498