xref: /freebsd/contrib/sendmail/libsm/niprop.c (revision 1edc20b76953d9ef571b0bcf89b206b98ed13d9b)
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>
11  SM_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  
60  char *
61  ni_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