#include "cupsd.h"
#include <stdarg.h>
#include <pwd.h>
#include <grp.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_DOMAINSOCKETS
# include <sys/un.h>
#endif
#ifdef HAVE_CDSASSL
# include <Security/SecureTransport.h>
# include <Security/SecIdentity.h>
# include <Security/SecIdentitySearch.h>
# include <Security/SecKeychain.h>
#endif
#ifdef HAVE_VSYSLOG
# include <syslog.h>
#endif
#ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
#endif
typedef struct
{
char *name;
void *ptr;
int type;
} var_t;
#define VAR_INTEGER 0
#define VAR_STRING 1
#define VAR_BOOLEAN 2
static var_t variables[] =
{
{ "AccessLog", &AccessLog, VAR_STRING },
{ "AutoPurgeJobs", &JobAutoPurge, VAR_BOOLEAN },
{ "BrowseInterval", &BrowseInterval, VAR_INTEGER },
{ "BrowsePort", &BrowsePort, VAR_INTEGER },
{ "BrowseShortNames", &BrowseShortNames, VAR_BOOLEAN },
{ "BrowseTimeout", &BrowseTimeout, VAR_INTEGER },
{ "Browsing", &Browsing, VAR_BOOLEAN },
{ "Classification", &Classification, VAR_STRING },
{ "ClassifyOverride", &ClassifyOverride, VAR_BOOLEAN },
{ "ConfigFilePerm", &ConfigFilePerm, VAR_INTEGER },
{ "DataDir", &DataDir, VAR_STRING },
{ "DefaultCharset", &DefaultCharset, VAR_STRING },
{ "DefaultLanguage", &DefaultLanguage, VAR_STRING },
{ "DefaultShared", &DefaultShared, VAR_BOOLEAN },
{ "DocumentRoot", &DocumentRoot, VAR_STRING },
{ "ErrorLog", &ErrorLog, VAR_STRING },
{ "FaxRetryLimit", &FaxRetryLimit, VAR_INTEGER },
{ "FaxRetryInterval", &FaxRetryInterval, VAR_INTEGER },
{ "FileDevice", &FileDevice, VAR_BOOLEAN },
{ "FilterLimit", &FilterLimit, VAR_INTEGER },
{ "FilterNice", &FilterNice, VAR_INTEGER },
{ "FontPath", &FontPath, VAR_STRING },
{ "HideImplicitMembers", &HideImplicitMembers, VAR_BOOLEAN },
{ "ImplicitClasses", &ImplicitClasses, VAR_BOOLEAN },
{ "ImplicitAnyClasses", &ImplicitAnyClasses, VAR_BOOLEAN },
{ "KeepAliveTimeout", &KeepAliveTimeout, VAR_INTEGER },
{ "KeepAlive", &KeepAlive, VAR_BOOLEAN },
{ "LimitRequestBody", &MaxRequestSize, VAR_INTEGER },
{ "ListenBackLog", &ListenBackLog, VAR_INTEGER },
{ "LogFilePerm", &LogFilePerm, VAR_INTEGER },
{ "MaxClients", &MaxClients, VAR_INTEGER },
{ "MaxClientsPerHost", &MaxClientsPerHost, VAR_INTEGER },
{ "MaxCopies", &MaxCopies, VAR_INTEGER },
#ifdef __APPLE__
{ "MinCopies", &MinCopies, VAR_INTEGER },
{ "AppleQuotas", &AppleQuotas, VAR_BOOLEAN },
{ "ApplePreserveJobHistoryAttributes",
&ApplePreserveJobHistoryAttributes,
VAR_BOOLEAN },
#endif
{ "MaxJobs", &MaxJobs, VAR_INTEGER },
{ "MaxJobsPerPrinter", &MaxJobsPerPrinter, VAR_INTEGER },
{ "MaxJobsPerUser", &MaxJobsPerUser, VAR_INTEGER },
{ "MaxLogSize", &MaxLogSize, VAR_INTEGER },
{ "MaxPrinterHistory", &MaxPrinterHistory, VAR_INTEGER },
{ "MaxRequestSize", &MaxRequestSize, VAR_INTEGER },
{ "PageLog", &PageLog, VAR_STRING },
{ "PreserveJobFiles", &JobFiles, VAR_BOOLEAN },
{ "PreserveJobHistory", &JobHistory, VAR_BOOLEAN },
{ "Printcap", &Printcap, VAR_STRING },
{ "PrintcapGUI", &PrintcapGUI, VAR_STRING },
{ "ReloadTimeout", &ReloadTimeout, VAR_INTEGER },
{ "RemoteRoot", &RemoteRoot, VAR_STRING },
{ "RequestRoot", &RequestRoot, VAR_STRING },
{ "RIPCache", &RIPCache, VAR_STRING },
{ "RunAsUser", &RunAsUser, VAR_BOOLEAN },
{ "RootCertDuration", &RootCertDuration, VAR_INTEGER },
{ "ServerAdmin", &ServerAdmin, VAR_STRING },
{ "ServerBin", &ServerBin, VAR_STRING },
#ifdef HAVE_SSL
{ "ServerCertificate", &ServerCertificate, VAR_STRING },
# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
{ "ServerKey", &ServerKey, VAR_STRING },
# endif
# ifdef HAVE_CDSASSL
{ "SSLVerifyCertificates", &SSLVerifyCertificates, VAR_BOOLEAN },
# endif
#endif
{ "ServerName", &ServerName, VAR_STRING },
{ "ServerRoot", &ServerRoot, VAR_STRING },
{ "TempDir", &TempDir, VAR_STRING },
{ "Timeout", &Timeout, VAR_INTEGER }
};
#define NUM_VARS (sizeof(variables) / sizeof(variables[0]))
static int read_configuration(cups_file_t *fp);
static int read_location(cups_file_t *fp, char *name, int linenum);
static int get_address(char *value, unsigned defaddress, int defport,
struct sockaddr_in *address);
static int conf_file_check(const char*filename, const char *root, int mode,
int user, int group, int is_dir, int create_dir);
int
ReadConfiguration(void)
{
int i;
cups_file_t *fp;
int status;
char temp[1024],
*slash;
char type[MIME_MAX_SUPER + MIME_MAX_TYPE];
char *language;
struct passwd *user;
struct group *group;
char *old_serverroot,
*old_requestroot;
StopServer();
old_serverroot = NULL;
SetString(&old_serverroot, ServerRoot);
old_requestroot = NULL;
SetString(&old_requestroot, RequestRoot);
DeleteAllLocations();
if (NumBrowsers > 0)
{
free(Browsers);
NumBrowsers = 0;
}
if (NumPolled > 0)
{
free(Polled);
NumPolled = 0;
}
if (NumRelays > 0)
{
for (i = 0; i < NumRelays; i ++)
if (Relays[i].from.type == AUTH_NAME)
free(Relays[i].from.mask.name.name);
free(Relays);
NumRelays = 0;
}
if (NumListeners > 0)
{
#ifdef HAVE_DOMAINSOCKETS
int i;
listener_t *lis;
for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++)
if (lis->address.sin_family == AF_LOCAL)
ClearString((char **)&lis->address.sin_addr);
#endif
free(Listeners);
NumListeners = 0;
}
gethostname(temp, sizeof(temp));
SetString(&ServerName, temp);
SetStringf(&ServerAdmin, "root@%s", temp);
SetString(&ServerBin, CUPS_SERVERBIN);
SetString(&RequestRoot, CUPS_REQUESTS);
SetString(&DocumentRoot, CUPS_DOCROOT);
SetString(&DataDir, CUPS_DATADIR);
SetString(&AccessLog, CUPS_LOGDIR "/access_log");
SetString(&ErrorLog, CUPS_LOGDIR "/error_log");
SetString(&PageLog, CUPS_LOGDIR "/page_log");
SetString(&Printcap, "/etc/printcap");
SetString(&PrintcapGUI, "/usr/bin/glpoptions");
SetString(&FontPath, CUPS_FONTPATH);
SetString(&RemoteRoot, "remroot");
SetString(&ServerHeader, "CUPS/1.1");
strlcpy(temp, ConfigurationFile, sizeof(temp));
if ((slash = strrchr(temp, '/')) != NULL)
*slash = '\0';
SetString(&ServerRoot, temp);
ClearString(&Classification);
ClassifyOverride = 0;
#ifdef HAVE_SSL
# ifdef HAVE_CDSASSL
if (ServerCertificatesArray)
{
CFRelease(ServerCertificatesArray);
ServerCertificatesArray = NULL;
}
SetString(&ServerCertificate, "/Library/Keychains/System.keychain");
# else
SetString(&ServerCertificate, "ssl/server.crt");
SetString(&ServerKey, "ssl/server.key");
# endif
#endif
if ((language = DEFAULT_LANGUAGE) == NULL)
language = "en";
else if (strcmp(language, "C") == 0 || strcmp(language, "POSIX") == 0)
language = "en";
SetString(&DefaultLanguage, language);
SetString(&DefaultCharset, DEFAULT_CHARSET);
SetString(&RIPCache, "8m");
if (getenv("TMPDIR") == NULL)
SetString(&TempDir, CUPS_REQUESTS "/tmp");
else
SetString(&TempDir, getenv("TMPDIR"));
group = getgrnam(CUPS_DEFAULT_GROUP);
endgrent();
NumSystemGroups = 0;
if (group != NULL)
{
SetString(&SystemGroups[0], CUPS_DEFAULT_GROUP);
Group = group->gr_gid;
}
else
{
group = getgrgid(0);
endgrent();
if (group != NULL)
{
SetString(&SystemGroups[0], group->gr_name);
Group = 0;
}
else
{
SetString(&SystemGroups[0], "unknown");
Group = 0;
}
}
if ((user = getpwnam(CUPS_DEFAULT_USER)) == NULL)
User = 1;
else
User = user->pw_uid;
endpwent();
ConfigFilePerm = 0640;
LogFilePerm = 0644;
FaxRetryLimit = 5;
FaxRetryInterval = 300;
FileDevice = FALSE;
FilterLevel = 0;
FilterLimit = 0;
FilterNice = 0;
HostNameLookups = FALSE;
ImplicitClasses = TRUE;
ImplicitAnyClasses = FALSE;
HideImplicitMembers = TRUE;
KeepAlive = TRUE;
KeepAliveTimeout = DEFAULT_KEEPALIVE;
ListenBackLog = SOMAXCONN;
LogLevel = L_ERROR;
MaxClients = 100;
MaxClientsPerHost = 0;
MaxLogSize = 1024 * 1024;
MaxPrinterHistory = 10;
MaxRequestSize = 0;
ReloadTimeout = 60;
RootCertDuration = 300;
RunAsUser = FALSE;
Timeout = DEFAULT_TIMEOUT;
BrowseInterval = DEFAULT_INTERVAL;
BrowsePort = ippPort();
#ifdef HAVE_DNSSD
BrowseLocalProtocols = BROWSE_CUPS | BROWSE_DNSSD;
#else
BrowseLocalProtocols = BROWSE_CUPS;
#endif
BrowseRemoteProtocols= BROWSE_CUPS;
BrowseShortNames = TRUE;
BrowseTimeout = DEFAULT_TIMEOUT;
Browsing = TRUE;
JobHistory = DEFAULT_HISTORY;
JobFiles = DEFAULT_FILES;
JobAutoPurge = 0;
MaxJobs = 500;
MaxJobsPerUser = 0;
MaxJobsPerPrinter = 0;
MaxCopies = 100;
#ifdef __APPLE__
MinCopies = 1;
AppleQuotas = TRUE;
ApplePreserveJobHistoryAttributes
= FALSE;
#endif
#ifdef HAVE_CDSASSL
SSLVerifyCertificates = FALSE;
#endif
if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
return (0);
status = read_configuration(fp);
cupsFileClose(fp);
if (!status)
return (0);
if (RunAsUser)
RunUser = User;
else
RunUser = getuid();
if (NumSystemGroups == 0)
NumSystemGroups ++;
BrowseACL = FindLocation("CUPS_INTERNAL_BROWSE_ACL");
#ifdef HAVE_VSYSLOG
if (strcmp(AccessLog, "syslog") == 0 ||
strcmp(ErrorLog, "syslog") == 0 ||
strcmp(PageLog, "syslog") == 0)
openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
#endif
LogMessage(L_INFO, "Loaded configuration file \"%s\"", ConfigurationFile);
if (NumListeners == 0)
{
LogMessage(L_EMERG, "No valid Listen or Port lines were found in the configuration file!");
kill(getpid(), SIGTERM);
}
SetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset);
if (DocumentRoot[0] != '/')
SetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
if (RequestRoot[0] != '/')
SetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
if (ServerBin[0] != '/')
SetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
#ifdef HAVE_SSL
if (ServerCertificate[0] != '/')
SetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
if (ServerKey[0] != '/')
SetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
# endif
#endif
conf_file_check(ServerRoot, NULL , 0755, RunUser, Group, 1, 0);
conf_file_check("certs", ServerRoot, 0711, RunUser, Group, 1, 0);
conf_file_check("ppd" , ServerRoot, 0755, RunUser, Group, 1, 0);
conf_file_check("cupsd.conf" , ServerRoot, ConfigFilePerm, RunUser, Group, 0, 0);
conf_file_check("classes.conf" , ServerRoot, 0600, RunUser, Group, 0, 0);
conf_file_check("printers.conf", ServerRoot, 0600, RunUser, Group, 0, 0);
conf_file_check("passwd.md5" , ServerRoot, 0600, RunUser, Group, 0, 0);
# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
conf_file_check("ssl" , ServerRoot, 0700, RunUser, Group, 1, 0);
conf_file_check(ServerCertificate, NULL, ConfigFilePerm, RunUser, Group, 0, 0);
conf_file_check(ServerKey, NULL, ConfigFilePerm, RunUser, Group, 0, 0);
# endif
conf_file_check(RequestRoot, NULL, 0710, RunUser, Group, 1, 0);
if (strncmp(TempDir, RequestRoot, strlen(RequestRoot)) == 0)
{
conf_file_check(TempDir, NULL, 01770, RunUser, Group, 1, 1);
DIR *dir;
struct dirent *dent;
char tempfile[1024];
struct stat fileinfo;
if ((dir = opendir(TempDir)) != NULL)
{
LogMessage(L_DEBUG, "Cleaning out old temporary files in \"%s\"...",
TempDir);
while ((dent = readdir(dir)) != NULL)
{
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
continue;
snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->d_name);
if (lstat(tempfile, &fileinfo))
{
LogMessage(L_WARN, "ReadConfiguration: Unable to stat \"%s\": %s",
dent->d_name, strerror(errno));
continue;
}
if (S_ISDIR(fileinfo.st_mode))
continue;
if (unlink(tempfile))
LogMessage(L_ERROR,
"Unable to remove temporary file \"%s\" - %s",
tempfile, strerror(errno));
else
LogMessage(L_DEBUG, "Removed temporary file \"%s\"...",
tempfile);
}
closedir(dir);
}
else
LogMessage(L_ERROR,
"Unable to open temporary directory \"%s\" - %s",
TempDir, strerror(errno));
}
if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
{
if (MaxClients > 0)
LogMessage(L_INFO, "MaxClients limited to 1/3 of the file descriptor limit (%d)...",
MaxFDs);
MaxClients = MaxFDs / 3;
}
LogMessage(L_INFO, "Configured for up to %d clients.", MaxClients);
if (Classification && strcasecmp(Classification, "none") == 0)
ClearString(&Classification);
if (Classification)
LogMessage(L_INFO, "Security set to \"%s\"", Classification);
if (MaxClientsPerHost <= 0)
MaxClientsPerHost = MaxClients;
if (MaxClientsPerHost > MaxClients)
MaxClientsPerHost = MaxClients;
LogMessage(L_INFO, "Allowing up to %d client connections per host.",
MaxClientsPerHost);
if (NeedReload == RELOAD_ALL ||
!old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
!old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
{
LogMessage(L_INFO, "Full reload is required.");
FreeAllJobs();
DeleteAllClasses();
DeleteAllPrinters();
DefaultPrinter = NULL;
if (Devices)
{
ippDelete(Devices);
Devices = NULL;
BackendsExeced = 0;
}
if (PPDs)
{
ippDelete(PPDs);
PPDs = NULL;
}
if (MimeDatabase != NULL)
mimeDelete(MimeDatabase);
if (NumMimeTypes)
{
for (i = 0; i < NumMimeTypes; i ++)
free((void *)MimeTypes[i]);
free(MimeTypes);
}
snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
MimeDatabase = mimeNew();
mimeMerge(MimeDatabase, ServerRoot, temp);
NumMimeTypes = MimeDatabase->num_types;
if (!mimeType(MimeDatabase, "application", "octet-stream"))
NumMimeTypes ++;
MimeTypes = calloc(NumMimeTypes, sizeof(const char *));
for (i = 0; i < MimeDatabase->num_types; i ++)
{
snprintf(type, sizeof(type), "%s/%s", MimeDatabase->types[i]->super,
MimeDatabase->types[i]->type);
MimeTypes[i] = strdup(type);
}
if (i < NumMimeTypes)
MimeTypes[i] = strdup("application/octet-stream");
snprintf(temp, sizeof(temp), "%s/banners", DataDir);
LoadBanners(temp);
LoadAllPrinters();
LoadAllClasses();
CreateCommonData();
#ifdef __APPLE__
snprintf(temp, sizeof(temp), "%s/backend", ServerBin);
LoadDevices(temp, FALSE);
#else
snprintf(temp, sizeof(temp), "%s/backend", ServerBin);
LoadDevices(temp, TRUE);
snprintf(temp, sizeof(temp), "%s/model", DataDir);
LoadPPDs(temp);
#endif
LoadAllJobs(ACTIVE_JOBS);
WritePrintcap();
LogMessage(L_INFO, "Full reload complete.");
}
else
{
CreateCommonData();
LogMessage(L_INFO, "Partial reload complete.");
}
NeedReload = RELOAD_NONE;
ClearString(&old_serverroot);
ClearString(&old_requestroot);
StartServer();
return (1);
}
static int
read_configuration(cups_file_t *fp)
{
int i;
int linenum;
int len;
char line[HTTP_MAX_BUFFER],
name[256],
*nameptr,
*value;
int valuelen;
int browseProtocol;
var_t *var;
unsigned address,
netmask;
int ip[4],
ipcount,
mask[4];
dirsvc_relay_t *relay;
dirsvc_poll_t *poll;
struct sockaddr_in polladdr;
location_t *location;
cups_file_t *incfile;
char incname[1024];
static unsigned netmasks[4] =
{
0xff000000,
0xffff0000,
0xffffff00,
0xffffffff
};
linenum = 0;
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
{
linenum ++;
if (line[0] == '#')
continue;
len = strlen(line);
while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
}
for (value = line; isspace(*value); value ++);
for (nameptr = name; *value != '\0' && !isspace(*value) &&
nameptr < (name + sizeof(name) - 1);)
*nameptr++ = *value++;
*nameptr = '\0';
while (isspace(*value))
value ++;
if (name[0] == '\0')
continue;
if (strcasecmp(name, "Include") == 0)
{
if (value[0] == '/')
strlcpy(incname, value, sizeof(incname));
else
snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
LogMessage(L_ERROR, "Unable to include config file \"%s\" - %s",
incname, strerror(errno));
else
{
read_configuration(incfile);
cupsFileClose(incfile);
}
}
else if (strcasecmp(name, "<Location") == 0)
{
if (line[len - 1] == '>')
{
line[len - 1] = '\0';
linenum = read_location(fp, value, linenum);
if (linenum == 0)
return (0);
}
else
{
LogMessage(L_ERROR, "Syntax error on line %d.",
linenum);
return (0);
}
}
else if (strcasecmp(name, "Port") == 0 ||
strcasecmp(name, "Listen") == 0)
{
listener_t *temp;
if (NumListeners == 0)
temp = malloc(sizeof(listener_t));
else
temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t));
if (!temp)
{
LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.",
name, linenum, strerror(errno));
continue;
}
Listeners = temp;
temp += NumListeners;
memset(temp, 0, sizeof(listener_t));
if (get_address(value, INADDR_ANY, IPP_PORT, &(temp->address)))
{
LogMessage(L_INFO, "Listening to %x:%d",
(unsigned)ntohl(temp->address.sin_addr.s_addr),
ntohs(temp->address.sin_port));
NumListeners ++;
}
else
LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
value, linenum);
}
#ifdef HAVE_SSL
else if (strcasecmp(name, "SSLPort") == 0 ||
strcasecmp(name, "SSLListen") == 0)
{
listener_t *temp;
if (NumListeners == 0)
temp = malloc(sizeof(listener_t));
else
temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t));
if (!temp)
{
LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.",
name, linenum, strerror(errno));
continue;
}
Listeners = temp;
temp += NumListeners;
if (get_address(value, INADDR_ANY, IPP_PORT, &(temp->address)))
{
LogMessage(L_INFO, "Listening to %x:%d (SSL)",
(unsigned)ntohl(temp->address.sin_addr.s_addr),
ntohs(temp->address.sin_port));
temp->encryption = HTTP_ENCRYPT_ALWAYS;
NumListeners ++;
}
else
LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
value, linenum);
}
#endif
else if (strcasecmp(name, "BrowseAddress") == 0)
{
dirsvc_addr_t *temp;
if (NumBrowsers == 0)
temp = malloc(sizeof(dirsvc_addr_t));
else
temp = realloc(Browsers, (NumBrowsers + 1) * sizeof(dirsvc_addr_t));
if (!temp)
{
LogMessage(L_ERROR, "Unable to allocate BrowseAddress at line %d - %s.",
linenum, strerror(errno));
continue;
}
Browsers = temp;
temp += NumBrowsers;
memset(temp, 0, sizeof(dirsvc_addr_t));
if (strcasecmp(value, "@LOCAL") == 0)
{
strcpy(temp->iface, "*");
NumBrowsers ++;
}
else if (strncasecmp(value, "@IF(", 4) == 0)
{
strlcpy(temp->iface, value + 4, sizeof(Browsers[0].iface));
nameptr = temp->iface + strlen(temp->iface) - 1;
if (*nameptr == ')')
*nameptr = '\0';
NumBrowsers ++;
}
else if (get_address(value, INADDR_NONE, BrowsePort, &(temp->to)))
{
LogMessage(L_INFO, "Sending browsing info to %x:%d",
(unsigned)ntohl(temp->to.sin_addr.s_addr),
ntohs(temp->to.sin_port));
NumBrowsers ++;
}
else
LogMessage(L_ERROR, "Bad BrowseAddress %s at line %d.", value,
linenum);
}
else if (strcasecmp(name, "BrowseOrder") == 0)
{
if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
if (location == NULL)
LogMessage(L_ERROR, "Unable to initialize browse access control list!");
else if (strncasecmp(value, "deny", 4) == 0)
location->order_type = AUTH_ALLOW;
else if (strncasecmp(value, "allow", 5) == 0)
location->order_type = AUTH_DENY;
else
LogMessage(L_ERROR, "Unknown BrowseOrder value %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "BrowseProtocols") == 0 ||
strcasecmp(name, "BrowseLocalProtocols") == 0 ||
strcasecmp(name, "BrowseRemoteProtocols") == 0)
{
browseProtocol = 0;
for (; *value;)
{
for (valuelen = 0; value[valuelen]; valuelen ++)
if (isspace(value[valuelen]) || value[valuelen] == ',')
break;
if (value[valuelen])
{
value[valuelen] = '\0';
valuelen ++;
}
if (strcasecmp(value, "cups") == 0)
browseProtocol |= BROWSE_CUPS;
else if (strcasecmp(value, "slp") == 0)
browseProtocol |= BROWSE_SLP;
else if (strcasecmp(value, "ldap") == 0)
browseProtocol |= BROWSE_LDAP;
#ifdef HAVE_DNSSD
else if (strcasecmp(value, "dnssd") == 0 ||
strcasecmp(value, "bonjour") == 0)
browseProtocol |= BROWSE_DNSSD;
#endif
else if (strcasecmp(value, "all") == 0)
browseProtocol |= BROWSE_ALL;
else
{
LogMessage(L_ERROR, "Unknown browse protocol \"%s\" on line %d.",
value, linenum);
break;
}
for (value += valuelen; *value; value ++)
if (!isspace(*value) || *value != ',')
break;
}
if (strcasecmp(name, "BrowseProtocols") == 0)
BrowseLocalProtocols = BrowseRemoteProtocols = browseProtocol;
else if (strcasecmp(name, "BrowseLocalProtocols") == 0)
BrowseLocalProtocols = browseProtocol;
else
BrowseRemoteProtocols = browseProtocol;
}
else if (strcasecmp(name, "BrowseAllow") == 0 ||
strcasecmp(name, "BrowseDeny") == 0)
{
if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
if (location == NULL)
LogMessage(L_ERROR, "Unable to initialize browse access control list!");
else
{
if (strncasecmp(value, "from ", 5) == 0)
{
value += 5;
while (isspace(*value))
value ++;
}
if (strcasecmp(value, "all") == 0)
{
if (strcasecmp(name, "BrowseAllow") == 0)
AllowIP(location, 0, 0);
else
DenyIP(location, 0, 0);
}
else if (strcasecmp(value, "none") == 0)
{
if (strcasecmp(name, "BrowseAllow") == 0)
AllowIP(location, ~0, 0);
else
DenyIP(location, ~0, 0);
}
else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
{
if (value[0] == '*')
value ++;
if (strcasecmp(name, "BrowseAllow") == 0)
AllowHost(location, value);
else
DenyHost(location, value);
}
else
{
memset(ip, 0, sizeof(ip));
ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
if ((value = strchr(value, '/')) != NULL)
{
value ++;
memset(mask, 0, sizeof(mask));
switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
mask + 2, mask + 3))
{
case 1 :
netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
break;
case 4 :
netmask = (((((mask[0] << 8) | mask[1]) << 8) |
mask[2]) << 8) | mask[3];
break;
default :
LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
value, linenum);
netmask = 0xffffffff;
break;
}
}
else
netmask = netmasks[ipcount - 1];
if ((address & ~netmask) != 0)
{
LogMessage(L_WARN, "Discarding extra bits in %s address %08x for netmask %08x...",
name, address, netmask);
address &= netmask;
}
if (strcasecmp(name, "BrowseAllow") == 0)
AllowIP(location, address, netmask);
else
DenyIP(location, address, netmask);
}
}
}
else if (strcasecmp(name, "BrowseRelay") == 0)
{
if (NumRelays == 0)
relay = malloc(sizeof(dirsvc_relay_t));
else
relay = realloc(Relays, (NumRelays + 1) * sizeof(dirsvc_relay_t));
if (!relay)
{
LogMessage(L_ERROR, "Unable to allocate BrowseRelay at line %d - %s.",
linenum, strerror(errno));
continue;
}
Relays = relay;
relay += NumRelays;
memset(relay, 0, sizeof(dirsvc_relay_t));
if (strncasecmp(value, "from ", 5) == 0)
{
value += 5;
while (isspace(*value))
value ++;
}
if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
{
if (value[0] == '*')
value ++;
strlcpy(name, value, sizeof(name));
if ((nameptr = strchr(name, ' ')) != NULL)
*nameptr = '\0';
relay->from.type = AUTH_NAME;
relay->from.mask.name.name = strdup(name);
relay->from.mask.name.length = strlen(name);
}
else
{
memset(ip, 0, sizeof(ip));
ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
for (; *value; value ++)
if (*value == '/' || isspace(*value))
break;
if (*value == '/')
{
value ++;
memset(mask, 0, sizeof(mask));
switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
mask + 2, mask + 3))
{
case 1 :
netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
break;
case 4 :
netmask = (((((mask[0] << 8) | mask[1]) << 8) |
mask[2]) << 8) | mask[3];
break;
default :
LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
value, linenum);
netmask = 0xffffffff;
break;
}
}
else
netmask = netmasks[ipcount - 1];
relay->from.type = AUTH_IP;
relay->from.mask.ip.address = address;
relay->from.mask.ip.netmask = netmask;
}
for (; *value; value ++)
if (isspace(*value))
break;
while (isspace(*value))
value ++;
if (strncasecmp(value, "to ", 3) == 0)
{
value += 3;
while (isspace(*value))
value ++;
}
if (get_address(value, INADDR_BROADCAST, BrowsePort, &(relay->to)))
{
if (relay->from.type == AUTH_NAME)
LogMessage(L_INFO, "Relaying from %s to %x:%d",
relay->from.mask.name.name,
(unsigned)ntohl(relay->to.sin_addr.s_addr),
ntohs(relay->to.sin_port));
else
LogMessage(L_INFO, "Relaying from %x/%x to %x:%d",
relay->from.mask.ip.address, relay->from.mask.ip.netmask,
(unsigned)ntohl(relay->to.sin_addr.s_addr),
ntohs(relay->to.sin_port));
NumRelays ++;
}
else
{
if (relay->from.type == AUTH_NAME)
free(relay->from.mask.name.name);
LogMessage(L_ERROR, "Bad relay address %s at line %d.", value, linenum);
}
}
else if (strcasecmp(name, "BrowsePoll") == 0)
{
if (NumPolled == 0)
poll = malloc(sizeof(dirsvc_poll_t));
else
poll = realloc(Polled, (NumPolled + 1) * sizeof(dirsvc_poll_t));
if (!poll)
{
LogMessage(L_ERROR, "Unable to allocate BrowsePoll at line %d - %s.",
linenum, strerror(errno));
continue;
}
Polled = poll;
poll += NumPolled;
if (get_address(value, INADDR_NONE, ippPort(), &polladdr))
{
LogMessage(L_INFO, "Polling %x:%d",
(unsigned)ntohl(polladdr.sin_addr.s_addr),
ntohs(polladdr.sin_port));
NumPolled ++;
memset(poll, 0, sizeof(dirsvc_poll_t));
address = ntohl(polladdr.sin_addr.s_addr);
sprintf(poll->hostname, "%d.%d.%d.%d", address >> 24,
(address >> 16) & 255, (address >> 8) & 255, address & 255);
poll->port = ntohs(polladdr.sin_port);
}
else
LogMessage(L_ERROR, "Bad poll address %s at line %d.", value, linenum);
}
else if (strcasecmp(name, "User") == 0)
{
if (isdigit(value[0]))
User = atoi(value);
else
{
struct passwd *p;
endpwent();
p = getpwnam(value);
if (p != NULL)
User = p->pw_uid;
else
LogMessage(L_WARN, "Unknown username \"%s\"",
value);
}
}
else if (strcasecmp(name, "Group") == 0)
{
if (isdigit(value[0]))
Group = atoi(value);
else
{
struct group *g;
endgrent();
g = getgrnam(value);
if (g != NULL)
Group = g->gr_gid;
else
LogMessage(L_WARN, "Unknown groupname \"%s\"",
value);
}
}
else if (strcasecmp(name, "SystemGroup") == 0)
{
char *valueptr,
quote;
for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS; i ++)
{
if (*value == '\'' || *value == '\"')
{
quote = *value++;
for (valueptr = value; *valueptr; valueptr ++)
if (*valueptr == quote)
break;
}
else
{
for (valueptr = value; *valueptr; valueptr ++)
if (isspace(*valueptr) || *valueptr == ',')
break;
}
if (*valueptr)
*valueptr++ = '\0';
SetString(SystemGroups + i, value);
value = valueptr;
while (*value == ',' || isspace(*value))
value ++;
}
if (i)
NumSystemGroups = i;
}
else if (strcasecmp(name, "HostNameLookups") == 0)
{
if (strcasecmp(value, "off") == 0)
HostNameLookups = 0;
else if (strcasecmp(value, "on") == 0)
HostNameLookups = 1;
else if (strcasecmp(value, "double") == 0)
HostNameLookups = 2;
else
LogMessage(L_WARN, "Unknown HostNameLookups %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "LogLevel") == 0)
{
if (strcasecmp(value, "debug2") == 0)
LogLevel = L_DEBUG2;
else if (strcasecmp(value, "debug") == 0)
LogLevel = L_DEBUG;
else if (strcasecmp(value, "info") == 0)
LogLevel = L_INFO;
else if (strcasecmp(value, "notice") == 0)
LogLevel = L_NOTICE;
else if (strcasecmp(value, "warn") == 0)
LogLevel = L_WARN;
else if (strcasecmp(value, "error") == 0)
LogLevel = L_ERROR;
else if (strcasecmp(value, "crit") == 0)
LogLevel = L_CRIT;
else if (strcasecmp(value, "alert") == 0)
LogLevel = L_ALERT;
else if (strcasecmp(value, "emerg") == 0)
LogLevel = L_EMERG;
else if (strcasecmp(value, "none") == 0)
LogLevel = L_NONE;
else
LogMessage(L_WARN, "Unknown LogLevel %s on line %d.", value, linenum);
}
else if (strcasecmp(name, "PrintcapFormat") == 0)
{
if (strcasecmp(value, "bsd") == 0)
PrintcapFormat = PRINTCAP_BSD;
else if (strcasecmp(value, "solaris") == 0)
PrintcapFormat = PRINTCAP_SOLARIS;
else
LogMessage(L_WARN, "Unknown PrintcapFormat %s on line %d.",
value, linenum);
}
else if (!strcasecmp(name, "ServerTokens"))
{
struct utsname plat;
uname(&plat);
if (!strcasecmp(value, "ProductOnly"))
SetString(&ServerHeader, "CUPS");
else if (!strcasecmp(value, "Major"))
SetString(&ServerHeader, "CUPS/1");
else if (!strcasecmp(value, "Minor"))
SetString(&ServerHeader, "CUPS/1.1");
else if (!strcasecmp(value, "Minimal"))
SetString(&ServerHeader, CUPS_MINIMAL);
else if (!strcasecmp(value, "OS"))
SetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
else if (!strcasecmp(value, "Full"))
SetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1", plat.sysname);
else if (!strcasecmp(value, "None"))
ClearString(&ServerHeader);
else
LogMessage(L_WARN, "Unknown ServerTokens %s on line %d.", value, linenum);
}
else
{
for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
if (strcasecmp(name, var->name) == 0)
break;
if (i == 0)
{
LogMessage(L_ERROR, "Unknown directive %s on line %d.", name,
linenum);
continue;
}
switch (var->type)
{
case VAR_INTEGER :
{
int n;
char *units;
n = strtol(value, &units, 0);
if (units && *units)
{
if (tolower(units[0] & 255) == 'g')
n *= 1024 * 1024 * 1024;
else if (tolower(units[0] & 255) == 'm')
n *= 1024 * 1024;
else if (tolower(units[0] & 255) == 'k')
n *= 1024;
else if (tolower(units[0] & 255) == 't')
n *= 262144;
}
*((int *)var->ptr) = n;
}
break;
case VAR_BOOLEAN :
if (strcasecmp(value, "true") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "enabled") == 0 ||
strcasecmp(value, "yes") == 0 ||
atoi(value) != 0)
*((int *)var->ptr) = TRUE;
else if (strcasecmp(value, "false") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "disabled") == 0 ||
strcasecmp(value, "no") == 0 ||
strcasecmp(value, "0") == 0)
*((int *)var->ptr) = FALSE;
else
LogMessage(L_ERROR, "Unknown boolean value %s on line %d.",
value, linenum);
break;
case VAR_STRING :
SetString((char **)var->ptr, value);
break;
}
}
}
return (1);
}
static int
read_location(cups_file_t *fp,
char *location,
int linenum)
{
int i;
location_t *loc,
*parent;
int len;
char line[HTTP_MAX_BUFFER],
name[256],
*nameptr,
*value,
*valptr;
unsigned address,
netmask;
int ip[4],
ipcount,
mask[4];
static unsigned netmasks[4] =
{
0xff000000,
0xffff0000,
0xffffff00,
0xffffffff
};
if ((parent = AddLocation(location)) == NULL)
return (0);
parent->limit = AUTH_LIMIT_ALL;
loc = parent;
while (cupsFileGets(fp, line, sizeof(line)) != NULL)
{
linenum ++;
if (line[0] == '#')
continue;
len = strlen(line);
while (len > 0 && isspace(line[len - 1] & 255))
{
len --;
line[len] = '\0';
}
for (value = line; isspace(*value & 255); value ++);
for (nameptr = name; *value != '\0' && !isspace(*value & 255) &&
nameptr < (name + sizeof(name) - 1);)
*nameptr++ = *value++;
*nameptr = '\0';
while (isspace(*value & 255))
value ++;
if (name[0] == '\0')
continue;
if (strcasecmp(name, "</Location>") == 0)
return (linenum);
else if (strcasecmp(name, "<Limit") == 0 ||
strcasecmp(name, "<LimitExcept") == 0)
{
if ((loc = CopyLocation(&parent)) == NULL)
return (0);
loc->limit = 0;
while (*value)
{
for (valptr = value;
!isspace(*valptr & 255) && *valptr != '>' && *valptr;
valptr ++);
if (*valptr)
*valptr++ = '\0';
if (strcmp(value, "ALL") == 0)
loc->limit = AUTH_LIMIT_ALL;
else if (strcmp(value, "GET") == 0)
loc->limit |= AUTH_LIMIT_GET;
else if (strcmp(value, "HEAD") == 0)
loc->limit |= AUTH_LIMIT_HEAD;
else if (strcmp(value, "OPTIONS") == 0)
loc->limit |= AUTH_LIMIT_OPTIONS;
else if (strcmp(value, "POST") == 0)
loc->limit |= AUTH_LIMIT_POST;
else if (strcmp(value, "PUT") == 0)
loc->limit |= AUTH_LIMIT_PUT;
else if (strcmp(value, "TRACE") == 0)
loc->limit |= AUTH_LIMIT_TRACE;
else
LogMessage(L_WARN, "Unknown request type %s on line %d!", value,
linenum);
for (value = valptr; isspace(*value & 255) || *value == '>'; value ++);
}
if (strcasecmp(name, "<LimitExcept") == 0)
loc->limit = AUTH_LIMIT_ALL ^ loc->limit;
parent->limit &= ~loc->limit;
}
else if (strcasecmp(name, "</Limit>") == 0)
loc = parent;
else if (strcasecmp(name, "Encryption") == 0)
{
if (strcasecmp(value, "never") == 0)
loc->encryption = HTTP_ENCRYPT_NEVER;
else if (strcasecmp(value, "always") == 0)
{
LogMessage(L_ERROR, "Encryption value \"%s\" on line %d is invalid in this context. "
"Using \"required\" instead.", value, linenum);
loc->encryption = HTTP_ENCRYPT_REQUIRED;
}
else if (strcasecmp(value, "required") == 0)
loc->encryption = HTTP_ENCRYPT_REQUIRED;
else if (strcasecmp(value, "ifrequested") == 0)
loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
else
LogMessage(L_ERROR, "Unknown Encryption value %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "Order") == 0)
{
if (strncasecmp(value, "deny", 4) == 0)
loc->order_type = AUTH_ALLOW;
else if (strncasecmp(value, "allow", 5) == 0)
loc->order_type = AUTH_DENY;
else
LogMessage(L_ERROR, "Unknown Order value %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "Allow") == 0 ||
strcasecmp(name, "Deny") == 0)
{
if (strncasecmp(value, "from", 4) == 0)
{
value += 4;
while (isspace(*value & 255))
value ++;
}
if (strcasecmp(value, "all") == 0)
{
if (strcasecmp(name, "Allow") == 0)
AllowIP(loc, 0, 0);
else
DenyIP(loc, 0, 0);
}
else if (strcasecmp(value, "none") == 0)
{
if (strcasecmp(name, "Allow") == 0)
AllowIP(loc, ~0, 0);
else
DenyIP(loc, ~0, 0);
}
else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
{
if (value[0] == '*')
value ++;
if (strcasecmp(name, "Allow") == 0)
AllowHost(loc, value);
else
DenyHost(loc, value);
}
else
{
memset(ip, 0, sizeof(ip));
ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
if ((value = strchr(value, '/')) != NULL)
{
value ++;
memset(mask, 0, sizeof(mask));
switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
mask + 2, mask + 3))
{
case 1 :
netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
break;
case 4 :
netmask = (((((mask[0] << 8) | mask[1]) << 8) |
mask[2]) << 8) | mask[3];
break;
default :
LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
value, linenum);
netmask = 0xffffffff;
break;
}
}
else
netmask = netmasks[ipcount - 1];
if ((address & ~netmask) != 0)
{
LogMessage(L_WARN, "Discarding extra bits in %s address %08x for netmask %08x...",
name, address, netmask);
address &= netmask;
}
if (strcasecmp(name, "Allow") == 0)
AllowIP(loc, address, netmask);
else
DenyIP(loc, address, netmask);
}
}
else if (strcasecmp(name, "AuthType") == 0)
{
if (strcasecmp(value, "none") == 0)
{
loc->type = AUTH_NONE;
loc->level = AUTH_ANON;
}
else if (strcasecmp(value, "basic") == 0)
{
loc->type = AUTH_BASIC;
if (loc->level == AUTH_ANON)
loc->level = AUTH_USER;
}
else if (strcasecmp(value, "digest") == 0)
{
loc->type = AUTH_DIGEST;
if (loc->level == AUTH_ANON)
loc->level = AUTH_USER;
}
else if (strcasecmp(value, "basicdigest") == 0)
{
loc->type = AUTH_BASICDIGEST;
if (loc->level == AUTH_ANON)
loc->level = AUTH_USER;
}
else
LogMessage(L_WARN, "Unknown authorization type %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "AuthClass") == 0)
{
if (strcasecmp(value, "anonymous") == 0)
{
loc->type = AUTH_NONE;
loc->level = AUTH_ANON;
}
else if (strcasecmp(value, "user") == 0)
loc->level = AUTH_USER;
else if (strcasecmp(value, "group") == 0)
loc->level = AUTH_GROUP;
else if (strcasecmp(value, "system") == 0)
{
loc->level = AUTH_GROUP;
if (NumSystemGroups == 0)
NumSystemGroups = 1;
for (i = 0; i < NumSystemGroups; i ++)
AddName(loc, SystemGroups[i]);
}
else
LogMessage(L_WARN, "Unknown authorization class %s on line %d.",
value, linenum);
}
else if (strcasecmp(name, "AuthGroupName") == 0)
AddName(loc, value);
else if (strcasecmp(name, "Require") == 0)
{
for (valptr = value;
!isspace(*valptr & 255) && *valptr != '>' && *valptr;
valptr ++);
if (*valptr)
*valptr++ = '\0';
if (strcasecmp(value, "valid-user") == 0 ||
strcasecmp(value, "user") == 0)
loc->level = AUTH_USER;
else if (strcasecmp(value, "group") == 0)
loc->level = AUTH_GROUP;
else
{
LogMessage(L_WARN, "Unknown Require type %s on line %d.",
value, linenum);
continue;
}
for (value = valptr; *value;)
{
for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
if (*valptr)
*valptr++ = '\0';
AddName(loc, value);
for (value = valptr; isspace(*value & 255); value ++);
}
}
else if (strcasecmp(name, "Satisfy") == 0)
{
if (strcasecmp(value, "all") == 0)
loc->satisfy = AUTH_SATISFY_ALL;
else if (strcasecmp(value, "any") == 0)
loc->satisfy = AUTH_SATISFY_ANY;
else
LogMessage(L_WARN, "Unknown Satisfy value %s on line %d.", value,
linenum);
}
else
LogMessage(L_ERROR, "Unknown Location directive %s on line %d.",
name, linenum);
}
return (0);
}
static int
get_address(char *value,
unsigned defaddress,
int defport,
struct sockaddr_in *address)
{
char hostname[256],
portname[256];
struct hostent *host;
struct servent *port;
memset(address, 0, sizeof(struct sockaddr_in));
#ifdef HAVE_DOMAINSOCKETS
if (*value == '/')
{
if (strlen(value) >= sizeof(((struct sockaddr_un*)NULL)->sun_path))
{
LogMessage(L_ERROR, "Domain socket name too long \"%s\"!", value);
return (0);
}
address->sin_family = AF_LOCAL;
(char *)address->sin_addr.s_addr = strdup(value);
}
else
#endif
{
address->sin_family = AF_INET;
address->sin_addr.s_addr = htonl(defaddress);
address->sin_port = htons(defport);
switch (sscanf(value, "%255[^:]:%255s", hostname, portname))
{
case 1 :
if (strchr(hostname, '.') == NULL && defaddress == INADDR_ANY)
{
strlcpy(portname, hostname, sizeof(portname));
hostname[0] = '\0';
}
else
portname[0] = '\0';
break;
case 2 :
break;
default :
LogMessage(L_ERROR, "Unable to decode address \"%s\"!", value);
return (0);
}
if (hostname[0] && strcmp(hostname, "*"))
{
if ((host = httpGetHostByName(hostname)) == NULL)
{
LogMessage(L_ERROR, "httpGetHostByName(\"%s\") failed - %s!", hostname,
hstrerror(h_errno));
return (0);
}
memcpy(&(address->sin_addr), host->h_addr, host->h_length);
address->sin_port = htons(defport);
}
if (portname[0] != '\0')
{
if (isdigit(portname[0]))
address->sin_port = htons(atoi(portname));
else
{
if ((port = getservbyname(portname, NULL)) == NULL)
{
LogMessage(L_ERROR, "getservbyname(\"%s\") failed - %s!", portname,
strerror(errno));
return (0);
}
else
address->sin_port = htons(port->s_port);
}
}
}
return (1);
}
static int
conf_file_check(const char*filename,
const char *root,
int mode,
int user,
int group,
int is_dir,
int create_dir)
{
int dir_created = 0;
char temp[1024];
struct stat sb;
if (root)
{
snprintf(temp, sizeof(temp), "%s/%s", root, filename);
filename = temp;
}
if (stat(filename, &sb) != 0)
{
if (errno == ENOENT && create_dir)
{
LogMessage(L_ERROR, "Creating missing directory \"%s\"", filename);
if (mkdir(filename, mode) != 0)
{
LogMessage(L_ERROR, "Unable to create directory \"%s\" - %s!", filename,
strerror(errno));
return -1;
}
dir_created = 1;
}
else
return -1;
}
if (!dir_created && !is_dir && !S_ISREG(sb.st_mode))
{
LogMessage(L_ERROR, "\"%s\" is not a regular file!", filename);
return -1;
}
if (!dir_created && is_dir && !S_ISDIR(sb.st_mode))
{
LogMessage(L_ERROR, "\"%s\" is not a directory!", filename);
return -1;
}
if (dir_created || sb.st_uid != user || sb.st_gid != group)
{
LogMessage(L_WARN, "Repairing ownership of \"%s\"", filename);
chown(filename, user, group);
}
if (dir_created || (sb.st_mode & ALLPERMS) != mode)
{
LogMessage(L_WARN, "Repairing access permissions of \"%s\"", filename);
chmod(filename, mode);
}
return 0;
}