void SpawnApplyConfig(const char *Config, int Flags) { char *User=NULL, *Group=NULL, *Dir=NULL; char *Name=NULL, *Value=NULL; const char *ptr; struct rlimit limit; rlim_t val; int i; //set all signal handlers to default if (Flags & SPAWN_SIGDEF) { for (i =0; i < _NSIG; i++) signal(i,SIG_DFL); } //Set controlling tty to be stdin. This means that CTRL-C, SIGWINCH etc is handled for the //stdin file descriptor, not for any oher if (Flags & SPAWN_DAEMON) demonize(); else { if (Flags & SPAWN_SETSID) setsid(); if (Flags & SPAWN_CTRL_TTY) tcsetpgrp(0, getpgrp()); } User=CopyStr(User,""); Group=CopyStr(Group,""); ptr=GetNameValuePair(Config,"\\S","=",&Name,&Value); while (ptr) { if (strcasecmp(Name,"User")==0) User=CopyStr(User, Value); else if (strcasecmp(Name,"Group")==0) Group=CopyStr(Group, Value); else if (strcasecmp(Name,"Dir")==0) Dir=CopyStr(Dir, Value); else if (strcasecmp(Name,"PidFile")==0) WritePidFile(Value); else if (strcasecmp(Name,"prio")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"nice")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"priority")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"mem")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_DATA, &limit); } else if (strcasecmp(Name,"fsize")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_FSIZE, &limit); } else if (strcasecmp(Name,"files")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_NOFILE, &limit); } else if (strcasecmp(Name,"coredumps")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_CORE, &limit); } else if ( (strcasecmp(Name,"procs")==0) || (strcasecmp(Name,"nproc")==0) ) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_NPROC, &limit); } ptr=GetNameValuePair(ptr,"\\S","=",&Name,&Value); } // This allows us to chroot into a whole different unix directory tree, with its own // password file etc if (Flags & SPAWN_CHROOT) chroot("."); if (StrLen(Dir)) chdir(Dir); //Always do group first, otherwise we'll lose ability to switch user/group if (StrLen(Group)) SwitchGroup(Group); if (StrLen(User)) SwitchUser(User); //Must do this last! After parsing Config, and also after functions like //SwitchUser that will need access to /etc/passwd if (Flags & SPAWN_JAIL) chroot("."); DestroyString(Name); DestroyString(Value); DestroyString(User); DestroyString(Group); DestroyString(Dir); }
void ParseConfigItem(char *ConfigLine) { const char *ConfTokens[]={"Chroot","Chhome","AllowUsers","DenyUsers","Port","LogFile","AuthPath","BindAddress","LogPasswords","HttpMethods","AuthMethods","DefaultUser","DefaultGroup","Path","FileType","LogVerbose","AuthRealm","Compression","DirListType","DisplayNameLen","MaxLogSize","ScriptHandler","ScriptHashFile","WebsocketHandler","LookupClientName","SanitizeAllowTags","CustomHeader","UserAgentSettings", "SSLKey","SSLCert","SSLCiphers","SSLDHParams","SSLClientCertificate","SSLVerifyPath", "SSLVersion", "Event","FileCacheTime","HttpKeepAlive","AccessTokenKey","Timezone","MaxMemory","MaxStack","ActivityTimeout","PackFormats",NULL}; typedef enum {CT_CHROOT, CT_CHHOME, CT_ALLOWUSERS,CT_DENYUSERS,CT_PORT, CT_LOGFILE,CT_AUTHFILE,CT_BINDADDRESS,CT_LOGPASSWORDS,CT_HTTPMETHODS, CT_AUTHMETHODS,CT_DEFAULTUSER, CT_DEFAULTGROUP, CT_PATH, CT_FILETYPE, CT_LOG_VERBOSE, CT_AUTH_REALM, CT_COMPRESSION, CT_DIRTYPE, CT_DISPLAYNAMELEN, CT_MAXLOGSIZE, CT_SCRIPTHANDLER, CT_SCRIPTHASHFILE, CT_WEBSOCKETHANDLER, CT_LOOKUPCLIENT, CT_SANITIZEALLOW, CT_CUSTOMHEADER, CT_USERAGENTSETTINGS, CT_SSLKEY, CT_SSLCERT, CT_SSLCIPHERS, CT_SSLDHPARAMS, CT_CLIENT_CERTIFICATION, CT_SSLVERIFY_PATH, CT_SSL_VERSION, CT_EVENT, CT_FILE_CACHE_TIME, CT_SESSION_KEEPALIVE, CT_ACCESS_TOKEN_KEY, CT_TIMEZONE, CT_MAX_MEM, CT_MAX_STACK, CT_ACTIVITY_TIMEOUT, CT_ARCHIVE_FORMATS} TConfigTokens; char *Token=NULL, *ptr; struct group *grent; struct stat Stat; TConfigTokens TokType; ptr=GetToken(ConfigLine,"=|:",&Token,GETTOKEN_MULTI_SEPARATORS); StripLeadingWhitespace(Token); StripTrailingWhitespace(Token); TokType=MatchTokenFromList(Token,ConfTokens,0); switch(TokType) { case CT_PORT: Settings.Port=atoi(ptr); break; case CT_CHROOT: Settings.Flags &= ~FLAG_CHHOME; Settings.Flags |= FLAG_CHROOT; Settings.DefaultDir=CopyStr(Settings.DefaultDir,ptr); break; case CT_CHHOME: Settings.Flags &= ~FLAG_CHROOT; Settings.Flags|=FLAG_CHHOME; break; case CT_ALLOWUSERS: Settings.AllowUsers=CopyStr(Settings.AllowUsers,ptr); break; case CT_DENYUSERS: Settings.DenyUsers=CopyStr(Settings.DenyUsers,ptr); break; case CT_AUTHFILE: Settings.AuthPath=CopyStr(Settings.AuthPath,ptr); break; case CT_BINDADDRESS: Settings.BindAddress=CopyStr(Settings.BindAddress,ptr); break; case CT_LOGPASSWORDS: // Settings.Flags |= FLAG_LOGPASSWORDS; break; case CT_DISPLAYNAMELEN: Settings.DisplayNameLen=atoi(ptr); break; case CT_AUTHMETHODS: Settings.AuthMethods=CopyStr(Settings.AuthMethods,ptr); break; case CT_HTTPMETHODS: Settings.HttpMethods=CopyStr(Settings.HttpMethods,ptr); break; case CT_DEFAULTUSER: Settings.DefaultUser=CopyStr(Settings.DefaultUser,ptr); break; case CT_DEFAULTGROUP: Settings.DefaultGroup=CopyStr(Settings.DefaultGroup,ptr); grent=getgrnam(ptr); if (grent) Settings.DefaultGroupID=grent->gr_gid; break; case CT_SSLKEY: if (! Settings.SSLKeys) Settings.SSLKeys=ListCreate(); Token=FormatStr(Token,"SSL_KEY_FILE:%d",ListSize(Settings.SSLKeys)); ListAddNamedItem(Settings.SSLKeys,Token,CopyStr(NULL,ptr)); Settings.Flags |=FLAG_SSL; break; case CT_SSLCERT: if (! Settings.SSLKeys) Settings.SSLKeys=ListCreate(); Token=FormatStr(Token,"SSL_CERT_FILE:%d",ListSize(Settings.SSLKeys)); ListAddNamedItem(Settings.SSLKeys,Token,CopyStr(NULL,ptr)); Settings.Flags |=FLAG_SSL; break; case CT_SSLCIPHERS: LibUsefulSetValue("SSL-Permitted-Ciphers",ptr); break; case CT_SSLDHPARAMS: LibUsefulSetValue("SSL-DHParams-File",ptr); break; case CT_SSL_VERSION: LibUsefulSetValue("SSL-Level",ptr); break; case CT_AUTH_REALM: Settings.AuthRealm=CopyStr(Settings.AuthRealm,ptr); break; case CT_COMPRESSION: if (strcasecmp(ptr,"partial")==0) { Settings.Flags &= ~FLAG_COMPRESS; Settings.Flags |= FLAG_PARTIAL_COMPRESS; } else if (! YesNoTrueFalse(ptr)) Settings.Flags &= ~(FLAG_COMPRESS | FLAG_PARTIAL_COMPRESS); else { Settings.Flags &= ~FLAG_PARTIAL_COMPRESS; Settings.Flags |= FLAG_COMPRESS; } break; case CT_PATH: ptr=GetToken(ptr,",",&Token,0); VPathParse(Settings.VPaths, Token, ptr); break; case CT_FILETYPE: VPathParse(Settings.VPaths, Token, ptr); break; case CT_DIRTYPE: ParseDirListType(ptr); break; case CT_LOGFILE: Settings.LogPath=CopyStr(Settings.LogPath,ptr); break; case CT_LOG_VERBOSE: if (YesNoTrueFalse(ptr)) Settings.Flags |= FLAG_LOG_VERBOSE; else Settings.Flags &= ~FLAG_LOG_VERBOSE; break; case CT_MAXLOGSIZE: Settings.MaxLogSize = (int) ParseHumanReadableDataQty(ptr, 0); break; case CT_SCRIPTHANDLER: ptr=GetToken(ptr,"=",&Token,0); if (! Settings.ScriptHandlers) Settings.ScriptHandlers=ListCreate(); SetTypedVar(Settings.ScriptHandlers,Token,ptr,PATHTYPE_CGI); break; case CT_SCRIPTHASHFILE: Settings.ScriptHashFile=CopyStr(Settings.ScriptHashFile,ptr); Settings.Flags |= FLAG_CHECK_SCRIPTS; break; case CT_WEBSOCKETHANDLER: if (! Settings.ScriptHandlers) Settings.ScriptHandlers=ListCreate(); ptr=GetToken(ptr,"=",&Token,0); SetTypedVar(Settings.ScriptHandlers,Token,ptr,PATHTYPE_WEBSOCKET); break; case CT_SANITIZEALLOW: if (! Settings.SanitizeArgumentsAllowedTags) Settings.SanitizeArgumentsAllowedTags=ListCreate(); ptr=GetToken(ptr,",",&Token,0); while (ptr) { SetVar(Settings.SanitizeArgumentsAllowedTags,Token,"Y"); ptr=GetToken(ptr,",",&Token,0); } break; case CT_CUSTOMHEADER: if (! Settings.CustomHeaders) Settings.CustomHeaders=ListCreate(); ptr=GetToken(ptr,":",&Token,0); ListAddNamedItem(Settings.CustomHeaders,Token,CopyStr(NULL,ptr)); break; case CT_LOOKUPCLIENT: if (YesNoTrueFalse(ptr)) Settings.Flags |= FLAG_LOOKUP_CLIENT; else Settings.Flags &= ~FLAG_LOOKUP_CLIENT; break; case CT_USERAGENTSETTINGS: if (! Settings.UserAgents) Settings.UserAgents=ListCreate(); ptr=GetToken(ptr,",",&Token,0); ListAddNamedItem(Settings.UserAgents,Token,CopyStr(NULL,ptr)); break; case CT_SSLVERIFY_PATH: if (stat(ptr,&Stat)==0) { if (S_ISDIR(Stat.st_mode)) LibUsefulSetValue("SSL_VERIFY_CERTDIR",ptr); else if (S_ISREG(Stat.st_mode)) LibUsefulSetValue("SSL_VERIFY_CERTFILE",ptr); } else HandleError(ERR_PRINT|ERR_LOG|ERR_EXIT, "ERROR: Can't access SSL certificate verify data at '%s'",ptr); break; case CT_CLIENT_CERTIFICATION: if (strcasecmp(ptr,"ask")==0) Settings.AuthFlags |= FLAG_AUTH_CERT_ASK; if (strcasecmp(ptr,"required")==0) Settings.AuthFlags |= FLAG_AUTH_CERT_REQUIRED; if (strcasecmp(ptr,"sufficient")==0) Settings.AuthFlags |= FLAG_AUTH_CERT_SUFFICIENT; if (strcasecmp(ptr,"optional")==0) Settings.AuthFlags |= FLAG_AUTH_CERT_SUFFICIENT; if (strcasecmp(ptr,"required+sufficient")==0) Settings.AuthFlags |= FLAG_AUTH_CERT_REQUIRED | FLAG_AUTH_CERT_SUFFICIENT; break; case CT_EVENT: ParseEventConfig(ptr); break; case CT_FILE_CACHE_TIME: Settings.DocumentCacheTime=strtol(ptr,NULL,10); break; case CT_SESSION_KEEPALIVE: if (YesNoTrueFalse(ptr)) Settings.Flags |= FLAG_KEEPALIVES; else Settings.Flags &= ~FLAG_KEEPALIVES; break; case CT_ACCESS_TOKEN_KEY: Settings.AccessTokenKey=CopyStr(Settings.AccessTokenKey,ptr); break; case CT_TIMEZONE: Settings.Timezone=CopyStr(Settings.Timezone,ptr); break; case CT_MAX_MEM: Settings.AddressSpace=CopyStr(Settings.AddressSpace,ptr); break; case CT_MAX_STACK: Settings.StackSize=CopyStr(Settings.StackSize,ptr); break; case CT_ACTIVITY_TIMEOUT: Settings.ActivityTimeout=atoi(ptr); break; case CT_ARCHIVE_FORMATS: Settings.PackFormats=ParsePackFormats(Settings.PackFormats, ptr); break; } DestroyString(Token); }