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