1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2011-2017 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 #ifndef SUDO_DEBUG_H
20 #define SUDO_DEBUG_H
21 
22 #include <sys/types.h>		/* for id_t, size_t, ssize_t, time_t */
23 #include <stdarg.h>
24 #ifdef HAVE_STDBOOL_H
25 # include <stdbool.h>
26 #else
27 # include "compat/stdbool.h"
28 #endif
29 #include "sudo_queue.h"
30 
31 /*
32  * List of debug files and flags for use in registration.
33  */
34 struct sudo_debug_file {
35     TAILQ_ENTRY(sudo_debug_file) entries;
36     char *debug_file;
37     char *debug_flags;
38 };
39 struct sudo_conf_debug_file_list;
40 
41 /*
42  * The priority and subsystem are encoded in a single 32-bit value.
43  * The lower 4 bits are the priority and the top 26 bits are the subsystem.
44  * This allows for 16 priorities and a very large number of subsystems.
45  * Bit 5 is used as a flag to specify whether to log the errno value.
46  * Bit 6 specifies whether to log the function, file and line number data.
47  */
48 
49 /*
50  * Sudo debug priorities, ordered least to most verbose,
51  * in other words, highest to lowest priority.  Max pri is 15.
52  * Note: order must match sudo_debug_priorities[]
53  */
54 #define SUDO_DEBUG_CRIT		1	/* critical errors */
55 #define SUDO_DEBUG_ERROR	2	/* non-critical errors */
56 #define SUDO_DEBUG_WARN		3	/* non-fatal warnings */
57 #define SUDO_DEBUG_NOTICE	4	/* non-error condition notices */
58 #define SUDO_DEBUG_DIAG		5	/* diagnostic messages */
59 #define SUDO_DEBUG_INFO		6	/* informational message */
60 #define SUDO_DEBUG_TRACE	7	/* log function enter/exit */
61 #define SUDO_DEBUG_DEBUG	8	/* very verbose debugging */
62 
63 /* Flag to include string version of errno in debug info. */
64 #define SUDO_DEBUG_ERRNO	(1<<4)
65 
66 /* Flag to include function, file and line number in debug info. */
67 #define SUDO_DEBUG_LINENO	(1<<5)
68 
69 /*
70  * Sudo debug subsystems.
71  * This includes subsystems in the sudoers plugin.
72  * Note: order must match sudo_debug_subsystems[]
73  */
74 #define SUDO_DEBUG_ARGS		( 1<<6)    /* command line argument handling */
75 #define SUDO_DEBUG_CONV		( 2<<6)    /* user conversation */
76 #define SUDO_DEBUG_EDIT		( 3<<6)    /* sudoedit */
77 #define SUDO_DEBUG_EVENT	( 4<<6)    /* event handling */
78 #define SUDO_DEBUG_EXEC		( 5<<6)    /* command execution */
79 #define SUDO_DEBUG_HOOKS	( 6<<6)    /* hook functions */
80 #define SUDO_DEBUG_MAIN		( 7<<6)    /* sudo main() */
81 #define SUDO_DEBUG_NETIF	( 8<<6)    /* network interface functions */
82 #define SUDO_DEBUG_PCOMM	( 9<<6)    /* plugin communications */
83 #define SUDO_DEBUG_PLUGIN	(10<<6)    /* main plugin functions */
84 #define SUDO_DEBUG_PTY		(11<<6)    /* pseudo-tty */
85 #define SUDO_DEBUG_SELINUX	(12<<6)    /* selinux */
86 #define SUDO_DEBUG_UTIL		(13<<6)    /* utility functions */
87 #define SUDO_DEBUG_UTMP		(14<<6)    /* utmp file ops */
88 #define SUDO_DEBUG_ALL		0xffff0000 /* all subsystems */
89 
90 /* Error return for sudo_debug_register().  */
91 #define SUDO_DEBUG_INSTANCE_ERROR	-2
92 
93 /* Initializer for instance index to indicate that debugging is not setup. */
94 #define SUDO_DEBUG_INSTANCE_INITIALIZER	-1
95 
96 /* Extract priority number and convert to an index. */
97 #define SUDO_DEBUG_PRI(n) (((n) & 0x0f) - 1)
98 
99 /* Extract subsystem number and convert to an index. */
100 #define SUDO_DEBUG_SUBSYS(n) (((n) >> 6) - 1)
101 
102 /*
103  * Wrapper for sudo_debug_enter() that declares __func__ as needed
104  * and sets sudo_debug_subsys for sudo_debug_exit().
105  */
106 #ifdef HAVE___FUNC__
107 # define debug_decl_func(funcname)
108 # define debug_decl_vars(funcname, subsys)				       \
109     const int sudo_debug_subsys = (subsys)
110 #else
111 # define debug_decl_func(funcname)					       \
112     const char __func__[] = #funcname;
113 # define debug_decl_vars(funcname, subsys)				       \
114     debug_decl_func(funcname)						       \
115     const int sudo_debug_subsys = (subsys)
116 #endif
117 #define debug_decl(funcname, subsys)					       \
118     debug_decl_vars((funcname), (subsys));				       \
119     sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys)
120 
121 /*
122  * Wrappers for sudo_debug_exit() and friends.
123  */
124 #define debug_return							       \
125     do {								       \
126 	sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys);      \
127 	return;								       \
128     } while (0)
129 
130 #define debug_return_int(ret)						       \
131     do {								       \
132 	int sudo_debug_ret = (ret);					       \
133 	sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys,   \
134 	    sudo_debug_ret);						       \
135 	return sudo_debug_ret;						       \
136     } while (0)
137 
138 #define debug_return_id_t(ret)					       \
139     do {								       \
140 	id_t sudo_debug_ret = (ret);				       \
141 	sudo_debug_exit_id_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
142 	    sudo_debug_ret);						       \
143 	return sudo_debug_ret;						       \
144     } while (0)
145 
146 #define debug_return_size_t(ret)					       \
147     do {								       \
148 	size_t sudo_debug_ret = (ret);				       \
149 	sudo_debug_exit_size_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
150 	    sudo_debug_ret);						       \
151 	return sudo_debug_ret;						       \
152     } while (0)
153 
154 #define debug_return_ssize_t(ret)					       \
155     do {								       \
156 	ssize_t sudo_debug_ret = (ret);				       \
157 	sudo_debug_exit_ssize_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
158 	    sudo_debug_ret);						       \
159 	return sudo_debug_ret;						       \
160     } while (0)
161 
162 #define debug_return_time_t(ret)					       \
163     do {								       \
164 	time_t sudo_debug_ret = (ret);				       \
165 	sudo_debug_exit_time_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\
166 	    sudo_debug_ret);						       \
167 	return sudo_debug_ret;						       \
168     } while (0)
169 
170 #define debug_return_long(ret)						       \
171     do {								       \
172 	long sudo_debug_ret = (ret);					       \
173 	sudo_debug_exit_long(__func__, __FILE__, __LINE__, sudo_debug_subsys,  \
174 	    sudo_debug_ret);						       \
175 	return sudo_debug_ret;						       \
176     } while (0)
177 
178 #define debug_return_bool(ret)						       \
179     do {								       \
180 	bool sudo_debug_ret = (ret);					       \
181 	sudo_debug_exit_bool(__func__, __FILE__, __LINE__, sudo_debug_subsys,  \
182 	    sudo_debug_ret);						       \
183 	return sudo_debug_ret;						       \
184     } while (0)
185 
186 #define debug_return_str(ret)						       \
187     do {								       \
188 	char *sudo_debug_ret = (ret);					       \
189 	sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys,   \
190 	    sudo_debug_ret);						       \
191 	return sudo_debug_ret;						       \
192     } while (0)
193 
194 #define debug_return_const_str(ret)					       \
195     do {								       \
196 	const char *sudo_debug_ret = (ret);				       \
197 	sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys,   \
198 	    sudo_debug_ret);						       \
199 	return sudo_debug_ret;						       \
200     } while (0)
201 
202 #define debug_return_str_masked(ret)					       \
203     do {								       \
204 	char *sudo_debug_ret = (ret);					       \
205 	sudo_debug_exit_str_masked(__func__, __FILE__, __LINE__,	       \
206 	    sudo_debug_subsys, sudo_debug_ret);			       \
207 	return sudo_debug_ret;						       \
208     } while (0)
209 
210 #define debug_return_ptr(ret)						       \
211     do {								       \
212 	void *sudo_debug_ret = (ret);					       \
213 	sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys,   \
214 	    sudo_debug_ret);						       \
215 	return sudo_debug_ret;						       \
216     } while (0)
217 
218 #define debug_return_const_ptr(ret)					       \
219     do {								       \
220 	const void *sudo_debug_ret = (ret);				       \
221 	sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys,   \
222 	    sudo_debug_ret);						       \
223 	return sudo_debug_ret;						       \
224     } while (0)
225 
226 /*
227  * Variadic macros are a C99 feature but GNU cpp has supported
228  * a (different) version of them for a long time.
229  */
230 #if defined(NO_VARIADIC_MACROS)
231 # define sudo_debug_printf sudo_debug_printf_nvm
232 #elif defined(__GNUC__) && __GNUC__ == 2
233 # define sudo_debug_printf(pri, fmt...) \
234     sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \
235     fmt)
236 #else
237 # define sudo_debug_printf(pri, ...) \
238     sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \
239     __VA_ARGS__)
240 #endif
241 
242 #define sudo_debug_execve(pri, path, argv, envp) \
243     sudo_debug_execve2((pri)|sudo_debug_subsys, (path), (argv), (envp))
244 
245 #define sudo_debug_write(fd, str, len, errnum) \
246     sudo_debug_write2(fd, NULL, NULL, 0, (str), (len), (errnum))
247 
248 sudo_dso_public int sudo_debug_deregister_v1(int instance_id);
249 sudo_dso_public void sudo_debug_enter_v1(const char *func, const char *file, int line, int subsys);
250 sudo_dso_public void sudo_debug_execve2_v1(int level, const char *path, char *const argv[], char *const envp[]);
251 sudo_dso_public void sudo_debug_exit_v1(const char *func, const char *file, int line, int subsys);
252 sudo_dso_public void sudo_debug_exit_bool_v1(const char *func, const char *file, int line, int subsys, bool ret);
253 sudo_dso_public void sudo_debug_exit_int_v1(const char *func, const char *file, int line, int subsys, int ret);
254 sudo_dso_public void sudo_debug_exit_long_v1(const char *func, const char *file, int line, int subsys, long ret);
255 sudo_dso_public void sudo_debug_exit_ptr_v1(const char *func, const char *file, int line, int subsys, const void *ret);
256 sudo_dso_public void sudo_debug_exit_id_t_v1(const char *func, const char *file, int line, int subsys, id_t ret);
257 sudo_dso_public void sudo_debug_exit_size_t_v1(const char *func, const char *file, int line, int subsys, size_t ret);
258 sudo_dso_public void sudo_debug_exit_ssize_t_v1(const char *func, const char *file, int line, int subsys, ssize_t ret);
259 sudo_dso_public void sudo_debug_exit_str_v1(const char *func, const char *file, int line, int subsys, const char *ret);
260 sudo_dso_public void sudo_debug_exit_str_masked_v1(const char *func, const char *file, int line, int subsys, const char *ret);
261 sudo_dso_public void sudo_debug_exit_time_t_v1(const char *func, const char *file, int line, int subsys, time_t ret);
262 sudo_dso_public pid_t sudo_debug_fork_v1(void);
263 sudo_dso_public int sudo_debug_get_active_instance_v1(void);
264 sudo_dso_public int sudo_debug_get_fds_v1(unsigned char **fds);
265 sudo_dso_public int sudo_debug_get_instance_v1(const char *program);
266 sudo_dso_public int sudo_debug_parse_flags_v1(struct sudo_conf_debug_file_list *debug_files, const char *entry);
267 sudo_dso_public void sudo_debug_printf2_v1(const char *func, const char *file, int line, int level, const char *fmt, ...) __printf0like(5, 6);
268 sudo_dso_public void sudo_debug_printf_nvm_v1(int pri, const char *fmt, ...) __printf0like(2, 3);
269 sudo_dso_public int sudo_debug_register_v1(const char *program, const char *const subsystems[], unsigned int ids[], struct sudo_conf_debug_file_list *debug_files);
270 sudo_dso_public int sudo_debug_register_v2(const char *program, const char *const subsystems[], unsigned int ids[], struct sudo_conf_debug_file_list *debug_files, int minfd);
271 sudo_dso_public int sudo_debug_set_active_instance_v1(int inst);
272 sudo_dso_public void sudo_debug_update_fd_v1(int ofd, int nfd);
273 sudo_dso_public void sudo_debug_vprintf2_v1(const char *func, const char *file, int line, int level, const char *fmt, va_list ap) __printf0like(5, 0);
274 sudo_dso_public void sudo_debug_write2_v1(int fd, const char *func, const char *file, int line, const char *str, int len, int errnum);
275 sudo_dso_public bool sudo_debug_needed_v1(int level);
276 
277 #define sudo_debug_needed(level) sudo_debug_needed_v1((level)|sudo_debug_subsys)
278 #define sudo_debug_deregister(_a) sudo_debug_deregister_v1((_a))
279 #define sudo_debug_enter(_a, _b, _c, _d) sudo_debug_enter_v1((_a), (_b), (_c), (_d))
280 #define sudo_debug_execve2(_a, _b, _c, _d) sudo_debug_execve2_v1((_a), (_b), (_c), (_d))
281 #define sudo_debug_exit(_a, _b, _c, _d) sudo_debug_exit_v1((_a), (_b), (_c), (_d))
282 #define sudo_debug_exit_bool(_a, _b, _c, _d, _e) sudo_debug_exit_bool_v1((_a), (_b), (_c), (_d), (_e))
283 #define sudo_debug_exit_int(_a, _b, _c, _d, _e) sudo_debug_exit_int_v1((_a), (_b), (_c), (_d), (_e))
284 #define sudo_debug_exit_long(_a, _b, _c, _d, _e) sudo_debug_exit_long_v1((_a), (_b), (_c), (_d), (_e))
285 #define sudo_debug_exit_ptr(_a, _b, _c, _d, _e) sudo_debug_exit_ptr_v1((_a), (_b), (_c), (_d), (_e))
286 #define sudo_debug_exit_id_t(_a, _b, _c, _d, _e) sudo_debug_exit_id_t_v1((_a), (_b), (_c), (_d), (_e))
287 #define sudo_debug_exit_size_t(_a, _b, _c, _d, _e) sudo_debug_exit_size_t_v1((_a), (_b), (_c), (_d), (_e))
288 #define sudo_debug_exit_ssize_t(_a, _b, _c, _d, _e) sudo_debug_exit_ssize_t_v1((_a), (_b), (_c), (_d), (_e))
289 #define sudo_debug_exit_str(_a, _b, _c, _d, _e) sudo_debug_exit_str_v1((_a), (_b), (_c), (_d), (_e))
290 #define sudo_debug_exit_str_masked(_a, _b, _c, _d, _e) sudo_debug_exit_str_masked_v1((_a), (_b), (_c), (_d), (_e))
291 #define sudo_debug_exit_time_t(_a, _b, _c, _d, _e) sudo_debug_exit_time_t_v1((_a), (_b), (_c), (_d), (_e))
292 #define sudo_debug_fork() sudo_debug_fork_v1()
293 #define sudo_debug_get_active_instance() sudo_debug_get_active_instance_v1()
294 #define sudo_debug_get_fds(_a) sudo_debug_get_fds_v1((_a))
295 #define sudo_debug_get_instance(_a) sudo_debug_get_instance_v1((_a))
296 #define sudo_debug_parse_flags(_a, _b) sudo_debug_parse_flags_v1((_a), (_b))
297 #define sudo_debug_printf2 sudo_debug_printf2_v1
298 #define sudo_debug_printf_nvm sudo_debug_printf_nvm_v1
299 #define sudo_debug_register(_a, _b, _c, _d, _e) sudo_debug_register_v2((_a), (_b), (_c), (_d), (_e))
300 #define sudo_debug_set_active_instance(_a) sudo_debug_set_active_instance_v1((_a))
301 #define sudo_debug_update_fd(_a, _b) sudo_debug_update_fd_v1((_a), (_b))
302 #define sudo_debug_vprintf2(_a, _b, _c, _d, _e, _f) sudo_debug_vprintf2_v1((_a), (_b), (_c), (_d), (_e), (_f))
303 #define sudo_debug_write2(_a, _b, _c, _d, _e, _f, _g) sudo_debug_write2_v1((_a), (_b), (_c), (_d), (_e), (_f), (_g))
304 
305 #endif /* SUDO_DEBUG_H */
306