2 * "$Id: dirsvc.c 10243 2012-02-11 02:05:21Z mike $"
4 * Directory services routines for the CUPS scheduler.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
18 * printer and remove any pending references to
20 * cupsdLoadRemoteCache() - Load the remote printer cache.
21 * cupsdRegisterPrinter() - Start sending broadcast information for a
22 * printer or update the broadcast contents.
23 * cupsdRestartPolling() - Restart polling servers as needed.
24 * cupsdSaveRemoteCache() - Save the remote printer cache.
25 * cupsdSendBrowseList() - Send new browsing information as necessary.
26 * ldap_rebind_proc() - Callback function for LDAP rebind
27 * ldap_connect() - Start new LDAP connection
28 * ldap_reconnect() - Reconnect to LDAP Server
29 * ldap_disconnect() - Disconnect from LDAP Server
30 * cupsdStartAvahiClient() - Start an Avahi client if needed
31 * cupsdStartBrowsing() - Start sending and receiving broadcast
33 * cupsdStartPolling() - Start polling servers as needed.
34 * cupsdStopBrowsing() - Stop sending and receiving broadcast
36 * cupsdStopPolling() - Stop polling servers as needed.
37 * cupsdUpdateDNSSDName() - Update the computer name we use for
39 * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
40 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
41 * dequote() - Remote quotes from a string.
42 * dnssdAddAlias() - Add a DNS-SD alias name.
43 * dnssdBuildTxtRecord() - Build a TXT record from printer info.
44 * dnssdComparePrinters() - Compare the registered names of two printers.
45 * dnssdDeregisterPrinter() - Stop sending broadcast information for a
47 * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
49 * avahiPackTxtRecord() - Pack an array of key/value pairs into an
51 * dnssdRegisterCallback() - DNSServiceRegister callback.
52 * dnssdRegisterPrinter() - Start sending broadcast information for a
53 * printer or update the broadcast contents.
54 * dnssdStop() - Stop all DNS-SD registrations.
55 * dnssdUpdate() - Handle DNS-SD queries.
56 * get_auth_info_required() - Get the auth-info-required value to advertise.
57 * get_hostconfig() - Get an /etc/hostconfig service setting.
58 * is_local_queue() - Determine whether the URI points at a local
60 * process_browse_data() - Process new browse data.
61 * process_implicit_classes() - Create/update implicit classes as needed.
62 * send_cups_browse() - Send new browsing information using the CUPS
64 * ldap_search_rec() - LDAP Search with reconnect
65 * ldap_freeres() - Free LDAPMessage
66 * ldap_getval_char() - Get first LDAP value and convert to string
67 * send_ldap_ou() - Send LDAP ou registrations.
68 * send_ldap_browse() - Send LDAP printer registrations.
69 * ldap_dereg_printer() - Delete printer from directory
70 * ldap_dereg_ou() - Remove the organizational unit.
71 * send_slp_browse() - Register the specified printer with SLP.
72 * slp_attr_callback() - SLP attribute callback
73 * slp_dereg_printer() - SLPDereg() the specified printer
74 * slp_get_attr() - Get an attribute from an SLP registration.
75 * slp_reg_callback() - Empty SLPRegReport.
76 * slp_url_callback() - SLP service url callback
77 * update_cups_browse() - Update the browse lists using the CUPS
79 * update_lpd() - Update the LPD configuration as needed.
80 * update_polling() - Read status messages from the poll daemons.
81 * update_smb() - Update the SMB configuration as needed.
85 * Include necessary headers...
96 # ifdef HAVE_COREFOUNDATION
97 # include <CoreFoundation/CoreFoundation.h>
98 # endif /* HAVE_COREFOUNDATION */
99 # ifdef HAVE_SYSTEMCONFIGURATION
100 # include <SystemConfiguration/SystemConfiguration.h>
101 # endif /* HAVE_SYSTEMCONFIGURATION */
102 # endif /* __APPLE__ */
103 #endif /* HAVE_DNSSD */
105 # include <avahi-common/domain.h>
106 #endif /* HAVE_AVAHI */
110 typedef char *cupsd_txt_record_t;
111 #endif /* HAVE_DNSSD */
113 typedef AvahiStringList *cupsd_txt_record_t;
114 #endif /* HAVE_AVAHI */
121 static char *dequote(char *d, const char *s, int dlen);
122 static char *get_auth_info_required(cupsd_printer_t *p, char *buffer,
125 static int get_hostconfig(const char *name);
126 #endif /* __APPLE__ */
127 static int is_local_queue(const char *uri, char *host, int hostlen,
128 char *resource, int resourcelen);
129 static void process_browse_data(const char *uri, const char *host,
130 const char *resource, cups_ptype_t type,
131 ipp_pstate_t state, const char *location,
132 const char *info, const char *make_model,
133 int num_attrs, cups_option_t *attrs);
134 static void process_implicit_classes(void);
135 static void send_cups_browse(cupsd_printer_t *p);
137 static LDAP *ldap_connect(void);
138 static LDAP *ldap_reconnect(void);
139 static void ldap_disconnect(LDAP *ld);
140 static int ldap_search_rec(LDAP *ld, char *base, int scope,
141 char *filter, char *attrs[],
142 int attrsonly, LDAPMessage **res);
143 static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
144 char *attr, char *retval,
145 unsigned long maxsize);
146 static void ldap_freeres(LDAPMessage *entry);
147 static void send_ldap_ou(char *ou, char *basedn, char *descstring);
148 static void send_ldap_browse(cupsd_printer_t *p);
149 static void ldap_dereg_printer(cupsd_printer_t *p);
150 static void ldap_dereg_ou(char *ou, char *basedn);
151 # ifdef HAVE_LDAP_REBIND_PROC
152 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
153 static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
154 LDAP_CONST char *refsp,
159 static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
165 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
166 # endif /* HAVE_LDAP_REBIND_PROC */
167 #endif /* HAVE_LDAP */
169 static void send_slp_browse(cupsd_printer_t *p);
170 #endif /* HAVE_LIBSLP */
171 static void update_cups_browse(void);
172 static void update_lpd(int onoff);
173 static void update_polling(void);
174 static void update_smb(int onoff);
177 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
178 static cupsd_txt_record_t dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
180 static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
181 static void dnssdDeregisterPrinter(cupsd_printer_t *p);
182 static void dnssdRegisterPrinter(cupsd_printer_t *p);
183 static void dnssdStop(void);
184 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
187 # ifdef HAVE_COREFOUNDATION
188 static void dnssdAddAlias(const void *key, const void *value,
190 # endif /* HAVE_COREFOUNDATION */
191 static void dnssdRegisterCallback(DNSServiceRef sdRef,
192 DNSServiceFlags flags,
193 DNSServiceErrorType errorCode,
194 const char *name, const char *regtype,
195 const char *domain, void *context);
196 static void dnssdUpdate(void);
197 #endif /* HAVE_DNSSD */
200 static AvahiStringList *avahiPackTxtRecord(char *keyvalue[][2],
202 static void avahi_entry_group_cb (AvahiEntryGroup *group,
203 AvahiEntryGroupState state,
205 static void avahi_client_cb (AvahiClient *client,
206 AvahiClientState state,
208 #endif /* HAVE_AVAHI */
211 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
213 "printerDescription",
215 "printerMakeAndModel",
220 #endif /* HAVE_LDAP */
228 * SLP service name for CUPS...
231 # define SLP_CUPS_SRVTYPE "service:printer"
232 # define SLP_CUPS_SRVLEN 15
236 * Printer service URL structure
239 typedef struct _slpsrvurl_s /**** SLP URL list ****/
241 struct _slpsrvurl_s *next; /* Next URL in list */
242 char url[HTTP_MAX_URI];
251 static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
252 SLPError errcode, void *cookie);
253 static void slp_dereg_printer(cupsd_printer_t *p);
254 static int slp_get_attr(const char *attrlist, const char *tag,
256 static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
258 static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
259 unsigned short lifetime,
260 SLPError errcode, void *cookie);
261 #endif /* HAVE_LIBSLP */
265 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
266 * local printer and remove any pending
267 * references to remote printers.
271 cupsdDeregisterPrinter(
272 cupsd_printer_t *p, /* I - Printer to register */
273 int removeit) /* I - Printer being permanently removed */
276 * Only deregister if browsing is enabled and it's a local printer...
279 cupsdLogMessage(CUPSD_LOG_DEBUG,
280 "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
283 if (!Browsing || !p->shared ||
284 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
285 CUPS_PRINTER_SCANNER)))
289 * Announce the deletion...
292 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
294 cups_ptype_t savedtype = p->type; /* Saved printer type */
296 p->type |= CUPS_PRINTER_DELETE;
304 if (BrowseLocalProtocols & BROWSE_SLP)
305 slp_dereg_printer(p);
306 #endif /* HAVE_LIBSLP */
309 if (BrowseLocalProtocols & BROWSE_LDAP)
310 ldap_dereg_printer(p);
311 #endif /* HAVE_LDAP */
313 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
314 if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
315 dnssdDeregisterPrinter(p);
316 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
321 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
325 cupsdLoadRemoteCache(void)
327 int i; /* Looping var */
328 cups_file_t *fp; /* remote.cache file */
329 int linenum; /* Current line number */
330 char line[4096], /* Line from file */
331 *value, /* Pointer to value */
332 *valueptr, /* Pointer into value */
333 scheme[32], /* Scheme portion of URI */
334 username[64], /* Username portion of URI */
336 /* Hostname portion of URI */
337 resource[HTTP_MAX_URI];
338 /* Resource portion of URI */
339 int port; /* Port number */
340 cupsd_printer_t *p; /* Current printer */
341 time_t now; /* Current time */
345 * Don't load the cache if the remote protocols are disabled...
350 cupsdLogMessage(CUPSD_LOG_DEBUG,
351 "cupsdLoadRemoteCache: Not loading remote cache.");
356 * Open the remote.cache file...
359 snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
360 if ((fp = cupsdOpenConfFile(line)) == NULL)
364 * Read printer configurations until we hit EOF...
371 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
374 * Decode the directive...
377 if (!_cups_strcasecmp(line, "<Printer") ||
378 !_cups_strcasecmp(line, "<DefaultPrinter"))
381 * <Printer name> or <DefaultPrinter name>
384 if (p == NULL && value)
387 * Add the printer and a base file type...
390 cupsdLogMessage(CUPSD_LOG_DEBUG,
391 "cupsdLoadRemoteCache: Loading printer %s...", value);
393 if ((p = cupsdFindDest(value)) != NULL)
395 if (p->type & CUPS_PRINTER_CLASS)
397 cupsdLogMessage(CUPSD_LOG_WARN,
398 "Cached remote printer \"%s\" conflicts with "
406 p = cupsdAddPrinter(value);
409 p->state = IPP_PRINTER_IDLE;
410 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
411 p->browse_time = now;
412 p->browse_expire = now + BrowseTimeout;
415 * Set the default printer as needed...
418 if (!_cups_strcasecmp(line, "<DefaultPrinter"))
423 cupsdLogMessage(CUPSD_LOG_ERROR,
424 "Syntax error on line %d of remote.cache.", linenum);
428 else if (!_cups_strcasecmp(line, "<Class") ||
429 !_cups_strcasecmp(line, "<DefaultClass"))
432 * <Class name> or <DefaultClass name>
435 if (p == NULL && value)
438 * Add the printer and a base file type...
441 cupsdLogMessage(CUPSD_LOG_DEBUG,
442 "cupsdLoadRemoteCache: Loading class %s...", value);
444 if ((p = cupsdFindDest(value)) != NULL)
445 p->type = CUPS_PRINTER_CLASS;
447 p = cupsdAddClass(value);
450 p->state = IPP_PRINTER_IDLE;
451 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
452 p->browse_time = now;
453 p->browse_expire = now + BrowseTimeout;
456 * Set the default printer as needed...
459 if (!_cups_strcasecmp(line, "<DefaultClass"))
464 cupsdLogMessage(CUPSD_LOG_ERROR,
465 "Syntax error on line %d of remote.cache.", linenum);
469 else if (!_cups_strcasecmp(line, "</Printer>") ||
470 !_cups_strcasecmp(line, "</Class>"))
475 * Close out the current printer...
478 cupsdSetPrinterAttrs(p);
483 cupsdLogMessage(CUPSD_LOG_ERROR,
484 "Syntax error on line %d of remote.cache.", linenum);
488 cupsdLogMessage(CUPSD_LOG_ERROR,
489 "Syntax error on line %d of remote.cache.", linenum);
491 else if (!_cups_strcasecmp(line, "UUID"))
493 if (value && !strncmp(value, "urn:uuid:", 9))
494 cupsdSetString(&(p->uuid), value);
496 cupsdLogMessage(CUPSD_LOG_ERROR,
497 "Bad UUID on line %d of remote.cache.", linenum);
499 else if (!_cups_strcasecmp(line, "Info"))
502 cupsdSetString(&p->info, value);
504 else if (!_cups_strcasecmp(line, "MakeModel"))
507 cupsdSetString(&p->make_model, value);
509 else if (!_cups_strcasecmp(line, "Location"))
512 cupsdSetString(&p->location, value);
514 else if (!_cups_strcasecmp(line, "DeviceURI"))
518 httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
519 username, sizeof(username), host, sizeof(host), &port,
520 resource, sizeof(resource));
522 cupsdSetString(&p->hostname, host);
523 cupsdSetString(&p->uri, value);
524 cupsdSetDeviceURI(p, value);
527 cupsdLogMessage(CUPSD_LOG_ERROR,
528 "Syntax error on line %d of remote.cache.", linenum);
530 else if (!_cups_strcasecmp(line, "Option") && value)
536 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
539 cupsdLogMessage(CUPSD_LOG_ERROR,
540 "Syntax error on line %d of remote.cache.", linenum);
543 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
545 p->num_options = cupsAddOption(value, valueptr, p->num_options,
549 else if (!_cups_strcasecmp(line, "Reason"))
553 for (i = 0 ; i < p->num_reasons; i ++)
554 if (!strcmp(value, p->reasons[i]))
557 if (i >= p->num_reasons &&
558 p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
560 p->reasons[p->num_reasons] = _cupsStrAlloc(value);
565 cupsdLogMessage(CUPSD_LOG_ERROR,
566 "Syntax error on line %d of remote.cache.", linenum);
568 else if (!_cups_strcasecmp(line, "State"))
571 * Set the initial queue state...
574 if (value && !_cups_strcasecmp(value, "idle"))
575 p->state = IPP_PRINTER_IDLE;
576 else if (value && !_cups_strcasecmp(value, "stopped"))
578 p->state = IPP_PRINTER_STOPPED;
579 cupsdSetPrinterReasons(p, "+paused");
582 cupsdLogMessage(CUPSD_LOG_ERROR,
583 "Syntax error on line %d of remote.cache.", linenum);
585 else if (!_cups_strcasecmp(line, "StateMessage"))
588 * Set the initial queue state message...
592 strlcpy(p->state_message, value, sizeof(p->state_message));
594 else if (!_cups_strcasecmp(line, "Accepting"))
597 * Set the initial accepting state...
601 (!_cups_strcasecmp(value, "yes") ||
602 !_cups_strcasecmp(value, "on") ||
603 !_cups_strcasecmp(value, "true")))
606 (!_cups_strcasecmp(value, "no") ||
607 !_cups_strcasecmp(value, "off") ||
608 !_cups_strcasecmp(value, "false")))
611 cupsdLogMessage(CUPSD_LOG_ERROR,
612 "Syntax error on line %d of remote.cache.", linenum);
614 else if (!_cups_strcasecmp(line, "Type"))
617 p->type = atoi(value);
619 cupsdLogMessage(CUPSD_LOG_ERROR,
620 "Syntax error on line %d of remote.cache.", linenum);
622 else if (!_cups_strcasecmp(line, "BrowseTime"))
626 time_t t = atoi(value);
628 if (t > p->browse_expire)
629 p->browse_expire = t;
632 cupsdLogMessage(CUPSD_LOG_ERROR,
633 "Syntax error on line %d of remote.cache.", linenum);
635 else if (!_cups_strcasecmp(line, "JobSheets"))
638 * Set the initial job sheets...
643 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
648 cupsdSetString(&p->job_sheets[0], value);
650 while (isspace(*valueptr & 255))
655 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
660 cupsdSetString(&p->job_sheets[1], value);
664 cupsdLogMessage(CUPSD_LOG_ERROR,
665 "Syntax error on line %d of remote.cache.", linenum);
667 else if (!_cups_strcasecmp(line, "AllowUser"))
672 cupsdAddString(&(p->users), value);
675 cupsdLogMessage(CUPSD_LOG_ERROR,
676 "Syntax error on line %d of remote.cache.", linenum);
678 else if (!_cups_strcasecmp(line, "DenyUser"))
683 cupsdAddString(&(p->users), value);
686 cupsdLogMessage(CUPSD_LOG_ERROR,
687 "Syntax error on line %d of remote.cache.", linenum);
692 * Something else we don't understand...
695 cupsdLogMessage(CUPSD_LOG_ERROR,
696 "Unknown configuration directive %s on line %d of remote.cache.",
704 * Do auto-classing if needed...
707 process_implicit_classes();
712 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
713 * printer or update the broadcast contents.
717 cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
719 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
722 if (!Browsing || !BrowseLocalProtocols ||
723 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
724 CUPS_PRINTER_SCANNER)))
728 /* if (BrowseLocalProtocols & BROWSE_SLP)
729 slpRegisterPrinter(p); */
730 #endif /* HAVE_LIBSLP */
732 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
733 if ((BrowseLocalProtocols & BROWSE_DNSSD))
734 dnssdRegisterPrinter(p);
735 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
740 * 'cupsdRestartPolling()' - Restart polling servers as needed.
744 cupsdRestartPolling(void)
746 int i; /* Looping var */
747 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
750 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
752 kill(pollp->pid, SIGHUP);
757 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
761 cupsdSaveRemoteCache(void)
763 int i; /* Looping var */
764 cups_file_t *fp; /* remote.cache file */
765 char filename[1024], /* remote.cache filename */
766 temp[1024], /* Temporary string */
767 value[2048], /* Value string */
768 *name; /* Current user name */
769 cupsd_printer_t *printer; /* Current printer class */
770 time_t curtime; /* Current time */
771 struct tm *curdate; /* Current date */
772 cups_option_t *option; /* Current option */
776 * Create the remote.cache file...
779 snprintf(filename, sizeof(filename), "%s/remote.cache", CacheDir);
781 if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
784 cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
787 * Write a small header to the file...
790 curtime = time(NULL);
791 curdate = localtime(&curtime);
792 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
794 cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
795 cupsFilePrintf(fp, "# Written by cupsd\n");
798 * Write each local printer known to the system...
801 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
803 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
806 * Skip local destinations...
809 if (!(printer->type & CUPS_PRINTER_DISCOVERED))
813 * Write printers as needed...
816 if (printer == DefaultPrinter)
817 cupsFilePuts(fp, "<Default");
819 cupsFilePutChar(fp, '<');
821 if (printer->type & CUPS_PRINTER_CLASS)
822 cupsFilePrintf(fp, "Class %s>\n", printer->name);
824 cupsFilePrintf(fp, "Printer %s>\n", printer->name);
826 cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
828 cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
831 cupsFilePutConf(fp, "Info", printer->info);
833 if (printer->location)
834 cupsFilePutConf(fp, "Location", printer->location);
836 if (printer->make_model)
837 cupsFilePutConf(fp, "MakeModel", printer->make_model);
839 cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
841 if (printer->state == IPP_PRINTER_STOPPED)
842 cupsFilePuts(fp, "State Stopped\n");
844 cupsFilePuts(fp, "State Idle\n");
846 for (i = 0; i < printer->num_reasons; i ++)
847 cupsFilePutConf(fp, "Reason", printer->reasons[i]);
849 cupsFilePrintf(fp, "Type %d\n", printer->type);
851 if (printer->accepting)
852 cupsFilePuts(fp, "Accepting Yes\n");
854 cupsFilePuts(fp, "Accepting No\n");
856 snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
857 printer->job_sheets[1]);
858 cupsFilePutConf(fp, "JobSheets", value);
860 for (name = (char *)cupsArrayFirst(printer->users);
862 name = (char *)cupsArrayNext(printer->users))
863 cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
865 for (i = printer->num_options, option = printer->options;
869 snprintf(value, sizeof(value), "%s %s", option->name, option->value);
870 cupsFilePutConf(fp, "Option", value);
873 if (printer->type & CUPS_PRINTER_CLASS)
874 cupsFilePuts(fp, "</Class>\n");
876 cupsFilePuts(fp, "</Printer>\n");
879 cupsdCloseCreatedConfFile(fp, filename);
884 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
888 cupsdSendBrowseList(void)
890 int count; /* Number of dests to update */
891 cupsd_printer_t *p; /* Current printer */
892 time_t ut, /* Minimum update time */
893 to; /* Timeout time */
896 if (!Browsing || !Printers)
900 * Compute the update and timeout times...
904 ut = to - BrowseInterval;
907 * Figure out how many printers need an update...
910 if (BrowseInterval > 0 && BrowseLocalProtocols)
912 int max_count; /* Maximum number to update */
916 * Throttle the number of printers we'll be updating this time
917 * around based on the number of queues that need updating and
918 * the maximum number of queues to update each second...
921 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
923 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
924 count < max_count && p != NULL;
925 p = (cupsd_printer_t *)cupsArrayNext(Printers))
926 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
927 CUPS_PRINTER_SCANNER)) &&
928 p->shared && p->browse_time < ut)
932 * Loop through all of the printers and send local updates as needed...
936 p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
938 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
942 p = (cupsd_printer_t *)cupsArrayNext(Printers))
945 * Check for wraparound...
949 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
953 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
954 CUPS_PRINTER_SCANNER)) ||
957 else if (p->browse_time < ut)
960 * Need to send an update...
965 p->browse_time = time(NULL);
967 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
971 if (BrowseLocalProtocols & BROWSE_SLP)
973 #endif /* HAVE_LIBSLP */
976 if (BrowseLocalProtocols & BROWSE_LDAP)
978 #endif /* HAVE_LDAP */
983 * Save where we left off so that all printers get updated...
990 * Loop through all of the printers and timeout old printers as needed...
993 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
995 p = (cupsd_printer_t *)cupsArrayNext(Printers))
998 * If this is a remote queue, see if it needs to be timed out...
1001 if ((p->type & CUPS_PRINTER_DISCOVERED) &&
1002 !(p->type & CUPS_PRINTER_IMPLICIT) &&
1003 p->browse_expire < to)
1005 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
1006 "%s \'%s\' deleted by directory services (timeout).",
1007 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
1010 cupsdLogMessage(CUPSD_LOG_DEBUG,
1011 "Remote destination \"%s\" has timed out; "
1015 cupsArraySave(Printers);
1016 cupsdDeletePrinter(p, 1);
1017 cupsArrayRestore(Printers);
1018 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
1024 #ifdef HAVE_LDAP_REBIND_PROC
1025 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1027 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
1030 static int /* O - Result code */
1032 LDAP *RebindLDAPHandle, /* I - LDAP handle */
1033 LDAP_CONST char *refsp, /* I - ??? */
1034 ber_tag_t request, /* I - ??? */
1035 ber_int_t msgid, /* I - ??? */
1036 void *params) /* I - ??? */
1038 int rc; /* Result code */
1039 # if LDAP_API_VERSION > 3000
1040 struct berval bval; /* Bind value */
1041 # endif /* LDAP_API_VERSION > 3000 */
1049 * Bind to new LDAP server...
1052 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Rebind to %s", refsp);
1054 # if LDAP_API_VERSION > 3000
1055 bval.bv_val = BrowseLDAPPassword;
1056 bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1058 rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE,
1059 &bval, NULL, NULL, NULL);
1061 rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, BrowseLDAPPassword,
1063 # endif /* LDAP_API_VERSION > 3000 */
1069 # else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1071 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
1074 static int /* O - Result code */
1076 LDAP *RebindLDAPHandle, /* I - LDAP handle */
1077 char **dnp, /* I - ??? */
1078 char **passwdp, /* I - ??? */
1079 int *authmethodp, /* I - ??? */
1080 int freeit, /* I - ??? */
1081 void *arg) /* I - ??? */
1087 * Free current values...
1090 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Free values...");
1095 if (passwdp && *passwdp)
1101 * Return credentials for LDAP referal...
1104 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1105 "ldap_rebind_proc: Return necessary values...");
1107 *dnp = strdup(BrowseLDAPBindDN);
1108 *passwdp = strdup(BrowseLDAPPassword);
1109 *authmethodp = LDAP_AUTH_SIMPLE;
1114 * Should never happen...
1117 cupsdLogMessage(CUPSD_LOG_ERROR,
1118 "LDAP rebind has been called with wrong freeit value!");
1122 return (LDAP_SUCCESS);
1124 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1125 #endif /* HAVE_LDAP_REBIND_PROC */
1130 * 'ldap_connect()' - Start new LDAP connection
1133 static LDAP * /* O - LDAP handle */
1136 int rc; /* LDAP API status */
1137 int version = 3; /* LDAP version */
1138 struct berval bv = {0, ""}; /* SASL bind value */
1139 LDAP *TempBrowseLDAPHandle=NULL;
1140 /* Temporary LDAP Handle */
1141 # if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1142 int ldap_ssl = 0; /* LDAP SSL indicator */
1143 int ssl_err = 0; /* LDAP SSL error value */
1144 # endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1147 # ifdef HAVE_OPENLDAP
1148 # ifdef HAVE_LDAP_SSL
1150 * Set the certificate file to use for encrypted LDAP sessions...
1153 if (BrowseLDAPCACertFile)
1155 cupsdLogMessage(CUPSD_LOG_DEBUG,
1156 "ldap_connect: Setting CA certificate file \"%s\"",
1157 BrowseLDAPCACertFile);
1159 if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
1160 (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
1161 cupsdLogMessage(CUPSD_LOG_ERROR,
1162 "Unable to set CA certificate file for LDAP "
1163 "connections: %d - %s", rc, ldap_err2string(rc));
1165 # endif /* HAVE_LDAP_SSL */
1168 * Initialize OPENLDAP connection...
1169 * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1172 if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost"))
1173 rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
1175 rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
1177 # else /* HAVE_OPENLDAP */
1179 int ldap_port = 0; /* LDAP port */
1180 char ldap_protocol[11], /* LDAP protocol */
1181 ldap_host[255]; /* LDAP host */
1184 * Split LDAP URI into its components...
1187 if (!BrowseLDAPServer)
1189 cupsdLogMessage(CUPSD_LOG_ERROR, "BrowseLDAPServer not configured!");
1190 cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1191 BrowseLocalProtocols &= ~BROWSE_LDAP;
1192 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1196 sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host,
1199 if (!strcmp(ldap_protocol, "ldap"))
1201 else if (!strcmp(ldap_protocol, "ldaps"))
1205 cupsdLogMessage(CUPSD_LOG_ERROR, "Unrecognized LDAP protocol (%s)!",
1207 cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1208 BrowseLocalProtocols &= ~BROWSE_LDAP;
1209 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1216 ldap_port = LDAPS_PORT;
1218 ldap_port = LDAP_PORT;
1221 cupsdLogMessage(CUPSD_LOG_DEBUG, "ldap_connect: PROT:%s HOST:%s PORT:%d",
1222 ldap_protocol, ldap_host, ldap_port);
1225 * Initialize LDAP connection...
1230 if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
1231 rc = LDAP_OPERATIONS_ERROR;
1235 # ifdef HAVE_LDAP_SSL
1240 * Initialize SSL LDAP connection...
1243 if (BrowseLDAPCACertFile)
1245 rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
1246 if (rc != LDAP_SUCCESS)
1248 cupsdLogMessage(CUPSD_LOG_ERROR,
1249 "Failed to initialize LDAP SSL client!");
1250 rc = LDAP_OPERATIONS_ERROR;
1254 if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port,
1256 rc = LDAP_OPERATIONS_ERROR;
1263 cupsdLogMessage(CUPSD_LOG_ERROR,
1264 "LDAP SSL certificate file/database not configured!");
1265 rc = LDAP_OPERATIONS_ERROR;
1268 # else /* HAVE_LDAP_SSL */
1271 * Return error, because client libraries doesn't support SSL
1274 cupsdLogMessage(CUPSD_LOG_ERROR,
1275 "LDAP client libraries do not support SSL");
1276 rc = LDAP_OPERATIONS_ERROR;
1278 # endif /* HAVE_LDAP_SSL */
1280 # endif /* HAVE_OPENLDAP */
1283 * Check return code from LDAP initialize...
1286 if (rc != LDAP_SUCCESS)
1288 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize LDAP!");
1290 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
1291 cupsdLogMessage(CUPSD_LOG_ERROR, "Temporarily disabling LDAP browsing...");
1294 cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1296 BrowseLocalProtocols &= ~BROWSE_LDAP;
1297 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1300 ldap_disconnect(TempBrowseLDAPHandle);
1306 * Upgrade LDAP version...
1309 if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
1310 (const void *)&version) != LDAP_SUCCESS)
1312 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set LDAP protocol version %d!",
1314 cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1316 BrowseLocalProtocols &= ~BROWSE_LDAP;
1317 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1318 ldap_disconnect(TempBrowseLDAPHandle);
1324 * Register LDAP rebind procedure...
1327 # ifdef HAVE_LDAP_REBIND_PROC
1328 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1330 rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc,
1332 if (rc != LDAP_SUCCESS)
1333 cupsdLogMessage(CUPSD_LOG_ERROR,
1334 "Setting LDAP rebind function failed with status %d: %s",
1335 rc, ldap_err2string(rc));
1339 ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
1341 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1342 # endif /* HAVE_LDAP_REBIND_PROC */
1345 * Start LDAP bind...
1348 # if LDAP_API_VERSION > 3000
1350 bval.bv_val = BrowseLDAPPassword;
1351 bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1353 if (!BrowseLDAPServer || !_cups_strcasecmp(BrowseLDAPServer, "localhost"))
1354 rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
1357 rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
1360 rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
1361 BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1362 # endif /* LDAP_API_VERSION > 3000 */
1364 if (rc != LDAP_SUCCESS)
1366 cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP bind failed with error %d: %s",
1367 rc, ldap_err2string(rc));
1369 # if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1370 if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
1372 ssl_err = PORT_GetError();
1374 cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP SSL error %d: %s", ssl_err,
1375 ldapssl_err2string(ssl_err));
1377 # endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1379 ldap_disconnect(TempBrowseLDAPHandle);
1384 cupsdLogMessage(CUPSD_LOG_INFO, "LDAP connection established");
1386 return (TempBrowseLDAPHandle);
1391 * 'ldap_reconnect()' - Reconnect to LDAP Server
1394 static LDAP * /* O - New LDAP handle */
1395 ldap_reconnect(void)
1397 LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
1401 * Get a new LDAP Handle and replace the global Handle
1402 * if the new connection was successful.
1405 cupsdLogMessage(CUPSD_LOG_INFO, "Try LDAP reconnect...");
1407 TempBrowseLDAPHandle = ldap_connect();
1409 if (TempBrowseLDAPHandle != NULL)
1411 if (BrowseLDAPHandle != NULL)
1412 ldap_disconnect(BrowseLDAPHandle);
1414 BrowseLDAPHandle = TempBrowseLDAPHandle;
1417 return (BrowseLDAPHandle);
1422 * 'ldap_disconnect()' - Disconnect from LDAP Server
1426 ldap_disconnect(LDAP *ld) /* I - LDAP handle */
1428 int rc; /* Return code */
1432 * Close LDAP handle...
1435 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
1436 rc = ldap_unbind_ext_s(ld, NULL, NULL);
1438 rc = ldap_unbind_s(ld);
1439 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
1441 if (rc != LDAP_SUCCESS)
1442 cupsdLogMessage(CUPSD_LOG_ERROR,
1443 "Unbind from LDAP server failed with status %d: %s",
1444 rc, ldap_err2string(rc));
1446 #endif /* HAVE_LDAP */
1451 * 'cupsdStartAvahiClient()' - Start an Avahi client if needed
1455 cupsdStartAvahiClient(void)
1459 if (!AvahiCupsClient && !AvahiCupsClientConnecting)
1461 if (!AvahiCupsPollHandle)
1462 AvahiCupsPollHandle = avahi_cups_poll_new ();
1464 if (AvahiCupsPollHandle)
1466 if (avahi_client_new (avahi_cups_poll_get (AvahiCupsPollHandle),
1467 AVAHI_CLIENT_NO_FAIL,
1468 avahi_client_cb, NULL,
1470 AvahiCupsClientConnecting = 1;
1472 cupsdLogMessage (CUPSD_LOG_WARN, "Avahi client failed: %d", error);
1476 #endif /* HAVE_AVAHI */
1480 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
1484 cupsdStartBrowsing(void)
1486 int val; /* Socket option value */
1487 struct sockaddr_in addr; /* Broadcast address */
1488 cupsd_printer_t *p; /* Current printer */
1493 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1496 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
1498 if (BrowseSocket < 0)
1501 * Create the broadcast socket...
1504 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1506 cupsdLogMessage(CUPSD_LOG_ERROR,
1507 "Unable to create broadcast socket - %s.",
1509 BrowseLocalProtocols &= ~BROWSE_CUPS;
1510 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1512 if (FatalErrors & CUPSD_FATAL_BROWSE)
1513 cupsdEndProcess(getpid(), 0);
1517 if (BrowseSocket >= 0)
1520 * Bind the socket to browse port...
1523 memset(&addr, 0, sizeof(addr));
1524 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1525 addr.sin_family = AF_INET;
1526 addr.sin_port = htons(BrowsePort);
1528 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
1530 cupsdLogMessage(CUPSD_LOG_ERROR,
1531 "Unable to bind broadcast socket - %s.",
1535 closesocket(BrowseSocket);
1537 close(BrowseSocket);
1541 BrowseLocalProtocols &= ~BROWSE_CUPS;
1542 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1544 if (FatalErrors & CUPSD_FATAL_BROWSE)
1545 cupsdEndProcess(getpid(), 0);
1549 if (BrowseSocket >= 0)
1552 * Set the "broadcast" flag...
1556 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1558 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
1562 closesocket(BrowseSocket);
1564 close(BrowseSocket);
1568 BrowseLocalProtocols &= ~BROWSE_CUPS;
1569 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1571 if (FatalErrors & CUPSD_FATAL_BROWSE)
1572 cupsdEndProcess(getpid(), 0);
1576 if (BrowseSocket >= 0)
1579 * Close the socket on exec...
1582 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1585 * Finally, add the socket to the input selection set as needed...
1588 if (BrowseRemoteProtocols & BROWSE_CUPS)
1591 * We only listen if we want remote printers...
1594 cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
1602 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1603 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1606 DNSServiceErrorType error; /* Error from service creation */
1607 #endif /* HAVE_DNSSD */
1608 cupsd_listener_t *lis; /* Current listening socket */
1613 * First create a "master" connection for all registrations...
1616 if ((error = DNSServiceCreateConnection(&DNSSDRef))
1617 != kDNSServiceErr_NoError)
1619 cupsdLogMessage(CUPSD_LOG_ERROR,
1620 "Unable to create master DNS-SD reference: %d", error);
1622 if (FatalErrors & CUPSD_FATAL_BROWSE)
1623 cupsdEndProcess(getpid(), 0);
1628 * Add the master connection to the select list...
1631 int fd = DNSServiceRefSockFD(DNSSDRef);
1633 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1635 cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
1636 #endif /* HAVE_DNSSD */
1639 * Then get the port we use for registrations. If we are not listening
1640 * on any non-local ports, there is no sense sharing local printers via
1646 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1648 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1650 if (httpAddrLocalhost(&(lis->address)))
1653 DNSSDPort = _httpAddrPort(&(lis->address));
1658 * Create an array to track the printers we share...
1661 if (BrowseRemoteProtocols & BROWSE_DNSSD)
1662 DNSSDPrinters = cupsArrayNew(NULL, NULL);
1665 * Set the computer name and register the web interface...
1668 cupsdUpdateDNSSDName();
1671 cupsdStartAvahiClient ();
1672 #endif /* HAVE_AVAHI */
1676 #endif /* HAVE_DNSSD */
1678 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1681 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1684 * Open SLP handle...
1687 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1689 cupsdLogMessage(CUPSD_LOG_ERROR,
1690 "Unable to open an SLP handle; disabling SLP browsing!");
1691 BrowseLocalProtocols &= ~BROWSE_SLP;
1692 BrowseRemoteProtocols &= ~BROWSE_SLP;
1693 BrowseSLPHandle = NULL;
1695 if (FatalErrors & CUPSD_FATAL_BROWSE)
1696 cupsdEndProcess(getpid(), 0);
1699 BrowseSLPRefresh = 0;
1702 BrowseSLPHandle = NULL;
1703 #endif /* HAVE_LIBSLP */
1706 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1710 cupsdLogMessage(CUPSD_LOG_ERROR,
1711 "Need to set BrowseLDAPDN to use LDAP browsing!");
1712 BrowseLocalProtocols &= ~BROWSE_LDAP;
1713 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1715 if (FatalErrors & CUPSD_FATAL_BROWSE)
1716 cupsdEndProcess(getpid(), 0);
1721 * Open LDAP handle...
1724 if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
1725 (FatalErrors & CUPSD_FATAL_BROWSE))
1726 cupsdEndProcess(getpid(), 0);
1729 BrowseLDAPRefresh = 0;
1731 #endif /* HAVE_LDAP */
1734 * Enable LPD and SMB printer sharing as needed through external programs...
1737 if (BrowseLocalProtocols & BROWSE_LPD)
1740 if (BrowseLocalProtocols & BROWSE_SMB)
1744 * Register the individual printers
1747 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1749 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1750 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1751 CUPS_PRINTER_SCANNER)))
1752 cupsdRegisterPrinter(p);
1757 * 'cupsdStartPolling()' - Start polling servers as needed.
1761 cupsdStartPolling(void)
1763 int i; /* Looping var */
1764 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1765 char polld[1024]; /* Poll daemon path */
1766 char sport[255]; /* Server port */
1767 char bport[255]; /* Browser port */
1768 char interval[255]; /* Poll interval */
1769 int statusfds[2]; /* Status pipe */
1770 char *argv[6]; /* Arguments */
1771 char *envp[100]; /* Environment */
1775 * Don't do anything if we aren't polling...
1778 if (NumPolled == 0 || BrowseSocket < 0)
1781 PollStatusBuffer = NULL;
1786 * Setup string arguments for polld, port and interval options.
1789 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1791 sprintf(bport, "%d", BrowsePort);
1794 sprintf(interval, "%d", BrowseInterval);
1796 strcpy(interval, "30");
1798 argv[0] = "cups-polld";
1804 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1807 * Create a pipe that receives the status messages from each
1811 if (cupsdOpenPipe(statusfds))
1813 cupsdLogMessage(CUPSD_LOG_ERROR,
1814 "Unable to create polling status pipes - %s.",
1817 PollStatusBuffer = NULL;
1821 PollPipe = statusfds[0];
1822 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
1825 * Run each polling daemon, redirecting stderr to the polling pipe...
1828 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1830 sprintf(sport, "%d", pollp->port);
1832 argv[1] = pollp->hostname;
1834 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
1835 0, DefaultProfile, NULL, &(pollp->pid)) < 0)
1837 cupsdLogMessage(CUPSD_LOG_ERROR,
1838 "cupsdStartPolling: Unable to fork polling daemon - %s",
1844 cupsdLogMessage(CUPSD_LOG_DEBUG,
1845 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1846 pollp->hostname, pollp->port, pollp->pid);
1849 close(statusfds[1]);
1852 * Finally, add the pipe to the input selection set...
1855 cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
1860 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1864 cupsdStopBrowsing(void)
1866 cupsd_printer_t *p; /* Current printer */
1869 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1873 * De-register the individual printers
1876 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1878 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1879 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1880 CUPS_PRINTER_SCANNER)))
1881 cupsdDeregisterPrinter(p, 1);
1884 * Shut down browsing sockets...
1887 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1891 * Close the socket and remove it from the input selection set.
1895 closesocket(BrowseSocket);
1897 close(BrowseSocket);
1900 cupsdRemoveSelect(BrowseSocket);
1904 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1905 if ((BrowseLocalProtocols & BROWSE_DNSSD))
1907 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1910 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1914 * Close SLP handle...
1917 SLPClose(BrowseSLPHandle);
1918 BrowseSLPHandle = NULL;
1920 #endif /* HAVE_LIBSLP */
1923 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1926 ldap_dereg_ou(ServerName, BrowseLDAPDN);
1927 ldap_disconnect(BrowseLDAPHandle);
1928 BrowseLDAPHandle = NULL;
1930 #endif /* HAVE_OPENLDAP */
1933 * Disable LPD and SMB printer sharing as needed through external programs...
1936 if (BrowseLocalProtocols & BROWSE_LPD)
1939 if (BrowseLocalProtocols & BROWSE_SMB)
1945 * 'cupsdStopPolling()' - Stop polling servers as needed.
1949 cupsdStopPolling(void)
1951 int i; /* Looping var */
1952 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1957 cupsdStatBufDelete(PollStatusBuffer);
1960 cupsdRemoveSelect(PollPipe);
1963 PollStatusBuffer = NULL;
1966 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1968 cupsdEndProcess(pollp->pid, 0);
1972 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1974 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1978 cupsdUpdateDNSSDName(void)
1981 DNSServiceErrorType error; /* Error from service creation */
1982 char webif[1024]; /* Web interface share name */
1983 #endif /* HAVE_DNSSD */
1985 int ret; /* Error from service creation */
1986 char webif[AVAHI_LABEL_MAX]; /* Web interface share name */
1987 #endif /* HAVE_AVAHI */
1988 # ifdef HAVE_SYSTEMCONFIGURATION
1989 SCDynamicStoreRef sc; /* Context for dynamic store */
1990 CFDictionaryRef btmm; /* Back-to-My-Mac domains */
1991 CFStringEncoding nameEncoding; /* Encoding of computer name */
1992 CFStringRef nameRef; /* Host name CFString */
1993 char nameBuffer[1024]; /* C-string buffer */
1994 # endif /* HAVE_SYSTEMCONFIGURATION */
1998 * Only share the web interface and printers when non-local listening is
2007 * Get the computer name as a c-string...
2010 # ifdef HAVE_SYSTEMCONFIGURATION
2011 sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
2016 * Get the computer name from the dynamic store...
2019 cupsdClearString(&DNSSDComputerName);
2021 if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
2023 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
2024 kCFStringEncodingUTF8))
2026 cupsdLogMessage(CUPSD_LOG_DEBUG,
2027 "Dynamic store computer name is \"%s\".", nameBuffer);
2028 cupsdSetString(&DNSSDComputerName, nameBuffer);
2034 if (!DNSSDComputerName)
2037 * Use the ServerName instead...
2040 cupsdLogMessage(CUPSD_LOG_DEBUG,
2041 "Using ServerName \"%s\" as computer name.", ServerName);
2042 cupsdSetString(&DNSSDComputerName, ServerName);
2046 * Get the local hostname from the dynamic store...
2049 cupsdClearString(&DNSSDHostName);
2051 if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
2053 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
2054 kCFStringEncodingUTF8))
2056 cupsdLogMessage(CUPSD_LOG_DEBUG,
2057 "Dynamic store host name is \"%s\".", nameBuffer);
2058 cupsdSetString(&DNSSDHostName, nameBuffer);
2067 * Use the ServerName instead...
2070 cupsdLogMessage(CUPSD_LOG_DEBUG,
2071 "Using ServerName \"%s\" as host name.", ServerName);
2072 cupsdSetString(&DNSSDHostName, ServerName);
2076 * Get any Back-to-My-Mac domains and add them as aliases...
2079 cupsdFreeAliases(DNSSDAlias);
2082 btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
2083 if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
2085 cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
2086 (int)CFDictionaryGetCount(btmm));
2087 CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
2090 cupsdLogMessage(CUPSD_LOG_ERROR,
2091 "Bad Back to My Mac data in dynamic store!");
2093 cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
2101 # endif /* HAVE_SYSTEMCONFIGURATION */
2103 cupsdSetString(&DNSSDComputerName, ServerName);
2104 cupsdSetString(&DNSSDHostName, ServerName);
2108 * Then (re)register the web interface if enabled...
2113 if (DNSSDComputerName)
2114 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
2116 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
2120 DNSServiceRefDeallocate(WebIFRef);
2122 WebIFRef = DNSSDRef;
2123 if ((error = DNSServiceRegister(&WebIFRef,
2124 kDNSServiceFlagsShareConnection,
2125 0, webif, "_http._tcp", NULL,
2126 NULL, htons(DNSSDPort), 7,
2127 "\006path=/", dnssdRegisterCallback,
2128 NULL)) != kDNSServiceErr_NoError)
2129 cupsdLogMessage(CUPSD_LOG_ERROR,
2130 "DNS-SD web interface registration failed: %d", error);
2131 #endif /* HAVE_DNSSD */
2134 if (!AvahiCupsClient)
2136 * Client not yet running.
2140 if (AvahiWebIFGroup)
2141 avahi_entry_group_reset (AvahiWebIFGroup);
2143 AvahiWebIFGroup = avahi_entry_group_new (AvahiCupsClient,
2144 avahi_entry_group_cb,
2147 if (AvahiWebIFGroup)
2149 ret = avahi_entry_group_add_service (AvahiWebIFGroup,
2154 "_http._tcp", /* type */
2157 DNSSDPort, /* port */
2160 ret = avahi_entry_group_commit (AvahiWebIFGroup);
2163 cupsdLogMessage (CUPSD_LOG_ERROR,
2164 "Avahi web interface registration failed: %d", ret);
2166 #endif /* HAVE_AVAHI */
2169 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
2174 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
2178 cupsdUpdateLDAPBrowse(void)
2180 char uri[HTTP_MAX_URI], /* Printer URI */
2181 host[HTTP_MAX_URI], /* Hostname */
2182 resource[HTTP_MAX_URI], /* Resource path */
2183 location[1024], /* Printer location */
2184 info[1024], /* Printer information */
2185 make_model[1024], /* Printer make and model */
2186 type_num[30]; /* Printer type number */
2187 int type; /* Printer type */
2188 int rc; /* LDAP status */
2189 int limit; /* Size limit */
2190 LDAPMessage *res, /* LDAP search results */
2191 *e; /* Current entry from search */
2193 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
2195 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
2198 * Reconnect if LDAP Handle is invalid...
2201 if (! BrowseLDAPHandle)
2208 * Search for cups printers in LDAP directory...
2211 rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
2212 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
2215 * If ldap search was successfull then exit function
2216 * and temporary disable LDAP updates...
2219 if (rc != LDAP_SUCCESS)
2221 if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
2223 BrowseLDAPUpdate = FALSE;
2224 cupsdLogMessage(CUPSD_LOG_INFO,
2225 "LDAP update temporary disabled");
2231 * If LDAP updates were disabled, we will reenable them...
2234 if (! BrowseLDAPUpdate)
2236 BrowseLDAPUpdate = TRUE;
2237 cupsdLogMessage(CUPSD_LOG_INFO,
2238 "LDAP update enabled");
2242 * Count LDAP entries and return if no entry exist...
2245 limit = ldap_count_entries(BrowseLDAPHandle, res);
2246 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
2254 * Loop through the available printers...
2257 for (e = ldap_first_entry(BrowseLDAPHandle, res);
2259 e = ldap_next_entry(BrowseLDAPHandle, e))
2262 * Get the required values from this entry...
2265 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2266 "printerDescription", info, sizeof(info)) == -1)
2269 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2270 "printerLocation", location, sizeof(location)) == -1)
2273 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2274 "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
2277 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2278 "printerType", type_num, sizeof(type_num)) == -1)
2281 type = atoi(type_num);
2283 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2284 "printerURI", uri, sizeof(uri)) == -1)
2288 * Process the entry as browse data...
2291 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2292 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
2293 location, info, make_model, 0, NULL);
2299 #endif /* HAVE_LDAP */
2304 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
2308 cupsdUpdateSLPBrowse(void)
2310 slpsrvurl_t *s, /* Temporary list of service URLs */
2311 *next; /* Next service in list */
2312 cupsd_printer_t p; /* Printer information */
2313 const char *uri; /* Pointer to printer URI */
2314 char host[HTTP_MAX_URI], /* Host portion of URI */
2315 resource[HTTP_MAX_URI]; /* Resource portion of URI */
2319 * Reset the refresh time...
2322 BrowseSLPRefresh = time(NULL) + BrowseInterval;
2325 * Poll for remote printers using SLP...
2330 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
2331 slp_url_callback, &s);
2334 * Loop through the list of available printers...
2340 * Save the "next" pointer...
2346 * Load a cupsd_printer_t structure with the SLP service attributes...
2349 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
2352 * Process this printer entry...
2355 uri = s->url + SLP_CUPS_SRVLEN + 1;
2357 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
2360 * Pull the URI apart to see if this is a local or remote printer...
2363 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2364 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
2365 p.location, p.info, p.make_model, 0, NULL);
2369 * Free this listing...
2372 cupsdClearString(&p.info);
2373 cupsdClearString(&p.location);
2374 cupsdClearString(&p.make_model);
2379 #endif /* HAVE_LIBSLP */
2383 * 'dequote()' - Remote quotes from a string.
2386 static char * /* O - Dequoted string */
2387 dequote(char *d, /* I - Destination string */
2388 const char *s, /* I - Source string */
2389 int dlen) /* I - Destination length */
2391 char *dptr; /* Pointer into destination */
2396 for (dptr = d, dlen --; *s && dlen > 0; s ++)
2413 # ifdef HAVE_COREFOUNDATION
2415 * 'dnssdAddAlias()' - Add a DNS-SD alias name.
2419 dnssdAddAlias(const void *key, /* I - Key */
2420 const void *value, /* I - Value (domain) */
2421 void *context) /* I - Unused */
2423 char valueStr[1024], /* Domain string */
2424 hostname[1024], /* Complete hostname */
2425 *hostptr; /* Pointer into hostname */
2431 if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
2432 CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
2433 kCFStringEncodingUTF8))
2435 snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
2436 hostptr = hostname + strlen(hostname) - 1;
2437 if (*hostptr == '.')
2438 *hostptr = '\0'; /* Strip trailing dot */
2441 DNSSDAlias = cupsArrayNew(NULL, NULL);
2443 cupsdAddAlias(DNSSDAlias, hostname);
2444 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
2448 cupsdLogMessage(CUPSD_LOG_ERROR,
2449 "Bad Back to My Mac domain in dynamic store!");
2451 # endif /* HAVE_COREFOUNDATION */
2452 #endif /* HAVE_DNSSD */
2455 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2457 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2460 static cupsd_txt_record_t /* O - TXT record */
2461 dnssdBuildTxtRecord(
2462 int *txt_len, /* O - TXT record length */
2463 cupsd_printer_t *p, /* I - Printer information */
2464 int for_lpd) /* I - 1 = LPD, 0 = IPP */
2466 int i; /* Looping var */
2467 char admin_hostname[256], /* .local hostname for admin page */
2468 adminurl_str[256], /* URL for the admin page */
2469 type_str[32], /* Type to string buffer */
2470 state_str[32], /* State to string buffer */
2471 rp_str[1024], /* Queue name string buffer */
2472 air_str[1024], /* auth-info-required string buffer */
2473 *keyvalue[32][2]; /* Table of key/value pairs */
2477 * Load up the key value pairs...
2482 keyvalue[i ][0] = "txtvers";
2483 keyvalue[i++][1] = "1";
2485 keyvalue[i ][0] = "qtotal";
2486 keyvalue[i++][1] = "1";
2488 keyvalue[i ][0] = "rp";
2489 keyvalue[i++][1] = rp_str;
2491 strlcpy(rp_str, p->name, sizeof(rp_str));
2493 snprintf(rp_str, sizeof(rp_str), "%s/%s",
2494 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
2496 keyvalue[i ][0] = "ty";
2497 keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";
2499 snprintf(admin_hostname, sizeof(admin_hostname),
2502 "." /* terminating dot no good for Avahi */
2503 #endif /* HAVE_DNSSD */
2505 httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
2506 "http", NULL, admin_hostname, DNSSDPort, "/%s/%s",
2507 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
2509 keyvalue[i ][0] = "adminurl";
2510 keyvalue[i++][1] = adminurl_str;
2512 keyvalue[i ][0] = "note";
2513 keyvalue[i++][1] = p->location ? p->location : "";
2515 keyvalue[i ][0] = "priority";
2516 keyvalue[i++][1] = for_lpd ? "100" : "0";
2518 keyvalue[i ][0] = "product";
2519 keyvalue[i++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
2521 keyvalue[i ][0] = "pdl";
2522 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2524 keyvalue[i ][0] = "URF";
2525 keyvalue[i++][1] = "none";
2527 if (get_auth_info_required(p, air_str, sizeof(air_str)))
2529 keyvalue[i ][0] = "air";
2530 keyvalue[i++][1] = air_str;
2533 keyvalue[i ][0] = "UUID";
2534 keyvalue[i++][1] = p->uuid + 9;
2537 keyvalue[i ][0] = "TLS";
2538 keyvalue[i++][1] = "1.2";
2539 #endif /* HAVE_SSL */
2541 keyvalue[i ][0] = "Transparent";
2542 keyvalue[i++][1] = "F";
2544 keyvalue[i ][0] = "Binary";
2545 keyvalue[i++][1] = "F";
2547 keyvalue[i ][0] = "Fax";
2548 keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
2550 keyvalue[i ][0] = "Color";
2551 keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
2553 keyvalue[i ][0] = "Duplex";
2554 keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
2556 keyvalue[i ][0] = "Staple";
2557 keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
2559 keyvalue[i ][0] = "Copies";
2560 keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
2562 keyvalue[i ][0] = "Collate";
2563 keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
2565 keyvalue[i ][0] = "Punch";
2566 keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
2568 keyvalue[i ][0] = "Bind";
2569 keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
2571 keyvalue[i ][0] = "Sort";
2572 keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
2574 keyvalue[i ][0] = "Scan";
2575 keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
2577 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2578 snprintf(state_str, sizeof(state_str), "%d", p->state);
2580 keyvalue[i ][0] = "printer-state";
2581 keyvalue[i++][1] = state_str;
2583 keyvalue[i ][0] = "printer-type";
2584 keyvalue[i++][1] = type_str;
2587 * Then pack them into a proper txt record...
2591 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2592 #endif /* HAVE_DNSSD */
2594 return (avahiPackTxtRecord(keyvalue, i));
2595 #endif /* HAVE_AVAHI */
2600 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
2603 static int /* O - Result of comparison */
2604 dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
2605 cupsd_printer_t *b)/* I - Second printer */
2616 return (_cups_strcasecmp(a->reg_name, b->reg_name));
2621 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2626 dnssdDeregisterPrinter(
2627 cupsd_printer_t *p) /* I - Printer */
2629 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2636 * Closing the socket deregisters the service
2641 DNSServiceRefDeallocate(p->ipp_ref);
2648 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
2657 DNSServiceRefDeallocate(p->printer_ref);
2658 p->printer_ref = NULL;
2664 * p->printer_txt is malloc'd, not _cupsStrAlloc'd...
2667 free(p->printer_txt);
2668 p->printer_txt = NULL;
2670 #endif /* HAVE_DNSSD */
2675 avahi_entry_group_reset (p->avahi_group);
2676 avahi_entry_group_free (p->avahi_group);
2677 p->avahi_group = NULL;
2680 avahi_string_list_free (p->ipp_txt);
2683 avahi_string_list_free (p->printer_txt);
2685 p->ipp_txt = p->printer_txt = NULL;
2687 #endif /* HAVE_AVAHI */
2690 * Remove the printer from the array of DNS-SD printers, then clear the
2691 * registered name...
2694 cupsArrayRemove(DNSSDPrinters, p);
2695 cupsdClearString(&p->reg_name);
2697 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
2702 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2703 * TXT record format.
2706 static char * /* O - TXT record */
2707 dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2708 char *keyvalue[][2], /* I - Table of key value pairs */
2709 int count) /* I - Items in table */
2711 int i; /* Looping var */
2712 int length; /* Length of TXT record */
2713 int length2; /* Length of value */
2714 char *txtRecord; /* TXT record buffer */
2715 char *cursor; /* Looping pointer */
2719 * Calculate the buffer size
2725 for (length = i = 0; i < count; i++)
2726 length += 1 + strlen(keyvalue[i][0]) +
2727 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2730 * Allocate and fill it
2733 txtRecord = malloc(length);
2738 for (cursor = txtRecord, i = 0; i < count; i++)
2741 * Drop in the p-string style length byte followed by the data
2744 length = strlen(keyvalue[i][0]);
2745 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2747 *cursor++ = (unsigned char)(length + length2);
2749 memcpy(cursor, keyvalue[i][0], length);
2756 memcpy(cursor, keyvalue[i][1], length2);
2767 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2771 dnssdRegisterCallback(
2772 DNSServiceRef sdRef, /* I - DNS Service reference */
2773 DNSServiceFlags flags, /* I - Reserved for future use */
2774 DNSServiceErrorType errorCode, /* I - Error code */
2775 const char *name, /* I - Service name */
2776 const char *regtype, /* I - Service type */
2777 const char *domain, /* I - Domain. ".local" for now */
2778 void *context) /* I - User-defined context */
2780 cupsd_printer_t *p = (cupsd_printer_t *)context;
2781 /* Current printer */
2788 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
2789 name, regtype, p ? p->name : "Web Interface",
2790 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
2794 cupsdLogMessage(CUPSD_LOG_ERROR,
2795 "DNSServiceRegister failed with error %d", (int)errorCode);
2798 else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
2800 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2803 cupsArrayRemove(DNSSDPrinters, p);
2804 cupsdSetString(&p->reg_name, name);
2805 cupsArrayAdd(DNSSDPrinters, p);
2807 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2810 #endif /* HAVE_DNSSD */
2813 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2815 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2816 * or update the broadcast contents.
2820 dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2823 DNSServiceErrorType se; /* dnssd errors */
2824 char *ipp_txt, /* IPP TXT record buffer */
2825 *printer_txt, /* LPD TXT record buffer */
2826 name[1024]; /* Service name */
2827 int ipp_len, /* IPP TXT record length */
2828 printer_len, /* LPD TXT record length */
2829 printer_port; /* LPD port number */
2830 #endif /* HAVE_DNSSD */
2832 int ret; /* Error code */
2833 AvahiStringList *ipp_txt, /* IPP TXT record */
2834 *printer_txt; /* LPD TXT record */
2835 char name[AVAHI_LABEL_MAX], /* Service name */
2836 fullsubtype[AVAHI_LABEL_MAX]; /* Full subtype */
2837 char *regtype_copy, /* Writeable copy of reg type */
2838 *subtype, /* Current service sub type */
2839 *nextsubtype; /* Next service sub type */
2840 #endif /* HAVE_AVAHI */
2841 char *nameptr; /* Pointer into name */
2842 const char *regtype; /* Registration type */
2849 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2850 !p->ipp_ref ? "new" : "update");
2851 #endif /* HAVE_DNSSD */
2853 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2854 !p->avahi_group ? "new" : "update");
2855 #endif /* HAVE_AVAHI */
2857 * If per-printer sharing was just disabled make sure we're not
2858 * registered before returning.
2863 dnssdDeregisterPrinter(p);
2868 * The registered name takes the form of "<printer-info> @ <computer name>"...
2871 if (p->info && strlen(p->info) > 0)
2873 if (DNSSDComputerName)
2876 * Make sure there is room for at least 15 characters of
2877 * DNSSDComputerName.
2880 assert(sizeof(name) >= 15 + 4);
2881 nameptr = name + strlcpy(name, p->info,
2883 strnlen(DNSSDComputerName, 15));
2884 nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
2885 strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
2888 strlcpy(name, p->info, sizeof(name));
2890 else if (DNSSDComputerName)
2893 * Make sure there is room for at least 15 characters of
2894 * DNSSDComputerName.
2897 assert(sizeof(name) >= 15 + 4);
2898 nameptr = name + strlcpy(name, p->info,
2900 strnlen(DNSSDComputerName, 15));
2901 nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
2902 strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
2905 strlcpy(name, p->name, sizeof(name));
2908 * If an existing printer was renamed, unregister it and start over...
2911 if (p->reg_name && strcmp(p->reg_name, name))
2912 dnssdDeregisterPrinter(p);
2916 cupsdSetString(&p->reg_name, name);
2917 cupsArrayAdd(DNSSDPrinters, p);
2921 * Register IPP and (optionally) LPD...
2925 ipp_len = 0; /* anti-compiler-warning-code */
2926 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2929 (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)))
2932 * Update the existing registration...
2935 /* A TTL of 0 means use record's original value (Radar 3176248) */
2936 if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt,
2937 0)) == kDNSServiceErr_NoError)
2942 p->ipp_txt = ipp_txt;
2943 p->ipp_len = ipp_len;
2949 * Failed to update record, lets close this reference and move on...
2952 cupsdLogMessage(CUPSD_LOG_ERROR,
2953 "Unable to update IPP DNS-SD record for %s - %d", p->name,
2956 DNSServiceRefDeallocate(p->ipp_ref);
2964 * Initial registration. Use the _fax-ipp regtype for fax queues...
2967 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
2969 cupsdLogMessage(CUPSD_LOG_DEBUG,
2970 "Registering DNS-SD printer %s with name \"%s\" and "
2971 "type \"%s\"", p->name, name, regtype);
2974 * Register the queue, dropping characters as needed until we succeed...
2977 nameptr = name + strlen(name);
2981 p->ipp_ref = DNSSDRef;
2982 if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
2983 0, name, regtype, NULL, NULL,
2984 htons(DNSSDPort), ipp_len, ipp_txt,
2985 dnssdRegisterCallback,
2986 p)) == kDNSServiceErr_BadParam)
2989 * Name is too long, drop trailing characters, taking into account
2995 while (nameptr > name && (*nameptr & 0xc0) == 0x80)
3002 while (se == kDNSServiceErr_BadParam && nameptr > name);
3004 if (se == kDNSServiceErr_NoError)
3006 p->ipp_txt = ipp_txt;
3007 p->ipp_len = ipp_len;
3011 cupsdLogMessage(CUPSD_LOG_WARN,
3012 "DNS-SD IPP registration of \"%s\" failed: %d",
3019 if (BrowseLocalProtocols & BROWSE_LPD)
3021 printer_len = 0; /* anti-compiler-warning-code */
3023 printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
3032 if (p->printer_ref &&
3033 (printer_len != p->printer_len ||
3034 memcmp(printer_txt, p->printer_txt, printer_len)))
3037 * Update the existing registration...
3040 /* A TTL of 0 means use record's original value (Radar 3176248) */
3041 if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
3043 0)) == kDNSServiceErr_NoError)
3046 free(p->printer_txt);
3048 p->printer_txt = printer_txt;
3049 p->printer_len = printer_len;
3055 * Failed to update record, lets close this reference and move on...
3058 cupsdLogMessage(CUPSD_LOG_ERROR,
3059 "Unable to update LPD DNS-SD record for %s - %d",
3062 DNSServiceRefDeallocate(p->printer_ref);
3063 p->printer_ref = NULL;
3067 if (!p->printer_ref)
3070 * Initial registration...
3073 cupsdLogMessage(CUPSD_LOG_DEBUG,
3074 "Registering DNS-SD printer %s with name \"%s\" and "
3075 "type \"_printer._tcp\"", p->name, name);
3077 p->printer_ref = DNSSDRef;
3078 if ((se = DNSServiceRegister(&p->printer_ref,
3079 kDNSServiceFlagsShareConnection,
3080 0, name, "_printer._tcp", NULL, NULL,
3081 htons(printer_port), printer_len, printer_txt,
3082 dnssdRegisterCallback,
3083 p)) == kDNSServiceErr_NoError)
3085 p->printer_txt = printer_txt;
3086 p->printer_len = printer_len;
3090 cupsdLogMessage(CUPSD_LOG_WARN,
3091 "DNS-SD LPD registration of \"%s\" failed: %d",
3097 #endif /* HAVE_DNSSD */
3099 if (!AvahiCupsClient)
3101 * Client not running yet. The client callback will call us again later.
3105 ipp_txt = dnssdBuildTxtRecord(NULL, p, 0);
3106 printer_txt = dnssdBuildTxtRecord(NULL, p, 1);
3107 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : DNSSDRegType;
3109 if (p->avahi_group && p->ipp_txt && ipp_txt &&
3110 !avahi_string_list_equal (p->ipp_txt, ipp_txt))
3113 * Update the existing registration...
3116 avahi_string_list_free (p->ipp_txt);
3119 avahi_string_list_free (p->printer_txt);
3122 * Update the service group entry.
3125 regtype_copy = strdup (regtype);
3126 subtype = strchr (regtype_copy, ',');
3130 cupsdLogMessage (CUPSD_LOG_DEBUG,
3131 "Updating TXT record for %s (%s)", name, regtype_copy);
3132 ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
3138 free (regtype_copy);
3143 p->ipp_txt = ipp_txt;
3146 if (BrowseLocalProtocols & BROWSE_LPD)
3148 ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
3152 "_printer._tcp", NULL,
3157 p->printer_txt = printer_txt;
3161 ret = avahi_entry_group_commit (p->avahi_group);
3165 cupsdLogMessage (CUPSD_LOG_ERROR,
3166 "Failed to update TXT record for %s: %d",
3168 avahi_entry_group_reset (p->avahi_group);
3169 avahi_entry_group_free (p->avahi_group);
3170 p->avahi_group = NULL;
3171 ipp_txt = p->ipp_txt;
3176 if (!p->avahi_group)
3179 * Initial registration. Use the _fax subtype for fax queues...
3182 p->avahi_group = avahi_entry_group_new (AvahiCupsClient,
3183 avahi_entry_group_cb,
3186 cupsdLogMessage(CUPSD_LOG_DEBUG,
3187 "Registering Avahi printer %s with name \"%s\" and "
3188 "type \"%s\"", p->name, name, regtype);
3190 if (!p->avahi_group)
3197 * Add each service type (DNSSDRegType may contain several,
3198 * separated by commas).
3201 subtype = regtype_copy = strdup (regtype);
3202 while (subtype && *subtype)
3204 nextsubtype = strchr (subtype, ',');
3206 *nextsubtype++ = '\0';
3208 if (subtype == regtype_copy)
3214 cupsdLogMessage (CUPSD_LOG_DEBUG,
3215 "Adding TXT record for %s (%s)", name, regtype_copy);
3216 ret = avahi_entry_group_add_service_strlst (p->avahi_group,
3219 0, name, regtype_copy,
3230 snprintf (fullsubtype, sizeof(fullsubtype),
3231 "%s._sub.%s", subtype, regtype_copy);
3232 cupsdLogMessage (CUPSD_LOG_DEBUG,
3233 "Adding TXT record for %s (%s)", name, fullsubtype);
3234 ret = avahi_entry_group_add_service_subtype (p->avahi_group,
3244 free (regtype_copy);
3248 subtype = nextsubtype;
3251 free (regtype_copy);
3252 p->ipp_txt = ipp_txt;
3255 if (BrowseLocalProtocols & BROWSE_LPD)
3257 cupsdLogMessage(CUPSD_LOG_DEBUG,
3258 "Registering Avahi printer %s with name \"%s\" and "
3259 "type \"_printer._tcp\"", p->name, name);
3261 ret = avahi_entry_group_add_service_strlst (p->avahi_group,
3265 "_printer._tcp", NULL, NULL,
3271 p->printer_txt = printer_txt;
3275 ret = avahi_entry_group_commit (p->avahi_group);
3280 cupsdLogMessage (CUPSD_LOG_ERROR,
3281 "Failed to add Avahi entry for %s: %d",
3285 avahi_entry_group_reset (p->avahi_group);
3286 avahi_entry_group_free (p->avahi_group);
3287 p->avahi_group = NULL;
3289 ipp_txt = p->ipp_txt;
3295 avahi_string_list_free (ipp_txt);
3298 avahi_string_list_free (printer_txt);
3299 #endif /* HAVE_AVAHI */
3304 * 'dnssdStop()' - Stop all DNS-SD registrations.
3310 cupsd_printer_t *p; /* Current printer */
3315 #endif /* HAVE_DNSSD */
3318 * De-register the individual printers
3321 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3323 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3324 dnssdDeregisterPrinter(p);
3328 * Shutdown the rest of the service refs...
3333 DNSServiceRefDeallocate(WebIFRef);
3339 DNSServiceRefDeallocate(RemoteRef);
3343 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
3345 DNSServiceRefDeallocate(DNSSDRef);
3347 #endif /* HAVE_DNSSD */
3349 cupsArrayDelete(DNSSDPrinters);
3350 DNSSDPrinters = NULL;
3354 #endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3359 * 'dnssdUpdate()' - Handle DNS-SD queries.
3365 DNSServiceErrorType sdErr; /* Service discovery error */
3368 if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
3370 cupsdLogMessage(CUPSD_LOG_ERROR,
3371 "DNS Service Discovery registration error %d!",
3376 #endif /* HAVE_DNSSD */
3381 * 'avahiPackTxtRecord()' - Pack an array of key/value pairs into an
3385 static AvahiStringList * /* O - new string list */
3386 avahiPackTxtRecord(char *keyvalue[][2], /* I - Table of key value pairs */
3387 int count) /* I - Number of items in table */
3389 AvahiStringList *strlst = NULL;
3394 elements = malloc ((1 + count) * sizeof (char *));
3398 for (i = 0; i < count; i++)
3400 len = (1 + strlen (keyvalue[i][0]) +
3401 (keyvalue[i][1] ? 1 + strlen (keyvalue[i][1]) : 1));
3402 elements[i] = malloc (len * sizeof (char));
3406 snprintf (elements[i], len, "%s=%s", keyvalue[i][0], keyvalue[i][1]);
3409 strlst = avahi_string_list_new_from_array ((const char **) elements, count);
3421 * 'avahi_entry_group_cb()' - Avahi entry group callback function.
3424 avahi_entry_group_cb (AvahiEntryGroup *group,
3425 AvahiEntryGroupState state,
3431 name = ((cupsd_printer_t *) userdata)->reg_name;
3433 name = "CUPS web interface";
3437 case AVAHI_ENTRY_GROUP_UNCOMMITED:
3438 case AVAHI_ENTRY_GROUP_REGISTERING:
3441 case AVAHI_ENTRY_GROUP_ESTABLISHED:
3442 cupsdLogMessage (CUPSD_LOG_DEBUG,
3443 "Avahi entry group established for %s", name);
3447 cupsdLogMessage (CUPSD_LOG_DEBUG,
3448 "Avahi entry group %s has state %d",
3456 * 'avahi_client_cb()' - Avahi client callback function.
3459 avahi_client_cb (AvahiClient *client,
3460 AvahiClientState state,
3463 cupsd_printer_t *printer;
3466 case AVAHI_CLIENT_S_RUNNING:
3468 * Avahi client started successfully.
3470 AvahiCupsClient = client;
3471 AvahiCupsClientConnecting = 0;
3472 cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client started");
3474 cupsdUpdateDNSSDName ();
3476 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
3478 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
3479 if (Browsing && (BrowseLocalProtocols & BROWSE_DNSSD) &&
3480 (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
3481 CUPS_PRINTER_SCANNER))) && printer->shared)
3482 dnssdRegisterPrinter (printer);
3486 case AVAHI_CLIENT_CONNECTING:
3488 * No Avahi daemon, client is waiting.
3490 cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client connecting");
3493 case AVAHI_CLIENT_S_REGISTERING:
3495 * Not yet registered.
3497 cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client registering");
3500 case AVAHI_CLIENT_FAILURE:
3502 * Avahi client failed, close it to allow a clean restart.
3504 cupsdLogMessage (CUPSD_LOG_ERROR,
3505 "Avahi client failed, "
3506 "closing client to allow a clean restart");
3508 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
3510 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
3511 dnssdDeregisterPrinter (printer);
3513 avahi_client_free(client);
3514 AvahiCupsClientConnecting = 0;
3515 AvahiCupsClient = NULL;
3520 cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client state: %d", state);
3523 #endif /* HAVE_AVAHI */
3527 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
3530 static char * /* O - String or NULL if none */
3531 get_auth_info_required(
3532 cupsd_printer_t *p, /* I - Printer */
3533 char *buffer, /* I - Value buffer */
3534 size_t bufsize) /* I - Size of value buffer */
3536 cupsd_location_t *auth; /* Pointer to authentication element */
3537 char resource[1024]; /* Printer/class resource path */
3541 * If auth-info-required is set for this printer, return that...
3544 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
3546 int i; /* Looping var */
3547 char *bufptr; /* Pointer into buffer */
3549 for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
3551 if (bufptr >= (buffer + bufsize - 2))
3557 strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer));
3558 bufptr += strlen(bufptr);
3565 * Figure out the authentication data requirements to advertise...
3568 if (p->type & CUPS_PRINTER_CLASS)
3569 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
3571 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
3573 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
3574 auth->type == CUPSD_AUTH_NONE)
3575 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
3579 int auth_type; /* Authentication type */
3581 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
3582 auth_type = DefaultAuthType;
3586 case CUPSD_AUTH_NONE :
3589 case CUPSD_AUTH_NEGOTIATE :
3590 strlcpy(buffer, "negotiate", bufsize);
3594 strlcpy(buffer, "username,password", bufsize);
3607 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
3610 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
3611 get_hostconfig(const char *name) /* I - Name of service */
3613 cups_file_t *fp; /* Hostconfig file */
3614 char line[1024], /* Line from file */
3615 *ptr; /* Pointer to value */
3616 int state = 1; /* State of service */
3620 * Try opening the /etc/hostconfig file; if we can't open it, assume that
3621 * the service is enabled/auto.
3624 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
3627 * Read lines from the file until we find the service...
3630 while (cupsFileGets(fp, line, sizeof(line)))
3632 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
3637 if (!_cups_strcasecmp(line, name))
3640 * Found the service, see if it is set to "-NO-"...
3643 if (!_cups_strncasecmp(ptr, "-NO-", 4))
3654 #endif /* __APPLE__ */
3658 * 'is_local_queue()' - Determine whether the URI points at a local queue.
3661 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
3662 is_local_queue(const char *uri, /* I - Printer URI */
3663 char *host, /* O - Host string */
3664 int hostlen, /* I - Length of host buffer */
3665 char *resource, /* O - Resource string */
3666 int resourcelen) /* I - Length of resource buffer */
3668 char scheme[32], /* Scheme portion of URI */
3669 username[HTTP_MAX_URI]; /* Username portion of URI */
3670 int port; /* Port portion of URI */
3671 cupsd_netif_t *iface; /* Network interface */
3675 * Pull the URI apart to see if this is a local or remote printer...
3678 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
3679 username, sizeof(username), host, hostlen, &port,
3680 resource, resourcelen) < HTTP_URI_OK)
3683 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
3686 * Check for local server addresses...
3689 if (!_cups_strcasecmp(host, ServerName) && port == LocalPort)
3694 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3696 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3697 if (!_cups_strcasecmp(host, iface->hostname) && port == iface->port)
3701 * If we get here, the printer is remote...
3709 * 'process_browse_data()' - Process new browse data.
3713 process_browse_data(
3714 const char *uri, /* I - URI of printer/class */
3715 const char *host, /* I - Hostname */
3716 const char *resource, /* I - Resource path */
3717 cups_ptype_t type, /* I - Printer type */
3718 ipp_pstate_t state, /* I - Printer state */
3719 const char *location, /* I - Printer location */
3720 const char *info, /* I - Printer information */
3721 const char *make_model, /* I - Printer make and model */
3722 int num_attrs, /* I - Number of attributes */
3723 cups_option_t *attrs) /* I - Attributes */
3725 int i; /* Looping var */
3726 int update; /* Update printer attributes? */
3727 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
3728 name[IPP_MAX_NAME], /* Name of printer */
3729 newname[IPP_MAX_NAME], /* New name of printer */
3730 *hptr, /* Pointer into hostname */
3731 *sptr; /* Pointer into ServerName */
3732 const char *shortname; /* Short queue name (queue) */
3733 char local_make_model[IPP_MAX_NAME];
3734 /* Local make and model */
3735 cupsd_printer_t *p; /* Printer information */
3736 const char *ipp_options, /* ipp-options value */
3737 *lease_duration, /* lease-duration value */
3738 *uuid; /* uuid value */
3739 int is_class; /* Is this queue a class? */
3742 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3743 "process_browse_data(uri=\"%s\", host=\"%s\", "
3744 "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
3745 "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
3746 uri, host, resource, type, state,
3747 location ? location : "(nil)", info ? info : "(nil)",
3748 make_model ? make_model : "(nil)", num_attrs, attrs);
3751 * Determine if the URI contains any illegal characters in it...
3754 if (strncmp(uri, "ipp://", 6) || !host[0] ||
3755 (strncmp(resource, "/printers/", 10) &&
3756 strncmp(resource, "/classes/", 9)))
3758 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
3762 if (strchr(resource, '?') ||
3763 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
3764 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
3766 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
3772 * OK, this isn't a local printer; add any remote options...
3775 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
3777 if (BrowseRemoteOptions)
3779 if (BrowseRemoteOptions[0] == '?')
3782 * Override server-supplied options...
3785 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
3787 else if (ipp_options)
3790 * Combine the server and local options...
3793 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
3794 BrowseRemoteOptions);
3799 * Just use the local options...
3802 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
3807 else if (ipp_options)
3810 * Just use the server-supplied options...
3813 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
3818 * See if we already have it listed in the Printers list, and add it if not...
3821 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
3822 type &= ~CUPS_PRINTER_IMPLICIT;
3824 hptr = strchr(host, '.');
3825 sptr = strchr(ServerName, '.');
3826 is_class = type & CUPS_PRINTER_CLASS;
3827 uuid = cupsGetOption("uuid", num_attrs, attrs);
3829 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
3832 * Strip the common domain name components...
3835 while (hptr != NULL)
3837 if (!_cups_strcasecmp(hptr, sptr))
3843 hptr = strchr(hptr + 1, '.');
3850 * Remote destination is a class...
3853 if (!strncmp(resource, "/classes/", 9))
3854 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
3858 shortname = resource + 9;
3863 * Remote destination is a printer...
3866 if (!strncmp(resource, "/printers/", 10))
3867 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
3871 shortname = resource + 10;
3875 *hptr = '.'; /* Resource FQDN */
3877 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
3880 * Long name doesn't exist, try short name...
3883 cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
3886 if ((p = cupsdFindDest(shortname)) == NULL)
3889 * Short name doesn't exist, use it for this shared queue.
3892 cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
3894 strlcpy(name, shortname, sizeof(name));
3899 * Short name exists...
3902 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3903 "process_browse_data: %s found, type=%x, hostname=%s...",
3904 shortname, p->type, p->hostname ? p->hostname : "(nil)");
3906 if (p->type & CUPS_PRINTER_IMPLICIT)
3907 p = NULL; /* Don't replace implicit classes */
3908 else if (p->hostname && _cups_strcasecmp(p->hostname, host))
3911 * Short name exists but is for a different host. If this is a remote
3912 * queue, rename it and use the long name...
3915 if (p->type & CUPS_PRINTER_REMOTE)
3917 cupsdLogMessage(CUPSD_LOG_DEBUG,
3918 "Renamed remote %s \"%s\" to \"%s@%s\"...",
3919 is_class ? "class" : "printer", p->name, p->name,
3921 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3922 "%s \'%s\' deleted by directory services.",
3923 is_class ? "Class" : "Printer", p->name);
3925 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
3926 cupsdRenamePrinter(p, newname);
3928 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3929 "%s \'%s\' added by directory services.",
3930 is_class ? "Class" : "Printer", p->name);
3934 * Force creation with long name...
3942 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3943 "process_browse_data: %s found, type=%x, hostname=%s...",
3944 name, p->type, p->hostname ? p->hostname : "(nil)");
3949 * Queue doesn't exist; add it...
3953 p = cupsdAddClass(name);
3955 p = cupsdAddPrinter(name);
3960 cupsdClearString(&(p->hostname));
3962 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
3963 is_class ? "class" : "printer", name);
3965 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3966 "%s \'%s\' added by directory services.",
3967 is_class ? "Class" : "Printer", name);
3970 * Force the URI to point to the real server...
3973 p->type = type & ~CUPS_PRINTER_REJECTING;
3976 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3982 * Hostname not set, so this must be a cached remote printer
3983 * that was created for a pending print job...
3986 cupsdSetString(&p->hostname, host);
3987 cupsdSetString(&p->uri, uri);
3988 cupsdSetString(&p->device_uri, uri);
3991 cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
3995 * Update the state...
3999 p->browse_time = time(NULL);
4001 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
4005 * Grab the lease-duration for the browse data; anything less then 1
4006 * second or more than 1 week gets the default BrowseTimeout...
4009 i = atoi(lease_duration);
4010 if (i < 1 || i > 604800)
4013 p->browse_expire = p->browse_time + i;
4016 p->browse_expire = p->browse_time + BrowseTimeout;
4018 if (type & CUPS_PRINTER_REJECTING)
4020 type &= ~CUPS_PRINTER_REJECTING;
4028 else if (!p->accepting)
4034 if (p->type != type)
4040 if (uuid && strcmp(p->uuid, uuid))
4042 cupsdSetString(&p->uuid, uuid);
4046 if (location && (!p->location || strcmp(p->location, location)))
4048 cupsdSetString(&p->location, location);
4052 if (info && (!p->info || strcmp(p->info, info)))
4054 cupsdSetString(&p->info, info);
4057 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4060 if (!make_model || !make_model[0])
4063 snprintf(local_make_model, sizeof(local_make_model),
4064 "Remote Class on %s", host);
4066 snprintf(local_make_model, sizeof(local_make_model),
4067 "Remote Printer on %s", host);
4070 snprintf(local_make_model, sizeof(local_make_model),
4071 "%s on %s", make_model, host);
4073 if (!p->make_model || strcmp(p->make_model, local_make_model))
4075 cupsdSetString(&p->make_model, local_make_model);
4081 if (!update && !(type & CUPS_PRINTER_DELETE))
4084 * See if we need to update the attributes...
4087 if (p->num_options != num_attrs)
4091 for (i = 0; i < num_attrs; i ++)
4092 if (strcmp(attrs[i].name, p->options[i].name) ||
4093 (!attrs[i].value != !p->options[i].value) ||
4094 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
4103 * Free the old options...
4106 cupsFreeOptions(p->num_options, p->options);
4109 p->num_options = num_attrs;
4112 if (type & CUPS_PRINTER_DELETE)
4114 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
4115 "%s \'%s\' deleted by directory services.",
4116 is_class ? "Class" : "Printer", p->name);
4118 cupsdExpireSubscriptions(p, NULL);
4120 cupsdDeletePrinter(p, 1);
4121 cupsdUpdateImplicitClasses();
4122 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4126 cupsdSetPrinterAttrs(p);
4127 cupsdUpdateImplicitClasses();
4131 * See if we have a default printer... If not, make the first network
4132 * default printer the default.
4135 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
4138 * Find the first network default printer and use it...
4141 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
4143 p = (cupsd_printer_t *)cupsArrayNext(Printers))
4144 if (p->type & CUPS_PRINTER_DEFAULT)
4147 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4153 * Do auto-classing if needed...
4156 process_implicit_classes();
4161 * 'process_implicit_classes()' - Create/update implicit classes as needed.
4165 process_implicit_classes(void)
4167 int i; /* Looping var */
4168 int update; /* Update printer attributes? */
4169 char name[IPP_MAX_NAME], /* Name of printer */
4170 *hptr; /* Pointer into hostname */
4171 cupsd_printer_t *p, /* Printer information */
4172 *pclass, /* Printer class */
4173 *first; /* First printer in class */
4174 int offset, /* Offset of name */
4175 len; /* Length of name */
4178 if (!ImplicitClasses || !Printers)
4182 * Loop through all available printers and create classes as needed...
4185 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
4186 update = 0, pclass = NULL, first = NULL;
4188 p = (cupsd_printer_t *)cupsArrayNext(Printers))
4191 * Skip implicit classes...
4194 if (p->type & CUPS_PRINTER_IMPLICIT)
4201 * If len == 0, get the length of this printer name up to the "@"
4205 cupsArraySave(Printers);
4208 !_cups_strncasecmp(p->name, name + offset, len) &&
4209 (p->name[len] == '\0' || p->name[len] == '@'))
4212 * We have more than one printer with the same name; see if
4213 * we have a class, and if this printer is a member...
4216 if (pclass && _cups_strcasecmp(pclass->name, name))
4219 cupsdSetPrinterAttrs(pclass);
4225 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
4228 * Need to add the class...
4231 pclass = cupsdAddPrinter(name);
4232 cupsArrayAdd(ImplicitPrinters, pclass);
4234 pclass->type |= CUPS_PRINTER_IMPLICIT;
4235 pclass->accepting = 1;
4236 pclass->state = IPP_PRINTER_IDLE;
4238 cupsdSetString(&pclass->location, p->location);
4239 cupsdSetString(&pclass->info, p->info);
4241 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
4242 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
4246 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4248 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
4250 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
4251 "Implicit class \'%s\' added by directory services.",
4257 for (i = 0; i < pclass->num_printers; i ++)
4258 if (pclass->printers[i] == first)
4261 if (i >= pclass->num_printers)
4263 first->in_implicit_class = 1;
4264 cupsdAddPrinterToClass(pclass, first);
4270 for (i = 0; i < pclass->num_printers; i ++)
4271 if (pclass->printers[i] == p)
4274 if (i >= pclass->num_printers)
4276 p->in_implicit_class = 1;
4277 cupsdAddPrinterToClass(pclass, p);
4284 * First time around; just get name length and mark it as first
4288 if ((hptr = strchr(p->name, '@')) != NULL)
4289 len = hptr - p->name;
4291 len = strlen(p->name);
4293 if (len >= sizeof(name))
4296 * If the printer name length somehow is greater than we normally allow,
4297 * skip this printer...
4301 cupsArrayRestore(Printers);
4305 strncpy(name, p->name, len);
4309 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
4310 !(first->type & CUPS_PRINTER_IMPLICIT))
4313 * Can't use same name as a local printer; add "Any" to the
4314 * front of the name, unless we have explicitly disabled
4315 * the "ImplicitAnyClasses"...
4318 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
4321 * Add "Any" to the class name...
4324 strcpy(name, "Any");
4325 strncpy(name + 3, p->name, len);
4326 name[len + 3] = '\0';
4332 * Don't create an implicit class if we have a local printer
4333 * with the same name...
4337 cupsArrayRestore(Printers);
4345 cupsArrayRestore(Printers);
4349 * Update the last printer class as needed...
4352 if (pclass && update)
4353 cupsdSetPrinterAttrs(pclass);
4358 * 'send_cups_browse()' - Send new browsing information using the CUPS
4363 send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
4365 int i; /* Looping var */
4366 cups_ptype_t type; /* Printer type */
4367 cupsd_dirsvc_addr_t *b; /* Browse address */
4368 int bytes; /* Length of packet */
4369 char packet[1453], /* Browse data packet */
4370 uri[1024], /* Printer URI */
4371 location[1024], /* printer-location */
4372 info[1024], /* printer-info */
4374 /* printer-make-and-model */
4375 air[1024]; /* auth-info-required */
4376 cupsd_netif_t *iface; /* Network interface */
4380 * Figure out the printer type value...
4383 type = p->type | CUPS_PRINTER_REMOTE;
4386 type |= CUPS_PRINTER_REJECTING;
4388 if (p == DefaultPrinter)
4389 type |= CUPS_PRINTER_DEFAULT;
4392 * Remove quotes from printer-info, printer-location, and
4393 * printer-make-and-model attributes...
4396 dequote(location, p->location, sizeof(location));
4397 dequote(info, p->info, sizeof(info));
4400 dequote(make_model, p->make_model, sizeof(make_model));
4401 else if (p->type & CUPS_PRINTER_CLASS)
4403 if (p->num_printers > 0 && p->printers[0]->make_model)
4404 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
4406 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
4409 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
4411 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
4413 if (get_auth_info_required(p, packet, sizeof(packet)))
4414 snprintf(air, sizeof(air), " auth-info-required=%s", packet);
4419 * Send a packet to each browse address...
4422 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
4426 * Send the browse packet to one or more interfaces...
4429 if (!strcmp(b->iface, "*"))
4432 * Send to all local interfaces...
4437 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
4439 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
4442 * Only send to local, IPv4 interfaces...
4445 if (!iface->is_local || !iface->port ||
4446 iface->address.addr.sa_family != AF_INET)
4449 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
4450 iface->hostname, iface->port,
4451 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4454 snprintf(packet, sizeof(packet),
4455 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
4456 type, p->state, uri, location, info, make_model,
4457 p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
4459 bytes = strlen(packet);
4461 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4462 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
4463 iface->name, packet);
4465 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
4467 sendto(BrowseSocket, packet, bytes, 0,
4468 (struct sockaddr *)&(iface->broadcast),
4469 httpAddrLength(&(iface->broadcast)));
4472 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
4475 * Send to the named interface using the IPv4 address...
4479 if (strcmp(b->iface, iface->name))
4484 else if (iface->address.addr.sa_family == AF_INET && iface->port)
4487 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
4491 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
4492 iface->hostname, iface->port,
4493 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4496 snprintf(packet, sizeof(packet),
4497 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
4498 type, p->state, uri, location, info, make_model,
4499 p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
4501 bytes = strlen(packet);
4503 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4504 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
4505 iface->name, packet);
4507 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
4509 sendto(BrowseSocket, packet, bytes, 0,
4510 (struct sockaddr *)&(iface->broadcast),
4511 httpAddrLength(&(iface->broadcast)));
4518 * Send the browse packet to the indicated address using
4519 * the default server name...
4522 snprintf(packet, sizeof(packet),
4523 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
4524 type, p->state, p->uri, location, info, make_model,
4525 p->browse_attrs ? p->browse_attrs : "", air, p->uuid);
4527 bytes = strlen(packet);
4528 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4529 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
4531 if (sendto(BrowseSocket, packet, bytes, 0,
4532 (struct sockaddr *)&(b->to),
4533 httpAddrLength(&(b->to))) <= 0)
4536 * Unable to send browse packet, so remove this address from the
4540 cupsdLogMessage(CUPSD_LOG_ERROR,
4541 "cupsdSendBrowseList: sendto failed for browser "
4543 (int)(b - Browsers + 1), strerror(errno));
4546 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
4557 * 'ldap_search_rec()' - LDAP Search with reconnect
4560 static int /* O - Return code */
4561 ldap_search_rec(LDAP *ld, /* I - LDAP handler */
4562 char *base, /* I - Base dn */
4563 int scope, /* I - LDAP search scope */
4564 char *filter, /* I - Filter string */
4565 char *attrs[], /* I - Requested attributes */
4566 int attrsonly, /* I - Return only attributes? */
4567 LDAPMessage **res) /* I - LDAP handler */
4569 int rc; /* Return code */
4570 LDAP *ldr; /* LDAP handler after reconnect */
4573 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4574 rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
4575 NULL, LDAP_NO_LIMIT, res);
4577 rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
4578 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4581 * If we have a connection problem try again...
4584 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4586 cupsdLogMessage(CUPSD_LOG_ERROR,
4587 "LDAP search failed with status %d: %s",
4588 rc, ldap_err2string(rc));
4589 cupsdLogMessage(CUPSD_LOG_INFO,
4590 "We try the LDAP search once again after reconnecting to "
4593 ldr = ldap_reconnect();
4595 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4596 rc = ldap_search_ext_s(ldr, base, scope, filter, attrs, attrsonly, NULL,
4597 NULL, NULL, LDAP_NO_LIMIT, res);
4599 rc = ldap_search_s(ldr, base, scope, filter, attrs, attrsonly, res);
4600 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4603 if (rc == LDAP_NO_SUCH_OBJECT)
4604 cupsdLogMessage(CUPSD_LOG_DEBUG,
4605 "ldap_search_rec: LDAP entry/object not found");
4606 else if (rc != LDAP_SUCCESS)
4607 cupsdLogMessage(CUPSD_LOG_ERROR,
4608 "ldap_search_rec: LDAP search failed with status %d: %s",
4609 rc, ldap_err2string(rc));
4611 if (rc != LDAP_SUCCESS)
4619 * 'ldap_freeres()' - Free LDAPMessage
4623 ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
4625 int rc; /* Return value */
4628 rc = ldap_msgfree(entry);
4630 cupsdLogMessage(CUPSD_LOG_WARN, "Can't free LDAPMessage!");
4632 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Freeing LDAPMessage was unnecessary");
4637 * 'ldap_getval_char()' - Get first LDAP value and convert to string
4640 static int /* O - Return code */
4641 ldap_getval_firststring(
4642 LDAP *ld, /* I - LDAP handler */
4643 LDAPMessage *entry, /* I - LDAP message or search result */
4644 char *attr, /* I - the wanted attribute */
4645 char *retval, /* O - String to return */
4646 unsigned long maxsize) /* I - Max string size */
4648 char *dn; /* LDAP DN */
4649 int rc = 0; /* Return code */
4650 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4651 struct berval **bval; /* LDAP value array */
4652 unsigned long size; /* String size */
4656 * Get value from LDAPMessage...
4659 if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
4662 dn = ldap_get_dn(ld, entry);
4663 cupsdLogMessage(CUPSD_LOG_WARN,
4664 "Failed to get LDAP value %s for %s!",
4671 * Check size and copy value into our string...
4675 if (size < (bval[0]->bv_len + 1))
4678 dn = ldap_get_dn(ld, entry);
4679 cupsdLogMessage(CUPSD_LOG_WARN,
4680 "Attribute %s is too big! (dn: %s)",
4685 size = bval[0]->bv_len + 1;
4687 strlcpy(retval, bval[0]->bv_val, size);
4688 ldap_value_free_len(bval);
4691 char **value; /* LDAP value */
4694 * Get value from LDAPMessage...
4697 if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
4700 dn = ldap_get_dn(ld, entry);
4701 cupsdLogMessage(CUPSD_LOG_WARN, "Failed to get LDAP value %s for %s!",
4707 strlcpy(retval, *value, maxsize);
4708 ldap_value_free(value);
4710 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4717 * 'send_ldap_ou()' - Send LDAP ou registrations.
4721 send_ldap_ou(char *ou, /* I - Servername/ou to register */
4722 char *basedn, /* I - Our base dn */
4723 char *descstring) /* I - Description for ou */
4725 int i; /* Looping var... */
4726 LDAPMod mods[3]; /* The 3 attributes we will be adding */
4727 LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
4728 LDAPMessage *res, /* Search result token */
4729 *e; /* Current entry from search */
4730 int rc; /* LDAP status */
4731 int rcmod; /* LDAP status for modifications */
4732 char dn[1024], /* DN of the organizational unit we are adding */
4733 *desc[2], /* Change records */
4735 char old_desc[1024]; /* Old description */
4736 static const char * const objectClass_values[] =
4737 { /* The 2 objectClass's we use in */
4738 "top", /* our LDAP entries */
4739 "organizationalUnit",
4742 static const char * const ou_attrs[] =/* CUPS LDAP attributes */
4749 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
4752 * Reconnect if LDAP Handle is invalid...
4755 if (!BrowseLDAPHandle)
4757 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4758 "send_ldap_ou: LDAP Handle is invalid. Try reconnecting...");
4764 * Prepare ldap search...
4767 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
4768 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
4772 desc[0] = descstring;
4775 mods[0].mod_type = "ou";
4776 mods[0].mod_values = ou_value;
4777 mods[1].mod_type = "description";
4778 mods[1].mod_values = desc;
4779 mods[2].mod_type = "objectClass";
4780 mods[2].mod_values = (char **)objectClass_values;
4782 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4783 (char **)ou_attrs, 0, &res);
4786 * If ldap search was not successfull then exit function...
4789 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4793 * Check if we need to insert or update the LDAP entry...
4796 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4797 rc != LDAP_NO_SUCH_OBJECT)
4800 * Printserver has already been registered, check if
4801 * modification is required...
4804 e = ldap_first_entry(BrowseLDAPHandle, res);
4807 * Get the required values from this entry...
4810 if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
4811 sizeof(old_desc)) == -1)
4815 * Check if modification is required...
4818 if ( strcmp(desc[0], old_desc) == 0 )
4821 * LDAP entry for the printer exists.
4822 * Printer has already been registered,
4823 * no modifications required...
4825 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4826 "send_ldap_ou: No updates required for %s", ou);
4831 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4832 "send_ldap_ou: Replace entry for %s", ou);
4834 for (i = 0; i < 3; i ++)
4836 pmods[i] = mods + i;
4837 pmods[i]->mod_op = LDAP_MOD_REPLACE;
4841 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4842 if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4843 NULL)) != LDAP_SUCCESS)
4845 if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4846 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4848 cupsdLogMessage(CUPSD_LOG_ERROR,
4849 "LDAP modify for %s failed with status %d: %s",
4850 ou, rcmod, ldap_err2string(rcmod));
4851 if (rcmod == LDAP_SERVER_DOWN)
4859 * Printserver has never been registered,
4860 * add registration...
4863 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4864 "send_ldap_ou: Add entry for %s", ou);
4866 for (i = 0; i < 3; i ++)
4868 pmods[i] = mods + i;
4869 pmods[i]->mod_op = LDAP_MOD_ADD;
4873 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4874 if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4875 NULL)) != LDAP_SUCCESS)
4877 if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4878 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4880 cupsdLogMessage(CUPSD_LOG_ERROR,
4881 "LDAP add for %s failed with status %d: %s",
4882 ou, rcmod, ldap_err2string(rcmod));
4883 if (rcmod == LDAP_SERVER_DOWN)
4888 if (rc == LDAP_SUCCESS)
4894 * 'send_ldap_browse()' - Send LDAP printer registrations.
4898 send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
4900 int i; /* Looping var... */
4901 LDAPMod mods[7]; /* The 7 attributes we will be adding */
4902 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
4903 LDAPMessage *res, /* Search result token */
4904 *e; /* Current entry from search */
4905 char *cn_value[2], /* Change records */
4911 typestring[255], /* String to hold printer-type */
4912 dn[1024]; /* DN of the printer we are adding */
4913 int rc; /* LDAP status */
4914 int rcmod; /* LDAP status for modifications */
4915 char old_uri[HTTP_MAX_URI], /* Printer URI */
4916 old_location[1024], /* Printer location */
4917 old_info[1024], /* Printer information */
4918 old_make_model[1024], /* Printer make and model */
4919 old_type_string[30]; /* Temporary type number */
4920 int old_type; /* Printer type */
4921 static const char * const objectClass_values[] =
4922 { /* The 3 objectClass's we use in */
4923 "top", /* our LDAP entries */
4930 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
4933 * Exit function if LDAP updates has been disabled...
4936 if (!BrowseLDAPUpdate)
4938 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4939 "send_ldap_browse: Updates temporary disabled; "
4945 * Reconnect if LDAP Handle is invalid...
4948 if (!BrowseLDAPHandle)
4950 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4951 "send_ldap_browse: LDAP Handle is invalid. Try "
4958 * Everything in ldap is ** so we fudge around it...
4961 sprintf(typestring, "%u", p->type);
4963 cn_value[0] = p->name;
4965 info[0] = p->info ? p->info : "Unknown";
4967 location[0] = p->location ? p->location : "Unknown";
4969 make_model[0] = p->make_model ? p->make_model : "Unknown";
4970 make_model[1] = NULL;
4971 type[0] = typestring;
4977 * Get ldap entry for printer ...
4980 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4982 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
4984 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4985 (char **)ldap_attrs, 0, &res);
4988 * If ldap search was not successfull then exit function
4989 * and temporary disable LDAP updates...
4992 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4994 if (BrowseLDAPUpdate &&
4995 (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
4997 BrowseLDAPUpdate = FALSE;
4998 cupsdLogMessage(CUPSD_LOG_INFO,
4999 "LDAP update temporary disabled");
5006 * Fill modification array...
5009 mods[0].mod_type = "cn";
5010 mods[0].mod_values = cn_value;
5011 mods[1].mod_type = "printerDescription";
5012 mods[1].mod_values = info;
5013 mods[2].mod_type = "printerURI";
5014 mods[2].mod_values = uri;
5015 mods[3].mod_type = "printerLocation";
5016 mods[3].mod_values = location;
5017 mods[4].mod_type = "printerMakeAndModel";
5018 mods[4].mod_values = make_model;
5019 mods[5].mod_type = "printerType";
5020 mods[5].mod_values = type;
5021 mods[6].mod_type = "objectClass";
5022 mods[6].mod_values = (char **)objectClass_values;
5025 * Check if we need to insert or update the LDAP entry...
5028 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
5029 rc != LDAP_NO_SUCH_OBJECT)
5032 * Printer has already been registered, check if
5033 * modification is required...
5036 e = ldap_first_entry(BrowseLDAPHandle, res);
5039 * Get the required values from this entry...
5042 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
5043 old_info, sizeof(old_info)) == -1)
5046 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
5047 old_location, sizeof(old_location)) == -1)
5050 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
5051 old_make_model, sizeof(old_make_model)) == -1)
5054 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
5055 old_type_string, sizeof(old_type_string)) == -1)
5058 old_type = atoi(old_type_string);
5060 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
5061 sizeof(old_uri)) == -1)
5065 * Check if modification is required...
5068 if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
5069 !strcmp(location[0], old_location) &&
5070 !strcmp(make_model[0], old_make_model) && p->type == old_type)
5073 * LDAP entry for the printer exists. Printer has already been registered,
5074 * no modifications required...
5077 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5078 "send_ldap_browse: No updates required for %s", p->name);
5083 * LDAP entry for the printer exists. Printer has already been registered,
5084 * modify the current registration...
5087 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5088 "send_ldap_browse: Replace entry for %s", p->name);
5090 for (i = 0; i < 7; i ++)
5092 pmods[i] = mods + i;
5093 pmods[i]->mod_op = LDAP_MOD_REPLACE;
5097 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5098 if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
5099 NULL)) != LDAP_SUCCESS)
5101 if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
5102 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5104 cupsdLogMessage(CUPSD_LOG_ERROR,
5105 "LDAP modify for %s failed with status %d: %s",
5106 p->name, rcmod, ldap_err2string(rcmod));
5107 if (rcmod == LDAP_SERVER_DOWN)
5115 * No LDAP entry exists for the printer. Printer has never been registered,
5116 * add the current registration...
5119 send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
5121 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5122 "send_ldap_browse: Add entry for %s", p->name);
5124 for (i = 0; i < 7; i ++)
5126 pmods[i] = mods + i;
5127 pmods[i]->mod_op = LDAP_MOD_ADD;
5131 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5132 if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
5133 NULL)) != LDAP_SUCCESS)
5135 if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
5136 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5138 cupsdLogMessage(CUPSD_LOG_ERROR,
5139 "LDAP add for %s failed with status %d: %s",
5140 p->name, rcmod, ldap_err2string(rcmod));
5141 if (rcmod == LDAP_SERVER_DOWN)
5146 if (rc == LDAP_SUCCESS)
5152 * 'ldap_dereg_printer()' - Delete printer from directory
5156 ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
5158 char dn[1024]; /* DN of the printer */
5159 int rc; /* LDAP status */
5162 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
5166 * Reconnect if LDAP Handle is invalid...
5169 if (!BrowseLDAPHandle)
5176 * Get dn for printer and delete LDAP entry...
5179 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
5181 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
5183 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5184 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5185 NULL)) != LDAP_SUCCESS)
5187 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5188 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5190 cupsdLogMessage(CUPSD_LOG_WARN,
5191 "LDAP delete for %s failed with status %d: %s",
5192 p->name, rc, ldap_err2string(rc));
5195 * If we had a connection problem (connection timed out, etc.)
5196 * we should reconnect and try again to delete the entry...
5199 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
5201 cupsdLogMessage(CUPSD_LOG_INFO,
5202 "Retry deleting LDAP entry for %s after a reconnect...", p->name);
5205 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5206 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5207 NULL)) != LDAP_SUCCESS)
5209 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5210 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5211 cupsdLogMessage(CUPSD_LOG_WARN,
5212 "LDAP delete for %s failed with status %d: %s",
5213 p->name, rc, ldap_err2string(rc));
5220 * 'ldap_dereg_ou()' - Remove the organizational unit.
5224 ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
5225 char *basedn) /* I - Dase dn */
5227 char dn[1024]; /* DN of the printer */
5228 int rc; /* LDAP status */
5231 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
5234 * Reconnect if LDAP Handle is invalid...
5237 if (!BrowseLDAPHandle)
5244 * Get dn for printer and delete LDAP entry...
5247 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
5248 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
5250 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5251 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5252 NULL)) != LDAP_SUCCESS)
5254 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5255 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5257 cupsdLogMessage(CUPSD_LOG_WARN,
5258 "LDAP delete for %s failed with status %d: %s",
5259 ou, rc, ldap_err2string(rc));
5262 * If we had a connection problem (connection timed out, etc.)
5263 * we should reconnect and try again to delete the entry...
5266 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
5268 cupsdLogMessage(CUPSD_LOG_INFO,
5269 "Retry deleting LDAP entry for %s after a reconnect...", ou);
5271 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5272 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5273 NULL)) != LDAP_SUCCESS)
5275 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5276 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5277 cupsdLogMessage(CUPSD_LOG_WARN,
5278 "LDAP delete for %s failed with status %d: %s",
5279 ou, rc, ldap_err2string(rc));
5283 #endif /* HAVE_LDAP */
5288 * 'send_slp_browse()' - Register the specified printer with SLP.
5292 send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
5294 char srvurl[HTTP_MAX_URI], /* Printer service URI */
5295 attrs[8192], /* Printer attributes */
5296 finishings[1024], /* Finishings to support */
5297 make_model[IPP_MAX_NAME * 2],
5298 /* Make and model, quoted */
5299 location[IPP_MAX_NAME * 2],
5300 /* Location, quoted */
5301 info[IPP_MAX_NAME * 2], /* Info, quoted */
5302 *src, /* Pointer to original string */
5303 *dst; /* Pointer to destination string */
5304 ipp_attribute_t *authentication; /* uri-authentication-supported value */
5305 SLPError error; /* SLP error, if any */
5308 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
5312 * Make the SLP service URL that conforms to the IANA
5313 * 'printer:' template.
5316 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
5318 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
5321 * Figure out the finishings string...
5324 if (p->type & CUPS_PRINTER_STAPLE)
5325 strcpy(finishings, "staple");
5327 finishings[0] = '\0';
5329 if (p->type & CUPS_PRINTER_BIND)
5332 strlcat(finishings, ",bind", sizeof(finishings));
5334 strcpy(finishings, "bind");
5337 if (p->type & CUPS_PRINTER_PUNCH)
5340 strlcat(finishings, ",punch", sizeof(finishings));
5342 strcpy(finishings, "punch");
5345 if (p->type & CUPS_PRINTER_COVER)
5348 strlcat(finishings, ",cover", sizeof(finishings));
5350 strcpy(finishings, "cover");
5353 if (p->type & CUPS_PRINTER_SORT)
5356 strlcat(finishings, ",sort", sizeof(finishings));
5358 strcpy(finishings, "sort");
5362 strcpy(finishings, "none");
5365 * Quote any commas in the make and model, location, and info strings...
5368 for (src = p->make_model, dst = make_model;
5369 src && *src && dst < (make_model + sizeof(make_model) - 2);)
5371 if (*src == ',' || *src == '\\' || *src == ')')
5380 strcpy(make_model, "Unknown");
5382 for (src = p->location, dst = location;
5383 src && *src && dst < (location + sizeof(location) - 2);)
5385 if (*src == ',' || *src == '\\' || *src == ')')
5394 strcpy(location, "Unknown");
5396 for (src = p->info, dst = info;
5397 src && *src && dst < (info + sizeof(info) - 2);)
5399 if (*src == ',' || *src == '\\' || *src == ')')
5408 strcpy(info, "Unknown");
5411 * Get the authentication value...
5414 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
5418 * Make the SLP attribute string list that conforms to
5419 * the IANA 'printer:' template.
5422 snprintf(attrs, sizeof(attrs),
5423 "(printer-uri-supported=%s),"
5424 "(uri-authentication-supported=%s>),"
5426 "(uri-security-supported=tls>),"
5428 "(uri-security-supported=none>),"
5429 #endif /* HAVE_SSL */
5430 "(printer-name=%s),"
5431 "(printer-location=%s),"
5432 "(printer-info=%s),"
5433 "(printer-more-info=%s),"
5434 "(printer-make-and-model=%s),"
5435 "(printer-type=%d),"
5436 "(charset-supported=utf-8),"
5437 "(natural-language-configured=%s),"
5438 "(natural-language-supported=de,en,es,fr,it),"
5439 "(color-supported=%s),"
5440 "(finishings-supported=%s),"
5441 "(sides-supported=one-sided%s),"
5442 "(multiple-document-jobs-supported=true)"
5443 "(ipp-versions-supported=1.0,1.1)",
5444 p->uri, authentication->values[0].string.text, p->name, location,
5445 info, p->uri, make_model, p->type, DefaultLanguage,
5446 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
5448 p->type & CUPS_PRINTER_DUPLEX ?
5449 ",two-sided-long-edge,two-sided-short-edge" : "");
5451 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
5454 * Register the printer with the SLP server...
5457 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
5458 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
5460 if (error != SLP_OK)
5461 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
5467 * 'slp_attr_callback()' - SLP attribute callback
5470 static SLPBoolean /* O - SLP_TRUE for success */
5472 SLPHandle hslp, /* I - SLP handle */
5473 const char *attrlist, /* I - Attribute list */
5474 SLPError errcode, /* I - Parsing status for this attr */
5475 void *cookie) /* I - Current printer */
5477 char *tmp = 0; /* Temporary string */
5478 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
5479 /* Current printer */
5482 (void)hslp; /* anti-compiler-warning-code */
5485 * Bail if there was an error
5488 if (errcode != SLP_OK)
5492 * Parse the attrlist to obtain things needed to build CUPS browse packet
5495 memset(p, 0, sizeof(cupsd_printer_t));
5497 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
5499 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
5501 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
5503 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
5504 p->type = atoi(tmp);
5506 p->type = CUPS_PRINTER_REMOTE;
5508 cupsdClearString(&tmp);
5515 * 'slp_dereg_printer()' - SLPDereg() the specified printer
5519 slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
5521 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
5524 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
5526 if (!(p->type & CUPS_PRINTER_REMOTE))
5529 * Make the SLP service URL that conforms to the IANA
5530 * 'printer:' template.
5533 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
5536 * Deregister the printer...
5539 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
5545 * 'slp_get_attr()' - Get an attribute from an SLP registration.
5548 static int /* O - 0 on success */
5549 slp_get_attr(const char *attrlist, /* I - Attribute list string */
5550 const char *tag, /* I - Name of attribute */
5551 char **valbuf) /* O - Value */
5553 char *ptr1, /* Pointer into string */
5557 cupsdClearString(valbuf);
5559 if ((ptr1 = strstr(attrlist, tag)) != NULL)
5561 ptr1 += strlen(tag);
5563 if ((ptr2 = strchr(ptr1,')')) != NULL)
5569 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
5570 strncpy(*valbuf, ptr1, ptr2 - ptr1);
5573 * Dequote the value...
5576 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
5577 if (*ptr1 == '\\' && ptr1[1])
5578 _cups_strcpy(ptr1, ptr1 + 1);
5589 * 'slp_reg_callback()' - Empty SLPRegReport.
5593 slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
5594 SLPError errcode, /* I - Error code, if any */
5595 void *cookie) /* I - App data */
5606 * 'slp_url_callback()' - SLP service url callback
5609 static SLPBoolean /* O - TRUE = OK, FALSE = error */
5611 SLPHandle hslp, /* I - SLP handle */
5612 const char *srvurl, /* I - URL of service */
5613 unsigned short lifetime, /* I - Life of service */
5614 SLPError errcode, /* I - Existing error code */
5615 void *cookie) /* I - Pointer to service list */
5617 slpsrvurl_t *s, /* New service entry */
5618 **head; /* Pointer to head of entry */
5622 * Let the compiler know we won't be using these vars...
5629 * Bail if there was an error
5632 if (errcode != SLP_OK)
5636 * Grab the head of the list...
5639 head = (slpsrvurl_t**)cookie;
5642 * Allocate a *temporary* slpsrvurl_t to hold this entry.
5645 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
5649 * Copy the SLP service URL...
5652 strlcpy(s->url, srvurl, sizeof(s->url));
5655 * Link the SLP service URL into the head of the list
5665 #endif /* HAVE_LIBSLP */
5669 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
5673 update_cups_browse(void)
5675 int i; /* Looping var */
5676 int auth; /* Authorization status */
5677 int len; /* Length of name string */
5678 int bytes; /* Number of bytes left */
5679 char packet[1541], /* Broadcast packet */
5680 *pptr; /* Pointer into packet */
5681 socklen_t srclen; /* Length of source address */
5682 http_addr_t srcaddr; /* Source address */
5683 char srcname[1024]; /* Source hostname */
5684 unsigned address[4]; /* Source address */
5685 unsigned type; /* Printer type */
5686 unsigned state; /* Printer state */
5687 char uri[HTTP_MAX_URI], /* Printer URI */
5688 host[HTTP_MAX_URI], /* Host portion of URI */
5689 resource[HTTP_MAX_URI], /* Resource portion of URI */
5690 info[IPP_MAX_NAME], /* Information string */
5691 location[IPP_MAX_NAME], /* Location string */
5692 make_model[IPP_MAX_NAME];/* Make and model string */
5693 int num_attrs; /* Number of attributes */
5694 cups_option_t *attrs; /* Attributes */
5698 * Read a packet from the browse socket...
5701 srclen = sizeof(srcaddr);
5702 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
5703 (struct sockaddr *)&srcaddr, &srclen)) < 0)
5706 * "Connection refused" is returned under Linux if the destination port
5707 * or address is unreachable from a previous sendto(); check for the
5708 * error here and ignore it for now...
5711 if (errno != ECONNREFUSED && errno != EAGAIN)
5713 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
5715 cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
5718 closesocket(BrowseSocket);
5720 close(BrowseSocket);
5723 cupsdRemoveSelect(BrowseSocket);
5726 BrowseLocalProtocols &= ~BROWSE_CUPS;
5727 BrowseRemoteProtocols &= ~BROWSE_CUPS;
5733 packet[bytes] = '\0';
5736 * If we're about to sleep, ignore incoming browse packets.
5743 * Figure out where it came from...
5747 if (srcaddr.addr.sa_family == AF_INET6)
5749 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
5750 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
5751 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
5752 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
5755 #endif /* AF_INET6 */
5760 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
5763 if (HostNameLookups)
5764 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
5766 httpAddrString(&srcaddr, srcname, sizeof(srcname));
5768 len = strlen(srcname);
5776 if (httpAddrLocalhost(&srcaddr) || !_cups_strcasecmp(srcname, "localhost"))
5779 * Access from localhost (127.0.0.1) is always allowed...
5782 auth = CUPSD_AUTH_ALLOW;
5787 * Do authorization checks on the domain/address...
5790 switch (BrowseACL->order_type)
5793 auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
5796 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
5797 auth = CUPSD_AUTH_ALLOW;
5799 if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
5800 auth = CUPSD_AUTH_DENY;
5802 if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
5803 auth = CUPSD_AUTH_ALLOW;
5806 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
5807 auth = CUPSD_AUTH_DENY;
5809 if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
5810 auth = CUPSD_AUTH_ALLOW;
5812 if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
5813 auth = CUPSD_AUTH_DENY;
5819 auth = CUPSD_AUTH_ALLOW;
5821 if (auth == CUPSD_AUTH_DENY)
5823 cupsdLogMessage(CUPSD_LOG_DEBUG,
5824 "update_cups_browse: Refused %d bytes from %s", bytes,
5829 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5830 "update_cups_browse: (%d bytes from %s) %s", bytes,
5837 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
5839 cupsdLogMessage(CUPSD_LOG_WARN,
5840 "update_cups_browse: Garbled browse packet - %s", packet);
5844 strcpy(location, "Location Unknown");
5845 strcpy(info, "No Information Available");
5846 make_model[0] = '\0';
5850 if ((pptr = strchr(packet, '\"')) != NULL)
5853 * Have extended information; can't use sscanf for it because not all
5854 * sscanf's allow empty strings with %[^\"]...
5857 for (i = 0, pptr ++;
5858 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
5860 location[i] = *pptr;
5868 while (*pptr && isspace(*pptr & 255))
5873 for (i = 0, pptr ++;
5874 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
5883 while (*pptr && isspace(*pptr & 255))
5888 for (i = 0, pptr ++;
5889 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
5891 make_model[i] = *pptr;
5896 make_model[i] = '\0';
5899 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
5905 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
5906 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
5907 type, state, uri, location, info, make_model));
5910 * Pull the URI apart to see if this is a local or remote printer...
5913 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
5915 cupsFreeOptions(num_attrs, attrs);
5923 for (i = 0; i < NumRelays; i ++)
5924 if (cupsdCheckAuth(address, srcname, len, Relays[i].from))
5925 if (sendto(BrowseSocket, packet, bytes, 0,
5926 (struct sockaddr *)&(Relays[i].to),
5927 httpAddrLength(&(Relays[i].to))) <= 0)
5929 cupsdLogMessage(CUPSD_LOG_ERROR,
5930 "update_cups_browse: sendto failed for relay %d - %s.",
5931 i + 1, strerror(errno));
5932 cupsFreeOptions(num_attrs, attrs);
5937 * Process the browse data...
5940 process_browse_data(uri, host, resource, (cups_ptype_t)type,
5941 (ipp_pstate_t)state, location, info, make_model,
5947 * 'update_lpd()' - Update the LPD configuration as needed.
5951 update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
5958 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
5959 * setting for backwards-compatibility.
5962 if (onoff && !get_hostconfig("CUPS_LPD"))
5964 #endif /* __APPLE__ */
5966 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
5969 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
5972 char newfile[1024]; /* New cups-lpd.N file */
5973 cups_file_t *ofp, /* Original file pointer */
5974 *nfp; /* New file pointer */
5975 char line[1024]; /* Line from file */
5978 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
5980 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
5982 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5983 LPDConfigFile + 9, strerror(errno));
5987 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5989 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5990 newfile, strerror(errno));
5996 * Copy all of the lines from the cups-lpd file...
5999 while (cupsFileGets(ofp, line, sizeof(line)))
6003 cupsFilePrintf(nfp, "%s\n", line);
6004 snprintf(line, sizeof(line), "\tdisable = %s",
6005 onoff ? "no" : "yes");
6007 else if (!strstr(line, "disable ="))
6008 cupsFilePrintf(nfp, "%s\n", line);
6013 rename(newfile, LPDConfigFile + 9);
6016 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
6019 * Enable/disable LPD via the launchctl command...
6022 char *argv[5], /* Arguments for command */
6023 *envp[MAX_ENV]; /* Environment for command */
6024 int pid; /* Process ID */
6027 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
6028 argv[0] = (char *)"launchctl";
6029 argv[1] = (char *)(onoff ? "load" : "unload");
6030 argv[2] = (char *)"-w";
6031 argv[3] = LPDConfigFile + 10;
6034 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
6037 #endif /* __APPLE__ */
6039 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
6044 * 'update_polling()' - Read status messages from the poll daemons.
6048 update_polling(void)
6050 char *ptr, /* Pointer to end of line in buffer */
6051 message[1024]; /* Pointer to message text */
6052 int loglevel; /* Log level for message */
6055 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
6056 message, sizeof(message))) != NULL)
6058 if (loglevel == CUPSD_LOG_INFO)
6059 cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
6061 if (!strchr(PollStatusBuffer->buffer, '\n'))
6065 if (ptr == NULL && !PollStatusBuffer->bufused)
6068 * All polling processes have died; stop polling...
6071 cupsdLogMessage(CUPSD_LOG_ERROR,
6072 "update_polling: all polling processes have exited!");
6079 * 'update_smb()' - Update the SMB configuration as needed.
6083 update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
6088 if (!strncmp(SMBConfigFile, "samba:///", 9))
6091 * Enable/disable SMB via the specified smb.conf config file...
6094 char newfile[1024]; /* New smb.conf.N file */
6095 cups_file_t *ofp, /* Original file pointer */
6096 *nfp; /* New file pointer */
6097 char line[1024]; /* Line from file */
6098 int in_printers; /* In [printers] section? */
6101 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
6103 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
6105 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
6106 SMBConfigFile + 8, strerror(errno));
6110 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
6112 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
6113 newfile, strerror(errno));
6119 * Copy all of the lines from the smb.conf file...
6124 while (cupsFileGets(ofp, line, sizeof(line)))
6126 if (in_printers && strstr(line, "printable ="))
6127 snprintf(line, sizeof(line), " printable = %s",
6128 onoff ? "yes" : "no");
6130 cupsFilePrintf(nfp, "%s\n", line);
6133 in_printers = !strcmp(line, "[printers]");
6138 rename(newfile, SMBConfigFile + 8);
6141 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
6146 * End of "$Id: dirsvc.c 10243 2012-02-11 02:05:21Z mike $".