VirtualBox

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

Last change on this file since 1598 was 1598, checked in by bird, 17 years ago

split out the path protection code from rm.

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