]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/adminutil.c
1a5067f1ba66216b08d7bb63ef89642bf62078e0
[thirdparty/cups.git] / cups / adminutil.c
1 /*
2 * Administration utility API definitions for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 2001-2007 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups-private.h"
16 #include "debug-internal.h"
17 #include "ppd.h"
18 #include "adminutil.h"
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #ifndef _WIN32
22 # include <unistd.h>
23 # include <sys/wait.h>
24 #endif /* !_WIN32 */
25
26
27 /*
28 * Local functions...
29 */
30
31 static http_status_t get_cupsd_conf(http_t *http, _cups_globals_t *cg,
32 time_t last_update, char *name,
33 size_t namelen, int *remote);
34 static void invalidate_cupsd_cache(_cups_globals_t *cg);
35
36
37 /*
38 * 'cupsAdminCreateWindowsPPD()' - Create the Windows PPD file for a printer.
39 *
40 * @deprecated@
41 */
42
43 char * /* O - PPD file or NULL */
44 cupsAdminCreateWindowsPPD(
45 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
46 const char *dest, /* I - Printer or class */
47 char *buffer, /* I - Filename buffer */
48 int bufsize) /* I - Size of filename buffer */
49 {
50 if (buffer)
51 *buffer = '\0';
52
53 return (NULL);
54 }
55
56
57 /*
58 * 'cupsAdminExportSamba()' - Export a printer to Samba.
59 *
60 * @deprecated@
61 */
62
63 int /* O - 1 on success, 0 on failure */
64 cupsAdminExportSamba(
65 const char *dest, /* I - Destination to export */
66 const char *ppd, /* I - PPD file */
67 const char *samba_server, /* I - Samba server */
68 const char *samba_user, /* I - Samba username */
69 const char *samba_password, /* I - Samba password */
70 FILE *logfile) /* I - Log file, if any */
71 {
72 return (0);
73 }
74
75
76 /*
77 * 'cupsAdminGetServerSettings()' - Get settings from the server.
78 *
79 * The returned settings should be freed with cupsFreeOptions() when
80 * you are done with them.
81 *
82 * @since CUPS 1.3/macOS 10.5@
83 */
84
85 int /* O - 1 on success, 0 on failure */
86 cupsAdminGetServerSettings(
87 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
88 int *num_settings, /* O - Number of settings */
89 cups_option_t **settings) /* O - Settings */
90 {
91 int i; /* Looping var */
92 cups_file_t *cupsd; /* cupsd.conf file */
93 char cupsdconf[1024]; /* cupsd.conf filename */
94 int remote; /* Remote cupsd.conf file? */
95 http_status_t status; /* Status of getting cupsd.conf */
96 char line[1024], /* Line from cupsd.conf file */
97 *value; /* Value on line */
98 cups_option_t *setting; /* Current setting */
99 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
100
101
102 /*
103 * Range check input...
104 */
105
106 if (!http)
107 {
108 /*
109 * See if we are connected to the same server...
110 */
111
112 if (cg->http)
113 {
114 /*
115 * Compare the connection hostname, port, and encryption settings to
116 * the cached defaults; these were initialized the first time we
117 * connected...
118 */
119
120 if (strcmp(cg->http->hostname, cg->server) ||
121 cg->ipp_port != httpAddrPort(cg->http->hostaddr) ||
122 (cg->http->encryption != cg->encryption &&
123 cg->http->encryption == HTTP_ENCRYPTION_NEVER))
124 {
125 /*
126 * Need to close the current connection because something has changed...
127 */
128
129 httpClose(cg->http);
130 cg->http = NULL;
131 }
132 }
133
134 /*
135 * (Re)connect as needed...
136 */
137
138 if (!cg->http)
139 {
140 if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
141 cupsEncryption(), 1, 0, NULL)) == NULL)
142 {
143 if (errno)
144 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0);
145 else
146 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE,
147 _("Unable to connect to host."), 1);
148
149 if (num_settings)
150 *num_settings = 0;
151
152 if (settings)
153 *settings = NULL;
154
155 return (0);
156 }
157 }
158
159 http = cg->http;
160 }
161
162 if (!http || !num_settings || !settings)
163 {
164 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
165
166 if (num_settings)
167 *num_settings = 0;
168
169 if (settings)
170 *settings = NULL;
171
172 return (0);
173 }
174
175 *num_settings = 0;
176 *settings = NULL;
177
178 /*
179 * Get the cupsd.conf file...
180 */
181
182 if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf,
183 sizeof(cupsdconf), &remote)) == HTTP_STATUS_OK)
184 {
185 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
186 {
187 char message[1024]; /* Message string */
188
189
190 snprintf(message, sizeof(message),
191 _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
192 cupsdconf, strerror(errno));
193 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
194 }
195 }
196 else
197 cupsd = NULL;
198
199 if (cupsd)
200 {
201 /*
202 * Read the file, keeping track of what settings are enabled...
203 */
204
205 int remote_access = 0, /* Remote access allowed? */
206 remote_admin = 0, /* Remote administration allowed? */
207 remote_any = 0, /* Remote access from anywhere allowed? */
208 browsing = 1, /* Browsing enabled? */
209 cancel_policy = 1, /* Cancel-job policy set? */
210 debug_logging = 0; /* LogLevel debug set? */
211 int linenum = 0, /* Line number in file */
212 in_location = 0, /* In a location section? */
213 in_policy = 0, /* In a policy section? */
214 in_cancel_job = 0, /* In a cancel-job section? */
215 in_admin_location = 0; /* In the /admin location? */
216
217
218 invalidate_cupsd_cache(cg);
219
220 cg->cupsd_update = time(NULL);
221 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
222
223 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
224 {
225 if (!value && strncmp(line, "</", 2))
226 value = line + strlen(line);
227
228 if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value)
229 {
230 char *port; /* Pointer to port number, if any */
231
232
233 if ((port = strrchr(value, ':')) != NULL)
234 *port = '\0';
235 else if (isdigit(*value & 255))
236 {
237 /*
238 * Listen on a port number implies remote access...
239 */
240
241 remote_access = 1;
242 continue;
243 }
244
245 if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")
246 #ifdef AF_LOCAL
247 && *value != '/'
248 #endif /* AF_LOCAL */
249 #ifdef AF_INET6
250 && strcmp(value, "[::1]")
251 #endif /* AF_INET6 */
252 )
253 remote_access = 1;
254 }
255 else if (!_cups_strcasecmp(line, "Browsing"))
256 {
257 browsing = !_cups_strcasecmp(value, "yes") ||
258 !_cups_strcasecmp(value, "on") ||
259 !_cups_strcasecmp(value, "true");
260 }
261 else if (!_cups_strcasecmp(line, "LogLevel"))
262 {
263 debug_logging = !_cups_strncasecmp(value, "debug", 5);
264 }
265 else if (!_cups_strcasecmp(line, "<Policy") &&
266 !_cups_strcasecmp(value, "default"))
267 {
268 in_policy = 1;
269 }
270 else if (!_cups_strcasecmp(line, "</Policy>"))
271 {
272 in_policy = 0;
273 }
274 else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value)
275 {
276 /*
277 * See if the policy limit is for the Cancel-Job operation...
278 */
279
280 char *valptr; /* Pointer into value */
281
282
283 while (*value)
284 {
285 for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
286
287 if (*valptr)
288 *valptr++ = '\0';
289
290 if (!_cups_strcasecmp(value, "cancel-job") ||
291 !_cups_strcasecmp(value, "all"))
292 {
293 in_cancel_job = 1;
294 break;
295 }
296
297 for (value = valptr; _cups_isspace(*value); value ++);
298 }
299 }
300 else if (!_cups_strcasecmp(line, "</Limit>"))
301 {
302 in_cancel_job = 0;
303 }
304 else if (!_cups_strcasecmp(line, "Require") && in_cancel_job)
305 {
306 cancel_policy = 0;
307 }
308 else if (!_cups_strcasecmp(line, "<Location") && value)
309 {
310 in_admin_location = !_cups_strcasecmp(value, "/admin");
311 in_location = 1;
312 }
313 else if (!_cups_strcasecmp(line, "</Location>"))
314 {
315 in_admin_location = 0;
316 in_location = 0;
317 }
318 else if (!_cups_strcasecmp(line, "Allow") && value &&
319 _cups_strcasecmp(value, "localhost") &&
320 _cups_strcasecmp(value, "127.0.0.1")
321 #ifdef AF_LOCAL
322 && *value != '/'
323 #endif /* AF_LOCAL */
324 #ifdef AF_INET6
325 && strcmp(value, "::1")
326 #endif /* AF_INET6 */
327 )
328 {
329 if (in_admin_location)
330 remote_admin = 1;
331 else if (!_cups_strcasecmp(value, "all"))
332 remote_any = 1;
333 }
334 else if (line[0] != '<' && !in_location && !in_policy &&
335 _cups_strcasecmp(line, "Allow") &&
336 _cups_strcasecmp(line, "AuthType") &&
337 _cups_strcasecmp(line, "Deny") &&
338 _cups_strcasecmp(line, "Order") &&
339 _cups_strcasecmp(line, "Require") &&
340 _cups_strcasecmp(line, "Satisfy"))
341 cg->cupsd_num_settings = cupsAddOption(line, value,
342 cg->cupsd_num_settings,
343 &(cg->cupsd_settings));
344 }
345
346 cupsFileClose(cupsd);
347
348 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
349 debug_logging ? "1" : "0",
350 cg->cupsd_num_settings,
351 &(cg->cupsd_settings));
352
353 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
354 (remote_access && remote_admin) ?
355 "1" : "0",
356 cg->cupsd_num_settings,
357 &(cg->cupsd_settings));
358
359 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
360 remote_any ? "1" : "0",
361 cg->cupsd_num_settings,
362 &(cg->cupsd_settings));
363
364 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
365 (remote_access && browsing) ? "1" :
366 "0",
367 cg->cupsd_num_settings,
368 &(cg->cupsd_settings));
369
370 cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
371 cancel_policy ? "1" : "0",
372 cg->cupsd_num_settings,
373 &(cg->cupsd_settings));
374 }
375 else if (status != HTTP_STATUS_NOT_MODIFIED)
376 invalidate_cupsd_cache(cg);
377
378 /*
379 * Remove any temporary files and copy the settings array...
380 */
381
382 if (remote)
383 unlink(cupsdconf);
384
385 for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings;
386 i > 0;
387 i --, setting ++)
388 *num_settings = cupsAddOption(setting->name, setting->value,
389 *num_settings, settings);
390
391 return (cg->cupsd_num_settings > 0);
392 }
393
394
395 /*
396 * 'cupsAdminSetServerSettings()' - Set settings on the server.
397 *
398 * @since CUPS 1.3/macOS 10.5@
399 */
400
401 int /* O - 1 on success, 0 on failure */
402 cupsAdminSetServerSettings(
403 http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
404 int num_settings, /* I - Number of settings */
405 cups_option_t *settings) /* I - Settings */
406 {
407 int i; /* Looping var */
408 http_status_t status; /* GET/PUT status */
409 const char *server_port_env; /* SERVER_PORT env var */
410 int server_port; /* IPP port for server */
411 cups_file_t *cupsd; /* cupsd.conf file */
412 char cupsdconf[1024]; /* cupsd.conf filename */
413 int remote; /* Remote cupsd.conf file? */
414 char tempfile[1024]; /* Temporary new cupsd.conf */
415 cups_file_t *temp; /* Temporary file */
416 char line[1024], /* Line from cupsd.conf file */
417 *value; /* Value on line */
418 int linenum, /* Line number in file */
419 in_location, /* In a location section? */
420 in_policy, /* In a policy section? */
421 in_default_policy, /* In the default policy section? */
422 in_cancel_job, /* In a cancel-job section? */
423 in_admin_location, /* In the /admin location? */
424 in_conf_location, /* In the /admin/conf location? */
425 in_log_location, /* In the /admin/log location? */
426 in_root_location; /* In the / location? */
427 const char *val; /* Setting value */
428 int share_printers, /* Share local printers */
429 remote_admin, /* Remote administration allowed? */
430 remote_any, /* Remote access from anywhere? */
431 user_cancel_any, /* Cancel-job policy set? */
432 debug_logging; /* LogLevel debug set? */
433 int wrote_port_listen, /* Wrote the port/listen lines? */
434 wrote_browsing, /* Wrote the browsing lines? */
435 wrote_policy, /* Wrote the policy? */
436 wrote_loglevel, /* Wrote the LogLevel line? */
437 wrote_admin_location, /* Wrote the /admin location? */
438 wrote_conf_location, /* Wrote the /admin/conf location? */
439 wrote_log_location, /* Wrote the /admin/log location? */
440 wrote_root_location; /* Wrote the / location? */
441 int indent; /* Indentation */
442 int cupsd_num_settings; /* New number of settings */
443 int old_share_printers, /* Share local printers */
444 old_remote_admin, /* Remote administration allowed? */
445 old_remote_any, /* Remote access from anywhere? */
446 old_user_cancel_any, /* Cancel-job policy set? */
447 old_debug_logging; /* LogLevel debug set? */
448 cups_option_t *cupsd_settings, /* New settings */
449 *setting; /* Current setting */
450 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
451
452
453 /*
454 * Range check input...
455 */
456
457 if (!http)
458 http = _cupsConnect();
459
460 if (!http || !num_settings || !settings)
461 {
462 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
463
464 return (0);
465 }
466
467 /*
468 * Get the cupsd.conf file...
469 */
470
471 if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf),
472 &remote) == HTTP_STATUS_OK)
473 {
474 if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
475 {
476 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
477 return (0);
478 }
479 }
480 else
481 return (0);
482
483 /*
484 * Get current settings...
485 */
486
487 if (!cupsAdminGetServerSettings(http, &cupsd_num_settings,
488 &cupsd_settings))
489 return (0);
490
491 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings,
492 cupsd_settings)) != NULL)
493 old_debug_logging = atoi(val);
494 else
495 old_debug_logging = 0;
496
497 DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d",
498 old_debug_logging));
499
500 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings,
501 cupsd_settings)) != NULL)
502 old_remote_admin = atoi(val);
503 else
504 old_remote_admin = 0;
505
506 DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d",
507 old_remote_admin));
508
509 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings,
510 cupsd_settings)) != NULL)
511 old_remote_any = atoi(val);
512 else
513 old_remote_any = 0;
514
515 DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d",
516 old_remote_any));
517
518 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings,
519 cupsd_settings)) != NULL)
520 old_share_printers = atoi(val);
521 else
522 old_share_printers = 0;
523
524 DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d",
525 old_share_printers));
526
527 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings,
528 cupsd_settings)) != NULL)
529 old_user_cancel_any = atoi(val);
530 else
531 old_user_cancel_any = 0;
532
533 DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d",
534 old_user_cancel_any));
535
536 cupsFreeOptions(cupsd_num_settings, cupsd_settings);
537
538 /*
539 * Get basic settings...
540 */
541
542 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
543 settings)) != NULL)
544 {
545 debug_logging = atoi(val);
546
547 if (debug_logging == old_debug_logging)
548 {
549 /*
550 * No change to this setting...
551 */
552
553 debug_logging = -1;
554 }
555 }
556 else
557 debug_logging = -1;
558
559 DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d",
560 debug_logging));
561
562 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, settings)) != NULL)
563 {
564 remote_any = atoi(val);
565
566 if (remote_any == old_remote_any)
567 {
568 /*
569 * No change to this setting...
570 */
571
572 remote_any = -1;
573 }
574 }
575 else
576 remote_any = -1;
577
578 DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d", remote_any));
579
580 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
581 settings)) != NULL)
582 {
583 remote_admin = atoi(val);
584
585 if (remote_admin == old_remote_admin)
586 {
587 /*
588 * No change to this setting...
589 */
590
591 remote_admin = -1;
592 }
593 }
594 else
595 remote_admin = -1;
596
597 DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d",
598 remote_admin));
599
600 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
601 settings)) != NULL)
602 {
603 share_printers = atoi(val);
604
605 if (share_printers == old_share_printers)
606 {
607 /*
608 * No change to this setting...
609 */
610
611 share_printers = -1;
612 }
613 }
614 else
615 share_printers = -1;
616
617 DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d",
618 share_printers));
619
620 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
621 settings)) != NULL)
622 {
623 user_cancel_any = atoi(val);
624
625 if (user_cancel_any == old_user_cancel_any)
626 {
627 /*
628 * No change to this setting...
629 */
630
631 user_cancel_any = -1;
632 }
633 }
634 else
635 user_cancel_any = -1;
636
637 DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d",
638 user_cancel_any));
639
640 /*
641 * Create a temporary file for the new cupsd.conf file...
642 */
643
644 if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
645 {
646 cupsFileClose(cupsd);
647
648 if (remote)
649 unlink(cupsdconf);
650
651 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
652 return (0);
653 }
654
655 /*
656 * Copy the old file to the new, making changes along the way...
657 */
658
659 cupsd_num_settings = 0;
660 in_admin_location = 0;
661 in_cancel_job = 0;
662 in_conf_location = 0;
663 in_default_policy = 0;
664 in_location = 0;
665 in_log_location = 0;
666 in_policy = 0;
667 in_root_location = 0;
668 linenum = 0;
669 wrote_admin_location = 0;
670 wrote_browsing = 0;
671 wrote_conf_location = 0;
672 wrote_log_location = 0;
673 wrote_loglevel = 0;
674 wrote_policy = 0;
675 wrote_port_listen = 0;
676 wrote_root_location = 0;
677 indent = 0;
678
679 if ((server_port_env = getenv("SERVER_PORT")) != NULL)
680 {
681 if ((server_port = atoi(server_port_env)) <= 0)
682 server_port = ippPort();
683 }
684 else
685 server_port = ippPort();
686
687 if (server_port <= 0)
688 server_port = IPP_PORT;
689
690 while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
691 {
692 if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) &&
693 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
694 {
695 if (!wrote_port_listen)
696 {
697 wrote_port_listen = 1;
698
699 if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
700 {
701 cupsFilePuts(temp, "# Allow remote access\n");
702 cupsFilePrintf(temp, "Port %d\n", server_port);
703 }
704 else
705 {
706 cupsFilePuts(temp, "# Only listen for connections from the local "
707 "machine.\n");
708 cupsFilePrintf(temp, "Listen localhost:%d\n", server_port);
709 }
710
711 #ifdef CUPS_DEFAULT_DOMAINSOCKET
712 if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) &&
713 !access(CUPS_DEFAULT_DOMAINSOCKET, 0))
714 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
715 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
716 }
717 else if (value && value[0] == '/'
718 #ifdef CUPS_DEFAULT_DOMAINSOCKET
719 && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)
720 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
721 )
722 cupsFilePrintf(temp, "Listen %s\n", value);
723 }
724 else if ((!_cups_strcasecmp(line, "Browsing") ||
725 !_cups_strcasecmp(line, "BrowseLocalProtocols")) &&
726 share_printers >= 0)
727 {
728 if (!wrote_browsing)
729 {
730 int new_share_printers = (share_printers > 0 ||
731 (share_printers == -1 &&
732 old_share_printers > 0));
733
734 wrote_browsing = 1;
735
736 if (new_share_printers)
737 {
738 const char *localp = cupsGetOption("BrowseLocalProtocols",
739 num_settings, settings);
740
741 if (!localp || !localp[0])
742 localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings,
743 cupsd_settings);
744
745 cupsFilePuts(temp, "# Share local printers on the local network.\n");
746 cupsFilePuts(temp, "Browsing On\n");
747
748 if (!localp)
749 localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
750
751 cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp);
752
753 cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp,
754 cupsd_num_settings,
755 &cupsd_settings);
756 }
757 else
758 {
759 cupsFilePuts(temp, "# Disable printer sharing.\n");
760 cupsFilePuts(temp, "Browsing Off\n");
761 }
762 }
763 }
764 else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0)
765 {
766 wrote_loglevel = 1;
767
768 if (debug_logging)
769 {
770 cupsFilePuts(temp,
771 "# Show troubleshooting information in error_log.\n");
772 cupsFilePuts(temp, "LogLevel debug\n");
773 }
774 else
775 {
776 cupsFilePuts(temp, "# Show general information in error_log.\n");
777 cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n");
778 }
779 }
780 else if (!_cups_strcasecmp(line, "<Policy"))
781 {
782 in_default_policy = !_cups_strcasecmp(value, "default");
783 in_policy = 1;
784
785 cupsFilePrintf(temp, "%s %s>\n", line, value);
786 indent += 2;
787 }
788 else if (!_cups_strcasecmp(line, "</Policy>"))
789 {
790 indent -= 2;
791 if (!wrote_policy && in_default_policy)
792 {
793 wrote_policy = 1;
794
795 if (!user_cancel_any)
796 cupsFilePuts(temp, " # Only the owner or an administrator can "
797 "cancel a job...\n"
798 " <Limit Cancel-Job>\n"
799 " Order deny,allow\n"
800 " Require user @OWNER "
801 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
802 " </Limit>\n");
803 }
804
805 in_policy = 0;
806 in_default_policy = 0;
807
808 cupsFilePuts(temp, "</Policy>\n");
809 }
810 else if (!_cups_strcasecmp(line, "<Location"))
811 {
812 in_location = 1;
813 indent += 2;
814 if (!strcmp(value, "/admin"))
815 in_admin_location = 1;
816 else if (!strcmp(value, "/admin/conf"))
817 in_conf_location = 1;
818 else if (!strcmp(value, "/admin/log"))
819 in_log_location = 1;
820 else if (!strcmp(value, "/"))
821 in_root_location = 1;
822
823 cupsFilePrintf(temp, "%s %s>\n", line, value);
824 }
825 else if (!_cups_strcasecmp(line, "</Location>"))
826 {
827 in_location = 0;
828 indent -= 2;
829 if (in_admin_location && remote_admin >= 0)
830 {
831 wrote_admin_location = 1;
832
833 if (remote_admin)
834 cupsFilePuts(temp, " # Allow remote administration...\n");
835 else if (remote_admin == 0)
836 cupsFilePuts(temp, " # Restrict access to the admin pages...\n");
837
838 cupsFilePuts(temp, " Order allow,deny\n");
839
840 if (remote_admin)
841 cupsFilePrintf(temp, " Allow %s\n",
842 remote_any > 0 ? "all" : "@LOCAL");
843 }
844 else if (in_conf_location && remote_admin >= 0)
845 {
846 wrote_conf_location = 1;
847
848 if (remote_admin)
849 cupsFilePuts(temp, " # Allow remote access to the configuration "
850 "files...\n");
851 else
852 cupsFilePuts(temp, " # Restrict access to the configuration "
853 "files...\n");
854
855 cupsFilePuts(temp, " Order allow,deny\n");
856
857 if (remote_admin)
858 cupsFilePrintf(temp, " Allow %s\n",
859 remote_any > 0 ? "all" : "@LOCAL");
860 }
861 else if (in_log_location && remote_admin >= 0)
862 {
863 wrote_log_location = 1;
864
865 if (remote_admin)
866 cupsFilePuts(temp, " # Allow remote access to the log "
867 "files...\n");
868 else
869 cupsFilePuts(temp, " # Restrict access to the log "
870 "files...\n");
871
872 cupsFilePuts(temp, " Order allow,deny\n");
873
874 if (remote_admin)
875 cupsFilePrintf(temp, " Allow %s\n",
876 remote_any > 0 ? "all" : "@LOCAL");
877 }
878 else if (in_root_location &&
879 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
880 {
881 wrote_root_location = 1;
882
883 if (remote_admin > 0 && share_printers > 0)
884 cupsFilePuts(temp, " # Allow shared printing and remote "
885 "administration...\n");
886 else if (remote_admin > 0)
887 cupsFilePuts(temp, " # Allow remote administration...\n");
888 else if (share_printers > 0)
889 cupsFilePuts(temp, " # Allow shared printing...\n");
890 else if (remote_any > 0)
891 cupsFilePuts(temp, " # Allow remote access...\n");
892 else
893 cupsFilePuts(temp, " # Restrict access to the server...\n");
894
895 cupsFilePuts(temp, " Order allow,deny\n");
896
897 if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
898 cupsFilePrintf(temp, " Allow %s\n",
899 remote_any > 0 ? "all" : "@LOCAL");
900 }
901
902 in_admin_location = 0;
903 in_conf_location = 0;
904 in_log_location = 0;
905 in_root_location = 0;
906
907 cupsFilePuts(temp, "</Location>\n");
908 }
909 else if (!_cups_strcasecmp(line, "<Limit"))
910 {
911 if (in_default_policy)
912 {
913 /*
914 * See if the policy limit is for the Cancel-Job operation...
915 */
916
917 char *valptr; /* Pointer into value */
918
919
920 if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
921 {
922 /*
923 * Don't write anything for this limit section...
924 */
925
926 in_cancel_job = 2;
927 }
928 else
929 {
930 cupsFilePrintf(temp, "%*s%s", indent, "", line);
931
932 while (*value)
933 {
934 for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
935
936 if (*valptr)
937 *valptr++ = '\0';
938
939 if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
940 {
941 /*
942 * Write everything except for this definition...
943 */
944
945 in_cancel_job = 1;
946 }
947 else
948 cupsFilePrintf(temp, " %s", value);
949
950 for (value = valptr; _cups_isspace(*value); value ++);
951 }
952
953 cupsFilePuts(temp, ">\n");
954 }
955 }
956 else
957 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
958
959 indent += 2;
960 }
961 else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job)
962 {
963 indent -= 2;
964
965 if (in_cancel_job == 1)
966 cupsFilePuts(temp, " </Limit>\n");
967
968 wrote_policy = 1;
969
970 if (!user_cancel_any)
971 cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
972 "a job...\n"
973 " <Limit Cancel-Job>\n"
974 " Order deny,allow\n"
975 " Require user @OWNER "
976 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
977 " </Limit>\n");
978
979 in_cancel_job = 0;
980 }
981 else if ((((in_admin_location || in_conf_location || in_root_location) &&
982 (remote_admin >= 0 || remote_any >= 0)) ||
983 (in_root_location && share_printers >= 0)) &&
984 (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") ||
985 !_cups_strcasecmp(line, "Order")))
986 continue;
987 else if (in_cancel_job == 2)
988 continue;
989 else if (line[0] == '<')
990 {
991 if (value)
992 {
993 cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
994 indent += 2;
995 }
996 else
997 {
998 if (line[1] == '/')
999 indent -= 2;
1000
1001 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1002 }
1003 }
1004 else if (!in_policy && !in_location &&
1005 (val = cupsGetOption(line, num_settings, settings)) != NULL)
1006 {
1007 /*
1008 * Replace this directive's value with the new one...
1009 */
1010
1011 cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings,
1012 &cupsd_settings);
1013
1014 /*
1015 * Write the new value in its place, without indentation since we
1016 * only support setting root directives, not in sections...
1017 */
1018
1019 cupsFilePrintf(temp, "%s %s\n", line, val);
1020 }
1021 else if (value)
1022 {
1023 if (!in_policy && !in_location)
1024 {
1025 /*
1026 * Record the non-policy, non-location directives that we find
1027 * in the server settings, since we cache this info and record it
1028 * in cupsAdminGetServerSettings()...
1029 */
1030
1031 cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings,
1032 &cupsd_settings);
1033 }
1034
1035 cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
1036 }
1037 else
1038 cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1039 }
1040
1041 /*
1042 * Write any missing info...
1043 */
1044
1045 if (!wrote_browsing && share_printers >= 0)
1046 {
1047 if (share_printers > 0)
1048 {
1049 cupsFilePuts(temp, "# Share local printers on the local network.\n");
1050 cupsFilePuts(temp, "Browsing On\n");
1051 }
1052 else
1053 {
1054 cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
1055 cupsFilePuts(temp, "Browsing Off\n");
1056 }
1057 }
1058
1059 if (!wrote_loglevel && debug_logging >= 0)
1060 {
1061 if (debug_logging)
1062 {
1063 cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
1064 cupsFilePuts(temp, "LogLevel debug\n");
1065 }
1066 else
1067 {
1068 cupsFilePuts(temp, "# Show general information in error_log.\n");
1069 cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n");
1070 }
1071 }
1072
1073 if (!wrote_port_listen &&
1074 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1075 {
1076 if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1077 {
1078 cupsFilePuts(temp, "# Allow remote access\n");
1079 cupsFilePrintf(temp, "Port %d\n", ippPort());
1080 }
1081 else
1082 {
1083 cupsFilePuts(temp,
1084 "# Only listen for connections from the local machine.\n");
1085 cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
1086 }
1087
1088 #ifdef CUPS_DEFAULT_DOMAINSOCKET
1089 if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0))
1090 cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1091 #endif /* CUPS_DEFAULT_DOMAINSOCKET */
1092 }
1093
1094 if (!wrote_root_location &&
1095 (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1096 {
1097 if (remote_admin > 0 && share_printers > 0)
1098 cupsFilePuts(temp,
1099 "# Allow shared printing and remote administration...\n");
1100 else if (remote_admin > 0)
1101 cupsFilePuts(temp, "# Allow remote administration...\n");
1102 else if (share_printers > 0)
1103 cupsFilePuts(temp, "# Allow shared printing...\n");
1104 else if (remote_any > 0)
1105 cupsFilePuts(temp, "# Allow remote access...\n");
1106 else
1107 cupsFilePuts(temp, "# Restrict access to the server...\n");
1108
1109 cupsFilePuts(temp, "<Location />\n"
1110 " Order allow,deny\n");
1111
1112 if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1113 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1114
1115 cupsFilePuts(temp, "</Location>\n");
1116 }
1117
1118 if (!wrote_admin_location && remote_admin >= 0)
1119 {
1120 if (remote_admin)
1121 cupsFilePuts(temp, "# Allow remote administration...\n");
1122 else
1123 cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
1124
1125 cupsFilePuts(temp, "<Location /admin>\n"
1126 " Order allow,deny\n");
1127
1128 if (remote_admin)
1129 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1130
1131 cupsFilePuts(temp, "</Location>\n");
1132 }
1133
1134 if (!wrote_conf_location && remote_admin >= 0)
1135 {
1136 if (remote_admin)
1137 cupsFilePuts(temp,
1138 "# Allow remote access to the configuration files...\n");
1139 else
1140 cupsFilePuts(temp, "# Restrict access to the configuration files...\n");
1141
1142 cupsFilePuts(temp, "<Location /admin/conf>\n"
1143 " AuthType Default\n"
1144 " Require user @SYSTEM\n"
1145 " Order allow,deny\n");
1146
1147 if (remote_admin)
1148 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1149
1150 cupsFilePuts(temp, "</Location>\n");
1151 }
1152
1153 if (!wrote_log_location && remote_admin >= 0)
1154 {
1155 if (remote_admin)
1156 cupsFilePuts(temp,
1157 "# Allow remote access to the log files...\n");
1158 else
1159 cupsFilePuts(temp, "# Restrict access to the log files...\n");
1160
1161 cupsFilePuts(temp, "<Location /admin/log>\n"
1162 " AuthType Default\n"
1163 " Require user @SYSTEM\n"
1164 " Order allow,deny\n");
1165
1166 if (remote_admin)
1167 cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1168
1169 cupsFilePuts(temp, "</Location>\n");
1170 }
1171
1172 if (!wrote_policy && user_cancel_any >= 0)
1173 {
1174 cupsFilePuts(temp, "<Policy default>\n"
1175 " # Job-related operations must be done by the owner "
1176 "or an administrator...\n"
1177 " <Limit Send-Document Send-URI Hold-Job Release-Job "
1178 "Restart-Job Purge-Jobs Set-Job-Attributes "
1179 "Create-Job-Subscription Renew-Subscription "
1180 "Cancel-Subscription Get-Notifications Reprocess-Job "
1181 "Cancel-Current-Job Suspend-Current-Job Resume-Job "
1182 "CUPS-Move-Job>\n"
1183 " Require user @OWNER @SYSTEM\n"
1184 " Order deny,allow\n"
1185 " </Limit>\n"
1186 " # All administration operations require an "
1187 "administrator to authenticate...\n"
1188 " <Limit Pause-Printer Resume-Printer "
1189 "Set-Printer-Attributes Enable-Printer "
1190 "Disable-Printer Pause-Printer-After-Current-Job "
1191 "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
1192 "Activate-Printer Restart-Printer Shutdown-Printer "
1193 "Startup-Printer Promote-Job Schedule-Job-After "
1194 "CUPS-Add-Printer CUPS-Delete-Printer "
1195 "CUPS-Add-Class CUPS-Delete-Class "
1196 "CUPS-Accept-Jobs CUPS-Reject-Jobs "
1197 "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
1198 " AuthType Default\n"
1199 " Require user @SYSTEM\n"
1200 " Order deny,allow\n"
1201 "</Limit>\n");
1202
1203 if (!user_cancel_any)
1204 cupsFilePuts(temp, " # Only the owner or an administrator can cancel "
1205 "a job...\n"
1206 " <Limit Cancel-Job>\n"
1207 " Order deny,allow\n"
1208 " Require user @OWNER "
1209 CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
1210 " </Limit>\n");
1211
1212 cupsFilePuts(temp, " <Limit All>\n"
1213 " Order deny,allow\n"
1214 " </Limit>\n"
1215 "</Policy>\n");
1216 }
1217
1218 for (i = num_settings, setting = settings; i > 0; i --, setting ++)
1219 if (setting->name[0] != '_' &&
1220 _cups_strcasecmp(setting->name, "Listen") &&
1221 _cups_strcasecmp(setting->name, "Port") &&
1222 !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings))
1223 {
1224 /*
1225 * Add this directive to the list of directives we have written...
1226 */
1227
1228 cupsd_num_settings = cupsAddOption(setting->name, setting->value,
1229 cupsd_num_settings, &cupsd_settings);
1230
1231 /*
1232 * Write the new value, without indentation since we only support
1233 * setting root directives, not in sections...
1234 */
1235
1236 cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value);
1237 }
1238
1239 cupsFileClose(cupsd);
1240 cupsFileClose(temp);
1241
1242 /*
1243 * Upload the configuration file to the server...
1244 */
1245
1246 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1247
1248 if (status == HTTP_STATUS_CREATED)
1249 {
1250 /*
1251 * Updated OK, add the basic settings...
1252 */
1253
1254 if (debug_logging >= 0)
1255 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1256 debug_logging ? "1" : "0",
1257 cupsd_num_settings, &cupsd_settings);
1258 else
1259 cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1260 old_debug_logging ? "1" : "0",
1261 cupsd_num_settings, &cupsd_settings);
1262
1263 if (remote_admin >= 0)
1264 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1265 remote_admin ? "1" : "0",
1266 cupsd_num_settings, &cupsd_settings);
1267 else
1268 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1269 old_remote_admin ? "1" : "0",
1270 cupsd_num_settings, &cupsd_settings);
1271
1272 if (remote_any >= 0)
1273 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1274 remote_any ? "1" : "0",
1275 cupsd_num_settings, &cupsd_settings);
1276 else
1277 cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1278 old_remote_any ? "1" : "0",
1279 cupsd_num_settings, &cupsd_settings);
1280
1281 if (share_printers >= 0)
1282 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1283 share_printers ? "1" : "0",
1284 cupsd_num_settings, &cupsd_settings);
1285 else
1286 cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1287 old_share_printers ? "1" : "0",
1288 cupsd_num_settings, &cupsd_settings);
1289
1290 if (user_cancel_any >= 0)
1291 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1292 user_cancel_any ? "1" : "0",
1293 cupsd_num_settings, &cupsd_settings);
1294 else
1295 cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1296 old_user_cancel_any ? "1" : "0",
1297 cupsd_num_settings, &cupsd_settings);
1298
1299 /*
1300 * Save the new values...
1301 */
1302
1303 invalidate_cupsd_cache(cg);
1304
1305 cg->cupsd_num_settings = cupsd_num_settings;
1306 cg->cupsd_settings = cupsd_settings;
1307 cg->cupsd_update = time(NULL);
1308
1309 httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
1310 }
1311 else
1312 cupsFreeOptions(cupsd_num_settings, cupsd_settings);
1313
1314 /*
1315 * Remote our temp files and return...
1316 */
1317
1318 if (remote)
1319 unlink(cupsdconf);
1320
1321 unlink(tempfile);
1322
1323 return (status == HTTP_STATUS_CREATED);
1324 }
1325
1326
1327 /*
1328 * 'get_cupsd_conf()' - Get the current cupsd.conf file.
1329 */
1330
1331 static http_status_t /* O - Status of request */
1332 get_cupsd_conf(
1333 http_t *http, /* I - Connection to server */
1334 _cups_globals_t *cg, /* I - Global data */
1335 time_t last_update, /* I - Last update time for file */
1336 char *name, /* I - Filename buffer */
1337 size_t namesize, /* I - Size of filename buffer */
1338 int *remote) /* O - Remote file? */
1339 {
1340 int fd; /* Temporary file descriptor */
1341 #ifndef _WIN32
1342 struct stat info; /* cupsd.conf file information */
1343 #endif /* _WIN32 */
1344 http_status_t status; /* Status of getting cupsd.conf */
1345 char host[HTTP_MAX_HOST]; /* Hostname for connection */
1346
1347
1348 /*
1349 * See if we already have the data we need...
1350 */
1351
1352 httpGetHostname(http, host, sizeof(host));
1353
1354 if (_cups_strcasecmp(cg->cupsd_hostname, host))
1355 invalidate_cupsd_cache(cg);
1356
1357 snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot);
1358 *remote = 0;
1359
1360 #ifndef _WIN32
1361 if (!_cups_strcasecmp(host, "localhost") && !access(name, R_OK))
1362 {
1363 /*
1364 * Read the local file rather than using HTTP...
1365 */
1366
1367 if (stat(name, &info))
1368 {
1369 char message[1024]; /* Message string */
1370
1371
1372 snprintf(message, sizeof(message),
1373 _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
1374 name, strerror(errno));
1375 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
1376
1377 *name = '\0';
1378
1379 return (HTTP_STATUS_SERVER_ERROR);
1380 }
1381 else if (last_update && info.st_mtime <= last_update)
1382 status = HTTP_STATUS_NOT_MODIFIED;
1383 else
1384 status = HTTP_STATUS_OK;
1385 }
1386 else
1387 #endif /* !_WIN32 */
1388 {
1389 /*
1390 * Read cupsd.conf via a HTTP GET request...
1391 */
1392
1393 if ((fd = cupsTempFd(name, (int)namesize)) < 0)
1394 {
1395 *name = '\0';
1396
1397 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
1398
1399 invalidate_cupsd_cache(cg);
1400
1401 return (HTTP_STATUS_SERVER_ERROR);
1402 }
1403
1404 *remote = 1;
1405
1406 httpClearFields(http);
1407
1408 if (last_update)
1409 httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE,
1410 httpGetDateString(last_update));
1411
1412 status = cupsGetFd(http, "/admin/conf/cupsd.conf", fd);
1413
1414 close(fd);
1415
1416 if (status != HTTP_STATUS_OK)
1417 {
1418 unlink(name);
1419 *name = '\0';
1420 }
1421 }
1422
1423 return (status);
1424 }
1425
1426
1427 /*
1428 * 'invalidate_cupsd_cache()' - Invalidate the cached cupsd.conf settings.
1429 */
1430
1431 static void
1432 invalidate_cupsd_cache(
1433 _cups_globals_t *cg) /* I - Global data */
1434 {
1435 cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
1436
1437 cg->cupsd_hostname[0] = '\0';
1438 cg->cupsd_update = 0;
1439 cg->cupsd_num_settings = 0;
1440 cg->cupsd_settings = NULL;
1441 }