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