1 /* $NetBSD: dict_random.c,v 1.5 2026/05/09 18:49:22 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dict_random 3 6 /* SUMMARY 7 /* dictionary manager interface for randomized tables 8 /* SYNOPSIS 9 /* #include <dict_random.h> 10 /* 11 /* DICT *dict_random_open(name, open_flags, dict_flags) 12 /* const char *name; 13 /* int open_flags; 14 /* int dict_flags; 15 /* DESCRIPTION 16 /* dict_random_open() opens an in-memory, read-only, table. 17 /* Example: "\fBrandmap:{\fIresult_1, ... ,result_n}\fR". 18 /* 19 /* Each table query returns a random choice from the specified 20 /* results. Other table access methods are not supported. 21 /* 22 /* The first and last characters of the "randmap:" table name 23 /* must be '{' and '}'. Within these, individual maps are 24 /* separated with comma or whitespace. 25 /* SEE ALSO 26 /* dict(3) generic dictionary manager 27 /* LICENSE 28 /* .ad 29 /* .fi 30 /* The Secure Mailer license must be distributed with this software. 31 /* AUTHOR(S) 32 /* Wietse Venema 33 /* IBM T.J. Watson Research 34 /* P.O. Box 704 35 /* Yorktown Heights, NY 10598, USA 36 /* 37 /* Wietse Venema 38 /* Google, Inc. 39 /* 111 8th Avenue 40 /* New York, NY 10011, USA 41 /*--*/ 42 43 /* System library. */ 44 45 #include <sys_defs.h> 46 #include <string.h> 47 48 /* Utility library. */ 49 50 #include <msg.h> 51 #include <mymalloc.h> 52 #include <myrand.h> 53 #include <stringops.h> 54 #include <dict_random.h> 55 56 /* Application-specific. */ 57 58 typedef struct { 59 DICT dict; /* generic members */ 60 ARGV *replies; /* reply values */ 61 } DICT_RANDOM; 62 63 #define STR(x) vstring_str(x) 64 65 /* dict_random_lookup - find randomized-table entry */ 66 67 static const char *dict_random_lookup(DICT *dict, const char *unused_query) 68 { 69 DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; 70 71 DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, 72 dict_random->replies->argv[myrand() % dict_random->replies->argc]); 73 } 74 75 /* dict_random_close - disassociate from randomized table */ 76 77 static void dict_random_close(DICT *dict) 78 { 79 DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; 80 81 if (dict_random->replies) 82 argv_free(dict_random->replies); 83 dict_free(dict); 84 } 85 86 static char *dict_random_parse_name(DICT *dict, ARGV **argv, 87 const char *string, 88 const char *delim, 89 const char *parens) 90 { 91 ARGV *argvp = argv_alloc(1); 92 char *saved_string = mystrdup(string); 93 char *bp = saved_string; 94 char *arg; 95 VSTRING *b64 = 0; 96 char *err = 0; 97 98 while ((arg = mystrtokq(&bp, delim, parens)) != 0) { 99 if (dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) { 100 if ((b64 = dict_file_to_b64(dict, arg)) != 0) { 101 argv_add(argvp, vstring_str(b64), (char *) 0); 102 } else { 103 err = dict_file_get_error(dict); 104 break; 105 } 106 } else { 107 argv_add(argvp, arg, (char *) 0); 108 } 109 } 110 argv_terminate(argvp); 111 myfree(saved_string); 112 *argv = argvp; 113 return (err); 114 } 115 116 /* dict_random_open - open a randomized table */ 117 118 DICT *dict_random_open(const char *name, int open_flags, int dict_flags) 119 { 120 DICT_RANDOM *dict_random; 121 char *saved_name = 0; 122 size_t len; 123 char *err = 0; 124 125 /* 126 * Clarity first. Let the optimizer worry about redundant code. 127 */ 128 #define DICT_RANDOM_RETURN(x) do { \ 129 DICT *__d = (x); \ 130 if (saved_name != 0) \ 131 myfree(saved_name); \ 132 if (err != 0) \ 133 myfree(err); \ 134 return (__d); \ 135 } while (0) 136 137 /* 138 * Sanity checks. 139 */ 140 if (open_flags != O_RDONLY) 141 DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, 142 open_flags, dict_flags, 143 "%s:%s map requires O_RDONLY access mode", 144 DICT_TYPE_RANDOM, name)); 145 146 /* 147 * Bundle up preliminary results. 148 */ 149 dict_random = 150 (DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random)); 151 dict_random->dict.lookup = dict_random_lookup; 152 dict_random->dict.close = dict_random_close; 153 dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN; 154 dict_random->replies = 0; 155 dict_random->dict.owner.status = DICT_OWNER_TRUSTED; 156 dict_random->dict.owner.uid = 0; 157 158 /* 159 * Split the table name into its constituent parts. 160 */ 161 if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0 162 || *(saved_name = mystrndup(name + 1, len - 2)) == 0 163 || (err = dict_random_parse_name(&dict_random->dict, 164 &dict_random->replies, saved_name, 165 CHARS_COMMA_SP, CHARS_BRACE)) != 0 166 || dict_random->replies->argc == 0) { 167 dict_random_close(&dict_random->dict); 168 DICT_RANDOM_RETURN(err == 0 ? 169 dict_surrogate(DICT_TYPE_RANDOM, name, 170 open_flags, dict_flags, 171 "bad syntax: \"%s:%s\"; " 172 "need \"%s:{value...}\"", 173 DICT_TYPE_RANDOM, name, 174 DICT_TYPE_RANDOM) : 175 dict_surrogate(DICT_TYPE_RANDOM, name, 176 open_flags, dict_flags, 177 "%s", err)); 178 } 179 dict_file_purge_buffers(&dict_random->dict); 180 DICT_RANDOM_RETURN(&dict_random->dict); 181 } 182