1 /* $NetBSD: dict_open.c,v 1.1.1.6 2013/09/25 19:06:37 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dict_open 3 6 /* SUMMARY 7 /* low-level dictionary interface 8 /* SYNOPSIS 9 /* #include <dict.h> 10 /* 11 /* DICT *dict_open(dict_spec, open_flags, dict_flags) 12 /* const char *dict_spec; 13 /* int open_flags; 14 /* int dict_flags; 15 /* 16 /* DICT *dict_open3(dict_type, dict_name, open_flags, dict_flags) 17 /* const char *dict_type; 18 /* const char *dict_name; 19 /* int open_flags; 20 /* int dict_flags; 21 /* 22 /* int dict_put(dict, key, value) 23 /* DICT *dict; 24 /* const char *key; 25 /* const char *value; 26 /* 27 /* const char *dict_get(dict, key) 28 /* DICT *dict; 29 /* const char *key; 30 /* 31 /* int dict_del(dict, key) 32 /* DICT *dict; 33 /* const char *key; 34 /* 35 /* int dict_seq(dict, func, key, value) 36 /* DICT *dict; 37 /* int func; 38 /* const char **key; 39 /* const char **value; 40 /* 41 /* void dict_close(dict) 42 /* DICT *dict; 43 /* 44 /* dict_open_register(type, open) 45 /* char *type; 46 /* DICT *(*open) (const char *, int, int); 47 /* 48 /* ARGV *dict_mapnames() 49 /* DESCRIPTION 50 /* This module implements a low-level interface to multiple 51 /* physical dictionary types. 52 /* 53 /* dict_open() takes a type:name pair that specifies a dictionary type 54 /* and dictionary name, opens the dictionary, and returns a dictionary 55 /* handle. The \fIopen_flags\fR arguments are as in open(2). The 56 /* \fIdict_flags\fR are the bit-wise OR of zero or more of the following: 57 /* .IP DICT_FLAG_DUP_WARN 58 /* Warn about duplicate keys, if the underlying database does not 59 /* support duplicate keys. The default is to terminate with a fatal 60 /* error. 61 /* .IP DICT_FLAG_DUP_IGNORE 62 /* Ignore duplicate keys if the underlying database does not 63 /* support duplicate keys. The default is to terminate with a fatal 64 /* error. 65 /* .IP DICT_FLAG_DUP_REPLACE 66 /* Replace duplicate keys if the underlying database supports such 67 /* an operation. The default is to terminate with a fatal error. 68 /* .IP DICT_FLAG_TRY0NULL 69 /* With maps where this is appropriate, append no null byte to 70 /* keys and values. 71 /* When neither DICT_FLAG_TRY0NULL nor DICT_FLAG_TRY1NULL are 72 /* specified, the software guesses what format to use for reading; 73 /* and in the absence of definite information, a system-dependent 74 /* default is chosen for writing. 75 /* .IP DICT_FLAG_TRY1NULL 76 /* With maps where this is appropriate, append one null byte to 77 /* keys and values. 78 /* When neither DICT_FLAG_TRY0NULL nor DICT_FLAG_TRY1NULL are 79 /* specified, the software guesses what format to use for reading; 80 /* and in the absence of definite information, a system-dependent 81 /* default is chosen for writing. 82 /* .IP DICT_FLAG_LOCK 83 /* With maps where this is appropriate, acquire an exclusive lock 84 /* before writing, and acquire a shared lock before reading. 85 /* .IP DICT_FLAG_OPEN_LOCK 86 /* With databases that are not multi-writer safe, request that 87 /* dict_open() acquires an exclusive lock, or that it terminates 88 /* with a fatal run-time error. 89 /* .IP DICT_FLAG_FOLD_FIX 90 /* With databases whose lookup fields are fixed-case strings, 91 /* fold the search string to lower case before accessing the 92 /* database. This includes hash:, cdb:, dbm:. nis:, ldap:, 93 /* *sql. 94 /* .IP DICT_FLAG_FOLD_MUL 95 /* With databases where one lookup field can match both upper 96 /* and lower case, fold the search key to lower case before 97 /* accessing the database. This includes regexp: and pcre: 98 /* .IP DICT_FLAG_FOLD_ANY 99 /* Short-hand for (DICT_FLAG_FOLD_FIX | DICT_FLAG_FOLD_MUL). 100 /* .IP DICT_FLAG_SYNC_UPDATE 101 /* With file-based maps, flush I/O buffers to file after each update. 102 /* Thus feature is not supported with some file-based dictionaries. 103 /* .IP DICT_FLAG_NO_REGSUB 104 /* Disallow regular expression substitution from the lookup string 105 /* into the lookup result, to block data injection attacks. 106 /* .IP DICT_FLAG_NO_PROXY 107 /* Disallow access through the unprivileged \fBproxymap\fR 108 /* service, to block privilege escalation attacks. 109 /* .IP DICT_FLAG_NO_UNAUTH 110 /* Disallow lookup mechanisms that lack any form of authentication, 111 /* to block privilege escalation attacks (example: tcp_table; 112 /* even NIS can be secured to some extent by requiring that 113 /* the server binds to a privileged port). 114 /* .IP DICT_FLAG_PARANOID 115 /* A combination of all the paranoia flags: DICT_FLAG_NO_REGSUB, 116 /* DICT_FLAG_NO_PROXY and DICT_FLAG_NO_UNAUTH. 117 /* .IP DICT_FLAG_DEBUG 118 /* Enable additional logging. 119 /* .PP 120 /* Specify DICT_FLAG_NONE for no special processing. 121 /* 122 /* The dictionary types are as follows: 123 /* .IP environ 124 /* The process environment array. The \fIdict_name\fR argument is ignored. 125 /* .IP dbm 126 /* DBM file. 127 /* .IP hash 128 /* Berkeley DB file in hash format. 129 /* .IP btree 130 /* Berkeley DB file in btree format. 131 /* .IP nis 132 /* NIS map. Only read access is supported. 133 /* .IP nisplus 134 /* NIS+ map. Only read access is supported. 135 /* .IP netinfo 136 /* NetInfo table. Only read access is supported. 137 /* .IP ldap 138 /* LDAP ("light-weight" directory access protocol) database access. 139 /* .IP pcre 140 /* PERL-compatible regular expressions. 141 /* .IP regexp 142 /* POSIX-compatible regular expressions. 143 /* .IP texthash 144 /* Flat text in postmap(1) input format. 145 /* .PP 146 /* dict_open3() takes separate arguments for dictionary type and 147 /* name, but otherwise performs the same functions as dict_open(). 148 /* 149 /* dict_get() retrieves the value stored in the named dictionary 150 /* under the given key. A null pointer means the value was not found. 151 /* As with dict_lookup(), the result is owned by the lookup table 152 /* implementation. Make a copy if the result is to be modified, 153 /* or if the result is to survive multiple table lookups. 154 /* 155 /* dict_put() stores the specified key and value into the named 156 /* dictionary. A zero (DICT_STAT_SUCCESS) result means the 157 /* update was made. 158 /* 159 /* dict_del() removes a dictionary entry, and returns 160 /* DICT_STAT_SUCCESS in case of success. 161 /* 162 /* dict_seq() iterates over all members in the named dictionary. 163 /* func is define DICT_SEQ_FUN_FIRST (select first member) or 164 /* DICT_SEQ_FUN_NEXT (select next member). A zero (DICT_STAT_SUCCESS) 165 /* result means that an entry was found. 166 /* 167 /* dict_close() closes the specified dictionary and cleans up the 168 /* associated data structures. 169 /* 170 /* dict_open_register() adds support for a new dictionary type. 171 /* 172 /* dict_mapnames() returns a sorted list with the names of all available 173 /* dictionary types. 174 /* DIAGNOSTICS 175 /* Fatal error: open error, unsupported dictionary type, attempt to 176 /* update non-writable dictionary. 177 /* 178 /* The lookup routine returns non-null when the request is 179 /* satisfied. The update, delete and sequence routines return 180 /* zero (DICT_STAT_SUCCESS) when the request is satisfied. 181 /* The dict->errno value is non-zero only when the last operation 182 /* was not satisfied due to a dictionary access error. This 183 /* can have the following values: 184 /* .IP DICT_ERR_NONE(zero) 185 /* There was no dictionary access error. For example, the 186 /* request was satisfied, the requested information did not 187 /* exist in the dictionary, or the information already existed 188 /* when it should not exist (collision). 189 /* .IP DICT_ERR_RETRY(<0) 190 /* The dictionary was temporarily unavailable. This can happen 191 /* with network-based services. 192 /* .IP DICT_ERR_CONFIG(<0) 193 /* The dictionary was unavailable due to a configuration error. 194 /* .PP 195 /* Generally, a program is expected to test the function result 196 /* value for "success" first. If the operation was not successful, 197 /* a program is expected to test for a non-zero dict->error 198 /* status to distinguish between a data notfound/collision 199 /* condition or a dictionary access error. 200 /* LICENSE 201 /* .ad 202 /* .fi 203 /* The Secure Mailer license must be distributed with this software. 204 /* AUTHOR(S) 205 /* Wietse Venema 206 /* IBM T.J. Watson Research 207 /* P.O. Box 704 208 /* Yorktown Heights, NY 10598, USA 209 /*--*/ 210 211 /* System library. */ 212 213 #include <sys_defs.h> 214 #include <string.h> 215 #include <stdlib.h> 216 217 #ifdef STRCASECMP_IN_STRINGS_H 218 #include <strings.h> 219 #endif 220 221 /* Utility library. */ 222 223 #include <argv.h> 224 #include <mymalloc.h> 225 #include <msg.h> 226 #include <dict.h> 227 #include <dict_cdb.h> 228 #include <dict_env.h> 229 #include <dict_unix.h> 230 #include <dict_tcp.h> 231 #include <dict_sdbm.h> 232 #include <dict_dbm.h> 233 #include <dict_db.h> 234 #include <dict_nis.h> 235 #include <dict_nisplus.h> 236 #include <dict_ni.h> 237 #include <dict_pcre.h> 238 #include <dict_regexp.h> 239 #include <dict_static.h> 240 #include <dict_cidr.h> 241 #include <dict_ht.h> 242 #include <dict_thash.h> 243 #include <dict_sockmap.h> 244 #include <dict_fail.h> 245 #include <stringops.h> 246 #include <split_at.h> 247 #include <htable.h> 248 #include <myflock.h> 249 250 /* 251 * lookup table for available map types. 252 */ 253 typedef struct { 254 char *type; 255 struct DICT *(*open) (const char *, int, int); 256 } DICT_OPEN_INFO; 257 258 static const DICT_OPEN_INFO dict_open_info[] = { 259 #ifdef HAS_CDB 260 DICT_TYPE_CDB, dict_cdb_open, 261 #endif 262 DICT_TYPE_ENVIRON, dict_env_open, 263 DICT_TYPE_HT, dict_ht_open, 264 DICT_TYPE_UNIX, dict_unix_open, 265 DICT_TYPE_TCP, dict_tcp_open, 266 #ifdef HAS_SDBM 267 DICT_TYPE_SDBM, dict_sdbm_open, 268 #endif 269 #ifdef HAS_DBM 270 DICT_TYPE_DBM, dict_dbm_open, 271 #endif 272 #ifdef HAS_DB 273 DICT_TYPE_HASH, dict_hash_open, 274 DICT_TYPE_BTREE, dict_btree_open, 275 #endif 276 #ifdef HAS_NIS 277 DICT_TYPE_NIS, dict_nis_open, 278 #endif 279 #ifdef HAS_NISPLUS 280 DICT_TYPE_NISPLUS, dict_nisplus_open, 281 #endif 282 #ifdef HAS_NETINFO 283 DICT_TYPE_NETINFO, dict_ni_open, 284 #endif 285 #ifdef HAS_PCRE 286 DICT_TYPE_PCRE, dict_pcre_open, 287 #endif 288 #ifdef HAS_POSIX_REGEXP 289 DICT_TYPE_REGEXP, dict_regexp_open, 290 #endif 291 DICT_TYPE_STATIC, dict_static_open, 292 DICT_TYPE_CIDR, dict_cidr_open, 293 DICT_TYPE_THASH, dict_thash_open, 294 DICT_TYPE_SOCKMAP, dict_sockmap_open, 295 DICT_TYPE_FAIL, dict_fail_open, 296 0, 297 }; 298 299 static HTABLE *dict_open_hash; 300 301 /* dict_open_init - one-off initialization */ 302 303 static void dict_open_init(void) 304 { 305 const char *myname = "dict_open_init"; 306 const DICT_OPEN_INFO *dp; 307 308 if (dict_open_hash != 0) 309 msg_panic("%s: multiple initialization", myname); 310 dict_open_hash = htable_create(10); 311 312 for (dp = dict_open_info; dp->type; dp++) 313 htable_enter(dict_open_hash, dp->type, (char *) dp); 314 } 315 316 /* dict_open - open dictionary */ 317 318 DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags) 319 { 320 char *saved_dict_spec = mystrdup(dict_spec); 321 char *dict_name; 322 DICT *dict; 323 324 if ((dict_name = split_at(saved_dict_spec, ':')) == 0) 325 msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s\"", 326 dict_spec); 327 328 dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags); 329 myfree(saved_dict_spec); 330 return (dict); 331 } 332 333 334 /* dict_open3 - open dictionary */ 335 336 DICT *dict_open3(const char *dict_type, const char *dict_name, 337 int open_flags, int dict_flags) 338 { 339 const char *myname = "dict_open"; 340 DICT_OPEN_INFO *dp; 341 DICT *dict; 342 343 if (*dict_type == 0 || *dict_name == 0) 344 msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s:%s\"", 345 dict_type, dict_name); 346 if (dict_open_hash == 0) 347 dict_open_init(); 348 if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0) 349 return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags, 350 "unsupported dictionary type: %s", dict_type)); 351 if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0) 352 return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags, 353 "cannot open %s:%s: %m", dict_type, dict_name)); 354 if (msg_verbose) 355 msg_info("%s: %s:%s", myname, dict_type, dict_name); 356 /* XXX the choice between wait-for-lock or no-wait is hard-coded. */ 357 if (dict_flags & DICT_FLAG_OPEN_LOCK) { 358 if (dict_flags & DICT_FLAG_LOCK) 359 msg_panic("%s: attempt to open %s:%s with both \"open\" lock and \"access\" lock", 360 myname, dict_type, dict_name); 361 if (dict->lock(dict, MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) < 0) 362 msg_fatal("%s:%s: unable to get exclusive lock: %m", 363 dict_type, dict_name); 364 } 365 return (dict); 366 } 367 368 /* dict_open_register - register dictionary type */ 369 370 void dict_open_register(const char *type, 371 DICT *(*open) (const char *, int, int)) 372 { 373 const char *myname = "dict_open_register"; 374 DICT_OPEN_INFO *dp; 375 376 if (dict_open_hash == 0) 377 dict_open_init(); 378 if (htable_find(dict_open_hash, type)) 379 msg_panic("%s: dictionary type exists: %s", myname, type); 380 dp = (DICT_OPEN_INFO *) mymalloc(sizeof(*dp)); 381 dp->type = mystrdup(type); 382 dp->open = open; 383 htable_enter(dict_open_hash, dp->type, (char *) dp); 384 } 385 386 /* dict_sort_alpha_cpp - qsort() callback */ 387 388 static int dict_sort_alpha_cpp(const void *a, const void *b) 389 { 390 return (strcmp(((char **) a)[0], ((char **) b)[0])); 391 } 392 393 /* dict_mapnames - return an ARGV of available map_names */ 394 395 ARGV *dict_mapnames() 396 { 397 HTABLE_INFO **ht_info; 398 HTABLE_INFO **ht; 399 DICT_OPEN_INFO *dp; 400 ARGV *mapnames; 401 402 if (dict_open_hash == 0) 403 dict_open_init(); 404 mapnames = argv_alloc(dict_open_hash->used + 1); 405 for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) { 406 dp = (DICT_OPEN_INFO *) ht[0]->value; 407 argv_add(mapnames, dp->type, ARGV_END); 408 } 409 qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]), 410 dict_sort_alpha_cpp); 411 myfree((char *) ht_info); 412 argv_terminate(mapnames); 413 return mapnames; 414 } 415 416 #ifdef TEST 417 418 /* 419 * Proof-of-concept test program. 420 */ 421 int main(int argc, char **argv) 422 { 423 dict_test(argc, argv); 424 return (0); 425 } 426 427 #endif 428