/src/sudo/plugins/sudoers/iolog_path_escapes.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * SPDX-License-Identifier: ISC |
3 | | * |
4 | | * Copyright (c) 2011-2015 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 <stdio.h> |
27 | | #include <stdlib.h> |
28 | | #include <string.h> |
29 | | #include <pwd.h> |
30 | | #include <grp.h> |
31 | | #include <unistd.h> |
32 | | |
33 | | #include <sudoers.h> |
34 | | #include <sudo_iolog.h> |
35 | | |
36 | | /* |
37 | | * Like strlcpy(3) but replaces '/' with '_'. |
38 | | */ |
39 | | static size_t |
40 | | strlcpy_no_slash(char * restrict dst, const char * restrict src, size_t size) |
41 | 0 | { |
42 | 0 | size_t len = 0; |
43 | 0 | char ch; |
44 | 0 | debug_decl(strlcpy_no_slash, SUDOERS_DEBUG_UTIL); |
45 | |
|
46 | 0 | while ((ch = *src++) != '\0') { |
47 | 0 | if (size > 1) { |
48 | | /* Replace '/' with '_' */ |
49 | 0 | if (ch == '/') |
50 | 0 | ch = '_'; |
51 | 0 | *dst++ = ch; |
52 | 0 | size--; |
53 | 0 | } |
54 | 0 | len++; |
55 | 0 | } |
56 | 0 | if (size > 0) |
57 | 0 | *dst = '\0'; |
58 | |
|
59 | 0 | debug_return_size_t(len); |
60 | 0 | } |
61 | | |
62 | | static size_t |
63 | | fill_seq(char * restrict str, size_t strsize, void * restrict v) |
64 | 0 | { |
65 | | #ifdef SUDOERS_NO_SEQ |
66 | | debug_decl(fill_seq, SUDOERS_DEBUG_UTIL); |
67 | | debug_return_size_t(strlcpy(str, "%{seq}", strsize)); |
68 | | #else |
69 | 0 | struct sudoers_context *ctx = v; |
70 | 0 | static char sessid[7]; |
71 | 0 | int len; |
72 | 0 | debug_decl(fill_seq, SUDOERS_DEBUG_UTIL); |
73 | |
|
74 | 0 | if (sessid[0] == '\0') { |
75 | 0 | if (!iolog_nextid(ctx->iolog_dir, sessid)) |
76 | 0 | debug_return_size_t((size_t)-1); |
77 | 0 | } |
78 | | |
79 | | /* Path is of the form /var/log/sudo-io/00/00/01. */ |
80 | 0 | len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0], |
81 | 0 | sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]); |
82 | 0 | if (len < 0) |
83 | 0 | debug_return_size_t(strsize); /* handle non-standard snprintf() */ |
84 | 0 | debug_return_size_t((size_t)len); |
85 | 0 | #endif /* SUDOERS_NO_SEQ */ |
86 | 0 | } |
87 | | |
88 | | static size_t |
89 | | fill_user(char * restrict str, size_t strsize, void * restrict v) |
90 | 0 | { |
91 | 0 | struct sudoers_context *ctx = v; |
92 | 0 | debug_decl(fill_user, SUDOERS_DEBUG_UTIL); |
93 | 0 | debug_return_size_t(strlcpy_no_slash(str, ctx->user.name, strsize)); |
94 | 0 | } |
95 | | |
96 | | static size_t |
97 | | fill_group(char * restrict str, size_t strsize, void * restrict v) |
98 | 0 | { |
99 | 0 | struct sudoers_context *ctx = v; |
100 | 0 | struct group *grp; |
101 | 0 | size_t len; |
102 | 0 | debug_decl(fill_group, SUDOERS_DEBUG_UTIL); |
103 | |
|
104 | 0 | if ((grp = sudo_getgrgid(ctx->user.gid)) != NULL) { |
105 | 0 | len = strlcpy_no_slash(str, grp->gr_name, strsize); |
106 | 0 | sudo_gr_delref(grp); |
107 | 0 | } else { |
108 | 0 | len = (size_t)snprintf(str, strsize, "#%u", (unsigned int)ctx->user.gid); |
109 | 0 | } |
110 | 0 | debug_return_size_t(len); |
111 | 0 | } |
112 | | |
113 | | static size_t |
114 | | fill_runas_user(char * restrict str, size_t strsize, void * restrict v) |
115 | 0 | { |
116 | 0 | struct sudoers_context *ctx = v; |
117 | 0 | debug_decl(fill_runas_user, SUDOERS_DEBUG_UTIL); |
118 | 0 | debug_return_size_t(strlcpy_no_slash(str, ctx->runas.pw->pw_name, strsize)); |
119 | 0 | } |
120 | | |
121 | | static size_t |
122 | | fill_runas_group(char * restrict str, size_t strsize, void * restrict v) |
123 | 0 | { |
124 | 0 | struct sudoers_context *ctx = v; |
125 | 0 | struct group *grp; |
126 | 0 | size_t len; |
127 | 0 | debug_decl(fill_runas_group, SUDOERS_DEBUG_UTIL); |
128 | |
|
129 | 0 | if (ctx->runas.gr != NULL) { |
130 | 0 | len = strlcpy_no_slash(str, ctx->runas.gr->gr_name, strsize); |
131 | 0 | } else { |
132 | 0 | if ((grp = sudo_getgrgid(ctx->runas.pw->pw_gid)) != NULL) { |
133 | 0 | len = strlcpy_no_slash(str, grp->gr_name, strsize); |
134 | 0 | sudo_gr_delref(grp); |
135 | 0 | } else { |
136 | 0 | len = (size_t)snprintf(str, strsize, "#%u", |
137 | 0 | (unsigned int)ctx->runas.pw->pw_gid); |
138 | 0 | } |
139 | 0 | } |
140 | 0 | debug_return_size_t(len); |
141 | 0 | } |
142 | | |
143 | | static size_t |
144 | | fill_hostname(char * restrict str, size_t strsize, void * restrict v) |
145 | 0 | { |
146 | 0 | struct sudoers_context *ctx = v; |
147 | 0 | debug_decl(fill_hostname, SUDOERS_DEBUG_UTIL); |
148 | 0 | debug_return_size_t(strlcpy_no_slash(str, ctx->user.shost, strsize)); |
149 | 0 | } |
150 | | |
151 | | static size_t |
152 | | fill_command(char * restrict str, size_t strsize, void * restrict v) |
153 | 0 | { |
154 | 0 | struct sudoers_context *ctx = v; |
155 | 0 | debug_decl(fill_command, SUDOERS_DEBUG_UTIL); |
156 | 0 | debug_return_size_t(strlcpy_no_slash(str, ctx->user.cmnd_base, strsize)); |
157 | 0 | } |
158 | | |
159 | | /* Note: "seq" must be first in the list. */ |
160 | | static const struct iolog_path_escape path_escapes[] = { |
161 | | { "seq", fill_seq }, |
162 | | { "user", fill_user }, |
163 | | { "group", fill_group }, |
164 | | { "runas_user", fill_runas_user }, |
165 | | { "runas_group", fill_runas_group }, |
166 | | { "hostname", fill_hostname }, |
167 | | { "command", fill_command }, |
168 | | { NULL, NULL } |
169 | | }; |
170 | | const struct iolog_path_escape *sudoers_iolog_path_escapes = path_escapes; |