xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/dict_ni.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /*	$NetBSD: dict_ni.c,v 1.1.1.2 2013/01/02 18:59:12 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	dict_ni 3
6 /* SUMMARY
7 /*	dictionary manager interface to NetInfo
8 /* SYNOPSIS
9 /*	#include <dict_ni.h>
10 /*
11 /*	DICT	*dict_ni_open(path, dummy, dict_flags)
12 /*	char	*path;
13 /*	int	dummy;
14 /*	int	dict_flags;
15 /* DESCRIPTION
16 /*	dict_ni_open() `opens' the named NetInfo database. The result is
17 /*	a pointer to a structure that can be used to access the dictionary
18 /*	using the generic methods documented in dict_open(3).
19 /* DIAGNOSTICS
20 /*	dict_ni_register() returns 0 in case of success, -1 in case
21 /*	of problems.
22 /*	Fatal errors: NetInfo errors, out of memory.
23 /* SEE ALSO
24 /*	dict(3) generic dictionary manager
25 /*	netinfo(3N) data base subroutines
26 /* AUTHOR(S)
27 /*	Pieter Schoenmakers
28 /*	Eindhoven University of Technology
29 /*	P.O. Box 513
30 /*	5600 MB Eindhoven
31 /*	The Netherlands
32 /*--*/
33 
34 #include "sys_defs.h"
35 
36 #ifdef HAS_NETINFO
37 
38 /* System library. */
39 
40 #include <stdio.h>
41 #include <netinfo/ni.h>
42 
43 /* Utility library. */
44 
45 #include "dict.h"
46 #include "dict_ni.h"
47 #include "msg.h"
48 #include "mymalloc.h"
49 #include "stringops.h"
50 
51 typedef struct {
52     DICT    dict;			/* my super */
53     char   *path;			/* directory path */
54 } DICT_NI;
55 
56  /*
57   * We'd like other possibilities, but that is not possible in the current
58   * dictionary setup...  An example of a different setup: use `members' for
59   * multi-valued lookups (to be compatible with /aliases), and `value' for
60   * single-valued tables.
61   */
62 #define NETINFO_PROP_KEY	"name"
63 #define NETINFO_PROP_VALUE	"members"
64 #define NETINFO_VALUE_SEP	 ","
65 
66 #define NETINFO_MAX_DOMAIN_DEPTH	100
67 
68 /* Hard worker doing lookups.	Returned value is statically allocated and
69    reused each call.  */
70 static const char *dict_ni_do_lookup(char *path, char *key_prop,
71 			              const char *key_value, char *val_prop)
72 {
73     unsigned int result_cap = 0;
74     static char *result = 0;
75 
76     char   *return_val = 0;
77     ni_namelist values;
78     int     depth = 0;
79     void   *domain;
80     void   *next_domain;
81     char   *query;
82     ni_status r;
83     ni_id   dir;
84 
85     if (msg_verbose)
86 	msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
87 
88     r = ni_open(NULL, ".", &domain);
89     if (r != NI_OK) {
90 	msg_warn("ni_open `.': %d", r);
91 	return NULL;
92     }
93     query = alloca(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
94     sprintf(query, "%s/%s=%s", path, key_prop, key_value);
95 
96     for (;;) {
97 
98 	/*
99 	 * What does it _mean_ if we find the directory but not the value?
100 	 */
101 	if (ni_pathsearch(domain, &dir, query) == NI_OK
102 	    && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
103 	    if (values.ni_namelist_len <= 0)
104 		ni_namelist_free(&values);
105 	    else {
106 		unsigned int i, l, n;
107 
108 		for (i = l = 0; i < values.ni_namelist_len; i++)
109 		    l += 1 + strlen(values.ni_namelist_val[i]);
110 		if (result_cap < l) {
111 		    if (result)
112 			myfree(result);
113 		    result_cap = l + 100;
114 		    result = mymalloc(result_cap);
115 		}
116 		for (i = l = 0; i < values.ni_namelist_len; i++) {
117 		    n = strlen(values.ni_namelist_val[i]);
118 		    memcpy(result + l, values.ni_namelist_val[i], n);
119 		    l += n;
120 		    if (i < values.ni_namelist_len - 1)
121 			result[l++] = ',';
122 		}
123 		result[l] = '\0';
124 		return_val = result;
125 		break;
126 	    }
127 
128 	if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
129 	    msg_warn("ni_open: domain depth limit");
130 	    break;
131 	}
132 	r = ni_open(domain, "..", &next_domain);
133 	if (r != NI_OK) {
134 	    if (r != NI_FAILED)
135 		msg_warn("ni_open `..': %d", r);
136 	    break;
137 	}
138 	ni_free(domain);
139 	domain = next_domain;
140     }
141 
142     ni_free(domain);
143 
144     return return_val;
145 }
146 
147 /* dict_ni_lookup - find table entry */
148 
149 static const char *dict_ni_lookup(DICT *dict, const char *key)
150 {
151     DICT_NI *d = (DICT_NI *) dict;
152 
153     dict->error = 0;
154 
155     /*
156      * Optionally fold the key.
157      */
158     if (dict->flags & DICT_FLAG_FOLD_FIX) {
159 	if (dict->fold_buf == 0)
160 	    dict->fold_buf = vstring_alloc(10);
161 	vstring_strcpy(dict->fold_buf, key);
162 	key = lowercase(vstring_str(dict->fold_buf));
163     }
164     return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
165 			     key, NETINFO_PROP_VALUE);
166 }
167 
168 /* dict_ni_close - disassociate from NetInfo map */
169 
170 static void dict_ni_close(DICT *dict)
171 {
172     DICT_NI *d = (DICT_NI *) dict;
173 
174     if (dict->fold_buf)
175 	vstring_free(dict->fold_buf);
176     dict_free(dict);
177 }
178 
179 /* dict_ni_open - create association with NetInfo map */
180 
181 DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
182 {
183     DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
184 
185     d->dict.lookup = dict_ni_lookup;
186     d->dict.close = dict_ni_close;
187     d->dict.flags = dict_flags | DICT_FLAG_FIXED;
188     if (dict_flags & DICT_FLAG_FOLD_FIX)
189 	d->dict.fold_buf = vstring_alloc(10);
190     d->dict.owner.status = DICT_OWNER_TRUSTED;
191 
192     return (DICT_DEBUG (&d->dict));
193 }
194 
195 #endif
196