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