]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/conf.c
The scheduler used a select() timeout of INT_MAX seconds when
[thirdparty/cups.git] / scheduler / conf.c
1 /*
2 * "$Id: conf.c,v 1.151 2004/08/23 18:00:59 mike Exp $"
3 *
4 * Configuration routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2004 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 * ReadConfiguration() - Read the cupsd.conf file.
27 * read_configuration() - Read a configuration file.
28 * read_location() - Read a <Location path> definition.
29 * get_address() - Get an address + port number from a line.
30 * CDSAGetServerCerts() - Convert a keychain name into the CFArrayRef
31 * required by SSLSetCertificate.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "cupsd.h"
39 #include <stdarg.h>
40 #include <pwd.h>
41 #include <grp.h>
42 #include <sys/utsname.h>
43
44 #ifdef HAVE_CDSASSL
45 # include <Security/SecureTransport.h>
46 # include <Security/SecIdentitySearch.h>
47 #endif /* HAVE_CDSASSL */
48
49 #ifdef HAVE_VSYSLOG
50 # include <syslog.h>
51 #endif /* HAVE_VSYSLOG */
52
53
54 /*
55 * Possibly missing network definitions...
56 */
57
58 #ifndef INADDR_NONE
59 # define INADDR_NONE 0xffffffff
60 #endif /* !INADDR_NONE */
61
62
63 /*
64 * Configuration variable structure...
65 */
66
67 typedef struct
68 {
69 char *name; /* Name of variable */
70 void *ptr; /* Pointer to variable */
71 int type; /* Type (int, string, address) */
72 } var_t;
73
74 #define VAR_INTEGER 0
75 #define VAR_STRING 1
76 #define VAR_BOOLEAN 2
77
78
79 /*
80 * Local globals...
81 */
82
83 static var_t variables[] =
84 {
85 { "AccessLog", &AccessLog, VAR_STRING },
86 { "AutoPurgeJobs", &JobAutoPurge, VAR_BOOLEAN },
87 { "BrowseInterval", &BrowseInterval, VAR_INTEGER },
88 { "BrowsePort", &BrowsePort, VAR_INTEGER },
89 { "BrowseShortNames", &BrowseShortNames, VAR_BOOLEAN },
90 { "BrowseTimeout", &BrowseTimeout, VAR_INTEGER },
91 { "Browsing", &Browsing, VAR_BOOLEAN },
92 { "Classification", &Classification, VAR_STRING },
93 { "ClassifyOverride", &ClassifyOverride, VAR_BOOLEAN },
94 { "ConfigFilePerm", &ConfigFilePerm, VAR_INTEGER },
95 { "DataDir", &DataDir, VAR_STRING },
96 { "DefaultCharset", &DefaultCharset, VAR_STRING },
97 { "DefaultLanguage", &DefaultLanguage, VAR_STRING },
98 { "DocumentRoot", &DocumentRoot, VAR_STRING },
99 { "ErrorLog", &ErrorLog, VAR_STRING },
100 { "FaxRetryLimit", &FaxRetryLimit, VAR_INTEGER },
101 { "FaxRetryInterval", &FaxRetryInterval, VAR_INTEGER },
102 { "FileDevice", &FileDevice, VAR_BOOLEAN },
103 { "FilterLimit", &FilterLimit, VAR_INTEGER },
104 { "FilterNice", &FilterNice, VAR_INTEGER },
105 { "FontPath", &FontPath, VAR_STRING },
106 { "HideImplicitMembers", &HideImplicitMembers, VAR_BOOLEAN },
107 { "ImplicitClasses", &ImplicitClasses, VAR_BOOLEAN },
108 { "ImplicitAnyClasses", &ImplicitAnyClasses, VAR_BOOLEAN },
109 { "KeepAliveTimeout", &KeepAliveTimeout, VAR_INTEGER },
110 { "KeepAlive", &KeepAlive, VAR_BOOLEAN },
111 { "LimitRequestBody", &MaxRequestSize, VAR_INTEGER },
112 { "ListenBackLog", &ListenBackLog, VAR_INTEGER },
113 { "LogFilePerm", &LogFilePerm, VAR_INTEGER },
114 { "MaxClients", &MaxClients, VAR_INTEGER },
115 { "MaxClientsPerHost", &MaxClientsPerHost, VAR_INTEGER },
116 { "MaxCopies", &MaxCopies, VAR_INTEGER },
117 { "MaxJobs", &MaxJobs, VAR_INTEGER },
118 { "MaxJobsPerPrinter", &MaxJobsPerPrinter, VAR_INTEGER },
119 { "MaxJobsPerUser", &MaxJobsPerUser, VAR_INTEGER },
120 { "MaxLogSize", &MaxLogSize, VAR_INTEGER },
121 { "MaxPrinterHistory", &MaxPrinterHistory, VAR_INTEGER },
122 { "MaxRequestSize", &MaxRequestSize, VAR_INTEGER },
123 { "PageLog", &PageLog, VAR_STRING },
124 { "PreserveJobFiles", &JobFiles, VAR_BOOLEAN },
125 { "PreserveJobHistory", &JobHistory, VAR_BOOLEAN },
126 { "Printcap", &Printcap, VAR_STRING },
127 { "PrintcapGUI", &PrintcapGUI, VAR_STRING },
128 { "ReloadTimeout", &ReloadTimeout, VAR_INTEGER },
129 { "RemoteRoot", &RemoteRoot, VAR_STRING },
130 { "RequestRoot", &RequestRoot, VAR_STRING },
131 { "RIPCache", &RIPCache, VAR_STRING },
132 { "RunAsUser", &RunAsUser, VAR_BOOLEAN },
133 { "RootCertDuration", &RootCertDuration, VAR_INTEGER },
134 { "ServerAdmin", &ServerAdmin, VAR_STRING },
135 { "ServerBin", &ServerBin, VAR_STRING },
136 #ifdef HAVE_SSL
137 { "ServerCertificate", &ServerCertificate, VAR_STRING },
138 # if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
139 { "ServerKey", &ServerKey, VAR_STRING },
140 # endif /* HAVE_LIBSSL || HAVE_GNUTLS */
141 #endif /* HAVE_SSL */
142 { "ServerName", &ServerName, VAR_STRING },
143 { "ServerRoot", &ServerRoot, VAR_STRING },
144 { "TempDir", &TempDir, VAR_STRING },
145 { "Timeout", &Timeout, VAR_INTEGER }
146 };
147 #define NUM_VARS (sizeof(variables) / sizeof(variables[0]))
148
149
150 /*
151 * Local functions...
152 */
153
154 static int read_configuration(cups_file_t *fp);
155 static int read_location(cups_file_t *fp, char *name, int linenum);
156 static int get_address(char *value, unsigned defaddress, int defport,
157 struct sockaddr_in *address);
158
159 #ifdef HAVE_CDSASSL
160 static CFArrayRef CDSAGetServerCerts();
161 #endif /* HAVE_CDSASSL */
162
163
164 /*
165 * 'ReadConfiguration()' - Read the cupsd.conf file.
166 */
167
168 int /* O - 1 on success, 0 otherwise */
169 ReadConfiguration(void)
170 {
171 int i; /* Looping var */
172 cups_file_t *fp; /* Configuration file */
173 int status; /* Return status */
174 char temp[1024], /* Temporary buffer */
175 *slash; /* Directory separator */
176 char type[MIME_MAX_SUPER + MIME_MAX_TYPE];
177 /* MIME type name */
178 char *language; /* Language string */
179 struct passwd *user; /* Default user */
180 struct group *group; /* Default group */
181 char *old_serverroot, /* Old ServerRoot */
182 *old_requestroot; /* Old RequestRoot */
183
184
185 /*
186 * Shutdown the server...
187 */
188
189 StopServer();
190
191 /*
192 * Save the old root paths...
193 */
194
195 old_serverroot = NULL;
196 SetString(&old_serverroot, ServerRoot);
197 old_requestroot = NULL;
198 SetString(&old_requestroot, RequestRoot);
199
200 /*
201 * Reset the server configuration data...
202 */
203
204 DeleteAllLocations();
205
206 if (NumBrowsers > 0)
207 {
208 free(Browsers);
209
210 NumBrowsers = 0;
211 }
212
213 if (NumPolled > 0)
214 {
215 free(Polled);
216
217 NumPolled = 0;
218 }
219
220 if (NumRelays > 0)
221 {
222 for (i = 0; i < NumRelays; i ++)
223 if (Relays[i].from.type == AUTH_NAME)
224 free(Relays[i].from.mask.name.name);
225
226 free(Relays);
227
228 NumRelays = 0;
229 }
230
231 if (NumListeners > 0)
232 {
233 free(Listeners);
234
235 NumListeners = 0;
236 }
237
238 /*
239 * String options...
240 */
241
242 gethostname(temp, sizeof(temp));
243 SetString(&ServerName, temp);
244 SetStringf(&ServerAdmin, "root@%s", temp);
245 SetString(&ServerBin, CUPS_SERVERBIN);
246 SetString(&RequestRoot, CUPS_REQUESTS);
247 SetString(&DocumentRoot, CUPS_DOCROOT);
248 SetString(&DataDir, CUPS_DATADIR);
249 SetString(&AccessLog, CUPS_LOGDIR "/access_log");
250 SetString(&ErrorLog, CUPS_LOGDIR "/error_log");
251 SetString(&PageLog, CUPS_LOGDIR "/page_log");
252 SetString(&Printcap, "/etc/printcap");
253 SetString(&PrintcapGUI, "/usr/bin/glpoptions");
254 SetString(&FontPath, CUPS_FONTPATH);
255 SetString(&RemoteRoot, "remroot");
256 SetString(&ServerHeader, "CUPS/1.1");
257
258 strlcpy(temp, ConfigurationFile, sizeof(temp));
259 if ((slash = strrchr(temp, '/')) != NULL)
260 *slash = '\0';
261
262 SetString(&ServerRoot, temp);
263
264 ClearString(&Classification);
265 ClassifyOverride = 0;
266
267 #ifdef HAVE_SSL
268 # ifdef HAVE_CDSASSL
269 SetString(&ServerCertificate, "/var/root/Library/Keychains/CUPS");
270 # else
271 SetString(&ServerCertificate, "ssl/server.crt");
272 SetString(&ServerKey, "ssl/server.key");
273 # endif /* HAVE_CDSASSL */
274 #endif /* HAVE_SSL */
275
276 if ((language = DEFAULT_LANGUAGE) == NULL)
277 language = "en";
278 else if (strcmp(language, "C") == 0 || strcmp(language, "POSIX") == 0)
279 language = "en";
280
281 SetString(&DefaultLanguage, language);
282 SetString(&DefaultCharset, DEFAULT_CHARSET);
283
284 SetString(&RIPCache, "8m");
285
286 if (getenv("TMPDIR") == NULL)
287 SetString(&TempDir, CUPS_REQUESTS "/tmp");
288 else
289 SetString(&TempDir, getenv("TMPDIR"));
290
291 /*
292 * Find the default system group: "sys", "system", or "root"...
293 */
294
295 group = getgrnam(CUPS_DEFAULT_GROUP);
296 endgrent();
297
298 NumSystemGroups = 0;
299
300 if (group != NULL)
301 {
302 SetString(&SystemGroups[0], CUPS_DEFAULT_GROUP);
303 Group = group->gr_gid;
304 }
305 else
306 {
307 group = getgrgid(0);
308 endgrent();
309
310 if (group != NULL)
311 {
312 SetString(&SystemGroups[0], group->gr_name);
313 Group = 0;
314 }
315 else
316 {
317 SetString(&SystemGroups[0], "unknown");
318 Group = 0;
319 }
320 }
321
322 /*
323 * Find the default user...
324 */
325
326 if ((user = getpwnam(CUPS_DEFAULT_USER)) == NULL)
327 User = 1; /* Force to a non-priviledged account */
328 else
329 User = user->pw_uid;
330
331 endpwent();
332
333 /*
334 * Numeric options...
335 */
336
337 ConfigFilePerm = 0640;
338 LogFilePerm = 0644;
339
340 FaxRetryLimit = 5;
341 FaxRetryInterval = 300;
342 FileDevice = FALSE;
343 FilterLevel = 0;
344 FilterLimit = 0;
345 FilterNice = 0;
346 HostNameLookups = FALSE;
347 ImplicitClasses = TRUE;
348 ImplicitAnyClasses = FALSE;
349 HideImplicitMembers = TRUE;
350 KeepAlive = TRUE;
351 KeepAliveTimeout = DEFAULT_KEEPALIVE;
352 ListenBackLog = SOMAXCONN;
353 LogLevel = L_ERROR;
354 MaxClients = 100;
355 MaxClientsPerHost = 0;
356 MaxLogSize = 1024 * 1024;
357 MaxPrinterHistory = 10;
358 MaxRequestSize = 0;
359 ReloadTimeout = 60;
360 RootCertDuration = 300;
361 RunAsUser = FALSE;
362 Timeout = DEFAULT_TIMEOUT;
363
364 BrowseInterval = DEFAULT_INTERVAL;
365 BrowsePort = ippPort();
366 BrowseProtocols = BROWSE_CUPS;
367 BrowseShortNames = TRUE;
368 BrowseTimeout = DEFAULT_TIMEOUT;
369 Browsing = TRUE;
370
371 JobHistory = DEFAULT_HISTORY;
372 JobFiles = DEFAULT_FILES;
373 JobAutoPurge = 0;
374 MaxJobs = 500;
375 MaxJobsPerUser = 0;
376 MaxJobsPerPrinter = 0;
377 MaxCopies = 100;
378
379 /*
380 * Read the configuration file...
381 */
382
383 if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
384 return (0);
385
386 status = read_configuration(fp);
387
388 cupsFileClose(fp);
389
390 if (!status)
391 return (0);
392
393 if (RunAsUser)
394 RunUser = User;
395 else
396 RunUser = getuid();
397
398 /*
399 * Use the default system group if none was supplied in cupsd.conf...
400 */
401
402 if (NumSystemGroups == 0)
403 NumSystemGroups ++;
404
405 /*
406 * Get the access control list for browsing...
407 */
408
409 BrowseACL = FindLocation("CUPS_INTERNAL_BROWSE_ACL");
410
411 /*
412 * Open the system log for cupsd if necessary...
413 */
414
415 #ifdef HAVE_VSYSLOG
416 if (strcmp(AccessLog, "syslog") == 0 ||
417 strcmp(ErrorLog, "syslog") == 0 ||
418 strcmp(PageLog, "syslog") == 0)
419 openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
420 #endif /* HAVE_VSYSLOG */
421
422 /*
423 * Log the configuration file that was used...
424 */
425
426 LogMessage(L_INFO, "Loaded configuration file \"%s\"", ConfigurationFile);
427
428 /*
429 * Check that we have at least one listen/port line; if not, report this
430 * as an error and exit!
431 */
432
433 if (NumListeners == 0)
434 {
435 /*
436 * No listeners!
437 */
438
439 LogMessage(L_EMERG, "No valid Listen or Port lines were found in the configuration file!");
440
441 /*
442 * Commit suicide...
443 */
444
445 kill(getpid(), SIGTERM);
446 }
447
448 /*
449 * Set the default locale using the language and charset...
450 */
451
452 SetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset);
453
454 /*
455 * Update all relative filenames to include the full path from ServerRoot...
456 */
457
458 if (DocumentRoot[0] != '/')
459 SetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
460
461 if (RequestRoot[0] != '/')
462 SetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
463
464 if (ServerBin[0] != '/')
465 SetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
466
467 #ifdef HAVE_SSL
468 if (ServerCertificate[0] != '/')
469 SetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
470
471 # if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
472 chown(ServerCertificate, RunUser, Group);
473 chmod(ServerCertificate, ConfigFilePerm);
474
475 if (ServerKey[0] != '/')
476 SetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
477
478 chown(ServerKey, RunUser, Group);
479 chmod(ServerKey, ConfigFilePerm);
480 # endif /* HAVE_LIBSSL || HAVE_GNUTLS */
481 #endif /* HAVE_SSL */
482
483 /*
484 * Make sure that ServerRoot and the config files are owned and
485 * writable by the user and group in the cupsd.conf file...
486 */
487
488 chown(ServerRoot, RunUser, Group);
489 chmod(ServerRoot, 0775);
490
491 snprintf(temp, sizeof(temp), "%s/certs", ServerRoot);
492 chown(temp, RunUser, Group);
493 chmod(temp, 0711);
494
495 snprintf(temp, sizeof(temp), "%s/ppd", ServerRoot);
496 chown(temp, RunUser, Group);
497 chmod(temp, 0755);
498
499 snprintf(temp, sizeof(temp), "%s/ssl", ServerRoot);
500 chown(temp, RunUser, Group);
501 chmod(temp, 0700);
502
503 snprintf(temp, sizeof(temp), "%s/cupsd.conf", ServerRoot);
504 chown(temp, RunUser, Group);
505 chmod(temp, ConfigFilePerm);
506
507 snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot);
508 chown(temp, RunUser, Group);
509 #ifdef __APPLE__
510 chmod(temp, 0600);
511 #else
512 chmod(temp, ConfigFilePerm);
513 #endif /* __APPLE__ */
514
515 snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
516 chown(temp, RunUser, Group);
517 #ifdef __APPLE__
518 chmod(temp, 0600);
519 #else
520 chmod(temp, ConfigFilePerm);
521 #endif /* __APPLE__ */
522
523 snprintf(temp, sizeof(temp), "%s/passwd.md5", ServerRoot);
524 chown(temp, User, Group);
525 chmod(temp, 0600);
526
527 /*
528 * Make sure the request and temporary directories have the right
529 * permissions...
530 */
531
532 chown(RequestRoot, RunUser, Group);
533 chmod(RequestRoot, 0710);
534
535 if (strncmp(TempDir, RequestRoot, strlen(RequestRoot)) == 0)
536 {
537 /*
538 * Only update ownership and permissions if the CUPS temp directory
539 * is under the spool directory...
540 */
541
542 chown(TempDir, RunUser, Group);
543 chmod(TempDir, 01770);
544 }
545
546 /*
547 * Check the MaxClients setting, and then allocate memory for it...
548 */
549
550 if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
551 {
552 if (MaxClients > 0)
553 LogMessage(L_INFO, "MaxClients limited to 1/3 of the file descriptor limit (%d)...",
554 MaxFDs);
555
556 MaxClients = MaxFDs / 3;
557 }
558
559 if ((Clients = calloc(sizeof(client_t), MaxClients)) == NULL)
560 {
561 LogMessage(L_ERROR, "ReadConfiguration: Unable to allocate memory for %d clients: %s",
562 MaxClients, strerror(errno));
563 exit(1);
564 }
565 else
566 LogMessage(L_INFO, "Configured for up to %d clients.", MaxClients);
567
568 if (Classification && strcasecmp(Classification, "none") == 0)
569 ClearString(&Classification);
570
571 if (Classification)
572 LogMessage(L_INFO, "Security set to \"%s\"", Classification);
573
574 /*
575 * Update the MaxClientsPerHost value, as needed...
576 */
577
578 if (MaxClientsPerHost <= 0)
579 MaxClientsPerHost = MaxClients;
580
581 if (MaxClientsPerHost > MaxClients)
582 MaxClientsPerHost = MaxClients;
583
584 LogMessage(L_INFO, "Allowing up to %d client connections per host.",
585 MaxClientsPerHost);
586
587 /*
588 * If we are doing a full reload or the server root has changed, flush
589 * the jobs, printers, etc. and start from scratch...
590 */
591
592 if (NeedReload == RELOAD_ALL ||
593 !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
594 !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
595 {
596 LogMessage(L_INFO, "Full reload is required.");
597
598 /*
599 * Free all memory...
600 */
601
602 FreeAllJobs();
603 DeleteAllClasses();
604 DeleteAllPrinters();
605
606 DefaultPrinter = NULL;
607
608 if (Devices)
609 {
610 ippDelete(Devices);
611 Devices = NULL;
612 }
613
614 if (PPDs)
615 {
616 ippDelete(PPDs);
617 PPDs = NULL;
618 }
619
620 if (MimeDatabase != NULL)
621 mimeDelete(MimeDatabase);
622
623 if (NumMimeTypes)
624 {
625 for (i = 0; i < NumMimeTypes; i ++)
626 free((void *)MimeTypes[i]);
627
628 free(MimeTypes);
629 }
630
631 /*
632 * Read the MIME type and conversion database...
633 */
634
635 snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
636
637 MimeDatabase = mimeNew();
638 mimeMerge(MimeDatabase, ServerRoot, temp);
639
640 /*
641 * Create a list of MIME types for the document-format-supported
642 * attribute...
643 */
644
645 NumMimeTypes = MimeDatabase->num_types;
646 if (!mimeType(MimeDatabase, "application", "octet-stream"))
647 NumMimeTypes ++;
648
649 MimeTypes = calloc(NumMimeTypes, sizeof(const char *));
650
651 for (i = 0; i < MimeDatabase->num_types; i ++)
652 {
653 snprintf(type, sizeof(type), "%s/%s", MimeDatabase->types[i]->super,
654 MimeDatabase->types[i]->type);
655
656 MimeTypes[i] = strdup(type);
657 }
658
659 if (i < NumMimeTypes)
660 MimeTypes[i] = strdup("application/octet-stream");
661
662 /*
663 * Load banners...
664 */
665
666 snprintf(temp, sizeof(temp), "%s/banners", DataDir);
667 LoadBanners(temp);
668
669 /*
670 * Load printers and classes...
671 */
672
673 LoadAllPrinters();
674 LoadAllClasses();
675
676 CreateCommonData();
677
678 /*
679 * Load devices and PPDs...
680 */
681
682 snprintf(temp, sizeof(temp), "%s/backend", ServerBin);
683 LoadDevices(temp);
684
685 snprintf(temp, sizeof(temp), "%s/model", DataDir);
686 LoadPPDs(temp);
687
688 /*
689 * Load queued jobs...
690 */
691
692 LoadAllJobs();
693
694 LogMessage(L_INFO, "Full reload complete.");
695 }
696 else
697 {
698 CreateCommonData();
699
700 LogMessage(L_INFO, "Partial reload complete.");
701 }
702
703 /*
704 * Reset the reload state...
705 */
706
707 NeedReload = RELOAD_NONE;
708
709 ClearString(&old_serverroot);
710 ClearString(&old_requestroot);
711
712 /*
713 * Startup the server and return...
714 */
715
716 StartServer();
717
718 return (1);
719 }
720
721
722 /*
723 * 'read_configuration()' - Read a configuration file.
724 */
725
726 static int /* O - 1 on success, 0 on failure */
727 read_configuration(cups_file_t *fp) /* I - File to read from */
728 {
729 int i; /* Looping var */
730 int linenum; /* Current line number */
731 int len; /* Length of line */
732 char line[HTTP_MAX_BUFFER], /* Line from file */
733 name[256], /* Parameter name */
734 *nameptr, /* Pointer into name */
735 *value; /* Pointer to value */
736 int valuelen; /* Length of value */
737 var_t *var; /* Current variable */
738 unsigned address, /* Address value */
739 netmask; /* Netmask value */
740 int ip[4], /* IP address components */
741 ipcount, /* Number of components provided */
742 mask[4]; /* IP netmask components */
743 dirsvc_relay_t *relay; /* Relay data */
744 dirsvc_poll_t *poll; /* Polling data */
745 struct sockaddr_in polladdr; /* Polling address */
746 location_t *location; /* Browse location */
747 cups_file_t *incfile; /* Include file */
748 char incname[1024]; /* Include filename */
749 static unsigned netmasks[4] = /* Standard netmasks... */
750 {
751 0xff000000,
752 0xffff0000,
753 0xffffff00,
754 0xffffffff
755 };
756
757
758 /*
759 * Loop through each line in the file...
760 */
761
762 linenum = 0;
763
764 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
765 {
766 linenum ++;
767
768 /*
769 * Skip comment lines...
770 */
771
772 if (line[0] == '#')
773 continue;
774
775 /*
776 * Strip trailing whitespace, if any...
777 */
778
779 len = strlen(line);
780
781 while (len > 0 && isspace(line[len - 1]))
782 {
783 len --;
784 line[len] = '\0';
785 }
786
787 /*
788 * Extract the name from the beginning of the line...
789 */
790
791 for (value = line; isspace(*value); value ++);
792
793 for (nameptr = name; *value != '\0' && !isspace(*value) &&
794 nameptr < (name + sizeof(name) - 1);)
795 *nameptr++ = *value++;
796 *nameptr = '\0';
797
798 while (isspace(*value))
799 value ++;
800
801 if (name[0] == '\0')
802 continue;
803
804 /*
805 * Decode the directive...
806 */
807
808 if (strcasecmp(name, "Include") == 0)
809 {
810 /*
811 * Include filename
812 */
813
814 if (value[0] == '/')
815 strlcpy(incname, value, sizeof(incname));
816 else
817 snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
818
819 if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
820 LogMessage(L_ERROR, "Unable to include config file \"%s\" - %s",
821 incname, strerror(errno));
822 else
823 {
824 read_configuration(incfile);
825 cupsFileClose(incfile);
826 }
827 }
828 else if (strcasecmp(name, "<Location") == 0)
829 {
830 /*
831 * <Location path>
832 */
833
834 if (line[len - 1] == '>')
835 {
836 line[len - 1] = '\0';
837
838 linenum = read_location(fp, value, linenum);
839 if (linenum == 0)
840 return (0);
841 }
842 else
843 {
844 LogMessage(L_ERROR, "Syntax error on line %d.",
845 linenum);
846 return (0);
847 }
848 }
849 else if (strcasecmp(name, "Port") == 0 ||
850 strcasecmp(name, "Listen") == 0)
851 {
852 /*
853 * Add a listening address to the list...
854 */
855
856 listener_t *temp; /* New listeners array */
857
858
859 if (NumListeners == 0)
860 temp = malloc(sizeof(listener_t));
861 else
862 temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t));
863
864 if (!temp)
865 {
866 LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.",
867 name, linenum, strerror(errno));
868 continue;
869 }
870
871 Listeners = temp;
872 temp += NumListeners;
873
874 memset(temp, 0, sizeof(listener_t));
875
876 if (get_address(value, INADDR_ANY, IPP_PORT, &(temp->address)))
877 {
878 LogMessage(L_INFO, "Listening to %x:%d",
879 (unsigned)ntohl(temp->address.sin_addr.s_addr),
880 ntohs(temp->address.sin_port));
881 NumListeners ++;
882 }
883 else
884 LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
885 value, linenum);
886 }
887 #ifdef HAVE_SSL
888 else if (strcasecmp(name, "SSLPort") == 0 ||
889 strcasecmp(name, "SSLListen") == 0)
890 {
891 /*
892 * Add a listening address to the list...
893 */
894
895 listener_t *temp; /* New listeners array */
896
897
898 if (NumListeners == 0)
899 temp = malloc(sizeof(listener_t));
900 else
901 temp = realloc(Listeners, (NumListeners + 1) * sizeof(listener_t));
902
903 if (!temp)
904 {
905 LogMessage(L_ERROR, "Unable to allocate %s at line %d - %s.",
906 name, linenum, strerror(errno));
907 continue;
908 }
909
910 Listeners = temp;
911 temp += NumListeners;
912
913 if (get_address(value, INADDR_ANY, IPP_PORT, &(temp->address)))
914 {
915 LogMessage(L_INFO, "Listening to %x:%d (SSL)",
916 (unsigned)ntohl(temp->address.sin_addr.s_addr),
917 ntohs(temp->address.sin_port));
918 temp->encryption = HTTP_ENCRYPT_ALWAYS;
919 NumListeners ++;
920 }
921 else
922 LogMessage(L_ERROR, "Bad %s address %s at line %d.", name,
923 value, linenum);
924 }
925 #endif /* HAVE_SSL */
926 else if (strcasecmp(name, "BrowseAddress") == 0)
927 {
928 /*
929 * Add a browse address to the list...
930 */
931
932 dirsvc_addr_t *temp; /* New browse address array */
933
934
935 if (NumBrowsers == 0)
936 temp = malloc(sizeof(dirsvc_addr_t));
937 else
938 temp = realloc(Browsers, (NumBrowsers + 1) * sizeof(dirsvc_addr_t));
939
940 if (!temp)
941 {
942 LogMessage(L_ERROR, "Unable to allocate BrowseAddress at line %d - %s.",
943 linenum, strerror(errno));
944 continue;
945 }
946
947 Browsers = temp;
948 temp += NumBrowsers;
949
950 memset(temp, 0, sizeof(dirsvc_addr_t));
951
952 if (strcasecmp(value, "@LOCAL") == 0)
953 {
954 /*
955 * Send browse data to all local interfaces...
956 */
957
958 strcpy(temp->iface, "*");
959 NumBrowsers ++;
960 }
961 else if (strncasecmp(value, "@IF(", 4) == 0)
962 {
963 /*
964 * Send browse data to the named interface...
965 */
966
967 strlcpy(temp->iface, value + 4, sizeof(Browsers[0].iface));
968
969 nameptr = temp->iface + strlen(temp->iface) - 1;
970 if (*nameptr == ')')
971 *nameptr = '\0';
972
973 NumBrowsers ++;
974 }
975 else if (get_address(value, INADDR_NONE, BrowsePort, &(temp->to)))
976 {
977 LogMessage(L_INFO, "Sending browsing info to %x:%d",
978 (unsigned)ntohl(temp->to.sin_addr.s_addr),
979 ntohs(temp->to.sin_port));
980
981 NumBrowsers ++;
982 }
983 else
984 LogMessage(L_ERROR, "Bad BrowseAddress %s at line %d.", value,
985 linenum);
986 }
987 else if (strcasecmp(name, "BrowseOrder") == 0)
988 {
989 /*
990 * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"...
991 */
992
993 if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
994 location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
995
996 if (location == NULL)
997 LogMessage(L_ERROR, "Unable to initialize browse access control list!");
998 else if (strncasecmp(value, "deny", 4) == 0)
999 location->order_type = AUTH_ALLOW;
1000 else if (strncasecmp(value, "allow", 5) == 0)
1001 location->order_type = AUTH_DENY;
1002 else
1003 LogMessage(L_ERROR, "Unknown BrowseOrder value %s on line %d.",
1004 value, linenum);
1005 }
1006 else if (strcasecmp(name, "BrowseProtocols") == 0)
1007 {
1008 /*
1009 * "BrowseProtocol name [... name]"
1010 */
1011
1012 BrowseProtocols = 0;
1013
1014 for (; *value;)
1015 {
1016 for (valuelen = 0; value[valuelen]; valuelen ++)
1017 if (isspace(value[valuelen]) || value[valuelen] == ',')
1018 break;
1019
1020 if (value[valuelen])
1021 {
1022 value[valuelen] = '\0';
1023 valuelen ++;
1024 }
1025
1026 if (strcasecmp(value, "cups") == 0)
1027 BrowseProtocols |= BROWSE_CUPS;
1028 else if (strcasecmp(value, "slp") == 0)
1029 BrowseProtocols |= BROWSE_SLP;
1030 else if (strcasecmp(value, "ldap") == 0)
1031 BrowseProtocols |= BROWSE_LDAP;
1032 else if (strcasecmp(value, "all") == 0)
1033 BrowseProtocols |= BROWSE_ALL;
1034 else
1035 {
1036 LogMessage(L_ERROR, "Unknown browse protocol \"%s\" on line %d.",
1037 value, linenum);
1038 break;
1039 }
1040
1041 for (value += valuelen; *value; value ++)
1042 if (!isspace(*value) || *value != ',')
1043 break;
1044 }
1045 }
1046 else if (strcasecmp(name, "BrowseAllow") == 0 ||
1047 strcasecmp(name, "BrowseDeny") == 0)
1048 {
1049 /*
1050 * BrowseAllow [From] host/ip...
1051 * BrowseDeny [From] host/ip...
1052 */
1053
1054 if ((location = FindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
1055 location = AddLocation("CUPS_INTERNAL_BROWSE_ACL");
1056
1057 if (location == NULL)
1058 LogMessage(L_ERROR, "Unable to initialize browse access control list!");
1059 else
1060 {
1061 if (strncasecmp(value, "from ", 5) == 0)
1062 {
1063 /*
1064 * Strip leading "from"...
1065 */
1066
1067 value += 5;
1068
1069 while (isspace(*value))
1070 value ++;
1071 }
1072
1073 /*
1074 * Figure out what form the allow/deny address takes:
1075 *
1076 * All
1077 * None
1078 * *.domain.com
1079 * .domain.com
1080 * host.domain.com
1081 * nnn.*
1082 * nnn.nnn.*
1083 * nnn.nnn.nnn.*
1084 * nnn.nnn.nnn.nnn
1085 * nnn.nnn.nnn.nnn/mm
1086 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
1087 */
1088
1089 if (strcasecmp(value, "all") == 0)
1090 {
1091 /*
1092 * All hosts...
1093 */
1094
1095 if (strcasecmp(name, "BrowseAllow") == 0)
1096 AllowIP(location, 0, 0);
1097 else
1098 DenyIP(location, 0, 0);
1099 }
1100 else if (strcasecmp(value, "none") == 0)
1101 {
1102 /*
1103 * No hosts...
1104 */
1105
1106 if (strcasecmp(name, "BrowseAllow") == 0)
1107 AllowIP(location, ~0, 0);
1108 else
1109 DenyIP(location, ~0, 0);
1110 }
1111 else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
1112 {
1113 /*
1114 * Host or domain name...
1115 */
1116
1117 if (value[0] == '*')
1118 value ++;
1119
1120 if (strcasecmp(name, "BrowseAllow") == 0)
1121 AllowHost(location, value);
1122 else
1123 DenyHost(location, value);
1124 }
1125 else
1126 {
1127 /*
1128 * One of many IP address forms...
1129 */
1130
1131 memset(ip, 0, sizeof(ip));
1132 ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
1133 address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
1134
1135 if ((value = strchr(value, '/')) != NULL)
1136 {
1137 value ++;
1138 memset(mask, 0, sizeof(mask));
1139 switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
1140 mask + 2, mask + 3))
1141 {
1142 case 1 :
1143 netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
1144 break;
1145 case 4 :
1146 netmask = (((((mask[0] << 8) | mask[1]) << 8) |
1147 mask[2]) << 8) | mask[3];
1148 break;
1149 default :
1150 LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
1151 value, linenum);
1152 netmask = 0xffffffff;
1153 break;
1154 }
1155 }
1156 else
1157 netmask = netmasks[ipcount - 1];
1158
1159 if ((address & ~netmask) != 0)
1160 {
1161 LogMessage(L_WARN, "Discarding extra bits in %s address %08x for netmask %08x...",
1162 name, address, netmask);
1163 address &= netmask;
1164 }
1165
1166 if (strcasecmp(name, "BrowseAllow") == 0)
1167 AllowIP(location, address, netmask);
1168 else
1169 DenyIP(location, address, netmask);
1170 }
1171 }
1172 }
1173 else if (strcasecmp(name, "BrowseRelay") == 0)
1174 {
1175 /*
1176 * BrowseRelay [from] source [to] destination
1177 */
1178
1179 if (NumRelays == 0)
1180 relay = malloc(sizeof(dirsvc_relay_t));
1181 else
1182 relay = realloc(Relays, (NumRelays + 1) * sizeof(dirsvc_relay_t));
1183
1184 if (!relay)
1185 {
1186 LogMessage(L_ERROR, "Unable to allocate BrowseRelay at line %d - %s.",
1187 linenum, strerror(errno));
1188 continue;
1189 }
1190
1191 Relays = relay;
1192 relay += NumRelays;
1193
1194 memset(relay, 0, sizeof(dirsvc_relay_t));
1195
1196 if (strncasecmp(value, "from ", 5) == 0)
1197 {
1198 /*
1199 * Strip leading "from"...
1200 */
1201
1202 value += 5;
1203
1204 while (isspace(*value))
1205 value ++;
1206 }
1207
1208 /*
1209 * Figure out what form the from address takes:
1210 *
1211 * *.domain.com
1212 * .domain.com
1213 * host.domain.com
1214 * nnn.*
1215 * nnn.nnn.*
1216 * nnn.nnn.nnn.*
1217 * nnn.nnn.nnn.nnn
1218 * nnn.nnn.nnn.nnn/mm
1219 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
1220 */
1221
1222 if (value[0] == '*' || value[0] == '.' || !isdigit(value[0]))
1223 {
1224 /*
1225 * Host or domain name...
1226 */
1227
1228 if (value[0] == '*')
1229 value ++;
1230
1231 strlcpy(name, value, sizeof(name));
1232 if ((nameptr = strchr(name, ' ')) != NULL)
1233 *nameptr = '\0';
1234
1235 relay->from.type = AUTH_NAME;
1236 relay->from.mask.name.name = strdup(name);
1237 relay->from.mask.name.length = strlen(name);
1238 }
1239 else
1240 {
1241 /*
1242 * One of many IP address forms...
1243 */
1244
1245 memset(ip, 0, sizeof(ip));
1246 ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
1247 address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
1248
1249 for (; *value; value ++)
1250 if (*value == '/' || isspace(*value))
1251 break;
1252
1253 if (*value == '/')
1254 {
1255 value ++;
1256 memset(mask, 0, sizeof(mask));
1257 switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
1258 mask + 2, mask + 3))
1259 {
1260 case 1 :
1261 netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
1262 break;
1263 case 4 :
1264 netmask = (((((mask[0] << 8) | mask[1]) << 8) |
1265 mask[2]) << 8) | mask[3];
1266 break;
1267 default :
1268 LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
1269 value, linenum);
1270 netmask = 0xffffffff;
1271 break;
1272 }
1273 }
1274 else
1275 netmask = netmasks[ipcount - 1];
1276
1277 relay->from.type = AUTH_IP;
1278 relay->from.mask.ip.address = address;
1279 relay->from.mask.ip.netmask = netmask;
1280 }
1281
1282 /*
1283 * Skip value and trailing whitespace...
1284 */
1285
1286 for (; *value; value ++)
1287 if (isspace(*value))
1288 break;
1289
1290 while (isspace(*value))
1291 value ++;
1292
1293 if (strncasecmp(value, "to ", 3) == 0)
1294 {
1295 /*
1296 * Strip leading "to"...
1297 */
1298
1299 value += 3;
1300
1301 while (isspace(*value))
1302 value ++;
1303 }
1304
1305 /*
1306 * Get "to" address and port...
1307 */
1308
1309 if (get_address(value, INADDR_BROADCAST, BrowsePort, &(relay->to)))
1310 {
1311 if (relay->from.type == AUTH_NAME)
1312 LogMessage(L_INFO, "Relaying from %s to %x:%d",
1313 relay->from.mask.name.name,
1314 (unsigned)ntohl(relay->to.sin_addr.s_addr),
1315 ntohs(relay->to.sin_port));
1316 else
1317 LogMessage(L_INFO, "Relaying from %x/%x to %x:%d",
1318 relay->from.mask.ip.address, relay->from.mask.ip.netmask,
1319 (unsigned)ntohl(relay->to.sin_addr.s_addr),
1320 ntohs(relay->to.sin_port));
1321
1322 NumRelays ++;
1323 }
1324 else
1325 {
1326 if (relay->from.type == AUTH_NAME)
1327 free(relay->from.mask.name.name);
1328
1329 LogMessage(L_ERROR, "Bad relay address %s at line %d.", value, linenum);
1330 }
1331 }
1332 else if (strcasecmp(name, "BrowsePoll") == 0)
1333 {
1334 /*
1335 * BrowsePoll address[:port]
1336 */
1337
1338 if (NumPolled == 0)
1339 poll = malloc(sizeof(dirsvc_poll_t));
1340 else
1341 poll = realloc(Polled, (NumPolled + 1) * sizeof(dirsvc_poll_t));
1342
1343 if (!poll)
1344 {
1345 LogMessage(L_ERROR, "Unable to allocate BrowsePoll at line %d - %s.",
1346 linenum, strerror(errno));
1347 continue;
1348 }
1349
1350 Polled = poll;
1351 poll += NumPolled;
1352
1353 /*
1354 * Get poll address and port...
1355 */
1356
1357 if (get_address(value, INADDR_NONE, ippPort(), &polladdr))
1358 {
1359 LogMessage(L_INFO, "Polling %x:%d",
1360 (unsigned)ntohl(polladdr.sin_addr.s_addr),
1361 ntohs(polladdr.sin_port));
1362
1363 NumPolled ++;
1364 memset(poll, 0, sizeof(dirsvc_poll_t));
1365
1366 address = ntohl(polladdr.sin_addr.s_addr);
1367
1368 sprintf(poll->hostname, "%d.%d.%d.%d", address >> 24,
1369 (address >> 16) & 255, (address >> 8) & 255, address & 255);
1370 poll->port = ntohs(polladdr.sin_port);
1371 }
1372 else
1373 LogMessage(L_ERROR, "Bad poll address %s at line %d.", value, linenum);
1374 }
1375 else if (strcasecmp(name, "User") == 0)
1376 {
1377 /*
1378 * User ID to run as...
1379 */
1380
1381 if (isdigit(value[0]))
1382 User = atoi(value);
1383 else
1384 {
1385 struct passwd *p; /* Password information */
1386
1387 endpwent();
1388 p = getpwnam(value);
1389
1390 if (p != NULL)
1391 User = p->pw_uid;
1392 else
1393 LogMessage(L_WARN, "Unknown username \"%s\"",
1394 value);
1395 }
1396 }
1397 else if (strcasecmp(name, "Group") == 0)
1398 {
1399 /*
1400 * Group ID to run as...
1401 */
1402
1403 if (isdigit(value[0]))
1404 Group = atoi(value);
1405 else
1406 {
1407 struct group *g; /* Group information */
1408
1409 endgrent();
1410 g = getgrnam(value);
1411
1412 if (g != NULL)
1413 Group = g->gr_gid;
1414 else
1415 LogMessage(L_WARN, "Unknown groupname \"%s\"",
1416 value);
1417 }
1418 }
1419 else if (strcasecmp(name, "SystemGroup") == 0)
1420 {
1421 /*
1422 * System (admin) group(s)...
1423 */
1424
1425 char *valueptr, /* Pointer into value */
1426 quote; /* Quote character */
1427
1428
1429 for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS; i ++)
1430 {
1431 if (*value == '\'' || *value == '\"')
1432 {
1433 /*
1434 * Scan quoted name...
1435 */
1436
1437 quote = *value++;
1438
1439 for (valueptr = value; *valueptr; valueptr ++)
1440 if (*valueptr == quote)
1441 break;
1442 }
1443 else
1444 {
1445 /*
1446 * Scan space or comma-delimited name...
1447 */
1448
1449 for (valueptr = value; *valueptr; valueptr ++)
1450 if (isspace(*valueptr) || *valueptr == ',')
1451 break;
1452 }
1453
1454 if (*valueptr)
1455 *valueptr++ = '\0';
1456
1457 SetString(SystemGroups + i, value);
1458
1459 value = valueptr;
1460
1461 while (*value == ',' || isspace(*value))
1462 value ++;
1463 }
1464
1465 if (i)
1466 NumSystemGroups = i;
1467 }
1468 else if (strcasecmp(name, "HostNameLookups") == 0)
1469 {
1470 /*
1471 * Do hostname lookups?
1472 */
1473
1474 if (strcasecmp(value, "off") == 0)
1475 HostNameLookups = 0;
1476 else if (strcasecmp(value, "on") == 0)
1477 HostNameLookups = 1;
1478 else if (strcasecmp(value, "double") == 0)
1479 HostNameLookups = 2;
1480 else
1481 LogMessage(L_WARN, "Unknown HostNameLookups %s on line %d.",
1482 value, linenum);
1483 }
1484 else if (strcasecmp(name, "LogLevel") == 0)
1485 {
1486 /*
1487 * Amount of logging to do...
1488 */
1489
1490 if (strcasecmp(value, "debug2") == 0)
1491 LogLevel = L_DEBUG2;
1492 else if (strcasecmp(value, "debug") == 0)
1493 LogLevel = L_DEBUG;
1494 else if (strcasecmp(value, "info") == 0)
1495 LogLevel = L_INFO;
1496 else if (strcasecmp(value, "notice") == 0)
1497 LogLevel = L_NOTICE;
1498 else if (strcasecmp(value, "warn") == 0)
1499 LogLevel = L_WARN;
1500 else if (strcasecmp(value, "error") == 0)
1501 LogLevel = L_ERROR;
1502 else if (strcasecmp(value, "crit") == 0)
1503 LogLevel = L_CRIT;
1504 else if (strcasecmp(value, "alert") == 0)
1505 LogLevel = L_ALERT;
1506 else if (strcasecmp(value, "emerg") == 0)
1507 LogLevel = L_EMERG;
1508 else if (strcasecmp(value, "none") == 0)
1509 LogLevel = L_NONE;
1510 else
1511 LogMessage(L_WARN, "Unknown LogLevel %s on line %d.", value, linenum);
1512 }
1513 else if (strcasecmp(name, "PrintcapFormat") == 0)
1514 {
1515 /*
1516 * Format of printcap file?
1517 */
1518
1519 if (strcasecmp(value, "bsd") == 0)
1520 PrintcapFormat = PRINTCAP_BSD;
1521 else if (strcasecmp(value, "solaris") == 0)
1522 PrintcapFormat = PRINTCAP_SOLARIS;
1523 else
1524 LogMessage(L_WARN, "Unknown PrintcapFormat %s on line %d.",
1525 value, linenum);
1526 }
1527 else if (!strcasecmp(name, "ServerTokens"))
1528 {
1529 /*
1530 * Set the string used for the Server header...
1531 */
1532
1533 struct utsname plat; /* Platform info */
1534
1535
1536 uname(&plat);
1537
1538 if (!strcasecmp(value, "ProductOnly"))
1539 SetString(&ServerHeader, "CUPS");
1540 else if (!strcasecmp(value, "Major"))
1541 SetString(&ServerHeader, "CUPS/1");
1542 else if (!strcasecmp(value, "Minor"))
1543 SetString(&ServerHeader, "CUPS/1.1");
1544 else if (!strcasecmp(value, "Minimal"))
1545 SetString(&ServerHeader, CUPS_MINIMAL);
1546 else if (!strcasecmp(value, "OS"))
1547 SetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname);
1548 else if (!strcasecmp(value, "Full"))
1549 SetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1", plat.sysname);
1550 else if (!strcasecmp(value, "None"))
1551 ClearString(&ServerHeader);
1552 else
1553 LogMessage(L_WARN, "Unknown ServerTokens %s on line %d.", value, linenum);
1554 }
1555 else
1556 {
1557 /*
1558 * Find a simple variable in the list...
1559 */
1560
1561 for (i = NUM_VARS, var = variables; i > 0; i --, var ++)
1562 if (strcasecmp(name, var->name) == 0)
1563 break;
1564
1565 if (i == 0)
1566 {
1567 /*
1568 * Unknown directive! Output an error message and continue...
1569 */
1570
1571 LogMessage(L_ERROR, "Unknown directive %s on line %d.", name,
1572 linenum);
1573 continue;
1574 }
1575
1576 switch (var->type)
1577 {
1578 case VAR_INTEGER :
1579 {
1580 int n; /* Number */
1581 char *units; /* Units */
1582
1583
1584 n = strtol(value, &units, 0);
1585
1586 if (units && *units)
1587 {
1588 if (tolower(units[0] & 255) == 'g')
1589 n *= 1024 * 1024 * 1024;
1590 else if (tolower(units[0] & 255) == 'm')
1591 n *= 1024 * 1024;
1592 else if (tolower(units[0] & 255) == 'k')
1593 n *= 1024;
1594 else if (tolower(units[0] & 255) == 't')
1595 n *= 262144;
1596 }
1597
1598 *((int *)var->ptr) = n;
1599 }
1600 break;
1601
1602 case VAR_BOOLEAN :
1603 if (strcasecmp(value, "true") == 0 ||
1604 strcasecmp(value, "on") == 0 ||
1605 strcasecmp(value, "enabled") == 0 ||
1606 strcasecmp(value, "yes") == 0 ||
1607 atoi(value) != 0)
1608 *((int *)var->ptr) = TRUE;
1609 else if (strcasecmp(value, "false") == 0 ||
1610 strcasecmp(value, "off") == 0 ||
1611 strcasecmp(value, "disabled") == 0 ||
1612 strcasecmp(value, "no") == 0 ||
1613 strcasecmp(value, "0") == 0)
1614 *((int *)var->ptr) = FALSE;
1615 else
1616 LogMessage(L_ERROR, "Unknown boolean value %s on line %d.",
1617 value, linenum);
1618 break;
1619
1620 case VAR_STRING :
1621 SetString((char **)var->ptr, value);
1622 break;
1623 }
1624 }
1625 }
1626
1627 return (1);
1628 }
1629
1630
1631 /*
1632 * 'read_location()' - Read a <Location path> definition.
1633 */
1634
1635 static int /* O - New line number or 0 on error */
1636 read_location(cups_file_t *fp, /* I - Configuration file */
1637 char *location, /* I - Location name/path */
1638 int linenum) /* I - Current line number */
1639 {
1640 int i; /* Looping var */
1641 location_t *loc, /* New location */
1642 *parent; /* Parent location */
1643 int len; /* Length of line */
1644 char line[HTTP_MAX_BUFFER], /* Line buffer */
1645 name[256], /* Configuration directive */
1646 *nameptr, /* Pointer into name */
1647 *value, /* Value for directive */
1648 *valptr; /* Pointer into value */
1649 unsigned address, /* Address value */
1650 netmask; /* Netmask value */
1651 int ip[4], /* IP address components */
1652 ipcount, /* Number of components provided */
1653 mask[4]; /* IP netmask components */
1654 static unsigned netmasks[4] = /* Standard netmasks... */
1655 {
1656 0xff000000,
1657 0xffff0000,
1658 0xffffff00,
1659 0xffffffff
1660 };
1661
1662
1663 if ((parent = AddLocation(location)) == NULL)
1664 return (0);
1665
1666 parent->limit = AUTH_LIMIT_ALL;
1667 loc = parent;
1668
1669 while (cupsFileGets(fp, line, sizeof(line)) != NULL)
1670 {
1671 linenum ++;
1672
1673 /*
1674 * Skip comment lines...
1675 */
1676
1677 if (line[0] == '#')
1678 continue;
1679
1680 /*
1681 * Strip trailing whitespace, if any...
1682 */
1683
1684 len = strlen(line);
1685
1686 while (len > 0 && isspace(line[len - 1] & 255))
1687 {
1688 len --;
1689 line[len] = '\0';
1690 }
1691
1692 /*
1693 * Extract the name from the beginning of the line...
1694 */
1695
1696 for (value = line; isspace(*value & 255); value ++);
1697
1698 for (nameptr = name; *value != '\0' && !isspace(*value & 255) &&
1699 nameptr < (name + sizeof(name) - 1);)
1700 *nameptr++ = *value++;
1701 *nameptr = '\0';
1702
1703 while (isspace(*value & 255))
1704 value ++;
1705
1706 if (name[0] == '\0')
1707 continue;
1708
1709 /*
1710 * Decode the directive...
1711 */
1712
1713 if (strcasecmp(name, "</Location>") == 0)
1714 return (linenum);
1715 else if (strcasecmp(name, "<Limit") == 0 ||
1716 strcasecmp(name, "<LimitExcept") == 0)
1717 {
1718 if ((loc = CopyLocation(&parent)) == NULL)
1719 return (0);
1720
1721 loc->limit = 0;
1722 while (*value)
1723 {
1724 for (valptr = value;
1725 !isspace(*valptr & 255) && *valptr != '>' && *valptr;
1726 valptr ++);
1727
1728 if (*valptr)
1729 *valptr++ = '\0';
1730
1731 if (strcmp(value, "ALL") == 0)
1732 loc->limit = AUTH_LIMIT_ALL;
1733 else if (strcmp(value, "GET") == 0)
1734 loc->limit |= AUTH_LIMIT_GET;
1735 else if (strcmp(value, "HEAD") == 0)
1736 loc->limit |= AUTH_LIMIT_HEAD;
1737 else if (strcmp(value, "OPTIONS") == 0)
1738 loc->limit |= AUTH_LIMIT_OPTIONS;
1739 else if (strcmp(value, "POST") == 0)
1740 loc->limit |= AUTH_LIMIT_POST;
1741 else if (strcmp(value, "PUT") == 0)
1742 loc->limit |= AUTH_LIMIT_PUT;
1743 else if (strcmp(value, "TRACE") == 0)
1744 loc->limit |= AUTH_LIMIT_TRACE;
1745 else
1746 LogMessage(L_WARN, "Unknown request type %s on line %d!", value,
1747 linenum);
1748
1749 for (value = valptr; isspace(*value & 255) || *value == '>'; value ++);
1750 }
1751
1752 if (strcasecmp(name, "<LimitExcept") == 0)
1753 loc->limit = AUTH_LIMIT_ALL ^ loc->limit;
1754
1755 parent->limit &= ~loc->limit;
1756 }
1757 else if (strcasecmp(name, "</Limit>") == 0)
1758 loc = parent;
1759 else if (strcasecmp(name, "Encryption") == 0)
1760 {
1761 /*
1762 * "Encryption xxx" - set required encryption level...
1763 */
1764
1765 if (strcasecmp(value, "never") == 0)
1766 loc->encryption = HTTP_ENCRYPT_NEVER;
1767 else if (strcasecmp(value, "always") == 0)
1768 {
1769 LogMessage(L_ERROR, "Encryption value \"%s\" on line %d is invalid in this context. "
1770 "Using \"required\" instead.", value, linenum);
1771
1772 loc->encryption = HTTP_ENCRYPT_REQUIRED;
1773 }
1774 else if (strcasecmp(value, "required") == 0)
1775 loc->encryption = HTTP_ENCRYPT_REQUIRED;
1776 else if (strcasecmp(value, "ifrequested") == 0)
1777 loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
1778 else
1779 LogMessage(L_ERROR, "Unknown Encryption value %s on line %d.",
1780 value, linenum);
1781 }
1782 else if (strcasecmp(name, "Order") == 0)
1783 {
1784 /*
1785 * "Order Deny,Allow" or "Order Allow,Deny"...
1786 */
1787
1788 if (strncasecmp(value, "deny", 4) == 0)
1789 loc->order_type = AUTH_ALLOW;
1790 else if (strncasecmp(value, "allow", 5) == 0)
1791 loc->order_type = AUTH_DENY;
1792 else
1793 LogMessage(L_ERROR, "Unknown Order value %s on line %d.",
1794 value, linenum);
1795 }
1796 else if (strcasecmp(name, "Allow") == 0 ||
1797 strcasecmp(name, "Deny") == 0)
1798 {
1799 /*
1800 * Allow [From] host/ip...
1801 * Deny [From] host/ip...
1802 */
1803
1804 if (strncasecmp(value, "from", 4) == 0)
1805 {
1806 /*
1807 * Strip leading "from"...
1808 */
1809
1810 value += 4;
1811
1812 while (isspace(*value & 255))
1813 value ++;
1814 }
1815
1816 /*
1817 * Figure out what form the allow/deny address takes:
1818 *
1819 * All
1820 * None
1821 * *.domain.com
1822 * .domain.com
1823 * host.domain.com
1824 * nnn.*
1825 * nnn.nnn.*
1826 * nnn.nnn.nnn.*
1827 * nnn.nnn.nnn.nnn
1828 * nnn.nnn.nnn.nnn/mm
1829 * nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
1830 */
1831
1832 if (strcasecmp(value, "all") == 0)
1833 {
1834 /*
1835 * All hosts...
1836 */
1837
1838 if (strcasecmp(name, "Allow") == 0)
1839 AllowIP(loc, 0, 0);
1840 else
1841 DenyIP(loc, 0, 0);
1842 }
1843 else if (strcasecmp(value, "none") == 0)
1844 {
1845 /*
1846 * No hosts...
1847 */
1848
1849 if (strcasecmp(name, "Allow") == 0)
1850 AllowIP(loc, ~0, 0);
1851 else
1852 DenyIP(loc, ~0, 0);
1853 }
1854 else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
1855 {
1856 /*
1857 * Host or domain name...
1858 */
1859
1860 if (value[0] == '*')
1861 value ++;
1862
1863 if (strcasecmp(name, "Allow") == 0)
1864 AllowHost(loc, value);
1865 else
1866 DenyHost(loc, value);
1867 }
1868 else
1869 {
1870 /*
1871 * One of many IP address forms...
1872 */
1873
1874 memset(ip, 0, sizeof(ip));
1875 ipcount = sscanf(value, "%d.%d.%d.%d", ip + 0, ip + 1, ip + 2, ip + 3);
1876 address = (((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3];
1877
1878 if ((value = strchr(value, '/')) != NULL)
1879 {
1880 value ++;
1881 memset(mask, 0, sizeof(mask));
1882 switch (sscanf(value, "%d.%d.%d.%d", mask + 0, mask + 1,
1883 mask + 2, mask + 3))
1884 {
1885 case 1 :
1886 netmask = (0xffffffff << (32 - mask[0])) & 0xffffffff;
1887 break;
1888 case 4 :
1889 netmask = (((((mask[0] << 8) | mask[1]) << 8) |
1890 mask[2]) << 8) | mask[3];
1891 break;
1892 default :
1893 LogMessage(L_ERROR, "Bad netmask value %s on line %d.",
1894 value, linenum);
1895 netmask = 0xffffffff;
1896 break;
1897 }
1898 }
1899 else
1900 netmask = netmasks[ipcount - 1];
1901
1902 if ((address & ~netmask) != 0)
1903 {
1904 LogMessage(L_WARN, "Discarding extra bits in %s address %08x for netmask %08x...",
1905 name, address, netmask);
1906 address &= netmask;
1907 }
1908
1909 if (strcasecmp(name, "Allow") == 0)
1910 AllowIP(loc, address, netmask);
1911 else
1912 DenyIP(loc, address, netmask);
1913 }
1914 }
1915 else if (strcasecmp(name, "AuthType") == 0)
1916 {
1917 /*
1918 * AuthType {none,basic,digest,basicdigest}
1919 */
1920
1921 if (strcasecmp(value, "none") == 0)
1922 {
1923 loc->type = AUTH_NONE;
1924 loc->level = AUTH_ANON;
1925 }
1926 else if (strcasecmp(value, "basic") == 0)
1927 {
1928 loc->type = AUTH_BASIC;
1929
1930 if (loc->level == AUTH_ANON)
1931 loc->level = AUTH_USER;
1932 }
1933 else if (strcasecmp(value, "digest") == 0)
1934 {
1935 loc->type = AUTH_DIGEST;
1936
1937 if (loc->level == AUTH_ANON)
1938 loc->level = AUTH_USER;
1939 }
1940 else if (strcasecmp(value, "basicdigest") == 0)
1941 {
1942 loc->type = AUTH_BASICDIGEST;
1943
1944 if (loc->level == AUTH_ANON)
1945 loc->level = AUTH_USER;
1946 }
1947 else
1948 LogMessage(L_WARN, "Unknown authorization type %s on line %d.",
1949 value, linenum);
1950 }
1951 else if (strcasecmp(name, "AuthClass") == 0)
1952 {
1953 /*
1954 * AuthClass anonymous, user, system, group
1955 */
1956
1957 if (strcasecmp(value, "anonymous") == 0)
1958 {
1959 loc->type = AUTH_NONE;
1960 loc->level = AUTH_ANON;
1961 }
1962 else if (strcasecmp(value, "user") == 0)
1963 loc->level = AUTH_USER;
1964 else if (strcasecmp(value, "group") == 0)
1965 loc->level = AUTH_GROUP;
1966 else if (strcasecmp(value, "system") == 0)
1967 {
1968 loc->level = AUTH_GROUP;
1969
1970 /*
1971 * Use the default system group if none is defined so far...
1972 */
1973
1974 if (NumSystemGroups == 0)
1975 NumSystemGroups = 1;
1976
1977 for (i = 0; i < NumSystemGroups; i ++)
1978 AddName(loc, SystemGroups[i]);
1979 }
1980 else
1981 LogMessage(L_WARN, "Unknown authorization class %s on line %d.",
1982 value, linenum);
1983 }
1984 else if (strcasecmp(name, "AuthGroupName") == 0)
1985 AddName(loc, value);
1986 else if (strcasecmp(name, "Require") == 0)
1987 {
1988 /*
1989 * Apache synonym for AuthClass and AuthGroupName...
1990 *
1991 * Get initial word:
1992 *
1993 * Require valid-user
1994 * Require group names
1995 * Require user names
1996 */
1997
1998 for (valptr = value;
1999 !isspace(*valptr & 255) && *valptr != '>' && *valptr;
2000 valptr ++);
2001
2002 if (*valptr)
2003 *valptr++ = '\0';
2004
2005 if (strcasecmp(value, "valid-user") == 0 ||
2006 strcasecmp(value, "user") == 0)
2007 loc->level = AUTH_USER;
2008 else if (strcasecmp(value, "group") == 0)
2009 loc->level = AUTH_GROUP;
2010 else
2011 {
2012 LogMessage(L_WARN, "Unknown Require type %s on line %d.",
2013 value, linenum);
2014 continue;
2015 }
2016
2017 /*
2018 * Get the list of names from the line...
2019 */
2020
2021 for (value = valptr; *value;)
2022 {
2023 for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
2024
2025 if (*valptr)
2026 *valptr++ = '\0';
2027
2028 AddName(loc, value);
2029
2030 for (value = valptr; isspace(*value & 255); value ++);
2031 }
2032 }
2033 else if (strcasecmp(name, "Satisfy") == 0)
2034 {
2035 if (strcasecmp(value, "all") == 0)
2036 loc->satisfy = AUTH_SATISFY_ALL;
2037 else if (strcasecmp(value, "any") == 0)
2038 loc->satisfy = AUTH_SATISFY_ANY;
2039 else
2040 LogMessage(L_WARN, "Unknown Satisfy value %s on line %d.", value,
2041 linenum);
2042 }
2043 else
2044 LogMessage(L_ERROR, "Unknown Location directive %s on line %d.",
2045 name, linenum);
2046 }
2047
2048 return (0);
2049 }
2050
2051
2052 /*
2053 * 'get_address()' - Get an address + port number from a line.
2054 */
2055
2056 static int /* O - 1 if address good, 0 if bad */
2057 get_address(char *value, /* I - Value string */
2058 unsigned defaddress, /* I - Default address */
2059 int defport, /* I - Default port */
2060 struct sockaddr_in *address) /* O - Socket address */
2061 {
2062 char hostname[256], /* Hostname or IP */
2063 portname[256]; /* Port number or name */
2064 struct hostent *host; /* Host address */
2065 struct servent *port; /* Port number */
2066
2067
2068 /*
2069 * Initialize the socket address to the defaults...
2070 */
2071
2072 memset(address, 0, sizeof(struct sockaddr_in));
2073 address->sin_family = AF_INET;
2074 address->sin_addr.s_addr = htonl(defaddress);
2075 address->sin_port = htons(defport);
2076
2077 /*
2078 * Try to grab a hostname and port number...
2079 */
2080
2081 switch (sscanf(value, "%255[^:]:%255s", hostname, portname))
2082 {
2083 case 1 :
2084 if (strchr(hostname, '.') == NULL && defaddress == INADDR_ANY)
2085 {
2086 /*
2087 * Hostname is a port number...
2088 */
2089
2090 strlcpy(portname, hostname, sizeof(portname));
2091 hostname[0] = '\0';
2092 }
2093 else
2094 portname[0] = '\0';
2095 break;
2096 case 2 :
2097 break;
2098 default :
2099 LogMessage(L_ERROR, "Unable to decode address \"%s\"!", value);
2100 return (0);
2101 }
2102
2103 /*
2104 * Decode the hostname and port number as needed...
2105 */
2106
2107 if (hostname[0] && strcmp(hostname, "*"))
2108 {
2109 if ((host = httpGetHostByName(hostname)) == NULL)
2110 {
2111 LogMessage(L_ERROR, "httpGetHostByName(\"%s\") failed - %s!", hostname,
2112 hstrerror(h_errno));
2113 return (0);
2114 }
2115
2116 memcpy(&(address->sin_addr), host->h_addr, host->h_length);
2117 address->sin_port = htons(defport);
2118 }
2119
2120 if (portname[0] != '\0')
2121 {
2122 if (isdigit(portname[0] & 255))
2123 address->sin_port = htons(atoi(portname));
2124 else
2125 {
2126 if ((port = getservbyname(portname, NULL)) == NULL)
2127 {
2128 LogMessage(L_ERROR, "getservbyname(\"%s\") failed - %s!", portname,
2129 strerror(errno));
2130 return (0);
2131 }
2132 else
2133 address->sin_port = htons(port->s_port);
2134 }
2135 }
2136
2137 return (1);
2138 }
2139
2140
2141 #ifdef HAVE_CDSASSL
2142 /*
2143 * 'CDSAGetServerCerts()' - Convert a keychain name into the CFArrayRef
2144 * required by SSLSetCertificate.
2145 *
2146 * For now we assumes that there is exactly one SecIdentity in the
2147 * keychain - i.e. there is exactly one matching cert/private key pair.
2148 * In the future we will search a keychain for a SecIdentity matching a
2149 * specific criteria. We also skip the operation of adding additional
2150 * non-signing certs from the keychain to the CFArrayRef.
2151 *
2152 * To create a self-signed certificate for testing use the certtool.
2153 * Executing the following as root will do it:
2154 *
2155 * certtool c c v k=CUPS
2156 */
2157
2158 static CFArrayRef
2159 CDSAGetServerCerts(void)
2160 {
2161 OSStatus err; /* Error info */
2162 SecKeychainRef kcRef; /* Keychain reference */
2163 SecIdentitySearchRef srchRef; /* Search reference */
2164 SecIdentityRef identity; /* Identity */
2165 CFArrayRef ca; /* Certificate array */
2166
2167
2168 kcRef = NULL;
2169 srchRef = NULL;
2170 identity = NULL;
2171 ca = NULL;
2172 err = SecKeychainOpen(ServerCertificate, &kcRef);
2173
2174 if (err)
2175 LogMessage(L_ERROR, "Cannot open keychain \"%s\", error %d.",
2176 ServerCertificate, err);
2177 else
2178 {
2179 /*
2180 * Search for "any" identity matching specified key use;
2181 * in this app, we expect there to be exactly one.
2182 */
2183
2184 err = SecIdentitySearchCreate(kcRef, CSSM_KEYUSE_SIGN, &srchRef);
2185
2186 if (err)
2187 LogMessage(L_ERROR,
2188 "Cannot find signing key in keychain \"%s\", error %d",
2189 ServerCertificate, err);
2190 else
2191 {
2192 err = SecIdentitySearchCopyNext(srchRef, &identity);
2193
2194 if (err)
2195 LogMessage(L_ERROR,
2196 "Cannot find signing key in keychain \"%s\", error %d",
2197 ServerCertificate, err);
2198 else
2199 {
2200 if (CFGetTypeID(identity) != SecIdentityGetTypeID())
2201 LogMessage(L_ERROR, "SecIdentitySearchCopyNext CFTypeID failure!");
2202 else
2203 {
2204 /*
2205 * Found one. Place it in a CFArray.
2206 * TBD: snag other (non-identity) certs from keychain and add them
2207 * to array as well.
2208 */
2209
2210 ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL);
2211
2212 if (ca == nil)
2213 LogMessage(L_ERROR, "CFArrayCreate error");
2214 }
2215
2216 /*CFRelease(identity);*/
2217 }
2218
2219 /*CFRelease(srchRef);*/
2220 }
2221
2222 /*CFRelease(kcRef);*/
2223 }
2224
2225 return ca;
2226 }
2227 #endif /* HAVE_CDSASSL */
2228
2229
2230 /*
2231 * End of "$Id: conf.c,v 1.151 2004/08/23 18:00:59 mike Exp $".
2232 */