DICT * dict_erlang_open(const char *key, int open_flags, int dict_flags) { DICT_ERLANG *dict_erlang; if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_ERLANG, key); erl_init(NULL, 0); dict_erlang = (DICT_ERLANG *)dict_alloc(DICT_TYPE_ERLANG, key, sizeof(DICT_ERLANG)); dict_erlang->dict.lookup = dict_erlang_lookup; dict_erlang->dict.close = dict_erlang_close; dict_erlang->dict.flags = dict_flags; erlang_parse_config(dict_erlang, key); if (dict_erlang->nodes->argc == 0) msg_fatal("no erlang nodes specified"); dict_erlang->active_node = 0; if (dict_erlang->cookie == NULL) msg_fatal("no erlang cookie specified"); if (dict_erlang->mod == NULL) msg_fatal("no erlang module specified"); if (dict_erlang->fun == NULL) msg_fatal("no erlang function specified"); return (DICT_DEBUG(&dict_erlang->dict)); }
DICT *dict_tcp_open(const char *map, int open_flags, int dict_flags) { DICT_TCP *dict_tcp; dict_errno = 0; /* * Sanity checks. */ if (dict_flags & DICT_FLAG_NO_UNAUTH) msg_fatal("%s:%s map is not allowed for security sensitive data", DICT_TYPE_TCP, map); if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_TCP, map); /* * Create the dictionary handle. Do not open the connection until the * first request is made. */ dict_tcp = (DICT_TCP *) dict_alloc(DICT_TYPE_TCP, map, sizeof(*dict_tcp)); dict_tcp->fp = 0; dict_tcp->raw_buf = dict_tcp->hex_buf = 0; dict_tcp->dict.lookup = dict_tcp_lookup; dict_tcp->dict.close = dict_tcp_close; dict_tcp->dict.flags = dict_flags | DICT_FLAG_PATTERN; if (dict_flags & DICT_FLAG_FOLD_MUL) dict_tcp->dict.fold_buf = vstring_alloc(10); return (DICT_DEBUG (&dict_tcp->dict)); }
DICT *dict_pgsql_open(const char *name, int open_flags, int dict_flags) { DICT_PGSQL *dict_pgsql; CFG_PARSER *parser; /* * Sanity check. */ if (open_flags != O_RDONLY) return (dict_surrogate(DICT_TYPE_PGSQL, name, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_PGSQL, name)); /* * Open the configuration file. */ if ((parser = cfg_parser_alloc(name)) == 0) return (dict_surrogate(DICT_TYPE_PGSQL, name, open_flags, dict_flags, "open %s: %m", name)); dict_pgsql = (DICT_PGSQL *) dict_alloc(DICT_TYPE_PGSQL, name, sizeof(DICT_PGSQL)); dict_pgsql->dict.lookup = dict_pgsql_lookup; dict_pgsql->dict.close = dict_pgsql_close; dict_pgsql->dict.flags = dict_flags; dict_pgsql->parser = parser; pgsql_parse_config(dict_pgsql, name); dict_pgsql->active_host = 0; dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts); if (dict_pgsql->pldb == NULL) msg_fatal("couldn't intialize pldb!\n"); dict_pgsql->dict.owner = cfg_get_owner(dict_pgsql->parser); return (DICT_DEBUG (&dict_pgsql->dict)); }
DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags) { DICT_CIDR *dict_cidr; VSTREAM *map_fp; VSTRING *line_buffer = vstring_alloc(100); VSTRING *why = vstring_alloc(100); DICT_CIDR_ENTRY *rule; DICT_CIDR_ENTRY *last_rule = 0; int lineno = 0; /* * Sanity checks. */ if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_CIDR, mapname); /* * XXX Eliminate unnecessary queries by setting a flag that says "this * map matches network addresses only". */ dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname, sizeof(*dict_cidr)); dict_cidr->dict.lookup = dict_cidr_lookup; dict_cidr->dict.close = dict_cidr_close; dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_cidr->head = 0; if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0) msg_fatal("open %s: %m", mapname); while (readlline(line_buffer, map_fp, &lineno)) { rule = dict_cidr_parse_rule(vstring_str(line_buffer), why); if (rule == 0) { msg_warn("cidr map %s, line %d: %s: skipping this rule", mapname, lineno, vstring_str(why)); continue; } if (last_rule == 0) dict_cidr->head = rule; else last_rule->cidr_info.next = &(rule->cidr_info); last_rule = rule; } /* * Clean up. */ if (vstream_fclose(map_fp)) msg_fatal("cidr map %s: read error: %m", mapname); vstring_free(line_buffer); vstring_free(why); return (DICT_DEBUG (&dict_cidr->dict)); }
DICT *dict_static_open(const char *name, int unused_flags, int dict_flags) { DICT *dict; dict = dict_alloc(DICT_TYPE_STATIC, name, sizeof(*dict)); dict->lookup = dict_static_lookup; dict->close = dict_static_close; dict->flags = dict_flags | DICT_FLAG_FIXED; dict->owner.status = DICT_OWNER_TRUSTED; return (DICT_DEBUG (dict)); }
DICT *dict_random_open(const char *name, int open_flags, int dict_flags) { DICT_RANDOM *dict_random; char *saved_name = 0; size_t len; /* * Clarity first. Let the optimizer worry about redundant code. */ #define DICT_RANDOM_RETURN(x) do { \ if (saved_name != 0) \ myfree(saved_name); \ return (x); \ } while (0) /* * Sanity checks. */ if (open_flags != O_RDONLY) DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_RANDOM, name)); /* * Split the name name into its constituent parts. */ if ((len = balpar(name, "{}")) == 0 || name[len] != 0 || *(saved_name = mystrndup(name + 1, len - 2)) == 0) DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, open_flags, dict_flags, "bad syntax: \"%s:%s\"; " "need \"%s:{type:name...}\"", DICT_TYPE_RANDOM, name, DICT_TYPE_RANDOM)); /* * Bundle up the result. */ dict_random = (DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random)); dict_random->dict.lookup = dict_random_lookup; dict_random->dict.close = dict_random_close; dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_random->replies = argv_splitq(saved_name, ", \t\r\n", "{}"); dict_random->dict.owner.status = DICT_OWNER_TRUSTED; dict_random->dict.owner.uid = 0; DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict)); }
DICT *dict_env_open(const char *name, int unused_flags, int dict_flags) { DICT *dict; dict = dict_alloc(DICT_TYPE_ENVIRON, name, sizeof(*dict)); dict->lookup = dict_env_lookup; dict->update = dict_env_update; dict->close = dict_env_close; dict->flags = dict_flags | DICT_FLAG_FIXED; if (dict_flags & DICT_FLAG_FOLD_FIX) dict->fold_buf = vstring_alloc(10); dict->owner.status = DICT_OWNER_TRUSTED; return (DICT_DEBUG (dict)); }
DICT *dict_nis_open(const char *map, int open_flags, int dict_flags) { DICT_NIS *dict_nis; if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_NIS, map); dict_nis = (DICT_NIS *) dict_alloc(DICT_TYPE_NIS, map, sizeof(*dict_nis)); dict_nis->dict.lookup = dict_nis_lookup; dict_nis->dict.close = dict_nis_close; dict_nis->dict.flags = dict_flags | DICT_FLAG_FIXED; if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0) dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL); if (dict_flags & DICT_FLAG_FOLD_FIX) dict_nis->dict.fold_buf = vstring_alloc(10); if (dict_nis_domain == 0) dict_nis_init(); return (DICT_DEBUG (&dict_nis->dict)); }
/********************************************************************** * public interface dict_mysql_open * create association with database with appropriate values * parse the map's config file * allocate memory **********************************************************************/ DICT *dict_mysql_open(const char *name, int open_flags, int dict_flags) { DICT_MYSQL *dict_mysql; /* * Sanity checks. */ if (open_flags != O_RDONLY) msg_fatal("%s:%s map requires O_RDONLY access mode", DICT_TYPE_MYSQL, name); dict_mysql = (DICT_MYSQL *) dict_alloc(DICT_TYPE_MYSQL, name, sizeof(DICT_MYSQL)); dict_mysql->dict.lookup = dict_mysql_lookup; dict_mysql->dict.close = dict_mysql_close; dict_mysql->dict.flags = dict_flags | DICT_FLAG_FIXED; dict_mysql->name = mysqlname_parse(name); dict_mysql->pldb = plmysql_init(dict_mysql->name->hostnames, dict_mysql->name->len_hosts); if (dict_mysql->pldb == NULL) msg_fatal("couldn't intialize pldb!\n"); return (DICT_DEBUG (&dict_mysql->dict)); }
DICT *dict_sqlite_open(const char *name, int open_flags, int dict_flags) { DICT_SQLITE *dict_sqlite; CFG_PARSER *parser; /* * Sanity checks. */ if (open_flags != O_RDONLY) return (dict_surrogate(DICT_TYPE_SQLITE, name, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_SQLITE, name)); /* * Open the configuration file. */ if ((parser = cfg_parser_alloc(name)) == 0) return (dict_surrogate(DICT_TYPE_SQLITE, name, open_flags, dict_flags, "open %s: %m", name)); dict_sqlite = (DICT_SQLITE *) dict_alloc(DICT_TYPE_SQLITE, name, sizeof(DICT_SQLITE)); dict_sqlite->dict.lookup = dict_sqlite_lookup; dict_sqlite->dict.close = dict_sqlite_close; dict_sqlite->dict.flags = dict_flags; dict_sqlite->parser = parser; sqlite_parse_config(dict_sqlite, name); if (sqlite3_open(dict_sqlite->dbpath, &dict_sqlite->db)) msg_fatal("%s:%s: Can't open database: %s\n", DICT_TYPE_SQLITE, name, sqlite3_errmsg(dict_sqlite->db)); dict_sqlite->dict.owner = cfg_get_owner(dict_sqlite->parser); return (DICT_DEBUG (&dict_sqlite->dict)); }
DICT *dict_thash_open(const char *path, int open_flags, int dict_flags) { DICT_THASH *dict_thash; VSTREAM *fp = 0; struct stat st; time_t before; time_t after; VSTRING *line_buffer = 0; int lineno; char *key; char *value; HTABLE *table; HTABLE_INFO *ht; /* * Let the optimizer worry about eliminating redundant code. */ #define DICT_THASH_OPEN_RETURN(d) { \ DICT *__d = (d); \ if (fp != 0) \ vstream_fclose(fp); \ if (line_buffer != 0) \ vstring_free(line_buffer); \ return (__d); \ } while (0) /* * Sanity checks. */ if (open_flags != O_RDONLY) DICT_THASH_OPEN_RETURN(dict_surrogate(DICT_TYPE_THASH, path, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_THASH, path)); /* * Read the flat text file into in-memory hash. Read the file again if it * may have changed while we were reading. */ for (before = time((time_t *) 0); /* see below */ ; before = after) { if ((fp = vstream_fopen(path, open_flags, 0644)) == 0) { DICT_THASH_OPEN_RETURN(dict_surrogate(DICT_TYPE_THASH, path, open_flags, dict_flags, "open database %s: %m", path)); } if (line_buffer == 0) line_buffer = vstring_alloc(100); lineno = 0; table = htable_create(13); while (readlline(line_buffer, fp, &lineno)) { /* * Split on the first whitespace character, then trim leading and * trailing whitespace from key and value. */ key = STR(line_buffer); value = key + strcspn(key, " \t\r\n"); if (*value) *value++ = 0; while (ISSPACE(*value)) value++; trimblanks(key, 0)[0] = 0; trimblanks(value, 0)[0] = 0; /* * Enforce the "key whitespace value" format. Disallow missing * keys or missing values. */ if (*key == 0 || *value == 0) { msg_warn("%s, line %d: expected format: key whitespace value" " -- ignoring this line", path, lineno); continue; } if (key[strlen(key) - 1] == ':') msg_warn("%s, line %d: record is in \"key: value\" format;" " is this an alias file?", path, lineno); /* * Optionally fold the key. */ if (dict_flags & DICT_FLAG_FOLD_FIX) lowercase(key); /* * Store the value under the key. Handle duplicates * appropriately. */ if ((ht = htable_locate(table, key)) != 0) { if (dict_flags & DICT_FLAG_DUP_IGNORE) { /* void */ ; } else if (dict_flags & DICT_FLAG_DUP_REPLACE) { myfree(ht->value); ht->value = mystrdup(value); } else if (dict_flags & DICT_FLAG_DUP_WARN) { msg_warn("%s, line %d: duplicate entry: \"%s\"", path, lineno, key); } else { msg_fatal("%s, line %d: duplicate entry: \"%s\"", path, lineno, key); } } else { htable_enter(table, key, mystrdup(value)); } } /* * See if the source file is hot. */ if (fstat(vstream_fileno(fp), &st) < 0) msg_fatal("fstat %s: %m", path); if (vstream_fclose(fp)) msg_fatal("read %s: %m", path); fp = 0; /* DICT_THASH_OPEN_RETURN() */ after = time((time_t *) 0); if (st.st_mtime < before - 1 || st.st_mtime > after) break; /* * Yes, it is hot. Discard the result and read the file again. */ htable_free(table, myfree); if (msg_verbose > 1) msg_info("pausing to let file %s cool down", path); doze(300000); } /* * Create the in-memory table. */ dict_thash = (DICT_THASH *) dict_alloc(DICT_TYPE_THASH, path, sizeof(*dict_thash)); dict_thash->dict.lookup = dict_thash_lookup; dict_thash->dict.sequence = dict_thash_sequence; dict_thash->dict.close = dict_thash_close; dict_thash->dict.flags = dict_flags | DICT_FLAG_DUP_WARN | DICT_FLAG_FIXED; if (dict_flags & DICT_FLAG_FOLD_FIX) dict_thash->dict.fold_buf = vstring_alloc(10); dict_thash->info = 0; dict_thash->table = table; dict_thash->dict.owner.uid = st.st_uid; dict_thash->dict.owner.status = (st.st_uid != 0); DICT_THASH_OPEN_RETURN(DICT_DEBUG (&dict_thash->dict)); }
DICT *dict_sockmap_open(const char *mapname, int open_flags, int dict_flags) { DICT_SOCKMAP *dp; char *saved_name = 0; char *sockmap; DICT_SOCKMAP_REFC_HANDLE *ref_handle; HTABLE_INFO *client_info; /* * Let the optimizer worry about eliminating redundant code. */ #define DICT_SOCKMAP_OPEN_RETURN(d) { \ DICT *__d = (d); \ if (saved_name != 0) \ myfree(saved_name); \ return (__d); \ } while (0) /* * Sanity checks. */ if (open_flags != O_RDONLY) DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_SOCKMAP, mapname)); if (dict_flags & DICT_FLAG_NO_UNAUTH) DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname, open_flags, dict_flags, "%s:%s map is not allowed for security-sensitive data", DICT_TYPE_SOCKMAP, mapname)); /* * Separate the socketmap name from the socketmap server name. */ saved_name = mystrdup(mapname); if ((sockmap = split_at_right(saved_name, ':')) == 0) DICT_SOCKMAP_OPEN_RETURN(dict_surrogate(DICT_TYPE_SOCKMAP, mapname, open_flags, dict_flags, "%s requires server:socketmap argument", DICT_TYPE_SOCKMAP)); /* * Use one reference-counted client handle for all socketmaps with the * same inet:host:port or unix:pathname information. * * XXX Todo: graceful degradation after endpoint syntax error. */ if (dict_sockmap_handles == 0) dict_sockmap_handles = htable_create(1); if ((client_info = htable_locate(dict_sockmap_handles, saved_name)) == 0) { ref_handle = (DICT_SOCKMAP_REFC_HANDLE *) mymalloc(sizeof(*ref_handle)); client_info = htable_enter(dict_sockmap_handles, saved_name, (char *) ref_handle); /* XXX Late initialization, so we can reuse macros for consistency. */ DICT_SOCKMAP_RH_REFCOUNT(client_info) = 1; DICT_SOCKMAP_RH_HANDLE(client_info) = auto_clnt_create(saved_name, dict_sockmap_timeout, dict_sockmap_max_idle, dict_sockmap_max_ttl); } else DICT_SOCKMAP_RH_REFCOUNT(client_info) += 1; /* * Instantiate a socket map handle. */ dp = (DICT_SOCKMAP *) dict_alloc(DICT_TYPE_SOCKMAP, mapname, sizeof(*dp)); dp->rdwr_buf = vstring_alloc(100); dp->sockmap_name = mystrdup(sockmap); dp->client_info = client_info; dp->dict.lookup = dict_sockmap_lookup; dp->dict.close = dict_sockmap_close; /* Don't look up parent domains or network superblocks. */ dp->dict.flags = dict_flags | DICT_FLAG_PATTERN; DICT_SOCKMAP_OPEN_RETURN(DICT_DEBUG (&dp->dict)); }
DICT *dict_pcre_open(const char *mapname, int open_flags, int dict_flags) { DICT_PCRE *dict_pcre; VSTREAM *map_fp; struct stat st; VSTRING *line_buffer; DICT_PCRE_RULE *last_rule = 0; DICT_PCRE_RULE *rule; int lineno = 0; int nesting = 0; char *p; /* * Sanity checks. */ if (open_flags != O_RDONLY) return (dict_surrogate(DICT_TYPE_PCRE, mapname, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_PCRE, mapname)); /* * Open the configuration file. */ if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0) return (dict_surrogate(DICT_TYPE_PCRE, mapname, open_flags, dict_flags, "open %s: %m", mapname)); if (fstat(vstream_fileno(map_fp), &st) < 0) msg_fatal("fstat %s: %m", mapname); line_buffer = vstring_alloc(100); dict_pcre = (DICT_PCRE *) dict_alloc(DICT_TYPE_PCRE, mapname, sizeof(*dict_pcre)); dict_pcre->dict.lookup = dict_pcre_lookup; dict_pcre->dict.close = dict_pcre_close; dict_pcre->dict.flags = dict_flags | DICT_FLAG_PATTERN; if (dict_flags & DICT_FLAG_FOLD_MUL) dict_pcre->dict.fold_buf = vstring_alloc(10); dict_pcre->head = 0; dict_pcre->expansion_buf = 0; if (dict_pcre_init == 0) { pcre_malloc = (void *(*) (size_t)) mymalloc; pcre_free = (void (*) (void *)) myfree; dict_pcre_init = 1; } dict_pcre->dict.owner.uid = st.st_uid; dict_pcre->dict.owner.status = (st.st_uid != 0); /* * Parse the pcre table. */ while (readlline(line_buffer, map_fp, &lineno)) { p = vstring_str(line_buffer); trimblanks(p, 0)[0] = 0; /* Trim space at end */ if (*p == 0) continue; rule = dict_pcre_parse_rule(mapname, lineno, p, nesting, dict_flags); if (rule == 0) continue; if (rule->op == DICT_PCRE_OP_IF) { nesting++; } else if (rule->op == DICT_PCRE_OP_ENDIF) { nesting--; } if (last_rule == 0) dict_pcre->head = rule; else last_rule->next = rule; last_rule = rule; } if (nesting) msg_warn("pcre map %s, line %d: more IFs than ENDIFs", mapname, lineno); vstring_free(line_buffer); vstream_fclose(map_fp); return (DICT_DEBUG (&dict_pcre->dict)); }
DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) { char *myname = "dict_ldap_open"; DICT_LDAP *dict_ldap; VSTRING *url_list; char *s; char *h; char *server_host; char *domainlist; char *scope; char *attr; int tmp; if (msg_verbose) msg_info("%s: Using LDAP source %s", myname, ldapsource); dict_ldap = (DICT_LDAP *) dict_alloc(DICT_TYPE_LDAP, ldapsource, sizeof(*dict_ldap)); dict_ldap->dict.lookup = dict_ldap_lookup; dict_ldap->dict.close = dict_ldap_close; dict_ldap->dict.flags = dict_flags | DICT_FLAG_FIXED; dict_ldap->ld = NULL; dict_ldap->parser = cfg_parser_alloc(ldapsource); dict_ldap->ldapsource = mystrdup(ldapsource); server_host = cfg_get_str(dict_ldap->parser, "server_host", "localhost", 1, 0); /* * get configured value of "server_port"; default to LDAP_PORT (389) */ dict_ldap->server_port = cfg_get_int(dict_ldap->parser, "server_port", LDAP_PORT, 0, 0); /* * Define LDAP Version. */ dict_ldap->version = cfg_get_int(dict_ldap->parser, "version", 2, 2, 0); switch (dict_ldap->version) { case 2: dict_ldap->version = LDAP_VERSION2; break; case 3: dict_ldap->version = LDAP_VERSION3; break; default: msg_warn("%s: %s Unknown version %d.", myname, ldapsource, dict_ldap->version); dict_ldap->version = LDAP_VERSION2; } #if defined(LDAP_API_FEATURE_X_OPENLDAP) dict_ldap->ldap_ssl = 0; #endif url_list = vstring_alloc(32); s = server_host; while ((h = mystrtok(&s, " \t\n\r,")) != NULL) { #if defined(LDAP_API_FEATURE_X_OPENLDAP) /* * Convert (host, port) pairs to LDAP URLs */ if (ldap_is_ldap_url(h)) { LDAPURLDesc *url_desc; int rc; if ((rc = ldap_url_parse(h, &url_desc)) != 0) { msg_error("%s: error parsing URL %s: %d: %s; skipping", myname, h, rc, ldap_err2string(rc)); continue; } if (strcasecmp(url_desc->lud_scheme, "ldap") != 0 && dict_ldap->version != LDAP_VERSION3) { msg_warn("%s: URL scheme %s requires protocol version 3", myname, url_desc->lud_scheme); dict_ldap->version = LDAP_VERSION3; } if (strcasecmp(url_desc->lud_scheme, "ldaps") == 0) dict_ldap->ldap_ssl = 1; ldap_free_urldesc(url_desc); vstring_sprintf_append(url_list, " %s", h); } else { if (strrchr(h, ':')) vstring_sprintf_append(url_list, " ldap://%s", h); else vstring_sprintf_append(url_list, " ldap://%s:%d", h, dict_ldap->server_port); } #else vstring_sprintf_append(url_list, " %s", h); #endif } dict_ldap->server_host = mystrdup(VSTRING_LEN(url_list) > 0 ? vstring_str(url_list) + 1 : ""); #if defined(LDAP_API_FEATURE_X_OPENLDAP) /* * With URL scheme, clear port to normalize connection cache key */ dict_ldap->server_port = LDAP_PORT; if (msg_verbose) msg_info("%s: %s server_host URL is %s", myname, ldapsource, dict_ldap->server_host); #endif myfree(server_host); vstring_free(url_list); /* * Scope handling thanks to Carsten Hoeger of SuSE. */ scope = cfg_get_str(dict_ldap->parser, "scope", "sub", 1, 0); if (strcasecmp(scope, "one") == 0) { dict_ldap->scope = LDAP_SCOPE_ONELEVEL; } else if (strcasecmp(scope, "base") == 0) { dict_ldap->scope = LDAP_SCOPE_BASE; } else if (strcasecmp(scope, "sub") == 0) { dict_ldap->scope = LDAP_SCOPE_SUBTREE; } else { msg_warn("%s: %s: Unrecognized value %s specified for scope; using sub", myname, ldapsource, scope); dict_ldap->scope = LDAP_SCOPE_SUBTREE; } myfree(scope); dict_ldap->search_base = cfg_get_str(dict_ldap->parser, "search_base", "", 0, 0); domainlist = cfg_get_str(dict_ldap->parser, "domain", "", 0, 0); if (*domainlist) { #ifdef MATCH_FLAG_NONE dict_ldap->domain = match_list_init(MATCH_FLAG_NONE, domainlist, 1, match_string); #else dict_ldap->domain = match_list_init(domainlist, 1, match_string); #endif if (dict_ldap->domain == NULL) msg_warn("%s: domain match list creation using \"%s\" failed, will continue without it", myname, domainlist); if (msg_verbose) msg_info("%s: domain list created using \"%s\"", myname, domainlist); } else { dict_ldap->domain = NULL; } myfree(domainlist); /* * get configured value of "timeout"; default to 10 seconds * * Thanks to Manuel Guesdon for spotting that this wasn't really getting * set. */ dict_ldap->timeout = cfg_get_int(dict_ldap->parser, "timeout", 10, 0, 0); dict_ldap->query_filter = cfg_get_str(dict_ldap->parser, "query_filter", "(mailacceptinggeneralid=%s)", 0, 0); dict_ldap->result_filter = cfg_get_str(dict_ldap->parser, "result_filter", "%s", 0, 0); if (strcmp(dict_ldap->result_filter, "%s") == 0) { myfree(dict_ldap->result_filter); dict_ldap->result_filter = NULL; } attr = cfg_get_str(dict_ldap->parser, "result_attribute", "maildrop", 0, 0); dict_ldap->result_attributes = argv_split(attr, " ,\t\r\n"); dict_ldap->num_attributes = dict_ldap->result_attributes->argc; myfree(attr); attr = cfg_get_str(dict_ldap->parser, "special_result_attribute", "", 0, 0); if (*attr) { argv_split_append(dict_ldap->result_attributes, attr, " ,\t\r\n"); } myfree(attr); /* * get configured value of "bind"; default to true */ dict_ldap->bind = cfg_get_bool(dict_ldap->parser, "bind", 1); /* * get configured value of "bind_dn"; default to "" */ dict_ldap->bind_dn = cfg_get_str(dict_ldap->parser, "bind_dn", "", 0, 0); /* * get configured value of "bind_pw"; default to "" */ dict_ldap->bind_pw = cfg_get_str(dict_ldap->parser, "bind_pw", "", 0, 0); /* * get configured value of "cache"; default to false */ tmp = cfg_get_bool(dict_ldap->parser, "cache", 0); if (tmp) msg_warn("%s: %s ignoring cache", myname, ldapsource); /* * get configured value of "cache_expiry"; default to 30 seconds */ tmp = cfg_get_int(dict_ldap->parser, "cache_expiry", -1, 0, 0); if (tmp >= 0) msg_warn("%s: %s ignoring cache_expiry", myname, ldapsource); /* * get configured value of "cache_size"; default to 32k */ tmp = cfg_get_int(dict_ldap->parser, "cache_size", -1, 0, 0); if (tmp >= 0) msg_warn("%s: %s ignoring cache_size", myname, ldapsource); /* * get configured value of "recursion_limit"; default to 1000 */ dict_ldap->recursion_limit = cfg_get_int(dict_ldap->parser, "recursion_limit", 1000, 1, 0); /* * get configured value of "expansion_limit"; default to 0 */ dict_ldap->expansion_limit = cfg_get_int(dict_ldap->parser, "expansion_limit", 0, 0, 0); /* * get configured value of "size_limit"; default to expansion_limit */ dict_ldap->size_limit = cfg_get_int(dict_ldap->parser, "size_limit", dict_ldap->expansion_limit, 0, 0); /* * Alias dereferencing suggested by Mike Mattice. */ dict_ldap->dereference = cfg_get_int(dict_ldap->parser, "dereference", 0, 0, 0); if (dict_ldap->dereference < 0 || dict_ldap->dereference > 3) { msg_warn("%s: %s Unrecognized value %d specified for dereference; using 0", myname, ldapsource, dict_ldap->dereference); dict_ldap->dereference = 0; } /* Referral chasing */ dict_ldap->chase_referrals = cfg_get_bool(dict_ldap->parser, "chase_referrals", 0); #ifdef LDAP_API_FEATURE_X_OPENLDAP /* * TLS options */ /* get configured value of "start_tls"; default to no */ dict_ldap->start_tls = cfg_get_bool(dict_ldap->parser, "start_tls", 0); if (dict_ldap->start_tls && dict_ldap->version < LDAP_VERSION3) { msg_warn("%s: %s start_tls requires protocol version 3", myname, ldapsource); dict_ldap->version = LDAP_VERSION3; } /* get configured value of "tls_require_cert"; default to no */ dict_ldap->tls_require_cert = cfg_get_bool(dict_ldap->parser, "tls_require_cert", 0); /* get configured value of "tls_ca_cert_file"; default "" */ dict_ldap->tls_ca_cert_file = cfg_get_str(dict_ldap->parser, "tls_ca_cert_file", "", 0, 0); /* get configured value of "tls_ca_cert_dir"; default "" */ dict_ldap->tls_ca_cert_dir = cfg_get_str(dict_ldap->parser, "tls_ca_cert_dir", "", 0, 0); /* get configured value of "tls_cert"; default "" */ dict_ldap->tls_cert = cfg_get_str(dict_ldap->parser, "tls_cert", "", 0, 0); /* get configured value of "tls_key"; default "" */ dict_ldap->tls_key = cfg_get_str(dict_ldap->parser, "tls_key", "", 0, 0); /* get configured value of "tls_random_file"; default "" */ dict_ldap->tls_random_file = cfg_get_str(dict_ldap->parser, "tls_random_file", "", 0, 0); /* get configured value of "tls_cipher_suite"; default "" */ dict_ldap->tls_cipher_suite = cfg_get_str(dict_ldap->parser, "tls_cipher_suite", "", 0, 0); #endif /* * Debug level. */ #if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN) dict_ldap->debuglevel = cfg_get_int(dict_ldap->parser, "debuglevel", 0, 0, 0); #endif /* * Find or allocate shared LDAP connection container. */ dict_ldap_conn_find(dict_ldap); /* * Return the new dict_ldap structure. */ return (DICT_DEBUG (&dict_ldap->dict)); }
DICT *dict_union_open(const char *name, int open_flags, int dict_flags) { static const char myname[] = "dict_union_open"; DICT_UNION *dict_union; char *saved_name = 0; char *dict_type_name; ARGV *argv = 0; char **cpp; DICT *dict; int match_flags = 0; struct DICT_OWNER aggr_owner; size_t len; /* * Clarity first. Let the optimizer worry about redundant code. */ #define DICT_UNION_RETURN(x) do { \ if (saved_name != 0) \ myfree(saved_name); \ if (argv != 0) \ argv_free(argv); \ return (x); \ } while (0) /* * Sanity checks. */ if (open_flags != O_RDONLY) DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_UNION, name)); /* * Split the table name into its constituent parts. */ if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0 || *(saved_name = mystrndup(name + 1, len - 2)) == 0 || ((argv = argv_splitq(saved_name, CHARS_COMMA_SP, CHARS_BRACE)), (argv->argc == 0))) DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name, open_flags, dict_flags, "bad syntax: \"%s:%s\"; " "need \"%s:{type:name...}\"", DICT_TYPE_UNION, name, DICT_TYPE_UNION)); /* * The least-trusted table in the set determines the over-all trust * level. The first table determines the pattern-matching flags. */ DICT_OWNER_AGGREGATE_INIT(aggr_owner); for (cpp = argv->argv; (dict_type_name = *cpp) != 0; cpp++) { if (msg_verbose) msg_info("%s: %s", myname, dict_type_name); if (strchr(dict_type_name, ':') == 0) DICT_UNION_RETURN(dict_surrogate(DICT_TYPE_UNION, name, open_flags, dict_flags, "bad syntax: \"%s:%s\"; " "need \"%s:{type:name...}\"", DICT_TYPE_UNION, name, DICT_TYPE_UNION)); if ((dict = dict_handle(dict_type_name)) == 0) dict = dict_open(dict_type_name, open_flags, dict_flags); dict_register(dict_type_name, dict); DICT_OWNER_AGGREGATE_UPDATE(aggr_owner, dict->owner); if (cpp == argv->argv) match_flags = dict->flags & (DICT_FLAG_FIXED | DICT_FLAG_PATTERN); } /* * Bundle up the result. */ dict_union = (DICT_UNION *) dict_alloc(DICT_TYPE_UNION, name, sizeof(*dict_union)); dict_union->dict.lookup = dict_union_lookup; dict_union->dict.close = dict_union_close; dict_union->dict.flags = dict_flags | match_flags; dict_union->dict.owner = aggr_owner; dict_union->re_buf = vstring_alloc(100); dict_union->map_union = argv; argv = 0; DICT_UNION_RETURN(DICT_DEBUG (&dict_union->dict)); }
DICT *dict_cidr_open(const char *mapname, int open_flags, int dict_flags) { const char myname[] = "dict_cidr_open"; DICT_CIDR *dict_cidr; VSTREAM *map_fp = 0; struct stat st; VSTRING *line_buffer = 0; VSTRING *why = 0; DICT_CIDR_ENTRY *rule; DICT_CIDR_ENTRY *last_rule = 0; int last_line = 0; int lineno; int nesting = 0; DICT_CIDR_ENTRY **rule_stack = 0; MVECT mvect; /* * Let the optimizer worry about eliminating redundant code. */ #define DICT_CIDR_OPEN_RETURN(d) do { \ DICT *__d = (d); \ if (map_fp != 0 && vstream_fclose(map_fp)) \ msg_fatal("cidr map %s: read error: %m", mapname); \ if (line_buffer != 0) \ vstring_free(line_buffer); \ if (why != 0) \ vstring_free(why); \ return (__d); \ } while (0) /* * Sanity checks. */ if (open_flags != O_RDONLY) DICT_CIDR_OPEN_RETURN(dict_surrogate(DICT_TYPE_CIDR, mapname, open_flags, dict_flags, "%s:%s map requires O_RDONLY access mode", DICT_TYPE_CIDR, mapname)); /* * Open the configuration file. */ if ((map_fp = vstream_fopen(mapname, O_RDONLY, 0)) == 0) DICT_CIDR_OPEN_RETURN(dict_surrogate(DICT_TYPE_CIDR, mapname, open_flags, dict_flags, "open %s: %m", mapname)); if (fstat(vstream_fileno(map_fp), &st) < 0) msg_fatal("fstat %s: %m", mapname); line_buffer = vstring_alloc(100); why = vstring_alloc(100); /* * XXX Eliminate unnecessary queries by setting a flag that says "this * map matches network addresses only". */ dict_cidr = (DICT_CIDR *) dict_alloc(DICT_TYPE_CIDR, mapname, sizeof(*dict_cidr)); dict_cidr->dict.lookup = dict_cidr_lookup; dict_cidr->dict.close = dict_cidr_close; dict_cidr->dict.flags = dict_flags | DICT_FLAG_PATTERN; dict_cidr->head = 0; dict_cidr->dict.owner.uid = st.st_uid; dict_cidr->dict.owner.status = (st.st_uid != 0); while (readllines(line_buffer, map_fp, &last_line, &lineno)) { rule = dict_cidr_parse_rule(vstring_str(line_buffer), lineno, nesting, why); if (rule == 0) { msg_warn("cidr map %s, line %d: %s: skipping this rule", mapname, lineno, vstring_str(why)); continue; } if (rule->cidr_info.op == CIDR_MATCH_OP_IF) { if (rule_stack == 0) rule_stack = (DICT_CIDR_ENTRY **) mvect_alloc(&mvect, sizeof(*rule_stack), nesting + 1, (MVECT_FN) 0, (MVECT_FN) 0); else rule_stack = (DICT_CIDR_ENTRY **) mvect_realloc(&mvect, nesting + 1); rule_stack[nesting] = rule; nesting++; } else if (rule->cidr_info.op == CIDR_MATCH_OP_ENDIF) { DICT_CIDR_ENTRY *if_rule; if (nesting-- <= 0) /* Already handled in dict_cidr_parse_rule(). */ msg_panic("%s: ENDIF without IF", myname); if_rule = rule_stack[nesting]; if (if_rule->cidr_info.op != CIDR_MATCH_OP_IF) msg_panic("%s: unexpected rule stack element type %d", myname, if_rule->cidr_info.op); if_rule->cidr_info.block_end = &(rule->cidr_info); } if (last_rule == 0) dict_cidr->head = rule; else last_rule->cidr_info.next = &(rule->cidr_info); last_rule = rule; } while (nesting-- > 0) msg_warn("cidr map %s, line %d: IF has no matching ENDIF", mapname, rule_stack[nesting]->lineno); if (rule_stack) (void) mvect_free(&mvect); DICT_CIDR_OPEN_RETURN(DICT_DEBUG (&dict_cidr->dict)); }