VirtualBox

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

Last change on this file since 2101 was 2019, checked in by bird, 16 years ago

GPLv2 -> GPLv3. See Ticket #44 for clarifications. Fixes #44.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette