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