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 /* 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 */ 214