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