xref: /titanic_51/usr/src/cmd/sendmail/libsm/niprop.c (revision d73ae94e59c019f5cc3221ee0a0012d02091b40e)
1  /*
2   * Copyright (c) 2001 Sendmail, Inc. and its suppliers.
3   *	All rights reserved.
4   *
5   * By using this file, you agree to the terms and conditions set
6   * forth in the LICENSE file which can be found at the top level of
7   * the sendmail distribution.
8   */
9  
10  #pragma ident	"%Z%%M%	%I%	%E% SMI"
11  
12  #include <sm/gen.h>
13  SM_RCSID("@(#)$Id: niprop.c,v 1.6 2001/09/04 22:41:27 ca Exp $")
14  
15  #if NETINFO
16  #include <ctype.h>
17  #include <stdlib.h>
18  #include <sm/io.h>
19  #include <sm/assert.h>
20  #include <sm/debug.h>
21  #include <sm/string.h>
22  #include <sm/varargs.h>
23  #include <sm/heap.h>
24  
25  /*
26  **  NI_PROPVAL -- NetInfo property value lookup routine
27  **
28  **	Parameters:
29  **		keydir -- the NetInfo directory name in which to search
30  **			for the key.
31  **		keyprop -- the name of the property in which to find the
32  **			property we are interested.  Defaults to "name".
33  **		keyval -- the value for which we are really searching.
34  **		valprop -- the property name for the value in which we
35  **			are interested.
36  **		sepchar -- if non-nil, this can be multiple-valued, and
37  **			we should return a string separated by this
38  **			character.
39  **
40  **	Returns:
41  **		NULL -- if:
42  **			1. the directory is not found
43  **			2. the property name is not found
44  **			3. the property contains multiple values
45  **			4. some error occurred
46  **		else -- the value of the lookup.
47  **
48  **	Example:
49  **		To search for an alias value, use:
50  **		  ni_propval("/aliases", "name", aliasname, "members", ',')
51  **
52  **	Notes:
53  **		Caller should free the return value of ni_proval
54  */
55  
56  # include <netinfo/ni.h>
57  
58  # define LOCAL_NETINFO_DOMAIN	"."
59  # define PARENT_NETINFO_DOMAIN	".."
60  # define MAX_NI_LEVELS		256
61  
62  char *
63  ni_propval(keydir, keyprop, keyval, valprop, sepchar)
64  	char *keydir;
65  	char *keyprop;
66  	char *keyval;
67  	char *valprop;
68  	int sepchar;
69  {
70  	char *propval = NULL;
71  	int i;
72  	int j, alen, l;
73  	void *ni = NULL;
74  	void *lastni = NULL;
75  	ni_status nis;
76  	ni_id nid;
77  	ni_namelist ninl;
78  	register char *p;
79  	char keybuf[1024];
80  
81  	/*
82  	**  Create the full key from the two parts.
83  	**
84  	**	Note that directory can end with, e.g., "name=" to specify
85  	**	an alternate search property.
86  	*/
87  
88  	i = strlen(keydir) + strlen(keyval) + 2;
89  	if (keyprop != NULL)
90  		i += strlen(keyprop) + 1;
91  	if (i >= sizeof keybuf)
92  		return NULL;
93  	(void) sm_strlcpyn(keybuf, sizeof keybuf, 2, keydir, "/");
94  	if (keyprop != NULL)
95  	{
96  		(void) sm_strlcat2(keybuf, keyprop, "=", sizeof keybuf);
97  	}
98  	(void) sm_strlcat(keybuf, keyval, sizeof keybuf);
99  
100  #if 0
101  	if (tTd(38, 21))
102  		sm_dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n",
103  			keydir, keyprop, keyval, valprop, sepchar, keybuf);
104  #endif /* 0 */
105  
106  	/*
107  	**  If the passed directory and property name are found
108  	**  in one of netinfo domains we need to search (starting
109  	**  from the local domain moving all the way back to the
110  	**  root domain) set propval to the property's value
111  	**  and return it.
112  	*/
113  
114  	for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++)
115  	{
116  		if (i == 0)
117  		{
118  			nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni);
119  #if 0
120  			if (tTd(38, 20))
121  				sm_dprintf("ni_open(LOCAL) = %d\n", nis);
122  #endif /* 0 */
123  		}
124  		else
125  		{
126  			if (lastni != NULL)
127  				ni_free(lastni);
128  			lastni = ni;
129  			nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni);
130  #if 0
131  			if (tTd(38, 20))
132  				sm_dprintf("ni_open(PARENT) = %d\n", nis);
133  #endif /* 0 */
134  		}
135  
136  		/*
137  		**  Don't bother if we didn't get a handle on a
138  		**  proper domain.  This is not necessarily an error.
139  		**  We would get a positive ni_status if, for instance
140  		**  we never found the directory or property and tried
141  		**  to open the parent of the root domain!
142  		*/
143  
144  		if (nis != 0)
145  			break;
146  
147  		/*
148  		**  Find the path to the server information.
149  		*/
150  
151  		if (ni_pathsearch(ni, &nid, keybuf) != 0)
152  			continue;
153  
154  		/*
155  		**  Find associated value information.
156  		*/
157  
158  		if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0)
159  			continue;
160  
161  #if 0
162  		if (tTd(38, 20))
163  			sm_dprintf("ni_lookupprop: len=%d\n",
164  				ninl.ni_namelist_len);
165  #endif /* 0 */
166  
167  		/*
168  		**  See if we have an acceptable number of values.
169  		*/
170  
171  		if (ninl.ni_namelist_len <= 0)
172  			continue;
173  
174  		if (sepchar == '\0' && ninl.ni_namelist_len > 1)
175  		{
176  			ni_namelist_free(&ninl);
177  			continue;
178  		}
179  
180  		/*
181  		**  Calculate number of bytes needed and build result
182  		*/
183  
184  		alen = 1;
185  		for (j = 0; j < ninl.ni_namelist_len; j++)
186  			alen += strlen(ninl.ni_namelist_val[j]) + 1;
187  		propval = p = sm_malloc(alen);
188  		if (propval == NULL)
189  			goto cleanup;
190  		for (j = 0; j < ninl.ni_namelist_len; j++)
191  		{
192  			(void) sm_strlcpy(p, ninl.ni_namelist_val[j], alen);
193  			l = strlen(p);
194  			p += l;
195  			*p++ = sepchar;
196  			alen -= l + 1;
197  		}
198  		*--p = '\0';
199  
200  		ni_namelist_free(&ninl);
201  	}
202  
203    cleanup:
204  	if (ni != NULL)
205  		ni_free(ni);
206  	if (lastni != NULL && ni != lastni)
207  		ni_free(lastni);
208  #if 0
209  	if (tTd(38, 20))
210  		sm_dprintf("ni_propval returns: '%s'\n", propval);
211  #endif /* 0 */
212  
213  	return propval;
214  }
215  #endif /* NETINFO */
216