
commit
d2ea4e1057
3 changed files with 562 additions and 0 deletions
@ -0,0 +1,266 @@
|
||||
|
||||
---------- |
||||
OVERVIEW |
||||
---------- |
||||
|
||||
ExecWrap is a super-user exec wrapper for the lighttpd web-server, but it can be used in |
||||
any environment as long as arguments can be passed from the server to its children via the |
||||
environment. |
||||
|
||||
ExecWrap is released under the BSD license, which may be found in the source file. |
||||
|
||||
The different compile-time configuration options are explained below. For optimal security, |
||||
please review ALL of them, as default values are hard to provide in most cases. The |
||||
configuration is mainly concerned with security. Next, the run-time configuration options |
||||
are explained. |
||||
|
||||
An overview of the security implications of each check the wrapper performs is then given, |
||||
along with some checks it doesn't perform and the reason for it. |
||||
|
||||
Finally, the run-time configuration is explained and a usage example is given. |
||||
|
||||
|
||||
------------------- |
||||
COMMAND ARGUMENTS |
||||
------------------- |
||||
|
||||
The super user and the user specified by the PARENT_UID parameter (see below) are allowed |
||||
to give command line options to the wrapper. These are only useful for humans, and not for |
||||
a web-server. |
||||
|
||||
Argument Explanation |
||||
------------------------------------------------------------------------------------------- |
||||
-v Displays the name, i.e. ExecWrap, and version of the wrapper. |
||||
-V Displays name, version and the compile-time configuration parameters. |
||||
|
||||
|
||||
---------------------------- |
||||
COMPILE-TIME CONFIGURATION |
||||
---------------------------- |
||||
|
||||
After compiling, remember that the program must be owned by the super user and have its |
||||
setuid-user bit set to work! The configuration parameters are found in the file |
||||
execwrap_config.h, except for the ones that shouldn't normally be changed. Those are found |
||||
in the main file. |
||||
|
||||
Config parameter Explanation |
||||
------------------------------------------------------------------------------------------- |
||||
PARENT_UID The (numeric only) value of this parameter controls what parent UID |
||||
the wrapper will accept. If it is started by any other UID than this |
||||
or the super user, it will instantly abort. |
||||
|
||||
TARGET_MIN_UID This (numeric) value sets the _minimum_ UID the wrapper can be told |
||||
to switch to. If asked to switch to a lower value, it will abort. |
||||
It is _strongly_ advised to set this value to the _minimum_ needed. |
||||
Setting it to 0 would allow the server to become root, wherefore it |
||||
is disallowed (by compile-time security checks). |
||||
|
||||
TARGET_MIN_GID The same as TARGET_MIN_UID, but for the GID. The same reasons and |
||||
restrictions apply. |
||||
|
||||
TARGET_PATH_PREFIX This parameter sets the prefix of any target program the wrapper is |
||||
instructed to invoke. If asked to start something _not_ under this |
||||
path, the wrapper aborts. |
||||
|
||||
DEFAULT_UID The default (numeric) UID to become, if no UID is given via the |
||||
environment. It defaults to 65534, which usually maps to the nobody |
||||
user. This is recommended. At any rate, it must be at least as high |
||||
as TARGET_MIN_UID. This is ensured by compile time security checks. |
||||
|
||||
DEFAULT_GID The same as DEFAULT_UID, but for the GID. The same reasons and |
||||
restrictions apply. |
||||
|
||||
|
||||
The following configuration parameters shouldn't normally be changed. In case you have a |
||||
clash with some other ENV arguments to the target program, they can be changed, however. |
||||
The configuration dump command line option, -V, will not output them. |
||||
|
||||
|
||||
ENV_UID This parameter controls the name of the environment variable used to |
||||
tell the wrapper what UID to switch to. It defaults to "UID=" and |
||||
there is usually no need to change it. If you do, remember that it |
||||
must end in "=" like the default, or it will fail to be recognised. |
||||
See the run-time configuration section below. |
||||
|
||||
ENV_GID The same as ENV_UID, but controls the name of the GID parameter. |
||||
Defaults to "GID=". |
||||
|
||||
ENV_TARGET The same as ENV_UID, but controls the name of the TARGET parameter. |
||||
Defaults to "TARGET=". |
||||
|
||||
ENV_CHECK_GID The same as ENV_UID, but controls the name of the CHECK_GID |
||||
parameter. Defaults to "CHECK_GID=". |
||||
|
||||
ENV_NON_RESIDENT The same as ENV_UID, but controls the name of the NON_RESIDENT |
||||
parameter. Defaults to "NON_RESIDENT=". |
||||
|
||||
|
||||
--------------------- |
||||
COMPILE AND INSTALL |
||||
--------------------- |
||||
|
||||
There is no Makefile right now, but compile is as simple as: |
||||
|
||||
> gcc -O2 -o execwrap execwrap.c && strip execwrap |
||||
|
||||
Or similar, depending on taste. You need something other than an ancient compiler to make |
||||
it work, preferably C99. To install, make sure the file is owned by the super user and has |
||||
the proper modes: |
||||
|
||||
> chown root execwrap |
||||
> chmod og-w,+rx,u+s execwrap |
||||
|
||||
Then move it to where it's supposed to reside. That's all. If you're really fanatic about |
||||
security, you can also do something like this (before the chmod u+s): |
||||
|
||||
> chgrp lighttpd execwrap # <-- Or whatever group your web-server is in. |
||||
> chmod o-rwx,g-rw execwrap |
||||
|
||||
To make the command impossible to start for anyone but the super user and the server admin. |
||||
But since the first thing the wrapper does on start up is to check the parent UID, this |
||||
really isn't necessary. |
||||
|
||||
|
||||
------------------------ |
||||
RUN TIME CONFIGURATION |
||||
------------------------ |
||||
|
||||
The run-time configuration is provided by environment variables, and not the command line. |
||||
Currently, command line arguments are completely ignored. The run-time arguments are |
||||
subjected to the restrictions imposed by the compile-time configuration discussed above. |
||||
|
||||
Note that since the names of the parameters can be changed, the defaults are used in the |
||||
following list. |
||||
|
||||
Config parameter Explanation |
||||
------------------------------------------------------------------------------------------- |
||||
UID The UID to switch to. Only numerical values are accepted currently. |
||||
|
||||
GID The GID to switch to. Only numerical values are accepted currently. |
||||
|
||||
TARGET The target program to start. For security, it must be absolute and |
||||
must not contain any ~ characters or ".." sub-strings. Of course the |
||||
compiled-in prefix must also be a prefix of it. |
||||
|
||||
CHECK_GID If set (to anything, even the empty string), the security checks will |
||||
be slightly relaxed to allow targets owned by the target GID but not |
||||
necessarily by the target UID, as well as allowing the target to be |
||||
group-writable if owned by the target GID. Useful for projects where |
||||
several people collaborate so file ownership can vary. |
||||
|
||||
NON_RESIDENT If set (to anything), the wrapper will drop privileges and become the |
||||
target process directly, instead of the default behaviour where it |
||||
forks off before becoming the target, allowing SIGTERM to propagate |
||||
from the caller of the wrapper, to the target. It is not recommended |
||||
to set this, as it will make it impossible for the caller (usually a |
||||
web-server) to terminate the target process, and thus prevents it |
||||
from effectively managing it. |
||||
|
||||
|
||||
----------------------------------- |
||||
SECURITY CHECKS AND THEIR REASONS |
||||
----------------------------------- |
||||
|
||||
The security checks below are listed in the order they are performed. |
||||
|
||||
Security check Reason it's performed |
||||
------------------------------------------------------------------------------------------- |
||||
Check parent UID Done to disallow people other than root and server admins to become |
||||
another user. The reason for this should be obvious, but given all |
||||
the other checks, this one actually isn't the most important one. |
||||
|
||||
Check min. UID/GID Done to control what users the server admins can start programs as. |
||||
In particular, they can't start programs as root. Again, the reason |
||||
for checking this should be obvious. Never ever set these values to |
||||
anything at or below system services users and groups! |
||||
|
||||
Target path checks We check that it's absolute and doesn't contain ~ and "..". This is |
||||
an overly careful (but also simpler) way to make sure it doesn't |
||||
lead outside of the prefix. |
||||
|
||||
Target path prefix Done to prevent server admins from executing user code outside the |
||||
designated server root. This is not in itself a security enhancement |
||||
unless the system in general is kept in a tight leash, but it also |
||||
helps prevent a run-away server from causing problems. |
||||
|
||||
Target given Done. This isn't for security, but without a target there is no work |
||||
to be done in the first place :-p. |
||||
|
||||
Can switch UID/GID Done. Again, this is usually not a security enhancement, as the |
||||
switch should never fail. In certain environments however, additional |
||||
security measures such as MAC might prevent even the super user from |
||||
switching to certain UIDs or GIDs. |
||||
|
||||
Can stat the target Done. Otherwise, we can hardly expect to become the target anyway. |
||||
Not for security as such. |
||||
|
||||
Target has wrong Done to prevent users not owning the target file, or not in the same |
||||
modes or UID/GID group, from replacing it with malicious code. The following checks |
||||
are performed. If any of them fails, the wrapper aborts. |
||||
1. Target is NOT world-writable. |
||||
2. Target is owned by the UID we switched to OR, when CHECK_GID is |
||||
given, target is owned by the GID we switched to. |
||||
3. Target is NOT group-writable unless CHECK_GID was given and it |
||||
is owned by the GID we switched to. |
||||
|
||||
|
||||
Also, there is one common check we do not perform: |
||||
|
||||
Target dir checks Not done. Checking the target directory adds no real security. True, |
||||
if someone else has write permissions he can remove the target and |
||||
replace it with something else, but this won't have the correct UID |
||||
and GID. If he can make it have the right values, he would be able to |
||||
overwrite the target in the first place. Care must be taken here if |
||||
the CHECK_GID feature is used along with the setgid bit. See below. |
||||
|
||||
|
||||
------------------------------- |
||||
OTHER SECURITY CONSIDERATIONS |
||||
------------------------------- |
||||
|
||||
Even though several steps are taken to prevent abuse, care must be taken when setting up |
||||
any system involving a super-user executable. In particular, consider the following: |
||||
|
||||
1. Make sure the wrapper is safe. It should at most be user-writable. |
||||
2. Make sure the group setup for the web server is sane. If the setgid bit is enabled for |
||||
the web root, which is useful in many cases and is the reason for the CHECK_GID |
||||
feature, make SURE that ALL members of the group in question are accounted for, since |
||||
they might be able to replace files in any directory at and below the web root. |
||||
|
||||
|
||||
----------------------- |
||||
CONFIGURATION EXAMPLE |
||||
----------------------- |
||||
|
||||
|
||||
Compile-time configuration (the <- parts are comments, obviously): |
||||
------------------------------------------------------------------------------------------- |
||||
PARENT_UID 104 <- My lighttpd UID. |
||||
TARGET_MIN_UID 1000 <- The first regular user UID. |
||||
TARGET_MIN_GID 100 <- Ditto for group. |
||||
TARGET_PATH_PREFIX "/var/www/light/" <- Site web-roots are below this. |
||||
DEFAULT_UID 65534 <- Nobody. |
||||
DEFAULT_GID 65534 <- Nobody. |
||||
|
||||
|
||||
Run-time configuration in lighttpd: |
||||
------------------------------------------------------------------------------------------- |
||||
fastcgi.server = ( |
||||
"/dispatch.fcg" => |
||||
( "dispatcher" => |
||||
( |
||||
"socket" => "/tmp/fcgi.sock", |
||||
"bin-path" => "/var/www/light/execwrap", <- The wrapper. |
||||
"check-local" => "disable", |
||||
"min-procs" => 1, |
||||
"max-procs" => 1, |
||||
"bin-environment" => ( |
||||
"UID" => "1000", |
||||
"GID" => "407", |
||||
"TARGET" => "/var/www/light/blah.tld/html/dispatch.fcg", <- The real script. |
||||
"CHECK_GID" => "1" |
||||
) |
||||
) |
||||
) |
||||
) |
||||
|
@ -0,0 +1,268 @@
|
||||
/*
|
||||
|
||||
Superuser-exec wrapper for HTTP serves and other needs (made especially for lighttpd). |
||||
Allows programs to be run with configurable uid/gid. |
||||
Version 0.4 (2006-06-09) |
||||
|
||||
For documentation on how to configure the wrapper, see the README. |
||||
Command line option -v displays version, while -V displays compile-time configuration. |
||||
These options are only available for the super user and the server admin. |
||||
|
||||
Brief version history: |
||||
|
||||
Vers Date Changes |
||||
----------------------------------------------------------------------------------------- |
||||
0.4 2006-06-09 Added a BSD license. |
||||
0.3 2005-09-27 Changed the wrapper to stay resident and propagate SIGTERM to the |
||||
target. Not doing so will prevent the server from managing the target. |
||||
The old behaviour can be restored with a run-time option. Fixed a bug |
||||
in the call to execl, which could cause it to fail or crash. No |
||||
security risk. Added custom return codes on errors. Added some command |
||||
line options. |
||||
0.2 2005-09-14 Cleaned up source a bit, and added compile-time security checks. Fixed |
||||
a few minor issues. Compiles under C89 now (e.g. gcc -std=c89). |
||||
0.1 2005-09-08 Initial version. |
||||
|
||||
|
||||
License: |
||||
|
||||
Copyright (c) 2006, Sune Foldager |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are |
||||
permitted provided that the following conditions are met: |
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this list of |
||||
conditions and the following disclaimer. |
||||
- Redistributions in binary form must reproduce the above copyright notice, this list of |
||||
conditions and the following disclaimer in the documentation and/or other materials |
||||
provided with the distribution. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY |
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
||||
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR |
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
|
||||
*/ |
||||
|
||||
|
||||
/* Configuration. Shouldn't be changed. */ |
||||
|
||||
#define ENV_UID "UID=" |
||||
#define ENV_GID "GID=" |
||||
#define ENV_TARGET "TARGET=" |
||||
#define ENV_CHECK_GID "CHECK_GID=" |
||||
#define ENV_NON_RESIDENT "NON_RESIDENT=" |
||||
|
||||
/* Return values for various errors. */ |
||||
|
||||
#define RC_CALLER_UID 10 |
||||
#define RC_TARGET_UID 11 |
||||
#define RC_TARGET_GID 12 |
||||
#define RC_TARGET 13 |
||||
#define RC_MISSING_CONFIG 14 |
||||
#define RC_SIGNAL_HANDLER 15 |
||||
#define RC_SETGID 16 |
||||
#define RC_SETUID 17 |
||||
#define RC_STAT 18 |
||||
#define RC_WORLD_WRITE 19 |
||||
#define RC_WRONG_USER 20 |
||||
#define RC_GROUP_WRITE 21 |
||||
#define RC_WRONG_GROUP 22 |
||||
#define RC_EXEC 23 |
||||
#define RC_BAD_OPTION 24 |
||||
|
||||
/* User configuration. */ |
||||
#include "execwrap_config.h" |
||||
|
||||
/* Compile-time security checks. */ |
||||
#if !TARGET_MIN_UID |
||||
#error SECURITY: TARGET_MIN_UID set to 0. See README for details. |
||||
#endif |
||||
#if !TARGET_MIN_GID |
||||
#error SECURITY: TARGET_MIN_GID set to 0. See README for details. |
||||
#endif |
||||
#if DEFAULT_UID < TARGET_MIN_UID |
||||
#error SECURITY: DEFAULT_UID set to a lower value than TARGET_MIN_UID. See README for details. |
||||
#endif |
||||
#if DEFAULT_GID < TARGET_MIN_GID |
||||
#error SECURITY: DEFAULT_GID set to a lower value than TARGET_MIN_GID. See README for details. |
||||
#endif |
||||
|
||||
/* Useful macro and other stuff. */ |
||||
#define VERSION_STRING "ExecWrap v0.3 by Sune Foldager." |
||||
#define STRLEN(a) (sizeof(a)-1) |
||||
|
||||
/* Shortcuts. */ |
||||
#define TARGET_PATH_PREFIX_LEN STRLEN(TARGET_PATH_PREFIX) |
||||
#define ENV_UID_LEN STRLEN(ENV_UID) |
||||
#define ENV_GID_LEN STRLEN(ENV_GID) |
||||
#define ENV_TARGET_LEN STRLEN(ENV_TARGET) |
||||
#define ENV_CHECK_GID_LEN STRLEN(ENV_CHECK_GID) |
||||
#define ENV_NON_RESIDENT_LEN STRLEN(ENV_NON_RESIDENT) |
||||
|
||||
/* Stuff we need. */ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/stat.h> |
||||
#include <unistd.h> |
||||
#include <signal.h> |
||||
|
||||
|
||||
/* The global child PID and previous SIGTERM handler. */ |
||||
int pid; |
||||
void (*oldHandler)(int); |
||||
|
||||
|
||||
/* SIGTERM handler. */ |
||||
void sigTermHandler(int signal) |
||||
{ |
||||
|
||||
/* If we're in the parent, kill the child as well. */ |
||||
if(pid) kill(pid, SIGTERM); |
||||
|
||||
/* Call the default handler. */ |
||||
oldHandler(signal); |
||||
|
||||
} |
||||
|
||||
|
||||
/* Down to business. */ |
||||
int main(int argc, char* argv[], char* envp[]) |
||||
{ |
||||
|
||||
/* Verify parent UID. Only the super user and PARENT_UID are allowed. */ |
||||
if(getuid() != 0 && getuid() != PARENT_UID) return RC_CALLER_UID; |
||||
|
||||
/* Command line options. */ |
||||
if(argc > 1) |
||||
{ |
||||
if(argv[1][0] == '-') switch(argv[1][1]) |
||||
{ |
||||
case 'v': puts(VERSION_STRING); |
||||
return 0; |
||||
case 'V': puts(VERSION_STRING); |
||||
puts("Compile-time configuration:"); |
||||
printf("PARENT_UID : %d\n", PARENT_UID); |
||||
printf("TARGET_MIN_UID : %d\n", TARGET_MIN_UID); |
||||
printf("TARGET_MIN_GID : %d\n", TARGET_MIN_GID); |
||||
printf("TARGET_PATH_PREFIX : %s\n", TARGET_PATH_PREFIX); |
||||
printf("DEFAULT_UID : %d\n", DEFAULT_UID); |
||||
printf("DEFAULT_GID : %d\n", DEFAULT_GID); |
||||
return 0; |
||||
} |
||||
|
||||
/* Fail on unknown option. Known options return quietly above. */ |
||||
return RC_BAD_OPTION; |
||||
} |
||||
|
||||
/* Grab stuff from environment, and set defaults. */ |
||||
int uid = DEFAULT_UID; |
||||
int gid = DEFAULT_GID; |
||||
char* target = 0; |
||||
char* args = 0; |
||||
char check_gid = 0; |
||||
char non_resident = 0; |
||||
char** p = envp; |
||||
char* s; |
||||
char* t; |
||||
while(s = *p++) |
||||
{ |
||||
|
||||
/* Target UID. */ |
||||
if(!strncmp(ENV_UID, s, ENV_UID_LEN)) |
||||
{ |
||||
uid = atoi(s + ENV_UID_LEN); |
||||
if(uid < TARGET_MIN_UID) return RC_TARGET_UID; |
||||
} |
||||
|
||||
/* Target GID. */ |
||||
if(!strncmp(ENV_GID, s, ENV_GID_LEN)) |
||||
{ |
||||
gid = atoi(s + ENV_GID_LEN); |
||||
if(gid < TARGET_MIN_GID) return RC_TARGET_GID; |
||||
} |
||||
|
||||
/* Target script. */ |
||||
if(!strncmp(ENV_TARGET, s, ENV_TARGET_LEN)) |
||||
{ |
||||
target = s + ENV_TARGET_LEN; |
||||
if((target[0] != '/') || strchr(target, '~') || strstr(target, "..") || |
||||
strncmp(TARGET_PATH_PREFIX, target, TARGET_PATH_PREFIX_LEN)) return RC_TARGET; |
||||
} |
||||
|
||||
/* Check GID instead of UID. */ |
||||
if(!strncmp(ENV_CHECK_GID, s, ENV_CHECK_GID_LEN)) |
||||
{ |
||||
check_gid = 1; |
||||
} |
||||
|
||||
/* Use non-resident wrapping style. */ |
||||
if(!strncmp(ENV_NON_RESIDENT, s, ENV_NON_RESIDENT_LEN)) |
||||
{ |
||||
non_resident = 1; |
||||
} |
||||
|
||||
} |
||||
|
||||
/* See if we got all we need. */ |
||||
if(!target) return RC_MISSING_CONFIG; |
||||
|
||||
/* Install the SIGTERM handler. */ |
||||
if(!non_resident) |
||||
{ |
||||
oldHandler = signal(SIGTERM, sigTermHandler); |
||||
if(oldHandler == SIG_ERR) return RC_SIGNAL_HANDLER; |
||||
} |
||||
|
||||
/* Fork off (or, if we are a non-resident wrapper, just carry on). */ |
||||
if(non_resident || !(pid = fork())) |
||||
{ |
||||
|
||||
/* We're in the child. Drop privileges. */ |
||||
if(setgid(gid)) return RC_SETGID; |
||||
if(setuid(uid)) return RC_SETUID; |
||||
|
||||
/* Stat the target script. */ |
||||
char uid_ok = 1; |
||||
struct stat stat_buf; |
||||
if(stat(target, &stat_buf)) return RC_STAT; |
||||
int modes = stat_buf.st_mode; |
||||
|
||||
/* Never allow world-write. */ |
||||
if(modes & S_IWOTH) return RC_WORLD_WRITE; |
||||
|
||||
/* Only allow user miss-match if check_gid is set. */ |
||||
if(uid != stat_buf.st_uid) |
||||
{ |
||||
if(!check_gid) return RC_WRONG_USER; |
||||
uid_ok = 0; |
||||
} |
||||
|
||||
/* If group doesn't match, don't allow group-write.
|
||||
Also, don't allow if neither user or group match. */ |
||||
if(gid != stat_buf.st_gid) |
||||
{ |
||||
if(modes & S_IWGRP) return RC_GROUP_WRITE; |
||||
if(!uid_ok) return RC_WRONG_GROUP; |
||||
} |
||||
|
||||
/* All checks passed, let's become the target! */ |
||||
execl(target, target, NULL); |
||||
return RC_EXEC; |
||||
|
||||
} |
||||
|
||||
/* Here we're in the parent. Wait for the child to be done, and return. */ |
||||
int status; |
||||
wait(&status); |
||||
return status; |
||||
|
||||
} |
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
|
||||
User configuration for ExecWrap. Please review ALL items in this file, before you compile. |
||||
Remember, the security of your system depends on getting these right! |
||||
|
||||
See the README for documentation. |
||||
|
||||
*/ |
||||
|
||||
|
||||
/* Our parent must have this UID, or we will abort. */ |
||||
#define PARENT_UID 104 |
||||
|
||||
/* Minimum UID we can switch to. */ |
||||
#define TARGET_MIN_UID 1000 |
||||
|
||||
/* Minimum GID we can switch to. */ |
||||
#define TARGET_MIN_GID 100 |
||||
|
||||
/* Path prefix all targets must start with. */ |
||||
#define TARGET_PATH_PREFIX "/var/www/light/" |
||||
|
||||
/* Default UID to switch to, if none given. */ |
||||
#define DEFAULT_UID 65534 |
||||
|
||||
/* Default GID to switch to, if none given. */ |
||||
#define DEFAULT_GID 65534 |
||||
|
Loading…
Reference in new issue