s3/utils: Use sddl_decode_err_msg instead of sddl_decode
[samba.git] / source3 / utils / regedit_valuelist.c
1 /*
2  * Samba Unix/Linux SMB client library
3  * Registry Editor
4  * Copyright (C) Christopher Davis 2012
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "regedit.h"
22 #include "regedit_valuelist.h"
23 #include "regedit_list.h"
24 #include "lib/registry/registry.h"
25
26 #define HEADING_X 3
27
28 static int value_list_free(struct value_list *vl)
29 {
30         if (vl->panel) {
31                 del_panel(vl->panel);
32         }
33         if (vl->sub) {
34                 delwin(vl->sub);
35         }
36         if (vl->window) {
37                 delwin(vl->window);
38         }
39
40         return 0;
41 }
42
43 static const char *vl_get_column_header(const void *data, unsigned col)
44 {
45         switch (col) {
46         case 0:
47                 return "Name";
48         case 1:
49                 return "Type";
50         case 2:
51                 return "Data";
52         }
53
54         return "???";
55 }
56
57 static const void *vl_get_first_row(const void *data)
58 {
59         const struct value_list *vl;
60
61         if (data) {
62                 vl = talloc_get_type_abort(data, struct value_list);
63                 if (vl->nvalues) {
64                         return &vl->values[0];
65                 }
66         }
67
68         return NULL;
69 }
70
71 static const void *vl_get_next_row(const void *data, const void *row)
72 {
73         const struct value_list *vl;
74         const struct value_item *value = row;
75
76         SMB_ASSERT(data != NULL);
77         SMB_ASSERT(value != NULL);
78         vl = talloc_get_type_abort(data, struct value_list);
79         if (value == &vl->values[vl->nvalues - 1]) {
80                 return NULL;
81         }
82
83         return value + 1;
84 }
85
86 static const void *vl_get_prev_row(const void *data, const void *row)
87 {
88         const struct value_list *vl;
89         const struct value_item *value = row;
90
91         SMB_ASSERT(data != NULL);
92         SMB_ASSERT(value != NULL);
93         vl = talloc_get_type_abort(data, struct value_list);
94         if (value == &vl->values[0]) {
95                 return NULL;
96         }
97
98         return value - 1;
99 }
100
101 static const char *vl_get_item_label(const void *row, unsigned col)
102 {
103         const struct value_item *value = row;
104
105         SMB_ASSERT(value != NULL);
106         SMB_ASSERT(value->value_name != NULL);
107         switch (col) {
108         case 0:
109                 return value->value_name;
110         case 1:
111                 return str_regtype(value->type);
112         case 2:
113                 if (value->value) {
114                         return value->value;
115                 }
116                 return "";
117         }
118
119         return "???";
120 }
121
122 static struct multilist_accessors vl_accessors = {
123         .get_column_header = vl_get_column_header,
124         .get_first_row = vl_get_first_row,
125         .get_next_row = vl_get_next_row,
126         .get_prev_row = vl_get_prev_row,
127         .get_item_label = vl_get_item_label
128 };
129
130 struct value_list *value_list_new(TALLOC_CTX *ctx, int nlines, int ncols,
131                                   int begin_y, int begin_x)
132 {
133         struct value_list *vl;
134
135         vl = talloc_zero(ctx, struct value_list);
136         if (vl == NULL) {
137                 return NULL;
138         }
139
140         talloc_set_destructor(vl, value_list_free);
141
142         vl->window = newwin(nlines, ncols, begin_y, begin_x);
143         if (vl->window == NULL) {
144                 goto fail;
145         }
146         vl->sub = subwin(vl->window, nlines - 2, ncols - 2,
147                          begin_y + 1, begin_x + 1);
148         if (vl->sub == NULL) {
149                 goto fail;
150         }
151         box(vl->window, 0, 0);
152         mvwprintw(vl->window, 0, HEADING_X, "Value");
153
154         vl->panel = new_panel(vl->window);
155         if (vl->panel == NULL) {
156                 goto fail;
157         }
158
159         vl->list = multilist_new(vl, vl->sub, &vl_accessors, 3);
160         if (vl->list == NULL) {
161                 goto fail;
162         }
163
164         return vl;
165
166 fail:
167         talloc_free(vl);
168
169         return NULL;
170 }
171
172 void value_list_set_selected(struct value_list *vl, bool reverse)
173 {
174         attr_t attr = A_NORMAL;
175
176         if (reverse) {
177                 attr = A_REVERSE;
178         }
179         mvwchgat(vl->window, 0, HEADING_X, 5, attr, 0, NULL);
180 }
181
182 void value_list_resize(struct value_list *vl, int nlines, int ncols,
183                        int begin_y, int begin_x)
184 {
185         WINDOW *nwin, *nsub;
186
187         nwin = newwin(nlines, ncols, begin_y, begin_x);
188         if (nwin == NULL) {
189                 return;
190         }
191         nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1);
192         if (nsub == NULL) {
193                 delwin(nwin);
194                 return;
195         }
196         replace_panel(vl->panel, nwin);
197         delwin(vl->sub);
198         delwin(vl->window);
199         vl->window = nwin;
200         vl->sub = nsub;
201         box(vl->window, 0, 0);
202         mvwprintw(vl->window, 0, HEADING_X, "Value");
203         multilist_set_window(vl->list, vl->sub);
204         value_list_show(vl);
205 }
206
207 static uint32_t get_num_values(TALLOC_CTX *ctx, const struct registry_key *key)
208 {
209         const char *classname;
210         uint32_t num_subkeys;
211         uint32_t num_values;
212         NTTIME last_change_time;
213         uint32_t max_subkeynamelen;
214         uint32_t max_valnamelen;
215         uint32_t max_valbufsize;
216         WERROR rv;
217
218         rv = reg_key_get_info(ctx, key, &classname, &num_subkeys,
219                               &num_values, &last_change_time,
220                               &max_subkeynamelen, &max_valnamelen,
221                               &max_valbufsize);
222
223         if (W_ERROR_IS_OK(rv)) {
224                 return num_values;
225         }
226
227         return 0;
228 }
229
230 void value_list_show(struct value_list *vl)
231 {
232         multilist_refresh(vl->list);
233         touchwin(vl->window);
234         wnoutrefresh(vl->window);
235         wnoutrefresh(vl->sub);
236 }
237
238 static bool string_is_printable(const char *s)
239 {
240         const char *p;
241
242         for (p = s; *p; ++p) {
243                 if (!isprint(*p)) {
244                         return false;
245                 }
246         }
247
248         return true;
249 }
250
251 static WERROR append_data_summary(TALLOC_CTX *ctx, struct value_item *vitem)
252 {
253         char *tmp = NULL;
254
255 /* This is adapted from print_registry_value() in net_registry_util.c */
256
257         switch(vitem->type) {
258         case REG_DWORD: {
259                 uint32_t v = 0;
260                 if (vitem->data.length >= 4) {
261                         v = IVAL(vitem->data.data, 0);
262                 }
263                 tmp = talloc_asprintf(ctx, "0x%08x (%u)", v, v);
264                 break;
265         }
266         case REG_SZ:
267         case REG_EXPAND_SZ: {
268                 const char *s;
269
270                 if (!pull_reg_sz(ctx, &vitem->data, &s)) {
271                         break;
272                 }
273                 vitem->unprintable = !string_is_printable(s);
274                 if (vitem->unprintable) {
275                         tmp = talloc_asprintf(ctx, "(unprintable)");
276                 } else {
277                         tmp = talloc_asprintf(ctx, "%s", s);
278                 }
279                 break;
280         }
281         case REG_MULTI_SZ: {
282                 size_t i, len;
283                 const char **a;
284                 const char *val;
285
286                 if (!pull_reg_multi_sz(ctx, &vitem->data, &a)) {
287                         break;
288                 }
289                 for (len = 0; a[len] != NULL; ++len) {
290                 }
291                 tmp = talloc_asprintf(ctx, "(%u) ", (unsigned)len);
292                 if (tmp == NULL) {
293                         return WERR_NOT_ENOUGH_MEMORY;
294                 }
295                 for (i = 0; i < len; ++i) {
296                         if (!string_is_printable(a[i])) {
297                                 val = "(unprintable)";
298                                 vitem->unprintable = true;
299                         } else {
300                                 val = a[i];
301                         }
302                         if (i == len - 1) {
303                                 tmp = talloc_asprintf_append(tmp,
304                                                              "[%u]=\"%s\"",
305                                                              (unsigned)i, val);
306                         } else {
307                                 tmp = talloc_asprintf_append(tmp,
308                                                              "[%u]=\"%s\", ",
309                                                              (unsigned)i, val);
310                         }
311                         if (tmp == NULL) {
312                                 return WERR_NOT_ENOUGH_MEMORY;
313                         }
314                 }
315                 break;
316         }
317         case REG_BINARY:
318                 tmp = talloc_asprintf(ctx, "(%d bytes)",
319                                       (int)vitem->data.length);
320                 break;
321         default:
322                 tmp = talloc_asprintf(ctx, "(unknown)");
323                 break;
324         }
325
326         if (tmp == NULL) {
327                 return WERR_NOT_ENOUGH_MEMORY;
328         }
329
330         vitem->value = tmp;
331
332         return WERR_OK;
333 }
334
335 static int vitem_cmp(struct value_item *a, struct value_item *b)
336 {
337         return strcmp(a->value_name, b->value_name);
338 }
339
340 /* load only the value names into memory to enable searching */
341 WERROR value_list_load_quick(struct value_list *vl, struct registry_key *key)
342 {
343         uint32_t nvalues;
344         uint32_t idx;
345         struct value_item *vitem, *new_items;
346         WERROR rv;
347
348         multilist_set_data(vl->list, NULL);
349         vl->nvalues = 0;
350         TALLOC_FREE(vl->values);
351
352         nvalues = get_num_values(vl, key);
353         if (nvalues == 0) {
354                 return WERR_OK;
355         }
356
357         new_items = talloc_zero_array(vl, struct value_item, nvalues);
358         if (new_items == NULL) {
359                 return WERR_NOT_ENOUGH_MEMORY;
360         }
361
362         for (idx = 0; idx < nvalues; ++idx) {
363                 vitem = &new_items[idx];
364                 rv = reg_key_get_value_by_index(new_items, key, idx,
365                                                 &vitem->value_name,
366                                                 &vitem->type,
367                                                 &vitem->data);
368                 if (!W_ERROR_IS_OK(rv)) {
369                         talloc_free(new_items);
370                         return rv;
371                 }
372         }
373
374         TYPESAFE_QSORT(new_items, nvalues, vitem_cmp);
375         vl->nvalues = nvalues;
376         vl->values = new_items;
377
378         return rv;
379 }
380
381 /* sync up the UI with the list */
382 WERROR value_list_sync(struct value_list *vl)
383 {
384         uint32_t idx;
385         WERROR rv;
386
387         for (idx = 0; idx < vl->nvalues; ++idx) {
388                 rv = append_data_summary(vl->values, &vl->values[idx]);
389                 if (!W_ERROR_IS_OK(rv)) {
390                         return rv;
391                 }
392         }
393
394         rv = multilist_set_data(vl->list, vl);
395         if (W_ERROR_IS_OK(rv)) {
396                 multilist_refresh(vl->list);
397         }
398
399         return rv;
400 }
401
402 WERROR value_list_load(struct value_list *vl, struct registry_key *key)
403 {
404         WERROR rv;
405
406         rv = value_list_load_quick(vl, key);
407         if (!W_ERROR_IS_OK(rv)) {
408                 return rv;
409         }
410
411         rv = value_list_sync(vl);
412
413         return rv;
414 }
415
416 struct value_item *value_list_find_next_item(struct value_list *vl,
417                                              struct value_item *vitem,
418                                              const char *s,
419                                              regedit_search_match_fn_t match)
420 {
421         struct value_item *end;
422
423         if (!vl->values) {
424                 return NULL;
425         }
426
427         if (vitem) {
428                 ++vitem;
429         } else {
430                 vitem = &vl->values[0];
431         }
432
433         for (end = &vl->values[vl->nvalues]; vitem < end; ++vitem) {
434                 if (match(vitem->value_name, s)) {
435                         return vitem;
436                 }
437         }
438
439         return NULL;
440 }
441
442 struct value_item *value_list_find_prev_item(struct value_list *vl,
443                                              struct value_item *vitem,
444                                              const char *s,
445                                              regedit_search_match_fn_t match)
446 {
447         struct value_item *end;
448
449         if (!vl->values) {
450                 return NULL;
451         }
452
453         if (vitem) {
454                 --vitem;
455         } else {
456                 vitem = &vl->values[vl->nvalues - 1];
457         }
458
459         for (end = &vl->values[-1]; vitem > end; --vitem) {
460                 if (match(vitem->value_name, s)) {
461                         return vitem;
462                 }
463         }
464
465         return NULL;
466 }
467
468 struct value_item *value_list_get_current_item(struct value_list *vl)
469 {
470         return discard_const_p(struct value_item,
471                                multilist_get_current_row(vl->list));
472 }
473
474 void value_list_set_current_item_by_name(struct value_list *vl,
475                                          const char *name)
476 {
477         size_t i;
478
479         for (i = 0; i < vl->nvalues; ++i) {
480                 if (strequal(vl->values[i].value_name, name)) {
481                         multilist_set_current_row(vl->list, &vl->values[i]);
482                         return;
483                 }
484         }
485 }
486
487 void value_list_set_current_item(struct value_list *vl,
488                                  const struct value_item *item)
489 {
490         multilist_set_current_row(vl->list, item);
491 }
492
493 void value_list_driver(struct value_list *vl, int c)
494 {
495         multilist_driver(vl->list, c);
496 }