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