VirtualBox

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

Last change on this file since 2134 was 2113, checked in by bird, 16 years ago

kmkbuiltin: include config.h

  • 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 2113 2008-12-25 13:21:58Z 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 "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(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(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(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)
220{
221 pThis->uMagic = KBUILD_PROTECTION_MAGIC;
222 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] = 0;
223 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] = 1;
224 pThis->cProtectionDepth = DEFAULT_PROTECTION_DEPTH;
225}
226
227
228/**
229 * Destroys the instance data.
230 *
231 * @param pThis Pointer to the instance data.
232 */
233void kBuildProtectionTerm(PKBUILDPROTECTION pThis)
234{
235 pThis->uMagic = 0;
236}
237
238
239void kBuildProtectionEnable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
240{
241 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
242 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
243 pThis->afTypes[enmType] |= 1;
244}
245
246
247void kBuildProtectionDisable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
248{
249 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
250 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
251 pThis->afTypes[enmType] &= ~1U;
252}
253
254
255/**
256 * Sets the protection depth according to the option argument.
257 *
258 * @param pszValue The value.
259 *
260 * @returns 0 on success, -1 and errx on failure.
261 */
262int kBuildProtectionSetDepth(PKBUILDPROTECTION pThis, const char *pszValue)
263{
264 /* skip leading blanks, they don't count either way. */
265 while (isspace(*pszValue))
266 pszValue++;
267
268 /* number or path? */
269 if (!isdigit(*pszValue) || strpbrk(pszValue, ":/\\"))
270 pThis->cProtectionDepth = countPathComponents(pszValue);
271 else
272 {
273 char *pszMore = 0;
274 pThis->cProtectionDepth = strtol(pszValue, &pszMore, 0);
275 if (pThis->cProtectionDepth != 0 && pszMore)
276 {
277 /* trailing space is harmless. */
278 while (isspace(*pszMore))
279 pszMore++;
280 }
281 if (!pThis->cProtectionDepth || pszValue == pszMore || *pszMore)
282 return errx(1, "bogus protection depth: %s", pszValue);
283 }
284
285 if (pThis->cProtectionDepth < 1)
286 return errx(1, "bogus protection depth: %s", pszValue);
287 return 0;
288}
289
290
291/**
292 * Scans the environment for option overrides.
293 *
294 * @param pThis Pointer to the instance data.
295 * @param papszEnv The environment array.
296 * @param pszPrefix The variable prefix.
297 *
298 * @returns 0 on success, -1 and err*() on failure.
299 */
300int kBuildProtectionScanEnv(PKBUILDPROTECTION pThis, char **papszEnv, const char *pszPrefix)
301{
302 unsigned i;
303 const size_t cchPrefix = strlen(pszPrefix);
304
305 for (i = 0; papszEnv[i]; i++)
306 {
307 const char *pszVar = papszEnv[i];
308 if (!strncmp(pszVar, pszPrefix, cchPrefix))
309 {
310 pszVar += cchPrefix;
311 if (!strncmp(pszVar, "PROTECTION_DEPTH=", sizeof("PROTECTION_DEPTH=") - 1))
312 {
313 const char *pszVal = pszVar + sizeof("PROTECTION_DEPTH=") - 1;
314 if (kBuildProtectionSetDepth(pThis, pszVal))
315 return -1;
316 }
317 else if (!strncmp(pszVar, "DISABLE_PROTECTION=", sizeof("DISABLE_PROTECTION=") - 1))
318 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] &= ~1U;
319 else if (!strncmp(pszVar, "ENABLE_PROTECTION=", sizeof("ENABLE_PROTECTION=") - 1))
320 pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] |= 3;
321 else if (!strncmp(pszVar, "DISABLE_FULL_PROTECTION=", sizeof("DISABLE_FULL_PROTECTION=") - 1))
322 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] &= ~1U;
323 else if (!strncmp(pszVar, "ENABLE_FULL_PROTECTION=", sizeof("ENABLE_FULL_PROTECTION=") - 1))
324 pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] |= 3;
325 }
326 }
327 return 0;
328}
329
330
331/**
332 * Protect the upper layers of the file system against accidental
333 * or malicious deletetion attempt from within a makefile.
334 *
335 * @param pszPath The path to check.
336 * @param required_depth The minimum number of components in the
337 * path counting from the root.
338 *
339 * @returns 0 on success.
340 * On failure an error is printed and -1 is returned.
341 */
342int kBuildProtectionEnforce(PCKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType, const char *pszPath)
343{
344 assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
345 assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
346
347 if ( (pThis->afTypes[enmType] & 3)
348 || (pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] & 3))
349 {
350 /*
351 * Count the path and compare it with the required depth.
352 */
353 int cComponents = countPathComponents(pszPath);
354 if (cComponents < 0)
355 return -1;
356 if ((unsigned int)cComponents <= pThis->cProtectionDepth)
357 {
358 errx(1, "%s: protected", pszPath);
359 return -1;
360 }
361 }
362 return 0;
363}
364
365
366/**
367 * Retrieve the default path protection depth.
368 *
369 * @returns the default value.
370 */
371int kBuildProtectionDefaultDepth(void)
372{
373 return DEFAULT_PROTECTION_DEPTH;
374}
375
Note: See TracBrowser for help on using the repository browser.

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