Revert manifest to default one
[external/cups.git] / scheduler / conf.c
1 /*
2  * "$Id: conf.c 10121 2011-11-16 15:28:11Z mike $"
3  *
4  *   Configuration routines for the CUPS scheduler.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
7  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
8  *
9  *   These coded instructions, statements, and computer programs are the
10  *   property of Apple Inc. and are protected by Federal copyright
11  *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
12  *   which should have been included with this file.  If this file is
13  *   file is missing or damaged, see the license at "http://www.cups.org/".
14  *
15  * Contents:
16  *
17  *   cupsdAddAlias()          - Add a host alias.
18  *   cupsdCheckPermissions()  - Fix the mode and ownership of a file or
19  *                              directory.
20  *   cupsdFreeAliases()       - Free all of the alias entries.
21  *   cupsdReadConfiguration() - Read the cupsd.conf file.
22  *   get_address()            - Get an address + port number from a line.
23  *   get_addr_and_mask()      - Get an IP address and netmask.
24  *   mime_error_cb()          - Log a MIME error.
25  *   parse_aaa()              - Parse authentication, authorization, and access
26  *                              control lines.
27  *   parse_fatal_errors()     - Parse FatalErrors values in a string.
28  *   parse_groups()           - Parse system group names in a string.
29  *   parse_protocols()        - Parse browse protocols in a string.
30  *   read_configuration()     - Read a configuration file.
31  *   read_location()          - Read a <Location path> definition.
32  *   read_policy()            - Read a <Policy name> definition.
33  *   set_policy_defaults()    - Set default policy values as needed.
34  */
35
36 /*
37  * Include necessary headers...
38  */
39
40 #include "cupsd.h"
41 #include <stdarg.h>
42 #include <grp.h>
43 #include <sys/utsname.h>
44 #include <syslog.h>
45
46 #ifdef HAVE_LIBPAPER
47 #  include <paper.h>
48 #endif /* HAVE_LIBPAPER */
49
50
51 /*
52  * Possibly missing network definitions...
53  */
54
55 #ifndef INADDR_NONE
56 #  define INADDR_NONE   0xffffffff
57 #endif /* !INADDR_NONE */
58
59
60 /*
61  * Configuration variable structure...
62  */
63
64 typedef enum
65 {
66   CUPSD_VARTYPE_INTEGER,                /* Integer option */
67   CUPSD_VARTYPE_STRING,                 /* String option */
68   CUPSD_VARTYPE_BOOLEAN,                /* Boolean option */
69   CUPSD_VARTYPE_PATHNAME                /* File/directory name option */
70 } cupsd_vartype_t;
71
72 typedef struct
73 {
74   char                  *name;          /* Name of variable */
75   void                  *ptr;           /* Pointer to variable */
76   cupsd_vartype_t       type;           /* Type (int, string, address) */
77 } cupsd_var_t;
78
79
80 /*
81  * Local globals...
82  */
83
84 static const cupsd_var_t        variables[] =
85 {
86   { "AccessLog",                &AccessLog,             CUPSD_VARTYPE_STRING },
87   { "AutoPurgeJobs",            &JobAutoPurge,          CUPSD_VARTYPE_BOOLEAN },
88 #ifdef HAVE_DNSSD
89   { "BrowseDNSSDRegType",       &DNSSDRegType,          CUPSD_VARTYPE_STRING },
90 #endif /* HAVE_DNSSD */
91   { "BrowseInterval",           &BrowseInterval,        CUPSD_VARTYPE_INTEGER },
92 #ifdef HAVE_LDAP
93   { "BrowseLDAPBindDN",         &BrowseLDAPBindDN,      CUPSD_VARTYPE_STRING },
94 #  ifdef HAVE_LDAP_SSL
95   { "BrowseLDAPCACertFile",     &BrowseLDAPCACertFile,  CUPSD_VARTYPE_PATHNAME },
96 #  endif /* HAVE_LDAP_SSL */
97   { "BrowseLDAPDN",             &BrowseLDAPDN,          CUPSD_VARTYPE_STRING },
98   { "BrowseLDAPPassword",       &BrowseLDAPPassword,    CUPSD_VARTYPE_STRING },
99   { "BrowseLDAPServer",         &BrowseLDAPServer,      CUPSD_VARTYPE_STRING },
100 #endif /* HAVE_LDAP */
101   { "BrowseLocalOptions",       &BrowseLocalOptions,    CUPSD_VARTYPE_STRING },
102   { "BrowsePort",               &BrowsePort,            CUPSD_VARTYPE_INTEGER },
103   { "BrowseRemoteOptions",      &BrowseRemoteOptions,   CUPSD_VARTYPE_STRING },
104   { "BrowseShortNames",         &BrowseShortNames,      CUPSD_VARTYPE_BOOLEAN },
105   { "BrowseTimeout",            &BrowseTimeout,         CUPSD_VARTYPE_INTEGER },
106   { "BrowseWebIF",              &BrowseWebIF,           CUPSD_VARTYPE_BOOLEAN },
107   { "Browsing",                 &Browsing,              CUPSD_VARTYPE_BOOLEAN },
108   { "CacheDir",                 &CacheDir,              CUPSD_VARTYPE_STRING },
109   { "Classification",           &Classification,        CUPSD_VARTYPE_STRING },
110   { "ClassifyOverride",         &ClassifyOverride,      CUPSD_VARTYPE_BOOLEAN },
111   { "ConfigFilePerm",           &ConfigFilePerm,        CUPSD_VARTYPE_INTEGER },
112   { "DataDir",                  &DataDir,               CUPSD_VARTYPE_STRING },
113   { "DefaultLanguage",          &DefaultLanguage,       CUPSD_VARTYPE_STRING },
114   { "DefaultLeaseDuration",     &DefaultLeaseDuration,  CUPSD_VARTYPE_INTEGER },
115   { "DefaultPaperSize",         &DefaultPaperSize,      CUPSD_VARTYPE_STRING },
116   { "DefaultPolicy",            &DefaultPolicy,         CUPSD_VARTYPE_STRING },
117   { "DefaultShared",            &DefaultShared,         CUPSD_VARTYPE_BOOLEAN },
118   { "DirtyCleanInterval",       &DirtyCleanInterval,    CUPSD_VARTYPE_INTEGER },
119   { "DocumentRoot",             &DocumentRoot,          CUPSD_VARTYPE_STRING },
120   { "ErrorLog",                 &ErrorLog,              CUPSD_VARTYPE_STRING },
121   { "ErrorPolicy",              &ErrorPolicy,           CUPSD_VARTYPE_STRING },
122   { "FileDevice",               &FileDevice,            CUPSD_VARTYPE_BOOLEAN },
123   { "FilterLimit",              &FilterLimit,           CUPSD_VARTYPE_INTEGER },
124   { "FilterNice",               &FilterNice,            CUPSD_VARTYPE_INTEGER },
125   { "FontPath",                 &FontPath,              CUPSD_VARTYPE_STRING },
126   { "HideImplicitMembers",      &HideImplicitMembers,   CUPSD_VARTYPE_BOOLEAN },
127   { "ImplicitClasses",          &ImplicitClasses,       CUPSD_VARTYPE_BOOLEAN },
128   { "ImplicitAnyClasses",       &ImplicitAnyClasses,    CUPSD_VARTYPE_BOOLEAN },
129   { "JobKillDelay",             &JobKillDelay,          CUPSD_VARTYPE_INTEGER },
130   { "JobRetryLimit",            &JobRetryLimit,         CUPSD_VARTYPE_INTEGER },
131   { "JobRetryInterval",         &JobRetryInterval,      CUPSD_VARTYPE_INTEGER },
132   { "KeepAliveTimeout",         &KeepAliveTimeout,      CUPSD_VARTYPE_INTEGER },
133   { "KeepAlive",                &KeepAlive,             CUPSD_VARTYPE_BOOLEAN },
134 #ifdef HAVE_LAUNCHD
135   { "LaunchdTimeout",           &LaunchdTimeout,        CUPSD_VARTYPE_INTEGER },
136 #endif /* HAVE_LAUNCHD */
137   { "LimitRequestBody",         &MaxRequestSize,        CUPSD_VARTYPE_INTEGER },
138   { "ListenBackLog",            &ListenBackLog,         CUPSD_VARTYPE_INTEGER },
139   { "LogDebugHistory",          &LogDebugHistory,       CUPSD_VARTYPE_INTEGER },
140   { "LogFilePerm",              &LogFilePerm,           CUPSD_VARTYPE_INTEGER },
141   { "LPDConfigFile",            &LPDConfigFile,         CUPSD_VARTYPE_STRING },
142   { "MaxActiveJobs",            &MaxActiveJobs,         CUPSD_VARTYPE_INTEGER },
143   { "MaxClients",               &MaxClients,            CUPSD_VARTYPE_INTEGER },
144   { "MaxClientsPerHost",        &MaxClientsPerHost,     CUPSD_VARTYPE_INTEGER },
145   { "MaxCopies",                &MaxCopies,             CUPSD_VARTYPE_INTEGER },
146   { "MaxEvents",                &MaxEvents,             CUPSD_VARTYPE_INTEGER },
147   { "MaxJobs",                  &MaxJobs,               CUPSD_VARTYPE_INTEGER },
148   { "MaxJobsPerPrinter",        &MaxJobsPerPrinter,     CUPSD_VARTYPE_INTEGER },
149   { "MaxJobsPerUser",           &MaxJobsPerUser,        CUPSD_VARTYPE_INTEGER },
150   { "MaxLeaseDuration",         &MaxLeaseDuration,      CUPSD_VARTYPE_INTEGER },
151   { "MaxLogSize",               &MaxLogSize,            CUPSD_VARTYPE_INTEGER },
152   { "MaxRequestSize",           &MaxRequestSize,        CUPSD_VARTYPE_INTEGER },
153   { "MaxSubscriptions",         &MaxSubscriptions,      CUPSD_VARTYPE_INTEGER },
154   { "MaxSubscriptionsPerJob",   &MaxSubscriptionsPerJob,        CUPSD_VARTYPE_INTEGER },
155   { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter,   CUPSD_VARTYPE_INTEGER },
156   { "MaxSubscriptionsPerUser",  &MaxSubscriptionsPerUser,       CUPSD_VARTYPE_INTEGER },
157   { "MultipleOperationTimeout", &MultipleOperationTimeout,      CUPSD_VARTYPE_INTEGER },
158   { "PageLog",                  &PageLog,               CUPSD_VARTYPE_STRING },
159   { "PageLogFormat",            &PageLogFormat,         CUPSD_VARTYPE_STRING },
160   { "PreserveJobFiles",         &JobFiles,              CUPSD_VARTYPE_BOOLEAN },
161   { "PreserveJobHistory",       &JobHistory,            CUPSD_VARTYPE_BOOLEAN },
162   { "Printcap",                 &Printcap,              CUPSD_VARTYPE_STRING },
163   { "PrintcapGUI",              &PrintcapGUI,           CUPSD_VARTYPE_STRING },
164   { "ReloadTimeout",            &ReloadTimeout,         CUPSD_VARTYPE_INTEGER },
165   { "RemoteRoot",               &RemoteRoot,            CUPSD_VARTYPE_STRING },
166   { "RequestRoot",              &RequestRoot,           CUPSD_VARTYPE_STRING },
167   { "RIPCache",                 &RIPCache,              CUPSD_VARTYPE_STRING },
168   { "RootCertDuration",         &RootCertDuration,      CUPSD_VARTYPE_INTEGER },
169   { "ServerAdmin",              &ServerAdmin,           CUPSD_VARTYPE_STRING },
170   { "ServerBin",                &ServerBin,             CUPSD_VARTYPE_PATHNAME },
171 #ifdef HAVE_SSL
172   { "ServerCertificate",        &ServerCertificate,     CUPSD_VARTYPE_PATHNAME },
173 #  if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
174   { "ServerKey",                &ServerKey,             CUPSD_VARTYPE_PATHNAME },
175 #  endif /* HAVE_LIBSSL || HAVE_GNUTLS */
176 #endif /* HAVE_SSL */
177   { "ServerName",               &ServerName,            CUPSD_VARTYPE_STRING },
178   { "ServerRoot",               &ServerRoot,            CUPSD_VARTYPE_PATHNAME },
179   { "SMBConfigFile",            &SMBConfigFile,         CUPSD_VARTYPE_STRING },
180   { "StateDir",                 &StateDir,              CUPSD_VARTYPE_STRING },
181 #ifdef HAVE_AUTHORIZATION_H
182   { "SystemGroupAuthKey",       &SystemGroupAuthKey,    CUPSD_VARTYPE_STRING },
183 #endif /* HAVE_AUTHORIZATION_H */
184   { "TempDir",                  &TempDir,               CUPSD_VARTYPE_PATHNAME },
185   { "Timeout",                  &Timeout,               CUPSD_VARTYPE_INTEGER },
186   { "UseNetworkDefault",        &UseNetworkDefault,     CUPSD_VARTYPE_BOOLEAN },
187   { "WebInterface",             &WebInterface,          CUPSD_VARTYPE_BOOLEAN },
188   { "PidFile",                  &PidFile,               CUPSD_VARTYPE_STRING }
189 };
190 #define NUM_VARS        (sizeof(variables) / sizeof(variables[0]))
191
192
193 static const unsigned   ones[4] =
194                         {
195                           0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
196                         };
197 static const unsigned   zeros[4] =
198                         {
199                           0x00000000, 0x00000000, 0x00000000, 0x00000000
200                         };
201
202
203 /*
204  * Local functions...
205  */
206
207 static http_addrlist_t  *get_address(const char *value, int defport);
208 static int              get_addr_and_mask(const char *value, unsigned *ip,
209                                           unsigned *mask);
210 static void             mime_error_cb(void *ctx, const char *message);
211 static int              parse_aaa(cupsd_location_t *loc, char *line,
212                                   char *value, int linenum);
213 static int              parse_fatal_errors(const char *s);
214 static int              parse_groups(const char *s);
215 static int              parse_protocols(const char *s);
216 static int              read_configuration(cups_file_t *fp);
217 static int              read_location(cups_file_t *fp, char *name, int linenum);
218 static int              read_policy(cups_file_t *fp, char *name, int linenum);
219 static void             set_policy_defaults(cupsd_policy_t *pol);
220
221
222 /*
223  * 'cupsdAddAlias()' - Add a host alias.
224  */
225
226 void
227 cupsdAddAlias(cups_array_t *aliases,    /* I - Array of aliases */
228               const char   *name)       /* I - Name to add */
229 {
230   cupsd_alias_t *a;                     /*  New alias */
231   size_t        namelen;                /* Length of name */
232
233
234   namelen = strlen(name);
235
236   if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL)
237     return;
238
239   a->namelen = namelen;
240   strcpy(a->name, name);                /* OK since a->name is allocated */
241
242   cupsArrayAdd(aliases, a);
243 }
244
245
246 /*
247  * 'cupsdCheckPermissions()' - Fix the mode and ownership of a file or directory.
248  */
249
250 int                                     /* O - 0 on success, -1 on error, 1 on warning */
251 cupsdCheckPermissions(
252     const char *filename,               /* I - File/directory name */
253     const char *suffix,                 /* I - Additional file/directory name */
254     int        mode,                    /* I - Permissions */
255     int        user,                    /* I - Owner */
256     int        group,                   /* I - Group */
257     int        is_dir,                  /* I - 1 = directory, 0 = file */
258     int        create_dir)              /* I - 1 = create directory, -1 = create w/o logging, 0 = not */
259 {
260   int           dir_created = 0;        /* Did we create a directory? */
261   char          pathname[1024];         /* File name with prefix */
262   struct stat   fileinfo;               /* Stat buffer */
263   int           is_symlink;             /* Is "filename" a symlink? */
264
265
266  /*
267   * Prepend the given root to the filename before testing it...
268   */
269
270   if (suffix)
271   {
272     snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
273     filename = pathname;
274   }
275
276  /*
277   * See if we can stat the file/directory...
278   */
279
280   if (lstat(filename, &fileinfo))
281   {
282     if (errno == ENOENT && create_dir)
283     {
284       if (create_dir > 0)
285         cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating missing directory \"%s\"",
286                         filename);
287
288       if (mkdir(filename, mode))
289       {
290         if (create_dir > 0)
291           cupsdLogMessage(CUPSD_LOG_ERROR,
292                           "Unable to create directory \"%s\" - %s", filename,
293                           strerror(errno));
294         else
295           syslog(LOG_ERR, "Unable to create directory \"%s\" - %s", filename,
296                  strerror(errno));
297
298         return (-1);
299       }
300
301       dir_created      = 1;
302       fileinfo.st_mode = mode | S_IFDIR;
303     }
304     else
305       return (create_dir ? -1 : 1);
306   }
307
308   if ((is_symlink = S_ISLNK(fileinfo.st_mode)) != 0)
309   {
310     if (stat(filename, &fileinfo))
311     {
312       cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is a bad symlink - %s",
313                       filename, strerror(errno));
314       return (-1);
315     }
316   }
317
318  /*
319   * Make sure it's a regular file or a directory as needed...
320   */
321
322   if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
323   {
324     cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file.", filename);
325     return (-1);
326   }
327
328   if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
329   {
330     if (create_dir >= 0)
331       cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory.", filename);
332     else
333       syslog(LOG_ERR, "\"%s\" is not a directory.", filename);
334
335     return (-1);
336   }
337
338  /*
339   * If the filename is a symlink, do not change permissions (STR #2937)...
340   */
341
342   if (is_symlink)
343     return (0);
344
345  /*
346   * Fix owner, group, and mode as needed...
347   */
348
349   if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
350   {
351     if (create_dir >= 0)
352       cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing ownership of \"%s\"",
353                       filename);
354
355     if (chown(filename, user, group) && !getuid())
356     {
357       if (create_dir >= 0)
358         cupsdLogMessage(CUPSD_LOG_ERROR,
359                         "Unable to change ownership of \"%s\" - %s", filename,
360                         strerror(errno));
361       else
362         syslog(LOG_ERR, "Unable to change ownership of \"%s\" - %s", filename,
363                strerror(errno));
364
365       return (1);
366     }
367   }
368
369   if (dir_created || (fileinfo.st_mode & 07777) != mode)
370   {
371     if (create_dir >= 0)
372       cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing access permissions of \"%s\"",
373                       filename);
374
375     if (chmod(filename, mode))
376     {
377       if (create_dir >= 0)
378         cupsdLogMessage(CUPSD_LOG_ERROR,
379                         "Unable to change permissions of \"%s\" - %s", filename,
380                         strerror(errno));
381       else
382         syslog(LOG_ERR, "Unable to change permissions of \"%s\" - %s", filename,
383                strerror(errno));
384
385       return (1);
386     }
387   }
388
389  /*
390   * Everything is OK...
391   */
392
393   return (0);
394 }
395
396
397 /*
398  * 'cupsdFreeAliases()' - Free all of the alias entries.
399  */
400
401 void
402 cupsdFreeAliases(cups_array_t *aliases) /* I - Array of aliases */
403 {
404   cupsd_alias_t *a;                     /* Current alias */
405
406
407   for (a = (cupsd_alias_t *)cupsArrayFirst(aliases);
408        a;
409        a = (cupsd_alias_t *)cupsArrayNext(aliases))
410     free(a);
411
412   cupsArrayDelete(aliases);
413 }
414
415
416 /*
417  * 'cupsdReadConfiguration()' - Read the cupsd.conf file.
418  */
419
420 int                                     /* O - 1 on success, 0 otherwise */
421 cupsdReadConfiguration(void)
422 {
423   int           i;                      /* Looping var */
424   cups_file_t   *fp;                    /* Configuration file */
425   int           status;                 /* Return status */
426   char          temp[1024],             /* Temporary buffer */
427                 mimedir[1024],          /* MIME directory */
428                 *slash;                 /* Directory separator */
429   cups_lang_t   *language;              /* Language */
430   struct passwd *user;                  /* Default user */
431   struct group  *group;                 /* Default group */
432   char          *old_serverroot,        /* Old ServerRoot */
433                 *old_requestroot;       /* Old RequestRoot */
434   int           old_remote_port;        /* Old RemotePort */
435   const char    *tmpdir;                /* TMPDIR environment variable */
436   struct stat   tmpinfo;                /* Temporary directory info */
437   cupsd_policy_t *p;                    /* Policy */
438
439
440  /*
441   * Save the old root paths...
442   */
443
444   old_serverroot = NULL;
445   cupsdSetString(&old_serverroot, ServerRoot);
446   old_requestroot = NULL;
447   cupsdSetString(&old_requestroot, RequestRoot);
448
449  /*
450   * Reset the server configuration data...
451   */
452
453   cupsdDeleteAllLocations();
454
455   if (NumBrowsers > 0)
456   {
457     free(Browsers);
458     Browsers = NULL;
459
460     NumBrowsers = 0;
461   }
462
463   if (NumPolled > 0)
464   {
465     free(Polled);
466
467     NumPolled = 0;
468   }
469
470   if (NumRelays > 0)
471   {
472     for (i = 0; i < NumRelays; i ++)
473       cupsArrayDelete(Relays[i].from);
474
475     free(Relays);
476
477     NumRelays = 0;
478   }
479
480   cupsdDeleteAllListeners();
481
482   old_remote_port = RemotePort;
483   RemotePort      = 0;
484
485  /*
486   * String options...
487   */
488
489   cupsdFreeAliases(ServerAlias);
490   ServerAlias = NULL;
491
492   cupsdClearString(&ServerName);
493   cupsdClearString(&ServerAdmin);
494   cupsdSetString(&ServerBin, CUPS_SERVERBIN);
495   cupsdSetString(&RequestRoot, CUPS_REQUESTS);
496   cupsdSetString(&CacheDir, CUPS_CACHEDIR);
497   cupsdSetString(&DataDir, CUPS_DATADIR);
498   cupsdSetString(&DocumentRoot, CUPS_DOCROOT);
499   cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log");
500   cupsdClearString(&ErrorLog);
501   cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log");
502   cupsdSetString(&PageLogFormat,
503                  "%p %u %j %T %P %C %{job-billing} "
504                  "%{job-originating-host-name} %{job-name} %{media} %{sides}");
505   cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
506   cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
507   cupsdSetString(&FontPath, CUPS_FONTPATH);
508   cupsdSetString(&RemoteRoot, "remroot");
509   cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR,
510                   CUPS_VERSION_MINOR);
511   cupsdSetString(&StateDir, CUPS_STATEDIR);
512   cupsdSetString(&PidFile, "/opt/var/run/cups/cupsd.pid");
513
514   if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf"))
515     PrintcapFormat = PRINTCAP_SOLARIS;
516   else if (!strcmp(CUPS_DEFAULT_PRINTCAP,
517                    "/Library/Preferences/org.cups.printers.plist"))
518     PrintcapFormat = PRINTCAP_PLIST;
519   else
520     PrintcapFormat = PRINTCAP_BSD;
521
522   strlcpy(temp, ConfigurationFile, sizeof(temp));
523   if ((slash = strrchr(temp, '/')) != NULL)
524     *slash = '\0';
525
526   cupsdSetString(&ServerRoot, temp);
527
528   cupsdClearString(&Classification);
529   ClassifyOverride  = 0;
530
531 #ifdef HAVE_SSL
532 #  ifdef HAVE_CDSASSL
533   cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain");
534 #  else
535   cupsdSetString(&ServerCertificate, "ssl/server.crt");
536   cupsdSetString(&ServerKey, "ssl/server.key");
537 #  endif /* HAVE_CDSASSL */
538 #endif /* HAVE_SSL */
539
540   language = cupsLangDefault();
541
542   if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX"))
543     cupsdSetString(&DefaultLanguage, "en");
544   else
545     cupsdSetString(&DefaultLanguage, language->language);
546
547   cupsdClearString(&DefaultPaperSize);
548
549   cupsdSetString(&RIPCache, "128m");
550
551   cupsdSetString(&TempDir, NULL);
552
553  /*
554   * Find the default user...
555   */
556
557   if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL)
558     User = user->pw_uid;
559   else
560   {
561    /*
562     * Use the (historical) NFS nobody user ID (-2 as a 16-bit twos-
563     * complement number...)
564     */
565
566     User = 65534;
567   }
568
569   endpwent();
570
571  /*
572   * Find the default group...
573   */
574
575   group = getgrnam(CUPS_DEFAULT_GROUP);
576   endgrent();
577
578   if (group)
579     Group = group->gr_gid;
580   else
581   {
582    /*
583     * Fallback to group "nobody"...
584     */
585
586     group = getgrnam("nobody");
587     endgrent();
588
589     if (group)
590       Group = group->gr_gid;
591     else
592     {
593      /*
594       * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
595       * complement number...)
596       */
597
598       Group = 65534;
599     }
600   }
601
602  /*
603   * Numeric options...
604   */
605
606   AccessLogLevel           = CUPSD_ACCESSLOG_ACTIONS;
607   ConfigFilePerm           = CUPS_DEFAULT_CONFIG_FILE_PERM;
608   FatalErrors              = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS);
609   DefaultAuthType          = CUPSD_AUTH_BASIC;
610 #ifdef HAVE_SSL
611   DefaultEncryption        = HTTP_ENCRYPT_REQUIRED;
612   SSLOptions               = CUPSD_SSL_NONE;
613 #endif /* HAVE_SSL */
614   DirtyCleanInterval       = DEFAULT_KEEPALIVE;
615   JobKillDelay             = DEFAULT_TIMEOUT;
616   JobRetryLimit            = 5;
617   JobRetryInterval         = 300;
618   FileDevice               = FALSE;
619   FilterLevel              = 0;
620   FilterLimit              = 0;
621   FilterNice               = 0;
622   HostNameLookups          = FALSE;
623   ImplicitClasses          = CUPS_DEFAULT_IMPLICIT_CLASSES;
624   ImplicitAnyClasses       = FALSE;
625   HideImplicitMembers      = TRUE;
626   KeepAlive                = TRUE;
627   KeepAliveTimeout         = DEFAULT_KEEPALIVE;
628   ListenBackLog            = SOMAXCONN;
629   LogDebugHistory          = 99999;
630   LogFilePerm              = CUPS_DEFAULT_LOG_FILE_PERM;
631   LogLevel                 = CUPSD_LOG_WARN;
632   LogTimeFormat            = CUPSD_TIME_STANDARD;
633   MaxClients               = 100;
634   MaxClientsPerHost        = 0;
635   MaxLogSize               = 1024 * 1024;
636   MaxRequestSize           = 0;
637   MultipleOperationTimeout = DEFAULT_TIMEOUT;
638   ReloadTimeout            = DEFAULT_KEEPALIVE;
639   RootCertDuration         = 300;
640   Timeout                  = DEFAULT_TIMEOUT;
641   NumSystemGroups          = 0;
642   WebInterface             = CUPS_DEFAULT_WEBIF;
643
644   BrowseInterval           = DEFAULT_INTERVAL;
645   BrowsePort               = ippPort();
646   BrowseLocalProtocols     = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS);
647   BrowseRemoteProtocols    = parse_protocols(CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS);
648   BrowseShortNames         = CUPS_DEFAULT_BROWSE_SHORT_NAMES;
649   BrowseTimeout            = DEFAULT_TIMEOUT;
650   BrowseWebIF              = FALSE;
651   Browsing                 = CUPS_DEFAULT_BROWSING;
652   DefaultShared            = CUPS_DEFAULT_DEFAULT_SHARED;
653
654 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
655   cupsdSetString(&DNSSDRegType, "_ipp._tcp,_cups,_universal");
656 #endif /* HAVE_DNSSD */
657
658   cupsdSetString(&LPDConfigFile, CUPS_DEFAULT_LPD_CONFIG_FILE);
659   cupsdSetString(&SMBConfigFile, CUPS_DEFAULT_SMB_CONFIG_FILE);
660
661   cupsdClearString(&BrowseLocalOptions);
662   cupsdClearString(&BrowseRemoteOptions);
663
664   cupsdSetString(&ErrorPolicy, "stop-printer");
665
666 #ifdef HAVE_LDAP
667   cupsdClearString(&BrowseLDAPBindDN);
668   cupsdClearString(&BrowseLDAPDN);
669   cupsdClearString(&BrowseLDAPPassword);
670   cupsdClearString(&BrowseLDAPServer);
671 #  ifdef HAVE_LDAP_SSL
672   cupsdClearString(&BrowseLDAPCACertFile);
673 #  endif /* HAVE_LDAP_SSL */
674 #endif /* HAVE_LDAP */
675
676   JobHistory          = DEFAULT_HISTORY;
677   JobFiles            = DEFAULT_FILES;
678   JobAutoPurge        = 0;
679   MaxJobs             = 500;
680   MaxActiveJobs       = 0;
681   MaxJobsPerUser      = 0;
682   MaxJobsPerPrinter   = 0;
683   MaxCopies           = CUPS_DEFAULT_MAX_COPIES;
684
685   cupsdDeleteAllPolicies();
686   cupsdClearString(&DefaultPolicy);
687
688 #ifdef HAVE_AUTHORIZATION_H
689   cupsdClearString(&SystemGroupAuthKey);
690 #endif /* HAVE_AUTHORIZATION_H */
691
692   MaxSubscriptions           = 100;
693   MaxSubscriptionsPerJob     = 0;
694   MaxSubscriptionsPerPrinter = 0;
695   MaxSubscriptionsPerUser    = 0;
696   DefaultLeaseDuration       = 86400;
697   MaxLeaseDuration           = 0;
698
699 #ifdef HAVE_LAUNCHD
700   LaunchdTimeout = DEFAULT_TIMEOUT + 10;
701 #endif /* HAVE_LAUNCHD */
702
703  /*
704   * Setup environment variables...
705   */
706
707   cupsdInitEnv();
708
709  /*
710   * Read the configuration file...
711   */
712
713   if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
714     return (0);
715
716   status = read_configuration(fp);
717
718   cupsFileClose(fp);
719
720   if (!status)
721     return (0);
722
723   if (!ErrorLog)
724     cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
725
726   RunUser = getuid();
727
728   cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
729                   RemotePort ? "enabled" : "disabled");
730
731   if (!RemotePort)
732     BrowseLocalProtocols = 0;           /* Disable sharing - no remote access */
733
734  /*
735   * See if the ServerName is an IP address...
736   */
737
738   if (ServerName)
739   {
740     if (!ServerAlias)
741       ServerAlias = cupsArrayNew(NULL, NULL);
742
743     cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", ServerName);
744   }
745   else
746   {
747     if (gethostname(temp, sizeof(temp)))
748     {
749       cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s",
750                       strerror(errno));
751       strlcpy(temp, "localhost", sizeof(temp));
752     }
753
754     cupsdSetString(&ServerName, temp);
755
756     if (!ServerAlias)
757       ServerAlias = cupsArrayNew(NULL, NULL);
758
759     cupsdAddAlias(ServerAlias, temp);
760     cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
761
762     if (HostNameLookups)
763     {
764       struct hostent    *host;          /* Host entry to get FQDN */
765
766       if ((host = gethostbyname(temp)) != NULL)
767       {
768         if (_cups_strcasecmp(temp, host->h_name))
769         {
770           cupsdSetString(&ServerName, host->h_name);
771           cupsdAddAlias(ServerAlias, host->h_name);
772           cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
773                           host->h_name);
774         }
775
776         if (host->h_aliases)
777         {
778           for (i = 0; host->h_aliases[i]; i ++)
779             if (_cups_strcasecmp(temp, host->h_aliases[i]))
780             {
781               cupsdAddAlias(ServerAlias, host->h_aliases[i]);
782               cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
783                               host->h_aliases[i]);
784             }
785         }
786       }
787     }
788
789    /*
790     * Make sure we have the base hostname added as an alias, too!
791     */
792
793     if ((slash = strchr(temp, '.')) != NULL)
794     {
795       *slash = '\0';
796       cupsdAddAlias(ServerAlias, temp);
797       cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
798     }
799   }
800
801   for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++);
802
803   ServerNameIsIP = !*slash;
804
805  /*
806   * Make sure ServerAdmin is initialized...
807   */
808
809   if (!ServerAdmin)
810     cupsdSetStringf(&ServerAdmin, "root@%s", ServerName);
811
812  /*
813   * Use the default system group if none was supplied in cupsd.conf...
814   */
815
816   if (NumSystemGroups == 0)
817   {
818     if (!parse_groups(CUPS_DEFAULT_SYSTEM_GROUPS))
819     {
820      /*
821       * Find the group associated with GID 0...
822       */
823
824       group = getgrgid(0);
825       endgrent();
826
827       if (group != NULL)
828         cupsdSetString(&SystemGroups[0], group->gr_name);
829       else
830         cupsdSetString(&SystemGroups[0], "unknown");
831
832       SystemGroupIDs[0] = 0;
833       NumSystemGroups   = 1;
834     }
835   }
836
837  /*
838   * Get the access control list for browsing...
839   */
840
841   BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL");
842
843  /*
844   * Open the system log for cupsd if necessary...
845   */
846
847 #ifdef HAVE_VSYSLOG
848   if (!strcmp(AccessLog, "syslog") ||
849       !strcmp(ErrorLog, "syslog") ||
850       !strcmp(PageLog, "syslog"))
851     openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
852 #endif /* HAVE_VSYSLOG */
853
854  /*
855   * Make sure each of the log files exists and gets rotated as necessary...
856   */
857
858   if (strcmp(AccessLog, "syslog"))
859     cupsdCheckLogFile(&AccessFile, AccessLog);
860
861   if (strcmp(ErrorLog, "syslog"))
862     cupsdCheckLogFile(&ErrorFile, ErrorLog);
863
864   if (strcmp(PageLog, "syslog"))
865     cupsdCheckLogFile(&PageFile, PageLog);
866
867  /*
868   * Log the configuration file that was used...
869   */
870
871   cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"",
872                   ConfigurationFile);
873
874  /*
875   * Validate the Group and SystemGroup settings - they cannot be the same,
876   * otherwise the CGI programs will be able to authenticate as root without
877   * a password!
878   */
879
880   if (!RunUser)
881   {
882     for (i = 0; i < NumSystemGroups; i ++)
883       if (Group == SystemGroupIDs[i])
884         break;
885
886     if (i < NumSystemGroups)
887     {
888      /*
889       * Log the error and reset the group to a safe value...
890       */
891
892       cupsdLogMessage(CUPSD_LOG_NOTICE,
893                       "Group and SystemGroup cannot use the same groups.");
894       cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"...");
895
896       group = getgrnam("nobody");
897       endgrent();
898
899       if (group != NULL)
900         Group = group->gr_gid;
901       else
902       {
903        /*
904         * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
905         * complement number...)
906         */
907
908         Group = 65534;
909       }
910     }
911   }
912
913  /*
914   * Check that we have at least one listen/port line; if not, report this
915   * as an error and exit!
916   */
917
918   if (cupsArrayCount(Listeners) == 0)
919   {
920    /*
921     * No listeners!
922     */
923
924     cupsdLogMessage(CUPSD_LOG_EMERG,
925                     "No valid Listen or Port lines were found in the "
926                     "configuration file.");
927
928    /*
929     * Commit suicide...
930     */
931
932     cupsdEndProcess(getpid(), 0);
933   }
934
935  /*
936   * Set the default locale using the language and charset...
937   */
938
939   cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage);
940
941  /*
942   * Update all relative filenames to include the full path from ServerRoot...
943   */
944
945   if (DocumentRoot[0] != '/')
946     cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
947
948   if (RequestRoot[0] != '/')
949     cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
950
951   if (ServerBin[0] != '/')
952     cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
953
954   if (StateDir[0] != '/')
955     cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir);
956
957   if (CacheDir[0] != '/')
958     cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
959
960 #ifdef HAVE_SSL
961   if (ServerCertificate[0] != '/')
962     cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
963
964   if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot)) &&
965       cupsdCheckPermissions(ServerCertificate, NULL, 0600, RunUser, Group,
966                             0, 0) < 0 &&
967       (FatalErrors & CUPSD_FATAL_PERMISSIONS))
968     return (0);
969
970 #  if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
971   if (ServerKey[0] != '/')
972     cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
973
974   if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot)) &&
975       cupsdCheckPermissions(ServerKey, NULL, 0600, RunUser, Group, 0, 0) < 0 &&
976       (FatalErrors & CUPSD_FATAL_PERMISSIONS))
977     return (0);
978 #  endif /* HAVE_LIBSSL || HAVE_GNUTLS */
979 #endif /* HAVE_SSL */
980
981  /*
982   * Make sure that directories and config files are owned and
983   * writable by the user and group in the cupsd.conf file...
984   */
985
986   snprintf(temp, sizeof(temp), "%s/rss", CacheDir);
987
988   if ((cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
989                              Group, 1, 1) < 0 ||
990        cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
991                              Group, 1, 1) < 0 ||
992        cupsdCheckPermissions(temp, NULL, 0775, RunUser,
993                              Group, 1, 1) < 0 ||
994        cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
995                              Group, 1, 1) < 0 ||
996        cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
997                              SystemGroupIDs[0], 1, 1) < 0 ||
998        cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser,
999                              Group, 1, 0) < 0 ||
1000        cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser,
1001                              Group, 1, 1) < 0 ||
1002        cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser,
1003                              Group, 1, 0) < 0 ||
1004        /* Never alter permissions of central conffile
1005        cupsdCheckPermissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser,
1006                              Group, 0, 0) < 0 ||
1007        */
1008        cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser,
1009                              Group, 0, 0) < 0 ||
1010        cupsdCheckPermissions(ServerRoot, "printers.conf", 0600, RunUser,
1011                              Group, 0, 0) < 0 ||
1012        cupsdCheckPermissions(ServerRoot, "passwd.md5", 0600, User,
1013                              Group, 0, 0) < 0) &&
1014       (FatalErrors & CUPSD_FATAL_PERMISSIONS))
1015     return (0);
1016
1017  /*
1018   * Update TempDir to the default if it hasn't been set already...
1019   */
1020
1021   if (!TempDir)
1022   {
1023 #ifdef __APPLE__
1024     if ((tmpdir = getenv("TMPDIR")) != NULL &&
1025         strncmp(tmpdir, "/private/tmp", 12))
1026 #else
1027     if ((tmpdir = getenv("TMPDIR")) != NULL)
1028 #endif /* __APPLE__ */
1029     {
1030      /*
1031       * TMPDIR is defined, see if it is OK for us to use...
1032       */
1033
1034       if (stat(tmpdir, &tmpinfo))
1035         cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to access TMPDIR (%s): %s",
1036                         tmpdir, strerror(errno));
1037       else if (!S_ISDIR(tmpinfo.st_mode))
1038         cupsdLogMessage(CUPSD_LOG_ERROR, "TMPDIR (%s) is not a directory.",
1039                         tmpdir);
1040       else if ((tmpinfo.st_uid != User || !(tmpinfo.st_mode & S_IWUSR)) &&
1041                (tmpinfo.st_gid != Group || !(tmpinfo.st_mode & S_IWGRP)) &&
1042                !(tmpinfo.st_mode & S_IWOTH))
1043         cupsdLogMessage(CUPSD_LOG_ERROR,
1044                         "TMPDIR (%s) has the wrong permissions.", tmpdir);
1045       else
1046         cupsdSetString(&TempDir, tmpdir);
1047     }
1048
1049     if (!TempDir)
1050     {
1051       cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...",
1052                       RequestRoot);
1053       cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot);
1054     }
1055   }
1056
1057  /*
1058   * Make sure the temporary directory has the right permissions...
1059   */
1060
1061   if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) ||
1062       access(TempDir, 0))
1063   {
1064    /*
1065     * Update ownership and permissions if the CUPS temp directory
1066     * is under the spool directory or does not exist...
1067     */
1068
1069     if (cupsdCheckPermissions(TempDir, NULL, 01770, RunUser, Group, 1, 1) < 0 &&
1070         (FatalErrors & CUPSD_FATAL_PERMISSIONS))
1071       return (0);
1072   }
1073
1074  /*
1075   * Update environment variables...
1076   */
1077
1078   cupsdUpdateEnv();
1079
1080  /*
1081   * Update default paper size setting as needed...
1082   */
1083
1084   if (!DefaultPaperSize)
1085   {
1086 #ifdef HAVE_LIBPAPER
1087     char        *paper_result;          /* Paper size name from libpaper */
1088
1089     if ((paper_result = systempapername()) != NULL)
1090       cupsdSetString(&DefaultPaperSize, paper_result);
1091     else
1092 #endif /* HAVE_LIBPAPER */
1093     if (!DefaultLanguage ||
1094         !_cups_strcasecmp(DefaultLanguage, "C") ||
1095         !_cups_strcasecmp(DefaultLanguage, "POSIX") ||
1096         !_cups_strcasecmp(DefaultLanguage, "en") ||
1097         !_cups_strncasecmp(DefaultLanguage, "en.", 3) ||
1098         !_cups_strncasecmp(DefaultLanguage, "en_US", 5) ||
1099         !_cups_strncasecmp(DefaultLanguage, "en_CA", 5) ||
1100         !_cups_strncasecmp(DefaultLanguage, "fr_CA", 5))
1101     {
1102      /*
1103       * These are the only locales that will default to "letter" size...
1104       */
1105
1106       cupsdSetString(&DefaultPaperSize, "Letter");
1107     }
1108     else
1109       cupsdSetString(&DefaultPaperSize, "A4");
1110   }
1111
1112  /*
1113   * Update classification setting as needed...
1114   */
1115
1116   if (Classification && !_cups_strcasecmp(Classification, "none"))
1117     cupsdClearString(&Classification);
1118
1119   if (Classification)
1120     cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
1121
1122  /*
1123   * Check the MaxClients setting, and then allocate memory for it...
1124   */
1125
1126   if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
1127   {
1128     if (MaxClients > 0)
1129       cupsdLogMessage(CUPSD_LOG_INFO,
1130                       "MaxClients limited to 1/3 (%d) of the file descriptor "
1131                       "limit (%d)...",
1132                       MaxFDs / 3, MaxFDs);
1133
1134     MaxClients = MaxFDs / 3;
1135   }
1136
1137   cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.",
1138                   MaxClients);
1139
1140  /*
1141   * Check the MaxActiveJobs setting; limit to 1/3 the available
1142   * file descriptors, since we need a pipe for each job...
1143   */
1144
1145   if (MaxActiveJobs > (MaxFDs / 3))
1146     MaxActiveJobs = MaxFDs / 3;
1147
1148  /*
1149   * Update the MaxClientsPerHost value, as needed...
1150   */
1151
1152   if (MaxClientsPerHost <= 0)
1153     MaxClientsPerHost = MaxClients;
1154
1155   if (MaxClientsPerHost > MaxClients)
1156     MaxClientsPerHost = MaxClients;
1157
1158   cupsdLogMessage(CUPSD_LOG_INFO,
1159                   "Allowing up to %d client connections per host.",
1160                   MaxClientsPerHost);
1161
1162  /*
1163   * Make sure that BrowseTimeout is at least twice the interval...
1164   */
1165
1166   if (BrowseTimeout < (2 * BrowseInterval) || BrowseTimeout <= 0)
1167   {
1168     cupsdLogMessage(CUPSD_LOG_ALERT, "Invalid BrowseTimeout value %d.",
1169                     BrowseTimeout);
1170
1171     if (BrowseInterval)
1172       BrowseTimeout = BrowseInterval * 2;
1173     else
1174       BrowseTimeout = DEFAULT_TIMEOUT;
1175
1176     cupsdLogMessage(CUPSD_LOG_ALERT, "Reset BrowseTimeout to %d.",
1177                     BrowseTimeout);
1178   }
1179
1180  /*
1181   * Update the default policy, as needed...
1182   */
1183
1184   if (DefaultPolicy)
1185     DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy);
1186   else
1187     DefaultPolicyPtr = NULL;
1188
1189   if (!DefaultPolicyPtr)
1190   {
1191     cupsd_location_t    *po;            /* New policy operation */
1192
1193
1194     if (DefaultPolicy)
1195       cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found.",
1196                       DefaultPolicy);
1197
1198     cupsdSetString(&DefaultPolicy, "default");
1199
1200     if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL)
1201       cupsdLogMessage(CUPSD_LOG_INFO,
1202                       "Using policy \"default\" as the default.");
1203     else
1204     {
1205       cupsdLogMessage(CUPSD_LOG_INFO,
1206                       "Creating CUPS default administrative policy:");
1207
1208       DefaultPolicyPtr = p = cupsdAddPolicy("default");
1209
1210       cupsdLogMessage(CUPSD_LOG_INFO, "<Policy default>");
1211
1212       cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateAccess default");
1213       cupsdAddString(&(p->job_access), "@OWNER");
1214       cupsdAddString(&(p->job_access), "@SYSTEM");
1215
1216       cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateValues default");
1217       cupsdAddString(&(p->job_attrs), "job-name");
1218       cupsdAddString(&(p->job_attrs), "job-originating-host-name");
1219       cupsdAddString(&(p->job_attrs), "job-originating-user-name");
1220
1221       cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateAccess default");
1222       cupsdAddString(&(p->sub_access), "@OWNER");
1223       cupsdAddString(&(p->sub_access), "@SYSTEM");
1224
1225       cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateValues default");
1226       cupsdAddString(&(p->job_attrs), "notify-events");
1227       cupsdAddString(&(p->job_attrs), "notify-pull-method");
1228       cupsdAddString(&(p->job_attrs), "notify-recipient-uri");
1229       cupsdAddString(&(p->job_attrs), "notify-subscriber-user-name");
1230       cupsdAddString(&(p->job_attrs), "notify-user-data");
1231
1232       cupsdLogMessage(CUPSD_LOG_INFO,
1233                       "<Limit Create-Job Print-Job Print-URI Validate-Job>");
1234       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1235
1236       po = cupsdAddPolicyOp(p, NULL, IPP_CREATE_JOB);
1237       po->order_type = CUPSD_AUTH_ALLOW;
1238
1239       cupsdAddPolicyOp(p, po, IPP_PRINT_JOB);
1240       cupsdAddPolicyOp(p, po, IPP_PRINT_URI);
1241       cupsdAddPolicyOp(p, po, IPP_VALIDATE_JOB);
1242
1243       cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1244
1245       cupsdLogMessage(CUPSD_LOG_INFO,
1246                       "<Limit Send-Document Send-URI Cancel-Job Hold-Job "
1247                       "Release-Job Restart-Job Purge-Jobs "
1248                       "Set-Job-Attributes Create-Job-Subscription "
1249                       "Renew-Subscription Cancel-Subscription "
1250                       "Get-Notifications Reprocess-Job Cancel-Current-Job "
1251                       "Suspend-Current-Job Resume-Job "
1252                       "Cancel-My-Jobs Close-Job CUPS-Move-Job "
1253                       "CUPS-Authenticate-Job CUPS-Get-Document>");
1254       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1255
1256       po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT);
1257       po->order_type = CUPSD_AUTH_ALLOW;
1258       po->level      = CUPSD_AUTH_USER;
1259
1260       cupsdAddName(po, "@OWNER");
1261       cupsdAddName(po, "@SYSTEM");
1262       cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM");
1263
1264       cupsdAddPolicyOp(p, po, IPP_SEND_URI);
1265       cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB);
1266       cupsdAddPolicyOp(p, po, IPP_HOLD_JOB);
1267       cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB);
1268       cupsdAddPolicyOp(p, po, IPP_RESTART_JOB);
1269       cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS);
1270       cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES);
1271       cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION);
1272       cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION);
1273       cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION);
1274       cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS);
1275       cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB);
1276       cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB);
1277       cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB);
1278       cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
1279       cupsdAddPolicyOp(p, po, IPP_CANCEL_MY_JOBS);
1280       cupsdAddPolicyOp(p, po, IPP_CLOSE_JOB);
1281       cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
1282       cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB);
1283       cupsdAddPolicyOp(p, po, CUPS_GET_DOCUMENT);
1284
1285       cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1286
1287       cupsdLogMessage(CUPSD_LOG_INFO,
1288                       "<Limit Pause-Printer Resume-Printer "
1289                       "Set-Printer-Attributes Enable-Printer "
1290                       "Disable-Printer Pause-Printer-After-Current-Job "
1291                       "Hold-New-Jobs Release-Held-New-Jobs "
1292                       "Deactivate-Printer Activate-Printer Restart-Printer "
1293                       "Shutdown-Printer Startup-Printer Promote-Job "
1294                       "Schedule-Job-After Cancel-Jobs CUPS-Add-Printer "
1295                       "CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class "
1296                       "CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>");
1297       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1298       cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Default");
1299
1300       po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER);
1301       po->order_type = CUPSD_AUTH_ALLOW;
1302       po->type       = CUPSD_AUTH_DEFAULT;
1303       po->level      = CUPSD_AUTH_USER;
1304
1305       cupsdAddName(po, "@SYSTEM");
1306       cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM");
1307
1308       cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER);
1309       cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES);
1310       cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER);
1311       cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER);
1312       cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB);
1313       cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS);
1314       cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS);
1315       cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER);
1316       cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER);
1317       cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER);
1318       cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER);
1319       cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER);
1320       cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB);
1321       cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER);
1322       cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS);
1323       cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER);
1324       cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER);
1325       cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS);
1326       cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS);
1327       cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS);
1328       cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS);
1329       cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT);
1330
1331       cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1332
1333       cupsdLogMessage(CUPSD_LOG_INFO, "<Limit All>");
1334       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1335
1336       po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION);
1337       po->order_type = CUPSD_AUTH_ALLOW;
1338
1339       cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1340       cupsdLogMessage(CUPSD_LOG_INFO, "</Policy>");
1341     }
1342   }
1343
1344   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d",
1345                   cupsArrayCount(Policies));
1346   for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
1347        p;
1348        i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
1349     cupsdLogMessage(CUPSD_LOG_DEBUG2,
1350                     "cupsdReadConfiguration: Policies[%d]=\"%s\"", i, p->name);
1351
1352  /*
1353   * If we are doing a full reload or the server root has changed, flush
1354   * the jobs, printers, etc. and start from scratch...
1355   */
1356
1357   if (NeedReload == RELOAD_ALL ||
1358       old_remote_port != RemotePort ||
1359       !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
1360       !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
1361   {
1362     mime_type_t *type;                  /* Current type */
1363     char        mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE];
1364                                         /* MIME type name */
1365
1366
1367     cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required.");
1368
1369    /*
1370     * Free all memory...
1371     */
1372
1373     cupsdDeleteAllSubscriptions();
1374     cupsdFreeAllJobs();
1375     cupsdDeleteAllPrinters();
1376
1377     DefaultPrinter = NULL;
1378
1379     if (MimeDatabase != NULL)
1380       mimeDelete(MimeDatabase);
1381
1382     if (NumMimeTypes)
1383     {
1384       for (i = 0; i < NumMimeTypes; i ++)
1385         _cupsStrFree(MimeTypes[i]);
1386
1387       free(MimeTypes);
1388     }
1389
1390    /*
1391     * Read the MIME type and conversion database...
1392     */
1393
1394     snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
1395     snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
1396
1397     MimeDatabase = mimeNew();
1398     mimeSetErrorCallback(MimeDatabase, mime_error_cb, NULL);
1399
1400     MimeDatabase = mimeLoadTypes(MimeDatabase, mimedir);
1401     MimeDatabase = mimeLoadTypes(MimeDatabase, ServerRoot);
1402     MimeDatabase = mimeLoadFilters(MimeDatabase, mimedir, temp);
1403     MimeDatabase = mimeLoadFilters(MimeDatabase, ServerRoot, temp);
1404
1405     if (!MimeDatabase)
1406     {
1407       cupsdLogMessage(CUPSD_LOG_EMERG,
1408                       "Unable to load MIME database from \"%s\" or \"%s\".",
1409                       mimedir, ServerRoot);
1410       if (FatalErrors & CUPSD_FATAL_CONFIG)
1411         return (0);
1412     }
1413
1414     cupsdLogMessage(CUPSD_LOG_INFO,
1415                     "Loaded MIME database from \"%s\" and \"%s\": %d types, "
1416                     "%d filters...", mimedir, ServerRoot,
1417                     mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
1418
1419    /*
1420     * Create a list of MIME types for the document-format-supported
1421     * attribute...
1422     */
1423
1424     NumMimeTypes = mimeNumTypes(MimeDatabase);
1425     if (!mimeType(MimeDatabase, "application", "octet-stream"))
1426       NumMimeTypes ++;
1427
1428     if ((MimeTypes = calloc(NumMimeTypes, sizeof(const char *))) == NULL)
1429     {
1430       cupsdLogMessage(CUPSD_LOG_ERROR,
1431                       "Unable to allocate memory for %d MIME types.",
1432                       NumMimeTypes);
1433       NumMimeTypes = 0;
1434     }
1435     else
1436     {
1437       for (i = 0, type = mimeFirstType(MimeDatabase);
1438            type;
1439            i ++, type = mimeNextType(MimeDatabase))
1440       {
1441         snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
1442
1443         MimeTypes[i] = _cupsStrAlloc(mimetype);
1444       }
1445
1446       if (i < NumMimeTypes)
1447         MimeTypes[i] = _cupsStrAlloc("application/octet-stream");
1448     }
1449
1450     if (LogLevel == CUPSD_LOG_DEBUG2)
1451     {
1452       mime_filter_t     *filter;        /* Current filter */
1453
1454
1455       for (type = mimeFirstType(MimeDatabase);
1456            type;
1457            type = mimeNextType(MimeDatabase))
1458         cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: type %s/%s",
1459                         type->super, type->type);
1460
1461       for (filter = mimeFirstFilter(MimeDatabase);
1462            filter;
1463            filter = mimeNextFilter(MimeDatabase))
1464         cupsdLogMessage(CUPSD_LOG_DEBUG2,
1465                         "cupsdReadConfiguration: filter %s/%s to %s/%s %d %s",
1466                         filter->src->super, filter->src->type,
1467                         filter->dst->super, filter->dst->type,
1468                         filter->cost, filter->filter);
1469     }
1470
1471    /*
1472     * Load banners...
1473     */
1474
1475     snprintf(temp, sizeof(temp), "%s/banners", DataDir);
1476     cupsdLoadBanners(temp);
1477
1478    /*
1479     * Load printers and classes...
1480     */
1481
1482     cupsdLoadAllPrinters();
1483     cupsdLoadAllClasses();
1484     cupsdLoadRemoteCache();
1485
1486     cupsdCreateCommonData();
1487
1488    /*
1489     * Update the printcap file as needed...
1490     */
1491
1492     if (Printcap && *Printcap && access(Printcap, 0))
1493       cupsdWritePrintcap();
1494
1495    /*
1496     * Load queued jobs...
1497     */
1498
1499     cupsdLoadAllJobs();
1500
1501    /*
1502     * Load subscriptions...
1503     */
1504
1505     cupsdLoadAllSubscriptions();
1506
1507     cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete.");
1508   }
1509   else
1510   {
1511    /*
1512     * Not a full reload, so recreate the common printer attributes...
1513     */
1514
1515     cupsdCreateCommonData();
1516
1517    /*
1518     * Update all printers as needed...
1519     */
1520
1521     cupsdUpdatePrinters();
1522     cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
1523
1524     cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete.");
1525   }
1526
1527  /*
1528   * Reset the reload state...
1529   */
1530
1531   NeedReload = RELOAD_NONE;
1532
1533   cupsdClearString(&old_serverroot);
1534   cupsdClearString(&old_requestroot);
1535
1536   return (1);
1537 }
1538
1539
1540 /*
1541  * 'get_address()' - Get an address + port number from a line.
1542  */
1543
1544 static http_addrlist_t *                /* O - Pointer to list if address good, NULL if bad */
1545 get_address(const char  *value,         /* I - Value string */
1546             int         defport)        /* I - Default port */
1547 {
1548   char                  buffer[1024],   /* Hostname + port number buffer */
1549                         defpname[255],  /* Default port name */
1550                         *hostname,      /* Hostname or IP */
1551                         *portname;      /* Port number or name */
1552   http_addrlist_t       *addrlist;      /* Address list */
1553
1554
1555  /*
1556   * Check for an empty value...
1557   */
1558
1559   if (!*value)
1560   {
1561     cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address.");
1562     return (NULL);
1563   }
1564
1565  /*
1566   * Grab a hostname and port number; if there is no colon and the port name
1567   * is only digits, then we have a port number by itself...
1568   */
1569
1570   strlcpy(buffer, value, sizeof(buffer));
1571
1572   if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']'))
1573   {
1574     *portname++ = '\0';
1575     hostname = buffer;
1576   }
1577   else
1578   {
1579     for (portname = buffer; isdigit(*portname & 255); portname ++);
1580
1581     if (*portname)
1582     {
1583      /*
1584       * Use the default port...
1585       */
1586
1587       sprintf(defpname, "%d", defport);
1588       portname = defpname;
1589       hostname = buffer;
1590     }
1591     else
1592     {
1593      /*
1594       * The buffer contains just a port number...
1595       */
1596
1597       portname = buffer;
1598       hostname = NULL;
1599     }
1600   }
1601
1602   if (hostname && !strcmp(hostname, "*"))
1603     hostname = NULL;
1604
1605  /*
1606   * Now lookup the address using httpAddrGetList()...
1607   */
1608
1609   if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
1610     cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed.",
1611                     hostname ? hostname : "(nil)");
1612
1613   return (addrlist);
1614 }
1615
1616
1617 /*
1618  * 'get_addr_and_mask()' - Get an IP address and netmask.
1619  */
1620
1621 static int                              /* O - 1 on success, 0 on failure */
1622 get_addr_and_mask(const char *value,    /* I - String from config file */
1623                   unsigned   *ip,       /* O - Address value */
1624                   unsigned   *mask)     /* O - Mask value */
1625 {
1626   int           i, j,                   /* Looping vars */
1627                 family,                 /* Address family */
1628                 ipcount;                /* Count of fields in address */
1629   unsigned      ipval;                  /* Value */
1630   const char    *maskval,               /* Pointer to start of mask value */
1631                 *ptr,                   /* Pointer into value */
1632                 *ptr2;                  /* ... */
1633
1634
1635  /*
1636   * Get the address...
1637   */
1638
1639   ip[0]   = ip[1]   = ip[2]   = ip[3]   = 0x00000000;
1640   mask[0] = mask[1] = mask[2] = mask[3] = 0xffffffff;
1641
1642   if ((maskval = strchr(value, '/')) != NULL)
1643     maskval ++;
1644   else
1645     maskval = value + strlen(value);
1646
1647 #ifdef AF_INET6
1648  /*
1649   * Check for an IPv6 address...
1650   */
1651
1652   if (*value == '[')
1653   {
1654    /*
1655     * Parse hexadecimal IPv6/IPv4 address...
1656     */
1657
1658     family  = AF_INET6;
1659
1660     for (i = 0, ptr = value + 1; *ptr && i < 8; i ++)
1661     {
1662       if (*ptr == ']')
1663         break;
1664       else if (!strncmp(ptr, "::", 2))
1665       {
1666         for (ptr2 = strchr(ptr + 2, ':'), j = 0;
1667              ptr2;
1668              ptr2 = strchr(ptr2 + 1, ':'), j ++);
1669
1670         i = 6 - j;
1671         ptr += 2;
1672       }
1673       else if (isdigit(*ptr & 255) && strchr(ptr + 1, '.') && i >= 6)
1674       {
1675        /*
1676         * Read IPv4 dotted quad...
1677         */
1678
1679         unsigned val[4] = { 0, 0, 0, 0 };
1680                                         /* IPv4 address values */
1681
1682         ipcount = sscanf(ptr, "%u.%u.%u.%u", val + 0, val + 1, val + 2,
1683                          val + 3);
1684
1685        /*
1686         * Range check the IP numbers...
1687         */
1688
1689         for (i = 0; i < ipcount; i ++)
1690           if (val[i] > 255)
1691             return (0);
1692
1693        /*
1694         * Merge everything into a 32-bit IPv4 address in ip[3]...
1695         */
1696
1697         ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
1698
1699         if (ipcount < 4)
1700           mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
1701
1702        /*
1703         * If the leading words are all 0's then this is an IPv4 address...
1704         */
1705
1706         if (!val[0] && !val[1] && !val[2])
1707           family  = AF_INET;
1708
1709         while (isdigit(*ptr & 255) || *ptr == '.')
1710           ptr ++;
1711         break;
1712       }
1713       else if (isxdigit(*ptr & 255))
1714       {
1715         ipval = strtoul(ptr, (char **)&ptr, 16);
1716
1717         if (*ptr == ':' && ptr[1] != ':')
1718           ptr ++;
1719
1720         if (ipval > 0xffff)
1721           return (0);
1722
1723         if (i & 1)
1724           ip[i / 2] |= ipval;
1725         else
1726           ip[i / 2] |= ipval << 16;
1727       }
1728       else
1729         return (0);
1730     }
1731
1732     if (*ptr != ']')
1733       return (0);
1734
1735     ptr ++;
1736
1737     if (*ptr && *ptr != '/')
1738       return (0);
1739   }
1740   else
1741 #endif /* AF_INET6 */
1742   {
1743    /*
1744     * Parse dotted-decimal IPv4 address...
1745     */
1746
1747     unsigned val[4] = { 0, 0, 0, 0 };   /* IPv4 address values */
1748
1749
1750     family  = AF_INET;
1751     ipcount = sscanf(value, "%u.%u.%u.%u", val + 0, val + 1, val + 2, val + 3);
1752
1753    /*
1754     * Range check the IP numbers...
1755     */
1756
1757     for (i = 0; i < ipcount; i ++)
1758       if (val[i] > 255)
1759         return (0);
1760
1761    /*
1762     * Merge everything into a 32-bit IPv4 address in ip[3]...
1763     */
1764
1765     ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
1766
1767     if (ipcount < 4)
1768       mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
1769   }
1770
1771   if (*maskval)
1772   {
1773    /*
1774     * Get the netmask value(s)...
1775     */
1776
1777     memset(mask, 0, sizeof(unsigned) * 4);
1778
1779     if (strchr(maskval, '.'))
1780     {
1781      /*
1782       * Get dotted-decimal mask...
1783       */
1784
1785       if (family != AF_INET)
1786         return (0);
1787
1788       if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2,
1789                  mask + 3) != 4)
1790         return (0);
1791
1792       mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8;
1793       mask[0] = mask[1] = mask[2] = 0;
1794     }
1795     else
1796     {
1797      /*
1798       * Get address/bits format...
1799       */
1800
1801       i = atoi(maskval);
1802
1803 #ifdef AF_INET6
1804       if (family == AF_INET6)
1805       {
1806         if (i > 128)
1807           return (0);
1808
1809         i = 128 - i;
1810
1811         if (i <= 96)
1812           mask[0] = 0xffffffff;
1813         else
1814           mask[0] = (0xffffffff << (i - 96)) & 0xffffffff;
1815
1816         if (i <= 64)
1817           mask[1] = 0xffffffff;
1818         else if (i >= 96)
1819           mask[1] = 0;
1820         else
1821           mask[1] = (0xffffffff << (i - 64)) & 0xffffffff;
1822
1823         if (i <= 32)
1824           mask[2] = 0xffffffff;
1825         else if (i >= 64)
1826           mask[2] = 0;
1827         else
1828           mask[2] = (0xffffffff << (i - 32)) & 0xffffffff;
1829
1830         if (i == 0)
1831           mask[3] = 0xffffffff;
1832         else if (i >= 32)
1833           mask[3] = 0;
1834         else
1835           mask[3] = (0xffffffff << i) & 0xffffffff;
1836       }
1837       else
1838 #endif /* AF_INET6 */
1839       {
1840         if (i > 32)
1841           return (0);
1842
1843         mask[0] = 0xffffffff;
1844         mask[1] = 0xffffffff;
1845         mask[2] = 0xffffffff;
1846
1847         if (i < 32)
1848           mask[3] = (0xffffffff << (32 - i)) & 0xffffffff;
1849         else
1850           mask[3] = 0xffffffff;
1851       }
1852     }
1853   }
1854
1855   cupsdLogMessage(CUPSD_LOG_DEBUG2,
1856                   "get_addr_and_mask(value=\"%s\", "
1857                   "ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x])",
1858              value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2],
1859              mask[3]);
1860
1861  /*
1862   * Check for a valid netmask; no fallback like in CUPS 1.1.x!
1863   */
1864
1865   if ((ip[0] & ~mask[0]) != 0 ||
1866       (ip[1] & ~mask[1]) != 0 ||
1867       (ip[2] & ~mask[2]) != 0 ||
1868       (ip[3] & ~mask[3]) != 0)
1869     return (0);
1870
1871   return (1);
1872 }
1873
1874
1875 /*
1876  * 'mime_error_cb()' - Log a MIME error.
1877  */
1878
1879 static void
1880 mime_error_cb(void       *ctx,          /* I - Context pointer (unused) */
1881               const char *message)      /* I - Message */
1882 {
1883   (void)ctx;
1884
1885   cupsdLogMessage(CUPSD_LOG_ERROR, "%s", message);
1886 }
1887
1888
1889 /*
1890  * 'parse_aaa()' - Parse authentication, authorization, and access control lines.
1891  */
1892
1893 static int                              /* O - 1 on success, 0 on failure */
1894 parse_aaa(cupsd_location_t *loc,        /* I - Location */
1895           char             *line,       /* I - Line from file */
1896           char             *value,      /* I - Start of value data */
1897           int              linenum)     /* I - Current line number */
1898 {
1899   char          *valptr;                /* Pointer into value */
1900   unsigned      ip[4],                  /* IP address components */
1901                 mask[4];                /* IP netmask components */
1902
1903
1904   if (!_cups_strcasecmp(line, "Encryption"))
1905   {
1906    /*
1907     * "Encryption xxx" - set required encryption level...
1908     */
1909
1910     if (!_cups_strcasecmp(value, "never"))
1911       loc->encryption = HTTP_ENCRYPT_NEVER;
1912     else if (!_cups_strcasecmp(value, "always"))
1913     {
1914       cupsdLogMessage(CUPSD_LOG_ERROR,
1915                       "Encryption value \"%s\" on line %d is invalid in this "
1916                       "context. Using \"required\" instead.", value, linenum);
1917
1918       loc->encryption = HTTP_ENCRYPT_REQUIRED;
1919     }
1920     else if (!_cups_strcasecmp(value, "required"))
1921       loc->encryption = HTTP_ENCRYPT_REQUIRED;
1922     else if (!_cups_strcasecmp(value, "ifrequested"))
1923       loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
1924     else
1925     {
1926       cupsdLogMessage(CUPSD_LOG_ERROR,
1927                       "Unknown Encryption value %s on line %d.", value, linenum);
1928       return (0);
1929     }
1930   }
1931   else if (!_cups_strcasecmp(line, "Order"))
1932   {
1933    /*
1934     * "Order Deny,Allow" or "Order Allow,Deny"...
1935     */
1936
1937     if (!_cups_strncasecmp(value, "deny", 4))
1938       loc->order_type = CUPSD_AUTH_ALLOW;
1939     else if (!_cups_strncasecmp(value, "allow", 5))
1940       loc->order_type = CUPSD_AUTH_DENY;
1941     else
1942     {
1943       cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.",
1944                       value, linenum);
1945       return (0);
1946     }
1947   }
1948   else if (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny"))
1949   {
1950    /*
1951     * Allow [From] host/ip...
1952     * Deny [From] host/ip...
1953     */
1954
1955     while (*value)
1956     {
1957       if (!_cups_strncasecmp(value, "from", 4))
1958       {
1959        /*
1960         * Strip leading "from"...
1961         */
1962
1963         value += 4;
1964
1965         while (_cups_isspace(*value))
1966           value ++;
1967
1968         if (!*value)
1969           break;
1970       }
1971
1972      /*
1973       * Find the end of the value...
1974       */
1975
1976       for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
1977
1978       while (_cups_isspace(*valptr))
1979         *valptr++ = '\0';
1980
1981      /*
1982       * Figure out what form the allow/deny address takes:
1983       *
1984       *    All
1985       *    None
1986       *    *.domain.com
1987       *    .domain.com
1988       *    host.domain.com
1989       *    nnn.*
1990       *    nnn.nnn.*
1991       *    nnn.nnn.nnn.*
1992       *    nnn.nnn.nnn.nnn
1993       *    nnn.nnn.nnn.nnn/mm
1994       *    nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
1995       */
1996
1997       if (!_cups_strcasecmp(value, "all"))
1998       {
1999        /*
2000         * All hosts...
2001         */
2002
2003         if (!_cups_strcasecmp(line, "Allow"))
2004           cupsdAddIPMask(&(loc->allow), zeros, zeros);
2005         else
2006           cupsdAddIPMask(&(loc->deny), zeros, zeros);
2007       }
2008       else if (!_cups_strcasecmp(value, "none"))
2009       {
2010        /*
2011         * No hosts...
2012         */
2013
2014         if (!_cups_strcasecmp(line, "Allow"))
2015           cupsdAddIPMask(&(loc->allow), ones, zeros);
2016         else
2017           cupsdAddIPMask(&(loc->deny), ones, zeros);
2018       }
2019 #ifdef AF_INET6
2020       else if (value[0] == '*' || value[0] == '.' ||
2021                (!isdigit(value[0] & 255) && value[0] != '['))
2022 #else
2023       else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
2024 #endif /* AF_INET6 */
2025       {
2026        /*
2027         * Host or domain name...
2028         */
2029
2030         if (value[0] == '*')
2031           value ++;
2032
2033         if (!_cups_strcasecmp(line, "Allow"))
2034           cupsdAddNameMask(&(loc->allow), value);
2035         else
2036           cupsdAddNameMask(&(loc->deny), value);
2037       }
2038       else
2039       {
2040        /*
2041         * One of many IP address forms...
2042         */
2043
2044         if (!get_addr_and_mask(value, ip, mask))
2045         {
2046           cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
2047                           value, linenum);
2048           return (0);
2049         }
2050
2051         if (!_cups_strcasecmp(line, "Allow"))
2052           cupsdAddIPMask(&(loc->allow), ip, mask);
2053         else
2054           cupsdAddIPMask(&(loc->deny), ip, mask);
2055       }
2056
2057      /*
2058       * Advance to next value...
2059       */
2060
2061       value = valptr;
2062     }
2063   }
2064   else if (!_cups_strcasecmp(line, "AuthType"))
2065   {
2066    /*
2067     * AuthType {none,basic,digest,basicdigest,negotiate,default}
2068     */
2069
2070     if (!_cups_strcasecmp(value, "none"))
2071     {
2072       loc->type  = CUPSD_AUTH_NONE;
2073       loc->level = CUPSD_AUTH_ANON;
2074     }
2075     else if (!_cups_strcasecmp(value, "basic"))
2076     {
2077       loc->type = CUPSD_AUTH_BASIC;
2078
2079       if (loc->level == CUPSD_AUTH_ANON)
2080         loc->level = CUPSD_AUTH_USER;
2081     }
2082     else if (!_cups_strcasecmp(value, "digest"))
2083     {
2084       loc->type = CUPSD_AUTH_DIGEST;
2085
2086       if (loc->level == CUPSD_AUTH_ANON)
2087         loc->level = CUPSD_AUTH_USER;
2088     }
2089     else if (!_cups_strcasecmp(value, "basicdigest"))
2090     {
2091       loc->type = CUPSD_AUTH_BASICDIGEST;
2092
2093       if (loc->level == CUPSD_AUTH_ANON)
2094         loc->level = CUPSD_AUTH_USER;
2095     }
2096     else if (!_cups_strcasecmp(value, "default"))
2097     {
2098       loc->type = CUPSD_AUTH_DEFAULT;
2099
2100       if (loc->level == CUPSD_AUTH_ANON)
2101         loc->level = CUPSD_AUTH_USER;
2102     }
2103 #ifdef HAVE_GSSAPI
2104     else if (!_cups_strcasecmp(value, "negotiate"))
2105     {
2106       loc->type = CUPSD_AUTH_NEGOTIATE;
2107
2108       if (loc->level == CUPSD_AUTH_ANON)
2109         loc->level = CUPSD_AUTH_USER;
2110     }
2111 #endif /* HAVE_GSSAPI */
2112     else
2113     {
2114       cupsdLogMessage(CUPSD_LOG_WARN,
2115                       "Unknown authorization type %s on line %d.",
2116                       value, linenum);
2117       return (0);
2118     }
2119   }
2120   else if (!_cups_strcasecmp(line, "AuthClass"))
2121   {
2122    /*
2123     * AuthClass anonymous, user, system, group
2124     */
2125
2126     if (!_cups_strcasecmp(value, "anonymous"))
2127     {
2128       loc->type  = CUPSD_AUTH_NONE;
2129       loc->level = CUPSD_AUTH_ANON;
2130
2131       cupsdLogMessage(CUPSD_LOG_WARN,
2132                       "\"AuthClass %s\" is deprecated; consider removing "
2133                       "it from line %d.",
2134                       value, linenum);
2135     }
2136     else if (!_cups_strcasecmp(value, "user"))
2137     {
2138       loc->level = CUPSD_AUTH_USER;
2139
2140       cupsdLogMessage(CUPSD_LOG_WARN,
2141                       "\"AuthClass %s\" is deprecated; consider using "
2142                       "\"Require valid-user\" on line %d.",
2143                       value, linenum);
2144     }
2145     else if (!_cups_strcasecmp(value, "group"))
2146     {
2147       loc->level = CUPSD_AUTH_GROUP;
2148
2149       cupsdLogMessage(CUPSD_LOG_WARN,
2150                       "\"AuthClass %s\" is deprecated; consider using "
2151                       "\"Require user @groupname\" on line %d.",
2152                       value, linenum);
2153     }
2154     else if (!_cups_strcasecmp(value, "system"))
2155     {
2156       loc->level = CUPSD_AUTH_GROUP;
2157
2158       cupsdAddName(loc, "@SYSTEM");
2159
2160       cupsdLogMessage(CUPSD_LOG_WARN,
2161                       "\"AuthClass %s\" is deprecated; consider using "
2162                       "\"Require user @SYSTEM\" on line %d.",
2163                       value, linenum);
2164     }
2165     else
2166     {
2167       cupsdLogMessage(CUPSD_LOG_WARN,
2168                       "Unknown authorization class %s on line %d.",
2169                       value, linenum);
2170       return (0);
2171     }
2172   }
2173   else if (!_cups_strcasecmp(line, "AuthGroupName"))
2174   {
2175     cupsdAddName(loc, value);
2176
2177     cupsdLogMessage(CUPSD_LOG_WARN,
2178                     "\"AuthGroupName %s\" directive is deprecated; consider "
2179                     "using \"Require user @%s\" on line %d.",
2180                     value, value, linenum);
2181   }
2182   else if (!_cups_strcasecmp(line, "Require"))
2183   {
2184    /*
2185     * Apache synonym for AuthClass and AuthGroupName...
2186     *
2187     * Get initial word:
2188     *
2189     *     Require valid-user
2190     *     Require group names
2191     *     Require user names
2192     */
2193
2194     for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
2195
2196     if (*valptr)
2197       *valptr++ = '\0';
2198
2199     if (!_cups_strcasecmp(value, "valid-user") ||
2200         !_cups_strcasecmp(value, "user"))
2201       loc->level = CUPSD_AUTH_USER;
2202     else if (!_cups_strcasecmp(value, "group"))
2203       loc->level = CUPSD_AUTH_GROUP;
2204     else
2205     {
2206       cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.",
2207                       value, linenum);
2208       return (0);
2209     }
2210
2211    /*
2212     * Get the list of names from the line...
2213     */
2214
2215     for (value = valptr; *value;)
2216     {
2217       while (_cups_isspace(*value))
2218         value ++;
2219
2220 #ifdef HAVE_AUTHORIZATION_H
2221       if (!strncmp(value, "@AUTHKEY(", 9))
2222       {
2223        /*
2224         * Grab "@AUTHKEY(name)" value...
2225         */
2226
2227         for (valptr = value + 9; *valptr != ')' && *valptr; valptr ++);
2228
2229         if (*valptr)
2230           *valptr++ = '\0';
2231       }
2232       else
2233 #endif /* HAVE_AUTHORIZATION_H */
2234       if (*value == '\"' || *value == '\'')
2235       {
2236        /*
2237         * Grab quoted name...
2238         */
2239
2240         for (valptr = value + 1; *valptr != *value && *valptr; valptr ++);
2241
2242         value ++;
2243       }
2244       else
2245       {
2246        /*
2247         * Grab literal name.
2248         */
2249
2250         for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
2251       }
2252
2253       if (*valptr)
2254         *valptr++ = '\0';
2255
2256       cupsdAddName(loc, value);
2257
2258       for (value = valptr; _cups_isspace(*value); value ++);
2259     }
2260   }
2261   else if (!_cups_strcasecmp(line, "Satisfy"))
2262   {
2263     if (!_cups_strcasecmp(value, "all"))
2264       loc->satisfy = CUPSD_AUTH_SATISFY_ALL;
2265     else if (!_cups_strcasecmp(value, "any"))
2266       loc->satisfy = CUPSD_AUTH_SATISFY_ANY;
2267     else
2268     {
2269       cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.",
2270                       value, linenum);
2271       return (0);
2272     }
2273   }
2274   else
2275     return (0);
2276
2277   return (1);
2278 }
2279
2280
2281 /*
2282  * 'parse_fatal_errors()' - Parse FatalErrors values in a string.
2283  */
2284
2285 static int                              /* O - FatalErrors bits */
2286 parse_fatal_errors(const char *s)       /* I - FatalErrors string */
2287 {
2288   int   fatal;                          /* FatalErrors bits */
2289   char  value[1024],                    /* Value string */
2290         *valstart,                      /* Pointer into value */
2291         *valend;                        /* End of value */
2292
2293
2294  /*
2295   * Empty FatalErrors line yields NULL pointer...
2296   */
2297
2298   if (!s)
2299     return (CUPSD_FATAL_NONE);
2300
2301  /*
2302   * Loop through the value string,...
2303   */
2304
2305   strlcpy(value, s, sizeof(value));
2306
2307   fatal = CUPSD_FATAL_NONE;
2308
2309   for (valstart = value; *valstart;)
2310   {
2311    /*
2312     * Get the current space/comma-delimited kind name...
2313     */
2314
2315     for (valend = valstart; *valend; valend ++)
2316       if (_cups_isspace(*valend) || *valend == ',')
2317         break;
2318
2319     if (*valend)
2320       *valend++ = '\0';
2321
2322    /*
2323     * Add the error to the bitmask...
2324     */
2325
2326     if (!_cups_strcasecmp(valstart, "all"))
2327       fatal = CUPSD_FATAL_ALL;
2328     else if (!_cups_strcasecmp(valstart, "browse"))
2329       fatal |= CUPSD_FATAL_BROWSE;
2330     else if (!_cups_strcasecmp(valstart, "-browse"))
2331       fatal &= ~CUPSD_FATAL_BROWSE;
2332     else if (!_cups_strcasecmp(valstart, "config"))
2333       fatal |= CUPSD_FATAL_CONFIG;
2334     else if (!_cups_strcasecmp(valstart, "-config"))
2335       fatal &= ~CUPSD_FATAL_CONFIG;
2336     else if (!_cups_strcasecmp(valstart, "listen"))
2337       fatal |= CUPSD_FATAL_LISTEN;
2338     else if (!_cups_strcasecmp(valstart, "-listen"))
2339       fatal &= ~CUPSD_FATAL_LISTEN;
2340     else if (!_cups_strcasecmp(valstart, "log"))
2341       fatal |= CUPSD_FATAL_LOG;
2342     else if (!_cups_strcasecmp(valstart, "-log"))
2343       fatal &= ~CUPSD_FATAL_LOG;
2344     else if (!_cups_strcasecmp(valstart, "permissions"))
2345       fatal |= CUPSD_FATAL_PERMISSIONS;
2346     else if (!_cups_strcasecmp(valstart, "-permissions"))
2347       fatal &= ~CUPSD_FATAL_PERMISSIONS;
2348     else if (_cups_strcasecmp(valstart, "none"))
2349       cupsdLogMessage(CUPSD_LOG_ERROR,
2350                       "Unknown FatalErrors kind \"%s\" ignored.", valstart);
2351
2352     for (valstart = valend; *valstart; valstart ++)
2353       if (!_cups_isspace(*valstart) || *valstart != ',')
2354         break;
2355   }
2356
2357   return (fatal);
2358 }
2359
2360
2361 /*
2362  * 'parse_groups()' - Parse system group names in a string.
2363  */
2364
2365 static int                              /* O - 1 on success, 0 on failure */
2366 parse_groups(const char *s)             /* I - Space-delimited groups */
2367 {
2368   int           status;                 /* Return status */
2369   char          value[1024],            /* Value string */
2370                 *valstart,              /* Pointer into value */
2371                 *valend,                /* End of value */
2372                 quote;                  /* Quote character */
2373   struct group  *group;                 /* Group */
2374
2375
2376  /*
2377   * Make a copy of the string and parse out the groups...
2378   */
2379
2380   strlcpy(value, s, sizeof(value));
2381
2382   status   = 1;
2383   valstart = value;
2384
2385   while (*valstart && NumSystemGroups < MAX_SYSTEM_GROUPS)
2386   {
2387     if (*valstart == '\'' || *valstart == '\"')
2388     {
2389      /*
2390       * Scan quoted name...
2391       */
2392
2393       quote = *valstart++;
2394
2395       for (valend = valstart; *valend; valend ++)
2396         if (*valend == quote)
2397           break;
2398     }
2399     else
2400     {
2401      /*
2402       * Scan space or comma-delimited name...
2403       */
2404
2405       for (valend = valstart; *valend; valend ++)
2406         if (_cups_isspace(*valend) || *valend == ',')
2407           break;
2408     }
2409
2410     if (*valend)
2411       *valend++ = '\0';
2412
2413     group = getgrnam(valstart);
2414     if (group)
2415     {
2416       cupsdSetString(SystemGroups + NumSystemGroups, valstart);
2417       SystemGroupIDs[NumSystemGroups] = group->gr_gid;
2418
2419       NumSystemGroups ++;
2420     }
2421     else
2422       status = 0;
2423
2424     endgrent();
2425
2426     valstart = valend;
2427
2428     while (*valstart == ',' || _cups_isspace(*valstart))
2429       valstart ++;
2430   }
2431
2432   return (status);
2433 }
2434
2435
2436 /*
2437  * 'parse_protocols()' - Parse browse protocols in a string.
2438  */
2439
2440 static int                              /* O - Browse protocol bits */
2441 parse_protocols(const char *s)          /* I - Space-delimited protocols */
2442 {
2443   int   protocols;                      /* Browse protocol bits */
2444   char  value[1024],                    /* Value string */
2445         *valstart,                      /* Pointer into value */
2446         *valend;                        /* End of value */
2447
2448
2449  /*
2450   * Empty protocol line yields NULL pointer...
2451   */
2452
2453   if (!s)
2454     return (0);
2455
2456  /*
2457   * Loop through the value string,...
2458   */
2459
2460   strlcpy(value, s, sizeof(value));
2461
2462   protocols = 0;
2463
2464   for (valstart = value; *valstart;)
2465   {
2466    /*
2467     * Get the current space/comma-delimited protocol name...
2468     */
2469
2470     for (valend = valstart; *valend; valend ++)
2471       if (_cups_isspace(*valend) || *valend == ',')
2472         break;
2473
2474     if (*valend)
2475       *valend++ = '\0';
2476
2477    /*
2478     * Add the protocol to the bitmask...
2479     */
2480
2481     if (!_cups_strcasecmp(valstart, "cups"))
2482       protocols |= BROWSE_CUPS;
2483     else if (!_cups_strcasecmp(valstart, "slp"))
2484       protocols |= BROWSE_SLP;
2485     else if (!_cups_strcasecmp(valstart, "ldap"))
2486       protocols |= BROWSE_LDAP;
2487     else if (!_cups_strcasecmp(valstart, "dnssd") ||
2488              !_cups_strcasecmp(valstart, "dns-sd") ||
2489              !_cups_strcasecmp(valstart, "bonjour"))
2490       protocols |= BROWSE_DNSSD;
2491     else if (!_cups_strcasecmp(valstart, "lpd"))
2492       protocols |= BROWSE_LPD;
2493     else if (!_cups_strcasecmp(valstart, "smb"))
2494       protocols |= BROWSE_SMB;
2495     else if (!_cups_strcasecmp(valstart, "all"))
2496       protocols |= BROWSE_ALL;
2497     else if (_cups_strcasecmp(valstart, "none"))
2498       cupsdLogMessage(CUPSD_LOG_ERROR,
2499                       "Unknown browse protocol \"%s\" ignored.", valstart);
2500
2501     for (valstart = valend; *valstart; valstart ++)
2502       if (!_cups_isspace(*valstart) || *valstart != ',')
2503         break;
2504   }
2505
2506   return (protocols);
2507 }
2508
2509
2510 /*
2511  * 'read_configuration()' - Read a configuration file.
2512  */
2513
2514 static int                              /* O - 1 on success, 0 on failure */
2515 read_configuration(cups_file_t *fp)     /* I - File to read from */
2516 {
2517   int                   i;              /* Looping var */
2518   int                   linenum;        /* Current line number */
2519   char                  line[HTTP_MAX_BUFFER],
2520                                         /* Line from file */
2521                         temp[HTTP_MAX_BUFFER],
2522                                         /* Temporary buffer for value */
2523                         *ptr,           /* Pointer into line/temp */
2524                         *value,         /* Pointer to value */
2525                         *valueptr;      /* Pointer into value */
2526   int                   valuelen;       /* Length of value */
2527   cupsd_var_t const     *var;           /* Current variable */
2528   http_addrlist_t       *addrlist,      /* Address list */
2529                         *addr;          /* Current address */
2530   unsigned              ip[4],          /* Address value */
2531                         mask[4];        /* Netmask value */
2532   cupsd_dirsvc_relay_t  *relay;         /* Relay data */
2533   cupsd_dirsvc_poll_t   *pollp;         /* Polling data */
2534   cupsd_location_t      *location;      /* Browse location */
2535   cups_file_t           *incfile;       /* Include file */
2536   char                  incname[1024];  /* Include filename */
2537   struct group          *group;         /* Group */
2538
2539
2540  /*
2541   * Loop through each line in the file...
2542   */
2543
2544   linenum = 0;
2545
2546   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
2547   {
2548    /*
2549     * Decode the directive...
2550     */
2551
2552     if (!_cups_strcasecmp(line, "Include") && value)
2553     {
2554      /*
2555       * Include filename
2556       */
2557
2558       if (value[0] == '/')
2559         strlcpy(incname, value, sizeof(incname));
2560       else
2561         snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
2562
2563       if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
2564         cupsdLogMessage(CUPSD_LOG_ERROR,
2565                         "Unable to include config file \"%s\" - %s",
2566                         incname, strerror(errno));
2567       else
2568       {
2569         read_configuration(incfile);
2570         cupsFileClose(incfile);
2571       }
2572     }
2573     else if (!_cups_strcasecmp(line, "<Location") && value)
2574     {
2575      /*
2576       * <Location path>
2577       */
2578
2579       linenum = read_location(fp, value, linenum);
2580       if (linenum == 0)
2581         return (0);
2582     }
2583     else if (!_cups_strcasecmp(line, "<Policy") && value)
2584     {
2585      /*
2586       * <Policy name>
2587       */
2588
2589       linenum = read_policy(fp, value, linenum);
2590       if (linenum == 0)
2591         return (0);
2592     }
2593     else if (!_cups_strcasecmp(line, "FatalErrors"))
2594       FatalErrors = parse_fatal_errors(value);
2595     else if (!_cups_strcasecmp(line, "FaxRetryInterval") && value)
2596     {
2597       JobRetryInterval = atoi(value);
2598       cupsdLogMessage(CUPSD_LOG_WARN,
2599                       "FaxRetryInterval is deprecated; use "
2600                       "JobRetryInterval on line %d.", linenum);
2601     }
2602     else if (!_cups_strcasecmp(line, "FaxRetryLimit") && value)
2603     {
2604       JobRetryLimit = atoi(value);
2605       cupsdLogMessage(CUPSD_LOG_WARN,
2606                       "FaxRetryLimit is deprecated; use "
2607                       "JobRetryLimit on line %d.", linenum);
2608     }
2609     else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")
2610 #ifdef HAVE_SSL
2611              || !_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen")
2612 #endif /* HAVE_SSL */
2613              ) && value)
2614     {
2615      /*
2616       * Add listening address(es) to the list...
2617       */
2618
2619       cupsd_listener_t  *lis;           /* New listeners array */
2620
2621
2622      /*
2623       * Get the address list...
2624       */
2625
2626       addrlist = get_address(value, IPP_PORT);
2627
2628       if (!addrlist)
2629       {
2630         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line,
2631                         value, linenum);
2632         continue;
2633       }
2634
2635      /*
2636       * Add each address...
2637       */
2638
2639       for (addr = addrlist; addr; addr = addr->next)
2640       {
2641        /*
2642         * See if this address is already present...
2643         */
2644
2645         for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
2646              lis;
2647              lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
2648           if (httpAddrEqual(&(addr->addr), &(lis->address)) &&
2649               _httpAddrPort(&(addr->addr)) == _httpAddrPort(&(lis->address)))
2650             break;
2651
2652         if (lis)
2653         {
2654           httpAddrString(&lis->address, temp, sizeof(temp));
2655           cupsdLogMessage(CUPSD_LOG_WARN,
2656                           "Duplicate listen address \"%s\" ignored.", temp);
2657           continue;
2658         }
2659
2660        /*
2661         * Allocate another listener...
2662         */
2663
2664         if (!Listeners)
2665           Listeners = cupsArrayNew(NULL, NULL);
2666
2667         if (!Listeners)
2668         {
2669           cupsdLogMessage(CUPSD_LOG_ERROR,
2670                           "Unable to allocate %s at line %d - %s.",
2671                           line, linenum, strerror(errno));
2672           break;
2673         }
2674
2675         if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
2676         {
2677           cupsdLogMessage(CUPSD_LOG_ERROR,
2678                           "Unable to allocate %s at line %d - %s.",
2679                           line, linenum, strerror(errno));
2680           break;
2681         }
2682
2683         cupsArrayAdd(Listeners, lis);
2684
2685        /*
2686         * Copy the current address and log it...
2687         */
2688
2689         memcpy(&(lis->address), &(addr->addr), sizeof(lis->address));
2690         lis->fd = -1;
2691
2692 #ifdef HAVE_SSL
2693         if (!_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen"))
2694           lis->encryption = HTTP_ENCRYPT_ALWAYS;
2695 #endif /* HAVE_SSL */
2696
2697         httpAddrString(&lis->address, temp, sizeof(temp));
2698
2699 #ifdef AF_LOCAL
2700         if (lis->address.addr.sa_family == AF_LOCAL)
2701           cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp);
2702         else
2703 #endif /* AF_LOCAL */
2704         cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv%d)", temp,
2705                         _httpAddrPort(&(lis->address)),
2706                         _httpAddrFamily(&(lis->address)) == AF_INET ? 4 : 6);
2707
2708         if (!httpAddrLocalhost(&(lis->address)))
2709           RemotePort = _httpAddrPort(&(lis->address));
2710       }
2711
2712      /*
2713       * Free the list...
2714       */
2715
2716       httpAddrFreeList(addrlist);
2717     }
2718     else if (!_cups_strcasecmp(line, "BrowseAddress") && value)
2719     {
2720      /*
2721       * Add a browse address to the list...
2722       */
2723
2724       cupsd_dirsvc_addr_t       *dira;  /* New browse address array */
2725
2726
2727       if (NumBrowsers == 0)
2728         dira = malloc(sizeof(cupsd_dirsvc_addr_t));
2729       else
2730         dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t));
2731
2732       if (!dira)
2733       {
2734         cupsdLogMessage(CUPSD_LOG_ERROR,
2735                         "Unable to allocate BrowseAddress at line %d - %s.",
2736                         linenum, strerror(errno));
2737         continue;
2738       }
2739
2740       Browsers = dira;
2741       dira     += NumBrowsers;
2742
2743       memset(dira, 0, sizeof(cupsd_dirsvc_addr_t));
2744
2745       if (!_cups_strcasecmp(value, "@LOCAL"))
2746       {
2747        /*
2748         * Send browse data to all local interfaces...
2749         */
2750
2751         strcpy(dira->iface, "*");
2752         NumBrowsers ++;
2753       }
2754       else if (!_cups_strncasecmp(value, "@IF(", 4))
2755       {
2756        /*
2757         * Send browse data to the named interface...
2758         */
2759
2760         strlcpy(dira->iface, value + 4, sizeof(Browsers[0].iface));
2761
2762         ptr = dira->iface + strlen(dira->iface) - 1;
2763         if (*ptr == ')')
2764           *ptr = '\0';
2765
2766         NumBrowsers ++;
2767       }
2768       else if ((addrlist = get_address(value, BrowsePort)) != NULL)
2769       {
2770        /*
2771         * Only IPv4 addresses are supported...
2772         */
2773
2774         for (addr = addrlist; addr; addr = addr->next)
2775           if (_httpAddrFamily(&(addr->addr)) == AF_INET)
2776             break;
2777
2778         if (addr)
2779         {
2780           memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to));
2781           httpAddrString(&(dira->to), temp, sizeof(temp));
2782
2783           cupsdLogMessage(CUPSD_LOG_INFO,
2784                           "Sending browsing info to %s:%d (IPv4)",
2785                           temp, _httpAddrPort(&(dira->to)));
2786
2787           NumBrowsers ++;
2788         }
2789         else
2790           cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
2791                           value, linenum);
2792
2793         httpAddrFreeList(addrlist);
2794       }
2795       else
2796         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
2797                         value, linenum);
2798     }
2799     else if (!_cups_strcasecmp(line, "BrowseOrder") && value)
2800     {
2801      /*
2802       * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"...
2803       */
2804
2805       if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
2806         if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
2807           cupsdAddLocation(location);
2808
2809       if (location == NULL)
2810         cupsdLogMessage(CUPSD_LOG_ERROR,
2811                         "Unable to initialize browse access control list.");
2812       else if (!_cups_strncasecmp(value, "deny", 4))
2813         location->order_type = CUPSD_AUTH_ALLOW;
2814       else if (!_cups_strncasecmp(value, "allow", 5))
2815         location->order_type = CUPSD_AUTH_DENY;
2816       else
2817         cupsdLogMessage(CUPSD_LOG_ERROR,
2818                         "Unknown BrowseOrder value %s on line %d.",
2819                         value, linenum);
2820     }
2821     else if (!_cups_strcasecmp(line, "BrowseProtocols") ||
2822              !_cups_strcasecmp(line, "BrowseLocalProtocols") ||
2823              !_cups_strcasecmp(line, "BrowseRemoteProtocols"))
2824     {
2825      /*
2826       * "BrowseProtocols name [... name]"
2827       * "BrowseLocalProtocols name [... name]"
2828       * "BrowseRemoteProtocols name [... name]"
2829       */
2830
2831       int protocols = parse_protocols(value);
2832
2833       if (protocols < 0)
2834       {
2835         cupsdLogMessage(CUPSD_LOG_ERROR,
2836                         "Unknown browse protocol \"%s\" on line %d.",
2837                         value, linenum);
2838         break;
2839       }
2840
2841       if (_cups_strcasecmp(line, "BrowseLocalProtocols"))
2842         BrowseRemoteProtocols = protocols;
2843       if (_cups_strcasecmp(line, "BrowseRemoteProtocols"))
2844         BrowseLocalProtocols = protocols;
2845     }
2846     else if ((!_cups_strcasecmp(line, "BrowseAllow") ||
2847               !_cups_strcasecmp(line, "BrowseDeny")) && value)
2848     {
2849      /*
2850       * BrowseAllow [From] host/ip...
2851       * BrowseDeny [From] host/ip...
2852       */
2853
2854       if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
2855         if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
2856           cupsdAddLocation(location);
2857
2858
2859       if (location == NULL)
2860         cupsdLogMessage(CUPSD_LOG_ERROR,
2861                         "Unable to initialize browse access control list.");
2862       else
2863       {
2864         if (!_cups_strncasecmp(value, "from", 4))
2865         {
2866          /*
2867           * Skip leading "from"...
2868           */
2869
2870           value += 4;
2871         }
2872
2873         while (*value)
2874         {
2875          /*
2876           * Skip leading whitespace...
2877           */
2878
2879           while (_cups_isspace(*value))
2880             value ++;
2881
2882           if (!*value)
2883             break;
2884
2885          /*
2886           * Find the end of the value...
2887           */
2888
2889           for (valueptr = value;
2890                *valueptr && !_cups_isspace(*valueptr);
2891                valueptr ++);
2892
2893           while (_cups_isspace(*valueptr))
2894             *valueptr++ = '\0';
2895
2896          /*
2897           * Figure out what form the allow/deny address takes:
2898           *
2899           *    All
2900           *    None
2901           *    *.domain.com
2902           *    .domain.com
2903           *    host.domain.com
2904           *    nnn.*
2905           *    nnn.nnn.*
2906           *    nnn.nnn.nnn.*
2907           *    nnn.nnn.nnn.nnn
2908           *    nnn.nnn.nnn.nnn/mm
2909           *    nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
2910           */
2911
2912           if (!_cups_strcasecmp(value, "all"))
2913           {
2914            /*
2915             * All hosts...
2916             */
2917
2918             if (!_cups_strcasecmp(line, "BrowseAllow"))
2919               cupsdAddIPMask(&(location->allow), zeros, zeros);
2920             else
2921               cupsdAddIPMask(&(location->deny), zeros, zeros);
2922           }
2923           else if (!_cups_strcasecmp(value, "none"))
2924           {
2925            /*
2926             * No hosts...
2927             */
2928
2929             if (!_cups_strcasecmp(line, "BrowseAllow"))
2930               cupsdAddIPMask(&(location->allow), ones, zeros);
2931             else
2932               cupsdAddIPMask(&(location->deny), ones, zeros);
2933           }
2934 #ifdef AF_INET6
2935           else if (value[0] == '*' || value[0] == '.' ||
2936                    (!isdigit(value[0] & 255) && value[0] != '['))
2937 #else
2938           else if (value[0] == '*' || value[0] == '.' ||
2939                    !isdigit(value[0] & 255))
2940 #endif /* AF_INET6 */
2941           {
2942            /*
2943             * Host or domain name...
2944             */
2945
2946             if (!_cups_strcasecmp(line, "BrowseAllow"))
2947               cupsdAddNameMask(&(location->allow), value);
2948             else
2949               cupsdAddNameMask(&(location->deny), value);
2950           }
2951           else
2952           {
2953            /*
2954             * One of many IP address forms...
2955             */
2956
2957             if (!get_addr_and_mask(value, ip, mask))
2958             {
2959               cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
2960                               value, linenum);
2961               break;
2962             }
2963
2964             if (!_cups_strcasecmp(line, "BrowseAllow"))
2965               cupsdAddIPMask(&(location->allow), ip, mask);
2966             else
2967               cupsdAddIPMask(&(location->deny), ip, mask);
2968           }
2969
2970          /*
2971           * Advance to next value...
2972           */
2973
2974           value = valueptr;
2975         }
2976       }
2977     }
2978     else if (!_cups_strcasecmp(line, "BrowseRelay") && value)
2979     {
2980      /*
2981       * BrowseRelay [from] source [to] destination
2982       */
2983
2984       if (NumRelays == 0)
2985         relay = malloc(sizeof(cupsd_dirsvc_relay_t));
2986       else
2987         relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t));
2988
2989       if (!relay)
2990       {
2991         cupsdLogMessage(CUPSD_LOG_ERROR,
2992                         "Unable to allocate BrowseRelay at line %d - %s.",
2993                         linenum, strerror(errno));
2994         continue;
2995       }
2996
2997       Relays = relay;
2998       relay  += NumRelays;
2999
3000       memset(relay, 0, sizeof(cupsd_dirsvc_relay_t));
3001
3002       if (!_cups_strncasecmp(value, "from ", 5))
3003       {
3004        /*
3005         * Skip leading "from"...
3006         */
3007
3008         value += 5;
3009
3010        /*
3011         * Skip leading whitespace...
3012         */
3013
3014         while (_cups_isspace(*value))
3015           value ++;
3016       }
3017
3018      /*
3019       * Find the end of the from value...
3020       */
3021
3022       for (valueptr = value;
3023            *valueptr && !_cups_isspace(*valueptr);
3024            valueptr ++);
3025
3026       while (_cups_isspace(*valueptr))
3027         *valueptr++ = '\0';
3028
3029      /*
3030       * Figure out what form the from address takes:
3031       *
3032       *    *.domain.com
3033       *    .domain.com
3034       *    host.domain.com
3035       *    nnn.*
3036       *    nnn.nnn.*
3037       *    nnn.nnn.nnn.*
3038       *    nnn.nnn.nnn.nnn
3039       *    nnn.nnn.nnn.nnn/mm
3040       *    nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
3041       */
3042
3043 #ifdef AF_INET6
3044       if (value[0] == '*' || value[0] == '.' ||
3045           (!isdigit(value[0] & 255) && value[0] != '['))
3046 #else
3047       if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
3048 #endif /* AF_INET6 */
3049       {
3050        /*
3051         * Host or domain name...
3052         */
3053
3054         if (!cupsdAddNameMask(&(relay->from), value))
3055         {
3056           cupsdLogMessage(CUPSD_LOG_ERROR,
3057                           "Unable to allocate BrowseRelay name at line %d - %s.",
3058                           linenum, strerror(errno));
3059           continue;
3060         }
3061       }
3062       else
3063       {
3064        /*
3065         * One of many IP address forms...
3066         */
3067
3068         if (!get_addr_and_mask(value, ip, mask))
3069         {
3070           cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
3071                           value, linenum);
3072           break;
3073         }
3074
3075         if (!cupsdAddIPMask(&(relay->from), ip, mask))
3076         {
3077           cupsdLogMessage(CUPSD_LOG_ERROR,
3078                           "Unable to allocate BrowseRelay IP at line %d - %s.",
3079                           linenum, strerror(errno));
3080           continue;
3081         }
3082       }
3083
3084      /*
3085       * Get "to" address and port...
3086       */
3087
3088       if (!_cups_strncasecmp(valueptr, "to ", 3))
3089       {
3090        /*
3091         * Strip leading "to"...
3092         */
3093
3094         valueptr += 3;
3095
3096         while (_cups_isspace(*valueptr))
3097           valueptr ++;
3098       }
3099
3100       if ((addrlist = get_address(valueptr, BrowsePort)) != NULL)
3101       {
3102        /*
3103         * Only IPv4 addresses are supported...
3104         */
3105
3106         for (addr = addrlist; addr; addr = addr->next)
3107           if (addr->addr.addr.sa_family == AF_INET)
3108             break;
3109
3110         if (addr)
3111         {
3112           memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to));
3113
3114           httpAddrString(&(relay->to), temp, sizeof(temp));
3115
3116           cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)",
3117                           value, temp, _httpAddrPort(&(relay->to)));
3118
3119           NumRelays ++;
3120         }
3121         else
3122         {
3123           cupsArrayDelete(relay->from);
3124           relay->from = NULL;
3125
3126           cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
3127                           valueptr, linenum);
3128         }
3129
3130         httpAddrFreeList(addrlist);
3131       }
3132       else
3133       {
3134         cupsArrayDelete(relay->from);
3135         relay->from = NULL;
3136
3137         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
3138                         valueptr, linenum);
3139       }
3140     }
3141     else if (!_cups_strcasecmp(line, "BrowsePoll") && value)
3142     {
3143      /*
3144       * BrowsePoll address[:port]
3145       */
3146
3147       char              *portname;      /* Port name */
3148       int               portnum;        /* Port number */
3149       struct servent    *service;       /* Service */
3150
3151
3152      /*
3153       * Extract the port name from the address...
3154       */
3155
3156       if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']'))
3157       {
3158         *portname++ = '\0';
3159
3160         if (isdigit(*portname & 255))
3161           portnum = atoi(portname);
3162         else if ((service = getservbyname(portname, NULL)) != NULL)
3163           portnum = ntohs(service->s_port);
3164         else
3165         {
3166           cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed.",
3167                           portname);
3168           continue;
3169         }
3170       }
3171       else
3172         portnum = ippPort();
3173
3174      /*
3175       * Add the poll entry...
3176       */
3177
3178       if (NumPolled == 0)
3179         pollp = malloc(sizeof(cupsd_dirsvc_poll_t));
3180       else
3181         pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t));
3182
3183       if (!pollp)
3184       {
3185         cupsdLogMessage(CUPSD_LOG_ERROR,
3186                         "Unable to allocate BrowsePoll at line %d - %s.",
3187                         linenum, strerror(errno));
3188         continue;
3189       }
3190
3191       Polled = pollp;
3192       pollp   += NumPolled;
3193
3194       NumPolled ++;
3195       memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t));
3196
3197       strlcpy(pollp->hostname, value, sizeof(pollp->hostname));
3198       pollp->port = portnum;
3199
3200       cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname,
3201                       pollp->port);
3202     }
3203     else if (!_cups_strcasecmp(line, "DefaultAuthType") && value)
3204     {
3205      /*
3206       * DefaultAuthType {basic,digest,basicdigest,negotiate}
3207       */
3208
3209       if (!_cups_strcasecmp(value, "none"))
3210         DefaultAuthType = CUPSD_AUTH_NONE;
3211       else if (!_cups_strcasecmp(value, "basic"))
3212         DefaultAuthType = CUPSD_AUTH_BASIC;
3213       else if (!_cups_strcasecmp(value, "digest"))
3214         DefaultAuthType = CUPSD_AUTH_DIGEST;
3215       else if (!_cups_strcasecmp(value, "basicdigest"))
3216         DefaultAuthType = CUPSD_AUTH_BASICDIGEST;
3217 #ifdef HAVE_GSSAPI
3218       else if (!_cups_strcasecmp(value, "negotiate"))
3219         DefaultAuthType = CUPSD_AUTH_NEGOTIATE;
3220 #endif /* HAVE_GSSAPI */
3221       else
3222       {
3223         cupsdLogMessage(CUPSD_LOG_WARN,
3224                         "Unknown default authorization type %s on line %d.",
3225                         value, linenum);
3226         if (FatalErrors & CUPSD_FATAL_CONFIG)
3227           return (0);
3228       }
3229     }
3230 #ifdef HAVE_SSL
3231     else if (!_cups_strcasecmp(line, "DefaultEncryption"))
3232     {
3233      /*
3234       * DefaultEncryption {Never,IfRequested,Required}
3235       */
3236
3237       if (!value || !_cups_strcasecmp(value, "never"))
3238         DefaultEncryption = HTTP_ENCRYPT_NEVER;
3239       else if (!_cups_strcasecmp(value, "required"))
3240         DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
3241       else if (!_cups_strcasecmp(value, "ifrequested"))
3242         DefaultEncryption = HTTP_ENCRYPT_IF_REQUESTED;
3243       else
3244       {
3245         cupsdLogMessage(CUPSD_LOG_WARN,
3246                         "Unknown default encryption %s on line %d.",
3247                         value, linenum);
3248         if (FatalErrors & CUPSD_FATAL_CONFIG)
3249           return (0);
3250       }
3251     }
3252 #endif /* HAVE_SSL */
3253     else if (!_cups_strcasecmp(line, "User") && value)
3254     {
3255      /*
3256       * User ID to run as...
3257       */
3258
3259       if (isdigit(value[0] & 255))
3260       {
3261         int uid = atoi(value);
3262
3263         if (!uid)
3264           cupsdLogMessage(CUPSD_LOG_ERROR,
3265                           "Will not use User 0 as specified on line %d "
3266                           "for security reasons.  You must use a non-"
3267                           "privileged account instead.",
3268                           linenum);
3269         else
3270           User = atoi(value);
3271       }
3272       else
3273       {
3274         struct passwd *p;       /* Password information */
3275
3276         endpwent();
3277         p = getpwnam(value);
3278
3279         if (p)
3280         {
3281           if (!p->pw_uid)
3282             cupsdLogMessage(CUPSD_LOG_ERROR,
3283                             "Will not use User %s (UID=0) as specified on line "
3284                             "%d for security reasons.  You must use a non-"
3285                             "privileged account instead.",
3286                             value, linenum);
3287           else
3288             User = p->pw_uid;
3289         }
3290         else
3291           cupsdLogMessage(CUPSD_LOG_ERROR,
3292                           "Unknown User \"%s\" on line %d, ignoring.",
3293                           value, linenum);
3294       }
3295     }
3296     else if (!_cups_strcasecmp(line, "Group") && value)
3297     {
3298      /*
3299       * Group ID to run as...
3300       */
3301
3302       if (isdigit(value[0]))
3303         Group = atoi(value);
3304       else
3305       {
3306         endgrent();
3307         group = getgrnam(value);
3308
3309         if (group != NULL)
3310           Group = group->gr_gid;
3311         else
3312           cupsdLogMessage(CUPSD_LOG_ERROR,
3313                           "Unknown Group \"%s\" on line %d, ignoring.",
3314                           value, linenum);
3315       }
3316     }
3317     else if (!_cups_strcasecmp(line, "SystemGroup") && value)
3318     {
3319      /*
3320       * SystemGroup (admin) group(s)...
3321       */
3322
3323       if (!parse_groups(value))
3324         cupsdLogMessage(CUPSD_LOG_ERROR,
3325                         "Unknown SystemGroup \"%s\" on line %d, ignoring.",
3326                         value, linenum);
3327     }
3328     else if (!_cups_strcasecmp(line, "HostNameLookups") && value)
3329     {
3330      /*
3331       * Do hostname lookups?
3332       */
3333
3334       if (!_cups_strcasecmp(value, "off") || !_cups_strcasecmp(value, "no") ||
3335           !_cups_strcasecmp(value, "false"))
3336         HostNameLookups = 0;
3337       else if (!_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "yes") ||
3338           !_cups_strcasecmp(value, "true"))
3339         HostNameLookups = 1;
3340       else if (!_cups_strcasecmp(value, "double"))
3341         HostNameLookups = 2;
3342       else
3343         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.",
3344                         value, linenum);
3345     }
3346     else if (!_cups_strcasecmp(line, "AccessLogLevel") && value)
3347     {
3348      /*
3349       * Amount of logging to do to access log...
3350       */
3351
3352       if (!_cups_strcasecmp(value, "all"))
3353         AccessLogLevel = CUPSD_ACCESSLOG_ALL;
3354       else if (!_cups_strcasecmp(value, "actions"))
3355         AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS;
3356       else if (!_cups_strcasecmp(value, "config"))
3357         AccessLogLevel = CUPSD_ACCESSLOG_CONFIG;
3358       else
3359         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown AccessLogLevel %s on line %d.",
3360                         value, linenum);
3361     }
3362     else if (!_cups_strcasecmp(line, "LogLevel") && value)
3363     {
3364      /*
3365       * Amount of logging to do to error log...
3366       */
3367
3368       if (!_cups_strcasecmp(value, "debug2"))
3369         LogLevel = CUPSD_LOG_DEBUG2;
3370       else if (!_cups_strcasecmp(value, "debug"))
3371         LogLevel = CUPSD_LOG_DEBUG;
3372       else if (!_cups_strcasecmp(value, "info"))
3373         LogLevel = CUPSD_LOG_INFO;
3374       else if (!_cups_strcasecmp(value, "notice"))
3375         LogLevel = CUPSD_LOG_NOTICE;
3376       else if (!_cups_strcasecmp(value, "warn"))
3377         LogLevel = CUPSD_LOG_WARN;
3378       else if (!_cups_strcasecmp(value, "error"))
3379         LogLevel = CUPSD_LOG_ERROR;
3380       else if (!_cups_strcasecmp(value, "crit"))
3381         LogLevel = CUPSD_LOG_CRIT;
3382       else if (!_cups_strcasecmp(value, "alert"))
3383         LogLevel = CUPSD_LOG_ALERT;
3384       else if (!_cups_strcasecmp(value, "emerg"))
3385         LogLevel = CUPSD_LOG_EMERG;
3386       else if (!_cups_strcasecmp(value, "none"))
3387         LogLevel = CUPSD_LOG_NONE;
3388       else
3389         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.",
3390                         value, linenum);
3391     }
3392     else if (!_cups_strcasecmp(line, "LogTimeFormat") && value)
3393     {
3394      /*
3395       * Amount of logging to do to error log...
3396       */
3397
3398       if (!_cups_strcasecmp(value, "standard"))
3399         LogTimeFormat = CUPSD_TIME_STANDARD;
3400       else if (!_cups_strcasecmp(value, "usecs"))
3401         LogTimeFormat = CUPSD_TIME_USECS;
3402       else
3403         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogTimeFormat %s on line %d.",
3404                         value, linenum);
3405     }
3406     else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
3407     {
3408      /*
3409       * Format of printcap file?
3410       */
3411
3412       if (!_cups_strcasecmp(value, "bsd"))
3413         PrintcapFormat = PRINTCAP_BSD;
3414       else if (!_cups_strcasecmp(value, "plist"))
3415         PrintcapFormat = PRINTCAP_PLIST;
3416       else if (!_cups_strcasecmp(value, "solaris"))
3417         PrintcapFormat = PRINTCAP_SOLARIS;
3418       else
3419         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.",
3420                         value, linenum);
3421     }
3422     else if (!_cups_strcasecmp(line, "ServerTokens") && value)
3423     {
3424      /*
3425       * Set the string used for the Server header...
3426       */
3427
3428       struct utsname plat;              /* Platform info */
3429
3430
3431       uname(&plat);
3432
3433       if (!_cups_strcasecmp(value, "ProductOnly"))
3434         cupsdSetString(&ServerHeader, "CUPS");
3435       else if (!_cups_strcasecmp(value, "Major"))
3436         cupsdSetStringf(&ServerHeader, "CUPS/%d", CUPS_VERSION_MAJOR);
3437       else if (!_cups_strcasecmp(value, "Minor"))
3438         cupsdSetStringf(&ServerHeader, "CUPS/%d.%d", CUPS_VERSION_MAJOR,
3439                         CUPS_VERSION_MINOR);
3440       else if (!_cups_strcasecmp(value, "Minimal"))
3441         cupsdSetString(&ServerHeader, CUPS_MINIMAL);
3442       else if (!_cups_strcasecmp(value, "OS"))
3443         cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
3444       else if (!_cups_strcasecmp(value, "Full"))
3445         cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/2.1",
3446                         plat.sysname);
3447       else if (!_cups_strcasecmp(value, "None"))
3448         cupsdClearString(&ServerHeader);
3449       else
3450         cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.",
3451                         value, linenum);
3452     }
3453     else if (!_cups_strcasecmp(line, "PassEnv") && value)
3454     {
3455      /*
3456       * PassEnv variable [... variable]
3457       */
3458
3459       for (; *value;)
3460       {
3461         for (valuelen = 0; value[valuelen]; valuelen ++)
3462           if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
3463             break;
3464
3465         if (value[valuelen])
3466         {
3467           value[valuelen] = '\0';
3468           valuelen ++;
3469         }
3470
3471         cupsdSetEnv(value, NULL);
3472
3473         for (value += valuelen; *value; value ++)
3474           if (!_cups_isspace(*value) || *value != ',')
3475             break;
3476       }
3477     }
3478     else if (!_cups_strcasecmp(line, "ServerAlias") && value)
3479     {
3480      /*
3481       * ServerAlias name [... name]
3482       */
3483
3484       if (!ServerAlias)
3485         ServerAlias = cupsArrayNew(NULL, NULL);
3486
3487       for (; *value;)
3488       {
3489         for (valuelen = 0; value[valuelen]; valuelen ++)
3490           if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
3491             break;
3492
3493         if (value[valuelen])
3494         {
3495           value[valuelen] = '\0';
3496           valuelen ++;
3497         }
3498
3499         cupsdAddAlias(ServerAlias, value);
3500
3501         for (value += valuelen; *value; value ++)
3502           if (!_cups_isspace(*value) || *value != ',')
3503             break;
3504       }
3505     }
3506     else if (!_cups_strcasecmp(line, "SetEnv") && value)
3507     {
3508      /*
3509       * SetEnv variable value
3510       */
3511
3512       for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
3513
3514       if (*valueptr)
3515       {
3516        /*
3517         * Found a value...
3518         */
3519
3520         while (isspace(*valueptr & 255))
3521           *valueptr++ = '\0';
3522
3523         cupsdSetEnv(value, valueptr);
3524       }
3525       else
3526         cupsdLogMessage(CUPSD_LOG_ERROR,
3527                         "Missing value for SetEnv directive on line %d.",
3528                         linenum);
3529     }
3530 #ifdef HAVE_SSL
3531     else if (!_cups_strcasecmp(line, "SSLOptions"))
3532     {
3533      /*
3534       * SSLOptions options
3535       */
3536
3537       if (!value || !_cups_strcasecmp(value, "none"))
3538         SSLOptions = CUPSD_SSL_NONE;
3539       else if (!_cups_strcasecmp(value, "noemptyfragments"))
3540         SSLOptions = CUPSD_SSL_NOEMPTY;
3541       else
3542         cupsdLogMessage(CUPSD_LOG_ERROR,
3543                         "Unknown value \"%s\" for SSLOptions directive on "
3544                         "line %d.", value, linenum);
3545     }
3546 #endif /* HAVE_SSL */
3547     else
3548     {
3549      /*
3550       * Find a simple variable in the list...
3551       */
3552
3553       for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
3554         if (!_cups_strcasecmp(line, var->name))
3555           break;
3556
3557       if (i == 0)
3558       {
3559        /*
3560         * Unknown directive!  Output an error message and continue...
3561         */
3562
3563         if (!value)
3564           cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d.",
3565                           line, linenum);
3566         else
3567           cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.",
3568                           line, linenum);
3569         continue;
3570       }
3571
3572       switch (var->type)
3573       {
3574         case CUPSD_VARTYPE_INTEGER :
3575             if (!value)
3576               cupsdLogMessage(CUPSD_LOG_ERROR,
3577                               "Missing integer value for %s on line %d.",
3578                               line, linenum);
3579             else
3580             {
3581               int       n;              /* Number */
3582               char      *units;         /* Units */
3583
3584
3585               n = strtol(value, &units, 0);
3586
3587               if (units && *units)
3588               {
3589                 if (tolower(units[0] & 255) == 'g')
3590                   n *= 1024 * 1024 * 1024;
3591                 else if (tolower(units[0] & 255) == 'm')
3592                   n *= 1024 * 1024;
3593                 else if (tolower(units[0] & 255) == 'k')
3594                   n *= 1024;
3595                 else if (tolower(units[0] & 255) == 't')
3596                   n *= 262144;
3597               }
3598
3599               if (n < 0)
3600                 cupsdLogMessage(CUPSD_LOG_ERROR,
3601                                 "Bad negative integer value for %s on line %d.",
3602                                 line, linenum);
3603               else
3604                 *((int *)var->ptr) = n;
3605             }
3606             break;
3607
3608         case CUPSD_VARTYPE_BOOLEAN :
3609             if (!value)
3610               cupsdLogMessage(CUPSD_LOG_ERROR,
3611                               "Missing boolean value for %s on line %d.",
3612                               line, linenum);
3613             else if (!_cups_strcasecmp(value, "true") ||
3614                      !_cups_strcasecmp(value, "on") ||
3615                      !_cups_strcasecmp(value, "enabled") ||
3616                      !_cups_strcasecmp(value, "yes") ||
3617                      atoi(value) != 0)
3618               *((int *)var->ptr) = TRUE;
3619             else if (!_cups_strcasecmp(value, "false") ||
3620                      !_cups_strcasecmp(value, "off") ||
3621                      !_cups_strcasecmp(value, "disabled") ||
3622                      !_cups_strcasecmp(value, "no") ||
3623                      !_cups_strcasecmp(value, "0"))
3624               *((int *)var->ptr) = FALSE;
3625             else
3626               cupsdLogMessage(CUPSD_LOG_ERROR,
3627                               "Unknown boolean value %s on line %d.",
3628                               value, linenum);
3629             break;
3630
3631         case CUPSD_VARTYPE_PATHNAME :
3632             if (!value)
3633             {
3634               cupsdLogMessage(CUPSD_LOG_ERROR,
3635                               "Missing pathname value for %s on line %d.",
3636                               line, linenum);
3637               break;
3638             }
3639
3640             if (value[0] == '/')
3641               strlcpy(temp, value, sizeof(temp));
3642             else
3643               snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value);
3644
3645             if (access(temp, 0))
3646             {
3647               cupsdLogMessage(CUPSD_LOG_ERROR,
3648                               "File or directory for \"%s %s\" on line %d "
3649                               "does not exist.", line, value, linenum);
3650               break;
3651             }
3652
3653         case CUPSD_VARTYPE_STRING :
3654             cupsdSetString((char **)var->ptr, value);
3655             break;
3656       }
3657     }
3658   }
3659
3660   return (1);
3661 }
3662
3663
3664 /*
3665  * 'read_location()' - Read a <Location path> definition.
3666  */
3667
3668 static int                              /* O - New line number or 0 on error */
3669 read_location(cups_file_t *fp,          /* I - Configuration file */
3670               char        *location,    /* I - Location name/path */
3671               int         linenum)      /* I - Current line number */
3672 {
3673   cupsd_location_t      *loc,           /* New location */
3674                         *parent;        /* Parent location */
3675   char                  line[HTTP_MAX_BUFFER],
3676                                         /* Line buffer */
3677                         *value,         /* Value for directive */
3678                         *valptr;        /* Pointer into value */
3679
3680
3681   if ((parent = cupsdFindLocation(location)) != NULL)
3682     cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Location %s> on line %d.",
3683                     location, linenum);
3684   else if ((parent = cupsdNewLocation(location)) == NULL)
3685     return (0);
3686   else
3687   {
3688     cupsdAddLocation(parent);
3689
3690     parent->limit = CUPSD_AUTH_LIMIT_ALL;
3691   }
3692
3693   loc = parent;
3694
3695   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3696   {
3697    /*
3698     * Decode the directive...
3699     */
3700
3701     if (!_cups_strcasecmp(line, "</Location>"))
3702       return (linenum);
3703     else if (!_cups_strcasecmp(line, "<Limit") ||
3704              !_cups_strcasecmp(line, "<LimitExcept"))
3705     {
3706       if (!value)
3707       {
3708         cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
3709         if (FatalErrors & CUPSD_FATAL_CONFIG)
3710           return (0);
3711         else
3712           continue;
3713       }
3714
3715       if ((loc = cupsdCopyLocation(parent)) == NULL)
3716         return (0);
3717
3718       cupsdAddLocation(loc);
3719
3720       loc->limit = 0;
3721       while (*value)
3722       {
3723         for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3724
3725         if (*valptr)
3726           *valptr++ = '\0';
3727
3728         if (!strcmp(value, "ALL"))
3729           loc->limit = CUPSD_AUTH_LIMIT_ALL;
3730         else if (!strcmp(value, "GET"))
3731           loc->limit |= CUPSD_AUTH_LIMIT_GET;
3732         else if (!strcmp(value, "HEAD"))
3733           loc->limit |= CUPSD_AUTH_LIMIT_HEAD;
3734         else if (!strcmp(value, "OPTIONS"))
3735           loc->limit |= CUPSD_AUTH_LIMIT_OPTIONS;
3736         else if (!strcmp(value, "POST"))
3737           loc->limit |= CUPSD_AUTH_LIMIT_POST;
3738         else if (!strcmp(value, "PUT"))
3739           loc->limit |= CUPSD_AUTH_LIMIT_PUT;
3740         else if (!strcmp(value, "TRACE"))
3741           loc->limit |= CUPSD_AUTH_LIMIT_TRACE;
3742         else
3743           cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d.",
3744                           value, linenum);
3745
3746         for (value = valptr; isspace(*value & 255); value ++);
3747       }
3748
3749       if (!_cups_strcasecmp(line, "<LimitExcept"))
3750         loc->limit = CUPSD_AUTH_LIMIT_ALL ^ loc->limit;
3751
3752       parent->limit &= ~loc->limit;
3753     }
3754     else if (!_cups_strcasecmp(line, "</Limit>") ||
3755              !_cups_strcasecmp(line, "</LimitExcept>"))
3756       loc = parent;
3757     else if (!value)
3758     {
3759       cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum);
3760       if (FatalErrors & CUPSD_FATAL_CONFIG)
3761         return (0);
3762     }
3763     else if (!parse_aaa(loc, line, value, linenum))
3764     {
3765       cupsdLogMessage(CUPSD_LOG_ERROR,
3766                       "Unknown Location directive %s on line %d.",
3767                       line, linenum);
3768       if (FatalErrors & CUPSD_FATAL_CONFIG)
3769         return (0);
3770     }
3771   }
3772
3773   cupsdLogMessage(CUPSD_LOG_ERROR,
3774                   "Unexpected end-of-file at line %d while reading location.",
3775                   linenum);
3776
3777   return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
3778 }
3779
3780
3781 /*
3782  * 'read_policy()' - Read a <Policy name> definition.
3783  */
3784
3785 static int                              /* O - New line number or 0 on error */
3786 read_policy(cups_file_t *fp,            /* I - Configuration file */
3787             char        *policy,        /* I - Location name/path */
3788             int         linenum)        /* I - Current line number */
3789 {
3790   int                   i;              /* Looping var */
3791   cupsd_policy_t        *pol;           /* Policy */
3792   cupsd_location_t      *op;            /* Policy operation */
3793   int                   num_ops;        /* Number of IPP operations */
3794   ipp_op_t              ops[100];       /* Operations */
3795   char                  line[HTTP_MAX_BUFFER],
3796                                         /* Line buffer */
3797                         *value,         /* Value for directive */
3798                         *valptr;        /* Pointer into value */
3799
3800
3801  /*
3802   * Create the policy...
3803   */
3804
3805   if ((pol = cupsdFindPolicy(policy)) != NULL)
3806     cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Policy %s> on line %d.",
3807                     policy, linenum);
3808   else if ((pol = cupsdAddPolicy(policy)) == NULL)
3809     return (0);
3810
3811  /*
3812   * Read from the file...
3813   */
3814
3815   op      = NULL;
3816   num_ops = 0;
3817
3818   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3819   {
3820    /*
3821     * Decode the directive...
3822     */
3823
3824     if (!_cups_strcasecmp(line, "</Policy>"))
3825     {
3826       if (op)
3827         cupsdLogMessage(CUPSD_LOG_WARN,
3828                         "Missing </Limit> before </Policy> on line %d.",
3829                         linenum);
3830
3831       set_policy_defaults(pol);
3832
3833       return (linenum);
3834     }
3835     else if (!_cups_strcasecmp(line, "<Limit") && !op)
3836     {
3837       if (!value)
3838       {
3839         cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
3840         if (FatalErrors & CUPSD_FATAL_CONFIG)
3841           return (0);
3842         else
3843           continue;
3844       }
3845
3846      /*
3847       * Scan for IPP operation names...
3848       */
3849
3850       num_ops = 0;
3851
3852       while (*value)
3853       {
3854         for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3855
3856         if (*valptr)
3857           *valptr++ = '\0';
3858
3859         if (num_ops < (int)(sizeof(ops) / sizeof(ops[0])))
3860         {
3861           if (!_cups_strcasecmp(value, "All"))
3862             ops[num_ops] = IPP_ANY_OPERATION;
3863           else if ((ops[num_ops] = ippOpValue(value)) == IPP_BAD_OPERATION)
3864             cupsdLogMessage(CUPSD_LOG_ERROR,
3865                             "Bad IPP operation name \"%s\" on line %d.",
3866                             value, linenum);
3867           else
3868             num_ops ++;
3869         }
3870         else
3871           cupsdLogMessage(CUPSD_LOG_ERROR,
3872                           "Too many operations listed on line %d.",
3873                           linenum);
3874
3875         for (value = valptr; isspace(*value & 255); value ++);
3876       }
3877
3878      /*
3879       * If none are specified, apply the policy to all operations...
3880       */
3881
3882       if (num_ops == 0)
3883       {
3884         ops[0]  = IPP_ANY_OPERATION;
3885         num_ops = 1;
3886       }
3887
3888      /*
3889       * Add a new policy for the first operation...
3890       */
3891
3892       op = cupsdAddPolicyOp(pol, NULL, ops[0]);
3893     }
3894     else if (!_cups_strcasecmp(line, "</Limit>") && op)
3895     {
3896      /*
3897       * Finish the current operation limit...
3898       */
3899
3900       if (num_ops > 1)
3901       {
3902        /*
3903         * Copy the policy to the other operations...
3904         */
3905
3906         for (i = 1; i < num_ops; i ++)
3907           cupsdAddPolicyOp(pol, op, ops[i]);
3908       }
3909
3910       op = NULL;
3911     }
3912     else if (!value)
3913     {
3914       cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum);
3915       if (FatalErrors & CUPSD_FATAL_CONFIG)
3916         return (0);
3917     }
3918     else if (!_cups_strcasecmp(line, "JobPrivateAccess") ||
3919              !_cups_strcasecmp(line, "JobPrivateValues") ||
3920              !_cups_strcasecmp(line, "SubscriptionPrivateAccess") ||
3921              !_cups_strcasecmp(line, "SubscriptionPrivateValues"))
3922     {
3923       if (op)
3924       {
3925         cupsdLogMessage(CUPSD_LOG_ERROR,
3926                         "%s directive must appear outside <Limit>...</Limit> "
3927                         "on line %d.", line, linenum);
3928         if (FatalErrors & CUPSD_FATAL_CONFIG)
3929           return (0);
3930       }
3931       else
3932       {
3933        /*
3934         * Pull out whitespace-delimited values...
3935         */
3936
3937         while (*value)
3938         {
3939          /*
3940           * Find the end of the current value...
3941           */
3942
3943           for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3944
3945           if (*valptr)
3946             *valptr++ = '\0';
3947
3948          /*
3949           * Save it appropriately...
3950           */
3951
3952           if (!_cups_strcasecmp(line, "JobPrivateAccess"))
3953           {
3954            /*
3955             * JobPrivateAccess {all|default|user/group list|@@ACL}
3956             */
3957
3958             if (!_cups_strcasecmp(value, "default"))
3959             {
3960               cupsdAddString(&(pol->job_access), "@OWNER");
3961               cupsdAddString(&(pol->job_access), "@SYSTEM");
3962             }
3963             else
3964               cupsdAddString(&(pol->job_access), value);
3965           }
3966           else if (!_cups_strcasecmp(line, "JobPrivateValues"))
3967           {
3968            /*
3969             * JobPrivateValues {all|none|default|attribute list}
3970             */
3971
3972             if (!_cups_strcasecmp(value, "default"))
3973             {
3974               cupsdAddString(&(pol->job_attrs), "job-name");
3975               cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
3976               cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
3977             }
3978             else
3979               cupsdAddString(&(pol->job_attrs), value);
3980           }
3981           else if (!_cups_strcasecmp(line, "SubscriptionPrivateAccess"))
3982           {
3983            /*
3984             * SubscriptionPrivateAccess {all|default|user/group list|@@ACL}
3985             */
3986
3987             if (!_cups_strcasecmp(value, "default"))
3988             {
3989               cupsdAddString(&(pol->sub_access), "@OWNER");
3990               cupsdAddString(&(pol->sub_access), "@SYSTEM");
3991             }
3992             else
3993               cupsdAddString(&(pol->sub_access), value);
3994           }
3995           else /* if (!_cups_strcasecmp(line, "SubscriptionPrivateValues")) */
3996           {
3997            /*
3998             * SubscriptionPrivateValues {all|none|default|attribute list}
3999             */
4000
4001             if (!_cups_strcasecmp(value, "default"))
4002             {
4003               cupsdAddString(&(pol->sub_attrs), "notify-events");
4004               cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
4005               cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
4006               cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
4007               cupsdAddString(&(pol->sub_attrs), "notify-user-data");
4008             }
4009             else
4010               cupsdAddString(&(pol->sub_attrs), value);
4011           }
4012
4013          /*
4014           * Find the next string on the line...
4015           */
4016
4017           for (value = valptr; isspace(*value & 255); value ++);
4018         }
4019       }
4020     }
4021     else if (!op)
4022     {
4023       cupsdLogMessage(CUPSD_LOG_ERROR,
4024                       "Missing <Limit ops> directive before %s on line %d.",
4025                       line, linenum);
4026       if (FatalErrors & CUPSD_FATAL_CONFIG)
4027         return (0);
4028     }
4029     else if (!parse_aaa(op, line, value, linenum))
4030     {
4031       cupsdLogMessage(CUPSD_LOG_ERROR,
4032                       "Unknown Policy Limit directive %s on line %d.",
4033                       line, linenum);
4034
4035       if (FatalErrors & CUPSD_FATAL_CONFIG)
4036         return (0);
4037     }
4038   }
4039
4040   cupsdLogMessage(CUPSD_LOG_ERROR,
4041                   "Unexpected end-of-file at line %d while reading policy "
4042                   "\"%s\".", linenum, policy);
4043
4044   return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
4045 }
4046
4047
4048 /*
4049  * 'set_policy_defaults()' - Set default policy values as needed.
4050  */
4051
4052 static void
4053 set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
4054 {
4055   cupsd_location_t      *op;            /* Policy operation */
4056
4057
4058  /*
4059   * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs,
4060   * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that
4061   * upgrades do not introduce new security issues...
4062   */
4063
4064   if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL ||
4065       op->op == IPP_ANY_OPERATION)
4066   {
4067     if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL &&
4068         op->op != IPP_ANY_OPERATION)
4069     {
4070      /*
4071       * Add a new limit for Validate-Job using the Print-Job limit as a
4072       * template...
4073       */
4074
4075       cupsdLogMessage(CUPSD_LOG_WARN,
4076                       "No limit for Validate-Job defined in policy %s "
4077                       "- using Print-Job's policy.", pol->name);
4078
4079       cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB);
4080     }
4081     else
4082       cupsdLogMessage(CUPSD_LOG_WARN,
4083                       "No limit for Validate-Job defined in policy %s "
4084                       "and no suitable template found.", pol->name);
4085   }
4086
4087   if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL ||
4088       op->op == IPP_ANY_OPERATION)
4089   {
4090     if ((op = cupsdFindPolicyOp(pol, IPP_PAUSE_PRINTER)) != NULL &&
4091         op->op != IPP_ANY_OPERATION)
4092     {
4093      /*
4094       * Add a new limit for Cancel-Jobs using the Pause-Printer limit as a
4095       * template...
4096       */
4097
4098       cupsdLogMessage(CUPSD_LOG_WARN,
4099                       "No limit for Cancel-Jobs defined in policy %s "
4100                       "- using Pause-Printer's policy.", pol->name);
4101
4102       cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS);
4103     }
4104     else
4105       cupsdLogMessage(CUPSD_LOG_WARN,
4106                       "No limit for Cancel-Jobs defined in policy %s "
4107                       "and no suitable template found.", pol->name);
4108   }
4109
4110   if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL ||
4111       op->op == IPP_ANY_OPERATION)
4112   {
4113     if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
4114         op->op != IPP_ANY_OPERATION)
4115     {
4116      /*
4117       * Add a new limit for Cancel-My-Jobs using the Send-Document limit as
4118       * a template...
4119       */
4120
4121       cupsdLogMessage(CUPSD_LOG_WARN,
4122                       "No limit for Cancel-My-Jobs defined in policy %s "
4123                       "- using Send-Document's policy.", pol->name);
4124
4125       cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS);
4126     }
4127     else
4128       cupsdLogMessage(CUPSD_LOG_WARN,
4129                       "No limit for Cancel-My-Jobs defined in policy %s "
4130                       "and no suitable template found.", pol->name);
4131   }
4132
4133   if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL ||
4134       op->op == IPP_ANY_OPERATION)
4135   {
4136     if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
4137         op->op != IPP_ANY_OPERATION)
4138     {
4139      /*
4140       * Add a new limit for Close-Job using the Send-Document limit as a
4141       * template...
4142       */
4143
4144       cupsdLogMessage(CUPSD_LOG_WARN,
4145                       "No limit for Close-Job defined in policy %s "
4146                       "- using Send-Document's policy.", pol->name);
4147
4148       cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB);
4149     }
4150     else
4151       cupsdLogMessage(CUPSD_LOG_WARN,
4152                       "No limit for Close-Job defined in policy %s "
4153                       "and no suitable template found.", pol->name);
4154   }
4155
4156   if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL ||
4157       op->op == IPP_ANY_OPERATION)
4158   {
4159     if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
4160         op->op != IPP_ANY_OPERATION)
4161     {
4162      /*
4163       * Add a new limit for CUPS-Get-Document using the Send-Document
4164       * limit as a template...
4165       */
4166
4167       cupsdLogMessage(CUPSD_LOG_WARN,
4168                       "No limit for CUPS-Get-Document defined in policy %s "
4169                       "- using Send-Document's policy.", pol->name);
4170
4171       cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT);
4172     }
4173     else
4174       cupsdLogMessage(CUPSD_LOG_WARN,
4175                       "No limit for CUPS-Get-Document defined in policy %s "
4176                       "and no suitable template found.", pol->name);
4177   }
4178
4179  /*
4180   * Verify we have JobPrivateAccess, JobPrivateValues,
4181   * SubscriptionPrivateAccess, and SubscriptionPrivateValues in the policy.
4182   */
4183
4184   if (!pol->job_access)
4185   {
4186     cupsdLogMessage(CUPSD_LOG_WARN,
4187                     "No JobPrivateAccess defined in policy %s "
4188                     "- using defaults.", pol->name);
4189     cupsdAddString(&(pol->job_access), "@OWNER");
4190     cupsdAddString(&(pol->job_access), "@SYSTEM");
4191   }
4192
4193   if (!pol->job_attrs)
4194   {
4195     cupsdLogMessage(CUPSD_LOG_WARN,
4196                     "No JobPrivateValues defined in policy %s "
4197                     "- using defaults.", pol->name);
4198     cupsdAddString(&(pol->job_attrs), "job-name");
4199     cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
4200     cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
4201   }
4202
4203   if (!pol->sub_access)
4204   {
4205     cupsdLogMessage(CUPSD_LOG_WARN,
4206                     "No SubscriptionPrivateAccess defined in policy %s "
4207                     "- using defaults.", pol->name);
4208     cupsdAddString(&(pol->sub_access), "@OWNER");
4209     cupsdAddString(&(pol->sub_access), "@SYSTEM");
4210   }
4211
4212   if (!pol->sub_attrs)
4213   {
4214     cupsdLogMessage(CUPSD_LOG_WARN,
4215                     "No SubscriptionPrivateValues defined in policy %s "
4216                     "- using defaults.", pol->name);
4217     cupsdAddString(&(pol->sub_attrs), "notify-events");
4218     cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
4219     cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
4220     cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
4221     cupsdAddString(&(pol->sub_attrs), "notify-user-data");
4222   }
4223 }
4224
4225
4226 /*
4227  * End of "$Id: conf.c 10121 2011-11-16 15:28:11Z mike $".
4228  */