]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/conf.c
Full sweep of all Clang warnings, plus some bug fixes for incorrect memcpy usage.
[thirdparty/cups.git] / scheduler / conf.c
index de9d80c0ef8029220ce85a83b2220581db18b714..ebd065b769a09e5b3329210a45f627fedc976822 100644 (file)
@@ -1,37 +1,16 @@
 /*
- * "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $"
+ * "$Id$"
  *
- *   Configuration routines for the CUPS scheduler.
+ * Configuration routines for the CUPS scheduler.
  *
- *   Copyright 2007-2012 by Apple Inc.
- *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2013 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- *   which should have been included with this file.  If this file is
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * Contents:
- *
- *   cupsdAddAlias()          - Add a host alias.
- *   cupsdCheckPermissions()  - Fix the mode and ownership of a file or
- *                              directory.
- *   cupsdDefaultAuthType()   - Get the default AuthType.
- *   cupsdFreeAliases()       - Free all of the alias entries.
- *   cupsdReadConfiguration() - Read the cupsd.conf file.
- *   get_address()            - Get an address + port number from a line.
- *   get_addr_and_mask()      - Get an IP address and netmask.
- *   mime_error_cb()          - Log a MIME error.
- *   parse_aaa()              - Parse authentication, authorization, and access
- *                              control lines.
- *   parse_fatal_errors()     - Parse FatalErrors values in a string.
- *   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 <Location path> definition.
- *   read_policy()            - Read a <Policy name> definition.
- *   set_policy_defaults()    - Set default policy values as needed.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file.  If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
 typedef enum
 {
   CUPSD_VARTYPE_INTEGER,               /* Integer option */
+  CUPSD_VARTYPE_TIME,                  /* Time interval option */
   CUPSD_VARTYPE_STRING,                        /* String option */
   CUPSD_VARTYPE_BOOLEAN,               /* Boolean option */
-  CUPSD_VARTYPE_PATHNAME               /* File/directory name option */
+  CUPSD_VARTYPE_PATHNAME,              /* File/directory name option */
+  CUPSD_VARTYPE_PERM                   /* File/directory permissions */
 } cupsd_vartype_t;
 
 typedef struct
@@ -82,101 +63,101 @@ typedef struct
  * Local globals...
  */
 
-static int                     default_auth_type       = CUPSD_AUTH_AUTO;
-                                       /* Default AuthType, if not specified */
-static const cupsd_var_t       variables[] =
+static const cupsd_var_t       cupsd_vars[] =
 {
-  { "AccessLog",               &AccessLog,             CUPSD_VARTYPE_STRING },
   { "AutoPurgeJobs",           &JobAutoPurge,          CUPSD_VARTYPE_BOOLEAN },
-#ifdef HAVE_DNSSD
-  { "BrowseDNSSDRegType",      &DNSSDRegType,          CUPSD_VARTYPE_STRING },
-#endif /* HAVE_DNSSD */
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+  { "BrowseDNSSDSubTypes",     &DNSSDSubTypes,         CUPSD_VARTYPE_STRING },
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
   { "BrowseWebIF",             &BrowseWebIF,           CUPSD_VARTYPE_BOOLEAN },
   { "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 },
   { "DefaultLanguage",         &DefaultLanguage,       CUPSD_VARTYPE_STRING },
-  { "DefaultLeaseDuration",    &DefaultLeaseDuration,  CUPSD_VARTYPE_INTEGER },
+  { "DefaultLeaseDuration",    &DefaultLeaseDuration,  CUPSD_VARTYPE_TIME },
   { "DefaultPaperSize",                &DefaultPaperSize,      CUPSD_VARTYPE_STRING },
   { "DefaultPolicy",           &DefaultPolicy,         CUPSD_VARTYPE_STRING },
   { "DefaultShared",           &DefaultShared,         CUPSD_VARTYPE_BOOLEAN },
-  { "DirtyCleanInterval",      &DirtyCleanInterval,    CUPSD_VARTYPE_INTEGER },
-  { "DocumentRoot",            &DocumentRoot,          CUPSD_VARTYPE_STRING },
-  { "ErrorLog",                        &ErrorLog,              CUPSD_VARTYPE_STRING },
+  { "DirtyCleanInterval",      &DirtyCleanInterval,    CUPSD_VARTYPE_TIME },
   { "ErrorPolicy",             &ErrorPolicy,           CUPSD_VARTYPE_STRING },
-  { "FileDevice",              &FileDevice,            CUPSD_VARTYPE_BOOLEAN },
   { "FilterLimit",             &FilterLimit,           CUPSD_VARTYPE_INTEGER },
   { "FilterNice",              &FilterNice,            CUPSD_VARTYPE_INTEGER },
-  { "FontPath",                        &FontPath,              CUPSD_VARTYPE_STRING },
 #ifdef HAVE_GSSAPI
   { "GSSServiceName",          &GSSServiceName,        CUPSD_VARTYPE_STRING },
 #endif /* HAVE_GSSAPI */
-  { "JobKillDelay",            &JobKillDelay,          CUPSD_VARTYPE_INTEGER },
+  { "JobKillDelay",            &JobKillDelay,          CUPSD_VARTYPE_TIME },
   { "JobRetryLimit",           &JobRetryLimit,         CUPSD_VARTYPE_INTEGER },
-  { "JobRetryInterval",                &JobRetryInterval,      CUPSD_VARTYPE_INTEGER },
-  { "KeepAliveTimeout",                &KeepAliveTimeout,      CUPSD_VARTYPE_INTEGER },
+  { "JobRetryInterval",                &JobRetryInterval,      CUPSD_VARTYPE_TIME },
+  { "KeepAliveTimeout",                &KeepAliveTimeout,      CUPSD_VARTYPE_TIME },
   { "KeepAlive",               &KeepAlive,             CUPSD_VARTYPE_BOOLEAN },
 #ifdef HAVE_LAUNCHD
-  { "LaunchdTimeout",          &LaunchdTimeout,        CUPSD_VARTYPE_INTEGER },
+  { "LaunchdTimeout",          &LaunchdTimeout,        CUPSD_VARTYPE_TIME },
 #endif /* HAVE_LAUNCHD */
   { "LimitRequestBody",                &MaxRequestSize,        CUPSD_VARTYPE_INTEGER },
   { "ListenBackLog",           &ListenBackLog,         CUPSD_VARTYPE_INTEGER },
   { "LogDebugHistory",         &LogDebugHistory,       CUPSD_VARTYPE_INTEGER },
-  { "LogFilePerm",             &LogFilePerm,           CUPSD_VARTYPE_INTEGER },
-  { "LPDConfigFile",           &LPDConfigFile,         CUPSD_VARTYPE_STRING },
   { "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 },
-  { "MaxHoldTime",             &MaxHoldTime,           CUPSD_VARTYPE_INTEGER },
+  { "MaxHoldTime",             &MaxHoldTime,           CUPSD_VARTYPE_TIME },
   { "MaxJobs",                 &MaxJobs,               CUPSD_VARTYPE_INTEGER },
   { "MaxJobsPerPrinter",       &MaxJobsPerPrinter,     CUPSD_VARTYPE_INTEGER },
   { "MaxJobsPerUser",          &MaxJobsPerUser,        CUPSD_VARTYPE_INTEGER },
   { "MaxJobTime",              &MaxJobTime,            CUPSD_VARTYPE_INTEGER },
-  { "MaxLeaseDuration",                &MaxLeaseDuration,      CUPSD_VARTYPE_INTEGER },
+  { "MaxLeaseDuration",                &MaxLeaseDuration,      CUPSD_VARTYPE_TIME },
   { "MaxLogSize",              &MaxLogSize,            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 },
-  { "MultipleOperationTimeout",        &MultipleOperationTimeout,      CUPSD_VARTYPE_INTEGER },
-  { "PageLog",                 &PageLog,               CUPSD_VARTYPE_STRING },
+  { "MultipleOperationTimeout",        &MultipleOperationTimeout,      CUPSD_VARTYPE_TIME },
   { "PageLogFormat",           &PageLogFormat,         CUPSD_VARTYPE_STRING },
-  { "PreserveJobFiles",                &JobFiles,              CUPSD_VARTYPE_BOOLEAN },
-  { "PreserveJobHistory",      &JobHistory,            CUPSD_VARTYPE_BOOLEAN },
+  { "PreserveJobFiles",                &JobFiles,              CUPSD_VARTYPE_TIME },
+  { "PreserveJobHistory",      &JobHistory,            CUPSD_VARTYPE_TIME },
+  { "ReloadTimeout",           &ReloadTimeout,         CUPSD_VARTYPE_TIME },
+  { "RIPCache",                        &RIPCache,              CUPSD_VARTYPE_STRING },
+  { "RootCertDuration",                &RootCertDuration,      CUPSD_VARTYPE_TIME },
+  { "ServerAdmin",             &ServerAdmin,           CUPSD_VARTYPE_STRING },
+  { "ServerName",              &ServerName,            CUPSD_VARTYPE_STRING },
+  { "StrictConformance",       &StrictConformance,     CUPSD_VARTYPE_BOOLEAN },
+  { "Timeout",                 &Timeout,               CUPSD_VARTYPE_TIME },
+  { "WebInterface",            &WebInterface,          CUPSD_VARTYPE_BOOLEAN }
+};
+static const cupsd_var_t       cupsfiles_vars[] =
+{
+  { "AccessLog",               &AccessLog,             CUPSD_VARTYPE_STRING },
+  { "CacheDir",                        &CacheDir,              CUPSD_VARTYPE_STRING },
+  { "ConfigFilePerm",          &ConfigFilePerm,        CUPSD_VARTYPE_PERM },
+  { "DataDir",                 &DataDir,               CUPSD_VARTYPE_STRING },
+  { "DocumentRoot",            &DocumentRoot,          CUPSD_VARTYPE_STRING },
+  { "ErrorLog",                        &ErrorLog,              CUPSD_VARTYPE_STRING },
+  { "FileDevice",              &FileDevice,            CUPSD_VARTYPE_BOOLEAN },
+  { "FontPath",                        &FontPath,              CUPSD_VARTYPE_STRING },
+  { "LogFilePerm",             &LogFilePerm,           CUPSD_VARTYPE_PERM },
+  { "LPDConfigFile",           &LPDConfigFile,         CUPSD_VARTYPE_STRING },
+  { "PageLog",                 &PageLog,               CUPSD_VARTYPE_STRING },
   { "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_PATHNAME },
 #ifdef HAVE_SSL
-  { "ServerCertificate",       &ServerCertificate,     CUPSD_VARTYPE_PATHNAME },
-#  if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
-  { "ServerKey",               &ServerKey,             CUPSD_VARTYPE_PATHNAME },
-#  endif /* HAVE_LIBSSL || HAVE_GNUTLS */
+  { "ServerKeychain",          &ServerKeychain,        CUPSD_VARTYPE_PATHNAME },
 #endif /* HAVE_SSL */
-  { "ServerName",              &ServerName,            CUPSD_VARTYPE_STRING },
   { "ServerRoot",              &ServerRoot,            CUPSD_VARTYPE_PATHNAME },
   { "SMBConfigFile",           &SMBConfigFile,         CUPSD_VARTYPE_STRING },
   { "StateDir",                        &StateDir,              CUPSD_VARTYPE_STRING },
+  { "SyncOnClose",             &SyncOnClose,           CUPSD_VARTYPE_BOOLEAN },
 #ifdef HAVE_AUTHORIZATION_H
   { "SystemGroupAuthKey",      &SystemGroupAuthKey,    CUPSD_VARTYPE_STRING },
 #endif /* HAVE_AUTHORIZATION_H */
-  { "TempDir",                 &TempDir,               CUPSD_VARTYPE_PATHNAME },
-  { "Timeout",                 &Timeout,               CUPSD_VARTYPE_INTEGER },
-  { "WebInterface",            &WebInterface,          CUPSD_VARTYPE_BOOLEAN }
+  { "TempDir",                 &TempDir,               CUPSD_VARTYPE_PATHNAME }
 };
-#define NUM_VARS       (sizeof(variables) / sizeof(variables[0]))
 
+static int             default_auth_type = CUPSD_AUTH_AUTO;
+                                       /* Default AuthType, if not specified */
 
 static const unsigned  ones[4] =
                        {
@@ -201,7 +182,12 @@ static int         parse_aaa(cupsd_location_t *loc, char *line,
 static int             parse_fatal_errors(const char *s);
 static int             parse_groups(const char *s);
 static int             parse_protocols(const char *s);
-static int             read_configuration(cups_file_t *fp);
+static int             parse_variable(const char *filename, int linenum,
+                                      const char *line, const char *value,
+                                      size_t num_vars,
+                                      const cupsd_var_t *vars);
+static int             read_cupsd_conf(cups_file_t *fp);
+static int             read_cups_files_conf(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 void            set_policy_defaults(cupsd_policy_t *pol);
@@ -225,7 +211,7 @@ cupsdAddAlias(cups_array_t *aliases,        /* I - Array of aliases */
     return;
 
   a->namelen = namelen;
-  strcpy(a->name, name);               /* OK since a->name is allocated */
+  memcpy(a->name, name, namelen + 1);  /* OK since a->name is allocated */
 
   cupsArrayAdd(aliases, a);
 }
@@ -239,9 +225,9 @@ int                                 /* O - 0 on success, -1 on error, 1 on warning */
 cupsdCheckPermissions(
     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 */
+    mode_t     mode,                   /* I - Permissions */
+    uid_t      user,                   /* I - Owner */
+    gid_t      group,                  /* I - Group */
     int        is_dir,                 /* I - 1 = directory, 0 = file */
     int        create_dir)             /* I - 1 = create directory, -1 = create w/o logging, 0 = not */
 {
@@ -578,10 +564,9 @@ cupsdReadConfiguration(void)
                  "%p %u %j %T %P %C %{job-billing} "
                 "%{job-originating-host-name} %{job-name} %{media} %{sides}");
   cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
-  cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
   cupsdSetString(&FontPath, CUPS_FONTPATH);
   cupsdSetString(&RemoteRoot, "remroot");
-  cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR,
+  cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR,
                   CUPS_VERSION_MINOR);
   cupsdSetString(&StateDir, CUPS_STATEDIR);
 
@@ -603,12 +588,11 @@ cupsdReadConfiguration(void)
   ClassifyOverride  = 0;
 
 #ifdef HAVE_SSL
-#  ifdef HAVE_CDSASSL
-  cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain");
+#  ifdef HAVE_GNUTLS
+  cupsdSetString(&ServerKeychain, "ssl");
 #  else
-  cupsdSetString(&ServerCertificate, "ssl/server.crt");
-  cupsdSetString(&ServerKey, "ssl/server.key");
-#  endif /* HAVE_CDSASSL */
+  cupsdSetString(&ServerKeychain, "/Library/Keychains/System.keychain");
+#  endif /* HAVE_GNUTLS */
 #endif /* HAVE_SSL */
 
   language = cupsLangDefault();
@@ -695,10 +679,9 @@ cupsdReadConfiguration(void)
   AccessLogLevel           = CUPSD_ACCESSLOG_ACTIONS;
   ConfigFilePerm           = CUPS_DEFAULT_CONFIG_FILE_PERM;
   FatalErrors              = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS);
-  default_auth_type          = CUPSD_AUTH_BASIC;
+  default_auth_type        = CUPSD_AUTH_BASIC;
 #ifdef HAVE_SSL
   DefaultEncryption        = HTTP_ENCRYPT_REQUIRED;
-  SSLOptions               = CUPSD_SSL_NONE;
 #endif /* HAVE_SSL */
   DirtyCleanInterval       = DEFAULT_KEEPALIVE;
   JobKillDelay             = DEFAULT_TIMEOUT;
@@ -721,10 +704,12 @@ cupsdReadConfiguration(void)
   MaxLogSize               = 1024 * 1024;
   MaxRequestSize           = 0;
   MultipleOperationTimeout = DEFAULT_TIMEOUT;
+  NumSystemGroups          = 0;
   ReloadTimeout                   = DEFAULT_KEEPALIVE;
   RootCertDuration         = 300;
+  StrictConformance        = FALSE;
+  SyncOnClose              = FALSE;
   Timeout                  = DEFAULT_TIMEOUT;
-  NumSystemGroups          = 0;
   WebInterface             = CUPS_DEFAULT_WEBIF;
 
   BrowseLocalProtocols     = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS);
@@ -732,9 +717,9 @@ cupsdReadConfiguration(void)
   Browsing                 = CUPS_DEFAULT_BROWSING;
   DefaultShared            = CUPS_DEFAULT_DEFAULT_SHARED;
 
-#ifdef HAVE_DNSSD
-  cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups");
-#endif /* HAVE_DNSSD */
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+  cupsdSetString(&DNSSDSubTypes, "_cups,_print");
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   cupsdSetString(&LPDConfigFile, CUPS_DEFAULT_LPD_CONFIG_FILE);
   cupsdSetString(&SMBConfigFile, CUPS_DEFAULT_SMB_CONFIG_FILE);
@@ -756,7 +741,7 @@ cupsdReadConfiguration(void)
   cupsdClearString(&DefaultPolicy);
 
 #ifdef HAVE_AUTHORIZATION_H
-  cupsdClearString(&SystemGroupAuthKey);
+  cupsdSetString(&SystemGroupAuthKey, CUPS_DEFAULT_SYSTEM_AUTHKEY);
 #endif /* HAVE_AUTHORIZATION_H */
 
   MaxSubscriptions           = 100;
@@ -777,21 +762,63 @@ cupsdReadConfiguration(void)
   cupsdInitEnv();
 
  /*
-  * Read the configuration file...
+  * Read the cups-files.conf file...
+  */
+
+  if ((fp = cupsFileOpen(CupsFilesFile, "r")) != NULL)
+  {
+    status = read_cups_files_conf(fp);
+
+    cupsFileClose(fp);
+
+    if (!status)
+    {
+      if (TestConfigFile)
+        printf("\"%s\" contains errors.\n", CupsFilesFile);
+      else
+        syslog(LOG_LPR, "Unable to read \"%s\" due to errors.",
+               CupsFilesFile);
+
+      return (0);
+    }
+  }
+  else if (errno == ENOENT)
+    cupsdLogMessage(CUPSD_LOG_INFO, "No %s, using defaults.", CupsFilesFile);
+  else
+  {
+    syslog(LOG_LPR, "Unable to open \"%s\": %s", CupsFilesFile,
+          strerror(errno));
+    return (0);
+  }
+
+  if (!ErrorLog)
+    cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
+
+ /*
+  * Read the cupsd.conf file...
   */
 
   if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
+  {
+    syslog(LOG_LPR, "Unable to open \"%s\": %s", ConfigurationFile,
+          strerror(errno));
     return (0);
+  }
 
-  status = read_configuration(fp);
+  status = read_cupsd_conf(fp);
 
   cupsFileClose(fp);
 
   if (!status)
-    return (0);
+  {
+    if (TestConfigFile)
+      printf("\"%s\" contains errors.\n", ConfigurationFile);
+    else
+      syslog(LOG_LPR, "Unable to read \"%s\" due to errors.",
+            ConfigurationFile);
 
-  if (!ErrorLog)
-    cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
+    return (0);
+  }
 
   RunUser = getuid();
 
@@ -904,6 +931,13 @@ cupsdReadConfiguration(void)
     }
   }
 
+ /*
+  * Make sure ConfigFilePerm and LogFilePerm have sane values...
+  */
+
+  ConfigFilePerm &= 0664;
+  LogFilePerm    &= 0664;
+
  /*
   * Open the system log for cupsd if necessary...
   */
@@ -1022,24 +1056,11 @@ cupsdReadConfiguration(void)
     cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
 
 #ifdef HAVE_SSL
-  if (ServerCertificate[0] != '/')
-    cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
+  if (ServerKeychain[0] != '/')
+    cupsdSetStringf(&ServerKeychain, "%s/%s", ServerRoot, ServerKeychain);
 
-  if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot)) &&
-      cupsdCheckPermissions(ServerCertificate, NULL, 0600, RunUser, Group,
-                            0, 0) < 0 &&
-      (FatalErrors & CUPSD_FATAL_PERMISSIONS))
-    return (0);
-
-#  if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
-  if (ServerKey[0] != '/')
-    cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
-
-  if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot)) &&
-      cupsdCheckPermissions(ServerKey, NULL, 0600, RunUser, Group, 0, 0) < 0 &&
-      (FatalErrors & CUPSD_FATAL_PERMISSIONS))
-    return (0);
-#  endif /* HAVE_LIBSSL || HAVE_GNUTLS */
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Using keychain \"%s\" for server name \"%s\".", ServerKeychain, ServerName);
+  cupsSetServerCredentials(ServerKeychain, ServerName, 1);
 #endif /* HAVE_SSL */
 
  /*
@@ -1065,7 +1086,9 @@ cupsdReadConfiguration(void)
                             Group, 1, 1) < 0 ||
        cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser,
                             Group, 1, 0) < 0 ||
-       cupsdCheckPermissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser,
+       cupsdCheckPermissions(ConfigurationFile, NULL, ConfigFilePerm, RunUser,
+                            Group, 0, 0) < 0 ||
+       cupsdCheckPermissions(CupsFilesFile, NULL, ConfigFilePerm, RunUser,
                             Group, 0, 0) < 0 ||
        cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser,
                             Group, 0, 0) < 0 ||
@@ -1080,11 +1103,20 @@ cupsdReadConfiguration(void)
   * Update TempDir to the default if it hasn't been set already...
   */
 
+#ifdef __APPLE__
+  if (TempDir && !RunUser &&
+      (!strncmp(TempDir, "/private/tmp", 12) || !strncmp(TempDir, "/tmp", 4)))
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot use %s for TempDir.", TempDir);
+    cupsdClearString(&TempDir);
+  }
+#endif /* __APPLE__ */
+
   if (!TempDir)
   {
 #ifdef __APPLE__
     if ((tmpdir = getenv("TMPDIR")) != NULL &&
-        strncmp(tmpdir, "/private/tmp", 12))
+        strncmp(tmpdir, "/private/tmp", 12) && strncmp(tmpdir, "/tmp", 4))
 #else
     if ((tmpdir = getenv("TMPDIR")) != NULL)
 #endif /* __APPLE__ */
@@ -1107,15 +1139,17 @@ cupsdReadConfiguration(void)
       else
         cupsdSetString(&TempDir, tmpdir);
     }
+  }
 
-    if (!TempDir)
-    {
-      cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...",
-                     RequestRoot);
-      cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot);
-    }
+  if (!TempDir)
+  {
+    cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...",
+                   RequestRoot);
+    cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot);
   }
 
+  setenv("TMPDIR", TempDir, 1);
+
  /*
   * Make sure the temporary directory has the right permissions...
   */
@@ -1469,7 +1503,7 @@ cupsdReadConfiguration(void)
     if (!mimeType(MimeDatabase, "application", "octet-stream"))
       NumMimeTypes ++;
 
-    if ((MimeTypes = calloc(NumMimeTypes, sizeof(const char *))) == NULL)
+    if ((MimeTypes = calloc((size_t)NumMimeTypes, sizeof(const char *))) == NULL)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Unable to allocate memory for %d MIME types.",
@@ -1557,6 +1591,12 @@ cupsdReadConfiguration(void)
 
     cupsdCreateCommonData();
 
+   /*
+    * Update all jobs as needed...
+    */
+
+    cupsdUpdateJobs();
+
    /*
     * Update all printers as needed...
     */
@@ -1737,7 +1777,8 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
        * Merge everything into a 32-bit IPv4 address in ip[3]...
        */
 
-       ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
+       ip[3] = ((((((unsigned)val[0] << 8) | (unsigned)val[1]) << 8) |
+                (unsigned)val[2]) << 8) | (unsigned)val[3];
 
        if (ipcount < 4)
          mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
@@ -1805,7 +1846,8 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
     * Merge everything into a 32-bit IPv4 address in ip[3]...
     */
 
-    ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
+    ip[3] = ((((((unsigned)val[0] << 8) | (unsigned)val[1]) << 8) |
+             (unsigned)val[2]) << 8) | (unsigned)val[3];
 
     if (ipcount < 4)
       mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
@@ -1832,7 +1874,8 @@ get_addr_and_mask(const char *value,      /* I - String from config file */
                  mask + 3) != 4)
         return (0);
 
-      mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8;
+      mask[3] |= (((((unsigned)mask[0] << 8) | (unsigned)mask[1]) << 8) |
+                  (unsigned)mask[2]) << 8;
       mask[0] = mask[1] = mask[2] = 0;
     }
     else
@@ -2541,13 +2584,279 @@ parse_protocols(const char *s)         /* I - Space-delimited protocols */
 
 
 /*
- * 'read_configuration()' - Read a configuration file.
+ * 'parse_variable()' - Parse a variable line.
  */
 
 static int                             /* O - 1 on success, 0 on failure */
-read_configuration(cups_file_t *fp)    /* I - File to read from */
+parse_variable(
+    const char        *filename,       /* I - Name of configuration file */
+    int               linenum,         /* I - Line in configuration file */
+    const char        *line,           /* I - Line from configuration file */
+    const char        *value,          /* I - Value from configuration file */
+    size_t            num_vars,                /* I - Number of variables */
+    const cupsd_var_t *vars)           /* I - Variables */
+{
+  size_t               i;              /* Looping var */
+  const cupsd_var_t    *var;           /* Variables */
+  char                 temp[1024];     /* Temporary string */
+
+
+  for (i = num_vars, var = vars; i > 0; i --, var ++)
+    if (!_cups_strcasecmp(line, var->name))
+      break;
+
+  if (i == 0)
+  {
+   /*
+    * Unknown directive!  Output an error message and continue...
+    */
+
+    if (!value)
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.",
+                     line, linenum, filename);
+    else
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.",
+                     line, linenum, filename);
+
+    return (0);
+  }
+
+  switch (var->type)
+  {
+    case CUPSD_VARTYPE_INTEGER :
+       if (!value)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Missing integer value for %s on line %d of %s.",
+                         line, linenum, filename);
+          return (0);
+       }
+       else if (!isdigit(*value & 255))
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Bad integer value for %s on line %d of %s.",
+                         line, linenum, filename);
+          return (0);
+       }
+       else
+       {
+         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;
+           else
+           {
+             cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "Unknown integer value for %s on line %d of %s.",
+                             line, linenum, filename);
+             return (0);
+           }
+         }
+
+         if (n < 0)
+         {
+           cupsdLogMessage(CUPSD_LOG_ERROR,
+                           "Bad negative integer value for %s on line %d of "
+                           "%s.", line, linenum, filename);
+           return (0);
+         }
+         else
+         {
+           *((int *)var->ptr) = n;
+         }
+       }
+       break;
+
+    case CUPSD_VARTYPE_PERM :
+       if (!value)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Missing permissions value for %s on line %d of %s.",
+                         line, linenum, filename);
+          return (0);
+       }
+       else if (!isdigit(*value & 255))
+       {
+        /* TODO: Add chmod UGO syntax support */
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Bad permissions value for %s on line %d of %s.",
+                         line, linenum, filename);
+          return (0);
+       }
+       else
+       {
+         int n = strtol(value, NULL, 8);
+                                       /* Permissions value */
+
+         if (n < 0)
+         {
+           cupsdLogMessage(CUPSD_LOG_ERROR,
+                           "Bad negative permissions value for %s on line %d of "
+                           "%s.", line, linenum, filename);
+           return (0);
+         }
+         else
+         {
+           *((mode_t *)var->ptr) = (mode_t)n;
+         }
+       }
+       break;
+
+    case CUPSD_VARTYPE_TIME :
+       if (!value)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Missing time interval value for %s on line %d of "
+                         "%s.", line, linenum, filename);
+         return (0);
+       }
+       else if (!_cups_strncasecmp(line, "PreserveJob", 11) &&
+                (!_cups_strcasecmp(value, "true") ||
+                 !_cups_strcasecmp(value, "on") ||
+                 !_cups_strcasecmp(value, "enabled") ||
+                 !_cups_strcasecmp(value, "yes")))
+       {
+         *((int *)var->ptr) = INT_MAX;
+       }
+       else if (!_cups_strcasecmp(value, "false") ||
+                !_cups_strcasecmp(value, "off") ||
+                !_cups_strcasecmp(value, "disabled") ||
+                !_cups_strcasecmp(value, "no"))
+       {
+         *((int *)var->ptr) = 0;
+       }
+       else if (!isdigit(*value & 255))
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unknown time interval value for %s on line %d of "
+                         "%s.", line, linenum, filename);
+          return (0);
+       }
+       else
+       {
+         double        n;              /* Number */
+         char          *units;         /* Units */
+
+         n = strtod(value, &units);
+
+         if (units && *units)
+         {
+           if (tolower(units[0] & 255) == 'w')
+             n *= 7 * 24 * 60 * 60;
+           else if (tolower(units[0] & 255) == 'd')
+             n *= 24 * 60 * 60;
+           else if (tolower(units[0] & 255) == 'h')
+             n *= 60 * 60;
+           else if (tolower(units[0] & 255) == 'm')
+             n *= 60;
+           else
+           {
+             cupsdLogMessage(CUPSD_LOG_ERROR,
+                             "Unknown time interval value for %s on line "
+                             "%d of %s.", line, linenum, filename);
+             return (0);
+           }
+         }
+
+         if (n < 0.0 || n > INT_MAX)
+         {
+           cupsdLogMessage(CUPSD_LOG_ERROR,
+                           "Bad time value for %s on line %d of %s.",
+                           line, linenum, filename);
+           return (0);
+         }
+         else
+         {
+           *((int *)var->ptr) = (int)n;
+         }
+       }
+       break;
+
+    case CUPSD_VARTYPE_BOOLEAN :
+       if (!value)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Missing boolean value for %s on line %d of %s.",
+                         line, linenum, filename);
+         return (0);
+       }
+       else if (!_cups_strcasecmp(value, "true") ||
+                !_cups_strcasecmp(value, "on") ||
+                !_cups_strcasecmp(value, "enabled") ||
+                !_cups_strcasecmp(value, "yes") ||
+                atoi(value) != 0)
+       {
+         *((int *)var->ptr) = TRUE;
+       }
+       else if (!_cups_strcasecmp(value, "false") ||
+                !_cups_strcasecmp(value, "off") ||
+                !_cups_strcasecmp(value, "disabled") ||
+                !_cups_strcasecmp(value, "no") ||
+                !_cups_strcasecmp(value, "0"))
+       {
+         *((int *)var->ptr) = FALSE;
+       }
+       else
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unknown boolean value %s on line %d of %s.",
+                         value, linenum, filename);
+         return (0);
+       }
+       break;
+
+    case CUPSD_VARTYPE_PATHNAME :
+       if (!value)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Missing pathname value for %s on line %d of %s.",
+                         line, linenum, filename);
+         return (0);
+       }
+
+       if (value[0] == '/')
+         strlcpy(temp, value, sizeof(temp));
+       else
+         snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value);
+
+       if (access(temp, 0))
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "File or directory for \"%s %s\" on line %d of %s "
+                         "does not exist.", line, value, linenum, filename);
+         return (0);
+       }
+
+       cupsdSetString((char **)var->ptr, temp);
+       break;
+
+    case CUPSD_VARTYPE_STRING :
+       cupsdSetString((char **)var->ptr, value);
+       break;
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'read_cupsd_conf()' - Read the cupsd.conf configuration file.
+ */
+
+static int                             /* O - 1 on success, 0 on failure */
+read_cupsd_conf(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 */
@@ -2556,12 +2865,10 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
                        *value,         /* Pointer to value */
                        *valueptr;      /* Pointer into value */
   int                  valuelen;       /* Length of value */
-  cupsd_var_t const    *var;           /* Current variable */
   http_addrlist_t      *addrlist,      /* Address list */
                        *addr;          /* Current address */
   cups_file_t          *incfile;       /* Include file */
   char                 incname[1024];  /* Include filename */
-  struct group         *group;         /* Group */
 
 
  /*
@@ -2593,7 +2900,7 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
                        incname, strerror(errno));
       else
       {
-        read_configuration(incfile);
+        read_cupsd_conf(incfile);
        cupsFileClose(incfile);
       }
     }
@@ -2617,8 +2924,6 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
       if (linenum == 0)
        return (0);
     }
-    else if (!_cups_strcasecmp(line, "FatalErrors"))
-      FatalErrors = parse_fatal_errors(value);
     else if (!_cups_strcasecmp(line, "FaxRetryInterval") && value)
     {
       JobRetryInterval = atoi(value);
@@ -2673,7 +2978,7 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
             lis;
             lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
           if (httpAddrEqual(&(addr->addr), &(lis->address)) &&
-             _httpAddrPort(&(addr->addr)) == _httpAddrPort(&(lis->address)))
+             httpAddrPort(&(addr->addr)) == httpAddrPort(&(lis->address)))
            break;
 
         if (lis)
@@ -2729,11 +3034,11 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
        else
 #endif /* AF_LOCAL */
        cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv%d)", temp,
-                        _httpAddrPort(&(lis->address)),
-                       _httpAddrFamily(&(lis->address)) == AF_INET ? 4 : 6);
+                        httpAddrPort(&(lis->address)),
+                       httpAddrFamily(&(lis->address)) == AF_INET ? 4 : 6);
 
         if (!httpAddrLocalhost(&(lis->address)))
-         RemotePort = _httpAddrPort(&(lis->address));
+         RemotePort = httpAddrPort(&(lis->address));
       }
 
      /*
@@ -2762,10 +3067,10 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
 
       BrowseLocalProtocols = protocols;
     }
-    else if (!_cups_strcasecmp(line, "default_auth_type") && value)
+    else if (!_cups_strcasecmp(line, "DefaultAuthType") && value)
     {
      /*
-      * default_auth_type {basic,digest,basicdigest,negotiate}
+      * DefaultAuthType {basic,digest,basicdigest,negotiate}
       */
 
       if (!_cups_strcasecmp(value, "none"))
@@ -2814,81 +3119,6 @@ read_configuration(cups_file_t *fp)      /* I - File to read from */
       }
     }
 #endif /* HAVE_SSL */
-    else if (!_cups_strcasecmp(line, "User") && value)
-    {
-     /*
-      * User ID to run as...
-      */
-
-      if (isdigit(value[0] & 255))
-      {
-        int uid = atoi(value);
-
-       if (!uid)
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Will not use User 0 as specified on line %d "
-                         "for security reasons.  You must use a non-"
-                         "privileged account instead.",
-                         linenum);
-        else
-         User = atoi(value);
-      }
-      else
-      {
-        struct passwd *p;      /* Password information */
-
-        endpwent();
-       p = getpwnam(value);
-
-       if (p)
-       {
-         if (!p->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
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Unknown User \"%s\" on line %d, ignoring.",
-                         value, linenum);
-      }
-    }
-    else if (!_cups_strcasecmp(line, "Group") && value)
-    {
-     /*
-      * Group ID to run as...
-      */
-
-      if (isdigit(value[0]))
-        Group = atoi(value);
-      else
-      {
-        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 (!_cups_strcasecmp(line, "SystemGroup") && value)
-    {
-     /*
-      * SystemGroup (admin) group(s)...
-      */
-
-      if (!parse_groups(value))
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unknown SystemGroup \"%s\" on line %d, ignoring.",
-                       value, linenum);
-    }
     else if (!_cups_strcasecmp(line, "HostNameLookups") && value)
     {
      /*
@@ -2967,22 +3197,6 @@ read_configuration(cups_file_t *fp)      /* I - File to read from */
         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogTimeFormat %s on line %d.",
                        value, linenum);
     }
-    else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
-    {
-     /*
-      * Format of printcap file?
-      */
-
-      if (!_cups_strcasecmp(value, "bsd"))
-        PrintcapFormat = PRINTCAP_BSD;
-      else if (!_cups_strcasecmp(value, "plist"))
-        PrintcapFormat = PRINTCAP_PLIST;
-      else if (!_cups_strcasecmp(value, "solaris"))
-        PrintcapFormat = PRINTCAP_SOLARIS;
-      else
-       cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.",
-                       value, linenum);
-    }
     else if (!_cups_strcasecmp(line, "ServerTokens") && value)
     {
      /*
@@ -2995,19 +3209,20 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
       uname(&plat);
 
       if (!_cups_strcasecmp(value, "ProductOnly"))
-       cupsdSetString(&ServerHeader, "CUPS");
+       cupsdSetString(&ServerHeader, "CUPS IPP");
       else if (!_cups_strcasecmp(value, "Major"))
-       cupsdSetStringf(&ServerHeader, "CUPS/%d", CUPS_VERSION_MAJOR);
+       cupsdSetStringf(&ServerHeader, "CUPS/%d IPP/2", CUPS_VERSION_MAJOR);
       else if (!_cups_strcasecmp(value, "Minor"))
-       cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR,
+       cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR,
                        CUPS_VERSION_MINOR);
       else if (!_cups_strcasecmp(value, "Minimal"))
-       cupsdSetString(&ServerHeader, CUPS_MINIMAL);
+       cupsdSetString(&ServerHeader, CUPS_MINIMAL " IPP/2.1");
       else if (!_cups_strcasecmp(value, "OS"))
-       cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
+       cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s) IPP/2.1",
+                       plat.sysname, plat.release);
       else if (!_cups_strcasecmp(value, "Full"))
-       cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/2.1",
-                       plat.sysname);
+       cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s; %s) IPP/2.1",
+                       plat.sysname, plat.release, plat.machine);
       else if (!_cups_strcasecmp(value, "None"))
        cupsdClearString(&ServerHeader);
       else
@@ -3091,134 +3306,203 @@ read_configuration(cups_file_t *fp)   /* I - File to read from */
                        "Missing value for SetEnv directive on line %d.",
                        linenum);
     }
-#ifdef HAVE_SSL
-    else if (!_cups_strcasecmp(line, "SSLOptions"))
+    else if (!_cups_strcasecmp(line, "AccessLog") ||
+             !_cups_strcasecmp(line, "CacheDir") ||
+             !_cups_strcasecmp(line, "ConfigFilePerm") ||
+             !_cups_strcasecmp(line, "DataDir") ||
+             !_cups_strcasecmp(line, "DocumentRoot") ||
+             !_cups_strcasecmp(line, "ErrorLog") ||
+             !_cups_strcasecmp(line, "FatalErrors") ||
+             !_cups_strcasecmp(line, "FileDevice") ||
+             !_cups_strcasecmp(line, "FontPath") ||
+             !_cups_strcasecmp(line, "Group") ||
+             !_cups_strcasecmp(line, "LogFilePerm") ||
+             !_cups_strcasecmp(line, "LPDConfigFile") ||
+             !_cups_strcasecmp(line, "PageLog") ||
+             !_cups_strcasecmp(line, "Printcap") ||
+             !_cups_strcasecmp(line, "PrintcapFormat") ||
+             !_cups_strcasecmp(line, "RemoteRoot") ||
+             !_cups_strcasecmp(line, "RequestRoot") ||
+             !_cups_strcasecmp(line, "ServerBin") ||
+             !_cups_strcasecmp(line, "ServerCertificate") ||
+             !_cups_strcasecmp(line, "ServerKey") ||
+             !_cups_strcasecmp(line, "ServerKeychain") ||
+             !_cups_strcasecmp(line, "ServerRoot") ||
+             !_cups_strcasecmp(line, "SMBConfigFile") ||
+             !_cups_strcasecmp(line, "StateDir") ||
+             !_cups_strcasecmp(line, "SystemGroup") ||
+             !_cups_strcasecmp(line, "SystemGroupAuthKey") ||
+             !_cups_strcasecmp(line, "TempDir") ||
+            !_cups_strcasecmp(line, "User"))
     {
-     /*
-      * SSLOptions options
-      */
-
-      if (!value || !_cups_strcasecmp(value, "none"))
-        SSLOptions = CUPSD_SSL_NONE;
-      else if (!_cups_strcasecmp(value, "noemptyfragments"))
-        SSLOptions = CUPSD_SSL_NOEMPTY;
-      else
-        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unknown value \"%s\" for SSLOptions directive on "
-                       "line %d.", value, linenum);
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                     "Please move \"%s%s%s\" on line %d of %s to the %s file; "
+                     "this will become an error in a future release.",
+                     line, value ? " " : "", value ? value : "", linenum,
+                     ConfigurationFile, CupsFilesFile);
     }
-#endif /* HAVE_SSL */
     else
+      parse_variable(ConfigurationFile, linenum, line, value,
+                     sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars);
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'read_cups_files_conf()' - Read the cups-files.conf configuration file.
+ */
+
+static int                             /* O - 1 on success, 0 on failure */
+read_cups_files_conf(cups_file_t *fp)  /* I - File to read from */
+{
+  int          linenum;                /* Current line number */
+  char         line[HTTP_MAX_BUFFER],  /* Line from file */
+               *value;                 /* Value from line */
+  struct group *group;                 /* Group */
+
+
+ /*
+  * Loop through each line in the file...
+  */
+
+  linenum = 0;
+
+  while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+  {
+    if (!_cups_strcasecmp(line, "FatalErrors"))
+      FatalErrors = parse_fatal_errors(value);
+    else if (!_cups_strcasecmp(line, "Group") && value)
     {
      /*
-      * Find a simple variable in the list...
+      * Group ID to run as...
       */
 
-      for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
-        if (!_cups_strcasecmp(line, var->name))
-         break;
-
-      if (i == 0)
+      if (isdigit(value[0]))
+        Group = (gid_t)atoi(value);
+      else
       {
-       /*
-        * Unknown directive!  Output an error message and continue...
-       */
+        endgrent();
+       group = getgrnam(value);
 
-        if (!value)
-         cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d.",
-                         line, linenum);
+       if (group != NULL)
+         Group = group->gr_gid;
        else
-         cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.",
-                         line, linenum);
-        continue;
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unknown Group \"%s\" on line %d of %s.", value,
+                         linenum, CupsFilesFile);
+         if (FatalErrors & CUPSD_FATAL_CONFIG)
+           return (0);
+       }
       }
+    }
+    else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
+    {
+     /*
+      * Format of printcap file?
+      */
 
-      switch (var->type)
+      if (!_cups_strcasecmp(value, "bsd"))
+        PrintcapFormat = PRINTCAP_BSD;
+      else if (!_cups_strcasecmp(value, "plist"))
+        PrintcapFormat = PRINTCAP_PLIST;
+      else if (!_cups_strcasecmp(value, "solaris"))
+        PrintcapFormat = PRINTCAP_SOLARIS;
+      else
       {
-        case CUPSD_VARTYPE_INTEGER :
-           if (!value)
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "Missing integer value for %s on line %d.",
-                             line, linenum);
-           else
-           {
-             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;
-             }
-
-              if (n < 0)
-               cupsdLogMessage(CUPSD_LOG_ERROR,
-                               "Bad negative integer value for %s on line %d.",
-                               line, linenum);
-             else
-               *((int *)var->ptr) = n;
-           }
-           break;
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unknown PrintcapFormat \"%s\" on line %d of %s.",
+                       value, linenum, CupsFilesFile);
+        if (FatalErrors & CUPSD_FATAL_CONFIG)
+          return (0);
+      }
+    }
+    else if (!_cups_strcasecmp(line, "SystemGroup") && value)
+    {
+     /*
+      * SystemGroup (admin) group(s)...
+      */
 
-       case CUPSD_VARTYPE_BOOLEAN :
-           if (!value)
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "Missing boolean value for %s on line %d.",
-                             line, linenum);
-            else if (!_cups_strcasecmp(value, "true") ||
-                    !_cups_strcasecmp(value, "on") ||
-                    !_cups_strcasecmp(value, "enabled") ||
-                    !_cups_strcasecmp(value, "yes") ||
-                    atoi(value) != 0)
-              *((int *)var->ptr) = TRUE;
-           else if (!_cups_strcasecmp(value, "false") ||
-                    !_cups_strcasecmp(value, "off") ||
-                    !_cups_strcasecmp(value, "disabled") ||
-                    !_cups_strcasecmp(value, "no") ||
-                    !_cups_strcasecmp(value, "0"))
-              *((int *)var->ptr) = FALSE;
-           else
-              cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "Unknown boolean value %s on line %d.",
-                             value, linenum);
-           break;
+      if (!parse_groups(value))
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unknown SystemGroup \"%s\" on line %d of %s.", value,
+                       linenum, CupsFilesFile);
+        if (FatalErrors & CUPSD_FATAL_CONFIG)
+          return (0);
+      }
+    }
+    else if (!_cups_strcasecmp(line, "User") && value)
+    {
+     /*
+      * User ID to run as...
+      */
 
-       case CUPSD_VARTYPE_PATHNAME :
-            if (!value)
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "Missing pathname value for %s on line %d.",
-                             line, linenum);
-              break;
-           }
+      if (isdigit(value[0] & 255))
+      {
+        int uid = atoi(value);
 
-           if (value[0] == '/')
-             strlcpy(temp, value, sizeof(temp));
-           else
-             snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value);
+       if (!uid)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Will not use User 0 as specified on line %d of %s "
+                         "for security reasons.  You must use a non-"
+                         "privileged account instead.",
+                         linenum, CupsFilesFile);
+          if (FatalErrors & CUPSD_FATAL_CONFIG)
+            return (0);
+        }
+        else
+         User = (uid_t)atoi(value);
+      }
+      else
+      {
+        struct passwd *p;      /* Password information */
 
-            if (access(temp, 0))
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "File or directory for \"%s %s\" on line %d "
-                             "does not exist.", line, value, linenum);
-              break;
-           }
+        endpwent();
+       p = getpwnam(value);
 
-       case CUPSD_VARTYPE_STRING :
-           cupsdSetString((char **)var->ptr, value);
-           break;
+       if (p)
+       {
+         if (!p->pw_uid)
+         {
+           cupsdLogMessage(CUPSD_LOG_ERROR,
+                           "Will not use User %s (UID=0) as specified on line "
+                           "%d of %s for security reasons.  You must use a "
+                           "non-privileged account instead.",
+                           value, linenum, CupsFilesFile);
+           if (FatalErrors & CUPSD_FATAL_CONFIG)
+             return (0);
+         }
+         else
+           User = p->pw_uid;
+       }
+       else
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unknown User \"%s\" on line %d of %s.",
+                         value, linenum, CupsFilesFile);
+          if (FatalErrors & CUPSD_FATAL_CONFIG)
+            return (0);
+        }
       }
     }
+    else if (!_cups_strcasecmp(line, "ServerCertificate") ||
+             !_cups_strcasecmp(line, "ServerKey"))
+    {
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                     "The \"%s\" directive on line %d of %s is no longer "
+                     "supported; this will become an error in a future "
+                     "release.",
+                     line, linenum, CupsFilesFile);
+    }
+    else if (!parse_variable(CupsFilesFile, linenum, line, value,
+                            sizeof(cupsfiles_vars) / sizeof(cupsfiles_vars[0]),
+                            cupsfiles_vars) &&
+            (FatalErrors & CUPSD_FATAL_CONFIG))
+      return (0);
   }
 
   return (1);
@@ -3538,6 +3822,7 @@ read_policy(cups_file_t *fp,              /* I - Configuration file */
              cupsdAddString(&(pol->job_attrs), "job-name");
              cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
              cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+             cupsdAddString(&(pol->job_attrs), "phone");
            }
            else
              cupsdAddString(&(pol->job_attrs), value);
@@ -3762,6 +4047,7 @@ set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
     cupsdAddString(&(pol->job_attrs), "job-name");
     cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
     cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+    cupsdAddString(&(pol->job_attrs), "phone");
   }
 
   if (!pol->sub_access)
@@ -3788,5 +4074,5 @@ set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
 
 
 /*
- * End of "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $".
+ * End of "$Id$".
  */