Coverage Report

Created: 2026-05-30 06:41

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