2 * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z 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 * cupsdStartBrowsing() - Start sending and receiving broadcast
32 * cupsdStartPolling() - Start polling servers as needed.
33 * cupsdStopBrowsing() - Stop sending and receiving broadcast
35 * cupsdStopPolling() - Stop polling servers as needed.
36 * cupsdUpdateDNSSDName() - Update the computer name we use for
38 * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
39 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
40 * dequote() - Remote quotes from a string.
41 * dnssdAddAlias() - Add a DNS-SD alias name.
42 * dnssdBuildTxtRecord() - Build a TXT record from printer info.
43 * dnssdComparePrinters() - Compare the registered names of two printers.
44 * dnssdDeregisterPrinter() - Stop sending broadcast information for a
46 * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
48 * dnssdRegisterCallback() - DNSServiceRegister callback.
49 * dnssdRegisterPrinter() - Start sending broadcast information for a
50 * printer or update the broadcast contents.
51 * dnssdStop() - Stop all DNS-SD registrations.
52 * dnssdUpdate() - Handle DNS-SD queries.
53 * get_auth_info_required() - Get the auth-info-required value to advertise.
54 * get_hostconfig() - Get an /etc/hostconfig service setting.
55 * is_local_queue() - Determine whether the URI points at a local
57 * process_browse_data() - Process new browse data.
58 * process_implicit_classes() - Create/update implicit classes as needed.
59 * send_cups_browse() - Send new browsing information using the CUPS
61 * ldap_search_rec() - LDAP Search with reconnect
62 * ldap_freeres() - Free LDAPMessage
63 * ldap_getval_char() - Get first LDAP value and convert to string
64 * send_ldap_ou() - Send LDAP ou registrations.
65 * send_ldap_browse() - Send LDAP printer registrations.
66 * ldap_dereg_printer() - Delete printer from directory
67 * ldap_dereg_ou() - Remove the organizational unit.
68 * send_slp_browse() - Register the specified printer with SLP.
69 * slp_attr_callback() - SLP attribute callback
70 * slp_dereg_printer() - SLPDereg() the specified printer
71 * slp_get_attr() - Get an attribute from an SLP registration.
72 * slp_reg_callback() - Empty SLPRegReport.
73 * slp_url_callback() - SLP service url callback
74 * update_cups_browse() - Update the browse lists using the CUPS
76 * update_lpd() - Update the LPD configuration as needed.
77 * update_polling() - Read status messages from the poll daemons.
78 * update_smb() - Update the SMB configuration as needed.
82 * Include necessary headers...
92 # ifdef HAVE_COREFOUNDATION
93 # include <CoreFoundation/CoreFoundation.h>
94 # endif /* HAVE_COREFOUNDATION */
95 # ifdef HAVE_SYSTEMCONFIGURATION
96 # include <SystemConfiguration/SystemConfiguration.h>
97 # endif /* HAVE_SYSTEMCONFIGURATION */
98 # endif /* __APPLE__ */
99 #endif /* HAVE_DNSSD */
106 static char *dequote(char *d
, const char *s
, int dlen
);
107 static char *get_auth_info_required(cupsd_printer_t
*p
, char *buffer
,
110 static int get_hostconfig(const char *name
);
111 #endif /* __APPLE__ */
112 static int is_local_queue(const char *uri
, char *host
, int hostlen
,
113 char *resource
, int resourcelen
);
114 static void process_browse_data(const char *uri
, const char *host
,
115 const char *resource
, cups_ptype_t type
,
116 ipp_pstate_t state
, const char *location
,
117 const char *info
, const char *make_model
,
118 int num_attrs
, cups_option_t
*attrs
);
119 static void process_implicit_classes(void);
120 static void send_cups_browse(cupsd_printer_t
*p
);
122 static LDAP
*ldap_connect(void);
123 static LDAP
*ldap_reconnect(void);
124 static void ldap_disconnect(LDAP
*ld
);
125 static int ldap_search_rec(LDAP
*ld
, char *base
, int scope
,
126 char *filter
, char *attrs
[],
127 int attrsonly
, LDAPMessage
**res
);
128 static int ldap_getval_firststring(LDAP
*ld
, LDAPMessage
*entry
,
129 char *attr
, char *retval
,
130 unsigned long maxsize
);
131 static void ldap_freeres(LDAPMessage
*entry
);
132 static void send_ldap_ou(char *ou
, char *basedn
, char *descstring
);
133 static void send_ldap_browse(cupsd_printer_t
*p
);
134 static void ldap_dereg_printer(cupsd_printer_t
*p
);
135 static void ldap_dereg_ou(char *ou
, char *basedn
);
136 # ifdef HAVE_LDAP_REBIND_PROC
137 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
138 static int ldap_rebind_proc(LDAP
*RebindLDAPHandle
,
139 LDAP_CONST
char *refsp
,
144 static int ldap_rebind_proc(LDAP
*RebindLDAPHandle
,
150 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
151 # endif /* HAVE_LDAP_REBIND_PROC */
152 #endif /* HAVE_LDAP */
154 static void send_slp_browse(cupsd_printer_t
*p
);
155 #endif /* HAVE_LIBSLP */
156 static void update_cups_browse(void);
157 static void update_lpd(int onoff
);
158 static void update_polling(void);
159 static void update_smb(int onoff
);
163 # ifdef HAVE_COREFOUNDATION
164 static void dnssdAddAlias(const void *key
, const void *value
,
166 # endif /* HAVE_COREFOUNDATION */
167 static char *dnssdBuildTxtRecord(int *txt_len
, cupsd_printer_t
*p
,
169 static int dnssdComparePrinters(cupsd_printer_t
*a
, cupsd_printer_t
*b
);
170 static void dnssdDeregisterPrinter(cupsd_printer_t
*p
);
171 static char *dnssdPackTxtRecord(int *txt_len
, char *keyvalue
[][2],
173 static void dnssdRegisterCallback(DNSServiceRef sdRef
,
174 DNSServiceFlags flags
,
175 DNSServiceErrorType errorCode
,
176 const char *name
, const char *regtype
,
177 const char *domain
, void *context
);
178 static void dnssdRegisterPrinter(cupsd_printer_t
*p
);
179 static void dnssdStop(void);
180 static void dnssdUpdate(void);
181 #endif /* HAVE_DNSSD */
184 static const char * const ldap_attrs
[] =/* CUPS LDAP attributes */
186 "printerDescription",
188 "printerMakeAndModel",
193 #endif /* HAVE_LDAP */
201 * SLP service name for CUPS...
204 # define SLP_CUPS_SRVTYPE "service:printer"
205 # define SLP_CUPS_SRVLEN 15
209 * Printer service URL structure
212 typedef struct _slpsrvurl_s
/**** SLP URL list ****/
214 struct _slpsrvurl_s
*next
; /* Next URL in list */
215 char url
[HTTP_MAX_URI
];
224 static SLPBoolean
slp_attr_callback(SLPHandle hslp
, const char *attrlist
,
225 SLPError errcode
, void *cookie
);
226 static void slp_dereg_printer(cupsd_printer_t
*p
);
227 static int slp_get_attr(const char *attrlist
, const char *tag
,
229 static void slp_reg_callback(SLPHandle hslp
, SLPError errcode
,
231 static SLPBoolean
slp_url_callback(SLPHandle hslp
, const char *srvurl
,
232 unsigned short lifetime
,
233 SLPError errcode
, void *cookie
);
234 #endif /* HAVE_LIBSLP */
238 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
239 * local printer and remove any pending
240 * references to remote printers.
244 cupsdDeregisterPrinter(
245 cupsd_printer_t
*p
, /* I - Printer to register */
246 int removeit
) /* I - Printer being permanently removed */
249 * Only deregister if browsing is enabled and it's a local printer...
252 cupsdLogMessage(CUPSD_LOG_DEBUG
,
253 "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p
, p
->name
,
256 if (!Browsing
|| !p
->shared
||
257 (p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
258 CUPS_PRINTER_SCANNER
)))
262 * Announce the deletion...
265 if ((BrowseLocalProtocols
& BROWSE_CUPS
) && BrowseSocket
>= 0)
267 cups_ptype_t savedtype
= p
->type
; /* Saved printer type */
269 p
->type
|= CUPS_PRINTER_DELETE
;
277 if (BrowseLocalProtocols
& BROWSE_SLP
)
278 slp_dereg_printer(p
);
279 #endif /* HAVE_LIBSLP */
282 if (BrowseLocalProtocols
& BROWSE_LDAP
)
283 ldap_dereg_printer(p
);
284 #endif /* HAVE_LDAP */
287 if (removeit
&& (BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDRef
)
288 dnssdDeregisterPrinter(p
);
289 #endif /* HAVE_DNSSD */
294 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
298 cupsdLoadRemoteCache(void)
300 int i
; /* Looping var */
301 cups_file_t
*fp
; /* remote.cache file */
302 int linenum
; /* Current line number */
303 char line
[4096], /* Line from file */
304 *value
, /* Pointer to value */
305 *valueptr
, /* Pointer into value */
306 scheme
[32], /* Scheme portion of URI */
307 username
[64], /* Username portion of URI */
309 /* Hostname portion of URI */
310 resource
[HTTP_MAX_URI
];
311 /* Resource portion of URI */
312 int port
; /* Port number */
313 cupsd_printer_t
*p
; /* Current printer */
314 time_t now
; /* Current time */
318 * Don't load the cache if the remote protocols are disabled...
323 cupsdLogMessage(CUPSD_LOG_DEBUG
,
324 "cupsdLoadRemoteCache: Not loading remote cache.");
329 * Open the remote.cache file...
332 snprintf(line
, sizeof(line
), "%s/remote.cache", CacheDir
);
333 if ((fp
= cupsdOpenConfFile(line
)) == NULL
)
337 * Read printer configurations until we hit EOF...
344 while (cupsFileGetConf(fp
, line
, sizeof(line
), &value
, &linenum
))
347 * Decode the directive...
350 if (!_cups_strcasecmp(line
, "<Printer") ||
351 !_cups_strcasecmp(line
, "<DefaultPrinter"))
354 * <Printer name> or <DefaultPrinter name>
357 if (p
== NULL
&& value
)
360 * Add the printer and a base file type...
363 cupsdLogMessage(CUPSD_LOG_DEBUG
,
364 "cupsdLoadRemoteCache: Loading printer %s...", value
);
366 if ((p
= cupsdFindDest(value
)) != NULL
)
368 if (p
->type
& CUPS_PRINTER_CLASS
)
370 cupsdLogMessage(CUPSD_LOG_WARN
,
371 "Cached remote printer \"%s\" conflicts with "
379 p
= cupsdAddPrinter(value
);
382 p
->state
= IPP_PRINTER_IDLE
;
383 p
->type
|= CUPS_PRINTER_REMOTE
| CUPS_PRINTER_DISCOVERED
;
384 p
->browse_time
= now
;
385 p
->browse_expire
= now
+ BrowseTimeout
;
388 * Set the default printer as needed...
391 if (!_cups_strcasecmp(line
, "<DefaultPrinter"))
396 cupsdLogMessage(CUPSD_LOG_ERROR
,
397 "Syntax error on line %d of remote.cache.", linenum
);
401 else if (!_cups_strcasecmp(line
, "<Class") ||
402 !_cups_strcasecmp(line
, "<DefaultClass"))
405 * <Class name> or <DefaultClass name>
408 if (p
== NULL
&& value
)
411 * Add the printer and a base file type...
414 cupsdLogMessage(CUPSD_LOG_DEBUG
,
415 "cupsdLoadRemoteCache: Loading class %s...", value
);
417 if ((p
= cupsdFindDest(value
)) != NULL
)
418 p
->type
= CUPS_PRINTER_CLASS
;
420 p
= cupsdAddClass(value
);
423 p
->state
= IPP_PRINTER_IDLE
;
424 p
->type
|= CUPS_PRINTER_REMOTE
| CUPS_PRINTER_DISCOVERED
;
425 p
->browse_time
= now
;
426 p
->browse_expire
= now
+ BrowseTimeout
;
429 * Set the default printer as needed...
432 if (!_cups_strcasecmp(line
, "<DefaultClass"))
437 cupsdLogMessage(CUPSD_LOG_ERROR
,
438 "Syntax error on line %d of remote.cache.", linenum
);
442 else if (!_cups_strcasecmp(line
, "</Printer>") ||
443 !_cups_strcasecmp(line
, "</Class>"))
448 * Close out the current printer...
451 cupsdSetPrinterAttrs(p
);
456 cupsdLogMessage(CUPSD_LOG_ERROR
,
457 "Syntax error on line %d of remote.cache.", linenum
);
461 cupsdLogMessage(CUPSD_LOG_ERROR
,
462 "Syntax error on line %d of remote.cache.", linenum
);
464 else if (!_cups_strcasecmp(line
, "UUID"))
466 if (value
&& !strncmp(value
, "urn:uuid:", 9))
467 cupsdSetString(&(p
->uuid
), value
);
469 cupsdLogMessage(CUPSD_LOG_ERROR
,
470 "Bad UUID on line %d of remote.cache.", linenum
);
472 else if (!_cups_strcasecmp(line
, "Info"))
475 cupsdSetString(&p
->info
, value
);
477 else if (!_cups_strcasecmp(line
, "MakeModel"))
480 cupsdSetString(&p
->make_model
, value
);
482 else if (!_cups_strcasecmp(line
, "Location"))
485 cupsdSetString(&p
->location
, value
);
487 else if (!_cups_strcasecmp(line
, "DeviceURI"))
491 httpSeparateURI(HTTP_URI_CODING_ALL
, value
, scheme
, sizeof(scheme
),
492 username
, sizeof(username
), host
, sizeof(host
), &port
,
493 resource
, sizeof(resource
));
495 cupsdSetString(&p
->hostname
, host
);
496 cupsdSetString(&p
->uri
, value
);
497 cupsdSetDeviceURI(p
, value
);
500 cupsdLogMessage(CUPSD_LOG_ERROR
,
501 "Syntax error on line %d of remote.cache.", linenum
);
503 else if (!_cups_strcasecmp(line
, "Option") && value
)
509 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
512 cupsdLogMessage(CUPSD_LOG_ERROR
,
513 "Syntax error on line %d of remote.cache.", linenum
);
516 for (; *valueptr
&& isspace(*valueptr
& 255); *valueptr
++ = '\0');
518 p
->num_options
= cupsAddOption(value
, valueptr
, p
->num_options
,
522 else if (!_cups_strcasecmp(line
, "Reason"))
526 for (i
= 0 ; i
< p
->num_reasons
; i
++)
527 if (!strcmp(value
, p
->reasons
[i
]))
530 if (i
>= p
->num_reasons
&&
531 p
->num_reasons
< (int)(sizeof(p
->reasons
) / sizeof(p
->reasons
[0])))
533 p
->reasons
[p
->num_reasons
] = _cupsStrAlloc(value
);
538 cupsdLogMessage(CUPSD_LOG_ERROR
,
539 "Syntax error on line %d of remote.cache.", linenum
);
541 else if (!_cups_strcasecmp(line
, "State"))
544 * Set the initial queue state...
547 if (value
&& !_cups_strcasecmp(value
, "idle"))
548 p
->state
= IPP_PRINTER_IDLE
;
549 else if (value
&& !_cups_strcasecmp(value
, "stopped"))
551 p
->state
= IPP_PRINTER_STOPPED
;
552 cupsdSetPrinterReasons(p
, "+paused");
555 cupsdLogMessage(CUPSD_LOG_ERROR
,
556 "Syntax error on line %d of remote.cache.", linenum
);
558 else if (!_cups_strcasecmp(line
, "StateMessage"))
561 * Set the initial queue state message...
565 strlcpy(p
->state_message
, value
, sizeof(p
->state_message
));
567 else if (!_cups_strcasecmp(line
, "Accepting"))
570 * Set the initial accepting state...
574 (!_cups_strcasecmp(value
, "yes") ||
575 !_cups_strcasecmp(value
, "on") ||
576 !_cups_strcasecmp(value
, "true")))
579 (!_cups_strcasecmp(value
, "no") ||
580 !_cups_strcasecmp(value
, "off") ||
581 !_cups_strcasecmp(value
, "false")))
584 cupsdLogMessage(CUPSD_LOG_ERROR
,
585 "Syntax error on line %d of remote.cache.", linenum
);
587 else if (!_cups_strcasecmp(line
, "Type"))
590 p
->type
= atoi(value
);
592 cupsdLogMessage(CUPSD_LOG_ERROR
,
593 "Syntax error on line %d of remote.cache.", linenum
);
595 else if (!_cups_strcasecmp(line
, "BrowseTime"))
599 time_t t
= atoi(value
);
601 if (t
> p
->browse_expire
)
602 p
->browse_expire
= t
;
605 cupsdLogMessage(CUPSD_LOG_ERROR
,
606 "Syntax error on line %d of remote.cache.", linenum
);
608 else if (!_cups_strcasecmp(line
, "JobSheets"))
611 * Set the initial job sheets...
616 for (valueptr
= value
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
621 cupsdSetString(&p
->job_sheets
[0], value
);
623 while (isspace(*valueptr
& 255))
628 for (value
= valueptr
; *valueptr
&& !isspace(*valueptr
& 255); valueptr
++);
633 cupsdSetString(&p
->job_sheets
[1], value
);
637 cupsdLogMessage(CUPSD_LOG_ERROR
,
638 "Syntax error on line %d of remote.cache.", linenum
);
640 else if (!_cups_strcasecmp(line
, "AllowUser"))
645 cupsdAddString(&(p
->users
), value
);
648 cupsdLogMessage(CUPSD_LOG_ERROR
,
649 "Syntax error on line %d of remote.cache.", linenum
);
651 else if (!_cups_strcasecmp(line
, "DenyUser"))
656 cupsdAddString(&(p
->users
), value
);
659 cupsdLogMessage(CUPSD_LOG_ERROR
,
660 "Syntax error on line %d of remote.cache.", linenum
);
665 * Something else we don't understand...
668 cupsdLogMessage(CUPSD_LOG_ERROR
,
669 "Unknown configuration directive %s on line %d of remote.cache.",
677 * Do auto-classing if needed...
680 process_implicit_classes();
685 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
686 * printer or update the broadcast contents.
690 cupsdRegisterPrinter(cupsd_printer_t
*p
)/* I - Printer */
692 cupsdLogMessage(CUPSD_LOG_DEBUG
, "cupsdRegisterPrinter(p=%p(%s))", p
,
695 if (!Browsing
|| !BrowseLocalProtocols
||
696 (p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
697 CUPS_PRINTER_SCANNER
)))
701 /* if (BrowseLocalProtocols & BROWSE_SLP)
702 slpRegisterPrinter(p); */
703 #endif /* HAVE_LIBSLP */
706 if ((BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDRef
)
707 dnssdRegisterPrinter(p
);
708 #endif /* HAVE_DNSSD */
713 * 'cupsdRestartPolling()' - Restart polling servers as needed.
717 cupsdRestartPolling(void)
719 int i
; /* Looping var */
720 cupsd_dirsvc_poll_t
*pollp
; /* Current polling server */
723 for (i
= 0, pollp
= Polled
; i
< NumPolled
; i
++, pollp
++)
725 kill(pollp
->pid
, SIGHUP
);
730 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
734 cupsdSaveRemoteCache(void)
736 int i
; /* Looping var */
737 cups_file_t
*fp
; /* remote.cache file */
738 char filename
[1024], /* remote.cache filename */
739 temp
[1024], /* Temporary string */
740 value
[2048], /* Value string */
741 *name
; /* Current user name */
742 cupsd_printer_t
*printer
; /* Current printer class */
743 time_t curtime
; /* Current time */
744 struct tm
*curdate
; /* Current date */
745 cups_option_t
*option
; /* Current option */
749 * Create the remote.cache file...
752 snprintf(filename
, sizeof(filename
), "%s/remote.cache", CacheDir
);
754 if ((fp
= cupsdCreateConfFile(filename
, ConfigFilePerm
)) == NULL
)
757 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Saving remote.cache...");
760 * Write a small header to the file...
763 curtime
= time(NULL
);
764 curdate
= localtime(&curtime
);
765 strftime(temp
, sizeof(temp
) - 1, "%Y-%m-%d %H:%M", curdate
);
767 cupsFilePuts(fp
, "# Remote cache file for " CUPS_SVERSION
"\n");
768 cupsFilePrintf(fp
, "# Written by cupsd on %s\n", temp
);
771 * Write each local printer known to the system...
774 for (printer
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
776 printer
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
779 * Skip local destinations...
782 if (!(printer
->type
& CUPS_PRINTER_DISCOVERED
))
786 * Write printers as needed...
789 if (printer
== DefaultPrinter
)
790 cupsFilePuts(fp
, "<Default");
792 cupsFilePutChar(fp
, '<');
794 if (printer
->type
& CUPS_PRINTER_CLASS
)
795 cupsFilePrintf(fp
, "Class %s>\n", printer
->name
);
797 cupsFilePrintf(fp
, "Printer %s>\n", printer
->name
);
799 cupsFilePrintf(fp
, "BrowseTime %d\n", (int)printer
->browse_expire
);
801 cupsFilePrintf(fp
, "UUID %s\n", printer
->uuid
);
804 cupsFilePutConf(fp
, "Info", printer
->info
);
806 if (printer
->location
)
807 cupsFilePutConf(fp
, "Location", printer
->location
);
809 if (printer
->make_model
)
810 cupsFilePutConf(fp
, "MakeModel", printer
->make_model
);
812 cupsFilePutConf(fp
, "DeviceURI", printer
->device_uri
);
814 if (printer
->state
== IPP_PRINTER_STOPPED
)
815 cupsFilePuts(fp
, "State Stopped\n");
817 cupsFilePuts(fp
, "State Idle\n");
819 for (i
= 0; i
< printer
->num_reasons
; i
++)
820 cupsFilePutConf(fp
, "Reason", printer
->reasons
[i
]);
822 cupsFilePrintf(fp
, "Type %d\n", printer
->type
);
824 if (printer
->accepting
)
825 cupsFilePuts(fp
, "Accepting Yes\n");
827 cupsFilePuts(fp
, "Accepting No\n");
829 snprintf(value
, sizeof(value
), "%s %s", printer
->job_sheets
[0],
830 printer
->job_sheets
[1]);
831 cupsFilePutConf(fp
, "JobSheets", value
);
833 for (name
= (char *)cupsArrayFirst(printer
->users
);
835 name
= (char *)cupsArrayNext(printer
->users
))
836 cupsFilePutConf(fp
, printer
->deny_users
? "DenyUser" : "AllowUser", name
);
838 for (i
= printer
->num_options
, option
= printer
->options
;
842 snprintf(value
, sizeof(value
), "%s %s", option
->name
, option
->value
);
843 cupsFilePutConf(fp
, "Option", value
);
846 if (printer
->type
& CUPS_PRINTER_CLASS
)
847 cupsFilePuts(fp
, "</Class>\n");
849 cupsFilePuts(fp
, "</Printer>\n");
852 cupsdCloseCreatedConfFile(fp
, filename
);
857 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
861 cupsdSendBrowseList(void)
863 int count
; /* Number of dests to update */
864 cupsd_printer_t
*p
; /* Current printer */
865 time_t ut
, /* Minimum update time */
866 to
; /* Timeout time */
869 if (!Browsing
|| !Printers
)
873 * Compute the update and timeout times...
877 ut
= to
- BrowseInterval
;
880 * Figure out how many printers need an update...
883 if (BrowseInterval
> 0 && BrowseLocalProtocols
)
885 int max_count
; /* Maximum number to update */
889 * Throttle the number of printers we'll be updating this time
890 * around based on the number of queues that need updating and
891 * the maximum number of queues to update each second...
894 max_count
= 2 * cupsArrayCount(Printers
) / BrowseInterval
+ 1;
896 for (count
= 0, p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
897 count
< max_count
&& p
!= NULL
;
898 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
899 if (!(p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
900 CUPS_PRINTER_SCANNER
)) &&
901 p
->shared
&& p
->browse_time
< ut
)
905 * Loop through all of the printers and send local updates as needed...
909 p
= (cupsd_printer_t
*)cupsArrayFind(Printers
, BrowseNext
);
911 p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
915 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
918 * Check for wraparound...
922 p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
926 else if ((p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
927 CUPS_PRINTER_SCANNER
)) ||
930 else if (p
->browse_time
< ut
)
933 * Need to send an update...
938 p
->browse_time
= time(NULL
);
940 if ((BrowseLocalProtocols
& BROWSE_CUPS
) && BrowseSocket
>= 0)
944 if (BrowseLocalProtocols
& BROWSE_SLP
)
946 #endif /* HAVE_LIBSLP */
949 if (BrowseLocalProtocols
& BROWSE_LDAP
)
951 #endif /* HAVE_LDAP */
956 * Save where we left off so that all printers get updated...
963 * Loop through all of the printers and timeout old printers as needed...
966 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
968 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
971 * If this is a remote queue, see if it needs to be timed out...
974 if ((p
->type
& CUPS_PRINTER_DISCOVERED
) &&
975 !(p
->type
& CUPS_PRINTER_IMPLICIT
) &&
976 p
->browse_expire
< to
)
978 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, p
, NULL
,
979 "%s \'%s\' deleted by directory services (timeout).",
980 (p
->type
& CUPS_PRINTER_CLASS
) ? "Class" : "Printer",
983 cupsdLogMessage(CUPSD_LOG_DEBUG
,
984 "Remote destination \"%s\" has timed out; "
988 cupsArraySave(Printers
);
989 cupsdDeletePrinter(p
, 1);
990 cupsArrayRestore(Printers
);
991 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
| CUPSD_DIRTY_REMOTE
);
997 #ifdef HAVE_LDAP_REBIND_PROC
998 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1000 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
1003 static int /* O - Result code */
1005 LDAP
*RebindLDAPHandle
, /* I - LDAP handle */
1006 LDAP_CONST
char *refsp
, /* I - ??? */
1007 ber_tag_t request
, /* I - ??? */
1008 ber_int_t msgid
, /* I - ??? */
1009 void *params
) /* I - ??? */
1011 int rc
; /* Result code */
1012 # if LDAP_API_VERSION > 3000
1013 struct berval bval
; /* Bind value */
1014 # endif /* LDAP_API_VERSION > 3000 */
1022 * Bind to new LDAP server...
1025 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_rebind_proc: Rebind to %s", refsp
);
1027 # if LDAP_API_VERSION > 3000
1028 bval
.bv_val
= BrowseLDAPPassword
;
1029 bval
.bv_len
= (BrowseLDAPPassword
== NULL
) ? 0 : strlen(BrowseLDAPPassword
);
1031 rc
= ldap_sasl_bind_s(RebindLDAPHandle
, BrowseLDAPBindDN
, LDAP_SASL_SIMPLE
,
1032 &bval
, NULL
, NULL
, NULL
);
1034 rc
= ldap_bind_s(RebindLDAPHandle
, BrowseLDAPBindDN
, BrowseLDAPPassword
,
1036 # endif /* LDAP_API_VERSION > 3000 */
1042 # else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1044 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
1047 static int /* O - Result code */
1049 LDAP
*RebindLDAPHandle
, /* I - LDAP handle */
1050 char **dnp
, /* I - ??? */
1051 char **passwdp
, /* I - ??? */
1052 int *authmethodp
, /* I - ??? */
1053 int freeit
, /* I - ??? */
1054 void *arg
) /* I - ??? */
1060 * Free current values...
1063 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_rebind_proc: Free values...");
1068 if (passwdp
&& *passwdp
)
1074 * Return credentials for LDAP referal...
1077 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
1078 "ldap_rebind_proc: Return necessary values...");
1080 *dnp
= strdup(BrowseLDAPBindDN
);
1081 *passwdp
= strdup(BrowseLDAPPassword
);
1082 *authmethodp
= LDAP_AUTH_SIMPLE
;
1087 * Should never happen...
1090 cupsdLogMessage(CUPSD_LOG_ERROR
,
1091 "LDAP rebind has been called with wrong freeit value!");
1095 return (LDAP_SUCCESS
);
1097 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1098 #endif /* HAVE_LDAP_REBIND_PROC */
1103 * 'ldap_connect()' - Start new LDAP connection
1106 static LDAP
* /* O - LDAP handle */
1109 int rc
; /* LDAP API status */
1110 int version
= 3; /* LDAP version */
1111 struct berval bv
= {0, ""}; /* SASL bind value */
1112 LDAP
*TempBrowseLDAPHandle
=NULL
;
1113 /* Temporary LDAP Handle */
1114 # if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1115 int ldap_ssl
= 0; /* LDAP SSL indicator */
1116 int ssl_err
= 0; /* LDAP SSL error value */
1117 # endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1120 # ifdef HAVE_OPENLDAP
1121 # ifdef HAVE_LDAP_SSL
1123 * Set the certificate file to use for encrypted LDAP sessions...
1126 if (BrowseLDAPCACertFile
)
1128 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1129 "ldap_connect: Setting CA certificate file \"%s\"",
1130 BrowseLDAPCACertFile
);
1132 if ((rc
= ldap_set_option(NULL
, LDAP_OPT_X_TLS_CACERTFILE
,
1133 (void *)BrowseLDAPCACertFile
)) != LDAP_SUCCESS
)
1134 cupsdLogMessage(CUPSD_LOG_ERROR
,
1135 "Unable to set CA certificate file for LDAP "
1136 "connections: %d - %s", rc
, ldap_err2string(rc
));
1138 # endif /* HAVE_LDAP_SSL */
1141 * Initialize OPENLDAP connection...
1142 * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1145 if (!BrowseLDAPServer
|| !_cups_strcasecmp(BrowseLDAPServer
, "localhost"))
1146 rc
= ldap_initialize(&TempBrowseLDAPHandle
, "ldapi:///");
1148 rc
= ldap_initialize(&TempBrowseLDAPHandle
, BrowseLDAPServer
);
1150 # else /* HAVE_OPENLDAP */
1152 int ldap_port
= 0; /* LDAP port */
1153 char ldap_protocol
[11], /* LDAP protocol */
1154 ldap_host
[255]; /* LDAP host */
1157 * Split LDAP URI into its components...
1160 if (!BrowseLDAPServer
)
1162 cupsdLogMessage(CUPSD_LOG_ERROR
, "BrowseLDAPServer not configured!");
1163 cupsdLogMessage(CUPSD_LOG_ERROR
, "Disabling LDAP browsing!");
1164 BrowseLocalProtocols
&= ~BROWSE_LDAP
;
1165 BrowseRemoteProtocols
&= ~BROWSE_LDAP
;
1169 sscanf(BrowseLDAPServer
, "%10[^:]://%254[^:/]:%d", ldap_protocol
, ldap_host
,
1172 if (!strcmp(ldap_protocol
, "ldap"))
1174 else if (!strcmp(ldap_protocol
, "ldaps"))
1178 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unrecognized LDAP protocol (%s)!",
1180 cupsdLogMessage(CUPSD_LOG_ERROR
, "Disabling LDAP browsing!");
1181 BrowseLocalProtocols
&= ~BROWSE_LDAP
;
1182 BrowseRemoteProtocols
&= ~BROWSE_LDAP
;
1189 ldap_port
= LDAPS_PORT
;
1191 ldap_port
= LDAP_PORT
;
1194 cupsdLogMessage(CUPSD_LOG_DEBUG
, "ldap_connect: PROT:%s HOST:%s PORT:%d",
1195 ldap_protocol
, ldap_host
, ldap_port
);
1198 * Initialize LDAP connection...
1203 if ((TempBrowseLDAPHandle
= ldap_init(ldap_host
, ldap_port
)) == NULL
)
1204 rc
= LDAP_OPERATIONS_ERROR
;
1208 # ifdef HAVE_LDAP_SSL
1213 * Initialize SSL LDAP connection...
1216 if (BrowseLDAPCACertFile
)
1218 rc
= ldapssl_client_init(BrowseLDAPCACertFile
, (void *)NULL
);
1219 if (rc
!= LDAP_SUCCESS
)
1221 cupsdLogMessage(CUPSD_LOG_ERROR
,
1222 "Failed to initialize LDAP SSL client!");
1223 rc
= LDAP_OPERATIONS_ERROR
;
1227 if ((TempBrowseLDAPHandle
= ldapssl_init(ldap_host
, ldap_port
,
1229 rc
= LDAP_OPERATIONS_ERROR
;
1236 cupsdLogMessage(CUPSD_LOG_ERROR
,
1237 "LDAP SSL certificate file/database not configured!");
1238 rc
= LDAP_OPERATIONS_ERROR
;
1241 # else /* HAVE_LDAP_SSL */
1244 * Return error, because client libraries doesn't support SSL
1247 cupsdLogMessage(CUPSD_LOG_ERROR
,
1248 "LDAP client libraries do not support SSL");
1249 rc
= LDAP_OPERATIONS_ERROR
;
1251 # endif /* HAVE_LDAP_SSL */
1253 # endif /* HAVE_OPENLDAP */
1256 * Check return code from LDAP initialize...
1259 if (rc
!= LDAP_SUCCESS
)
1261 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to initialize LDAP!");
1263 if (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
)
1264 cupsdLogMessage(CUPSD_LOG_ERROR
, "Temporarily disabling LDAP browsing...");
1267 cupsdLogMessage(CUPSD_LOG_ERROR
, "Disabling LDAP browsing!");
1269 BrowseLocalProtocols
&= ~BROWSE_LDAP
;
1270 BrowseRemoteProtocols
&= ~BROWSE_LDAP
;
1273 ldap_disconnect(TempBrowseLDAPHandle
);
1279 * Upgrade LDAP version...
1282 if (ldap_set_option(TempBrowseLDAPHandle
, LDAP_OPT_PROTOCOL_VERSION
,
1283 (const void *)&version
) != LDAP_SUCCESS
)
1285 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to set LDAP protocol version %d!",
1287 cupsdLogMessage(CUPSD_LOG_ERROR
, "Disabling LDAP browsing!");
1289 BrowseLocalProtocols
&= ~BROWSE_LDAP
;
1290 BrowseRemoteProtocols
&= ~BROWSE_LDAP
;
1291 ldap_disconnect(TempBrowseLDAPHandle
);
1297 * Register LDAP rebind procedure...
1300 # ifdef HAVE_LDAP_REBIND_PROC
1301 # if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1303 rc
= ldap_set_rebind_proc(TempBrowseLDAPHandle
, &ldap_rebind_proc
,
1305 if (rc
!= LDAP_SUCCESS
)
1306 cupsdLogMessage(CUPSD_LOG_ERROR
,
1307 "Setting LDAP rebind function failed with status %d: %s",
1308 rc
, ldap_err2string(rc
));
1312 ldap_set_rebind_proc(TempBrowseLDAPHandle
, &ldap_rebind_proc
, (void *)NULL
);
1314 # endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1315 # endif /* HAVE_LDAP_REBIND_PROC */
1318 * Start LDAP bind...
1321 # if LDAP_API_VERSION > 3000
1323 bval
.bv_val
= BrowseLDAPPassword
;
1324 bval
.bv_len
= (BrowseLDAPPassword
== NULL
) ? 0 : strlen(BrowseLDAPPassword
);
1326 if (!BrowseLDAPServer
|| !_cups_strcasecmp(BrowseLDAPServer
, "localhost"))
1327 rc
= ldap_sasl_bind_s(TempBrowseLDAPHandle
, NULL
, "EXTERNAL", &bv
, NULL
,
1330 rc
= ldap_sasl_bind_s(TempBrowseLDAPHandle
, BrowseLDAPBindDN
, LDAP_SASL_SIMPLE
, &bval
, NULL
, NULL
, NULL
);
1333 rc
= ldap_bind_s(TempBrowseLDAPHandle
, BrowseLDAPBindDN
,
1334 BrowseLDAPPassword
, LDAP_AUTH_SIMPLE
);
1335 # endif /* LDAP_API_VERSION > 3000 */
1337 if (rc
!= LDAP_SUCCESS
)
1339 cupsdLogMessage(CUPSD_LOG_ERROR
, "LDAP bind failed with error %d: %s",
1340 rc
, ldap_err2string(rc
));
1342 # if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1343 if (ldap_ssl
&& (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
))
1345 ssl_err
= PORT_GetError();
1347 cupsdLogMessage(CUPSD_LOG_ERROR
, "LDAP SSL error %d: %s", ssl_err
,
1348 ldapssl_err2string(ssl_err
));
1350 # endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1352 ldap_disconnect(TempBrowseLDAPHandle
);
1357 cupsdLogMessage(CUPSD_LOG_INFO
, "LDAP connection established");
1359 return (TempBrowseLDAPHandle
);
1364 * 'ldap_reconnect()' - Reconnect to LDAP Server
1367 static LDAP
* /* O - New LDAP handle */
1368 ldap_reconnect(void)
1370 LDAP
*TempBrowseLDAPHandle
= NULL
; /* Temp Handle to LDAP server */
1374 * Get a new LDAP Handle and replace the global Handle
1375 * if the new connection was successful.
1378 cupsdLogMessage(CUPSD_LOG_INFO
, "Try LDAP reconnect...");
1380 TempBrowseLDAPHandle
= ldap_connect();
1382 if (TempBrowseLDAPHandle
!= NULL
)
1384 if (BrowseLDAPHandle
!= NULL
)
1385 ldap_disconnect(BrowseLDAPHandle
);
1387 BrowseLDAPHandle
= TempBrowseLDAPHandle
;
1390 return (BrowseLDAPHandle
);
1395 * 'ldap_disconnect()' - Disconnect from LDAP Server
1399 ldap_disconnect(LDAP
*ld
) /* I - LDAP handle */
1401 int rc
; /* Return code */
1405 * Close LDAP handle...
1408 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
1409 rc
= ldap_unbind_ext_s(ld
, NULL
, NULL
);
1411 rc
= ldap_unbind_s(ld
);
1412 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
1414 if (rc
!= LDAP_SUCCESS
)
1415 cupsdLogMessage(CUPSD_LOG_ERROR
,
1416 "Unbind from LDAP server failed with status %d: %s",
1417 rc
, ldap_err2string(rc
));
1419 #endif /* HAVE_LDAP */
1423 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
1427 cupsdStartBrowsing(void)
1429 int val
; /* Socket option value */
1430 struct sockaddr_in addr
; /* Broadcast address */
1431 cupsd_printer_t
*p
; /* Current printer */
1436 if (!Browsing
|| !(BrowseLocalProtocols
| BrowseRemoteProtocols
))
1439 if ((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_CUPS
)
1441 if (BrowseSocket
< 0)
1444 * Create the broadcast socket...
1447 if ((BrowseSocket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
1449 cupsdLogMessage(CUPSD_LOG_ERROR
,
1450 "Unable to create broadcast socket - %s.",
1452 BrowseLocalProtocols
&= ~BROWSE_CUPS
;
1453 BrowseRemoteProtocols
&= ~BROWSE_CUPS
;
1455 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1456 cupsdEndProcess(getpid(), 0);
1460 if (BrowseSocket
>= 0)
1463 * Bind the socket to browse port...
1466 memset(&addr
, 0, sizeof(addr
));
1467 addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
1468 addr
.sin_family
= AF_INET
;
1469 addr
.sin_port
= htons(BrowsePort
);
1471 if (bind(BrowseSocket
, (struct sockaddr
*)&addr
, sizeof(addr
)))
1473 cupsdLogMessage(CUPSD_LOG_ERROR
,
1474 "Unable to bind broadcast socket - %s.",
1478 closesocket(BrowseSocket
);
1480 close(BrowseSocket
);
1484 BrowseLocalProtocols
&= ~BROWSE_CUPS
;
1485 BrowseRemoteProtocols
&= ~BROWSE_CUPS
;
1487 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1488 cupsdEndProcess(getpid(), 0);
1492 if (BrowseSocket
>= 0)
1495 * Set the "broadcast" flag...
1499 if (setsockopt(BrowseSocket
, SOL_SOCKET
, SO_BROADCAST
, &val
, sizeof(val
)))
1501 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to set broadcast mode - %s.",
1505 closesocket(BrowseSocket
);
1507 close(BrowseSocket
);
1511 BrowseLocalProtocols
&= ~BROWSE_CUPS
;
1512 BrowseRemoteProtocols
&= ~BROWSE_CUPS
;
1514 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1515 cupsdEndProcess(getpid(), 0);
1519 if (BrowseSocket
>= 0)
1522 * Close the socket on exec...
1525 fcntl(BrowseSocket
, F_SETFD
, fcntl(BrowseSocket
, F_GETFD
) | FD_CLOEXEC
);
1528 * Finally, add the socket to the input selection set as needed...
1531 if (BrowseRemoteProtocols
& BROWSE_CUPS
)
1534 * We only listen if we want remote printers...
1537 cupsdAddSelect(BrowseSocket
, (cupsd_selfunc_t
)update_cups_browse
,
1546 if ((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_DNSSD
)
1548 DNSServiceErrorType error
; /* Error from service creation */
1549 cupsd_listener_t
*lis
; /* Current listening socket */
1553 * First create a "master" connection for all registrations...
1556 if ((error
= DNSServiceCreateConnection(&DNSSDRef
))
1557 != kDNSServiceErr_NoError
)
1559 cupsdLogMessage(CUPSD_LOG_ERROR
,
1560 "Unable to create master DNS-SD reference: %d", error
);
1562 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1563 cupsdEndProcess(getpid(), 0);
1568 * Add the master connection to the select list...
1571 int fd
= DNSServiceRefSockFD(DNSSDRef
);
1573 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
1575 cupsdAddSelect(fd
, (cupsd_selfunc_t
)dnssdUpdate
, NULL
, NULL
);
1578 * Then get the port we use for registrations. If we are not listening
1579 * on any non-local ports, there is no sense sharing local printers via
1585 for (lis
= (cupsd_listener_t
*)cupsArrayFirst(Listeners
);
1587 lis
= (cupsd_listener_t
*)cupsArrayNext(Listeners
))
1589 if (httpAddrLocalhost(&(lis
->address
)))
1592 DNSSDPort
= _httpAddrPort(&(lis
->address
));
1597 * Create an array to track the printers we share...
1600 if (BrowseRemoteProtocols
& BROWSE_DNSSD
)
1601 DNSSDPrinters
= cupsArrayNew((cups_array_func_t
)dnssdComparePrinters
,
1605 * Set the computer name and register the web interface...
1608 cupsdUpdateDNSSDName();
1611 #endif /* HAVE_DNSSD */
1614 if ((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_SLP
)
1617 * Open SLP handle...
1620 if (SLPOpen("en", SLP_FALSE
, &BrowseSLPHandle
) != SLP_OK
)
1622 cupsdLogMessage(CUPSD_LOG_ERROR
,
1623 "Unable to open an SLP handle; disabling SLP browsing!");
1624 BrowseLocalProtocols
&= ~BROWSE_SLP
;
1625 BrowseRemoteProtocols
&= ~BROWSE_SLP
;
1626 BrowseSLPHandle
= NULL
;
1628 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1629 cupsdEndProcess(getpid(), 0);
1632 BrowseSLPRefresh
= 0;
1635 BrowseSLPHandle
= NULL
;
1636 #endif /* HAVE_LIBSLP */
1639 if ((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_LDAP
)
1643 cupsdLogMessage(CUPSD_LOG_ERROR
,
1644 "Need to set BrowseLDAPDN to use LDAP browsing!");
1645 BrowseLocalProtocols
&= ~BROWSE_LDAP
;
1646 BrowseRemoteProtocols
&= ~BROWSE_LDAP
;
1648 if (FatalErrors
& CUPSD_FATAL_BROWSE
)
1649 cupsdEndProcess(getpid(), 0);
1654 * Open LDAP handle...
1657 if ((BrowseLDAPHandle
= ldap_connect()) == NULL
&&
1658 (FatalErrors
& CUPSD_FATAL_BROWSE
))
1659 cupsdEndProcess(getpid(), 0);
1662 BrowseLDAPRefresh
= 0;
1664 #endif /* HAVE_LDAP */
1667 * Enable LPD and SMB printer sharing as needed through external programs...
1670 if (BrowseLocalProtocols
& BROWSE_LPD
)
1673 if (BrowseLocalProtocols
& BROWSE_SMB
)
1677 * Register the individual printers
1680 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1682 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1683 if (!(p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
1684 CUPS_PRINTER_SCANNER
)))
1685 cupsdRegisterPrinter(p
);
1690 * 'cupsdStartPolling()' - Start polling servers as needed.
1694 cupsdStartPolling(void)
1696 int i
; /* Looping var */
1697 cupsd_dirsvc_poll_t
*pollp
; /* Current polling server */
1698 char polld
[1024]; /* Poll daemon path */
1699 char sport
[255]; /* Server port */
1700 char bport
[255]; /* Browser port */
1701 char interval
[255]; /* Poll interval */
1702 int statusfds
[2]; /* Status pipe */
1703 char *argv
[6]; /* Arguments */
1704 char *envp
[100]; /* Environment */
1708 * Don't do anything if we aren't polling...
1711 if (NumPolled
== 0 || BrowseSocket
< 0)
1714 PollStatusBuffer
= NULL
;
1719 * Setup string arguments for polld, port and interval options.
1722 snprintf(polld
, sizeof(polld
), "%s/daemon/cups-polld", ServerBin
);
1724 sprintf(bport
, "%d", BrowsePort
);
1727 sprintf(interval
, "%d", BrowseInterval
);
1729 strcpy(interval
, "30");
1731 argv
[0] = "cups-polld";
1737 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
1740 * Create a pipe that receives the status messages from each
1744 if (cupsdOpenPipe(statusfds
))
1746 cupsdLogMessage(CUPSD_LOG_ERROR
,
1747 "Unable to create polling status pipes - %s.",
1750 PollStatusBuffer
= NULL
;
1754 PollPipe
= statusfds
[0];
1755 PollStatusBuffer
= cupsdStatBufNew(PollPipe
, "[Poll]");
1758 * Run each polling daemon, redirecting stderr to the polling pipe...
1761 for (i
= 0, pollp
= Polled
; i
< NumPolled
; i
++, pollp
++)
1763 sprintf(sport
, "%d", pollp
->port
);
1765 argv
[1] = pollp
->hostname
;
1767 if (cupsdStartProcess(polld
, argv
, envp
, -1, -1, statusfds
[1], -1, -1,
1768 0, DefaultProfile
, NULL
, &(pollp
->pid
)) < 0)
1770 cupsdLogMessage(CUPSD_LOG_ERROR
,
1771 "cupsdStartPolling: Unable to fork polling daemon - %s",
1777 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1778 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1779 pollp
->hostname
, pollp
->port
, pollp
->pid
);
1782 close(statusfds
[1]);
1785 * Finally, add the pipe to the input selection set...
1788 cupsdAddSelect(PollPipe
, (cupsd_selfunc_t
)update_polling
, NULL
, NULL
);
1793 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1797 cupsdStopBrowsing(void)
1799 cupsd_printer_t
*p
; /* Current printer */
1802 if (!Browsing
|| !(BrowseLocalProtocols
| BrowseRemoteProtocols
))
1806 * De-register the individual printers
1809 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
1811 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
1812 if (!(p
->type
& (CUPS_PRINTER_REMOTE
| CUPS_PRINTER_IMPLICIT
|
1813 CUPS_PRINTER_SCANNER
)))
1814 cupsdDeregisterPrinter(p
, 1);
1817 * Shut down browsing sockets...
1820 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_CUPS
) &&
1824 * Close the socket and remove it from the input selection set.
1828 closesocket(BrowseSocket
);
1830 close(BrowseSocket
);
1833 cupsdRemoveSelect(BrowseSocket
);
1838 if ((BrowseLocalProtocols
& BROWSE_DNSSD
) && DNSSDRef
)
1840 #endif /* HAVE_DNSSD */
1843 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_SLP
) &&
1847 * Close SLP handle...
1850 SLPClose(BrowseSLPHandle
);
1851 BrowseSLPHandle
= NULL
;
1853 #endif /* HAVE_LIBSLP */
1856 if (((BrowseLocalProtocols
| BrowseRemoteProtocols
) & BROWSE_LDAP
) &&
1859 ldap_dereg_ou(ServerName
, BrowseLDAPDN
);
1860 ldap_disconnect(BrowseLDAPHandle
);
1861 BrowseLDAPHandle
= NULL
;
1863 #endif /* HAVE_OPENLDAP */
1866 * Disable LPD and SMB printer sharing as needed through external programs...
1869 if (BrowseLocalProtocols
& BROWSE_LPD
)
1872 if (BrowseLocalProtocols
& BROWSE_SMB
)
1878 * 'cupsdStopPolling()' - Stop polling servers as needed.
1882 cupsdStopPolling(void)
1884 int i
; /* Looping var */
1885 cupsd_dirsvc_poll_t
*pollp
; /* Current polling server */
1890 cupsdStatBufDelete(PollStatusBuffer
);
1893 cupsdRemoveSelect(PollPipe
);
1896 PollStatusBuffer
= NULL
;
1899 for (i
= 0, pollp
= Polled
; i
< NumPolled
; i
++, pollp
++)
1901 cupsdEndProcess(pollp
->pid
, 0);
1907 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1911 cupsdUpdateDNSSDName(void)
1913 DNSServiceErrorType error
; /* Error from service creation */
1914 char webif
[1024]; /* Web interface share name */
1915 # ifdef HAVE_SYSTEMCONFIGURATION
1916 SCDynamicStoreRef sc
; /* Context for dynamic store */
1917 CFDictionaryRef btmm
; /* Back-to-My-Mac domains */
1918 CFStringEncoding nameEncoding
; /* Encoding of computer name */
1919 CFStringRef nameRef
; /* Host name CFString */
1920 char nameBuffer
[1024]; /* C-string buffer */
1921 # endif /* HAVE_SYSTEMCONFIGURATION */
1925 * Only share the web interface and printers when non-local listening is
1934 * Get the computer name as a c-string...
1937 # ifdef HAVE_SYSTEMCONFIGURATION
1938 sc
= SCDynamicStoreCreate(kCFAllocatorDefault
, CFSTR("cupsd"), NULL
, NULL
);
1943 * Get the computer name from the dynamic store...
1946 cupsdClearString(&DNSSDComputerName
);
1948 if ((nameRef
= SCDynamicStoreCopyComputerName(sc
, &nameEncoding
)) != NULL
)
1950 if (CFStringGetCString(nameRef
, nameBuffer
, sizeof(nameBuffer
),
1951 kCFStringEncodingUTF8
))
1953 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1954 "Dynamic store computer name is \"%s\".", nameBuffer
);
1955 cupsdSetString(&DNSSDComputerName
, nameBuffer
);
1961 if (!DNSSDComputerName
)
1964 * Use the ServerName instead...
1967 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1968 "Using ServerName \"%s\" as computer name.", ServerName
);
1969 cupsdSetString(&DNSSDComputerName
, ServerName
);
1973 * Get the local hostname from the dynamic store...
1976 cupsdClearString(&DNSSDHostName
);
1978 if ((nameRef
= SCDynamicStoreCopyLocalHostName(sc
)) != NULL
)
1980 if (CFStringGetCString(nameRef
, nameBuffer
, sizeof(nameBuffer
),
1981 kCFStringEncodingUTF8
))
1983 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1984 "Dynamic store host name is \"%s\".", nameBuffer
);
1985 cupsdSetString(&DNSSDHostName
, nameBuffer
);
1994 * Use the ServerName instead...
1997 cupsdLogMessage(CUPSD_LOG_DEBUG
,
1998 "Using ServerName \"%s\" as host name.", ServerName
);
1999 cupsdSetString(&DNSSDHostName
, ServerName
);
2003 * Get any Back-to-My-Mac domains and add them as aliases...
2006 cupsdFreeAliases(DNSSDAlias
);
2009 btmm
= SCDynamicStoreCopyValue(sc
, CFSTR("Setup:/Network/BackToMyMac"));
2010 if (btmm
&& CFGetTypeID(btmm
) == CFDictionaryGetTypeID())
2012 cupsdLogMessage(CUPSD_LOG_DEBUG
, "%d Back to My Mac aliases to add.",
2013 (int)CFDictionaryGetCount(btmm
));
2014 CFDictionaryApplyFunction(btmm
, dnssdAddAlias
, NULL
);
2017 cupsdLogMessage(CUPSD_LOG_ERROR
,
2018 "Bad Back to My Mac data in dynamic store!");
2020 cupsdLogMessage(CUPSD_LOG_DEBUG
, "No Back to My Mac aliases to add.");
2028 # endif /* HAVE_SYSTEMCONFIGURATION */
2030 cupsdSetString(&DNSSDComputerName
, ServerName
);
2031 cupsdSetString(&DNSSDHostName
, ServerName
);
2035 * Then (re)register the web interface if enabled...
2040 if (DNSSDComputerName
)
2041 snprintf(webif
, sizeof(webif
), "CUPS @ %s", DNSSDComputerName
);
2043 strlcpy(webif
, "CUPS Web Interface", sizeof(webif
));
2046 DNSServiceRefDeallocate(WebIFRef
);
2048 WebIFRef
= DNSSDRef
;
2049 if ((error
= DNSServiceRegister(&WebIFRef
,
2050 kDNSServiceFlagsShareConnection
,
2051 0, webif
, "_http._tcp", NULL
,
2052 NULL
, htons(DNSSDPort
), 7,
2053 "\006path=/", dnssdRegisterCallback
,
2054 NULL
)) != kDNSServiceErr_NoError
)
2055 cupsdLogMessage(CUPSD_LOG_ERROR
,
2056 "DNS-SD web interface registration failed: %d", error
);
2059 #endif /* HAVE_DNSSD */
2064 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
2068 cupsdUpdateLDAPBrowse(void)
2070 char uri
[HTTP_MAX_URI
], /* Printer URI */
2071 host
[HTTP_MAX_URI
], /* Hostname */
2072 resource
[HTTP_MAX_URI
], /* Resource path */
2073 location
[1024], /* Printer location */
2074 info
[1024], /* Printer information */
2075 make_model
[1024], /* Printer make and model */
2076 type_num
[30]; /* Printer type number */
2077 int type
; /* Printer type */
2078 int rc
; /* LDAP status */
2079 int limit
; /* Size limit */
2080 LDAPMessage
*res
, /* LDAP search results */
2081 *e
; /* Current entry from search */
2083 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "UpdateLDAPBrowse: %s", ServerName
);
2085 BrowseLDAPRefresh
= time(NULL
) + BrowseInterval
;
2088 * Reconnect if LDAP Handle is invalid...
2091 if (! BrowseLDAPHandle
)
2098 * Search for cups printers in LDAP directory...
2101 rc
= ldap_search_rec(BrowseLDAPHandle
, BrowseLDAPDN
, LDAP_SCOPE_SUBTREE
,
2102 "(objectclass=cupsPrinter)", (char **)ldap_attrs
, 0, &res
);
2105 * If ldap search was successfull then exit function
2106 * and temporary disable LDAP updates...
2109 if (rc
!= LDAP_SUCCESS
)
2111 if (BrowseLDAPUpdate
&& ((rc
== LDAP_SERVER_DOWN
) || (rc
== LDAP_CONNECT_ERROR
)))
2113 BrowseLDAPUpdate
= FALSE
;
2114 cupsdLogMessage(CUPSD_LOG_INFO
,
2115 "LDAP update temporary disabled");
2121 * If LDAP updates were disabled, we will reenable them...
2124 if (! BrowseLDAPUpdate
)
2126 BrowseLDAPUpdate
= TRUE
;
2127 cupsdLogMessage(CUPSD_LOG_INFO
,
2128 "LDAP update enabled");
2132 * Count LDAP entries and return if no entry exist...
2135 limit
= ldap_count_entries(BrowseLDAPHandle
, res
);
2136 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "LDAP search returned %d entries", limit
);
2144 * Loop through the available printers...
2147 for (e
= ldap_first_entry(BrowseLDAPHandle
, res
);
2149 e
= ldap_next_entry(BrowseLDAPHandle
, e
))
2152 * Get the required values from this entry...
2155 if (ldap_getval_firststring(BrowseLDAPHandle
, e
,
2156 "printerDescription", info
, sizeof(info
)) == -1)
2159 if (ldap_getval_firststring(BrowseLDAPHandle
, e
,
2160 "printerLocation", location
, sizeof(location
)) == -1)
2163 if (ldap_getval_firststring(BrowseLDAPHandle
, e
,
2164 "printerMakeAndModel", make_model
, sizeof(make_model
)) == -1)
2167 if (ldap_getval_firststring(BrowseLDAPHandle
, e
,
2168 "printerType", type_num
, sizeof(type_num
)) == -1)
2171 type
= atoi(type_num
);
2173 if (ldap_getval_firststring(BrowseLDAPHandle
, e
,
2174 "printerURI", uri
, sizeof(uri
)) == -1)
2178 * Process the entry as browse data...
2181 if (!is_local_queue(uri
, host
, sizeof(host
), resource
, sizeof(resource
)))
2182 process_browse_data(uri
, host
, resource
, type
, IPP_PRINTER_IDLE
,
2183 location
, info
, make_model
, 0, NULL
);
2189 #endif /* HAVE_LDAP */
2194 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
2198 cupsdUpdateSLPBrowse(void)
2200 slpsrvurl_t
*s
, /* Temporary list of service URLs */
2201 *next
; /* Next service in list */
2202 cupsd_printer_t p
; /* Printer information */
2203 const char *uri
; /* Pointer to printer URI */
2204 char host
[HTTP_MAX_URI
], /* Host portion of URI */
2205 resource
[HTTP_MAX_URI
]; /* Resource portion of URI */
2209 * Reset the refresh time...
2212 BrowseSLPRefresh
= time(NULL
) + BrowseInterval
;
2215 * Poll for remote printers using SLP...
2220 SLPFindSrvs(BrowseSLPHandle
, SLP_CUPS_SRVTYPE
, "", "",
2221 slp_url_callback
, &s
);
2224 * Loop through the list of available printers...
2230 * Save the "next" pointer...
2236 * Load a cupsd_printer_t structure with the SLP service attributes...
2239 SLPFindAttrs(BrowseSLPHandle
, s
->url
, "", "", slp_attr_callback
, &p
);
2242 * Process this printer entry...
2245 uri
= s
->url
+ SLP_CUPS_SRVLEN
+ 1;
2247 if (!strncmp(uri
, "http://", 7) || !strncmp(uri
, "ipp://", 6))
2250 * Pull the URI apart to see if this is a local or remote printer...
2253 if (!is_local_queue(uri
, host
, sizeof(host
), resource
, sizeof(resource
)))
2254 process_browse_data(uri
, host
, resource
, p
.type
, IPP_PRINTER_IDLE
,
2255 p
.location
, p
.info
, p
.make_model
, 0, NULL
);
2259 * Free this listing...
2262 cupsdClearString(&p
.info
);
2263 cupsdClearString(&p
.location
);
2264 cupsdClearString(&p
.make_model
);
2269 #endif /* HAVE_LIBSLP */
2273 * 'dequote()' - Remote quotes from a string.
2276 static char * /* O - Dequoted string */
2277 dequote(char *d
, /* I - Destination string */
2278 const char *s
, /* I - Source string */
2279 int dlen
) /* I - Destination length */
2281 char *dptr
; /* Pointer into destination */
2286 for (dptr
= d
, dlen
--; *s
&& dlen
> 0; s
++)
2303 # ifdef HAVE_COREFOUNDATION
2305 * 'dnssdAddAlias()' - Add a DNS-SD alias name.
2309 dnssdAddAlias(const void *key
, /* I - Key */
2310 const void *value
, /* I - Value (domain) */
2311 void *context
) /* I - Unused */
2313 char valueStr
[1024], /* Domain string */
2314 hostname
[1024]; /* Complete hostname */
2320 if (CFGetTypeID((CFStringRef
)value
) == CFStringGetTypeID() &&
2321 CFStringGetCString((CFStringRef
)value
, valueStr
, sizeof(valueStr
),
2322 kCFStringEncodingUTF8
))
2324 snprintf(hostname
, sizeof(hostname
), "%s.%s", DNSSDHostName
, valueStr
);
2326 DNSSDAlias
= cupsArrayNew(NULL
, NULL
);
2328 cupsdAddAlias(DNSSDAlias
, hostname
);
2329 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added Back to My Mac ServerAlias %s",
2333 cupsdLogMessage(CUPSD_LOG_ERROR
,
2334 "Bad Back to My Mac domain in dynamic store!");
2336 # endif /* HAVE_COREFOUNDATION */
2340 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2343 static char * /* O - TXT record */
2344 dnssdBuildTxtRecord(
2345 int *txt_len
, /* O - TXT record length */
2346 cupsd_printer_t
*p
, /* I - Printer information */
2347 int for_lpd
) /* I - 1 = LPD, 0 = IPP */
2349 int i
; /* Looping var */
2350 char admin_hostname
[256], /* .local hostname for admin page */
2351 adminurl_str
[256], /* URL for the admin page */
2352 type_str
[32], /* Type to string buffer */
2353 state_str
[32], /* State to string buffer */
2354 rp_str
[1024], /* Queue name string buffer */
2355 air_str
[1024], /* auth-info-required string buffer */
2356 *keyvalue
[32][2]; /* Table of key/value pairs */
2360 * Load up the key value pairs...
2365 keyvalue
[i
][0] = "txtvers";
2366 keyvalue
[i
++][1] = "1";
2368 keyvalue
[i
][0] = "qtotal";
2369 keyvalue
[i
++][1] = "1";
2371 keyvalue
[i
][0] = "rp";
2372 keyvalue
[i
++][1] = rp_str
;
2374 strlcpy(rp_str
, p
->name
, sizeof(rp_str
));
2376 snprintf(rp_str
, sizeof(rp_str
), "%s/%s",
2377 (p
->type
& CUPS_PRINTER_CLASS
) ? "classes" : "printers", p
->name
);
2379 keyvalue
[i
][0] = "ty";
2380 keyvalue
[i
++][1] = p
->make_model
? p
->make_model
: "Unknown";
2382 snprintf(admin_hostname
, sizeof(admin_hostname
), "%s.local.", DNSSDHostName
);
2383 httpAssembleURIf(HTTP_URI_CODING_ALL
, adminurl_str
, sizeof(adminurl_str
),
2384 "http", NULL
, admin_hostname
, DNSSDPort
, "/%s/%s",
2385 (p
->type
& CUPS_PRINTER_CLASS
) ? "classes" : "printers",
2387 keyvalue
[i
][0] = "adminurl";
2388 keyvalue
[i
++][1] = adminurl_str
;
2390 keyvalue
[i
][0] = "note";
2391 keyvalue
[i
++][1] = p
->location
? p
->location
: "";
2393 keyvalue
[i
][0] = "priority";
2394 keyvalue
[i
++][1] = for_lpd
? "100" : "0";
2396 keyvalue
[i
][0] = "product";
2397 keyvalue
[i
++][1] = p
->pc
&& p
->pc
->product
? p
->pc
->product
: "Unknown";
2399 keyvalue
[i
][0] = "pdl";
2400 keyvalue
[i
++][1] = p
->pdl
? p
->pdl
: "application/postscript";
2402 if (get_auth_info_required(p
, air_str
, sizeof(air_str
)))
2404 keyvalue
[i
][0] = "air";
2405 keyvalue
[i
++][1] = air_str
;
2408 keyvalue
[i
][0] = "UUID";
2409 keyvalue
[i
++][1] = p
->uuid
+ 9;
2412 keyvalue
[i
][0] = "TLS";
2413 keyvalue
[i
++][1] = "1.2";
2414 #endif /* HAVE_SSL */
2416 keyvalue
[i
][0] = "Transparent";
2417 keyvalue
[i
++][1] = "F";
2419 keyvalue
[i
][0] = "Binary";
2420 keyvalue
[i
++][1] = "F";
2422 keyvalue
[i
][0] = "Fax";
2423 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_FAX
) ? "T" : "F";
2425 keyvalue
[i
][0] = "Color";
2426 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_COLOR
) ? "T" : "F";
2428 keyvalue
[i
][0] = "Duplex";
2429 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_DUPLEX
) ? "T" : "F";
2431 keyvalue
[i
][0] = "Staple";
2432 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_STAPLE
) ? "T" : "F";
2434 keyvalue
[i
][0] = "Copies";
2435 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_COPIES
) ? "T" : "F";
2437 keyvalue
[i
][0] = "Collate";
2438 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_COLLATE
) ? "T" : "F";
2440 keyvalue
[i
][0] = "Punch";
2441 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_PUNCH
) ? "T" : "F";
2443 keyvalue
[i
][0] = "Bind";
2444 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_BIND
) ? "T" : "F";
2446 keyvalue
[i
][0] = "Sort";
2447 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_SORT
) ? "T" : "F";
2449 keyvalue
[i
][0] = "Scan";
2450 keyvalue
[i
++][1] = (p
->type
& CUPS_PRINTER_MFP
) ? "T" : "F";
2452 snprintf(type_str
, sizeof(type_str
), "0x%X", p
->type
| CUPS_PRINTER_REMOTE
);
2453 snprintf(state_str
, sizeof(state_str
), "%d", p
->state
);
2455 keyvalue
[i
][0] = "printer-state";
2456 keyvalue
[i
++][1] = state_str
;
2458 keyvalue
[i
][0] = "printer-type";
2459 keyvalue
[i
++][1] = type_str
;
2462 * Then pack them into a proper txt record...
2465 return (dnssdPackTxtRecord(txt_len
, keyvalue
, i
));
2470 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
2473 static int /* O - Result of comparison */
2474 dnssdComparePrinters(cupsd_printer_t
*a
,/* I - First printer */
2475 cupsd_printer_t
*b
)/* I - Second printer */
2477 return (_cups_strcasecmp(a
->reg_name
, b
->reg_name
));
2482 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2487 dnssdDeregisterPrinter(
2488 cupsd_printer_t
*p
) /* I - Printer */
2490 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "dnssdDeregisterPrinter(%s)", p
->name
);
2493 * Closing the socket deregisters the service
2498 DNSServiceRefDeallocate(p
->ipp_ref
);
2505 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
2514 DNSServiceRefDeallocate(p
->printer_ref
);
2515 p
->printer_ref
= NULL
;
2521 * p->printer_txt is malloc'd, not _cupsStrAlloc'd...
2524 free(p
->printer_txt
);
2525 p
->printer_txt
= NULL
;
2529 * Remove the printer from the array of DNS-SD printers, then clear the
2530 * registered name...
2533 cupsArrayRemove(DNSSDPrinters
, p
);
2534 cupsdClearString(&p
->reg_name
);
2539 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2540 * TXT record format.
2543 static char * /* O - TXT record */
2544 dnssdPackTxtRecord(int *txt_len
, /* O - TXT record length */
2545 char *keyvalue
[][2], /* I - Table of key value pairs */
2546 int count
) /* I - Items in table */
2548 int i
; /* Looping var */
2549 int length
; /* Length of TXT record */
2550 int length2
; /* Length of value */
2551 char *txtRecord
; /* TXT record buffer */
2552 char *cursor
; /* Looping pointer */
2556 * Calculate the buffer size
2562 for (length
= i
= 0; i
< count
; i
++)
2563 length
+= 1 + strlen(keyvalue
[i
][0]) +
2564 (keyvalue
[i
][1] ? 1 + strlen(keyvalue
[i
][1]) : 0);
2567 * Allocate and fill it
2570 txtRecord
= malloc(length
);
2575 for (cursor
= txtRecord
, i
= 0; i
< count
; i
++)
2578 * Drop in the p-string style length byte followed by the data
2581 length
= strlen(keyvalue
[i
][0]);
2582 length2
= keyvalue
[i
][1] ? 1 + strlen(keyvalue
[i
][1]) : 0;
2584 *cursor
++ = (unsigned char)(length
+ length2
);
2586 memcpy(cursor
, keyvalue
[i
][0], length
);
2593 memcpy(cursor
, keyvalue
[i
][1], length2
);
2604 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2608 dnssdRegisterCallback(
2609 DNSServiceRef sdRef
, /* I - DNS Service reference */
2610 DNSServiceFlags flags
, /* I - Reserved for future use */
2611 DNSServiceErrorType errorCode
, /* I - Error code */
2612 const char *name
, /* I - Service name */
2613 const char *regtype
, /* I - Service type */
2614 const char *domain
, /* I - Domain. ".local" for now */
2615 void *context
) /* I - User-defined context */
2617 cupsd_printer_t
*p
= (cupsd_printer_t
*)context
;
2618 /* Current printer */
2625 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "dnssdRegisterCallback(%s, %s) for %s (%s)",
2626 name
, regtype
, p
? p
->name
: "Web Interface",
2627 p
? (p
->reg_name
? p
->reg_name
: "(null)") : "NA");
2631 cupsdLogMessage(CUPSD_LOG_ERROR
,
2632 "DNSServiceRegister failed with error %d", (int)errorCode
);
2635 else if (p
&& (!p
->reg_name
|| _cups_strcasecmp(name
, p
->reg_name
)))
2637 cupsdLogMessage(CUPSD_LOG_INFO
, "Using service name \"%s\" for \"%s\"",
2640 cupsArrayRemove(DNSSDPrinters
, p
);
2641 cupsdSetString(&p
->reg_name
, name
);
2642 cupsArrayAdd(DNSSDPrinters
, p
);
2644 LastEvent
|= CUPSD_EVENT_PRINTER_MODIFIED
;
2650 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2651 * or update the broadcast contents.
2655 dnssdRegisterPrinter(cupsd_printer_t
*p
)/* I - Printer */
2657 DNSServiceErrorType se
; /* dnssd errors */
2658 char *ipp_txt
, /* IPP TXT record buffer */
2659 *printer_txt
, /* LPD TXT record buffer */
2660 name
[1024], /* Service name */
2661 *nameptr
; /* Pointer into name */
2662 int ipp_len
, /* IPP TXT record length */
2663 printer_len
, /* LPD TXT record length */
2664 printer_port
; /* LPD port number */
2665 const char *regtype
; /* Registration type */
2668 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "dnssdRegisterPrinter(%s) %s", p
->name
,
2669 !p
->ipp_ref
? "new" : "update");
2672 * If per-printer sharing was just disabled make sure we're not
2673 * registered before returning.
2678 dnssdDeregisterPrinter(p
);
2683 * The registered name takes the form of "<printer-info> @ <computer name>"...
2686 if (p
->info
&& strlen(p
->info
) > 0)
2688 if (DNSSDComputerName
)
2689 snprintf(name
, sizeof(name
), "%s @ %s", p
->info
, DNSSDComputerName
);
2691 strlcpy(name
, p
->info
, sizeof(name
));
2693 else if (DNSSDComputerName
)
2694 snprintf(name
, sizeof(name
), "%s @ %s", p
->name
, DNSSDComputerName
);
2696 strlcpy(name
, p
->name
, sizeof(name
));
2699 * If an existing printer was renamed, unregister it and start over...
2702 if (p
->reg_name
&& strcmp(p
->reg_name
, name
))
2703 dnssdDeregisterPrinter(p
);
2707 cupsdSetString(&p
->reg_name
, name
);
2708 cupsArrayAdd(DNSSDPrinters
, p
);
2712 * Register IPP and (optionally) LPD...
2715 ipp_len
= 0; /* anti-compiler-warning-code */
2716 ipp_txt
= dnssdBuildTxtRecord(&ipp_len
, p
, 0);
2719 (ipp_len
!= p
->ipp_len
|| memcmp(ipp_txt
, p
->ipp_txt
, ipp_len
)))
2722 * Update the existing registration...
2725 /* A TTL of 0 means use record's original value (Radar 3176248) */
2726 if ((se
= DNSServiceUpdateRecord(p
->ipp_ref
, NULL
, 0, ipp_len
, ipp_txt
,
2727 0)) == kDNSServiceErr_NoError
)
2732 p
->ipp_txt
= ipp_txt
;
2733 p
->ipp_len
= ipp_len
;
2739 * Failed to update record, lets close this reference and move on...
2742 cupsdLogMessage(CUPSD_LOG_ERROR
,
2743 "Unable to update IPP DNS-SD record for %s - %d", p
->name
,
2746 DNSServiceRefDeallocate(p
->ipp_ref
);
2754 * Initial registration. Use the _fax-ipp regtype for fax queues...
2757 regtype
= (p
->type
& CUPS_PRINTER_FAX
) ? "_fax-ipp._tcp" : DNSSDRegType
;
2759 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2760 "Registering DNS-SD printer %s with name \"%s\" and "
2761 "type \"%s\"", p
->name
, name
, regtype
);
2764 * Register the queue, dropping characters as needed until we succeed...
2767 nameptr
= name
+ strlen(name
);
2771 p
->ipp_ref
= DNSSDRef
;
2772 if ((se
= DNSServiceRegister(&p
->ipp_ref
, kDNSServiceFlagsShareConnection
,
2773 0, name
, regtype
, NULL
, NULL
,
2774 htons(DNSSDPort
), ipp_len
, ipp_txt
,
2775 dnssdRegisterCallback
,
2776 p
)) == kDNSServiceErr_BadParam
)
2779 * Name is too long, drop trailing characters, taking into account
2785 while (nameptr
> name
&& (*nameptr
& 0xc0) == 0x80)
2792 while (se
== kDNSServiceErr_BadParam
&& nameptr
> name
);
2794 if (se
== kDNSServiceErr_NoError
)
2796 p
->ipp_txt
= ipp_txt
;
2797 p
->ipp_len
= ipp_len
;
2801 cupsdLogMessage(CUPSD_LOG_WARN
,
2802 "DNS-SD IPP registration of \"%s\" failed: %d",
2809 if (BrowseLocalProtocols
& BROWSE_LPD
)
2811 printer_len
= 0; /* anti-compiler-warning-code */
2813 printer_txt
= dnssdBuildTxtRecord(&printer_len
, p
, 1);
2822 if (p
->printer_ref
&&
2823 (printer_len
!= p
->printer_len
||
2824 memcmp(printer_txt
, p
->printer_txt
, printer_len
)))
2827 * Update the existing registration...
2830 /* A TTL of 0 means use record's original value (Radar 3176248) */
2831 if ((se
= DNSServiceUpdateRecord(p
->printer_ref
, NULL
, 0, printer_len
,
2833 0)) == kDNSServiceErr_NoError
)
2836 free(p
->printer_txt
);
2838 p
->printer_txt
= printer_txt
;
2839 p
->printer_len
= printer_len
;
2845 * Failed to update record, lets close this reference and move on...
2848 cupsdLogMessage(CUPSD_LOG_ERROR
,
2849 "Unable to update LPD DNS-SD record for %s - %d",
2852 DNSServiceRefDeallocate(p
->printer_ref
);
2853 p
->printer_ref
= NULL
;
2857 if (!p
->printer_ref
)
2860 * Initial registration...
2863 cupsdLogMessage(CUPSD_LOG_DEBUG
,
2864 "Registering DNS-SD printer %s with name \"%s\" and "
2865 "type \"_printer._tcp\"", p
->name
, name
);
2867 p
->printer_ref
= DNSSDRef
;
2868 if ((se
= DNSServiceRegister(&p
->printer_ref
,
2869 kDNSServiceFlagsShareConnection
,
2870 0, name
, "_printer._tcp", NULL
, NULL
,
2871 htons(printer_port
), printer_len
, printer_txt
,
2872 dnssdRegisterCallback
,
2873 p
)) == kDNSServiceErr_NoError
)
2875 p
->printer_txt
= printer_txt
;
2876 p
->printer_len
= printer_len
;
2880 cupsdLogMessage(CUPSD_LOG_WARN
,
2881 "DNS-SD LPD registration of \"%s\" failed: %d",
2891 * 'dnssdStop()' - Stop all DNS-SD registrations.
2897 cupsd_printer_t
*p
; /* Current printer */
2901 * De-register the individual printers
2904 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
2906 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
2907 dnssdDeregisterPrinter(p
);
2910 * Shutdown the rest of the service refs...
2915 DNSServiceRefDeallocate(WebIFRef
);
2921 DNSServiceRefDeallocate(RemoteRef
);
2925 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef
));
2927 DNSServiceRefDeallocate(DNSSDRef
);
2930 cupsArrayDelete(DNSSDPrinters
);
2931 DNSSDPrinters
= NULL
;
2938 * 'dnssdUpdate()' - Handle DNS-SD queries.
2944 DNSServiceErrorType sdErr
; /* Service discovery error */
2947 if ((sdErr
= DNSServiceProcessResult(DNSSDRef
)) != kDNSServiceErr_NoError
)
2949 cupsdLogMessage(CUPSD_LOG_ERROR
,
2950 "DNS Service Discovery registration error %d!",
2955 #endif /* HAVE_DNSSD */
2959 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
2962 static char * /* O - String or NULL if none */
2963 get_auth_info_required(
2964 cupsd_printer_t
*p
, /* I - Printer */
2965 char *buffer
, /* I - Value buffer */
2966 size_t bufsize
) /* I - Size of value buffer */
2968 cupsd_location_t
*auth
; /* Pointer to authentication element */
2969 char resource
[1024]; /* Printer/class resource path */
2973 * If auth-info-required is set for this printer, return that...
2976 if (p
->num_auth_info_required
> 0 && strcmp(p
->auth_info_required
[0], "none"))
2978 int i
; /* Looping var */
2979 char *bufptr
; /* Pointer into buffer */
2981 for (i
= 0, bufptr
= buffer
; i
< p
->num_auth_info_required
; i
++)
2983 if (bufptr
>= (buffer
+ bufsize
- 2))
2989 strlcpy(bufptr
, p
->auth_info_required
[i
], bufsize
- (bufptr
- buffer
));
2990 bufptr
+= strlen(bufptr
);
2997 * Figure out the authentication data requirements to advertise...
3000 if (p
->type
& CUPS_PRINTER_CLASS
)
3001 snprintf(resource
, sizeof(resource
), "/classes/%s", p
->name
);
3003 snprintf(resource
, sizeof(resource
), "/printers/%s", p
->name
);
3005 if ((auth
= cupsdFindBest(resource
, HTTP_POST
)) == NULL
||
3006 auth
->type
== CUPSD_AUTH_NONE
)
3007 auth
= cupsdFindPolicyOp(p
->op_policy_ptr
, IPP_PRINT_JOB
);
3011 int auth_type
; /* Authentication type */
3013 if ((auth_type
= auth
->type
) == CUPSD_AUTH_DEFAULT
)
3014 auth_type
= DefaultAuthType
;
3018 case CUPSD_AUTH_NONE
:
3021 case CUPSD_AUTH_NEGOTIATE
:
3022 strlcpy(buffer
, "negotiate", bufsize
);
3026 strlcpy(buffer
, "username,password", bufsize
);
3039 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
3042 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
3043 get_hostconfig(const char *name
) /* I - Name of service */
3045 cups_file_t
*fp
; /* Hostconfig file */
3046 char line
[1024], /* Line from file */
3047 *ptr
; /* Pointer to value */
3048 int state
= 1; /* State of service */
3052 * Try opening the /etc/hostconfig file; if we can't open it, assume that
3053 * the service is enabled/auto.
3056 if ((fp
= cupsFileOpen("/etc/hostconfig", "r")) != NULL
)
3059 * Read lines from the file until we find the service...
3062 while (cupsFileGets(fp
, line
, sizeof(line
)))
3064 if (line
[0] == '#' || (ptr
= strchr(line
, '=')) == NULL
)
3069 if (!_cups_strcasecmp(line
, name
))
3072 * Found the service, see if it is set to "-NO-"...
3075 if (!_cups_strncasecmp(ptr
, "-NO-", 4))
3086 #endif /* __APPLE__ */
3090 * 'is_local_queue()' - Determine whether the URI points at a local queue.
3093 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
3094 is_local_queue(const char *uri
, /* I - Printer URI */
3095 char *host
, /* O - Host string */
3096 int hostlen
, /* I - Length of host buffer */
3097 char *resource
, /* O - Resource string */
3098 int resourcelen
) /* I - Length of resource buffer */
3100 char scheme
[32], /* Scheme portion of URI */
3101 username
[HTTP_MAX_URI
]; /* Username portion of URI */
3102 int port
; /* Port portion of URI */
3103 cupsd_netif_t
*iface
; /* Network interface */
3107 * Pull the URI apart to see if this is a local or remote printer...
3110 if (httpSeparateURI(HTTP_URI_CODING_ALL
, uri
, scheme
, sizeof(scheme
),
3111 username
, sizeof(username
), host
, hostlen
, &port
,
3112 resource
, resourcelen
) < HTTP_URI_OK
)
3115 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host
, ServerName
));
3118 * Check for local server addresses...
3121 if (!_cups_strcasecmp(host
, ServerName
) && port
== LocalPort
)
3126 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
3128 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
3129 if (!_cups_strcasecmp(host
, iface
->hostname
) && port
== iface
->port
)
3133 * If we get here, the printer is remote...
3141 * 'process_browse_data()' - Process new browse data.
3145 process_browse_data(
3146 const char *uri
, /* I - URI of printer/class */
3147 const char *host
, /* I - Hostname */
3148 const char *resource
, /* I - Resource path */
3149 cups_ptype_t type
, /* I - Printer type */
3150 ipp_pstate_t state
, /* I - Printer state */
3151 const char *location
, /* I - Printer location */
3152 const char *info
, /* I - Printer information */
3153 const char *make_model
, /* I - Printer make and model */
3154 int num_attrs
, /* I - Number of attributes */
3155 cups_option_t
*attrs
) /* I - Attributes */
3157 int i
; /* Looping var */
3158 int update
; /* Update printer attributes? */
3159 char finaluri
[HTTP_MAX_URI
], /* Final URI for printer */
3160 name
[IPP_MAX_NAME
], /* Name of printer */
3161 newname
[IPP_MAX_NAME
], /* New name of printer */
3162 *hptr
, /* Pointer into hostname */
3163 *sptr
; /* Pointer into ServerName */
3164 const char *shortname
; /* Short queue name (queue) */
3165 char local_make_model
[IPP_MAX_NAME
];
3166 /* Local make and model */
3167 cupsd_printer_t
*p
; /* Printer information */
3168 const char *ipp_options
, /* ipp-options value */
3169 *lease_duration
, /* lease-duration value */
3170 *uuid
; /* uuid value */
3171 int is_class
; /* Is this queue a class? */
3174 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3175 "process_browse_data(uri=\"%s\", host=\"%s\", "
3176 "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
3177 "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
3178 uri
, host
, resource
, type
, state
,
3179 location
? location
: "(nil)", info
? info
: "(nil)",
3180 make_model
? make_model
: "(nil)", num_attrs
, attrs
);
3183 * Determine if the URI contains any illegal characters in it...
3186 if (strncmp(uri
, "ipp://", 6) || !host
[0] ||
3187 (strncmp(resource
, "/printers/", 10) &&
3188 strncmp(resource
, "/classes/", 9)))
3190 cupsdLogMessage(CUPSD_LOG_ERROR
, "Bad printer URI in browse data: %s", uri
);
3194 if (strchr(resource
, '?') ||
3195 (!strncmp(resource
, "/printers/", 10) && strchr(resource
+ 10, '/')) ||
3196 (!strncmp(resource
, "/classes/", 9) && strchr(resource
+ 9, '/')))
3198 cupsdLogMessage(CUPSD_LOG_ERROR
, "Bad resource in browse data: %s",
3204 * OK, this isn't a local printer; add any remote options...
3207 ipp_options
= cupsGetOption("ipp-options", num_attrs
, attrs
);
3209 if (BrowseRemoteOptions
)
3211 if (BrowseRemoteOptions
[0] == '?')
3214 * Override server-supplied options...
3217 snprintf(finaluri
, sizeof(finaluri
), "%s%s", uri
, BrowseRemoteOptions
);
3219 else if (ipp_options
)
3222 * Combine the server and local options...
3225 snprintf(finaluri
, sizeof(finaluri
), "%s?%s+%s", uri
, ipp_options
,
3226 BrowseRemoteOptions
);
3231 * Just use the local options...
3234 snprintf(finaluri
, sizeof(finaluri
), "%s?%s", uri
, BrowseRemoteOptions
);
3239 else if (ipp_options
)
3242 * Just use the server-supplied options...
3245 snprintf(finaluri
, sizeof(finaluri
), "%s?%s", uri
, ipp_options
);
3250 * See if we already have it listed in the Printers list, and add it if not...
3253 type
|= CUPS_PRINTER_REMOTE
| CUPS_PRINTER_DISCOVERED
;
3254 type
&= ~CUPS_PRINTER_IMPLICIT
;
3256 hptr
= strchr(host
, '.');
3257 sptr
= strchr(ServerName
, '.');
3258 is_class
= type
& CUPS_PRINTER_CLASS
;
3259 uuid
= cupsGetOption("uuid", num_attrs
, attrs
);
3261 if (!ServerNameIsIP
&& sptr
!= NULL
&& hptr
!= NULL
)
3264 * Strip the common domain name components...
3267 while (hptr
!= NULL
)
3269 if (!_cups_strcasecmp(hptr
, sptr
))
3275 hptr
= strchr(hptr
+ 1, '.');
3282 * Remote destination is a class...
3285 if (!strncmp(resource
, "/classes/", 9))
3286 snprintf(name
, sizeof(name
), "%s@%s", resource
+ 9, host
);
3290 shortname
= resource
+ 9;
3295 * Remote destination is a printer...
3298 if (!strncmp(resource
, "/printers/", 10))
3299 snprintf(name
, sizeof(name
), "%s@%s", resource
+ 10, host
);
3303 shortname
= resource
+ 10;
3307 *hptr
= '.'; /* Resource FQDN */
3309 if ((p
= cupsdFindDest(name
)) == NULL
&& BrowseShortNames
)
3312 * Long name doesn't exist, try short name...
3315 cupsdLogMessage(CUPSD_LOG_DEBUG
, "process_browse_data: %s not found...",
3318 if ((p
= cupsdFindDest(shortname
)) == NULL
)
3321 * Short name doesn't exist, use it for this shared queue.
3324 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "process_browse_data: %s not found...",
3326 strlcpy(name
, shortname
, sizeof(name
));
3331 * Short name exists...
3334 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3335 "process_browse_data: %s found, type=%x, hostname=%s...",
3336 shortname
, p
->type
, p
->hostname
? p
->hostname
: "(nil)");
3338 if (p
->type
& CUPS_PRINTER_IMPLICIT
)
3339 p
= NULL
; /* Don't replace implicit classes */
3340 else if (p
->hostname
&& _cups_strcasecmp(p
->hostname
, host
))
3343 * Short name exists but is for a different host. If this is a remote
3344 * queue, rename it and use the long name...
3347 if (p
->type
& CUPS_PRINTER_REMOTE
)
3349 cupsdLogMessage(CUPSD_LOG_DEBUG
,
3350 "Renamed remote %s \"%s\" to \"%s@%s\"...",
3351 is_class
? "class" : "printer", p
->name
, p
->name
,
3353 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, p
, NULL
,
3354 "%s \'%s\' deleted by directory services.",
3355 is_class
? "Class" : "Printer", p
->name
);
3357 snprintf(newname
, sizeof(newname
), "%s@%s", p
->name
, p
->hostname
);
3358 cupsdRenamePrinter(p
, newname
);
3360 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, p
, NULL
,
3361 "%s \'%s\' added by directory services.",
3362 is_class
? "Class" : "Printer", p
->name
);
3366 * Force creation with long name...
3374 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3375 "process_browse_data: %s found, type=%x, hostname=%s...",
3376 name
, p
->type
, p
->hostname
? p
->hostname
: "(nil)");
3381 * Queue doesn't exist; add it...
3385 p
= cupsdAddClass(name
);
3387 p
= cupsdAddPrinter(name
);
3392 cupsdClearString(&(p
->hostname
));
3394 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added remote %s \"%s\"...",
3395 is_class
? "class" : "printer", name
);
3397 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, p
, NULL
,
3398 "%s \'%s\' added by directory services.",
3399 is_class
? "Class" : "Printer", name
);
3402 * Force the URI to point to the real server...
3405 p
->type
= type
& ~CUPS_PRINTER_REJECTING
;
3408 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
);
3414 * Hostname not set, so this must be a cached remote printer
3415 * that was created for a pending print job...
3418 cupsdSetString(&p
->hostname
, host
);
3419 cupsdSetString(&p
->uri
, uri
);
3420 cupsdSetString(&p
->device_uri
, uri
);
3423 cupsdMarkDirty(CUPSD_DIRTY_REMOTE
);
3427 * Update the state...
3431 p
->browse_time
= time(NULL
);
3433 if ((lease_duration
= cupsGetOption("lease-duration", num_attrs
,
3437 * Grab the lease-duration for the browse data; anything less then 1
3438 * second or more than 1 week gets the default BrowseTimeout...
3441 i
= atoi(lease_duration
);
3442 if (i
< 1 || i
> 604800)
3445 p
->browse_expire
= p
->browse_time
+ i
;
3448 p
->browse_expire
= p
->browse_time
+ BrowseTimeout
;
3450 if (type
& CUPS_PRINTER_REJECTING
)
3452 type
&= ~CUPS_PRINTER_REJECTING
;
3460 else if (!p
->accepting
)
3466 if (p
->type
!= type
)
3472 if (uuid
&& strcmp(p
->uuid
, uuid
))
3474 cupsdSetString(&p
->uuid
, uuid
);
3478 if (location
&& (!p
->location
|| strcmp(p
->location
, location
)))
3480 cupsdSetString(&p
->location
, location
);
3484 if (info
&& (!p
->info
|| strcmp(p
->info
, info
)))
3486 cupsdSetString(&p
->info
, info
);
3489 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
| CUPSD_DIRTY_REMOTE
);
3492 if (!make_model
|| !make_model
[0])
3495 snprintf(local_make_model
, sizeof(local_make_model
),
3496 "Remote Class on %s", host
);
3498 snprintf(local_make_model
, sizeof(local_make_model
),
3499 "Remote Printer on %s", host
);
3502 snprintf(local_make_model
, sizeof(local_make_model
),
3503 "%s on %s", make_model
, host
);
3505 if (!p
->make_model
|| strcmp(p
->make_model
, local_make_model
))
3507 cupsdSetString(&p
->make_model
, local_make_model
);
3513 if (!update
&& !(type
& CUPS_PRINTER_DELETE
))
3516 * See if we need to update the attributes...
3519 if (p
->num_options
!= num_attrs
)
3523 for (i
= 0; i
< num_attrs
; i
++)
3524 if (strcmp(attrs
[i
].name
, p
->options
[i
].name
) ||
3525 (!attrs
[i
].value
!= !p
->options
[i
].value
) ||
3526 (attrs
[i
].value
&& strcmp(attrs
[i
].value
, p
->options
[i
].value
)))
3535 * Free the old options...
3538 cupsFreeOptions(p
->num_options
, p
->options
);
3541 p
->num_options
= num_attrs
;
3544 if (type
& CUPS_PRINTER_DELETE
)
3546 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED
, p
, NULL
,
3547 "%s \'%s\' deleted by directory services.",
3548 is_class
? "Class" : "Printer", p
->name
);
3550 cupsdExpireSubscriptions(p
, NULL
);
3552 cupsdDeletePrinter(p
, 1);
3553 cupsdUpdateImplicitClasses();
3554 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
| CUPSD_DIRTY_REMOTE
);
3558 cupsdSetPrinterAttrs(p
);
3559 cupsdUpdateImplicitClasses();
3563 * See if we have a default printer... If not, make the first network
3564 * default printer the default.
3567 if (DefaultPrinter
== NULL
&& Printers
!= NULL
&& UseNetworkDefault
)
3570 * Find the first network default printer and use it...
3573 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
);
3575 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
3576 if (p
->type
& CUPS_PRINTER_DEFAULT
)
3579 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
| CUPSD_DIRTY_REMOTE
);
3585 * Do auto-classing if needed...
3588 process_implicit_classes();
3593 * 'process_implicit_classes()' - Create/update implicit classes as needed.
3597 process_implicit_classes(void)
3599 int i
; /* Looping var */
3600 int update
; /* Update printer attributes? */
3601 char name
[IPP_MAX_NAME
], /* Name of printer */
3602 *hptr
; /* Pointer into hostname */
3603 cupsd_printer_t
*p
, /* Printer information */
3604 *pclass
, /* Printer class */
3605 *first
; /* First printer in class */
3606 int offset
, /* Offset of name */
3607 len
; /* Length of name */
3610 if (!ImplicitClasses
|| !Printers
)
3614 * Loop through all available printers and create classes as needed...
3617 for (p
= (cupsd_printer_t
*)cupsArrayFirst(Printers
), len
= 0, offset
= 0,
3618 update
= 0, pclass
= NULL
, first
= NULL
;
3620 p
= (cupsd_printer_t
*)cupsArrayNext(Printers
))
3623 * Skip implicit classes...
3626 if (p
->type
& CUPS_PRINTER_IMPLICIT
)
3633 * If len == 0, get the length of this printer name up to the "@"
3637 cupsArraySave(Printers
);
3640 !_cups_strncasecmp(p
->name
, name
+ offset
, len
) &&
3641 (p
->name
[len
] == '\0' || p
->name
[len
] == '@'))
3644 * We have more than one printer with the same name; see if
3645 * we have a class, and if this printer is a member...
3648 if (pclass
&& _cups_strcasecmp(pclass
->name
, name
))
3651 cupsdSetPrinterAttrs(pclass
);
3657 if (!pclass
&& (pclass
= cupsdFindDest(name
)) == NULL
)
3660 * Need to add the class...
3663 pclass
= cupsdAddPrinter(name
);
3664 cupsArrayAdd(ImplicitPrinters
, pclass
);
3666 pclass
->type
|= CUPS_PRINTER_IMPLICIT
;
3667 pclass
->accepting
= 1;
3668 pclass
->state
= IPP_PRINTER_IDLE
;
3670 cupsdSetString(&pclass
->location
, p
->location
);
3671 cupsdSetString(&pclass
->info
, p
->info
);
3673 cupsdSetString(&pclass
->job_sheets
[0], p
->job_sheets
[0]);
3674 cupsdSetString(&pclass
->job_sheets
[1], p
->job_sheets
[1]);
3678 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP
| CUPSD_DIRTY_REMOTE
);
3680 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Added implicit class \"%s\"...",
3682 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED
, p
, NULL
,
3683 "Implicit class \'%s\' added by directory services.",
3689 for (i
= 0; i
< pclass
->num_printers
; i
++)
3690 if (pclass
->printers
[i
] == first
)
3693 if (i
>= pclass
->num_printers
)
3695 first
->in_implicit_class
= 1;
3696 cupsdAddPrinterToClass(pclass
, first
);
3702 for (i
= 0; i
< pclass
->num_printers
; i
++)
3703 if (pclass
->printers
[i
] == p
)
3706 if (i
>= pclass
->num_printers
)
3708 p
->in_implicit_class
= 1;
3709 cupsdAddPrinterToClass(pclass
, p
);
3716 * First time around; just get name length and mark it as first
3720 if ((hptr
= strchr(p
->name
, '@')) != NULL
)
3721 len
= hptr
- p
->name
;
3723 len
= strlen(p
->name
);
3725 if (len
>= sizeof(name
))
3728 * If the printer name length somehow is greater than we normally allow,
3729 * skip this printer...
3733 cupsArrayRestore(Printers
);
3737 strncpy(name
, p
->name
, len
);
3741 if ((first
= (hptr
? cupsdFindDest(name
) : p
)) != NULL
&&
3742 !(first
->type
& CUPS_PRINTER_IMPLICIT
))
3745 * Can't use same name as a local printer; add "Any" to the
3746 * front of the name, unless we have explicitly disabled
3747 * the "ImplicitAnyClasses"...
3750 if (ImplicitAnyClasses
&& len
< (sizeof(name
) - 4))
3753 * Add "Any" to the class name...
3756 strcpy(name
, "Any");
3757 strncpy(name
+ 3, p
->name
, len
);
3758 name
[len
+ 3] = '\0';
3764 * Don't create an implicit class if we have a local printer
3765 * with the same name...
3769 cupsArrayRestore(Printers
);
3777 cupsArrayRestore(Printers
);
3781 * Update the last printer class as needed...
3784 if (pclass
&& update
)
3785 cupsdSetPrinterAttrs(pclass
);
3790 * 'send_cups_browse()' - Send new browsing information using the CUPS
3795 send_cups_browse(cupsd_printer_t
*p
) /* I - Printer to send */
3797 int i
; /* Looping var */
3798 cups_ptype_t type
; /* Printer type */
3799 cupsd_dirsvc_addr_t
*b
; /* Browse address */
3800 int bytes
; /* Length of packet */
3801 char packet
[1453], /* Browse data packet */
3802 uri
[1024], /* Printer URI */
3803 location
[1024], /* printer-location */
3804 info
[1024], /* printer-info */
3806 /* printer-make-and-model */
3807 air
[1024]; /* auth-info-required */
3808 cupsd_netif_t
*iface
; /* Network interface */
3812 * Figure out the printer type value...
3815 type
= p
->type
| CUPS_PRINTER_REMOTE
;
3818 type
|= CUPS_PRINTER_REJECTING
;
3820 if (p
== DefaultPrinter
)
3821 type
|= CUPS_PRINTER_DEFAULT
;
3824 * Remove quotes from printer-info, printer-location, and
3825 * printer-make-and-model attributes...
3828 dequote(location
, p
->location
, sizeof(location
));
3829 dequote(info
, p
->info
, sizeof(info
));
3832 dequote(make_model
, p
->make_model
, sizeof(make_model
));
3833 else if (p
->type
& CUPS_PRINTER_CLASS
)
3835 if (p
->num_printers
> 0 && p
->printers
[0]->make_model
)
3836 strlcpy(make_model
, p
->printers
[0]->make_model
, sizeof(make_model
));
3838 strlcpy(make_model
, "Local Printer Class", sizeof(make_model
));
3841 strlcpy(make_model
, "Local Raw Printer", sizeof(make_model
));
3843 strlcpy(make_model
, "Local System V Printer", sizeof(make_model
));
3845 if (get_auth_info_required(p
, packet
, sizeof(packet
)))
3846 snprintf(air
, sizeof(air
), " auth-info-required=%s", packet
);
3851 * Send a packet to each browse address...
3854 for (i
= NumBrowsers
, b
= Browsers
; i
> 0; i
--, b
++)
3858 * Send the browse packet to one or more interfaces...
3861 if (!strcmp(b
->iface
, "*"))
3864 * Send to all local interfaces...
3869 for (iface
= (cupsd_netif_t
*)cupsArrayFirst(NetIFList
);
3871 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
))
3874 * Only send to local, IPv4 interfaces...
3877 if (!iface
->is_local
|| !iface
->port
||
3878 iface
->address
.addr
.sa_family
!= AF_INET
)
3881 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3882 iface
->hostname
, iface
->port
,
3883 (p
->type
& CUPS_PRINTER_CLASS
) ? "/classes/%s" :
3886 snprintf(packet
, sizeof(packet
),
3887 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
3888 type
, p
->state
, uri
, location
, info
, make_model
,
3889 p
->browse_attrs
? p
->browse_attrs
: "", air
, p
->uuid
);
3891 bytes
= strlen(packet
);
3893 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3894 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes
,
3895 iface
->name
, packet
);
3897 iface
->broadcast
.ipv4
.sin_port
= htons(BrowsePort
);
3899 sendto(BrowseSocket
, packet
, bytes
, 0,
3900 (struct sockaddr
*)&(iface
->broadcast
),
3901 httpAddrLength(&(iface
->broadcast
)));
3904 else if ((iface
= cupsdNetIFFind(b
->iface
)) != NULL
)
3907 * Send to the named interface using the IPv4 address...
3911 if (strcmp(b
->iface
, iface
->name
))
3916 else if (iface
->address
.addr
.sa_family
== AF_INET
&& iface
->port
)
3919 iface
= (cupsd_netif_t
*)cupsArrayNext(NetIFList
);
3923 httpAssembleURIf(HTTP_URI_CODING_ALL
, uri
, sizeof(uri
), "ipp", NULL
,
3924 iface
->hostname
, iface
->port
,
3925 (p
->type
& CUPS_PRINTER_CLASS
) ? "/classes/%s" :
3928 snprintf(packet
, sizeof(packet
),
3929 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
3930 type
, p
->state
, uri
, location
, info
, make_model
,
3931 p
->browse_attrs
? p
->browse_attrs
: "", air
, p
->uuid
);
3933 bytes
= strlen(packet
);
3935 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3936 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes
,
3937 iface
->name
, packet
);
3939 iface
->broadcast
.ipv4
.sin_port
= htons(BrowsePort
);
3941 sendto(BrowseSocket
, packet
, bytes
, 0,
3942 (struct sockaddr
*)&(iface
->broadcast
),
3943 httpAddrLength(&(iface
->broadcast
)));
3950 * Send the browse packet to the indicated address using
3951 * the default server name...
3954 snprintf(packet
, sizeof(packet
),
3955 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s uuid=%s\n",
3956 type
, p
->state
, p
->uri
, location
, info
, make_model
,
3957 p
->browse_attrs
? p
->browse_attrs
: "", air
, p
->uuid
);
3959 bytes
= strlen(packet
);
3960 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
3961 "cupsdSendBrowseList: (%d bytes) %s", bytes
, packet
);
3963 if (sendto(BrowseSocket
, packet
, bytes
, 0,
3964 (struct sockaddr
*)&(b
->to
),
3965 httpAddrLength(&(b
->to
))) <= 0)
3968 * Unable to send browse packet, so remove this address from the
3972 cupsdLogMessage(CUPSD_LOG_ERROR
,
3973 "cupsdSendBrowseList: sendto failed for browser "
3975 (int)(b
- Browsers
+ 1), strerror(errno
));
3978 memmove(b
, b
+ 1, (i
- 1) * sizeof(cupsd_dirsvc_addr_t
));
3989 * 'ldap_search_rec()' - LDAP Search with reconnect
3992 static int /* O - Return code */
3993 ldap_search_rec(LDAP
*ld
, /* I - LDAP handler */
3994 char *base
, /* I - Base dn */
3995 int scope
, /* I - LDAP search scope */
3996 char *filter
, /* I - Filter string */
3997 char *attrs
[], /* I - Requested attributes */
3998 int attrsonly
, /* I - Return only attributes? */
3999 LDAPMessage
**res
) /* I - LDAP handler */
4001 int rc
; /* Return code */
4002 LDAP
*ldr
; /* LDAP handler after reconnect */
4005 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4006 rc
= ldap_search_ext_s(ld
, base
, scope
, filter
, attrs
, attrsonly
, NULL
, NULL
,
4007 NULL
, LDAP_NO_LIMIT
, res
);
4009 rc
= ldap_search_s(ld
, base
, scope
, filter
, attrs
, attrsonly
, res
);
4010 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4013 * If we have a connection problem try again...
4016 if (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
)
4018 cupsdLogMessage(CUPSD_LOG_ERROR
,
4019 "LDAP search failed with status %d: %s",
4020 rc
, ldap_err2string(rc
));
4021 cupsdLogMessage(CUPSD_LOG_INFO
,
4022 "We try the LDAP search once again after reconnecting to "
4025 ldr
= ldap_reconnect();
4027 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4028 rc
= ldap_search_ext_s(ldr
, base
, scope
, filter
, attrs
, attrsonly
, NULL
,
4029 NULL
, NULL
, LDAP_NO_LIMIT
, res
);
4031 rc
= ldap_search_s(ldr
, base
, scope
, filter
, attrs
, attrsonly
, res
);
4032 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4035 if (rc
== LDAP_NO_SUCH_OBJECT
)
4036 cupsdLogMessage(CUPSD_LOG_DEBUG
,
4037 "ldap_search_rec: LDAP entry/object not found");
4038 else if (rc
!= LDAP_SUCCESS
)
4039 cupsdLogMessage(CUPSD_LOG_ERROR
,
4040 "ldap_search_rec: LDAP search failed with status %d: %s",
4041 rc
, ldap_err2string(rc
));
4043 if (rc
!= LDAP_SUCCESS
)
4051 * 'ldap_freeres()' - Free LDAPMessage
4055 ldap_freeres(LDAPMessage
*entry
) /* I - LDAP handler */
4057 int rc
; /* Return value */
4060 rc
= ldap_msgfree(entry
);
4062 cupsdLogMessage(CUPSD_LOG_WARN
, "Can't free LDAPMessage!");
4064 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "Freeing LDAPMessage was unnecessary");
4069 * 'ldap_getval_char()' - Get first LDAP value and convert to string
4072 static int /* O - Return code */
4073 ldap_getval_firststring(
4074 LDAP
*ld
, /* I - LDAP handler */
4075 LDAPMessage
*entry
, /* I - LDAP message or search result */
4076 char *attr
, /* I - the wanted attribute */
4077 char *retval
, /* O - String to return */
4078 unsigned long maxsize
) /* I - Max string size */
4080 char *dn
; /* LDAP DN */
4081 int rc
= 0; /* Return code */
4082 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4083 struct berval
**bval
; /* LDAP value array */
4084 unsigned long size
; /* String size */
4088 * Get value from LDAPMessage...
4091 if ((bval
= ldap_get_values_len(ld
, entry
, attr
)) == NULL
)
4094 dn
= ldap_get_dn(ld
, entry
);
4095 cupsdLogMessage(CUPSD_LOG_WARN
,
4096 "Failed to get LDAP value %s for %s!",
4103 * Check size and copy value into our string...
4107 if (size
< (bval
[0]->bv_len
+ 1))
4110 dn
= ldap_get_dn(ld
, entry
);
4111 cupsdLogMessage(CUPSD_LOG_WARN
,
4112 "Attribute %s is too big! (dn: %s)",
4117 size
= bval
[0]->bv_len
+ 1;
4119 strlcpy(retval
, bval
[0]->bv_val
, size
);
4120 ldap_value_free_len(bval
);
4123 char **value
; /* LDAP value */
4126 * Get value from LDAPMessage...
4129 if ((value
= (char **)ldap_get_values(ld
, entry
, attr
)) == NULL
)
4132 dn
= ldap_get_dn(ld
, entry
);
4133 cupsdLogMessage(CUPSD_LOG_WARN
, "Failed to get LDAP value %s for %s!",
4139 strlcpy(retval
, *value
, maxsize
);
4140 ldap_value_free(value
);
4142 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4149 * 'send_ldap_ou()' - Send LDAP ou registrations.
4153 send_ldap_ou(char *ou
, /* I - Servername/ou to register */
4154 char *basedn
, /* I - Our base dn */
4155 char *descstring
) /* I - Description for ou */
4157 int i
; /* Looping var... */
4158 LDAPMod mods
[3]; /* The 3 attributes we will be adding */
4159 LDAPMod
*pmods
[4]; /* Pointers to the 3 attributes + NULL */
4160 LDAPMessage
*res
, /* Search result token */
4161 *e
; /* Current entry from search */
4162 int rc
; /* LDAP status */
4163 int rcmod
; /* LDAP status for modifications */
4164 char dn
[1024], /* DN of the organizational unit we are adding */
4165 *desc
[2], /* Change records */
4167 char old_desc
[1024]; /* Old description */
4168 static const char * const objectClass_values
[] =
4169 { /* The 2 objectClass's we use in */
4170 "top", /* our LDAP entries */
4171 "organizationalUnit",
4174 static const char * const ou_attrs
[] =/* CUPS LDAP attributes */
4181 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_ldap_ou: %s", ou
);
4184 * Reconnect if LDAP Handle is invalid...
4187 if (!BrowseLDAPHandle
)
4189 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4190 "send_ldap_ou: LDAP Handle is invalid. Try reconnecting...");
4196 * Prepare ldap search...
4199 snprintf(dn
, sizeof(dn
), "ou=%s, %s", ou
, basedn
);
4200 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_ldap_ou: dn=\"%s\"", dn
);
4204 desc
[0] = descstring
;
4207 mods
[0].mod_type
= "ou";
4208 mods
[0].mod_values
= ou_value
;
4209 mods
[1].mod_type
= "description";
4210 mods
[1].mod_values
= desc
;
4211 mods
[2].mod_type
= "objectClass";
4212 mods
[2].mod_values
= (char **)objectClass_values
;
4214 rc
= ldap_search_rec(BrowseLDAPHandle
, dn
, LDAP_SCOPE_BASE
, NULL
,
4215 (char **)ou_attrs
, 0, &res
);
4218 * If ldap search was not successfull then exit function...
4221 if (rc
!= LDAP_SUCCESS
&& rc
!= LDAP_NO_SUCH_OBJECT
)
4225 * Check if we need to insert or update the LDAP entry...
4228 if (ldap_count_entries(BrowseLDAPHandle
, res
) > 0 &&
4229 rc
!= LDAP_NO_SUCH_OBJECT
)
4232 * Printserver has already been registered, check if
4233 * modification is required...
4236 e
= ldap_first_entry(BrowseLDAPHandle
, res
);
4239 * Get the required values from this entry...
4242 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "description", old_desc
,
4243 sizeof(old_desc
)) == -1)
4247 * Check if modification is required...
4250 if ( strcmp(desc
[0], old_desc
) == 0 )
4253 * LDAP entry for the printer exists.
4254 * Printer has already been registered,
4255 * no modifications required...
4257 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4258 "send_ldap_ou: No updates required for %s", ou
);
4263 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4264 "send_ldap_ou: Replace entry for %s", ou
);
4266 for (i
= 0; i
< 3; i
++)
4268 pmods
[i
] = mods
+ i
;
4269 pmods
[i
]->mod_op
= LDAP_MOD_REPLACE
;
4273 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4274 if ((rcmod
= ldap_modify_ext_s(BrowseLDAPHandle
, dn
, pmods
, NULL
,
4275 NULL
)) != LDAP_SUCCESS
)
4277 if ((rcmod
= ldap_modify_s(BrowseLDAPHandle
, dn
, pmods
)) != LDAP_SUCCESS
)
4278 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4280 cupsdLogMessage(CUPSD_LOG_ERROR
,
4281 "LDAP modify for %s failed with status %d: %s",
4282 ou
, rcmod
, ldap_err2string(rcmod
));
4283 if (rcmod
== LDAP_SERVER_DOWN
)
4291 * Printserver has never been registered,
4292 * add registration...
4295 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4296 "send_ldap_ou: Add entry for %s", ou
);
4298 for (i
= 0; i
< 3; i
++)
4300 pmods
[i
] = mods
+ i
;
4301 pmods
[i
]->mod_op
= LDAP_MOD_ADD
;
4305 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4306 if ((rcmod
= ldap_add_ext_s(BrowseLDAPHandle
, dn
, pmods
, NULL
,
4307 NULL
)) != LDAP_SUCCESS
)
4309 if ((rcmod
= ldap_add_s(BrowseLDAPHandle
, dn
, pmods
)) != LDAP_SUCCESS
)
4310 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4312 cupsdLogMessage(CUPSD_LOG_ERROR
,
4313 "LDAP add for %s failed with status %d: %s",
4314 ou
, rcmod
, ldap_err2string(rcmod
));
4315 if (rcmod
== LDAP_SERVER_DOWN
)
4320 if (rc
== LDAP_SUCCESS
)
4326 * 'send_ldap_browse()' - Send LDAP printer registrations.
4330 send_ldap_browse(cupsd_printer_t
*p
) /* I - Printer to register */
4332 int i
; /* Looping var... */
4333 LDAPMod mods
[7]; /* The 7 attributes we will be adding */
4334 LDAPMod
*pmods
[8]; /* Pointers to the 7 attributes + NULL */
4335 LDAPMessage
*res
, /* Search result token */
4336 *e
; /* Current entry from search */
4337 char *cn_value
[2], /* Change records */
4343 typestring
[255], /* String to hold printer-type */
4344 dn
[1024]; /* DN of the printer we are adding */
4345 int rc
; /* LDAP status */
4346 int rcmod
; /* LDAP status for modifications */
4347 char old_uri
[HTTP_MAX_URI
], /* Printer URI */
4348 old_location
[1024], /* Printer location */
4349 old_info
[1024], /* Printer information */
4350 old_make_model
[1024], /* Printer make and model */
4351 old_type_string
[30]; /* Temporary type number */
4352 int old_type
; /* Printer type */
4353 static const char * const objectClass_values
[] =
4354 { /* The 3 objectClass's we use in */
4355 "top", /* our LDAP entries */
4362 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_ldap_browse: %s", p
->name
);
4365 * Exit function if LDAP updates has been disabled...
4368 if (!BrowseLDAPUpdate
)
4370 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4371 "send_ldap_browse: Updates temporary disabled; "
4377 * Reconnect if LDAP Handle is invalid...
4380 if (!BrowseLDAPHandle
)
4382 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4383 "send_ldap_browse: LDAP Handle is invalid. Try "
4390 * Everything in ldap is ** so we fudge around it...
4393 sprintf(typestring
, "%u", p
->type
);
4395 cn_value
[0] = p
->name
;
4397 info
[0] = p
->info
? p
->info
: "Unknown";
4399 location
[0] = p
->location
? p
->location
: "Unknown";
4401 make_model
[0] = p
->make_model
? p
->make_model
: "Unknown";
4402 make_model
[1] = NULL
;
4403 type
[0] = typestring
;
4409 * Get ldap entry for printer ...
4412 snprintf(dn
, sizeof(dn
), "cn=%s, ou=%s, %s", p
->name
, ServerName
,
4414 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "send_ldap_browse: dn=\"%s\"", dn
);
4416 rc
= ldap_search_rec(BrowseLDAPHandle
, dn
, LDAP_SCOPE_BASE
, NULL
,
4417 (char **)ldap_attrs
, 0, &res
);
4420 * If ldap search was not successfull then exit function
4421 * and temporary disable LDAP updates...
4424 if (rc
!= LDAP_SUCCESS
&& rc
!= LDAP_NO_SUCH_OBJECT
)
4426 if (BrowseLDAPUpdate
&&
4427 (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
))
4429 BrowseLDAPUpdate
= FALSE
;
4430 cupsdLogMessage(CUPSD_LOG_INFO
,
4431 "LDAP update temporary disabled");
4438 * Fill modification array...
4441 mods
[0].mod_type
= "cn";
4442 mods
[0].mod_values
= cn_value
;
4443 mods
[1].mod_type
= "printerDescription";
4444 mods
[1].mod_values
= info
;
4445 mods
[2].mod_type
= "printerURI";
4446 mods
[2].mod_values
= uri
;
4447 mods
[3].mod_type
= "printerLocation";
4448 mods
[3].mod_values
= location
;
4449 mods
[4].mod_type
= "printerMakeAndModel";
4450 mods
[4].mod_values
= make_model
;
4451 mods
[5].mod_type
= "printerType";
4452 mods
[5].mod_values
= type
;
4453 mods
[6].mod_type
= "objectClass";
4454 mods
[6].mod_values
= (char **)objectClass_values
;
4457 * Check if we need to insert or update the LDAP entry...
4460 if (ldap_count_entries(BrowseLDAPHandle
, res
) > 0 &&
4461 rc
!= LDAP_NO_SUCH_OBJECT
)
4464 * Printer has already been registered, check if
4465 * modification is required...
4468 e
= ldap_first_entry(BrowseLDAPHandle
, res
);
4471 * Get the required values from this entry...
4474 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "printerDescription",
4475 old_info
, sizeof(old_info
)) == -1)
4478 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "printerLocation",
4479 old_location
, sizeof(old_location
)) == -1)
4482 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "printerMakeAndModel",
4483 old_make_model
, sizeof(old_make_model
)) == -1)
4486 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "printerType",
4487 old_type_string
, sizeof(old_type_string
)) == -1)
4490 old_type
= atoi(old_type_string
);
4492 if (ldap_getval_firststring(BrowseLDAPHandle
, e
, "printerURI", old_uri
,
4493 sizeof(old_uri
)) == -1)
4497 * Check if modification is required...
4500 if (!strcmp(info
[0], old_info
) && !strcmp(uri
[0], old_uri
) &&
4501 !strcmp(location
[0], old_location
) &&
4502 !strcmp(make_model
[0], old_make_model
) && p
->type
== old_type
)
4505 * LDAP entry for the printer exists. Printer has already been registered,
4506 * no modifications required...
4509 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4510 "send_ldap_browse: No updates required for %s", p
->name
);
4515 * LDAP entry for the printer exists. Printer has already been registered,
4516 * modify the current registration...
4519 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4520 "send_ldap_browse: Replace entry for %s", p
->name
);
4522 for (i
= 0; i
< 7; i
++)
4524 pmods
[i
] = mods
+ i
;
4525 pmods
[i
]->mod_op
= LDAP_MOD_REPLACE
;
4529 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4530 if ((rcmod
= ldap_modify_ext_s(BrowseLDAPHandle
, dn
, pmods
, NULL
,
4531 NULL
)) != LDAP_SUCCESS
)
4533 if ((rcmod
= ldap_modify_s(BrowseLDAPHandle
, dn
, pmods
)) != LDAP_SUCCESS
)
4534 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4536 cupsdLogMessage(CUPSD_LOG_ERROR
,
4537 "LDAP modify for %s failed with status %d: %s",
4538 p
->name
, rcmod
, ldap_err2string(rcmod
));
4539 if (rcmod
== LDAP_SERVER_DOWN
)
4547 * No LDAP entry exists for the printer. Printer has never been registered,
4548 * add the current registration...
4551 send_ldap_ou(ServerName
, BrowseLDAPDN
, "CUPS Server");
4553 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
4554 "send_ldap_browse: Add entry for %s", p
->name
);
4556 for (i
= 0; i
< 7; i
++)
4558 pmods
[i
] = mods
+ i
;
4559 pmods
[i
]->mod_op
= LDAP_MOD_ADD
;
4563 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4564 if ((rcmod
= ldap_add_ext_s(BrowseLDAPHandle
, dn
, pmods
, NULL
,
4565 NULL
)) != LDAP_SUCCESS
)
4567 if ((rcmod
= ldap_add_s(BrowseLDAPHandle
, dn
, pmods
)) != LDAP_SUCCESS
)
4568 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4570 cupsdLogMessage(CUPSD_LOG_ERROR
,
4571 "LDAP add for %s failed with status %d: %s",
4572 p
->name
, rcmod
, ldap_err2string(rcmod
));
4573 if (rcmod
== LDAP_SERVER_DOWN
)
4578 if (rc
== LDAP_SUCCESS
)
4584 * 'ldap_dereg_printer()' - Delete printer from directory
4588 ldap_dereg_printer(cupsd_printer_t
*p
) /* I - Printer to deregister */
4590 char dn
[1024]; /* DN of the printer */
4591 int rc
; /* LDAP status */
4594 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_dereg_printer: Remove entry for %s",
4598 * Reconnect if LDAP Handle is invalid...
4601 if (!BrowseLDAPHandle
)
4608 * Get dn for printer and delete LDAP entry...
4611 snprintf(dn
, sizeof(dn
), "cn=%s, ou=%s, %s", p
->name
, ServerName
,
4613 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_dereg_printer: dn=\"%s\"", dn
);
4615 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4616 if ((rc
= ldap_delete_ext_s(BrowseLDAPHandle
, dn
, NULL
,
4617 NULL
)) != LDAP_SUCCESS
)
4619 if ((rc
= ldap_delete_s(BrowseLDAPHandle
, dn
)) != LDAP_SUCCESS
)
4620 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4622 cupsdLogMessage(CUPSD_LOG_WARN
,
4623 "LDAP delete for %s failed with status %d: %s",
4624 p
->name
, rc
, ldap_err2string(rc
));
4627 * If we had a connection problem (connection timed out, etc.)
4628 * we should reconnect and try again to delete the entry...
4631 if (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
)
4633 cupsdLogMessage(CUPSD_LOG_INFO
,
4634 "Retry deleting LDAP entry for %s after a reconnect...", p
->name
);
4637 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4638 if ((rc
= ldap_delete_ext_s(BrowseLDAPHandle
, dn
, NULL
,
4639 NULL
)) != LDAP_SUCCESS
)
4641 if ((rc
= ldap_delete_s(BrowseLDAPHandle
, dn
)) != LDAP_SUCCESS
)
4642 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4643 cupsdLogMessage(CUPSD_LOG_WARN
,
4644 "LDAP delete for %s failed with status %d: %s",
4645 p
->name
, rc
, ldap_err2string(rc
));
4652 * 'ldap_dereg_ou()' - Remove the organizational unit.
4656 ldap_dereg_ou(char *ou
, /* I - Organizational unit (servername) */
4657 char *basedn
) /* I - Dase dn */
4659 char dn
[1024]; /* DN of the printer */
4660 int rc
; /* LDAP status */
4663 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_dereg_ou: Remove entry for %s", ou
);
4666 * Reconnect if LDAP Handle is invalid...
4669 if (!BrowseLDAPHandle
)
4676 * Get dn for printer and delete LDAP entry...
4679 snprintf(dn
, sizeof(dn
), "ou=%s, %s", ou
, basedn
);
4680 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "ldap_dereg_ou: dn=\"%s\"", dn
);
4682 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4683 if ((rc
= ldap_delete_ext_s(BrowseLDAPHandle
, dn
, NULL
,
4684 NULL
)) != LDAP_SUCCESS
)
4686 if ((rc
= ldap_delete_s(BrowseLDAPHandle
, dn
)) != LDAP_SUCCESS
)
4687 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4689 cupsdLogMessage(CUPSD_LOG_WARN
,
4690 "LDAP delete for %s failed with status %d: %s",
4691 ou
, rc
, ldap_err2string(rc
));
4694 * If we had a connection problem (connection timed out, etc.)
4695 * we should reconnect and try again to delete the entry...
4698 if (rc
== LDAP_SERVER_DOWN
|| rc
== LDAP_CONNECT_ERROR
)
4700 cupsdLogMessage(CUPSD_LOG_INFO
,
4701 "Retry deleting LDAP entry for %s after a reconnect...", ou
);
4703 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4704 if ((rc
= ldap_delete_ext_s(BrowseLDAPHandle
, dn
, NULL
,
4705 NULL
)) != LDAP_SUCCESS
)
4707 if ((rc
= ldap_delete_s(BrowseLDAPHandle
, dn
)) != LDAP_SUCCESS
)
4708 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4709 cupsdLogMessage(CUPSD_LOG_WARN
,
4710 "LDAP delete for %s failed with status %d: %s",
4711 ou
, rc
, ldap_err2string(rc
));
4715 #endif /* HAVE_LDAP */
4720 * 'send_slp_browse()' - Register the specified printer with SLP.
4724 send_slp_browse(cupsd_printer_t
*p
) /* I - Printer to register */
4726 char srvurl
[HTTP_MAX_URI
], /* Printer service URI */
4727 attrs
[8192], /* Printer attributes */
4728 finishings
[1024], /* Finishings to support */
4729 make_model
[IPP_MAX_NAME
* 2],
4730 /* Make and model, quoted */
4731 location
[IPP_MAX_NAME
* 2],
4732 /* Location, quoted */
4733 info
[IPP_MAX_NAME
* 2], /* Info, quoted */
4734 *src
, /* Pointer to original string */
4735 *dst
; /* Pointer to destination string */
4736 ipp_attribute_t
*authentication
; /* uri-authentication-supported value */
4737 SLPError error
; /* SLP error, if any */
4740 cupsdLogMessage(CUPSD_LOG_DEBUG
, "send_slp_browse(%p = \"%s\")", p
,
4744 * Make the SLP service URL that conforms to the IANA
4745 * 'printer:' template.
4748 snprintf(srvurl
, sizeof(srvurl
), SLP_CUPS_SRVTYPE
":%s", p
->uri
);
4750 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "Service URL = \"%s\"", srvurl
);
4753 * Figure out the finishings string...
4756 if (p
->type
& CUPS_PRINTER_STAPLE
)
4757 strcpy(finishings
, "staple");
4759 finishings
[0] = '\0';
4761 if (p
->type
& CUPS_PRINTER_BIND
)
4764 strlcat(finishings
, ",bind", sizeof(finishings
));
4766 strcpy(finishings
, "bind");
4769 if (p
->type
& CUPS_PRINTER_PUNCH
)
4772 strlcat(finishings
, ",punch", sizeof(finishings
));
4774 strcpy(finishings
, "punch");
4777 if (p
->type
& CUPS_PRINTER_COVER
)
4780 strlcat(finishings
, ",cover", sizeof(finishings
));
4782 strcpy(finishings
, "cover");
4785 if (p
->type
& CUPS_PRINTER_SORT
)
4788 strlcat(finishings
, ",sort", sizeof(finishings
));
4790 strcpy(finishings
, "sort");
4794 strcpy(finishings
, "none");
4797 * Quote any commas in the make and model, location, and info strings...
4800 for (src
= p
->make_model
, dst
= make_model
;
4801 src
&& *src
&& dst
< (make_model
+ sizeof(make_model
) - 2);)
4803 if (*src
== ',' || *src
== '\\' || *src
== ')')
4812 strcpy(make_model
, "Unknown");
4814 for (src
= p
->location
, dst
= location
;
4815 src
&& *src
&& dst
< (location
+ sizeof(location
) - 2);)
4817 if (*src
== ',' || *src
== '\\' || *src
== ')')
4826 strcpy(location
, "Unknown");
4828 for (src
= p
->info
, dst
= info
;
4829 src
&& *src
&& dst
< (info
+ sizeof(info
) - 2);)
4831 if (*src
== ',' || *src
== '\\' || *src
== ')')
4840 strcpy(info
, "Unknown");
4843 * Get the authentication value...
4846 authentication
= ippFindAttribute(p
->attrs
, "uri-authentication-supported",
4850 * Make the SLP attribute string list that conforms to
4851 * the IANA 'printer:' template.
4854 snprintf(attrs
, sizeof(attrs
),
4855 "(printer-uri-supported=%s),"
4856 "(uri-authentication-supported=%s>),"
4858 "(uri-security-supported=tls>),"
4860 "(uri-security-supported=none>),"
4861 #endif /* HAVE_SSL */
4862 "(printer-name=%s),"
4863 "(printer-location=%s),"
4864 "(printer-info=%s),"
4865 "(printer-more-info=%s),"
4866 "(printer-make-and-model=%s),"
4867 "(printer-type=%d),"
4868 "(charset-supported=utf-8),"
4869 "(natural-language-configured=%s),"
4870 "(natural-language-supported=de,en,es,fr,it),"
4871 "(color-supported=%s),"
4872 "(finishings-supported=%s),"
4873 "(sides-supported=one-sided%s),"
4874 "(multiple-document-jobs-supported=true)"
4875 "(ipp-versions-supported=1.0,1.1)",
4876 p
->uri
, authentication
->values
[0].string
.text
, p
->name
, location
,
4877 info
, p
->uri
, make_model
, p
->type
, DefaultLanguage
,
4878 p
->type
& CUPS_PRINTER_COLOR
? "true" : "false",
4880 p
->type
& CUPS_PRINTER_DUPLEX
?
4881 ",two-sided-long-edge,two-sided-short-edge" : "");
4883 cupsdLogMessage(CUPSD_LOG_DEBUG2
, "Attributes = \"%s\"", attrs
);
4886 * Register the printer with the SLP server...
4889 error
= SLPReg(BrowseSLPHandle
, srvurl
, BrowseTimeout
,
4890 SLP_CUPS_SRVTYPE
, attrs
, SLP_TRUE
, slp_reg_callback
, 0);
4892 if (error
!= SLP_OK
)
4893 cupsdLogMessage(CUPSD_LOG_ERROR
, "SLPReg of \"%s\" failed with status %d!", p
->name
,
4899 * 'slp_attr_callback()' - SLP attribute callback
4902 static SLPBoolean
/* O - SLP_TRUE for success */
4904 SLPHandle hslp
, /* I - SLP handle */
4905 const char *attrlist
, /* I - Attribute list */
4906 SLPError errcode
, /* I - Parsing status for this attr */
4907 void *cookie
) /* I - Current printer */
4909 char *tmp
= 0; /* Temporary string */
4910 cupsd_printer_t
*p
= (cupsd_printer_t
*)cookie
;
4911 /* Current printer */
4914 (void)hslp
; /* anti-compiler-warning-code */
4917 * Bail if there was an error
4920 if (errcode
!= SLP_OK
)
4924 * Parse the attrlist to obtain things needed to build CUPS browse packet
4927 memset(p
, 0, sizeof(cupsd_printer_t
));
4929 if (slp_get_attr(attrlist
, "(printer-location=", &(p
->location
)))
4931 if (slp_get_attr(attrlist
, "(printer-info=", &(p
->info
)))
4933 if (slp_get_attr(attrlist
, "(printer-make-and-model=", &(p
->make_model
)))
4935 if (!slp_get_attr(attrlist
, "(printer-type=", &tmp
))
4936 p
->type
= atoi(tmp
);
4938 p
->type
= CUPS_PRINTER_REMOTE
;
4940 cupsdClearString(&tmp
);
4947 * 'slp_dereg_printer()' - SLPDereg() the specified printer
4951 slp_dereg_printer(cupsd_printer_t
*p
) /* I - Printer */
4953 char srvurl
[HTTP_MAX_URI
]; /* Printer service URI */
4956 cupsdLogMessage(CUPSD_LOG_DEBUG
, "slp_dereg_printer: printer=\"%s\"", p
->name
);
4958 if (!(p
->type
& CUPS_PRINTER_REMOTE
))
4961 * Make the SLP service URL that conforms to the IANA
4962 * 'printer:' template.
4965 snprintf(srvurl
, sizeof(srvurl
), SLP_CUPS_SRVTYPE
":%s", p
->uri
);
4968 * Deregister the printer...
4971 SLPDereg(BrowseSLPHandle
, srvurl
, slp_reg_callback
, 0);
4977 * 'slp_get_attr()' - Get an attribute from an SLP registration.
4980 static int /* O - 0 on success */
4981 slp_get_attr(const char *attrlist
, /* I - Attribute list string */
4982 const char *tag
, /* I - Name of attribute */
4983 char **valbuf
) /* O - Value */
4985 char *ptr1
, /* Pointer into string */
4989 cupsdClearString(valbuf
);
4991 if ((ptr1
= strstr(attrlist
, tag
)) != NULL
)
4993 ptr1
+= strlen(tag
);
4995 if ((ptr2
= strchr(ptr1
,')')) != NULL
)
5001 *valbuf
= calloc(ptr2
- ptr1
+ 1, 1);
5002 strncpy(*valbuf
, ptr1
, ptr2
- ptr1
);
5005 * Dequote the value...
5008 for (ptr1
= *valbuf
; *ptr1
; ptr1
++)
5009 if (*ptr1
== '\\' && ptr1
[1])
5010 _cups_strcpy(ptr1
, ptr1
+ 1);
5021 * 'slp_reg_callback()' - Empty SLPRegReport.
5025 slp_reg_callback(SLPHandle hslp
, /* I - SLP handle */
5026 SLPError errcode
, /* I - Error code, if any */
5027 void *cookie
) /* I - App data */
5038 * 'slp_url_callback()' - SLP service url callback
5041 static SLPBoolean
/* O - TRUE = OK, FALSE = error */
5043 SLPHandle hslp
, /* I - SLP handle */
5044 const char *srvurl
, /* I - URL of service */
5045 unsigned short lifetime
, /* I - Life of service */
5046 SLPError errcode
, /* I - Existing error code */
5047 void *cookie
) /* I - Pointer to service list */
5049 slpsrvurl_t
*s
, /* New service entry */
5050 **head
; /* Pointer to head of entry */
5054 * Let the compiler know we won't be using these vars...
5061 * Bail if there was an error
5064 if (errcode
!= SLP_OK
)
5068 * Grab the head of the list...
5071 head
= (slpsrvurl_t
**)cookie
;
5074 * Allocate a *temporary* slpsrvurl_t to hold this entry.
5077 if ((s
= (slpsrvurl_t
*)calloc(1, sizeof(slpsrvurl_t
))) == NULL
)
5081 * Copy the SLP service URL...
5084 strlcpy(s
->url
, srvurl
, sizeof(s
->url
));
5087 * Link the SLP service URL into the head of the list
5097 #endif /* HAVE_LIBSLP */
5101 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
5105 update_cups_browse(void)
5107 int i
; /* Looping var */
5108 int auth
; /* Authorization status */
5109 int len
; /* Length of name string */
5110 int bytes
; /* Number of bytes left */
5111 char packet
[1541], /* Broadcast packet */
5112 *pptr
; /* Pointer into packet */
5113 socklen_t srclen
; /* Length of source address */
5114 http_addr_t srcaddr
; /* Source address */
5115 char srcname
[1024]; /* Source hostname */
5116 unsigned address
[4]; /* Source address */
5117 unsigned type
; /* Printer type */
5118 unsigned state
; /* Printer state */
5119 char uri
[HTTP_MAX_URI
], /* Printer URI */
5120 host
[HTTP_MAX_URI
], /* Host portion of URI */
5121 resource
[HTTP_MAX_URI
], /* Resource portion of URI */
5122 info
[IPP_MAX_NAME
], /* Information string */
5123 location
[IPP_MAX_NAME
], /* Location string */
5124 make_model
[IPP_MAX_NAME
];/* Make and model string */
5125 int num_attrs
; /* Number of attributes */
5126 cups_option_t
*attrs
; /* Attributes */
5130 * Read a packet from the browse socket...
5133 srclen
= sizeof(srcaddr
);
5134 if ((bytes
= recvfrom(BrowseSocket
, packet
, sizeof(packet
) - 1, 0,
5135 (struct sockaddr
*)&srcaddr
, &srclen
)) < 0)
5138 * "Connection refused" is returned under Linux if the destination port
5139 * or address is unreachable from a previous sendto(); check for the
5140 * error here and ignore it for now...
5143 if (errno
!= ECONNREFUSED
&& errno
!= EAGAIN
)
5145 cupsdLogMessage(CUPSD_LOG_ERROR
, "Browse recv failed - %s.",
5147 cupsdLogMessage(CUPSD_LOG_ERROR
, "CUPS browsing turned off.");
5150 closesocket(BrowseSocket
);
5152 close(BrowseSocket
);
5155 cupsdRemoveSelect(BrowseSocket
);
5158 BrowseLocalProtocols
&= ~BROWSE_CUPS
;
5159 BrowseRemoteProtocols
&= ~BROWSE_CUPS
;
5165 packet
[bytes
] = '\0';
5168 * If we're about to sleep, ignore incoming browse packets.
5175 * Figure out where it came from...
5179 if (srcaddr
.addr
.sa_family
== AF_INET6
)
5181 address
[0] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[0]);
5182 address
[1] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[1]);
5183 address
[2] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[2]);
5184 address
[3] = ntohl(srcaddr
.ipv6
.sin6_addr
.s6_addr32
[3]);
5187 #endif /* AF_INET6 */
5192 address
[3] = ntohl(srcaddr
.ipv4
.sin_addr
.s_addr
);
5195 if (HostNameLookups
)
5196 httpAddrLookup(&srcaddr
, srcname
, sizeof(srcname
));
5198 httpAddrString(&srcaddr
, srcname
, sizeof(srcname
));
5200 len
= strlen(srcname
);
5208 if (httpAddrLocalhost(&srcaddr
) || !_cups_strcasecmp(srcname
, "localhost"))
5211 * Access from localhost (127.0.0.1) is always allowed...
5214 auth
= CUPSD_AUTH_ALLOW
;
5219 * Do authorization checks on the domain/address...
5222 switch (BrowseACL
->order_type
)
5225 auth
= CUPSD_AUTH_DENY
; /* anti-compiler-warning-code */
5228 case CUPSD_AUTH_ALLOW
: /* Order Deny,Allow */
5229 auth
= CUPSD_AUTH_ALLOW
;
5231 if (cupsdCheckAuth(address
, srcname
, len
, BrowseACL
->deny
))
5232 auth
= CUPSD_AUTH_DENY
;
5234 if (cupsdCheckAuth(address
, srcname
, len
, BrowseACL
->allow
))
5235 auth
= CUPSD_AUTH_ALLOW
;
5238 case CUPSD_AUTH_DENY
: /* Order Allow,Deny */
5239 auth
= CUPSD_AUTH_DENY
;
5241 if (cupsdCheckAuth(address
, srcname
, len
, BrowseACL
->allow
))
5242 auth
= CUPSD_AUTH_ALLOW
;
5244 if (cupsdCheckAuth(address
, srcname
, len
, BrowseACL
->deny
))
5245 auth
= CUPSD_AUTH_DENY
;
5251 auth
= CUPSD_AUTH_ALLOW
;
5253 if (auth
== CUPSD_AUTH_DENY
)
5255 cupsdLogMessage(CUPSD_LOG_DEBUG
,
5256 "update_cups_browse: Refused %d bytes from %s", bytes
,
5261 cupsdLogMessage(CUPSD_LOG_DEBUG2
,
5262 "update_cups_browse: (%d bytes from %s) %s", bytes
,
5269 if (sscanf(packet
, "%x%x%1023s", &type
, &state
, uri
) < 3)
5271 cupsdLogMessage(CUPSD_LOG_WARN
,
5272 "update_cups_browse: Garbled browse packet - %s", packet
);
5276 strcpy(location
, "Location Unknown");
5277 strcpy(info
, "No Information Available");
5278 make_model
[0] = '\0';
5282 if ((pptr
= strchr(packet
, '\"')) != NULL
)
5285 * Have extended information; can't use sscanf for it because not all
5286 * sscanf's allow empty strings with %[^\"]...
5289 for (i
= 0, pptr
++;
5290 i
< (sizeof(location
) - 1) && *pptr
&& *pptr
!= '\"';
5292 location
[i
] = *pptr
;
5300 while (*pptr
&& isspace(*pptr
& 255))
5305 for (i
= 0, pptr
++;
5306 i
< (sizeof(info
) - 1) && *pptr
&& *pptr
!= '\"';
5315 while (*pptr
&& isspace(*pptr
& 255))
5320 for (i
= 0, pptr
++;
5321 i
< (sizeof(make_model
) - 1) && *pptr
&& *pptr
!= '\"';
5323 make_model
[i
] = *pptr
;
5328 make_model
[i
] = '\0';
5331 num_attrs
= cupsParseOptions(pptr
, num_attrs
, &attrs
);
5337 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
5338 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
5339 type
, state
, uri
, location
, info
, make_model
));
5342 * Pull the URI apart to see if this is a local or remote printer...
5345 if (is_local_queue(uri
, host
, sizeof(host
), resource
, sizeof(resource
)))
5347 cupsFreeOptions(num_attrs
, attrs
);
5355 for (i
= 0; i
< NumRelays
; i
++)
5356 if (cupsdCheckAuth(address
, srcname
, len
, Relays
[i
].from
))
5357 if (sendto(BrowseSocket
, packet
, bytes
, 0,
5358 (struct sockaddr
*)&(Relays
[i
].to
),
5359 httpAddrLength(&(Relays
[i
].to
))) <= 0)
5361 cupsdLogMessage(CUPSD_LOG_ERROR
,
5362 "update_cups_browse: sendto failed for relay %d - %s.",
5363 i
+ 1, strerror(errno
));
5364 cupsFreeOptions(num_attrs
, attrs
);
5369 * Process the browse data...
5372 process_browse_data(uri
, host
, resource
, (cups_ptype_t
)type
,
5373 (ipp_pstate_t
)state
, location
, info
, make_model
,
5379 * 'update_lpd()' - Update the LPD configuration as needed.
5383 update_lpd(int onoff
) /* - 1 = turn on, 0 = turn off */
5390 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
5391 * setting for backwards-compatibility.
5394 if (onoff
&& !get_hostconfig("CUPS_LPD"))
5396 #endif /* __APPLE__ */
5398 if (!strncmp(LPDConfigFile
, "xinetd:///", 10))
5401 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
5404 char newfile
[1024]; /* New cups-lpd.N file */
5405 cups_file_t
*ofp
, /* Original file pointer */
5406 *nfp
; /* New file pointer */
5407 char line
[1024]; /* Line from file */
5410 snprintf(newfile
, sizeof(newfile
), "%s.N", LPDConfigFile
+ 9);
5412 if ((ofp
= cupsFileOpen(LPDConfigFile
+ 9, "r")) == NULL
)
5414 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open \"%s\" - %s",
5415 LPDConfigFile
+ 9, strerror(errno
));
5419 if ((nfp
= cupsFileOpen(newfile
, "w")) == NULL
)
5421 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create \"%s\" - %s",
5422 newfile
, strerror(errno
));
5428 * Copy all of the lines from the cups-lpd file...
5431 while (cupsFileGets(ofp
, line
, sizeof(line
)))
5435 cupsFilePrintf(nfp
, "%s\n", line
);
5436 snprintf(line
, sizeof(line
), "\tdisable = %s",
5437 onoff
? "no" : "yes");
5439 else if (!strstr(line
, "disable ="))
5440 cupsFilePrintf(nfp
, "%s\n", line
);
5445 rename(newfile
, LPDConfigFile
+ 9);
5448 else if (!strncmp(LPDConfigFile
, "launchd:///", 11))
5451 * Enable/disable LPD via the launchctl command...
5454 char *argv
[5], /* Arguments for command */
5455 *envp
[MAX_ENV
]; /* Environment for command */
5456 int pid
; /* Process ID */
5459 cupsdLoadEnv(envp
, (int)(sizeof(envp
) / sizeof(envp
[0])));
5460 argv
[0] = (char *)"launchctl";
5461 argv
[1] = (char *)(onoff
? "load" : "unload");
5462 argv
[2] = (char *)"-w";
5463 argv
[3] = LPDConfigFile
+ 10;
5466 cupsdStartProcess("/bin/launchctl", argv
, envp
, -1, -1, -1, -1, -1, 1,
5469 #endif /* __APPLE__ */
5471 cupsdLogMessage(CUPSD_LOG_INFO
, "Unknown LPDConfigFile scheme!");
5476 * 'update_polling()' - Read status messages from the poll daemons.
5480 update_polling(void)
5482 char *ptr
, /* Pointer to end of line in buffer */
5483 message
[1024]; /* Pointer to message text */
5484 int loglevel
; /* Log level for message */
5487 while ((ptr
= cupsdStatBufUpdate(PollStatusBuffer
, &loglevel
,
5488 message
, sizeof(message
))) != NULL
)
5490 if (loglevel
== CUPSD_LOG_INFO
)
5491 cupsdLogMessage(CUPSD_LOG_INFO
, "%s", message
);
5493 if (!strchr(PollStatusBuffer
->buffer
, '\n'))
5497 if (ptr
== NULL
&& !PollStatusBuffer
->bufused
)
5500 * All polling processes have died; stop polling...
5503 cupsdLogMessage(CUPSD_LOG_ERROR
,
5504 "update_polling: all polling processes have exited!");
5511 * 'update_smb()' - Update the SMB configuration as needed.
5515 update_smb(int onoff
) /* I - 1 = turn on, 0 = turn off */
5520 if (!strncmp(SMBConfigFile
, "samba:///", 9))
5523 * Enable/disable SMB via the specified smb.conf config file...
5526 char newfile
[1024]; /* New smb.conf.N file */
5527 cups_file_t
*ofp
, /* Original file pointer */
5528 *nfp
; /* New file pointer */
5529 char line
[1024]; /* Line from file */
5530 int in_printers
; /* In [printers] section? */
5533 snprintf(newfile
, sizeof(newfile
), "%s.N", SMBConfigFile
+ 8);
5535 if ((ofp
= cupsFileOpen(SMBConfigFile
+ 8, "r")) == NULL
)
5537 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to open \"%s\" - %s",
5538 SMBConfigFile
+ 8, strerror(errno
));
5542 if ((nfp
= cupsFileOpen(newfile
, "w")) == NULL
)
5544 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create \"%s\" - %s",
5545 newfile
, strerror(errno
));
5551 * Copy all of the lines from the smb.conf file...
5556 while (cupsFileGets(ofp
, line
, sizeof(line
)))
5558 if (in_printers
&& strstr(line
, "printable ="))
5559 snprintf(line
, sizeof(line
), " printable = %s",
5560 onoff
? "yes" : "no");
5562 cupsFilePrintf(nfp
, "%s\n", line
);
5565 in_printers
= !strcmp(line
, "[printers]");
5570 rename(newfile
, SMBConfigFile
+ 8);
5573 cupsdLogMessage(CUPSD_LOG_INFO
, "Unknown SMBConfigFile scheme!");
5578 * End of "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $".