/*
- * "$Id: dirsvc.c 6538 2007-05-17 18:26:05Z mike $"
+ * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $"
*
- * Directory services routines for the Common UNIX Printing System (CUPS).
+ * Directory services routines for the CUPS scheduler.
*
+ * Copyright 2007-2011 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.
- * cupsdSendBrowseList() - Send new browsing information as necessary.
- * cupsdStartBrowsing() - Start sending and receiving broadcast
- * information.
- * cupsdStartPolling() - Start polling servers as needed.
- * cupsdStopBrowsing() - Stop sending and receiving broadcast
- * information.
- * cupsdStopPolling() - Stop polling servers as needed.
- * cupsdUpdateDNSSDBrowse() - Handle DNS-SD queries.
- * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
- * 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.
- * send_cups_browse() - Send new browsing information using the
- * CUPS protocol.
- * send_ldap_browse() - Send LDAP printer registrations.
- * send_slp_browse() - Register the specified printer with SLP.
- * slp_attr_callback() - SLP attribute callback
- * slp_dereg_printer() - SLPDereg() the specified printer
- * 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_polling() - Read status messages from the poll daemons.
+ * 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 or update the broadcast contents.
+ * cupsdRestartPolling() - Restart polling servers as needed.
+ * cupsdSaveRemoteCache() - Save the remote printer cache.
+ * cupsdSendBrowseList() - Send new browsing information as necessary.
+ * ldap_rebind_proc() - Callback function for LDAP rebind
+ * ldap_connect() - Start new LDAP connection
+ * ldap_reconnect() - Reconnect to LDAP Server
+ * ldap_disconnect() - Disconnect from LDAP Server
+ * cupsdStartBrowsing() - Start sending and receiving broadcast
+ * information.
+ * cupsdStartPolling() - Start polling servers as needed.
+ * cupsdStopBrowsing() - Stop sending and receiving broadcast
+ * information.
+ * cupsdStopPolling() - Stop polling servers as needed.
+ * cupsdUpdateDNSSDName() - Update the computer name we use for
+ * browsing...
+ * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
+ * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
+ * dequote() - Remote quotes from a string.
+ * dnssdAddAlias() - Add a DNS-SD alias name.
+ * dnssdBuildTxtRecord() - Build a TXT record from printer info.
+ * dnssdComparePrinters() - Compare the registered names of two printers.
+ * 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.
+ * dnssdStop() - Stop all DNS-SD registrations.
+ * dnssdUpdate() - Handle DNS-SD queries.
+ * get_auth_info_required() - Get the auth-info-required value to advertise.
+ * get_hostconfig() - Get an /etc/hostconfig service setting.
+ * is_local_queue() - Determine whether the URI points at a local
+ * queue.
+ * process_browse_data() - Process new browse data.
+ * process_implicit_classes() - Create/update implicit classes as needed.
+ * send_cups_browse() - Send new browsing information using the CUPS
+ * protocol.
+ * ldap_search_rec() - LDAP Search with reconnect
+ * ldap_freeres() - Free LDAPMessage
+ * ldap_getval_char() - Get first LDAP value and convert to string
+ * send_ldap_ou() - Send LDAP ou registrations.
+ * send_ldap_browse() - Send LDAP printer registrations.
+ * ldap_dereg_printer() - Delete printer from directory
+ * ldap_dereg_ou() - Remove the organizational unit.
+ * send_slp_browse() - Register the specified printer with SLP.
+ * slp_attr_callback() - SLP attribute callback
+ * slp_dereg_printer() - SLPDereg() the specified printer
+ * 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.
*/
/*
#ifdef HAVE_DNSSD
# include <dns_sd.h>
-# include <nameser.h>
-# include <nameser.h>
-# ifdef HAVE_COREFOUNDATION
-# include <CoreFoundation/CoreFoundation.h>
-# endif /* HAVE_COREFOUNDATION */
-# ifdef HAVE_SYSTEMCONFIGURATION
-# include <SystemConfiguration/SystemConfiguration.h>
-# endif /* HAVE_SYSTEMCONFIGURATION */
+# 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 */
*/
static char *dequote(char *d, const char *s, int dlen);
+static char *get_auth_info_required(cupsd_printer_t *p, char *buffer,
+ size_t bufsize);
+#ifdef __APPLE__
+static int get_hostconfig(const char *name);
+#endif /* __APPLE__ */
static int is_local_queue(const char *uri, char *host, int hostlen,
char *resource, int resourcelen);
static void process_browse_data(const char *uri, const char *host,
static void process_implicit_classes(void);
static void send_cups_browse(cupsd_printer_t *p);
#ifdef HAVE_LDAP
+static LDAP *ldap_connect(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);
+static void send_ldap_ou(char *ou, char *basedn, char *descstring);
static void send_ldap_browse(cupsd_printer_t *p);
+static void ldap_dereg_printer(cupsd_printer_t *p);
+static void ldap_dereg_ou(char *ou, char *basedn);
+# 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 */
#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
+#ifdef HAVE_DNSSD
+# ifdef HAVE_COREFOUNDATION
+static void dnssdAddAlias(const void *key, const void *value,
+ void *context);
+# endif /* HAVE_COREFOUNDATION */
+static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
+ int for_lpd);
+static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
+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);
+static void dnssdStop(void);
+static void dnssdUpdate(void);
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LDAP
static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
{
"printerDescription",
"printerURI",
NULL
};
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
/*
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
int removeit) /* I - Printer being permanently removed */
{
/*
- * Only deregister if browsing is enabled and it's a local printers...
+ * Only deregister if browsing is enabled and it's a local printer...
*/
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
+ removeit);
+
if (!Browsing || !p->shared ||
- (p->external_type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
return;
/*
* Announce the deletion...
*/
- if ((BrowseLocalProtocols & BROWSE_CUPS))
+ if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
{
cups_ptype_t savedtype = p->type; /* Saved printer type */
slp_dereg_printer(p);
#endif /* HAVE_LIBSLP */
+#ifdef HAVE_LDAP
+ if (BrowseLocalProtocols & BROWSE_LDAP)
+ ldap_dereg_printer(p);
+#endif /* HAVE_LDAP */
+
#ifdef HAVE_DNSSD
- if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
+ if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
dnssdDeregisterPrinter(p);
#endif /* HAVE_DNSSD */
}
void
cupsdLoadRemoteCache(void)
{
+ int i; /* Looping var */
cups_file_t *fp; /* remote.cache file */
int linenum; /* Current line number */
- char line[1024], /* Line from file */
+ char line[4096], /* Line from file */
*value, /* Pointer to value */
*valueptr, /* Pointer into value */
scheme[32], /* Scheme portion of URI */
/*
- * Don't load the cache if the CUPS remote protocol is disabled...
+ * Don't load the cache if the remote protocols are disabled...
*/
- if (!Browsing || !(BrowseRemoteProtocols & BROWSE_CUPS))
+ if (!Browsing)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"cupsdLoadRemoteCache: Not loading remote cache.");
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;
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "<Class") ||
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;
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ break;
}
}
else if (!strcasecmp(line, "</Printer>") ||
p = NULL;
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!p)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
+ }
+ else if (!strcasecmp(line, "UUID"))
+ {
+ if (value && !strncmp(value, "urn:uuid:", 9))
+ cupsdSetString(&(p->uuid), value);
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad UUID on line %d of remote.cache.", linenum);
}
else if (!strcasecmp(line, "Info"))
{
cupsdSetString(&p->hostname, host);
cupsdSetString(&p->uri, value);
- cupsdSetString(&p->device_uri, value);
+ cupsdSetDeviceURI(p, value);
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "Option") && value)
{
&(p->options));
}
}
+ else if (!strcasecmp(line, "Reason"))
+ {
+ if (value)
+ {
+ for (i = 0 ; i < p->num_reasons; i ++)
+ if (!strcmp(value, p->reasons[i]))
+ break;
+
+ if (i >= p->num_reasons &&
+ p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
+ {
+ p->reasons[p->num_reasons] = _cupsStrAlloc(value);
+ p->num_reasons ++;
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Syntax error on line %d of remote.cache.", linenum);
+ }
else if (!strcasecmp(line, "State"))
{
/*
if (value && !strcasecmp(value, "idle"))
p->state = IPP_PRINTER_IDLE;
else if (value && !strcasecmp(value, "stopped"))
+ {
p->state = IPP_PRINTER_STOPPED;
+ cupsdSetPrinterReasons(p, "+paused");
+ }
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "StateMessage"))
{
!strcasecmp(value, "false")))
p->accepting = 0;
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "Type"))
{
if (value)
p->type = atoi(value);
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "BrowseTime"))
{
p->browse_expire = t;
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "JobSheets"))
{
for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
if (*valueptr)
- *valueptr++ = '\0';
+ *valueptr = '\0';
cupsdSetString(&p->job_sheets[1], value);
}
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "AllowUser"))
{
if (value)
{
p->deny_users = 0;
- cupsdAddPrinterUser(p, value);
+ cupsdAddString(&(p->users), value);
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else if (!strcasecmp(line, "DenyUser"))
{
if (value)
{
p->deny_users = 1;
- cupsdAddPrinterUser(p, value);
+ cupsdAddString(&(p->users), value);
}
else
- {
cupsdLogMessage(CUPSD_LOG_ERROR,
"Syntax error on line %d of remote.cache.", linenum);
- return;
- }
}
else
{
void
cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
{
- if (!Browsing || !BrowseLocalProtocols || !BrowseInterval || !NumBrowsers ||
- (p->external_type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
+ p->name);
+
+ if (!Browsing || !BrowseLocalProtocols ||
+ (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
return;
#ifdef HAVE_LIBSLP
#endif /* HAVE_LIBSLP */
#ifdef HAVE_DNSSD
- if (BrowseLocalProtocols & BROWSE_DNSSD)
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
dnssdRegisterPrinter(p);
#endif /* HAVE_DNSSD */
}
{
int i; /* Looping var */
cups_file_t *fp; /* printers.conf file */
- char temp[1024]; /* Temporary string */
+ char temp[1024], /* Temporary string */
+ value[2048], /* Value string */
+ *name; /* Current user name */
cupsd_printer_t *printer; /* Current printer class */
time_t curtime; /* Current time */
struct tm *curdate; /* Current date */
* Skip local destinations...
*/
- if (!(printer->type & CUPS_PRINTER_REMOTE))
+ if (!(printer->type & CUPS_PRINTER_DISCOVERED))
continue;
/*
else
cupsFilePrintf(fp, "Printer %s>\n", printer->name);
- cupsFilePrintf(fp, "Type %d\n", printer->type);
-
cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
- if (printer->info)
- cupsFilePrintf(fp, "Info %s\n", printer->info);
+ cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
- if (printer->make_model)
- cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model);
+ if (printer->info)
+ cupsFilePutConf(fp, "Info", printer->info);
if (printer->location)
- cupsFilePrintf(fp, "Location %s\n", printer->location);
+ cupsFilePutConf(fp, "Location", printer->location);
+
+ if (printer->make_model)
+ cupsFilePutConf(fp, "MakeModel", printer->make_model);
- if (printer->device_uri)
- cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri);
+ cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
if (printer->state == IPP_PRINTER_STOPPED)
- {
cupsFilePuts(fp, "State Stopped\n");
- cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message);
- }
else
cupsFilePuts(fp, "State Idle\n");
+ for (i = 0; i < printer->num_reasons; i ++)
+ cupsFilePutConf(fp, "Reason", printer->reasons[i]);
+
+ cupsFilePrintf(fp, "Type %d\n", printer->type);
+
if (printer->accepting)
cupsFilePuts(fp, "Accepting Yes\n");
else
cupsFilePuts(fp, "Accepting No\n");
- cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
- printer->job_sheets[1]);
+ snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
+ printer->job_sheets[1]);
+ cupsFilePutConf(fp, "JobSheets", value);
- for (i = 0; i < printer->num_users; i ++)
- cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
- printer->users[i]);
+ for (name = (char *)cupsArrayFirst(printer->users);
+ name;
+ name = (char *)cupsArrayNext(printer->users))
+ cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
for (i = printer->num_options, option = printer->options;
i > 0;
i --, option ++)
- cupsFilePrintf(fp, "Option %s %s\n", option->name, option->value);
+ {
+ snprintf(value, sizeof(value), "%s %s", option->name, option->value);
+ cupsFilePutConf(fp, "Option", value);
+ }
if (printer->type & CUPS_PRINTER_CLASS)
cupsFilePuts(fp, "</Class>\n");
to; /* Timeout time */
- if (!Browsing || !BrowseLocalProtocols || !Printers)
+ if (!Browsing || !Printers)
return;
/*
* Figure out how many printers need an update...
*/
- if (BrowseInterval > 0)
+ if (BrowseInterval > 0 && BrowseLocalProtocols)
{
int max_count; /* Maximum number to update */
for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
count < max_count && p != NULL;
p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (!(p->external_type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)) &&
p->shared && p->browse_time < ut)
count ++;
if (!p)
break;
- else if ((p->external_type & (CUPS_PRINTER_REMOTE |
- CUPS_PRINTER_IMPLICIT)) ||
+ else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)) ||
!p->shared)
continue;
else if (p->browse_time < ut)
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...
+ * Loop through all of the printers and timeout old printers as needed...
*/
for (p = (cupsd_printer_t *)cupsArrayFirst(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) &&
+ !(p->type & CUPS_PRINTER_IMPLICIT) &&
+ p->browse_expire < to)
{
- if (p->browse_expire < to)
- {
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "%s \'%s\' deleted by directory services (timeout).",
- (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
- p->name);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services (timeout).",
+ (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
+ p->name);
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Remote destination \"%s\" has timed out; "
- "deleting it...",
- p->name);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Remote destination \"%s\" has timed out; "
+ "deleting it...",
+ p->name);
- cupsArraySave(Printers);
- cupsdDeletePrinter(p, 1);
- cupsArrayRestore(Printers);
- }
+ cupsArraySave(Printers);
+ cupsdDeletePrinter(p, 1);
+ cupsArrayRestore(Printers);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
}
}
}
+#ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
/*
- * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
*/
-void
-cupsdStartBrowsing(void)
+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 val; /* Socket option value */
- struct sockaddr_in addr; /* Broadcast address */
- cupsd_printer_t *p; /* Current printer */
+ int rc; /* Result code */
+# if LDAP_API_VERSION > 3000
+ struct berval bval; /* Bind value */
+# endif /* LDAP_API_VERSION > 3000 */
+ /*
+ * Bind to new LDAP server...
+ */
- BrowseNext = NULL;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Rebind to %s", refsp);
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
+# if LDAP_API_VERSION > 3000
+ bval.bv_val = BrowseLDAPPassword;
+ bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
- {
- if (BrowseSocket < 0)
- {
- /*
- * Create the broadcast socket...
- */
+ 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 */
- if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to create broadcast "
- "socket - %s.", strerror(errno));
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
- }
+ return (rc);
+}
- /*
- * Bind the socket to browse port...
- */
- memset(&addr, 0, sizeof(addr));
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(BrowsePort);
+# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+/*
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
+ */
- if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to bind broadcast "
- "socket - %s.", strerror(errno));
+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...
+ */
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Free values...");
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
- }
- }
+ if (dnp && *dnp)
+ free(*dnp);
- /*
- * Set the "broadcast" flag...
- */
+ if (passwdp && *passwdp)
+ free(*passwdp);
+ break;
- val = 1;
- if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
- strerror(errno));
+ case 0:
+ /*
+ * Return credentials for LDAP referal...
+ */
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "ldap_rebind_proc: Return necessary values...");
- BrowseSocket = -1;
- BrowseLocalProtocols &= ~BROWSE_CUPS;
- BrowseRemoteProtocols &= ~BROWSE_CUPS;
- return;
- }
+ *dnp = strdup(BrowseLDAPBindDN);
+ *passwdp = strdup(BrowseLDAPPassword);
+ *authmethodp = LDAP_AUTH_SIMPLE;
+ break;
- /*
- * Close the socket on exec...
- */
+ default:
+ /*
+ * Should never happen...
+ */
- fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP rebind has been called with wrong freeit value!");
+ break;
+ }
- /*
- * Finally, add the socket to the input selection set as needed...
- */
+ return (LDAP_SUCCESS);
+}
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+#endif /* HAVE_LDAP_REBIND_PROC */
- if (BrowseRemoteProtocols & BROWSE_CUPS)
- {
- /*
- * We only listen if we want remote printers...
- */
- cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
- NULL, NULL);
- }
- }
- else
- BrowseSocket = -1;
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_connect()' - Start new LDAP connection
+ */
-#ifdef HAVE_LIBSLP
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
+static LDAP * /* O - LDAP handle */
+ldap_connect(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)
{
- /*
- * Open SLP handle...
- */
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "ldap_connect: Setting CA certificate file \"%s\"",
+ BrowseLDAPCACertFile);
- if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
- {
+ if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+ (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to open an SLP handle; disabling SLP browsing!");
- BrowseLocalProtocols &= ~BROWSE_SLP;
- BrowseRemoteProtocols &= ~BROWSE_SLP;
- }
+ "Unable to set CA certificate file for LDAP "
+ "connections: %d - %s", rc, ldap_err2string(rc));
+ }
+# endif /* HAVE_LDAP_SSL */
- BrowseSLPRefresh = 0;
+ /*
+ * 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)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "BrowseLDAPServer not configured!");
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+ 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
- BrowseSLPHandle = NULL;
-#endif /* HAVE_LIBSLP */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unrecognized LDAP protocol (%s)!",
+ ldap_protocol);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ return (NULL);
+ }
-#ifdef HAVE_OPENLDAP
- if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
+ if (ldap_port == 0)
{
- if (!BrowseLDAPDN)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Need to set BrowseLDAPDN to use LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
+ if (ldap_ssl)
+ ldap_port = LDAPS_PORT;
else
- {
- /*
- * Open LDAP handle...
- */
+ ldap_port = LDAP_PORT;
+ }
- int rc; /* LDAP API status */
- int version = 3; /* LDAP version */
- struct berval bv = {0, ""}; /* SASL bind value */
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "ldap_connect: PROT:%s HOST:%s PORT:%d",
+ ldap_protocol, ldap_host, ldap_port);
+ /*
+ * Initialize LDAP connection...
+ */
- /*
- * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
- */
+ if (!ldap_ssl)
+ {
+ if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
+ rc = LDAP_OPERATIONS_ERROR;
+ else
+ rc = LDAP_SUCCESS;
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
- else
- rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
+# ifdef HAVE_LDAP_SSL
+ }
+ else
+ {
+ /*
+ * Initialize SSL LDAP connection...
+ */
+ if (BrowseLDAPCACertFile)
+ {
+ rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
if (rc != LDAP_SUCCESS)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to initialize LDAP; disabling LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
- else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
- (const void *)&version) != LDAP_SUCCESS)
- {
- ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
- BrowseLDAPHandle = NULL;
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to set LDAP protocol version; "
- "disabling LDAP browsing!");
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Failed to initialize LDAP SSL client!");
+ rc = LDAP_OPERATIONS_ERROR;
}
else
{
- if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
- rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
- NULL, NULL);
- else
- rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
- BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
-
- if (rc != LDAP_SUCCESS)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to bind to LDAP server; "
- "disabling LDAP browsing!");
- ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
- BrowseLocalProtocols &= ~BROWSE_LDAP;
- BrowseRemoteProtocols &= ~BROWSE_LDAP;
- }
+ if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port,
+ 1)) == NULL)
+ rc = LDAP_OPERATIONS_ERROR;
+ else
+ rc = LDAP_SUCCESS;
}
}
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP SSL certificate file/database not configured!");
+ rc = LDAP_OPERATIONS_ERROR;
+ }
- BrowseLDAPRefresh = 0;
+# else /* HAVE_LDAP_SSL */
+
+ /*
+ * Return error, because client libraries doesn't support SSL
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP client libraries do not support SSL");
+ rc = LDAP_OPERATIONS_ERROR;
+
+# endif /* HAVE_LDAP_SSL */
}
-#endif /* HAVE_OPENLDAP */
+# endif /* HAVE_OPENLDAP */
/*
- * Register the individual printers
+ * Check return code from LDAP initialize...
*/
- 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);
-}
+ if (rc != LDAP_SUCCESS)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize LDAP!");
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Temporarily disabling LDAP browsing...");
+ else
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
-/*
- * 'cupsdStartPolling()' - Start polling servers as needed.
- */
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ }
-void
-cupsdStartPolling(void)
-{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
- char polld[1024]; /* Poll daemon path */
- char sport[255]; /* Server port */
- char bport[255]; /* Browser port */
- char interval[255]; /* Poll interval */
- int statusfds[2]; /* Status pipe */
- char *argv[6]; /* Arguments */
- char *envp[100]; /* Environment */
+ ldap_disconnect(TempBrowseLDAPHandle);
+ return (NULL);
+ }
/*
- * Don't do anything if we aren't polling...
+ * Upgrade LDAP version...
*/
- if (NumPolled == 0 || BrowseSocket < 0)
+ if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
+ (const void *)&version) != LDAP_SUCCESS)
{
- PollPipe = -1;
- PollStatusBuffer = NULL;
- return;
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set LDAP protocol version %d!",
+ version);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
+
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+ ldap_disconnect(TempBrowseLDAPHandle);
+
+ return (NULL);
}
/*
- * Setup string arguments for polld, port and interval options.
+ * Register LDAP rebind procedure...
*/
- snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
+# ifdef HAVE_LDAP_REBIND_PROC
+# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
- sprintf(bport, "%d", BrowsePort);
+ rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc,
+ (void *)NULL);
+ if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Setting LDAP rebind function failed with status %d: %s",
+ rc, ldap_err2string(rc));
- if (BrowseInterval)
- sprintf(interval, "%d", BrowseInterval);
- else
- strcpy(interval, "30");
+# else
- argv[0] = "cups-polld";
- argv[2] = sport;
- argv[3] = interval;
- argv[4] = bport;
- argv[5] = NULL;
+ ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
- cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+# endif /* HAVE_LDAP_REBIND_PROC */
/*
- * Create a pipe that receives the status messages from each
- * polling daemon...
+ * Start LDAP bind...
*/
- if (cupsdOpenPipe(statusfds))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create polling status pipes - %s.",
- strerror(errno));
- PollPipe = -1;
- PollStatusBuffer = NULL;
- return;
- }
+# if LDAP_API_VERSION > 3000
+ struct berval bval;
+ bval.bv_val = BrowseLDAPPassword;
+ bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
- PollPipe = statusfds[0];
- PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
+ 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);
- /*
- * Run each polling daemon, redirecting stderr to the polling pipe...
- */
+# else
+ rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
+ BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
+# endif /* LDAP_API_VERSION > 3000 */
- for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (rc != LDAP_SUCCESS)
{
- sprintf(sport, "%d", pollp->port);
-
- argv[1] = pollp->hostname;
+ cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP bind failed with error %d: %s",
+ rc, ldap_err2string(rc));
- if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
- 0, &(pollp->pid)) < 0)
+# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
+ if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "cupsdStartPolling: Unable to fork polling daemon - %s",
- strerror(errno));
- pollp->pid = 0;
- break;
+ ssl_err = PORT_GetError();
+ if (ssl_err != 0)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP SSL error %d: %s", ssl_err,
+ ldapssl_err2string(ssl_err));
}
- else
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
- pollp->hostname, pollp->port, pollp->pid);
- }
+# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
- close(statusfds[1]);
+ ldap_disconnect(TempBrowseLDAPHandle);
- /*
- * Finally, add the pipe to the input selection set...
- */
+ return (NULL);
+ }
- cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
+ cupsdLogMessage(CUPSD_LOG_INFO, "LDAP connection established");
+
+ return (TempBrowseLDAPHandle);
}
/*
- * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
+ * 'ldap_reconnect()' - Reconnect to LDAP Server
*/
-void
-cupsdStopBrowsing(void)
+static LDAP * /* O - New LDAP handle */
+ldap_reconnect(void)
{
- cupsd_printer_t *p; /* Current printer */
-
-
- if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
- return;
-
- /*
- * De-register the individual printers
- */
+ LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
- 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...
+ * Get a new LDAP Handle and replace the global Handle
+ * if the new connection was successful.
*/
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
- BrowseSocket >= 0)
- {
- /*
- * Close the socket and remove it from the input selection set.
- */
-
-#ifdef WIN32
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 */
+ cupsdLogMessage(CUPSD_LOG_INFO, "Try LDAP reconnect...");
- cupsdRemoveSelect(BrowseSocket);
- BrowseSocket = -1;
- }
+ TempBrowseLDAPHandle = ldap_connect();
-#ifdef HAVE_LIBSLP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
- BrowseSLPHandle)
+ if (TempBrowseLDAPHandle != NULL)
{
- /*
- * Close SLP handle...
- */
+ if (BrowseLDAPHandle != NULL)
+ ldap_disconnect(BrowseLDAPHandle);
- SLPClose(BrowseSLPHandle);
- BrowseSLPHandle = NULL;
+ BrowseLDAPHandle = TempBrowseLDAPHandle;
}
-#endif /* HAVE_LIBSLP */
-#ifdef HAVE_OPENLDAP
- if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
- BrowseLDAPHandle)
- {
- ldap_unbind(BrowseLDAPHandle);
- BrowseLDAPHandle = NULL;
- }
-#endif /* HAVE_OPENLDAP */
+ return (BrowseLDAPHandle);
}
/*
- * 'cupsdStopPolling()' - Stop polling servers as needed.
+ * 'ldap_disconnect()' - Disconnect from LDAP Server
*/
-void
-cupsdStopPolling(void)
+static void
+ldap_disconnect(LDAP *ld) /* I - LDAP handle */
{
- int i; /* Looping var */
- cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+ int rc; /* Return code */
- if (PollPipe >= 0)
- {
- cupsdStatBufDelete(PollStatusBuffer);
- close(PollPipe);
-
- cupsdRemoveSelect(PollPipe);
+ /*
+ * Close LDAP handle...
+ */
- PollPipe = -1;
- PollStatusBuffer = NULL;
- }
+# 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 */
- for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
- if (pollp->pid)
- cupsdEndProcess(pollp->pid, 0);
+ if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unbind from LDAP server failed with status %d: %s",
+ rc, ldap_err2string(rc));
}
+#endif /* HAVE_LDAP */
-#ifdef HAVE_DNSSD
/*
- * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
+ * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
*/
void
-cupsdUpdateDNSSDBrowse(
- cupsd_printer_t *p) /* I - Printer being queried */
+cupsdStartBrowsing(void)
{
- DNSServiceErrorType sdErr; /* Service discovery error */
+ int val; /* Socket option value */
+ struct sockaddr_in addr; /* Broadcast address */
+ cupsd_printer_t *p; /* Current printer */
- if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
- != kDNSServiceErr_NoError)
- {
- 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);
+ BrowseNext = NULL;
- p->dnssd_ipp_ref = NULL;
- p->dnssd_ipp_fd = -1;
- }
-}
-#endif /* HAVE_DNSSD */
+ if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
+ return;
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
+ {
+ if (BrowseSocket < 0)
+ {
+ /*
+ * Create the broadcast socket...
+ */
-#ifdef HAVE_OPENLDAP
-/*
- * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
- */
+ if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create broadcast socket - %s.",
+ strerror(errno));
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
-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 */
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Bind the socket to browse port...
+ */
- /*
- * Search for printers...
- */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(BrowsePort);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
+ if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to bind broadcast socket - %s.",
+ strerror(errno));
- BrowseLDAPRefresh = time(NULL) + BrowseInterval;
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
- 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;
- }
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
- limit = ldap_count_entries(BrowseLDAPHandle, res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
- if (limit < 1)
- return;
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
- /*
- * Loop through the available printers...
- */
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Set the "broadcast" flag...
+ */
- for (e = ldap_first_entry(BrowseLDAPHandle, res);
- e;
- e = ldap_next_entry(BrowseLDAPHandle, e))
- {
- /*
- * Get the required values from this entry...
- */
+ val = 1;
+ if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
+ strerror(errno));
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerDescription")) == NULL)
- continue;
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
- strlcpy(info, *value, sizeof(info));
- ldap_value_free(value);
+ BrowseSocket = -1;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerLocation")) == NULL)
- continue;
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ }
- strlcpy(location, *value, sizeof(location));
- ldap_value_free(value);
+ if (BrowseSocket >= 0)
+ {
+ /*
+ * Close the socket on exec...
+ */
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerMakeAndModel")) == NULL)
- continue;
+ fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
- strlcpy(make_model, *value, sizeof(make_model));
- ldap_value_free(value);
+ /*
+ * Finally, add the socket to the input selection set as needed...
+ */
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerType")) == NULL)
- continue;
+ if (BrowseRemoteProtocols & BROWSE_CUPS)
+ {
+ /*
+ * We only listen if we want remote printers...
+ */
- type = atoi(*value);
- ldap_value_free(value);
+ cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
+ NULL, NULL);
+ }
+ }
+ }
+ else
+ BrowseSocket = -1;
- if ((value = ldap_get_values(BrowseLDAPHandle, e,
- "printerURI")) == NULL)
- continue;
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
+ {
+ DNSServiceErrorType error; /* Error from service creation */
+ cupsd_listener_t *lis; /* Current listening socket */
- strlcpy(uri, *value, sizeof(uri));
- ldap_value_free(value);
/*
- * Process the entry as browse data...
+ * First create a "master" connection for all registrations...
*/
- if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
- process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
- location, info, make_model, 0, NULL);
-
- }
-}
-#endif /* HAVE_OPENLDAP */
+ if ((error = DNSServiceCreateConnection(&DNSSDRef))
+ != kDNSServiceErr_NoError)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create master DNS-SD reference: %d", error);
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ else
+ {
+ /*
+ * Add the master connection to the select list...
+ */
-#ifdef HAVE_LIBSLP
-/*
- * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
- */
+ int fd = DNSServiceRefSockFD(DNSSDRef);
-void
-cupsdUpdateSLPBrowse(void)
-{
- slpsrvurl_t *s, /* Temporary list of service URLs */
- *next; /* Next service in list */
- cupsd_printer_t p; /* Printer information */
- const char *uri; /* Pointer to printer URI */
- char host[HTTP_MAX_URI], /* Host portion of URI */
- resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+ cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
- /*
- * Reset the refresh time...
- */
+ /*
+ * Then get the port we use for registrations. If we are not listening
+ * on any non-local ports, there is no sense sharing local printers via
+ * Bonjour...
+ */
- BrowseSLPRefresh = time(NULL) + BrowseInterval;
+ DNSSDPort = 0;
- /*
- * Poll for remote printers using SLP...
- */
+ for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+ lis;
+ lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ {
+ if (httpAddrLocalhost(&(lis->address)))
+ continue;
- s = NULL;
+ DNSSDPort = _httpAddrPort(&(lis->address));
+ break;
+ }
- SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
- slp_url_callback, &s);
+ /*
+ * Create an array to track the printers we share...
+ */
- /*
- * Loop through the list of available printers...
- */
+ if (BrowseRemoteProtocols & BROWSE_DNSSD)
+ DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
+ NULL);
- for (; s; s = next)
- {
- /*
- * Save the "next" pointer...
- */
+ /*
+ * Set the computer name and register the web interface...
+ */
- next = s->next;
+ cupsdUpdateDNSSDName();
+ }
+ }
+#endif /* HAVE_DNSSD */
+#ifdef HAVE_LIBSLP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
+ {
/*
- * Load a cupsd_printer_t structure with the SLP service attributes...
+ * Open SLP handle...
*/
- SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
+ if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open an SLP handle; disabling SLP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_SLP;
+ BrowseRemoteProtocols &= ~BROWSE_SLP;
+ BrowseSLPHandle = NULL;
- /*
- * Process this printer entry...
- */
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
- uri = s->url + SLP_CUPS_SRVLEN + 1;
+ BrowseSLPRefresh = 0;
+ }
+ else
+ BrowseSLPHandle = NULL;
+#endif /* HAVE_LIBSLP */
- if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
+#ifdef HAVE_LDAP
+ if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
+ {
+ if (!BrowseLDAPDN)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Need to set BrowseLDAPDN to use LDAP browsing!");
+ BrowseLocalProtocols &= ~BROWSE_LDAP;
+ BrowseRemoteProtocols &= ~BROWSE_LDAP;
+
+ if (FatalErrors & CUPSD_FATAL_BROWSE)
+ cupsdEndProcess(getpid(), 0);
+ }
+ else
{
/*
- * Pull the URI apart to see if this is a local or remote printer...
+ * Open LDAP handle...
*/
- if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
- process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
- p.location, p.info, p.make_model, 0, NULL);
+ if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
+ (FatalErrors & CUPSD_FATAL_BROWSE))
+ cupsdEndProcess(getpid(), 0);
}
- /*
- * Free this listing...
- */
-
- cupsdClearString(&p.info);
- cupsdClearString(&p.location);
- cupsdClearString(&p.make_model);
-
- free(s);
- }
-}
-#endif /* HAVE_LIBSLP */
-
-
-/*
- * 'dequote()' - Remote quotes from a string.
- */
+ BrowseLDAPRefresh = 0;
+ }
+#endif /* HAVE_LDAP */
-static char * /* O - Dequoted string */
-dequote(char *d, /* I - Destination string */
- const char *s, /* I - Source string */
- int dlen) /* I - Destination length */
-{
- char *dptr; /* Pointer into destination */
+ /*
+ * Enable LPD and SMB printer sharing as needed through external programs...
+ */
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ update_lpd(1);
- if (s)
- {
- for (dptr = d, dlen --; *s && dlen > 0; s ++)
- if (*s != '\"')
- {
- *dptr++ = *s;
- dlen --;
- }
+ if (BrowseLocalProtocols & BROWSE_SMB)
+ update_smb(1);
- *dptr = '\0';
- }
- else
- *d = '\0';
+ /*
+ * Register the individual printers
+ */
- return (d);
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
+ CUPS_PRINTER_SCANNER)))
+ cupsdRegisterPrinter(p);
}
/*
- * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ * 'cupsdStartPolling()' - Start polling servers as needed.
*/
-static int /* O - 1 = local, 0 = remote, -1 = bad URI */
-is_local_queue(const char *uri, /* I - Printer URI */
- char *host, /* O - Host string */
- int hostlen, /* I - Length of host buffer */
- char *resource, /* O - Resource string */
- int resourcelen) /* I - Length of resource buffer */
+void
+cupsdStartPolling(void)
{
- char scheme[32], /* Scheme portion of URI */
- username[HTTP_MAX_URI]; /* Username portion of URI */
- int port; /* Port portion of URI */
- cupsd_netif_t *iface; /* Network interface */
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+ char polld[1024]; /* Poll daemon path */
+ char sport[255]; /* Server port */
+ char bport[255]; /* Browser port */
+ char interval[255]; /* Poll interval */
+ int statusfds[2]; /* Status pipe */
+ char *argv[6]; /* Arguments */
+ char *envp[100]; /* Environment */
/*
- * Pull the URI apart to see if this is a local or remote printer...
+ * Don't do anything if we aren't polling...
*/
- if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
- username, sizeof(username), host, hostlen, &port,
- resource, resourcelen) < HTTP_URI_OK)
- return (-1);
-
- DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
+ if (NumPolled == 0 || BrowseSocket < 0)
+ {
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
/*
- * Check for local server addresses...
+ * Setup string arguments for polld, port and interval options.
*/
- if (!strcasecmp(host, ServerName) && port == LocalPort)
- return (1);
-
- cupsdNetIFUpdate();
+ snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
- for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
- iface;
- iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
- if (!strcasecmp(host, iface->hostname) && port == iface->port)
- return (1);
+ sprintf(bport, "%d", BrowsePort);
- /*
- * If we get here, the printer is remote...
- */
+ if (BrowseInterval)
+ sprintf(interval, "%d", BrowseInterval);
+ else
+ strcpy(interval, "30");
- return (0);
+ argv[0] = "cups-polld";
+ argv[2] = sport;
+ argv[3] = interval;
+ argv[4] = bport;
+ argv[5] = NULL;
+
+ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+
+ /*
+ * Create a pipe that receives the status messages from each
+ * polling daemon...
+ */
+
+ if (cupsdOpenPipe(statusfds))
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create polling status pipes - %s.",
+ strerror(errno));
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ return;
+ }
+
+ PollPipe = statusfds[0];
+ PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
+
+ /*
+ * Run each polling daemon, redirecting stderr to the polling pipe...
+ */
+
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ {
+ sprintf(sport, "%d", pollp->port);
+
+ argv[1] = pollp->hostname;
+
+ if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
+ 0, DefaultProfile, NULL, &(pollp->pid)) < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "cupsdStartPolling: Unable to fork polling daemon - %s",
+ strerror(errno));
+ pollp->pid = 0;
+ break;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
+ pollp->hostname, pollp->port, pollp->pid);
+ }
+
+ close(statusfds[1]);
+
+ /*
+ * Finally, add the pipe to the input selection set...
+ */
+
+ cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
+}
+
+
+/*
+ * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
+ */
+
+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 |
+ CUPS_PRINTER_SCANNER)))
+ cupsdDeregisterPrinter(p, 1);
+
+ /*
+ * Shut down browsing sockets...
+ */
+
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
+ BrowseSocket >= 0)
+ {
+ /*
+ * Close the socket and remove it from the input selection set.
+ */
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
+ }
+
+#ifdef HAVE_DNSSD
+ if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
+ dnssdStop();
+#endif /* HAVE_DNSSD */
+
+#ifdef HAVE_LIBSLP
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
+ BrowseSLPHandle)
+ {
+ /*
+ * Close SLP handle...
+ */
+
+ SLPClose(BrowseSLPHandle);
+ BrowseSLPHandle = NULL;
+ }
+#endif /* HAVE_LIBSLP */
+
+#ifdef HAVE_LDAP
+ if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
+ BrowseLDAPHandle)
+ {
+ ldap_dereg_ou(ServerName, BrowseLDAPDN);
+ ldap_disconnect(BrowseLDAPHandle);
+ 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);
+}
+
+
+/*
+ * 'cupsdStopPolling()' - Stop polling servers as needed.
+ */
+
+void
+cupsdStopPolling(void)
+{
+ int i; /* Looping var */
+ cupsd_dirsvc_poll_t *pollp; /* Current polling server */
+
+
+ if (PollPipe >= 0)
+ {
+ cupsdStatBufDelete(PollStatusBuffer);
+ close(PollPipe);
+
+ cupsdRemoveSelect(PollPipe);
+
+ PollPipe = -1;
+ PollStatusBuffer = NULL;
+ }
+
+ for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
+ if (pollp->pid)
+ cupsdEndProcess(pollp->pid, 0);
+}
+
+
+#ifdef HAVE_DNSSD
+/*
+ * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
+ */
+
+void
+cupsdUpdateDNSSDName(void)
+{
+ DNSServiceErrorType error; /* Error from service creation */
+ char webif[1024]; /* Web interface share name */
+# ifdef HAVE_SYSTEMCONFIGURATION
+ SCDynamicStoreRef sc; /* Context for dynamic store */
+ CFDictionaryRef btmm; /* Back-to-My-Mac domains */
+ CFStringEncoding nameEncoding; /* Encoding of computer name */
+ CFStringRef nameRef; /* Host name CFString */
+ char nameBuffer[1024]; /* C-string buffer */
+# endif /* HAVE_SYSTEMCONFIGURATION */
+
+
+ /*
+ * Only share the web interface and printers when non-local listening is
+ * enabled...
+ */
+
+
+ if (!DNSSDPort)
+ return;
+
+ /*
+ * Get the computer name as a c-string...
+ */
+
+# ifdef HAVE_SYSTEMCONFIGURATION
+ sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
+
+ if (sc)
+ {
+ /*
+ * Get the computer name from the dynamic store...
+ */
+
+ cupsdClearString(&DNSSDComputerName);
+
+ if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
+ {
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Dynamic store computer name is \"%s\".", nameBuffer);
+ cupsdSetString(&DNSSDComputerName, nameBuffer);
+ }
+
+ CFRelease(nameRef);
+ }
+
+ if (!DNSSDComputerName)
+ {
+ /*
+ * Use the ServerName instead...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Using ServerName \"%s\" as computer name.", ServerName);
+ cupsdSetString(&DNSSDComputerName, ServerName);
+ }
+
+ /*
+ * Get the local hostname from the dynamic store...
+ */
+
+ cupsdClearString(&DNSSDHostName);
+
+ if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
+ {
+ if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
+ kCFStringEncodingUTF8))
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Dynamic store host name is \"%s\".", nameBuffer);
+ cupsdSetString(&DNSSDHostName, nameBuffer);
+ }
+
+ CFRelease(nameRef);
+ }
+
+ if (!DNSSDHostName)
+ {
+ /*
+ * Use the ServerName instead...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Using ServerName \"%s\" as host name.", ServerName);
+ cupsdSetString(&DNSSDHostName, ServerName);
+ }
+
+ /*
+ * Get any Back-to-My-Mac domains and add them as aliases...
+ */
+
+ cupsdFreeAliases(DNSSDAlias);
+ DNSSDAlias = NULL;
+
+ btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
+ if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
+ (int)CFDictionaryGetCount(btmm));
+ CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
+ }
+ else if (btmm)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad Back to My Mac data in dynamic store!");
+ else
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
+
+ if (btmm)
+ CFRelease(btmm);
+
+ CFRelease(sc);
+ }
+ else
+# endif /* HAVE_SYSTEMCONFIGURATION */
+ {
+ cupsdSetString(&DNSSDComputerName, ServerName);
+ cupsdSetString(&DNSSDHostName, ServerName);
+ }
+
+ /*
+ * Then (re)register the web interface if enabled...
+ */
+
+ if (BrowseWebIF)
+ {
+ if (DNSSDComputerName)
+ snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
+ else
+ strlcpy(webif, "CUPS Web Interface", sizeof(webif));
+
+ if (WebIFRef)
+ DNSServiceRefDeallocate(WebIFRef);
+
+ WebIFRef = DNSSDRef;
+ if ((error = DNSServiceRegister(&WebIFRef,
+ kDNSServiceFlagsShareConnection,
+ 0, webif, "_http._tcp", NULL,
+ NULL, htons(DNSSDPort), 7,
+ "\006path=/", dnssdRegisterCallback,
+ NULL)) != kDNSServiceErr_NoError)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS-SD web interface registration failed: %d", error);
+ }
+}
+#endif /* HAVE_DNSSD */
+
+
+#ifdef HAVE_LDAP
+/*
+ * '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 */
+ type_num[30]; /* Printer type number */
+ int type; /* Printer type */
+ int rc; /* LDAP status */
+ int limit; /* Size limit */
+ LDAPMessage *res, /* LDAP search results */
+ *e; /* Current entry from search */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
+
+ BrowseLDAPRefresh = time(NULL) + BrowseInterval;
+
+ /*
+ * 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,
+ "(objectclass=cupsPrinter)", (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;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update temporary disabled");
+ }
+ return;
+ }
+
+ /*
+ * If LDAP updates were disabled, we will reenable them...
+ */
+
+ if (! BrowseLDAPUpdate)
+ {
+ BrowseLDAPUpdate = TRUE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update enabled");
+ }
+
+ /*
+ * Count LDAP entries and return if no entry exist...
+ */
+
+ limit = ldap_count_entries(BrowseLDAPHandle, res);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", 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;
+
+ type = atoi(type_num);
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e,
+ "printerURI", uri, sizeof(uri)) == -1)
+ continue;
+
+ /*
+ * Process the entry as browse data...
+ */
+
+ if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+ process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
+ location, info, make_model, 0, NULL);
+
+ }
+
+ ldap_freeres(res);
+}
+#endif /* HAVE_LDAP */
+
+
+#ifdef HAVE_LIBSLP
+/*
+ * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
+ */
+
+void
+cupsdUpdateSLPBrowse(void)
+{
+ slpsrvurl_t *s, /* Temporary list of service URLs */
+ *next; /* Next service in list */
+ cupsd_printer_t p; /* Printer information */
+ const char *uri; /* Pointer to printer URI */
+ char host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+
+
+ /*
+ * Reset the refresh time...
+ */
+
+ BrowseSLPRefresh = time(NULL) + BrowseInterval;
+
+ /*
+ * Poll for remote printers using SLP...
+ */
+
+ s = NULL;
+
+ SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
+ slp_url_callback, &s);
+
+ /*
+ * Loop through the list of available printers...
+ */
+
+ for (; s; s = next)
+ {
+ /*
+ * Save the "next" pointer...
+ */
+
+ next = s->next;
+
+ /*
+ * Load a cupsd_printer_t structure with the SLP service attributes...
+ */
+
+ SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
+
+ /*
+ * Process this printer entry...
+ */
+
+ uri = s->url + SLP_CUPS_SRVLEN + 1;
+
+ if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
+ {
+ /*
+ * 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)))
+ process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
+ p.location, p.info, p.make_model, 0, NULL);
+ }
+
+ /*
+ * Free this listing...
+ */
+
+ cupsdClearString(&p.info);
+ cupsdClearString(&p.location);
+ cupsdClearString(&p.make_model);
+
+ free(s);
+ }
+}
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * 'dequote()' - Remote quotes from a string.
+ */
+
+static char * /* O - Dequoted string */
+dequote(char *d, /* I - Destination string */
+ const char *s, /* I - Source string */
+ int dlen) /* I - Destination length */
+{
+ char *dptr; /* Pointer into destination */
+
+
+ if (s)
+ {
+ for (dptr = d, dlen --; *s && dlen > 0; s ++)
+ if (*s != '\"')
+ {
+ *dptr++ = *s;
+ dlen --;
+ }
+
+ *dptr = '\0';
+ }
+ else
+ *d = '\0';
+
+ return (d);
+}
+
+
+#ifdef HAVE_DNSSD
+# ifdef HAVE_COREFOUNDATION
+/*
+ * 'dnssdAddAlias()' - Add a DNS-SD alias name.
+ */
+
+static void
+dnssdAddAlias(const void *key, /* I - Key */
+ const void *value, /* I - Value (domain) */
+ void *context) /* I - Unused */
+{
+ char valueStr[1024], /* Domain string */
+ hostname[1024]; /* Complete hostname */
+
+
+ (void)context;
+
+ if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
+ CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
+ kCFStringEncodingUTF8))
+ {
+ snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
+ if (!DNSSDAlias)
+ DNSSDAlias = cupsArrayNew(NULL, NULL);
+
+ cupsdAddAlias(DNSSDAlias, hostname);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
+ hostname);
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Bad Back to My Mac domain in dynamic store!");
+}
+# endif /* HAVE_COREFOUNDATION */
+
+
+/*
+ * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
+ */
+
+static char * /* O - TXT record */
+dnssdBuildTxtRecord(
+ int *txt_len, /* O - TXT record length */
+ cupsd_printer_t *p, /* I - Printer information */
+ int for_lpd) /* I - 1 = LPD, 0 = IPP */
+{
+ int i; /* Looping var */
+ char admin_hostname[256], /* .local hostname for admin page */
+ adminurl_str[256], /* URL for the admin page */
+ 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;
+ if (for_lpd)
+ strlcpy(rp_str, p->name, sizeof(rp_str));
+ else
+ 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 ? p->make_model : "Unknown";
+
+ snprintf(admin_hostname, sizeof(admin_hostname), "%s.local.", DNSSDHostName);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
+ "http", NULL, admin_hostname, DNSSDPort, "/%s/%s",
+ (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
+ p->name);
+ keyvalue[i ][0] = "adminurl";
+ keyvalue[i++][1] = adminurl_str;
+
+ keyvalue[i ][0] = "note";
+ keyvalue[i++][1] = p->location ? p->location : "";
+
+ keyvalue[i ][0] = "priority";
+ keyvalue[i++][1] = for_lpd ? "100" : "0";
+
+ keyvalue[i ][0] = "product";
+ keyvalue[i++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
+
+ keyvalue[i ][0] = "pdl";
+ keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+
+ if (get_auth_info_required(p, air_str, sizeof(air_str)))
+ {
+ keyvalue[i ][0] = "air";
+ keyvalue[i++][1] = air_str;
+ }
+
+ keyvalue[i ][0] = "UUID";
+ keyvalue[i++][1] = p->uuid + 9;
+
+#ifdef HAVE_SSL
+ keyvalue[i ][0] = "TLS";
+ keyvalue[i++][1] = "1.2";
+#endif /* HAVE_SSL */
+
+ keyvalue[i ][0] = "Transparent";
+ keyvalue[i++][1] = "F";
+
+ keyvalue[i ][0] = "Binary";
+ keyvalue[i++][1] = "F";
+
+ keyvalue[i ][0] = "Fax";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
+
+ keyvalue[i ][0] = "Color";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
+
+ keyvalue[i ][0] = "Duplex";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
+
+ keyvalue[i ][0] = "Staple";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
+
+ keyvalue[i ][0] = "Copies";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
+
+ keyvalue[i ][0] = "Collate";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
+
+ keyvalue[i ][0] = "Punch";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
+
+ keyvalue[i ][0] = "Bind";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
+
+ keyvalue[i ][0] = "Sort";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
+
+ keyvalue[i ][0] = "Scan";
+ keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
+
+ 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;
+
+ /*
+ * Then pack them into a proper txt record...
+ */
+
+ return (dnssdPackTxtRecord(txt_len, keyvalue, i));
}
/*
- * 'process_browse_data()' - Process new browse data.
+ * 'dnssdComparePrinters()' - Compare the registered names of two printers.
+ */
+
+static int /* O - Result of comparison */
+dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
+ cupsd_printer_t *b)/* I - Second printer */
+{
+ return (strcasecmp(a->reg_name, b->reg_name));
+}
+
+
+/*
+ * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
+ * printer.
*/
static void
-process_browse_data(
- const char *uri, /* I - URI of printer/class */
- const char *host, /* I - Hostname */
- const char *resource, /* I - Resource path */
- cups_ptype_t type, /* I - Printer type */
- ipp_pstate_t state, /* I - Printer state */
- const char *location, /* I - Printer location */
- const char *info, /* I - Printer information */
- const char *make_model, /* I - Printer make and model */
- int num_attrs, /* I - Number of attributes */
- cups_option_t *attrs) /* I - Attributes */
+dnssdDeregisterPrinter(
+ cupsd_printer_t *p) /* I - Printer */
{
- int i; /* Looping var */
- int update; /* Update printer attributes? */
- char finaluri[HTTP_MAX_URI], /* Final URI for printer */
- name[IPP_MAX_NAME], /* Name of printer */
- newname[IPP_MAX_NAME], /* New name of printer */
- *hptr, /* Pointer into hostname */
- *sptr; /* Pointer into ServerName */
- char local_make_model[IPP_MAX_NAME];
- /* Local make and model */
- cupsd_printer_t *p; /* Printer information */
- const char *ipp_options, /* ipp-options value */
- *lease_duration; /* lease-duration value */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
+
+ /*
+ * Closing the socket deregisters the service
+ */
+
+ if (p->ipp_ref)
+ {
+ DNSServiceRefDeallocate(p->ipp_ref);
+ p->ipp_ref = NULL;
+ }
+
+ if (p->ipp_txt)
+ {
+ /*
+ * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
+ */
+
+ free(p->ipp_txt);
+ p->ipp_txt = NULL;
+ }
+
+ if (p->printer_ref)
+ {
+ DNSServiceRefDeallocate(p->printer_ref);
+ p->printer_ref = NULL;
+ }
+
+ if (p->printer_txt)
+ {
+ /*
+ * p->printer_txt is malloc'd, not _cupsStrAlloc'd...
+ */
+ free(p->printer_txt);
+ p->printer_txt = NULL;
+ }
/*
- * Determine if the URI contains any illegal characters in it...
+ * Remove the printer from the array of DNS-SD printers, then clear the
+ * registered name...
*/
- if (strncmp(uri, "ipp://", 6) || !host[0] ||
- (strncmp(resource, "/printers/", 10) &&
- strncmp(resource, "/classes/", 9)))
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdClearString(&p->reg_name);
+}
+
+
+/*
+ * '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
+ */
+
+ if (count <= 0)
+ return (NULL);
+
+ 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)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "process_browse_data: Bad printer URI in browse data: %s",
- uri);
+ *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 */
+{
+ cupsd_printer_t *p = (cupsd_printer_t *)context;
+ /* Current printer */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
+ name, regtype, p ? p->name : "Web Interface",
+ p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
+
+ if (errorCode)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNSServiceRegister failed with error %d", (int)errorCode);
+ return;
+ }
+ else if (p && (!p->reg_name || strcasecmp(name, p->reg_name)))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
+ name, p->name);
+
+ cupsArrayRemove(DNSSDPrinters, p);
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
+
+ LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
+ }
+}
+
+
+/*
+ * '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 */
+ char *ipp_txt, /* IPP TXT record buffer */
+ *printer_txt, /* LPD TXT record buffer */
+ name[1024], /* Service name */
+ *nameptr; /* Pointer into name */
+ int ipp_len, /* IPP TXT record length */
+ printer_len, /* LPD TXT record length */
+ printer_port; /* LPD port number */
+ const char *regtype; /* Registration type */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
+ !p->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;
}
- if (strchr(resource, '?') ||
- (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
- (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
+ /*
+ * The registered name takes the form of "<printer-info> @ <computer name>"...
+ */
+
+ if (p->info && strlen(p->info) > 0)
+ {
+ if (DNSSDComputerName)
+ snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDComputerName);
+ else
+ strlcpy(name, p->info, sizeof(name));
+ }
+ else if (DNSSDComputerName)
+ snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
+ else
+ strlcpy(name, p->name, sizeof(name));
+
+ /*
+ * If an existing printer was renamed, unregister it and start over...
+ */
+
+ if (p->reg_name && strcmp(p->reg_name, name))
+ dnssdDeregisterPrinter(p);
+
+ if (!p->reg_name)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "process_browse_data: Bad resource in browse data: %s",
- resource);
- return;
+ cupsdSetString(&p->reg_name, name);
+ cupsArrayAdd(DNSSDPrinters, p);
}
/*
- * OK, this isn't a local printer; add any remote options...
+ * Register IPP and (optionally) LPD...
*/
- ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+ ipp_len = 0; /* anti-compiler-warning-code */
+ ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
- if (BrowseRemoteOptions)
+ if (p->ipp_ref &&
+ (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)))
{
- if (BrowseRemoteOptions[0] == '?')
- {
- /*
- * Override server-supplied options...
- */
+ /*
+ * Update the existing registration...
+ */
- snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
- }
- else if (ipp_options)
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt,
+ 0)) == kDNSServiceErr_NoError)
{
- /*
- * Combine the server and local options...
- */
+ if (p->ipp_txt)
+ free(p->ipp_txt);
- snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
- BrowseRemoteOptions);
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
}
else
{
/*
- * Just use the local options...
+ * Failed to update record, lets close this reference and move on...
*/
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
- }
-
- uri = finaluri;
- }
- else if (ipp_options)
- {
- /*
- * Just use the server-supplied options...
- */
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to update IPP DNS-SD record for %s - %d", p->name,
+ se);
- snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
- uri = finaluri;
+ DNSServiceRefDeallocate(p->ipp_ref);
+ p->ipp_ref = NULL;
+ }
}
- /*
- * 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, '.');
-
- if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
+ if (!p->ipp_ref)
{
/*
- * Strip the common domain name components...
+ * Initial registration. Use the _fax-ipp regtype for fax queues...
*/
- while (hptr != NULL)
- {
- if (!strcasecmp(hptr, sptr))
- {
- *hptr = '\0';
- break;
- }
- else
- hptr = strchr(hptr + 1, '.');
- }
- }
+ regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\" and "
+ "type \"%s\"", p->name, name, regtype);
- if (type & CUPS_PRINTER_CLASS)
- {
/*
- * Remote destination is a class...
+ * Register the queue, dropping characters as needed until we succeed...
*/
- if (!strncmp(resource, "/classes/", 9))
- snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
- else
- return;
+ nameptr = name + strlen(name);
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
-
- if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames)
+ do
{
- if ((p = cupsdFindClass(resource + 9)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other class and then find a class using the full host
- * name...
- */
-
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Renamed remote class \"%s\" to \"%s@%s\"...",
- p->name, p->name, p->hostname);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "Class \'%s\' deleted by directory services.",
- p->name);
-
- snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
- cupsdRenamePrinter(p, newname);
-
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.",
- p->name);
- }
-
- p = NULL;
- }
- else if (!p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
-
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
+ p->ipp_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
+ 0, name, regtype, NULL, NULL,
+ htons(DNSSDPort), ipp_len, ipp_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_BadParam)
{
/*
- * Use the short name for this shared class.
+ * Name is too long, drop trailing characters, taking into account
+ * UTF-8 encoding...
*/
- strlcpy(name, resource + 9, sizeof(name));
- }
- }
- else if (p && !p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
+ nameptr --;
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
+ while (nameptr > name && (*nameptr & 0xc0) == 0x80)
+ nameptr --;
+
+ if (nameptr > name)
+ *nameptr = '\0';
+ }
}
+ while (se == kDNSServiceErr_BadParam && nameptr > name);
- if (!p)
+ if (se == kDNSServiceErr_NoError)
{
- /*
- * Class doesn't exist; add it...
- */
-
- p = cupsdAddClass(name);
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote class \"%s\"...", name);
-
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Class \'%s\' added by directory services.", name);
-
- /*
- * Force the URI to point to the real server...
- */
+ p->ipp_txt = ipp_txt;
+ p->ipp_len = ipp_len;
+ ipp_txt = NULL;
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD IPP registration of \"%s\" failed: %d",
+ p->name, se);
+ }
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- cupsdSetString(&p->hostname, host);
+ if (ipp_txt)
+ free(ipp_txt);
- update = 1;
- }
+ if (BrowseLocalProtocols & BROWSE_LPD)
+ {
+ printer_len = 0; /* anti-compiler-warning-code */
+ printer_port = 515;
+ printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
}
else
+ {
+ printer_len = 0;
+ printer_port = 0;
+ printer_txt = NULL;
+ }
+
+ if (p->printer_ref &&
+ (printer_len != p->printer_len ||
+ memcmp(printer_txt, p->printer_txt, printer_len)))
{
/*
- * Remote destination is a printer...
+ * Update the existing registration...
*/
- if (!strncmp(resource, "/printers/", 10))
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
-
- if (hptr && !*hptr)
- *hptr = '.'; /* Resource FQDN */
-
- if ((p = cupsdFindPrinter(name)) == NULL && BrowseShortNames)
- {
- if ((p = cupsdFindPrinter(resource + 10)) != NULL)
- {
- if (p->hostname && strcasecmp(p->hostname, host))
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other printer and then find a printer using the full host
- * name...
- */
-
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "Renamed remote printer \"%s\" to \"%s@%s\"...",
- p->name, p->name, p->hostname);
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "Printer \'%s\' deleted by directory services.",
- p->name);
-
- snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
- cupsdRenamePrinter(p, newname);
-
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.",
- p->name);
- }
-
- p = NULL;
- }
- else if (!p->hostname)
- {
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
-
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
- }
- }
- else
- {
- /*
- * Use the short name for this shared printer.
- */
-
- strlcpy(name, resource + 10, sizeof(name));
- }
- }
- else if (p && !p->hostname)
+ /* A TTL of 0 means use record's original value (Radar 3176248) */
+ if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
+ printer_txt,
+ 0)) == kDNSServiceErr_NoError)
{
- /*
- * Hostname not set, so this must be a cached remote printer
- * that was created for a pending print job...
- */
+ if (p->printer_txt)
+ free(p->printer_txt);
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
- update = 1;
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
}
-
- if (!p)
+ else
{
/*
- * Printer doesn't exist; add it...
- */
-
- p = cupsdAddPrinter(name);
-
- cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
- "Printer \'%s\' added by directory services.", name);
-
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote printer \"%s\"...", name);
-
- /*
- * Force the URI to point to the real server...
+ * Failed to update record, lets close this reference and move on...
*/
- p->type = type & ~CUPS_PRINTER_REJECTING;
- p->accepting = 1;
- cupsdSetString(&p->hostname, host);
- cupsdSetString(&p->uri, uri);
- cupsdSetString(&p->device_uri, uri);
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to update LPD DNS-SD record for %s - %d",
+ p->name, se);
- update = 1;
+ DNSServiceRefDeallocate(p->printer_ref);
+ p->printer_ref = NULL;
}
}
-
- /*
- * Update the state...
- */
-
- p->state = state;
- p->browse_time = time(NULL);
-
- if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
- attrs)) != NULL)
+
+ if (!p->printer_ref)
{
/*
- * Grab the lease-duration for the browse data; anything less then 1
- * second or more than 1 week gets the default BrowseTimeout...
+ * Initial registration...
*/
- i = atoi(lease_duration);
- if (i < 1 || i > 604800)
- i = BrowseTimeout;
-
- p->browse_expire = p->browse_time + i;
- }
- else
- p->browse_expire = p->browse_time + BrowseTimeout;
-
- if (type & CUPS_PRINTER_REJECTING)
- {
- type &= ~CUPS_PRINTER_REJECTING;
-
- if (p->accepting)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Registering DNS-SD printer %s with name \"%s\" and "
+ "type \"_printer._tcp\"", p->name, name);
+
+ p->printer_ref = DNSSDRef;
+ if ((se = DNSServiceRegister(&p->printer_ref,
+ kDNSServiceFlagsShareConnection,
+ 0, name, "_printer._tcp", NULL, NULL,
+ htons(printer_port), printer_len, printer_txt,
+ dnssdRegisterCallback,
+ p)) == kDNSServiceErr_NoError)
{
- update = 1;
- p->accepting = 0;
+ p->printer_txt = printer_txt;
+ p->printer_len = printer_len;
+ printer_txt = NULL;
}
- }
- else if (!p->accepting)
- {
- update = 1;
- p->accepting = 1;
- }
-
- if (p->type != type)
- {
- p->type = type;
- update = 1;
- }
-
- if (location && (!p->location || strcmp(p->location, location)))
- {
- cupsdSetString(&p->location, location);
- update = 1;
+ else
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "DNS-SD LPD registration of \"%s\" failed: %d",
+ p->name, se);
}
- if (info && (!p->info || strcmp(p->info, info)))
- {
- cupsdSetString(&p->info, info);
- update = 1;
- }
+ if (printer_txt)
+ free(printer_txt);
+}
- if (!make_model || !make_model[0])
- {
- if (type & CUPS_PRINTER_CLASS)
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Class on %s", host);
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "Remote Printer on %s", host);
- }
- else
- snprintf(local_make_model, sizeof(local_make_model),
- "%s on %s", make_model, host);
- if (!p->make_model || strcmp(p->make_model, local_make_model))
- {
- cupsdSetString(&p->make_model, local_make_model);
- update = 1;
- }
+/*
+ * 'dnssdStop()' - Stop all DNS-SD registrations.
+ */
- if (p->num_options)
- {
- if (!update && !(type & CUPS_PRINTER_DELETE))
- {
- /*
- * See if we need to update the attributes...
- */
+static void
+dnssdStop(void)
+{
+ cupsd_printer_t *p; /* Current printer */
- if (p->num_options != num_attrs)
- update = 1;
- else
- {
- for (i = 0; i < num_attrs; i ++)
- if (strcmp(attrs[i].name, p->options[i].name) ||
- (!attrs[i].value != !p->options[i].value) ||
- (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
- {
- update = 1;
- break;
- }
- }
- }
- /*
- * Free the old options...
- */
+ /*
+ * De-register the individual printers
+ */
- cupsFreeOptions(p->num_options, p->options);
- }
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ dnssdDeregisterPrinter(p);
- p->num_options = num_attrs;
- p->options = attrs;
+ /*
+ * Shutdown the rest of the service refs...
+ */
- if (type & CUPS_PRINTER_DELETE)
+ if (WebIFRef)
{
- cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
- "%s \'%s\' deleted by directory services.",
- (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name);
+ DNSServiceRefDeallocate(WebIFRef);
+ WebIFRef = NULL;
+ }
- cupsdExpireSubscriptions(p, NULL);
-
- cupsdDeletePrinter(p, 1);
- cupsdUpdateImplicitClasses();
+ if (RemoteRef)
+ {
+ DNSServiceRefDeallocate(RemoteRef);
+ RemoteRef = NULL;
}
- else if (update)
+
+ cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
+
+ DNSServiceRefDeallocate(DNSSDRef);
+ DNSSDRef = NULL;
+
+ cupsArrayDelete(DNSSDPrinters);
+ DNSSDPrinters = NULL;
+
+ DNSSDPort = 0;
+}
+
+
+/*
+ * 'dnssdUpdate()' - Handle DNS-SD queries.
+ */
+
+static void
+dnssdUpdate(void)
+{
+ DNSServiceErrorType sdErr; /* Service discovery error */
+
+
+ if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
{
- cupsdSetPrinterAttrs(p);
- cupsdUpdateImplicitClasses();
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "DNS Service Discovery registration error %d!",
+ sdErr);
+ dnssdStop();
}
+}
+#endif /* HAVE_DNSSD */
+
+
+/*
+ * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
+ */
+
+static char * /* O - String or NULL if none */
+get_auth_info_required(
+ cupsd_printer_t *p, /* I - Printer */
+ char *buffer, /* I - Value buffer */
+ size_t bufsize) /* I - Size of value buffer */
+{
+ cupsd_location_t *auth; /* Pointer to authentication element */
+ char resource[1024]; /* Printer/class resource path */
+
/*
- * See if we have a default printer... If not, make the first network
- * default printer the default.
+ * If auth-info-required is set for this printer, return that...
*/
- if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
+ if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
{
- /*
- * Find the first network default printer and use it...
- */
+ int i; /* Looping var */
+ char *bufptr; /* Pointer into buffer */
- for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
- p;
- p = (cupsd_printer_t *)cupsArrayNext(Printers))
- if (p->type & CUPS_PRINTER_DEFAULT)
- {
- DefaultPrinter = p;
+ for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
+ {
+ if (bufptr >= (buffer + bufsize - 2))
break;
- }
+
+ if (i)
+ *bufptr++ = ',';
+
+ strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer));
+ bufptr += strlen(bufptr);
+ }
+
+ return (buffer);
}
/*
- * Do auto-classing if needed...
+ * Figure out the authentication data requirements to advertise...
*/
- process_implicit_classes();
+ if (p->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", p->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", p->name);
- /*
- * Update the printcap file...
- */
+ if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+ auth->type == CUPSD_AUTH_NONE)
+ auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
+
+ if (auth)
+ {
+ int auth_type; /* Authentication type */
+
+ if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
+ auth_type = DefaultAuthType;
+
+ switch (auth_type)
+ {
+ case CUPSD_AUTH_NONE :
+ return (NULL);
+
+ case CUPSD_AUTH_NEGOTIATE :
+ strlcpy(buffer, "negotiate", bufsize);
+ break;
+
+ default :
+ strlcpy(buffer, "username,password", bufsize);
+ break;
+ }
+
+ return (buffer);
+ }
- cupsdWritePrintcap();
+ return ("none");
}
-#ifdef HAVE_DNSSD
+#ifdef __APPLE__
/*
- * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
+ * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
*/
-static char * /* O - TXT record */
-dnssdBuildTxtRecord(
- int *txt_len, /* O - TXT record length */
- cupsd_printer_t *p) /* I - Printer information */
+static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
+get_hostconfig(const char *name) /* I - Name of service */
{
- 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 */
+ cups_file_t *fp; /* Hostconfig file */
+ char line[1024], /* Line from file */
+ *ptr; /* Pointer to value */
+ int state = 1; /* State of service */
/*
- * Load up the key value pairs...
+ * Try opening the /etc/hostconfig file; if we can't open it, assume that
+ * the service is enabled/auto.
*/
- i = 0;
+ if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
+ {
+ /*
+ * Read lines from the file until we find the service...
+ */
- keyvalue[i ][0] = "txtvers";
- keyvalue[i++][1] = "1";
+ while (cupsFileGets(fp, line, sizeof(line)))
+ {
+ if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
+ continue;
- keyvalue[i ][0] = "qtotal";
- keyvalue[i++][1] = "1";
+ *ptr++ = '\0';
- 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);
+ if (!strcasecmp(line, name))
+ {
+ /*
+ * Found the service, see if it is set to "-NO-"...
+ */
- keyvalue[i ][0] = "ty";
- keyvalue[i++][1] = p->make_model;
+ if (!strncasecmp(ptr, "-NO-", 4))
+ state = 0;
+ break;
+ }
+ }
- if (p->location && *p->location != '\0')
- {
- keyvalue[i ][0] = "note";
- keyvalue[i++][1] = p->location;
+ cupsFileClose(fp);
}
- keyvalue[i ][0] = "product";
- keyvalue[i++][1] = p->product ? p->product : "Unknown";
+ return (state);
+}
+#endif /* __APPLE__ */
- 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;
+/*
+ * 'is_local_queue()' - Determine whether the URI points at a local queue.
+ */
- keyvalue[i ][0] = "printer-type";
- keyvalue[i++][1] = type_str;
+static int /* O - 1 = local, 0 = remote, -1 = bad URI */
+is_local_queue(const char *uri, /* I - Printer URI */
+ char *host, /* O - Host string */
+ int hostlen, /* I - Length of host buffer */
+ char *resource, /* O - Resource string */
+ int resourcelen) /* I - Length of resource buffer */
+{
+ char scheme[32], /* Scheme portion of URI */
+ username[HTTP_MAX_URI]; /* Username portion of URI */
+ int port; /* Port portion of URI */
+ cupsd_netif_t *iface; /* Network interface */
- keyvalue[i ][0] = "Transparent";
- keyvalue[i++][1] = "T";
- keyvalue[i ][0] = "Binary";
- keyvalue[i++][1] = "T";
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
- if ((p->type & CUPS_PRINTER_FAX))
- {
- keyvalue[i ][0] = "Fax";
- keyvalue[i++][1] = "T";
- }
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+ username, sizeof(username), host, hostlen, &port,
+ resource, resourcelen) < HTTP_URI_OK)
+ return (-1);
- if ((p->type & CUPS_PRINTER_COLOR))
- {
- keyvalue[i ][0] = "Color";
- keyvalue[i++][1] = "T";
- }
+ DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
- if ((p->type & CUPS_PRINTER_DUPLEX))
- {
- keyvalue[i ][0] = "Duplex";
- keyvalue[i++][1] = "T";
- }
+ /*
+ * Check for local server addresses...
+ */
- if ((p->type & CUPS_PRINTER_STAPLE))
- {
- keyvalue[i ][0] = "Staple";
- keyvalue[i++][1] = "T";
- }
+ if (!strcasecmp(host, ServerName) && port == LocalPort)
+ return (1);
- if ((p->type & CUPS_PRINTER_COPIES))
- {
- keyvalue[i ][0] = "Copies";
- keyvalue[i++][1] = "T";
- }
+ cupsdNetIFUpdate();
- if ((p->type & CUPS_PRINTER_COLLATE))
- {
- keyvalue[i ][0] = "Collate";
- keyvalue[i++][1] = "T";
- }
+ for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
+ iface;
+ iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
+ if (!strcasecmp(host, iface->hostname) && port == iface->port)
+ return (1);
- if ((p->type & CUPS_PRINTER_PUNCH))
- {
- keyvalue[i ][0] = "Punch";
- keyvalue[i++][1] = "T";
- }
+ /*
+ * If we get here, the printer is remote...
+ */
+
+ return (0);
+}
+
+
+/*
+ * 'process_browse_data()' - Process new browse data.
+ */
+
+static void
+process_browse_data(
+ const char *uri, /* I - URI of printer/class */
+ const char *host, /* I - Hostname */
+ const char *resource, /* I - Resource path */
+ cups_ptype_t type, /* I - Printer type */
+ ipp_pstate_t state, /* I - Printer state */
+ const char *location, /* I - Printer location */
+ const char *info, /* I - Printer information */
+ const char *make_model, /* I - Printer make and model */
+ int num_attrs, /* I - Number of attributes */
+ cups_option_t *attrs) /* I - Attributes */
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char finaluri[HTTP_MAX_URI], /* Final URI for printer */
+ name[IPP_MAX_NAME], /* Name of printer */
+ newname[IPP_MAX_NAME], /* New name of printer */
+ *hptr, /* Pointer into hostname */
+ *sptr; /* Pointer into ServerName */
+ const char *shortname; /* Short queue name (queue) */
+ char local_make_model[IPP_MAX_NAME];
+ /* Local make and model */
+ cupsd_printer_t *p; /* Printer information */
+ const char *ipp_options, /* ipp-options value */
+ *lease_duration, /* lease-duration value */
+ *uuid; /* uuid value */
+ int is_class; /* Is this queue a class? */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data(uri=\"%s\", host=\"%s\", "
+ "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
+ "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
+ uri, host, resource, type, state,
+ location ? location : "(nil)", info ? info : "(nil)",
+ make_model ? make_model : "(nil)", num_attrs, attrs);
+
+ /*
+ * Determine if the URI contains any illegal characters in it...
+ */
- if ((p->type & CUPS_PRINTER_BIND))
+ if (strncmp(uri, "ipp://", 6) || !host[0] ||
+ (strncmp(resource, "/printers/", 10) &&
+ strncmp(resource, "/classes/", 9)))
{
- keyvalue[i ][0] = "Bind";
- keyvalue[i++][1] = "T";
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
+ return;
}
- if ((p->type & CUPS_PRINTER_SORT))
+ if (strchr(resource, '?') ||
+ (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
+ (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
{
- keyvalue[i ][0] = "Sort";
- keyvalue[i++][1] = "T";
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
+ resource);
+ return;
}
- keyvalue[i ][0] = "pdl";
- keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
+ /*
+ * OK, this isn't a local printer; add any remote options...
+ */
- if (p->num_auth_info_required)
- {
- char *air = air_str; /* Pointer into string */
+ ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
+ if (BrowseRemoteOptions)
+ {
+ if (BrowseRemoteOptions[0] == '?')
+ {
+ /*
+ * Override server-supplied options...
+ */
- for (j = 0; j < p->num_auth_info_required; j ++)
+ snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
+ }
+ else if (ipp_options)
{
- if (air >= (air_str + sizeof(air_str) - 2))
- break;
+ /*
+ * Combine the server and local options...
+ */
- if (j)
- *air++ = ',';
+ snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
+ BrowseRemoteOptions);
+ }
+ else
+ {
+ /*
+ * Just use the local options...
+ */
- strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
- air += strlen(air);
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
}
- keyvalue[i ][0] = "air";
- keyvalue[i++][1] = air;
+ uri = finaluri;
}
+ else if (ipp_options)
+ {
+ /*
+ * Just use the server-supplied options...
+ */
- /*
- * 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);
+ snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
+ uri = finaluri;
+ }
/*
- * Closing the socket deregisters the service
+ * See if we already have it listed in the Printers list, and add it if not...
*/
- 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);
+ type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+ type &= ~CUPS_PRINTER_IMPLICIT;
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
+ is_class = type & CUPS_PRINTER_CLASS;
+ uuid = cupsGetOption("uuid", num_attrs, attrs);
- if (p->txt_record)
+ if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
{
/*
- * p->txt_record is malloc'd, not _cupsStrAlloc'd...
+ * Strip the common domain name components...
*/
- free(p->txt_record);
- p->txt_record = NULL;
+ while (hptr != NULL)
+ {
+ if (!strcasecmp(hptr, sptr))
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
}
-}
+ if (is_class)
+ {
+ /*
+ * Remote destination is a class...
+ */
-/*
- * '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 */
+ if (!strncmp(resource, "/classes/", 9))
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+ shortname = resource + 9;
+ }
+ else
+ {
+ /*
+ * Remote destination is a printer...
+ */
- /*
- * Calculate the buffer size
- */
+ if (!strncmp(resource, "/printers/", 10))
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
- for (length = i = 0; i < count; i++)
- length += 1 + strlen(keyvalue[i][0]) +
- (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
+ shortname = resource + 10;
+ }
- /*
- * Allocate and fill it
- */
+ if (hptr && !*hptr)
+ *hptr = '.'; /* Resource FQDN */
- txtRecord = malloc(length);
- if (txtRecord)
+ if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
{
- *txt_len = length;
+ /*
+ * Long name doesn't exist, try short name...
+ */
- for (cursor = txtRecord, i = 0; i < count; i++)
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
+ name);
+
+ if ((p = cupsdFindDest(shortname)) == NULL)
{
/*
- * Drop in the p-string style length byte followed by the data
+ * Short name doesn't exist, use it for this shared queue.
*/
- length = strlen(keyvalue[i][0]);
- length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
-
- *cursor++ = (unsigned char)(length + length2);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
+ shortname);
+ strlcpy(name, shortname, sizeof(name));
+ }
+ else
+ {
+ /*
+ * Short name exists...
+ */
- memcpy(cursor, keyvalue[i][0], length);
- cursor += length;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data: %s found, type=%x, hostname=%s...",
+ shortname, p->type, p->hostname ? p->hostname : "(nil)");
- if (length2)
+ if (p->type & CUPS_PRINTER_IMPLICIT)
+ p = NULL; /* Don't replace implicit classes */
+ else if (p->hostname && strcasecmp(p->hostname, host))
{
- length2 --;
- *cursor++ = '=';
- memcpy(cursor, keyvalue[i][1], length2);
- cursor += length2;
+ /*
+ * Short name exists but is for a different host. If this is a remote
+ * queue, rename it and use the long name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "Renamed remote %s \"%s\" to \"%s@%s\"...",
+ is_class ? "class" : "printer", p->name, p->name,
+ p->hostname);
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services.",
+ is_class ? "Class" : "Printer", p->name);
+
+ snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
+ cupsdRenamePrinter(p, newname);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "%s \'%s\' added by directory services.",
+ is_class ? "Class" : "Printer", p->name);
+ }
+
+ /*
+ * Force creation with long name...
+ */
+
+ p = NULL;
}
}
}
+ else if (p)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "process_browse_data: %s found, type=%x, hostname=%s...",
+ name, p->type, p->hostname ? p->hostname : "(nil)");
- return (txtRecord);
-}
+ if (!p)
+ {
+ /*
+ * Queue doesn't exist; add it...
+ */
+ if (is_class)
+ p = cupsdAddClass(name);
+ else
+ p = cupsdAddPrinter(name);
-/*
- * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
- */
+ if (!p)
+ return;
-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;
+ cupsdClearString(&(p->hostname));
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "dnssdRegisterCallback(%s, %s)", name, regtype);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
+ is_class ? "class" : "printer", name);
- if (errorCode)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "DNSServiceRegister failed with error %d", (int)errorCode);
- return;
- }
-}
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
+ "%s \'%s\' added by directory services.",
+ is_class ? "Class" : "Printer", name);
+ /*
+ * Force the URI to point to the real server...
+ */
-/*
- * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
- * or update the broadcast contents.
- */
+ p->type = type & ~CUPS_PRINTER_REJECTING;
+ p->accepting = 1;
-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 */
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ }
+ if (!p->hostname)
+ {
+ /*
+ * Hostname not set, so this must be a cached remote printer
+ * that was created for a pending print job...
+ */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
- !p->dnssd_ipp_ref ? "new" : "update");
+ cupsdSetString(&p->hostname, host);
+ cupsdSetString(&p->uri, uri);
+ cupsdSetString(&p->device_uri, uri);
+ update = 1;
+
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ }
/*
- * If per-printer sharing was just disabled make sure we're not
- * registered before returning.
+ * Update the state...
*/
- if (!p->shared)
+ p->state = state;
+ p->browse_time = time(NULL);
+
+ if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
+ attrs)) != NULL)
{
- dnssdDeregisterPrinter(p);
- return;
+ /*
+ * Grab the lease-duration for the browse data; anything less then 1
+ * second or more than 1 week gets the default BrowseTimeout...
+ */
+
+ i = atoi(lease_duration);
+ if (i < 1 || i > 604800)
+ i = BrowseTimeout;
+
+ p->browse_expire = p->browse_time + i;
}
+ else
+ p->browse_expire = p->browse_time + BrowseTimeout;
- /*
- * Get the computer name as a c-string...
- */
+ if (type & CUPS_PRINTER_REJECTING)
+ {
+ type &= ~CUPS_PRINTER_REJECTING;
-#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 */
+ if (p->accepting)
+ {
+ update = 1;
+ p->accepting = 0;
+ }
+ }
+ else if (!p->accepting)
+ {
+ update = 1;
+ p->accepting = 1;
+ }
- /*
- * The registered name takes the form of "<printer-info> @ <computer name>"...
- */
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
- 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);
+ if (uuid && strcmp(p->uuid, uuid))
+ {
+ cupsdSetString(&p->uuid, uuid);
+ update = 1;
+ }
-#ifdef HAVE_COREFOUNDATION_H
- if (computerNameRef)
- CFRelease(computerNameRef);
-#endif /* HAVE_COREFOUNDATION_H */
+ if (location && (!p->location || strcmp(p->location, location)))
+ {
+ cupsdSetString(&p->location, location);
+ update = 1;
+ }
- /*
- * If an existing printer was renamed, unregister it and start over...
- */
+ if (info && (!p->info || strcmp(p->info, info)))
+ {
+ cupsdSetString(&p->info, info);
+ update = 1;
- if (p->reg_name && strcmp(p->reg_name, name))
- dnssdDeregisterPrinter(p);
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
- txt_len = 0; /* anti-compiler-warning-code */
- txt_record = dnssdBuildTxtRecord(&txt_len, p);
+ if (!make_model || !make_model[0])
+ {
+ if (is_class)
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Class on %s", host);
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Printer on %s", host);
+ }
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "%s on %s", make_model, host);
- if (!p->dnssd_ipp_ref)
+ if (!p->make_model || strcmp(p->make_model, local_make_model))
{
- /*
- * Initial registration...
- */
-
- cupsdSetString(&p->reg_name, name);
-
- port = ippPort();
+ cupsdSetString(&p->make_model, local_make_model);
+ update = 1;
+ }
- for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
- lis;
- lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+ if (p->num_options)
+ {
+ if (!update && !(type & CUPS_PRINTER_DELETE))
{
- 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)
+ /*
+ * See if we need to update the attributes...
+ */
+
+ if (p->num_options != num_attrs)
+ update = 1;
+ else
{
- port = ntohs(lis->address.ipv6.sin6_port);
- break;
+ for (i = 0; i < num_attrs; i ++)
+ if (strcmp(attrs[i].name, p->options[i].name) ||
+ (!attrs[i].value != !p->options[i].value) ||
+ (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
+ {
+ update = 1;
+ break;
+ }
}
}
/*
- * Use the _fax subtype for fax queues...
+ * Free the old options...
*/
- 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...
- */
+ cupsFreeOptions(p->num_options, p->options);
+ }
- if (se == kDNSServiceErr_BadParam)
- {
-#ifdef HAVE_COREFOUNDATION_H
- if ((shortNameRef = CFStringCreateMutable(NULL, 0)) != NULL)
- {
- CFStringAppendCString(shortNameRef, name, kCFStringEncodingUTF8);
- nameLength = CFStringGetLength(shortNameRef);
+ p->num_options = num_attrs;
+ p->options = attrs;
- 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);
- }
- }
+ if (type & CUPS_PRINTER_DELETE)
+ {
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
+ "%s \'%s\' deleted by directory services.",
+ is_class ? "Class" : "Printer", p->name);
- 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 */
- }
+ cupsdExpireSubscriptions(p, NULL);
+
+ cupsdDeletePrinter(p, 1);
+ cupsdUpdateImplicitClasses();
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ }
+ else if (update)
+ {
+ cupsdSetPrinterAttrs(p);
+ cupsdUpdateImplicitClasses();
+ }
- 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;
+ /*
+ * See if we have a default printer... If not, make the first network
+ * default printer the default.
+ */
- 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))
+ if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
{
/*
- * Update the existing registration...
+ * Find the first network default printer and use it...
*/
- /* 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;
+ for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+ p;
+ p = (cupsd_printer_t *)cupsArrayNext(Printers))
+ if (p->type & CUPS_PRINTER_DEFAULT)
+ {
+ DefaultPrinter = p;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+ break;
+ }
}
- if (txt_record)
- free(txt_record);
+ /*
+ * Do auto-classing if needed...
+ */
- cupsdClearString(&name);
+ process_implicit_classes();
}
-#endif /* HAVE_DNSSD */
/*
update = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
+
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
name);
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
else
len = strlen(p->name);
+ if (len >= sizeof(name))
+ {
+ /*
+ * If the printer name length somehow is greater than we normally allow,
+ * skip this printer...
+ */
+
+ len = 0;
+ cupsArrayRestore(Printers);
+ continue;
+ }
+
strncpy(name, p->name, len);
name[len] = '\0';
offset = 0;
uri[1024], /* Printer URI */
location[1024], /* printer-location */
info[1024], /* printer-info */
- make_model[1024];
+ make_model[1024],
/* printer-make-and-model */
+ air[1024]; /* auth-info-required */
cupsd_netif_t *iface; /* Network interface */
else
strlcpy(make_model, "Local System V Printer", sizeof(make_model));
+ if (get_auth_info_required(p, packet, sizeof(packet)))
+ snprintf(air, sizeof(air), " auth-info-required=%s", packet);
+ else
+ air[0] = '\0';
+
/*
* Send a packet to each browse address...
*/
(p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
"/printers/%s",
p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
type, p->state, uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
bytes = strlen(packet);
(p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
"/printers/%s",
p->name);
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
type, p->state, uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
bytes = strlen(packet);
* the default server name...
*/
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
+ snprintf(packet, sizeof(packet),
+ "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
type, p->state, p->uri, location, info, make_model,
- p->browse_attrs ? p->browse_attrs : "");
+ p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
bytes = strlen(packet);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"%d - %s.",
(int)(b - Browsers + 1), strerror(errno));
- if (i > 1)
- memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+ if (i > 1)
+ memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
+
+ b --;
+ NumBrowsers --;
+ }
+ }
+}
+
+
+#ifdef HAVE_LDAP
+/*
+ * '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)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP search failed with status %d: %s",
+ rc, ldap_err2string(rc));
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "We try the LDAP search once again after reconnecting to "
+ "the server");
+ 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)
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "ldap_search_rec: LDAP entry/object not found");
+ else if (rc != LDAP_SUCCESS)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "ldap_search_rec: LDAP search failed with status %d: %s",
+ 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 */
+
+
+ rc = ldap_msgfree(entry);
+ if (rc == -1)
+ cupsdLogMessage(CUPSD_LOG_WARN, "Can't free LDAPMessage!");
+ else if (rc == 0)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "Freeing LDAPMessage was unnecessary");
+}
+
+
+/*
+ * '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 */
+{
+ 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 */
+
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+ /*
+ * Check size and copy value into our string...
+ */
+
+ size = maxsize;
+ if (size < (bval[0]->bv_len + 1))
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "Attribute %s is too big! (dn: %s)",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ size = bval[0]->bv_len + 1;
+
+ strlcpy(retval, bval[0]->bv_val, size);
+ ldap_value_free_len(bval);
+ }
+# else
+ char **value; /* LDAP value */
+
+ /*
+ * Get value from LDAPMessage...
+ */
+
+ if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
+ {
+ rc = -1;
+ dn = ldap_get_dn(ld, entry);
+ cupsdLogMessage(CUPSD_LOG_WARN, "Failed to get LDAP value %s for %s!",
+ attr, dn);
+ ldap_memfree(dn);
+ }
+ else
+ {
+ strlcpy(retval, *value, maxsize);
+ ldap_value_free(value);
+ }
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ return (rc);
+}
+
+
+/*
+ * 'send_ldap_ou()' - Send LDAP ou registrations.
+ */
+
+static void
+send_ldap_ou(char *ou, /* I - Servername/ou to register */
+ char *basedn, /* I - Our base dn */
+ char *descstring) /* I - Description for ou */
+{
+ int i; /* Looping var... */
+ LDAPMod mods[3]; /* The 3 attributes we will be adding */
+ LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
+ int rc; /* LDAP status */
+ int rcmod; /* LDAP status for modifications */
+ char dn[1024], /* DN of the organizational unit we are adding */
+ *desc[2], /* Change records */
+ *ou_value[2];
+ char old_desc[1024]; /* Old description */
+ static const char * const objectClass_values[] =
+ { /* The 2 objectClass's we use in */
+ "top", /* our LDAP entries */
+ "organizationalUnit",
+ NULL
+ };
+ static const char * const ou_attrs[] =/* CUPS LDAP attributes */
+ {
+ "description",
+ NULL
+ };
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: LDAP Handle is invalid. Try reconnecting...");
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Prepare ldap search...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
+
+ ou_value[0] = ou;
+ ou_value[1] = NULL;
+ desc[0] = descstring;
+ desc[1] = NULL;
+
+ mods[0].mod_type = "ou";
+ mods[0].mod_values = ou_value;
+ mods[1].mod_type = "description";
+ mods[1].mod_values = desc;
+ mods[2].mod_type = "objectClass";
+ mods[2].mod_values = (char **)objectClass_values;
+
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ou_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ return;
+
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
+
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
+ {
+ /*
+ * Printserver has already been registered, check if
+ * modification is required...
+ */
+
+ e = ldap_first_entry(BrowseLDAPHandle, res);
+
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
+ sizeof(old_desc)) == -1)
+ old_desc[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if ( strcmp(desc[0], old_desc) == 0 )
+ {
+ /*
+ * LDAP entry for the printer exists.
+ * Printer has already been registered,
+ * no modifications required...
+ */
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: No updates required for %s", ou);
+ }
+ else
+ {
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Replace entry for %s", ou);
+
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ ou, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Printserver has never been registered,
+ * add registration...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_ou: Add entry for %s", ou);
- b --;
- NumBrowsers --;
- }
+ for (i = 0; i < 3; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_ADD;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP add for %s failed with status %d: %s",
+ ou, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
}
+ }
+
+ if (rc == LDAP_SUCCESS)
+ ldap_freeres(res);
}
-#ifdef HAVE_OPENLDAP
/*
* 'send_ldap_browse()' - Send LDAP printer registrations.
*/
int i; /* Looping var... */
LDAPMod mods[7]; /* The 7 attributes we will be adding */
LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
- LDAPMessage *res; /* Search result token */
+ LDAPMessage *res, /* Search result token */
+ *e; /* Current entry from search */
char *cn_value[2], /* Change records */
*uri[2],
*info[2],
*make_model[2],
*type[2],
typestring[255], /* String to hold printer-type */
- filter[256], /* Search filter for possible UPDATEs */
dn[1024]; /* DN of the printer we are adding */
int rc; /* LDAP status */
+ int rcmod; /* LDAP status for modifications */
+ char old_uri[HTTP_MAX_URI], /* Printer URI */
+ old_location[1024], /* Printer location */
+ old_info[1024], /* Printer information */
+ old_make_model[1024], /* Printer make and model */
+ old_type_string[30]; /* Temporary type number */
+ int old_type; /* Printer type */
static const char * const objectClass_values[] =
{ /* The 3 objectClass's we use in */
"top", /* our LDAP entries */
NULL
};
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s\n", p->name);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
+
+ /*
+ * Exit function if LDAP updates has been disabled...
+ */
+
+ if (!BrowseLDAPUpdate)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Updates temporary disabled; "
+ "skipping...");
+ return;
+ }
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: LDAP Handle is invalid. Try "
+ "reconnecting...");
+ ldap_reconnect();
+ return;
+ }
/*
* Everything in ldap is ** so we fudge around it...
uri[0] = p->uri;
uri[1] = NULL;
- snprintf(filter, sizeof(filter),
- "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
+ /*
+ * Get ldap entry for printer ...
+ */
+
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+
+ rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+ (char **)ldap_attrs, 0, &res);
+
+ /*
+ * If ldap search was not successfull then exit function
+ * and temporary disable LDAP updates...
+ */
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ {
+ if (BrowseLDAPUpdate &&
+ (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
+ {
+ BrowseLDAPUpdate = FALSE;
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "LDAP update temporary disabled");
+ }
+
+ return;
+ }
- ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
- filter, (char **)ldap_attrs, 0, &res);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
- filter);
+ /*
+ * Fill modification array...
+ */
- mods[0].mod_type = "cn";
+ mods[0].mod_type = "cn";
mods[0].mod_values = cn_value;
- mods[1].mod_type = "printerDescription";
+ mods[1].mod_type = "printerDescription";
mods[1].mod_values = info;
- mods[2].mod_type = "printerURI";
+ mods[2].mod_type = "printerURI";
mods[2].mod_values = uri;
- mods[3].mod_type = "printerLocation";
+ mods[3].mod_type = "printerLocation";
mods[3].mod_values = location;
- mods[4].mod_type = "printerMakeAndModel";
+ mods[4].mod_type = "printerMakeAndModel";
mods[4].mod_values = make_model;
- mods[5].mod_type = "printerType";
+ mods[5].mod_type = "printerType";
mods[5].mod_values = type;
- mods[6].mod_type = "objectClass";
+ mods[6].mod_type = "objectClass";
mods[6].mod_values = (char **)objectClass_values;
- snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+ /*
+ * Check if we need to insert or update the LDAP entry...
+ */
- if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
+ if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+ rc != LDAP_NO_SUCH_OBJECT)
{
/*
- * Printer has already been registered, modify the current
- * registration...
+ * Printer has already been registered, check if
+ * modification is required...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Replacing entry...");
+ e = ldap_first_entry(BrowseLDAPHandle, res);
- for (i = 0; i < 7; i ++)
+ /*
+ * Get the required values from this entry...
+ */
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
+ old_info, sizeof(old_info)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
+ old_location, sizeof(old_location)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
+ old_make_model, sizeof(old_make_model)) == -1)
+ old_info[0] = '\0';
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
+ old_type_string, sizeof(old_type_string)) == -1)
+ old_info[0] = '\0';
+
+ old_type = atoi(old_type_string);
+
+ if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
+ sizeof(old_uri)) == -1)
+ old_info[0] = '\0';
+
+ /*
+ * Check if modification is required...
+ */
+
+ if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
+ !strcmp(location[0], old_location) &&
+ !strcmp(make_model[0], old_make_model) && p->type == old_type)
{
- pmods[i] = mods + i;
- pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * no modifications required...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: No updates required for %s", p->name);
}
- pmods[i] = NULL;
+ else
+ {
+ /*
+ * LDAP entry for the printer exists. Printer has already been registered,
+ * modify the current registration...
+ */
- if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "LDAP modify for %s failed with status %d: %s",
- p->name, rc, ldap_err2string(rc));
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "send_ldap_browse: Replace entry for %s", p->name);
+
+ for (i = 0; i < 7; i ++)
+ {
+ pmods[i] = mods + i;
+ pmods[i]->mod_op = LDAP_MOD_REPLACE;
+ }
+ pmods[i] = NULL;
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "LDAP modify for %s failed with status %d: %s",
+ p->name, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
}
else
{
/*
- * Printer has never been registered, add the current
- * registration...
+ * No LDAP entry exists for the printer. Printer has never been registered,
+ * add the current registration...
*/
+ send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
+
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "send_ldap_browse: Adding entry...");
+ "send_ldap_browse: Add entry for %s", p->name);
for (i = 0; i < 7; i ++)
{
}
pmods[i] = NULL;
- if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
cupsdLogMessage(CUPSD_LOG_ERROR,
"LDAP add for %s failed with status %d: %s",
- p->name, rc, ldap_err2string(rc));
+ p->name, rcmod, ldap_err2string(rcmod));
+ if (rcmod == LDAP_SERVER_DOWN)
+ ldap_reconnect();
+ }
+ }
+
+ if (rc == LDAP_SUCCESS)
+ ldap_freeres(res);
+}
+
+
+/*
+ * 'ldap_dereg_printer()' - Delete printer from directory
+ */
+
+static void
+ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
+ p->name);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+ BrowseLDAPDN);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", p->name);
+ ldap_reconnect();
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ p->name, rc, ldap_err2string(rc));
+ }
}
}
-#endif /* HAVE_OPENLDAP */
+
+
+/*
+ * 'ldap_dereg_ou()' - Remove the organizational unit.
+ */
+
+static void
+ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
+ char *basedn) /* I - Dase dn */
+{
+ char dn[1024]; /* DN of the printer */
+ int rc; /* LDAP status */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
+
+ /*
+ * Reconnect if LDAP Handle is invalid...
+ */
+
+ if (!BrowseLDAPHandle)
+ {
+ ldap_reconnect();
+ return;
+ }
+
+ /*
+ * Get dn for printer and delete LDAP entry...
+ */
+
+ snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
+
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ {
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+
+ /*
+ * If we had a connection problem (connection timed out, etc.)
+ * we should reconnect and try again to delete the entry...
+ */
+
+ if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Retry deleting LDAP entry for %s after a reconnect...", ou);
+ ldap_reconnect();
+# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+ if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+ NULL)) != LDAP_SUCCESS)
+# else
+ if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "LDAP delete for %s failed with status %d: %s",
+ ou, rc, ldap_err2string(rc));
+ }
+ }
+}
+#endif /* HAVE_LDAP */
#ifdef HAVE_LIBSLP
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
strerror(errno));
- cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+ cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
+
+#ifdef WIN32
+ closesocket(BrowseSocket);
+#else
+ close(BrowseSocket);
+#endif /* WIN32 */
+
+ cupsdRemoveSelect(BrowseSocket);
+ BrowseSocket = -1;
- cupsdStopBrowsing();
- Browsing = 0;
+ BrowseLocalProtocols &= ~BROWSE_CUPS;
+ BrowseRemoteProtocols &= ~BROWSE_CUPS;
}
return;
* Access from localhost (127.0.0.1) is always allowed...
*/
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
}
else
{
switch (BrowseACL->order_type)
{
default :
- auth = AUTH_DENY; /* anti-compiler-warning-code */
+ auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
break;
- case AUTH_ALLOW : /* Order Deny,Allow */
- auth = AUTH_ALLOW;
+ case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
+ auth = CUPSD_AUTH_ALLOW;
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
break;
- case AUTH_DENY : /* Order Allow,Deny */
- auth = AUTH_DENY;
+ case CUPSD_AUTH_DENY : /* Order Allow,Deny */
+ auth = CUPSD_AUTH_DENY;
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_allow, BrowseACL->allow))
- auth = AUTH_ALLOW;
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
+ auth = CUPSD_AUTH_ALLOW;
- if (cupsdCheckAuth(address, srcname, len,
- BrowseACL->num_deny, BrowseACL->deny))
- auth = AUTH_DENY;
+ if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
+ auth = CUPSD_AUTH_DENY;
break;
}
}
}
else
- auth = AUTH_ALLOW;
+ auth = CUPSD_AUTH_ALLOW;
- if (auth == AUTH_DENY)
+ if (auth == CUPSD_AUTH_DENY)
{
cupsdLogMessage(CUPSD_LOG_DEBUG,
"update_cups_browse: Refused %d bytes from %s", bytes,
*/
for (i = 0; i < NumRelays; i ++)
- if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+ if (cupsdCheckAuth(address, srcname, len, Relays[i].from))
if (sendto(BrowseSocket, packet, bytes, 0,
(struct sockaddr *)&(Relays[i].to),
httpAddrLength(&(Relays[i].to))) <= 0)
}
+/*
+ * 'update_lpd()' - Update the LPD configuration as needed.
+ */
+
+static void
+update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
+{
+ if (!LPDConfigFile)
+ return;
+
+#ifdef __APPLE__
+ /*
+ * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
+ * setting for backwards-compatibility.
+ */
+
+ if (onoff && !get_hostconfig("CUPS_LPD"))
+ onoff = 0;
+#endif /* __APPLE__ */
+
+ 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 ="))
+ cupsFilePrintf(nfp, "%s\n", line);
+ }
+
+ cupsFileClose(nfp);
+ cupsFileClose(ofp);
+ rename(newfile, LPDConfigFile + 9);
+ }
+#ifdef __APPLE__
+ 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,
+ NULL, NULL, &pid);
+ }
+#endif /* __APPLE__ */
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
+}
+
+
/*
* 'update_polling()' - Read status messages from the poll daemons.
*/
while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
message, sizeof(message))) != NULL)
+ {
+ if (loglevel == CUPSD_LOG_INFO)
+ cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
+
if (!strchr(PollStatusBuffer->buffer, '\n'))
break;
+ }
if (ptr == NULL && !PollStatusBuffer->bufused)
{
/*
- * End of "$Id: dirsvc.c 6538 2007-05-17 18:26:05Z mike $".
+ * '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
+ cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
+}
+
+
+/*
+ * End of "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $".
*/