1 /*        $NetBSD: dict_ni.c,v 1.1.1.3 2014/07/06 19:27:58 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.  */
dict_ni_do_lookup(char * path,char * key_prop,const char * key_value,char * val_prop)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 = mymalloc(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     myfree(query);
144 
145     return return_val;
146 }
147 
148 /* dict_ni_lookup - find table entry */
149 
dict_ni_lookup(DICT * dict,const char * key)150 static const char *dict_ni_lookup(DICT *dict, const char *key)
151 {
152     DICT_NI *d = (DICT_NI *) dict;
153 
154     dict->error = 0;
155 
156     /*
157      * Optionally fold the key.
158      */
159     if (dict->flags & DICT_FLAG_FOLD_FIX) {
160           if (dict->fold_buf == 0)
161               dict->fold_buf = vstring_alloc(10);
162           vstring_strcpy(dict->fold_buf, key);
163           key = lowercase(vstring_str(dict->fold_buf));
164     }
165     return dict_ni_do_lookup(d->dict.name, NETINFO_PROP_KEY,
166                                    key, NETINFO_PROP_VALUE);
167 }
168 
169 /* dict_ni_close - disassociate from NetInfo map */
170 
dict_ni_close(DICT * dict)171 static void dict_ni_close(DICT *dict)
172 {
173     DICT_NI *d = (DICT_NI *) dict;
174 
175     if (dict->fold_buf)
176           vstring_free(dict->fold_buf);
177     dict_free(dict);
178 }
179 
180 /* dict_ni_open - create association with NetInfo map */
181 
dict_ni_open(const char * path,int unused_flags,int dict_flags)182 DICT   *dict_ni_open(const char *path, int unused_flags, int dict_flags)
183 {
184     DICT_NI *d = (void *) dict_alloc(DICT_TYPE_NETINFO, path, sizeof(*d));
185 
186     d->dict.lookup = dict_ni_lookup;
187     d->dict.close = dict_ni_close;
188     d->dict.flags = dict_flags | DICT_FLAG_FIXED;
189     if (dict_flags & DICT_FLAG_FOLD_FIX)
190           d->dict.fold_buf = vstring_alloc(10);
191     d->dict.owner.status = DICT_OWNER_TRUSTED;
192 
193     return (DICT_DEBUG (&d->dict));
194 }
195 
196 #endif
197