Coverage Report

Created: 2026-09-28 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/sudo/plugins/sudoers/policy.c
Line
Count
Source
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 2010-2026 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
#include <config.h>
20
21
#include <sys/types.h>
22
#include <sys/stat.h>
23
#include <netinet/in.h>
24
#include <stdio.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <unistd.h>
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <grp.h>
31
#include <pwd.h>
32
33
#include <sudoers.h>
34
#include <sudoers_version.h>
35
#include <timestamp.h>
36
#include <interfaces.h>
37
#include "auth/sudo_auth.h"
38
39
static char **command_info;
40
41
/*
42
 * Command execution args to be filled in: argv, envp and command info.
43
 */
44
struct sudoers_exec_args {
45
    char ***argv;
46
    char ***envp;
47
    char ***info;
48
};
49
50
static unsigned int sudo_version;
51
static const char *interfaces_string;
52
sudo_conv_t sudo_conv;
53
sudo_printf_t sudo_printf;
54
struct sudo_plugin_event * (*plugin_event_alloc)(void);
55
static const char *path_sudoers = _PATH_SUDOERS;
56
static bool session_opened;
57
58
extern sudo_dso_public struct policy_plugin sudoers_policy;
59
60
static int
61
parse_bool(const char *line, int varlen, unsigned int *flags, unsigned int fval)
62
0
{
63
0
    debug_decl(parse_bool, SUDOERS_DEBUG_PLUGIN);
64
65
0
    switch (sudo_strtobool(line + varlen + 1)) {
66
0
    case true:
67
0
  SET(*flags, fval);
68
0
  debug_return_int(true);
69
0
    case false:
70
0
  CLR(*flags, fval);
71
0
  debug_return_int(false);
72
0
    default:
73
0
  sudo_warnx(U_("invalid %.*s set by sudo front-end"),
74
0
      varlen, line);
75
0
  debug_return_int(-1);
76
0
    }
77
0
}
78
79
0
#define RUN_VALID_FLAGS (MODE_ASKPASS|MODE_PRESERVE_ENV|MODE_RESET_HOME|MODE_IMPLIED_SHELL|MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_IGNORE_TICKET|MODE_UPDATE_TICKET|MODE_PRESERVE_GROUPS|MODE_SHELL|MODE_RUN|MODE_POLICY_INTERCEPTED)
80
0
#define EDIT_VALID_FLAGS  (MODE_ASKPASS|MODE_NONINTERACTIVE|MODE_IGNORE_TICKET|MODE_UPDATE_TICKET|MODE_EDIT)
81
0
#define LIST_VALID_FLAGS  (MODE_ASKPASS|MODE_NONINTERACTIVE|MODE_IGNORE_TICKET|MODE_UPDATE_TICKET|MODE_LIST|MODE_CHECK)
82
0
#define VALIDATE_VALID_FLAGS  (MODE_ASKPASS|MODE_NONINTERACTIVE|MODE_IGNORE_TICKET|MODE_UPDATE_TICKET|MODE_VALIDATE)
83
0
#define INVALIDATE_VALID_FLAGS  (MODE_ASKPASS|MODE_NONINTERACTIVE|MODE_IGNORE_TICKET|MODE_UPDATE_TICKET|MODE_INVALIDATE)
84
85
/*
86
 * Deserialize args, settings and user_info arrays.
87
 * Fills in struct sudoers_user_context and other common sudoers state.
88
 */
89
unsigned int
90
sudoers_policy_deserialize_info(struct sudoers_context *ctx, void *v,
91
    struct defaults_list *defaults)
92
0
{
93
0
    const size_t host_name_max = sudo_host_name_max();
94
0
    const size_t login_name_max = sudo_login_name_max();
95
0
    const char *p, *errstr, *groups = NULL;
96
0
    struct sudoers_open_info *info = v;
97
0
    unsigned int flags = MODE_UPDATE_TICKET;
98
0
    const char *host = NULL;
99
0
    const char *remhost = NULL;
100
0
    unsigned char uuid[16];
101
0
    char * const *cur;
102
0
    debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN);
103
104
0
#define MATCHES(s, v) \
105
0
    (strncmp((s), (v), sizeof(v) - 1) == 0)
106
107
0
#define INVALID(v) do { \
108
0
    sudo_warnx(U_("invalid %.*s set by sudo front-end"), \
109
0
  (int)(sizeof(v) - 2), (v)); \
110
0
} while (0)
111
112
0
#define CHECK(s, v) do { \
113
0
    if ((s)[sizeof(v) - 1] == '\0') { \
114
0
  INVALID(v); \
115
0
  goto bad; \
116
0
    } \
117
0
} while (0)
118
119
    /* Parse sudo.conf plugin args. */
120
0
    if (info->plugin_args != NULL) {
121
0
  for (cur = info->plugin_args; *cur != NULL; cur++) {
122
0
      if (MATCHES(*cur, "error_recovery=")) {
123
0
    int val = sudo_strtobool(*cur + sizeof("error_recovery=") - 1);
124
0
    if (val == -1) {
125
0
        INVALID("error_recovery=");  /* Not a fatal error. */
126
0
    } else {
127
0
        ctx->parser_conf.recovery = val;
128
0
    }
129
0
    continue;
130
0
      }
131
0
      if (MATCHES(*cur, "ignore_perms=")) {
132
0
    int val = sudo_strtobool(*cur + sizeof("ignore_perms=") - 1);
133
0
    if (val == -1) {
134
0
        INVALID("ignore_perms=");  /* Not a fatal error. */
135
0
    } else {
136
0
        ctx->parser_conf.ignore_perms = val;
137
0
    }
138
0
    continue;
139
0
      }
140
0
      if (MATCHES(*cur, "sudoers_file=")) {
141
0
    CHECK(*cur, "sudoers_file=");
142
0
    path_sudoers = *cur + sizeof("sudoers_file=") - 1;
143
0
    if (strlen(path_sudoers) >= PATH_MAX) {
144
0
        sudo_warnx(U_("path name for \"%s\" too long"), "sudoers_file");
145
0
        goto bad;
146
0
    }
147
0
    continue;
148
0
      }
149
0
      if (MATCHES(*cur, "sudoers_uid=")) {
150
0
    p = *cur + sizeof("sudoers_uid=") - 1;
151
0
    ctx->parser_conf.sudoers_uid = (uid_t)sudo_strtoid(p, &errstr);
152
0
    if (errstr != NULL) {
153
0
        sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
154
0
        goto bad;
155
0
    }
156
0
    continue;
157
0
      }
158
0
      if (MATCHES(*cur, "sudoers_gid=")) {
159
0
    p = *cur + sizeof("sudoers_gid=") - 1;
160
0
    ctx->parser_conf.sudoers_gid = (gid_t)sudo_strtoid(p, &errstr);
161
0
    if (errstr != NULL) {
162
0
        sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
163
0
        goto bad;
164
0
    }
165
0
    continue;
166
0
      }
167
0
      if (MATCHES(*cur, "sudoers_mode=")) {
168
0
    p = *cur + sizeof("sudoers_mode=") - 1;
169
0
    ctx->parser_conf.sudoers_mode = sudo_strtomode(p, &errstr);
170
0
    if (errstr != NULL) {
171
0
        sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
172
0
        goto bad;
173
0
    }
174
0
    continue;
175
0
      }
176
0
      if (MATCHES(*cur, "ldap_conf=")) {
177
0
    CHECK(*cur, "ldap_conf=");
178
0
    ctx->settings.ldap_conf = *cur + sizeof("ldap_conf=") - 1;
179
0
    if (strlen(ctx->settings.ldap_conf) >= PATH_MAX) {
180
0
        sudo_warnx(U_("path name for \"%s\" too long"), "ldap_conf");
181
0
        goto bad;
182
0
    }
183
0
    continue;
184
0
      }
185
0
      if (MATCHES(*cur, "ldap_secret=")) {
186
0
    CHECK(*cur, "ldap_secret=");
187
0
    ctx->settings.ldap_secret = *cur + sizeof("ldap_secret=") - 1;
188
0
    if (strlen(ctx->settings.ldap_secret) >= PATH_MAX) {
189
0
        sudo_warnx(U_("path name for \"%s\" too long"), "ldap_secret");
190
0
        goto bad;
191
0
    }
192
0
    continue;
193
0
      }
194
0
  }
195
0
    }
196
0
    ctx->parser_conf.sudoers_path = path_sudoers;
197
198
    /* Parse command line settings. */
199
0
    ctx->settings.flags = 0;
200
0
    ctx->user.closefrom = -1;
201
0
    ctx->sudoedit_nfiles = 0;
202
0
    ctx->mode = 0;
203
0
    for (cur = info->settings; *cur != NULL; cur++) {
204
0
  if (MATCHES(*cur, "closefrom=")) {
205
0
      p = *cur + sizeof("closefrom=") - 1;
206
0
      ctx->user.closefrom = (int)sudo_strtonum(p, 3, INT_MAX, &errstr);
207
0
      if (ctx->user.closefrom == 0) {
208
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
209
0
    goto bad;
210
0
      }
211
0
      continue;
212
0
  }
213
0
  if (MATCHES(*cur, "cmnd_chroot=")) {
214
0
      CHECK(*cur, "cmnd_chroot=");
215
0
      ctx->runas.chroot = *cur + sizeof("cmnd_chroot=") - 1;
216
0
      if (strlen(ctx->runas.chroot) >= PATH_MAX) {
217
0
    sudo_warnx(U_("path name for \"%s\" too long"), "cmnd_chroot");
218
0
    goto bad;
219
0
      }
220
0
      continue;
221
0
  }
222
0
  if (MATCHES(*cur, "cmnd_cwd=")) {
223
0
      CHECK(*cur, "cmnd_cwd=");
224
0
      ctx->runas.cwd = *cur + sizeof("cmnd_cwd=") - 1;
225
0
      if (strlen(ctx->runas.cwd) >= PATH_MAX) {
226
0
    sudo_warnx(U_("path name for \"%s\" too long"), "cmnd_cwd");
227
0
    goto bad;
228
0
      }
229
0
      continue;
230
0
  }
231
0
  if (MATCHES(*cur, "runas_user=")) {
232
0
      CHECK(*cur, "runas_user=");
233
0
      ctx->runas.user = *cur + sizeof("runas_user=") - 1;
234
0
      if (strlen(ctx->runas.user) >= login_name_max) {
235
0
    errno = ENAMETOOLONG;
236
0
    sudo_warn("runas_user");
237
0
    goto bad;
238
0
      }
239
0
      SET(ctx->settings.flags, RUNAS_USER_SPECIFIED);
240
0
      continue;
241
0
  }
242
0
  if (MATCHES(*cur, "runas_group=")) {
243
0
      CHECK(*cur, "runas_group=");
244
0
      ctx->runas.group = *cur + sizeof("runas_group=") - 1;
245
0
      if (strlen(ctx->runas.group) >= login_name_max) {
246
0
    errno = ENAMETOOLONG;
247
0
    sudo_warn("runas_group");
248
0
    goto bad;
249
0
      }
250
0
      SET(ctx->settings.flags, RUNAS_GROUP_SPECIFIED);
251
0
      continue;
252
0
  }
253
0
  if (MATCHES(*cur, "prompt=")) {
254
      /* Allow empty prompt. */
255
0
      ctx->user.prompt = *cur + sizeof("prompt=") - 1;
256
0
      if (!append_default("passprompt_override", NULL, true, NULL, defaults))
257
0
    goto oom;
258
0
      continue;
259
0
  }
260
0
  if (MATCHES(*cur, "set_home=")) {
261
0
      if (parse_bool(*cur, sizeof("set_home") - 1, &flags,
262
0
    MODE_RESET_HOME) == -1)
263
0
    goto bad;
264
0
      continue;
265
0
  }
266
0
  if (MATCHES(*cur, "preserve_environment=")) {
267
0
      if (parse_bool(*cur, sizeof("preserve_environment") - 1, &flags,
268
0
    MODE_PRESERVE_ENV) == -1)
269
0
    goto bad;
270
0
      continue;
271
0
  }
272
0
  if (MATCHES(*cur, "run_shell=")) {
273
0
      if (parse_bool(*cur, sizeof("run_shell") -1, &flags,
274
0
    MODE_SHELL) == -1)
275
0
    goto bad;
276
0
      continue;
277
0
  }
278
0
  if (MATCHES(*cur, "login_shell=")) {
279
0
      if (parse_bool(*cur, sizeof("login_shell") - 1, &flags,
280
0
    MODE_LOGIN_SHELL) == -1)
281
0
    goto bad;
282
0
      continue;
283
0
  }
284
0
  if (MATCHES(*cur, "implied_shell=")) {
285
0
      if (parse_bool(*cur, sizeof("implied_shell") - 1, &flags,
286
0
    MODE_IMPLIED_SHELL) == -1)
287
0
    goto bad;
288
0
      continue;
289
0
  }
290
0
  if (MATCHES(*cur, "preserve_groups=")) {
291
0
      if (parse_bool(*cur, sizeof("preserve_groups") - 1, &flags,
292
0
    MODE_PRESERVE_GROUPS) == -1)
293
0
    goto bad;
294
0
      continue;
295
0
  }
296
0
  if (MATCHES(*cur, "ignore_ticket=")) {
297
0
      if (parse_bool(*cur, sizeof("ignore_ticket") -1, &flags,
298
0
    MODE_IGNORE_TICKET) == -1)
299
0
    goto bad;
300
0
      continue;
301
0
  }
302
0
  if (MATCHES(*cur, "update_ticket=")) {
303
0
      if (parse_bool(*cur, sizeof("update_ticket") -1, &flags,
304
0
    MODE_UPDATE_TICKET) == -1)
305
0
    goto bad;
306
0
      continue;
307
0
  }
308
0
  if (MATCHES(*cur, "noninteractive=")) {
309
0
      if (parse_bool(*cur, sizeof("noninteractive") - 1, &flags,
310
0
    MODE_NONINTERACTIVE) == -1)
311
0
    goto bad;
312
0
      continue;
313
0
  }
314
0
  if (MATCHES(*cur, "sudoedit=")) {
315
0
      if (parse_bool(*cur, sizeof("sudoedit") - 1, &flags,
316
0
    MODE_EDIT) == -1)
317
0
    goto bad;
318
0
      continue;
319
0
  }
320
0
  if (MATCHES(*cur, "login_class=")) {
321
0
      CHECK(*cur, "login_class=");
322
0
      ctx->runas.class = *cur + sizeof("login_class=") - 1;
323
0
      if (strlen(ctx->runas.class) >= 1024) {
324
0
    errno = ENAMETOOLONG;
325
0
    sudo_warn("login_class");
326
0
    goto bad;
327
0
      }
328
0
      if (!append_default("use_loginclass", NULL, true, NULL, defaults))
329
0
    goto oom;
330
0
      continue;
331
0
  }
332
0
  if (MATCHES(*cur, "intercept_ptrace=")) {
333
0
      if (parse_bool(*cur, sizeof("intercept_ptrace") - 1, &ctx->settings.flags,
334
0
        HAVE_INTERCEPT_PTRACE) == -1)
335
0
    goto bad;
336
0
      continue;
337
0
  }
338
0
  if (MATCHES(*cur, "intercept_setid=")) {
339
0
      if (parse_bool(*cur, sizeof("intercept_setid") - 1, &ctx->settings.flags,
340
0
        CAN_INTERCEPT_SETID) == -1)
341
0
    goto bad;
342
0
      continue;
343
0
  }
344
0
  if (MATCHES(*cur, "selinux_role=")) {
345
0
      CHECK(*cur, "selinux_role=");
346
0
      p = *cur + sizeof("selinux_role=") - 1;
347
0
      if (strlen(p) >= 1024) {
348
0
    errno = ENAMETOOLONG;
349
0
    sudo_warn("selinux_role");
350
0
    goto bad;
351
0
      }
352
0
      free(ctx->runas.role);
353
0
      if ((ctx->runas.role = strdup(p)) == NULL)
354
0
    goto oom;
355
0
      continue;
356
0
  }
357
0
  if (MATCHES(*cur, "selinux_type=")) {
358
0
      CHECK(*cur, "selinux_type=");
359
0
      p = *cur + sizeof("selinux_type=") - 1;
360
0
      if (strlen(p) >= 1024) {
361
0
    errno = ENAMETOOLONG;
362
0
    sudo_warn("selinux_type");
363
0
    goto bad;
364
0
      }
365
0
      free(ctx->runas.type);
366
0
      if ((ctx->runas.type = strdup(p)) == NULL)
367
0
    goto oom;
368
0
      continue;
369
0
  }
370
#ifdef HAVE_BSD_AUTH_H
371
  if (MATCHES(*cur, "bsdauth_type=")) {
372
      CHECK(*cur, "bsdauth_type=");
373
      p = *cur + sizeof("bsdauth_type=") - 1;
374
      if (strlen(p) >= 1024) {
375
    errno = ENAMETOOLONG;
376
    sudo_warn("bsdauth_type");
377
    goto bad;
378
      }
379
      bsdauth_set_style(p);
380
      continue;
381
  }
382
#endif /* HAVE_BSD_AUTH_H */
383
0
  if (MATCHES(*cur, "network_addrs=")) {
384
0
      interfaces_string = *cur + sizeof("network_addrs=") - 1;
385
0
      if (!set_interfaces(interfaces_string)) {
386
0
    sudo_warn("%s", U_("unable to parse network address list"));
387
0
    goto bad;
388
0
      }
389
0
      continue;
390
0
  }
391
0
  if (MATCHES(*cur, "max_groups=")) {
392
0
      int max_groups;
393
0
      p = *cur + sizeof("max_groups=") - 1;
394
0
      max_groups = (int)sudo_strtonum(p, 1, 1024, &errstr);
395
0
      if (max_groups == 0) {
396
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
397
0
    goto bad;
398
0
      }
399
0
      sudo_pwutil_set_max_groups(max_groups);
400
0
      continue;
401
0
  }
402
0
  if (MATCHES(*cur, "remote_host=")) {
403
0
      CHECK(*cur, "remote_host=");
404
0
      p = *cur + sizeof("remote_host=") - 1;
405
0
      if (strlen(p) >= host_name_max) {
406
0
    errno = ENAMETOOLONG;
407
0
    sudo_warn("remote_host");
408
0
    goto bad;
409
0
      }
410
0
      remhost = p;
411
0
      continue;
412
0
  }
413
0
  if (MATCHES(*cur, "timeout=")) {
414
0
      p = *cur + sizeof("timeout=") - 1;
415
0
      ctx->user.timeout = parse_timeout(p);
416
0
      if (ctx->user.timeout == -1) {
417
0
    if (errno == ERANGE)
418
0
        sudo_warnx(U_("%s: %s"), p, U_("timeout value too large"));
419
0
    else
420
0
        sudo_warnx(U_("%s: %s"), p, U_("invalid timeout value"));
421
0
    goto bad;
422
0
      }
423
0
      continue;
424
0
  }
425
0
  if (MATCHES(*cur, "askpass=")) {
426
0
      if (parse_bool(*cur, sizeof("askpass") - 1, &flags,
427
0
    MODE_ASKPASS) == -1)
428
0
    goto bad;
429
0
      continue;
430
0
  }
431
#ifdef ENABLE_SUDO_PLUGIN_API
432
  if (MATCHES(*cur, "plugin_dir=")) {
433
      CHECK(*cur, "plugin_dir=");
434
      p = *cur + sizeof("plugin_dir=") - 1;
435
      if (strlen(p) >= PATH_MAX) {
436
    sudo_warnx(U_("path name for \"%s\" too long"), "plugin_dir");
437
    goto bad;
438
      }
439
      ctx->settings.plugin_dir = p;
440
      continue;
441
  }
442
#endif
443
0
    }
444
    /* Ignore ticket trumps update. */
445
0
    if (ISSET(flags, MODE_IGNORE_TICKET))
446
0
  CLR(flags, MODE_UPDATE_TICKET);
447
448
0
    ctx->user.gid = (gid_t)-1;
449
0
    ctx->user.uid = (gid_t)-1;
450
0
    ctx->user.umask = (mode_t)-1;
451
0
    ctx->user.ttydev = NODEV;
452
0
    for (cur = info->user_info; *cur != NULL; cur++) {
453
0
  if (MATCHES(*cur, "user=")) {
454
0
      CHECK(*cur, "user=");
455
0
      p = *cur + sizeof("user=") - 1;
456
0
      if (strlen(p) >= login_name_max) {
457
0
    errno = ENAMETOOLONG;
458
0
    sudo_warn("user");
459
0
    goto bad;
460
0
      }
461
0
      free(ctx->user.name);
462
0
      if ((ctx->user.name = strdup(p)) == NULL)
463
0
    goto oom;
464
0
      continue;
465
0
  }
466
0
  if (MATCHES(*cur, "euid=")) {
467
0
      p = *cur + sizeof("euid=") - 1;
468
0
      ctx->user.euid = (uid_t) sudo_strtoid(p, &errstr);
469
0
      if (errstr != NULL) {
470
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
471
0
    goto bad;
472
0
      }
473
0
      continue;
474
0
  }
475
0
  if (MATCHES(*cur, "uid=")) {
476
0
      p = *cur + sizeof("uid=") - 1;
477
0
      ctx->user.uid = (uid_t) sudo_strtoid(p, &errstr);
478
0
      if (errstr != NULL) {
479
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
480
0
    goto bad;
481
0
      }
482
0
      continue;
483
0
  }
484
0
  if (MATCHES(*cur, "egid=")) {
485
0
      p = *cur + sizeof("egid=") - 1;
486
0
      ctx->user.egid = (gid_t) sudo_strtoid(p, &errstr);
487
0
      if (errstr != NULL) {
488
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
489
0
    goto bad;
490
0
      }
491
0
      continue;
492
0
  }
493
0
  if (MATCHES(*cur, "gid=")) {
494
0
      p = *cur + sizeof("gid=") - 1;
495
0
      ctx->user.gid = (gid_t) sudo_strtoid(p, &errstr);
496
0
      if (errstr != NULL) {
497
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
498
0
    goto bad;
499
0
      }
500
0
      continue;
501
0
  }
502
0
  if (MATCHES(*cur, "groups=")) {
503
0
      CHECK(*cur, "groups=");
504
0
      groups = *cur + sizeof("groups=") - 1;
505
0
      continue;
506
0
  }
507
0
  if (MATCHES(*cur, "cwd=")) {
508
0
      CHECK(*cur, "cwd=");
509
0
      p = *cur + sizeof("cwd=") - 1;
510
      /* It is possible for the actual cwd to be larger than PATH_MAX. */
511
0
      if (strlen(p) >= PATH_MAX * 2) {
512
0
    sudo_warnx(U_("path name for \"%s\" too long"), "cwd");
513
0
    goto bad;
514
0
      }
515
0
      free(ctx->user.cwd);
516
0
      if ((ctx->user.cwd = strdup(p)) == NULL)
517
0
    goto oom;
518
0
      continue;
519
0
  }
520
0
  if (MATCHES(*cur, "tty=")) {
521
0
      CHECK(*cur, "tty=");
522
0
      p = *cur + sizeof("tty=") - 1;
523
0
      if (strlen(p) >= PATH_MAX) {
524
0
    sudo_warnx(U_("path name for \"%s\" too long"), "tty");
525
0
    goto bad;
526
0
      }
527
0
      free(ctx->user.ttypath);
528
0
      if ((ctx->user.ttypath = strdup(p)) == NULL)
529
0
    goto oom;
530
0
      ctx->user.tty = ctx->user.ttypath;
531
0
      if (strncmp(ctx->user.tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
532
0
    ctx->user.tty += sizeof(_PATH_DEV) - 1;
533
0
      continue;
534
0
  }
535
0
  if (MATCHES(*cur, "ttydev=")) {
536
0
      long long llval;
537
538
      /*
539
       * dev_t can be signed or unsigned.  The front-end formats it
540
       * as long long (signed).  We allow the full range of values
541
       * which should work with either signed or unsigned dev_t.
542
       */
543
0
      p = *cur + sizeof("ttydev=") - 1;
544
0
      llval = sudo_strtonum(p, LLONG_MIN, LLONG_MAX, &errstr);
545
0
      if (errstr != NULL) {
546
    /* Front end bug?  Not a fatal error. */
547
0
    INVALID("ttydev=");
548
0
    continue;
549
0
      }
550
0
      ctx->user.ttydev = (dev_t)llval;
551
0
      continue;
552
0
  }
553
0
  if (MATCHES(*cur, "host=")) {
554
0
      CHECK(*cur, "host=");
555
0
      p = *cur + sizeof("host=") - 1;
556
0
      if (strlen(p) >= host_name_max) {
557
0
    errno = ENAMETOOLONG;
558
0
    sudo_warnx("host");
559
0
    goto bad;
560
0
      }
561
0
      host = p;
562
0
      continue;
563
0
  }
564
0
  if (MATCHES(*cur, "lines=")) {
565
0
      p = *cur + sizeof("lines=") - 1;
566
0
      ctx->user.lines = (int)sudo_strtonum(p, 1, INT_MAX, &errstr);
567
0
      if (ctx->user.lines == 0) {
568
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
569
0
    goto bad;
570
0
      }
571
0
      continue;
572
0
  }
573
0
  if (MATCHES(*cur, "cols=")) {
574
0
      p = *cur + sizeof("cols=") - 1;
575
0
      ctx->user.cols = (int)sudo_strtonum(p, 1, INT_MAX, &errstr);
576
0
      if (ctx->user.cols == 0) {
577
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
578
0
    goto bad;
579
0
      }
580
0
      continue;
581
0
  }
582
0
  if (MATCHES(*cur, "pid=")) {
583
0
      p = *cur + sizeof("pid=") - 1;
584
0
      ctx->user.pid = (pid_t) sudo_strtoid(p, &errstr);
585
0
      if (errstr != NULL) {
586
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
587
0
    goto bad;
588
0
      }
589
0
      continue;
590
0
  }
591
0
  if (MATCHES(*cur, "ppid=")) {
592
0
      p = *cur + sizeof("ppid=") - 1;
593
0
      ctx->user.ppid = (pid_t) sudo_strtoid(p, &errstr);
594
0
      if (errstr != NULL) {
595
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
596
0
    goto bad;
597
0
      }
598
0
      continue;
599
0
  }
600
0
  if (MATCHES(*cur, "sid=")) {
601
0
      p = *cur + sizeof("sid=") - 1;
602
0
      ctx->user.sid = (pid_t) sudo_strtoid(p, &errstr);
603
0
      if (errstr != NULL) {
604
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
605
0
    goto bad;
606
0
      }
607
0
      continue;
608
0
  }
609
0
  if (MATCHES(*cur, "tcpgid=")) {
610
0
      p = *cur + sizeof("tcpgid=") - 1;
611
0
      ctx->user.tcpgid = (pid_t) sudo_strtoid(p, &errstr);
612
0
      if (errstr != NULL) {
613
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
614
0
    goto bad;
615
0
      }
616
0
      continue;
617
0
  }
618
0
  if (MATCHES(*cur, "umask=")) {
619
0
      p = *cur + sizeof("umask=") - 1;
620
0
      ctx->user.umask = sudo_strtomode(p, &errstr);
621
0
      if (errstr != NULL) {
622
0
    sudo_warnx(U_("%s: %s"), *cur, U_(errstr));
623
0
    goto bad;
624
0
      }
625
0
      continue;
626
0
  }
627
0
    }
628
629
    /* User name, user-ID, group-ID and host name must be specified. */
630
0
    if (ctx->user.name == NULL) {
631
0
  sudo_warnx("%s", U_("user name not set by sudo front-end"));
632
0
  goto bad;
633
0
    }
634
0
    if (ctx->user.uid == (uid_t)-1) {
635
0
  sudo_warnx("%s", U_("user-ID not set by sudo front-end"));
636
0
  goto bad;
637
0
    }
638
0
    if (ctx->user.gid == (gid_t)-1) {
639
0
  sudo_warnx("%s", U_("group-ID not set by sudo front-end"));
640
0
  goto bad;
641
0
    }
642
0
    if (host == NULL) {
643
0
  sudo_warnx("%s", U_("host name not set by sudo front-end"));
644
0
  goto bad;
645
0
    }
646
647
0
    if (!sudoers_sethost(ctx, host, remhost)) {
648
  /* sudoers_sethost() will print a warning on error. */
649
0
  goto bad;
650
0
    }
651
0
    if (ctx->user.tty == NULL) {
652
0
  if ((ctx->user.tty = strdup("unknown")) == NULL)
653
0
      goto oom;
654
  /* ctx->user.ttypath remains NULL */
655
0
    }
656
657
0
    ctx->user.pw = sudo_getpwnam(ctx->user.name);
658
0
    if (ctx->user.pw != NULL && groups != NULL) {
659
  /* sudo_parse_gids() will print a warning on error. */
660
0
  GETGROUPS_T *gids;
661
0
  int ngids = sudo_parse_gids(groups, &ctx->user.gid, &gids);
662
0
  if (ngids == -1)
663
0
      goto bad;
664
665
  /* sudo_set_gidlist will adopt gids[] */
666
0
  if (sudo_set_gidlist(ctx->user.pw, ngids, gids, NULL, ENTRY_TYPE_FRONTEND) == -1) {
667
0
      free(gids);
668
0
      goto bad;
669
0
  }
670
0
    }
671
672
    /* ttydev is only set in user_info[] for API 1.22 and above. */
673
0
    if (ctx->user.ttydev == NODEV && ctx->user.ttypath != NULL) {
674
0
  struct stat sb;
675
0
  if (stat(ctx->user.ttypath, &sb) == 0)
676
0
      ctx->user.ttydev = sb.st_rdev;
677
0
  else
678
0
      sudo_warn("%s", ctx->user.ttypath);
679
0
    }
680
681
    /* umask is only set in user_info[] for API 1.10 and above. */
682
0
    if (ctx->user.umask == (mode_t)-1) {
683
0
  ctx->user.umask = umask(0);
684
0
  umask(ctx->user.umask);
685
0
    }
686
687
    /* Always reset the environment for a login shell. */
688
0
    if (ISSET(flags, MODE_LOGIN_SHELL))
689
0
  def_env_reset = true;
690
691
    /* Some systems support fexecve() which we use for digest matches. */
692
0
    ctx->runas.execfd = -1;
693
694
    /* Create a UUID to store in the event log. */
695
0
    sudo_uuid_create(uuid);
696
0
    if (sudo_uuid_to_string(uuid, ctx->uuid_str, sizeof(ctx->uuid_str)) == NULL) {
697
0
  sudo_warnx("%s", U_("unable to generate UUID"));
698
0
  goto bad;
699
0
    }
700
701
    /*
702
     * Set intercept defaults based on flags set above.
703
     * We pass -1 as the operator to indicate it is set by the front end.
704
     */
705
0
    if (ISSET(ctx->settings.flags, HAVE_INTERCEPT_PTRACE)) {
706
0
  if (!append_default("intercept_type", "trace", -1, NULL, defaults))
707
0
      goto oom;
708
0
    }
709
0
    if (ISSET(ctx->settings.flags, CAN_INTERCEPT_SETID)) {
710
0
  if (!append_default("intercept_allow_setid", NULL, -1, NULL, defaults))
711
0
      goto oom;
712
0
    }
713
714
#ifdef NO_ROOT_MAILER
715
    eventlog_set_maileruser(ctx->user.name, ctx->user.uid, ctx->user.gid);
716
#endif
717
718
    /* Dump settings and user info (XXX - plugin args) */
719
0
    for (cur = info->settings; *cur != NULL; cur++)
720
0
  sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur);
721
0
    for (cur = info->user_info; *cur != NULL; cur++)
722
0
  sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur);
723
724
0
#undef MATCHES
725
0
#undef INVALID
726
0
#undef CHECK
727
0
    debug_return_uint(flags);
728
729
0
oom:
730
0
    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
731
0
bad:
732
0
    debug_return_uint(MODE_ERROR);
733
0
}
734
735
/*
736
 * Store the execution environment and other front-end settings.
737
 * Builds up the command_info list and sets argv and envp.
738
 * Consumes iolog_path if not NULL.
739
 * Returns true on success, else false.
740
 */
741
bool
742
sudoers_policy_store_result(struct sudoers_context *ctx, bool accepted,
743
    char *argv[], char *envp[], mode_t cmnd_umask, char *iolog_path, void *v)
744
0
{
745
0
    struct sudoers_exec_args *exec_args = v;
746
0
    unsigned int info_len = 0;
747
0
    debug_decl(sudoers_policy_store_result, SUDOERS_DEBUG_PLUGIN);
748
749
0
    if (exec_args == NULL)
750
0
  debug_return_bool(true); /* nothing to do */
751
752
    /* Free old data, if any. */
753
0
    if (command_info != NULL) {
754
0
  char **cur;
755
0
  sudoers_gc_remove(GC_VECTOR, command_info);
756
0
  for (cur = command_info; *cur != NULL; cur++)
757
0
      free(*cur);
758
0
  free(command_info);
759
0
    }
760
761
    /* Increase the length of command_info as needed, it is *not* checked. */
762
0
    command_info = calloc(74, sizeof(char *));
763
0
    if (command_info == NULL)
764
0
  goto oom;
765
766
0
    if (ctx->runas.cmnd != NULL) {
767
0
  command_info[info_len] = sudo_new_key_val("command", ctx->runas.cmnd);
768
0
  if (command_info[info_len++] == NULL)
769
0
      goto oom;
770
0
    }
771
0
    if (def_log_subcmds) {
772
0
  if ((command_info[info_len++] = strdup("log_subcmds=true")) == NULL)
773
0
      goto oom;
774
0
    }
775
0
    if (iolog_enabled) {
776
0
  if (iolog_path)
777
0
      command_info[info_len++] = iolog_path; /* now owned */
778
0
  if (def_log_stdin) {
779
0
      if ((command_info[info_len++] = strdup("iolog_stdin=true")) == NULL)
780
0
    goto oom;
781
0
  }
782
0
  if (def_log_stdout) {
783
0
      if ((command_info[info_len++] = strdup("iolog_stdout=true")) == NULL)
784
0
    goto oom;
785
0
  }
786
0
  if (def_log_stderr) {
787
0
      if ((command_info[info_len++] = strdup("iolog_stderr=true")) == NULL)
788
0
    goto oom;
789
0
  }
790
0
  if (def_log_ttyin) {
791
0
      if ((command_info[info_len++] = strdup("iolog_ttyin=true")) == NULL)
792
0
    goto oom;
793
0
  }
794
0
  if (def_log_ttyout) {
795
0
      if ((command_info[info_len++] = strdup("iolog_ttyout=true")) == NULL)
796
0
    goto oom;
797
0
  }
798
0
  if (def_compress_io) {
799
0
      if ((command_info[info_len++] = strdup("iolog_compress=true")) == NULL)
800
0
    goto oom;
801
0
  }
802
0
  if (def_iolog_flush) {
803
0
      if ((command_info[info_len++] = strdup("iolog_flush=true")) == NULL)
804
0
    goto oom;
805
0
  }
806
0
  if ((command_info[info_len++] = sudo_new_key_val("log_passwords",
807
0
    def_log_passwords ? "true" : "false")) == NULL)
808
0
      goto oom;
809
0
  if (!SLIST_EMPTY(&def_passprompt_regex)) {
810
0
      char *passprompt_regex =
811
0
    serialize_list("passprompt_regex", &def_passprompt_regex);
812
0
      if (passprompt_regex == NULL)
813
0
    goto oom;
814
0
      command_info[info_len++] = passprompt_regex;
815
0
  }
816
0
  if (def_maxseq != NULL) {
817
0
      if ((command_info[info_len++] = sudo_new_key_val("maxseq", def_maxseq)) == NULL)
818
0
    goto oom;
819
0
  }
820
0
    }
821
0
    if (ISSET(ctx->mode, MODE_EDIT)) {
822
0
  if ((command_info[info_len++] = strdup("sudoedit=true")) == NULL)
823
0
      goto oom;
824
0
  if (ctx->sudoedit_nfiles > 0) {
825
0
      if (asprintf(&command_info[info_len++], "sudoedit_nfiles=%d",
826
0
    ctx->sudoedit_nfiles) == -1)
827
0
    goto oom;
828
0
  }
829
0
  if (!def_sudoedit_checkdir) {
830
0
      if ((command_info[info_len++] = strdup("sudoedit_checkdir=false")) == NULL)
831
0
    goto oom;
832
0
  }
833
0
  if (def_sudoedit_follow) {
834
0
      if ((command_info[info_len++] = strdup("sudoedit_follow=true")) == NULL)
835
0
    goto oom;
836
0
  }
837
0
    }
838
0
    if (def_runcwd && strcmp(def_runcwd, "*") != 0) {
839
  /* Set cwd to explicit value (sudoers or user-specified). */
840
0
  if (!expand_tilde(&def_runcwd, ctx->runas.pw->pw_name)) {
841
0
      sudo_warnx(U_("invalid working directory: %s"), def_runcwd);
842
0
      goto bad;
843
0
  }
844
0
  if ((command_info[info_len++] = sudo_new_key_val("cwd", def_runcwd)) == NULL)
845
0
      goto oom;
846
0
    } else if (ISSET(ctx->mode, MODE_LOGIN_SHELL)) {
847
  /* Set cwd to run user's homedir. */
848
0
  if ((command_info[info_len++] = sudo_new_key_val("cwd", ctx->runas.pw->pw_dir)) == NULL)
849
0
      goto oom;
850
0
  if ((command_info[info_len++] = strdup("cwd_optional=true")) == NULL)
851
0
      goto oom;
852
0
    }
853
0
    if ((command_info[info_len++] = sudo_new_key_val("runas_user", ctx->runas.pw->pw_name)) == NULL)
854
0
  goto oom;
855
0
    if (ctx->runas.gr != NULL) {
856
0
  if ((command_info[info_len++] = sudo_new_key_val("runas_group", ctx->runas.gr->gr_name)) == NULL)
857
0
      goto oom;
858
0
    }
859
0
    if (def_stay_setuid) {
860
0
  if (asprintf(&command_info[info_len++], "runas_uid=%u",
861
0
      (unsigned int)ctx->user.uid) == -1)
862
0
      goto oom;
863
0
  if (asprintf(&command_info[info_len++], "runas_gid=%u",
864
0
      (unsigned int)ctx->user.gid) == -1)
865
0
      goto oom;
866
0
  if (asprintf(&command_info[info_len++], "runas_euid=%u",
867
0
      (unsigned int)ctx->runas.pw->pw_uid) == -1)
868
0
      goto oom;
869
0
  if (asprintf(&command_info[info_len++], "runas_egid=%u",
870
0
      ctx->runas.gr ? (unsigned int)ctx->runas.gr->gr_gid :
871
0
      (unsigned int)ctx->runas.pw->pw_gid) == -1)
872
0
      goto oom;
873
0
    } else {
874
0
  if (asprintf(&command_info[info_len++], "runas_uid=%u",
875
0
      (unsigned int)ctx->runas.pw->pw_uid) == -1)
876
0
      goto oom;
877
0
  if (asprintf(&command_info[info_len++], "runas_gid=%u",
878
0
      ctx->runas.gr ? (unsigned int)ctx->runas.gr->gr_gid :
879
0
      (unsigned int)ctx->runas.pw->pw_gid) == -1)
880
0
      goto oom;
881
0
    }
882
0
    if (def_preserve_groups) {
883
0
  if ((command_info[info_len++] = strdup("preserve_groups=true")) == NULL)
884
0
      goto oom;
885
0
    } else {
886
0
  int i, len;
887
0
  gid_t egid;
888
0
  size_t glsize;
889
0
  char *cp, *gid_list;
890
0
  struct gid_list *gidlist;
891
892
  /* Only use results from a group db query, not the front end. */
893
0
  if ((gidlist = sudo_get_gidlist(ctx->runas.pw, ENTRY_TYPE_QUERIED)) == NULL)
894
0
      goto oom;
895
896
  /* We reserve an extra spot in the list for the effective gid. */
897
0
  glsize = sizeof("runas_groups=") - 1 +
898
0
      (((size_t)gidlist->ngids + 1) * (STRLEN_MAX_UNSIGNED(gid_t) + 1));
899
0
  gid_list = malloc(glsize);
900
0
  if (gid_list == NULL) {
901
0
      sudo_gidlist_delref(gidlist);
902
0
      goto oom;
903
0
  }
904
0
  memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
905
0
  cp = gid_list + sizeof("runas_groups=") - 1;
906
0
  glsize -= (size_t)(cp - gid_list);
907
908
  /* On BSD systems the effective gid is the first group in the list. */
909
0
  egid = ctx->runas.gr ? (unsigned int)ctx->runas.gr->gr_gid :
910
0
      (unsigned int)ctx->runas.pw->pw_gid;
911
0
  len = snprintf(cp, glsize, "%u", (unsigned int)egid);
912
0
  if (len < 0 || (size_t)len >= glsize) {
913
0
      sudo_warnx(U_("internal error, %s overflow"), __func__);
914
0
      free(gid_list);
915
0
      sudo_gidlist_delref(gidlist);
916
0
      goto bad;
917
0
  }
918
0
  cp += len;
919
0
  glsize -= (size_t)len;
920
0
  for (i = 0; i < gidlist->ngids; i++) {
921
0
      if (gidlist->gids[i] != egid) {
922
0
    len = snprintf(cp, glsize, ",%u",
923
0
         (unsigned int)gidlist->gids[i]);
924
0
    if (len < 0 || (size_t)len >= glsize) {
925
0
        sudo_warnx(U_("internal error, %s overflow"), __func__);
926
0
        free(gid_list);
927
0
        sudo_gidlist_delref(gidlist);
928
0
        goto bad;
929
0
    }
930
0
    cp += len;
931
0
    glsize -= (size_t)len;
932
0
      }
933
0
  }
934
0
  command_info[info_len++] = gid_list;
935
0
  sudo_gidlist_delref(gidlist);
936
0
    }
937
0
    if (def_closefrom >= 0) {
938
0
  if (asprintf(&command_info[info_len++], "closefrom=%d", def_closefrom) == -1)
939
0
      goto oom;
940
0
    }
941
0
    if (def_ignore_iolog_errors) {
942
0
  if ((command_info[info_len++] = strdup("ignore_iolog_errors=true")) == NULL)
943
0
      goto oom;
944
0
    }
945
0
    if (def_intercept) {
946
0
  if ((command_info[info_len++] = strdup("intercept=true")) == NULL)
947
0
      goto oom;
948
0
    }
949
0
    if (def_intercept_type == trace) {
950
0
  if ((command_info[info_len++] = strdup("use_ptrace=true")) == NULL)
951
0
      goto oom;
952
0
    }
953
0
    if (def_intercept_verify) {
954
0
  if ((command_info[info_len++] = strdup("intercept_verify=true")) == NULL)
955
0
      goto oom;
956
0
    }
957
0
    if (def_noexec) {
958
0
  if ((command_info[info_len++] = strdup("noexec=true")) == NULL)
959
0
      goto oom;
960
0
    }
961
0
    if (def_exec_background) {
962
0
  if ((command_info[info_len++] = strdup("exec_background=true")) == NULL)
963
0
      goto oom;
964
0
    }
965
0
    if (def_set_utmp) {
966
0
  if ((command_info[info_len++] = strdup("set_utmp=true")) == NULL)
967
0
      goto oom;
968
0
    }
969
0
    if (def_use_pty) {
970
0
  if ((command_info[info_len++] = strdup("use_pty=true")) == NULL)
971
0
      goto oom;
972
0
    }
973
0
    if (def_utmp_runas) {
974
0
  if ((command_info[info_len++] = sudo_new_key_val("utmp_user", ctx->runas.pw->pw_name)) == NULL)
975
0
      goto oom;
976
0
    }
977
0
    if (def_iolog_mode != (S_IRUSR|S_IWUSR)) {
978
0
  if (asprintf(&command_info[info_len++], "iolog_mode=0%o", (unsigned int)def_iolog_mode) == -1)
979
0
      goto oom;
980
0
    }
981
0
    if (def_iolog_user != NULL) {
982
0
  if ((command_info[info_len++] = sudo_new_key_val("iolog_user", def_iolog_user)) == NULL)
983
0
      goto oom;
984
0
    }
985
0
    if (def_iolog_group != NULL) {
986
0
  if ((command_info[info_len++] = sudo_new_key_val("iolog_group", def_iolog_group)) == NULL)
987
0
      goto oom;
988
0
    }
989
0
    if (!SLIST_EMPTY(&def_log_servers)) {
990
0
  char *log_servers = serialize_list("log_servers", &def_log_servers);
991
0
  if (log_servers == NULL)
992
0
      goto oom;
993
0
  command_info[info_len++] = log_servers;
994
995
0
  if (asprintf(&command_info[info_len++], "log_server_timeout=%u", def_log_server_timeout) == -1)
996
0
      goto oom;
997
0
    }
998
999
0
    if ((command_info[info_len++] = sudo_new_key_val("log_server_keepalive",
1000
0
      def_log_server_keepalive ? "true" : "false")) == NULL)
1001
0
        goto oom;
1002
1003
0
    if ((command_info[info_len++] = sudo_new_key_val("log_server_verify",
1004
0
      def_log_server_verify ? "true" : "false")) == NULL)
1005
0
        goto oom;
1006
1007
0
    if (def_log_server_cabundle != NULL) {
1008
0
        if ((command_info[info_len++] = sudo_new_key_val("log_server_cabundle", def_log_server_cabundle)) == NULL)
1009
0
            goto oom;
1010
0
    }
1011
0
    if (def_log_server_peer_cert != NULL) {
1012
0
        if ((command_info[info_len++] = sudo_new_key_val("log_server_peer_cert", def_log_server_peer_cert)) == NULL)
1013
0
            goto oom;
1014
0
    }
1015
0
    if (def_log_server_peer_key != NULL) {
1016
0
        if ((command_info[info_len++] = sudo_new_key_val("log_server_peer_key", def_log_server_peer_key)) == NULL)
1017
0
            goto oom;
1018
0
    }
1019
1020
0
    if (def_command_timeout > 0 || ctx->user.timeout > 0) {
1021
0
  int timeout = ctx->user.timeout;
1022
0
    if (timeout == 0 || (def_command_timeout > 0 && def_command_timeout < timeout))
1023
0
      timeout = def_command_timeout;
1024
0
  if (asprintf(&command_info[info_len++], "timeout=%u", timeout) == -1)
1025
0
      goto oom;
1026
0
    }
1027
0
    if (def_runchroot != NULL && strcmp(def_runchroot, "*") != 0) {
1028
0
  if (!expand_tilde(&def_runchroot, ctx->runas.pw->pw_name)) {
1029
0
      sudo_warnx(U_("invalid chroot directory: %s"), def_runchroot);
1030
0
      goto bad;
1031
0
  }
1032
0
        if ((command_info[info_len++] = sudo_new_key_val("chroot", def_runchroot)) == NULL)
1033
0
            goto oom;
1034
0
    }
1035
0
    if (cmnd_umask != ACCESSPERMS) {
1036
0
  if (asprintf(&command_info[info_len++], "umask=0%o", (unsigned int)cmnd_umask) == -1)
1037
0
      goto oom;
1038
0
    }
1039
0
    if (sudoers_override_umask()) {
1040
0
  if ((command_info[info_len++] = strdup("umask_override=true")) == NULL)
1041
0
      goto oom;
1042
0
    }
1043
0
    if (ctx->runas.execfd != -1) {
1044
0
  if (sudo_version < SUDO_API_MKVERSION(1, 9)) {
1045
      /* execfd only supported by plugin API 1.9 and higher */
1046
0
      close(ctx->runas.execfd);
1047
0
      ctx->runas.execfd = -1;
1048
0
  } else {
1049
0
      if (asprintf(&command_info[info_len++], "execfd=%d", ctx->runas.execfd) == -1)
1050
0
    goto oom;
1051
0
  }
1052
0
    }
1053
0
    if (def_rlimit_as != NULL) {
1054
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_as", def_rlimit_as)) == NULL)
1055
0
            goto oom;
1056
0
    }
1057
0
    if (def_rlimit_core != NULL) {
1058
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_core", def_rlimit_core)) == NULL)
1059
0
            goto oom;
1060
0
    }
1061
0
    if (def_rlimit_cpu != NULL) {
1062
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_cpu", def_rlimit_cpu)) == NULL)
1063
0
            goto oom;
1064
0
    }
1065
0
    if (def_rlimit_data != NULL) {
1066
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_data", def_rlimit_data)) == NULL)
1067
0
            goto oom;
1068
0
    }
1069
0
    if (def_rlimit_fsize != NULL) {
1070
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_fsize", def_rlimit_fsize)) == NULL)
1071
0
            goto oom;
1072
0
    }
1073
0
    if (def_rlimit_locks != NULL) {
1074
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_locks", def_rlimit_locks)) == NULL)
1075
0
            goto oom;
1076
0
    }
1077
0
    if (def_rlimit_memlock != NULL) {
1078
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_memlock", def_rlimit_memlock)) == NULL)
1079
0
            goto oom;
1080
0
    }
1081
0
    if (def_rlimit_nofile != NULL) {
1082
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_nofile", def_rlimit_nofile)) == NULL)
1083
0
            goto oom;
1084
0
    }
1085
0
    if (def_rlimit_nproc != NULL) {
1086
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_nproc", def_rlimit_nproc)) == NULL)
1087
0
            goto oom;
1088
0
    }
1089
0
    if (def_rlimit_rss != NULL) {
1090
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_rss", def_rlimit_rss)) == NULL)
1091
0
            goto oom;
1092
0
    }
1093
0
    if (def_rlimit_stack != NULL) {
1094
0
        if ((command_info[info_len++] = sudo_new_key_val("rlimit_stack", def_rlimit_stack)) == NULL)
1095
0
            goto oom;
1096
0
    }
1097
0
    if (ctx->source != NULL) {
1098
0
  command_info[info_len] = sudo_new_key_val("source", ctx->source);
1099
0
  if (command_info[info_len++] == NULL)
1100
0
      goto oom;
1101
0
    }
1102
#ifdef HAVE_LOGIN_CAP_H
1103
    if (def_use_loginclass) {
1104
  if ((command_info[info_len++] = sudo_new_key_val("login_class", ctx->runas.class)) == NULL)
1105
      goto oom;
1106
    }
1107
#endif /* HAVE_LOGIN_CAP_H */
1108
0
    if (def_selinux && ctx->runas.role != NULL) {
1109
0
  if ((command_info[info_len++] = sudo_new_key_val("selinux_role", ctx->runas.role)) == NULL)
1110
0
      goto oom;
1111
0
    }
1112
0
    if (def_selinux && ctx->runas.type != NULL) {
1113
0
  if ((command_info[info_len++] = sudo_new_key_val("selinux_type", ctx->runas.type)) == NULL)
1114
0
      goto oom;
1115
0
    }
1116
0
    if (ctx->runas.apparmor_profile != NULL) {
1117
0
  if ((command_info[info_len++] = sudo_new_key_val("apparmor_profile", ctx->runas.apparmor_profile)) == NULL)
1118
0
      goto oom;
1119
0
    }
1120
0
    if (ctx->runas.privs != NULL) {
1121
0
  if ((command_info[info_len++] = sudo_new_key_val("runas_privs", ctx->runas.privs)) == NULL)
1122
0
      goto oom;
1123
0
    }
1124
0
    if (ctx->runas.limitprivs != NULL) {
1125
0
  if ((command_info[info_len++] = sudo_new_key_val("runas_limitprivs", ctx->runas.limitprivs)) == NULL)
1126
0
      goto oom;
1127
0
    }
1128
1129
    /* Set command start time (monotonic) for the first accepted command. */
1130
0
    if (accepted && !ISSET(ctx->mode, MODE_POLICY_INTERCEPTED)) {
1131
0
  if (sudo_gettime_awake(&ctx->start_time) == -1) {
1132
0
      sudo_warn("%s", U_("unable to get time of day"));
1133
0
      goto bad;
1134
0
  }
1135
0
    }
1136
1137
    /* Fill in exec environment info. */
1138
0
    *(exec_args->argv) = argv;
1139
0
    *(exec_args->envp) = envp;
1140
0
    *(exec_args->info) = command_info;
1141
1142
    /* Free command_info on exit. */
1143
0
    sudoers_gc_add(GC_VECTOR, command_info);
1144
1145
0
    debug_return_bool(true);
1146
1147
0
oom:
1148
0
    sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
1149
0
bad:
1150
0
    free(audit_msg);
1151
0
    audit_msg = NULL;
1152
0
    while (info_len)
1153
0
  free(command_info[--info_len]);
1154
0
    free(command_info);
1155
0
    command_info = NULL;
1156
0
    debug_return_bool(false);
1157
0
}
1158
1159
bool
1160
sudoers_tty_present(struct sudoers_context *ctx)
1161
0
{
1162
0
    debug_decl(sudoers_tty_present, SUDOERS_DEBUG_PLUGIN);
1163
    
1164
0
    if (ctx->user.tcpgid == 0 && ctx->user.ttypath == NULL) {
1165
  /* No job control or terminal, check /dev/tty. */
1166
0
  int fd = open(_PATH_TTY, O_RDWR);
1167
0
  if (fd == -1)
1168
0
      debug_return_bool(false);
1169
0
  close(fd);
1170
0
    }
1171
0
    debug_return_bool(true);
1172
0
}
1173
1174
static int
1175
sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
1176
    sudo_printf_t plugin_printf, char * const settings[],
1177
    char * const user_info[], char * const envp[], char * const args[],
1178
    const char **errstr)
1179
0
{
1180
0
    struct sudo_conf_debug_file_list debug_files = TAILQ_HEAD_INITIALIZER(debug_files);
1181
0
    struct sudoers_open_info info;
1182
0
    const char *cp, *plugin_path = NULL;
1183
0
    char * const *cur;
1184
0
    int ret;
1185
0
    debug_decl(sudoers_policy_open, SUDOERS_DEBUG_PLUGIN);
1186
1187
0
    sudo_version = version;
1188
0
    sudo_conv = conversation;
1189
0
    sudo_printf = plugin_printf;
1190
0
    if (sudoers_policy.event_alloc != NULL)
1191
0
  plugin_event_alloc = sudoers_policy.event_alloc;
1192
1193
    /* Plugin args are only specified for API version 1.2 and higher. */
1194
0
    if (sudo_version < SUDO_API_MKVERSION(1, 2))
1195
0
  args = NULL;
1196
1197
    /* Initialize the debug subsystem.  */
1198
0
    for (cur = settings; (cp = *cur) != NULL; cur++) {
1199
0
  if (strncmp(cp, "debug_flags=", sizeof("debug_flags=") - 1) == 0) {
1200
0
      cp += sizeof("debug_flags=") - 1;
1201
0
      if (!sudoers_debug_parse_flags(&debug_files, cp))
1202
0
    debug_return_int(-1);
1203
0
      continue;
1204
0
  }
1205
0
  if (strncmp(cp, "plugin_path=", sizeof("plugin_path=") - 1) == 0) {
1206
0
      plugin_path = cp + sizeof("plugin_path=") - 1;
1207
0
      continue;
1208
0
  }
1209
0
    }
1210
0
    if (!sudoers_debug_register(plugin_path, &debug_files))
1211
0
  debug_return_int(-1);
1212
1213
    /* Call the sudoers init function. */
1214
0
    info.settings = settings;
1215
0
    info.user_info = user_info;
1216
0
    info.plugin_args = args;
1217
0
    ret = sudoers_init(&info, log_parse_error, envp);
1218
1219
    /* The audit functions set audit_msg on failure. */
1220
0
    if (ret != 1 && audit_msg != NULL) {
1221
0
  if (sudo_version >= SUDO_API_MKVERSION(1, 15))
1222
0
      *errstr = audit_msg;
1223
0
    }
1224
1225
0
    debug_return_int(ret);
1226
0
}
1227
1228
static void
1229
sudoers_policy_close(int exit_status, int error_code)
1230
0
{
1231
0
    const struct sudoers_context *ctx = sudoers_get_context();
1232
0
    debug_decl(sudoers_policy_close, SUDOERS_DEBUG_PLUGIN);
1233
1234
0
    if (session_opened) {
1235
  /* Close the session we opened in sudoers_policy_init_session(). */
1236
0
  (void)sudo_auth_end_session();
1237
1238
0
  if (error_code) {
1239
0
      errno = error_code;
1240
0
      sudo_warn(U_("unable to execute %s"), ctx->runas.cmnd);
1241
0
  } else {
1242
0
      log_exit_status(ctx, exit_status);
1243
0
  }
1244
0
    }
1245
1246
    /* Deregister the callback for sudo_fatal()/sudo_fatalx(). */
1247
0
    sudo_fatal_callback_deregister(sudoers_cleanup);
1248
1249
    /* Free sudoers sources, ctx->user.and passwd/group caches. */
1250
0
    sudoers_cleanup();
1251
1252
    /* command_info was freed by the g/c code. */
1253
0
    command_info = NULL;
1254
1255
    /* Free error message passed back to front-end, if any. */
1256
0
    free(audit_msg);
1257
0
    audit_msg = NULL;
1258
1259
    /* sudoers_debug_deregister() calls sudo_debug_exit() for us. */
1260
0
    sudoers_debug_deregister();
1261
0
}
1262
1263
/*
1264
 * The init_session function is called before executing the command
1265
 * and before uid/gid changes occur.
1266
 * Returns 1 on success, 0 on failure and -1 on error.
1267
 */
1268
static int
1269
sudoers_policy_init_session(struct passwd *pwd, char **user_env[],
1270
    const char **errstr)
1271
0
{
1272
0
    const struct sudoers_context *ctx = sudoers_get_context();
1273
0
    int ret;
1274
0
    debug_decl(sudoers_policy_init_session, SUDOERS_DEBUG_PLUGIN);
1275
1276
    /* user_env is only specified for API version 1.2 and higher. */
1277
0
    if (sudo_version < SUDO_API_MKVERSION(1, 2))
1278
0
  user_env = NULL;
1279
1280
0
    ret = sudo_auth_begin_session(ctx, pwd, user_env);
1281
1282
0
    if (ret == 1) {
1283
0
  session_opened = true;
1284
0
    } else if (audit_msg != NULL) {
1285
  /* The audit functions set audit_msg on failure. */
1286
0
  if (sudo_version >= SUDO_API_MKVERSION(1, 15))
1287
0
      *errstr = audit_msg;
1288
0
    }
1289
0
    debug_return_int(ret);
1290
0
}
1291
1292
static int
1293
sudoers_policy_check(int argc, char * const argv[], char *env_add[],
1294
    char **command_infop[], char **argv_out[], char **user_env_out[],
1295
    const char **errstr)
1296
0
{
1297
0
    const struct sudoers_context *ctx = sudoers_get_context();
1298
0
    unsigned int valid_flags = RUN_VALID_FLAGS;
1299
0
    unsigned int flags = MODE_RUN;
1300
0
    struct sudoers_exec_args exec_args;
1301
0
    int ret;
1302
0
    debug_decl(sudoers_policy_check, SUDOERS_DEBUG_PLUGIN);
1303
1304
0
    if (ISSET(ctx->mode, MODE_EDIT)) {
1305
0
  valid_flags = EDIT_VALID_FLAGS;
1306
0
  flags = 0;
1307
0
    }
1308
0
    if (!sudoers_set_mode(flags, valid_flags)) {
1309
0
  sudo_warnx(U_("%s: invalid mode flags from sudo front end: 0x%x"),
1310
0
      __func__, ctx->mode);
1311
0
  debug_return_int(-1);
1312
0
    }
1313
1314
0
    exec_args.argv = argv_out;
1315
0
    exec_args.envp = user_env_out;
1316
0
    exec_args.info = command_infop;
1317
1318
0
    ret = sudoers_check_cmnd(argc, argv, env_add, &exec_args);
1319
#ifndef NO_LEAKS
1320
    if (ret == true && sudo_version >= SUDO_API_MKVERSION(1, 3)) {
1321
  /* Unset close function if we don't need it to avoid extra process. */
1322
  if (!iolog_enabled && !def_use_pty && !def_log_exit_status &&
1323
    SLIST_EMPTY(&def_log_servers) && !sudo_auth_needs_end_session())
1324
      sudoers_policy.close = NULL;
1325
    }
1326
#endif
1327
1328
    /* The audit functions set audit_msg on failure. */
1329
0
    if (ret != 1 && audit_msg != NULL) {
1330
0
  if (sudo_version >= SUDO_API_MKVERSION(1, 15))
1331
0
      *errstr = audit_msg;
1332
0
    }
1333
0
    debug_return_int(ret);
1334
0
}
1335
1336
static int
1337
sudoers_policy_validate(const char **errstr)
1338
0
{
1339
0
    const struct sudoers_context *ctx = sudoers_get_context();
1340
0
    int ret;
1341
0
    debug_decl(sudoers_policy_validate, SUDOERS_DEBUG_PLUGIN);
1342
1343
0
    if (!sudoers_set_mode(MODE_VALIDATE, VALIDATE_VALID_FLAGS)) {
1344
0
  sudo_warnx(U_("%s: invalid mode flags from sudo front end: 0x%x"),
1345
0
      __func__, ctx->mode);
1346
0
  debug_return_int(-1);
1347
0
    }
1348
1349
0
    ret = sudoers_validate_user();
1350
1351
    /* The audit functions set audit_msg on failure. */
1352
0
    if (ret != 1 && audit_msg != NULL) {
1353
0
  if (sudo_version >= SUDO_API_MKVERSION(1, 15))
1354
0
      *errstr = audit_msg;
1355
0
    }
1356
0
    debug_return_int(ret);
1357
0
}
1358
1359
static void
1360
sudoers_policy_invalidate(int unlinkit)
1361
0
{
1362
0
    const struct sudoers_context *ctx = sudoers_get_context();
1363
0
    debug_decl(sudoers_policy_invalidate, SUDOERS_DEBUG_PLUGIN);
1364
1365
0
    if (!sudoers_set_mode(MODE_INVALIDATE, INVALIDATE_VALID_FLAGS)) {
1366
0
  sudo_warnx(U_("%s: invalid mode flags from sudo front end: 0x%x"),
1367
0
      __func__, ctx->mode);
1368
0
    } else {
1369
0
  timestamp_remove(ctx, unlinkit);
1370
0
    }
1371
1372
0
    debug_return;
1373
0
}
1374
1375
static int
1376
sudoers_policy_list(int argc, char * const argv[], int verbose,
1377
    const char *list_user, const char **errstr)
1378
0
{
1379
0
    const struct sudoers_context *ctx = sudoers_get_context();
1380
0
    int ret;
1381
0
    debug_decl(sudoers_policy_list, SUDOERS_DEBUG_PLUGIN);
1382
1383
0
    if (!sudoers_set_mode(argc ? MODE_CHECK : MODE_LIST, LIST_VALID_FLAGS)) {
1384
0
  sudo_warnx(U_("%s: invalid mode flags from sudo front end: 0x%x"),
1385
0
      __func__, ctx->mode);
1386
0
  debug_return_int(-1);
1387
0
    }
1388
1389
0
    ret = sudoers_list(argc, argv, list_user, verbose);
1390
1391
    /* The audit functions set audit_msg on failure. */
1392
0
    if (ret != 1 && audit_msg != NULL) {
1393
0
  if (sudo_version >= SUDO_API_MKVERSION(1, 15))
1394
0
      *errstr = audit_msg;
1395
0
    }
1396
0
    debug_return_int(ret);
1397
0
}
1398
1399
static int
1400
sudoers_policy_version(int verbose)
1401
0
{
1402
#ifdef HAVE_LDAP
1403
    const struct sudoers_context *ctx = sudoers_get_context();
1404
#endif
1405
0
    debug_decl(sudoers_policy_version, SUDOERS_DEBUG_PLUGIN);
1406
1407
0
    sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"),
1408
0
  PACKAGE_VERSION);
1409
0
    sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"),
1410
0
  SUDOERS_GRAMMAR_VERSION);
1411
1412
0
    if (verbose) {
1413
0
  sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), path_sudoers);
1414
#ifdef HAVE_LDAP
1415
# ifdef _PATH_NSSWITCH_CONF
1416
  sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF);
1417
# endif
1418
  if (ctx->settings.ldap_conf != NULL)
1419
      sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), ctx->settings.ldap_conf);
1420
  if (ctx->settings.ldap_secret != NULL)
1421
      sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), ctx->settings.ldap_secret);
1422
#endif
1423
0
  dump_auth_methods();
1424
0
  dump_defaults();
1425
0
  sudo_printf(SUDO_CONV_INFO_MSG, "\n");
1426
0
  if (interfaces_string != NULL) {
1427
0
      dump_interfaces(interfaces_string);
1428
0
      sudo_printf(SUDO_CONV_INFO_MSG, "\n");
1429
0
  }
1430
0
    }
1431
0
    debug_return_int(true);
1432
0
}
1433
1434
static struct sudo_hook sudoers_hooks[] = {
1435
    { SUDO_HOOK_VERSION, SUDO_HOOK_SETENV, (sudo_hook_fn_t)sudoers_hook_setenv, NULL },
1436
    { SUDO_HOOK_VERSION, SUDO_HOOK_UNSETENV, (sudo_hook_fn_t)sudoers_hook_unsetenv, NULL },
1437
    { SUDO_HOOK_VERSION, SUDO_HOOK_GETENV, (sudo_hook_fn_t)sudoers_hook_getenv, NULL },
1438
    { SUDO_HOOK_VERSION, SUDO_HOOK_PUTENV, (sudo_hook_fn_t)sudoers_hook_putenv, NULL },
1439
    { 0, 0, NULL, NULL }
1440
};
1441
1442
/*
1443
 * Register environment function hooks.
1444
 * Note that we have not registered sudoers with the debug subsystem yet.
1445
 */
1446
static void
1447
sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook))
1448
0
{
1449
0
    struct sudo_hook *hook;
1450
1451
0
    for (hook = sudoers_hooks; hook->hook_fn != NULL; hook++) {
1452
0
  if (register_hook(hook) != 0) {
1453
0
      sudo_warn_nodebug(
1454
0
    U_("unable to register hook of type %d (version %d.%d)"),
1455
0
    hook->hook_type, SUDO_API_VERSION_GET_MAJOR(hook->hook_version),
1456
0
    SUDO_API_VERSION_GET_MINOR(hook->hook_version));
1457
0
  }
1458
0
    }
1459
0
}
1460
1461
/*
1462
 * De-register environment function hooks.
1463
 */
1464
static void
1465
sudoers_policy_deregister_hooks(int version, int (*deregister_hook)(struct sudo_hook *hook))
1466
0
{
1467
0
    struct sudo_hook *hook;
1468
1469
0
    for (hook = sudoers_hooks; hook->hook_fn != NULL; hook++) {
1470
0
  if (deregister_hook(hook) != 0) {
1471
0
      sudo_warn_nodebug(
1472
0
    U_("unable to deregister hook of type %d (version %d.%d)"),
1473
0
    hook->hook_type, SUDO_API_VERSION_GET_MAJOR(hook->hook_version),
1474
0
    SUDO_API_VERSION_GET_MINOR(hook->hook_version));
1475
0
  }
1476
0
    }
1477
0
}
1478
1479
sudo_dso_public struct policy_plugin sudoers_policy = {
1480
    SUDO_POLICY_PLUGIN,
1481
    SUDO_API_VERSION,
1482
    sudoers_policy_open,
1483
    sudoers_policy_close,
1484
    sudoers_policy_version,
1485
    sudoers_policy_check,
1486
    sudoers_policy_list,
1487
    sudoers_policy_validate,
1488
    sudoers_policy_invalidate,
1489
    sudoers_policy_init_session,
1490
    sudoers_policy_register_hooks,
1491
    sudoers_policy_deregister_hooks,
1492
    NULL /* event_alloc() filled in by sudo */
1493
};