1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2014-2015 Todd C. Miller <Todd.Miller@sudo.ws>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
21  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
22  */
23 
24 #include <config.h>
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "sudoers.h"
31 
32 static int sudoers_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
33 static unsigned int sudoers_debug_refcnt;
34 
35 static const char *const sudoers_subsystem_names[] = {
36     "alias",
37     "audit",
38     "auth",
39     "defaults",
40     "env",
41     "event",
42     "ldap",
43     "logging",
44     "main",
45     "match",
46     "netif",
47     "nss",
48     "parser",
49     "perms",
50     "plugin",
51     "rbtree",
52     "sssd",
53     "util",
54     NULL
55 };
56 
57 #define NUM_SUBSYSTEMS  (nitems(sudoers_subsystem_names) - 1)
58 
59 /* Subsystem IDs assigned at registration time. */
60 unsigned int sudoers_subsystem_ids[NUM_SUBSYSTEMS];
61 
62 /*
63  * Parse the "filename flags,..." debug_flags entry and insert a new
64  * sudo_debug_file struct into debug_files.
65  */
66 bool
sudoers_debug_parse_flags(struct sudo_conf_debug_file_list * debug_files,const char * entry)67 sudoers_debug_parse_flags(struct sudo_conf_debug_file_list *debug_files,
68     const char *entry)
69 {
70     /* Already initialized? */
71     if (sudoers_debug_instance != SUDO_DEBUG_INSTANCE_INITIALIZER)
72 	return true;
73 
74     return sudo_debug_parse_flags(debug_files, entry) != -1;
75 }
76 
77 /*
78  * Register the specified debug files and program with the
79  * debug subsystem, freeing the debug list when done.
80  * Sets the active debug instance as a side effect.
81  */
82 bool
sudoers_debug_register(const char * program,struct sudo_conf_debug_file_list * debug_files)83 sudoers_debug_register(const char *program,
84     struct sudo_conf_debug_file_list *debug_files)
85 {
86     int instance = sudoers_debug_instance;
87     struct sudo_debug_file *debug_file, *debug_next;
88 
89     /* Setup debugging if indicated. */
90     if (debug_files != NULL && !TAILQ_EMPTY(debug_files)) {
91 	if (program != NULL) {
92 	    instance = sudo_debug_register(program, sudoers_subsystem_names,
93 		sudoers_subsystem_ids, debug_files, -1);
94 	}
95 	TAILQ_FOREACH_SAFE(debug_file, debug_files, entries, debug_next) {
96 	    TAILQ_REMOVE(debug_files, debug_file, entries);
97 	    free(debug_file->debug_file);
98 	    free(debug_file->debug_flags);
99 	    free(debug_file);
100 	}
101     }
102 
103     switch (instance) {
104     case SUDO_DEBUG_INSTANCE_ERROR:
105 	return false;
106     case SUDO_DEBUG_INSTANCE_INITIALIZER:
107 	/* Nothing to do */
108 	break;
109     default:
110 	/* New debug instance or additional reference on existing one. */
111 	sudoers_debug_instance = instance;
112 	sudo_debug_set_active_instance(sudoers_debug_instance);
113 	sudoers_debug_refcnt++;
114 	break;
115     }
116 
117     return true;
118 }
119 
120 /*
121  * Deregister sudoers_debug_instance if it is registered.
122  */
123 void
sudoers_debug_deregister(void)124 sudoers_debug_deregister(void)
125 {
126     debug_decl(sudoers_debug_deregister, SUDOERS_DEBUG_PLUGIN);
127 
128     if (sudoers_debug_refcnt != 0) {
129 	sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys);
130 	if (--sudoers_debug_refcnt == 0) {
131 	    if (sudo_debug_deregister(sudoers_debug_instance) < 1)
132 		sudoers_debug_instance = SUDO_DEBUG_INSTANCE_INITIALIZER;
133 	}
134     }
135 }
136