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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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*/ 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*/ 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 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 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 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 */ 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 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 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 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 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 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