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