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> 11SM_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 60char * 61ni_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