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