/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifdef SLP
/*
* This file contains all the dynamic server discovery functionality
* for ldap_cachemgr. SLP is used to query the network for any changes
* in the set of deployed LDAP servers.
*
* The algorithm used is outlined here:
*
* 1. Find all naming contexts with SLPFindAttrs. (See
* find_all_contexts())
* 2. For each context, find all servers which serve that context
* with SLPFindSrvs. (See foreach_context())
* 3. For each server, retrieve that server's attributes with
* SLPFindAttributes. (See foreach_server())
* 4. Aggregate the servers' attributes into a config object. There
* is one config object associated with each context found in
* step 1. (See aggregate_attrs())
* 5. Update the global config cache for each found context and its
* associated servers and attributes. (See update_config())
*
* The entry point for ldap_cachemgr is discover(). The actual entry
* point into the discovery routine is find_all_contexts(); the
* code thereafter is actually not specific to LDAP, and could also
* be used to discover YP, or any other server which conforms
* to the SLP Naming and Directory abstract service type.
*
* find_all_attributes() takes as parameters three callback routines
* which are used to report all information back to the caller. The
* signatures and synopses of these routines are:
*
* void *get_cfghandle(const char *domain);
*
* Returns an opaque handle to a configuration object specific
* to the 'domain' parameter. 'domain' will be a naming context
* string, i.e. foo.bar.sun.com ( i.e. a secure-RPC domain-
* name).
*
* void aggregate(void *handle, const char *tag, const char *value);
*
* Adds this tag / value pair to the set of aggregated attributes
* associated with the given handle.
*
* void set_cfghandle(void *handle);
*
* Sets and destroys the config object; SLP will no longer attempt
* to use this handle after this call. Thus, this call marks the
* end of configuration information for this handle.
*/
#include <stdio.h>
#include <slp.h>
#include <stdlib.h>
#include <string.h>
#include <door.h>
#include <unistd.h>
#include "ns_sldap.h"
#include "ns_internal.h"
#include "cachemgr.h"
/* The configuration cookie passed along through all SLP callbacks. */
struct config_cookie {
SLPHandle h; /* An open SLPHandle */
void *(*get_cfghandle)(const char *);
void (*aggregate)(void *, const char *, const char *);
void (*set_cfghandle)(void *);
};
/*
* Utility routine: getlocale():
* Returns the locale specified by the SLP locale property, or just
* returns the default SLP locale if the property was not set.
*/
static const char *getlocale() {
}
/*
* Utility routine: next_attr():
* Parses an SLP attribute string. On the first call, *type
* must be set to 0, and *s_inout must point to the beginning
* of the attr string. The following results are possible:
*
* If the term is of the form 'tag' only, *t_inout is set to tag,
* and *v_inout is set to NULL.
* If the term is of the form '(tag=val)', *t_inout and *v_inout
* are set to the tag and val strings, respectively.
* If the term is of the form '(tag=val1,val2,..,valN)', on each
* successive call, next_attr will return the next value. On the
* first invocation, tag is set to 'tag'; on successive invocations,
* tag is set to *t_inout.
*
* The string passed in *s_inout is destructively modified; all values
* returned simply point into the initial string. Hence the caller
* is responsible for all memory management. The type parameter is
* for internal use only and should be set to 0 by the caller only
* on the first invocation.
*
* If more attrs are available, returns SLP_TRUE, otherwise returns
* SLP_FALSE. If SLP_FALSE is returned, all value-result parameters
* will be undefined, and should not be used.
*/
return (SLP_FALSE);
return (SLP_FALSE);
/* type: 0 = start, 1 = '(tag=val)' type, 2 = 'tag' type */
switch (*type) {
case 0:
switch (*state) {
case '(':
*type = 1;
break;
case ',':
state++;
*type = 0;
break;
default:
*type = 2;
}
break;
case 1:
switch (*state) {
case '(':
/* start of attr of the form (tag=val[,val]) */
state++;
if (!end)
return (SLP_FALSE); /* fatal parse error */
if (state) {
return (SLP_FALSE); /* fatal parse err */
*state++ = 0;
} else {
return (SLP_FALSE); /* fatal parse error */
}
/* fallthru to default case, which handles multivals */
default:
/* somewhere in a multivalued attr */
if (!end) { /* did not fallthru from '(' case */
if (!end)
return (SLP_FALSE); /* fatal parse error */
}
/* no, so skip to the next attr */
*type = 0;
} /* else attr is multivalued */
*state++ = 0;
break;
}
break;
case 2:
/* attr term with tag only */
if (state) {
*state++ = 0;
}
*type = 0;
break;
default:
return (SLP_FALSE);
}
return (SLP_TRUE);
}
/*
* The SLP callback routine for foreach_server(). Aggregates each
* server's attributes into the caller-specified config object.
*/
/*ARGSUSED*/
int type = 0;
char *attrs;
return (SLP_TRUE);
}
if (tag) {
(void) logit("aggregate_attrs: ",
"could not unescape attr tag %s:%s\n",
}
}
}
if (val) {
!= SLP_OK) {
(void) logit("aggregate_attrs: ",
"could not unescape attr val %s:%s\n",
}
}
}
(void) logit("discovery:\t\t%s=%s\n",
}
}
return (SLP_TRUE);
}
/*
* The SLP callback routine for update_config(). For each
* server found, retrieves that server's attributes.
*/
/*ARGSUSED*/
unsigned short life,
return (SLP_TRUE);
}
/* dup url so we can slice 'n dice */
(void) logit("foreach_server: no memory");
return (SLP_FALSE);
}
(void) logit("foreach_server: ",
"dropping unparsable URL %s: %s\n",
return (SLP_TRUE);
}
}
}
/* retrieve all attrs for this server */
(void) logit("foreach_server: FindAttrs failed: %s\n",
slp_strerror(err));
}
goto cleanup;
}
/* add this server and its attrs to the config object */
return (SLP_TRUE);
}
/*
* This routine does the dirty work of finding all servers for a
* given domain and injecting this information into the caller's
* configuration namespace via callbacks.
*/
/* Unescape the naming context string */
(void) logit("update_config: ",
"dropping unparsable domain: %s: %s\n",
}
return;
}
/* Open a handle which all attrs calls can use */
(void) logit("update_config: SLPOpen failed: %s\n",
slp_strerror(err));
}
goto cleanup;
}
}
/* (re)construct the search filter form the input context */
if (!search) {
(void) logit("update_config: no memory\n");
goto cleanup;
}
/* Find all servers which serve this context */
(void) logit("upate_config: SLPOpen failed: %s\n",
slp_strerror(err));
}
goto cleanup;
}
(void) logit("update_config: SLPFindSrvs failed: %s\n",
slp_strerror(err));
}
goto cleanup;
}
/* update the config cache with the new info */
if (h) SLPClose(h);
}
/*
* The SLP callback routine for find_all_contexts(). For each context
* found, finds all the servers and their attributes.
*/
/*ARGSUSED*/
int type = 0;
return (SLP_TRUE);
}
/*
* Parse out each context. Attrs will be of the following form:
* (naming-context=dc\3deng\2c dc\3dsun\2c dc\3dcom)
* Note that ',' and '=' are reserved in SLP, so they are escaped.
*/
if (!attrs) {
(void) logit("foreach_context: no memory\n");
return (SLP_FALSE);
}
}
return (SLP_TRUE);
}
/*
* Initiates server and attribute discovery for the concrete type
* 'type'. Currently the only useful type is "ldap", but perhaps
* "nis" and "nisplus" will also be useful in the future.
*
* get_cfghandle, aggregate, and set_cfghandle are callback routines
* used to pass any discovered configuration information back to the
* caller. See the introduction at the top of this file for more info.
*/
void *(*get_cfghandle)(const char *),
void (*aggregate)(
void *, const char *, const char *),
void (*set_cfghandle)(void *)) {
scope = "default";
}
/* construct the full type from the partial type parameter */
if (!fulltype) {
(void) logit("find_all_contexts: no memory");
goto done;
}
/* set up the cookie for this discovery operation */
/* Sun LDAP is special */
} else {
}
(void) logit("discover: %s",
"Aborting discovery: SLPOpen failed: %s\n",
slp_strerror(err));
}
goto done;
}
/* use find attrs to get a list of all available contexts */
(void) logit(
"discover: Aborting discovery: SLPFindAttrs failed: %s\n",
slp_strerror(err));
}
goto done;
}
done:
if (h) SLPClose(h);
}
/*
* This is the ldap_cachemgr entry point into SLP dynamic discovery. The
* parameter 'r' should be a pointer to an unsigned int containing
* the requested interval at which the network should be queried.
*/
void discover(void *r) {
unsigned short reqrefresh = *((unsigned int *)r);
for (;;) {
find_all_contexts("ldap",
(void) logit(
"dynamic discovery: using refresh interval %d\n",
}
(void) sleep(reqrefresh);
}
}
#endif /* SLP */