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