From 90948a51f85163941b7ff8e291ffd0b6aaf3915d Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Tue, 5 Nov 2024 03:52:45 +0300 Subject: [PATCH] import cups-browsed-2.0.0-8.el10 --- ...enerate-PPD-for-remote-raw-queues-44.patch | 44 + ...for-legacy-CUPS-browsing-and-for-LDA.patch | 2390 +++++++++++++++++ SPECS/cups-browsed.spec | 22 +- 3 files changed, 2455 insertions(+), 1 deletion(-) create mode 100644 SOURCES/0001-Do-not-generate-PPD-for-remote-raw-queues-44.patch create mode 100644 SOURCES/0001-Removed-support-for-legacy-CUPS-browsing-and-for-LDA.patch diff --git a/SOURCES/0001-Do-not-generate-PPD-for-remote-raw-queues-44.patch b/SOURCES/0001-Do-not-generate-PPD-for-remote-raw-queues-44.patch new file mode 100644 index 0000000..0b3f3e1 --- /dev/null +++ b/SOURCES/0001-Do-not-generate-PPD-for-remote-raw-queues-44.patch @@ -0,0 +1,44 @@ +diff --git a/daemon/cups-browsed.c b/daemon/cups-browsed.c +index 8c5349f..5496970 100644 +--- a/daemon/cups-browsed.c ++++ b/daemon/cups-browsed.c +@@ -6736,6 +6736,9 @@ create_remote_printer_entry (const char *queue_name, + p->queue_name, p->uri); + goto fail; + } ++ ++ attr = ippFindAttribute(p->prattrs, "printer-make-and-model", IPP_TAG_TEXT); ++ p->make_model = attr ? strdup(ippGetString(attr, 0, NULL)) : NULL; + } + } + else +@@ -7520,7 +7523,7 @@ create_queue(void* arg) + debug_printf("Generated Default Attributes for local queue %s\n", + p->queue_name); + } +- if (ppdfile == NULL) ++ if (ppdfile == NULL && make_model && strcmp(make_model, "Local Raw Printer")) + { + // If we do not want CUPS-generated PPDs or we cannot obtain a + // CUPS-generated PPD, for example if CUPS does not create a +@@ -7712,7 +7715,7 @@ create_queue(void* arg) + debug_printf("Generated Default Attributes for local queue %s\n", + p->queue_name); + } +- if (ppdfile == NULL) ++ if (ppdfile == NULL && make_model && strcmp(make_model, "Local Raw Printer")) + { + // If we do not want CUPS-generated PPDs or we cannot obtain a + // CUPS-generated PPD, for example if CUPS does not create a +@@ -7983,6 +7986,11 @@ create_queue(void* arg) + } + ppdfile = strdup(buf); + } ++ else ++ { ++ // No PPD - define nickname as make_model for remote raw queue ++ p->nickname = p->make_model ? strdup(p->make_model) : strdup("Local Raw Printer"); ++ } + + // Create a new CUPS queue or modify the existing queue + request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); diff --git a/SOURCES/0001-Removed-support-for-legacy-CUPS-browsing-and-for-LDA.patch b/SOURCES/0001-Removed-support-for-legacy-CUPS-browsing-and-for-LDA.patch new file mode 100644 index 0000000..bac9196 --- /dev/null +++ b/SOURCES/0001-Removed-support-for-legacy-CUPS-browsing-and-for-LDA.patch @@ -0,0 +1,2390 @@ +From 1d1072a0de573b7850958df614e9ec5b73ea0e0d Mon Sep 17 00:00:00 2001 +From: Till Kamppeter +Date: Tue, 1 Oct 2024 00:59:58 +0200 +Subject: [PATCH] Removed support for legacy CUPS browsing and for LDAP + +Legacy CUPS browsing is not needed any more. this functionality got +removed from CUPS with version 1.6, more than a decade ago. In +cups-browsed it was implemented as a legacy support layer for servers +or clients running long-term-support enterprise distributions still +using CUPS 1.5.x or older. Now the support life of all these +distributions should have expired and so this legacy support by +cups-browsed is not needed any more. + +In addition, the legacy CUPS browsing implementation in cups-browsed +was listening for UDP packaets on port 631 and by default it accepted +packets from any source, making it easy for attackers to set up forged +printers which could make use of vulnerabilities of CUPS or just find +out about the identity and properties of clients. This is +CVE-2024-47176: + + https://ubuntu.com/security/CVE-2024-47176 + https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8 + https://openprinting.github.io/OpenPrinting-News-Flash-cups-browsed-Remote-Code-Execution-vulnerability/ + +The removal of the legacy CUPS browsing support removes also this +vulnerability. + +The LDAP implementation in cups-browsed does not follow the LDAP +printer schema RFC 7612 and is therefore of very limited use. +--- + INSTALL | 3 +- + README.md | 53 +- + configure.ac | 46 +- + daemon/cups-browsed.8 | 38 +- + daemon/cups-browsed.c | 1675 ++--------------------------------- + daemon/cups-browsed.conf.5 | 43 +- + daemon/cups-browsed.conf.in | 27 +- + test/run-tests.sh | 4 +- + 8 files changed, 138 insertions(+), 1751 deletions(-) + +diff --git a/INSTALL b/INSTALL +index 7c5d5941..e48305d2 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -111,5 +111,4 @@ PACKAGING THE SOFTWARE FOR OPERATING SYSTEM DISTRIBUTIONS + `--enable-auto-setup-driverless-only` then. + + Otherwise cups-browsed is only needed for more advanced setups, +- like printer clusters or support for legacy CUPS (< 1.6.x) on +- remote servers or clients. ++ like printer clusters. +diff --git a/README.md b/README.md +index fbdcd186..ee4ee88d 100644 +--- a/README.md ++++ b/README.md +@@ -26,15 +26,6 @@ cups-browsed has the following functionality: + several print dialogs use old CUPS APIs and therefore require + permanent local queues to see such printers. + +-- Auto-discover shared printers on remote CUPS servers running CUPS +- 1.5.x or older via legacy CUPS browsing. This is intended for +- settings with print servers running long-term-support enterprise +- distributions. +- +-- Broadcast shared local printers using legacy CUPS browsing (of CUPS +- 1.5.x) for settings with printing clients running long-term-support +- enterprise distributions. +- + - Creating printer clusters where jobs are printed to one single queue + and get automatically passed on to a suitable member printer. + +@@ -63,8 +54,8 @@ cups-browsed has the following functionality: + + - Highly configurable: Which printers are considered? For which type + of printers queues are created? Cluster types and member printers? +- which names auto-created queues should get? DNS-SD and/or legacy +- browsing? ... ++ which names auto-created queues should get? DNS-SD and/or ++ BrowsePoll? ... + + - Multi-threading allows several tasks to be done in parallel and + assures responsiveness of the daemon when there is a large amount of +@@ -154,43 +145,33 @@ Most of this is still valid for the current cups-browsed. + ### HELPER DAEMON FOR BROWSING REMOTE CUPS PRINTERS AND IPP NETWORK PRINTERS + + From version 1.6.0 on in CUPS the CUPS broadcasting/browsing +-facility was dropped, in favour of Bonjour-based broadcasting of +-shared printers. This is done as Bonjour broadcasting of shared ++facility was dropped, in favour of DNS-SD-based broadcasting of ++shared printers. This is done as DNS-SD broadcasting of shared + printers is a standard, established by the PWG (Printing Working + Group, http://www.pwg.org/), and most other network services + (shared file systems, shared media files/streams, remote desktop +-services, ...) are also broadcasted via Bonjour. ++services, ...) are also broadcasted via DNS-SD. + + Problem is that CUPS only broadcasts its shared printers but does + not browse broadcasts of other CUPS servers to make the shared + remote printers available locally without any configuration + efforts. This is a regression compared to the old CUPS + broadcasting/browsing. The intention of CUPS upstream is that the +-application's print dialogs browse the Bonjour broadcasts as an ++application's print dialogs browse the DNS-SD broadcasts as an + AirPrint-capable iPhone does, but it will take its time until all + toolkit developers add the needed functionality, and programs + using old toolkits or no toolkits at all, or the command line stay + uncovered. + +-The solution is cups-browsed, a helper daemon running in parallel +-to the CUPS daemon which listens to Bonjour broadcasts of shared +-CUPS printers on remote machines in the local network via Avahi, +-and can also listen for (and send) CUPS Browsing broadcasts. For +-each reported remote printer it creates a local raw queue pointing +-to the remote printer so that the printer appears in local print +-dialogs and is also available for printing via the command +-line. As with the former CUPS broadcasting/browsing with this +-queue the driver on the server is used and the local print dialogs +-give access to all options of the server-side printer driver. +- +-Note that CUPS broadcasting/browsing is available for legacy +-support, to let the local CUPS daemon work seamlessly together +-with remote CUPS daemons of version 1.5.x and older which only +-support CUPS broadcasting/browsing. In networks with only CUPS +-1.6.x servers (or Ubuntu or Fedora/Red Hat servers with CUPS +-1.5.x) please use the native Bonjour broadcasting of your servers +-and cups-browsed, configured for Bonjour browsing only on the +-clients. ++The solution is cups-browsed, a helper daemon running in parallel to ++the CUPS daemon which listens to DNS-SD broadcasts of shared CUPS ++printers on remote machines in the local network via Avahi. For each ++reported remote printer it creates a local raw queue pointing to the ++remote printer so that the printer appears in local print dialogs and ++is also available for printing via the command line. As with the ++former CUPS broadcasting/browsing with this queue the driver on the ++server is used and the local print dialogs give access to all options ++of the server-side printer driver. + + Also high availability with redundant print servers and load + balancing is supported. If there is more than one server providing +@@ -301,7 +282,7 @@ up. cups-browsed is also robust against any shutdown and restart + of avahi-daemon. + + Here is some info on how cups-browsed works internally (first concept of a +-daemon which does only Bonjour browsing): ++daemon which does only DNS-SD browsing): + + - Daemon start + o Wait for CUPS daemon if it is not running +@@ -357,7 +338,7 @@ appears, create new queue as @]) +- AC_CHECK_LIB([ldap], [ldapssl_init], +- AC_DEFINE([HAVE_LDAP_SSL], [], [If LDAP has SSL/TLS support enabled]))])] +- ) +- AC_CHECK_LIB([ldap], [ldap_set_rebind_proc], AC_DEFINE([HAVE_LDAP_REBIND_PROC], [], [If libldap implements ldap_set_rebind_proc])) +- ]) +- +-fi +- + PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.30.2]) + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) +@@ -487,7 +443,7 @@ Environment settings: + Build configuration: + cups-config: ${with_cups_config} + init directory: ${INITDDIR} +- cups dom socket: ${CUPS_DEFAULT_DOMAINSOCKET} ++ cups domain socket: ${CUPS_DEFAULT_DOMAINSOCKET} + avahi: ${enable_avahi} + browsing: ${with_browseremoteprotocols} + local queue naming for remote CUPS queues: ${REMOTE_CUPS_LOCAL_QUEUE_NAMING} +diff --git a/daemon/cups-browsed.8 b/daemon/cups-browsed.8 +index 73c2f686..6eb713bf 100644 +--- a/daemon/cups-browsed.8 ++++ b/daemon/cups-browsed.8 +@@ -16,20 +16,14 @@ + .fam T + .fi + .SH DESCRIPTION +-\fBcups-browsed\fP has four independently switchable functions: ++\fBcups-browsed\fP has two independently switchable functions: + .IP 1. 4 +-Browse Bonjour broadcasts of remote printers and create/remove local +-raw queues pointing to these printers. ++Browse DNS-SD broadcasts of remote printers and create/remove local ++CUPS queues pointing to these printers. + .IP 2. 4 +-Browse CUPS broadcasts of remote printers and create/remove local raw +-queues pointing to these printers. +-.IP 3. 4 +-Browse an LDAP server for printers and create/remove local raw +-queues pointing to these printers. +-.IP 4. 4 +-Broadcast local queues with the CUPS protocol. ++Find shared printers on given CUPS servers and create local CUPS queues ++pointing to them. + .PP +-Note that 2. and 4. are only to allow communication with legacy CUPS servers (1.5.x or older) on the remote machine(s). The standard method to broadcast for shared/network printers to broadcast their presence is Bonjour. The CUPS broadcasting/browsing protocol is deprecated. + + cups-browsed can be run permanently (from system boot to shutdown) or on-demand (for example to save resources on mobile devices). For running it on-demand an auto-shutdown feature can be activated to let cups-browsed terminate when it does not have queues any more to take care of. + +@@ -76,28 +70,8 @@ Display usage and version info and do not start the daemon. + \fISIGUSR2\f1: Switches cups-browsed into auto shutdown mode. + + .SH NOTES +-Please take references to cups 1.6.x to include newer versions. +-Similarly, cups 1.5.x is intended to encompass older versions too. +-.PP +-In environments with only cups 1.6.x servers and clients (plus +-\fBcups-browsed\fP on either server or client or both) the function described in 1. +-enables the automatic discovery of remote queues and their display in +-printing dialogues of applications and with command line tools. +-.PP +-The facility provided by 3. allows printers that are registered in an LDAP +-server to be added as local queues. CUPS servers 1.5.x are able to automatically +-register printers in LDAP. The facility provided by \fBcups-browsed\fP allows +-a filter string to further limit the printers that are browsed from LDAP. +-.PP +-The facility provided by 4. means that servers running cups 1.6.x plus +-\fBcups-browsed\fP can broadcast their local queues so that clients with cups +-1.5.x get these queues automatically available. The outcome of 2. is +-that clients running cups 1.6.x plus \fBcups-browsed\fP can use the CUPS +-broadcasts from servers with cups 1.5.x. As with browsing of Bonjour +-broadcasts, the created local raw queues are available to applications +-and command line tools. +-.PP + This manual page was written for the Debian Project, but it may be used by others. ++ + .SH SEE ALSO + + \fBcups-browsed.conf\fP(5) +diff --git a/daemon/cups-browsed.c b/daemon/cups-browsed.c +index 828ca94c..31122ec5 100644 +--- a/daemon/cups-browsed.c ++++ b/daemon/cups-browsed.c +@@ -47,72 +47,6 @@ + + #include + +- +-#ifdef HAVE_LDAP +-# ifdef __sun +-# include +-# endif // __sun +-# include +-# ifdef HAVE_LDAP_SSL_H +-# include +-# endif // HAVE_LDAP_SSL_H +-#endif // HAVE_LDAP +- +- +-#ifdef HAVE_LDAP +-LDAP *BrowseLDAPHandle = NULL; +- // Handle to LDAP server +-char *BrowseLDAPBindDN = NULL, +- // LDAP login DN +- *BrowseLDAPDN = NULL, +- // LDAP search DN +- *BrowseLDAPPassword = NULL, +- // LDAP login password +- *BrowseLDAPServer = NULL, +- // LDAP server to use +- *BrowseLDAPFilter = NULL; +- // LDAP query filter +-int BrowseLDAPUpdate = TRUE, +- // enables LDAP updates +- BrowseLDAPInitialised = FALSE; +- // the init stuff has been done +-# ifdef HAVE_LDAP_SSL +-char *BrowseLDAPCACertFile = NULL; +- // LDAP CA CERT file to use +-# endif // HAVE_LDAP_SSL +-#endif // HAVE_LDAP +- +- +-#ifdef HAVE_LDAP +-#define LDAP_BROWSE_FILTER "(objectclass=cupsPrinter)" +-static LDAP *ldap_new_connection(void); +-static LDAP *ldap_reconnect(void); +-static void ldap_disconnect(LDAP *ld); +-static int ldap_search_rec(LDAP *ld, char *base, int scope, +- char *filter, char *attrs[], +- int attrsonly, LDAPMessage **res); +-static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry, +- char *attr, char *retval, +- unsigned long maxsize); +-static void ldap_freeres(LDAPMessage *entry); +-# ifdef HAVE_LDAP_REBIND_PROC +-# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-static int ldap_rebind_proc(LDAP *RebindLDAPHandle, +- LDAP_CONST char *refsp, +- ber_tag_t request, +- ber_int_t msgid, +- void *params); +-# else +-static int ldap_rebind_proc(LDAP *RebindLDAPHandle, +- char **dnp, +- char **passwdp, +- int *authmethodp, +- int freeit, +- void *arg); +-# endif // defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-# endif // HAVE_LDAP_REBIND_PROC +-#endif // HAVE_LDAP +- + #include + #include + #include +@@ -291,18 +225,6 @@ typedef struct local_printer_s { + gboolean cups_browsed_controlled; + } local_printer_t; + +-// Browse data to send for local printer +-typedef struct browse_data_s +-{ +- int type; +- int state; +- char *uri; +- char *location; +- char *info; +- char *make_model; +- char *browse_options; +-} browse_data_t; +- + // Data structure for manual definition of load-balancing clusters + typedef struct cluster_s + { +@@ -439,8 +361,6 @@ static browsepoll_t *local_printers_context = NULL; + static http_t *local_conn = NULL; + static gboolean inhibit_local_printers_update = FALSE; + +-static GList *browse_data = NULL; +- + static CupsNotifier *cups_notifier = NULL; + + static GMainLoop *gmainloop = NULL; +@@ -450,23 +370,10 @@ static AvahiClient *client = NULL; + static AvahiServiceBrowser *sb1 = NULL, *sb2 = NULL; + static int avahi_present = 0; + #endif // HAVE_AVAHI +-#ifdef HAVE_LDAP +-static const char * const ldap_attrs[] =// CUPS LDAP attributes +- { +- "printerDescription", +- "printerLocation", +- "printerMakeAndModel", +- "printerType", +- "printerURI", +- NULL +- }; +-#endif // HAVE_LDAP + static guint queues_timer_id = 0; + static int browsesocket = -1; + + #define BROWSE_DNSSD (1<<0) +-#define BROWSE_CUPS (1<<1) +-#define BROWSE_LDAP (1<<2) + static unsigned int BrowseLocalProtocols = 0; + static unsigned int BrowseRemoteProtocols = BROWSE_DNSSD; + static unsigned int BrowseInterval = 60; +@@ -4113,1087 +4020,106 @@ get_local_printers (void) + g_hash_table_insert (local_printers, + g_ascii_strdown (dest->name, -1), + printer); +- } +- +- cupsFreeDests (num_dests, dests); +- +- pthread_rwlock_unlock(&lock); +-} +- +- +-static browse_data_t * +-new_browse_data (int type, int state, const gchar *uri, +- const gchar *location, const gchar *info, +- const gchar *make_model, const gchar *browse_options) +-{ +- browse_data_t *data = g_malloc (sizeof (browse_data_t)); +- data->type = type; +- data->state = state; +- data->uri = g_strdup (uri); +- data->location = g_strdup (location); +- data->info = g_strdup (info); +- data->make_model = g_strdup (make_model); +- data->browse_options = g_strdup (browse_options); +- return (data); +-} +- +- +-static void +-browse_data_free (gpointer data) +-{ +- browse_data_t *bdata = data; +- debug_printf("browse_data_free() in THREAD %ld\n", pthread_self()); +- g_free (bdata->uri); +- g_free (bdata->location); +- g_free (bdata->info); +- g_free (bdata->make_model); +- g_free (bdata->browse_options); +- g_free (bdata); +-} +- +- +-static void +-prepare_browse_data (void) +-{ +- static const char * const rattrs[] = { "printer-type", +- "printer-state", +- "printer-uri-supported", +- "printer-info", +- "printer-location", +- "printer-make-and-model", +- "auth-info-required", +- "printer-uuid", +- "job-template" }; +- ipp_t *request, *response = NULL; +- ipp_attribute_t *attr; +- http_t *conn = NULL; +- GString *browse_options = NULL; +- +- conn = http_connect_local (); +- +- if (conn == NULL) +- { +- debug_printf("Browse send failed to connect to localhost\n"); +- goto fail; +- } +- +- request = ippNewRequest(CUPS_GET_PRINTERS); +- ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, +- "requested-attributes", sizeof (rattrs) / sizeof (rattrs[0]), +- NULL, rattrs); +- ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, +- "requesting-user-name", NULL, cupsUser ()); +- +- debug_printf("preparing browse data\n"); +- response = cupsDoRequest (conn, request, "/"); +- if (cupsLastError() > IPP_STATUS_OK_EVENTS_COMPLETE) +- { +- debug_printf("browse send failed for localhost: %s\n", +- cupsLastErrorString ()); +- goto fail; +- } +- +- g_list_free_full (browse_data, browse_data_free); +- browse_data = NULL; +- for (attr = ippFirstAttribute(response); attr; +- attr = ippNextAttribute(response)) +- { +- int type = -1, state = -1; +- const char *uri = NULL; +- gchar *location = NULL; +- gchar *info = NULL; +- gchar *make_model = NULL; +- browse_options = g_string_new (""); +- +- // Skip any non-printer attributes +- while (attr && ippGetGroupTag(attr) != IPP_TAG_PRINTER) +- attr = ippNextAttribute(response); +- +- if (!attr) +- break; +- +- while (attr && ippGetGroupTag(attr) == IPP_TAG_PRINTER) +- { +- const char *attrname = ippGetName(attr); +- int value_tag = ippGetValueTag(attr); +- +- if (!strcasecmp(attrname, "printer-type") && +- value_tag == IPP_TAG_ENUM) +- { +- type = ippGetInteger(attr, 0); +- if (type & CUPS_PRINTER_NOT_SHARED) +- { +- // Skip CUPS queues not marked as shared +- state = -1; +- type = -1; +- break; +- } +- } +- else if (!strcasecmp(attrname, "printer-state") && +- value_tag == IPP_TAG_ENUM) +- state = ippGetInteger(attr, 0); +- else if (!strcasecmp(attrname, "printer-uri-supported") && +- value_tag == IPP_TAG_URI) +- uri = ippGetString(attr, 0, NULL); +- else if (!strcasecmp(attrname, "printer-location") && +- value_tag == IPP_TAG_TEXT) +- { +- // Remove quotes +- gchar **tokens = g_strsplit (ippGetString(attr, 0, NULL), "\"", -1); +- location = g_strjoinv ("", tokens); +- g_strfreev (tokens); +- } +- else if (!strcasecmp(attrname, "printer-info") && +- value_tag == IPP_TAG_TEXT) +- { +- // Remove quotes +- gchar **tokens = g_strsplit (ippGetString(attr, 0, NULL), "\"", -1); +- info = g_strjoinv ("", tokens); +- g_strfreev (tokens); +- } +- else if (!strcasecmp(attrname, "printer-make-and-model") && +- value_tag == IPP_TAG_TEXT) +- { +- // Remove quotes +- gchar **tokens = g_strsplit (ippGetString(attr, 0, NULL), "\"", -1); +- make_model = g_strjoinv ("", tokens); +- g_strfreev (tokens); +- } +- else if (!strcasecmp(attrname, "auth-info-required") && +- value_tag == IPP_TAG_KEYWORD) +- { +- if (strcasecmp (ippGetString(attr, 0, NULL), "none")) +- g_string_append_printf (browse_options, "auth-info-required=%s ", +- ippGetString(attr, 0, NULL)); +- } +- else if (!strcasecmp(attrname, "printer-uuid") && +- value_tag == IPP_TAG_URI) +- g_string_append_printf (browse_options, "uuid=%s ", +- ippGetString(attr, 0, NULL)); +- else if (!strcasecmp(attrname, "job-sheets-default") && +- value_tag == IPP_TAG_NAME && +- ippGetCount(attr) == 2) +- g_string_append_printf (browse_options, "job-sheets=%s,%s ", +- ippGetString(attr, 0, NULL), +- ippGetString(attr, 1, NULL)); +- else if (strstr(attrname, "-default")) +- { +- gchar *name = g_strdup (attrname); +- gchar *value = NULL; +- *strstr (name, "-default") = '\0'; +- +- switch (value_tag) +- { +- gchar **tokens; +- +- case IPP_TAG_KEYWORD: +- case IPP_TAG_STRING: +- case IPP_TAG_NAME: +- // Escape value +- tokens = g_strsplit_set (ippGetString(attr, 0, NULL), +- " \"\'\\", -1); +- value = g_strjoinv ("\\", tokens); +- g_strfreev (tokens); +- break; +- +- default: +- // other values aren't needed? +- debug_printf("skipping %s (%d)\n", name, value_tag); +- break; +- } +- +- if (value) +- { +- g_string_append_printf (browse_options, "%s=%s ", name, value); +- g_free (value); +- } +- +- g_free (name); +- } +- +- attr = ippNextAttribute(response); +- } +- +- if (type != -1 && state != -1 && uri && location && info && make_model) +- { +- gchar *browse_options_str = g_string_free (browse_options, FALSE); +- browse_data_t *data; +- browse_options = NULL; +- g_strchomp (browse_options_str); +- data = new_browse_data (type, state, uri, location, +- info, make_model, browse_options_str); +- browse_data = g_list_insert (browse_data, data, 0); +- g_free (browse_options_str); +- } +- +- if (make_model) +- g_free (make_model); +- +- if (info) +- g_free (info); +- +- if (location) +- g_free (location); +- +- if (browse_options) +- { +- g_string_free (browse_options, TRUE); +- browse_options = NULL; +- } +- +- if (!attr) +- break; +- } +- +- fail: +- if (browse_options) +- g_string_free(browse_options, TRUE); +- if (response) +- ippDelete(response); +-} +- +- +-static void +-update_local_printers (void) +-{ +- gboolean get_printers = FALSE; +- http_t *conn; +- +- if (inhibit_local_printers_update) +- return; +- +- conn = http_connect_local (); +- if (conn && +- (!local_printers_context || local_printers_context->can_subscribe)) +- { +- if (!local_printers_context || +- local_printers_context->subscription_id == -1) +- { +- // No subscription yet. First, create the subscription. +- local_printers_create_subscription (conn); +- get_printers = TRUE; +- } +- else +- // We already have a subscription, so use it. +- +- // Note: for the moment, browse_poll_get_notifications() just +- // tells us whether we should re-fetch the printer list, so it +- // is safe to use here. +- get_printers = browse_poll_get_notifications (local_printers_context, +- conn); +- } +- else +- get_printers = TRUE; +- +- if (get_printers) +- { +- get_local_printers (); +- +- if (BrowseLocalProtocols & BROWSE_CUPS) +- prepare_browse_data (); +- } +-} +- +- +-static int +-check_jobs () +-{ +- int num_jobs = 0; +- cups_job_t *jobs = NULL; +- remote_printer_t *p; +- http_t *conn = NULL; +- +- conn = http_connect_local (); +- if (conn == NULL) +- { +- debug_printf("Cannot connect to local CUPS to check whether there are still jobs.\n"); +- return (0); +- } +- +- if (cupsArrayCount(remote_printers) > 0) +- for (p = (remote_printer_t *)cupsArrayFirst(remote_printers); +- p; +- p = (remote_printer_t *)cupsArrayNext(remote_printers)) +- if (!p->slave_of) +- { +- num_jobs = cupsGetJobs2(conn, &jobs, p->queue_name, 0, +- CUPS_WHICHJOBS_ACTIVE); +- if (num_jobs > 0) +- { +- debug_printf("Queue %s still has jobs!\n", p->queue_name); +- cupsFreeJobs(num_jobs, jobs); +- return (1); +- } +- } +- +- debug_printf("All our remote printers are without jobs.\n"); +- return (0); +-} +- +- +-static gboolean +-autoshutdown_execute (gpointer data) +-{ +- debug_printf("autoshutdown_execute() in THREAD %ld\n", pthread_self()); +- // Are we still in auto shutdown mode and are we still without queues or +- // jobs +- if (autoshutdown && +- (cupsArrayCount(remote_printers) == 0 || +- (autoshutdown_on == NO_JOBS && check_jobs() == 0))) +- { +- debug_printf("Automatic shutdown as there are no print queues maintained by us or no jobs on them for %d sec.\n", +- autoshutdown_timeout); +- g_main_loop_quit(gmainloop); +- g_main_context_wakeup(NULL); +- } +- +- // Stop this timeout handler, we needed it only once +- return (FALSE); +-} +- +- +-#ifdef HAVE_LDAP_REBIND_PROC +-# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-// +-// 'ldap_rebind_proc()' - Callback function for LDAP rebind +-// +- +-static int // O - Result code +-ldap_rebind_proc(LDAP *RebindLDAPHandle, // I - LDAP handle +- LDAP_CONST char *refsp, // I - ??? +- ber_tag_t request, // I - ??? +- ber_int_t msgid, // I - ??? +- void *params) // I - ??? +-{ +- int rc; // Result code +-# if LDAP_API_VERSION > 3000 +- struct berval bval; // Bind value +-# endif // LDAP_API_VERSION > 3000 +- (void)request; +- (void)msgid; +- (void)params; +- +- // +- // Bind to new LDAP server... +- // +- +- debug_printf("ldap_rebind_proc: Rebind to %s\n", refsp); +- +-# if LDAP_API_VERSION > 3000 +- bval.bv_val = BrowseLDAPPassword; +- bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword); +- +- rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, +- &bval, NULL, NULL, NULL); +-# else +- rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, BrowseLDAPPassword, +- LDAP_AUTH_SIMPLE); +-# endif // LDAP_API_VERSION > 3000 +- +- return (rc); +-} +- +- +-# else // defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-// +-// 'ldap_rebind_proc()' - Callback function for LDAP rebind +-// +- +-static int // O - Result code +-ldap_rebind_proc(LDAP *RebindLDAPHandle, // I - LDAP handle +- char **dnp, // I - ??? +- char **passwdp, // I - ??? +- int *authmethodp, // I - ??? +- int freeit, // I - ??? +- void *arg) // I - ??? +-{ +- switch (freeit) +- { +- case 1: +- // +- // Free current values... +- // +- +- debug_printf("ldap_rebind_proc: Free values...\n"); +- +- if (dnp && *dnp) +- free(*dnp); +- +- if (passwdp && *passwdp) +- free(*passwdp); +- break; +- +- case 0: +- // +- // Return credentials for LDAP referal... +- // +- +- debug_printf("ldap_rebind_proc: Return necessary values...\n"); +- +- *dnp = strdup(BrowseLDAPBindDN); +- *passwdp = strdup(BrowseLDAPPassword); +- *authmethodp = LDAP_AUTH_SIMPLE; +- break; +- +- default: +- // +- // Should never happen... +- // +- +- debug_printf("LDAP rebind has been called with wrong freeit value!\n"); +- break; +- } +- +- return (LDAP_SUCCESS); +-} +-# endif // defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-#endif // HAVE_LDAP_REBIND_PROC +- +- +-#ifdef HAVE_LDAP +-// +-// 'ldap_new_connection()' - Start new LDAP connection +-// +- +-static LDAP * // O - LDAP handle +-ldap_new_connection(void) +-{ +- int rc; // LDAP API status +- int version = 3; // LDAP version +- struct berval bv = {0, ""}; // SASL bind value +- LDAP *TempBrowseLDAPHandle=NULL; +- // Temporary LDAP Handle +-# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) +- int ldap_ssl = 0; // LDAP SSL indicator +- int ssl_err = 0; // LDAP SSL error value +-# endif // defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) +- +- +-# ifdef HAVE_OPENLDAP +-# ifdef HAVE_LDAP_SSL +- // +- // Set the certificate file to use for encrypted LDAP sessions... +- // +- +- if (BrowseLDAPCACertFile) +- { +- debug_printf("ldap_new_connection: Setting CA certificate file \"%s\"\n", +- BrowseLDAPCACertFile); +- +- if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, +- (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS) +- debug_printf("Unable to set CA certificate file for LDAP " +- "connections: %d - %s\n", rc, ldap_err2string(rc)); +- } +-# endif // HAVE_LDAP_SSL +- +- // +- // Initialize OPENLDAP connection... +- // LDAP stuff currently only supports ldapi EXTERNAL SASL binds... +- // +- +- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost")) +- rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///"); +- else +- rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer); +- +-# else // HAVE_OPENLDAP +- +- int ldap_port = 0; // LDAP port +- char ldap_protocol[11], // LDAP protocol +- ldap_host[255]; // LDAP host +- +- // +- // Split LDAP URI into its components... +- // +- +- if (!BrowseLDAPServer) +- { +- debug_printf("BrowseLDAPServer not configured!\n"); +- debug_printf("Disabling LDAP browsing!\n"); +- //BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- return (NULL); +- } +- +- sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host, +- &ldap_port); +- +- if (!strcmp(ldap_protocol, "ldap")) +- ldap_ssl = 0; +- else if (!strcmp(ldap_protocol, "ldaps")) +- ldap_ssl = 1; +- else +- { +- debug_printf("Unrecognized LDAP protocol (%s)!\n", +- ldap_protocol); +- debug_printf("Disabling LDAP browsing!\n"); +- //BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- return (NULL); +- } +- +- if (ldap_port == 0) +- { +- if (ldap_ssl) +- ldap_port = LDAPS_PORT; +- else +- ldap_port = LDAP_PORT; +- } +- +- debug_printf("ldap_new_connection: PROT:%s HOST:%s PORT:%d\n", +- ldap_protocol, ldap_host, ldap_port); +- +- // +- // Initialize LDAP connection... +- // +- +- if (!ldap_ssl) +- { +- if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL) +- rc = LDAP_OPERATIONS_ERROR; +- else +- rc = LDAP_SUCCESS; +- +-# ifdef HAVE_LDAP_SSL +- } +- else +- { +- // +- // Initialize SSL LDAP connection... +- // +- +- if (BrowseLDAPCACertFile) +- { +- rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL); +- if (rc != LDAP_SUCCESS) +- { +- debug_printf("Failed to initialize LDAP SSL client!\n"); +- rc = LDAP_OPERATIONS_ERROR; +- } +- else +- { +- if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port, +- 1)) == NULL) +- rc = LDAP_OPERATIONS_ERROR; +- else +- rc = LDAP_SUCCESS; +- } +- } +- else +- { +- debug_printf("LDAP SSL certificate file/database not configured!\n"); +- rc = LDAP_OPERATIONS_ERROR; +- } +- +-# else // HAVE_LDAP_SSL +- +- // +- // Return error, because client libraries doesn't support SSL +- // +- +- debug_printf("LDAP client libraries do not support SSL\n"); +- rc = LDAP_OPERATIONS_ERROR; +- +-# endif // HAVE_LDAP_SSL +- } +-# endif // HAVE_OPENLDAP +- +- // +- // Check return code from LDAP initialize... +- // +- +- if (rc != LDAP_SUCCESS) +- { +- debug_printf("Unable to initialize LDAP!\n"); +- +- if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) +- debug_printf("Temporarily disabling LDAP browsing...\n"); +- else +- { +- debug_printf("Disabling LDAP browsing!\n"); +- +- //BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- } +- +- ldap_disconnect(TempBrowseLDAPHandle); +- +- return (NULL); +- } +- +- // +- // Upgrade LDAP version... +- // +- +- if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION, +- (const void *)&version) != LDAP_SUCCESS) +- { +- debug_printf("Unable to set LDAP protocol version %d!\n", +- version); +- debug_printf("Disabling LDAP browsing!\n"); +- +- //BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- ldap_disconnect(TempBrowseLDAPHandle); +- +- return (NULL); +- } +- +- // +- // Register LDAP rebind procedure... +- // +- +-# ifdef HAVE_LDAP_REBIND_PROC +-# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +- +- rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, +- (void *)NULL); +- if (rc != LDAP_SUCCESS) +- debug_printf("Setting LDAP rebind function failed with status %d: %s\n", +- rc, ldap_err2string(rc)); +- +-# else +- +- ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL); +- +-# endif // defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) +-# endif // HAVE_LDAP_REBIND_PROC +- +- // +- // Start LDAP bind... +- // +- +-# if LDAP_API_VERSION > 3000 +- struct berval bval; +- bval.bv_val = BrowseLDAPPassword; +- bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword); +- +- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost")) +- rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL, +- NULL, NULL); +- else +- rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, +- LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL); +- +-# else +- rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, +- BrowseLDAPPassword, LDAP_AUTH_SIMPLE); +-# endif // LDAP_API_VERSION > 3000 +- +- if (rc != LDAP_SUCCESS) +- { +- debug_printf("LDAP bind failed with error %d: %s\n", +- rc, ldap_err2string(rc)); +- +-# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) +- if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)) +- { +- ssl_err = PORT_GetError(); +- if (ssl_err != 0) +- debug_printf("LDAP SSL error %d: %s\n", ssl_err, +- ldapssl_err2string(ssl_err)); +- } +-# endif // defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) +- +- ldap_disconnect(TempBrowseLDAPHandle); +- +- return (NULL); +- } +- +- debug_printf("LDAP connection established\n"); +- +- return (TempBrowseLDAPHandle); +-} +- +- +-// +-// 'ldap_reconnect()' - Reconnect to LDAP Server +-// +- +-static LDAP * // O - New LDAP handle +-ldap_reconnect(void) +-{ +- LDAP *TempBrowseLDAPHandle = NULL; // Temp Handle to LDAP server +- +- // +- // Get a new LDAP Handle and replace the global Handle +- // if the new connection was successful. +- // +- +- debug_printf("Try LDAP reconnect...\n"); +- +- TempBrowseLDAPHandle = ldap_new_connection(); +- +- if (TempBrowseLDAPHandle != NULL) +- { +- if (BrowseLDAPHandle != NULL) +- ldap_disconnect(BrowseLDAPHandle); +- +- BrowseLDAPHandle = TempBrowseLDAPHandle; +- } +- +- return (BrowseLDAPHandle); +-} +- +- +-// +-// 'ldap_disconnect()' - Disconnect from LDAP Server +-// +- +-static void +-ldap_disconnect(LDAP *ld) // I - LDAP handle +-{ +- int rc; // Return code +- +- // +- // Close LDAP handle... +- // +- +-# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- rc = ldap_unbind_ext_s(ld, NULL, NULL); +-# else +- rc = ldap_unbind_s(ld); +-# endif // defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- +- if (rc != LDAP_SUCCESS) +- debug_printf("Unbind from LDAP server failed with status %d: %s\n", +- rc, ldap_err2string(rc)); +-} +- +- +-// +-// 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP... +-// +- +-static void +-cupsdUpdateLDAPBrowse(void) +-{ +- char uri[HTTP_MAX_URI], // Printer URI +- host[HTTP_MAX_URI], // Hostname +- resource[HTTP_MAX_URI], // Resource path +- local_resource[HTTP_MAX_URI], // Resource path +- service_name[4096], +- location[1024], // Printer location +- info[1024], // Printer information +- make_model[1024], // Printer make and model +- type_num[30], // Printer type number +- scheme[32], // URI's scheme +- username[64]; // URI's username +- int port; // URI's port number +- char *c; +- int hl; +- int rc; // LDAP status +- int limit; // Size limit +- LDAPMessage *res, // LDAP search results +- *e; // Current entry from search +- +- debug_printf("UpdateLDAPBrowse\n"); +- +- // +- // Reconnect if LDAP Handle is invalid... +- // +- +- if (! BrowseLDAPHandle) +- { +- ldap_reconnect(); +- return; +- } +- +- // +- // Search for cups printers in LDAP directory... +- // +- +- rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE, +- BrowseLDAPFilter, (char **)ldap_attrs, 0, &res); +- +- // +- // If ldap search was successfull then exit function +- // and temporary disable LDAP updates... +- // +- +- if (rc != LDAP_SUCCESS) +- { +- if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || +- (rc == LDAP_CONNECT_ERROR))) +- { +- BrowseLDAPUpdate = FALSE; +- debug_printf("LDAP update temporary disabled\n"); +- } +- return; +- } +- +- // +- // If LDAP updates were disabled, we will reenable them... +- // +- +- if (!BrowseLDAPUpdate) +- { +- BrowseLDAPUpdate = TRUE; +- debug_printf("LDAP update enabled\n"); +- } +- +- // +- // Count LDAP entries and return if no entry exist... +- // +- +- limit = ldap_count_entries(BrowseLDAPHandle, res); +- debug_printf("LDAP search returned %d entries\n", limit); +- if (limit < 1) +- { +- ldap_freeres(res); +- return; +- } +- +- // +- // Loop through the available printers... +- // +- +- for (e = ldap_first_entry(BrowseLDAPHandle, res); +- e; +- e = ldap_next_entry(BrowseLDAPHandle, e)) +- { +- // +- // Get the required values from this entry... +- // +- +- if (ldap_getval_firststring(BrowseLDAPHandle, e, +- "printerDescription", info, sizeof(info)) == -1) +- continue; +- +- if (ldap_getval_firststring(BrowseLDAPHandle, e, +- "printerLocation", location, +- sizeof(location)) == -1) +- continue; +- +- if (ldap_getval_firststring(BrowseLDAPHandle, e, +- "printerMakeAndModel", make_model, +- sizeof(make_model)) == -1) +- continue; +- +- if (ldap_getval_firststring(BrowseLDAPHandle, e, +- "printerType", type_num, +- sizeof(type_num)) == -1) +- continue; +- +- if (ldap_getval_firststring(BrowseLDAPHandle, e, +- "printerURI", uri, sizeof(uri)) == -1) +- continue; +- +- // +- // Process the entry... +- // +- +- memset(scheme, 0, sizeof(scheme)); +- memset(username, 0, sizeof(username)); +- memset(host, 0, sizeof(host)); +- memset(resource, 0, sizeof(resource)); +- memset(local_resource, 0, sizeof(local_resource)); +- +- httpSeparateURI (HTTP_URI_CODING_ALL, uri, +- scheme, sizeof(scheme) - 1, +- username, sizeof(username) - 1, +- host, sizeof(host) - 1, +- &port, +- resource, sizeof(resource)- 1); +- +- if (strncasecmp (resource, "/printers/", 10) && +- strncasecmp (resource, "/classes/", 9)) +- { +- debug_printf("don't understand URI: %s\n", uri); +- return; +- } +- +- strncpy (local_resource, resource + 1, sizeof (local_resource) - 1); +- local_resource[sizeof (local_resource) - 1] = '\0'; +- c = strchr (local_resource, '?'); +- if (c) +- *c = '\0'; +- +- // Build the DNS-SD service name which CUPS would give to this printer +- // when DNS-SD-broadcasting it +- snprintf(service_name, sizeof (service_name), "%s @ %s", +- (strlen(info) > 0 ? info : strchr(local_resource, '/') + 1), host); +- // Cut off trailing ".local" of host name +- hl = strlen(service_name); +- if (hl > 6 && !strcasecmp(service_name + hl - 6, ".local")) +- service_name[hl - 6] = '\0'; +- if (hl > 7 && !strcasecmp(service_name + hl - 7, ".local.")) +- service_name[hl - 7] = '\0'; +- // DNS-SD service name has max. 63 characters +- service_name[63] = '\0'; +- +- debug_printf("LDAP: Remote host: %s; Port: %d; Remote queue name: %s; Service Name: %s\n", +- host, port, strchr(local_resource, '/') + 1, service_name); +- +- pthread_rwlock_wrlock(&lock); +- examine_discovered_printer_record(host, NULL, port, local_resource, +- service_name, location, info, "", "", +- "", 0, NULL); +- pthread_rwlock_unlock(&lock); +- +- } +- +- ldap_freeres(res); +-} +- +- +-// +-// 'ldap_search_rec()' - LDAP Search with reconnect +-// +- +-static int // O - Return code +-ldap_search_rec(LDAP *ld, // I - LDAP handler +- char *base, // I - Base dn +- int scope, // I - LDAP search scope +- char *filter, // I - Filter string +- char *attrs[], // I - Requested attributes +- int attrsonly, // I - Return only attributes? +- LDAPMessage **res) // I - LDAP handler +-{ +- int rc; // Return code +- LDAP *ldr; // LDAP handler after reconnect +- +- +-# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL, +- NULL, LDAP_NO_LIMIT, res); +-# else +- rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res); +-# endif // defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- +- // +- // If we have a connection problem try again... +- // +- +- if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR) +- { +- debug_printf("LDAP search failed with status %d: %s\n", +- rc, ldap_err2string(rc)); +- debug_printf("We try the LDAP search once again after reconnecting to " +- "the server\n"); +- ldap_freeres(*res); +- ldr = ldap_reconnect(); +- +-# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- rc = ldap_search_ext_s(ldr, base, scope, filter, attrs, attrsonly, NULL, +- NULL, NULL, LDAP_NO_LIMIT, res); +-# else +- rc = ldap_search_s(ldr, base, scope, filter, attrs, attrsonly, res); +-# endif // defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- } +- +- if (rc == LDAP_NO_SUCH_OBJECT) +- debug_printf("ldap_search_rec: LDAP entry/object not found\n"); +- else if (rc != LDAP_SUCCESS) +- debug_printf("ldap_search_rec: LDAP search failed with status %d: %s\n", +- rc, ldap_err2string(rc)); +- +- if (rc != LDAP_SUCCESS) +- ldap_freeres(*res); +- +- return (rc); +-} +- +- +-// +-// 'ldap_freeres()' - Free LDAPMessage +-// ++ } + +-static void +-ldap_freeres(LDAPMessage *entry) // I - LDAP handler +-{ +- int rc; // Return value ++ cupsFreeDests (num_dests, dests); + +- rc = ldap_msgfree(entry); +- if (rc == -1) +- debug_printf("Can't free LDAPMessage!\n"); +- else if (rc == 0) +- debug_printf("Freeing LDAPMessage was unnecessary\n"); ++ pthread_rwlock_unlock(&lock); + } + + +-// +-// 'ldap_getval_char()' - Get first LDAP value and convert to string +-// +- +-static int // O - Return code +-ldap_getval_firststring(LDAP *ld, // I - LDAP handler +- LDAPMessage *entry, // I - LDAP message or search +- // result +- char *attr, // I - the wanted attribute +- char *retval, // O - String to return +- unsigned long maxsize) // I - Max string size ++static void ++update_local_printers (void) + { +- char *dn; // LDAP DN +- int rc = 0; // Return code +-# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 +- struct berval **bval; // LDAP value array +- unsigned long size; // String size +- ++ gboolean get_printers = FALSE; ++ http_t *conn; + +- // +- // Get value from LDAPMessage... +- // ++ if (inhibit_local_printers_update) ++ return; + +- if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL) +- { +- rc = -1; +- dn = ldap_get_dn(ld, entry); +- debug_printf("Failed to get LDAP value %s for %s!\n", +- attr, dn); +- ldap_memfree(dn); +- } +- else ++ conn = http_connect_local (); ++ if (conn && ++ (!local_printers_context || local_printers_context->can_subscribe)) + { +- // +- // Check size and copy value into our string... +- // +- +- size = maxsize; +- if (size < (bval[0]->bv_len + 1)) ++ if (!local_printers_context || ++ local_printers_context->subscription_id == -1) + { +- rc = -1; +- dn = ldap_get_dn(ld, entry); +- debug_printf("Attribute %s is too big! (dn: %s)\n", +- attr, dn); +- ldap_memfree(dn); ++ // No subscription yet. First, create the subscription. ++ local_printers_create_subscription (conn); ++ get_printers = TRUE; + } + else +- size = bval[0]->bv_len + 1; ++ // We already have a subscription, so use it. + +- strncpy(retval, bval[0]->bv_val, size); +- if (size > 0) +- retval[size - 1] = '\0'; +- ldap_value_free_len(bval); ++ // Note: for the moment, browse_poll_get_notifications() just ++ // tells us whether we should re-fetch the printer list, so it ++ // is safe to use here. ++ get_printers = browse_poll_get_notifications (local_printers_context, ++ conn); + } +-# else +- char **value; // LDAP value ++ else ++ get_printers = TRUE; + +- // +- // Get value from LDAPMessage... +- // ++ if (get_printers) ++ get_local_printers (); ++} ++ ++ ++static int ++check_jobs () ++{ ++ int num_jobs = 0; ++ cups_job_t *jobs = NULL; ++ remote_printer_t *p; ++ http_t *conn = NULL; + +- if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL) ++ conn = http_connect_local (); ++ if (conn == NULL) + { +- rc = -1; +- dn = ldap_get_dn(ld, entry); +- debug_printf("Failed to get LDAP value %s for %s!\n", +- attr, dn); +- ldap_memfree(dn); ++ debug_printf("Cannot connect to local CUPS to check whether there are still jobs.\n"); ++ return (0); + } +- else ++ ++ if (cupsArrayCount(remote_printers) > 0) ++ for (p = (remote_printer_t *)cupsArrayFirst(remote_printers); ++ p; ++ p = (remote_printer_t *)cupsArrayNext(remote_printers)) ++ if (!p->slave_of) ++ { ++ num_jobs = cupsGetJobs2(conn, &jobs, p->queue_name, 0, ++ CUPS_WHICHJOBS_ACTIVE); ++ if (num_jobs > 0) ++ { ++ debug_printf("Queue %s still has jobs!\n", p->queue_name); ++ cupsFreeJobs(num_jobs, jobs); ++ return (1); ++ } ++ } ++ ++ debug_printf("All our remote printers are without jobs.\n"); ++ return (0); ++} ++ ++ ++static gboolean ++autoshutdown_execute (gpointer data) ++{ ++ debug_printf("autoshutdown_execute() in THREAD %ld\n", pthread_self()); ++ // Are we still in auto shutdown mode and are we still without queues or ++ // jobs ++ if (autoshutdown && ++ (cupsArrayCount(remote_printers) == 0 || ++ (autoshutdown_on == NO_JOBS && check_jobs() == 0))) + { +- strncpy(retval, *value, maxsize); +- if (maxsize > 0) +- retval[maxsize - 1] = '\0'; +- ldap_value_free(value); ++ debug_printf("Automatic shutdown as there are no print queues maintained by us or no jobs on them for %d sec.\n", ++ autoshutdown_timeout); ++ g_main_loop_quit(gmainloop); ++ g_main_context_wakeup(NULL); + } +-# endif // defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 + +- return (rc); ++ // Stop this timeout handler, we needed it only once ++ return (FALSE); + } +-#endif // HAVE_LDAP + + + static int +@@ -6214,7 +5140,7 @@ get_local_queue_name(const char *service_name, + /* We can get resource without / or without string after / - use + * the original string (possible trailing / will be removed) */ + if ((str = strrchr(resource, '/')) == NULL || strlen(str) <= 1) +- str = resource; ++ str = (char *)resource; + + queue_name = remove_bad_chars(str, 0); + } +@@ -9610,8 +8536,7 @@ update_cups_queues(gpointer unused) + // DNS-SD has reported a new remote printer, create a CUPS queue + // for it, or upgrade an existing queue, or update a queue to + // use a backup host when it has disappeared on the currently +- // used host (...or, we've just received a CUPS Browsing packet +- // for this queue) ++ // used host (...or, we've just discovered this queue via BrowsePoll) + case STATUS_TO_BE_CREATED: + if (p->called) + break; +@@ -10134,7 +9059,7 @@ update_netifs (gpointer data) + if (strlen(list) + strlen(iface->address) + 2 <= sizeof(list)) + { + snprintf(l, sizeof(list) - strlen(list) - 1, +- "%s*", iface->address); ++ "%.65533s*", iface->address); + l = list + strlen(list); + } + } +@@ -10318,7 +9243,7 @@ examine_discovered_printer_record(const char *host, + is_cups_queue = 1; + #endif // HAVE_AVAHI + // If we do not have a TXT record the printer was not discovered via +- // DNS-SD but via CUPS legacy or LDAP, so it is a remote CUPS queue ++ // DNS-SD and so it is a (BrowsePoll-discovered) remote CUPS queue + // and not an IPP network printer. + if (txt == NULL) + is_cups_queue = 1; +@@ -10441,8 +9366,8 @@ examine_discovered_printer_record(const char *host, + } + else + #endif // HAVE_AVAHI +- // Printer is discovered via legacy CUPS or LDAP, so we have to give +- // a IP-based/host-name-based URI to it ( or for DNS-SD-discovered ++ // Printer is discovered via BrowsePoll, so we have to give a ++ // IP-based/host-name-based URI to it (or for DNS-SD-discovered + // printers if DNSSDBasedDeviceURIs config option is not set) + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri) - 1, + (strcasestr(type, "_ipps") ? "ipps" : "ipp"), NULL, +@@ -10465,8 +9390,8 @@ examine_discovered_printer_record(const char *host, + } + + +- // Update network interface info if we were discovered by LDAP +- // or legacy CUPS, needed for the is_local_hostname() function calls. ++ // Update network interface info if we were discovered by ++ // BrowsePoll, needed for the is_local_hostname() function calls. + // During DNS-SD discovery the update is already done by the Avahi + // event handler function. + if (FrequentNetifUpdate && (type == NULL || type[0] == '\0')) +@@ -10527,9 +9452,9 @@ examine_discovered_printer_record(const char *host, + // We have already created a local queue, check whether the + // discovered service allows us to upgrade the queue to IPPS + // or whether the URI part after ipp(s):// has changed, or +- // whether the discovered queue is discovered via DNS-SD +- // having more info in contrary to the existing being +- // discovered by legacy CUPS or LDAP ++ // whether the discovered queue is discovered via DNS-SD, ++ // having more info in contrary to the existing one being ++ // discovered by BrowsePoll + + int downgrade = 0, upgrade = 0; + +@@ -10568,14 +9493,14 @@ examine_discovered_printer_record(const char *host, + debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is from a non-loopback interface, we have already one from the loopback interface, skipping\n", + p->queue_name, remote_host, port, uri); + } +- // DNS-SD -> CUPS Legacy/LDAP ++ // DNS-SD -> BrowsePoll + else if (p->domain != NULL && p->domain[0] != '\0' && + (domain == NULL || domain[0] == '\0') && + p->type != NULL && p->type[0] != '\0' && + (type == NULL || type[0] == '\0')) + { + downgrade = 1; +- debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is only discovered via legacy CUPS or LDAP, we have already a DNS-SD-discovered one, skipping\n", ++ debug_printf("Printer %s: New discovered service from host %s, port %d, URI %s is only discovered via BrowsePoll, we have already a DNS-SD-discovered one, skipping\n", + p->queue_name, remote_host, port, uri); + } + +@@ -10597,11 +9522,11 @@ examine_discovered_printer_record(const char *host, + debug_printf("Upgrading printer %s (Host: %s, Port: %d) to use loopback interface \"lo\". New URI: %s\n", + p->queue_name, remote_host, port, uri); + } +- // CUPS Legacy/LDAP -> DNS-SD ++ // BrowsePoll -> DNS-SD + else if ((p->domain == NULL || p->domain[0] == '\0') && + domain != NULL && domain[0] != '\0' && +- (p->type == NULL || p->type[0] == '\0') && +- type != NULL && type[0] != '\0') ++ (p->type == NULL || p->type[0] == '\0') && ++ type != NULL && type[0] != '\0') + { + upgrade = 1; + debug_printf("Discovered printer %s (Host: %s, Port: %d, URI: %s) by DNS-SD now.\n", +@@ -11683,7 +10608,7 @@ avahi_init() + + + // +-// A CUPS printer has been discovered via CUPS Browsing ++// A CUPS printer has been discovered via BrowsePoll + // or with BrowsePoll + // + +@@ -11757,7 +10682,7 @@ found_cups_printer(const char *remote_host, + // DNS-SD service name has max. 63 characters + service_name[63] = '\0'; + +- debug_printf("CUPS browsing: Remote host: %s; Port: %d; Remote queue name: %s; Service Name: %s\n", ++ debug_printf("BrowsePoll: Remote host: %s; Port: %d; Remote queue name: %s; Service Name: %s\n", + host, port, strchr(local_resource, '/') + 1, service_name); + + pthread_rwlock_wrlock(&lock); +@@ -11790,203 +10715,6 @@ found_cups_printer(const char *remote_host, + } + + +-static gboolean +-process_browse_data (GIOChannel *source, +- GIOCondition condition, +- gpointer data) +-{ +- char packet[2048]; +- http_addr_t srcaddr; +- socklen_t srclen; +- ssize_t got; +- unsigned int type; +- unsigned int state; +- char remote_host[256]; +- char uri[1024]; +- char location[1024]; +- char info[1024]; +- char *c = NULL, *end = NULL; +- +- debug_printf("process_browse_data() in THREAD %ld\n", pthread_self()); +- +- memset(packet, 0, sizeof(packet)); +- memset(remote_host, 0, sizeof(remote_host)); +- memset(uri, 0, sizeof(uri)); +- memset(info, 0, sizeof(info)); +- +- srclen = sizeof (srcaddr); +- got = recvfrom (browsesocket, packet, sizeof (packet) - 1, 0, +- &srcaddr.addr, &srclen); +- if (got == -1) +- { +- debug_printf ("cupsd-browsed: error receiving browse packet: %s\n", +- strerror (errno)); +- // Remove this I/O source +- return (FALSE); +- } +- +- packet[got] = '\0'; +- httpAddrString (&srcaddr, remote_host, sizeof (remote_host) - 1); +- +- // Check this packet is allowed +- if (!allowed ((struct sockaddr *) &srcaddr)) +- { +- debug_printf("browse packet from %s disallowed\n", +- remote_host); +- return (TRUE); +- } +- +- debug_printf("browse packet received from %s\n", +- remote_host); +- +- if (sscanf (packet, "%x%x%1023s", &type, &state, uri) < 3) +- { +- debug_printf("incorrect browse packet format\n"); +- return (TRUE); +- } +- +- info[0] = '\0'; +- +- // do not read OOB +- end = packet + sizeof(packet); +- c = strchr (packet, '\"'); +- if (c >= end) +- return (TRUE); +- +- if (c) +- { +- // Extract location field +- { +- int i; +- c++; +- for (i = 0; +- i < sizeof (location) - 1 && *c != '\"' && c < end; +- i++, c++) +- location[i] = *c; +- location[i] = '\0'; +- debug_printf("process_browse_data: location: |%s|\n", location); // !! +- } +- for (; c < end && *c != '\"'; c++); +- +- if (c >= end) +- return (TRUE); +- +- if (*c == '\"') +- for (c++; c < end && isspace(*c); c++); +- +- if (c >= end) +- return (TRUE); +- +- // Is there an info field? +- if (*c == '\"') +- { +- int i; +- c++; +- for (i = 0; +- i < sizeof (info) - 1 && *c != '\"' && c < end; +- i++, c++) +- info[i] = *c; +- info[i] = '\0'; +- debug_printf("process_browse_data: info: |%s|\n", info); // !! +- } +- } +- if (c >= end) +- return (TRUE); +- +- if (!(type & CUPS_PRINTER_DELETE)) +- found_cups_printer (remote_host, uri, location, info); +- +- if (in_shutdown == 0) +- recheck_timer (); +- +- // Don't remove this I/O source +- return (TRUE); +-} +- +- +-static void +-broadcast_browse_packets (gpointer data, +- gpointer user_data) +-{ +- browse_data_t *bdata = data; +- netif_t *browse; +- char packet[2048]; +- char uri[HTTP_MAX_URI]; +- char scheme[32]; +- char username[64]; +- char host[HTTP_MAX_HOST]; +- int port; +- char resource[HTTP_MAX_URI]; +- +- debug_printf("broadcast_browse_packets() in THREAD %ld\n", pthread_self()); +- +- for (browse = (netif_t *)cupsArrayFirst (netifs); +- browse != NULL; +- browse = (netif_t *)cupsArrayNext (netifs)) +- { +- // Replace 'localhost' with our IP address on this interface +- httpSeparateURI(HTTP_URI_CODING_ALL, bdata->uri, +- scheme, sizeof(scheme), +- username, sizeof(username), +- host, sizeof(host), +- &port, +- resource, sizeof(resource)); +- httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof (uri), +- scheme, username, browse->address, port, resource); +- +- if (snprintf (packet, sizeof (packet), +- "%x " // type +- "%x " // state +- "%s " // uri +- "\"%s\" " // location +- "\"%s\" " // info +- "\"%s\" " // make-and-model +- "lease-duration=%d" // BrowseTimeout +- "%s%s" // other browse options +- "\n", +- bdata->type, +- bdata->state, +- uri, +- bdata->location, +- bdata->info, +- bdata->make_model, +- BrowseTimeout, +- bdata->browse_options ? " " : "", +- bdata->browse_options ? bdata->browse_options : "") +- >= sizeof (packet)) +- { +- debug_printf ("oversize packet not sent\n"); +- continue; +- } +- +- debug_printf("packet to send:\n%s", packet); +- +- int err = sendto (browsesocket, packet, +- strlen (packet), 0, +- &browse->broadcast.addr, +- httpAddrLength (&browse->broadcast)); +- if (err == -1) +- debug_printf("cupsd-browsed: sendto returned %d: %s\n", +- err, strerror (errno)); +- } +-} +- +- +-static gboolean +-send_browse_data (gpointer data) +-{ +- debug_printf("send_browse_data() in THREAD %ld\n", pthread_self()); +- update_netifs (NULL); +- res_init (); +- update_local_printers (); +- g_list_foreach (browse_data, broadcast_browse_packets, NULL); +- g_timeout_add_seconds (BrowseInterval, send_browse_data, NULL); +- +- // Stop this timeout handler, we called a new one +- return (FALSE); +-} +- +- + static browsepoll_printer_t * + new_browsepoll_printer (const char *uri_supported, + const char *location, +@@ -12410,81 +11138,6 @@ browse_poll (gpointer data) + } + + +-#ifdef HAVE_LDAP +-static gboolean +-browse_ldap_poll (gpointer data) +-{ +- char *tmpFilter; // Query filter +- int filterLen; +- +- debug_printf("browse_ldap_poll() in THREAD %ld\n", pthread_self()); +- +- // do real stuff here +- if (!BrowseLDAPDN) +- { +- debug_printf("Need to set BrowseLDAPDN to use LDAP browsing!\n"); +- BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- +- return (FALSE); +- } +- else +- { +- if (!BrowseLDAPInitialised) +- { +- BrowseLDAPInitialised = TRUE; +- // +- // Query filter string +- // +- +- if (BrowseLDAPFilter) +- filterLen = snprintf(NULL, 0, "(&%s%s)", LDAP_BROWSE_FILTER, +- BrowseLDAPFilter); +- else +- filterLen = strlen(LDAP_BROWSE_FILTER); +- +- tmpFilter = (char *)malloc(filterLen + 1); +- if (!tmpFilter) +- { +- debug_printf("Could not allocate memory for LDAP browse query filter!\n"); +- BrowseLocalProtocols &= ~BROWSE_LDAP; +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- return (FALSE); +- } +- +- if (BrowseLDAPFilter) +- { +- snprintf(tmpFilter, filterLen + 1, "(&%s%s)", LDAP_BROWSE_FILTER, +- BrowseLDAPFilter); +- free(BrowseLDAPFilter); +- BrowseLDAPFilter = NULL; +- } +- else +- strcpy(tmpFilter, LDAP_BROWSE_FILTER); +- +- BrowseLDAPFilter = tmpFilter; +- +- // +- // Open LDAP handle... +- // +- +- BrowseLDAPHandle = ldap_new_connection(); +- } +- +- cupsdUpdateLDAPBrowse(); +- if (in_shutdown == 0) +- recheck_timer(); +- } +- +- // Call a new timeout handler so that we run again +- g_timeout_add_seconds (BrowseInterval, browse_ldap_poll, data); +- +- // Stop this timeout handler, we called a new one +- return (FALSE); +-} +-#endif // HAVE_LDAP +- +- + static void + sigterm_handler(int sig) + { +@@ -12728,10 +11381,6 @@ read_configuration (const char *filename) + { + if (!strcasecmp(p, "dnssd")) + protocols |= BROWSE_DNSSD; +- else if (!strcasecmp(p, "cups")) +- protocols |= BROWSE_CUPS; +- else if (!strcasecmp(p, "ldap")) +- protocols |= BROWSE_LDAP; + else if (strcasecmp(p, "none")) + debug_printf("Unknown protocol '%s'\n", p); + +@@ -13402,40 +12051,6 @@ read_configuration (const char *filename) + debug_printf("Invalid value for pause between calls of update_cups_queues(): %d\n", + t); + } +-#ifdef HAVE_LDAP +- else if (!strcasecmp(line, "BrowseLDAPBindDN") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPBindDN = strdup(value); +- } +-# ifdef HAVE_LDAP_SSL +- else if (!strcasecmp(line, "BrowseLDAPCACertFile") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPCACertFile = strdup(value); +- } +-# endif // HAVE_LDAP_SSL +- else if (!strcasecmp(line, "BrowseLDAPDN") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPDN = strdup(value); +- } +- else if (!strcasecmp(line, "BrowseLDAPPassword") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPPassword = strdup(value); +- } +- else if (!strcasecmp(line, "BrowseLDAPServer") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPServer = strdup(value); +- } +- else if (!strcasecmp(line, "BrowseLDAPFilter") && value) +- { +- if (value[0] != '\0') +- BrowseLDAPFilter = strdup(value); +- } +-#endif // HAVE_LDAP + } + + if (browse_line_found == 0) +@@ -13526,10 +12141,7 @@ find_previous_queue (gpointer key, + // in a certain time frame, we will remove the queue + p->status = STATUS_UNCONFIRMED; + +- if (BrowseRemoteProtocols & BROWSE_CUPS) +- p->timeout = time(NULL) + BrowseInterval * 3 / 2; +- else +- p->timeout = time(NULL) + TIMEOUT_CONFIRM; ++ p->timeout = time(NULL) + TIMEOUT_CONFIRM; + + p->slave_of = NULL; + debug_printf("Found CUPS queue %s (URI: %s) from previous session.\n", +@@ -13864,12 +12476,6 @@ main(int argc, char*argv[]) + BrowseLocalProtocols &= ~BROWSE_DNSSD; + } + +- if (BrowseLocalProtocols & BROWSE_LDAP) +- { +- debug_printf("Local support for LDAP not implemented\n"); +- BrowseLocalProtocols &= ~BROWSE_LDAP; +- } +- + #ifndef HAVE_AVAHI + if (BrowseRemoteProtocols & BROWSE_DNSSD) + { +@@ -13878,14 +12484,6 @@ main(int argc, char*argv[]) + } + #endif // HAVE_AVAHI + +-#ifndef HAVE_LDAP +- if (BrowseRemoteProtocols & BROWSE_LDAP) +- { +- debug_printf("Remote support for LDAP not supported\n"); +- BrowseRemoteProtocols &= ~BROWSE_LDAP; +- } +-#endif // HAVE_LDAP +- + // Wait for CUPS daemon to start + while ((http = http_connect_local ()) == NULL) + sleep(1); +@@ -13974,50 +12572,6 @@ main(int argc, char*argv[]) + } + } + +- if (BrowseLocalProtocols & BROWSE_CUPS || +- BrowseRemoteProtocols & BROWSE_CUPS) +- { +- // Set up our CUPS Browsing socket +- browsesocket = socket (AF_INET, SOCK_DGRAM, 0); +- if (browsesocket == -1) +- { +- debug_printf("failed to create CUPS Browsing socket: %s\n", +- strerror (errno)); +- } +- else +- { +- struct sockaddr_in addr; +- memset (&addr, 0, sizeof (addr)); +- addr.sin_addr.s_addr = htonl (INADDR_ANY); +- addr.sin_family = AF_INET; +- addr.sin_port = htons (BrowsePort); +- if (bind (browsesocket, (struct sockaddr *)&addr, sizeof (addr))) +- { +- debug_printf("failed to bind CUPS Browsing socket: %s\n", +- strerror (errno)); +- close (browsesocket); +- browsesocket = -1; +- } +- else +- { +- int on = 1; +- if (setsockopt (browsesocket, SOL_SOCKET, SO_BROADCAST, +- &on, sizeof (on))) +- { +- debug_printf("failed to allow broadcast: %s\n", +- strerror (errno)); +- BrowseLocalProtocols &= ~BROWSE_CUPS; +- } +- } +- } +- +- if (browsesocket == -1) +- { +- BrowseLocalProtocols &= ~BROWSE_CUPS; +- BrowseRemoteProtocols &= ~BROWSE_CUPS; +- } +- } +- + if (BrowseLocalProtocols == 0 && + BrowseRemoteProtocols == 0 && + !BrowsePoll) +@@ -14051,29 +12605,6 @@ main(int argc, char*argv[]) + gmainloop = g_main_loop_new (NULL, FALSE); + recheck_timer (); + +- if (BrowseRemoteProtocols & BROWSE_CUPS) +- { +- GIOChannel *browse_channel = g_io_channel_unix_new (browsesocket); +- g_io_channel_set_close_on_unref (browse_channel, FALSE); +- g_io_add_watch (browse_channel, G_IO_IN, process_browse_data, NULL); +- } +- +- if (BrowseLocalProtocols & BROWSE_CUPS) +- { +- debug_printf ("will send browse data every %ds\n", +- BrowseInterval); +- g_idle_add (send_browse_data, NULL); +- } +- +-#ifdef HAVE_LDAP +- if (BrowseRemoteProtocols & BROWSE_LDAP) +- { +- debug_printf ("will browse poll LDAP every %ds\n", +- BrowseInterval); +- g_idle_add (browse_ldap_poll, NULL); +- } +-#endif // HAVE_LDAP +- + if (BrowsePoll) + { + size_t index; +@@ -14194,24 +12725,12 @@ fail: + avahi_shutdown(); + #endif // HAVE_AVAHI + +-#ifdef HAVE_LDAP +- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) && +- BrowseLDAPHandle) +- { +- ldap_disconnect(BrowseLDAPHandle); +- BrowseLDAPHandle = NULL; +- } +-#endif // HAVE_LDAP +- + if (browsesocket != -1) + close (browsesocket); + + g_hash_table_destroy (local_printers); + g_hash_table_destroy (cups_supported_remote_printers); + +- if (BrowseLocalProtocols & BROWSE_CUPS) +- g_list_free_full (browse_data, browse_data_free); +- + // Close log file if we have one + if (debug_logfile == 1) + stop_debug_logging(); +diff --git a/daemon/cups-browsed.conf.5 b/daemon/cups-browsed.conf.5 +index 83c69d9f..4af67884 100644 +--- a/daemon/cups-browsed.conf.5 ++++ b/daemon/cups-browsed.conf.5 +@@ -47,7 +47,7 @@ journal or syslog. Only if you run cups-browsed from the command line + + .fam T + .fi +-Only browse remote printers (via DNS-SD or CUPS browsing) from ++Only browse remote printers (via DNS-SD) from + selected servers using the "BrowseAllow", "BrowseDeny", and + "BrowseOrder" directives + .PP +@@ -330,8 +330,6 @@ Printers from all servers except "prinserver2.local" are accepted: + The BrowsePoll directive polls a server for available printers once + every 60 seconds. Multiple BrowsePoll directives can be specified + to poll multiple servers. The default port to connect to is 631. +-BrowsePoll works independently of whether CUPS browsing is activated +-in BrowseRemoteProtocols. + .PP + .nf + .fam C +@@ -345,12 +343,11 @@ in BrowseRemoteProtocols. + The BrowseLocalProtocols directive specifies the protocols to use + when advertising local shared printers on the network. The default + is "none". Control of advertising of local shared printers using +-dnssd is done in /etc/cups/cupsd.conf. ++dnssd is done by CUPS and configured in /etc/cups/cupsd.conf. + .PP + .nf + .fam C + BrowseLocalProtocols none +- BrowseLocalProtocols CUPS + + + .fam T +@@ -358,50 +355,26 @@ dnssd is done in /etc/cups/cupsd.conf. + The BrowseRemoteProtocols directive specifies the protocols to use + when finding remote shared printers on the network. Multiple + protocols can be specified by separating them with spaces. +-The default is "dnssd cups". ++The default is "dnssd". + .PP + .nf + .fam C + BrowseRemoteProtocols none +- BrowseRemoteProtocols CUPS dnssd +- BrowseRemoteProtocols CUPS + BrowseRemoteProtocols dnssd +- BrowseRemoteProtocols ldap ++ + + .fam T + .fi + The BrowseProtocols directive specifies the protocols to use when + finding remote shared printers on the network and advertising local +-shared printers. "dnssd" and "ldap" are ignored for BrowseLocalProtocols. +-Multiple protocols can be specified by separating them with spaces. The +-default is "none" for BrowseLocalProtocols and "dnssd cups" for +-BrowseRemoteProtocols. ++shared printers. ++Multiple protocols can be specified by separating them with spaces. + .PP + .nf + .fam C + BrowseProtocols none +- BrowseProtocols CUPS dnssd +- BrowseProtocols CUPS + BrowseProtocols dnssd +- BrowseProtocols ldap + +-.fam T +-.fi +-The configuration for the LDAP browsing mode define where the LDAP search +-should be performed. If built with an LDAP library that supports TLS, the +-path to the server's certificate, or to a certificates store, can be +-specified. +-The optional filter allows the LDAP search to be more specific, and is used +-in addition to the hardcoded filter (objectclass=cupsPrinter). +-.PP +-.nf +-.fam C +- BrowseLDAPBindDN cn=cups-browsed,dc=domain,dc=tld +- BrowseLDAPCACertFile /path/to/server/certificate.pem +- BrowseLDAPDN ou=printers,dc=domain,dc=tld +- BrowseLDAPFilter (printerLocation=/Office 1/*) +- BrowseLDAPPassword s3cret +- BrowseLDAPServer ldaps://ldap.domain.tld + + .fam T + .fi +@@ -459,8 +432,6 @@ The BrowseTimeout directive determines the amount of time that + browsing-related operations are allowed to take in seconds. + Notably, adding or removing one printer queue is considered as one + operation. The timeout applies to each one of those operations. +-Especially queues discovered by CUPS broadcasts will be removed after +-this timeout if no further broadcast from the server happens. + .PP + .nf + .fam C +@@ -582,7 +553,7 @@ Set DNSSDBasedDeviceURIs to "No" if cups-browsed should use the + conventional host-name/IP-based URIs. + .PP + Note that this option has only influence on URIs for printers +-discovered via DNS-SD, not via legacy CUPS broewsing or LDAP. ++discovered via DNS-SD, not via BrowsePoll. + Those printers get always assigned the conventional URIs. + .PP + .nf +diff --git a/daemon/cups-browsed.conf.in b/daemon/cups-browsed.conf.in +index 6c9612c1..af026966 100644 +--- a/daemon/cups-browsed.conf.in ++++ b/daemon/cups-browsed.conf.in +@@ -36,27 +36,27 @@ + + + # Which protocols will we use to discover printers on the network? +-# Can use DNSSD and/or CUPS and/or LDAP, or 'none' for neither. ++# Can use DNSSD or 'none'. + + BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@ + + + # Which protocols will we use to broadcast shared local printers to the network? +-# Can use DNSSD and/or CUPS, or 'none' for neither. +-# Only CUPS is actually supported, as DNSSD is done by CUPS itself (we ignore +-# DNSSD in this directive). ++# Can use DNSSD or 'none'. ++# Broadcasting is currently not supported, as DNSSD is done by CUPS itself ++# (we ignore DNSSD in this directive). + + # BrowseLocalProtocols none + + + # Settings of this directive apply to both BrowseRemoteProtocols and + # BrowseLocalProtocols. +-# Can use DNSSD and/or CUPS and/or LDAP, or 'none' for neither. ++# Can use DNSSD or 'none'. + + # BrowseProtocols none + + +-# Only browse remote printers (via DNS-SD or CUPS browsing) from ++# Only browse remote printers (via DNS-SD) from + # selected servers using the "BrowseAllow", "BrowseDeny", and + # "BrowseOrder" directives + +@@ -120,8 +120,6 @@ BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@ + # Browsing-related operations such as adding or removing printer queues + # and broadcasting are each allowed to take up to a given amount of time. + # It can be configured, in seconds, with the BrowseTimeout directive. +-# Especially queues discovered by CUPS broadcasts will be removed after +-# this timeout if no further broadcast from the server happens. + + # BrowseTimeout 300 + +@@ -286,17 +284,6 @@ BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@ + # BrowsePoll cups.example.com:631/version=1.1 + + +-# LDAP browsing configuration +-# The default value for all options is an empty string. Example configuration: +- +-# BrowseLDAPBindDN cn=cups-browsed,dc=domain,dc=tld +-# BrowseLDAPCACertFile /path/to/server/certificate.pem +-# BrowseLDAPDN ou=printers,dc=domain,dc=tld +-# BrowseLDAPFilter (printerLocation=/Office 1/*) +-# BrowseLDAPPassword s3cret +-# BrowseLDAPServer ldaps://ldap.domain.tld +- +- + # Use DomainSocket to access the local CUPS daemon via another than the + # default domain socket. "None" or "Off" lets cups-browsed not use CUPS' + # domain socket. +@@ -405,7 +392,7 @@ BrowseRemoteProtocols @BROWSEREMOTEPROTOCOLS@ + # conventional host-name/IP-based URIs. + + # Note that this option has only influence on URIs for printers +-# discovered via DNS-SD, not via legacy CUPS broewsing or LDAP. ++# discovered via DNS-SD, not via BrowsePoll. + # Those printers get always assigned the conventional URIs. + + # DNSSDBasedDeviceURIs Yes +diff --git a/test/run-tests.sh b/test/run-tests.sh +index f3dfaf3d..23a5dd29 100755 +--- a/test/run-tests.sh ++++ b/test/run-tests.sh +@@ -938,7 +938,7 @@ while test $tries -lt $timeout; do + done + + if test $tries -ge $timeout; then +- echo "FAIL: CUPS browsed did not remove CUPS queue ${queue_prefix}_ippeve_1 for first test printer!" ++ echo "FAIL: cups-browsed did not remove CUPS queue ${queue_prefix}_ippeve_1 for first test printer!" + clean_up 1 + exit 1 + fi +@@ -1021,7 +1021,7 @@ $runcups lpstat -v + echo "" + + if test $tries -ge $timeout; then +- echo "FAIL: CUPS browsed did not remove CUPS queue ${queue_prefix}_ippeve_2 for second test printer!" ++ echo "FAIL: cups-browsed did not remove CUPS queue ${queue_prefix}_ippeve_2 for second test printer!" + clean_up 1 + exit 1 + fi +-- +2.47.0 + diff --git a/SPECS/cups-browsed.spec b/SPECS/cups-browsed.spec index 99ac6cc..e22c8a8 100644 --- a/SPECS/cups-browsed.spec +++ b/SPECS/cups-browsed.spec @@ -10,7 +10,7 @@ Name: cups-browsed Epoch: 1 Version: 2.0.0 -Release: 6%{?dist} +Release: 8%{?dist} Summary: Daemon for local auto-installation of remote printers # the CUPS exception text is the same as LLVM exception, so using that name with # agreement from legal team @@ -30,6 +30,10 @@ Patch003: browsed-goto-fail.patch # https://github.com/OpenPrinting/cups-browsed/pull/32 # https://github.com/OpenPrinting/cups-browsed/pull/33 Patch04: browsed-ignore-NULL-attrs.patch +# CVE-2024-47176 cups-browsed: cups-browsed binds on UDP INADDR_ANY:631 trusting any packet from any source +Patch05: 0001-Removed-support-for-legacy-CUPS-browsing-and-for-LDA.patch +# RHEL-17124 [cups-browsed] Prints to remote RAW queues are converted to PDF documents +Patch07: 0001-Do-not-generate-PPD-for-remote-raw-queues-44.patch # remove once CentOS Stream 10 is released, cups-browsed @@ -160,6 +164,14 @@ do fi done +# Set BrowseRemoteProtocols to none in light of CVE-2024-47176 +if ! grep -Fxq "# added by post scriptlet" %{_sysconfdir}/cups/cups-browsed.conf +then + cp %{_sysconfdir}/cups/cups-browsed.conf %{_sysconfdir}/cups/cups-browsed.conf.rpmsave + sed -i "s/^\s*BrowseRemoteProtocols.*/# added by post scriptlet\nBrowseRemoteProtocols none/" %{_sysconfdir}/cups/cups-browsed.conf +fi + + %preun %systemd_preun cups-browsed.service @@ -216,6 +228,14 @@ fi %changelog +* Tue Oct 29 2024 Troy Dawson - 1:2.0.0-8 +- Bump release for October 2024 mass rebuild: + Resolves: RHEL-64018 + +* Tue Oct 15 2024 Zdenek Dohnal - 1:2.0.0-7 +- CVE-2024-47176 cups-browsed: cups-browsed binds on UDP INADDR_ANY:631 trusting any packet from any source +- RHEL-17124 [cups-browsed] Prints to remote RAW queues are converted to PDF documents + * Tue Aug 06 2024 Zdenek Dohnal - 1:2.0.0-6 - RHEL-51349 Cups browsing with 'Autoclustering on' cannot find printer clusters for HA due incorrect orientation-requested-default