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