#include "cupsd.h"
#include <stdarg.h>
#include <pwd.h>
#include <grp.h>
#ifdef HAVE_CDSASSL
# include <Security/SecureTransport.h>
# include <Security/SecIdentitySearch.h>
#endif
#ifdef HAVE_VSYSLOG
# include <syslog.h>
#endif
#ifndef INADDR_NONE
# define INADDR_NONE 0xffffffff
#endif
#ifndef HAVE_HSTRERROR
const char *
cups_hstrerror(int error)
{
static const char * const errors[] =
{
"OK",
"Host not found.",
"Try again.",
"Unrecoverable lookup error.",
"No data associated with name."
};
if (error < 0 || error > 4)
return ("Unknown hostname lookup error.");
else
return (errors[error]);
}
#elif defined(_AIX)
extern const char *hstrerror(int);
#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 },
{ "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 },
#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 },
{ "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
#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);
#ifdef HAVE_CDSASSL
static CFArrayRef CDSAGetServerCerts();
#endif
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;
int run_user;
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)
{
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");
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, "/var/root/Library/Keychains/CUPS");
# 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;
RootCertDuration = 300;
RunAsUser = FALSE;
Timeout = DEFAULT_TIMEOUT;
BrowseInterval = DEFAULT_INTERVAL;
BrowsePort = ippPort();
BrowseProtocols = 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;
#endif
#ifdef HAVE_NOTIFY_POST
NotifyPaused = 1;
NotifyPending = 0;
#endif
if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
return (0);
status = read_configuration(fp);
cupsFileClose(fp);
if (!status)
return (0);
if (RunAsUser)
run_user = User;
else
run_user = 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 (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)
chown(ServerCertificate, run_user, Group);
chmod(ServerCertificate, ConfigFilePerm);
if (ServerKey[0] != '/')
SetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
chown(ServerKey, run_user, Group);
chmod(ServerKey, ConfigFilePerm);
# endif
#endif
chown(ServerRoot, run_user, Group);
chmod(ServerRoot, 0755);
snprintf(temp, sizeof(temp), "%s/certs", ServerRoot);
chown(temp, run_user, Group);
chmod(temp, 0711);
snprintf(temp, sizeof(temp), "%s/ppd", ServerRoot);
chown(temp, run_user, Group);
chmod(temp, 0755);
snprintf(temp, sizeof(temp), "%s/ssl", ServerRoot);
chown(temp, run_user, Group);
chmod(temp, 0700);
snprintf(temp, sizeof(temp), "%s/cupsd.conf", ServerRoot);
chown(temp, run_user, Group);
chmod(temp, ConfigFilePerm);
snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
chown(temp, run_user, Group);
#ifdef __APPLE__
chmod(temp, 0600);
#else
chmod(temp, ConfigFilePerm);
#endif
snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
chown(temp, run_user, Group);
#ifdef __APPLE__
chmod(temp, 0600);
#else
chmod(temp, ConfigFilePerm);
#endif
snprintf(temp, sizeof(temp), "%s/passwd.md5", ServerRoot);
chown(temp, User, Group);
chmod(temp, 0600);
chown(RequestRoot, run_user, Group);
chmod(RequestRoot, 0710);
if (strncmp(TempDir, RequestRoot, strlen(RequestRoot)) == 0)
{
chown(TempDir, run_user, Group);
chmod(TempDir, 01770);
}
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;
}
if ((Clients = calloc(sizeof(client_t), MaxClients)) == NULL)
{
LogMessage(L_ERROR, "ReadConfiguration: Unable to allocate memory for %d clients: %s",
MaxClients, strerror(errno));
exit(1);
}
else
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;
}
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();
snprintf(temp, sizeof(temp), "%s/backend", ServerBin);
LoadDevices(temp);
snprintf(temp, sizeof(temp), "%s/model", DataDir);
LoadPPDs(temp);
LoadAllJobs();
#ifdef HAVE_CDSASSL
ServerCertificatesArray = CDSAGetServerCerts();
#endif
LogMessage(L_INFO, "Full reload complete.");
}
else
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;
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, "ReadConfiguration() 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)
{
BrowseProtocols = 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)
BrowseProtocols |= BROWSE_CUPS;
else if (strcasecmp(value, "slp") == 0)
BrowseProtocols |= BROWSE_SLP;
else if (strcasecmp(value, "ldap") == 0)
BrowseProtocols |= BROWSE_LDAP;
else if (strcasecmp(value, "all") == 0)
BrowseProtocols |= 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;
}
}
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 (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 ++;
relay->from.type = AUTH_NAME;
relay->from.mask.name.name = strdup(value);
relay->from.mask.name.length = strlen(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];
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, "ReadConfiguration() 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, "ReadConfiguration() Unknown groupname \"%s\"",
value);
}
}
else if (strcasecmp(name, "SystemGroup") == 0)
{
char *valueptr;
for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS; i ++)
{
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, "ReadConfiguration() 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, "ReadConfiguration() Unknown PrintcapFormat %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]) == 'g')
n *= 1024 * 1024 * 1024;
else if (tolower(units[0]) == 'm')
n *= 1024 * 1024;
else if (tolower(units[0]) == 'k')
n *= 1024;
else if (tolower(units[0]) == '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]))
{
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, "</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) && *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) || *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))
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]))
{
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 (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) && *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) && *valptr; valptr ++);
if (*valptr)
*valptr++ = '\0';
AddName(loc, value);
for (value = valptr; isspace(*value); 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));
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);
}
#ifdef HAVE_CDSASSL
static CFArrayRef
CDSAGetServerCerts(void)
{
OSStatus err;
SecKeychainRef kcRef;
SecIdentitySearchRef srchRef;
SecIdentityRef identity;
CFArrayRef ca;
kcRef = NULL;
srchRef = NULL;
identity = NULL;
ca = NULL;
err = SecKeychainOpen(ServerCertificate, &kcRef);
if (err)
LogMessage(L_ERROR, "Cannot open keychain \"%s\", error %d.",
ServerCertificate, err);
else
{
err = SecIdentitySearchCreate(kcRef, CSSM_KEYUSE_SIGN, &srchRef);
if (err)
LogMessage(L_ERROR,
"Cannot find signing key in keychain \"%s\", error %d",
ServerCertificate, err);
else
{
err = SecIdentitySearchCopyNext(srchRef, &identity);
if (err)
LogMessage(L_ERROR,
"Cannot find signing key in keychain \"%s\", error %d",
ServerCertificate, err);
else
{
if (CFGetTypeID(identity) != SecIdentityGetTypeID())
LogMessage(L_ERROR, "SecIdentitySearchCopyNext CFTypeID failure!");
else
{
ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL);
if (ca == nil)
LogMessage(L_ERROR, "CFArrayCreate error");
}
}
}
}
return ca;
}
#endif