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