Coverage Report

Created: 2025-07-11 06:58

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