]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/conf.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / conf.c
1 /*
2 * "$Id: conf.c 5028 2006-01-31 01:16:43Z mike $"
3 *
4 * Configuration routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * cupsdReadConfiguration() - Read the cupsd.conf file.
27 * check_permissions() - Fix the mode and ownership of a file or
28 * directory.
29 * get_address() - Get an address + port number from a line.
30 * get_addr_and_mask() - Get an IP address and netmask.
31 * parse_aaa() - Parse authentication, authorization, and
32 * access control lines.
33 * read_configuration() - Read a configuration file.
34 * read_location() - Read a <Location path> definition.
35 * read_policy() - Read a <Policy name> definition.
36 */
37
38 /*
39 * Include necessary headers...
40 */
41
42 #include "cupsd.h"
43 #include <stdarg.h>
44 #include <grp.h>
45 #include <sys/utsname.h>
46 #include <cups/dir.h>
47
48 #ifdef HAVE_VSYSLOG
49 # include <syslog.h>
50 #endif /* HAVE_VSYSLOG */
51
52
53 /*
54 * Possibly missing network definitions...
55 */
56
57 #ifndef INADDR_NONE
58 # define INADDR_NONE 0xffffffff
59 #endif /* !INADDR_NONE */
60
61
62 /*
63 * Configuration variable structure...
64 */
65
66 typedef enum
67 {
68 CUPSD_VARTYPE_INTEGER, /* Integer option */
69 CUPSD_VARTYPE_STRING, /* String option */
70 CUPSD_VARTYPE_BOOLEAN /* Boolean option */
71 } cupsd_vartype_t;
72
73 typedef struct
74 {
75 char *name; /* Name of variable */
76 void *ptr; /* Pointer to variable */
77 cupsd_vartype_t type; /* Type (int, string, address) */
78 } cupsd_var_t;
79
80
81 /*
82 * Local globals...
83 */
84
85 static cupsd_var_t variables[] =
86 {
87 { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING },
88 { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN },
89 { "BrowseInterval", &BrowseInterval, CUPSD_VARTYPE_INTEGER },
90 { "BrowseLocalOptions", &BrowseLocalOptions, CUPSD_VARTYPE_STRING },
91 { "BrowsePort", &BrowsePort, CUPSD_VARTYPE_INTEGER },
92 { "BrowseRemoteOptions", &BrowseRemoteOptions, CUPSD_VARTYPE_STRING },
93 { "BrowseShortNames", &BrowseShortNames, CUPSD_VARTYPE_BOOLEAN },
94 { "BrowseTimeout", &BrowseTimeout, CUPSD_VARTYPE_INTEGER },
95 { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN },
96 { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING },
97 { "Classification", &Classification, CUPSD_VARTYPE_STRING },
98 { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN },
99 { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER },
100 { "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
101 { "DefaultCharset", &DefaultCharset, CUPSD_VARTYPE_STRING },
102 { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING },
103 { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER },
104 { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING },
105 { "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN },
106 { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING },
107 { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING },
108 { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN },
109 { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER },
110 { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER },
111 { "FontPath", &FontPath, CUPSD_VARTYPE_STRING },
112 { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN },
113 { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN },
114 { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN },
115 { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER },
116 { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER },
117 { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER },
118 { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN },
119 { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
120 { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER },
121 { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER },
122 { "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER },
123 { "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER },
124 { "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER },
125 { "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER },
126 { "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER },
127 { "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER },
128 { "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER },
129 { "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER },
130 { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_INTEGER },
131 { "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER },
132 { "MaxPrinterHistory", &MaxPrinterHistory, CUPSD_VARTYPE_INTEGER },
133 { "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
134 { "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER },
135 { "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER },
136 { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER },
137 { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER },
138 { "PageLog", &PageLog, CUPSD_VARTYPE_STRING },
139 { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_BOOLEAN },
140 { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_BOOLEAN },
141 { "Printcap", &Printcap, CUPSD_VARTYPE_STRING },
142 { "PrintcapGUI", &PrintcapGUI, CUPSD_VARTYPE_STRING },
143 { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_INTEGER },
144 { "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING },
145 { "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING },
146 { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING },
147 { "RunAsUser", &RunAsUser, CUPSD_VARTYPE_BOOLEAN },
148 { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_INTEGER },
149 { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING },
150 { "ServerBin", &ServerBin, CUPSD_VARTYPE_STRING },
151 #ifdef HAVE_SSL
152 { "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_STRING },
153 # if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
154 { "ServerKey", &ServerKey, CUPSD_VARTYPE_STRING },
155 # endif /* HAVE_LIBSSL || HAVE_GNUTLS */
156 #endif /* HAVE_SSL */
157 #ifdef HAVE_LAUNCHD
158 { "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_INTEGER },
159 { "LaunchdConf", &LaunchdConf, CUPSD_VARTYPE_STRING },
160 #endif /* HAVE_LAUNCHD */
161 { "ServerName", &ServerName, CUPSD_VARTYPE_STRING },
162 { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_STRING },
163 { "StateDir", &StateDir, CUPSD_VARTYPE_STRING },
164 { "TempDir", &TempDir, CUPSD_VARTYPE_STRING },
165 { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER },
166 { "UseNetworkDefault", &UseNetworkDefault, CUPSD_VARTYPE_BOOLEAN }
167 };
168 #define NUM_VARS (sizeof(variables) / sizeof(variables[0]))
169
170
171 static unsigned ones[4] =
172 {
173 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
174 };
175 static unsigned zeros[4] =
176 {
177 0x00000000, 0x00000000, 0x00000000, 0x00000000
178 };
179
180
181 /*
182 * Local functions...
183 */
184 static int check_permissions(const char *filename,
185 const char *suffix, int mode,
186 int user, int group, int is_dir,
187 int create_dir);
188 static http_addrlist_t *get_address(const char *value, int defport);
189 static int get_addr_and_mask(const char *value, unsigned *ip,
190 unsigned *mask);
191 static int parse_aaa(cupsd_location_t *loc, char *line,
192 char *value, int linenum);
193 static int read_configuration(cups_file_t *fp);
194 static int read_location(cups_file_t *fp, char *name, int linenum);
195 static int read_policy(cups_file_t *fp, char *name, int linenum);
196
197
198 /*
199 * 'cupsdReadConfiguration()' - Read the cupsd.conf file.
200 */
201
202 int /* O - 1 on success, 0 otherwise */
203 cupsdReadConfiguration(void)
204 {
205 int i; /* Looping var */
206 cups_file_t *fp; /* Configuration file */
207 int status; /* Return status */
208 char temp[1024], /* Temporary buffer */
209 *slash; /* Directory separator */
210 cups_lang_t *language; /* Language */
211 struct passwd *user; /* Default user */
212 struct group *group; /* Default group */
213 char *old_serverroot, /* Old ServerRoot */
214 *old_requestroot; /* Old RequestRoot */
215
216 /*
217 * Save the old root paths...
218 */
219
220 old_serverroot = NULL;
221 cupsdSetString(&old_serverroot, ServerRoot);
222 old_requestroot = NULL;
223 cupsdSetString(&old_requestroot, RequestRoot);
224
225 /*
226 * Reset the server configuration data...
227 */
228
229 cupsdDeleteAllLocations();
230
231 if (NumBrowsers > 0)
232 {
233 free(Browsers);
234
235 NumBrowsers = 0;
236 }
237
238 if (NumPolled > 0)
239 {
240 free(Polled);
241
242 NumPolled = 0;
243 }
244
245 if (NumRelays > 0)
246 {
247 for (i = 0; i < NumRelays; i ++)
248 if (Relays[i].from.type == AUTH_NAME)
249 free(Relays[i].from.mask.name.name);
250
251 free(Relays);
252
253 NumRelays = 0;
254 }
255
256 if (NumListeners > 0)
257 {
258 free(Listeners);
259 NumListeners = 0;
260 }
261
262 /*
263 * String options...
264 */
265
266 cupsdSetString(&ServerName, httpGetHostname(temp, sizeof(temp)));
267 cupsdSetStringf(&ServerAdmin, "root@%s", temp);
268 cupsdSetString(&ServerBin, CUPS_SERVERBIN);
269 cupsdSetString(&RequestRoot, CUPS_REQUESTS);
270 cupsdSetString(&CacheDir, CUPS_CACHEDIR);
271 cupsdSetString(&DataDir, CUPS_DATADIR);
272 cupsdSetString(&DocumentRoot, CUPS_DOCROOT);
273 cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log");
274 cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
275 cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log");
276 cupsdSetString(&Printcap, "/etc/printcap");
277 cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
278 cupsdSetString(&FontPath, CUPS_FONTPATH);
279 cupsdSetString(&RemoteRoot, "remroot");
280 cupsdSetString(&ServerHeader, "CUPS/1.1");
281 cupsdSetString(&StateDir, CUPS_STATEDIR);
282
283 strlcpy(temp, ConfigurationFile, sizeof(temp));
284 if ((slash = strrchr(temp, '/')) != NULL)
285 *slash = '\0';
286
287 cupsdSetString(&ServerRoot, temp);
288
289 cupsdClearString(&Classification);
290 ClassifyOverride = 0;
291
292 #ifdef HAVE_SSL
293 # ifdef HAVE_CDSASSL
294 cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain");
295 # else
296 cupsdSetString(&ServerCertificate, "ssl/server.crt");
297 cupsdSetString(&ServerKey, "ssl/server.key");
298 # endif /* HAVE_CDSASSL */
299 #endif /* HAVE_SSL */
300
301 language = cupsLangDefault();
302
303 if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX"))
304 cupsdSetString(&DefaultLanguage, "en");
305 else
306 cupsdSetString(&DefaultLanguage, language->language);
307
308 cupsdSetString(&DefaultCharset, _cupsEncodingName(language->encoding));
309
310 cupsdSetString(&RIPCache, "8m");
311
312 if (getenv("TMPDIR") == NULL)
313 cupsdSetString(&TempDir, CUPS_REQUESTS "/tmp");
314 else
315 cupsdSetString(&TempDir, getenv("TMPDIR"));
316
317 /*
318 * Find the default system group: "sys", "system", or "root"...
319 */
320
321 group = getgrnam(CUPS_DEFAULT_GROUP);
322 endgrent();
323
324 NumSystemGroups = 0;
325
326 if (group != NULL)
327 {
328 /*
329 * Found the group, use it!
330 */
331
332 cupsdSetString(&SystemGroups[0], CUPS_DEFAULT_GROUP);
333
334 SystemGroupIDs[0] = group->gr_gid;
335 }
336 else
337 {
338 /*
339 * Find the group associated with GID 0...
340 */
341
342 group = getgrgid(0);
343 endgrent();
344
345 if (group != NULL)
346 cupsdSetString(&SystemGroups[0], group->gr_name);
347 else
348 cupsdSetString(&SystemGroups[0], "unknown");
349
350 SystemGroupIDs[0] = 0;
351 }
352
353 /*
354 * Find the default user...
355 */
356
357 if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL)
358 User = user->pw_uid;
359 else
360 {
361 /*
362 * Use the (historical) NFS nobody user ID (-2 as a 16-bit twos-
363 * complement number...)
364 */
365
366 User = 65534;
367 }
368
369 endpwent();
370
371 /*
372 * Find the default group (nobody)...
373 */
374
375 group = getgrnam("nobody");
376 endgrent();
377
378 if (group != NULL)
379 Group = group->gr_gid;
380 else
381 {
382 /*
383 * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
384 * complement number...)
385 */
386
387 Group = 65534;
388 }
389
390 /*
391 * Numeric options...
392 */
393
394 ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM;
395 DefaultAuthType = AUTH_BASIC;
396 JobRetryLimit = 5;
397 JobRetryInterval = 300;
398 FileDevice = FALSE;
399 FilterLevel = 0;
400 FilterLimit = 0;
401 FilterNice = 0;
402 HostNameLookups = FALSE;
403 ImplicitClasses = CUPS_DEFAULT_IMPLICIT_CLASSES;
404 ImplicitAnyClasses = FALSE;
405 HideImplicitMembers = TRUE;
406 KeepAlive = TRUE;
407 KeepAliveTimeout = DEFAULT_KEEPALIVE;
408 ListenBackLog = SOMAXCONN;
409 LogFilePerm = CUPS_DEFAULT_LOG_FILE_PERM;
410 LogLevel = CUPSD_LOG_ERROR;
411 MaxClients = 100;
412 MaxClientsPerHost = 0;
413 MaxLogSize = 1024 * 1024;
414 MaxPrinterHistory = 10;
415 MaxRequestSize = 0;
416 ReloadTimeout = 60;
417 RootCertDuration = 300;
418 RunAsUser = FALSE;
419 Timeout = DEFAULT_TIMEOUT;
420
421 BrowseInterval = DEFAULT_INTERVAL;
422 BrowsePort = ippPort();
423 BrowseLocalProtocols = BROWSE_CUPS; /* TODO: Use configure option */
424 BrowseRemoteProtocols = BROWSE_CUPS; /* TODO: Use configure option */
425 BrowseShortNames = CUPS_DEFAULT_BROWSE_SHORT_NAMES;
426 BrowseTimeout = DEFAULT_TIMEOUT;
427 Browsing = CUPS_DEFAULT_BROWSING;
428 DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED;
429
430 cupsdClearString(&BrowseLocalOptions);
431 cupsdClearString(&BrowseRemoteOptions);
432
433 JobHistory = DEFAULT_HISTORY;
434 JobFiles = DEFAULT_FILES;
435 JobAutoPurge = 0;
436 MaxJobs = 500;
437 MaxActiveJobs = 0;
438 MaxJobsPerUser = 0;
439 MaxJobsPerPrinter = 0;
440 MaxCopies = 100;
441
442 cupsdDeleteAllPolicies();
443 cupsdClearString(&DefaultPolicy);
444
445 MaxSubscriptions = 100;
446 MaxSubscriptionsPerJob = 0;
447 MaxSubscriptionsPerPrinter = 0;
448 MaxSubscriptionsPerUser = 0;
449 DefaultLeaseDuration = 86400;
450 MaxLeaseDuration = 0;
451
452 #ifdef HAVE_LAUNCHD
453 LaunchdTimeout = DEFAULT_TIMEOUT + 10;
454 cupsdSetString(&LaunchdConf, CUPS_DEFAULT_LAUNCHD_CONF);
455 #endif /* HAVE_LAUNCHD */
456
457 /*
458 * Read the configuration file...
459 */
460
461 if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
462 return (0);
463
464 status = read_configuration(fp);
465
466 cupsFileClose(fp);
467
468 if (!status)
469 return (0);
470
471 if (RunAsUser)
472 RunUser = User;
473 else
474 RunUser = getuid();
475
476 /*
477 * Use the default system group if none was supplied in cupsd.conf...
478 */
479
480 if (NumSystemGroups == 0)
481 NumSystemGroups ++;
482
483 /*
484 * Get the access control list for browsing...
485 */
486
487 BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL");
488
489 /*
490 * Open the system log for cupsd if necessary...
491 */
492
493 #ifdef HAVE_VSYSLOG
494 if (!strcmp(AccessLog, "syslog") ||
495 !strcmp(ErrorLog, "syslog") ||
496 !strcmp(PageLog, "syslog"))
497 openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
498 #endif /* HAVE_VSYSLOG */
499
500 /*
501 * Log the configuration file that was used...
502 */
503
504 cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"",
505 ConfigurationFile);
506
507 /*
508 * Validate the Group and SystemGroup settings - they cannot be the same,
509 * otherwise the CGI programs will be able to authenticate as root without
510 * a password!
511 */
512
513 if (!RunUser)
514 {
515 for (i = 0; i < NumSystemGroups; i ++)
516 if (Group == SystemGroupIDs[i])
517 break;
518
519 if (i < NumSystemGroups)
520 {
521 /*
522 * Log the error and reset the group to a safe value...
523 */
524
525 cupsdLogMessage(CUPSD_LOG_NOTICE,
526 "Group and SystemGroup cannot use the same groups!");
527 cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"...");
528
529 group = getgrnam("nobody");
530 endgrent();
531
532 if (group != NULL)
533 Group = group->gr_gid;
534 else
535 {
536 /*
537 * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
538 * complement number...)
539 */
540
541 Group = 65534;
542 }
543 }
544 }
545
546 /*
547 * Check that we have at least one listen/port line; if not, report this
548 * as an error and exit!
549 */
550
551 if (NumListeners == 0)
552 {
553 /*
554 * No listeners!
555 */
556
557 cupsdLogMessage(CUPSD_LOG_EMERG,
558 "No valid Listen or Port lines were found in the configuration file!");
559
560 /*
561 * Commit suicide...
562 */
563
564 cupsdEndProcess(getpid(), 0);
565 }
566
567 /*
568 * Set the default locale using the language and charset...
569 */
570
571 cupsdSetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset);
572
573 /*
574 * Update all relative filenames to include the full path from ServerRoot...
575 */
576
577 if (DocumentRoot[0] != '/')
578 cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
579
580 if (RequestRoot[0] != '/')
581 cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
582
583 if (ServerBin[0] != '/')
584 cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
585
586 if (StateDir[0] != '/')
587 cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir);
588
589 if (CacheDir[0] != '/')
590 cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
591
592 #ifdef HAVE_SSL
593 if (ServerCertificate[0] != '/')
594 cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
595
596 if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot)))
597 {
598 chown(ServerCertificate, RunUser, Group);
599 chmod(ServerCertificate, 0600);
600 }
601
602 # if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
603 if (ServerKey[0] != '/')
604 cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
605
606 if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot)))
607 {
608 chown(ServerKey, RunUser, Group);
609 chmod(ServerKey, 0600);
610 }
611 # endif /* HAVE_LIBSSL || HAVE_GNUTLS */
612 #endif /* HAVE_SSL */
613
614 /*
615 * Make sure that directories and config files are owned and
616 * writable by the user and group in the cupsd.conf file...
617 */
618
619 check_permissions(CacheDir, NULL, 0775, RunUser, Group, 1, 1);
620 check_permissions(CacheDir, "ppd", 0755, RunUser, Group, 1, 1);
621
622 check_permissions(StateDir, NULL, 0755, RunUser, Group, 1, 1);
623 check_permissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
624 SystemGroupIDs[0], 1, 1);
625
626 check_permissions(ServerRoot, NULL, 0755, RunUser, Group, 1, 0);
627 check_permissions(ServerRoot, "ppd", 0755, RunUser, Group, 1, 1);
628 check_permissions(ServerRoot, "ssl", 0700, RunUser, Group, 1, 0);
629 check_permissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser, Group,
630 0, 0);
631 check_permissions(ServerRoot, "classes.conf", 0600, RunUser, Group, 0, 0);
632 check_permissions(ServerRoot, "printers.conf", 0600, RunUser, Group, 0, 0);
633 check_permissions(ServerRoot, "passwd.md5", 0600, User, Group, 0, 0);
634
635 /*
636 * Make sure the request and temporary directories have the right
637 * permissions...
638 */
639
640 check_permissions(RequestRoot, NULL, 0710, RunUser, Group, 1, 1);
641
642 if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) ||
643 access(TempDir, 0))
644 {
645 /*
646 * Update ownership and permissions if the CUPS temp directory
647 * is under the spool directory or does not exist...
648 */
649
650 check_permissions(TempDir, NULL, 01770, RunUser, Group, 1, 1);
651 }
652
653 if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)))
654 {
655 /*
656 * Clean out the temporary directory...
657 */
658
659 cups_dir_t *dir; /* Temporary directory */
660 cups_dentry_t *dent; /* Directory entry */
661 char tempfile[1024]; /* Temporary filename */
662
663
664 if ((dir = cupsDirOpen(TempDir)) != NULL)
665 {
666 cupsdLogMessage(CUPSD_LOG_INFO,
667 "Cleaning out old temporary files in \"%s\"...", TempDir);
668
669 while ((dent = cupsDirRead(dir)) != NULL)
670 {
671 snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename);
672
673 if (unlink(tempfile))
674 cupsdLogMessage(CUPSD_LOG_ERROR,
675 "Unable to remove temporary file \"%s\" - %s",
676 tempfile, strerror(errno));
677 else
678 cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...",
679 tempfile);
680 }
681
682 cupsDirClose(dir);
683 }
684 else
685 cupsdLogMessage(CUPSD_LOG_ERROR,
686 "Unable to open temporary directory \"%s\" - %s",
687 TempDir, strerror(errno));
688 }
689
690 /*
691 * Setup environment variables...
692 */
693
694 cupsdInitEnv();
695
696 /*
697 * Check the MaxClients setting, and then allocate memory for it...
698 */
699
700 if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
701 {
702 if (MaxClients > 0)
703 cupsdLogMessage(CUPSD_LOG_INFO, "MaxClients limited to 1/3 (%d) of the file descriptor limit (%d)...",
704 MaxFDs / 3, MaxFDs);
705
706 MaxClients = MaxFDs / 3;
707 }
708
709 if ((Clients = calloc(sizeof(cupsd_client_t), MaxClients)) == NULL)
710 {
711 cupsdLogMessage(CUPSD_LOG_ERROR,
712 "cupsdReadConfiguration: Unable to allocate memory for %d clients: %s",
713 MaxClients, strerror(errno));
714 exit(1);
715 }
716 else
717 cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.",
718 MaxClients);
719
720 /*
721 * Check the MaxActiveJobs setting; limit to 1/3 the available
722 * file descriptors, since we need a pipe for each job...
723 */
724
725 if (MaxActiveJobs > (MaxFDs / 3))
726 MaxActiveJobs = MaxFDs / 3;
727
728 if (Classification && strcasecmp(Classification, "none") == 0)
729 cupsdClearString(&Classification);
730
731 if (Classification)
732 cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
733
734 /*
735 * Update the MaxClientsPerHost value, as needed...
736 */
737
738 if (MaxClientsPerHost <= 0)
739 MaxClientsPerHost = MaxClients;
740
741 if (MaxClientsPerHost > MaxClients)
742 MaxClientsPerHost = MaxClients;
743
744 cupsdLogMessage(CUPSD_LOG_INFO,
745 "Allowing up to %d client connections per host.",
746 MaxClientsPerHost);
747
748 /*
749 * Update the default policy, as needed...
750 */
751
752 if (DefaultPolicy)
753 DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy);
754 else
755 DefaultPolicyPtr = NULL;
756
757 if (!DefaultPolicyPtr)
758 {
759 cupsd_policy_t *p; /* New policy */
760 cupsd_location_t *po; /* New policy operation */
761
762
763 if (DefaultPolicy)
764 cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found!",
765 DefaultPolicy);
766
767 if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL)
768 cupsdLogMessage(CUPSD_LOG_INFO,
769 "Using policy \"default\" as the default!");
770 else
771 {
772 cupsdLogMessage(CUPSD_LOG_INFO,
773 "Creating CUPS default administrative policy:");
774
775 DefaultPolicyPtr = p = cupsdAddPolicy("default");
776
777 cupsdLogMessage(CUPSD_LOG_INFO, "<Policy default>");
778 cupsdLogMessage(CUPSD_LOG_INFO,
779 "<Limit Send-Document Send-URI Cancel-Job Hold-Job "
780 "Release-Job Restart-Job Purge-Jobs "
781 "Set-Job-Attributes Create-Job-Subscription "
782 "Renew-Subscription Cancel-Subscription "
783 "Get-Notifications Reprocess-Job Cancel-Current-Job "
784 "Suspend-Current-Job Resume-Job CUPS-Move-Job "
785 "CUPS-Authenticate-Job>");
786 cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
787
788 po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT);
789 po->order_type = AUTH_ALLOW;
790 po->level = AUTH_USER;
791
792 cupsdAddName(po, "@OWNER");
793 cupsdAddName(po, "@SYSTEM");
794 cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM");
795
796 cupsdAddPolicyOp(p, po, IPP_SEND_URI);
797 cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB);
798 cupsdAddPolicyOp(p, po, IPP_HOLD_JOB);
799 cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB);
800 cupsdAddPolicyOp(p, po, IPP_RESTART_JOB);
801 cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS);
802 cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES);
803 cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION);
804 cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION);
805 cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION);
806 cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS);
807 cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB);
808 cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB);
809 cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB);
810 cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
811 cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
812 cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB);
813
814 cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
815
816 cupsdLogMessage(CUPSD_LOG_INFO,
817 "<Limit Pause-Printer Resume-Printer "
818 "Set-Printer-Attributes Enable-Printer "
819 "Disable-Printer Pause-Printer-After-Current-Job "
820 "Hold-New-Jobs Release-Held-New-Jobs "
821 "Deactivate-Printer Activate-Printer Restart-Printer "
822 "Shutdown-Printer Startup-Printer Promote-Job "
823 "Schedule-Job-After CUPS-Add-Printer "
824 "CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class "
825 "CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>");
826 cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
827 cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Basic");
828
829 po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER);
830 po->order_type = AUTH_ALLOW;
831 po->type = AUTH_BASIC;
832 po->level = AUTH_USER;
833
834 cupsdAddName(po, "@SYSTEM");
835 cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM");
836
837 cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER);
838 cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES);
839 cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER);
840 cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER);
841 cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB);
842 cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS);
843 cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS);
844 cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER);
845 cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER);
846 cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER);
847 cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER);
848 cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER);
849 cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB);
850 cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER);
851 cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER);
852 cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER);
853 cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS);
854 cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS);
855 cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS);
856 cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS);
857 cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT);
858
859 cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
860
861 cupsdLogMessage(CUPSD_LOG_INFO, "<Limit All>");
862 cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
863
864 po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION);
865 po->order_type = AUTH_ALLOW;
866
867 cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
868 cupsdLogMessage(CUPSD_LOG_INFO, "</Policy>");
869 }
870 }
871
872 cupsdLogMessage(CUPSD_LOG_DEBUG,"NumPolicies=%d", NumPolicies);
873 for (i = 0; i < NumPolicies; i ++)
874 cupsdLogMessage(CUPSD_LOG_DEBUG, "Policies[%d]=\"%s\"", i,
875 Policies[i]->name);
876
877 /*
878 * If we are doing a full reload or the server root has changed, flush
879 * the jobs, printers, etc. and start from scratch...
880 */
881
882 if (NeedReload == RELOAD_ALL ||
883 !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
884 !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
885 {
886 mime_type_t *type; /* Current type */
887 char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE];
888 /* MIME type name */
889
890
891 cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required.");
892
893 /*
894 * Free all memory...
895 */
896
897 cupsdDeleteAllSubscriptions();
898 cupsdFreeAllJobs();
899 cupsdDeleteAllClasses();
900 cupsdDeleteAllPrinters();
901
902 DefaultPrinter = NULL;
903
904 if (MimeDatabase != NULL)
905 mimeDelete(MimeDatabase);
906
907 if (NumMimeTypes)
908 {
909 for (i = 0; i < NumMimeTypes; i ++)
910 free((void *)MimeTypes[i]);
911
912 free(MimeTypes);
913 }
914
915 /*
916 * Read the MIME type and conversion database...
917 */
918
919 snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
920
921 MimeDatabase = mimeLoad(ServerRoot, temp);
922
923 if (!MimeDatabase)
924 {
925 cupsdLogMessage(CUPSD_LOG_EMERG,
926 "Unable to load MIME database from \'%s\'!", ServerRoot);
927 exit(errno);
928 }
929
930 cupsdLogMessage(CUPSD_LOG_INFO,
931 "Loaded MIME database from \'%s\': %d types, %d filters...",
932 ServerRoot, mimeNumTypes(MimeDatabase),
933 mimeNumFilters(MimeDatabase));
934
935 /*
936 * Create a list of MIME types for the document-format-supported
937 * attribute...
938 */
939
940 NumMimeTypes = mimeNumTypes(MimeDatabase);
941 if (!mimeType(MimeDatabase, "application", "octet-stream"))
942 NumMimeTypes ++;
943
944 MimeTypes = calloc(NumMimeTypes, sizeof(const char *));
945
946 for (i = 0, type = mimeFirstType(MimeDatabase);
947 type;
948 i ++, type = mimeNextType(MimeDatabase))
949 {
950 snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
951
952 MimeTypes[i] = strdup(mimetype);
953 }
954
955 if (i < NumMimeTypes)
956 MimeTypes[i] = strdup("application/octet-stream");
957
958 /*
959 * Load banners...
960 */
961
962 snprintf(temp, sizeof(temp), "%s/banners", DataDir);
963 cupsdLoadBanners(temp);
964
965 /*
966 * Load printers and classes...
967 */
968
969 cupsdLoadAllPrinters();
970 cupsdLoadAllClasses();
971 cupsdLoadRemoteCache();
972 cupsdWritePrintcap();
973
974 cupsdCreateCommonData();
975
976 /*
977 * Load queued jobs...
978 */
979
980 cupsdLoadAllJobs();
981
982 /*
983 * Load subscriptions...
984 */
985
986 cupsdLoadAllSubscriptions();
987
988 cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete.");
989 }
990 else
991 {
992 /*
993 * Not a full reload, so recreate the common printer attributes...
994 */
995
996 cupsdCreateCommonData();
997
998 /*
999 * Update all printers as needed...
1000 */
1001
1002 cupsdUpdatePrinters();
1003 cupsdWritePrintcap();
1004
1005 cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete.");
1006 }
1007
1008 /*
1009 * Reset the reload state...
1010 */
1011
1012 NeedReload = RELOAD_NONE;
1013
1014 cupsdClearString(&old_serverroot);
1015 cupsdClearString(&old_requestroot);
1016
1017 return (1);
1018 }
1019
1020
1021 /*
1022 * 'check_permissions()' - Fix the mode and ownership of a file or directory.
1023 */
1024
1025 static int /* O - 0 on success, -1 on error */
1026 check_permissions(const char *filename, /* I - File/directory name */
1027 const char *suffix, /* I - Additional file/directory name */
1028 int mode, /* I - Permissions */
1029 int user, /* I - Owner */
1030 int group, /* I - Group */
1031 int is_dir, /* I - 1 = directory, 0 = file */
1032 int create_dir)/* I - 1 = create directory, 0 = not */
1033 {
1034 int dir_created = 0; /* Did we create a directory? */
1035 char pathname[1024]; /* File name with prefix */
1036 struct stat fileinfo; /* Stat buffer */
1037
1038
1039 /*
1040 * Prepend the given root to the filename before testing it...
1041 */
1042
1043 if (suffix)
1044 {
1045 snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
1046 filename = pathname;
1047 }
1048
1049 /*
1050 * See if we can stat the file/directory...
1051 */
1052
1053 if (stat(filename, &fileinfo))
1054 {
1055 if (errno == ENOENT && create_dir)
1056 {
1057 cupsdLogMessage(CUPSD_LOG_ERROR, "Creating missing directory \"%s\"",
1058 filename);
1059
1060 if (mkdir(filename, mode))
1061 {
1062 cupsdLogMessage(CUPSD_LOG_ERROR,
1063 "Unable to create directory \"%s\" - %s", filename,
1064 strerror(errno));
1065 return (-1);
1066 }
1067
1068 dir_created = 1;
1069 }
1070 else
1071 return (-1);
1072 }
1073
1074 /*
1075 * Make sure it's a regular file...
1076 */
1077
1078 if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
1079 {
1080 cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file!", filename);
1081 return (-1);
1082 }
1083
1084 if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
1085 {
1086 cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory!", filename);
1087 return (-1);
1088 }
1089
1090 /*
1091 * Fix owner, group, and mode as needed...
1092 */
1093
1094 if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
1095 {
1096 cupsdLogMessage(CUPSD_LOG_WARN, "Repairing ownership of \"%s\"", filename);
1097
1098 if (chown(filename, user, group))
1099 {
1100 cupsdLogMessage(CUPSD_LOG_ERROR,
1101 "Unable to change ownership of \"%s\" - %s", filename,
1102 strerror(errno));
1103 return (-1);
1104 }
1105 }
1106
1107 if (dir_created || (fileinfo.st_mode & 0777) != mode)
1108 {
1109 cupsdLogMessage(CUPSD_LOG_WARN, "Repairing access permissions of \"%s\"", filename);
1110
1111 if (chmod(filename, mode))
1112 {
1113 cupsdLogMessage(CUPSD_LOG_ERROR,
1114 "Unable to change permissions of \"%s\" - %s", filename,
1115 strerror(errno));
1116 return (-1);
1117 }
1118 }
1119
1120 /*
1121 * Everything is OK...
1122 */
1123
1124 return (0);
1125 }
1126
1127
1128 /*
1129 * 'get_address()' - Get an address + port number from a line.
1130 */
1131
1132 static http_addrlist_t * /* O - Pointer to list if address good, NULL if bad */
1133 get_address(const char *value, /* I - Value string */
1134 int defport) /* I - Default port */
1135 {
1136 char buffer[1024], /* Hostname + port number buffer */
1137 defpname[255], /* Default port name */
1138 *hostname, /* Hostname or IP */
1139 *portname; /* Port number or name */
1140 http_addrlist_t *addrlist; /* Address list */
1141
1142
1143 /*
1144 * Check for an empty value...
1145 */
1146
1147 if (!*value)
1148 {
1149 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address!");
1150 return (NULL);
1151 }
1152
1153 /*
1154 * Grab a hostname and port number; if there is no colon and the port name
1155 * is only digits, then we have a port number by itself...
1156 */
1157
1158 strlcpy(buffer, value, sizeof(buffer));
1159
1160 if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']'))
1161 {
1162 *portname++ = '\0';
1163 hostname = buffer;
1164 }
1165 else
1166 {
1167 for (portname = buffer; isdigit(*portname & 255); portname ++);
1168
1169 if (*portname)
1170 {
1171 /*
1172 * Use the default port...
1173 */
1174
1175 sprintf(defpname, "%d", defport);
1176 portname = defpname;
1177 hostname = buffer;
1178 }
1179 else
1180 {
1181 /*
1182 * The buffer contains just a port number...
1183 */
1184
1185 portname = buffer;
1186 hostname = NULL;
1187 }
1188 }
1189
1190 if (hostname && !strcmp(hostname, "*"))
1191 hostname = NULL;
1192
1193 /*
1194 * Now lookup the address using httpAddrGetList()...
1195 */
1196
1197 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
1198 cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed!",
1199 hostname ? hostname : "(nil)");
1200
1201 return (addrlist);
1202 }
1203
1204
1205 /*
1206 * 'get_addr_and_mask()' - Get an IP address and netmask.
1207 */
1208
1209 static int /* O - 1 on success, 0 on failure */
1210 get_addr_and_mask(const char *value, /* I - String from config file */
1211 unsigned *ip, /* O - Address value */
1212 unsigned *mask) /* O - Mask value */
1213 {
1214 int i, j, /* Looping vars */
1215 family, /* Address family */
1216 ipcount; /* Count of fields in address */
1217 unsigned ipval; /* Value */
1218 const char *maskval, /* Pointer to start of mask value */
1219 *ptr, /* Pointer into value */
1220 *ptr2; /* ... */
1221 static unsigned netmasks[4][4] = /* Standard IPv4 netmasks... */
1222 {
1223 { 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000 },
1224 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 },
1225 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00 },
1226 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
1227 };
1228 #ifdef AF_INET6
1229 static unsigned netmasks6[8][4] = /* Standard IPv6 netmasks... */
1230 {
1231 { 0xffff0000, 0x00000000, 0x00000000, 0x00000000 },
1232 { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 },
1233 { 0xffffffff, 0xffff0000, 0x00000000, 0x00000000 },
1234 { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 },
1235 { 0xffffffff, 0xffffffff, 0xffff0000, 0x00000000 },
1236 { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 },
1237 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 },
1238 { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }
1239 };
1240 #endif /* AF_INET6 */
1241
1242
1243 /*
1244 * Get the address...
1245 */
1246
1247 memset(ip, 0, sizeof(unsigned) * 4);
1248
1249 if ((maskval = strchr(value, '/')) != NULL)
1250 maskval ++;
1251 else
1252 maskval = value + strlen(value);
1253
1254 #ifdef AF_INET6
1255 /*
1256 * Check for an IPv6 address...
1257 */
1258
1259 if (*value == '[')
1260 {
1261 /*
1262 * Parse hexadecimal IPv6 address...
1263 */
1264
1265 family = AF_INET6;
1266
1267 for (i = 0, ptr = value + 1; *ptr && i < 8; i ++)
1268 {
1269 if (*ptr == ']')
1270 break;
1271 else if (!strncmp(ptr, "::", 2))
1272 {
1273 for (ptr2 = strchr(ptr + 2, ':'), j = 0;
1274 ptr2;
1275 ptr2 = strchr(ptr2 + 1, ':'), j ++);
1276
1277 i = 7 - j;
1278 }
1279 else if (isxdigit(*ptr & 255))
1280 {
1281 ipval = strtoul(ptr, (char **)&ptr, 16);
1282
1283 if (ipval > 0xffff)
1284 return (0);
1285
1286 if (i & 1)
1287 ip[i] |= ipval;
1288 else
1289 ip[i] |= ipval << 16;
1290 }
1291 else
1292 return (0);
1293
1294 while (*ptr == ':')
1295 ptr ++;
1296 }
1297
1298 ipcount = i;
1299
1300 if (*ptr && *ptr != '/')
1301 return (0);
1302 }
1303 else
1304 #endif /* AF_INET6 */
1305 {
1306 /*
1307 * Parse dotted-decimal IPv4 address...
1308 */
1309
1310 family = AF_INET;
1311 ipcount = sscanf(value, "%u.%u.%u.%u", ip + 0, ip + 1, ip + 2, ip + 3);
1312
1313 ip[3] |= ((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8;
1314 ip[0] = ip[1] = ip[2] = 0;
1315 }
1316
1317 if (*maskval)
1318 {
1319 /*
1320 * Get the netmask value(s)...
1321 */
1322
1323 memset(mask, 0, sizeof(unsigned) * 4);
1324
1325 #ifdef AF_INET6
1326 if (*maskval == '[')
1327 {
1328 /*
1329 * Get hexadecimal mask value...
1330 */
1331
1332 for (i = 0, ptr = maskval + 1; *ptr && i < 8; i ++)
1333 {
1334 if (*ptr == ']')
1335 break;
1336 else if (!strncmp(ptr, "::", 2))
1337 {
1338 for (ptr2 = strchr(ptr + 2, ':'), j = 0;
1339 ptr2;
1340 ptr2 = strchr(ptr2 + 1, ':'), j ++);
1341
1342 i = 7 - j;
1343 }
1344 else if (isxdigit(*ptr & 255))
1345 {
1346 ipval = strtoul(ptr, (char **)&ptr, 16);
1347
1348 if (ipval > 0xffff)
1349 return (0);
1350
1351 if (i & 1)
1352 mask[i] |= ipval;
1353 else
1354 mask[i] |= ipval << 16;
1355 }
1356 else
1357 return (0);
1358
1359 while (*ptr == ':')
1360 ptr ++;
1361 }
1362
1363 if (*ptr)
1364 return (0);
1365 }
1366 else
1367 #endif /* AF_INET6 */
1368 if (strchr(maskval, '.'))
1369 {
1370 /*
1371 * Get dotted-decimal mask...
1372 */
1373
1374 if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2, mask + 3) != 4)
1375 return (0);
1376
1377 mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8;
1378 mask[0] = mask[1] = mask[2] = 0;
1379 }
1380 else
1381 {
1382 /*
1383 * Get address/bits format...
1384 */
1385
1386 i = atoi(maskval);
1387
1388 #ifdef AF_INET6
1389 if (family == AF_INET6)
1390 {
1391 i = 128 - i;
1392
1393 if (i <= 96)
1394 mask[0] = 0xffffffff;
1395 else
1396 mask[0] = (0xffffffff << (i - 96)) & 0xffffffff;
1397
1398 if (i <= 64)
1399 mask[1] = 0xffffffff;
1400 else if (i >= 96)
1401 mask[1] = 0;
1402 else
1403 mask[1] = (0xffffffff << (i - 64)) & 0xffffffff;
1404
1405 if (i <= 32)
1406 mask[2] = 0xffffffff;
1407 else if (i >= 64)
1408 mask[2] = 0;
1409 else
1410 mask[2] = (0xffffffff << (i - 32)) & 0xffffffff;
1411
1412 if (i == 0)
1413 mask[3] = 0xffffffff;
1414 else if (i >= 32)
1415 mask[3] = 0;
1416 else
1417 mask[3] = (0xffffffff << i) & 0xffffffff;
1418 }
1419 else
1420 #endif /* AF_INET6 */
1421 {
1422 i = 32 - i;
1423
1424 mask[0] = 0xffffffff;
1425 mask[1] = 0xffffffff;
1426 mask[2] = 0xffffffff;
1427
1428 if (i > 0)
1429 mask[3] = (0xffffffff << i) & 0xffffffff;
1430 else
1431 mask[3] = 0xffffffff;
1432 }
1433 }
1434 }
1435 #ifdef AF_INET6
1436 else if (family == AF_INET6)
1437 memcpy(mask, netmasks6[ipcount - 1], sizeof(unsigned) * 4);
1438 #endif /* AF_INET6 */
1439 else
1440 memcpy(mask, netmasks[ipcount - 1], sizeof(unsigned) * 4);
1441
1442 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1443 "get_addr_and_mask(value=\"%s\", "
1444 "ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x]",
1445 value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2],
1446 mask[3]);
1447
1448 /*
1449 * Check for a valid netmask; no fallback like in CUPS 1.1.x!
1450 */
1451
1452 if ((ip[0] & ~mask[0]) != 0 ||
1453 (ip[1] & ~mask[1]) != 0 ||
1454 (ip[2] & ~mask[2]) != 0 ||
1455 (ip[3] & ~mask[3]) != 0)
1456 return (0);
1457
1458 return (1);
1459 }
1460
1461
1462 /*
1463 * 'parse_aaa()' - Parse authentication, authorization, and access control lines.
1464 */
1465
1466 static int /* O - 1 on success, 0 on failure */
1467 parse_aaa(cupsd_location_t *loc, /* I - Location */
1468 char *line, /* I - Line from file */
1469 char *value, /* I - Start of value data */
1470 int linenum) /* I - Current line number */
1471 {
1472 char *valptr; /* Pointer into value */
1473 unsigned ip[4], /* IP address components */
1474 mask[4]; /* IP netmask components */
1475
1476
1477 if (!strcasecmp(line, "Encryption"))
1478 {
1479 /*
1480 * "Encryption xxx" - set required encryption level...
1481 */
1482
1483 if (!strcasecmp(value, "never"))
1484 loc->encryption = HTTP_ENCRYPT_NEVER;
1485 else if (!strcasecmp(value, "always"))
1486 {
1487 cupsdLogMessage(CUPSD_LOG_ERROR,
1488 "Encryption value \"%s\" on line %d is invalid in this "
1489 "context. Using \"required\" instead.", value, linenum);
1490
1491 loc->encryption = HTTP_ENCRYPT_REQUIRED;
1492 }
1493 else if (!strcasecmp(value, "required"))
1494 loc->encryption = HTTP_ENCRYPT_REQUIRED;
1495 else if (!strcasecmp(value, "ifrequested"))
1496 loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
1497 else
1498 {
1499 cupsdLogMessage(CUPSD_LOG_ERROR,
1500 "Unknown Encryption value %s on line %d.", value, linenum);
1501 return (0);
1502 }
1503 }
1504 else if (!strcasecmp(line, "Order"))
1505 {
1506 /*
1507 * "Order Deny,Allow" or "Order Allow,Deny"...
1508 */
1509
1510 if (!strncasecmp(value, "deny", 4))
1511 loc->order_type = AUTH_ALLOW;
1512 else if (!strncasecmp(value, "allow", 5))
1513 loc->order_type = AUTH_DENY;
1514 else
1515 {
1516 cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.",
1517 value, linenum);
1518 return (0);
1519 }
1520 }
1521 else if (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny"))
1522 {
1523 /*
1524 * Allow [From] host/ip...
1525 * Deny [From] host/ip...
1526 */
1527
1528 if (!strncasecmp(value, "from", 4))
1529 {
1530 /*
1531 * Strip leading "from"...
1532 */
1533
1534 value += 4;
1535
1536 while (isspace(*value & 255))
1537 value ++;
1538 }
1539
1540 /*
1541 * Figure out what form the allow/deny address takes:
1542 *
1543 * All
1544 * None
1545 * *.domain.com
1546 * .domain.com
1547 * host.domain.com
1548 * nnn.*
1549 * nnn.nnn.*
1550 * nnn.nnn.nnn.*
1551 * nnn.nnn.nnn.nnn
1552 * nnn.nnn.nnn.nnn/mm
1553 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
1554 */
1555
1556 if (!strcasecmp(value, "all"))
1557 {
1558 /*
1559 * All hosts...
1560 */
1561
1562 if (!strcasecmp(line, "Allow"))
1563 cupsdAllowIP(loc, zeros, zeros);
1564 else
1565 cupsdDenyIP(loc, zeros, zeros);
1566 }
1567 else if (!strcasecmp(value, "none"))
1568 {
1569 /*
1570 * No hosts...
1571 */
1572
1573 if (!strcasecmp(line, "Allow"))
1574 cupsdAllowIP(loc, ones, zeros);
1575 else
1576 cupsdDenyIP(loc, ones, zeros);
1577 }
1578 else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
1579 {
1580 /*
1581 * Host or domain name...
1582 */
1583
1584 if (value[0] == '*')
1585 value ++;
1586
1587 if (!strcasecmp(line, "Allow"))
1588 cupsdAllowHost(loc, value);
1589 else
1590 cupsdDenyHost(loc, value);
1591 }
1592 else
1593 {
1594 /*
1595 * One of many IP address forms...
1596 */
1597
1598 if (!get_addr_and_mask(value, ip, mask))
1599 {
1600 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
1601 value, linenum);
1602 return (0);
1603 }
1604
1605 if (!strcasecmp(line, "Allow"))
1606 cupsdAllowIP(loc, ip, mask);
1607 else
1608 cupsdDenyIP(loc, ip, mask);
1609 }
1610 }
1611 else if (!strcasecmp(line, "AuthType"))
1612 {
1613 /*
1614 * AuthType {none,basic,digest,basicdigest}
1615 */
1616
1617 if (!strcasecmp(value, "none"))
1618 {
1619 loc->type = AUTH_NONE;
1620 loc->level = AUTH_ANON;
1621 }
1622 else if (!strcasecmp(value, "basic"))
1623 {
1624 loc->type = AUTH_BASIC;
1625
1626 if (loc->level == AUTH_ANON)
1627 loc->level = AUTH_USER;
1628 }
1629 else if (!strcasecmp(value, "digest"))
1630 {
1631 loc->type = AUTH_DIGEST;
1632
1633 if (loc->level == AUTH_ANON)
1634 loc->level = AUTH_USER;
1635 }
1636 else if (!strcasecmp(value, "basicdigest"))
1637 {
1638 loc->type = AUTH_BASICDIGEST;
1639
1640 if (loc->level == AUTH_ANON)
1641 loc->level = AUTH_USER;
1642 }
1643 else
1644 {
1645 cupsdLogMessage(CUPSD_LOG_WARN,
1646 "Unknown authorization type %s on line %d.",
1647 value, linenum);
1648 return (0);
1649 }
1650 }
1651 else if (!strcasecmp(line, "AuthClass"))
1652 {
1653 /*
1654 * AuthClass anonymous, user, system, group
1655 */
1656
1657 if (!strcasecmp(value, "anonymous"))
1658 {
1659 loc->type = AUTH_NONE;
1660 loc->level = AUTH_ANON;
1661
1662 cupsdLogMessage(CUPSD_LOG_WARN,
1663 "\"AuthClass %s\" is deprecated; consider removing "
1664 "it from line %d.",
1665 value, linenum);
1666 }
1667 else if (!strcasecmp(value, "user"))
1668 {
1669 loc->level = AUTH_USER;
1670
1671 cupsdLogMessage(CUPSD_LOG_WARN,
1672 "\"AuthClass %s\" is deprecated; consider using "
1673 "\"Require valid-user\" on line %d.",
1674 value, linenum);
1675 }
1676 else if (!strcasecmp(value, "group"))
1677 {
1678 loc->level = AUTH_GROUP;
1679
1680 cupsdLogMessage(CUPSD_LOG_WARN,
1681 "\"AuthClass %s\" is deprecated; consider using "
1682 "\"Require @groupname\" on line %d.",
1683 value, linenum);
1684 }
1685 else if (!strcasecmp(value, "system"))
1686 {
1687 loc->level = AUTH_GROUP;
1688
1689 cupsdAddName(loc, "@SYSTEM");
1690
1691 cupsdLogMessage(CUPSD_LOG_WARN,
1692 "\"AuthClass %s\" is deprecated; consider using "
1693 "\"Require @SYSTEM\" on line %d.",
1694 value, linenum);
1695 }
1696 else
1697 {
1698 cupsdLogMessage(CUPSD_LOG_WARN,
1699 "Unknown authorization class %s on line %d.",
1700 value, linenum);
1701 return (0);
1702 }
1703 }
1704 else if (!strcasecmp(line, "AuthGroupName"))
1705 {
1706 cupsdAddName(loc, value);
1707
1708 cupsdLogMessage(CUPSD_LOG_WARN,
1709 "\"AuthGroupName %s\" directive is deprecated; consider "
1710 "using \"Require @%s\" on line %d.",
1711 value, value, linenum);
1712 }
1713 else if (!strcasecmp(line, "Require"))
1714 {
1715 /*
1716 * Apache synonym for AuthClass and AuthGroupName...
1717 *
1718 * Get initial word:
1719 *
1720 * Require valid-user
1721 * Require group names
1722 * Require user names
1723 */
1724
1725 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
1726
1727 if (*valptr)
1728 *valptr++ = '\0';
1729
1730 if (!strcasecmp(value, "valid-user") ||
1731 !strcasecmp(value, "user"))
1732 loc->level = AUTH_USER;
1733 else if (!strcasecmp(value, "group"))
1734 loc->level = AUTH_GROUP;
1735 else
1736 {
1737 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.",
1738 value, linenum);
1739 return (0);
1740 }
1741
1742 /*
1743 * Get the list of names from the line...
1744 */
1745
1746 for (value = valptr; *value;)
1747 {
1748 while (isspace(*value & 255))
1749 value ++;
1750
1751 if (*value == '\"' || *value == '\'')
1752 {
1753 /*
1754 * Grab quoted name...
1755 */
1756
1757 for (valptr = value + 1; *valptr != *value && *valptr; valptr ++);
1758
1759 value ++;
1760 }
1761 else
1762 {
1763 /*
1764 * Grab literal name.
1765 */
1766
1767 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
1768 }
1769
1770 if (*valptr)
1771 *valptr++ = '\0';
1772
1773 cupsdAddName(loc, value);
1774
1775 for (value = valptr; isspace(*value & 255); value ++);
1776 }
1777 }
1778 else if (!strcasecmp(line, "Satisfy"))
1779 {
1780 if (!strcasecmp(value, "all"))
1781 loc->satisfy = AUTH_SATISFY_ALL;
1782 else if (!strcasecmp(value, "any"))
1783 loc->satisfy = AUTH_SATISFY_ANY;
1784 else
1785 {
1786 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.",
1787 value, linenum);
1788 return (0);
1789 }
1790 }
1791 else
1792 return (0);
1793
1794 return (1);
1795 }
1796
1797
1798 /*
1799 * 'read_configuration()' - Read a configuration file.
1800 */
1801
1802 static int /* O - 1 on success, 0 on failure */
1803 read_configuration(cups_file_t *fp) /* I - File to read from */
1804 {
1805 int i; /* Looping var */
1806 int linenum; /* Current line number */
1807 char line[HTTP_MAX_BUFFER],
1808 /* Line from file */
1809 temp[HTTP_MAX_BUFFER],
1810 /* Temporary buffer for value */
1811 temp2[HTTP_MAX_BUFFER],
1812 /* Temporary buffer 2 for value */
1813 *ptr, /* Pointer into line/temp */
1814 *value, /* Pointer to value */
1815 *valueptr, /* Pointer into value */
1816 quote; /* Quote character */
1817 int valuelen; /* Length of value */
1818 cupsd_var_t *var; /* Current variable */
1819 http_addrlist_t *addrlist, /* Address list */
1820 *addr; /* Current address */
1821 unsigned ip[4], /* Address value */
1822 mask[4]; /* Netmask value */
1823 cupsd_dirsvc_relay_t *relay; /* Relay data */
1824 cupsd_dirsvc_poll_t *pollp; /* Polling data */
1825 cupsd_location_t *location; /* Browse location */
1826 cups_file_t *incfile; /* Include file */
1827 char incname[1024]; /* Include filename */
1828 struct group *group; /* Group */
1829
1830
1831 /*
1832 * Loop through each line in the file...
1833 */
1834
1835 linenum = 0;
1836
1837 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
1838 {
1839 /*
1840 * Decode the directive...
1841 */
1842
1843 if (!strcasecmp(line, "Include"))
1844 {
1845 /*
1846 * Include filename
1847 */
1848
1849 if (value[0] == '/')
1850 strlcpy(incname, value, sizeof(incname));
1851 else
1852 snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
1853
1854 if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
1855 cupsdLogMessage(CUPSD_LOG_ERROR,
1856 "Unable to include config file \"%s\" - %s",
1857 incname, strerror(errno));
1858 else
1859 {
1860 read_configuration(incfile);
1861 cupsFileClose(incfile);
1862 }
1863 }
1864 else if (!strcasecmp(line, "<Location"))
1865 {
1866 /*
1867 * <Location path>
1868 */
1869
1870 if (value)
1871 {
1872 linenum = read_location(fp, value, linenum);
1873 if (linenum == 0)
1874 return (0);
1875 }
1876 else
1877 {
1878 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.",
1879 linenum);
1880 return (0);
1881 }
1882 }
1883 else if (!strcasecmp(line, "<Policy"))
1884 {
1885 /*
1886 * <Policy name>
1887 */
1888
1889 if (value)
1890 {
1891 linenum = read_policy(fp, value, linenum);
1892 if (linenum == 0)
1893 return (0);
1894 }
1895 else
1896 {
1897 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
1898 return (0);
1899 }
1900 }
1901 else if (!strcasecmp(line, "FaxRetryInterval"))
1902 {
1903 if (value)
1904 {
1905 JobRetryInterval = atoi(value);
1906 cupsdLogMessage(CUPSD_LOG_WARN,
1907 "FaxRetryInterval is deprecated; use "
1908 "JobRetryInterval on line %d.", linenum);
1909 }
1910 else
1911 {
1912 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
1913 return (0);
1914 }
1915 }
1916 else if (!strcasecmp(line, "FaxRetryLimit"))
1917 {
1918 if (value)
1919 {
1920 JobRetryLimit = atoi(value);
1921 cupsdLogMessage(CUPSD_LOG_WARN,
1922 "FaxRetryLimit is deprecated; use "
1923 "JobRetryLimit on line %d.", linenum);
1924 }
1925 else
1926 {
1927 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
1928 return (0);
1929 }
1930 }
1931 else if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen")
1932 #ifdef HAVE_SSL
1933 || !strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen")
1934 #endif /* HAVE_SSL */
1935 )
1936 {
1937 /*
1938 * Add listening address(es) to the list...
1939 */
1940
1941 cupsd_listener_t *lis; /* New listeners array */
1942
1943
1944 /*
1945 * Get the address list...
1946 */
1947
1948 addrlist = get_address(value, IPP_PORT);
1949
1950 if (!addrlist)
1951 {
1952 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line,
1953 value, linenum);
1954 continue;
1955 }
1956
1957 /*
1958 * Add each address...
1959 */
1960
1961 for (addr = addrlist; addr; addr = addr->next)
1962 {
1963 /*
1964 * Allocate another listener...
1965 */
1966
1967 if (NumListeners == 0)
1968 lis = malloc(sizeof(cupsd_listener_t));
1969 else
1970 lis = realloc(Listeners, (NumListeners + 1) * sizeof(cupsd_listener_t));
1971
1972 if (!lis)
1973 {
1974 cupsdLogMessage(CUPSD_LOG_ERROR,
1975 "Unable to allocate %s at line %d - %s.",
1976 line, linenum, strerror(errno));
1977 break;
1978 }
1979
1980 Listeners = lis;
1981 lis += NumListeners;
1982
1983 /*
1984 * Copy the current address and log it...
1985 */
1986
1987 memset(lis, 0, sizeof(cupsd_listener_t));
1988 memcpy(&(lis->address), &(addr->addr), sizeof(lis->address));
1989 lis->fd = -1;
1990
1991 #ifdef HAVE_SSL
1992 if (!strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen"))
1993 lis->encryption = HTTP_ENCRYPT_ALWAYS;
1994 #endif /* HAVE_SSL */
1995
1996
1997 httpAddrString(&lis->address, temp, sizeof(temp));
1998
1999 #ifdef AF_INET6
2000 if (lis->address.addr.sa_family == AF_INET6)
2001 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv6)", temp,
2002 ntohs(lis->address.ipv6.sin6_port));
2003 else
2004 #endif /* AF_INET6 */
2005 #ifdef AF_LOCAL
2006 if (lis->address.addr.sa_family == AF_LOCAL)
2007 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp);
2008 else
2009 #endif /* AF_LOCAL */
2010 cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp,
2011 ntohs(lis->address.ipv4.sin_port));
2012
2013 NumListeners ++;
2014 }
2015
2016 /*
2017 * Free the list...
2018 */
2019
2020 httpAddrFreeList(addrlist);
2021 }
2022 else if (!strcasecmp(line, "BrowseAddress"))
2023 {
2024 /*
2025 * Add a browse address to the list...
2026 */
2027
2028 cupsd_dirsvc_addr_t *dira; /* New browse address array */
2029
2030
2031 if (NumBrowsers == 0)
2032 dira = malloc(sizeof(cupsd_dirsvc_addr_t));
2033 else
2034 dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t));
2035
2036 if (!dira)
2037 {
2038 cupsdLogMessage(CUPSD_LOG_ERROR,
2039 "Unable to allocate BrowseAddress at line %d - %s.",
2040 linenum, strerror(errno));
2041 continue;
2042 }
2043
2044 Browsers = dira;
2045 dira += NumBrowsers;
2046
2047 memset(dira, 0, sizeof(cupsd_dirsvc_addr_t));
2048
2049 if (!strcasecmp(value, "@LOCAL"))
2050 {
2051 /*
2052 * Send browse data to all local interfaces...
2053 */
2054
2055 strcpy(dira->iface, "*");
2056 NumBrowsers ++;
2057 }
2058 else if (!strncasecmp(value, "@IF(", 4))
2059 {
2060 /*
2061 * Send browse data to the named interface...
2062 */
2063
2064 strlcpy(dira->iface, value + 4, sizeof(Browsers[0].iface));
2065
2066 ptr = dira->iface + strlen(dira->iface) - 1;
2067 if (*ptr == ')')
2068 *ptr = '\0';
2069
2070 NumBrowsers ++;
2071 }
2072 else if ((addrlist = get_address(value, BrowsePort)) != NULL)
2073 {
2074 /*
2075 * Only IPv4 addresses are supported...
2076 */
2077
2078 for (addr = addrlist; addr; addr = addr->next)
2079 if (addr->addr.addr.sa_family == AF_INET)
2080 break;
2081
2082 if (addr)
2083 {
2084 memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to));
2085 httpAddrString(&(dira->to), temp, sizeof(temp));
2086
2087 cupsdLogMessage(CUPSD_LOG_INFO,
2088 "Sending browsing info to %s:%d (IPv4)",
2089 temp, ntohs(dira->to.ipv4.sin_port));
2090
2091 NumBrowsers ++;
2092 }
2093 else
2094 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
2095 value, linenum);
2096
2097 httpAddrFreeList(addrlist);
2098 }
2099 else
2100 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.",
2101 value, linenum);
2102 }
2103 else if (!strcasecmp(line, "BrowseOrder"))
2104 {
2105 /*
2106 * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"...
2107 */
2108
2109 if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
2110 location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL");
2111
2112 if (location == NULL)
2113 cupsdLogMessage(CUPSD_LOG_ERROR,
2114 "Unable to initialize browse access control list!");
2115 else if (!strncasecmp(value, "deny", 4))
2116 location->order_type = AUTH_ALLOW;
2117 else if (!strncasecmp(value, "allow", 5))
2118 location->order_type = AUTH_DENY;
2119 else
2120 cupsdLogMessage(CUPSD_LOG_ERROR,
2121 "Unknown BrowseOrder value %s on line %d.",
2122 value, linenum);
2123 }
2124 else if (!strcasecmp(line, "BrowseProtocols") ||
2125 !strcasecmp(line, "BrowseLocalProtocols") ||
2126 !strcasecmp(line, "BrowseRemoteProtocols"))
2127 {
2128 /*
2129 * "BrowseProtocol name [... name]"
2130 */
2131
2132 if (strcasecmp(line, "BrowseLocalProtocols"))
2133 BrowseRemoteProtocols = 0;
2134 if (strcasecmp(line, "BrowseRemoteProtocols"))
2135 BrowseLocalProtocols = 0;
2136
2137 for (; *value;)
2138 {
2139 for (valuelen = 0; value[valuelen]; valuelen ++)
2140 if (isspace(value[valuelen]) || value[valuelen] == ',')
2141 break;
2142
2143 if (value[valuelen])
2144 {
2145 value[valuelen] = '\0';
2146 valuelen ++;
2147 }
2148
2149 if (!strcasecmp(value, "cups"))
2150 {
2151 if (strcasecmp(line, "BrowseLocalProtocols"))
2152 BrowseRemoteProtocols |= BROWSE_CUPS;
2153 if (strcasecmp(line, "BrowseRemoteProtocols"))
2154 BrowseLocalProtocols |= BROWSE_CUPS;
2155 }
2156 else if (!strcasecmp(value, "slp"))
2157 {
2158 if (strcasecmp(line, "BrowseLocalProtocols"))
2159 BrowseRemoteProtocols |= BROWSE_SLP;
2160 if (strcasecmp(line, "BrowseRemoteProtocols"))
2161 BrowseLocalProtocols |= BROWSE_SLP;
2162 }
2163 else if (!strcasecmp(value, "ldap"))
2164 {
2165 if (strcasecmp(line, "BrowseLocalProtocols"))
2166 BrowseRemoteProtocols |= BROWSE_LDAP;
2167 if (strcasecmp(line, "BrowseRemoteProtocols"))
2168 BrowseLocalProtocols |= BROWSE_LDAP;
2169 }
2170 else if (!strcasecmp(value, "all"))
2171 {
2172 if (strcasecmp(line, "BrowseLocalProtocols"))
2173 BrowseRemoteProtocols |= BROWSE_ALL;
2174 if (strcasecmp(line, "BrowseRemoteProtocols"))
2175 BrowseLocalProtocols |= BROWSE_ALL;
2176 }
2177 else
2178 {
2179 cupsdLogMessage(CUPSD_LOG_ERROR,
2180 "Unknown browse protocol \"%s\" on line %d.",
2181 value, linenum);
2182 break;
2183 }
2184
2185 for (value += valuelen; *value; value ++)
2186 if (!isspace(*value) || *value != ',')
2187 break;
2188 }
2189 }
2190 else if (!strcasecmp(line, "BrowseAllow") ||
2191 !strcasecmp(line, "BrowseDeny"))
2192 {
2193 /*
2194 * BrowseAllow [From] host/ip...
2195 * BrowseDeny [From] host/ip...
2196 */
2197
2198 if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
2199 location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL");
2200
2201 if (location == NULL)
2202 cupsdLogMessage(CUPSD_LOG_ERROR,
2203 "Unable to initialize browse access control list!");
2204 else
2205 {
2206 if (!strncasecmp(value, "from ", 5))
2207 {
2208 /*
2209 * Strip leading "from"...
2210 */
2211
2212 value += 5;
2213
2214 while (isspace(*value))
2215 value ++;
2216 }
2217
2218 /*
2219 * Figure out what form the allow/deny address takes:
2220 *
2221 * All
2222 * None
2223 * *.domain.com
2224 * .domain.com
2225 * host.domain.com
2226 * nnn.*
2227 * nnn.nnn.*
2228 * nnn.nnn.nnn.*
2229 * nnn.nnn.nnn.nnn
2230 * nnn.nnn.nnn.nnn/mm
2231 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
2232 */
2233
2234 if (!strcasecmp(value, "all"))
2235 {
2236 /*
2237 * All hosts...
2238 */
2239
2240 if (!strcasecmp(line, "BrowseAllow"))
2241 cupsdAllowIP(location, zeros, zeros);
2242 else
2243 cupsdDenyIP(location, zeros, zeros);
2244 }
2245 else if (!strcasecmp(value, "none"))
2246 {
2247 /*
2248 * No hosts...
2249 */
2250
2251 if (!strcasecmp(line, "BrowseAllow"))
2252 cupsdAllowIP(location, ones, zeros);
2253 else
2254 cupsdDenyIP(location, ones, zeros);
2255 }
2256 else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
2257 {
2258 /*
2259 * Host or domain name...
2260 */
2261
2262 if (value[0] == '*')
2263 value ++;
2264
2265 if (!strcasecmp(line, "BrowseAllow"))
2266 cupsdAllowHost(location, value);
2267 else
2268 cupsdDenyHost(location, value);
2269 }
2270 else
2271 {
2272 /*
2273 * One of many IP address forms...
2274 */
2275
2276 if (!get_addr_and_mask(value, ip, mask))
2277 {
2278 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
2279 value, linenum);
2280 break;
2281 }
2282
2283 if (!strcasecmp(line, "BrowseAllow"))
2284 cupsdAllowIP(location, ip, mask);
2285 else
2286 cupsdDenyIP(location, ip, mask);
2287 }
2288 }
2289 }
2290 else if (!strcasecmp(line, "BrowseRelay"))
2291 {
2292 /*
2293 * BrowseRelay [from] source [to] destination
2294 */
2295
2296 if (NumRelays == 0)
2297 relay = malloc(sizeof(cupsd_dirsvc_relay_t));
2298 else
2299 relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t));
2300
2301 if (!relay)
2302 {
2303 cupsdLogMessage(CUPSD_LOG_ERROR,
2304 "Unable to allocate BrowseRelay at line %d - %s.",
2305 linenum, strerror(errno));
2306 continue;
2307 }
2308
2309 Relays = relay;
2310 relay += NumRelays;
2311
2312 memset(relay, 0, sizeof(cupsd_dirsvc_relay_t));
2313
2314 if (!strncasecmp(value, "from ", 5))
2315 {
2316 /*
2317 * Strip leading "from"...
2318 */
2319
2320 value += 5;
2321
2322 while (isspace(*value))
2323 value ++;
2324 }
2325
2326 /*
2327 * Figure out what form the from address takes:
2328 *
2329 * *.domain.com
2330 * .domain.com
2331 * host.domain.com
2332 * nnn.*
2333 * nnn.nnn.*
2334 * nnn.nnn.nnn.*
2335 * nnn.nnn.nnn.nnn
2336 * nnn.nnn.nnn.nnn/mm
2337 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
2338 */
2339
2340 if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
2341 {
2342 /*
2343 * Host or domain name...
2344 */
2345
2346 if (value[0] == '*')
2347 value ++;
2348
2349 strlcpy(temp, value, sizeof(temp));
2350 if ((ptr = strchr(temp, ' ')) != NULL)
2351 *ptr = '\0';
2352
2353 relay->from.type = AUTH_NAME;
2354 relay->from.mask.name.name = strdup(temp);
2355 relay->from.mask.name.length = strlen(temp);
2356 }
2357 else
2358 {
2359 /*
2360 * One of many IP address forms...
2361 */
2362
2363 if (!get_addr_and_mask(value, ip, mask))
2364 {
2365 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
2366 value, linenum);
2367 break;
2368 }
2369
2370 relay->from.type = AUTH_IP;
2371 memcpy(relay->from.mask.ip.address, ip,
2372 sizeof(relay->from.mask.ip.address));
2373 memcpy(relay->from.mask.ip.netmask, mask,
2374 sizeof(relay->from.mask.ip.netmask));
2375 }
2376
2377 /*
2378 * Skip value and trailing whitespace...
2379 */
2380
2381 for (; *value; value ++)
2382 if (isspace(*value))
2383 break;
2384
2385 while (isspace(*value))
2386 value ++;
2387
2388 if (!strncasecmp(value, "to ", 3))
2389 {
2390 /*
2391 * Strip leading "to"...
2392 */
2393
2394 value += 3;
2395
2396 while (isspace(*value))
2397 value ++;
2398 }
2399
2400 /*
2401 * Get "to" address and port...
2402 */
2403
2404 if ((addrlist = get_address(value, BrowsePort)) != NULL)
2405 {
2406 /*
2407 * Only IPv4 addresses are supported...
2408 */
2409
2410 for (addr = addrlist; addr; addr = addr->next)
2411 if (addr->addr.addr.sa_family == AF_INET)
2412 break;
2413
2414 if (addr)
2415 {
2416 memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to));
2417
2418 httpAddrString(&(relay->to), temp, sizeof(temp));
2419
2420 if (relay->from.type == AUTH_IP)
2421 snprintf(temp2, sizeof(temp2), "%u.%u.%u.%u/%u.%u.%u.%u",
2422 relay->from.mask.ip.address[0],
2423 relay->from.mask.ip.address[1],
2424 relay->from.mask.ip.address[2],
2425 relay->from.mask.ip.address[3],
2426 relay->from.mask.ip.netmask[0],
2427 relay->from.mask.ip.netmask[1],
2428 relay->from.mask.ip.netmask[2],
2429 relay->from.mask.ip.netmask[3]);
2430 else
2431 strlcpy(temp2, relay->from.mask.name.name, sizeof(temp2));
2432
2433 cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)",
2434 temp, temp2, ntohs(relay->to.ipv4.sin_port));
2435
2436 NumRelays ++;
2437 }
2438 else
2439 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
2440 value, linenum);
2441
2442 httpAddrFreeList(addrlist);
2443 }
2444 else
2445 {
2446 if (relay->from.type == AUTH_NAME)
2447 free(relay->from.mask.name.name);
2448
2449 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
2450 value, linenum);
2451 }
2452 }
2453 else if (!strcasecmp(line, "BrowsePoll"))
2454 {
2455 /*
2456 * BrowsePoll address[:port]
2457 */
2458
2459 char *portname; /* Port name */
2460 int portnum; /* Port number */
2461 struct servent *service; /* Service */
2462
2463
2464 /*
2465 * Extract the port name from the address...
2466 */
2467
2468 if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']'))
2469 {
2470 *portname++ = '\0';
2471
2472 if (isdigit(*portname & 255))
2473 portnum = atoi(portname);
2474 else if ((service = getservbyname(portname, NULL)) != NULL)
2475 portnum = ntohs(service->s_port);
2476 else
2477 {
2478 cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed!",
2479 portname);
2480 continue;
2481 }
2482 }
2483 else
2484 portnum = ippPort();
2485
2486 /*
2487 * Add the poll entry...
2488 */
2489
2490 if (NumPolled == 0)
2491 pollp = malloc(sizeof(cupsd_dirsvc_poll_t));
2492 else
2493 pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t));
2494
2495 if (!pollp)
2496 {
2497 cupsdLogMessage(CUPSD_LOG_ERROR,
2498 "Unable to allocate BrowsePoll at line %d - %s.",
2499 linenum, strerror(errno));
2500 continue;
2501 }
2502
2503 Polled = pollp;
2504 pollp += NumPolled;
2505
2506 NumPolled ++;
2507 memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t));
2508
2509 strlcpy(pollp->hostname, value, sizeof(pollp->hostname));
2510 pollp->port = portnum;
2511
2512 cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname,
2513 pollp->port);
2514 }
2515 else if (!strcasecmp(line, "DefaultAuthType"))
2516 {
2517 /*
2518 * DefaultAuthType {basic,digest,basicdigest}
2519 */
2520
2521 if (!strcasecmp(value, "basic"))
2522 DefaultAuthType = AUTH_BASIC;
2523 else if (!strcasecmp(value, "digest"))
2524 DefaultAuthType = AUTH_DIGEST;
2525 else if (!strcasecmp(value, "basicdigest"))
2526 DefaultAuthType = AUTH_BASICDIGEST;
2527 else
2528 {
2529 cupsdLogMessage(CUPSD_LOG_WARN,
2530 "Unknown default authorization type %s on line %d.",
2531 value, linenum);
2532 return (0);
2533 }
2534 }
2535 else if (!strcasecmp(line, "User"))
2536 {
2537 /*
2538 * User ID to run as...
2539 */
2540
2541 if (value && isdigit(value[0] & 255))
2542 {
2543 int uid = atoi(value);
2544
2545 if (!uid)
2546 cupsdLogMessage(CUPSD_LOG_ERROR,
2547 "Will not use User 0 as specified on line %d "
2548 "for security reasons. You must use a non-"
2549 "privileged account instead.",
2550 linenum);
2551 else
2552 User = atoi(value);
2553 }
2554 else if (value)
2555 {
2556 struct passwd *p; /* Password information */
2557
2558 endpwent();
2559 p = getpwnam(value);
2560
2561 if (p)
2562 {
2563 if (!p->pw_uid)
2564 cupsdLogMessage(CUPSD_LOG_ERROR,
2565 "Will not use User %s (UID=0) as specified on line "
2566 "%d for security reasons. You must use a non-"
2567 "privileged account instead.",
2568 value, linenum);
2569 else
2570 User = p->pw_uid;
2571 }
2572 else
2573 cupsdLogMessage(CUPSD_LOG_ERROR,
2574 "Unknown User \"%s\" on line %d, ignoring!",
2575 value, linenum);
2576 }
2577 else
2578 cupsdLogMessage(CUPSD_LOG_ERROR,
2579 "User directive on line %d missing the username!",
2580 linenum);
2581 }
2582 else if (!strcasecmp(line, "Group"))
2583 {
2584 /*
2585 * Group ID to run as...
2586 */
2587
2588 if (isdigit(value[0]))
2589 Group = atoi(value);
2590 else
2591 {
2592 endgrent();
2593 group = getgrnam(value);
2594
2595 if (group != NULL)
2596 Group = group->gr_gid;
2597 else
2598 cupsdLogMessage(CUPSD_LOG_ERROR,
2599 "Unknown Group \"%s\" on line %d, ignoring!",
2600 value, linenum);
2601 }
2602 }
2603 else if (!strcasecmp(line, "SystemGroup"))
2604 {
2605 /*
2606 * System (admin) group(s)...
2607 */
2608
2609 for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS;)
2610 {
2611 if (*value == '\'' || *value == '\"')
2612 {
2613 /*
2614 * Scan quoted name...
2615 */
2616
2617 quote = *value++;
2618
2619 for (valueptr = value; *valueptr; valueptr ++)
2620 if (*valueptr == quote)
2621 break;
2622 }
2623 else
2624 {
2625 /*
2626 * Scan space or comma-delimited name...
2627 */
2628
2629 for (valueptr = value; *valueptr; valueptr ++)
2630 if (isspace(*valueptr) || *valueptr == ',')
2631 break;
2632 }
2633
2634 if (*valueptr)
2635 *valueptr++ = '\0';
2636
2637 group = getgrnam(value);
2638 if (group)
2639 {
2640 cupsdSetString(SystemGroups + i, value);
2641 SystemGroupIDs[i] = group->gr_gid;
2642
2643 i ++;
2644 }
2645 else
2646 cupsdLogMessage(CUPSD_LOG_ERROR,
2647 "Unknown SystemGroup \"%s\" on line %d, ignoring!",
2648 value, linenum);
2649
2650 endgrent();
2651
2652 value = valueptr;
2653
2654 while (*value == ',' || isspace(*value))
2655 value ++;
2656 }
2657
2658 if (i)
2659 NumSystemGroups = i;
2660 }
2661 else if (!strcasecmp(line, "HostNameLookups"))
2662 {
2663 /*
2664 * Do hostname lookups?
2665 */
2666
2667 if (!strcasecmp(value, "off"))
2668 HostNameLookups = 0;
2669 else if (!strcasecmp(value, "on"))
2670 HostNameLookups = 1;
2671 else if (!strcasecmp(value, "double"))
2672 HostNameLookups = 2;
2673 else
2674 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.",
2675 value, linenum);
2676 }
2677 else if (!strcasecmp(line, "LogLevel"))
2678 {
2679 /*
2680 * Amount of logging to do...
2681 */
2682
2683 if (!strcasecmp(value, "debug2"))
2684 LogLevel = CUPSD_LOG_DEBUG2;
2685 else if (!strcasecmp(value, "debug"))
2686 LogLevel = CUPSD_LOG_DEBUG;
2687 else if (!strcasecmp(value, "info"))
2688 LogLevel = CUPSD_LOG_INFO;
2689 else if (!strcasecmp(value, "notice"))
2690 LogLevel = CUPSD_LOG_NOTICE;
2691 else if (!strcasecmp(value, "warn"))
2692 LogLevel = CUPSD_LOG_WARN;
2693 else if (!strcasecmp(value, "error"))
2694 LogLevel = CUPSD_LOG_ERROR;
2695 else if (!strcasecmp(value, "crit"))
2696 LogLevel = CUPSD_LOG_CRIT;
2697 else if (!strcasecmp(value, "alert"))
2698 LogLevel = CUPSD_LOG_ALERT;
2699 else if (!strcasecmp(value, "emerg"))
2700 LogLevel = CUPSD_LOG_EMERG;
2701 else if (!strcasecmp(value, "none"))
2702 LogLevel = CUPSD_LOG_NONE;
2703 else
2704 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.",
2705 value, linenum);
2706 }
2707 else if (!strcasecmp(line, "PrintcapFormat"))
2708 {
2709 /*
2710 * Format of printcap file?
2711 */
2712
2713 if (!strcasecmp(value, "bsd"))
2714 PrintcapFormat = PRINTCAP_BSD;
2715 else if (!strcasecmp(value, "solaris"))
2716 PrintcapFormat = PRINTCAP_SOLARIS;
2717 else
2718 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.",
2719 value, linenum);
2720 }
2721 else if (!strcasecmp(line, "ServerTokens"))
2722 {
2723 /*
2724 * Set the string used for the Server header...
2725 */
2726
2727 struct utsname plat; /* Platform info */
2728
2729
2730 uname(&plat);
2731
2732 if (!strcasecmp(value, "ProductOnly"))
2733 cupsdSetString(&ServerHeader, "CUPS");
2734 else if (!strcasecmp(value, "Major"))
2735 cupsdSetString(&ServerHeader, "CUPS/1");
2736 else if (!strcasecmp(value, "Minor"))
2737 cupsdSetString(&ServerHeader, "CUPS/1.1");
2738 else if (!strcasecmp(value, "Minimal"))
2739 cupsdSetString(&ServerHeader, CUPS_MINIMAL);
2740 else if (!strcasecmp(value, "OS"))
2741 cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
2742 else if (!strcasecmp(value, "Full"))
2743 cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1",
2744 plat.sysname);
2745 else if (!strcasecmp(value, "None"))
2746 cupsdClearString(&ServerHeader);
2747 else
2748 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.",
2749 value, linenum);
2750 }
2751 else if (!strcasecmp(line, "PassEnv"))
2752 {
2753 /*
2754 * PassEnv variable [... variable]
2755 */
2756
2757 for (; *value;)
2758 {
2759 for (valuelen = 0; value[valuelen]; valuelen ++)
2760 if (isspace(value[valuelen]) || value[valuelen] == ',')
2761 break;
2762
2763 if (value[valuelen])
2764 {
2765 value[valuelen] = '\0';
2766 valuelen ++;
2767 }
2768
2769 cupsdSetEnv(value, NULL);
2770
2771 for (value += valuelen; *value; value ++)
2772 if (!isspace(*value) || *value != ',')
2773 break;
2774 }
2775 }
2776 else if (!strcasecmp(line, "SetEnv"))
2777 {
2778 /*
2779 * SetEnv variable value
2780 */
2781
2782 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
2783
2784 if (*valueptr)
2785 {
2786 /*
2787 * Found a value...
2788 */
2789
2790 while (isspace(*valueptr & 255))
2791 *valueptr++ = '\0';
2792
2793 cupsdSetEnv(value, valueptr);
2794 }
2795 else
2796 cupsdLogMessage(CUPSD_LOG_ERROR,
2797 "Missing value for SetEnv directive on line %d.",
2798 linenum);
2799 }
2800 else
2801 {
2802 /*
2803 * Find a simple variable in the list...
2804 */
2805
2806 for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
2807 if (!strcasecmp(line, var->name))
2808 break;
2809
2810 if (i == 0)
2811 {
2812 /*
2813 * Unknown directive! Output an error message and continue...
2814 */
2815
2816 cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.",
2817 line, linenum);
2818 continue;
2819 }
2820
2821 switch (var->type)
2822 {
2823 case CUPSD_VARTYPE_INTEGER :
2824 {
2825 int n; /* Number */
2826 char *units; /* Units */
2827
2828
2829 n = strtol(value, &units, 0);
2830
2831 if (units && *units)
2832 {
2833 if (tolower(units[0] & 255) == 'g')
2834 n *= 1024 * 1024 * 1024;
2835 else if (tolower(units[0] & 255) == 'm')
2836 n *= 1024 * 1024;
2837 else if (tolower(units[0] & 255) == 'k')
2838 n *= 1024;
2839 else if (tolower(units[0] & 255) == 't')
2840 n *= 262144;
2841 }
2842
2843 *((int *)var->ptr) = n;
2844 }
2845 break;
2846
2847 case CUPSD_VARTYPE_BOOLEAN :
2848 if (!strcasecmp(value, "true") ||
2849 !strcasecmp(value, "on") ||
2850 !strcasecmp(value, "enabled") ||
2851 !strcasecmp(value, "yes") ||
2852 atoi(value) != 0)
2853 *((int *)var->ptr) = TRUE;
2854 else if (!strcasecmp(value, "false") ||
2855 !strcasecmp(value, "off") ||
2856 !strcasecmp(value, "disabled") ||
2857 !strcasecmp(value, "no") ||
2858 !strcasecmp(value, "0"))
2859 *((int *)var->ptr) = FALSE;
2860 else
2861 cupsdLogMessage(CUPSD_LOG_ERROR,
2862 "Unknown boolean value %s on line %d.",
2863 value, linenum);
2864 break;
2865
2866 case CUPSD_VARTYPE_STRING :
2867 cupsdSetString((char **)var->ptr, value);
2868 break;
2869 }
2870 }
2871 }
2872
2873 return (1);
2874 }
2875
2876
2877 /*
2878 * 'read_location()' - Read a <Location path> definition.
2879 */
2880
2881 static int /* O - New line number or 0 on error */
2882 read_location(cups_file_t *fp, /* I - Configuration file */
2883 char *location, /* I - Location name/path */
2884 int linenum) /* I - Current line number */
2885 {
2886 cupsd_location_t *loc, /* New location */
2887 *parent; /* Parent location */
2888 char line[HTTP_MAX_BUFFER],
2889 /* Line buffer */
2890 *value, /* Value for directive */
2891 *valptr; /* Pointer into value */
2892
2893
2894 if ((parent = cupsdAddLocation(location)) == NULL)
2895 return (0);
2896
2897 parent->limit = AUTH_LIMIT_ALL;
2898 loc = parent;
2899
2900 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
2901 {
2902 /*
2903 * Decode the directive...
2904 */
2905
2906 if (!strcasecmp(line, "</Location>"))
2907 return (linenum);
2908 else if (!strcasecmp(line, "<Limit") ||
2909 !strcasecmp(line, "<LimitExcept"))
2910 {
2911 if (!value)
2912 {
2913 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
2914 return (0);
2915 }
2916
2917 if ((loc = cupsdCopyLocation(&parent)) == NULL)
2918 return (0);
2919
2920 loc->limit = 0;
2921 while (*value)
2922 {
2923 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
2924
2925 if (*valptr)
2926 *valptr++ = '\0';
2927
2928 if (!strcmp(value, "ALL"))
2929 loc->limit = AUTH_LIMIT_ALL;
2930 else if (!strcmp(value, "GET"))
2931 loc->limit |= AUTH_LIMIT_GET;
2932 else if (!strcmp(value, "HEAD"))
2933 loc->limit |= AUTH_LIMIT_HEAD;
2934 else if (!strcmp(value, "OPTIONS"))
2935 loc->limit |= AUTH_LIMIT_OPTIONS;
2936 else if (!strcmp(value, "POST"))
2937 loc->limit |= AUTH_LIMIT_POST;
2938 else if (!strcmp(value, "PUT"))
2939 loc->limit |= AUTH_LIMIT_PUT;
2940 else if (!strcmp(value, "TRACE"))
2941 loc->limit |= AUTH_LIMIT_TRACE;
2942 else
2943 cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d!",
2944 value, linenum);
2945
2946 for (value = valptr; isspace(*value & 255); value ++);
2947 }
2948
2949 if (!strcasecmp(line, "<LimitExcept"))
2950 loc->limit = AUTH_LIMIT_ALL ^ loc->limit;
2951
2952 parent->limit &= ~loc->limit;
2953 }
2954 else if (!strcasecmp(line, "</Limit>"))
2955 loc = parent;
2956 else if (!parse_aaa(loc, line, value, linenum))
2957 {
2958 cupsdLogMessage(CUPSD_LOG_ERROR,
2959 "Unknown Location directive %s on line %d.",
2960 line, linenum);
2961 return (0);
2962 }
2963 }
2964
2965 cupsdLogMessage(CUPSD_LOG_ERROR,
2966 "Unexpected end-of-file at line %d while reading location!",
2967 linenum);
2968
2969 return (0);
2970 }
2971
2972
2973 /*
2974 * 'read_policy()' - Read a <Policy name> definition.
2975 */
2976
2977 static int /* O - New line number or 0 on error */
2978 read_policy(cups_file_t *fp, /* I - Configuration file */
2979 char *policy, /* I - Location name/path */
2980 int linenum) /* I - Current line number */
2981 {
2982 int i; /* Looping var */
2983 cupsd_policy_t *pol; /* Policy */
2984 cupsd_location_t *op; /* Policy operation */
2985 int num_ops; /* Number of IPP operations */
2986 ipp_op_t ops[100]; /* Operations */
2987 char line[HTTP_MAX_BUFFER],
2988 /* Line buffer */
2989 *value, /* Value for directive */
2990 *valptr; /* Pointer into value */
2991
2992
2993 /*
2994 * Create the policy...
2995 */
2996
2997 if ((pol = cupsdAddPolicy(policy)) == NULL)
2998 return (0);
2999
3000 /*
3001 * Read from the file...
3002 */
3003
3004 op = NULL;
3005 num_ops = 0;
3006
3007 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3008 {
3009 /*
3010 * Decode the directive...
3011 */
3012
3013 if (!strcasecmp(line, "</Policy>"))
3014 {
3015 if (op)
3016 cupsdLogMessage(CUPSD_LOG_WARN,
3017 "Missing </Limit> before </Policy> on line %d!",
3018 linenum);
3019
3020 return (linenum);
3021 }
3022 else if (!strcasecmp(line, "<Limit") && !op)
3023 {
3024 if (!value)
3025 {
3026 cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
3027 return (0);
3028 }
3029
3030 /*
3031 * Scan for IPP operation names...
3032 */
3033
3034 num_ops = 0;
3035
3036 while (*value)
3037 {
3038 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3039
3040 if (*valptr)
3041 *valptr++ = '\0';
3042
3043 if (num_ops < (int)(sizeof(ops) / sizeof(ops[0])))
3044 {
3045 if (!strcasecmp(value, "All"))
3046 ops[num_ops] = IPP_ANY_OPERATION;
3047 else if ((ops[num_ops] = ippOpValue(value)) == IPP_BAD_OPERATION)
3048 cupsdLogMessage(CUPSD_LOG_ERROR,
3049 "Bad IPP operation name \"%s\" on line %d!",
3050 value, linenum);
3051 else
3052 num_ops ++;
3053 }
3054 else
3055 cupsdLogMessage(CUPSD_LOG_ERROR,
3056 "Too many operations listed on line %d!",
3057 linenum);
3058
3059 for (value = valptr; isspace(*value & 255); value ++);
3060 }
3061
3062 /*
3063 * If none are specified, apply the policy to all operations...
3064 */
3065
3066 if (num_ops == 0)
3067 {
3068 ops[0] = IPP_ANY_OPERATION;
3069 num_ops = 1;
3070 }
3071
3072 /*
3073 * Add a new policy for the first operation...
3074 */
3075
3076 op = cupsdAddPolicyOp(pol, NULL, ops[0]);
3077 }
3078 else if (!strcasecmp(line, "</Limit>") && op)
3079 {
3080 /*
3081 * Finish the current operation limit...
3082 */
3083
3084 if (num_ops > 1)
3085 {
3086 /*
3087 * Copy the policy to the other operations...
3088 */
3089
3090 for (i = 1; i < num_ops; i ++)
3091 cupsdAddPolicyOp(pol, op, ops[i]);
3092 }
3093
3094 op = NULL;
3095 }
3096 else if (!op)
3097 {
3098 cupsdLogMessage(CUPSD_LOG_ERROR,
3099 "Missing <Limit ops> directive before %s on line %d.",
3100 line, linenum);
3101 return (0);
3102 }
3103 else if (!parse_aaa(op, line, value, linenum))
3104 {
3105 if (op)
3106 cupsdLogMessage(CUPSD_LOG_ERROR,
3107 "Unknown Policy Limit directive %s on line %d.",
3108 line, linenum);
3109 else
3110 cupsdLogMessage(CUPSD_LOG_ERROR,
3111 "Unknown Policy directive %s on line %d.",
3112 line, linenum);
3113
3114 return (0);
3115 }
3116 }
3117
3118 cupsdLogMessage(CUPSD_LOG_ERROR,
3119 "Unexpected end-of-file at line %d while reading policy \"%s\"!",
3120 linenum, policy);
3121
3122 return (0);
3123 }
3124
3125
3126 /*
3127 * End of "$Id: conf.c 5028 2006-01-31 01:16:43Z mike $".
3128 */