/*
- * "$Id: dirsvc.c 6003 2006-10-02 16:26:04Z mike $"
+ * "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $"
*
* Directory services routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * Copyright 2007 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
+ * cupsdDeregisterPrinter() - Stop sending broadcast information for a
+ * local printer and remove any pending
+ * references to remote printers.
* cupsdLoadRemoteCache() - Load the remote printer cache.
+ * cupsdRegisterPrinter() - Start sending broadcast information for a
+ * printer update the broadcast contents.
* cupsdSaveRemoteCache() - Save the remote printer cache.
- * cupsdSendBrowseDelete() - Send a "browse delete" message for a
- * printer.
* cupsdSendBrowseList() - Send new browsing information as necessary.
* cupsdStartBrowsing() - Start sending and receiving broadcast
* information.
* cupsdStopBrowsing() - Stop sending and receiving broadcast
* information.
* cupsdStopPolling() - Stop polling servers as needed.
- * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS
- * protocol.
+ * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries.
* cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
- * cupsdUpdatePolling() - Read status messages from the poll daemons.
* cupsdUpdateSLPBrowse() - Get browsing information via SLP.
+ * dnssdBuildTxtRecord() - Build a TXT record from printer info.
+ * dnssdDeregisterPrinter() - Stop sending broadcast information for a
+ * printer.
+ * dnssdPackTxtRecord() - Pack an array of key/value pairs into the
+ * TXT record format.
+ * dnssdRegisterCallback() - DNSServiceRegister callback.
+ * dnssdRegisterPrinter() - Start sending broadcast information for a
+ * printer or update the broadcast contents.
* dequote() - Remote quotes from a string.
* process_browse_data() - Process new browse data.
* process_implicit_classes() - Create/update implicit classes as needed.
* slp_get_attr() - Get an attribute from an SLP registration.
* slp_reg_callback() - Empty SLPRegReport.
* slp_url_callback() - SLP service url callback
+ * update_cups_browse() - Update the browse lists using the CUPS
+ * protocol.
+ * update_lpd() - Update the LPD configuration as needed.
+ * update_polling() - Read status messages from the poll daemons.
+ * update_smb() - Update the SMB configuration as needed.
*/
/*
#include "cupsd.h"
#include <grp.h>
+#ifdef HAVE_DNSSD
+# include <dns_sd.h>
+# ifdef __APPLE__
+# include <nameser.h>
+# ifdef HAVE_COREFOUNDATION
+# include <CoreFoundation/CoreFoundation.h>
+# endif /* HAVE_COREFOUNDATION */
+# ifdef HAVE_SYSTEMCONFIGURATION
+# include <SystemConfiguration/SystemConfiguration.h>
+# endif /* HAVE_SYSTEMCONFIGURATION */
+# endif /* __APPLE__ */
+#endif /* HAVE_DNSSD */
+
/*
* Local functions...
ipp_pstate_t state, const char *location,
const char *info, const char *make_model,
int num_attrs, cups_option_t *attrs);
-static void process_implicit_classes(void);
+static void process_implicit_classes(int *write_printcap);
static void send_cups_browse(cupsd_printer_t *p);
#ifdef HAVE_LDAP
static void send_ldap_browse(cupsd_printer_t *p);
#ifdef HAVE_LIBSLP
static void send_slp_browse(cupsd_printer_t *p);
#endif /* HAVE_LIBSLP */
+static void update_cups_browse(void);
+static void update_lpd(int onoff);
+static void update_polling(void);
+static void update_smb(int onoff);
+
#ifdef HAVE_OPENLDAP
static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
SLPError errcode, void *cookie);
#endif /* HAVE_LIBSLP */
+#ifdef HAVE_DNSSD
+/*
+ * For IPP register using a subtype of 'cups' so that shared printer browsing
+ * only finds other CUPS servers (not all IPP based printers).
+ */
+static char dnssdIPPRegType[] = "_ipp._tcp,_cups";
+static char dnssdIPPFaxRegType[] = "_fax-ipp._tcp";
+
+static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p);
+static void dnssdDeregisterPrinter(cupsd_printer_t *p);
+static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
+ int count);
+static void dnssdRegisterCallback(DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ DNSServiceErrorType errorCode,
+ const char *name, const char *regtype,
+ const char *domain, void *context);
+static void dnssdRegisterPrinter(cupsd_printer_t *p);
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
+ * local printer and remove any pending
+ * references to remote printers.
+ */
+
+void
+cupsdDeregisterPrinter(
+ cupsd_printer_t *p, /* I - Printer to register */
+ int removeit) /* I - Printer being permanently removed */
+{
+ /*
+ * Only deregister if browsing is enabled and it's a local printers...
+ */
+
+ if (!Browsing || !p->shared ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ return;
+
+ /*
+ * Announce the deletion...
+ */
+
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
+ {
+ cups_ptype_t savedtype = p->type; /* Saved printer type */
+
+ p->type |= CUPS_PRINTER_DELETE;
+
+ send_cups_browse(p);
+
+ p->type = savedtype;
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseLocalProtocols & BROWSE_SLP)
+ slp_dereg_printer(p);
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_DNSSD
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
+ dnssdDeregisterPrinter(p);
+#endif /* HAVE_DNSSD */
+}
+
/*
* 'cupsdLoadRemoteCache()' - Load the remote printer cache.
time_t now; /* Current time */
+ /*
+ * Don't load the cache if the CUPS remote protocol is disabled...
+ */
+
+ if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdLoadRemoteCache: Not loading remote cache.");
+ return;
+ }
+
/*
* Open the remote.cache file...
*/
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
- p->type |= CUPS_PRINTER_REMOTE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
p->accepting = 1;
p->state = IPP_PRINTER_IDLE;
- p->type |= CUPS_PRINTER_REMOTE;
+ p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
p->browse_time = now;
p->browse_expire = now + BrowseTimeout;
* Do auto-classing if needed...
*/
- process_implicit_classes();
+ process_implicit_classes(NULL);
+}
+
+
+/*
+ * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
+ * printer or update the broadcast contents.
+ */
+
+void
+cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ return;
+
+#ifdef HAVE_LIBSLP
+/* if (BrowseLocalProtocols & BROWSE_SLP)
+ slpRegisterPrinter(p); */
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_DNSSD
+ if (BrowseLocalProtocols & BROWSE_DNSSD)
+ dnssdRegisterPrinter(p);
+#endif /* HAVE_DNSSD */
}
return;
}
else
- cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache...");
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
/*
* Restrict access to the file...
* Skip local destinations...
*/
- if (!(printer->type & CUPS_PRINTER_REMOTE))
+ if (!(printer->type & CUPS_PRINTER_DISCOVERED))
continue;
/*
}
-/*
- * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer.
- */
-
-void
-cupsdSendBrowseDelete(
- cupsd_printer_t *p) /* I - Printer to delete */
-{
- /*
- * Only announce if browsing is enabled and this is a local queue...
- */
-
- if (!Browsing || !p->shared ||
- (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
- return;
-
- /*
- * First mark the printer for deletion...
- */
-
- p->type |= CUPS_PRINTER_DELETE;
-
- /*
- * Announce the deletion...
- */
-
- if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
- send_cups_browse(p);
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols & BROWSE_SLP) && BrowseSLPHandle)
- slp_dereg_printer(p);
-#endif /* HAVE_LIBSLP */
-}
-
-
/*
* 'cupsdSendBrowseList()' - Send new browsing information as necessary.
*/
cupsd_printer_t *p; /* Current printer */
time_t ut, /* Minimum update time */
to; /* Timeout time */
+ int write_printcap; /* Write the printcap file? */
if (!Browsing || !BrowseLocalProtocols || !Printers)
p->browse_time = time(NULL);
- if (BrowseLocalProtocols & BROWSE_CUPS)
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
send_cups_browse(p);
#ifdef HAVE_LIBSLP
* Loop through all of the printers and send local updates as needed...
*/
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0;
p;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
{
* If this is a remote queue, see if it needs to be timed out...
*/
- if (p->type & CUPS_PRINTER_REMOTE)
+ if (p->type & CUPS_PRINTER_DISCOVERED)
{
if (p->browse_expire < to)
{
cupsArraySave(Printers);
cupsdDeletePrinter(p, 1);
cupsArrayRestore(Printers);
+ write_printcap = 1;
}
}
}
+
+ if (write_printcap)
+ cupsdWritePrintcap();
}
{
int val; /* Socket option value */
struct sockaddr_in addr; /* Broadcast address */
+ cupsd_printer_t *p; /* Current printer */
BrowseNext = NULL;
if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to create broadcast "
- "socket - %s.", strerror(errno));
+ "Unable to create broadcast socket - %s.",
+ strerror(errno));
BrowseLocalProtocols &= ~BROWSE_CUPS;
BrowseRemoteProtocols &= ~BROWSE_CUPS;
return;
if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to bind broadcast "
- "socket - %s.", strerror(errno));
+ "Unable to bind broadcast socket - %s.",
+ strerror(errno));
#ifdef WIN32
closesocket(BrowseSocket);
val = 1;
if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
strerror(errno));
#ifdef WIN32
* We only listen if we want remote printers...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartBrowsing: Adding fd %d to InputSet...",
- BrowseSocket);
-
- FD_SET(BrowseSocket, InputSet);
+ cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
+ NULL, NULL);
}
}
else
struct berval bv = {0, ""}; /* SASL bind value */
+ /*
+ * Set the certificate file to use for encrypted LDAP sessions...
+ */
+
+ if (BrowseLDAPCACertFile)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
+ BrowseLDAPCACertFile);
+
+ if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ (void *)BrowseLDAPCACertFile))
+ != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to set CA certificate file for LDAP "
+ "connections: %d - %s", rc, ldap_err2string(rc));
+ }
+
/*
* LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
*/
BrowseLDAPRefresh = 0;
}
#endif /* HAVE_OPENLDAP */
+
+ /*
+ * Enable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(1);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(1);
+
+ /*
+ * Register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ cupsdRegisterPrinter(p);
}
argv[1] = pollp->hostname;
- if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1,
+ if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
0, &(pollp->pid)) < 0)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
* Finally, add the pipe to the input selection set...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe);
-
- FD_SET(PollPipe, InputSet);
+ cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
}
void
cupsdStopBrowsing(void)
{
+ cupsd_printer_t *p; /* Current printer */
+
+
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
return;
+ /*
+ * De-register the individual printers
+ */
+
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ cupsdDeregisterPrinter(p, 1);
+
+ /*
+ * Shut down browsing sockets...
+ */
+
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
BrowseSocket >= 0)
{
close(BrowseSocket);
#endif /* WIN32 */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopBrowsing: Removing fd %d from InputSet...",
- BrowseSocket);
-
- FD_CLR(BrowseSocket, InputSet);
+ cupsdRemoveSelect(BrowseSocket);
BrowseSocket = -1;
}
BrowseLDAPHandle = NULL;
}
#endif /* HAVE_OPENLDAP */
+
+ /*
+ * Disable LPD and SMB printer sharing as needed through external programs...
+ */
+
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(0);
+
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(0);
}
cupsdStatBufDelete(PollStatusBuffer);
close(PollPipe);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopPolling: removing fd %d from InputSet.", PollPipe);
- FD_CLR(PollPipe, InputSet);
+ cupsdRemoveSelect(PollPipe);
PollPipe = -1;
PollStatusBuffer = NULL;
}
+#ifdef HAVE_DNSSD
/*
- * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
*/
void
-cupsdUpdateCUPSBrowse(void)
+cupsdUpdateDNSSDBrowse(
+ cupsd_printer_t *p) /* I - Printer being queried */
{
- int i; /* Looping var */
- int auth; /* Authorization status */
- int len; /* Length of name string */
- int bytes; /* Number of bytes left */
- char packet[1541], /* Broadcast packet */
- *pptr; /* Pointer into packet */
- socklen_t srclen; /* Length of source address */
- http_addr_t srcaddr; /* Source address */
- char srcname[1024]; /* Source hostname */
- unsigned address[4]; /* Source address */
- unsigned type; /* Printer type */
- unsigned state; /* Printer state */
- char uri[HTTP_MAX_URI], /* Printer URI */
- host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI], /* Resource portion of URI */
- info[IPP_MAX_NAME], /* Information string */
- location[IPP_MAX_NAME], /* Location string */
- make_model[IPP_MAX_NAME];/* Make and model string */
- int num_attrs; /* Number of attributes */
- cups_option_t *attrs; /* Attributes */
-
+ DNSServiceErrorType sdErr; /* Service discovery error */
- /*
- * Read a packet from the browse socket...
- */
- srclen = sizeof(srcaddr);
- if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
- (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
+ != kDNSServiceErr_NoError)
{
- /*
- * "Connection refused" is returned under Linux if the destination port
- * or address is unreachable from a previous sendto(); check for the
- * error here and ignore it for now...
- */
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS Service Discovery registration error %d for \"%s\"!",
+ sdErr, p->name);
+ cupsdRemoveSelect(p->dnssd_ipp_fd);
+ DNSServiceRefDeallocate(p->dnssd_ipp_ref);
- if (errno != ECONNREFUSED && errno != EAGAIN)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
- strerror(errno));
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+ p->dnssd_ipp_ref = NULL;
+ p->dnssd_ipp_fd = -1;
+ }
+}
+#endif /* HAVE_DNSSD */
- cupsdStopBrowsing();
- Browsing = 0;
- }
- return;
- }
+#ifdef HAVE_OPENLDAP
+/*
+ * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
+ */
+
+void
+cupsdUpdateLDAPBrowse(void)
+{
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ host[HTTP_MAX_URI], /* Hostname */
+ resource[HTTP_MAX_URI], /* Resource path */
+ location[1024], /* Printer location */
+ info[1024], /* Printer information */
+ make_model[1024], /* Printer make and model */
+ **value; /* Holds the returned data from LDAP */
+ int type; /* Printer type */
+ int rc; /* LDAP status */
+ int limit; /* Size limit */
+ LDAPMessage *res, /* LDAP search results */
+ *e; /* Current entry from search */
- packet[bytes] = '\0';
/*
- * If we're about to sleep, ignore incoming browse packets.
+ * Search for printers...
*/
- if (Sleeping)
- return;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
- /*
- * Figure out where it came from...
- */
+ BrowseLDAPRefresh = time(NULL) + BrowseInterval;
-#ifdef AF_INET6
- if (srcaddr.addr.sa_family == AF_INET6)
- {
- address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
- address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
- address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
- address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
- }
- else
-#endif /* AF_INET6 */
+ rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
+ if (rc != LDAP_SUCCESS)
{
- address[0] = 0;
- address[1] = 0;
- address[2] = 0;
- address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP search returned error %d: %s", rc,
+ ldap_err2string(rc));
+ return;
}
- if (HostNameLookups)
- httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
- else
- httpAddrString(&srcaddr, srcname, sizeof(srcname));
-
- len = strlen(srcname);
+ limit = ldap_count_entries(BrowseLDAPHandle, res);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
+ if (limit < 1)
+ return;
/*
- * Do ACL stuff...
+ * Loop through the available printers...
*/
- if (BrowseACL)
- {
- if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
- {
- /*
- * Access from localhost (127.0.0.1) is always allowed...
- */
-
- auth = AUTH_ALLOW;
- }
- else
- {
- /*
- * Do authorization checks on the domain/address...
- */
-
- switch (BrowseACL->order_type)
- {
- default :
- auth = AUTH_DENY; /* anti-compiler-warning-code */
- break;
-
- case AUTH_ALLOW : /* Order Deny,Allow */
- auth = AUTH_ALLOW;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
- break;
-
- case AUTH_DENY : /* Order Allow,Deny */
- auth = AUTH_DENY;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
-
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
- break;
- }
- }
- }
- else
- auth = AUTH_ALLOW;
-
- if (auth == AUTH_DENY)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
- srcname);
- return;
- }
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
- srcname, packet);
-
- /*
- * Parse packet...
- */
-
- if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
- {
- cupsdLogMessage(CUPSD_LOG_WARN,
- "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
- return;
- }
-
- strcpy(location, "Location Unknown");
- strcpy(info, "No Information Available");
- make_model[0] = '\0';
- num_attrs = 0;
- attrs = NULL;
-
- if ((pptr = strchr(packet, '\"')) != NULL)
- {
- /*
- * Have extended information; can't use sscanf for it because not all
- * sscanf's allow empty strings with %[^\"]...
- */
-
- for (i = 0, pptr ++;
- i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- location[i] = *pptr;
-
- if (i)
- location[i] = '\0';
-
- if (*pptr == '\"')
- pptr ++;
-
- while (*pptr && isspace(*pptr & 255))
- pptr ++;
-
- if (*pptr == '\"')
- {
- for (i = 0, pptr ++;
- i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- info[i] = *pptr;
-
- info[i] = '\0';
-
- if (*pptr == '\"')
- pptr ++;
-
- while (*pptr && isspace(*pptr & 255))
- pptr ++;
-
- if (*pptr == '\"')
- {
- for (i = 0, pptr ++;
- i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
- i ++, pptr ++)
- make_model[i] = *pptr;
-
- if (*pptr == '\"')
- pptr ++;
-
- make_model[i] = '\0';
-
- if (*pptr)
- num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
- }
- }
- }
-
- DEBUG_puts(packet);
- DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
- "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
- type, state, uri, location, info, make_model));
-
- /*
- * Pull the URI apart to see if this is a local or remote printer...
- */
-
- if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
- {
- cupsFreeOptions(num_attrs, attrs);
- return;
- }
-
- /*
- * Do relaying...
- */
-
- for (i = 0; i < NumRelays; i ++)
- if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
- if (sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)&(Relays[i].to),
- httpAddrLength(&(Relays[i].to))) <= 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
- i + 1, strerror(errno));
- cupsFreeOptions(num_attrs, attrs);
- return;
- }
-
- /*
- * Process the browse data...
- */
-
- process_browse_data(uri, host, resource, (cups_ptype_t)type,
- (ipp_pstate_t)state, location, info, make_model,
- num_attrs, attrs);
-}
-
-
-#ifdef HAVE_OPENLDAP
-/*
- * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
- */
-
-void
-cupsdUpdateLDAPBrowse(void)
-{
- char uri[HTTP_MAX_URI], /* Printer URI */
- host[HTTP_MAX_URI], /* Hostname */
- resource[HTTP_MAX_URI], /* Resource path */
- location[1024], /* Printer location */
- info[1024], /* Printer information */
- make_model[1024], /* Printer make and model */
- **value; /* Holds the returned data from LDAP */
- int type; /* Printer type */
- int rc; /* LDAP status */
- int limit; /* Size limit */
- LDAPMessage *res, /* LDAP search results */
- *e; /* Current entry from search */
-
-
- /*
- * Search for printers...
- */
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
-
- BrowseLDAPRefresh = time(NULL) + BrowseInterval;
-
- rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
- if (rc != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP search returned error %d: %s", rc,
- ldap_err2string(rc));
- return;
- }
-
- limit = ldap_count_entries(BrowseLDAPHandle, res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
- if (limit < 1)
- return;
-
- /*
- * Loop through the available printers...
- */
-
- for (e = ldap_first_entry(BrowseLDAPHandle, res);
- e;
- e = ldap_next_entry(BrowseLDAPHandle, e))
+ for (e = ldap_first_entry(BrowseLDAPHandle, res);
+ e;
+ e = ldap_next_entry(BrowseLDAPHandle, e))
{
/*
* Get the required values from this entry...
#endif /* HAVE_OPENLDAP */
-/*
- * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
- */
-
-void
-cupsdUpdatePolling(void)
-{
- char *ptr, /* Pointer to end of line in buffer */
- message[1024]; /* Pointer to message text */
- int loglevel; /* Log level for message */
-
-
- while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
- message, sizeof(message))) != NULL)
- if (!strchr(PollStatusBuffer->buffer, '\n'))
- break;
-
- if (ptr == NULL && !PollStatusBuffer->bufused)
- {
- /*
- * All polling processes have died; stop polling...
- */
-
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdUpdatePolling: all polling processes have exited!");
- cupsdStopPolling();
- }
-}
-
-
#ifdef HAVE_LIBSLP
/*
* 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
cups_option_t *attrs) /* I - Attributes */
{
int i; /* Looping var */
- int update; /* Update printer attributes? */
+ int update, /* Update printer attributes? */
+ write_printcap; /* Write the printcap file? */
char finaluri[HTTP_MAX_URI], /* Final URI for printer */
name[IPP_MAX_NAME], /* Name of printer */
newname[IPP_MAX_NAME], /* New name of printer */
* See if we already have it listed in the Printers list, and add it if not...
*/
- type |= CUPS_PRINTER_REMOTE;
- type &= ~CUPS_PRINTER_IMPLICIT;
- update = 0;
- hptr = strchr(host, '.');
- sptr = strchr(ServerName, '.');
+ type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ type &= ~CUPS_PRINTER_IMPLICIT;
+ update = 0;
+ write_printcap = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
{
cupsdSetString(&p->device_uri, uri);
cupsdSetString(&p->hostname, host);
- update = 1;
+ update = 1;
+ write_printcap = 1;
}
}
else
cupsdSetString(&p->uri, uri);
cupsdSetString(&p->device_uri, uri);
- update = 1;
+ write_printcap = 1;
+ update = 1;
}
}
if (info && (!p->info || strcmp(p->info, info)))
{
cupsdSetString(&p->info, info);
- update = 1;
+ update = 1;
+ write_printcap = 1;
}
if (!make_model || !make_model[0])
cupsdDeletePrinter(p, 1);
cupsdUpdateImplicitClasses();
+ write_printcap = 1;
}
else if (update)
{
if (p->type & CUPS_PRINTER_DEFAULT)
{
DefaultPrinter = p;
+ write_printcap = 1;
break;
}
}
* Do auto-classing if needed...
*/
- process_implicit_classes();
+ process_implicit_classes(&write_printcap);
/*
* Update the printcap file...
*/
- cupsdWritePrintcap();
+ if (write_printcap)
+ cupsdWritePrintcap();
}
+#ifdef HAVE_DNSSD
/*
- * 'process_implicit_classes()' - Create/update implicit classes as needed.
+ * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
*/
-static void
-process_implicit_classes(void)
+static char * /* O - TXT record */
+dnssdBuildTxtRecord(
+ int *txt_len, /* O - TXT record length */
+ cupsd_printer_t *p) /* I - Printer information */
{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char name[IPP_MAX_NAME], /* Name of printer */
- *hptr; /* Pointer into hostname */
- cupsd_printer_t *p, /* Printer information */
+ int i, j; /* Looping vars */
+ char type_str[32], /* Type to string buffer */
+ state_str[32], /* State to string buffer */
+ rp_str[1024], /* Queue name string buffer */
+ air_str[1024], /* auth-info-required string buffer */
+ *keyvalue[32][2]; /* Table of key/value pairs */
+
+
+ /*
+ * Load up the key value pairs...
+ */
+
+ i = 0;
+
+ keyvalue[i ][0] = "txtvers";
+ keyvalue[i++][1] = "1";
+
+ keyvalue[i ][0] = "qtotal";
+ keyvalue[i++][1] = "1";
+
+ keyvalue[i ][0] = "rp";
+ keyvalue[i++][1] = rp_str;
+ snprintf(rp_str, sizeof(rp_str), "%s/%s",
+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
+
+ keyvalue[i ][0] = "ty";
+ keyvalue[i++][1] = p->make_model;
+
+ if (p->location && *p->location != '\0')
+ {
+ keyvalue[i ][0] = "note";
+ keyvalue[i++][1] = p->location;
+ }
+
+ keyvalue[i ][0] = "product";
+ keyvalue[i++][1] = p->product ? p->product : "Unknown";
+
+ snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
+ snprintf(state_str, sizeof(state_str), "%d", p->state);
+
+ keyvalue[i ][0] = "printer-state";
+ keyvalue[i++][1] = state_str;
+
+ keyvalue[i ][0] = "printer-type";
+ keyvalue[i++][1] = type_str;
+
+ keyvalue[i ][0] = "Transparent";
+ keyvalue[i++][1] = "T";
+
+ keyvalue[i ][0] = "Binary";
+ keyvalue[i++][1] = "T";
+
+ if ((p->type & CUPS_PRINTER_FAX))
+ {
+ keyvalue[i ][0] = "Fax";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_COLOR))
+ {
+ keyvalue[i ][0] = "Color";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_DUPLEX))
+ {
+ keyvalue[i ][0] = "Duplex";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_STAPLE))
+ {
+ keyvalue[i ][0] = "Staple";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_COPIES))
+ {
+ keyvalue[i ][0] = "Copies";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_COLLATE))
+ {
+ keyvalue[i ][0] = "Collate";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_PUNCH))
+ {
+ keyvalue[i ][0] = "Punch";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_BIND))
+ {
+ keyvalue[i ][0] = "Bind";
+ keyvalue[i++][1] = "T";
+ }
+
+ if ((p->type & CUPS_PRINTER_SORT))
+ {
+ keyvalue[i ][0] = "Sort";
+ keyvalue[i++][1] = "T";
+ }
+
+ keyvalue[i ][0] = "pdl";
+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+
+ if (p->num_auth_info_required)
+ {
+ char *air = air_str; /* Pointer into string */
+
+
+ for (j = 0; j < p->num_auth_info_required; j ++)
+ {
+ if (air >= (air_str + sizeof(air_str) - 2))
+ break;
+
+ if (j)
+ *air++ = ',';
+
+ strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
+ air += strlen(air);
+ }
+
+ keyvalue[i ][0] = "air";
+ keyvalue[i++][1] = air;
+ }
+
+ /*
+ * Then pack them into a proper txt record...
+ */
+
+ return (dnssdPackTxtRecord(txt_len, keyvalue, i));
+}
+
+
+/*
+ * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
+ * printer.
+ */
+
+static void
+dnssdDeregisterPrinter(
+ cupsd_printer_t *p) /* I - Printer */
+{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
+
+ /*
+ * Closing the socket deregisters the service
+ */
+
+ if (p->dnssd_ipp_ref)
+ {
+ cupsdRemoveSelect(p->dnssd_ipp_fd);
+ DNSServiceRefDeallocate(p->dnssd_ipp_ref);
+ p->dnssd_ipp_ref = NULL;
+ p->dnssd_ipp_fd = -1;
+ }
+
+ cupsdClearString(&p->reg_name);
+
+ if (p->txt_record)
+ {
+ /*
+ * p->txt_record is malloc'd, not _cupsStrAlloc'd...
+ */
+
+ free(p->txt_record);
+ p->txt_record = NULL;
+ }
+}
+
+
+/*
+ * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
+ * TXT record format.
+ */
+
+static char * /* O - TXT record */
+dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
+ char *keyvalue[][2], /* I - Table of key value pairs */
+ int count) /* I - Items in table */
+{
+ int i; /* Looping var */
+ int length; /* Length of TXT record */
+ int length2; /* Length of value */
+ char *txtRecord; /* TXT record buffer */
+ char *cursor; /* Looping pointer */
+
+
+ /*
+ * Calculate the buffer size
+ */
+
+ for (length = i = 0; i < count; i++)
+ length += 1 + strlen(keyvalue[i][0]) +
+ (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
+
+ /*
+ * Allocate and fill it
+ */
+
+ txtRecord = malloc(length);
+ if (txtRecord)
+ {
+ *txt_len = length;
+
+ for (cursor = txtRecord, i = 0; i < count; i++)
+ {
+ /*
+ * Drop in the p-string style length byte followed by the data
+ */
+
+ length = strlen(keyvalue[i][0]);
+ length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
+
+ *cursor++ = (unsigned char)(length + length2);
+
+ memcpy(cursor, keyvalue[i][0], length);
+ cursor += length;
+
+ if (length2)
+ {
+ length2 --;
+ *cursor++ = '=';
+ memcpy(cursor, keyvalue[i][1], length2);
+ cursor += length2;
+ }
+ }
+ }
+
+ return (txtRecord);
+}
+
+
+/*
+ * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
+ */
+
+static void
+dnssdRegisterCallback(
+ DNSServiceRef sdRef, /* I - DNS Service reference */
+ DNSServiceFlags flags, /* I - Reserved for future use */
+ DNSServiceErrorType errorCode, /* I - Error code */
+ const char *name, /* I - Service name */
+ const char *regtype, /* I - Service type */
+ const char *domain, /* I - Domain. ".local" for now */
+ void *context) /* I - User-defined context */
+{
+ (void)context;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "dnssdRegisterCallback(%s, %s)", name, regtype);
+
+ if (errorCode)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNSServiceRegister failed with error %d", (int)errorCode);
+ return;
+ }
+}
+
+
+/*
+ * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
+ * or update the broadcast contents.
+ */
+
+static void
+dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
+{
+ DNSServiceErrorType se; /* dnssd errors */
+ cupsd_listener_t *lis; /* Current listening socket */
+ char *txt_record, /* TXT record buffer */
+ *name; /* Service name */
+ int txt_len, /* TXT record length */
+ port; /* IPP port number */
+ char str_buffer[1024];
+ /* C-string buffer */
+ const char *computerName; /* Computer name c-string ptr */
+ const char *regtype; /* Registration type */
+#ifdef HAVE_COREFOUNDATION_H
+ CFStringRef computerNameRef;/* Computer name CFString */
+ CFStringEncoding nameEncoding; /* Computer name encoding */
+ CFMutableStringRef shortNameRef; /* Mutable name string */
+ CFIndex nameLength; /* Name string length */
+#else
+ int nameLength; /* Name string length */
+#endif /* HAVE_COREFOUNDATION_H */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
+ !p->dnssd_ipp_ref ? "new" : "update");
+
+ /*
+ * If per-printer sharing was just disabled make sure we're not
+ * registered before returning.
+ */
+
+ if (!p->shared)
+ {
+ dnssdDeregisterPrinter(p);
+ return;
+ }
+
+ /*
+ * Get the computer name as a c-string...
+ */
+
+#ifdef HAVE_COREFOUNDATION_H
+ computerName = NULL;
+ if ((computerNameRef = SCDynamicStoreCopyComputerName(NULL, &nameEncoding)))
+ if ((computerName = CFStringGetCStringPtr(computerNameRef,
+ kCFStringEncodingUTF8)) == NULL)
+ if (CFStringGetCString(computerNameRef, str_buffer, sizeof(str_buffer),
+ kCFStringEncodingUTF8))
+ computerName = str_buffer;
+#else
+ computerName = ServerName;
+#endif /* HAVE_COREFOUNDATION_H */
+
+ /*
+ * The registered name takes the form of "<printer-info> @ <computer name>"...
+ */
+
+ name = NULL;
+ if (computerName)
+ cupsdSetStringf(&name, "%s @ %s",
+ (p->info && strlen(p->info)) ? p->info : p->name,
+ computerName);
+ else
+ cupsdSetString(&name, (p->info && strlen(p->info)) ? p->info : p->name);
+
+#ifdef HAVE_COREFOUNDATION_H
+ if (computerNameRef)
+ CFRelease(computerNameRef);
+#endif /* HAVE_COREFOUNDATION_H */
+
+ /*
+ * If an existing printer was renamed, unregister it and start over...
+ */
+
+ if (p->reg_name && strcmp(p->reg_name, name))
+ dnssdDeregisterPrinter(p);
+
+ txt_len = 0; /* anti-compiler-warning-code */
+ txt_record = dnssdBuildTxtRecord(&txt_len, p);
+
+ if (!p->dnssd_ipp_ref)
+ {
+ /*
+ * Initial registration...
+ */
+
+ cupsdSetString(&p->reg_name, name);
+
+ port = ippPort();
+
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if (lis->address.addr.sa_family == AF_INET)
+ {
+ port = ntohs(lis->address.ipv4.sin_port);
+ break;
+ }
+ else if (lis->address.addr.sa_family == AF_INET6)
+ {
+ port = ntohs(lis->address.ipv6.sin6_port);
+ break;
+ }
+ }
+
+ /*
+ * Use the _fax subtype for fax queues...
+ */
+
+ regtype = (p->type & CUPS_PRINTER_FAX) ? dnssdIPPFaxRegType :
+ dnssdIPPRegType;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) type is \"%s\"",
+ p->name, regtype);
+
+ se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, name, regtype,
+ NULL, NULL, htons(port), txt_len, txt_record,
+ dnssdRegisterCallback, p);
+
+ /*
+ * In case the name is too long, try shortening the string one character
+ * at a time...
+ */
+
+ if (se == kDNSServiceErr_BadParam)
+ {
+#ifdef HAVE_COREFOUNDATION_H
+ if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL)
+ {
+ CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8);
+ nameLength = CFStringGetLength(shortNameRef);
+
+ while (se == kDNSServiceErr_BadParam && nameLength > 1)
+ {
+ CFStringDelete(shortNameRef, CFRangeMake(--nameLength, 1));
+ if (CFStringGetCString(shortNameRef, str_buffer, sizeof(str_buffer),
+ kCFStringEncodingUTF8))
+ {
+ se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer,
+ regtype, NULL, NULL, htons(port),
+ txt_len, txt_record,
+ dnssdRegisterCallback, p);
+ }
+ }
+
+ CFRelease(shortNameRef);
+ }
+#else
+ nameLength = strlen(name);
+ while (se == kDNSServiceErr_BadParam && nameLength > 1)
+ {
+ name[--nameLength] = '\0';
+ se = DNSServiceRegister(&p->dnssd_ipp_ref, 0, 0, str_buffer, regtype,
+ NULL, NULL, htons(port), txt_len, txt_record,
+ dnssdRegisterCallback, p);
+ }
+#endif /* HAVE_COREFOUNDATION_H */
+ }
+
+ if (se == kDNSServiceErr_NoError)
+ {
+ p->dnssd_ipp_fd = DNSServiceRefSockFD(p->dnssd_ipp_ref);
+ p->txt_record = txt_record;
+ p->txt_len = txt_len;
+ txt_record = NULL;
+
+ cupsdAddSelect(p->dnssd_ipp_fd, (cupsd_selfunc_t)cupsdUpdateDNSSDBrowse,
+ NULL, (void *)p);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD registration of \"%s\" failed with %d",
+ p->name, se);
+ }
+ else if (txt_len != p->txt_len || memcmp(txt_record, p->txt_record, txt_len))
+ {
+ /*
+ * Update the existing registration...
+ */
+
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ se = DNSServiceUpdateRecord(p->dnssd_ipp_ref, NULL, 0,
+ txt_len, txt_record, 0);
+
+ if (p->txt_record)
+ free(p->txt_record);
+
+ p->txt_record = txt_record;
+ p->txt_len = txt_len;
+ txt_record = NULL;
+ }
+
+ if (txt_record)
+ free(txt_record);
+
+ cupsdClearString(&name);
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'process_implicit_classes()' - Create/update implicit classes as needed.
+ */
+
+static void
+process_implicit_classes(
+ int *write_printcap) /* O - Write printcap file? */
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr; /* Pointer into hostname */
+ cupsd_printer_t *p, /* Printer information */
*pclass, /* Printer class */
*first; /* First printer in class */
int offset, /* Offset of name */
cupsdSetString(&pclass->location, p->location);
cupsdSetString(&pclass->info, p->info);
+ cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
+ cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
+
update = 1;
+ if (write_printcap)
+ *write_printcap = 1;
+
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
name);
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
/*
* 'send_cups_browse()' - Send new browsing information using the CUPS
- * protocol.
+ * protocol.
*/
static void
{
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
iface->hostname, iface->port,
- (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
+ (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
"/printers/%s",
p->name);
snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
/*
- * End of "$Id: dirsvc.c 6003 2006-10-02 16:26:04Z mike $".
+ * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
+ */
+
+static void
+update_cups_browse(void)
+{
+ int i; /* Looping var */
+ int auth; /* Authorization status */
+ int len; /* Length of name string */
+ int bytes; /* Number of bytes left */
+ char packet[1541], /* Broadcast packet */
+ *pptr; /* Pointer into packet */
+ socklen_t srclen; /* Length of source address */
+ http_addr_t srcaddr; /* Source address */
+ char srcname[1024]; /* Source hostname */
+ unsigned address[4]; /* Source address */
+ unsigned type; /* Printer type */
+ unsigned state; /* Printer state */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI], /* Resource portion of URI */
+ info[IPP_MAX_NAME], /* Information string */
+ location[IPP_MAX_NAME], /* Location string */
+ make_model[IPP_MAX_NAME];/* Make and model string */
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
+
+
+ /*
+ * Read a packet from the browse socket...
+ */
+
+ srclen = sizeof(srcaddr);
+ if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
+ (struct sockaddr *)&srcaddr, &srclen)) < 0)
+ {
+ /*
+ * "Connection refused" is returned under Linux if the destination port
+ * or address is unreachable from a previous sendto(); check for the
+ * error here and ignore it for now...
+ */
+
+ if (errno != ECONNREFUSED && errno != EAGAIN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
+ strerror(errno));
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+
+ cupsdStopBrowsing();
+ Browsing = 0;
+ }
+
+ return;
+ }
+
+ packet[bytes] = '\0';
+
+ /*
+ * If we're about to sleep, ignore incoming browse packets.
+ */
+
+ if (Sleeping)
+ return;
+
+ /*
+ * Figure out where it came from...
+ */
+
+#ifdef AF_INET6
+ if (srcaddr.addr.sa_family == AF_INET6)
+ {
+ address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
+ address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
+ address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
+ address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
+ }
+ else
+#endif /* AF_INET6 */
+ {
+ address[0] = 0;
+ address[1] = 0;
+ address[2] = 0;
+ address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+ }
+
+ if (HostNameLookups)
+ httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
+ else
+ httpAddrString(&srcaddr, srcname, sizeof(srcname));
+
+ len = strlen(srcname);
+
+ /*
+ * Do ACL stuff...
+ */
+
+ if (BrowseACL)
+ {
+ if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
+ {
+ /*
+ * Access from localhost (127.0.0.1) is always allowed...
+ */
+
+ auth = AUTH_ALLOW;
+ }
+ else
+ {
+ /*
+ * Do authorization checks on the domain/address...
+ */
+
+ switch (BrowseACL->order_type)
+ {
+ default :
+ auth = AUTH_DENY; /* anti-compiler-warning-code */
+ break;
+
+ case AUTH_ALLOW : /* Order Deny,Allow */
+ auth = AUTH_ALLOW;
+
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
+
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
+ break;
+
+ case AUTH_DENY : /* Order Allow,Deny */
+ auth = AUTH_DENY;
+
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_allow, BrowseACL->allow))
+ auth = AUTH_ALLOW;
+
+ if (cupsdCheckAuth(address, srcname, len,
+ BrowseACL->num_deny, BrowseACL->deny))
+ auth = AUTH_DENY;
+ break;
+ }
+ }
+ }
+ else
+ auth = AUTH_ALLOW;
+
+ if (auth == AUTH_DENY)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "update_cups_browse: Refused %d bytes from %s", bytes,
+ srcname);
+ return;
+ }
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "update_cups_browse: (%d bytes from %s) %s", bytes,
+ srcname, packet);
+
+ /*
+ * Parse packet...
+ */
+
+ if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "update_cups_browse: Garbled browse packet - %s", packet);
+ return;
+ }
+
+ strcpy(location, "Location Unknown");
+ strcpy(info, "No Information Available");
+ make_model[0] = '\0';
+ num_attrs = 0;
+ attrs = NULL;
+
+ if ((pptr = strchr(packet, '\"')) != NULL)
+ {
+ /*
+ * Have extended information; can't use sscanf for it because not all
+ * sscanf's allow empty strings with %[^\"]...
+ */
+
+ for (i = 0, pptr ++;
+ i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ location[i] = *pptr;
+
+ if (i)
+ location[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ info[i] = *pptr;
+
+ info[i] = '\0';
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ while (*pptr && isspace(*pptr & 255))
+ pptr ++;
+
+ if (*pptr == '\"')
+ {
+ for (i = 0, pptr ++;
+ i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
+ i ++, pptr ++)
+ make_model[i] = *pptr;
+
+ if (*pptr == '\"')
+ pptr ++;
+
+ make_model[i] = '\0';
+
+ if (*pptr)
+ num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
+ }
+ }
+ }
+
+ DEBUG_puts(packet);
+ DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
+ "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
+ type, state, uri, location, info, make_model));
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ {
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
+
+ /*
+ * Do relaying...
+ */
+
+ for (i = 0; i < NumRelays; i ++)
+ if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)&(Relays[i].to),
+ httpAddrLength(&(Relays[i].to))) <= 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_cups_browse: sendto failed for relay %d - %s.",
+ i + 1, strerror(errno));
+ cupsFreeOptions(num_attrs, attrs);
+ return;
+ }
+
+ /*
+ * Process the browse data...
+ */
+
+ process_browse_data(uri, host, resource, (cups_ptype_t)type,
+ (ipp_pstate_t)state, location, info, make_model,
+ num_attrs, attrs);
+}
+
+
+/*
+ * 'update_lpd()' - Update the LPD configuration as needed.
+ */
+
+static void
+update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
+{
+ if (!LPDConfigFile)
+ return;
+
+ if (!strncmp(LPDConfigFile, "xinetd:///", 10))
+ {
+ /*
+ * Enable/disable LPD via the xinetd.d config file for cups-lpd...
+ */
+
+ char newfile[1024]; /* New cups-lpd.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
+
+
+ snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
+
+ if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ LPDConfigFile + 9, strerror(errno));
+ return;
+ }
+
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
+
+ /*
+ * Copy all of the lines from the cups-lpd file...
+ */
+
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (line[0] == '{')
+ {
+ cupsFilePrintf(nfp, "%s\n", line);
+ snprintf(line, sizeof(line), "\tdisable = %s",
+ onoff ? "no" : "yes");
+ }
+ else if (strstr(line, "disable ="))
+ continue;
+
+ cupsFilePrintf(nfp, "%s\n", line);
+ }
+
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, LPDConfigFile + 9);
+ }
+ else if (!strncmp(LPDConfigFile, "launchd:///", 11))
+ {
+ /*
+ * Enable/disable LPD via the launchctl command...
+ */
+
+ char *argv[5], /* Arguments for command */
+ *envp[MAX_ENV]; /* Environment for command */
+ int pid; /* Process ID */
+
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+ argv[0] = (char *)"launchctl";
+ argv[1] = (char *)(onoff ? "load" : "unload");
+ argv[2] = (char *)"-w";
+ argv[3] = LPDConfigFile + 10;
+ argv[4] = NULL;
+
+ cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+ }
+}
+
+
+/*
+ * 'update_polling()' - Read status messages from the poll daemons.
+ */
+
+static void
+update_polling(void)
+{
+ char *ptr, /* Pointer to end of line in buffer */
+ message[1024]; /* Pointer to message text */
+ int loglevel; /* Log level for message */
+
+
+ while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ if (!strchr(PollStatusBuffer->buffer, '\n'))
+ break;
+
+ if (ptr == NULL && !PollStatusBuffer->bufused)
+ {
+ /*
+ * All polling processes have died; stop polling...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "update_polling: all polling processes have exited!");
+ cupsdStopPolling();
+ }
+}
+
+
+/*
+ * 'update_smb()' - Update the SMB configuration as needed.
+ */
+
+static void
+update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
+{
+ if (!SMBConfigFile)
+ return;
+
+ if (!strncmp(SMBConfigFile, "samba:///", 9))
+ {
+ /*
+ * Enable/disable SMB via the specified smb.conf config file...
+ */
+
+ char newfile[1024]; /* New smb.conf.N file */
+ cups_file_t *ofp, /* Original file pointer */
+ *nfp; /* New file pointer */
+ char line[1024]; /* Line from file */
+ int in_printers; /* In [printers] section? */
+
+
+ snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
+
+ if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+ SMBConfigFile + 8, strerror(errno));
+ return;
+ }
+
+ if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+ newfile, strerror(errno));
+ cupsFileClose(ofp);
+ return;
+ }
+
+ /*
+ * Copy all of the lines from the smb.conf file...
+ */
+
+ in_printers = 0;
+
+ while (cupsFileGets(ofp, line, sizeof(line)))
+ {
+ if (in_printers && strstr(line, "printable ="))
+ snprintf(line, sizeof(line), " printable = %s",
+ onoff ? "yes" : "no");
+
+ cupsFilePrintf(nfp, "%s\n", line);
+
+ if (line[0] == '[')
+ in_printers = !strcmp(line, "[printers]");
+ }
+
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, SMBConfigFile + 8);
+ }
+ else if (!strncmp(SMBConfigFile, "launchd:///", 11))
+ {
+ /*
+ * Enable/disable SMB via the launchctl command...
+ */
+
+ char *argv[5], /* Arguments for command */
+ *envp[MAX_ENV]; /* Environment for command */
+ int pid; /* Process ID */
+
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+ argv[0] = (char *)"launchctl";
+ argv[1] = (char *)(onoff ? "load" : "unload");
+ argv[2] = (char *)"-w";
+ argv[3] = SMBConfigFile + 10;
+ argv[4] = NULL;
+
+ cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+ }
+}
+
+
+/*
+ * End of "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $".
*/