xref: /onnv-gate/usr/src/lib/libslp/clib/SLPUtils.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Public utilities and convenience calls (from the API spec):
31*0Sstevel@tonic-gate  *	SLPFindScopes (queries for all known scopes)
32*0Sstevel@tonic-gate  *	SLPEscape / Unescape
33*0Sstevel@tonic-gate  *	SLPFree
34*0Sstevel@tonic-gate  *	SLPSet/GetProperty
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate #include <stdlib.h>
39*0Sstevel@tonic-gate #include <string.h>
40*0Sstevel@tonic-gate #include <syslog.h>
41*0Sstevel@tonic-gate #include <netdb.h>
42*0Sstevel@tonic-gate #include <unistd.h>
43*0Sstevel@tonic-gate #include <libintl.h>
44*0Sstevel@tonic-gate #include <slp-internal.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate struct scopes_tree {
47*0Sstevel@tonic-gate 	void *scopes;
48*0Sstevel@tonic-gate 	int len;
49*0Sstevel@tonic-gate };
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate typedef SLPBoolean SLPScopeCallback(SLPHandle, const char *, SLPError, void *);
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static SLPSrvURLCallback collate_scopes;
54*0Sstevel@tonic-gate static void collect_scopes(void *, VISIT, int, void *);
55*0Sstevel@tonic-gate static SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *, char *,
56*0Sstevel@tonic-gate 					SLPScopeCallback, void *,
57*0Sstevel@tonic-gate 					void **, int *);
58*0Sstevel@tonic-gate static SLPError SAAdvert_for_scopes(SLPHandle, void **);
59*0Sstevel@tonic-gate static SLPError slp_unescape(const char *, char **, SLPBoolean, const char);
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * Finds scopes according the the user administrative model.
63*0Sstevel@tonic-gate  */
SLPFindScopes(SLPHandle hSLP,char ** ppcScopes)64*0Sstevel@tonic-gate SLPError SLPFindScopes(SLPHandle hSLP, char **ppcScopes) {
65*0Sstevel@tonic-gate 	SLPError err;
66*0Sstevel@tonic-gate 	char *reply, *unesc_reply;
67*0Sstevel@tonic-gate 	void *stree = NULL;
68*0Sstevel@tonic-gate 	void *collator = NULL;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	if (!hSLP || !ppcScopes) {
71*0Sstevel@tonic-gate 		return (SLP_PARAMETER_BAD);
72*0Sstevel@tonic-gate 	}
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	/* first try administratively configured scopes */
75*0Sstevel@tonic-gate 	if ((err = slp_administrative_scopes(ppcScopes, SLP_FALSE))
76*0Sstevel@tonic-gate 	    != SLP_OK) {
77*0Sstevel@tonic-gate 		return (err);
78*0Sstevel@tonic-gate 	}
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate 	if (*ppcScopes) {
81*0Sstevel@tonic-gate 	    /* got scopes */
82*0Sstevel@tonic-gate 	    return (SLP_OK);
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/* DAs from active and passive discovery */
86*0Sstevel@tonic-gate 	if ((err = slp_find_das("", &reply)) != SLP_OK &&
87*0Sstevel@tonic-gate 	    err != SLP_NETWORK_ERROR)
88*0Sstevel@tonic-gate 		return (err);
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	/* Unpack the reply */
91*0Sstevel@tonic-gate 	if (reply) {
92*0Sstevel@tonic-gate 		int numResults = 0;	/* placeholder; not actually used */
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 		/* tag call as internal */
95*0Sstevel@tonic-gate 		((slp_handle_impl_t *)hSLP)->internal_call = SLP_TRUE;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 		(void) slp_unpackSrvReply(
98*0Sstevel@tonic-gate 			hSLP, reply, collate_scopes,
99*0Sstevel@tonic-gate 			&stree, &collator, &numResults);
100*0Sstevel@tonic-gate 		/* invoke last call */
101*0Sstevel@tonic-gate 		(void) slp_unpackSrvReply(
102*0Sstevel@tonic-gate 			hSLP, NULL, collate_scopes,
103*0Sstevel@tonic-gate 			&stree, &collator, &numResults);
104*0Sstevel@tonic-gate 		free(reply);
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 		/* revert internal call tag */
107*0Sstevel@tonic-gate 		((slp_handle_impl_t *)hSLP)->internal_call = SLP_FALSE;
108*0Sstevel@tonic-gate 	}
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	/* Finally, if no results yet, try SA discovery */
111*0Sstevel@tonic-gate 	if (!stree) {
112*0Sstevel@tonic-gate 	    (void) SAAdvert_for_scopes(hSLP, &stree);
113*0Sstevel@tonic-gate 	}
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 	if (!stree) {
116*0Sstevel@tonic-gate 		/* found none, so just return "default" */
117*0Sstevel@tonic-gate 		if (!(*ppcScopes = strdup("default"))) {
118*0Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
119*0Sstevel@tonic-gate 			return (SLP_MEMORY_ALLOC_FAILED);
120*0Sstevel@tonic-gate 		}
121*0Sstevel@tonic-gate 		return (SLP_OK);
122*0Sstevel@tonic-gate 	}
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate 	/* we now have a btree, each leaf of which is a unique scope */
125*0Sstevel@tonic-gate 	slp_twalk(stree, collect_scopes, 0, (void *) ppcScopes);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	/* unescape scopes list */
128*0Sstevel@tonic-gate 	if ((err = slp_unescape(*ppcScopes, &unesc_reply, SLP_FALSE, '%'))
129*0Sstevel@tonic-gate 	    == SLP_OK) {
130*0Sstevel@tonic-gate 		free(*ppcScopes);
131*0Sstevel@tonic-gate 		*ppcScopes = unesc_reply;
132*0Sstevel@tonic-gate 	} else {
133*0Sstevel@tonic-gate 		free(unesc_reply);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	return (err);
137*0Sstevel@tonic-gate }
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate /*
140*0Sstevel@tonic-gate  * Finds scopes according to the adminstrative scoping model. A
141*0Sstevel@tonic-gate  * comma-seperated list of scopes is returned in *ppcScopes; the
142*0Sstevel@tonic-gate  * caller must free *ppcScopes.
143*0Sstevel@tonic-gate  * If the return_default parameter is true, and no scopes are found,
144*0Sstevel@tonic-gate  * *ppcScopes will be set to 'default', otherwise, *ppcScopes will
145*0Sstevel@tonic-gate  * be NULL. This helps simplify internal memory management.
146*0Sstevel@tonic-gate  */
slp_administrative_scopes(char ** ppcScopes,SLPBoolean return_default)147*0Sstevel@tonic-gate SLPError slp_administrative_scopes(char **ppcScopes,
148*0Sstevel@tonic-gate 					SLPBoolean return_default) {
149*0Sstevel@tonic-gate 	const char *useScopes;
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate 	*ppcScopes = NULL;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	/* @@@ first try DHCP */
154*0Sstevel@tonic-gate 	/* next try the useScopes property */
155*0Sstevel@tonic-gate 	useScopes = SLPGetProperty(SLP_CONFIG_USESCOPES);
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	if (useScopes && *useScopes) {
158*0Sstevel@tonic-gate 		if (!(*ppcScopes = strdup(useScopes))) {
159*0Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
160*0Sstevel@tonic-gate 			return (SLP_MEMORY_ALLOC_FAILED);
161*0Sstevel@tonic-gate 		}
162*0Sstevel@tonic-gate 		return (SLP_OK);
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 	/* found none, so just return "default" */
166*0Sstevel@tonic-gate 	if (return_default && !(*ppcScopes = strdup("default"))) {
167*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPFindScopes", "out of memory");
168*0Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
169*0Sstevel@tonic-gate 	}
170*0Sstevel@tonic-gate 	return (SLP_OK);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate /*
174*0Sstevel@tonic-gate  * This function operates on the same btree as the collate_scopes().
175*0Sstevel@tonic-gate  * The difference is that this one is called for each
176*0Sstevel@tonic-gate  * SAAdvert recieved.
177*0Sstevel@tonic-gate  */
178*0Sstevel@tonic-gate /* ARGSUSED */
saadvert_callback(SLPHandle hp,char * scopes,SLPError err,void ** stree)179*0Sstevel@tonic-gate static SLPBoolean saadvert_callback(SLPHandle hp, char *scopes,
180*0Sstevel@tonic-gate 					SLPError err, void **stree) {
181*0Sstevel@tonic-gate 	char *s, *tstate;
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	if (err != SLP_OK) {
184*0Sstevel@tonic-gate 		return (SLP_TRUE);
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	for (
188*0Sstevel@tonic-gate 		s = strtok_r((char *)scopes, ",", &tstate);
189*0Sstevel@tonic-gate 		s;
190*0Sstevel@tonic-gate 		s = strtok_r(NULL, ",", &tstate)) {
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 		char *ascope, **srch;
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 		if (!(ascope = strdup(s))) {	/* no memory! */
195*0Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "collate_scopes",
196*0Sstevel@tonic-gate 				"out of memory");
197*0Sstevel@tonic-gate 			return (SLP_TRUE);
198*0Sstevel@tonic-gate 		}
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 		srch = slp_tsearch(
201*0Sstevel@tonic-gate 			(void *) ascope, stree,
202*0Sstevel@tonic-gate 			(int (*)(const void *, const void *)) slp_strcasecmp);
203*0Sstevel@tonic-gate 		if (*srch != ascope)
204*0Sstevel@tonic-gate 			/* scope is already in there, so just free ascope */
205*0Sstevel@tonic-gate 			free(ascope);
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	return (SLP_TRUE);
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate /*
212*0Sstevel@tonic-gate  * Generates an SAAdvert solicitation, and returns any scopes found
213*0Sstevel@tonic-gate  * from all recieved SAAdverts in stree. stree must be a btree
214*0Sstevel@tonic-gate  * structure.
215*0Sstevel@tonic-gate  */
SAAdvert_for_scopes(SLPHandle hSLP,void ** stree)216*0Sstevel@tonic-gate static SLPError SAAdvert_for_scopes(SLPHandle hSLP, void **stree) {
217*0Sstevel@tonic-gate 	SLPError err;
218*0Sstevel@tonic-gate 	SLPBoolean sync_state;
219*0Sstevel@tonic-gate 	slp_handle_impl_t *hp = (slp_handle_impl_t *)hSLP;
220*0Sstevel@tonic-gate 	char *predicate;
221*0Sstevel@tonic-gate 	const char *type_hint;
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate 	/* get type hint, if set */
224*0Sstevel@tonic-gate 	if ((type_hint = SLPGetProperty(SLP_CONFIG_TYPEHINT)) != NULL &&
225*0Sstevel@tonic-gate 		*type_hint != 0) {
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 		size_t hintlen = strlen(type_hint);
228*0Sstevel@tonic-gate 		size_t predlen = strlen("(service-type=)");
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 		/* check bounds */
231*0Sstevel@tonic-gate 		if (hintlen > (SLP_MAX_STRINGLEN - predlen)) {
232*0Sstevel@tonic-gate 			return (SLP_PARAMETER_BAD);
233*0Sstevel@tonic-gate 		}
234*0Sstevel@tonic-gate 		if (!(predicate = malloc(hintlen + predlen + 1))) {
235*0Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "SAAdvert_for_scopes",
236*0Sstevel@tonic-gate 				"out of memory");
237*0Sstevel@tonic-gate 			return (SLP_MEMORY_ALLOC_FAILED);
238*0Sstevel@tonic-gate 		}
239*0Sstevel@tonic-gate 		(void) strcpy(predicate, "(service-type=");
240*0Sstevel@tonic-gate 		(void) strcat(predicate, type_hint);
241*0Sstevel@tonic-gate 		(void) strcat(predicate, ")");
242*0Sstevel@tonic-gate 	} else {
243*0Sstevel@tonic-gate 		predicate = "";
244*0Sstevel@tonic-gate 		type_hint = NULL;
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	/* No callback for SLPFindScopes, so force synchronous mode only */
248*0Sstevel@tonic-gate 	sync_state = hp->async;
249*0Sstevel@tonic-gate 	hp->async = SLP_FALSE;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	if ((err = slp_start_call(hp)) != SLP_OK)
252*0Sstevel@tonic-gate 		return (err);
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	err = slp_packSrvRqst("service:service-agent", predicate, hp);
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	if (err == SLP_OK)
257*0Sstevel@tonic-gate 		err = slp_ua_common(hSLP, "",
258*0Sstevel@tonic-gate 				    (SLPGenericAppCB *)saadvert_callback,
259*0Sstevel@tonic-gate 				    stree,
260*0Sstevel@tonic-gate 				    (SLPMsgReplyCB *)unpackSAAdvert_scope);
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	if (type_hint) {
263*0Sstevel@tonic-gate 		free(predicate);
264*0Sstevel@tonic-gate 	}
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (err != SLP_OK)
267*0Sstevel@tonic-gate 		slp_end_call(hp);
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	/* restore sync state */
270*0Sstevel@tonic-gate 	hp->async = sync_state;
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	return (err);
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate 
275*0Sstevel@tonic-gate /*
276*0Sstevel@tonic-gate  * Unpack an SAAdvert and pass each set of scopes into cb.
277*0Sstevel@tonic-gate  */
278*0Sstevel@tonic-gate /* ARGSUSED */
unpackSAAdvert_scope(slp_handle_impl_t * hSLP,char * reply,SLPScopeCallback cb,void * cookie,void ** collator,int * numResults)279*0Sstevel@tonic-gate static SLPBoolean unpackSAAdvert_scope(slp_handle_impl_t *hSLP, char *reply,
280*0Sstevel@tonic-gate 					SLPScopeCallback cb, void *cookie,
281*0Sstevel@tonic-gate 					void **collator, int *numResults) {
282*0Sstevel@tonic-gate 	char *surl, *scopes, *attrs;
283*0Sstevel@tonic-gate 	SLPBoolean cont;
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	if (!reply) {
286*0Sstevel@tonic-gate 		cb(hSLP, NULL, SLP_LAST_CALL, cookie);
287*0Sstevel@tonic-gate 		return (SLP_FALSE);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	/* tag call as internal; gets all scopes, regardless of maxResults */
291*0Sstevel@tonic-gate 	hSLP->internal_call = SLP_TRUE;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	if (slp_unpackSAAdvert(reply, &surl, &scopes, &attrs) != SLP_OK) {
294*0Sstevel@tonic-gate 		return (SLP_TRUE);
295*0Sstevel@tonic-gate 	}
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 	cont = cb(hSLP, scopes, SLP_OK, cookie);
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 	/* revert internal_call tag */
300*0Sstevel@tonic-gate 	hSLP->internal_call = SLP_FALSE;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	free(surl);
303*0Sstevel@tonic-gate 	free(scopes);
304*0Sstevel@tonic-gate 	free(attrs);
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	return (cont);
307*0Sstevel@tonic-gate }
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate /*
310*0Sstevel@tonic-gate  * Creates a service request for finding DAs or SAs (based on 'filter'),
311*0Sstevel@tonic-gate  * and sends it to slpd, returning the reply in 'reply'.
312*0Sstevel@tonic-gate  */
slp_find_das(const char * filter,char ** reply)313*0Sstevel@tonic-gate SLPError slp_find_das(const char *filter, char **reply) {
314*0Sstevel@tonic-gate 	SLPError err;
315*0Sstevel@tonic-gate 	char *msg, hostname[MAXHOSTNAMELEN];
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	/* Try the cache first */
318*0Sstevel@tonic-gate 	if (*reply = slp_find_das_cached(filter)) {
319*0Sstevel@tonic-gate 		return (SLP_OK);
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/*
323*0Sstevel@tonic-gate 	 * create a find scopes message:
324*0Sstevel@tonic-gate 	 * this is a SrvRqst for the type directory-agent.sun.
325*0Sstevel@tonic-gate 	 */
326*0Sstevel@tonic-gate 	/* use the local host's name for the scope */
327*0Sstevel@tonic-gate 	(void) gethostname(hostname, MAXHOSTNAMELEN);
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	err = slp_packSrvRqst_single(
330*0Sstevel@tonic-gate 		SLP_SUN_DA_TYPE, hostname, filter, &msg, "en");
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	if (err == SLP_OK) {
333*0Sstevel@tonic-gate 		err = slp_send2slpd(msg, reply);
334*0Sstevel@tonic-gate 		free(msg);
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	/* Add the reply to the cache */
338*0Sstevel@tonic-gate 	if (err == SLP_OK) {
339*0Sstevel@tonic-gate 		slp_put_das_cached(filter, *reply, slp_get_length(*reply));
340*0Sstevel@tonic-gate 	}
341*0Sstevel@tonic-gate 
342*0Sstevel@tonic-gate 	return (err);
343*0Sstevel@tonic-gate }
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate /*
346*0Sstevel@tonic-gate  * This is called for each URL entry in the DA service reply (sun private).
347*0Sstevel@tonic-gate  * Contained within the cookie is a btree, to which it adds new
348*0Sstevel@tonic-gate  * scopes from the URL entry. The scopes are retrieved from the btree
349*0Sstevel@tonic-gate  * by traversing the tree in SLPFindScopes().
350*0Sstevel@tonic-gate  * SLPHandle h is NULL, so don't touch it!
351*0Sstevel@tonic-gate  */
352*0Sstevel@tonic-gate /*ARGSUSED*/
collate_scopes(SLPHandle h,const char * u,unsigned short lifetime,SLPError errCode,void * cookie)353*0Sstevel@tonic-gate static SLPBoolean collate_scopes(SLPHandle h, const char *u,
354*0Sstevel@tonic-gate 					unsigned short lifetime,
355*0Sstevel@tonic-gate 					SLPError errCode, void *cookie) {
356*0Sstevel@tonic-gate 	SLPSrvURL *surl;
357*0Sstevel@tonic-gate 	char *s, *tstate, *p, *url;
358*0Sstevel@tonic-gate 	void **collator = cookie;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	if (errCode != SLP_OK)
361*0Sstevel@tonic-gate 		return (SLP_TRUE);
362*0Sstevel@tonic-gate 
363*0Sstevel@tonic-gate 	/* dup url so as not to corrupt da cache */
364*0Sstevel@tonic-gate 	if (!(url = strdup(u))) {
365*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "collate_scopes", "out of memory");
366*0Sstevel@tonic-gate 		return (SLP_FALSE);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	/* parse url into a SLPSrvURL struct */
370*0Sstevel@tonic-gate 	if (SLPParseSrvURL(url, &surl) != SLP_OK)
371*0Sstevel@tonic-gate 		return (SLP_TRUE);	/* bad URL; skip it */
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate 	/* collate the scopes using the btree stree->scopes: */
374*0Sstevel@tonic-gate 	/* skip the 'scopes=' part */
375*0Sstevel@tonic-gate 	if (!(p = strchr(surl->s_pcSrvPart, '='))) {
376*0Sstevel@tonic-gate 		free(surl);
377*0Sstevel@tonic-gate 		return (SLP_TRUE);	/* bad URL; skip it */
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 	p++;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	for (
382*0Sstevel@tonic-gate 		s = strtok_r(p, ",", &tstate);
383*0Sstevel@tonic-gate 		s;
384*0Sstevel@tonic-gate 		s = strtok_r(NULL, ",", &tstate)) {
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 		char *ascope, **srch;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 		if (!(ascope = strdup(s))) {	/* no memory! */
389*0Sstevel@tonic-gate 			slp_err(LOG_CRIT, 0, "collate_scopes",
390*0Sstevel@tonic-gate 				"out of memory");
391*0Sstevel@tonic-gate 			free(surl);
392*0Sstevel@tonic-gate 			return (SLP_TRUE);
393*0Sstevel@tonic-gate 		}
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 		srch = slp_tsearch(
396*0Sstevel@tonic-gate 			(void *) ascope, collator,
397*0Sstevel@tonic-gate 			(int (*)(const void *, const void *)) slp_strcasecmp);
398*0Sstevel@tonic-gate 		if (*srch != ascope)
399*0Sstevel@tonic-gate 			/* scope is already in there, so just free ascope */
400*0Sstevel@tonic-gate 			free(ascope);
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	free(url);
404*0Sstevel@tonic-gate 	free(surl);
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 	return (SLP_TRUE);
407*0Sstevel@tonic-gate }
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate /*
410*0Sstevel@tonic-gate  * Each time we visit a node for the last time, copy that scope into
411*0Sstevel@tonic-gate  * the scope collection and free the scope string and the node.
412*0Sstevel@tonic-gate  */
413*0Sstevel@tonic-gate /*ARGSUSED*/
collect_scopes(void * node,VISIT order,int level,void * cookie)414*0Sstevel@tonic-gate static void collect_scopes(void *node, VISIT order, int level, void *cookie) {
415*0Sstevel@tonic-gate 	char **scopes = (char **)cookie;
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	if (order == endorder || order == leaf) {
418*0Sstevel@tonic-gate 		char *s = *(char **)node;
419*0Sstevel@tonic-gate 		slp_add2list(s, scopes, SLP_FALSE);
420*0Sstevel@tonic-gate 		free(s);
421*0Sstevel@tonic-gate 		free(node);
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
SLPFree(void * pvMem)425*0Sstevel@tonic-gate void SLPFree(void *pvMem) {
426*0Sstevel@tonic-gate 	if (pvMem)
427*0Sstevel@tonic-gate 		free(pvMem);
428*0Sstevel@tonic-gate }
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate /*
431*0Sstevel@tonic-gate  * Escape / Unescape
432*0Sstevel@tonic-gate  */
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate #define	isBadTagChar(c)	((c) == '*' || (c) == '_' || \
435*0Sstevel@tonic-gate 			(c) == '\n' || (c) == '\t' || (c) == '\r')
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate #define	isReserved(c)	((c) <= 31 || (c) == '(' || (c) == ')' || \
438*0Sstevel@tonic-gate 			(c) == ',' || (c) == '\\' || (c) == '!' || \
439*0Sstevel@tonic-gate 			(c) == '<' || (c) == '=' || (c) == '>' || \
440*0Sstevel@tonic-gate 			(c) == '~')
441*0Sstevel@tonic-gate 
SLPEscape(const char * pcInbuf,char ** ppcOutBuf,SLPBoolean isTag)442*0Sstevel@tonic-gate SLPError SLPEscape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
443*0Sstevel@tonic-gate 	char *buf, *pin, *pout;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (!pcInbuf || !ppcOutBuf)
446*0Sstevel@tonic-gate 		return (SLP_PARAMETER_BAD);
447*0Sstevel@tonic-gate 
448*0Sstevel@tonic-gate 	if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
449*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
450*0Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
451*0Sstevel@tonic-gate 	}
452*0Sstevel@tonic-gate 	*ppcOutBuf = buf;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
455*0Sstevel@tonic-gate 		int len;
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 		/* If char is start of multibyte char, just copy it in */
458*0Sstevel@tonic-gate 		if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
459*0Sstevel@tonic-gate 			int i;
460*0Sstevel@tonic-gate 			for (i = 0; i < len && *pin; i++)
461*0Sstevel@tonic-gate 				*pout++ = *pin++;
462*0Sstevel@tonic-gate 			continue;
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		/* check for bad tag */
466*0Sstevel@tonic-gate 		if (isTag && isBadTagChar(*pin))
467*0Sstevel@tonic-gate 			return (SLP_PARSE_ERROR);
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 		if (isReserved(*pin)) {
470*0Sstevel@tonic-gate 			if (isTag)
471*0Sstevel@tonic-gate 				return (SLP_PARSE_ERROR);
472*0Sstevel@tonic-gate 			(void) sprintf(pout, "\\%.2x", *pin);
473*0Sstevel@tonic-gate 			pout += 3;
474*0Sstevel@tonic-gate 			pin++;
475*0Sstevel@tonic-gate 		} else {
476*0Sstevel@tonic-gate 			*pout++ = *pin++;
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 	*pout = 0;
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	return (SLP_OK);
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate 
SLPUnescape(const char * pcInbuf,char ** ppcOutBuf,SLPBoolean isTag)484*0Sstevel@tonic-gate SLPError SLPUnescape(const char *pcInbuf, char **ppcOutBuf, SLPBoolean isTag) {
485*0Sstevel@tonic-gate 	if (!pcInbuf || !ppcOutBuf)
486*0Sstevel@tonic-gate 		return (SLP_PARAMETER_BAD);
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	return (slp_unescape(pcInbuf, ppcOutBuf, isTag, '\\'));
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate /*
493*0Sstevel@tonic-gate  * The actual unescaping routine; allows for different escape chars.
494*0Sstevel@tonic-gate  */
slp_unescape(const char * pcInbuf,char ** ppcOutBuf,SLPBoolean isTag,const char esc_char)495*0Sstevel@tonic-gate static SLPError slp_unescape(const char *pcInbuf, char **ppcOutBuf,
496*0Sstevel@tonic-gate 				SLPBoolean isTag, const char esc_char) {
497*0Sstevel@tonic-gate 	char *buf, *pin, *pout, conv[3];
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 	if (!(buf = malloc(strlen(pcInbuf) * 3 + 1))) {
500*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPEscape", "out of memory");
501*0Sstevel@tonic-gate 		return (SLP_MEMORY_ALLOC_FAILED);
502*0Sstevel@tonic-gate 	}
503*0Sstevel@tonic-gate 	*ppcOutBuf = buf;
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	conv[2] = 0;
506*0Sstevel@tonic-gate 	for (pin = (char *)pcInbuf, pout = buf; *pin; ) {
507*0Sstevel@tonic-gate 		int len;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 		/* If char is start of multibyte char, just copy it in */
510*0Sstevel@tonic-gate 		if ((len = mblen(pin, MB_CUR_MAX)) > 1) {
511*0Sstevel@tonic-gate 			int i;
512*0Sstevel@tonic-gate 			for (i = 0; i < len && *pin; i++)
513*0Sstevel@tonic-gate 				*pout++ = *pin++;
514*0Sstevel@tonic-gate 			continue;
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 		if (*pin == esc_char) {
518*0Sstevel@tonic-gate 			if (!pin[1] || !pin[2])
519*0Sstevel@tonic-gate 				return (SLP_PARSE_ERROR);
520*0Sstevel@tonic-gate 			pin++;
521*0Sstevel@tonic-gate 			conv[0] = *pin++;
522*0Sstevel@tonic-gate 			conv[1] = *pin++;
523*0Sstevel@tonic-gate 			*pout++ = (char)strtol(conv, NULL, 16);
524*0Sstevel@tonic-gate 			if (isTag && isBadTagChar(*pout))
525*0Sstevel@tonic-gate 				return (SLP_PARSE_ERROR);
526*0Sstevel@tonic-gate 		} else {
527*0Sstevel@tonic-gate 			*pout++ = *pin++;
528*0Sstevel@tonic-gate 		}
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 	*pout = 0;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	return (SLP_OK);
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate /*
536*0Sstevel@tonic-gate  * Properties
537*0Sstevel@tonic-gate  *
538*0Sstevel@tonic-gate  * All properties are stored in a global tree (prop_table). This
539*0Sstevel@tonic-gate  * tree is created and accessed by slp_tsearch and slp_tfind.
540*0Sstevel@tonic-gate  */
541*0Sstevel@tonic-gate struct prop_entry {
542*0Sstevel@tonic-gate 	const char *key, *val;
543*0Sstevel@tonic-gate };
544*0Sstevel@tonic-gate typedef struct prop_entry slp_prop_entry_t;
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate /* Global properties table */
547*0Sstevel@tonic-gate static void *slp_props = NULL;
548*0Sstevel@tonic-gate static mutex_t prop_table_lock = DEFAULTMUTEX;
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate static void setDefaults();
551*0Sstevel@tonic-gate 
compare_props(const void * a,const void * b)552*0Sstevel@tonic-gate static int compare_props(const void *a, const void *b) {
553*0Sstevel@tonic-gate 	return (strcmp(
554*0Sstevel@tonic-gate 		((slp_prop_entry_t *)a)->key,
555*0Sstevel@tonic-gate 		((slp_prop_entry_t *)b)->key));
556*0Sstevel@tonic-gate }
557*0Sstevel@tonic-gate 
SLPSetProperty(const char * pcName,const char * pcValue)558*0Sstevel@tonic-gate void SLPSetProperty(const char *pcName, const char *pcValue) {
559*0Sstevel@tonic-gate 	slp_prop_entry_t *pe, **pe2;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 	if (!slp_props) setDefaults();
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	if (!pcName || !pcValue) {
564*0Sstevel@tonic-gate 		return;
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	if (!(pe = malloc(sizeof (*pe)))) {
568*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
569*0Sstevel@tonic-gate 		return;
570*0Sstevel@tonic-gate 	}
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	/* place the strings under library ownership */
573*0Sstevel@tonic-gate 	if (!(pe->key = strdup(pcName))) {
574*0Sstevel@tonic-gate 		free(pe);
575*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
576*0Sstevel@tonic-gate 		return;
577*0Sstevel@tonic-gate 	}
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 	if (!(pe->val = strdup(pcValue))) {
580*0Sstevel@tonic-gate 		free((void *) pe->key);
581*0Sstevel@tonic-gate 		free(pe);
582*0Sstevel@tonic-gate 		slp_err(LOG_CRIT, 0, "SLPSetProperty", "out of memory");
583*0Sstevel@tonic-gate 		return;
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	/* is pcName already set? */
587*0Sstevel@tonic-gate 	(void) mutex_lock(&prop_table_lock);
588*0Sstevel@tonic-gate 	pe2 = slp_tsearch((void *) pe, &slp_props, compare_props);
589*0Sstevel@tonic-gate 	if (pe != *pe2) {
590*0Sstevel@tonic-gate 		/* this prop is already set; overwrite the old value */
591*0Sstevel@tonic-gate 		free((void *) (*pe2)->val);
592*0Sstevel@tonic-gate 		(*pe2)->val = pe->val;
593*0Sstevel@tonic-gate 		free((void *) pe->key);
594*0Sstevel@tonic-gate 		free(pe);
595*0Sstevel@tonic-gate 	}
596*0Sstevel@tonic-gate 	(void) mutex_unlock(&prop_table_lock);
597*0Sstevel@tonic-gate }
598*0Sstevel@tonic-gate 
SLPGetProperty(const char * pcName)599*0Sstevel@tonic-gate const char *SLPGetProperty(const char *pcName) {
600*0Sstevel@tonic-gate 	slp_prop_entry_t pe[1], **ans;
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	if (!slp_props) setDefaults();
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	if (!pcName) {
605*0Sstevel@tonic-gate 		return (NULL);
606*0Sstevel@tonic-gate 	}
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 	pe->key = pcName;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	(void) mutex_lock(&prop_table_lock);
611*0Sstevel@tonic-gate 	ans = slp_tfind(pe, &slp_props, compare_props);
612*0Sstevel@tonic-gate 	(void) mutex_unlock(&prop_table_lock);
613*0Sstevel@tonic-gate 	if (ans)
614*0Sstevel@tonic-gate 		return ((*ans)->val);
615*0Sstevel@tonic-gate 	return (NULL);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate 
setDefaults()618*0Sstevel@tonic-gate static void setDefaults() {
619*0Sstevel@tonic-gate 	slp_prop_entry_t *pe;
620*0Sstevel@tonic-gate 	static mutex_t lock = DEFAULTMUTEX;
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	(void) mutex_lock(&lock);
623*0Sstevel@tonic-gate 	if (slp_props) {
624*0Sstevel@tonic-gate 		(void) mutex_unlock(&lock);
625*0Sstevel@tonic-gate 		return;
626*0Sstevel@tonic-gate 	}
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
629*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_ISBROADCASTONLY);
630*0Sstevel@tonic-gate 	pe->val = strdup("false");
631*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
634*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_MULTICASTTTL);
635*0Sstevel@tonic-gate 	pe->val = strdup("255");
636*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
639*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_MULTICASTMAXWAIT);
640*0Sstevel@tonic-gate 	pe->val = strdup("15000");
641*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
644*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_DATAGRAMTIMEOUTS);
645*0Sstevel@tonic-gate 	pe->val = strdup("2000,2000,2000");
646*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
649*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_MULTICASTTIMEOUTS);
650*0Sstevel@tonic-gate 	pe->val = strdup("1000,3000,3000,3000,3000");
651*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
654*0Sstevel@tonic-gate 	pe->key = SLP_CONFIG_MTU; pe->val = "1400";
655*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
658*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_MAXRESULTS);
659*0Sstevel@tonic-gate 	pe->val = strdup("-1");
660*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
663*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_SECURITY_ON);
664*0Sstevel@tonic-gate 	pe->val = strdup("false");
665*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	pe = malloc(sizeof (*pe));
668*0Sstevel@tonic-gate 	pe->key = strdup(SLP_CONFIG_BYPASS_AUTH);
669*0Sstevel@tonic-gate 	pe->val = strdup("false");
670*0Sstevel@tonic-gate 	(void) slp_tsearch((void *) pe, &slp_props, compare_props);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	slp_readConfig();
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	(void) mutex_unlock(&lock);
675*0Sstevel@tonic-gate }
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate static const char *error_strings[] = {
678*0Sstevel@tonic-gate 	"OK",				/* 0 */
679*0Sstevel@tonic-gate 	"Language not supported",	/* -1 */
680*0Sstevel@tonic-gate 	"Parse error",			/* -2 */
681*0Sstevel@tonic-gate 	"Invalid registration",		/* -3 */
682*0Sstevel@tonic-gate 	"Scope not supported",		/* -4 */
683*0Sstevel@tonic-gate 	"Invalid error number",		/* -5 */
684*0Sstevel@tonic-gate 	"Authentication absent",	/* -6 */
685*0Sstevel@tonic-gate 	"Authentication failed",	/* -7 */
686*0Sstevel@tonic-gate 	"Invalid error number",		/* -8 */
687*0Sstevel@tonic-gate 	"Invalid error number",		/* -9 */
688*0Sstevel@tonic-gate 	"Invalid error number",		/* -10 */
689*0Sstevel@tonic-gate 	"Invalid error number",		/* -11 */
690*0Sstevel@tonic-gate 	"Invalid error number",		/* -12 */
691*0Sstevel@tonic-gate 	"Invalid update",		/* -13 */
692*0Sstevel@tonic-gate 	"Invalid error number",		/* -14 */
693*0Sstevel@tonic-gate 	"Invalid error number",		/* -15 */
694*0Sstevel@tonic-gate 	"Invalid error number",		/* -16 */
695*0Sstevel@tonic-gate 	"Not implemented",		/* -17 */
696*0Sstevel@tonic-gate 	"Buffer overflow",		/* -18 */
697*0Sstevel@tonic-gate 	"Network timed out",		/* -19 */
698*0Sstevel@tonic-gate 	"Network init failed",		/* -20 */
699*0Sstevel@tonic-gate 	"Memory alloc failed",		/* -21 */
700*0Sstevel@tonic-gate 	"Parameter bad",		/* -22 */
701*0Sstevel@tonic-gate 	"Network error",		/* -23 */
702*0Sstevel@tonic-gate 	"Internal system error",	/* -24 */
703*0Sstevel@tonic-gate 	"Handle in use",		/* -25 */
704*0Sstevel@tonic-gate 	"Type error"			/* -26 */
705*0Sstevel@tonic-gate };
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate #define	SLP_MAX_ERR_CNT	26
708*0Sstevel@tonic-gate 
slp_strerror(SLPError err)709*0Sstevel@tonic-gate const char *slp_strerror(SLPError err) {
710*0Sstevel@tonic-gate 	int abserr;
711*0Sstevel@tonic-gate 	const char *str;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (err == SLP_LAST_CALL) {
714*0Sstevel@tonic-gate 		str = "Last call";
715*0Sstevel@tonic-gate 	} else if (err == SLP_SECURITY_UNAVAILABLE) {
716*0Sstevel@tonic-gate 		str = "Security Implementation Unavailable";
717*0Sstevel@tonic-gate 	} else {
718*0Sstevel@tonic-gate 		abserr = abs(err);
719*0Sstevel@tonic-gate 		if (abserr > SLP_MAX_ERR_CNT) {
720*0Sstevel@tonic-gate 			str = "Invalid error number";
721*0Sstevel@tonic-gate 		} else {
722*0Sstevel@tonic-gate 			str = error_strings[abserr];
723*0Sstevel@tonic-gate 		}
724*0Sstevel@tonic-gate 	}
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	return (dgettext("libslp", str));
727*0Sstevel@tonic-gate }
728