VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/kbuild_protection.c@ 3387

Last change on this file since 3387 was 3192, checked in by bird, 6 years ago

kmkbuiltin: funnel output thru output.c (usually via err.c).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: kbuild_protection.c 3192 2018-03-26 20:25:56Z bird $ */
2/** @file
3 * Simple File Protection.
4 */
5
6/*
7 * Copyright (c) 2008-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "config.h"
30#include <sys/types.h>
31#include <stdlib.h>
32#include <string.h>
33#include <ctype.h>
34#include <assert.h>
35#if defined(_MSC_VER) || defined(__OS2__)
36# include <limits.h>
37# include <direct.h>
38#else
39# include <unistd.h>
40#endif
41#include "kbuild_protection.h"
42#include "err.h"
43
44
45/*******************************************************************************
46* Defined Constants And Macros *
47*******************************************************************************/
48#define KBUILD_PROTECTION_MAGIC 0x00111100
49
50#if defined(__EMX__) || defined(_MSC_VER)
51# define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
52# define DEFAULT_PROTECTION_DEPTH 1
53#else
54# define IS_SLASH(ch) ( (ch) == '/' )
55# define DEFAULT_PROTECTION_DEPTH 2
56#endif
57
58
59
60/**
61 * Counts the components in the specified sub path.
62 * This is a helper for count_path_components.
63 *
64 * etc = 1
65 * etc/ = 1
66 * etc/x11 = 2
67 * and so and and so forth.
68 */
69static int countSubPathComponents(const char *pszPath, int cDepth)
70{
71 for (;;)
72 {
73 const char *pszEnd;
74 size_t cch;
75
76 /* skip slashes. */
77 while (IS_SLASH(*pszPath))
78 pszPath++;
79 if (!*pszPath)
80 break;
81
82 /* find end of component. */
83 pszEnd = pszPath;
84 while (!IS_SLASH(*pszEnd) && *pszEnd)
85 pszEnd++;
86
87 /* count it, checking for '..' and '.'. */
88 cch = pszEnd - pszPath;
89 if (cch == 2 && pszPath[0] == '.' && pszPath[1] == '.')
90 {
91 if (cDepth > 0)
92 cDepth--;
93 }
94 else if (cch != 1 || pszPath[0] != '.')
95 cDepth++;
96
97 /* advance */
98 if (!*pszEnd)
99 break;
100 pszPath = pszEnd + 1;
101 }
102 return cDepth;
103}
104
105
106/**
107 * Parses the specified path counting the number of components
108 * relative to root.
109 *
110 * We don't check symbolic links and such, just some simple and cheap
111 * path parsing.
112 *
113 * @param pszPath The path to process.
114 *
115 * @returns 0 or higher on success.
116 * On failure an error is printed, eval is set and -1 is returned.
117 */
118static int countPathComponents(PCKBUILDPROTECTION pThis, const char *pszPath)
119{
120 int cComponents = 0;
121
122 /*
123 * Deal with root, UNC, drive letter.
124 */
125#if defined(_MSC_VER) || defined(__OS2__)
126 if (IS_SLASH(pszPath[0]) && IS_SLASH(pszPath[1]) && !IS_SLASH(pszPath[2]))
127 {
128 /* skip the root - UNC */
129 pszPath += 3;
130 while (!IS_SLASH(*pszPath) && *pszPath) /* server name */
131 pszPath++;
132 while (IS_SLASH(*pszPath))
133 pszPath++;
134 while (!IS_SLASH(*pszPath) && *pszPath) /* share name */
135 pszPath++;
136 while (IS_SLASH(*pszPath))
137 pszPath++;
138 }
139 else
140 {
141 unsigned uDriveLetter = (unsigned)toupper(pszPath[0]) - (unsigned)'A';
142 if (uDriveLetter <= (unsigned)('Z' - 'A') && pszPath[1] == ':')
143 uDriveLetter++; /* A == 1 */
144 else
145 uDriveLetter = 0; /* 0 == default */
146
147 if (!IS_SLASH(pszPath[uDriveLetter ? 2 : 0]))
148 {
149 /*
150 * Relative path, must count cwd depth first.
151 */
152#ifdef __OS2__ /** @todo remove when ticket 194 has been fixed */
153 char *pszCwd = _getdcwd(uDriveLetter, NULL, PATH_MAX);
154#else
155 char *pszCwd = _getdcwd(uDriveLetter, NULL, 0);
156#endif
157 char *pszTmp = pszCwd;
158 if (!pszTmp)
159 {
160 err(pThis->pCtx, 1, "_getdcwd");
161 return -1;
162 }
163
164 if (IS_SLASH(pszTmp[0]) && IS_SLASH(pszTmp[1]))
165 {
166 /* skip the root - UNC */
167 pszTmp += 2;
168 while (!IS_SLASH(*pszTmp) && *pszTmp) /* server name */
169 pszTmp++;
170 while (IS_SLASH(*pszTmp))
171 pszTmp++;
172 while (!IS_SLASH(*pszTmp) && *pszTmp) /* share name */
173 pszTmp++;
174 }
175 else
176 {
177 /* skip the drive letter and while we're at it, the root slash too. */
178 pszTmp += 1 + (pszTmp[1] == ':');
179 }
180 cComponents = countSubPathComponents(pszTmp, 0);
181 free(pszCwd);
182 }
183 else
184 {
185 /* skip the drive letter and while we're at it, the root slash too. */
186 pszPath += uDriveLetter ? 3 : 1;
187 }
188 }
189#else /* !WIN && !OS2 */
190 if (!IS_SLASH(pszPath[0]))
191 {
192 /*
193 * Relative path, must count cwd depth first.
194 */
195 char szCwd[4096];
196 if (!getcwd(szCwd, sizeof(szCwd)))
197 {
198 err(pThis->pCtx, 1, "getcwd");
199 return -1;
200 }
201 cComponents = countSubPathComponents(szCwd, 0);
202 }
203#endif /* !WIN && !OS2 */
204
205 /*
206 * We're now past any UNC or drive letter crap, possibly positioned
207 * at the root slash or at the start of a path component at the
208 * given depth. Count the remainder.
209 */
210 return countSubPathComponents(pszPath, cComponents);
211}
212
213
214/**
215 * Initializes the instance data.
216 *
217 * @param pThis Pointer to the instance data.
218 */
219void kBuildProtectionInit(PKBUILDPROTECTION pThis, PKMKBUILTINCTX pCtx)
220{
221 pThis->uMagic = KBUILD_PROTECTION_MAGIC;
222 pThis->pCtx = pCtx;
223 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] = 0;
224 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] = 1;
225 pThis->cProtectionDepth = DEFAULT_PROTECTION_DEPTH;
226}
227
228
229/**
230 * Destroys the instance data.
231 *
232 * @param pThis Pointer to the instance data.
233 */
234void kBuildProtectionTerm(PKBUILDPROTECTION pThis)
235{
236 pThis->uMagic = 0;
237}
238
239
240void kBuildProtectionEnable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
241{
242 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
243 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
244 pThis->afTypes[enmType] |= 1;
245}
246
247
248void kBuildProtectionDisable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
249{
250 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
251 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
252 pThis->afTypes[enmType] &= ~1U;
253}
254
255
256/**
257 * Sets the protection depth according to the option argument.
258 *
259 * @param pszValue The value.
260 *
261 * @returns 0 on success, -1 and errx on failure.
262 */
263int kBuildProtectionSetDepth(PKBUILDPROTECTION pThis, const char *pszValue)
264{
265 /* skip leading blanks, they don't count either way. */
266 while (isspace(*pszValue))
267 pszValue++;
268
269 /* number or path? */
270 if (!isdigit(*pszValue) || strpbrk(pszValue, ":/\\"))
271 pThis->cProtectionDepth = countPathComponents(pThis, pszValue);
272 else
273 {
274 char *pszMore = 0;
275 pThis->cProtectionDepth = strtol(pszValue, &pszMore, 0);
276 if (pThis->cProtectionDepth != 0 && pszMore)
277 {
278 /* trailing space is harmless. */
279 while (isspace(*pszMore))
280 pszMore++;
281 }
282 if (!pThis->cProtectionDepth || pszValue == pszMore || *pszMore)
283 return errx(pThis->pCtx, 1, "bogus protection depth: %s", pszValue);
284 }
285
286 if (pThis->cProtectionDepth < 1)
287 return errx(pThis->pCtx, 1, "bogus protection depth: %s", pszValue);
288 return 0;
289}
290
291
292/**
293 * Scans the environment for option overrides.
294 *
295 * @param pThis Pointer to the instance data.
296 * @param papszEnv The environment array.
297 * @param pszPrefix The variable prefix.
298 *
299 * @returns 0 on success, -1 and err*() on failure.
300 */
301int kBuildProtectionScanEnv(PKBUILDPROTECTION pThis, char **papszEnv, const char *pszPrefix)
302{
303 unsigned i;
304 const size_t cchPrefix = strlen(pszPrefix);
305
306 for (i = 0; papszEnv[i]; i++)
307 {
308 const char *pszVar = papszEnv[i];
309 if (!strncmp(pszVar, pszPrefix, cchPrefix))
310 {
311 pszVar += cchPrefix;
312 if (!strncmp(pszVar, "PROTECTION_DEPTH=", sizeof("PROTECTION_DEPTH=") - 1))
313 {
314 const char *pszVal = pszVar + sizeof("PROTECTION_DEPTH=") - 1;
315 if (kBuildProtectionSetDepth(pThis, pszVal))
316 return -1;
317 }
318 else if (!strncmp(pszVar, "DISABLE_PROTECTION=", sizeof("DISABLE_PROTECTION=") - 1))
319 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] &= ~1U;
320 else if (!strncmp(pszVar, "ENABLE_PROTECTION=", sizeof("ENABLE_PROTECTION=") - 1))
321 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] |= 3;
322 else if (!strncmp(pszVar, "DISABLE_FULL_PROTECTION=", sizeof("DISABLE_FULL_PROTECTION=") - 1))
323 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] &= ~1U;
324 else if (!strncmp(pszVar, "ENABLE_FULL_PROTECTION=", sizeof("ENABLE_FULL_PROTECTION=") - 1))
325 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] |= 3;
326 }
327 }
328 return 0;
329}
330
331
332/**
333 * Protect the upper layers of the file system against accidental
334 * or malicious deletetion attempt from within a makefile.
335 *
336 * @param pszPath The path to check.
337 * @param required_depth The minimum number of components in the
338 * path counting from the root.
339 *
340 * @returns 0 on success.
341 * On failure an error is printed and -1 is returned.
342 */
343int kBuildProtectionEnforce(PCKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType, const char *pszPath)
344{
345 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
346 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
347
348 if ( (pThis->afTypes[enmType] & 3)
349 || (pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] & 3))
350 {
351 /*
352 * Count the path and compare it with the required depth.
353 */
354 int cComponents = countPathComponents(pThis, pszPath);
355 if (cComponents < 0)
356 return -1;
357 if ((unsigned int)cComponents <= pThis->cProtectionDepth)
358 {
359 errx(pThis->pCtx, 1, "%s: protected", pszPath);
360 return -1;
361 }
362 }
363 return 0;
364}
365
366
367/**
368 * Retrieve the default path protection depth.
369 *
370 * @returns the default value.
371 */
372int kBuildProtectionDefaultDepth(void)
373{
374 return DEFAULT_PROTECTION_DEPTH;
375}
376
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use