Home | History | Annotate | Line # | Download | only in util
      1 /*	$NetBSD: dict.h,v 1.7 2026/05/09 18:49:22 christos Exp $	*/
      2 
      3 #ifndef _DICT_H_INCLUDED_
      4 #define _DICT_H_INCLUDED_
      5 
      6 /*++
      7 /* NAME
      8 /*	dict 3h
      9 /* SUMMARY
     10 /*	dictionary manager
     11 /* SYNOPSIS
     12 /*	#include <dict.h>
     13 /* DESCRIPTION
     14 /* .nf
     15 
     16  /*
     17   * System library.
     18   */
     19 #include <sys/stat.h>
     20 #include <fcntl.h>
     21 #include <setjmp.h>
     22 
     23 #ifdef NO_SIGSETJMP
     24 #define DICT_JMP_BUF jmp_buf
     25 #else
     26 #define DICT_JMP_BUF sigjmp_buf
     27 #endif
     28 
     29  /*
     30   * Utility library.
     31   */
     32 #include <vstream.h>
     33 #include <argv.h>
     34 #include <vstring.h>
     35 #include <myflock.h>
     36 
     37  /*
     38   * Provenance information.
     39   */
     40 typedef struct DICT_OWNER {
     41     int     status;			/* see below */
     42     uid_t   uid;			/* use only if status == UNTRUSTED */
     43 } DICT_OWNER;
     44 
     45  /*
     46   * Note that trust levels are not in numerical order.
     47   */
     48 #define DICT_OWNER_UNKNOWN	(-1)	/* ex: unauthenticated tcp, proxy */
     49 #define DICT_OWNER_TRUSTED	(!1)	/* ex: root-owned config file */
     50 #define DICT_OWNER_UNTRUSTED	(!0)	/* ex: non-root config file */
     51 
     52  /*
     53   * When combining tables with different provenance, we initialize to the
     54   * highest trust level, and remember the lowest trust level that we find
     55   * during aggregation. If we combine tables that are owned by different
     56   * untrusted users, the resulting provenance is "unknown".
     57   */
     58 #define DICT_OWNER_AGGREGATE_INIT(dst) { \
     59 	(dst).status = DICT_OWNER_TRUSTED; \
     60 	(dst).uid = 0; \
     61     } while (0)
     62 
     63  /*
     64   * The following is derived from the 3x3 transition matrix.
     65   */
     66 #define DICT_OWNER_AGGREGATE_UPDATE(dst, src) do { \
     67 	if ((dst).status == DICT_OWNER_TRUSTED \
     68 	    || (src).status == DICT_OWNER_UNKNOWN) { \
     69 	    (dst) = (src); \
     70 	} else if ((dst).status == (src).status \
     71 		&& (dst).uid != (src).uid) { \
     72 	    (dst).status = DICT_OWNER_UNKNOWN; \
     73 	    (dst).uid = ~0; \
     74 	} \
     75     } while (0)
     76 
     77  /*
     78   * Generic dictionary interface - in reality, a dictionary extends this
     79   * structure with private members to maintain internal state.
     80   */
     81 typedef struct DICT {
     82     char   *type;			/* for diagnostics */
     83     char   *name;			/* for diagnostics */
     84     int     flags;			/* see below */
     85     const char *(*lookup) (struct DICT *, const char *);
     86     int     (*update) (struct DICT *, const char *, const char *);
     87     int     (*delete) (struct DICT *, const char *);
     88     int     (*sequence) (struct DICT *, int, const char **, const char **);
     89     int     (*lock) (struct DICT *, int);
     90     void    (*close) (struct DICT *);
     91     int     lock_type;			/* for read/write lock */
     92     int     lock_fd;			/* for read/write lock */
     93     int     stat_fd;			/* change detection */
     94     time_t  mtime;			/* mod time at open */
     95     VSTRING *fold_buf;			/* key folding buffer */
     96     DICT_OWNER owner;			/* provenance */
     97     int     error;			/* last operation only */
     98     DICT_JMP_BUF *jbuf;			/* exception handling */
     99     struct DICT_UTF8_BACKUP *utf8_backup;	/* see below */
    100     struct VSTRING *file_buf;		/* dict_file_to_buf() */
    101     struct VSTRING *file_b64;		/* dict_file_to_b64() */
    102     char   *reg_name;			/* managed by dict_register() */
    103     void    (*saved_close) (struct DICT *);	/* managed by dict_register() */
    104 } DICT;
    105 
    106 extern DICT *dict_alloc(const char *, const char *, ssize_t);
    107 extern void dict_free(DICT *);
    108 
    109  /*
    110   * See dict_open.c embedded manpage for flag definitions.
    111   */
    112 #define DICT_FLAG_NONE		(0)
    113 #define DICT_FLAG_DUP_WARN	(1<<0)	/* warn about dups if not supported */
    114 #define DICT_FLAG_DUP_IGNORE	(1<<1)	/* ignore dups if not supported */
    115 #define DICT_FLAG_TRY0NULL	(1<<2)	/* do not append 0 to key/value */
    116 #define DICT_FLAG_TRY1NULL	(1<<3)	/* append 0 to key/value */
    117 #define DICT_FLAG_FIXED		(1<<4)	/* fixed key map */
    118 #define DICT_FLAG_PATTERN	(1<<5)	/* keys are patterns */
    119 #define DICT_FLAG_LOCK		(1<<6)	/* use temp lock before access */
    120 #define DICT_FLAG_DUP_REPLACE	(1<<7)	/* replace dups if supported */
    121 #define DICT_FLAG_SYNC_UPDATE	(1<<8)	/* sync updates if supported */
    122 /*#define DICT_FLAG_DEBUG	(1<<9)	/* log access */
    123 /*#define DICT_FLAG_FOLD_KEY	(1<<10)	/* lowercase the lookup key */
    124 #define DICT_FLAG_NO_REGSUB	(1<<11)	/* disallow regexp substitution */
    125 #define DICT_FLAG_NO_PROXY	(1<<12)	/* disallow proxy mapping */
    126 #define DICT_FLAG_NO_UNAUTH	(1<<13)	/* disallow unauthenticated data */
    127 #define DICT_FLAG_FOLD_FIX	(1<<14)	/* case-fold key with fixed-case map */
    128 #define DICT_FLAG_FOLD_MUL	(1<<15)	/* case-fold key with multi-case map */
    129 #define DICT_FLAG_FOLD_ANY	(DICT_FLAG_FOLD_FIX | DICT_FLAG_FOLD_MUL)
    130 #define DICT_FLAG_OPEN_LOCK	(1<<16)	/* perm lock if not multi-writer safe */
    131 #define DICT_FLAG_BULK_UPDATE	(1<<17)	/* optimize for bulk updates */
    132 #define DICT_FLAG_MULTI_WRITER	(1<<18)	/* multi-writer safe map */
    133 #define DICT_FLAG_UTF8_REQUEST	(1<<19)	/* activate UTF-8 if possible */
    134 #define DICT_FLAG_UTF8_ACTIVE	(1<<20)	/* UTF-8 proxy layer is present */
    135 #define DICT_FLAG_SRC_RHS_IS_FILE \
    136 				(1<<21)	/* Map source RHS is a file */
    137 #define DICT_FLAG_SURROGATE	(1<22)	/* This is a surrogate dictionary */
    138 
    139 #define DICT_FLAG_UTF8_MASK	(DICT_FLAG_UTF8_REQUEST)
    140 
    141  /* IMPORTANT: Update the dict_mask[] table when the above changes */
    142 
    143  /*
    144   * The subsets of flags that control how a map is used. These are relevant
    145   * mainly for proxymap support. Note: some categories overlap.
    146   *
    147   * DICT_FLAG_PARANOID - requestor flags that forbid the use of insecure map
    148   * types for security-sensitive operations. These flags are checked by the
    149   * map implementation itself upon open, lookup etc. requests.
    150   */
    151 #define DICT_FLAG_PARANOID \
    152 	(DICT_FLAG_NO_REGSUB | DICT_FLAG_NO_PROXY | DICT_FLAG_NO_UNAUTH)
    153 
    154  /*
    155   * Feature tests.
    156   */
    157 #define DICT_NEED_UTF8_ACTIVATION(enable, flags) \
    158 	((enable) && ((flags) & DICT_FLAG_UTF8_MASK))
    159 
    160  /*
    161   * dict->error values. Errors must be negative; smtpd_check depends on this.
    162   */
    163 #define DICT_ERR_NONE	0		/* no error */
    164 #define DICT_ERR_RETRY	(-1)		/* soft error */
    165 #define DICT_ERR_CONFIG	(-2)		/* configuration error */
    166 
    167  /*
    168   * Result values for exposed functions except lookup. FAIL/ERROR are
    169   * suggested values, not for use in comparisons for equality.
    170   */
    171 #define DICT_STAT_FAIL		1	/* any value > 0: notfound, conflict */
    172 #define DICT_STAT_SUCCESS	0	/* request satisfied */
    173 #define DICT_STAT_ERROR		(-1)	/* any value < 0: database error */
    174 
    175  /*
    176   * Set an error code and return a result value.
    177   */
    178 #define DICT_ERR_VAL_RETURN(dict, err, val) do { \
    179 	(dict)->error = (err); \
    180 	return (val); \
    181     } while (0)
    182 
    183  /*
    184   * Sequence function types.
    185   */
    186 #define DICT_SEQ_FUN_FIRST     0	/* set cursor to first record */
    187 #define DICT_SEQ_FUN_NEXT      1	/* set cursor to next record */
    188 
    189  /*
    190   * Interface for dictionary types.
    191   */
    192 extern ARGV *dict_mapnames(void);
    193 typedef void (*DICT_MAPNAMES_EXTEND_FN) (ARGV *);
    194 extern DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(DICT_MAPNAMES_EXTEND_FN);
    195 
    196 
    197  /*
    198   * High-level interface, with logical dictionary names.
    199   */
    200 extern void dict_register(const char *, DICT *);
    201 extern DICT *dict_handle(const char *);
    202 extern void dict_unregister(const char *);
    203 extern int dict_update(const char *, const char *, const char *);
    204 extern const char *dict_lookup(const char *, const char *);
    205 extern int dict_delete(const char *, const char *);
    206 extern int dict_sequence(const char *, const int, const char **, const char **);
    207 extern int dict_load_file_xt(const char *, const char *);
    208 extern void dict_load_fp(const char *, VSTREAM *);
    209 extern const char *dict_eval(const char *, const char *, int);
    210 extern int dict_error(const char *);
    211 
    212  /*
    213   * Low-level interface, with physical dictionary handles.
    214   */
    215 typedef DICT *(*DICT_OPEN_FN) (const char *, int, int);
    216 typedef struct {
    217     const char *type;
    218     DICT_OPEN_FN dict_fn;
    219     struct MKMAP *(*mkmap_fn) (const char *);
    220 } DICT_OPEN_INFO;
    221 typedef const DICT_OPEN_INFO *(*DICT_OPEN_EXTEND_FN) (const char *);
    222 extern DICT *dict_open(const char *, int, int);
    223 extern DICT *dict_open3(const char *, const char *, int, int);
    224 extern void dict_open_register(const DICT_OPEN_INFO *);
    225 extern void dict_open_unregister(const char *);
    226 extern const DICT_OPEN_INFO *dict_open_lookup(const char *);
    227 extern DICT_OPEN_EXTEND_FN dict_open_extend(DICT_OPEN_EXTEND_FN);
    228 
    229 #define dict_get(dp, key)	((const char *) (dp)->lookup((dp), (key)))
    230 #define dict_put(dp, key, val)	(dp)->update((dp), (key), (val))
    231 #define dict_del(dp, key)	(dp)->delete((dp), (key))
    232 #define dict_seq(dp, f, key, val) (dp)->sequence((dp), (f), (key), (val))
    233 #define dict_close(dp)		(dp)->close(dp)
    234 typedef void (*DICT_WALK_ACTION) (const char *, DICT *, void *);
    235 extern void dict_walk(DICT_WALK_ACTION, void *);
    236 extern int dict_changed(void);
    237 extern const char *dict_changed_name(void);
    238 extern const char *dict_flags_str(int);
    239 extern int dict_flags_mask(const char *);
    240 extern void dict_type_override(DICT *, const char *);
    241 
    242  /*
    243   * Check and convert UTF-8 keys and values.
    244   */
    245 typedef struct DICT_UTF8_BACKUP {
    246     const char *(*lookup) (struct DICT *, const char *);
    247     int     (*update) (struct DICT *, const char *, const char *);
    248     int     (*delete) (struct DICT *, const char *);
    249 } DICT_UTF8_BACKUP;
    250 
    251 extern DICT *dict_utf8_activate(DICT *);
    252 
    253  /*
    254   * Driver for interactive or scripted tests.
    255   */
    256 void    dict_test(int, char **);
    257 
    258  /*
    259   * Behind-the-scenes support to continue execution with reduced
    260   * functionality.
    261   */
    262 extern int dict_allow_surrogate;
    263 extern DICT *PRINTFLIKE(5, 6) dict_surrogate(const char *, const char *, int, int, const char *,...);
    264 
    265  /*
    266   * Support for consistent sharing and collision avoidance when tables are
    267   * registered with dict_register(). Only share instances that have the same
    268   * type, name, open_flags, and (initial) dict_flags.
    269   */
    270 extern char *dict_make_registered_name(VSTRING *, const char *, int, int);
    271 extern char *dict_make_registered_name4(VSTRING *, const char *, const char *, int, int);
    272 
    273  /*
    274   * This name is reserved for matchlist error handling.
    275   */
    276 #define DICT_TYPE_NOFILE	"non-existent"
    277 #define DICT_TYPE_NOUTF8	"non-UTF-8"
    278 
    279  /*
    280   * Duplicated from vstream(3). This should probably be abstracted out.
    281   *
    282   * Exception handling. We use pointer to jmp_buf to avoid a lot of unused
    283   * baggage for streams that don't need this functionality.
    284   *
    285   * XXX sigsetjmp()/siglongjmp() save and restore the signal mask which can
    286   * avoid surprises in code that manipulates signals, but unfortunately some
    287   * systems have bugs in their implementation.
    288   */
    289 #ifdef NO_SIGSETJMP
    290 #define dict_setjmp(dict)	setjmp((dict)->jbuf[0])
    291 #define dict_longjmp(dict, val)	longjmp((dict)->jbuf[0], (val))
    292 #else
    293 #define dict_setjmp(dict)	sigsetjmp((dict)->jbuf[0], 1)
    294 #define dict_longjmp(dict, val)	siglongjmp((dict)->jbuf[0], (val))
    295 #endif
    296 #define dict_isjmp(dict)	((dict)->jbuf != 0)
    297 
    298  /*
    299   * Temporary API. If exception handling proves to be useful,
    300   * dict_jmp_alloc() should be integrated into dict_alloc().
    301   */
    302 extern void dict_jmp_alloc(DICT *);
    303 
    304  /*
    305   * dict_file(3).
    306   */
    307 extern struct VSTRING *dict_file_to_buf(DICT *, const char *);
    308 extern struct VSTRING *dict_file_to_b64(DICT *, const char *);
    309 extern struct VSTRING *dict_file_from_b64(DICT *, const char *);
    310 extern char *dict_file_get_error(DICT *);
    311 extern void dict_file_purge_buffers(DICT *);
    312 extern const char *dict_file_lookup(DICT *dict, const char *);
    313 
    314  /*
    315   * dict_stream(3)
    316   */
    317 extern VSTREAM *dict_stream_open(const char *dict_type, const char *mapname,
    318            int open_flags, int dict_flags, struct stat * st, VSTRING **why);
    319 
    320 /* LICENSE
    321 /* .ad
    322 /* .fi
    323 /*	The Secure Mailer license must be distributed with this software.
    324 /* AUTHOR(S)
    325 /*	Wietse Venema
    326 /*	IBM T.J. Watson Research
    327 /*	P.O. Box 704
    328 /*	Yorktown Heights, NY 10598, USA
    329 /*
    330 /*	Wietse Venema
    331 /*	Google, Inc.
    332 /*	111 8th Avenue
    333 /*	New York, NY 10011, USA
    334 /*--*/
    335 
    336 #endif
    337