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 "regedit_treeview.h"
21 #include "regedit_list.h"
22 #include "lib/registry/registry.h"
23 
24 #define HEADING_X 3
25 
tree_node_free(struct tree_node * node)26 static int tree_node_free(struct tree_node *node)
27 {
28 	DEBUG(9, ("tree_node_free('%s', %p)\n", node->name, node));
29 	return 0;
30 }
31 
tree_node_new(TALLOC_CTX * ctx,struct tree_node * parent,const char * name,struct registry_key * key)32 struct tree_node *tree_node_new(TALLOC_CTX *ctx, struct tree_node *parent,
33 				const char *name, struct registry_key *key)
34 {
35 	struct tree_node *node;
36 
37 	node = talloc_zero(ctx, struct tree_node);
38 	if (!node) {
39 		return NULL;
40 	}
41 	talloc_set_destructor(node, tree_node_free);
42 	DEBUG(9, ("tree_node_new('%s', %p)\n", name, node));
43 
44 	node->name = talloc_strdup(node, name);
45 	if (!node->name) {
46 		talloc_free(node);
47 		return NULL;
48 	}
49 
50 	if (key) {
51 		node->key = talloc_steal(node, key);
52 	}
53 
54 	if (parent) {
55 		/* Check if this node is the first descendant of parent. */
56 		if (!parent->child_head) {
57 			parent->child_head = node;
58 		}
59 		node->parent = parent;
60 	}
61 
62 	return node;
63 }
64 
65 /* prepare a root node with all available hives as children */
tree_node_new_root(TALLOC_CTX * ctx,struct registry_context * regctx)66 struct tree_node *tree_node_new_root(TALLOC_CTX *ctx,
67 				     struct registry_context *regctx)
68 {
69 	const char *hives[] = {
70 		"HKEY_CLASSES_ROOT",
71 		"HKEY_CURRENT_USER",
72 		"HKEY_LOCAL_MACHINE",
73 		"HKEY_PERFORMANCE_DATA",
74 		"HKEY_USERS",
75 		"HKEY_CURRENT_CONFIG",
76 		"HKEY_DYN_DATA",
77 		"HKEY_PERFORMANCE_TEXT",
78 		"HKEY_PERFORMANCE_NLSTEXT",
79 		NULL
80 	};
81 	struct tree_node *root, *prev, *node;
82 	struct registry_key *key;
83 	WERROR rv;
84 	size_t i;
85 
86 	root = tree_node_new(ctx, NULL, "ROOT", NULL);
87 	if (root == NULL) {
88 		return NULL;
89 	}
90 	prev = NULL;
91 
92 	for (i = 0; hives[i] != NULL; ++i) {
93 		rv = reg_get_predefined_key_by_name(regctx, hives[i], &key);
94 		if (!W_ERROR_IS_OK(rv)) {
95 			continue;
96 		}
97 
98 		node = tree_node_new(root, root, hives[i], key);
99 		if (node == NULL) {
100 			return NULL;
101 		}
102 		if (prev) {
103 			tree_node_append(prev, node);
104 		}
105 		prev = node;
106 	}
107 
108 	return root;
109 }
110 
tree_node_append(struct tree_node * left,struct tree_node * right)111 void tree_node_append(struct tree_node *left, struct tree_node *right)
112 {
113 	if (left->next) {
114 		right->next = left->next;
115 		left->next->previous = right;
116 	}
117 	left->next = right;
118 	right->previous = left;
119 }
120 
tree_node_append_last(struct tree_node * list,struct tree_node * node)121 void tree_node_append_last(struct tree_node *list, struct tree_node *node)
122 {
123 	tree_node_append(tree_node_last(list), node);
124 }
125 
tree_node_pop(struct tree_node ** plist)126 struct tree_node *tree_node_pop(struct tree_node **plist)
127 {
128 	struct tree_node *node;
129 
130 	node = *plist;
131 
132 	if (node == NULL)
133 		return NULL;
134 
135 	*plist = node->previous;
136 	if (*plist == NULL) {
137 		*plist = node->next;
138 	}
139 	if (node->previous) {
140 		node->previous->next = node->next;
141 	}
142 	if (node->next) {
143 		node->next->previous = node->previous;
144 	}
145 	if (node->parent && node->parent->child_head == node) {
146 		node->parent->child_head = node->next;
147 	}
148 	node->next = NULL;
149 	node->previous = NULL;
150 
151 	return node;
152 }
153 
tree_node_first(struct tree_node * list)154 struct tree_node *tree_node_first(struct tree_node *list)
155 {
156 	/* Grab the first node in this list from the parent if available. */
157 	if (list->parent) {
158 		return list->parent->child_head;
159 	}
160 
161 	while (list && list->previous) {
162 		list = list->previous;
163 	}
164 
165 	return list;
166 }
167 
tree_node_last(struct tree_node * list)168 struct tree_node *tree_node_last(struct tree_node *list)
169 {
170 	while (list && list->next) {
171 		list = list->next;
172 	}
173 
174 	return list;
175 }
176 
get_num_subkeys(struct tree_node * node)177 static uint32_t get_num_subkeys(struct tree_node *node)
178 {
179 	const char *classname;
180 	uint32_t num_subkeys;
181 	uint32_t num_values;
182 	NTTIME last_change_time;
183 	uint32_t max_subkeynamelen;
184 	uint32_t max_valnamelen;
185 	uint32_t max_valbufsize;
186 	WERROR rv;
187 
188 	rv = reg_key_get_info(node, node->key, &classname, &num_subkeys,
189 			      &num_values, &last_change_time,
190 			      &max_subkeynamelen, &max_valnamelen,
191 			      &max_valbufsize);
192 
193 	if (W_ERROR_IS_OK(rv)) {
194 		return num_subkeys;
195 	}
196 
197 	return 0;
198 }
199 
tree_node_reopen_key(struct registry_context * ctx,struct tree_node * node)200 WERROR tree_node_reopen_key(struct registry_context *ctx,
201 			    struct tree_node *node)
202 {
203 	SMB_ASSERT(node->parent != NULL);
204 	SMB_ASSERT(node->name != NULL);
205 	TALLOC_FREE(node->key);
206 
207 	if (tree_node_is_top_level(node)) {
208 		WERROR rv;
209 		struct registry_key *key;
210 		rv = reg_get_predefined_key_by_name(ctx, node->name, &key);
211 		if (W_ERROR_IS_OK(rv)) {
212 			node->key = talloc_steal(node, key);
213 		}
214 		return rv;
215 	}
216 
217 	return reg_open_key(node, node->parent->key, node->name, &node->key);
218 }
219 
tree_node_has_children(struct tree_node * node)220 bool tree_node_has_children(struct tree_node *node)
221 {
222 	if (node->child_head) {
223 		return true;
224 	}
225 
226 	return get_num_subkeys(node) > 0;
227 }
228 
node_cmp(struct tree_node ** a,struct tree_node ** b)229 static int node_cmp(struct tree_node **a, struct tree_node **b)
230 {
231 	return strcmp((*a)->name, (*b)->name);
232 }
233 
tree_node_insert_sorted(struct tree_node * list,struct tree_node * node)234 void tree_node_insert_sorted(struct tree_node *list, struct tree_node *node)
235 {
236 	list = tree_node_first(list);
237 
238 	if (node_cmp(&list, &node) >= 0) {
239 		tree_node_append(node, list);
240 		if (list->parent) {
241 			list->parent->child_head = node;
242 		}
243 		return;
244 	}
245 
246 	while (list->next && node_cmp(&list->next, &node) < 0) {
247 		list = list->next;
248 	}
249 
250 	tree_node_append(list, node);
251 }
252 
tree_node_load_children(struct tree_node * node)253 WERROR tree_node_load_children(struct tree_node *node)
254 {
255 	struct registry_key *key;
256 	const char *reg_key_name, *klass;
257 	NTTIME modified;
258 	uint32_t i, nsubkeys, count;
259 	WERROR rv;
260 	struct tree_node *prev, **array;
261 
262 	/* does this node already have it's children loaded? */
263 	if (node->child_head)
264 		return WERR_OK;
265 
266 	nsubkeys = get_num_subkeys(node);
267 	if (nsubkeys == 0)
268 		return WERR_OK;
269 
270 	array = talloc_zero_array(node, struct tree_node *, nsubkeys);
271 	if (array == NULL) {
272 		return WERR_NOT_ENOUGH_MEMORY;
273 	}
274 
275 	for (count = 0, i = 0; i < nsubkeys; ++i) {
276 		rv = reg_key_get_subkey_by_index(node, node->key, i,
277 						 &reg_key_name, &klass,
278 						 &modified);
279 		if (!W_ERROR_IS_OK(rv)) {
280 			goto finish;
281 		}
282 
283 		rv = reg_open_key(node, node->key, reg_key_name, &key);
284 		if (!W_ERROR_IS_OK(rv)) {
285 			continue;
286 		}
287 
288 		array[count] = tree_node_new(array, node, reg_key_name, key);
289 		if (array[count] == NULL) {
290 			rv = WERR_NOT_ENOUGH_MEMORY;
291 			goto finish;
292 		}
293 		++count;
294 	}
295 
296 	if (count) {
297 		TYPESAFE_QSORT(array, count, node_cmp);
298 
299 		for (i = 1, prev = array[0]; i < count; ++i) {
300 			talloc_steal(node, array[i]);
301 			tree_node_append(prev, array[i]);
302 			prev = array[i];
303 		}
304 		node->child_head = talloc_steal(node, array[0]);
305 
306 		rv = WERR_OK;
307 	}
308 
309 finish:
310 	talloc_free(array);
311 
312 	return rv;
313 }
314 
next_depth_first(struct tree_node ** node)315 static WERROR next_depth_first(struct tree_node **node)
316 {
317 	WERROR rv = WERR_OK;
318 
319 	SMB_ASSERT(node != NULL && *node != NULL);
320 
321 	if (tree_node_has_children(*node)) {
322 		/* 1. If the node has children, go to the first one. */
323 		rv = tree_node_load_children(*node);
324 		if (W_ERROR_IS_OK(rv)) {
325 			SMB_ASSERT((*node)->child_head != NULL);
326 			*node = (*node)->child_head;
327 		}
328 	} else if ((*node)->next) {
329 		/* 2. If there's a node directly after this one, go there */
330 		*node = (*node)->next;
331 	} else {
332 		/* 3. Otherwise, go up the hierarchy to find the next one */
333 		do {
334 			*node = (*node)->parent;
335 			if (*node && (*node)->next) {
336 				*node = (*node)->next;
337 				break;
338 			}
339 		} while (*node);
340 	}
341 
342 	return rv;
343 }
344 
prev_depth_first(struct tree_node ** node)345 static WERROR prev_depth_first(struct tree_node **node)
346 {
347 	WERROR rv = WERR_OK;
348 
349 	SMB_ASSERT(node != NULL && *node != NULL);
350 
351 	if ((*node)->previous) {
352 		*node = (*node)->previous;
353 		while (tree_node_has_children(*node)) {
354 			rv = tree_node_load_children(*node);
355 			if (W_ERROR_IS_OK(rv)) {
356 				SMB_ASSERT((*node)->child_head != NULL);
357 				*node = tree_node_last((*node)->child_head);
358 			}
359 		}
360 	} else if (!tree_node_is_top_level(*node)) {
361 		*node = (*node)->parent;
362 	} else {
363 		*node = NULL;
364 	}
365 
366 	return rv;
367 }
368 
tree_node_next(struct tree_node ** node,bool depth,WERROR * err)369 bool tree_node_next(struct tree_node **node, bool depth, WERROR *err)
370 {
371 	*err = WERR_OK;
372 
373 	if (*node == NULL) {
374 		return false;
375 	}
376 
377 	if (depth) {
378 		*err = next_depth_first(node);
379 	} else {
380 		*node = (*node)->next;
381 	}
382 
383 	return *node != NULL && W_ERROR_IS_OK(*err);
384 }
385 
tree_node_prev(struct tree_node ** node,bool depth,WERROR * err)386 bool tree_node_prev(struct tree_node **node, bool depth, WERROR *err)
387 {
388 	*err = WERR_OK;
389 
390 	if (*node == NULL) {
391 		return false;
392 	}
393 
394 	if (depth) {
395 		*err = prev_depth_first(node);
396 	} else {
397 		*node = (*node)->previous;
398 	}
399 
400 	return *node != NULL && W_ERROR_IS_OK(*err);
401 }
402 
tree_view_clear(struct tree_view * view)403 void tree_view_clear(struct tree_view *view)
404 {
405 	multilist_set_data(view->list, NULL);
406 }
407 
tree_view_set_root(struct tree_view * view,struct tree_node * root)408 WERROR tree_view_set_root(struct tree_view *view, struct tree_node *root)
409 {
410 	multilist_set_data(view->list, NULL);
411 	talloc_free(view->root);
412 	view->root = root;
413 	return tree_view_update(view, root->child_head);
414 }
415 
tree_view_set_path(struct tree_view * view,const char ** path)416 WERROR tree_view_set_path(struct tree_view *view, const char **path)
417 {
418 	struct tree_node *top, *node;
419 	WERROR rv;
420 
421 	top = view->root->child_head;
422 	while (*path) {
423 		for (node = top; node != NULL; node = node->next) {
424 			if (strcmp(*path, node->name) == 0) {
425 				if (path[1] && tree_node_has_children(node)) {
426 					rv = tree_node_load_children(node);
427 					if (!W_ERROR_IS_OK(rv)) {
428 						return rv;
429 					}
430 					SMB_ASSERT(node->child_head);
431 					top = node->child_head;
432 					break;
433 				} else {
434 					tree_view_update(view, top);
435 					tree_view_set_current_node(view, node);
436 					return WERR_OK;
437 				}
438 			}
439 		}
440 		++path;
441 	}
442 
443 	return WERR_OK;
444 }
445 
tree_view_update(struct tree_view * view,struct tree_node * list)446 WERROR tree_view_update(struct tree_view *view, struct tree_node *list)
447 {
448 	WERROR rv;
449 
450 	rv = multilist_set_data(view->list, list);
451 	if (W_ERROR_IS_OK(rv)) {
452 		multilist_refresh(view->list);
453 	}
454 
455 	return rv;
456 }
457 
458 /* is this node in the current level? */
tree_view_is_node_visible(struct tree_view * view,struct tree_node * node)459 bool tree_view_is_node_visible(struct tree_view *view, struct tree_node *node)
460 {
461 	const struct tree_node *first;
462 
463 	first = multilist_get_data(view->list);
464 
465 	return first && first->parent == node->parent;
466 }
467 
tree_view_set_current_node(struct tree_view * view,struct tree_node * node)468 void tree_view_set_current_node(struct tree_view *view, struct tree_node *node)
469 {
470 	multilist_set_current_row(view->list, node);
471 }
472 
tree_view_get_current_node(struct tree_view * view)473 struct tree_node *tree_view_get_current_node(struct tree_view *view)
474 {
475 	const void *row = multilist_get_current_row(view->list);
476 	return talloc_get_type_abort(row, struct tree_node);
477 }
478 
tree_view_driver(struct tree_view * view,int c)479 void tree_view_driver(struct tree_view *view, int c)
480 {
481 	multilist_driver(view->list, c);
482 }
483 
tree_view_set_selected(struct tree_view * view,bool reverse)484 void tree_view_set_selected(struct tree_view *view, bool reverse)
485 {
486 	attr_t attr = A_NORMAL;
487 
488 	if (reverse) {
489 		attr = A_REVERSE;
490 	}
491 	mvwchgat(view->window, 0, HEADING_X, 3, attr, 0, NULL);
492 }
493 
tree_view_show(struct tree_view * view)494 void tree_view_show(struct tree_view *view)
495 {
496 	multilist_refresh(view->list);
497 	touchwin(view->window);
498 	wnoutrefresh(view->window);
499 	wnoutrefresh(view->sub);
500 }
501 
tree_view_free(struct tree_view * view)502 static int tree_view_free(struct tree_view *view)
503 {
504 	if (view->panel) {
505 		del_panel(view->panel);
506 	}
507 	if (view->sub) {
508 		delwin(view->sub);
509 	}
510 	if (view->window) {
511 		delwin(view->window);
512 	}
513 
514 	return 0;
515 }
516 
tv_get_column_header(const void * data,unsigned col)517 static const char *tv_get_column_header(const void *data, unsigned col)
518 {
519 	SMB_ASSERT(col == 0);
520 	return "Name";
521 }
522 
tv_get_first_row(const void * data)523 static const void *tv_get_first_row(const void *data)
524 {
525 	if (data == NULL) {
526 		return NULL;
527 	}
528 
529 	return talloc_get_type_abort(data, struct tree_node);
530 }
531 
tv_get_next_row(const void * data,const void * row)532 static const void *tv_get_next_row(const void *data, const void *row)
533 {
534 	const struct tree_node *node;
535 	SMB_ASSERT(row != NULL);
536 	node = talloc_get_type_abort(row, struct tree_node);
537 	return node->next;
538 }
539 
tv_get_prev_row(const void * data,const void * row)540 static const void *tv_get_prev_row(const void *data, const void *row)
541 {
542 	const struct tree_node *node;
543 	SMB_ASSERT(row != NULL);
544 	node = talloc_get_type_abort(row, struct tree_node);
545 	return node->previous;
546 }
547 
tv_get_item_prefix(const void * row,unsigned col)548 static const char *tv_get_item_prefix(const void *row, unsigned col)
549 {
550 	struct tree_node *node;
551 
552 	SMB_ASSERT(col == 0);
553 	SMB_ASSERT(row != NULL);
554 	node = talloc_get_type_abort(row, struct tree_node);
555 	if (tree_node_has_children(node)) {
556 		return "+";
557 	}
558 	return " ";
559 }
560 
tv_get_item_label(const void * row,unsigned col)561 static const char *tv_get_item_label(const void *row, unsigned col)
562 {
563 	const struct tree_node *node;
564 	SMB_ASSERT(col == 0);
565 	SMB_ASSERT(row != NULL);
566 	node = talloc_get_type_abort(row, struct tree_node);
567 	return node->name;
568 }
569 
570 static struct multilist_accessors tv_accessors = {
571 	.get_column_header = tv_get_column_header,
572 	.get_first_row = tv_get_first_row,
573 	.get_next_row = tv_get_next_row,
574 	.get_prev_row = tv_get_prev_row,
575 	.get_item_prefix = tv_get_item_prefix,
576 	.get_item_label = tv_get_item_label
577 };
578 
tree_view_new(TALLOC_CTX * ctx,struct tree_node * root,int nlines,int ncols,int begin_y,int begin_x)579 struct tree_view *tree_view_new(TALLOC_CTX *ctx, struct tree_node *root,
580 				int nlines, int ncols, int begin_y,
581 				int begin_x)
582 {
583 	struct tree_view *view;
584 
585 	view = talloc_zero(ctx, struct tree_view);
586 	if (view == NULL) {
587 		return NULL;
588 	}
589 
590 	talloc_set_destructor(view, tree_view_free);
591 
592 	view->window = newwin(nlines, ncols, begin_y, begin_x);
593 	if (view->window == NULL) {
594 		goto fail;
595 	}
596 	view->sub = subwin(view->window, nlines - 2, ncols - 2,
597 			   begin_y + 1, begin_x + 1);
598 	if (view->sub == NULL) {
599 		goto fail;
600 	}
601 	box(view->window, 0, 0);
602 	mvwprintw(view->window, 0, HEADING_X, "Key");
603 
604 	view->panel = new_panel(view->window);
605 	if (view->panel == NULL) {
606 		goto fail;
607 	}
608 	view->root = root;
609 
610 	view->list = multilist_new(view, view->sub, &tv_accessors, 1);
611 	if (view->list == NULL) {
612 		goto fail;
613 	}
614 	tree_view_update(view, root->child_head);
615 
616 	return view;
617 
618 fail:
619 	talloc_free(view);
620 
621 	return NULL;
622 }
623 
tree_view_resize(struct tree_view * view,int nlines,int ncols,int begin_y,int begin_x)624 void tree_view_resize(struct tree_view *view, int nlines, int ncols,
625 		      int begin_y, int begin_x)
626 {
627 	WINDOW *nwin, *nsub;
628 
629 	nwin = newwin(nlines, ncols, begin_y, begin_x);
630 	if (nwin == NULL) {
631 		return;
632 	}
633 	nsub = subwin(nwin, nlines - 2, ncols - 2, begin_y + 1, begin_x + 1);
634 	if (nsub == NULL) {
635 		delwin(nwin);
636 		return;
637 	}
638 	replace_panel(view->panel, nwin);
639 	delwin(view->sub);
640 	delwin(view->window);
641 	view->window = nwin;
642 	view->sub = nsub;
643 	box(view->window, 0, 0);
644 	mvwprintw(view->window, 0, HEADING_X, "Key");
645 	multilist_set_window(view->list, view->sub);
646 	tree_view_show(view);
647 }
648 
tree_node_get_path(TALLOC_CTX * ctx,struct tree_node * node)649 const char **tree_node_get_path(TALLOC_CTX *ctx, struct tree_node *node)
650 {
651 	const char **array;
652 	size_t nitems, idx;
653 	struct tree_node *p;
654 
655 	for (nitems = 0, p = node; !tree_node_is_root(p); p = p->parent) {
656 		++nitems;
657 	}
658 
659 	array = talloc_zero_array(ctx, const char *, nitems + 1);
660 	if (array == NULL) {
661 		return NULL;
662 	}
663 
664 	for (idx = nitems - 1, p = node;
665 	     !tree_node_is_root(p);
666 	     p = p->parent, --idx) {
667 		array[idx] = talloc_strdup(array, p->name);
668 		if (array[idx] == NULL) {
669 			talloc_free(discard_const(array));
670 			return NULL;
671 		}
672 	}
673 
674 	return array;
675 }
676 
677 /* print the path of node to label */
tree_node_print_path(WINDOW * label,struct tree_node * node)678 size_t tree_node_print_path(WINDOW *label, struct tree_node *node)
679 {
680 	size_t len = 1;
681 	const char **path;
682 	TALLOC_CTX *frame;
683 
684 	if (node == NULL)
685 		return 0;
686 
687 	werase(label);
688 	wprintw(label, "/");
689 
690 	if (tree_node_is_top_level(node))
691 		return 0;
692 
693 	frame = talloc_stackframe();
694 	path = tree_node_get_path(frame, node->parent);
695 
696 	while (*path) {
697 		len += strlen(*path) + 1;
698 		wprintw(label, "%s/", *path);
699 		++path;
700 	}
701 
702 	talloc_free(frame);
703 
704 	return len;
705 }
706