2
* "$Id: conf.c 10824 2013-01-18 19:58:41Z mike $"
4
* Configuration routines for the CUPS scheduler.
6
* Copyright 2007-2012 by Apple Inc.
7
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
9
* These coded instructions, statements, and computer programs are the
10
* property of Apple Inc. and are protected by Federal copyright
11
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
12
* which should have been included with this file. If this file is
13
* file is missing or damaged, see the license at "http://www.cups.org/".
17
* cupsdAddAlias() - Add a host alias.
18
* cupsdCheckPermissions() - Fix the mode and ownership of a file or
20
* cupsdDefaultAuthType() - Get the default AuthType.
21
* cupsdFreeAliases() - Free all of the alias entries.
22
* cupsdReadConfiguration() - Read the cupsd.conf file.
23
* get_address() - Get an address + port number from a line.
24
* get_addr_and_mask() - Get an IP address and netmask.
25
* mime_error_cb() - Log a MIME error.
26
* parse_aaa() - Parse authentication, authorization, and access
28
* parse_fatal_errors() - Parse FatalErrors values in a string.
29
* parse_groups() - Parse system group names in a string.
30
* parse_protocols() - Parse browse protocols in a string.
31
* parse_variable() - Parse a variable line.
32
* read_cupsd_conf() - Read the cupsd.conf configuration file.
33
* read_cups_files_conf() - Read the cups-files.conf configuration file.
34
* read_location() - Read a <Location path> definition.
35
* read_policy() - Read a <Policy name> definition.
36
* set_policy_defaults() - Set default policy values as needed.
40
* Include necessary headers...
46
#include <sys/utsname.h>
51
#endif /* HAVE_LIBPAPER */
55
* Possibly missing network definitions...
59
# define INADDR_NONE 0xffffffff
60
#endif /* !INADDR_NONE */
64
* Configuration variable structure...
69
CUPSD_VARTYPE_INTEGER, /* Integer option */
70
CUPSD_VARTYPE_TIME, /* Time interval option */
71
CUPSD_VARTYPE_STRING, /* String option */
72
CUPSD_VARTYPE_BOOLEAN, /* Boolean option */
73
CUPSD_VARTYPE_PATHNAME /* File/directory name option */
78
const char *name; /* Name of variable */
79
void *ptr; /* Pointer to variable */
80
cupsd_vartype_t type; /* Type (int, string, address) */
88
static const cupsd_var_t cupsd_vars[] =
90
{ "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN },
91
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
92
{ "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_STRING },
93
#endif /* HAVE_DNSSD || HAVE_AVAHI */
94
{ "BrowseWebIF", &BrowseWebIF, CUPSD_VARTYPE_BOOLEAN },
95
{ "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN },
96
{ "Classification", &Classification, CUPSD_VARTYPE_STRING },
97
{ "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN },
98
{ "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING },
99
{ "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_TIME },
100
{ "DefaultPaperSize", &DefaultPaperSize, CUPSD_VARTYPE_STRING },
101
{ "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING },
102
{ "DefaultShared", &DefaultShared, CUPSD_VARTYPE_BOOLEAN },
103
{ "DirtyCleanInterval", &DirtyCleanInterval, CUPSD_VARTYPE_TIME },
104
{ "ErrorPolicy", &ErrorPolicy, CUPSD_VARTYPE_STRING },
105
{ "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER },
106
{ "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER },
108
{ "GSSServiceName", &GSSServiceName, CUPSD_VARTYPE_STRING },
109
#endif /* HAVE_GSSAPI */
110
{ "JobKillDelay", &JobKillDelay, CUPSD_VARTYPE_TIME },
111
{ "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER },
112
{ "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_TIME },
113
{ "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_TIME },
114
{ "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN },
116
{ "LaunchdTimeout", &LaunchdTimeout, CUPSD_VARTYPE_TIME },
117
#endif /* HAVE_LAUNCHD */
118
{ "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
119
{ "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER },
120
{ "LogDebugHistory", &LogDebugHistory, CUPSD_VARTYPE_INTEGER },
121
{ "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER },
122
{ "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER },
123
{ "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER },
124
{ "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER },
125
{ "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER },
126
{ "MaxHoldTime", &MaxHoldTime, CUPSD_VARTYPE_TIME },
127
{ "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER },
128
{ "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER },
129
{ "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER },
130
{ "MaxJobTime", &MaxJobTime, CUPSD_VARTYPE_INTEGER },
131
{ "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_TIME },
132
{ "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER },
133
{ "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER },
134
{ "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER },
135
{ "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER },
136
{ "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER },
137
{ "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER },
138
{ "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_TIME },
139
{ "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_STRING },
140
{ "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_TIME },
141
{ "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_TIME },
142
{ "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_TIME },
143
{ "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING },
144
{ "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_TIME },
145
{ "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING },
146
{ "ServerName", &ServerName, CUPSD_VARTYPE_STRING },
147
{ "StrictConformance", &StrictConformance, CUPSD_VARTYPE_BOOLEAN },
148
{ "Timeout", &Timeout, CUPSD_VARTYPE_TIME },
149
{ "WebInterface", &WebInterface, CUPSD_VARTYPE_BOOLEAN }
151
static const cupsd_var_t cupsfiles_vars[] =
153
{ "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING },
154
{ "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING },
155
{ "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER },
156
{ "DataDir", &DataDir, CUPSD_VARTYPE_STRING },
157
{ "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING },
158
{ "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING },
159
{ "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN },
160
{ "FontPath", &FontPath, CUPSD_VARTYPE_STRING },
161
{ "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER },
162
{ "LPDConfigFile", &LPDConfigFile, CUPSD_VARTYPE_STRING },
163
{ "PageLog", &PageLog, CUPSD_VARTYPE_STRING },
164
{ "Printcap", &Printcap, CUPSD_VARTYPE_STRING },
165
{ "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING },
166
{ "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING },
167
{ "ServerBin", &ServerBin, CUPSD_VARTYPE_PATHNAME },
169
{ "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_PATHNAME },
170
# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
171
{ "ServerKey", &ServerKey, CUPSD_VARTYPE_PATHNAME },
172
# endif /* HAVE_LIBSSL || HAVE_GNUTLS */
173
#endif /* HAVE_SSL */
174
{ "ServerRoot", &ServerRoot, CUPSD_VARTYPE_PATHNAME },
175
{ "SMBConfigFile", &SMBConfigFile, CUPSD_VARTYPE_STRING },
176
{ "StateDir", &StateDir, CUPSD_VARTYPE_STRING },
177
#ifdef HAVE_AUTHORIZATION_H
178
{ "SystemGroupAuthKey", &SystemGroupAuthKey, CUPSD_VARTYPE_STRING },
179
#endif /* HAVE_AUTHORIZATION_H */
180
{ "TempDir", &TempDir, CUPSD_VARTYPE_PATHNAME },
181
{ "PidFile", &PidFile, CUPSD_VARTYPE_STRING }
184
static int default_auth_type = CUPSD_AUTH_AUTO;
185
/* Default AuthType, if not specified */
187
static const unsigned ones[4] =
189
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
191
static const unsigned zeros[4] =
193
0x00000000, 0x00000000, 0x00000000, 0x00000000
201
static http_addrlist_t *get_address(const char *value, int defport);
202
static int get_addr_and_mask(const char *value, unsigned *ip,
204
static void mime_error_cb(void *ctx, const char *message);
205
static int parse_aaa(cupsd_location_t *loc, char *line,
206
char *value, int linenum);
207
static int parse_fatal_errors(const char *s);
208
static int parse_groups(const char *s);
209
static int parse_protocols(const char *s);
210
static int parse_variable(const char *filename, int linenum,
211
const char *line, const char *value,
213
const cupsd_var_t *vars);
214
static int read_cupsd_conf(cups_file_t *fp);
215
static int read_cups_files_conf(cups_file_t *fp);
216
static int read_location(cups_file_t *fp, char *name, int linenum);
217
static int read_policy(cups_file_t *fp, char *name, int linenum);
218
static void set_policy_defaults(cupsd_policy_t *pol);
222
* 'cupsdAddAlias()' - Add a host alias.
226
cupsdAddAlias(cups_array_t *aliases, /* I - Array of aliases */
227
const char *name) /* I - Name to add */
229
cupsd_alias_t *a; /* New alias */
230
size_t namelen; /* Length of name */
233
namelen = strlen(name);
235
if ((a = (cupsd_alias_t *)malloc(sizeof(cupsd_alias_t) + namelen)) == NULL)
238
a->namelen = namelen;
239
strcpy(a->name, name); /* OK since a->name is allocated */
241
cupsArrayAdd(aliases, a);
246
* 'cupsdCheckPermissions()' - Fix the mode and ownership of a file or directory.
249
int /* O - 0 on success, -1 on error, 1 on warning */
250
cupsdCheckPermissions(
251
const char *filename, /* I - File/directory name */
252
const char *suffix, /* I - Additional file/directory name */
253
int mode, /* I - Permissions */
254
int user, /* I - Owner */
255
int group, /* I - Group */
256
int is_dir, /* I - 1 = directory, 0 = file */
257
int create_dir) /* I - 1 = create directory, -1 = create w/o logging, 0 = not */
259
int dir_created = 0; /* Did we create a directory? */
260
char pathname[1024]; /* File name with prefix */
261
struct stat fileinfo; /* Stat buffer */
262
int is_symlink; /* Is "filename" a symlink? */
266
* Prepend the given root to the filename before testing it...
271
snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
276
* See if we can stat the file/directory...
279
if (lstat(filename, &fileinfo))
281
if (errno == ENOENT && create_dir)
284
cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating missing directory \"%s\"",
287
if (mkdir(filename, mode))
290
cupsdLogMessage(CUPSD_LOG_ERROR,
291
"Unable to create directory \"%s\" - %s", filename,
294
syslog(LOG_ERR, "Unable to create directory \"%s\" - %s", filename,
301
fileinfo.st_mode = mode | S_IFDIR;
304
return (create_dir ? -1 : 1);
307
if ((is_symlink = S_ISLNK(fileinfo.st_mode)) != 0)
309
if (stat(filename, &fileinfo))
311
cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is a bad symlink - %s",
312
filename, strerror(errno));
318
* Make sure it's a regular file or a directory as needed...
321
if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
323
cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file.", filename);
327
if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
330
cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory.", filename);
332
syslog(LOG_ERR, "\"%s\" is not a directory.", filename);
338
* If the filename is a symlink, do not change permissions (STR #2937)...
345
* Fix owner, group, and mode as needed...
348
if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
351
cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing ownership of \"%s\"",
354
if (chown(filename, user, group) && !getuid())
357
cupsdLogMessage(CUPSD_LOG_ERROR,
358
"Unable to change ownership of \"%s\" - %s", filename,
361
syslog(LOG_ERR, "Unable to change ownership of \"%s\" - %s", filename,
368
if (dir_created || (fileinfo.st_mode & 07777) != mode)
371
cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing access permissions of \"%s\"",
374
if (chmod(filename, mode))
377
cupsdLogMessage(CUPSD_LOG_ERROR,
378
"Unable to change permissions of \"%s\" - %s", filename,
381
syslog(LOG_ERR, "Unable to change permissions of \"%s\" - %s", filename,
389
* Everything is OK...
397
* 'cupsdDefaultAuthType()' - Get the default AuthType.
399
* When the default_auth_type is "auto", this function tries to get the GSS
400
* credentials for the server. If that succeeds we use Kerberos authentication,
401
* otherwise we do a fallback to Basic authentication against the local user
405
int /* O - Default AuthType value */
406
cupsdDefaultAuthType(void)
409
OM_uint32 major_status, /* Major status code */
410
minor_status; /* Minor status code */
411
gss_name_t server_name; /* Server name */
412
gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
413
/* Service name token */
414
char buf[1024]; /* Service name buffer */
415
#endif /* HAVE_GSSAPI */
419
* If we have already determined the correct default AuthType, use it...
422
if (default_auth_type != CUPSD_AUTH_AUTO)
423
return (default_auth_type);
428
* If the weak-linked GSSAPI/Kerberos library is not present, don't try
432
if (gss_init_sec_context == NULL)
433
return (default_auth_type = CUPSD_AUTH_BASIC);
434
# endif /* __APPLE__ */
437
* Try to obtain the server's GSS credentials (GSSServiceName@servername). If
438
* that fails we must use Basic...
441
snprintf(buf, sizeof(buf), "%s@%s", GSSServiceName, ServerName);
444
token.length = strlen(buf);
445
server_name = GSS_C_NO_NAME;
446
major_status = gss_import_name(&minor_status, &token,
447
GSS_C_NT_HOSTBASED_SERVICE,
450
memset(&token, 0, sizeof(token));
452
if (GSS_ERROR(major_status))
454
cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
455
"cupsdDefaultAuthType: gss_import_name(%s) failed", buf);
456
return (default_auth_type = CUPSD_AUTH_BASIC);
459
major_status = gss_display_name(&minor_status, server_name, &token, NULL);
461
if (GSS_ERROR(major_status))
463
cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
464
"cupsdDefaultAuthType: gss_display_name(%s) failed",
466
return (default_auth_type = CUPSD_AUTH_BASIC);
469
cupsdLogMessage(CUPSD_LOG_DEBUG,
470
"cupsdDefaultAuthType: Attempting to acquire Kerberos "
471
"credentials for %s...", (char *)token.value);
473
ServerCreds = GSS_C_NO_CREDENTIAL;
474
major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE,
475
GSS_C_NO_OID_SET, GSS_C_ACCEPT,
476
&ServerCreds, NULL, NULL);
477
if (GSS_ERROR(major_status))
479
cupsdLogGSSMessage(CUPSD_LOG_DEBUG, major_status, minor_status,
480
"cupsdDefaultAuthType: gss_acquire_cred(%s) failed",
481
(char *)token.value);
482
gss_release_name(&minor_status, &server_name);
483
gss_release_buffer(&minor_status, &token);
484
return (default_auth_type = CUPSD_AUTH_BASIC);
487
cupsdLogMessage(CUPSD_LOG_DEBUG,
488
"cupsdDefaultAuthType: Kerberos credentials acquired "
489
"successfully for %s.", (char *)token.value);
491
gss_release_name(&minor_status, &server_name);
492
gss_release_buffer(&minor_status, &token);
496
return (default_auth_type = CUPSD_AUTH_NEGOTIATE);
500
* No Kerberos support compiled in so just use Basic all the time...
503
return (default_auth_type = CUPSD_AUTH_BASIC);
504
#endif /* HAVE_GSSAPI */
509
* 'cupsdFreeAliases()' - Free all of the alias entries.
513
cupsdFreeAliases(cups_array_t *aliases) /* I - Array of aliases */
515
cupsd_alias_t *a; /* Current alias */
518
for (a = (cupsd_alias_t *)cupsArrayFirst(aliases);
520
a = (cupsd_alias_t *)cupsArrayNext(aliases))
523
cupsArrayDelete(aliases);
528
* 'cupsdReadConfiguration()' - Read the cupsd.conf file.
531
int /* O - 1 on success, 0 otherwise */
532
cupsdReadConfiguration(void)
534
int i; /* Looping var */
535
cups_file_t *fp; /* Configuration file */
536
int status; /* Return status */
537
char temp[1024], /* Temporary buffer */
538
mimedir[1024], /* MIME directory */
539
*slash; /* Directory separator */
540
cups_lang_t *language; /* Language */
541
struct passwd *user; /* Default user */
542
struct group *group; /* Default group */
543
char *old_serverroot, /* Old ServerRoot */
544
*old_requestroot; /* Old RequestRoot */
545
int old_remote_port; /* Old RemotePort */
546
const char *tmpdir; /* TMPDIR environment variable */
547
struct stat tmpinfo; /* Temporary directory info */
548
cupsd_policy_t *p; /* Policy */
552
* Save the old root paths...
555
old_serverroot = NULL;
556
cupsdSetString(&old_serverroot, ServerRoot);
557
old_requestroot = NULL;
558
cupsdSetString(&old_requestroot, RequestRoot);
561
* Reset the server configuration data...
564
cupsdDeleteAllLocations();
566
cupsdDeleteAllListeners();
568
old_remote_port = RemotePort;
575
cupsdFreeAliases(ServerAlias);
578
cupsdClearString(&ServerName);
579
cupsdClearString(&ServerAdmin);
580
cupsdSetString(&ServerBin, CUPS_SERVERBIN);
581
cupsdSetString(&RequestRoot, CUPS_REQUESTS);
582
cupsdSetString(&CacheDir, CUPS_CACHEDIR);
583
cupsdSetString(&DataDir, CUPS_DATADIR);
584
cupsdSetString(&DocumentRoot, CUPS_DOCROOT);
585
cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log");
586
cupsdClearString(&ErrorLog);
587
cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log");
588
cupsdSetString(&PageLogFormat,
589
"%p %u %j %T %P %C %{job-billing} "
590
"%{job-originating-host-name} %{job-name} %{media} %{sides}");
591
cupsdSetString(&Printcap, CUPS_DEFAULT_PRINTCAP);
592
cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions");
593
cupsdSetString(&FontPath, CUPS_FONTPATH);
594
cupsdSetString(&RemoteRoot, "remroot");
595
cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR,
597
cupsdSetString(&StateDir, CUPS_STATEDIR);
598
cupsdSetString(&PidFile, "/var/run/cups/cupsd.pid");
600
if (!strcmp(CUPS_DEFAULT_PRINTCAP, "/etc/printers.conf"))
601
PrintcapFormat = PRINTCAP_SOLARIS;
602
else if (!strcmp(CUPS_DEFAULT_PRINTCAP,
603
"/Library/Preferences/org.cups.printers.plist"))
604
PrintcapFormat = PRINTCAP_PLIST;
606
PrintcapFormat = PRINTCAP_BSD;
608
strlcpy(temp, ConfigurationFile, sizeof(temp));
609
if ((slash = strrchr(temp, '/')) != NULL)
612
cupsdSetString(&ServerRoot, temp);
614
cupsdClearString(&Classification);
615
ClassifyOverride = 0;
619
cupsdSetString(&ServerCertificate, "/Library/Keychains/System.keychain");
621
cupsdSetString(&ServerCertificate, "ssl/server.crt");
622
cupsdSetString(&ServerKey, "ssl/server.key");
623
# endif /* HAVE_CDSASSL */
624
#endif /* HAVE_SSL */
626
language = cupsLangDefault();
628
if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX"))
629
cupsdSetString(&DefaultLanguage, "en");
631
cupsdSetString(&DefaultLanguage, language->language);
633
cupsdClearString(&DefaultPaperSize);
635
cupsdSetString(&RIPCache, "128m");
637
cupsdSetString(&TempDir, NULL);
640
cupsdSetString(&GSSServiceName, CUPS_DEFAULT_GSSSERVICENAME);
644
OM_uint32 minor_status; /* Minor status code */
646
gss_release_cred(&minor_status, &ServerCreds);
651
ServerCreds = GSS_C_NO_CREDENTIAL;
652
#endif /* HAVE_GSSAPI */
655
* Find the default user...
658
if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL)
663
* Use the (historical) NFS nobody user ID (-2 as a 16-bit twos-
664
* complement number...)
673
* Find the default group...
676
group = getgrnam(CUPS_DEFAULT_GROUP);
680
Group = group->gr_gid;
684
* Fallback to group "nobody"...
687
group = getgrnam("nobody");
691
Group = group->gr_gid;
695
* Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
696
* complement number...)
707
AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS;
708
ConfigFilePerm = CUPS_DEFAULT_CONFIG_FILE_PERM;
709
FatalErrors = parse_fatal_errors(CUPS_DEFAULT_FATAL_ERRORS);
710
default_auth_type = CUPSD_AUTH_BASIC;
712
DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
713
SSLOptions = CUPSD_SSL_NONE;
714
#endif /* HAVE_SSL */
715
DirtyCleanInterval = DEFAULT_KEEPALIVE;
716
JobKillDelay = DEFAULT_TIMEOUT;
718
JobRetryInterval = 300;
723
HostNameLookups = FALSE;
725
KeepAliveTimeout = DEFAULT_KEEPALIVE;
726
ListenBackLog = SOMAXCONN;
727
LogDebugHistory = 200;
728
LogFilePerm = CUPS_DEFAULT_LOG_FILE_PERM;
729
LogLevel = CUPSD_LOG_WARN;
730
LogTimeFormat = CUPSD_TIME_STANDARD;
732
MaxClientsPerHost = 0;
733
MaxLogSize = 1024 * 1024;
735
MultipleOperationTimeout = DEFAULT_TIMEOUT;
737
ReloadTimeout = DEFAULT_KEEPALIVE;
738
RootCertDuration = 300;
739
StrictConformance = FALSE;
740
Timeout = DEFAULT_TIMEOUT;
741
WebInterface = CUPS_DEFAULT_WEBIF;
743
BrowseLocalProtocols = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS);
745
Browsing = CUPS_DEFAULT_BROWSING;
746
DefaultShared = CUPS_DEFAULT_DEFAULT_SHARED;
748
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
749
cupsdSetString(&DNSSDSubTypes, "_cups,_print");
750
#endif /* HAVE_DNSSD || HAVE_AVAHI */
752
cupsdSetString(&LPDConfigFile, CUPS_DEFAULT_LPD_CONFIG_FILE);
753
cupsdSetString(&SMBConfigFile, CUPS_DEFAULT_SMB_CONFIG_FILE);
755
cupsdSetString(&ErrorPolicy, "stop-printer");
757
JobHistory = DEFAULT_HISTORY;
758
JobFiles = DEFAULT_FILES;
764
MaxJobsPerPrinter = 0;
765
MaxJobTime = 3 * 60 * 60; /* 3 hours */
766
MaxCopies = CUPS_DEFAULT_MAX_COPIES;
768
cupsdDeleteAllPolicies();
769
cupsdClearString(&DefaultPolicy);
771
#ifdef HAVE_AUTHORIZATION_H
772
cupsdClearString(&SystemGroupAuthKey);
773
#endif /* HAVE_AUTHORIZATION_H */
775
MaxSubscriptions = 100;
776
MaxSubscriptionsPerJob = 0;
777
MaxSubscriptionsPerPrinter = 0;
778
MaxSubscriptionsPerUser = 0;
779
DefaultLeaseDuration = 86400;
780
MaxLeaseDuration = 0;
784
#endif /* HAVE_LAUNCHD */
787
* Setup environment variables...
793
* Read the cups-files.conf file...
796
if ((fp = cupsFileOpen(CupsFilesFile, "r")) != NULL)
798
status = read_cups_files_conf(fp);
805
printf("\"%s\" contains errors.\n", CupsFilesFile);
807
syslog(LOG_LPR, "Unable to read \"%s\" due to errors.",
813
else if (errno == ENOENT)
814
cupsdLogMessage(CUPSD_LOG_INFO, "No %s, using defaults.", CupsFilesFile);
817
syslog(LOG_LPR, "Unable to open \"%s\": %s", CupsFilesFile,
823
cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log");
826
* Read the cupsd.conf file...
829
if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL)
831
syslog(LOG_LPR, "Unable to open \"%s\": %s", ConfigurationFile,
836
status = read_cupsd_conf(fp);
843
printf("\"%s\" contains errors.\n", ConfigurationFile);
845
syslog(LOG_LPR, "Unable to read \"%s\" due to errors.",
853
cupsdLogMessage(CUPSD_LOG_INFO, "Remote access is %s.",
854
RemotePort ? "enabled" : "disabled");
857
BrowseLocalProtocols = 0; /* Disable sharing - no remote access */
860
* See if the ServerName is an IP address...
866
ServerAlias = cupsArrayNew(NULL, NULL);
868
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", ServerName);
872
if (gethostname(temp, sizeof(temp)))
874
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get hostname: %s",
876
strlcpy(temp, "localhost", sizeof(temp));
879
cupsdSetString(&ServerName, temp);
882
ServerAlias = cupsArrayNew(NULL, NULL);
884
cupsdAddAlias(ServerAlias, temp);
885
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
887
if (HostNameLookups || RemotePort)
889
struct hostent *host; /* Host entry to get FQDN */
891
if ((host = gethostbyname(temp)) != NULL)
893
if (_cups_strcasecmp(temp, host->h_name))
895
cupsdSetString(&ServerName, host->h_name);
896
cupsdAddAlias(ServerAlias, host->h_name);
897
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
903
for (i = 0; host->h_aliases[i]; i ++)
904
if (_cups_strcasecmp(temp, host->h_aliases[i]))
906
cupsdAddAlias(ServerAlias, host->h_aliases[i]);
907
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s",
915
* Make sure we have the base hostname added as an alias, too!
918
if ((slash = strchr(temp, '.')) != NULL)
921
cupsdAddAlias(ServerAlias, temp);
922
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added auto ServerAlias %s", temp);
926
for (slash = ServerName; isdigit(*slash & 255) || *slash == '.'; slash ++);
928
ServerNameIsIP = !*slash;
931
* Make sure ServerAdmin is initialized...
935
cupsdSetStringf(&ServerAdmin, "root@%s", ServerName);
938
* Use the default system group if none was supplied in cupsd.conf...
941
if (NumSystemGroups == 0)
943
if (!parse_groups(CUPS_DEFAULT_SYSTEM_GROUPS))
946
* Find the group associated with GID 0...
953
cupsdSetString(&SystemGroups[0], group->gr_name);
955
cupsdSetString(&SystemGroups[0], "unknown");
957
SystemGroupIDs[0] = 0;
963
* Make sure ConfigFilePerm and LogFilePerm have sane values...
966
ConfigFilePerm &= 0664;
970
* Open the system log for cupsd if necessary...
974
if (!strcmp(AccessLog, "syslog") ||
975
!strcmp(ErrorLog, "syslog") ||
976
!strcmp(PageLog, "syslog"))
977
openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR);
978
#endif /* HAVE_VSYSLOG */
981
* Make sure each of the log files exists and gets rotated as necessary...
984
if (strcmp(AccessLog, "syslog"))
985
cupsdCheckLogFile(&AccessFile, AccessLog);
987
if (strcmp(ErrorLog, "syslog"))
988
cupsdCheckLogFile(&ErrorFile, ErrorLog);
990
if (strcmp(PageLog, "syslog"))
991
cupsdCheckLogFile(&PageFile, PageLog);
994
* Log the configuration file that was used...
997
cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"",
1001
* Validate the Group and SystemGroup settings - they cannot be the same,
1002
* otherwise the CGI programs will be able to authenticate as root without
1008
for (i = 0; i < NumSystemGroups; i ++)
1009
if (Group == SystemGroupIDs[i])
1012
if (i < NumSystemGroups)
1015
* Log the error and reset the group to a safe value...
1018
cupsdLogMessage(CUPSD_LOG_NOTICE,
1019
"Group and SystemGroup cannot use the same groups.");
1020
cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"...");
1022
group = getgrnam("nobody");
1026
Group = group->gr_gid;
1030
* Use the (historical) NFS nobody group ID (-2 as a 16-bit twos-
1031
* complement number...)
1040
* Check that we have at least one listen/port line; if not, report this
1041
* as an error and exit!
1044
if (cupsArrayCount(Listeners) == 0)
1050
cupsdLogMessage(CUPSD_LOG_EMERG,
1051
"No valid Listen or Port lines were found in the "
1052
"configuration file.");
1058
cupsdEndProcess(getpid(), 0);
1062
* Set the default locale using the language and charset...
1065
cupsdSetStringf(&DefaultLocale, "%s.UTF-8", DefaultLanguage);
1068
* Update all relative filenames to include the full path from ServerRoot...
1071
if (DocumentRoot[0] != '/')
1072
cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot);
1074
if (RequestRoot[0] != '/')
1075
cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot);
1077
if (ServerBin[0] != '/')
1078
cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin);
1080
if (StateDir[0] != '/')
1081
cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir);
1083
if (CacheDir[0] != '/')
1084
cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir);
1087
if (ServerCertificate[0] != '/')
1088
cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate);
1090
if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot)) &&
1091
cupsdCheckPermissions(ServerCertificate, NULL, 0600, RunUser, Group,
1093
(FatalErrors & CUPSD_FATAL_PERMISSIONS))
1096
# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS)
1097
if (ServerKey[0] != '/')
1098
cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey);
1100
if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot)) &&
1101
cupsdCheckPermissions(ServerKey, NULL, 0600, RunUser, Group, 0, 0) < 0 &&
1102
(FatalErrors & CUPSD_FATAL_PERMISSIONS))
1104
# endif /* HAVE_LIBSSL || HAVE_GNUTLS */
1105
#endif /* HAVE_SSL */
1108
* Make sure that directories and config files are owned and
1109
* writable by the user and group in the cupsd.conf file...
1112
snprintf(temp, sizeof(temp), "%s/rss", CacheDir);
1114
if ((cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
1116
cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
1118
cupsdCheckPermissions(temp, NULL, 0775, RunUser,
1120
cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
1122
cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
1123
SystemGroupIDs[0], 1, 1) < 0 ||
1124
cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser,
1126
cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser,
1128
cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser,
1130
cupsdCheckPermissions(ConfigurationFile, NULL, ConfigFilePerm, RunUser,
1132
cupsdCheckPermissions(CupsFilesFile, NULL, ConfigFilePerm, RunUser,
1134
cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser,
1136
cupsdCheckPermissions(ServerRoot, "printers.conf", 0600, RunUser,
1138
cupsdCheckPermissions(ServerRoot, "passwd.md5", 0600, User,
1139
Group, 0, 0) < 0) &&
1140
(FatalErrors & CUPSD_FATAL_PERMISSIONS))
1144
* Update TempDir to the default if it hasn't been set already...
1148
if (TempDir && !RunUser &&
1149
(!strncmp(TempDir, "/private/tmp", 12) || !strncmp(TempDir, "/tmp", 4)))
1151
cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot use %s for TempDir.", TempDir);
1152
cupsdClearString(&TempDir);
1154
#endif /* __APPLE__ */
1159
if ((tmpdir = getenv("TMPDIR")) != NULL &&
1160
strncmp(tmpdir, "/private/tmp", 12) && strncmp(tmpdir, "/tmp", 4))
1162
if ((tmpdir = getenv("TMPDIR")) != NULL)
1163
#endif /* __APPLE__ */
1166
* TMPDIR is defined, see if it is OK for us to use...
1169
if (stat(tmpdir, &tmpinfo))
1170
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to access TMPDIR (%s): %s",
1171
tmpdir, strerror(errno));
1172
else if (!S_ISDIR(tmpinfo.st_mode))
1173
cupsdLogMessage(CUPSD_LOG_ERROR, "TMPDIR (%s) is not a directory.",
1175
else if ((tmpinfo.st_uid != User || !(tmpinfo.st_mode & S_IWUSR)) &&
1176
(tmpinfo.st_gid != Group || !(tmpinfo.st_mode & S_IWGRP)) &&
1177
!(tmpinfo.st_mode & S_IWOTH))
1178
cupsdLogMessage(CUPSD_LOG_ERROR,
1179
"TMPDIR (%s) has the wrong permissions.", tmpdir);
1181
cupsdSetString(&TempDir, tmpdir);
1187
cupsdLogMessage(CUPSD_LOG_INFO, "Using default TempDir of %s/tmp...",
1189
cupsdSetStringf(&TempDir, "%s/tmp", RequestRoot);
1193
* Make sure the temporary directory has the right permissions...
1196
if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) ||
1200
* Update ownership and permissions if the CUPS temp directory
1201
* is under the spool directory or does not exist...
1204
if (cupsdCheckPermissions(TempDir, NULL, 01770, RunUser, Group, 1, 1) < 0 &&
1205
(FatalErrors & CUPSD_FATAL_PERMISSIONS))
1210
* Update environment variables...
1216
* Update default paper size setting as needed...
1219
if (!DefaultPaperSize)
1221
#ifdef HAVE_LIBPAPER
1222
char *paper_result; /* Paper size name from libpaper */
1224
if ((paper_result = systempapername()) != NULL)
1225
cupsdSetString(&DefaultPaperSize, paper_result);
1227
#endif /* HAVE_LIBPAPER */
1228
if (!DefaultLanguage ||
1229
!_cups_strcasecmp(DefaultLanguage, "C") ||
1230
!_cups_strcasecmp(DefaultLanguage, "POSIX") ||
1231
!_cups_strcasecmp(DefaultLanguage, "en") ||
1232
!_cups_strncasecmp(DefaultLanguage, "en.", 3) ||
1233
!_cups_strncasecmp(DefaultLanguage, "en_US", 5) ||
1234
!_cups_strncasecmp(DefaultLanguage, "en_CA", 5) ||
1235
!_cups_strncasecmp(DefaultLanguage, "fr_CA", 5))
1238
* These are the only locales that will default to "letter" size...
1241
cupsdSetString(&DefaultPaperSize, "Letter");
1244
cupsdSetString(&DefaultPaperSize, "A4");
1248
* Update classification setting as needed...
1251
if (Classification && !_cups_strcasecmp(Classification, "none"))
1252
cupsdClearString(&Classification);
1255
cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification);
1258
* Check the MaxClients setting, and then allocate memory for it...
1261
if (MaxClients > (MaxFDs / 3) || MaxClients <= 0)
1264
cupsdLogMessage(CUPSD_LOG_INFO,
1265
"MaxClients limited to 1/3 (%d) of the file descriptor "
1267
MaxFDs / 3, MaxFDs);
1269
MaxClients = MaxFDs / 3;
1272
cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.",
1276
* Check the MaxActiveJobs setting; limit to 1/3 the available
1277
* file descriptors, since we need a pipe for each job...
1280
if (MaxActiveJobs > (MaxFDs / 3))
1281
MaxActiveJobs = MaxFDs / 3;
1284
* Update the MaxClientsPerHost value, as needed...
1287
if (MaxClientsPerHost <= 0)
1288
MaxClientsPerHost = MaxClients;
1290
if (MaxClientsPerHost > MaxClients)
1291
MaxClientsPerHost = MaxClients;
1293
cupsdLogMessage(CUPSD_LOG_INFO,
1294
"Allowing up to %d client connections per host.",
1298
* Update the default policy, as needed...
1302
DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy);
1304
DefaultPolicyPtr = NULL;
1306
if (!DefaultPolicyPtr)
1308
cupsd_location_t *po; /* New policy operation */
1312
cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found.",
1315
cupsdSetString(&DefaultPolicy, "default");
1317
if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL)
1318
cupsdLogMessage(CUPSD_LOG_INFO,
1319
"Using policy \"default\" as the default.");
1322
cupsdLogMessage(CUPSD_LOG_INFO,
1323
"Creating CUPS default administrative policy:");
1325
DefaultPolicyPtr = p = cupsdAddPolicy("default");
1327
cupsdLogMessage(CUPSD_LOG_INFO, "<Policy default>");
1329
cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateAccess default");
1330
cupsdAddString(&(p->job_access), "@OWNER");
1331
cupsdAddString(&(p->job_access), "@SYSTEM");
1333
cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateValues default");
1334
cupsdAddString(&(p->job_attrs), "job-name");
1335
cupsdAddString(&(p->job_attrs), "job-originating-host-name");
1336
cupsdAddString(&(p->job_attrs), "job-originating-user-name");
1338
cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateAccess default");
1339
cupsdAddString(&(p->sub_access), "@OWNER");
1340
cupsdAddString(&(p->sub_access), "@SYSTEM");
1342
cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateValues default");
1343
cupsdAddString(&(p->job_attrs), "notify-events");
1344
cupsdAddString(&(p->job_attrs), "notify-pull-method");
1345
cupsdAddString(&(p->job_attrs), "notify-recipient-uri");
1346
cupsdAddString(&(p->job_attrs), "notify-subscriber-user-name");
1347
cupsdAddString(&(p->job_attrs), "notify-user-data");
1349
cupsdLogMessage(CUPSD_LOG_INFO,
1350
"<Limit Create-Job Print-Job Print-URI Validate-Job>");
1351
cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1353
po = cupsdAddPolicyOp(p, NULL, IPP_CREATE_JOB);
1354
po->order_type = CUPSD_AUTH_ALLOW;
1356
cupsdAddPolicyOp(p, po, IPP_PRINT_JOB);
1357
cupsdAddPolicyOp(p, po, IPP_PRINT_URI);
1358
cupsdAddPolicyOp(p, po, IPP_VALIDATE_JOB);
1360
cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1362
cupsdLogMessage(CUPSD_LOG_INFO,
1363
"<Limit Send-Document Send-URI Cancel-Job Hold-Job "
1364
"Release-Job Restart-Job Purge-Jobs "
1365
"Set-Job-Attributes Create-Job-Subscription "
1366
"Renew-Subscription Cancel-Subscription "
1367
"Get-Notifications Reprocess-Job Cancel-Current-Job "
1368
"Suspend-Current-Job Resume-Job "
1369
"Cancel-My-Jobs Close-Job CUPS-Move-Job "
1370
"CUPS-Authenticate-Job CUPS-Get-Document>");
1371
cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1373
po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT);
1374
po->order_type = CUPSD_AUTH_ALLOW;
1375
po->level = CUPSD_AUTH_USER;
1377
cupsdAddName(po, "@OWNER");
1378
cupsdAddName(po, "@SYSTEM");
1379
cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM");
1381
cupsdAddPolicyOp(p, po, IPP_SEND_URI);
1382
cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB);
1383
cupsdAddPolicyOp(p, po, IPP_HOLD_JOB);
1384
cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB);
1385
cupsdAddPolicyOp(p, po, IPP_RESTART_JOB);
1386
cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS);
1387
cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES);
1388
cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION);
1389
cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION);
1390
cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION);
1391
cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS);
1392
cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB);
1393
cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB);
1394
cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB);
1395
cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
1396
cupsdAddPolicyOp(p, po, IPP_CANCEL_MY_JOBS);
1397
cupsdAddPolicyOp(p, po, IPP_CLOSE_JOB);
1398
cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
1399
cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB);
1400
cupsdAddPolicyOp(p, po, CUPS_GET_DOCUMENT);
1402
cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1404
cupsdLogMessage(CUPSD_LOG_INFO,
1405
"<Limit Pause-Printer Resume-Printer "
1406
"Set-Printer-Attributes Enable-Printer "
1407
"Disable-Printer Pause-Printer-After-Current-Job "
1408
"Hold-New-Jobs Release-Held-New-Jobs "
1409
"Deactivate-Printer Activate-Printer Restart-Printer "
1410
"Shutdown-Printer Startup-Printer Promote-Job "
1411
"Schedule-Job-After Cancel-Jobs CUPS-Add-Printer "
1412
"CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class "
1413
"CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>");
1414
cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1415
cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Default");
1417
po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER);
1418
po->order_type = CUPSD_AUTH_ALLOW;
1419
po->type = CUPSD_AUTH_DEFAULT;
1420
po->level = CUPSD_AUTH_USER;
1422
cupsdAddName(po, "@SYSTEM");
1423
cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM");
1425
cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER);
1426
cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES);
1427
cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER);
1428
cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER);
1429
cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB);
1430
cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS);
1431
cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS);
1432
cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER);
1433
cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER);
1434
cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER);
1435
cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER);
1436
cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER);
1437
cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB);
1438
cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER);
1439
cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS);
1440
cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER);
1441
cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER);
1442
cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS);
1443
cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS);
1444
cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS);
1445
cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS);
1446
cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT);
1448
cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1450
cupsdLogMessage(CUPSD_LOG_INFO, "<Limit All>");
1451
cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
1453
po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION);
1454
po->order_type = CUPSD_AUTH_ALLOW;
1456
cupsdLogMessage(CUPSD_LOG_INFO, "</Limit>");
1457
cupsdLogMessage(CUPSD_LOG_INFO, "</Policy>");
1461
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: NumPolicies=%d",
1462
cupsArrayCount(Policies));
1463
for (i = 0, p = (cupsd_policy_t *)cupsArrayFirst(Policies);
1465
i ++, p = (cupsd_policy_t *)cupsArrayNext(Policies))
1466
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1467
"cupsdReadConfiguration: Policies[%d]=\"%s\"", i, p->name);
1470
* If we are doing a full reload or the server root has changed, flush
1471
* the jobs, printers, etc. and start from scratch...
1474
if (NeedReload == RELOAD_ALL ||
1475
old_remote_port != RemotePort ||
1476
!old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) ||
1477
!old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot))
1479
mime_type_t *type; /* Current type */
1480
char mimetype[MIME_MAX_SUPER + MIME_MAX_TYPE];
1481
/* MIME type name */
1484
cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required.");
1487
* Free all memory...
1490
cupsdDeleteAllSubscriptions();
1492
cupsdDeleteAllPrinters();
1494
DefaultPrinter = NULL;
1496
if (MimeDatabase != NULL)
1497
mimeDelete(MimeDatabase);
1501
for (i = 0; i < NumMimeTypes; i ++)
1502
_cupsStrFree(MimeTypes[i]);
1508
* Read the MIME type and conversion database...
1511
snprintf(temp, sizeof(temp), "%s/filter", ServerBin);
1512
snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
1514
MimeDatabase = mimeNew();
1515
mimeSetErrorCallback(MimeDatabase, mime_error_cb, NULL);
1517
MimeDatabase = mimeLoadTypes(MimeDatabase, mimedir);
1518
MimeDatabase = mimeLoadTypes(MimeDatabase, ServerRoot);
1519
MimeDatabase = mimeLoadFilters(MimeDatabase, mimedir, temp);
1520
MimeDatabase = mimeLoadFilters(MimeDatabase, ServerRoot, temp);
1524
cupsdLogMessage(CUPSD_LOG_EMERG,
1525
"Unable to load MIME database from \"%s\" or \"%s\".",
1526
mimedir, ServerRoot);
1527
if (FatalErrors & CUPSD_FATAL_CONFIG)
1531
cupsdLogMessage(CUPSD_LOG_INFO,
1532
"Loaded MIME database from \"%s\" and \"%s\": %d types, "
1533
"%d filters...", mimedir, ServerRoot,
1534
mimeNumTypes(MimeDatabase), mimeNumFilters(MimeDatabase));
1537
* Create a list of MIME types for the document-format-supported
1541
NumMimeTypes = mimeNumTypes(MimeDatabase);
1542
if (!mimeType(MimeDatabase, "application", "octet-stream"))
1545
if ((MimeTypes = calloc(NumMimeTypes, sizeof(const char *))) == NULL)
1547
cupsdLogMessage(CUPSD_LOG_ERROR,
1548
"Unable to allocate memory for %d MIME types.",
1554
for (i = 0, type = mimeFirstType(MimeDatabase);
1556
i ++, type = mimeNextType(MimeDatabase))
1558
snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
1560
MimeTypes[i] = _cupsStrAlloc(mimetype);
1563
if (i < NumMimeTypes)
1564
MimeTypes[i] = _cupsStrAlloc("application/octet-stream");
1567
if (LogLevel == CUPSD_LOG_DEBUG2)
1569
mime_filter_t *filter; /* Current filter */
1572
for (type = mimeFirstType(MimeDatabase);
1574
type = mimeNextType(MimeDatabase))
1575
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadConfiguration: type %s/%s",
1576
type->super, type->type);
1578
for (filter = mimeFirstFilter(MimeDatabase);
1580
filter = mimeNextFilter(MimeDatabase))
1581
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1582
"cupsdReadConfiguration: filter %s/%s to %s/%s %d %s",
1583
filter->src->super, filter->src->type,
1584
filter->dst->super, filter->dst->type,
1585
filter->cost, filter->filter);
1592
snprintf(temp, sizeof(temp), "%s/banners", DataDir);
1593
cupsdLoadBanners(temp);
1596
* Load printers and classes...
1599
cupsdLoadAllPrinters();
1600
cupsdLoadAllClasses();
1602
cupsdCreateCommonData();
1605
* Update the printcap file as needed...
1608
if (Printcap && *Printcap && access(Printcap, 0))
1609
cupsdWritePrintcap();
1612
* Load queued jobs...
1618
* Load subscriptions...
1621
cupsdLoadAllSubscriptions();
1623
cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete.");
1628
* Not a full reload, so recreate the common printer attributes...
1631
cupsdCreateCommonData();
1634
* Update all jobs as needed...
1640
* Update all printers as needed...
1643
cupsdUpdatePrinters();
1644
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
1646
cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete.");
1650
* Reset the reload state...
1653
NeedReload = RELOAD_NONE;
1655
cupsdClearString(&old_serverroot);
1656
cupsdClearString(&old_requestroot);
1663
* 'get_address()' - Get an address + port number from a line.
1666
static http_addrlist_t * /* O - Pointer to list if address good, NULL if bad */
1667
get_address(const char *value, /* I - Value string */
1668
int defport) /* I - Default port */
1670
char buffer[1024], /* Hostname + port number buffer */
1671
defpname[255], /* Default port name */
1672
*hostname, /* Hostname or IP */
1673
*portname; /* Port number or name */
1674
http_addrlist_t *addrlist; /* Address list */
1678
* Check for an empty value...
1683
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address.");
1688
* Grab a hostname and port number; if there is no colon and the port name
1689
* is only digits, then we have a port number by itself...
1692
strlcpy(buffer, value, sizeof(buffer));
1694
if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']'))
1701
for (portname = buffer; isdigit(*portname & 255); portname ++);
1706
* Use the default port...
1709
sprintf(defpname, "%d", defport);
1710
portname = defpname;
1716
* The buffer contains just a port number...
1724
if (hostname && !strcmp(hostname, "*"))
1728
* Now lookup the address using httpAddrGetList()...
1731
if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
1732
cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed.",
1733
hostname ? hostname : "(nil)");
1740
* 'get_addr_and_mask()' - Get an IP address and netmask.
1743
static int /* O - 1 on success, 0 on failure */
1744
get_addr_and_mask(const char *value, /* I - String from config file */
1745
unsigned *ip, /* O - Address value */
1746
unsigned *mask) /* O - Mask value */
1748
int i, j, /* Looping vars */
1749
family, /* Address family */
1750
ipcount; /* Count of fields in address */
1751
unsigned ipval; /* Value */
1752
const char *maskval, /* Pointer to start of mask value */
1753
*ptr, /* Pointer into value */
1758
* Get the address...
1761
ip[0] = ip[1] = ip[2] = ip[3] = 0x00000000;
1762
mask[0] = mask[1] = mask[2] = mask[3] = 0xffffffff;
1764
if ((maskval = strchr(value, '/')) != NULL)
1767
maskval = value + strlen(value);
1771
* Check for an IPv6 address...
1777
* Parse hexadecimal IPv6/IPv4 address...
1782
for (i = 0, ptr = value + 1; *ptr && i < 8; i ++)
1786
else if (!strncmp(ptr, "::", 2))
1788
for (ptr2 = strchr(ptr + 2, ':'), j = 0;
1790
ptr2 = strchr(ptr2 + 1, ':'), j ++);
1795
else if (isdigit(*ptr & 255) && strchr(ptr + 1, '.') && i >= 6)
1798
* Read IPv4 dotted quad...
1801
unsigned val[4] = { 0, 0, 0, 0 };
1802
/* IPv4 address values */
1804
ipcount = sscanf(ptr, "%u.%u.%u.%u", val + 0, val + 1, val + 2,
1808
* Range check the IP numbers...
1811
for (i = 0; i < ipcount; i ++)
1816
* Merge everything into a 32-bit IPv4 address in ip[3]...
1819
ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
1822
mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
1825
* If the leading words are all 0's then this is an IPv4 address...
1828
if (!val[0] && !val[1] && !val[2])
1831
while (isdigit(*ptr & 255) || *ptr == '.')
1835
else if (isxdigit(*ptr & 255))
1837
ipval = strtoul(ptr, (char **)&ptr, 16);
1839
if (*ptr == ':' && ptr[1] != ':')
1848
ip[i / 2] |= ipval << 16;
1859
if (*ptr && *ptr != '/')
1863
#endif /* AF_INET6 */
1866
* Parse dotted-decimal IPv4 address...
1869
unsigned val[4] = { 0, 0, 0, 0 }; /* IPv4 address values */
1873
ipcount = sscanf(value, "%u.%u.%u.%u", val + 0, val + 1, val + 2, val + 3);
1876
* Range check the IP numbers...
1879
for (i = 0; i < ipcount; i ++)
1884
* Merge everything into a 32-bit IPv4 address in ip[3]...
1887
ip[3] = (((((val[0] << 8) | val[1]) << 8) | val[2]) << 8) | val[3];
1890
mask[3] = (0xffffffff << (32 - 8 * ipcount)) & 0xffffffff;
1896
* Get the netmask value(s)...
1899
memset(mask, 0, sizeof(unsigned) * 4);
1901
if (strchr(maskval, '.'))
1904
* Get dotted-decimal mask...
1907
if (family != AF_INET)
1910
if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2,
1914
mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8;
1915
mask[0] = mask[1] = mask[2] = 0;
1920
* Get address/bits format...
1926
if (family == AF_INET6)
1934
mask[0] = 0xffffffff;
1936
mask[0] = (0xffffffff << (i - 96)) & 0xffffffff;
1939
mask[1] = 0xffffffff;
1943
mask[1] = (0xffffffff << (i - 64)) & 0xffffffff;
1946
mask[2] = 0xffffffff;
1950
mask[2] = (0xffffffff << (i - 32)) & 0xffffffff;
1953
mask[3] = 0xffffffff;
1957
mask[3] = (0xffffffff << i) & 0xffffffff;
1960
#endif /* AF_INET6 */
1965
mask[0] = 0xffffffff;
1966
mask[1] = 0xffffffff;
1967
mask[2] = 0xffffffff;
1970
mask[3] = (0xffffffff << (32 - i)) & 0xffffffff;
1972
mask[3] = 0xffffffff;
1977
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1978
"get_addr_and_mask(value=\"%s\", "
1979
"ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x])",
1980
value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2],
1984
* Check for a valid netmask; no fallback like in CUPS 1.1.x!
1987
if ((ip[0] & ~mask[0]) != 0 ||
1988
(ip[1] & ~mask[1]) != 0 ||
1989
(ip[2] & ~mask[2]) != 0 ||
1990
(ip[3] & ~mask[3]) != 0)
1998
* 'mime_error_cb()' - Log a MIME error.
2002
mime_error_cb(void *ctx, /* I - Context pointer (unused) */
2003
const char *message) /* I - Message */
2007
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", message);
2012
* 'parse_aaa()' - Parse authentication, authorization, and access control lines.
2015
static int /* O - 1 on success, 0 on failure */
2016
parse_aaa(cupsd_location_t *loc, /* I - Location */
2017
char *line, /* I - Line from file */
2018
char *value, /* I - Start of value data */
2019
int linenum) /* I - Current line number */
2021
char *valptr; /* Pointer into value */
2022
unsigned ip[4], /* IP address components */
2023
mask[4]; /* IP netmask components */
2026
if (!_cups_strcasecmp(line, "Encryption"))
2029
* "Encryption xxx" - set required encryption level...
2032
if (!_cups_strcasecmp(value, "never"))
2033
loc->encryption = HTTP_ENCRYPT_NEVER;
2034
else if (!_cups_strcasecmp(value, "always"))
2036
cupsdLogMessage(CUPSD_LOG_ERROR,
2037
"Encryption value \"%s\" on line %d is invalid in this "
2038
"context. Using \"required\" instead.", value, linenum);
2040
loc->encryption = HTTP_ENCRYPT_REQUIRED;
2042
else if (!_cups_strcasecmp(value, "required"))
2043
loc->encryption = HTTP_ENCRYPT_REQUIRED;
2044
else if (!_cups_strcasecmp(value, "ifrequested"))
2045
loc->encryption = HTTP_ENCRYPT_IF_REQUESTED;
2048
cupsdLogMessage(CUPSD_LOG_ERROR,
2049
"Unknown Encryption value %s on line %d.", value, linenum);
2053
else if (!_cups_strcasecmp(line, "Order"))
2056
* "Order Deny,Allow" or "Order Allow,Deny"...
2059
if (!_cups_strncasecmp(value, "deny", 4))
2060
loc->order_type = CUPSD_AUTH_ALLOW;
2061
else if (!_cups_strncasecmp(value, "allow", 5))
2062
loc->order_type = CUPSD_AUTH_DENY;
2065
cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.",
2070
else if (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny"))
2073
* Allow [From] host/ip...
2074
* Deny [From] host/ip...
2079
if (!_cups_strncasecmp(value, "from", 4))
2082
* Strip leading "from"...
2087
while (_cups_isspace(*value))
2095
* Find the end of the value...
2098
for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
2100
while (_cups_isspace(*valptr))
2104
* Figure out what form the allow/deny address takes:
2115
* nnn.nnn.nnn.nnn/mm
2116
* nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
2119
if (!_cups_strcasecmp(value, "all"))
2125
if (!_cups_strcasecmp(line, "Allow"))
2126
cupsdAddIPMask(&(loc->allow), zeros, zeros);
2128
cupsdAddIPMask(&(loc->deny), zeros, zeros);
2130
else if (!_cups_strcasecmp(value, "none"))
2136
if (!_cups_strcasecmp(line, "Allow"))
2137
cupsdAddIPMask(&(loc->allow), ones, zeros);
2139
cupsdAddIPMask(&(loc->deny), ones, zeros);
2142
else if (value[0] == '*' || value[0] == '.' ||
2143
(!isdigit(value[0] & 255) && value[0] != '['))
2145
else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
2146
#endif /* AF_INET6 */
2149
* Host or domain name...
2152
if (value[0] == '*')
2155
if (!_cups_strcasecmp(line, "Allow"))
2156
cupsdAddNameMask(&(loc->allow), value);
2158
cupsdAddNameMask(&(loc->deny), value);
2163
* One of many IP address forms...
2166
if (!get_addr_and_mask(value, ip, mask))
2168
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.",
2173
if (!_cups_strcasecmp(line, "Allow"))
2174
cupsdAddIPMask(&(loc->allow), ip, mask);
2176
cupsdAddIPMask(&(loc->deny), ip, mask);
2180
* Advance to next value...
2186
else if (!_cups_strcasecmp(line, "AuthType"))
2189
* AuthType {none,basic,digest,basicdigest,negotiate,default}
2192
if (!_cups_strcasecmp(value, "none"))
2194
loc->type = CUPSD_AUTH_NONE;
2195
loc->level = CUPSD_AUTH_ANON;
2197
else if (!_cups_strcasecmp(value, "basic"))
2199
loc->type = CUPSD_AUTH_BASIC;
2201
if (loc->level == CUPSD_AUTH_ANON)
2202
loc->level = CUPSD_AUTH_USER;
2204
else if (!_cups_strcasecmp(value, "digest"))
2206
loc->type = CUPSD_AUTH_DIGEST;
2208
if (loc->level == CUPSD_AUTH_ANON)
2209
loc->level = CUPSD_AUTH_USER;
2211
else if (!_cups_strcasecmp(value, "basicdigest"))
2213
loc->type = CUPSD_AUTH_BASICDIGEST;
2215
if (loc->level == CUPSD_AUTH_ANON)
2216
loc->level = CUPSD_AUTH_USER;
2218
else if (!_cups_strcasecmp(value, "default"))
2220
loc->type = CUPSD_AUTH_DEFAULT;
2222
if (loc->level == CUPSD_AUTH_ANON)
2223
loc->level = CUPSD_AUTH_USER;
2226
else if (!_cups_strcasecmp(value, "negotiate"))
2228
loc->type = CUPSD_AUTH_NEGOTIATE;
2230
if (loc->level == CUPSD_AUTH_ANON)
2231
loc->level = CUPSD_AUTH_USER;
2233
#endif /* HAVE_GSSAPI */
2236
cupsdLogMessage(CUPSD_LOG_WARN,
2237
"Unknown authorization type %s on line %d.",
2242
else if (!_cups_strcasecmp(line, "AuthClass"))
2245
* AuthClass anonymous, user, system, group
2248
if (!_cups_strcasecmp(value, "anonymous"))
2250
loc->type = CUPSD_AUTH_NONE;
2251
loc->level = CUPSD_AUTH_ANON;
2253
cupsdLogMessage(CUPSD_LOG_WARN,
2254
"\"AuthClass %s\" is deprecated; consider removing "
2258
else if (!_cups_strcasecmp(value, "user"))
2260
loc->level = CUPSD_AUTH_USER;
2262
cupsdLogMessage(CUPSD_LOG_WARN,
2263
"\"AuthClass %s\" is deprecated; consider using "
2264
"\"Require valid-user\" on line %d.",
2267
else if (!_cups_strcasecmp(value, "group"))
2269
loc->level = CUPSD_AUTH_GROUP;
2271
cupsdLogMessage(CUPSD_LOG_WARN,
2272
"\"AuthClass %s\" is deprecated; consider using "
2273
"\"Require user @groupname\" on line %d.",
2276
else if (!_cups_strcasecmp(value, "system"))
2278
loc->level = CUPSD_AUTH_GROUP;
2280
cupsdAddName(loc, "@SYSTEM");
2282
cupsdLogMessage(CUPSD_LOG_WARN,
2283
"\"AuthClass %s\" is deprecated; consider using "
2284
"\"Require user @SYSTEM\" on line %d.",
2289
cupsdLogMessage(CUPSD_LOG_WARN,
2290
"Unknown authorization class %s on line %d.",
2295
else if (!_cups_strcasecmp(line, "AuthGroupName"))
2297
cupsdAddName(loc, value);
2299
cupsdLogMessage(CUPSD_LOG_WARN,
2300
"\"AuthGroupName %s\" directive is deprecated; consider "
2301
"using \"Require user @%s\" on line %d.",
2302
value, value, linenum);
2304
else if (!_cups_strcasecmp(line, "Require"))
2307
* Apache synonym for AuthClass and AuthGroupName...
2311
* Require valid-user
2312
* Require group names
2313
* Require user names
2316
for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
2321
if (!_cups_strcasecmp(value, "valid-user") ||
2322
!_cups_strcasecmp(value, "user"))
2323
loc->level = CUPSD_AUTH_USER;
2324
else if (!_cups_strcasecmp(value, "group"))
2325
loc->level = CUPSD_AUTH_GROUP;
2328
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.",
2334
* Get the list of names from the line...
2337
for (value = valptr; *value;)
2339
while (_cups_isspace(*value))
2342
#ifdef HAVE_AUTHORIZATION_H
2343
if (!strncmp(value, "@AUTHKEY(", 9))
2346
* Grab "@AUTHKEY(name)" value...
2349
for (valptr = value + 9; *valptr != ')' && *valptr; valptr ++);
2355
#endif /* HAVE_AUTHORIZATION_H */
2356
if (*value == '\"' || *value == '\'')
2359
* Grab quoted name...
2362
for (valptr = value + 1; *valptr != *value && *valptr; valptr ++);
2369
* Grab literal name.
2372
for (valptr = value; !_cups_isspace(*valptr) && *valptr; valptr ++);
2378
cupsdAddName(loc, value);
2380
for (value = valptr; _cups_isspace(*value); value ++);
2383
else if (!_cups_strcasecmp(line, "Satisfy"))
2385
if (!_cups_strcasecmp(value, "all"))
2386
loc->satisfy = CUPSD_AUTH_SATISFY_ALL;
2387
else if (!_cups_strcasecmp(value, "any"))
2388
loc->satisfy = CUPSD_AUTH_SATISFY_ANY;
2391
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.",
2404
* 'parse_fatal_errors()' - Parse FatalErrors values in a string.
2407
static int /* O - FatalErrors bits */
2408
parse_fatal_errors(const char *s) /* I - FatalErrors string */
2410
int fatal; /* FatalErrors bits */
2411
char value[1024], /* Value string */
2412
*valstart, /* Pointer into value */
2413
*valend; /* End of value */
2417
* Empty FatalErrors line yields NULL pointer...
2421
return (CUPSD_FATAL_NONE);
2424
* Loop through the value string,...
2427
strlcpy(value, s, sizeof(value));
2429
fatal = CUPSD_FATAL_NONE;
2431
for (valstart = value; *valstart;)
2434
* Get the current space/comma-delimited kind name...
2437
for (valend = valstart; *valend; valend ++)
2438
if (_cups_isspace(*valend) || *valend == ',')
2445
* Add the error to the bitmask...
2448
if (!_cups_strcasecmp(valstart, "all"))
2449
fatal = CUPSD_FATAL_ALL;
2450
else if (!_cups_strcasecmp(valstart, "browse"))
2451
fatal |= CUPSD_FATAL_BROWSE;
2452
else if (!_cups_strcasecmp(valstart, "-browse"))
2453
fatal &= ~CUPSD_FATAL_BROWSE;
2454
else if (!_cups_strcasecmp(valstart, "config"))
2455
fatal |= CUPSD_FATAL_CONFIG;
2456
else if (!_cups_strcasecmp(valstart, "-config"))
2457
fatal &= ~CUPSD_FATAL_CONFIG;
2458
else if (!_cups_strcasecmp(valstart, "listen"))
2459
fatal |= CUPSD_FATAL_LISTEN;
2460
else if (!_cups_strcasecmp(valstart, "-listen"))
2461
fatal &= ~CUPSD_FATAL_LISTEN;
2462
else if (!_cups_strcasecmp(valstart, "log"))
2463
fatal |= CUPSD_FATAL_LOG;
2464
else if (!_cups_strcasecmp(valstart, "-log"))
2465
fatal &= ~CUPSD_FATAL_LOG;
2466
else if (!_cups_strcasecmp(valstart, "permissions"))
2467
fatal |= CUPSD_FATAL_PERMISSIONS;
2468
else if (!_cups_strcasecmp(valstart, "-permissions"))
2469
fatal &= ~CUPSD_FATAL_PERMISSIONS;
2470
else if (_cups_strcasecmp(valstart, "none"))
2471
cupsdLogMessage(CUPSD_LOG_ERROR,
2472
"Unknown FatalErrors kind \"%s\" ignored.", valstart);
2474
for (valstart = valend; *valstart; valstart ++)
2475
if (!_cups_isspace(*valstart) || *valstart != ',')
2484
* 'parse_groups()' - Parse system group names in a string.
2487
static int /* O - 1 on success, 0 on failure */
2488
parse_groups(const char *s) /* I - Space-delimited groups */
2490
int status; /* Return status */
2491
char value[1024], /* Value string */
2492
*valstart, /* Pointer into value */
2493
*valend, /* End of value */
2494
quote; /* Quote character */
2495
struct group *group; /* Group */
2499
* Make a copy of the string and parse out the groups...
2502
strlcpy(value, s, sizeof(value));
2507
while (*valstart && NumSystemGroups < MAX_SYSTEM_GROUPS)
2509
if (*valstart == '\'' || *valstart == '\"')
2512
* Scan quoted name...
2515
quote = *valstart++;
2517
for (valend = valstart; *valend; valend ++)
2518
if (*valend == quote)
2524
* Scan space or comma-delimited name...
2527
for (valend = valstart; *valend; valend ++)
2528
if (_cups_isspace(*valend) || *valend == ',')
2535
group = getgrnam(valstart);
2538
cupsdSetString(SystemGroups + NumSystemGroups, valstart);
2539
SystemGroupIDs[NumSystemGroups] = group->gr_gid;
2550
while (*valstart == ',' || _cups_isspace(*valstart))
2559
* 'parse_protocols()' - Parse browse protocols in a string.
2562
static int /* O - Browse protocol bits */
2563
parse_protocols(const char *s) /* I - Space-delimited protocols */
2565
int protocols; /* Browse protocol bits */
2566
char value[1024], /* Value string */
2567
*valstart, /* Pointer into value */
2568
*valend; /* End of value */
2572
* Empty protocol line yields NULL pointer...
2579
* Loop through the value string,...
2582
strlcpy(value, s, sizeof(value));
2586
for (valstart = value; *valstart;)
2589
* Get the current space/comma-delimited protocol name...
2592
for (valend = valstart; *valend; valend ++)
2593
if (_cups_isspace(*valend) || *valend == ',')
2600
* Add the protocol to the bitmask...
2603
if (!_cups_strcasecmp(valstart, "dnssd") ||
2604
!_cups_strcasecmp(valstart, "dns-sd") ||
2605
!_cups_strcasecmp(valstart, "bonjour"))
2606
protocols |= BROWSE_DNSSD;
2607
else if (!_cups_strcasecmp(valstart, "all"))
2608
protocols |= BROWSE_ALL;
2609
else if (_cups_strcasecmp(valstart, "none"))
2610
cupsdLogMessage(CUPSD_LOG_ERROR,
2611
"Unknown browse protocol \"%s\" ignored.", valstart);
2613
for (valstart = valend; *valstart; valstart ++)
2614
if (!_cups_isspace(*valstart) || *valstart != ',')
2623
* 'parse_variable()' - Parse a variable line.
2626
static int /* O - 1 on success, 0 on failure */
2628
const char *filename, /* I - Name of configuration file */
2629
int linenum, /* I - Line in configuration file */
2630
const char *line, /* I - Line from configuration file */
2631
const char *value, /* I - Value from configuration file */
2632
size_t num_vars, /* I - Number of variables */
2633
const cupsd_var_t *vars) /* I - Variables */
2635
size_t i; /* Looping var */
2636
const cupsd_var_t *var; /* Variables */
2637
char temp[1024]; /* Temporary string */
2640
for (i = num_vars, var = vars; i > 0; i --, var ++)
2641
if (!_cups_strcasecmp(line, var->name))
2647
* Unknown directive! Output an error message and continue...
2651
cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.",
2652
line, linenum, filename);
2654
cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.",
2655
line, linenum, filename);
2662
case CUPSD_VARTYPE_INTEGER :
2665
cupsdLogMessage(CUPSD_LOG_ERROR,
2666
"Missing integer value for %s on line %d of %s.",
2667
line, linenum, filename);
2670
else if (!isdigit(*value & 255))
2672
cupsdLogMessage(CUPSD_LOG_ERROR,
2673
"Bad integer value for %s on line %d of %s.",
2674
line, linenum, filename);
2680
char *units; /* Units */
2682
n = strtol(value, &units, 0);
2684
if (units && *units)
2686
if (tolower(units[0] & 255) == 'g')
2687
n *= 1024 * 1024 * 1024;
2688
else if (tolower(units[0] & 255) == 'm')
2690
else if (tolower(units[0] & 255) == 'k')
2692
else if (tolower(units[0] & 255) == 't')
2696
cupsdLogMessage(CUPSD_LOG_ERROR,
2697
"Unknown integer value for %s on line %d of %s.",
2698
line, linenum, filename);
2705
cupsdLogMessage(CUPSD_LOG_ERROR,
2706
"Bad negative integer value for %s on line %d of "
2707
"%s.", line, linenum, filename);
2712
*((int *)var->ptr) = n;
2717
case CUPSD_VARTYPE_TIME :
2720
cupsdLogMessage(CUPSD_LOG_ERROR,
2721
"Missing time interval value for %s on line %d of "
2722
"%s.", line, linenum, filename);
2725
else if (!_cups_strncasecmp(line, "PreserveJob", 11) &&
2726
(!_cups_strcasecmp(value, "true") ||
2727
!_cups_strcasecmp(value, "on") ||
2728
!_cups_strcasecmp(value, "enabled") ||
2729
!_cups_strcasecmp(value, "yes")))
2731
*((int *)var->ptr) = INT_MAX;
2733
else if (!_cups_strcasecmp(value, "false") ||
2734
!_cups_strcasecmp(value, "off") ||
2735
!_cups_strcasecmp(value, "disabled") ||
2736
!_cups_strcasecmp(value, "no"))
2738
*((int *)var->ptr) = 0;
2740
else if (!isdigit(*value & 255))
2742
cupsdLogMessage(CUPSD_LOG_ERROR,
2743
"Unknown time interval value for %s on line %d of "
2744
"%s.", line, linenum, filename);
2749
double n; /* Number */
2750
char *units; /* Units */
2752
n = strtod(value, &units);
2754
if (units && *units)
2756
if (tolower(units[0] & 255) == 'w')
2757
n *= 7 * 24 * 60 * 60;
2758
else if (tolower(units[0] & 255) == 'd')
2760
else if (tolower(units[0] & 255) == 'h')
2762
else if (tolower(units[0] & 255) == 'm')
2766
cupsdLogMessage(CUPSD_LOG_ERROR,
2767
"Unknown time interval value for %s on line "
2768
"%d of %s.", line, linenum, filename);
2773
if (n < 0.0 || n > INT_MAX)
2775
cupsdLogMessage(CUPSD_LOG_ERROR,
2776
"Bad time value for %s on line %d of %s.",
2777
line, linenum, filename);
2782
*((int *)var->ptr) = (int)n;
2787
case CUPSD_VARTYPE_BOOLEAN :
2790
cupsdLogMessage(CUPSD_LOG_ERROR,
2791
"Missing boolean value for %s on line %d of %s.",
2792
line, linenum, filename);
2795
else if (!_cups_strcasecmp(value, "true") ||
2796
!_cups_strcasecmp(value, "on") ||
2797
!_cups_strcasecmp(value, "enabled") ||
2798
!_cups_strcasecmp(value, "yes") ||
2801
*((int *)var->ptr) = TRUE;
2803
else if (!_cups_strcasecmp(value, "false") ||
2804
!_cups_strcasecmp(value, "off") ||
2805
!_cups_strcasecmp(value, "disabled") ||
2806
!_cups_strcasecmp(value, "no") ||
2807
!_cups_strcasecmp(value, "0"))
2809
*((int *)var->ptr) = FALSE;
2813
cupsdLogMessage(CUPSD_LOG_ERROR,
2814
"Unknown boolean value %s on line %d of %s.",
2815
value, linenum, filename);
2820
case CUPSD_VARTYPE_PATHNAME :
2823
cupsdLogMessage(CUPSD_LOG_ERROR,
2824
"Missing pathname value for %s on line %d of %s.",
2825
line, linenum, filename);
2829
if (value[0] == '/')
2830
strlcpy(temp, value, sizeof(temp));
2832
snprintf(temp, sizeof(temp), "%s/%s", ServerRoot, value);
2834
if (access(temp, 0))
2836
cupsdLogMessage(CUPSD_LOG_ERROR,
2837
"File or directory for \"%s %s\" on line %d of %s "
2838
"does not exist.", line, value, linenum, filename);
2842
cupsdSetString((char **)var->ptr, temp);
2845
case CUPSD_VARTYPE_STRING :
2846
cupsdSetString((char **)var->ptr, value);
2855
* 'read_cupsd_conf()' - Read the cupsd.conf configuration file.
2858
static int /* O - 1 on success, 0 on failure */
2859
read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
2861
int linenum; /* Current line number */
2862
char line[HTTP_MAX_BUFFER],
2863
/* Line from file */
2864
temp[HTTP_MAX_BUFFER],
2865
/* Temporary buffer for value */
2866
*value, /* Pointer to value */
2867
*valueptr; /* Pointer into value */
2868
int valuelen; /* Length of value */
2869
http_addrlist_t *addrlist, /* Address list */
2870
*addr; /* Current address */
2871
cups_file_t *incfile; /* Include file */
2872
char incname[1024]; /* Include filename */
2876
* Loop through each line in the file...
2881
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
2884
* Decode the directive...
2887
if (!_cups_strcasecmp(line, "Include") && value)
2893
if (value[0] == '/')
2894
strlcpy(incname, value, sizeof(incname));
2896
snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);
2898
if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
2899
cupsdLogMessage(CUPSD_LOG_ERROR,
2900
"Unable to include config file \"%s\" - %s",
2901
incname, strerror(errno));
2904
read_cupsd_conf(incfile);
2905
cupsFileClose(incfile);
2908
else if (!_cups_strcasecmp(line, "<Location") && value)
2914
linenum = read_location(fp, value, linenum);
2918
else if (!_cups_strcasecmp(line, "<Policy") && value)
2924
linenum = read_policy(fp, value, linenum);
2928
else if (!_cups_strcasecmp(line, "FaxRetryInterval") && value)
2930
JobRetryInterval = atoi(value);
2931
cupsdLogMessage(CUPSD_LOG_WARN,
2932
"FaxRetryInterval is deprecated; use "
2933
"JobRetryInterval on line %d.", linenum);
2935
else if (!_cups_strcasecmp(line, "FaxRetryLimit") && value)
2937
JobRetryLimit = atoi(value);
2938
cupsdLogMessage(CUPSD_LOG_WARN,
2939
"FaxRetryLimit is deprecated; use "
2940
"JobRetryLimit on line %d.", linenum);
2942
else if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")
2944
|| !_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen")
2945
#endif /* HAVE_SSL */
2949
* Add listening address(es) to the list...
2952
cupsd_listener_t *lis; /* New listeners array */
2956
* Get the address list...
2959
addrlist = get_address(value, IPP_PORT);
2963
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line,
2969
* Add each address...
2972
for (addr = addrlist; addr; addr = addr->next)
2975
* See if this address is already present...
2978
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
2980
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
2981
if (httpAddrEqual(&(addr->addr), &(lis->address)) &&
2982
_httpAddrPort(&(addr->addr)) == _httpAddrPort(&(lis->address)))
2987
httpAddrString(&lis->address, temp, sizeof(temp));
2988
cupsdLogMessage(CUPSD_LOG_WARN,
2989
"Duplicate listen address \"%s\" ignored.", temp);
2994
* Allocate another listener...
2998
Listeners = cupsArrayNew(NULL, NULL);
3002
cupsdLogMessage(CUPSD_LOG_ERROR,
3003
"Unable to allocate %s at line %d - %s.",
3004
line, linenum, strerror(errno));
3008
if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
3010
cupsdLogMessage(CUPSD_LOG_ERROR,
3011
"Unable to allocate %s at line %d - %s.",
3012
line, linenum, strerror(errno));
3016
cupsArrayAdd(Listeners, lis);
3019
* Copy the current address and log it...
3022
memcpy(&(lis->address), &(addr->addr), sizeof(lis->address));
3026
if (!_cups_strcasecmp(line, "SSLPort") || !_cups_strcasecmp(line, "SSLListen"))
3027
lis->encryption = HTTP_ENCRYPT_ALWAYS;
3028
#endif /* HAVE_SSL */
3030
httpAddrString(&lis->address, temp, sizeof(temp));
3033
if (lis->address.addr.sa_family == AF_LOCAL)
3034
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp);
3036
#endif /* AF_LOCAL */
3037
cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv%d)", temp,
3038
_httpAddrPort(&(lis->address)),
3039
_httpAddrFamily(&(lis->address)) == AF_INET ? 4 : 6);
3041
if (!httpAddrLocalhost(&(lis->address)))
3042
RemotePort = _httpAddrPort(&(lis->address));
3049
httpAddrFreeList(addrlist);
3051
else if (!_cups_strcasecmp(line, "BrowseProtocols") ||
3052
!_cups_strcasecmp(line, "BrowseLocalProtocols"))
3055
* "BrowseProtocols name [... name]"
3056
* "BrowseLocalProtocols name [... name]"
3059
int protocols = parse_protocols(value);
3063
cupsdLogMessage(CUPSD_LOG_ERROR,
3064
"Unknown browse protocol \"%s\" on line %d.",
3069
BrowseLocalProtocols = protocols;
3071
else if (!_cups_strcasecmp(line, "DefaultAuthType") && value)
3074
* DefaultAuthType {basic,digest,basicdigest,negotiate}
3077
if (!_cups_strcasecmp(value, "none"))
3078
default_auth_type = CUPSD_AUTH_NONE;
3079
else if (!_cups_strcasecmp(value, "basic"))
3080
default_auth_type = CUPSD_AUTH_BASIC;
3081
else if (!_cups_strcasecmp(value, "digest"))
3082
default_auth_type = CUPSD_AUTH_DIGEST;
3083
else if (!_cups_strcasecmp(value, "basicdigest"))
3084
default_auth_type = CUPSD_AUTH_BASICDIGEST;
3086
else if (!_cups_strcasecmp(value, "negotiate"))
3087
default_auth_type = CUPSD_AUTH_NEGOTIATE;
3088
#endif /* HAVE_GSSAPI */
3089
else if (!_cups_strcasecmp(value, "auto"))
3090
default_auth_type = CUPSD_AUTH_AUTO;
3093
cupsdLogMessage(CUPSD_LOG_WARN,
3094
"Unknown default authorization type %s on line %d.",
3096
if (FatalErrors & CUPSD_FATAL_CONFIG)
3101
else if (!_cups_strcasecmp(line, "DefaultEncryption"))
3104
* DefaultEncryption {Never,IfRequested,Required}
3107
if (!value || !_cups_strcasecmp(value, "never"))
3108
DefaultEncryption = HTTP_ENCRYPT_NEVER;
3109
else if (!_cups_strcasecmp(value, "required"))
3110
DefaultEncryption = HTTP_ENCRYPT_REQUIRED;
3111
else if (!_cups_strcasecmp(value, "ifrequested"))
3112
DefaultEncryption = HTTP_ENCRYPT_IF_REQUESTED;
3115
cupsdLogMessage(CUPSD_LOG_WARN,
3116
"Unknown default encryption %s on line %d.",
3118
if (FatalErrors & CUPSD_FATAL_CONFIG)
3122
#endif /* HAVE_SSL */
3123
else if (!_cups_strcasecmp(line, "HostNameLookups") && value)
3126
* Do hostname lookups?
3129
if (!_cups_strcasecmp(value, "off") || !_cups_strcasecmp(value, "no") ||
3130
!_cups_strcasecmp(value, "false"))
3131
HostNameLookups = 0;
3132
else if (!_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "yes") ||
3133
!_cups_strcasecmp(value, "true"))
3134
HostNameLookups = 1;
3135
else if (!_cups_strcasecmp(value, "double"))
3136
HostNameLookups = 2;
3138
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.",
3141
else if (!_cups_strcasecmp(line, "AccessLogLevel") && value)
3144
* Amount of logging to do to access log...
3147
if (!_cups_strcasecmp(value, "all"))
3148
AccessLogLevel = CUPSD_ACCESSLOG_ALL;
3149
else if (!_cups_strcasecmp(value, "actions"))
3150
AccessLogLevel = CUPSD_ACCESSLOG_ACTIONS;
3151
else if (!_cups_strcasecmp(value, "config"))
3152
AccessLogLevel = CUPSD_ACCESSLOG_CONFIG;
3154
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown AccessLogLevel %s on line %d.",
3157
else if (!_cups_strcasecmp(line, "LogLevel") && value)
3160
* Amount of logging to do to error log...
3163
if (!_cups_strcasecmp(value, "debug2"))
3164
LogLevel = CUPSD_LOG_DEBUG2;
3165
else if (!_cups_strcasecmp(value, "debug"))
3166
LogLevel = CUPSD_LOG_DEBUG;
3167
else if (!_cups_strcasecmp(value, "info"))
3168
LogLevel = CUPSD_LOG_INFO;
3169
else if (!_cups_strcasecmp(value, "notice"))
3170
LogLevel = CUPSD_LOG_NOTICE;
3171
else if (!_cups_strcasecmp(value, "warn"))
3172
LogLevel = CUPSD_LOG_WARN;
3173
else if (!_cups_strcasecmp(value, "error"))
3174
LogLevel = CUPSD_LOG_ERROR;
3175
else if (!_cups_strcasecmp(value, "crit"))
3176
LogLevel = CUPSD_LOG_CRIT;
3177
else if (!_cups_strcasecmp(value, "alert"))
3178
LogLevel = CUPSD_LOG_ALERT;
3179
else if (!_cups_strcasecmp(value, "emerg"))
3180
LogLevel = CUPSD_LOG_EMERG;
3181
else if (!_cups_strcasecmp(value, "none"))
3182
LogLevel = CUPSD_LOG_NONE;
3184
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.",
3187
else if (!_cups_strcasecmp(line, "LogTimeFormat") && value)
3190
* Amount of logging to do to error log...
3193
if (!_cups_strcasecmp(value, "standard"))
3194
LogTimeFormat = CUPSD_TIME_STANDARD;
3195
else if (!_cups_strcasecmp(value, "usecs"))
3196
LogTimeFormat = CUPSD_TIME_USECS;
3198
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogTimeFormat %s on line %d.",
3201
else if (!_cups_strcasecmp(line, "ServerTokens") && value)
3204
* Set the string used for the Server header...
3207
struct utsname plat; /* Platform info */
3212
if (!_cups_strcasecmp(value, "ProductOnly"))
3213
cupsdSetString(&ServerHeader, "CUPS IPP");
3214
else if (!_cups_strcasecmp(value, "Major"))
3215
cupsdSetStringf(&ServerHeader, "CUPS/%d IPP/2", CUPS_VERSION_MAJOR);
3216
else if (!_cups_strcasecmp(value, "Minor"))
3217
cupsdSetStringf(&ServerHeader, "CUPS/%d.%d IPP/2.1", CUPS_VERSION_MAJOR,
3218
CUPS_VERSION_MINOR);
3219
else if (!_cups_strcasecmp(value, "Minimal"))
3220
cupsdSetString(&ServerHeader, CUPS_MINIMAL " IPP/2.1");
3221
else if (!_cups_strcasecmp(value, "OS"))
3222
cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s) IPP/2.1",
3223
plat.sysname, plat.release);
3224
else if (!_cups_strcasecmp(value, "Full"))
3225
cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s %s; %s) IPP/2.1",
3226
plat.sysname, plat.release, plat.machine);
3227
else if (!_cups_strcasecmp(value, "None"))
3228
cupsdClearString(&ServerHeader);
3230
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.",
3233
else if (!_cups_strcasecmp(line, "PassEnv") && value)
3236
* PassEnv variable [... variable]
3241
for (valuelen = 0; value[valuelen]; valuelen ++)
3242
if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
3245
if (value[valuelen])
3247
value[valuelen] = '\0';
3251
cupsdSetEnv(value, NULL);
3253
for (value += valuelen; *value; value ++)
3254
if (!_cups_isspace(*value) || *value != ',')
3258
else if (!_cups_strcasecmp(line, "ServerAlias") && value)
3261
* ServerAlias name [... name]
3265
ServerAlias = cupsArrayNew(NULL, NULL);
3269
for (valuelen = 0; value[valuelen]; valuelen ++)
3270
if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
3273
if (value[valuelen])
3275
value[valuelen] = '\0';
3279
cupsdAddAlias(ServerAlias, value);
3281
for (value += valuelen; *value; value ++)
3282
if (!_cups_isspace(*value) || *value != ',')
3286
else if (!_cups_strcasecmp(line, "SetEnv") && value)
3289
* SetEnv variable value
3292
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
3300
while (isspace(*valueptr & 255))
3303
cupsdSetEnv(value, valueptr);
3306
cupsdLogMessage(CUPSD_LOG_ERROR,
3307
"Missing value for SetEnv directive on line %d.",
3311
else if (!_cups_strcasecmp(line, "SSLOptions"))
3314
* SSLOptions options
3317
if (!value || !_cups_strcasecmp(value, "none"))
3318
SSLOptions = CUPSD_SSL_NONE;
3319
else if (!_cups_strcasecmp(value, "noemptyfragments"))
3320
SSLOptions = CUPSD_SSL_NOEMPTY;
3322
cupsdLogMessage(CUPSD_LOG_ERROR,
3323
"Unknown value \"%s\" for SSLOptions directive on "
3324
"line %d.", value, linenum);
3326
#endif /* HAVE_SSL */
3327
else if (!_cups_strcasecmp(line, "AccessLog") ||
3328
!_cups_strcasecmp(line, "CacheDir") ||
3329
!_cups_strcasecmp(line, "ConfigFilePerm") ||
3330
!_cups_strcasecmp(line, "DataDir") ||
3331
!_cups_strcasecmp(line, "DocumentRoot") ||
3332
!_cups_strcasecmp(line, "ErrorLog") ||
3333
!_cups_strcasecmp(line, "FatalErrors") ||
3334
!_cups_strcasecmp(line, "FileDevice") ||
3335
!_cups_strcasecmp(line, "FontPath") ||
3336
!_cups_strcasecmp(line, "Group") ||
3337
!_cups_strcasecmp(line, "LogFilePerm") ||
3338
!_cups_strcasecmp(line, "LPDConfigFile") ||
3339
!_cups_strcasecmp(line, "PageLog") ||
3340
!_cups_strcasecmp(line, "Printcap") ||
3341
!_cups_strcasecmp(line, "PrintcapFormat") ||
3342
!_cups_strcasecmp(line, "RemoteRoot") ||
3343
!_cups_strcasecmp(line, "RequestRoot") ||
3344
!_cups_strcasecmp(line, "ServerBin") ||
3345
!_cups_strcasecmp(line, "ServerCertificate") ||
3346
!_cups_strcasecmp(line, "ServerKey") ||
3347
!_cups_strcasecmp(line, "ServerRoot") ||
3348
!_cups_strcasecmp(line, "SMBConfigFile") ||
3349
!_cups_strcasecmp(line, "StateDir") ||
3350
!_cups_strcasecmp(line, "SystemGroup") ||
3351
!_cups_strcasecmp(line, "SystemGroupAuthKey") ||
3352
!_cups_strcasecmp(line, "TempDir") ||
3353
!_cups_strcasecmp(line, "PidFile") ||
3354
!_cups_strcasecmp(line, "User"))
3356
cupsdLogMessage(CUPSD_LOG_WARN,
3357
"Please move \"%s%s%s\" on line %d of %s to the %s file; "
3358
"this will become an error in a future release.",
3359
line, value ? " " : "", value ? value : "", linenum,
3360
ConfigurationFile, CupsFilesFile);
3363
parse_variable(ConfigurationFile, linenum, line, value,
3364
sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars);
3372
* 'read_cups_files_conf()' - Read the cups-files.conf configuration file.
3375
static int /* O - 1 on success, 0 on failure */
3376
read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
3378
int linenum; /* Current line number */
3379
char line[HTTP_MAX_BUFFER], /* Line from file */
3380
*value; /* Value from line */
3381
struct group *group; /* Group */
3385
* Loop through each line in the file...
3390
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3392
if (!_cups_strcasecmp(line, "FatalErrors"))
3393
FatalErrors = parse_fatal_errors(value);
3394
else if (!_cups_strcasecmp(line, "Group") && value)
3397
* Group ID to run as...
3400
if (isdigit(value[0]))
3401
Group = atoi(value);
3405
group = getgrnam(value);
3408
Group = group->gr_gid;
3411
cupsdLogMessage(CUPSD_LOG_ERROR,
3412
"Unknown Group \"%s\" on line %d of %s.", value,
3413
linenum, CupsFilesFile);
3414
if (FatalErrors & CUPSD_FATAL_CONFIG)
3419
else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
3422
* Format of printcap file?
3425
if (!_cups_strcasecmp(value, "bsd"))
3426
PrintcapFormat = PRINTCAP_BSD;
3427
else if (!_cups_strcasecmp(value, "plist"))
3428
PrintcapFormat = PRINTCAP_PLIST;
3429
else if (!_cups_strcasecmp(value, "solaris"))
3430
PrintcapFormat = PRINTCAP_SOLARIS;
3433
cupsdLogMessage(CUPSD_LOG_ERROR,
3434
"Unknown PrintcapFormat \"%s\" on line %d of %s.",
3435
value, linenum, CupsFilesFile);
3436
if (FatalErrors & CUPSD_FATAL_CONFIG)
3440
else if (!_cups_strcasecmp(line, "SystemGroup") && value)
3443
* SystemGroup (admin) group(s)...
3446
if (!parse_groups(value))
3448
cupsdLogMessage(CUPSD_LOG_ERROR,
3449
"Unknown SystemGroup \"%s\" on line %d of %s.", value,
3450
linenum, CupsFilesFile);
3451
if (FatalErrors & CUPSD_FATAL_CONFIG)
3455
else if (!_cups_strcasecmp(line, "User") && value)
3458
* User ID to run as...
3461
if (isdigit(value[0] & 255))
3463
int uid = atoi(value);
3467
cupsdLogMessage(CUPSD_LOG_ERROR,
3468
"Will not use User 0 as specified on line %d of %s "
3469
"for security reasons. You must use a non-"
3470
"privileged account instead.",
3471
linenum, CupsFilesFile);
3472
if (FatalErrors & CUPSD_FATAL_CONFIG)
3480
struct passwd *p; /* Password information */
3483
p = getpwnam(value);
3489
cupsdLogMessage(CUPSD_LOG_ERROR,
3490
"Will not use User %s (UID=0) as specified on line "
3491
"%d of %s for security reasons. You must use a "
3492
"non-privileged account instead.",
3493
value, linenum, CupsFilesFile);
3494
if (FatalErrors & CUPSD_FATAL_CONFIG)
3502
cupsdLogMessage(CUPSD_LOG_ERROR,
3503
"Unknown User \"%s\" on line %d of %s.",
3504
value, linenum, CupsFilesFile);
3505
if (FatalErrors & CUPSD_FATAL_CONFIG)
3510
else if (!parse_variable(CupsFilesFile, linenum, line, value,
3511
sizeof(cupsfiles_vars) / sizeof(cupsfiles_vars[0]),
3513
(FatalErrors & CUPSD_FATAL_CONFIG))
3522
* 'read_location()' - Read a <Location path> definition.
3525
static int /* O - New line number or 0 on error */
3526
read_location(cups_file_t *fp, /* I - Configuration file */
3527
char *location, /* I - Location name/path */
3528
int linenum) /* I - Current line number */
3530
cupsd_location_t *loc, /* New location */
3531
*parent; /* Parent location */
3532
char line[HTTP_MAX_BUFFER],
3534
*value, /* Value for directive */
3535
*valptr; /* Pointer into value */
3538
if ((parent = cupsdFindLocation(location)) != NULL)
3539
cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Location %s> on line %d.",
3541
else if ((parent = cupsdNewLocation(location)) == NULL)
3545
cupsdAddLocation(parent);
3547
parent->limit = CUPSD_AUTH_LIMIT_ALL;
3552
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3555
* Decode the directive...
3558
if (!_cups_strcasecmp(line, "</Location>"))
3560
else if (!_cups_strcasecmp(line, "<Limit") ||
3561
!_cups_strcasecmp(line, "<LimitExcept"))
3565
cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
3566
if (FatalErrors & CUPSD_FATAL_CONFIG)
3572
if ((loc = cupsdCopyLocation(parent)) == NULL)
3575
cupsdAddLocation(loc);
3580
for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3585
if (!strcmp(value, "ALL"))
3586
loc->limit = CUPSD_AUTH_LIMIT_ALL;
3587
else if (!strcmp(value, "GET"))
3588
loc->limit |= CUPSD_AUTH_LIMIT_GET;
3589
else if (!strcmp(value, "HEAD"))
3590
loc->limit |= CUPSD_AUTH_LIMIT_HEAD;
3591
else if (!strcmp(value, "OPTIONS"))
3592
loc->limit |= CUPSD_AUTH_LIMIT_OPTIONS;
3593
else if (!strcmp(value, "POST"))
3594
loc->limit |= CUPSD_AUTH_LIMIT_POST;
3595
else if (!strcmp(value, "PUT"))
3596
loc->limit |= CUPSD_AUTH_LIMIT_PUT;
3597
else if (!strcmp(value, "TRACE"))
3598
loc->limit |= CUPSD_AUTH_LIMIT_TRACE;
3600
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d.",
3603
for (value = valptr; isspace(*value & 255); value ++);
3606
if (!_cups_strcasecmp(line, "<LimitExcept"))
3607
loc->limit = CUPSD_AUTH_LIMIT_ALL ^ loc->limit;
3609
parent->limit &= ~loc->limit;
3611
else if (!_cups_strcasecmp(line, "</Limit>") ||
3612
!_cups_strcasecmp(line, "</LimitExcept>"))
3616
cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum);
3617
if (FatalErrors & CUPSD_FATAL_CONFIG)
3620
else if (!parse_aaa(loc, line, value, linenum))
3622
cupsdLogMessage(CUPSD_LOG_ERROR,
3623
"Unknown Location directive %s on line %d.",
3625
if (FatalErrors & CUPSD_FATAL_CONFIG)
3630
cupsdLogMessage(CUPSD_LOG_ERROR,
3631
"Unexpected end-of-file at line %d while reading location.",
3634
return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
3639
* 'read_policy()' - Read a <Policy name> definition.
3642
static int /* O - New line number or 0 on error */
3643
read_policy(cups_file_t *fp, /* I - Configuration file */
3644
char *policy, /* I - Location name/path */
3645
int linenum) /* I - Current line number */
3647
int i; /* Looping var */
3648
cupsd_policy_t *pol; /* Policy */
3649
cupsd_location_t *op; /* Policy operation */
3650
int num_ops; /* Number of IPP operations */
3651
ipp_op_t ops[100]; /* Operations */
3652
char line[HTTP_MAX_BUFFER],
3654
*value, /* Value for directive */
3655
*valptr; /* Pointer into value */
3659
* Create the policy...
3662
if ((pol = cupsdFindPolicy(policy)) != NULL)
3663
cupsdLogMessage(CUPSD_LOG_WARN, "Duplicate <Policy %s> on line %d.",
3665
else if ((pol = cupsdAddPolicy(policy)) == NULL)
3669
* Read from the file...
3675
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
3678
* Decode the directive...
3681
if (!_cups_strcasecmp(line, "</Policy>"))
3684
cupsdLogMessage(CUPSD_LOG_WARN,
3685
"Missing </Limit> before </Policy> on line %d.",
3688
set_policy_defaults(pol);
3692
else if (!_cups_strcasecmp(line, "<Limit") && !op)
3696
cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum);
3697
if (FatalErrors & CUPSD_FATAL_CONFIG)
3704
* Scan for IPP operation names...
3711
for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3716
if (num_ops < (int)(sizeof(ops) / sizeof(ops[0])))
3718
if (!_cups_strcasecmp(value, "All"))
3719
ops[num_ops] = IPP_ANY_OPERATION;
3720
else if ((ops[num_ops] = ippOpValue(value)) == IPP_BAD_OPERATION)
3721
cupsdLogMessage(CUPSD_LOG_ERROR,
3722
"Bad IPP operation name \"%s\" on line %d.",
3728
cupsdLogMessage(CUPSD_LOG_ERROR,
3729
"Too many operations listed on line %d.",
3732
for (value = valptr; isspace(*value & 255); value ++);
3736
* If none are specified, apply the policy to all operations...
3741
ops[0] = IPP_ANY_OPERATION;
3746
* Add a new policy for the first operation...
3749
op = cupsdAddPolicyOp(pol, NULL, ops[0]);
3751
else if (!_cups_strcasecmp(line, "</Limit>") && op)
3754
* Finish the current operation limit...
3760
* Copy the policy to the other operations...
3763
for (i = 1; i < num_ops; i ++)
3764
cupsdAddPolicyOp(pol, op, ops[i]);
3771
cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum);
3772
if (FatalErrors & CUPSD_FATAL_CONFIG)
3775
else if (!_cups_strcasecmp(line, "JobPrivateAccess") ||
3776
!_cups_strcasecmp(line, "JobPrivateValues") ||
3777
!_cups_strcasecmp(line, "SubscriptionPrivateAccess") ||
3778
!_cups_strcasecmp(line, "SubscriptionPrivateValues"))
3782
cupsdLogMessage(CUPSD_LOG_ERROR,
3783
"%s directive must appear outside <Limit>...</Limit> "
3784
"on line %d.", line, linenum);
3785
if (FatalErrors & CUPSD_FATAL_CONFIG)
3791
* Pull out whitespace-delimited values...
3797
* Find the end of the current value...
3800
for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
3806
* Save it appropriately...
3809
if (!_cups_strcasecmp(line, "JobPrivateAccess"))
3812
* JobPrivateAccess {all|default|user/group list|@@ACL}
3815
if (!_cups_strcasecmp(value, "default"))
3817
cupsdAddString(&(pol->job_access), "@OWNER");
3818
cupsdAddString(&(pol->job_access), "@SYSTEM");
3821
cupsdAddString(&(pol->job_access), value);
3823
else if (!_cups_strcasecmp(line, "JobPrivateValues"))
3826
* JobPrivateValues {all|none|default|attribute list}
3829
if (!_cups_strcasecmp(value, "default"))
3831
cupsdAddString(&(pol->job_attrs), "job-name");
3832
cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
3833
cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
3834
cupsdAddString(&(pol->job_attrs), "phone");
3837
cupsdAddString(&(pol->job_attrs), value);
3839
else if (!_cups_strcasecmp(line, "SubscriptionPrivateAccess"))
3842
* SubscriptionPrivateAccess {all|default|user/group list|@@ACL}
3845
if (!_cups_strcasecmp(value, "default"))
3847
cupsdAddString(&(pol->sub_access), "@OWNER");
3848
cupsdAddString(&(pol->sub_access), "@SYSTEM");
3851
cupsdAddString(&(pol->sub_access), value);
3853
else /* if (!_cups_strcasecmp(line, "SubscriptionPrivateValues")) */
3856
* SubscriptionPrivateValues {all|none|default|attribute list}
3859
if (!_cups_strcasecmp(value, "default"))
3861
cupsdAddString(&(pol->sub_attrs), "notify-events");
3862
cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
3863
cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
3864
cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
3865
cupsdAddString(&(pol->sub_attrs), "notify-user-data");
3868
cupsdAddString(&(pol->sub_attrs), value);
3872
* Find the next string on the line...
3875
for (value = valptr; isspace(*value & 255); value ++);
3881
cupsdLogMessage(CUPSD_LOG_ERROR,
3882
"Missing <Limit ops> directive before %s on line %d.",
3884
if (FatalErrors & CUPSD_FATAL_CONFIG)
3887
else if (!parse_aaa(op, line, value, linenum))
3889
cupsdLogMessage(CUPSD_LOG_ERROR,
3890
"Unknown Policy Limit directive %s on line %d.",
3893
if (FatalErrors & CUPSD_FATAL_CONFIG)
3898
cupsdLogMessage(CUPSD_LOG_ERROR,
3899
"Unexpected end-of-file at line %d while reading policy "
3900
"\"%s\".", linenum, policy);
3902
return ((FatalErrors & CUPSD_FATAL_CONFIG) ? 0 : linenum);
3907
* 'set_policy_defaults()' - Set default policy values as needed.
3911
set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
3913
cupsd_location_t *op; /* Policy operation */
3917
* Verify that we have an explicit policy for Validate-Job, Cancel-Jobs,
3918
* Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that
3919
* upgrades do not introduce new security issues...
3922
if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL ||
3923
op->op == IPP_ANY_OPERATION)
3925
if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL &&
3926
op->op != IPP_ANY_OPERATION)
3929
* Add a new limit for Validate-Job using the Print-Job limit as a
3933
cupsdLogMessage(CUPSD_LOG_WARN,
3934
"No limit for Validate-Job defined in policy %s "
3935
"- using Print-Job's policy.", pol->name);
3937
cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB);
3940
cupsdLogMessage(CUPSD_LOG_WARN,
3941
"No limit for Validate-Job defined in policy %s "
3942
"and no suitable template found.", pol->name);
3945
if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL ||
3946
op->op == IPP_ANY_OPERATION)
3948
if ((op = cupsdFindPolicyOp(pol, IPP_PAUSE_PRINTER)) != NULL &&
3949
op->op != IPP_ANY_OPERATION)
3952
* Add a new limit for Cancel-Jobs using the Pause-Printer limit as a
3956
cupsdLogMessage(CUPSD_LOG_WARN,
3957
"No limit for Cancel-Jobs defined in policy %s "
3958
"- using Pause-Printer's policy.", pol->name);
3960
cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS);
3963
cupsdLogMessage(CUPSD_LOG_WARN,
3964
"No limit for Cancel-Jobs defined in policy %s "
3965
"and no suitable template found.", pol->name);
3968
if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL ||
3969
op->op == IPP_ANY_OPERATION)
3971
if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
3972
op->op != IPP_ANY_OPERATION)
3975
* Add a new limit for Cancel-My-Jobs using the Send-Document limit as
3979
cupsdLogMessage(CUPSD_LOG_WARN,
3980
"No limit for Cancel-My-Jobs defined in policy %s "
3981
"- using Send-Document's policy.", pol->name);
3983
cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS);
3986
cupsdLogMessage(CUPSD_LOG_WARN,
3987
"No limit for Cancel-My-Jobs defined in policy %s "
3988
"and no suitable template found.", pol->name);
3991
if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL ||
3992
op->op == IPP_ANY_OPERATION)
3994
if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
3995
op->op != IPP_ANY_OPERATION)
3998
* Add a new limit for Close-Job using the Send-Document limit as a
4002
cupsdLogMessage(CUPSD_LOG_WARN,
4003
"No limit for Close-Job defined in policy %s "
4004
"- using Send-Document's policy.", pol->name);
4006
cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB);
4009
cupsdLogMessage(CUPSD_LOG_WARN,
4010
"No limit for Close-Job defined in policy %s "
4011
"and no suitable template found.", pol->name);
4014
if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL ||
4015
op->op == IPP_ANY_OPERATION)
4017
if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
4018
op->op != IPP_ANY_OPERATION)
4021
* Add a new limit for CUPS-Get-Document using the Send-Document
4022
* limit as a template...
4025
cupsdLogMessage(CUPSD_LOG_WARN,
4026
"No limit for CUPS-Get-Document defined in policy %s "
4027
"- using Send-Document's policy.", pol->name);
4029
cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT);
4032
cupsdLogMessage(CUPSD_LOG_WARN,
4033
"No limit for CUPS-Get-Document defined in policy %s "
4034
"and no suitable template found.", pol->name);
4038
* Verify we have JobPrivateAccess, JobPrivateValues,
4039
* SubscriptionPrivateAccess, and SubscriptionPrivateValues in the policy.
4042
if (!pol->job_access)
4044
cupsdLogMessage(CUPSD_LOG_WARN,
4045
"No JobPrivateAccess defined in policy %s "
4046
"- using defaults.", pol->name);
4047
cupsdAddString(&(pol->job_access), "@OWNER");
4048
cupsdAddString(&(pol->job_access), "@SYSTEM");
4051
if (!pol->job_attrs)
4053
cupsdLogMessage(CUPSD_LOG_WARN,
4054
"No JobPrivateValues defined in policy %s "
4055
"- using defaults.", pol->name);
4056
cupsdAddString(&(pol->job_attrs), "job-name");
4057
cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
4058
cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
4059
cupsdAddString(&(pol->job_attrs), "phone");
4062
if (!pol->sub_access)
4064
cupsdLogMessage(CUPSD_LOG_WARN,
4065
"No SubscriptionPrivateAccess defined in policy %s "
4066
"- using defaults.", pol->name);
4067
cupsdAddString(&(pol->sub_access), "@OWNER");
4068
cupsdAddString(&(pol->sub_access), "@SYSTEM");
4071
if (!pol->sub_attrs)
4073
cupsdLogMessage(CUPSD_LOG_WARN,
4074
"No SubscriptionPrivateValues defined in policy %s "
4075
"- using defaults.", pol->name);
4076
cupsdAddString(&(pol->sub_attrs), "notify-events");
4077
cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
4078
cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
4079
cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
4080
cupsdAddString(&(pol->sub_attrs), "notify-user-data");
4086
* End of "$Id: conf.c 10824 2013-01-18 19:58:41Z mike $".