X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fconf.c;h=4320ce660af97fd6456e4444595f571fc1e6d617;hb=781996c9136ff4ec23b858a3611c21698a6bb317;hp=8a2e9da05c43a337e8d70200b8ca11f9d25b3bc1;hpb=b2e108950fe59ee63a1f6d2381d67d3f06999cab;p=thirdparty%2Fcups.git diff --git a/scheduler/conf.c b/scheduler/conf.c index 8a2e9da05..4320ce660 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -3,7 +3,7 @@ * * Configuration routines for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2004 by Easy Software Products, all rights reserved. + * Copyright 1997-2006 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Easy Software Products and are protected by Federal @@ -23,14 +23,18 @@ * * Contents: * - * ReadConfiguration() - Read the cupsd.conf file. - * read_configuration() - Read a configuration file. - * read_location() - Read a definition. - * read_policy() - Read a definition. - * get_address() - Get an address + port number from a line. - * get_addr_and_mask() - Get an IP address and netmask. - * CDSAGetServerCerts() - Convert a keychain name into the CFArrayRef - * required by SSLSetCertificate. + * cupsdReadConfiguration() - Read the cupsd.conf file. + * check_permissions() - Fix the mode and ownership of a file or + * directory. + * get_address() - Get an address + port number from a line. + * get_addr_and_mask() - Get an IP address and netmask. + * parse_aaa() - Parse authentication, authorization, and + * access control lines. + * parse_groups() - Parse system group names in a string. + * parse_protocols() - Parse browse protocols in a string. + * read_configuration() - Read a configuration file. + * read_location() - Read a definition. + * read_policy() - Read a definition. */ /* @@ -39,18 +43,9 @@ #include "cupsd.h" #include -#include #include #include - -#ifdef HAVE_DOMAINSOCKETS -# include -#endif /* HAVE_DOMAINSOCKETS */ - -#ifdef HAVE_CDSASSL -# include -# include -#endif /* HAVE_CDSASSL */ +#include #ifdef HAVE_VSYSLOG # include @@ -70,89 +65,112 @@ * Configuration variable structure... */ -typedef struct +typedef enum { - char *name; /* Name of variable */ - void *ptr; /* Pointer to variable */ - int type; /* Type (int, string, address) */ -} var_t; + CUPSD_VARTYPE_INTEGER, /* Integer option */ + CUPSD_VARTYPE_STRING, /* String option */ + CUPSD_VARTYPE_BOOLEAN /* Boolean option */ +} cupsd_vartype_t; -#define VAR_INTEGER 0 -#define VAR_STRING 1 -#define VAR_BOOLEAN 2 +typedef struct +{ + char *name; /* Name of variable */ + void *ptr; /* Pointer to variable */ + cupsd_vartype_t type; /* Type (int, string, address) */ +} cupsd_var_t; /* * Local globals... */ -static var_t variables[] = +static cupsd_var_t variables[] = { - { "AccessLog", &AccessLog, VAR_STRING }, - { "AutoPurgeJobs", &JobAutoPurge, VAR_BOOLEAN }, - { "BrowseInterval", &BrowseInterval, VAR_INTEGER }, - { "BrowseLocalOptions", &BrowseLocalOptions, VAR_STRING }, - { "BrowsePort", &BrowsePort, VAR_INTEGER }, - { "BrowseRemoteOptions", &BrowseRemoteOptions, VAR_STRING }, - { "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 }, - { "DefaultPolicy", &DefaultPolicy, 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 }, - { "MaxActiveJobs", &MaxActiveJobs, VAR_INTEGER }, - { "MaxClients", &MaxClients, VAR_INTEGER }, - { "MaxClientsPerHost", &MaxClientsPerHost, VAR_INTEGER }, - { "MaxCopies", &MaxCopies, VAR_INTEGER }, - { "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 }, + { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING }, + { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN }, + { "BrowseInterval", &BrowseInterval, CUPSD_VARTYPE_INTEGER }, +#ifdef HAVE_LDAP + { "BrowseLDAPBindDN", &BrowseLDAPBindDN, CUPSD_VARTYPE_STRING }, + { "BrowseLDAPDN", &BrowseLDAPDN, CUPSD_VARTYPE_STRING }, + { "BrowseLDAPPassword", &BrowseLDAPPassword, CUPSD_VARTYPE_STRING }, + { "BrowseLDAPServer", &BrowseLDAPServer, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_LDAP */ + { "BrowseLocalOptions", &BrowseLocalOptions, CUPSD_VARTYPE_STRING }, + { "BrowsePort", &BrowsePort, CUPSD_VARTYPE_INTEGER }, + { "BrowseRemoteOptions", &BrowseRemoteOptions, CUPSD_VARTYPE_STRING }, + { "BrowseShortNames", &BrowseShortNames, CUPSD_VARTYPE_BOOLEAN }, + { "BrowseTimeout", &BrowseTimeout, CUPSD_VARTYPE_INTEGER }, + { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN }, + { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING }, + { "Classification", &Classification, CUPSD_VARTYPE_STRING }, + { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN }, + { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER }, + { "DataDir", &DataDir, CUPSD_VARTYPE_STRING }, + { "DefaultCharset", &DefaultCharset, CUPSD_VARTYPE_STRING }, + { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING }, + { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING }, + { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN }, + { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, + { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, + { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN }, + { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER }, + { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER }, + { "FontPath", &FontPath, CUPSD_VARTYPE_STRING }, + { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN }, + { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN }, + { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN }, + { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER }, + { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER }, + { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER }, + { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN }, + { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, + { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER }, + { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER }, + { "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER }, + { "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER }, + { "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER }, + { "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER }, + { "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER }, + { "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER }, + { "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER }, + { "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER }, + { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER }, + { "MaxPrinterHistory", &MaxPrinterHistory, CUPSD_VARTYPE_INTEGER }, + { "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER }, + { "PageLog", &PageLog, CUPSD_VARTYPE_STRING }, + { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_BOOLEAN }, + { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_BOOLEAN }, + { "Printcap", &Printcap, CUPSD_VARTYPE_STRING }, + { "PrintcapGUI", &PrintcapGUI, CUPSD_VARTYPE_STRING }, + { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_INTEGER }, + { "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING }, + { "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING }, + { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING }, + { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_INTEGER }, + { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING }, + { "ServerBin", &ServerBin, CUPSD_VARTYPE_STRING }, #ifdef HAVE_SSL - { "ServerCertificate", &ServerCertificate, VAR_STRING }, + { "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_STRING }, # if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) - { "ServerKey", &ServerKey, VAR_STRING }, + { "ServerKey", &ServerKey, CUPSD_VARTYPE_STRING }, # endif /* HAVE_LIBSSL || HAVE_GNUTLS */ #endif /* HAVE_SSL */ - { "ServerName", &ServerName, VAR_STRING }, - { "ServerRoot", &ServerRoot, VAR_STRING }, - { "TempDir", &TempDir, VAR_STRING }, - { "Timeout", &Timeout, VAR_INTEGER } +#ifdef HAVE_LAUNCHD + { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER }, + { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING }, +#endif /* HAVE_LAUNCHD */ + { "ServerName", &ServerName, CUPSD_VARTYPE_STRING }, + { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_STRING }, + { "StateDir", &StateDir, CUPSD_VARTYPE_STRING }, + { "TempDir", &TempDir, CUPSD_VARTYPE_STRING }, + { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER }, + { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN } }; #define NUM_VARS (sizeof(variables) / sizeof(variables[0])) @@ -166,66 +184,61 @@ static unsigned zeros[4] = 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; -#ifdef HAVE_CDSASSL -static CFArrayRef CDSAGetServerCerts(); -#endif /* HAVE_CDSASSL */ - /* * Local functions... */ - -static int read_configuration(cups_file_t *fp); -static int read_location(cups_file_t *fp, char *name, int linenum); -static int read_policy(cups_file_t *fp, char *name, int linenum); -static int get_address(const char *value, unsigned defaddress, int defport, - int deffamily, http_addr_t *address); -static int get_addr_and_mask(const char *value, unsigned *ip, - unsigned *mask); -static ipp_op_t get_operation(const char *name); +static int check_permissions(const char *filename, + const char *suffix, int mode, + int user, int group, int is_dir, + int create_dir); +static http_addrlist_t *get_address(const char *value, int defport); +static int get_addr_and_mask(const char *value, unsigned *ip, + unsigned *mask); +static int parse_aaa(cupsd_location_t *loc, char *line, + char *value, int linenum); +static int parse_groups(const char *s); +static int parse_protocols(const char *s); +static int read_configuration(cups_file_t *fp); +static int read_location(cups_file_t *fp, char *name, int linenum); +static int read_policy(cups_file_t *fp, char *name, int linenum); /* - * 'ReadConfiguration()' - Read the cupsd.conf file. + * 'cupsdReadConfiguration()' - Read the cupsd.conf file. */ int /* O - 1 on success, 0 otherwise */ -ReadConfiguration(void) +cupsdReadConfiguration(void) { int i; /* Looping var */ cups_file_t *fp; /* Configuration file */ int status; /* Return status */ char temp[1024], /* Temporary buffer */ *slash; /* Directory separator */ - char type[MIME_MAX_SUPER + MIME_MAX_TYPE]; - /* MIME type name */ - char *language; /* Language string */ + cups_lang_t *language; /* Language */ struct passwd *user; /* Default user */ struct group *group; /* Default group */ char *old_serverroot, /* Old ServerRoot */ *old_requestroot; /* Old RequestRoot */ + const char *tmpdir; /* TMPDIR environment variable */ + struct stat tmpinfo; /* Temporary directory info */ - /* - * Shutdown the server... - */ - - StopServer(); - /* * Save the old root paths... */ old_serverroot = NULL; - SetString(&old_serverroot, ServerRoot); + cupsdSetString(&old_serverroot, ServerRoot); old_requestroot = NULL; - SetString(&old_requestroot, RequestRoot); + cupsdSetString(&old_requestroot, RequestRoot); /* * Reset the server configuration data... */ - DeleteAllLocations(); + cupsdDeleteAllLocations(); if (NumBrowsers > 0) { @@ -252,157 +265,149 @@ ReadConfiguration(void) NumRelays = 0; } - if (NumListeners > 0) - { -#ifdef HAVE_DOMAINSOCKETS - int i; /* Looping var */ - listener_t *lis; /* Current listening socket */ - - for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) - if (lis->address.sin_family == AF_LOCAL) - ClearString((char **)&lis->address.sin_addr); -#endif /* HAVE_DOMAINSOCKETS */ - - free(Listeners); - - NumListeners = 0; - } + cupsdDeleteAllListeners(); /* * String options... */ - 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"); + cupsdSetString(&ServerName, httpGetHostname(temp, sizeof(temp))); + cupsdSetStringf(&ServerAdmin, "root@%s", temp); + cupsdSetString(&ServerBin, CUPS_SERVERBIN); + cupsdSetString(&RequestRoot, CUPS_REQUESTS); + cupsdSetString(&CacheDir, CUPS_CACHEDIR); + cupsdSetString(&DataDir, CUPS_DATADIR); + cupsdSetString(&DocumentRoot, CUPS_DOCROOT); + cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log"); + cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log"); + cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log"); + cupsdSetString(&Printcap, "/etc/printcap"); + cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions"); + cupsdSetString(&FontPath, CUPS_FONTPATH); + cupsdSetString(&RemoteRoot, "remroot"); + cupsdSetString(&ServerHeader, "CUPS/1.2"); + cupsdSetString(&StateDir, CUPS_STATEDIR); strlcpy(temp, ConfigurationFile, sizeof(temp)); if ((slash = strrchr(temp, '/')) != NULL) *slash = '\0'; - SetString(&ServerRoot, temp); + cupsdSetString(&ServerRoot, temp); - ClearString(&Classification); + cupsdClearString(&Classification); ClassifyOverride = 0; #ifdef HAVE_SSL # ifdef HAVE_CDSASSL - SetString(&ServerCertificate, "/var/root/Library/Keychains/CUPS"); + cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain"); # else - SetString(&ServerCertificate, "ssl/server.crt"); - SetString(&ServerKey, "ssl/server.key"); + cupsdSetString(&ServerCertificate, "ssl/server.crt"); + cupsdSetString(&ServerKey, "ssl/server.key"); # endif /* HAVE_CDSASSL */ #endif /* HAVE_SSL */ - if ((language = DEFAULT_LANGUAGE) == NULL) - language = "en"; - else if (strcmp(language, "C") == 0 || strcmp(language, "POSIX") == 0) - language = "en"; + language = cupsLangDefault(); + + if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX")) + cupsdSetString(&DefaultLanguage, "en"); + else + cupsdSetString(&DefaultLanguage, language->language); - SetString(&DefaultLanguage, language); - SetString(&DefaultCharset, DEFAULT_CHARSET); + cupsdSetString(&DefaultCharset, _cupsEncodingName(language->encoding)); - SetString(&RIPCache, "8m"); + cupsdSetString(&RIPCache, "8m"); - if (getenv("TMPDIR") == NULL) - SetString(&TempDir, CUPS_REQUESTS "/tmp"); - else - SetString(&TempDir, getenv("TMPDIR")); + cupsdSetString(&TempDir, NULL); /* - * Find the default system group: "sys", "system", or "root"... + * Find the default user... */ - group = getgrnam(CUPS_DEFAULT_GROUP); - endgrent(); - - NumSystemGroups = 0; - - if (group != NULL) - { - SetString(&SystemGroups[0], CUPS_DEFAULT_GROUP); - Group = group->gr_gid; - } + if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL) + User = user->pw_uid; else { - group = getgrgid(0); - endgrent(); + /* + * Use the (historical) NFS nobody user ID (-2 as a 16-bit twos- + * complement number...) + */ - if (group != NULL) - { - SetString(&SystemGroups[0], group->gr_name); - Group = 0; - } - else - { - SetString(&SystemGroups[0], "unknown"); - Group = 0; - } + User = 65534; } + endpwent(); + /* - * Find the default user... + * Find the default group (nobody)... */ - if ((user = getpwnam(CUPS_DEFAULT_USER)) == NULL) - User = 1; /* Force to a non-priviledged account */ + group = getgrnam("nobody"); + endgrent(); + + if (group != NULL) + Group = group->gr_gid; else - User = user->pw_uid; + { + /* + * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos- + * complement number...) + */ - endpwent(); + Group = 65534; + } /* * Numeric options... */ - 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(); - BrowseProtocols = BROWSE_CUPS; - BrowseShortNames = TRUE; - BrowseTimeout = DEFAULT_TIMEOUT; - Browsing = TRUE; - - ClearString(&BrowseLocalOptions); - ClearString(&BrowseRemoteOptions); + ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM; + DefaultAuthType = AUTH_BASIC; +#ifdef HAVE_SSL + DefaultEncryption = HTTP_ENCRYPT_REQUIRED; +#endif /* HAVE_SSL */ + JobRetryLimit = 5; + JobRetryInterval = 300; + FileDevice = FALSE; + FilterLevel = 0; + FilterLimit = 0; + FilterNice = 0; + HostNameLookups = FALSE; + ImplicitClasses = CUPS_DEFAULT_IMPLICIT_CLASSES; + ImplicitAnyClasses = FALSE; + HideImplicitMembers = TRUE; + KeepAlive = TRUE; + KeepAliveTimeout = DEFAULT_KEEPALIVE; + ListenBackLog = SOMAXCONN; + LogFilePerm = CUPS_DEFAULT_LOG_FILE_PERM; + LogLevel = CUPSD_LOG_ERROR; + MaxClients = 100; + MaxClientsPerHost = 0; + MaxLogSize = 1024 * 1024; + MaxPrinterHistory = 10; + MaxRequestSize = 0; + ReloadTimeout = 60; + RootCertDuration = 300; + Timeout = DEFAULT_TIMEOUT; + NumSystemGroups = 0; + + BrowseInterval = DEFAULT_INTERVAL; + BrowsePort = ippPort(); + BrowseLocalProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS); + BrowseRemoteProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS); + BrowseShortNames = CUPS_DEFAULT_BROWSE_SHORT_NAMES; + BrowseTimeout = DEFAULT_TIMEOUT; + Browsing = CUPS_DEFAULT_BROWSING; + DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED; + + cupsdClearString(&BrowseLocalOptions); + cupsdClearString(&BrowseRemoteOptions); + +#ifdef HAVE_LDAP + cupsdClearString(&BrowseLDAPBindDN); + cupsdClearString(&BrowseLDAPDN); + cupsdClearString(&BrowseLDAPPassword); + cupsdClearString(&BrowseLDAPServer); +#endif /* HAVE_LDAP */ JobHistory = DEFAULT_HISTORY; JobFiles = DEFAULT_FILES; @@ -413,7 +418,20 @@ ReadConfiguration(void) MaxJobsPerPrinter = 0; MaxCopies = 100; - ClearString(&DefaultPolicy); + cupsdDeleteAllPolicies(); + cupsdClearString(&DefaultPolicy); + + MaxSubscriptions = 100; + MaxSubscriptionsPerJob = 0; + MaxSubscriptionsPerPrinter = 0; + MaxSubscriptionsPerUser = 0; + DefaultLeaseDuration = 86400; + MaxLeaseDuration = 0; + +#ifdef HAVE_LAUNCHD + LaunchdTimeout = DEFAULT_TIMEOUT + 10; + cupsdSetString(&LaunchdConf, CUPS_DEFAULT_LAUNCHD_CONF); +#endif /* HAVE_LAUNCHD */ /* * Read the configuration file... @@ -429,32 +447,47 @@ ReadConfiguration(void) if (!status) return (0); - if (RunAsUser) - RunUser = User; - else - RunUser = getuid(); + RunUser = getuid(); /* * Use the default system group if none was supplied in cupsd.conf... */ if (NumSystemGroups == 0) - NumSystemGroups ++; + { + if (!parse_groups(CUPS_DEFAULT_SYSTEM_GROUPS)) + { + /* + * Find the group associated with GID 0... + */ + + group = getgrgid(0); + endgrent(); + + if (group != NULL) + cupsdSetString(&SystemGroups[0], group->gr_name); + else + cupsdSetString(&SystemGroups[0], "unknown"); + + SystemGroupIDs[0] = 0; + NumSystemGroups = 1; + } + } /* * Get the access control list for browsing... */ - BrowseACL = FindLocation("CUPS_INTERNAL_BROWSE_ACL"); + BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL"); /* * Open the system log for cupsd if necessary... */ #ifdef HAVE_VSYSLOG - if (strcmp(AccessLog, "syslog") == 0 || - strcmp(ErrorLog, "syslog") == 0 || - strcmp(PageLog, "syslog") == 0) + if (!strcmp(AccessLog, "syslog") || + !strcmp(ErrorLog, "syslog") || + !strcmp(PageLog, "syslog")) openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR); #endif /* HAVE_VSYSLOG */ @@ -462,126 +495,233 @@ ReadConfiguration(void) * Log the configuration file that was used... */ - LogMessage(L_INFO, "Loaded configuration file \"%s\"", ConfigurationFile); + cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"", + ConfigurationFile); + + /* + * Validate the Group and SystemGroup settings - they cannot be the same, + * otherwise the CGI programs will be able to authenticate as root without + * a password! + */ + + if (!RunUser) + { + for (i = 0; i < NumSystemGroups; i ++) + if (Group == SystemGroupIDs[i]) + break; + + if (i < NumSystemGroups) + { + /* + * Log the error and reset the group to a safe value... + */ + + cupsdLogMessage(CUPSD_LOG_NOTICE, + "Group and SystemGroup cannot use the same groups!"); + cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"..."); + + group = getgrnam("nobody"); + endgrent(); + + if (group != NULL) + Group = group->gr_gid; + else + { + /* + * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos- + * complement number...) + */ + + Group = 65534; + } + } + } /* * Check that we have at least one listen/port line; if not, report this * as an error and exit! */ - if (NumListeners == 0) + if (cupsArrayCount(Listeners) == 0) { /* * No listeners! */ - LogMessage(L_EMERG, "No valid Listen or Port lines were found in the configuration file!"); + cupsdLogMessage(CUPSD_LOG_EMERG, + "No valid Listen or Port lines were found in the configuration file!"); /* * Commit suicide... */ - kill(getpid(), SIGTERM); + cupsdEndProcess(getpid(), 0); } /* * Set the default locale using the language and charset... */ - SetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset); + cupsdSetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset); /* * Update all relative filenames to include the full path from ServerRoot... */ if (DocumentRoot[0] != '/') - SetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot); + cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot); if (RequestRoot[0] != '/') - SetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot); + cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot); if (ServerBin[0] != '/') - SetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin); + cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin); + + if (StateDir[0] != '/') + cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir); + + if (CacheDir[0] != '/') + cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir); #ifdef HAVE_SSL if (ServerCertificate[0] != '/') - SetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate); + cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate); -# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) - chown(ServerCertificate, RunUser, Group); - chmod(ServerCertificate, ConfigFilePerm); + if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot))) + { + chown(ServerCertificate, RunUser, Group); + chmod(ServerCertificate, 0600); + } +# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) if (ServerKey[0] != '/') - SetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey); + cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey); - chown(ServerKey, RunUser, Group); - chmod(ServerKey, ConfigFilePerm); + if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot))) + { + chown(ServerKey, RunUser, Group); + chmod(ServerKey, 0600); + } # endif /* HAVE_LIBSSL || HAVE_GNUTLS */ #endif /* HAVE_SSL */ /* - * Make sure that ServerRoot and the config files are owned and + * Make sure that directories and config files are owned and * writable by the user and group in the cupsd.conf file... */ - chown(ServerRoot, RunUser, Group); - chmod(ServerRoot, 0775); - - snprintf(temp, sizeof(temp), "%s/certs", ServerRoot); - chown(temp, RunUser, Group); - chmod(temp, 0711); - - snprintf(temp, sizeof(temp), "%s/ppd", ServerRoot); - chown(temp, RunUser, Group); - chmod(temp, 0755); - - snprintf(temp, sizeof(temp), "%s/ssl", ServerRoot); - chown(temp, RunUser, Group); - chmod(temp, 0700); - - snprintf(temp, sizeof(temp), "%s/cupsd.conf", ServerRoot); - chown(temp, RunUser, Group); - chmod(temp, ConfigFilePerm); - - snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot); - chown(temp, RunUser, Group); -#ifdef __APPLE__ - chmod(temp, 0600); -#else - chmod(temp, ConfigFilePerm); -#endif /* __APPLE__ */ - - snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot); - chown(temp, RunUser, Group); -#ifdef __APPLE__ - chmod(temp, 0600); -#else - chmod(temp, ConfigFilePerm); -#endif /* __APPLE__ */ - - snprintf(temp, sizeof(temp), "%s/passwd.md5", ServerRoot); - chown(temp, User, Group); - chmod(temp, 0600); + check_permissions(CacheDir, NULL, 0775, RunUser, Group, 1, 1); +/* check_permissions(CacheDir, "ppd", 0755, RunUser, Group, 1, 1);*/ + + check_permissions(StateDir, NULL, 0755, RunUser, Group, 1, 1); + check_permissions(StateDir, "certs", RunUser ? 0711 : 0511, User, + SystemGroupIDs[0], 1, 1); + + check_permissions(ServerRoot, NULL, 0755, RunUser, Group, 1, 0); + check_permissions(ServerRoot, "ppd", 0755, RunUser, Group, 1, 1); + check_permissions(ServerRoot, "ssl", 0700, RunUser, Group, 1, 0); + check_permissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser, Group, + 0, 0); + check_permissions(ServerRoot, "classes.conf", 0600, RunUser, Group, 0, 0); + check_permissions(ServerRoot, "printers.conf", 0600, RunUser, Group, 0, 0); + check_permissions(ServerRoot, "passwd.md5", 0600, User, Group, 0, 0); + + /* + * Update TempDir to the default if it hasn't been set already... + */ + + if (!TempDir) + { + if ((tmpdir = getenv("TMPDIR")) != NULL) + { + /* + * TMPDIR is defined, see if it is OK for us to use... + */ + + if (stat(tmpdir, &tmpinfo)) + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to access TMPDIR (%s): %s", + tmpdir, strerror(errno)); + else if (!S_ISDIR(tmpinfo.st_mode)) + cupsdLogMessage(CUPSD_LOG_ERROR, "TMPDIR (%s) is not a directory!", + tmpdir); + else if ((tmpinfo.st_uid != User || !(tmpinfo.st_mode & S_IWUSR)) && + (tmpinfo.st_gid != Group || !(tmpinfo.st_mode & S_IWGRP)) && + !(tmpinfo.st_mode & S_IWOTH)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "TMPDIR (%s) has the wrong permissions!", tmpdir); + else + cupsdSetString(&TempDir, tmpdir); + + if (!TempDir) + cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...", + RequestRoot); + } + + if (!TempDir) + cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot); + } /* * Make sure the request and temporary directories have the right * permissions... */ - chown(RequestRoot, RunUser, Group); - chmod(RequestRoot, 0710); + check_permissions(RequestRoot, NULL, 0710, RunUser, Group, 1, 1); + + if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) || + access(TempDir, 0)) + { + /* + * Update ownership and permissions if the CUPS temp directory + * is under the spool directory or does not exist... + */ + + check_permissions(TempDir, NULL, 01770, RunUser, Group, 1, 1); + } - if (strncmp(TempDir, RequestRoot, strlen(RequestRoot)) == 0) + if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot))) { /* - * Only update ownership and permissions if the CUPS temp directory - * is under the spool directory... + * Clean out the temporary directory... */ - chown(TempDir, RunUser, Group); - chmod(TempDir, 01770); + cups_dir_t *dir; /* Temporary directory */ + cups_dentry_t *dent; /* Directory entry */ + char tempfile[1024]; /* Temporary filename */ + + + if ((dir = cupsDirOpen(TempDir)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Cleaning out old temporary files in \"%s\"...", TempDir); + + while ((dent = cupsDirRead(dir)) != NULL) + { + snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename); + + if (unlink(tempfile)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to remove temporary file \"%s\" - %s", + tempfile, strerror(errno)); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...", + tempfile); + } + + cupsDirClose(dir); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open temporary directory \"%s\" - %s", + TempDir, strerror(errno)); } + /* + * Setup environment variables... + */ + + cupsdInitEnv(); + /* * Check the MaxClients setting, and then allocate memory for it... */ @@ -589,20 +729,14 @@ ReadConfiguration(void) if (MaxClients > (MaxFDs / 3) || MaxClients <= 0) { if (MaxClients > 0) - LogMessage(L_INFO, "MaxClients limited to 1/3 of the file descriptor limit (%d)...", - MaxFDs); + cupsdLogMessage(CUPSD_LOG_INFO, "MaxClients limited to 1/3 (%d) of the file descriptor limit (%d)...", + MaxFDs / 3, 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); + cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.", + MaxClients); /* * Check the MaxActiveJobs setting; limit to 1/3 the available @@ -613,10 +747,10 @@ ReadConfiguration(void) MaxActiveJobs = MaxFDs / 3; if (Classification && strcasecmp(Classification, "none") == 0) - ClearString(&Classification); + cupsdClearString(&Classification); if (Classification) - LogMessage(L_INFO, "Security set to \"%s\"", Classification); + cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification); /* * Update the MaxClientsPerHost value, as needed... @@ -628,138 +762,141 @@ ReadConfiguration(void) if (MaxClientsPerHost > MaxClients) MaxClientsPerHost = MaxClients; - LogMessage(L_INFO, "Allowing up to %d client connections per host.", - MaxClientsPerHost); + cupsdLogMessage(CUPSD_LOG_INFO, + "Allowing up to %d client connections per host.", + MaxClientsPerHost); /* * Update the default policy, as needed... */ if (DefaultPolicy) - DefaultPolicyPtr = FindPolicy(DefaultPolicy); + DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy); else DefaultPolicyPtr = NULL; if (!DefaultPolicyPtr) { - policy_t *p; /* New policy */ - policyop_t *po; /* New policy operation */ - char groupname[255]; /* Group name */ + cupsd_policy_t *p; /* New policy */ + cupsd_location_t *po; /* New policy operation */ if (DefaultPolicy) - LogMessage(L_ERROR, "Default policy \"%s\" not found!", DefaultPolicy); + cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found!", + DefaultPolicy); - if ((DefaultPolicyPtr = FindPolicy("default")) != NULL) - LogMessage(L_INFO, "Using policy \"default\" as the default!"); + if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL) + cupsdLogMessage(CUPSD_LOG_INFO, + "Using policy \"default\" as the default!"); else { - LogMessage(L_INFO, "Creating CUPS default administrative policy:"); - - DefaultPolicyPtr = p = AddPolicy("default"); - - LogMessage(L_INFO, ""); - LogMessage(L_INFO, ""); - LogMessage(L_INFO, "Order Allow,Deny"); - LogMessage(L_INFO, "Allow @OWNER"); - - po = AddPolicyOp(p, NULL, IPP_SEND_DOCUMENT); - po->order_type = POLICY_DENY; - - AddPolicyOpName(po, POLICY_ALLOW, "@OWNER"); - - for (i = 0; i < NumSystemGroups; i ++) - { - snprintf(groupname, sizeof(groupname), "@%s", SystemGroups[i]); - AddPolicyOpName(po, POLICY_ALLOW, groupname); - LogMessage(L_INFO, "Allow %s", groupname); - } - - AddPolicyOp(p, po, IPP_SEND_URI); - AddPolicyOp(p, po, IPP_CANCEL_JOB); - AddPolicyOp(p, po, IPP_HOLD_JOB); - AddPolicyOp(p, po, IPP_RELEASE_JOB); - AddPolicyOp(p, po, IPP_RESTART_JOB); - AddPolicyOp(p, po, IPP_PURGE_JOBS); - AddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES); - AddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION); - AddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION); - AddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION); - AddPolicyOp(p, po, IPP_GET_NOTIFICATIONS); - AddPolicyOp(p, po, IPP_REPROCESS_JOB); - AddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB); - AddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB); - AddPolicyOp(p, po, IPP_RESUME_JOB); - AddPolicyOp(p, po, CUPS_MOVE_JOB); - - LogMessage(L_INFO, ""); - - LogMessage(L_INFO, ""); - LogMessage(L_INFO, "Order Allow,Deny"); - LogMessage(L_INFO, "Authenticate yes"); - - po = AddPolicyOp(p, NULL, IPP_PAUSE_PRINTER); - po->order_type = POLICY_DENY; - po->authenticate = 1; - - for (i = 0; i < NumSystemGroups; i ++) - { - snprintf(groupname, sizeof(groupname), "@%s", SystemGroups[i]); - AddPolicyOpName(po, POLICY_ALLOW, groupname); - LogMessage(L_INFO, "Allow %s", groupname); - } - - AddPolicyOp(p, po, IPP_RESUME_PRINTER); - AddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES); - AddPolicyOp(p, po, IPP_ENABLE_PRINTER); - AddPolicyOp(p, po, IPP_DISABLE_PRINTER); - AddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB); - AddPolicyOp(p, po, IPP_HOLD_NEW_JOBS); - AddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS); - AddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER); - AddPolicyOp(p, po, IPP_ACTIVATE_PRINTER); - AddPolicyOp(p, po, IPP_RESTART_PRINTER); - AddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER); - AddPolicyOp(p, po, IPP_STARTUP_PRINTER); - AddPolicyOp(p, po, IPP_PROMOTE_JOB); - AddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER); - AddPolicyOp(p, po, CUPS_ADD_PRINTER); - AddPolicyOp(p, po, CUPS_DELETE_PRINTER); - AddPolicyOp(p, po, CUPS_ADD_CLASS); - AddPolicyOp(p, po, CUPS_DELETE_CLASS); - AddPolicyOp(p, po, CUPS_ACCEPT_JOBS); - AddPolicyOp(p, po, CUPS_REJECT_JOBS); - AddPolicyOp(p, po, CUPS_SET_DEFAULT); - AddPolicyOp(p, po, CUPS_ADD_DEVICE); - AddPolicyOp(p, po, CUPS_DELETE_DEVICE); - - LogMessage(L_INFO, ""); - - LogMessage(L_INFO, ""); - LogMessage(L_INFO, "Order Deny,Allow"); - - po = AddPolicyOp(p, NULL, IPP_ANY_OPERATION); - po->order_type = POLICY_ALLOW; - - LogMessage(L_INFO, ""); - LogMessage(L_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, + "Creating CUPS default administrative policy:"); + + DefaultPolicyPtr = p = cupsdAddPolicy("default"); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, + ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + + po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT); + po->order_type = AUTH_ALLOW; + po->level = AUTH_USER; + + cupsdAddName(po, "@OWNER"); + cupsdAddName(po, "@SYSTEM"); + cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM"); + + cupsdAddPolicyOp(p, po, IPP_SEND_URI); + cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB); + cupsdAddPolicyOp(p, po, IPP_HOLD_JOB); + cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB); + cupsdAddPolicyOp(p, po, IPP_RESTART_JOB); + cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS); + cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES); + cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS); + cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB); + cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_RESUME_JOB); + cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB); + cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + + cupsdLogMessage(CUPSD_LOG_INFO, + ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Basic"); + + po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER); + po->order_type = AUTH_ALLOW; + po->type = AUTH_BASIC; + po->level = AUTH_USER; + + cupsdAddName(po, "@SYSTEM"); + cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM"); + + cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER); + cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES); + cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS); + cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS); + cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER); + cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER); + cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER); + cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB); + cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER); + cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER); + cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER); + cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS); + cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS); + cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS); + cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS); + cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + + po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION); + po->order_type = AUTH_ALLOW; + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, ""); } } + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d", + NumPolicies); + for (i = 0; i < NumPolicies; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadConfiguration: Policies[%d]=\"%s\"", i, + Policies[i]->name); + /* * If we are doing a full reload or the server root has changed, flush * the jobs, printers, etc. and start from scratch... @@ -769,37 +906,31 @@ ReadConfiguration(void) !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) || !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot)) { - LogMessage(L_INFO, "Full reload is required."); + mime_type_t *type; /* Current type */ + char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE]; + /* MIME type name */ + + + cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required."); /* * Free all memory... */ - FreeAllJobs(); - DeleteAllClasses(); - DeleteAllPrinters(); + cupsdDeleteAllSubscriptions(); + cupsdFreeAllJobs(); + cupsdDeleteAllClasses(); + cupsdDeleteAllPrinters(); 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]); + _cups_sp_free(MimeTypes[i]); free(MimeTypes); } @@ -810,70 +941,112 @@ ReadConfiguration(void) snprintf(temp, sizeof(temp), "%s/filter", ServerBin); - MimeDatabase = mimeNew(); - mimeMerge(MimeDatabase, ServerRoot, temp); + MimeDatabase = mimeLoad(ServerRoot, temp); + + if (!MimeDatabase) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "Unable to load MIME database from \'%s\'!", ServerRoot); + exit(errno); + } + + cupsdLogMessage(CUPSD_LOG_INFO, + "Loaded MIME database from \'%s\': %d types, %d filters...", + ServerRoot, mimeNumTypes(MimeDatabase), + mimeNumFilters(MimeDatabase)); /* * Create a list of MIME types for the document-format-supported * attribute... */ - NumMimeTypes = MimeDatabase->num_types; + NumMimeTypes = mimeNumTypes(MimeDatabase); if (!mimeType(MimeDatabase, "application", "octet-stream")) NumMimeTypes ++; MimeTypes = calloc(NumMimeTypes, sizeof(const char *)); - for (i = 0; i < MimeDatabase->num_types; i ++) + for (i = 0, type = mimeFirstType(MimeDatabase); + type; + i ++, type = mimeNextType(MimeDatabase)) { - snprintf(type, sizeof(type), "%s/%s", MimeDatabase->types[i]->super, - MimeDatabase->types[i]->type); + snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type); - MimeTypes[i] = strdup(type); + MimeTypes[i] = _cups_sp_alloc(mimetype); } if (i < NumMimeTypes) - MimeTypes[i] = strdup("application/octet-stream"); + MimeTypes[i] = _cups_sp_alloc("application/octet-stream"); + + if (LogLevel == CUPSD_LOG_DEBUG2) + { + mime_filter_t *filter; /* Current filter */ + + + for (type = mimeFirstType(MimeDatabase); + type; + type = mimeNextType(MimeDatabase)) + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: type %s/%s", + type->super, type->type); + + for (filter = mimeFirstFilter(MimeDatabase); + filter; + filter = mimeNextFilter(MimeDatabase)) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadConfiguration: filter %s/%s to %s/%s %d %s", + filter->src->super, filter->src->type, + filter->dst->super, filter->dst->type, + filter->cost, filter->filter); + } /* * Load banners... */ snprintf(temp, sizeof(temp), "%s/banners", DataDir); - LoadBanners(temp); + cupsdLoadBanners(temp); /* * Load printers and classes... */ - LoadAllPrinters(); - LoadAllClasses(); + cupsdLoadAllPrinters(); + cupsdLoadAllClasses(); + cupsdLoadRemoteCache(); + cupsdWritePrintcap(); - CreateCommonData(); + cupsdCreateCommonData(); /* - * Load devices and PPDs... + * Load queued jobs... */ - snprintf(temp, sizeof(temp), "%s/backend", ServerBin); - LoadDevices(temp); - - snprintf(temp, sizeof(temp), "%s/model", DataDir); - LoadPPDs(temp); + cupsdLoadAllJobs(); /* - * Load queued jobs... + * Load subscriptions... */ - LoadAllJobs(); + cupsdLoadAllSubscriptions(); - LogMessage(L_INFO, "Full reload complete."); + cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete."); } else { - CreateCommonData(); + /* + * Not a full reload, so recreate the common printer attributes... + */ + + cupsdCreateCommonData(); - LogMessage(L_INFO, "Partial reload complete."); + /* + * Update all printers as needed... + */ + + cupsdUpdatePrinters(); + cupsdWritePrintcap(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete."); } /* @@ -882,1106 +1055,1415 @@ ReadConfiguration(void) NeedReload = RELOAD_NONE; - ClearString(&old_serverroot); - ClearString(&old_requestroot); - - /* - * Startup the server and return... - */ - - StartServer(); + cupsdClearString(&old_serverroot); + cupsdClearString(&old_requestroot); return (1); } /* - * 'read_configuration()' - Read a configuration file. + * 'check_permissions()' - Fix the mode and ownership of a file or directory. */ -static int /* O - 1 on success, 0 on failure */ -read_configuration(cups_file_t *fp) /* I - File to read from */ +static int /* O - 0 on success, -1 on error */ +check_permissions(const char *filename, /* I - File/directory name */ + const char *suffix, /* I - Additional file/directory name */ + int mode, /* I - Permissions */ + int user, /* I - Owner */ + int group, /* I - Group */ + int is_dir, /* I - 1 = directory, 0 = file */ + int create_dir)/* I - 1 = create directory, 0 = not */ { - int i; /* Looping var */ - int linenum; /* Current line number */ - int len; /* Length of line */ - char line[HTTP_MAX_BUFFER], /* Line from file */ - name[256], /* Parameter name */ - *nameptr, /* Pointer into name */ - *value; /* Pointer to value */ - int valuelen; /* Length of value */ - var_t *var; /* Current variable */ - unsigned ip[4], /* Address value */ - mask[4]; /* Netmask value */ - dirsvc_relay_t *relay; /* Relay data */ - dirsvc_poll_t *poll; /* Polling data */ - http_addr_t polladdr; /* Polling address */ - location_t *location; /* Browse location */ - cups_file_t *incfile; /* Include file */ - char incname[1024]; /* Include filename */ + int dir_created = 0; /* Did we create a directory? */ + char pathname[1024]; /* File name with prefix */ + struct stat fileinfo; /* Stat buffer */ /* - * Loop through each line in the file... + * Prepend the given root to the filename before testing it... */ - linenum = 0; + if (suffix) + { + snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix); + filename = pathname; + } - while (cupsFileGets(fp, line, sizeof(line)) != NULL) + /* + * See if we can stat the file/directory... + */ + + if (stat(filename, &fileinfo)) { - linenum ++; + if (errno == ENOENT && create_dir) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Creating missing directory \"%s\"", + filename); - /* - * Skip comment lines... - */ + if (mkdir(filename, mode)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create directory \"%s\" - %s", filename, + strerror(errno)); + return (-1); + } - if (line[0] == '#') - continue; + dir_created = 1; + } + else + return (-1); + } - /* - * Strip trailing whitespace, if any... - */ + /* + * Make sure it's a regular file... + */ + + if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file!", filename); + return (-1); + } + + if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory!", filename); + return (-1); + } + + /* + * Fix owner, group, and mode as needed... + */ - len = strlen(line); + if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group) + { + cupsdLogMessage(CUPSD_LOG_WARN, "Repairing ownership of \"%s\"", filename); - while (len > 0 && isspace(line[len - 1])) + if (chown(filename, user, group)) { - len --; - line[len] = '\0'; + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to change ownership of \"%s\" - %s", filename, + strerror(errno)); + return (-1); } + } - /* - * Extract the name from the beginning of the line... - */ + if (dir_created || (fileinfo.st_mode & 07777) != mode) + { + cupsdLogMessage(CUPSD_LOG_WARN, "Repairing access permissions of \"%s\"", filename); - for (value = line; isspace(*value); value ++); + if (chmod(filename, mode)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to change permissions of \"%s\" - %s", filename, + strerror(errno)); + return (-1); + } + } - for (nameptr = name; *value != '\0' && !isspace(*value) && - nameptr < (name + sizeof(name) - 1);) - *nameptr++ = *value++; - *nameptr = '\0'; + /* + * Everything is OK... + */ - while (isspace(*value)) - value ++; + return (0); +} - if (name[0] == '\0') - continue; - /* - * Decode the directive... - */ +/* + * 'get_address()' - Get an address + port number from a line. + */ + +static http_addrlist_t * /* O - Pointer to list if address good, NULL if bad */ +get_address(const char *value, /* I - Value string */ + int defport) /* I - Default port */ +{ + char buffer[1024], /* Hostname + port number buffer */ + defpname[255], /* Default port name */ + *hostname, /* Hostname or IP */ + *portname; /* Port number or name */ + http_addrlist_t *addrlist; /* Address list */ + + + /* + * Check for an empty value... + */ + + if (!*value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address!"); + return (NULL); + } + + /* + * Grab a hostname and port number; if there is no colon and the port name + * is only digits, then we have a port number by itself... + */ + + strlcpy(buffer, value, sizeof(buffer)); - if (strcasecmp(name, "Include") == 0) + if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']')) + { + *portname++ = '\0'; + hostname = buffer; + } + else + { + for (portname = buffer; isdigit(*portname & 255); portname ++); + + if (*portname) { /* - * Include filename + * Use the default port... */ - if (value[0] == '/') - strlcpy(incname, value, sizeof(incname)); - else - snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value); + sprintf(defpname, "%d", defport); + portname = defpname; + hostname = buffer; + } + else + { + /* + * The buffer contains just a port number... + */ - 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); - } + portname = buffer; + hostname = NULL; } - else if (strcasecmp(name, " - */ + } - if (line[len - 1] == '>') - { - line[len - 1] = '\0'; + if (hostname && !strcmp(hostname, "*")) + hostname = NULL; - 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, " - */ + /* + * Now lookup the address using httpAddrGetList()... + */ - if (line[len - 1] == '>') - { - line[len - 1] = '\0'; + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed!", + hostname ? hostname : "(nil)"); - linenum = read_policy(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) - { - /* - * Add a listening address to the list... - */ + return (addrlist); +} - listener_t *temp; /* New listeners array */ +/* + * 'get_addr_and_mask()' - Get an IP address and netmask. + */ - if (NumListeners == 0) - temp = malloc(sizeof(listener_t)); - else - temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t)); +static int /* O - 1 on success, 0 on failure */ +get_addr_and_mask(const char *value, /* I - String from config file */ + unsigned *ip, /* O - Address value */ + unsigned *mask) /* O - Mask value */ +{ + int i, j, /* Looping vars */ + family, /* Address family */ + ipcount; /* Count of fields in address */ + unsigned ipval; /* Value */ + const char *maskval, /* Pointer to start of mask value */ + *ptr, /* Pointer into value */ + *ptr2; /* ... */ + static unsigned netmasks[4][4] = /* Standard IPv4 netmasks... */ + { + { 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } + }; +#ifdef AF_INET6 + static unsigned netmasks6[8][4] = /* Standard IPv6 netmasks... */ + { + { 0xffff0000, 0x00000000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffff0000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffff0000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } + }; +#endif /* AF_INET6 */ - if (!temp) - { - LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.", - name, linenum, strerror(errno)); - continue; - } - Listeners = temp; - temp += NumListeners; + /* + * Get the address... + */ - memset(temp, 0, sizeof(listener_t)); + memset(ip, 0, sizeof(unsigned) * 4); - if (get_address(value, INADDR_ANY, IPP_PORT, AF_INET, &(temp->address))) - { - httpAddrString(&(temp->address), line, sizeof(line)); + if ((maskval = strchr(value, '/')) != NULL) + maskval ++; + else + maskval = value + strlen(value); #ifdef AF_INET6 - if (temp->address.addr.sa_family == AF_INET6) - LogMessage(L_INFO, "Listening to %s:%d (IPv6)", line, - ntohs(temp->address.ipv6.sin6_port)); - else -#endif /* AF_INET6 */ - LogMessage(L_INFO, "Listening to %s:%d", line, - ntohs(temp->address.ipv4.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) - { - /* - * Add a listening address to the list... - */ - - listener_t *temp; /* New listeners array */ + /* + * Check for an IPv6 address... + */ + if (*value == '[') + { + /* + * Parse hexadecimal IPv6 address... + */ - if (NumListeners == 0) - temp = malloc(sizeof(listener_t)); - else - temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t)); + family = AF_INET6; - if (!temp) + for (i = 0, ptr = value + 1; *ptr && i < 8; i ++) + { + if (*ptr == ']') + break; + else if (!strncmp(ptr, "::", 2)) { - LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.", - name, linenum, strerror(errno)); - continue; - } - - Listeners = temp; - temp += NumListeners; + for (ptr2 = strchr(ptr + 2, ':'), j = 0; + ptr2; + ptr2 = strchr(ptr2 + 1, ':'), j ++); - if (get_address(value, INADDR_ANY, IPP_PORT, AF_INET, &(temp->address))) + i = 7 - j; + } + else if (isxdigit(*ptr & 255)) { - httpAddrString(&(temp->address), line, sizeof(line)); + ipval = strtoul(ptr, (char **)&ptr, 16); -#ifdef AF_INET6 - if (temp->address.addr.sa_family == AF_INET6) - LogMessage(L_INFO, "Listening to %s:%d (IPv6)", line, - ntohs(temp->address.ipv6.sin6_port)); + if (ipval > 0xffff) + return (0); + + if (i & 1) + ip[i] |= ipval; else -#endif /* AF_INET6 */ - LogMessage(L_INFO, "Listening to %s:%d", line, - ntohs(temp->address.ipv4.sin_port)); - temp->encryption = HTTP_ENCRYPT_ALWAYS; - NumListeners ++; + ip[i] |= ipval << 16; } else - LogMessage(L_ERROR, "Bad %s address %s at line %d.", name, - value, linenum); + return (0); + + while (*ptr == ':') + ptr ++; } -#endif /* HAVE_SSL */ - else if (strcasecmp(name, "BrowseAddress") == 0) - { - /* - * Add a browse address to the list... - */ - dirsvc_addr_t *temp; /* New browse address array */ + ipcount = i; + if (*ptr && *ptr != '/') + return (0); + } + else +#endif /* AF_INET6 */ + { + /* + * Parse dotted-decimal IPv4 address... + */ - if (NumBrowsers == 0) - temp = malloc(sizeof(dirsvc_addr_t)); - else - temp = realloc(Browsers, (NumBrowsers + 1) * sizeof(dirsvc_addr_t)); + family = AF_INET; + ipcount = sscanf(value, "%u.%u.%u.%u", ip + 0, ip + 1, ip + 2, ip + 3); - if (!temp) - { - LogMessage(L_ERROR, "Unable to allocate BrowseAddress at line %d - %s.", - linenum, strerror(errno)); - continue; - } + ip[3] |= ((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8; + ip[0] = ip[1] = ip[2] = 0; + } - Browsers = temp; - temp += NumBrowsers; + if (*maskval) + { + /* + * Get the netmask value(s)... + */ - memset(temp, 0, sizeof(dirsvc_addr_t)); + memset(mask, 0, sizeof(unsigned) * 4); - if (strcasecmp(value, "@LOCAL") == 0) - { - /* - * Send browse data to all local interfaces... - */ +#ifdef AF_INET6 + if (*maskval == '[') + { + /* + * Get hexadecimal mask value... + */ - strcpy(temp->iface, "*"); - NumBrowsers ++; - } - else if (strncasecmp(value, "@IF(", 4) == 0) + for (i = 0, ptr = maskval + 1; *ptr && i < 8; i ++) { - /* - * Send browse data to the named interface... - */ - - strlcpy(temp->iface, value + 4, sizeof(Browsers[0].iface)); + if (*ptr == ']') + break; + else if (!strncmp(ptr, "::", 2)) + { + for (ptr2 = strchr(ptr + 2, ':'), j = 0; + ptr2; + ptr2 = strchr(ptr2 + 1, ':'), j ++); - nameptr = temp->iface + strlen(temp->iface) - 1; - if (*nameptr == ')') - *nameptr = '\0'; + i = 7 - j; + } + else if (isxdigit(*ptr & 255)) + { + ipval = strtoul(ptr, (char **)&ptr, 16); - NumBrowsers ++; - } - else if (get_address(value, INADDR_NONE, BrowsePort, AF_INET, &(temp->to))) - { - httpAddrString(&(temp->to), line, sizeof(line)); + if (ipval > 0xffff) + return (0); -#ifdef AF_INET6 - if (temp->to.addr.sa_family == AF_INET6) - LogMessage(L_INFO, "Sending browsing info to %s:%d (IPv6)", line, - ntohs(temp->to.ipv6.sin6_port)); + if (i & 1) + mask[i] |= ipval; + else + mask[i] |= ipval << 16; + } else -#endif /* AF_INET6 */ - LogMessage(L_INFO, "Sending browsing info to %s:%d", line, - ntohs(temp->to.ipv4.sin_port)); + return (0); - NumBrowsers ++; + while (*ptr == ':') + ptr ++; } - else - LogMessage(L_ERROR, "Bad BrowseAddress %s at line %d.", value, - linenum); + + if (*ptr) + return (0); } - else if (strcasecmp(name, "BrowseOrder") == 0) + else +#endif /* AF_INET6 */ + if (strchr(maskval, '.')) { /* - * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"... + * Get dotted-decimal mask... */ - if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - location = AddLocation("CUPS_INTERNAL_BROWSE_ACL"); + if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2, mask + 3) != 4) + return (0); - 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); + mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8; + mask[0] = mask[1] = mask[2] = 0; } - else if (strcasecmp(name, "BrowseProtocols") == 0) + else { /* - * "BrowseProtocol name [... name]" + * Get address/bits format... */ - BrowseProtocols = 0; + i = atoi(maskval); - for (; *value;) +#ifdef AF_INET6 + if (family == AF_INET6) { - for (valuelen = 0; value[valuelen]; valuelen ++) - if (isspace(value[valuelen]) || value[valuelen] == ',') - break; + i = 128 - i; - if (value[valuelen]) - { - value[valuelen] = '\0'; - valuelen ++; - } + if (i <= 96) + mask[0] = 0xffffffff; + else + mask[0] = (0xffffffff << (i - 96)) & 0xffffffff; - 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; + if (i <= 64) + mask[1] = 0xffffffff; + else if (i >= 96) + mask[1] = 0; else - { - LogMessage(L_ERROR, "Unknown browse protocol \"%s\" on line %d.", - value, linenum); - break; - } + mask[1] = (0xffffffff << (i - 64)) & 0xffffffff; - for (value += valuelen; *value; value ++) - if (!isspace(*value) || *value != ',') - break; + if (i <= 32) + mask[2] = 0xffffffff; + else if (i >= 64) + mask[2] = 0; + else + mask[2] = (0xffffffff << (i - 32)) & 0xffffffff; + + if (i == 0) + mask[3] = 0xffffffff; + else if (i >= 32) + mask[3] = 0; + else + mask[3] = (0xffffffff << i) & 0xffffffff; + } + else +#endif /* AF_INET6 */ + { + i = 32 - i; + + mask[0] = 0xffffffff; + mask[1] = 0xffffffff; + mask[2] = 0xffffffff; + + if (i > 0) + mask[3] = (0xffffffff << i) & 0xffffffff; + else + mask[3] = 0xffffffff; } } - else if (strcasecmp(name, "BrowseAllow") == 0 || - strcasecmp(name, "BrowseDeny") == 0) - { - /* - * BrowseAllow [From] host/ip... - * BrowseDeny [From] host/ip... - */ + } +#ifdef AF_INET6 + else if (family == AF_INET6) + memcpy(mask, netmasks6[ipcount - 1], sizeof(unsigned) * 4); +#endif /* AF_INET6 */ + else + memcpy(mask, netmasks[ipcount - 1], sizeof(unsigned) * 4); - if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) - location = AddLocation("CUPS_INTERNAL_BROWSE_ACL"); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_addr_and_mask(value=\"%s\", " + "ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x]", + value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2], + mask[3]); - if (location == NULL) - LogMessage(L_ERROR, "Unable to initialize browse access control list!"); - else - { - if (strncasecmp(value, "from ", 5) == 0) - { - /* - * Strip leading "from"... - */ + /* + * Check for a valid netmask; no fallback like in CUPS 1.1.x! + */ - value += 5; + if ((ip[0] & ~mask[0]) != 0 || + (ip[1] & ~mask[1]) != 0 || + (ip[2] & ~mask[2]) != 0 || + (ip[3] & ~mask[3]) != 0) + return (0); - while (isspace(*value)) - value ++; - } + return (1); +} - /* - * Figure out what form the allow/deny address takes: - * - * All - * None - * *.domain.com - * .domain.com - * host.domain.com - * nnn.* - * nnn.nnn.* - * nnn.nnn.nnn.* - * nnn.nnn.nnn.nnn - * nnn.nnn.nnn.nnn/mm - * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm - */ - if (strcasecmp(value, "all") == 0) - { - /* - * All hosts... - */ +/* + * 'parse_aaa()' - Parse authentication, authorization, and access control lines. + */ - if (strcasecmp(name, "BrowseAllow") == 0) - AllowIP(location, zeros, zeros); - else - DenyIP(location, zeros, zeros); - } - else if (strcasecmp(value, "none") == 0) - { - /* - * No hosts... - */ +static int /* O - 1 on success, 0 on failure */ +parse_aaa(cupsd_location_t *loc, /* I - Location */ + char *line, /* I - Line from file */ + char *value, /* I - Start of value data */ + int linenum) /* I - Current line number */ +{ + char *valptr; /* Pointer into value */ + unsigned ip[4], /* IP address components */ + mask[4]; /* IP netmask components */ - if (strcasecmp(name, "BrowseAllow") == 0) - AllowIP(location, ones, zeros); - else - DenyIP(location, ones, zeros); - } - else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0])) - { - /* - * Host or domain name... - */ - if (value[0] == '*') - value ++; + if (!strcasecmp(line, "Encryption")) + { + /* + * "Encryption xxx" - set required encryption level... + */ - if (strcasecmp(name, "BrowseAllow") == 0) - AllowHost(location, value); - else - DenyHost(location, value); - } - else - { - /* - * One of many IP address forms... - */ + if (!strcasecmp(value, "never")) + loc->encryption = HTTP_ENCRYPT_NEVER; + else if (!strcasecmp(value, "always")) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Encryption value \"%s\" on line %d is invalid in this " + "context. Using \"required\" instead.", value, linenum); - if (!get_addr_and_mask(value, ip, mask)) - { - LogMessage(L_ERROR, "Bad netmask value %s on line %d.", - value, linenum); - break; - } + loc->encryption = HTTP_ENCRYPT_REQUIRED; + } + else if (!strcasecmp(value, "required")) + loc->encryption = HTTP_ENCRYPT_REQUIRED; + else if (!strcasecmp(value, "ifrequested")) + loc->encryption = HTTP_ENCRYPT_IF_REQUESTED; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Encryption value %s on line %d.", value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "Order")) + { + /* + * "Order Deny,Allow" or "Order Allow,Deny"... + */ - if (strcasecmp(name, "BrowseAllow") == 0) - AllowIP(location, ip, mask); - else - DenyIP(location, ip, mask); - } - } + if (!strncasecmp(value, "deny", 4)) + loc->order_type = AUTH_ALLOW; + else if (!strncasecmp(value, "allow", 5)) + loc->order_type = AUTH_DENY; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.", + value, linenum); + return (0); } - else if (strcasecmp(name, "BrowseRelay") == 0) + } + else if (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny")) + { + /* + * Allow [From] host/ip... + * Deny [From] host/ip... + */ + + if (!strncasecmp(value, "from", 4)) { /* - * BrowseRelay [from] source [to] destination + * Strip leading "from"... */ - if (NumRelays == 0) - relay = malloc(sizeof(dirsvc_relay_t)); - else - relay = realloc(Relays, (NumRelays + 1) * sizeof(dirsvc_relay_t)); + value += 4; - if (!relay) - { - LogMessage(L_ERROR, "Unable to allocate BrowseRelay at line %d - %s.", - linenum, strerror(errno)); - continue; - } + while (isspace(*value & 255)) + value ++; + } - Relays = relay; - relay += NumRelays; + /* + * Figure out what form the allow/deny address takes: + * + * All + * None + * *.domain.com + * .domain.com + * host.domain.com + * nnn.* + * nnn.nnn.* + * nnn.nnn.nnn.* + * nnn.nnn.nnn.nnn + * nnn.nnn.nnn.nnn/mm + * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm + */ - memset(relay, 0, sizeof(dirsvc_relay_t)); + if (!strcasecmp(value, "all")) + { + /* + * All hosts... + */ - if (strncasecmp(value, "from ", 5) == 0) - { - /* - * Strip leading "from"... - */ + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, zeros, zeros); + else + cupsdDenyIP(loc, zeros, zeros); + } + else if (!strcasecmp(value, "none")) + { + /* + * No hosts... + */ - value += 5; + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, ones, zeros); + else + cupsdDenyIP(loc, ones, zeros); + } + else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255)) + { + /* + * Host or domain name... + */ - while (isspace(*value)) - value ++; - } + if (value[0] == '*') + value ++; + if (!strcasecmp(line, "Allow")) + cupsdAllowHost(loc, value); + else + cupsdDenyHost(loc, value); + } + else + { /* - * Figure out what form the from address takes: - * - * *.domain.com - * .domain.com - * host.domain.com - * nnn.* - * nnn.nnn.* - * nnn.nnn.nnn.* - * nnn.nnn.nnn.nnn - * nnn.nnn.nnn.nnn/mm - * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm + * One of many IP address forms... */ - if (value[0] == '*' || value[0] == '.' || !isdigit(value[0])) + if (!get_addr_and_mask(value, ip, mask)) { - /* - * Host or domain name... - */ + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); + return (0); + } - if (value[0] == '*') - value ++; + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, ip, mask); + else + cupsdDenyIP(loc, ip, mask); + } + } + else if (!strcasecmp(line, "AuthType")) + { + /* + * AuthType {none,basic,digest,basicdigest} + */ - strlcpy(name, value, sizeof(name)); - if ((nameptr = strchr(name, ' ')) != NULL) - *nameptr = '\0'; + if (!strcasecmp(value, "none")) + { + loc->type = AUTH_NONE; + loc->level = AUTH_ANON; + } + else if (!strcasecmp(value, "basic")) + { + loc->type = AUTH_BASIC; - relay->from.type = AUTH_NAME; - relay->from.mask.name.name = strdup(name); - relay->from.mask.name.length = strlen(name); - } - else - { - /* - * One of many IP address forms... - */ + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else if (!strcasecmp(value, "digest")) + { + loc->type = AUTH_DIGEST; - if (!get_addr_and_mask(value, ip, mask)) - { - LogMessage(L_ERROR, "Bad netmask value %s on line %d.", - value, linenum); - break; - } + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else if (!strcasecmp(value, "basicdigest")) + { + loc->type = AUTH_BASICDIGEST; - relay->from.type = AUTH_IP; - memcpy(relay->from.mask.ip.address, ip, - sizeof(relay->from.mask.ip.address)); - memcpy(relay->from.mask.ip.netmask, mask, - sizeof(relay->from.mask.ip.netmask)); - } + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown authorization type %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "AuthClass")) + { + /* + * AuthClass anonymous, user, system, group + */ - /* - * Skip value and trailing whitespace... - */ + if (!strcasecmp(value, "anonymous")) + { + loc->type = AUTH_NONE; + loc->level = AUTH_ANON; - for (; *value; value ++) - if (isspace(*value)) - break; + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider removing " + "it from line %d.", + value, linenum); + } + else if (!strcasecmp(value, "user")) + { + loc->level = AUTH_USER; - while (isspace(*value)) - value ++; + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require valid-user\" on line %d.", + value, linenum); + } + else if (!strcasecmp(value, "group")) + { + loc->level = AUTH_GROUP; - if (strncasecmp(value, "to ", 3) == 0) - { - /* - * Strip leading "to"... - */ + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require @groupname\" on line %d.", + value, linenum); + } + else if (!strcasecmp(value, "system")) + { + loc->level = AUTH_GROUP; - value += 3; + cupsdAddName(loc, "@SYSTEM"); - while (isspace(*value)) - value ++; - } + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require @SYSTEM\" on line %d.", + value, linenum); + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown authorization class %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "AuthGroupName")) + { + cupsdAddName(loc, value); - /* - * Get "to" address and port... - */ + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthGroupName %s\" directive is deprecated; consider " + "using \"Require @%s\" on line %d.", + value, value, linenum); + } + else if (!strcasecmp(line, "Require")) + { + /* + * Apache synonym for AuthClass and AuthGroupName... + * + * Get initial word: + * + * Require valid-user + * Require group names + * Require user names + */ + + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); + + if (*valptr) + *valptr++ = '\0'; + + if (!strcasecmp(value, "valid-user") || + !strcasecmp(value, "user")) + loc->level = AUTH_USER; + else if (!strcasecmp(value, "group")) + loc->level = AUTH_GROUP; + else + { + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.", + value, linenum); + return (0); + } + + /* + * Get the list of names from the line... + */ - if (get_address(value, INADDR_BROADCAST, BrowsePort, AF_INET, &(relay->to))) + for (value = valptr; *value;) + { + while (isspace(*value & 255)) + value ++; + + if (*value == '\"' || *value == '\'') { - httpAddrString(&(relay->to), line, sizeof(line)); - - if (relay->from.type == AUTH_IP) - snprintf(name, sizeof(name), "%u.%u.%u.%u/%u.%u.%u.%u", - relay->from.mask.ip.address[0], - relay->from.mask.ip.address[1], - relay->from.mask.ip.address[2], - relay->from.mask.ip.address[3], - relay->from.mask.ip.netmask[0], - relay->from.mask.ip.netmask[1], - relay->from.mask.ip.netmask[2], - relay->from.mask.ip.netmask[3]); - else - { - strncpy(name, relay->from.mask.name.name, sizeof(name) - 1); - name[sizeof(name) - 1] = '\0'; - } + /* + * Grab quoted name... + */ -#ifdef AF_INET6 - if (relay->to.addr.sa_family == AF_INET6) - LogMessage(L_INFO, "Relaying from %s to %s:%d", name, line, - ntohs(relay->to.ipv6.sin6_port)); - else -#endif /* AF_INET6 */ - LogMessage(L_INFO, "Relaying from %s to %s:%d", name, line, - ntohs(relay->to.ipv4.sin_port)); + for (valptr = value + 1; *valptr != *value && *valptr; valptr ++); - NumRelays ++; + value ++; } else { - if (relay->from.type == AUTH_NAME) - free(relay->from.mask.name.name); + /* + * Grab literal name. + */ - LogMessage(L_ERROR, "Bad relay address %s at line %d.", value, linenum); + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); } + + if (*valptr) + *valptr++ = '\0'; + + cupsdAddName(loc, value); + + for (value = valptr; isspace(*value & 255); value ++); } - else if (strcasecmp(name, "BrowsePoll") == 0) + } + else if (!strcasecmp(line, "Satisfy")) + { + if (!strcasecmp(value, "all")) + loc->satisfy = AUTH_SATISFY_ALL; + else if (!strcasecmp(value, "any")) + loc->satisfy = AUTH_SATISFY_ANY; + else { - /* - * BrowsePoll address[:port] - */ + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.", + value, linenum); + return (0); + } + } + else + return (0); - if (NumPolled == 0) - poll = malloc(sizeof(dirsvc_poll_t)); - else - poll = realloc(Polled, (NumPolled + 1) * sizeof(dirsvc_poll_t)); + return (1); +} - if (!poll) - { - LogMessage(L_ERROR, "Unable to allocate BrowsePoll at line %d - %s.", - linenum, strerror(errno)); - continue; - } - Polled = poll; - poll += NumPolled; +/* + * 'parse_groups()' - Parse system group names in a string. + */ - /* - * Get poll address and port... - */ +static int /* O - 1 on success, 0 on failure */ +parse_groups(const char *s) /* I - Space-delimited groups */ +{ + int status; /* Return status */ + char value[1024], /* Value string */ + *valstart, /* Pointer into value */ + *valend, /* End of value */ + quote; /* Quote character */ + struct group *group; /* Group */ - if (get_address(value, INADDR_NONE, ippPort(), AF_INET, &polladdr)) - { - NumPolled ++; - memset(poll, 0, sizeof(dirsvc_poll_t)); - httpAddrString(&polladdr, poll->hostname, sizeof(poll->hostname)); + /* + * Make a copy of the string and parse out the groups... + */ -#ifdef AF_INET6 - if (polladdr.addr.sa_family == AF_INET6) - poll->port = ntohs(polladdr.ipv6.sin6_port); - else -#endif /* AF_INET6 */ - poll->port = ntohs(polladdr.ipv4.sin_port); + strlcpy(value, s, sizeof(value)); - LogMessage(L_INFO, "Polling %s:%d", poll->hostname, poll->port); - } - else - LogMessage(L_ERROR, "Bad poll address %s at line %d.", value, linenum); - } - else if (strcasecmp(name, "User") == 0) + status = 1; + valstart = value; + + while (*valstart && NumSystemGroups < MAX_SYSTEM_GROUPS) + { + if (*valstart == '\'' || *valstart == '\"') { /* - * User ID to run as... + * Scan quoted name... */ - if (isdigit(value[0])) - User = atoi(value); - else - { - struct passwd *p; /* Password information */ + quote = *valstart++; - endpwent(); - p = getpwnam(value); - - if (p != NULL) - User = p->pw_uid; - else - LogMessage(L_WARN, "Unknown username \"%s\"", - value); - } + for (valend = valstart; *valend; valend ++) + if (*valend == quote) + break; } - else if (strcasecmp(name, "Group") == 0) + else { /* - * Group ID to run as... + * Scan space or comma-delimited name... */ - if (isdigit(value[0])) - Group = atoi(value); - else - { - struct group *g; /* Group information */ + for (valend = valstart; *valend; valend ++) + if (isspace(*valend) || *valend == ',') + break; + } - endgrent(); - g = getgrnam(value); + if (*valend) + *valend++ = '\0'; - if (g != NULL) - Group = g->gr_gid; - else - LogMessage(L_WARN, "Unknown groupname \"%s\"", - value); - } - } - else if (strcasecmp(name, "SystemGroup") == 0) + group = getgrnam(valstart); + if (group) { - /* - * System (admin) group(s)... - */ + cupsdSetString(SystemGroups + NumSystemGroups, valstart); + SystemGroupIDs[NumSystemGroups] = group->gr_gid; - char *valueptr, /* Pointer into value */ - quote; /* Quote character */ + NumSystemGroups ++; + } + else + status = 0; + endgrent(); - for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS; i ++) - { - if (*value == '\'' || *value == '\"') - { - /* - * Scan quoted name... - */ + valstart = valend; + + while (*valstart == ',' || isspace(*valstart)) + valstart ++; + } - quote = *value++; + return (status); +} - for (valueptr = value; *valueptr; valueptr ++) - if (*valueptr == quote) - break; - } - else - { - /* - * Scan space or comma-delimited name... - */ - for (valueptr = value; *valueptr; valueptr ++) - if (isspace(*valueptr) || *valueptr == ',') - break; - } +/* + * 'parse_protocols()' - Parse browse protocols in a string. + */ + +static int /* O - Browse protocol bits */ +parse_protocols(const char *s) /* I - Space-delimited protocols */ +{ + int protocols; /* Browse protocol bits */ + char value[1024], /* Value string */ + *valstart, /* Pointer into value */ + *valend; /* End of value */ - if (*valueptr) - *valueptr++ = '\0'; - SetString(SystemGroups + i, value); + /* + * Loop through the value string,... + */ - value = valueptr; + strlcpy(value, s, sizeof(value)); - while (*value == ',' || isspace(*value)) - value ++; - } + protocols = 0; - if (i) - NumSystemGroups = i; - } - else if (strcasecmp(name, "HostNameLookups") == 0) + for (valstart = value; *valstart;) + { + /* + * Get the current space/comma-delimited protocol name... + */ + + for (valend = valstart; *valend; valend ++) + if (isspace(*valend & 255) || *valend == ',') + break; + + if (*valend) + *valend++ = '\0'; + + /* + * Add the protocol to the bitmask... + */ + + if (!strcasecmp(valstart, "cups")) + protocols |= BROWSE_CUPS; + else if (!strcasecmp(valstart, "slp")) + protocols |= BROWSE_SLP; + else if (!strcasecmp(valstart, "ldap")) + protocols |= BROWSE_LDAP; + else if (!strcasecmp(valstart, "dnssd") || !strcasecmp(valstart, "bonjour")) + protocols |= BROWSE_DNSSD; + else if (!strcasecmp(valstart, "all")) + protocols |= BROWSE_ALL; + else + return (-1); + + for (valstart = valend; *valstart; valstart ++) + if (!isspace(*valstart & 255) || *valstart != ',') + break; + } + + return (protocols); +} + + +/* + * 'read_configuration()' - Read a configuration file. + */ + +static int /* O - 1 on success, 0 on failure */ +read_configuration(cups_file_t *fp) /* I - File to read from */ +{ + int i; /* Looping var */ + int linenum; /* Current line number */ + char line[HTTP_MAX_BUFFER], + /* Line from file */ + temp[HTTP_MAX_BUFFER], + /* Temporary buffer for value */ + temp2[HTTP_MAX_BUFFER], + /* Temporary buffer 2 for value */ + *ptr, /* Pointer into line/temp */ + *value, /* Pointer to value */ + *valueptr; /* Pointer into value */ + int valuelen; /* Length of value */ + cupsd_var_t *var; /* Current variable */ + http_addrlist_t *addrlist, /* Address list */ + *addr; /* Current address */ + unsigned ip[4], /* Address value */ + mask[4]; /* Netmask value */ + cupsd_dirsvc_relay_t *relay; /* Relay data */ + cupsd_dirsvc_poll_t *pollp; /* Polling data */ + cupsd_location_t *location; /* Browse location */ + cups_file_t *incfile; /* Include file */ + char incname[1024]; /* Include filename */ + struct group *group; /* Group */ + + + /* + * Loop through each line in the file... + */ + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, "Include")) { /* - * Do hostname lookups? + * Include filename */ - if (strcasecmp(value, "off") == 0) - HostNameLookups = 0; - else if (strcasecmp(value, "on") == 0) - HostNameLookups = 1; - else if (strcasecmp(value, "double") == 0) - HostNameLookups = 2; + if (value[0] == '/') + strlcpy(incname, value, sizeof(incname)); + else + snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value); + + if ((incfile = cupsFileOpen(incname, "rb")) == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to include config file \"%s\" - %s", + incname, strerror(errno)); else - LogMessage(L_WARN, "Unknown HostNameLookups %s on line %d.", - value, linenum); + { + read_configuration(incfile); + cupsFileClose(incfile); + } } - else if (strcasecmp(name, "LogLevel") == 0) + else if (!strcasecmp(line, " */ - 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; + if (value) + { + linenum = read_location(fp, value, linenum); + if (linenum == 0) + return (0); + } else - LogMessage(L_WARN, "Unknown LogLevel %s on line %d.", value, linenum); + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", + linenum); + return (0); + } } - else if (strcasecmp(name, "PrintcapFormat") == 0) + else if (!strcasecmp(line, " */ - if (strcasecmp(value, "bsd") == 0) - PrintcapFormat = PRINTCAP_BSD; - else if (strcasecmp(value, "solaris") == 0) - PrintcapFormat = PRINTCAP_SOLARIS; + if (value) + { + linenum = read_policy(fp, value, linenum); + if (linenum == 0) + return (0); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + } + else if (!strcasecmp(line, "FaxRetryInterval")) + { + if (value) + { + JobRetryInterval = atoi(value); + cupsdLogMessage(CUPSD_LOG_WARN, + "FaxRetryInterval is deprecated; use " + "JobRetryInterval on line %d.", linenum); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + } + else if (!strcasecmp(line, "FaxRetryLimit")) + { + if (value) + { + JobRetryLimit = atoi(value); + cupsdLogMessage(CUPSD_LOG_WARN, + "FaxRetryLimit is deprecated; use " + "JobRetryLimit on line %d.", linenum); + } else - LogMessage(L_WARN, "Unknown PrintcapFormat %s on line %d.", - value, linenum); + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } } - else if (!strcasecmp(name, "ServerTokens")) + else if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen") +#ifdef HAVE_SSL + || !strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen") +#endif /* HAVE_SSL */ + ) { /* - * Set the string used for the Server header... + * Add listening address(es) to the list... */ - struct utsname plat; /* Platform info */ - + cupsd_listener_t *lis; /* New listeners array */ - 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 - { /* - * Find a simple variable in the list... + * Get the address list... */ - for (i = NUM_VARS, var = variables; i > 0; i --, var ++) - if (strcasecmp(name, var->name) == 0) - break; + addrlist = get_address(value, IPP_PORT); - if (i == 0) + if (!addrlist) { - /* - * Unknown directive! Output an error message and continue... - */ - - LogMessage(L_ERROR, "Unknown directive %s on line %d.", name, - linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line, + value, linenum); continue; } - switch (var->type) - { - case VAR_INTEGER : - { - int n; /* Number */ - char *units; /* 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; + /* + * Add each address... + */ - case VAR_STRING : - SetString((char **)var->ptr, value); - break; - } - } - } + for (addr = addrlist; addr; addr = addr->next) + { + /* + * Allocate another listener... + */ - return (1); -} + if (!Listeners) + Listeners = cupsArrayNew(NULL, NULL); + if (!Listeners) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate %s at line %d - %s.", + line, linenum, strerror(errno)); + break; + } -/* - * 'read_location()' - Read a definition. - */ + if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate %s at line %d - %s.", + line, linenum, strerror(errno)); + break; + } -static int /* O - New line number or 0 on error */ -read_location(cups_file_t *fp, /* I - Configuration file */ - char *location, /* I - Location name/path */ - int linenum) /* I - Current line number */ -{ - int i; /* Looping var */ - location_t *loc, /* New location */ - *parent; /* Parent location */ - int len; /* Length of line */ - char line[HTTP_MAX_BUFFER], /* Line buffer */ - name[256], /* Configuration directive */ - *nameptr, /* Pointer into name */ - *value, /* Value for directive */ - *valptr; /* Pointer into value */ - unsigned ip[4], /* IP address components */ - mask[4]; /* IP netmask components */ + cupsArrayAdd(Listeners, lis); + /* + * Copy the current address and log it... + */ - if ((parent = AddLocation(location)) == NULL) - return (0); + memcpy(&(lis->address), &(addr->addr), sizeof(lis->address)); + lis->fd = -1; - parent->limit = AUTH_LIMIT_ALL; - loc = parent; +#ifdef HAVE_SSL + if (!strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen")) + lis->encryption = HTTP_ENCRYPT_ALWAYS; +#endif /* HAVE_SSL */ - while (cupsFileGets(fp, line, sizeof(line)) != NULL) - { - linenum ++; + httpAddrString(&lis->address, temp, sizeof(temp)); - /* - * Skip comment lines... - */ +#ifdef AF_INET6 + if (lis->address.addr.sa_family == AF_INET6) + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv6)", temp, + ntohs(lis->address.ipv6.sin6_port)); + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (lis->address.addr.sa_family == AF_LOCAL) + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp); + else +#endif /* AF_LOCAL */ + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp, + ntohs(lis->address.ipv4.sin_port)); + } - if (line[0] == '#') - continue; + /* + * Free the list... + */ - /* - * Strip trailing whitespace, if any... - */ + httpAddrFreeList(addrlist); + } + else if (!strcasecmp(line, "BrowseAddress")) + { + /* + * Add a browse address to the list... + */ - len = strlen(line); + cupsd_dirsvc_addr_t *dira; /* New browse address array */ - while (len > 0 && isspace(line[len - 1] & 255)) - { - len --; - line[len] = '\0'; - } - /* - * Extract the name from the beginning of the line... - */ + if (NumBrowsers == 0) + dira = malloc(sizeof(cupsd_dirsvc_addr_t)); + else + dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t)); - for (value = line; isspace(*value & 255); value ++); + if (!dira) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowseAddress at line %d - %s.", + linenum, strerror(errno)); + continue; + } - for (nameptr = name; *value != '\0' && !isspace(*value & 255) && - nameptr < (name + sizeof(name) - 1);) - *nameptr++ = *value++; - *nameptr = '\0'; + Browsers = dira; + dira += NumBrowsers; - while (isspace(*value & 255)) - value ++; + memset(dira, 0, sizeof(cupsd_dirsvc_addr_t)); - if (name[0] == '\0') - continue; + if (!strcasecmp(value, "@LOCAL")) + { + /* + * Send browse data to all local interfaces... + */ - /* - * Decode the directive... - */ + strcpy(dira->iface, "*"); + NumBrowsers ++; + } + else if (!strncasecmp(value, "@IF(", 4)) + { + /* + * Send browse data to the named interface... + */ - if (strcasecmp(name, "") == 0) - return (linenum); - else if (strcasecmp(name, "iface, value + 4, sizeof(Browsers[0].iface)); - loc->limit = 0; - while (*value) + ptr = dira->iface + strlen(dira->iface) - 1; + if (*ptr == ')') + *ptr = '\0'; + + NumBrowsers ++; + } + else if ((addrlist = get_address(value, BrowsePort)) != NULL) { - for (valptr = value; - !isspace(*valptr & 255) && *valptr != '>' && *valptr; - valptr ++); + /* + * Only IPv4 addresses are supported... + */ - if (*valptr) - *valptr++ = '\0'; + for (addr = addrlist; addr; addr = addr->next) + if (addr->addr.addr.sa_family == AF_INET) + break; - 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; + if (addr) + { + memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to)); + httpAddrString(&(dira->to), temp, sizeof(temp)); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Sending browsing info to %s:%d (IPv4)", + temp, ntohs(dira->to.ipv4.sin_port)); + + NumBrowsers ++; + } else - LogMessage(L_WARN, "Unknown request type %s on line %d!", value, - linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", + value, linenum); - for (value = valptr; isspace(*value & 255) || *value == '>'; value ++); + httpAddrFreeList(addrlist); } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", + value, linenum); + } + else if (!strcasecmp(line, "BrowseOrder")) + { + /* + * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"... + */ - if (strcasecmp(name, "limit = AUTH_LIMIT_ALL ^ loc->limit; + if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) + location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); - parent->limit &= ~loc->limit; + if (location == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to initialize browse access control list!"); + else if (!strncasecmp(value, "deny", 4)) + location->order_type = AUTH_ALLOW; + else if (!strncasecmp(value, "allow", 5)) + location->order_type = AUTH_DENY; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown BrowseOrder value %s on line %d.", + value, linenum); } - else if (strcasecmp(name, "") == 0) - loc = parent; - else if (strcasecmp(name, "Encryption") == 0) + else if (!strcasecmp(line, "BrowseProtocols") || + !strcasecmp(line, "BrowseLocalProtocols") || + !strcasecmp(line, "BrowseRemoteProtocols")) { /* - * "Encryption xxx" - set required encryption level... + * "BrowseProtocols name [... name]" + * "BrowseLocalProtocols name [... name]" + * "BrowseRemoteProtocols name [... name]" */ - 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); + int protocols = parse_protocols(value); - loc->encryption = HTTP_ENCRYPT_REQUIRED; + if (protocols < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown browse protocol \"%s\" on line %d.", + value, linenum); + break; } - 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); + + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols = protocols; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols = protocols; } - else if (strcasecmp(name, "Order") == 0) + else if (!strcasecmp(line, "BrowseAllow") || + !strcasecmp(line, "BrowseDeny")) { /* - * "Order Deny,Allow" or "Order Allow,Deny"... + * BrowseAllow [From] host/ip... + * BrowseDeny [From] host/ip... */ - if (strncasecmp(value, "deny", 4) == 0) - loc->order_type = AUTH_ALLOW; - else if (strncasecmp(value, "allow", 5) == 0) - loc->order_type = AUTH_DENY; + if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) + location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); + + if (location == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to initialize browse access control list!"); else - LogMessage(L_ERROR, "Unknown Order value %s on line %d.", - value, linenum); + { + if (!strncasecmp(value, "from ", 5)) + { + /* + * Strip leading "from"... + */ + + value += 5; + + while (isspace(*value)) + value ++; + } + + /* + * Figure out what form the allow/deny address takes: + * + * All + * None + * *.domain.com + * .domain.com + * host.domain.com + * nnn.* + * nnn.nnn.* + * nnn.nnn.nnn.* + * nnn.nnn.nnn.nnn + * nnn.nnn.nnn.nnn/mm + * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm + */ + + if (!strcasecmp(value, "all")) + { + /* + * All hosts... + */ + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, zeros, zeros); + else + cupsdDenyIP(location, zeros, zeros); + } + else if (!strcasecmp(value, "none")) + { + /* + * No hosts... + */ + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, ones, zeros); + else + cupsdDenyIP(location, ones, zeros); + } + else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0])) + { + /* + * Host or domain name... + */ + + if (value[0] == '*') + value ++; + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowHost(location, value); + else + cupsdDenyHost(location, value); + } + else + { + /* + * One of many IP address forms... + */ + + if (!get_addr_and_mask(value, ip, mask)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); + break; + } + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, ip, mask); + else + cupsdDenyIP(location, ip, mask); + } + } } - else if (strcasecmp(name, "Allow") == 0 || - strcasecmp(name, "Deny") == 0) + else if (!strcasecmp(line, "BrowseRelay")) { /* - * Allow [From] host/ip... - * Deny [From] host/ip... + * BrowseRelay [from] source [to] destination */ - if (strncasecmp(value, "from", 4) == 0) + if (NumRelays == 0) + relay = malloc(sizeof(cupsd_dirsvc_relay_t)); + else + relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t)); + + if (!relay) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowseRelay at line %d - %s.", + linenum, strerror(errno)); + continue; + } + + Relays = relay; + relay += NumRelays; + + memset(relay, 0, sizeof(cupsd_dirsvc_relay_t)); + + if (!strncasecmp(value, "from ", 5)) { /* * Strip leading "from"... */ - value += 4; + value += 5; - while (isspace(*value & 255)) + while (isspace(*value)) value ++; } /* - * Figure out what form the allow/deny address takes: + * Figure out what form the from address takes: * - * All - * None * *.domain.com * .domain.com * host.domain.com @@ -1993,29 +2475,7 @@ read_location(cups_file_t *fp, /* I - Configuration file */ * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm */ - if (strcasecmp(value, "all") == 0) - { - /* - * All hosts... - */ - - if (strcasecmp(name, "Allow") == 0) - AllowIP(loc, zeros, zeros); - else - DenyIP(loc, zeros, zeros); - } - else if (strcasecmp(value, "none") == 0) - { - /* - * No hosts... - */ - - if (strcasecmp(name, "Allow") == 0) - AllowIP(loc, ones, zeros); - else - DenyIP(loc, ones, zeros); - } - else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255)) + if (value[0] == '*' || value[0] == '.' || !isdigit(value[0])) { /* * Host or domain name... @@ -2024,10 +2484,13 @@ read_location(cups_file_t *fp, /* I - Configuration file */ if (value[0] == '*') value ++; - if (strcasecmp(name, "Allow") == 0) - AllowHost(loc, value); - else - DenyHost(loc, value); + strlcpy(temp, value, sizeof(temp)); + if ((ptr = strchr(temp, ' ')) != NULL) + *ptr = '\0'; + + relay->from.type = AUTH_NAME; + relay->from.mask.name.name = strdup(temp); + relay->from.mask.name.length = strlen(temp); } else { @@ -2037,880 +2500,740 @@ read_location(cups_file_t *fp, /* I - Configuration file */ if (!get_addr_and_mask(value, ip, mask)) { - LogMessage(L_ERROR, "Bad netmask value %s on line %d.", - value, linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); break; } - if (strcasecmp(name, "Allow") == 0) - AllowIP(loc, ip, mask); - else - DenyIP(loc, ip, mask); + relay->from.type = AUTH_IP; + memcpy(relay->from.mask.ip.address, ip, + sizeof(relay->from.mask.ip.address)); + memcpy(relay->from.mask.ip.netmask, mask, + sizeof(relay->from.mask.ip.netmask)); } - } - else if (strcasecmp(name, "AuthType") == 0) - { + /* - * AuthType {none,basic,digest,basicdigest} + * Skip value and trailing whitespace... */ - 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; + for (; *value; value ++) + if (isspace(*value)) + break; - 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) - { - /* - * AuthClass anonymous, user, system, group - */ + while (isspace(*value)) + value ++; - 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) + if (!strncasecmp(value, "to ", 3)) { - loc->level = AUTH_GROUP; - /* - * Use the default system group if none is defined so far... + * Strip leading "to"... */ - 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) - { - /* - * Apache synonym for AuthClass and AuthGroupName... - * - * Get initial word: - * - * Require valid-user - * Require group names - * Require user names - */ - - for (valptr = value; - !isspace(*valptr & 255) && *valptr != '>' && *valptr; - valptr ++); - - if (*valptr) - *valptr++ = '\0'; + value += 3; - 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; + while (isspace(*value)) + value ++; } /* - * Get the list of names from the line... + * Get "to" address and port... */ - for (value = valptr; *value;) + if ((addrlist = get_address(value, BrowsePort)) != NULL) { - while (isspace(*value & 255)) - value ++; - - if (*value == '\"' || *value == '\'') - { - /* - * Grab quoted name... - */ + /* + * Only IPv4 addresses are supported... + */ - for (valptr = value + 1; *valptr != *value && *valptr; valptr ++); + for (addr = addrlist; addr; addr = addr->next) + if (addr->addr.addr.sa_family == AF_INET) + break; - value ++; + if (addr) + { + memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to)); + + httpAddrString(&(relay->to), temp, sizeof(temp)); + + if (relay->from.type == AUTH_IP) + snprintf(temp2, sizeof(temp2), "%u.%u.%u.%u/%u.%u.%u.%u", + relay->from.mask.ip.address[0], + relay->from.mask.ip.address[1], + relay->from.mask.ip.address[2], + relay->from.mask.ip.address[3], + relay->from.mask.ip.netmask[0], + relay->from.mask.ip.netmask[1], + relay->from.mask.ip.netmask[2], + relay->from.mask.ip.netmask[3]); + else + strlcpy(temp2, relay->from.mask.name.name, sizeof(temp2)); + + cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)", + temp, temp2, ntohs(relay->to.ipv4.sin_port)); + + NumRelays ++; } else - { - /* - * Grab literal name. - */ - - for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); - } - - if (*valptr) - *valptr++ = '\0'; + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", + value, linenum); - AddName(loc, value); + httpAddrFreeList(addrlist); + } + else + { + if (relay->from.type == AUTH_NAME) + free(relay->from.mask.name.name); - for (value = valptr; isspace(*value & 255); value ++); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", + value, linenum); } } - else if (strcasecmp(name, "Satisfy") == 0) + else if (!strcasecmp(line, "BrowsePoll")) { - 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); - } - - LogMessage(L_ERROR, "Unexpected end-of-file at line %d while reading location!", - linenum); - - return (0); -} - - -/* - * 'read_policy()' - Read a definition. - */ + /* + * BrowsePoll address[:port] + */ -static int /* O - New line number or 0 on error */ -read_policy(cups_file_t *fp, /* I - Configuration file */ - char *policy, /* I - Location name/path */ - int linenum) /* I - Current line number */ -{ - int i; /* Looping var */ - policy_t *pol; /* Policy */ - policyop_t *op; /* Policy operation */ - int num_ops; /* Number of IPP operations */ - ipp_op_t ops[100]; /* Operations */ - int len; /* Length of line */ - char line[HTTP_MAX_BUFFER], /* Line buffer */ - name[256], /* Configuration directive */ - *nameptr, /* Pointer into name */ - *value, /* Value for directive */ - *valptr; /* Pointer into value */ + char *portname; /* Port name */ + int portnum; /* Port number */ + struct servent *service; /* Service */ - /* - * Create the policy... - */ + /* + * Extract the port name from the address... + */ - if ((pol = AddPolicy(policy)) == NULL) - return (0); + if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']')) + { + *portname++ = '\0'; - /* - * Read from the file... - */ + if (isdigit(*portname & 255)) + portnum = atoi(portname); + else if ((service = getservbyname(portname, NULL)) != NULL) + portnum = ntohs(service->s_port); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed!", + portname); + continue; + } + } + else + portnum = ippPort(); - op = NULL; - num_ops = 0; + /* + * Add the poll entry... + */ - while (cupsFileGets(fp, line, sizeof(line)) != NULL) - { - linenum ++; + if (NumPolled == 0) + pollp = malloc(sizeof(cupsd_dirsvc_poll_t)); + else + pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t)); - /* - * Skip comment lines... - */ + if (!pollp) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowsePoll at line %d - %s.", + linenum, strerror(errno)); + continue; + } - if (line[0] == '#') - continue; + Polled = pollp; + pollp += NumPolled; - /* - * Strip trailing whitespace, if any... - */ + NumPolled ++; + memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t)); - len = strlen(line); + strlcpy(pollp->hostname, value, sizeof(pollp->hostname)); + pollp->port = portnum; - while (len > 0 && isspace(line[len - 1] & 255)) - { - len --; - line[len] = '\0'; + cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname, + pollp->port); } - - /* - * Extract the name from the beginning of the line... - */ - - 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; - - /* - * Decode the directive... - */ - - if (!strcasecmp(name, "")) + else if (!strcasecmp(line, "DefaultAuthType")) { - if (op) - LogMessage(L_WARN, "Missing before on line %d!", - linenum); + /* + * DefaultAuthType {basic,digest,basicdigest} + */ - return (linenum); + if (!strcasecmp(value, "basic")) + DefaultAuthType = AUTH_BASIC; + else if (!strcasecmp(value, "digest")) + DefaultAuthType = AUTH_DIGEST; + else if (!strcasecmp(value, "basicdigest")) + DefaultAuthType = AUTH_BASICDIGEST; + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown default authorization type %s on line %d.", + value, linenum); + return (0); + } } - else if (!strcasecmp(name, "pw_uid) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Will not use User %s (UID=0) as specified on line " + "%d for security reasons. You must use a non-" + "privileged account instead.", + value, linenum); + else + User = p->pw_uid; } else - LogMessage(L_ERROR, "Too many operations listed on line %d!", - linenum); - - for (value = valptr; isspace(*value & 255) || *value == '>'; value ++); + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown User \"%s\" on line %d, ignoring!", + value, linenum); } - + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "User directive on line %d missing the username!", + linenum); + } + else if (!strcasecmp(line, "Group")) + { /* - * If none are specified, apply the policy to all operations... + * Group ID to run as... */ - if (num_ops == 0) + if (isdigit(value[0])) + Group = atoi(value); + else { - ops[0] = IPP_ANY_OPERATION; - num_ops = 1; - } + endgrent(); + group = getgrnam(value); + if (group != NULL) + Group = group->gr_gid; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Group \"%s\" on line %d, ignoring!", + value, linenum); + } + } + else if (!strcasecmp(line, "SystemGroup")) + { /* - * Add a new policy for the first operation... + * SystemGroup (admin) group(s)... */ - op = AddPolicyOp(pol, NULL, ops[0]); + if (!parse_groups(value)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown SystemGroup \"%s\" on line %d, ignoring!", + value, linenum); } - else if (!strcasecmp(name, "") && op) + else if (!strcasecmp(line, "HostNameLookups")) { /* - * Finish the current operation limit... + * Do hostname lookups? */ - if (num_ops > 1) - { - /* - * Copy the policy to the other operations... - */ + if (!strcasecmp(value, "off")) + HostNameLookups = 0; + else if (!strcasecmp(value, "on")) + HostNameLookups = 1; + else if (!strcasecmp(value, "double")) + HostNameLookups = 2; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "LogLevel")) + { + /* + * Amount of logging to do... + */ - for (i = 1; i < num_ops; i ++) - AddPolicyOp(pol, op, ops[i]); - } + if (!strcasecmp(value, "debug2")) + LogLevel = CUPSD_LOG_DEBUG2; + else if (!strcasecmp(value, "debug")) + LogLevel = CUPSD_LOG_DEBUG; + else if (!strcasecmp(value, "info")) + LogLevel = CUPSD_LOG_INFO; + else if (!strcasecmp(value, "notice")) + LogLevel = CUPSD_LOG_NOTICE; + else if (!strcasecmp(value, "warn")) + LogLevel = CUPSD_LOG_WARN; + else if (!strcasecmp(value, "error")) + LogLevel = CUPSD_LOG_ERROR; + else if (!strcasecmp(value, "crit")) + LogLevel = CUPSD_LOG_CRIT; + else if (!strcasecmp(value, "alert")) + LogLevel = CUPSD_LOG_ALERT; + else if (!strcasecmp(value, "emerg")) + LogLevel = CUPSD_LOG_EMERG; + else if (!strcasecmp(value, "none")) + LogLevel = CUPSD_LOG_NONE; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "PrintcapFormat")) + { + /* + * Format of printcap file? + */ - op = NULL; + if (!strcasecmp(value, "bsd")) + PrintcapFormat = PRINTCAP_BSD; + else if (!strcasecmp(value, "solaris")) + PrintcapFormat = PRINTCAP_SOLARIS; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.", + value, linenum); } - else if (!strcasecmp(name, "Authenticate") && op) + else if (!strcasecmp(line, "ServerTokens")) { /* - * Authenticate boolean + * Set the string used for the Server header... */ - if (!strcasecmp(value, "on") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "true")) - op->authenticate = 1; - else if (!strcasecmp(value, "off") || - !strcasecmp(value, "no") || - !strcasecmp(value, "false")) - op->authenticate = 0; + struct utsname plat; /* Platform info */ + + + uname(&plat); + + if (!strcasecmp(value, "ProductOnly")) + cupsdSetString(&ServerHeader, "CUPS"); + else if (!strcasecmp(value, "Major")) + cupsdSetString(&ServerHeader, "CUPS/1"); + else if (!strcasecmp(value, "Minor")) + cupsdSetString(&ServerHeader, "CUPS/1.2"); + else if (!strcasecmp(value, "Minimal")) + cupsdSetString(&ServerHeader, CUPS_MINIMAL); + else if (!strcasecmp(value, "OS")) + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname); + else if (!strcasecmp(value, "Full")) + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1", + plat.sysname); + else if (!strcasecmp(value, "None")) + cupsdClearString(&ServerHeader); else - LogMessage(L_ERROR, "Invalid Authenticate value \"%s\" on line %d!\n", - value, linenum); + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.", + value, linenum); } - else if (!strcasecmp(name, "Order") && op) + else if (!strcasecmp(line, "PassEnv")) { /* - * "Order Deny,Allow" or "Order Allow,Deny"... + * PassEnv variable [... variable] */ - if (!strncasecmp(value, "deny", 4)) - op->order_type = POLICY_ALLOW; - else if (!strncasecmp(value, "allow", 5)) - op->order_type = POLICY_DENY; + for (; *value;) + { + for (valuelen = 0; value[valuelen]; valuelen ++) + if (isspace(value[valuelen]) || value[valuelen] == ',') + break; + + if (value[valuelen]) + { + value[valuelen] = '\0'; + valuelen ++; + } + + cupsdSetEnv(value, NULL); + + for (value += valuelen; *value; value ++) + if (!isspace(*value) || *value != ',') + break; + } + } + else if (!strcasecmp(line, "SetEnv")) + { + /* + * SetEnv variable value + */ + + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + { + /* + * Found a value... + */ + + while (isspace(*valueptr & 255)) + *valueptr++ = '\0'; + + cupsdSetEnv(value, valueptr); + } else - LogMessage(L_ERROR, "Unknown Order value %s on line %d.", - value, linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing value for SetEnv directive on line %d.", + linenum); } - else if ((!strcasecmp(name, "Allow") || !strcasecmp(name, "Deny")) && op) + else { /* - * Allow name, @group, @OWNER - * Deny name, @group, @OWNER + * Find a simple variable in the list... */ - for (value = valptr; *value;) + for (i = NUM_VARS, var = variables; i > 0; i --, var ++) + if (!strcasecmp(line, var->name)) + break; + + if (i == 0) { - while (isspace(*value & 255)) - value ++; + /* + * Unknown directive! Output an error message and continue... + */ - if (*value == '\"' || *value == '\'') - { - /* - * Grab quoted name... - */ + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.", + line, linenum); + continue; + } - for (valptr = value + 1; *valptr != *value && *valptr; valptr ++); + switch (var->type) + { + case CUPSD_VARTYPE_INTEGER : + { + int n; /* Number */ + char *units; /* Units */ - value ++; - } - else - { - /* - * Grab literal name. - */ - for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); - } + n = strtol(value, &units, 0); - if (*valptr) - *valptr++ = '\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; - if (!strcasecmp(name, "Allow")) - AddPolicyOpName(op, POLICY_ALLOW, value); - else - AddPolicyOpName(op, POLICY_DENY, value); + case CUPSD_VARTYPE_BOOLEAN : + if (!strcasecmp(value, "true") || + !strcasecmp(value, "on") || + !strcasecmp(value, "enabled") || + !strcasecmp(value, "yes") || + atoi(value) != 0) + *((int *)var->ptr) = TRUE; + else if (!strcasecmp(value, "false") || + !strcasecmp(value, "off") || + !strcasecmp(value, "disabled") || + !strcasecmp(value, "no") || + !strcasecmp(value, "0")) + *((int *)var->ptr) = FALSE; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown boolean value %s on line %d.", + value, linenum); + break; - for (value = valptr; isspace(*value & 255); value ++); + case CUPSD_VARTYPE_STRING : + cupsdSetString((char **)var->ptr, value); + break; } } - else if (op) - LogMessage(L_ERROR, "Unknown Policy Limit directive %s on line %d.", - name, linenum); - else - LogMessage(L_ERROR, "Unknown Policy directive %s on line %d.", - name, linenum); } - LogMessage(L_ERROR, "Unexpected end-of-file at line %d while reading policy \"%s\"!", - linenum, policy); - - return (0); + return (1); } /* - * 'get_address()' - Get an address + port number from a line. + * 'read_location()' - Read a definition. */ -static int /* O - 1 if address good, 0 if bad */ -get_address(const char *value, /* I - Value string */ - unsigned defaddress, /* I - Default address */ - int defport, /* I - Default port */ - int deffamily, /* I - Default family */ - http_addr_t *address) /* O - Socket address */ +static int /* O - New line number or 0 on error */ +read_location(cups_file_t *fp, /* I - Configuration file */ + char *location, /* I - Location name/path */ + int linenum) /* I - Current line number */ { - char hostname[256], /* Hostname or IP */ - portname[256]; /* Port number or name */ - struct hostent *host; /* Host address */ - struct servent *port; /* Port number */ + cupsd_location_t *loc, /* New location */ + *parent; /* Parent location */ + char line[HTTP_MAX_BUFFER], + /* Line buffer */ + *value, /* Value for directive */ + *valptr; /* Pointer into value */ - /* - * Initialize the socket address to the defaults... - */ + if ((parent = cupsdAddLocation(location)) == NULL) + return (0); - memset(address, 0, sizeof(http_addr_t)); + parent->limit = AUTH_LIMIT_ALL; + loc = parent; -#ifdef AF_INET6 - if (deffamily == AF_INET6) - { - address->ipv6.sin6_family = AF_INET6; - address->ipv6.sin6_addr.s6_addr32[0] = htonl(defaddress); - address->ipv6.sin6_addr.s6_addr32[1] = htonl(defaddress); - address->ipv6.sin6_addr.s6_addr32[2] = htonl(defaddress); - address->ipv6.sin6_addr.s6_addr32[3] = htonl(defaddress); - address->ipv6.sin6_port = htons(defport); - } - else -#endif /* AF_INET6 */ + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { - address->ipv4.sin_family = AF_INET; - address->ipv4.sin_addr.s_addr = htonl(defaddress); - address->ipv4.sin_port = htons(defport); - } - -#ifdef AF_LOCAL - /* - * If the address starts with a "/", it is a domain socket... - */ + /* + * Decode the directive... + */ - if (*value == '/') - { - if (strlen(value) >= sizeof(address->un.sun_path)) + if (!strcasecmp(line, "")) + return (linenum); + else if (!strcasecmp(line, "un.sun_family = AF_LOCAL; - strcpy(address->un.sun_path, value); - - return (1); - } -#endif /* AF_LOCAL */ - - /* - * Try to grab a hostname and port number... - */ + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + + if ((loc = cupsdCopyLocation(&parent)) == NULL) + return (0); - switch (sscanf(value, "%255[^:]:%255s", hostname, portname)) - { - case 1 : - if (strchr(hostname, '.') == NULL && defaddress == INADDR_ANY) - { - /* - * Hostname is a port number... - */ + loc->limit = 0; + while (*value) + { + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); - strlcpy(portname, hostname, sizeof(portname)); - hostname[0] = '\0'; - } - else - portname[0] = '\0'; - break; + if (*valptr) + *valptr++ = '\0'; - case 2 : - break; + if (!strcmp(value, "ALL")) + loc->limit = AUTH_LIMIT_ALL; + else if (!strcmp(value, "GET")) + loc->limit |= AUTH_LIMIT_GET; + else if (!strcmp(value, "HEAD")) + loc->limit |= AUTH_LIMIT_HEAD; + else if (!strcmp(value, "OPTIONS")) + loc->limit |= AUTH_LIMIT_OPTIONS; + else if (!strcmp(value, "POST")) + loc->limit |= AUTH_LIMIT_POST; + else if (!strcmp(value, "PUT")) + loc->limit |= AUTH_LIMIT_PUT; + else if (!strcmp(value, "TRACE")) + loc->limit |= AUTH_LIMIT_TRACE; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d!", + value, linenum); - default : - LogMessage(L_ERROR, "Unable to decode address \"%s\"!", value); - return (0); - } + for (value = valptr; isspace(*value & 255); value ++); + } - /* - * Decode the hostname and port number as needed... - */ + if (!strcasecmp(line, "limit = AUTH_LIMIT_ALL ^ loc->limit; - if (hostname[0] && strcmp(hostname, "*")) - { - if ((host = httpGetHostByName(hostname)) == NULL) + parent->limit &= ~loc->limit; + } + else if (!strcasecmp(line, "")) + loc = parent; + else if (!parse_aaa(loc, line, value, linenum)) { - LogMessage(L_ERROR, "httpGetHostByName(\"%s\") failed - %s!", hostname, - hstrerror(h_errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Location directive %s on line %d.", + line, linenum); return (0); } - - httpAddrLoad(host, defport, 0, address); } - if (portname[0] != '\0') - { - if (isdigit(portname[0] & 255)) - { -#ifdef AF_INET6 - if (address->addr.sa_family == AF_INET6) - address->ipv6.sin6_port = htons(atoi(portname)); - else -#endif /* AF_INET6 */ - address->ipv4.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 - { -#ifdef AF_INET6 - if (address->addr.sa_family == AF_INET6) - address->ipv6.sin6_port = htons(port->s_port); - else -#endif /* AF_INET6 */ - address->ipv4.sin_port = htons(port->s_port); - } - } - } + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unexpected end-of-file at line %d while reading location!", + linenum); - return (1); + return (0); } /* - * 'get_addr_and_mask()' - Get an IP address and netmask. + * 'read_policy()' - Read a definition. */ -static int /* O - 1 on success, 0 on failure */ -get_addr_and_mask(const char *value, /* I - String from config file */ - unsigned *ip, /* O - Address value */ - unsigned *mask) /* O - Mask value */ +static int /* O - New line number or 0 on error */ +read_policy(cups_file_t *fp, /* I - Configuration file */ + char *policy, /* I - Location name/path */ + int linenum) /* I - Current line number */ { - int i, /* Looping var */ - family, /* Address family */ - ipcount; /* Count of fields in address */ - static unsigned netmasks[4][4] = /* Standard netmasks... */ - { - { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, - { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 }, - { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 }, - { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } - }; + int i; /* Looping var */ + cupsd_policy_t *pol; /* Policy */ + cupsd_location_t *op; /* Policy operation */ + int num_ops; /* Number of IPP operations */ + ipp_op_t ops[100]; /* Operations */ + char line[HTTP_MAX_BUFFER], + /* Line buffer */ + *value, /* Value for directive */ + *valptr; /* Pointer into value */ /* - * Get the address... + * Create the policy... */ - memset(ip, 0, sizeof(unsigned) * 4); - family = AF_INET; - ipcount = sscanf(value, "%u.%u.%u.%u", ip + 0, ip + 1, ip + 2, ip + 3); + if ((pol = cupsdAddPolicy(policy)) == NULL) + return (0); -#ifdef AF_INET6 /* - * See if we have any values > 255; if so, this is an IPv6 address only. + * Read from the file... */ - for (i = 0; i < ipcount; i ++) - if (ip[0] > 255) - { - family = AF_INET6; - break; - } -#endif /* AF_INET6 */ + op = NULL; + num_ops = 0; - if ((value = strchr(value, '/')) != NULL) + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) { /* - * Get the netmask value(s)... + * Decode the directive... */ - value ++; - memset(mask, 0, sizeof(unsigned) * 4); - switch (sscanf(value, "%u.%u.%u.%u", mask + 0, mask + 1, - mask + 2, mask + 3)) + if (!strcasecmp(line, "")) { - case 1 : -#ifdef AF_INET6 - if (mask[0] >= 32) - family = AF_INET6; - - if (family == AF_INET6) - { - i = 128 - mask[0]; - - if (i <= 96) - mask[0] = 0xffffffff; - else - mask[0] = (0xffffffff << (128 - mask[0])) & 0xffffffff; - - if (i <= 64) - mask[1] = 0xffffffff; - else if (i >= 96) - mask[1] = 0; - else - mask[1] = (0xffffffff << (96 - mask[0])) & 0xffffffff; - - if (i <= 32) - mask[1] = 0xffffffff; - else if (i >= 64) - mask[1] = 0; - else - mask[1] = (0xffffffff << (64 - mask[0])) & 0xffffffff; - - if (i >= 32) - mask[1] = 0; - else - mask[1] = (0xffffffff << (32 - mask[0])) & 0xffffffff; - } - else -#endif /* AF_INET6 */ - { - i = 32 - mask[0]; - - if (i <= 24) - mask[0] = 0xffffffff; - else - mask[0] = (0xffffffff << (32 - mask[0])) & 0xffffffff; - - if (i <= 16) - mask[1] = 0xffffffff; - else if (i >= 24) - mask[1] = 0; - else - mask[1] = (0xffffffff << (24 - mask[0])) & 0xffffffff; - - if (i <= 8) - mask[1] = 0xffffffff; - else if (i >= 16) - mask[1] = 0; - else - mask[1] = (0xffffffff << (16 - mask[0])) & 0xffffffff; - - if (i >= 8) - mask[1] = 0; - else - mask[1] = (0xffffffff << (8 - mask[0])) & 0xffffffff; - } - - case 4 : - break; + if (op) + cupsdLogMessage(CUPSD_LOG_WARN, + "Missing before on line %d!", + linenum); - default : - return (0); + return (linenum); } - } - else - memcpy(mask, netmasks[ipcount - 1], sizeof(unsigned) * 4); - - /* - * Check for a valid netmask; no fallback like in CUPS 1.1.x! - */ - - if ((ip[0] & ~mask[0]) != 0 || - (ip[1] & ~mask[1]) != 0 || - (ip[2] & ~mask[2]) != 0 || - (ip[3] & ~mask[3]) != 0) - return (0); + else if (!strcasecmp(line, "") && op) { - err = SecIdentitySearchCopyNext(srchRef, &identity); + /* + * Finish the current operation limit... + */ - if (err) - LogMessage(L_ERROR, - "Cannot find signing key in keychain \"%s\", error %d", - ServerCertificate, err); - else + if (num_ops > 1) { - if (CFGetTypeID(identity) != SecIdentityGetTypeID()) - LogMessage(L_ERROR, "SecIdentitySearchCopyNext CFTypeID failure!"); - else - { - /* - * Found one. Place it in a CFArray. - * TBD: snag other (non-identity) certs from keychain and add them - * to array as well. - */ - - ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL); - - if (ca == nil) - LogMessage(L_ERROR, "CFArrayCreate error"); - } + /* + * Copy the policy to the other operations... + */ - /*CFRelease(identity);*/ + for (i = 1; i < num_ops; i ++) + cupsdAddPolicyOp(pol, op, ops[i]); } - /*CFRelease(srchRef);*/ + op = NULL; + } + else if (!op) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing directive before %s on line %d.", + line, linenum); + return (0); } + else if (!parse_aaa(op, line, value, linenum)) + { + if (op) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Policy Limit directive %s on line %d.", + line, linenum); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Policy directive %s on line %d.", + line, linenum); - /*CFRelease(kcRef);*/ + return (0); + } } - return ca; + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unexpected end-of-file at line %d while reading policy \"%s\"!", + linenum, policy); + + return (0); } -#endif /* HAVE_CDSASSL */ /*