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