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