Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / policy.c
1 /*
2  * Copyright (c) 2010-2013 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <netinet/in.h>
22 #include <stdio.h>
23 #ifdef STDC_HEADERS
24 # include <stdlib.h>
25 # include <stddef.h>
26 #else
27 # ifdef HAVE_STDLIB_H
28 #  include <stdlib.h>
29 # endif
30 #endif /* STDC_HEADERS */
31 #ifdef HAVE_STRING_H
32 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
33 #  include <memory.h>
34 # endif
35 # include <string.h>
36 #endif /* HAVE_STRING_H */
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif /* HAVE_STRINGS_H */
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif /* HAVE_UNISTD_H */
43 #include <errno.h>
44 #include <grp.h>
45 #include <pwd.h>
46
47 #include "sudoers.h"
48 #include "sudoers_version.h"
49 #include "interfaces.h"
50
51 /*
52  * Info passed in from the sudo front-end.
53  */
54 struct sudoers_policy_open_info {
55     char * const *settings;
56     char * const *user_info;
57     char * const *plugin_args;
58 };
59
60 /*
61  * Command execution args to be filled in: argv, envp and command info.
62  */
63 struct sudoers_exec_args {
64     char ***argv;
65     char ***envp;
66     char ***info;
67 };
68
69 static int sudo_version;
70 static const char *interfaces_string;
71 sudo_conv_t sudo_conv;
72 const char *path_ldap_conf = _PATH_LDAP_CONF;
73 const char *path_ldap_secret = _PATH_LDAP_SECRET;
74
75 extern __dso_public struct policy_plugin sudoers_policy;
76
77 #ifdef HAVE_BSD_AUTH_H
78 extern char *login_style;
79 #endif /* HAVE_BSD_AUTH_H */
80
81 /*
82  * Deserialize args, settings and user_info arrays.
83  * Fills in struct sudo_user and other common sudoers state.
84  */
85 int
86 sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group)
87 {
88     struct sudoers_policy_open_info *info = v;
89     char * const *cur;
90     const char *p, *groups = NULL;
91     const char *debug_flags = NULL;
92     int flags = 0;
93     debug_decl(sudoers_policy_deserialize_info, SUDO_DEBUG_PLUGIN)
94
95 #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
96
97     /* Parse sudo.conf plugin args. */
98     if (info->plugin_args != NULL) {
99         for (cur = info->plugin_args; *cur != NULL; cur++) {
100             if (MATCHES(*cur, "sudoers_file=")) {
101                 sudoers_file = *cur + sizeof("sudoers_file=") - 1;
102                 continue;
103             }
104             if (MATCHES(*cur, "sudoers_uid=")) {
105                 sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1);
106                 continue;
107             }
108             if (MATCHES(*cur, "sudoers_gid=")) {
109                 sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1);
110                 continue;
111             }
112             if (MATCHES(*cur, "sudoers_mode=")) {
113                 sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1,
114                     NULL, 8);
115                 continue;
116             }
117             if (MATCHES(*cur, "ldap_conf=")) {
118                 path_ldap_conf = *cur + sizeof("ldap_conf=") - 1;
119                 continue;
120             }
121             if (MATCHES(*cur, "ldap_secret=")) {
122                 path_ldap_secret = *cur + sizeof("ldap_secret=") - 1;
123                 continue;
124             }
125         }
126     }
127
128     /* Parse command line settings. */
129     user_closefrom = -1;
130     sudo_user.max_groups = -1;
131     for (cur = info->settings; *cur != NULL; cur++) {
132         if (MATCHES(*cur, "closefrom=")) {
133             user_closefrom = atoi(*cur + sizeof("closefrom=") - 1);
134             continue;
135         }
136         if (MATCHES(*cur, "debug_flags=")) {
137             debug_flags = *cur + sizeof("debug_flags=") - 1;
138             continue;
139         }
140         if (MATCHES(*cur, "runas_user=")) {
141             *runas_user = *cur + sizeof("runas_user=") - 1;
142             sudo_user.flags |= RUNAS_USER_SPECIFIED;
143             continue;
144         }
145         if (MATCHES(*cur, "runas_group=")) {
146             *runas_group = *cur + sizeof("runas_group=") - 1;
147             sudo_user.flags |= RUNAS_GROUP_SPECIFIED;
148             continue;
149         }
150         if (MATCHES(*cur, "prompt=")) {
151             user_prompt = *cur + sizeof("prompt=") - 1;
152             def_passprompt_override = true;
153             continue;
154         }
155         if (MATCHES(*cur, "set_home=")) {
156             if (atobool(*cur + sizeof("set_home=") - 1) == true)
157                 SET(flags, MODE_RESET_HOME);
158             continue;
159         }
160         if (MATCHES(*cur, "preserve_environment=")) {
161             if (atobool(*cur + sizeof("preserve_environment=") - 1) == true)
162                 SET(flags, MODE_PRESERVE_ENV);
163             continue;
164         }
165         if (MATCHES(*cur, "run_shell=")) {
166             if (atobool(*cur + sizeof("run_shell=") - 1) == true)
167                 SET(flags, MODE_SHELL);
168             continue;
169         }
170         if (MATCHES(*cur, "login_shell=")) {
171             if (atobool(*cur + sizeof("login_shell=") - 1) == true) {
172                 SET(flags, MODE_LOGIN_SHELL);
173                 def_env_reset = true;
174             }
175             continue;
176         }
177         if (MATCHES(*cur, "implied_shell=")) {
178             if (atobool(*cur + sizeof("implied_shell=") - 1) == true)
179                 SET(flags, MODE_IMPLIED_SHELL);
180             continue;
181         }
182         if (MATCHES(*cur, "preserve_groups=")) {
183             if (atobool(*cur + sizeof("preserve_groups=") - 1) == true)
184                 SET(flags, MODE_PRESERVE_GROUPS);
185             continue;
186         }
187         if (MATCHES(*cur, "ignore_ticket=")) {
188             if (atobool(*cur + sizeof("ignore_ticket=") - 1) == true)
189                 SET(flags, MODE_IGNORE_TICKET);
190             continue;
191         }
192         if (MATCHES(*cur, "noninteractive=")) {
193             if (atobool(*cur + sizeof("noninteractive=") - 1) == true)
194                 SET(flags, MODE_NONINTERACTIVE);
195             continue;
196         }
197         if (MATCHES(*cur, "sudoedit=")) {
198             if (atobool(*cur + sizeof("sudoedit=") - 1) == true)
199                 SET(flags, MODE_EDIT);
200             continue;
201         }
202         if (MATCHES(*cur, "login_class=")) {
203             login_class = *cur + sizeof("login_class=") - 1;
204             def_use_loginclass = true;
205             continue;
206         }
207 #ifdef HAVE_PRIV_SET
208         if (MATCHES(*cur, "runas_privs=")) {
209             def_privs = *cur + sizeof("runas_privs=") - 1;
210             continue;
211         }
212         if (MATCHES(*cur, "runas_limitprivs=")) {
213             def_limitprivs = *cur + sizeof("runas_limitprivs=") - 1;
214             continue;
215         }
216 #endif /* HAVE_PRIV_SET */
217 #ifdef HAVE_SELINUX
218         if (MATCHES(*cur, "selinux_role=")) {
219             user_role = *cur + sizeof("selinux_role=") - 1;
220             continue;
221         }
222         if (MATCHES(*cur, "selinux_type=")) {
223             user_type = *cur + sizeof("selinux_type=") - 1;
224             continue;
225         }
226 #endif /* HAVE_SELINUX */
227 #ifdef HAVE_BSD_AUTH_H
228         if (MATCHES(*cur, "bsdauth_type=")) {
229             login_style = *cur + sizeof("bsdauth_type=") - 1;
230             continue;
231         }
232 #endif /* HAVE_BSD_AUTH_H */
233 #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
234         if (MATCHES(*cur, "progname=")) {
235             setprogname(*cur + sizeof("progname=") - 1);
236             continue;
237         }
238 #endif
239         if (MATCHES(*cur, "network_addrs=")) {
240             interfaces_string = *cur + sizeof("network_addrs=") - 1;
241             set_interfaces(interfaces_string);
242             continue;
243         }
244         if (MATCHES(*cur, "max_groups=")) {
245             sudo_user.max_groups = atoi(*cur + sizeof("max_groups=") - 1);
246             continue;
247         }
248     }
249
250     for (cur = info->user_info; *cur != NULL; cur++) {
251         if (MATCHES(*cur, "user=")) {
252             user_name = estrdup(*cur + sizeof("user=") - 1);
253             continue;
254         }
255         if (MATCHES(*cur, "uid=")) {
256             user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1);
257             continue;
258         }
259         if (MATCHES(*cur, "gid=")) {
260             p = *cur + sizeof("gid=") - 1;
261             user_gid = (gid_t) atoi(p);
262             continue;
263         }
264         if (MATCHES(*cur, "groups=")) {
265             groups = *cur + sizeof("groups=") - 1;
266             continue;
267         }
268         if (MATCHES(*cur, "cwd=")) {
269             user_cwd = estrdup(*cur + sizeof("cwd=") - 1);
270             continue;
271         }
272         if (MATCHES(*cur, "tty=")) {
273             user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1);
274             if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
275                 user_tty += sizeof(_PATH_DEV) - 1;
276             continue;
277         }
278         if (MATCHES(*cur, "host=")) {
279             user_host = user_shost = estrdup(*cur + sizeof("host=") - 1);
280             if ((p = strchr(user_host, '.')))
281                 user_shost = estrndup(user_host, (size_t)(p - user_host));
282             continue;
283         }
284         if (MATCHES(*cur, "lines=")) {
285             sudo_user.lines = atoi(*cur + sizeof("lines=") - 1);
286             continue;
287         }
288         if (MATCHES(*cur, "cols=")) {
289             sudo_user.cols = atoi(*cur + sizeof("cols=") - 1);
290             continue;
291         }
292         if (MATCHES(*cur, "sid=")) {
293             sudo_user.sid = atoi(*cur + sizeof("sid=") - 1);
294             continue;
295         }
296     }
297     if (user_cwd == NULL)
298         user_cwd = "unknown";
299     if (user_tty == NULL)
300         user_tty = "unknown"; /* user_ttypath remains NULL */
301
302     if (groups != NULL && groups[0] != '\0') {
303         const char *cp;
304         GETGROUPS_T *gids;
305         int ngids;
306
307         /* Count number of groups, including passwd gid. */
308         ngids = 2;
309         for (cp = groups; *cp != '\0'; cp++) {
310             if (*cp == ',')
311                 ngids++;
312         }
313
314         /* The first gid in the list is the passwd group gid. */
315         gids = emalloc2(ngids, sizeof(GETGROUPS_T));
316         gids[0] = user_gid;
317         ngids = 1;
318         cp = groups;
319         for (;;) {
320             gids[ngids] = atoi(cp);
321             if (gids[0] != gids[ngids])
322                 ngids++;
323             cp = strchr(cp, ',');
324             if (cp == NULL)
325                 break;
326             cp++; /* skip over comma */
327         }
328         user_gids = gids;
329         user_ngids = ngids;
330     }
331
332     /* Stash initial umask for later use. */
333     user_umask = umask(SUDO_UMASK);
334     umask(user_umask);
335
336     /* Setup debugging if indicated. */
337     if (debug_flags != NULL) {
338         sudo_debug_init(NULL, debug_flags);
339         for (cur = info->settings; *cur != NULL; cur++)
340             sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur);
341         for (cur = info->user_info; *cur != NULL; cur++)
342             sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur);
343     }
344
345 #undef MATCHES
346     debug_return_int(flags);
347 }
348
349 /*
350  * Setup the execution environment.
351  * Builds up the command_info list and sets argv and envp.
352  * Returns 1 on success and -1 on error.
353  */
354 int
355 sudoers_policy_exec_setup(char *argv[], char *envp[], mode_t cmnd_umask,
356     char *iolog_path, void *v)
357 {
358     struct sudoers_exec_args *exec_args = v;
359     char **command_info;
360     int info_len = 0;
361     debug_decl(sudoers_policy_exec_setup, SUDO_DEBUG_PLUGIN)
362
363     /* Increase the length of command_info as needed, it is *not* checked. */
364     command_info = ecalloc(32, sizeof(char **));
365
366     command_info[info_len++] = fmt_string("command", safe_cmnd);
367     if (def_log_input || def_log_output) {
368         if (iolog_path)
369             command_info[info_len++] = iolog_path;
370         if (def_log_input) {
371             command_info[info_len++] = estrdup("iolog_stdin=true");
372             command_info[info_len++] = estrdup("iolog_ttyin=true");
373         }
374         if (def_log_output) {
375             command_info[info_len++] = estrdup("iolog_stdout=true");
376             command_info[info_len++] = estrdup("iolog_stderr=true");
377             command_info[info_len++] = estrdup("iolog_ttyout=true");
378         }
379         if (def_compress_io) {
380             command_info[info_len++] = estrdup("iolog_compress=true");
381         }
382         if (def_maxseq) {
383             easprintf(&command_info[info_len++], "maxseq=%u", def_maxseq);
384         }
385     }
386     if (ISSET(sudo_mode, MODE_EDIT))
387         command_info[info_len++] = estrdup("sudoedit=true");
388     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
389         /* Set cwd to run user's homedir. */
390         command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);
391     }
392     if (def_stay_setuid) {
393         easprintf(&command_info[info_len++], "runas_uid=%u",
394             (unsigned int)user_uid);
395         easprintf(&command_info[info_len++], "runas_gid=%u",
396             (unsigned int)user_gid);
397         easprintf(&command_info[info_len++], "runas_euid=%u",
398             (unsigned int)runas_pw->pw_uid);
399         easprintf(&command_info[info_len++], "runas_egid=%u",
400             runas_gr ? (unsigned int)runas_gr->gr_gid :
401             (unsigned int)runas_pw->pw_gid);
402     } else {
403         easprintf(&command_info[info_len++], "runas_uid=%u",
404             (unsigned int)runas_pw->pw_uid);
405         easprintf(&command_info[info_len++], "runas_gid=%u",
406             runas_gr ? (unsigned int)runas_gr->gr_gid :
407             (unsigned int)runas_pw->pw_gid);
408     }
409     if (def_preserve_groups) {
410         command_info[info_len++] = "preserve_groups=true";
411     } else {
412         int i, len;
413         gid_t egid;
414         size_t glsize;
415         char *cp, *gid_list;
416         struct group_list *grlist = sudo_get_grlist(runas_pw);
417
418         /* We reserve an extra spot in the list for the effective gid. */
419         glsize = sizeof("runas_groups=") - 1 +
420             ((grlist->ngids + 1) * (MAX_UID_T_LEN + 1));
421         gid_list = emalloc(glsize);
422         memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
423         cp = gid_list + sizeof("runas_groups=") - 1;
424
425         /* On BSD systems the effective gid is the first group in the list. */
426         egid = runas_gr ? (unsigned int)runas_gr->gr_gid :
427             (unsigned int)runas_pw->pw_gid;
428         len = snprintf(cp, glsize - (cp - gid_list), "%u", egid);
429         if (len < 0 || len >= glsize - (cp - gid_list))
430             fatalx(_("internal error, %s overflow"), "runas_groups");
431         cp += len;
432         for (i = 0; i < grlist->ngids; i++) {
433             if (grlist->gids[i] != egid) {
434                 len = snprintf(cp, glsize - (cp - gid_list), ",%u",
435                      (unsigned int) grlist->gids[i]);
436                 if (len < 0 || len >= glsize - (cp - gid_list))
437                     fatalx(_("internal error, %s overflow"), "runas_groups");
438                 cp += len;
439             }
440         }
441         command_info[info_len++] = gid_list;
442         sudo_grlist_delref(grlist);
443     }
444     if (def_closefrom >= 0)
445         easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);
446     if (def_noexec)
447         command_info[info_len++] = estrdup("noexec=true");
448     if (def_exec_background)
449         command_info[info_len++] = estrdup("exec_background=true");
450     if (def_set_utmp)
451         command_info[info_len++] = estrdup("set_utmp=true");
452     if (def_use_pty)
453         command_info[info_len++] = estrdup("use_pty=true");
454     if (def_utmp_runas)
455         command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
456     if (cmnd_umask != 0777)
457         easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask);
458 #ifdef HAVE_LOGIN_CAP_H
459     if (def_use_loginclass)
460         command_info[info_len++] = fmt_string("login_class", login_class);
461 #endif /* HAVE_LOGIN_CAP_H */
462 #ifdef HAVE_SELINUX
463     if (user_role != NULL)
464         command_info[info_len++] = fmt_string("selinux_role", user_role);
465     if (user_type != NULL)
466         command_info[info_len++] = fmt_string("selinux_type", user_type);
467 #endif /* HAVE_SELINUX */
468 #ifdef HAVE_PRIV_SET
469     if (runas_privs != NULL)
470         command_info[info_len++] = fmt_string("runas_privs", runas_privs);
471     if (runas_limitprivs != NULL)
472         command_info[info_len++] = fmt_string("runas_limitprivs", runas_limitprivs);
473 #endif /* HAVE_SELINUX */
474
475     /* Fill in exec environment info */
476     *(exec_args->argv) = argv;
477     *(exec_args->envp) = envp;
478     *(exec_args->info) = command_info;
479
480     debug_return_bool(true);
481 }
482
483 static int
484 sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
485     sudo_printf_t plugin_printf, char * const settings[],
486     char * const user_info[], char * const envp[], char * const args[])
487 {
488     struct sudoers_policy_open_info info;
489     debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN)
490
491     sudo_version = version;
492     sudo_conv = conversation;
493     sudo_printf = plugin_printf;
494
495     /* Plugin args are only specified for API version 1.2 and higher. */
496     if (sudo_version < SUDO_API_MKVERSION(1, 2))
497         args = NULL;
498
499     if (fatal_setjmp() != 0) {
500         /* called via fatal(), fatalx() or log_fatal() */
501         rewind_perms();
502         fatal_disable_setjmp();
503         debug_return_bool(-1);
504     }
505
506     /* Call the sudoers init function. */
507     info.settings = settings;
508     info.user_info = user_info;
509     info.plugin_args = args;
510     debug_return_bool(sudoers_policy_init(&info, envp));
511 }
512
513 static void
514 sudoers_policy_close(int exit_status, int error_code)
515 {
516     debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN)
517
518     if (fatal_setjmp() != 0) {
519         /* called via fatal(), fatalx() or log_fatal() */
520         fatal_disable_setjmp();
521         debug_return;
522     }
523
524     /* We do not currently log the exit status. */
525     if (error_code) {
526         errno = error_code;
527         warning(_("unable to execute %s"), safe_cmnd);
528     }
529
530     /* Close the session we opened in sudoers_policy_init_session(). */
531     if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
532         (void)sudo_auth_end_session(runas_pw);
533
534     /* Free remaining references to password and group entries. */
535     /* XXX - move cleanup to function in sudoers.c */
536     sudo_pw_delref(sudo_user.pw);
537     sudo_user.pw = NULL;
538     sudo_pw_delref(runas_pw);
539     runas_pw = NULL;
540     if (runas_gr != NULL) {
541         sudo_gr_delref(runas_gr);
542         runas_gr = NULL;
543     }
544     if (user_group_list != NULL) {
545         sudo_grlist_delref(user_group_list);
546         user_group_list = NULL;
547     }
548     efree(user_gids);
549     user_gids = NULL;
550
551     debug_return;
552 }
553
554 /*
555  * The init_session function is called before executing the command
556  * and before uid/gid changes occur.
557  * Returns 1 on success, 0 on failure and -1 on error.
558  */
559 static int
560 sudoers_policy_init_session(struct passwd *pwd, char **user_env[])
561 {
562     debug_decl(sudoers_policy_init_session, SUDO_DEBUG_PLUGIN)
563
564     /* user_env is only specified for API version 1.2 and higher. */
565     if (sudo_version < SUDO_API_MKVERSION(1, 2))
566         user_env = NULL;
567
568     if (fatal_setjmp() != 0) {
569         /* called via fatal(), fatalx() or log_fatal() */
570         fatal_disable_setjmp();
571         debug_return_bool(-1);
572     }
573
574     debug_return_bool(sudo_auth_begin_session(pwd, user_env));
575 }
576
577 static int
578 sudoers_policy_check(int argc, char * const argv[], char *env_add[],
579     char **command_infop[], char **argv_out[], char **user_env_out[])
580 {
581     struct sudoers_exec_args exec_args;
582     int rval;
583     debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN)
584
585     if (!ISSET(sudo_mode, MODE_EDIT))
586         SET(sudo_mode, MODE_RUN);
587
588     exec_args.argv = argv_out;
589     exec_args.envp = user_env_out;
590     exec_args.info = command_infop;
591
592     rval = sudoers_policy_main(argc, argv, 0, env_add, &exec_args);
593     if (rval == true && sudo_version >= SUDO_API_MKVERSION(1, 3)) {
594         /* Unset close function if we don't need it to avoid extra process. */
595         if (!def_log_input && !def_log_output && !def_use_pty &&
596             !sudo_auth_needs_end_session())
597             sudoers_policy.close = NULL;
598     }
599     debug_return_bool(rval);
600 }
601
602 static int
603 sudoers_policy_validate(void)
604 {
605     debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN)
606
607     user_cmnd = "validate";
608     SET(sudo_mode, MODE_VALIDATE);
609
610     debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL));
611 }
612
613 static void
614 sudoers_policy_invalidate(int remove)
615 {
616     debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN)
617
618     user_cmnd = "kill";
619     if (fatal_setjmp() == 0) {
620         remove_timestamp(remove);
621         sudoers_cleanup();
622     }
623     fatal_disable_setjmp();
624
625     debug_return;
626 }
627
628 static int
629 sudoers_policy_list(int argc, char * const argv[], int verbose,
630     const char *list_user)
631 {
632     int rval;
633     debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN)
634
635     user_cmnd = "list";
636     if (argc)
637         SET(sudo_mode, MODE_CHECK);
638     else
639         SET(sudo_mode, MODE_LIST);
640     if (verbose)
641         long_list = 1;
642     if (list_user) {
643         list_pw = sudo_getpwnam(list_user);
644         if (list_pw == NULL) {
645             warningx(_("unknown user: %s"), list_user);
646             debug_return_bool(-1);
647         }
648     }
649     rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL);
650     if (list_user) {
651         sudo_pw_delref(list_pw);
652         list_pw = NULL;
653     }
654
655     debug_return_bool(rval);
656 }
657
658 static int
659 sudoers_policy_version(int verbose)
660 {
661     debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN)
662
663     if (fatal_setjmp() != 0) {
664         /* error recovery via fatal(), fatalx() or log_fatal() */
665         fatal_disable_setjmp();
666         debug_return_bool(-1);
667     }
668
669     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"),
670         PACKAGE_VERSION);
671     sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"),
672         SUDOERS_GRAMMAR_VERSION);
673
674     if (verbose) {
675         sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file);
676 #ifdef HAVE_LDAP
677 # ifdef _PATH_NSSWITCH_CONF
678         sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF);
679 # endif
680         sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), path_ldap_conf);
681         sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), path_ldap_secret);
682 #endif
683         dump_auth_methods();
684         dump_defaults();
685         sudo_printf(SUDO_CONV_INFO_MSG, "\n");
686         if (interfaces_string != NULL) {
687             dump_interfaces(interfaces_string);
688             sudo_printf(SUDO_CONV_INFO_MSG, "\n");
689         }
690     }
691     debug_return_bool(true);
692 }
693
694 static void
695 sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook))
696 {
697     struct sudo_hook hook;
698
699     memset(&hook, 0, sizeof(hook));
700     hook.hook_version = SUDO_HOOK_VERSION;
701
702     hook.hook_type = SUDO_HOOK_SETENV;
703     hook.hook_fn = sudoers_hook_setenv;
704     register_hook(&hook);
705
706     hook.hook_type = SUDO_HOOK_UNSETENV;
707     hook.hook_fn = sudoers_hook_unsetenv;
708     register_hook(&hook);
709
710     hook.hook_type = SUDO_HOOK_GETENV;
711     hook.hook_fn = sudoers_hook_getenv;
712     register_hook(&hook);
713
714     hook.hook_type = SUDO_HOOK_PUTENV;
715     hook.hook_fn = sudoers_hook_putenv;
716     register_hook(&hook);
717 }
718
719 __dso_public struct policy_plugin sudoers_policy = {
720     SUDO_POLICY_PLUGIN,
721     SUDO_API_VERSION,
722     sudoers_policy_open,
723     sudoers_policy_close,
724     sudoers_policy_version,
725     sudoers_policy_check,
726     sudoers_policy_list,
727     sudoers_policy_validate,
728     sudoers_policy_invalidate,
729     sudoers_policy_init_session,
730     sudoers_policy_register_hooks
731 };