VirtualBox

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

Last change on this file since 2014 was 2001, checked in by bird, 16 years ago

kmk: pedantic warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.9 KB
Line 
1/* $Id: kbuild_protection.c 2001 2008-10-29 22:14:48Z 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 2 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, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <sys/types.h>
32#include <stdlib.h>
33#include <string.h>
34#include <ctype.h>
35#include <assert.h>
36#if defined(_MSC_VER) || defined(__OS2__)
37# include <limits.h>
38# include <direct.h>
39#else
40# include <unistd.h>
41#endif
42#include "kbuild_protection.h"
43#include "err.h"
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49#define KBUILD_PROTECTION_MAGIC 0x00111100
50
51#if defined(__EMX__) || defined(_MSC_VER)
52# define IS_SLASH(ch) ( (ch) == '/' || (ch) == '\\' )
53# define DEFAULT_PROTECTION_DEPTH 1
54#else
55# define IS_SLASH(ch) ( (ch) == '/' )
56# define DEFAULT_PROTECTION_DEPTH 2
57#endif
58
59
60
61/**
62 * Counts the components in the specified sub path.
63 * This is a helper for count_path_components.
64 *
65 * etc = 1
66 * etc/ = 1
67 * etc/x11 = 2
68 * and so and and so forth.
69 */
70static int countSubPathComponents(const char *pszPath, int cDepth)
71{
72 for (;;)
73 {
74 const char *pszEnd;
75 size_t cch;
76
77 /* skip slashes. */
78 while (IS_SLASH(*pszPath))
79 pszPath++;
80 if (!*pszPath)
81 break;
82
83 /* find end of component. */
84 pszEnd = pszPath;
85 while (!IS_SLASH(*pszEnd) && *pszEnd)
86 pszEnd++;
87
88 /* count it, checking for '..' and '.'. */
89 cch = pszEnd - pszPath;
90 if (cch == 2 && pszPath[0] == '.' && pszPath[1] == '.')
91 {
92 if (cDepth > 0)
93 cDepth--;
94 }
95 else if (cch != 1 || pszPath[0] != '.')
96 cDepth++;
97
98 /* advance */
99 if (!*pszEnd)
100 break;
101 pszPath = pszEnd + 1;
102 }
103 return cDepth;
104}
105
106
107/**
108 * Parses the specified path counting the number of components
109 * relative to root.
110 *
111 * We don't check symbolic links and such, just some simple and cheap
112 * path parsing.
113 *
114 * @param pszPath The path to process.
115 *
116 * @returns 0 or higher on success.
117 * On failure an error is printed, eval is set and -1 is returned.
118 */
119static int countPathComponents(const char *pszPath)
120{
121 int cComponents = 0;
122
123 /*
124 * Deal with root, UNC, drive letter.
125 */
126#if defined(_MSC_VER) || defined(__OS2__)
127 if (IS_SLASH(pszPath[0]) && IS_SLASH(pszPath[1]) && !IS_SLASH(pszPath[2]))
128 {
129 /* skip the root - UNC */
130 pszPath += 3;
131 while (!IS_SLASH(*pszPath) && *pszPath) /* server name */
132 pszPath++;
133 while (IS_SLASH(*pszPath))
134 pszPath++;
135 while (!IS_SLASH(*pszPath) && *pszPath) /* share name */
136 pszPath++;
137 while (IS_SLASH(*pszPath))
138 pszPath++;
139 }
140 else
141 {
142 unsigned uDriveLetter = (unsigned)toupper(pszPath[0]) - (unsigned)'A';
143 if (uDriveLetter <= (unsigned)('Z' - 'A') && pszPath[1] == ':')
144 uDriveLetter++; /* A == 1 */
145 else
146 uDriveLetter = 0; /* 0 == default */
147
148 if (!IS_SLASH(pszPath[uDriveLetter ? 2 : 0]))
149 {
150 /*
151 * Relative path, must count cwd depth first.
152 */
153#ifdef __OS2__ /** @todo remove when ticket 194 has been fixed */
154 char *pszCwd = _getdcwd(uDriveLetter, NULL, PATH_MAX);
155#else
156 char *pszCwd = _getdcwd(uDriveLetter, NULL, 0);
157#endif
158 char *pszTmp = pszCwd;
159 if (!pszTmp)
160 {
161 err(1, "_getdcwd");
162 return -1;
163 }
164
165 if (IS_SLASH(pszTmp[0]) && IS_SLASH(pszTmp[1]))
166 {
167 /* skip the root - UNC */
168 pszTmp += 2;
169 while (!IS_SLASH(*pszTmp) && *pszTmp) /* server name */
170 pszTmp++;
171 while (IS_SLASH(*pszTmp))
172 pszTmp++;
173 while (!IS_SLASH(*pszTmp) && *pszTmp) /* share name */
174 pszTmp++;
175 }
176 else
177 {
178 /* skip the drive letter and while we're at it, the root slash too. */
179 pszTmp += 1 + (pszTmp[1] == ':');
180 }
181 cComponents = countSubPathComponents(pszTmp, 0);
182 free(pszCwd);
183 }
184 else
185 {
186 /* skip the drive letter and while we're at it, the root slash too. */
187 pszPath += uDriveLetter ? 3 : 1;
188 }
189 }
190#else /* !WIN && !OS2 */
191 if (!IS_SLASH(pszPath[0]))
192 {
193 /*
194 * Relative path, must count cwd depth first.
195 */
196 char szCwd[4096];
197 if (!getcwd(szCwd, sizeof(szCwd)))
198 {
199 err(1, "getcwd");
200 return -1;
201 }
202 cComponents = countSubPathComponents(szCwd, 0);
203 }
204#endif /* !WIN && !OS2 */
205
206 /*
207 * We're now past any UNC or drive letter crap, possibly positioned
208 * at the root slash or at the start of a path component at the
209 * given depth. Count the remainder.
210 */
211 return countSubPathComponents(pszPath, cComponents);
212}
213
214
215/**
216 * Initializes the instance data.
217 *
218 * @param pThis Pointer to the instance data.
219 */
220void kBuildProtectionInit(PKBUILDPROTECTION pThis)
221{
222 pThis->uMagic = KBUILD_PROTECTION_MAGIC;
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(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(1, "bogus protection depth: %s", pszValue);
284 }
285
286 if (pThis->cProtectionDepth < 1)
287 return errx(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(pszPath);
355 if (cComponents < 0)
356 return -1;
357 if ((unsigned int)cComponents <= pThis->cProtectionDepth)
358 {
359 errx(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.

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