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