Coverage Report

Created: 2025-07-11 06:57

/src/sudo/plugins/sudoers/match_digest.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: ISC
3
 *
4
 * Copyright (c) 1996, 1998-2005, 2007-2020
5
 *  Todd C. Miller <Todd.Miller@sudo.ws>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 *
19
 * Sponsored in part by the Defense Advanced Research Projects
20
 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21
 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22
 */
23
24
/*
25
 * This is an open source non-commercial project. Dear PVS-Studio, please check it.
26
 * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
27
 */
28
29
#include <config.h>
30
31
#include <errno.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <fcntl.h>
36
#include <unistd.h>
37
38
#include <sudoers.h>
39
#include <sudo_digest.h>
40
#include <gram.h>
41
42
int
43
digest_matches(int fd, const char *path, const char *runchroot,
44
    const struct command_digest_list *digests)
45
0
{
46
0
    unsigned int digest_type = SUDO_DIGEST_INVALID;
47
0
    unsigned char *file_digest = NULL;
48
0
    unsigned char *sudoers_digest = NULL;
49
0
    struct command_digest *digest;
50
0
    char pathbuf[PATH_MAX];
51
0
    size_t digest_len;
52
0
    int matched = DENY;
53
0
    int fd2 = -1;
54
0
    debug_decl(digest_matches, SUDOERS_DEBUG_MATCH);
55
56
0
    if (TAILQ_EMPTY(digests)) {
57
  /* No digest, no problem. */
58
0
  debug_return_int(ALLOW);
59
0
    }
60
61
0
    if (fd == -1) {
62
0
  fd2 = open(path, O_RDONLY|O_NONBLOCK);
63
0
  if (fd2 == -1) {
64
      /* No file, no match. */
65
0
      goto done;
66
0
  }
67
0
  fd = fd2;
68
0
    }
69
70
0
    if (runchroot != NULL) {
71
  /* XXX - handle symlinks and '..' in path outside chroot */
72
0
  const int len =
73
0
      snprintf(pathbuf, sizeof(pathbuf), "%s%s", runchroot, path);
74
0
  if (len >= ssizeof(pathbuf)) {
75
0
      errno = ENAMETOOLONG;
76
0
      debug_return_bool(false);
77
0
  }
78
0
  path = pathbuf;
79
0
    }
80
81
0
    TAILQ_FOREACH(digest, digests, entries) {
82
  /* Compute file digest if needed. */
83
0
  if (digest->digest_type != digest_type) {
84
0
      free(file_digest);
85
0
      file_digest = sudo_filedigest(fd, path, digest->digest_type,
86
0
    &digest_len);
87
0
      if (lseek(fd, (off_t)0, SEEK_SET) == -1) {
88
0
    sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
89
0
        "unable to rewind digest fd");
90
0
      }
91
0
      digest_type = digest->digest_type;
92
0
  }
93
0
  if (file_digest == NULL) {
94
      /* Warning (if any) printed by sudo_filedigest() */
95
0
      goto done;
96
0
  }
97
98
  /* Convert the command digest from ascii to binary. */
99
0
  if ((sudoers_digest = malloc(digest_len)) == NULL) {
100
0
      sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory"));
101
0
      goto done;
102
0
  }
103
0
  if (strlen(digest->digest_str) == digest_len * 2) {
104
      /* Convert ascii hex to binary. */
105
0
      size_t i;
106
0
      for (i = 0; i < digest_len; i++) {
107
0
    const int h = sudo_hexchar(&digest->digest_str[2 * i]);
108
0
    if (h == -1)
109
0
        goto bad_format;
110
0
    sudoers_digest[i] = (unsigned char)h;
111
0
      }
112
0
  } else {
113
      /* Convert base64 to binary. */
114
0
      size_t len = base64_decode(digest->digest_str, sudoers_digest, digest_len);
115
0
      if (len == (size_t)-1)
116
0
    goto bad_format;
117
0
      if (len != digest_len) {
118
0
    sudo_warnx(
119
0
        U_("digest for %s (%s) bad length %zu, expected %zu"),
120
0
        path, digest->digest_str, len, digest_len);
121
0
    goto done;
122
0
      }
123
0
  }
124
0
  if (memcmp(file_digest, sudoers_digest, digest_len) == 0) {
125
0
      matched = ALLOW;
126
0
      break;
127
0
  }
128
129
0
  sudo_debug_printf(SUDO_DEBUG_DIAG|SUDO_DEBUG_LINENO,
130
0
      "%s digest mismatch for %s, expecting %s",
131
0
      digest_type_to_name(digest->digest_type), path, digest->digest_str);
132
0
  free(sudoers_digest);
133
0
  sudoers_digest = NULL;
134
0
    }
135
0
    goto done;
136
137
0
bad_format:
138
0
    sudo_warnx(U_("digest for %s (%s) is not in %s form"), path,
139
0
  digest->digest_str, digest_type_to_name(digest->digest_type));
140
0
done:
141
0
    if (fd2 != -1)
142
0
  close(fd2);
143
0
    free(sudoers_digest);
144
0
    free(file_digest);
145
0
    debug_return_int(matched);
146
0
}