root/usr/src/cmd/sendmail/libsm/niprop.c
/*
 * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
 *      All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include <sm/gen.h>
SM_RCSID("@(#)$Id: niprop.c,v 1.6 2001/09/04 22:41:27 ca Exp $")

#if NETINFO
#include <ctype.h>
#include <stdlib.h>
#include <sm/io.h>
#include <sm/assert.h>
#include <sm/debug.h>
#include <sm/string.h>
#include <sm/varargs.h>
#include <sm/heap.h>

/*
**  NI_PROPVAL -- NetInfo property value lookup routine
**
**      Parameters:
**              keydir -- the NetInfo directory name in which to search
**                      for the key.
**              keyprop -- the name of the property in which to find the
**                      property we are interested.  Defaults to "name".
**              keyval -- the value for which we are really searching.
**              valprop -- the property name for the value in which we
**                      are interested.
**              sepchar -- if non-nil, this can be multiple-valued, and
**                      we should return a string separated by this
**                      character.
**
**      Returns:
**              NULL -- if:
**                      1. the directory is not found
**                      2. the property name is not found
**                      3. the property contains multiple values
**                      4. some error occurred
**              else -- the value of the lookup.
**
**      Example:
**              To search for an alias value, use:
**                ni_propval("/aliases", "name", aliasname, "members", ',')
**
**      Notes:
**              Caller should free the return value of ni_proval
*/

# include <netinfo/ni.h>

# define LOCAL_NETINFO_DOMAIN   "."
# define PARENT_NETINFO_DOMAIN  ".."
# define MAX_NI_LEVELS          256

char *
ni_propval(keydir, keyprop, keyval, valprop, sepchar)
        char *keydir;
        char *keyprop;
        char *keyval;
        char *valprop;
        int sepchar;
{
        char *propval = NULL;
        int i;
        int j, alen, l;
        void *ni = NULL;
        void *lastni = NULL;
        ni_status nis;
        ni_id nid;
        ni_namelist ninl;
        register char *p;
        char keybuf[1024];

        /*
        **  Create the full key from the two parts.
        **
        **      Note that directory can end with, e.g., "name=" to specify
        **      an alternate search property.
        */

        i = strlen(keydir) + strlen(keyval) + 2;
        if (keyprop != NULL)
                i += strlen(keyprop) + 1;
        if (i >= sizeof keybuf)
                return NULL;
        (void) sm_strlcpyn(keybuf, sizeof keybuf, 2, keydir, "/");
        if (keyprop != NULL)
        {
                (void) sm_strlcat2(keybuf, keyprop, "=", sizeof keybuf);
        }
        (void) sm_strlcat(keybuf, keyval, sizeof keybuf);

#if 0
        if (tTd(38, 21))
                sm_dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
                        keydir, keyprop, keyval, valprop, sepchar, keybuf);
#endif /* 0 */

        /*
        **  If the passed directory and property name are found
        **  in one of netinfo domains we need to search (starting
        **  from the local domain moving all the way back to the
        **  root domain) set propval to the property's value
        **  and return it.
        */

        for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
        {
                if (i == 0)
                {
                        nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
#if 0
                        if (tTd(38, 20))
                                sm_dprintf("ni_open(LOCAL) = %d\n", nis);
#endif /* 0 */
                }
                else
                {
                        if (lastni != NULL)
                                ni_free(lastni);
                        lastni = ni;
                        nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
#if 0
                        if (tTd(38, 20))
                                sm_dprintf("ni_open(PARENT) = %d\n", nis);
#endif /* 0 */
                }

                /*
                **  Don't bother if we didn't get a handle on a
                **  proper domain.  This is not necessarily an error.
                **  We would get a positive ni_status if, for instance
                **  we never found the directory or property and tried
                **  to open the parent of the root domain!
                */

                if (nis != 0)
                        break;

                /*
                **  Find the path to the server information.
                */

                if (ni_pathsearch(ni, &nid, keybuf) != 0)
                        continue;

                /*
                **  Find associated value information.
                */

                if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
                        continue;

#if 0
                if (tTd(38, 20))
                        sm_dprintf("ni_lookupprop: len=%d\n",
                                ninl.ni_namelist_len);
#endif /* 0 */

                /*
                **  See if we have an acceptable number of values.
                */

                if (ninl.ni_namelist_len <= 0)
                        continue;

                if (sepchar == '\0' && ninl.ni_namelist_len > 1)
                {
                        ni_namelist_free(&ninl);
                        continue;
                }

                /*
                **  Calculate number of bytes needed and build result
                */

                alen = 1;
                for (j = 0; j < ninl.ni_namelist_len; j++)
                        alen += strlen(ninl.ni_namelist_val[j]) + 1;
                propval = p = sm_malloc(alen);
                if (propval == NULL)
                        goto cleanup;
                for (j = 0; j < ninl.ni_namelist_len; j++)
                {
                        (void) sm_strlcpy(p, ninl.ni_namelist_val[j], alen);
                        l = strlen(p);
                        p += l;
                        *p++ = sepchar;
                        alen -= l + 1;
                }
                *--p = '\0';

                ni_namelist_free(&ninl);
        }

  cleanup:
        if (ni != NULL)
                ni_free(ni);
        if (lastni != NULL && ni != lastni)
                ni_free(lastni);
#if 0
        if (tTd(38, 20))
                sm_dprintf("ni_propval returns: '%s'\n", propval);
#endif /* 0 */

        return propval;
}
#endif /* NETINFO */