Merge from vendor branch GDB:
[dragonfly.git] / contrib / sendmail-8.13.4 / libsm / niprop.c
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 #include <sm/gen.h>
11 SM_RCSID("@(#)$Id: niprop.c,v 1.8 2001/09/11 04:04:48 gshapiro 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 /* 0 */
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 /* 0 */
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 /* 0 */
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 /* 0 */
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 /* 0 */
210
211         return propval;
212 }
213 #endif /* NETINFO */