xref: /freebsd/contrib/sendmail/libsm/niprop.c (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
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