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