2
* "$Id: dirsvc.c 9503 2011-01-22 00:07:22Z mike $"
4
* Directory services routines for the Common UNIX Printing System (CUPS).
6
* Copyright 2007-2010 by Apple Inc.
7
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
9
* These coded instructions, statements, and computer programs are the
10
* property of Apple Inc. and are protected by Federal copyright
11
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
12
* which should have been included with this file. If this file is
13
* file is missing or damaged, see the license at "http://www.cups.org/".
17
* cupsdDeregisterPrinter() - Stop sending broadcast information for a local
18
* printer and remove any pending references to
20
* cupsdLoadRemoteCache() - Load the remote printer cache.
21
* cupsdRegisterPrinter() - Start sending broadcast information for a
22
* printer or update the broadcast contents.
23
* cupsdRestartPolling() - Restart polling servers as needed.
24
* cupsdSaveRemoteCache() - Save the remote printer cache.
25
* cupsdSendBrowseList() - Send new browsing information as necessary.
26
* ldap_rebind_proc() - Callback function for LDAP rebind
27
* ldap_connect() - Start new LDAP connection
28
* ldap_reconnect() - Reconnect to LDAP Server
29
* ldap_disconnect() - Disconnect from LDAP Server
30
* cupsdStartAvahiClient() - Start an Avahi client if needed
31
* cupsdStartBrowsing() - Start sending and receiving broadcast
33
* cupsdStartPolling() - Start polling servers as needed.
34
* cupsdStopBrowsing() - Stop sending and receiving broadcast
36
* cupsdStopPolling() - Stop polling servers as needed.
37
* cupsdUpdateDNSSDName() - Update the computer name we use for
39
* cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
40
* cupsdUpdateSLPBrowse() - Get browsing information via SLP.
41
* dequote() - Remote quotes from a string.
42
* dnssdAddAlias() - Add a DNS-SD alias name.
43
* dnssdBuildTxtRecord() - Build a TXT record from printer info.
44
* dnssdComparePrinters() - Compare the registered names of two printers.
45
* dnssdDeregisterPrinter() - Stop sending broadcast information for a
47
* dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
49
* dnssdRegisterCallback() - DNSServiceRegister callback.
50
* dnssdRegisterPrinter() - Start sending broadcast information for a
51
* printer or update the broadcast contents.
52
* dnssdStop() - Stop all DNS-SD registrations.
53
* dnssdUpdate() - Handle DNS-SD queries.
54
* get_auth_info_required() - Get the auth-info-required value to advertise.
55
* get_hostconfig() - Get an /etc/hostconfig service setting.
56
* is_local_queue() - Determine whether the URI points at a local
58
* process_browse_data() - Process new browse data.
59
* process_implicit_classes() - Create/update implicit classes as needed.
60
* send_cups_browse() - Send new browsing information using the CUPS
62
* ldap_search_rec() - LDAP Search with reconnect
63
* ldap_freeres() - Free LDAPMessage
64
* ldap_getval_char() - Get first LDAP value and convert to string
65
* send_ldap_ou() - Send LDAP ou registrations.
66
* send_ldap_browse() - Send LDAP printer registrations.
67
* ldap_dereg_printer() - Delete printer from directory
68
* ldap_dereg_ou() - Remove the organizational unit.
69
* send_slp_browse() - Register the specified printer with SLP.
70
* slp_attr_callback() - SLP attribute callback
71
* slp_dereg_printer() - SLPDereg() the specified printer
72
* slp_get_attr() - Get an attribute from an SLP registration.
73
* slp_reg_callback() - Empty SLPRegReport.
74
* slp_url_callback() - SLP service url callback
75
* update_cups_browse() - Update the browse lists using the CUPS
77
* update_lpd() - Update the LPD configuration as needed.
78
* update_polling() - Read status messages from the poll daemons.
79
* update_smb() - Update the SMB configuration as needed.
83
* Include necessary headers...
94
# ifdef HAVE_COREFOUNDATION
95
# include <CoreFoundation/CoreFoundation.h>
96
# endif /* HAVE_COREFOUNDATION */
97
# ifdef HAVE_SYSTEMCONFIGURATION
98
# include <SystemConfiguration/SystemConfiguration.h>
99
# endif /* HAVE_SYSTEMCONFIGURATION */
100
# endif /* __APPLE__ */
101
#endif /* HAVE_DNSSD */
103
# include <avahi-common/domain.h>
104
#endif /* HAVE_AVAHI */
108
typedef char *cupsd_txt_record_t;
109
#endif /* HAVE_DNSSD */
111
typedef AvahiStringList *cupsd_txt_record_t;
112
#endif /* HAVE_AVAHI */
118
static char *dequote(char *d, const char *s, int dlen);
119
static char *get_auth_info_required(cupsd_printer_t *p, char *buffer,
122
static int get_hostconfig(const char *name);
123
#endif /* __APPLE__ */
124
static int is_local_queue(const char *uri, char *host, int hostlen,
125
char *resource, int resourcelen);
126
static void process_browse_data(const char *uri, const char *host,
127
const char *resource, cups_ptype_t type,
128
ipp_pstate_t state, const char *location,
129
const char *info, const char *make_model,
130
int num_attrs, cups_option_t *attrs);
131
static void process_implicit_classes(void);
132
static void send_cups_browse(cupsd_printer_t *p);
134
static LDAP *ldap_connect(void);
135
static LDAP *ldap_reconnect(void);
136
static void ldap_disconnect(LDAP *ld);
137
static int ldap_search_rec(LDAP *ld, char *base, int scope,
138
char *filter, char *attrs[],
139
int attrsonly, LDAPMessage **res);
140
static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
141
char *attr, char *retval,
142
unsigned long maxsize);
143
static void ldap_freeres(LDAPMessage *entry);
144
static void send_ldap_ou(char *ou, char *basedn, char *descstring);
145
static void send_ldap_browse(cupsd_printer_t *p);
146
static void ldap_dereg_printer(cupsd_printer_t *p);
147
static void ldap_dereg_ou(char *ou, char *basedn);
148
# ifdef HAVE_LDAP_REBIND_PROC
149
# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
150
static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
151
LDAP_CONST char *refsp,
156
static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
162
# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
163
# endif /* HAVE_LDAP_REBIND_PROC */
164
#endif /* HAVE_LDAP */
166
static void send_slp_browse(cupsd_printer_t *p);
167
#endif /* HAVE_LIBSLP */
168
static void update_cups_browse(void);
169
static void update_lpd(int onoff);
170
static void update_polling(void);
171
static void update_smb(int onoff);
174
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
175
static cupsd_txt_record_t dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
177
static void dnssdDeregisterPrinter(cupsd_printer_t *p);
178
static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
179
static void dnssdRegisterPrinter(cupsd_printer_t *p);
180
static void dnssdStop(void);
181
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
184
# ifdef HAVE_COREFOUNDATION
185
static void dnssdAddAlias(const void *key, const void *value,
187
# endif /* HAVE_COREFOUNDATION */
188
static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
190
static void dnssdRegisterCallback(DNSServiceRef sdRef,
191
DNSServiceFlags flags,
192
DNSServiceErrorType errorCode,
193
const char *name, const char *regtype,
194
const char *domain, void *context);
195
static void dnssdUpdate(void);
196
#endif /* HAVE_DNSSD */
199
static AvahiStringList *avahiPackTxtRecord(char *keyvalue[][2],
201
static void avahi_entry_group_cb (AvahiEntryGroup *group,
202
AvahiEntryGroupState state,
204
static void avahi_client_cb (AvahiClient *client,
205
AvahiClientState state,
207
#endif /* HAVE_AVAHI */
210
static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
212
"printerDescription",
214
"printerMakeAndModel",
219
#endif /* HAVE_LDAP */
227
* SLP service name for CUPS...
230
# define SLP_CUPS_SRVTYPE "service:printer"
231
# define SLP_CUPS_SRVLEN 15
235
* Printer service URL structure
238
typedef struct _slpsrvurl_s /**** SLP URL list ****/
240
struct _slpsrvurl_s *next; /* Next URL in list */
241
char url[HTTP_MAX_URI];
250
static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
251
SLPError errcode, void *cookie);
252
static void slp_dereg_printer(cupsd_printer_t *p);
253
static int slp_get_attr(const char *attrlist, const char *tag,
255
static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
257
static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
258
unsigned short lifetime,
259
SLPError errcode, void *cookie);
260
#endif /* HAVE_LIBSLP */
264
* 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
265
* local printer and remove any pending
266
* references to remote printers.
270
cupsdDeregisterPrinter(
271
cupsd_printer_t *p, /* I - Printer to register */
272
int removeit) /* I - Printer being permanently removed */
275
* Only deregister if browsing is enabled and it's a local printer...
278
cupsdLogMessage(CUPSD_LOG_DEBUG,
279
"cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
282
if (!Browsing || !p->shared ||
283
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
284
CUPS_PRINTER_SCANNER)))
288
* Announce the deletion...
291
if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
293
cups_ptype_t savedtype = p->type; /* Saved printer type */
295
p->type |= CUPS_PRINTER_DELETE;
303
if (BrowseLocalProtocols & BROWSE_SLP)
304
slp_dereg_printer(p);
305
#endif /* HAVE_LIBSLP */
308
if (BrowseLocalProtocols & BROWSE_LDAP)
309
ldap_dereg_printer(p);
310
#endif /* HAVE_LDAP */
312
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
313
if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD))
314
dnssdDeregisterPrinter(p);
315
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
320
* 'cupsdLoadRemoteCache()' - Load the remote printer cache.
324
cupsdLoadRemoteCache(void)
326
int i; /* Looping var */
327
cups_file_t *fp; /* remote.cache file */
328
int linenum; /* Current line number */
329
char line[4096], /* Line from file */
330
*value, /* Pointer to value */
331
*valueptr, /* Pointer into value */
332
scheme[32], /* Scheme portion of URI */
333
username[64], /* Username portion of URI */
335
/* Hostname portion of URI */
336
resource[HTTP_MAX_URI];
337
/* Resource portion of URI */
338
int port; /* Port number */
339
cupsd_printer_t *p; /* Current printer */
340
time_t now; /* Current time */
344
* Don't load the cache if the remote protocols are disabled...
349
cupsdLogMessage(CUPSD_LOG_DEBUG,
350
"cupsdLoadRemoteCache: Not loading remote cache.");
355
* Open the remote.cache file...
358
snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
359
if ((fp = cupsFileOpen(line, "r")) == NULL)
363
* Read printer configurations until we hit EOF...
370
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
373
* Decode the directive...
376
if (!strcasecmp(line, "<Printer") ||
377
!strcasecmp(line, "<DefaultPrinter"))
380
* <Printer name> or <DefaultPrinter name>
383
if (p == NULL && value)
386
* Add the printer and a base file type...
389
cupsdLogMessage(CUPSD_LOG_DEBUG,
390
"cupsdLoadRemoteCache: Loading printer %s...", value);
392
if ((p = cupsdFindDest(value)) != NULL)
394
if (p->type & CUPS_PRINTER_CLASS)
396
cupsdLogMessage(CUPSD_LOG_WARN,
397
"Cached remote printer \"%s\" conflicts with "
405
p = cupsdAddPrinter(value);
408
p->state = IPP_PRINTER_IDLE;
409
p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
410
p->browse_time = now;
411
p->browse_expire = now + BrowseTimeout;
414
* Set the default printer as needed...
417
if (!strcasecmp(line, "<DefaultPrinter"))
422
cupsdLogMessage(CUPSD_LOG_ERROR,
423
"Syntax error on line %d of remote.cache.", linenum);
427
else if (!strcasecmp(line, "<Class") ||
428
!strcasecmp(line, "<DefaultClass"))
431
* <Class name> or <DefaultClass name>
434
if (p == NULL && value)
437
* Add the printer and a base file type...
440
cupsdLogMessage(CUPSD_LOG_DEBUG,
441
"cupsdLoadRemoteCache: Loading class %s...", value);
443
if ((p = cupsdFindDest(value)) != NULL)
444
p->type = CUPS_PRINTER_CLASS;
446
p = cupsdAddClass(value);
449
p->state = IPP_PRINTER_IDLE;
450
p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
451
p->browse_time = now;
452
p->browse_expire = now + BrowseTimeout;
455
* Set the default printer as needed...
458
if (!strcasecmp(line, "<DefaultClass"))
463
cupsdLogMessage(CUPSD_LOG_ERROR,
464
"Syntax error on line %d of remote.cache.", linenum);
468
else if (!strcasecmp(line, "</Printer>") ||
469
!strcasecmp(line, "</Class>"))
474
* Close out the current printer...
477
cupsdSetPrinterAttrs(p);
482
cupsdLogMessage(CUPSD_LOG_ERROR,
483
"Syntax error on line %d of remote.cache.", linenum);
487
cupsdLogMessage(CUPSD_LOG_ERROR,
488
"Syntax error on line %d of remote.cache.", linenum);
490
else if (!strcasecmp(line, "Info"))
493
cupsdSetString(&p->info, value);
495
else if (!strcasecmp(line, "MakeModel"))
498
cupsdSetString(&p->make_model, value);
500
else if (!strcasecmp(line, "Location"))
503
cupsdSetString(&p->location, value);
505
else if (!strcasecmp(line, "DeviceURI"))
509
httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
510
username, sizeof(username), host, sizeof(host), &port,
511
resource, sizeof(resource));
513
cupsdSetString(&p->hostname, host);
514
cupsdSetString(&p->uri, value);
515
cupsdSetDeviceURI(p, value);
518
cupsdLogMessage(CUPSD_LOG_ERROR,
519
"Syntax error on line %d of remote.cache.", linenum);
521
else if (!strcasecmp(line, "Option") && value)
527
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
530
cupsdLogMessage(CUPSD_LOG_ERROR,
531
"Syntax error on line %d of remote.cache.", linenum);
534
for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
536
p->num_options = cupsAddOption(value, valueptr, p->num_options,
540
else if (!strcasecmp(line, "Reason"))
544
for (i = 0 ; i < p->num_reasons; i ++)
545
if (!strcmp(value, p->reasons[i]))
548
if (i >= p->num_reasons &&
549
p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
551
p->reasons[p->num_reasons] = _cupsStrAlloc(value);
556
cupsdLogMessage(CUPSD_LOG_ERROR,
557
"Syntax error on line %d of remote.cache.", linenum);
559
else if (!strcasecmp(line, "State"))
562
* Set the initial queue state...
565
if (value && !strcasecmp(value, "idle"))
566
p->state = IPP_PRINTER_IDLE;
567
else if (value && !strcasecmp(value, "stopped"))
569
p->state = IPP_PRINTER_STOPPED;
570
cupsdSetPrinterReasons(p, "+paused");
573
cupsdLogMessage(CUPSD_LOG_ERROR,
574
"Syntax error on line %d of remote.cache.", linenum);
576
else if (!strcasecmp(line, "StateMessage"))
579
* Set the initial queue state message...
583
strlcpy(p->state_message, value, sizeof(p->state_message));
585
else if (!strcasecmp(line, "Accepting"))
588
* Set the initial accepting state...
592
(!strcasecmp(value, "yes") ||
593
!strcasecmp(value, "on") ||
594
!strcasecmp(value, "true")))
597
(!strcasecmp(value, "no") ||
598
!strcasecmp(value, "off") ||
599
!strcasecmp(value, "false")))
602
cupsdLogMessage(CUPSD_LOG_ERROR,
603
"Syntax error on line %d of remote.cache.", linenum);
605
else if (!strcasecmp(line, "Type"))
608
p->type = atoi(value);
610
cupsdLogMessage(CUPSD_LOG_ERROR,
611
"Syntax error on line %d of remote.cache.", linenum);
613
else if (!strcasecmp(line, "BrowseTime"))
617
time_t t = atoi(value);
619
if (t > p->browse_expire)
620
p->browse_expire = t;
623
cupsdLogMessage(CUPSD_LOG_ERROR,
624
"Syntax error on line %d of remote.cache.", linenum);
626
else if (!strcasecmp(line, "JobSheets"))
629
* Set the initial job sheets...
634
for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
639
cupsdSetString(&p->job_sheets[0], value);
641
while (isspace(*valueptr & 255))
646
for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
651
cupsdSetString(&p->job_sheets[1], value);
655
cupsdLogMessage(CUPSD_LOG_ERROR,
656
"Syntax error on line %d of remote.cache.", linenum);
658
else if (!strcasecmp(line, "AllowUser"))
663
cupsdAddPrinterUser(p, value);
666
cupsdLogMessage(CUPSD_LOG_ERROR,
667
"Syntax error on line %d of remote.cache.", linenum);
669
else if (!strcasecmp(line, "DenyUser"))
674
cupsdAddPrinterUser(p, value);
677
cupsdLogMessage(CUPSD_LOG_ERROR,
678
"Syntax error on line %d of remote.cache.", linenum);
683
* Something else we don't understand...
686
cupsdLogMessage(CUPSD_LOG_ERROR,
687
"Unknown configuration directive %s on line %d of remote.cache.",
695
* Do auto-classing if needed...
698
process_implicit_classes();
703
* 'cupsdRegisterPrinter()' - Start sending broadcast information for a
704
* printer or update the broadcast contents.
708
cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
710
cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
713
if (!Browsing || !BrowseLocalProtocols ||
714
(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
715
CUPS_PRINTER_SCANNER)))
719
/* if (BrowseLocalProtocols & BROWSE_SLP)
720
slpRegisterPrinter(p); */
721
#endif /* HAVE_LIBSLP */
723
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
724
if ((BrowseLocalProtocols & BROWSE_DNSSD))
725
dnssdRegisterPrinter(p);
726
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
731
* 'cupsdRestartPolling()' - Restart polling servers as needed.
735
cupsdRestartPolling(void)
737
int i; /* Looping var */
738
cupsd_dirsvc_poll_t *pollp; /* Current polling server */
741
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
743
kill(pollp->pid, SIGHUP);
748
* 'cupsdSaveRemoteCache()' - Save the remote printer cache.
752
cupsdSaveRemoteCache(void)
754
int i; /* Looping var */
755
cups_file_t *fp; /* printers.conf file */
756
char temp[1024], /* Temporary string */
757
value[2048]; /* Value string */
758
cupsd_printer_t *printer; /* Current printer class */
759
time_t curtime; /* Current time */
760
struct tm *curdate; /* Current date */
761
cups_option_t *option; /* Current option */
765
* Create the remote.cache file...
768
snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
770
if ((fp = cupsFileOpen(temp, "w")) == NULL)
772
cupsdLogMessage(CUPSD_LOG_ERROR,
773
"Unable to save remote.cache - %s", strerror(errno));
777
cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
780
* Restrict access to the file...
783
fchown(cupsFileNumber(fp), getuid(), Group);
784
fchmod(cupsFileNumber(fp), ConfigFilePerm);
787
* Write a small header to the file...
790
curtime = time(NULL);
791
curdate = localtime(&curtime);
792
strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
794
cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
795
cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
798
* Write each local printer known to the system...
801
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
803
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
806
* Skip local destinations...
809
if (!(printer->type & CUPS_PRINTER_DISCOVERED))
813
* Write printers as needed...
816
if (printer == DefaultPrinter)
817
cupsFilePuts(fp, "<Default");
819
cupsFilePutChar(fp, '<');
821
if (printer->type & CUPS_PRINTER_CLASS)
822
cupsFilePrintf(fp, "Class %s>\n", printer->name);
824
cupsFilePrintf(fp, "Printer %s>\n", printer->name);
826
cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
829
cupsFilePutConf(fp, "Info", printer->info);
831
if (printer->location)
832
cupsFilePutConf(fp, "Location", printer->location);
834
if (printer->make_model)
835
cupsFilePutConf(fp, "MakeModel", printer->make_model);
837
cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
839
if (printer->state == IPP_PRINTER_STOPPED)
840
cupsFilePuts(fp, "State Stopped\n");
842
cupsFilePuts(fp, "State Idle\n");
844
for (i = 0; i < printer->num_reasons; i ++)
845
cupsFilePutConf(fp, "Reason", printer->reasons[i]);
847
cupsFilePrintf(fp, "Type %d\n", printer->type);
849
if (printer->accepting)
850
cupsFilePuts(fp, "Accepting Yes\n");
852
cupsFilePuts(fp, "Accepting No\n");
854
snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
855
printer->job_sheets[1]);
856
cupsFilePutConf(fp, "JobSheets", value);
858
for (i = 0; i < printer->num_users; i ++)
859
cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
862
for (i = printer->num_options, option = printer->options;
866
snprintf(value, sizeof(value), "%s %s", option->name, option->value);
867
cupsFilePutConf(fp, "Option", value);
870
if (printer->type & CUPS_PRINTER_CLASS)
871
cupsFilePuts(fp, "</Class>\n");
873
cupsFilePuts(fp, "</Printer>\n");
881
* 'cupsdSendBrowseList()' - Send new browsing information as necessary.
885
cupsdSendBrowseList(void)
887
int count; /* Number of dests to update */
888
cupsd_printer_t *p; /* Current printer */
889
time_t ut, /* Minimum update time */
890
to; /* Timeout time */
893
if (!Browsing || !Printers)
897
* Compute the update and timeout times...
901
ut = to - BrowseInterval;
904
* Figure out how many printers need an update...
907
if (BrowseInterval > 0 && BrowseLocalProtocols)
909
int max_count; /* Maximum number to update */
913
* Throttle the number of printers we'll be updating this time
914
* around based on the number of queues that need updating and
915
* the maximum number of queues to update each second...
918
max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
920
for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
921
count < max_count && p != NULL;
922
p = (cupsd_printer_t *)cupsArrayNext(Printers))
923
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
924
CUPS_PRINTER_SCANNER)) &&
925
p->shared && p->browse_time < ut)
929
* Loop through all of the printers and send local updates as needed...
933
p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
935
p = (cupsd_printer_t *)cupsArrayFirst(Printers);
939
p = (cupsd_printer_t *)cupsArrayNext(Printers))
942
* Check for wraparound...
946
p = (cupsd_printer_t *)cupsArrayFirst(Printers);
950
else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
951
CUPS_PRINTER_SCANNER)) ||
954
else if (p->browse_time < ut)
957
* Need to send an update...
962
p->browse_time = time(NULL);
964
if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
968
if (BrowseLocalProtocols & BROWSE_SLP)
970
#endif /* HAVE_LIBSLP */
973
if (BrowseLocalProtocols & BROWSE_LDAP)
975
#endif /* HAVE_LDAP */
980
* Save where we left off so that all printers get updated...
987
* Loop through all of the printers and timeout old printers as needed...
990
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
992
p = (cupsd_printer_t *)cupsArrayNext(Printers))
995
* If this is a remote queue, see if it needs to be timed out...
998
if ((p->type & CUPS_PRINTER_DISCOVERED) &&
999
!(p->type & CUPS_PRINTER_IMPLICIT) &&
1000
p->browse_expire < to)
1002
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
1003
"%s \'%s\' deleted by directory services (timeout).",
1004
(p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
1007
cupsdLogMessage(CUPSD_LOG_DEBUG,
1008
"Remote destination \"%s\" has timed out; "
1012
cupsArraySave(Printers);
1013
cupsdDeletePrinter(p, 1);
1014
cupsArrayRestore(Printers);
1015
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
1021
#ifdef HAVE_LDAP_REBIND_PROC
1022
# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1024
* 'ldap_rebind_proc()' - Callback function for LDAP rebind
1027
static int /* O - Result code */
1029
LDAP *RebindLDAPHandle, /* I - LDAP handle */
1030
LDAP_CONST char *refsp, /* I - ??? */
1031
ber_tag_t request, /* I - ??? */
1032
ber_int_t msgid, /* I - ??? */
1033
void *params) /* I - ??? */
1035
int rc; /* Result code */
1036
# if LDAP_API_VERSION > 3000
1037
struct berval bval; /* Bind value */
1038
# endif /* LDAP_API_VERSION > 3000 */
1041
* Bind to new LDAP server...
1044
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Rebind to %s", refsp);
1046
# if LDAP_API_VERSION > 3000
1047
bval.bv_val = BrowseLDAPPassword;
1048
bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1050
rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE,
1051
&bval, NULL, NULL, NULL);
1053
rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, BrowseLDAPPassword,
1055
# endif /* LDAP_API_VERSION > 3000 */
1061
# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1063
* 'ldap_rebind_proc()' - Callback function for LDAP rebind
1066
static int /* O - Result code */
1068
LDAP *RebindLDAPHandle, /* I - LDAP handle */
1069
char **dnp, /* I - ??? */
1070
char **passwdp, /* I - ??? */
1071
int *authmethodp, /* I - ??? */
1072
int freeit, /* I - ??? */
1073
void *arg) /* I - ??? */
1079
* Free current values...
1082
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_rebind_proc: Free values...");
1087
if (passwdp && *passwdp)
1093
* Return credentials for LDAP referal...
1096
cupsdLogMessage(CUPSD_LOG_DEBUG2,
1097
"ldap_rebind_proc: Return necessary values...");
1099
*dnp = strdup(BrowseLDAPBindDN);
1100
*passwdp = strdup(BrowseLDAPPassword);
1101
*authmethodp = LDAP_AUTH_SIMPLE;
1106
* Should never happen...
1109
cupsdLogMessage(CUPSD_LOG_ERROR,
1110
"LDAP rebind has been called with wrong freeit value!");
1114
return (LDAP_SUCCESS);
1116
# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1117
#endif /* HAVE_LDAP_REBIND_PROC */
1122
* 'ldap_connect()' - Start new LDAP connection
1125
static LDAP * /* O - LDAP handle */
1128
int rc; /* LDAP API status */
1129
int version = 3; /* LDAP version */
1130
struct berval bv = {0, ""}; /* SASL bind value */
1131
LDAP *TempBrowseLDAPHandle=NULL;
1132
/* Temporary LDAP Handle */
1133
# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1134
int ldap_ssl = 0; /* LDAP SSL indicator */
1135
int ssl_err = 0; /* LDAP SSL error value */
1136
# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1139
# ifdef HAVE_OPENLDAP
1140
# ifdef HAVE_LDAP_SSL
1142
* Set the certificate file to use for encrypted LDAP sessions...
1145
if (BrowseLDAPCACertFile)
1147
cupsdLogMessage(CUPSD_LOG_DEBUG,
1148
"ldap_connect: Setting CA certificate file \"%s\"",
1149
BrowseLDAPCACertFile);
1151
if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
1152
(void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
1153
cupsdLogMessage(CUPSD_LOG_ERROR,
1154
"Unable to set CA certificate file for LDAP "
1155
"connections: %d - %s", rc, ldap_err2string(rc));
1157
# endif /* HAVE_LDAP_SSL */
1160
* Initialize OPENLDAP connection...
1161
* LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1164
if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1165
rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
1167
rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
1169
# else /* HAVE_OPENLDAP */
1171
int ldap_port = 0; /* LDAP port */
1172
char ldap_protocol[11], /* LDAP protocol */
1173
ldap_host[255]; /* LDAP host */
1176
* Split LDAP URI into its components...
1179
if (!BrowseLDAPServer)
1181
cupsdLogMessage(CUPSD_LOG_ERROR, "BrowseLDAPServer not configured!");
1182
cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1183
BrowseLocalProtocols &= ~BROWSE_LDAP;
1184
BrowseRemoteProtocols &= ~BROWSE_LDAP;
1188
sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host,
1191
if (!strcmp(ldap_protocol, "ldap"))
1193
else if (!strcmp(ldap_protocol, "ldaps"))
1197
cupsdLogMessage(CUPSD_LOG_ERROR, "Unrecognized LDAP protocol (%s)!",
1199
cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1200
BrowseLocalProtocols &= ~BROWSE_LDAP;
1201
BrowseRemoteProtocols &= ~BROWSE_LDAP;
1208
ldap_port = LDAPS_PORT;
1210
ldap_port = LDAP_PORT;
1213
cupsdLogMessage(CUPSD_LOG_DEBUG, "ldap_connect: PROT:%s HOST:%s PORT:%d",
1214
ldap_protocol, ldap_host, ldap_port);
1217
* Initialize LDAP connection...
1222
if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
1223
rc = LDAP_OPERATIONS_ERROR;
1227
# ifdef HAVE_LDAP_SSL
1232
* Initialize SSL LDAP connection...
1235
if (BrowseLDAPCACertFile)
1237
rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
1238
if (rc != LDAP_SUCCESS)
1240
cupsdLogMessage(CUPSD_LOG_ERROR,
1241
"Failed to initialize LDAP SSL client!");
1242
rc = LDAP_OPERATIONS_ERROR;
1246
if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port,
1248
rc = LDAP_OPERATIONS_ERROR;
1255
cupsdLogMessage(CUPSD_LOG_ERROR,
1256
"LDAP SSL certificate file/database not configured!");
1257
rc = LDAP_OPERATIONS_ERROR;
1260
# else /* HAVE_LDAP_SSL */
1263
* Return error, because client libraries doesn't support SSL
1266
cupsdLogMessage(CUPSD_LOG_ERROR,
1267
"LDAP client libraries do not support SSL");
1268
rc = LDAP_OPERATIONS_ERROR;
1270
# endif /* HAVE_LDAP_SSL */
1272
# endif /* HAVE_OPENLDAP */
1275
* Check return code from LDAP initialize...
1278
if (rc != LDAP_SUCCESS)
1280
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize LDAP!");
1282
if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
1283
cupsdLogMessage(CUPSD_LOG_ERROR, "Temporarily disabling LDAP browsing...");
1286
cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1288
BrowseLocalProtocols &= ~BROWSE_LDAP;
1289
BrowseRemoteProtocols &= ~BROWSE_LDAP;
1292
ldap_disconnect(TempBrowseLDAPHandle);
1298
* Upgrade LDAP version...
1301
if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
1302
(const void *)&version) != LDAP_SUCCESS)
1304
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set LDAP protocol version %d!",
1306
cupsdLogMessage(CUPSD_LOG_ERROR, "Disabling LDAP browsing!");
1308
BrowseLocalProtocols &= ~BROWSE_LDAP;
1309
BrowseRemoteProtocols &= ~BROWSE_LDAP;
1310
ldap_disconnect(TempBrowseLDAPHandle);
1316
* Register LDAP rebind procedure...
1319
# ifdef HAVE_LDAP_REBIND_PROC
1320
# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1322
rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc,
1324
if (rc != LDAP_SUCCESS)
1325
cupsdLogMessage(CUPSD_LOG_ERROR,
1326
"Setting LDAP rebind function failed with status %d: %s",
1327
rc, ldap_err2string(rc));
1331
ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
1333
# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1334
# endif /* HAVE_LDAP_REBIND_PROC */
1337
* Start LDAP bind...
1340
# if LDAP_API_VERSION > 3000
1342
bval.bv_val = BrowseLDAPPassword;
1343
bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1345
if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1346
rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
1349
rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
1352
rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
1353
BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1354
# endif /* LDAP_API_VERSION > 3000 */
1356
if (rc != LDAP_SUCCESS)
1358
cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP bind failed with error %d: %s",
1359
rc, ldap_err2string(rc));
1361
# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1362
if (ldap_ssl && (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
1364
ssl_err = PORT_GetError();
1366
cupsdLogMessage(CUPSD_LOG_ERROR, "LDAP SSL error %d: %s", ssl_err,
1367
ldapssl_err2string(ssl_err));
1369
# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1371
ldap_disconnect(TempBrowseLDAPHandle);
1376
cupsdLogMessage(CUPSD_LOG_INFO, "LDAP connection established");
1378
return (TempBrowseLDAPHandle);
1383
* 'ldap_reconnect()' - Reconnect to LDAP Server
1386
static LDAP * /* O - New LDAP handle */
1387
ldap_reconnect(void)
1389
LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
1393
* Get a new LDAP Handle and replace the global Handle
1394
* if the new connection was successful.
1397
cupsdLogMessage(CUPSD_LOG_INFO, "Try LDAP reconnect...");
1399
TempBrowseLDAPHandle = ldap_connect();
1401
if (TempBrowseLDAPHandle != NULL)
1403
if (BrowseLDAPHandle != NULL)
1404
ldap_disconnect(BrowseLDAPHandle);
1406
BrowseLDAPHandle = TempBrowseLDAPHandle;
1409
return (BrowseLDAPHandle);
1414
* 'ldap_disconnect()' - Disconnect from LDAP Server
1418
ldap_disconnect(LDAP *ld) /* I - LDAP handle */
1420
int rc; /* Return code */
1424
* Close LDAP handle...
1427
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
1428
rc = ldap_unbind_ext_s(ld, NULL, NULL);
1430
rc = ldap_unbind_s(ld);
1431
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
1433
if (rc != LDAP_SUCCESS)
1434
cupsdLogMessage(CUPSD_LOG_ERROR,
1435
"Unbind from LDAP server failed with status %d: %s",
1436
rc, ldap_err2string(rc));
1438
#endif /* HAVE_LDAP */
1442
* 'cupsdStartAvahiClient()' - Start an Avahi client if needed
1446
cupsdStartAvahiClient(void) {
1447
if (!AvahiCupsClient && !AvahiCupsClientConnecting)
1449
if (!AvahiCupsPollHandle)
1450
AvahiCupsPollHandle = avahi_cups_poll_new ();
1451
if (AvahiCupsPollHandle)
1452
avahi_client_new (avahi_cups_poll_get (AvahiCupsPollHandle),
1453
AVAHI_CLIENT_NO_FAIL, avahi_client_cb, NULL, NULL);
1456
#endif /* HAVE_AVAHI */
1459
* 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
1463
cupsdStartBrowsing(void)
1465
int val; /* Socket option value */
1466
struct sockaddr_in addr; /* Broadcast address */
1467
cupsd_printer_t *p; /* Current printer */
1472
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1475
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
1477
if (BrowseSocket < 0)
1480
* Create the broadcast socket...
1483
if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1485
cupsdLogMessage(CUPSD_LOG_ERROR,
1486
"Unable to create broadcast socket - %s.",
1488
BrowseLocalProtocols &= ~BROWSE_CUPS;
1489
BrowseRemoteProtocols &= ~BROWSE_CUPS;
1491
if (FatalErrors & CUPSD_FATAL_BROWSE)
1492
cupsdEndProcess(getpid(), 0);
1496
if (BrowseSocket >= 0)
1499
* Bind the socket to browse port...
1502
memset(&addr, 0, sizeof(addr));
1503
addr.sin_addr.s_addr = htonl(INADDR_ANY);
1504
addr.sin_family = AF_INET;
1505
addr.sin_port = htons(BrowsePort);
1507
if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
1509
cupsdLogMessage(CUPSD_LOG_ERROR,
1510
"Unable to bind broadcast socket - %s.",
1514
closesocket(BrowseSocket);
1516
close(BrowseSocket);
1520
BrowseLocalProtocols &= ~BROWSE_CUPS;
1521
BrowseRemoteProtocols &= ~BROWSE_CUPS;
1523
if (FatalErrors & CUPSD_FATAL_BROWSE)
1524
cupsdEndProcess(getpid(), 0);
1528
if (BrowseSocket >= 0)
1531
* Set the "broadcast" flag...
1535
if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1537
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
1541
closesocket(BrowseSocket);
1543
close(BrowseSocket);
1547
BrowseLocalProtocols &= ~BROWSE_CUPS;
1548
BrowseRemoteProtocols &= ~BROWSE_CUPS;
1550
if (FatalErrors & CUPSD_FATAL_BROWSE)
1551
cupsdEndProcess(getpid(), 0);
1555
if (BrowseSocket >= 0)
1558
* Close the socket on exec...
1561
fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1564
* Finally, add the socket to the input selection set as needed...
1567
if (BrowseRemoteProtocols & BROWSE_CUPS)
1570
* We only listen if we want remote printers...
1573
cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
1581
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1582
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1585
DNSServiceErrorType error; /* Error from service creation */
1586
#endif /* HAVE_DNSSD */
1587
cupsd_listener_t *lis; /* Current listening socket */
1592
* First create a "master" connection for all registrations...
1595
if ((error = DNSServiceCreateConnection(&DNSSDRef))
1596
!= kDNSServiceErr_NoError)
1598
cupsdLogMessage(CUPSD_LOG_ERROR,
1599
"Unable to create master DNS-SD reference: %d", error);
1601
if (FatalErrors & CUPSD_FATAL_BROWSE)
1602
cupsdEndProcess(getpid(), 0);
1607
* Add the master connection to the select list...
1610
int fd = DNSServiceRefSockFD(DNSSDRef);
1612
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
1614
cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
1615
#endif /* HAVE_DNSSD */
1618
* Then get the port we use for registrations. If we are not listening
1619
* on any non-local ports, there is no sense sharing local printers via
1625
for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1627
lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1629
if (httpAddrLocalhost(&(lis->address)))
1632
if (lis->address.addr.sa_family == AF_INET)
1634
DNSSDPort = ntohs(lis->address.ipv4.sin_port);
1637
else if (lis->address.addr.sa_family == AF_INET6)
1639
DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
1645
* Create an array to track the printers we share...
1648
if (BrowseRemoteProtocols & BROWSE_DNSSD)
1649
DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
1653
* Set the computer name and register the web interface...
1656
cupsdUpdateDNSSDName();
1659
#endif /* HAVE_DNSSD */
1661
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1664
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1665
cupsdStartAvahiClient();
1666
#endif /* HAVE_AVAHI */
1669
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1672
* Open SLP handle...
1675
if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1677
cupsdLogMessage(CUPSD_LOG_ERROR,
1678
"Unable to open an SLP handle; disabling SLP browsing!");
1679
BrowseLocalProtocols &= ~BROWSE_SLP;
1680
BrowseRemoteProtocols &= ~BROWSE_SLP;
1681
BrowseSLPHandle = NULL;
1683
if (FatalErrors & CUPSD_FATAL_BROWSE)
1684
cupsdEndProcess(getpid(), 0);
1687
BrowseSLPRefresh = 0;
1690
BrowseSLPHandle = NULL;
1691
#endif /* HAVE_LIBSLP */
1694
if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1698
cupsdLogMessage(CUPSD_LOG_ERROR,
1699
"Need to set BrowseLDAPDN to use LDAP browsing!");
1700
BrowseLocalProtocols &= ~BROWSE_LDAP;
1701
BrowseRemoteProtocols &= ~BROWSE_LDAP;
1703
if (FatalErrors & CUPSD_FATAL_BROWSE)
1704
cupsdEndProcess(getpid(), 0);
1709
* Open LDAP handle...
1712
if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
1713
(FatalErrors & CUPSD_FATAL_BROWSE))
1714
cupsdEndProcess(getpid(), 0);
1717
BrowseLDAPRefresh = 0;
1719
#endif /* HAVE_LDAP */
1722
* Enable LPD and SMB printer sharing as needed through external programs...
1725
if (BrowseLocalProtocols & BROWSE_LPD)
1728
if (BrowseLocalProtocols & BROWSE_SMB)
1732
* Register the individual printers
1735
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1737
p = (cupsd_printer_t *)cupsArrayNext(Printers))
1738
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1739
CUPS_PRINTER_SCANNER)))
1740
cupsdRegisterPrinter(p);
1745
* 'cupsdStartPolling()' - Start polling servers as needed.
1749
cupsdStartPolling(void)
1751
int i; /* Looping var */
1752
cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1753
char polld[1024]; /* Poll daemon path */
1754
char sport[255]; /* Server port */
1755
char bport[255]; /* Browser port */
1756
char interval[255]; /* Poll interval */
1757
int statusfds[2]; /* Status pipe */
1758
char *argv[6]; /* Arguments */
1759
char *envp[100]; /* Environment */
1763
* Don't do anything if we aren't polling...
1766
if (NumPolled == 0 || BrowseSocket < 0)
1769
PollStatusBuffer = NULL;
1774
* Setup string arguments for polld, port and interval options.
1777
snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1779
sprintf(bport, "%d", BrowsePort);
1782
sprintf(interval, "%d", BrowseInterval);
1784
strcpy(interval, "30");
1786
argv[0] = "cups-polld";
1792
cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1795
* Create a pipe that receives the status messages from each
1799
if (cupsdOpenPipe(statusfds))
1801
cupsdLogMessage(CUPSD_LOG_ERROR,
1802
"Unable to create polling status pipes - %s.",
1805
PollStatusBuffer = NULL;
1809
PollPipe = statusfds[0];
1810
PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
1813
* Run each polling daemon, redirecting stderr to the polling pipe...
1816
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1818
sprintf(sport, "%d", pollp->port);
1820
argv[1] = pollp->hostname;
1822
if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
1823
0, DefaultProfile, NULL, &(pollp->pid)) < 0)
1825
cupsdLogMessage(CUPSD_LOG_ERROR,
1826
"cupsdStartPolling: Unable to fork polling daemon - %s",
1832
cupsdLogMessage(CUPSD_LOG_DEBUG,
1833
"cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1834
pollp->hostname, pollp->port, pollp->pid);
1837
close(statusfds[1]);
1840
* Finally, add the pipe to the input selection set...
1843
cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
1848
* 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1852
cupsdStopBrowsing(void)
1854
cupsd_printer_t *p; /* Current printer */
1857
if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1861
* De-register the individual printers
1864
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1866
p = (cupsd_printer_t *)cupsArrayNext(Printers))
1867
if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1868
CUPS_PRINTER_SCANNER)))
1869
cupsdDeregisterPrinter(p, 1);
1872
* Shut down browsing sockets...
1875
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1879
* Close the socket and remove it from the input selection set.
1883
closesocket(BrowseSocket);
1885
close(BrowseSocket);
1888
cupsdRemoveSelect(BrowseSocket);
1892
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1893
if ((BrowseLocalProtocols & BROWSE_DNSSD))
1895
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
1898
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1902
* Close SLP handle...
1905
SLPClose(BrowseSLPHandle);
1906
BrowseSLPHandle = NULL;
1908
#endif /* HAVE_LIBSLP */
1911
if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1914
ldap_dereg_ou(ServerName, BrowseLDAPDN);
1915
ldap_disconnect(BrowseLDAPHandle);
1916
BrowseLDAPHandle = NULL;
1918
#endif /* HAVE_OPENLDAP */
1921
* Disable LPD and SMB printer sharing as needed through external programs...
1924
if (BrowseLocalProtocols & BROWSE_LPD)
1927
if (BrowseLocalProtocols & BROWSE_SMB)
1933
* 'cupsdStopPolling()' - Stop polling servers as needed.
1937
cupsdStopPolling(void)
1939
int i; /* Looping var */
1940
cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1945
cupsdStatBufDelete(PollStatusBuffer);
1948
cupsdRemoveSelect(PollPipe);
1951
PollStatusBuffer = NULL;
1954
for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1956
cupsdEndProcess(pollp->pid, 0);
1960
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1962
* 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1966
cupsdUpdateDNSSDName(void)
1969
DNSServiceErrorType error; /* Error from service creation */
1970
#endif /* HAVE_DNSSD */
1972
int ret; /* Error from service creation */
1973
#endif /* HAVE_AVAHI */
1974
char webif[1024]; /* Web interface share name */
1975
#ifdef HAVE_COREFOUNDATION_H
1976
SCDynamicStoreRef sc; /* Context for dynamic store */
1977
CFDictionaryRef btmm; /* Back-to-My-Mac domains */
1978
CFStringEncoding nameEncoding; /* Encoding of computer name */
1979
CFStringRef nameRef; /* Host name CFString */
1980
char nameBuffer[1024]; /* C-string buffer */
1981
#endif /* HAVE_COREFOUNDATION_H */
1985
* Only share the web interface and printers when non-local listening is
1994
* Get the computer name as a c-string...
1997
#ifdef HAVE_COREFOUNDATION_H
1998
sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
2003
* Get the computer name from the dynamic store...
2006
cupsdClearString(&DNSSDComputerName);
2008
if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
2010
if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
2011
kCFStringEncodingUTF8))
2013
cupsdLogMessage(CUPSD_LOG_DEBUG,
2014
"Dynamic store computer name is \"%s\".", nameBuffer);
2015
cupsdSetString(&DNSSDComputerName, nameBuffer);
2021
if (!DNSSDComputerName)
2024
* Use the ServerName instead...
2027
cupsdLogMessage(CUPSD_LOG_DEBUG,
2028
"Using ServerName \"%s\" as computer name.", ServerName);
2029
cupsdSetString(&DNSSDComputerName, ServerName);
2033
* Get the local hostname from the dynamic store...
2036
cupsdClearString(&DNSSDHostName);
2038
if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
2040
if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
2041
kCFStringEncodingUTF8))
2043
cupsdLogMessage(CUPSD_LOG_DEBUG,
2044
"Dynamic store host name is \"%s\".", nameBuffer);
2045
cupsdSetString(&DNSSDHostName, nameBuffer);
2054
* Use the ServerName instead...
2057
cupsdLogMessage(CUPSD_LOG_DEBUG,
2058
"Using ServerName \"%s\" as host name.", ServerName);
2059
cupsdSetString(&DNSSDHostName, ServerName);
2063
* Get any Back-to-My-Mac domains and add them as aliases...
2066
cupsdFreeAliases(DNSSDAlias);
2069
btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
2070
if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
2072
cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
2073
(int)CFDictionaryGetCount(btmm));
2074
CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
2077
cupsdLogMessage(CUPSD_LOG_ERROR,
2078
"Bad Back to My Mac data in dynamic store!");
2080
cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
2088
#endif /* HAVE_COREFOUNDATION_H */
2090
cupsdSetString(&DNSSDComputerName, ServerName);
2091
cupsdSetString(&DNSSDHostName, ServerName);
2095
* Then (re)register the web interface if enabled...
2100
if (DNSSDComputerName)
2101
snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
2103
strlcpy(webif, "CUPS Web Interface", sizeof(webif));
2107
DNSServiceRefDeallocate(WebIFRef);
2109
WebIFRef = DNSSDRef;
2110
if ((error = DNSServiceRegister(&WebIFRef,
2111
kDNSServiceFlagsShareConnection,
2112
0, webif, "_http._tcp", NULL,
2113
NULL, htons(DNSSDPort), 7,
2114
"\006path=/", dnssdRegisterCallback,
2115
NULL)) != kDNSServiceErr_NoError)
2116
cupsdLogMessage(CUPSD_LOG_ERROR,
2117
"DNS-SD web interface registration failed: %d", error);
2118
#endif /* HAVE_DNSSD */
2121
if (!AvahiCupsClient)
2123
* Client not yet running.
2127
if (AvahiWebIFGroup)
2128
avahi_entry_group_reset (AvahiWebIFGroup);
2130
AvahiWebIFGroup = avahi_entry_group_new (AvahiCupsClient,
2131
avahi_entry_group_cb,
2134
if (AvahiWebIFGroup)
2136
ret = avahi_entry_group_add_service (AvahiWebIFGroup,
2141
"_http._tcp", /* type */
2144
DNSSDPort, /* port */
2147
ret = avahi_entry_group_commit (AvahiWebIFGroup);
2150
cupsdLogMessage (CUPSD_LOG_ERROR,
2151
"Avahi web interface registration failed: %d", ret);
2153
#endif /* HAVE_AVAHI */
2156
#endif /* HAVE_DNSSD */
2161
* 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
2165
cupsdUpdateLDAPBrowse(void)
2167
char uri[HTTP_MAX_URI], /* Printer URI */
2168
host[HTTP_MAX_URI], /* Hostname */
2169
resource[HTTP_MAX_URI], /* Resource path */
2170
location[1024], /* Printer location */
2171
info[1024], /* Printer information */
2172
make_model[1024], /* Printer make and model */
2173
type_num[30]; /* Printer type number */
2174
int type; /* Printer type */
2175
int rc; /* LDAP status */
2176
int limit; /* Size limit */
2177
LDAPMessage *res, /* LDAP search results */
2178
*e; /* Current entry from search */
2180
cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
2182
BrowseLDAPRefresh = time(NULL) + BrowseInterval;
2185
* Reconnect if LDAP Handle is invalid...
2188
if (! BrowseLDAPHandle)
2195
* Search for cups printers in LDAP directory...
2198
rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
2199
"(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
2202
* If ldap search was successfull then exit function
2203
* and temporary disable LDAP updates...
2206
if (rc != LDAP_SUCCESS)
2208
if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
2210
BrowseLDAPUpdate = FALSE;
2211
cupsdLogMessage(CUPSD_LOG_INFO,
2212
"LDAP update temporary disabled");
2218
* If LDAP updates were disabled, we will reenable them...
2221
if (! BrowseLDAPUpdate)
2223
BrowseLDAPUpdate = TRUE;
2224
cupsdLogMessage(CUPSD_LOG_INFO,
2225
"LDAP update enabled");
2229
* Count LDAP entries and return if no entry exist...
2232
limit = ldap_count_entries(BrowseLDAPHandle, res);
2233
cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
2241
* Loop through the available printers...
2244
for (e = ldap_first_entry(BrowseLDAPHandle, res);
2246
e = ldap_next_entry(BrowseLDAPHandle, e))
2249
* Get the required values from this entry...
2252
if (ldap_getval_firststring(BrowseLDAPHandle, e,
2253
"printerDescription", info, sizeof(info)) == -1)
2256
if (ldap_getval_firststring(BrowseLDAPHandle, e,
2257
"printerLocation", location, sizeof(location)) == -1)
2260
if (ldap_getval_firststring(BrowseLDAPHandle, e,
2261
"printerMakeAndModel", make_model, sizeof(make_model)) == -1)
2264
if (ldap_getval_firststring(BrowseLDAPHandle, e,
2265
"printerType", type_num, sizeof(type_num)) == -1)
2268
type = atoi(type_num);
2270
if (ldap_getval_firststring(BrowseLDAPHandle, e,
2271
"printerURI", uri, sizeof(uri)) == -1)
2275
* Process the entry as browse data...
2278
if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2279
process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
2280
location, info, make_model, 0, NULL);
2286
#endif /* HAVE_LDAP */
2291
* 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
2295
cupsdUpdateSLPBrowse(void)
2297
slpsrvurl_t *s, /* Temporary list of service URLs */
2298
*next; /* Next service in list */
2299
cupsd_printer_t p; /* Printer information */
2300
const char *uri; /* Pointer to printer URI */
2301
char host[HTTP_MAX_URI], /* Host portion of URI */
2302
resource[HTTP_MAX_URI]; /* Resource portion of URI */
2306
* Reset the refresh time...
2309
BrowseSLPRefresh = time(NULL) + BrowseInterval;
2312
* Poll for remote printers using SLP...
2317
SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
2318
slp_url_callback, &s);
2321
* Loop through the list of available printers...
2327
* Save the "next" pointer...
2333
* Load a cupsd_printer_t structure with the SLP service attributes...
2336
SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
2339
* Process this printer entry...
2342
uri = s->url + SLP_CUPS_SRVLEN + 1;
2344
if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
2347
* Pull the URI apart to see if this is a local or remote printer...
2350
if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2351
process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
2352
p.location, p.info, p.make_model, 0, NULL);
2356
* Free this listing...
2359
cupsdClearString(&p.info);
2360
cupsdClearString(&p.location);
2361
cupsdClearString(&p.make_model);
2366
#endif /* HAVE_LIBSLP */
2370
* 'dequote()' - Remote quotes from a string.
2373
static char * /* O - Dequoted string */
2374
dequote(char *d, /* I - Destination string */
2375
const char *s, /* I - Source string */
2376
int dlen) /* I - Destination length */
2378
char *dptr; /* Pointer into destination */
2383
for (dptr = d, dlen --; *s && dlen > 0; s ++)
2399
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
2401
* 'dnssdComparePrinters()' - Compare the registered names of two printers.
2404
static int /* O - Result of comparison */
2405
dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
2406
cupsd_printer_t *b)/* I - Second printer */
2417
return (strcasecmp(a->reg_name, b->reg_name));
2422
* 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2427
dnssdDeregisterPrinter(
2428
cupsd_printer_t *p) /* I - Printer */
2430
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2437
* Closing the socket deregisters the service
2442
DNSServiceRefDeallocate(p->ipp_ref);
2449
* p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
2458
DNSServiceRefDeallocate(p->printer_ref);
2459
p->printer_ref = NULL;
2465
* p->printer_txt is malloc'd, not _cupsStrAlloc'd...
2468
free(p->printer_txt);
2469
p->printer_txt = NULL;
2471
#endif /* HAVE_DNSSD */
2475
avahi_entry_group_reset (p->avahi_group);
2476
avahi_entry_group_free (p->avahi_group);
2477
p->avahi_group = NULL;
2480
avahi_string_list_free (p->ipp_txt);
2483
avahi_string_list_free (p->printer_txt);
2485
p->ipp_txt = p->printer_txt = NULL;
2487
#endif /* HAVE_AVAHI */
2490
* Remove the printer from the array of DNS-SD printers, then clear the
2491
* registered name...
2494
cupsArrayRemove(DNSSDPrinters, p);
2495
cupsdClearString(&p->reg_name);
2500
* 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2501
* or update the broadcast contents.
2505
dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2508
DNSServiceErrorType se; /* dnssd errors */
2509
char *ipp_txt, /* IPP TXT record buffer */
2510
*printer_txt; /* LPD TXT record buffer */
2511
int ipp_len, /* IPP TXT record length */
2512
printer_len; /* LPD TXT record length */
2513
char name[1024]; /* Service name */
2514
#endif /* HAVE_DNSSD */
2516
int ret; /* Error code */
2517
AvahiStringList *ipp_txt, /* IPP TXT record list */
2518
*printer_txt; /* LPD TXT record buffer */
2519
char name[AVAHI_LABEL_MAX]; /* Service name */
2520
#endif /* HAVE_AVAHI */
2521
const char *regtype; /* Registration type */
2522
char regsubtype[64], /* Registration subtype */
2523
*nameptr; /* Pointer into name */
2530
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2531
!p->ipp_ref ? "new" : "update");
2533
#endif /* HAVE_DNSSD */
2535
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2536
!p->avahi_group ? "new" : "update");
2537
#endif /* HAVE_AVAHI */
2540
* If per-printer sharing was just disabled make sure we're not
2541
* registered before returning.
2546
dnssdDeregisterPrinter(p);
2551
* The registered name takes the form of "<printer-info> @ <computer name>"...
2554
if (p->info && strlen(p->info) > 0)
2556
if (DNSSDComputerName)
2559
* Make sure there is room for at least 15 characters of
2560
* DNSSDComputerName.
2563
assert(sizeof(name) >= 15 + 4);
2564
nameptr = name + strlcpy(name, p->info,
2566
strnlen(DNSSDComputerName, 15));
2567
nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
2568
strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
2571
strlcpy(name, p->info, sizeof(name));
2573
else if (DNSSDComputerName)
2576
* Make sure there is room for at least 15 characters of
2577
* DNSSDComputerName.
2580
assert(sizeof(name) >= 15 + 4);
2581
nameptr = name + strlcpy(name, p->info,
2583
strnlen(DNSSDComputerName, 15));
2584
nameptr += strlcpy(nameptr, " @ ", sizeof(name) - (nameptr - name));
2585
strlcpy(nameptr, DNSSDComputerName, sizeof(name) - (nameptr - name));
2588
strlcpy(name, p->name, sizeof(name));
2591
* If an existing printer was renamed, unregister it and start over...
2594
if (p->reg_name && strcmp(p->reg_name, name))
2595
dnssdDeregisterPrinter(p);
2599
cupsdSetString(&p->reg_name, name);
2600
cupsArrayAdd(DNSSDPrinters, p);
2604
* Register IPP and (optionally) LPD...
2608
ipp_len = 0; /* anti-compiler-warning-code */
2609
ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2612
(ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)))
2615
* Update the existing registration...
2618
/* A TTL of 0 means use record's original value (Radar 3176248) */
2619
if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt,
2620
0)) == kDNSServiceErr_NoError)
2625
p->ipp_txt = ipp_txt;
2626
p->ipp_len = ipp_len;
2632
* Failed to update record, lets close this reference and move on...
2635
cupsdLogMessage(CUPSD_LOG_ERROR,
2636
"Unable to update IPP DNS-SD record for %s - %d", p->name,
2639
DNSServiceRefDeallocate(p->ipp_ref);
2647
* Initial registration. Use the _fax subtype for fax queues...
2650
regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
2653
cupsdLogMessage(CUPSD_LOG_DEBUG,
2654
"Registering DNS-SD printer %s with name \"%s\" and "
2655
"type \"%s\"", p->name, name, regtype);
2658
* Register the queue, dropping characters as needed until we succeed...
2661
nameptr = name + strlen(name);
2665
p->ipp_ref = DNSSDRef;
2666
if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
2667
0, name, regtype, NULL, NULL,
2668
htons(DNSSDPort), ipp_len, ipp_txt,
2669
dnssdRegisterCallback,
2670
p)) == kDNSServiceErr_BadParam)
2673
* Name is too long, drop trailing characters, taking into account
2679
while (nameptr > name && (*nameptr & 0xc0) == 0x80)
2686
while (se == kDNSServiceErr_BadParam && nameptr > name);
2688
if (se == kDNSServiceErr_NoError)
2690
p->ipp_txt = ipp_txt;
2691
p->ipp_len = ipp_len;
2695
cupsdLogMessage(CUPSD_LOG_WARN,
2696
"DNS-SD IPP registration of \"%s\" failed: %d",
2703
if (BrowseLocalProtocols & BROWSE_LPD)
2705
printer_len = 0; /* anti-compiler-warning-code */
2706
printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
2708
if (p->printer_ref &&
2709
(printer_len != p->printer_len ||
2710
memcmp(printer_txt, p->printer_txt, printer_len)))
2713
* Update the existing registration...
2716
/* A TTL of 0 means use record's original value (Radar 3176248) */
2717
if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
2719
0)) == kDNSServiceErr_NoError)
2722
free(p->printer_txt);
2724
p->printer_txt = printer_txt;
2725
p->printer_len = printer_len;
2731
* Failed to update record, lets close this reference and move on...
2734
cupsdLogMessage(CUPSD_LOG_ERROR,
2735
"Unable to update LPD DNS-SD record for %s - %d",
2738
DNSServiceRefDeallocate(p->printer_ref);
2739
p->printer_ref = NULL;
2743
if (!p->printer_ref)
2746
* Initial registration...
2749
cupsdLogMessage(CUPSD_LOG_DEBUG,
2750
"Registering DNS-SD printer %s with name \"%s\" and "
2751
"type \"_printer._tcp\"", p->name, name);
2753
p->printer_ref = DNSSDRef;
2754
if ((se = DNSServiceRegister(&p->printer_ref,
2755
kDNSServiceFlagsShareConnection,
2756
0, name, "_printer._tcp", NULL, NULL,
2757
htons(515), printer_len, printer_txt,
2758
dnssdRegisterCallback,
2759
p)) == kDNSServiceErr_NoError)
2761
p->printer_txt = printer_txt;
2762
p->printer_len = printer_len;
2766
cupsdLogMessage(CUPSD_LOG_WARN,
2767
"DNS-SD LPD registration of \"%s\" failed: %d",
2774
#endif /* HAVE_DNSSD */
2776
if (!AvahiCupsClient)
2778
* Client not running yet. The client callback will call us again later.
2782
ipp_txt = dnssdBuildTxtRecord(NULL, p, 0);
2783
printer_txt = dnssdBuildTxtRecord(NULL, p, 1);
2784
regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" : "_ipp._tcp";
2785
snprintf(regsubtype, sizeof(regsubtype), "_universal._sub.%s", regtype);
2787
if (p->avahi_group && p->ipp_txt && ipp_txt &&
2788
!avahi_string_list_equal (p->ipp_txt, ipp_txt))
2791
* Update the existing registration...
2794
avahi_string_list_free (p->ipp_txt);
2797
avahi_string_list_free (p->printer_txt);
2799
ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
2802
0, name, regtype, NULL,
2807
p->ipp_txt = ipp_txt;
2810
if (BrowseLocalProtocols & BROWSE_LPD)
2812
ret = avahi_entry_group_update_service_txt_strlst (p->avahi_group,
2816
"_printer._tcp", NULL,
2822
p->printer_txt = printer_txt;
2826
ret = avahi_entry_group_commit (p->avahi_group);
2830
cupsdLogMessage (CUPSD_LOG_ERROR,
2831
"Failed to update TXT record for %s: %d",
2833
avahi_entry_group_reset (p->avahi_group);
2834
avahi_entry_group_free (p->avahi_group);
2835
p->avahi_group = NULL;
2836
ipp_txt = p->ipp_txt;
2841
if (!p->avahi_group)
2844
* Initial registration. Use the _fax subtype for fax queues...
2847
p->avahi_group = avahi_entry_group_new (AvahiCupsClient,
2848
avahi_entry_group_cb,
2851
cupsdLogMessage(CUPSD_LOG_DEBUG,
2852
"Registering Avahi printer %s with name \"%s\" and "
2853
"type \"%s\"", p->name, name, regtype);
2855
if (!p->avahi_group)
2861
ret = avahi_entry_group_add_service_strlst (p->avahi_group,
2864
0, name, regtype, NULL, NULL,
2870
p->ipp_txt = ipp_txt;
2873
if (BrowseLocalProtocols & BROWSE_LPD)
2875
cupsdLogMessage(CUPSD_LOG_DEBUG,
2876
"Registering Avahi printer %s with name \"%s\" and "
2877
"type \"_printer._tcp\"", p->name, name);
2879
ret = avahi_entry_group_add_service_strlst (p->avahi_group,
2883
"_printer._tcp", NULL, NULL,
2889
p->printer_txt = printer_txt;
2894
ret = avahi_entry_group_add_service_subtype(p->avahi_group,
2903
ret = avahi_entry_group_commit (p->avahi_group);
2908
cupsdLogMessage (CUPSD_LOG_ERROR,
2909
"Failed to add Avahi entry for %s: %d",
2913
avahi_entry_group_reset (p->avahi_group);
2914
avahi_entry_group_free (p->avahi_group);
2915
p->avahi_group = NULL;
2917
ipp_txt = p->ipp_txt;
2923
avahi_string_list_free (ipp_txt);
2926
avahi_string_list_free (printer_txt);
2927
#endif /* HAVE_AVAHI */
2932
* 'dnssdStop()' - Stop all DNS-SD registrations.
2938
cupsd_printer_t *p; /* Current printer */
2943
#endif /* HAVE_DNSSD */
2946
* De-register the individual printers
2949
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2951
p = (cupsd_printer_t *)cupsArrayNext(Printers))
2952
dnssdDeregisterPrinter(p);
2956
* Shutdown the rest of the service refs...
2961
DNSServiceRefDeallocate(WebIFRef);
2967
DNSServiceRefDeallocate(RemoteRef);
2971
cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
2973
DNSServiceRefDeallocate(DNSSDRef);
2975
#endif /* HAVE_DNSSD */
2977
cupsArrayDelete(DNSSDPrinters);
2978
DNSSDPrinters = NULL;
2985
* 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2988
static cupsd_txt_record_t /* O - TXT record */
2989
dnssdBuildTxtRecord(
2990
int *txt_len, /* O - TXT record length */
2991
cupsd_printer_t *p, /* I - Printer information */
2992
int for_lpd) /* I - 1 = LPD, 0 = IPP */
2994
int i; /* Looping var */
2995
char adminurl_str[256], /* URL for th admin page */
2996
type_str[32], /* Type to string buffer */
2997
state_str[32], /* State to string buffer */
2998
rp_str[1024], /* Queue name string buffer */
2999
air_str[1024], /* auth-info-required string buffer */
3000
*keyvalue[32][2]; /* Table of key/value pairs */
3004
* Load up the key value pairs...
3009
keyvalue[i ][0] = "txtvers";
3010
keyvalue[i++][1] = "1";
3012
keyvalue[i ][0] = "qtotal";
3013
keyvalue[i++][1] = "1";
3015
keyvalue[i ][0] = "rp";
3016
keyvalue[i++][1] = rp_str;
3018
strlcpy(rp_str, p->name, sizeof(rp_str));
3020
snprintf(rp_str, sizeof(rp_str), "%s/%s",
3021
(p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
3023
keyvalue[i ][0] = "ty";
3024
keyvalue[i++][1] = p->make_model ? p->make_model : "Unknown";
3026
httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str),
3027
"http", NULL, DNSSDHostName, DNSSDPort, "/%s/%s",
3028
(p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers",
3030
keyvalue[i ][0] = "adminurl";
3031
keyvalue[i++][1] = adminurl_str;
3033
keyvalue[i ][0] = "note";
3034
keyvalue[i++][1] = p->location ? p->location : "";
3036
keyvalue[i ][0] = "priority";
3037
keyvalue[i++][1] = for_lpd ? "100" : "0";
3039
keyvalue[i ][0] = "product";
3040
keyvalue[i++][1] = p->product ? p->product : "Unknown";
3042
snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
3043
snprintf(state_str, sizeof(state_str), "%d", p->state);
3045
keyvalue[i ][0] = "printer-state";
3046
keyvalue[i++][1] = state_str;
3048
keyvalue[i ][0] = "printer-type";
3049
keyvalue[i++][1] = type_str;
3051
keyvalue[i ][0] = "Transparent";
3052
keyvalue[i++][1] = "T";
3054
keyvalue[i ][0] = "Binary";
3055
keyvalue[i++][1] = "T";
3057
keyvalue[i ][0] = "Fax";
3058
keyvalue[i++][1] = (p->type & CUPS_PRINTER_FAX) ? "T" : "F";
3060
keyvalue[i ][0] = "Color";
3061
keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLOR) ? "T" : "F";
3063
keyvalue[i ][0] = "Duplex";
3064
keyvalue[i++][1] = (p->type & CUPS_PRINTER_DUPLEX) ? "T" : "F";
3066
keyvalue[i ][0] = "Staple";
3067
keyvalue[i++][1] = (p->type & CUPS_PRINTER_STAPLE) ? "T" : "F";
3069
keyvalue[i ][0] = "Copies";
3070
keyvalue[i++][1] = (p->type & CUPS_PRINTER_COPIES) ? "T" : "F";
3072
keyvalue[i ][0] = "Collate";
3073
keyvalue[i++][1] = (p->type & CUPS_PRINTER_COLLATE) ? "T" : "F";
3075
keyvalue[i ][0] = "Punch";
3076
keyvalue[i++][1] = (p->type & CUPS_PRINTER_PUNCH) ? "T" : "F";
3078
keyvalue[i ][0] = "Bind";
3079
keyvalue[i++][1] = (p->type & CUPS_PRINTER_BIND) ? "T" : "F";
3081
keyvalue[i ][0] = "Sort";
3082
keyvalue[i++][1] = (p->type & CUPS_PRINTER_SORT) ? "T" : "F";
3084
keyvalue[i ][0] = "Scan";
3085
keyvalue[i++][1] = (p->type & CUPS_PRINTER_MFP) ? "T" : "F";
3087
keyvalue[i ][0] = "pdl";
3088
keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
3090
keyvalue[i ][0] = "URF";
3091
keyvalue[i++][1] = "none";
3093
if (get_auth_info_required(p, air_str, sizeof(air_str)))
3095
keyvalue[i ][0] = "air";
3096
keyvalue[i++][1] = air_str;
3100
* Then pack them into a proper txt record...
3104
return (dnssdPackTxtRecord(txt_len, keyvalue, i));
3105
#endif /* HAVE_DNSSD */
3107
return (avahiPackTxtRecord(keyvalue, i));
3108
#endif /* HAVE_AVAHI */
3110
#endif /* defined(HAVE_DNSSD) || defined(HAVE_AVAHI) */
3114
# ifdef HAVE_COREFOUNDATION
3116
* 'dnssdAddAlias()' - Add a DNS-SD alias name.
3120
dnssdAddAlias(const void *key, /* I - Key */
3121
const void *value, /* I - Value (domain) */
3122
void *context) /* I - Unused */
3124
char valueStr[1024], /* Domain string */
3125
hostname[1024]; /* Complete hostname */
3130
if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
3131
CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
3132
kCFStringEncodingUTF8))
3134
snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
3136
DNSSDAlias = cupsArrayNew(NULL, NULL);
3138
cupsdAddAlias(DNSSDAlias, hostname);
3139
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
3143
cupsdLogMessage(CUPSD_LOG_ERROR,
3144
"Bad Back to My Mac domain in dynamic store!");
3146
# endif /* HAVE_COREFOUNDATION */
3150
* 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
3151
* TXT record format.
3154
static char * /* O - TXT record */
3155
dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
3156
char *keyvalue[][2], /* I - Table of key value pairs */
3157
int count) /* I - Items in table */
3159
int i; /* Looping var */
3160
int length; /* Length of TXT record */
3161
int length2; /* Length of value */
3162
char *txtRecord; /* TXT record buffer */
3163
char *cursor; /* Looping pointer */
3167
* Calculate the buffer size
3173
for (length = i = 0; i < count; i++)
3174
length += 1 + strlen(keyvalue[i][0]) +
3175
(keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
3178
* Allocate and fill it
3181
txtRecord = malloc(length);
3186
for (cursor = txtRecord, i = 0; i < count; i++)
3189
* Drop in the p-string style length byte followed by the data
3192
length = strlen(keyvalue[i][0]);
3193
length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
3195
*cursor++ = (unsigned char)(length + length2);
3197
memcpy(cursor, keyvalue[i][0], length);
3204
memcpy(cursor, keyvalue[i][1], length2);
3215
* 'dnssdRegisterCallback()' - DNSServiceRegister callback.
3219
dnssdRegisterCallback(
3220
DNSServiceRef sdRef, /* I - DNS Service reference */
3221
DNSServiceFlags flags, /* I - Reserved for future use */
3222
DNSServiceErrorType errorCode, /* I - Error code */
3223
const char *name, /* I - Service name */
3224
const char *regtype, /* I - Service type */
3225
const char *domain, /* I - Domain. ".local" for now */
3226
void *context) /* I - User-defined context */
3228
cupsd_printer_t *p = (cupsd_printer_t *)context;
3229
/* Current printer */
3232
cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
3233
name, regtype, p ? p->name : "Web Interface",
3234
p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
3238
cupsdLogMessage(CUPSD_LOG_ERROR,
3239
"DNSServiceRegister failed with error %d", (int)errorCode);
3242
else if (p && (!p->reg_name || strcasecmp(name, p->reg_name)))
3244
cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
3247
cupsArrayRemove(DNSSDPrinters, p);
3248
cupsdSetString(&p->reg_name, name);
3249
cupsArrayAdd(DNSSDPrinters, p);
3251
LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
3257
* 'dnssdUpdate()' - Handle DNS-SD queries.
3263
DNSServiceErrorType sdErr; /* Service discovery error */
3266
if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
3268
cupsdLogMessage(CUPSD_LOG_ERROR,
3269
"DNS Service Discovery registration error %d!",
3274
#endif /* HAVE_DNSSD */
3279
* 'avahiPackTxtRecord()' - Pack an array of key/value pairs into an
3283
static AvahiStringList * /* O - new string list */
3284
avahiPackTxtRecord(char *keyvalue[][2], /* I - Table of key value pairs */
3285
int count) /* I - Items in table */
3287
AvahiStringList *strlst = NULL;
3292
elements = malloc ((1 + count) * sizeof (char *));
3296
for (i = 0; i < count; i++)
3298
len = (1 + strlen (keyvalue[i][0]) +
3299
(keyvalue[i][1] ? 1 + strlen (keyvalue[i][1]) : 1));
3300
elements[i] = malloc (len * sizeof (char));
3304
snprintf (elements[i], len, "%s=%s", keyvalue[i][0], keyvalue[i][1]);
3307
strlst = avahi_string_list_new_from_array ((const char **) elements, count);
3319
* 'avahi_entry_group_cb()' - Avahi entry group callback function.
3322
avahi_entry_group_cb (AvahiEntryGroup *group,
3323
AvahiEntryGroupState state,
3329
name = ((cupsd_printer_t *) userdata)->reg_name;
3331
name = "CUPS web interface";
3335
case AVAHI_ENTRY_GROUP_UNCOMMITED:
3336
case AVAHI_ENTRY_GROUP_REGISTERING:
3339
case AVAHI_ENTRY_GROUP_ESTABLISHED:
3340
cupsdLogMessage (CUPSD_LOG_DEBUG,
3341
"Avahi entry group established for %s", name);
3345
cupsdLogMessage (CUPSD_LOG_DEBUG,
3346
"Avahi entry group %s has state %d",
3353
* 'avahi_client_cb()' - Avahi client callback function.
3356
avahi_client_cb (AvahiClient *client,
3357
AvahiClientState state,
3360
cupsd_printer_t *printer;
3363
case AVAHI_CLIENT_S_RUNNING:
3365
* Avahi client started successfully.
3367
AvahiCupsClient = client;
3368
AvahiCupsClientConnecting = 0;
3369
cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client started");
3371
cupsdUpdateDNSSDName ();
3373
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
3375
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
3376
if (Browsing && (BrowseLocalProtocols & BROWSE_DNSSD) &&
3377
(!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
3378
CUPS_PRINTER_SCANNER))) && printer->shared)
3379
dnssdRegisterPrinter (printer);
3383
case AVAHI_CLIENT_CONNECTING:
3385
* No Avahi daemon, client is waiting.
3387
AvahiCupsClientConnecting = 1;
3388
cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client connecting");
3391
case AVAHI_CLIENT_FAILURE:
3393
* Avahi client failed, close it to allow a clean restart.
3395
cupsdLogMessage (CUPSD_LOG_ERROR,
3396
"Avahi client failed, "
3397
"closing client to allow a clean restart");
3399
for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
3401
printer = (cupsd_printer_t *)cupsArrayNext(Printers))
3402
dnssdDeregisterPrinter (printer);
3404
avahi_client_free(client);
3405
AvahiCupsClientConnecting = 0;
3406
AvahiCupsClient = NULL;
3411
cupsdLogMessage (CUPSD_LOG_DEBUG, "Avahi client state: %d", state);
3414
#endif /* HAVE_AVAHI */
3418
* 'get_auth_info_required()' - Get the auth-info-required value to advertise.
3421
static char * /* O - String or NULL if none */
3422
get_auth_info_required(
3423
cupsd_printer_t *p, /* I - Printer */
3424
char *buffer, /* I - Value buffer */
3425
size_t bufsize) /* I - Size of value buffer */
3427
cupsd_location_t *auth; /* Pointer to authentication element */
3428
char resource[1024]; /* Printer/class resource path */
3432
* If auth-info-required is set for this printer, return that...
3435
if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
3437
int i; /* Looping var */
3438
char *bufptr; /* Pointer into buffer */
3440
for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
3442
if (bufptr >= (buffer + bufsize - 2))
3448
strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer));
3449
bufptr += strlen(bufptr);
3456
* Figure out the authentication data requirements to advertise...
3459
if (p->type & CUPS_PRINTER_CLASS)
3460
snprintf(resource, sizeof(resource), "/classes/%s", p->name);
3462
snprintf(resource, sizeof(resource), "/printers/%s", p->name);
3464
if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
3465
auth->type == CUPSD_AUTH_NONE)
3466
auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
3470
int auth_type; /* Authentication type */
3472
if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
3473
auth_type = DefaultAuthType;
3477
case CUPSD_AUTH_NONE :
3480
case CUPSD_AUTH_NEGOTIATE :
3481
strlcpy(buffer, "negotiate", bufsize);
3485
strlcpy(buffer, "username,password", bufsize);
3498
* 'get_hostconfig()' - Get an /etc/hostconfig service setting.
3501
static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
3502
get_hostconfig(const char *name) /* I - Name of service */
3504
cups_file_t *fp; /* Hostconfig file */
3505
char line[1024], /* Line from file */
3506
*ptr; /* Pointer to value */
3507
int state = 1; /* State of service */
3511
* Try opening the /etc/hostconfig file; if we can't open it, assume that
3512
* the service is enabled/auto.
3515
if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
3518
* Read lines from the file until we find the service...
3521
while (cupsFileGets(fp, line, sizeof(line)))
3523
if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
3528
if (!strcasecmp(line, name))
3531
* Found the service, see if it is set to "-NO-"...
3534
if (!strncasecmp(ptr, "-NO-", 4))
3545
#endif /* __APPLE__ */
3549
* 'is_local_queue()' - Determine whether the URI points at a local queue.
3552
static int /* O - 1 = local, 0 = remote, -1 = bad URI */
3553
is_local_queue(const char *uri, /* I - Printer URI */
3554
char *host, /* O - Host string */
3555
int hostlen, /* I - Length of host buffer */
3556
char *resource, /* O - Resource string */
3557
int resourcelen) /* I - Length of resource buffer */
3559
char scheme[32], /* Scheme portion of URI */
3560
username[HTTP_MAX_URI]; /* Username portion of URI */
3561
int port; /* Port portion of URI */
3562
cupsd_netif_t *iface; /* Network interface */
3566
* Pull the URI apart to see if this is a local or remote printer...
3569
if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
3570
username, sizeof(username), host, hostlen, &port,
3571
resource, resourcelen) < HTTP_URI_OK)
3574
DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
3577
* Check for local server addresses...
3580
if (!strcasecmp(host, ServerName) && port == LocalPort)
3585
for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3587
iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3588
if (!strcasecmp(host, iface->hostname) && port == iface->port)
3592
* If we get here, the printer is remote...
3600
* 'process_browse_data()' - Process new browse data.
3604
process_browse_data(
3605
const char *uri, /* I - URI of printer/class */
3606
const char *host, /* I - Hostname */
3607
const char *resource, /* I - Resource path */
3608
cups_ptype_t type, /* I - Printer type */
3609
ipp_pstate_t state, /* I - Printer state */
3610
const char *location, /* I - Printer location */
3611
const char *info, /* I - Printer information */
3612
const char *make_model, /* I - Printer make and model */
3613
int num_attrs, /* I - Number of attributes */
3614
cups_option_t *attrs) /* I - Attributes */
3616
int i; /* Looping var */
3617
int update; /* Update printer attributes? */
3618
char finaluri[HTTP_MAX_URI], /* Final URI for printer */
3619
name[IPP_MAX_NAME], /* Name of printer */
3620
newname[IPP_MAX_NAME], /* New name of printer */
3621
*hptr, /* Pointer into hostname */
3622
*sptr; /* Pointer into ServerName */
3623
const char *shortname; /* Short queue name (queue) */
3624
char local_make_model[IPP_MAX_NAME];
3625
/* Local make and model */
3626
cupsd_printer_t *p; /* Printer information */
3627
const char *ipp_options, /* ipp-options value */
3628
*lease_duration; /* lease-duration value */
3629
int is_class; /* Is this queue a class? */
3632
cupsdLogMessage(CUPSD_LOG_DEBUG2,
3633
"process_browse_data(uri=\"%s\", host=\"%s\", "
3634
"resource=\"%s\", type=%x, state=%d, location=\"%s\", "
3635
"info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
3636
uri, host, resource, type, state,
3637
location ? location : "(nil)", info ? info : "(nil)",
3638
make_model ? make_model : "(nil)", num_attrs, attrs);
3641
* Determine if the URI contains any illegal characters in it...
3644
if (strncmp(uri, "ipp://", 6) || !host[0] ||
3645
(strncmp(resource, "/printers/", 10) &&
3646
strncmp(resource, "/classes/", 9)))
3648
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
3652
if (strchr(resource, '?') ||
3653
(!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
3654
(!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
3656
cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
3662
* OK, this isn't a local printer; add any remote options...
3665
ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
3667
if (BrowseRemoteOptions)
3669
if (BrowseRemoteOptions[0] == '?')
3672
* Override server-supplied options...
3675
snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
3677
else if (ipp_options)
3680
* Combine the server and local options...
3683
snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
3684
BrowseRemoteOptions);
3689
* Just use the local options...
3692
snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
3697
else if (ipp_options)
3700
* Just use the server-supplied options...
3703
snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
3708
* See if we already have it listed in the Printers list, and add it if not...
3711
type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
3712
type &= ~CUPS_PRINTER_IMPLICIT;
3714
hptr = strchr(host, '.');
3715
sptr = strchr(ServerName, '.');
3716
is_class = type & CUPS_PRINTER_CLASS;
3718
if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
3721
* Strip the common domain name components...
3724
while (hptr != NULL)
3726
if (!strcasecmp(hptr, sptr))
3732
hptr = strchr(hptr + 1, '.');
3739
* Remote destination is a class...
3742
if (!strncmp(resource, "/classes/", 9))
3743
snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
3747
shortname = resource + 9;
3752
* Remote destination is a printer...
3755
if (!strncmp(resource, "/printers/", 10))
3756
snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
3760
shortname = resource + 10;
3764
*hptr = '.'; /* Resource FQDN */
3766
if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
3769
* Long name doesn't exist, try short name...
3772
cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
3775
if ((p = cupsdFindDest(shortname)) == NULL)
3778
* Short name doesn't exist, use it for this shared queue.
3781
cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
3783
strlcpy(name, shortname, sizeof(name));
3788
* Short name exists...
3791
cupsdLogMessage(CUPSD_LOG_DEBUG2,
3792
"process_browse_data: %s found, type=%x, hostname=%s...",
3793
shortname, p->type, p->hostname ? p->hostname : "(nil)");
3795
if (p->type & CUPS_PRINTER_IMPLICIT)
3796
p = NULL; /* Don't replace implicit classes */
3797
else if (p->hostname && strcasecmp(p->hostname, host))
3800
* Short name exists but is for a different host. If this is a remote
3801
* queue, rename it and use the long name...
3804
if (p->type & CUPS_PRINTER_REMOTE)
3806
cupsdLogMessage(CUPSD_LOG_DEBUG,
3807
"Renamed remote %s \"%s\" to \"%s@%s\"...",
3808
is_class ? "class" : "printer", p->name, p->name,
3810
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3811
"%s \'%s\' deleted by directory services.",
3812
is_class ? "Class" : "Printer", p->name);
3814
snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
3815
cupsdRenamePrinter(p, newname);
3817
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3818
"%s \'%s\' added by directory services.",
3819
is_class ? "Class" : "Printer", p->name);
3823
* Force creation with long name...
3831
cupsdLogMessage(CUPSD_LOG_DEBUG2,
3832
"process_browse_data: %s found, type=%x, hostname=%s...",
3833
name, p->type, p->hostname ? p->hostname : "(nil)");
3838
* Queue doesn't exist; add it...
3842
p = cupsdAddClass(name);
3844
p = cupsdAddPrinter(name);
3849
cupsdClearString(&(p->hostname));
3851
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
3852
is_class ? "class" : "printer", name);
3854
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3855
"%s \'%s\' added by directory services.",
3856
is_class ? "Class" : "Printer", name);
3859
* Force the URI to point to the real server...
3862
p->type = type & ~CUPS_PRINTER_REJECTING;
3865
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3871
* Hostname not set, so this must be a cached remote printer
3872
* that was created for a pending print job...
3875
cupsdSetString(&p->hostname, host);
3876
cupsdSetString(&p->uri, uri);
3877
cupsdSetString(&p->device_uri, uri);
3880
cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
3884
* Update the state...
3888
p->browse_time = time(NULL);
3890
if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
3894
* Grab the lease-duration for the browse data; anything less then 1
3895
* second or more than 1 week gets the default BrowseTimeout...
3898
i = atoi(lease_duration);
3899
if (i < 1 || i > 604800)
3902
p->browse_expire = p->browse_time + i;
3905
p->browse_expire = p->browse_time + BrowseTimeout;
3907
if (type & CUPS_PRINTER_REJECTING)
3909
type &= ~CUPS_PRINTER_REJECTING;
3917
else if (!p->accepting)
3923
if (p->type != type)
3929
if (location && (!p->location || strcmp(p->location, location)))
3931
cupsdSetString(&p->location, location);
3935
if (info && (!p->info || strcmp(p->info, info)))
3937
cupsdSetString(&p->info, info);
3940
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3943
if (!make_model || !make_model[0])
3946
snprintf(local_make_model, sizeof(local_make_model),
3947
"Remote Class on %s", host);
3949
snprintf(local_make_model, sizeof(local_make_model),
3950
"Remote Printer on %s", host);
3953
snprintf(local_make_model, sizeof(local_make_model),
3954
"%s on %s", make_model, host);
3956
if (!p->make_model || strcmp(p->make_model, local_make_model))
3958
cupsdSetString(&p->make_model, local_make_model);
3964
if (!update && !(type & CUPS_PRINTER_DELETE))
3967
* See if we need to update the attributes...
3970
if (p->num_options != num_attrs)
3974
for (i = 0; i < num_attrs; i ++)
3975
if (strcmp(attrs[i].name, p->options[i].name) ||
3976
(!attrs[i].value != !p->options[i].value) ||
3977
(attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
3986
* Free the old options...
3989
cupsFreeOptions(p->num_options, p->options);
3992
p->num_options = num_attrs;
3995
if (type & CUPS_PRINTER_DELETE)
3997
cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3998
"%s \'%s\' deleted by directory services.",
3999
is_class ? "Class" : "Printer", p->name);
4001
cupsdExpireSubscriptions(p, NULL);
4003
cupsdDeletePrinter(p, 1);
4004
cupsdUpdateImplicitClasses();
4005
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4009
cupsdSetPrinterAttrs(p);
4010
cupsdUpdateImplicitClasses();
4014
* See if we have a default printer... If not, make the first network
4015
* default printer the default.
4018
if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
4021
* Find the first network default printer and use it...
4024
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
4026
p = (cupsd_printer_t *)cupsArrayNext(Printers))
4027
if (p->type & CUPS_PRINTER_DEFAULT)
4030
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4036
* Do auto-classing if needed...
4039
process_implicit_classes();
4044
* 'process_implicit_classes()' - Create/update implicit classes as needed.
4048
process_implicit_classes(void)
4050
int i; /* Looping var */
4051
int update; /* Update printer attributes? */
4052
char name[IPP_MAX_NAME], /* Name of printer */
4053
*hptr; /* Pointer into hostname */
4054
cupsd_printer_t *p, /* Printer information */
4055
*pclass, /* Printer class */
4056
*first; /* First printer in class */
4057
int offset, /* Offset of name */
4058
len; /* Length of name */
4061
if (!ImplicitClasses || !Printers)
4065
* Loop through all available printers and create classes as needed...
4068
for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
4069
update = 0, pclass = NULL, first = NULL;
4071
p = (cupsd_printer_t *)cupsArrayNext(Printers))
4074
* Skip implicit classes...
4077
if (p->type & CUPS_PRINTER_IMPLICIT)
4084
* If len == 0, get the length of this printer name up to the "@"
4088
cupsArraySave(Printers);
4091
!strncasecmp(p->name, name + offset, len) &&
4092
(p->name[len] == '\0' || p->name[len] == '@'))
4095
* We have more than one printer with the same name; see if
4096
* we have a class, and if this printer is a member...
4099
if (pclass && strcasecmp(pclass->name, name))
4102
cupsdSetPrinterAttrs(pclass);
4108
if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
4111
* Need to add the class...
4114
pclass = cupsdAddPrinter(name);
4115
cupsArrayAdd(ImplicitPrinters, pclass);
4117
pclass->type |= CUPS_PRINTER_IMPLICIT;
4118
pclass->accepting = 1;
4119
pclass->state = IPP_PRINTER_IDLE;
4121
cupsdSetString(&pclass->location, p->location);
4122
cupsdSetString(&pclass->info, p->info);
4124
cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
4125
cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
4129
cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
4131
cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
4133
cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
4134
"Implicit class \'%s\' added by directory services.",
4140
for (i = 0; i < pclass->num_printers; i ++)
4141
if (pclass->printers[i] == first)
4144
if (i >= pclass->num_printers)
4146
first->in_implicit_class = 1;
4147
cupsdAddPrinterToClass(pclass, first);
4153
for (i = 0; i < pclass->num_printers; i ++)
4154
if (pclass->printers[i] == p)
4157
if (i >= pclass->num_printers)
4159
p->in_implicit_class = 1;
4160
cupsdAddPrinterToClass(pclass, p);
4167
* First time around; just get name length and mark it as first
4171
if ((hptr = strchr(p->name, '@')) != NULL)
4172
len = hptr - p->name;
4174
len = strlen(p->name);
4176
if (len >= sizeof(name))
4179
* If the printer name length somehow is greater than we normally allow,
4180
* skip this printer...
4184
cupsArrayRestore(Printers);
4188
strncpy(name, p->name, len);
4192
if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
4193
!(first->type & CUPS_PRINTER_IMPLICIT))
4196
* Can't use same name as a local printer; add "Any" to the
4197
* front of the name, unless we have explicitly disabled
4198
* the "ImplicitAnyClasses"...
4201
if (ImplicitAnyClasses && len < (sizeof(name) - 4))
4204
* Add "Any" to the class name...
4207
strcpy(name, "Any");
4208
strncpy(name + 3, p->name, len);
4209
name[len + 3] = '\0';
4215
* Don't create an implicit class if we have a local printer
4216
* with the same name...
4220
cupsArrayRestore(Printers);
4228
cupsArrayRestore(Printers);
4232
* Update the last printer class as needed...
4235
if (pclass && update)
4236
cupsdSetPrinterAttrs(pclass);
4241
* 'send_cups_browse()' - Send new browsing information using the CUPS
4246
send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
4248
int i; /* Looping var */
4249
cups_ptype_t type; /* Printer type */
4250
cupsd_dirsvc_addr_t *b; /* Browse address */
4251
int bytes; /* Length of packet */
4252
char packet[1453], /* Browse data packet */
4253
uri[1024], /* Printer URI */
4254
location[1024], /* printer-location */
4255
info[1024], /* printer-info */
4257
/* printer-make-and-model */
4258
air[1024]; /* auth-info-required */
4259
cupsd_netif_t *iface; /* Network interface */
4263
* Figure out the printer type value...
4266
type = p->type | CUPS_PRINTER_REMOTE;
4269
type |= CUPS_PRINTER_REJECTING;
4271
if (p == DefaultPrinter)
4272
type |= CUPS_PRINTER_DEFAULT;
4275
* Remove quotes from printer-info, printer-location, and
4276
* printer-make-and-model attributes...
4279
dequote(location, p->location, sizeof(location));
4280
dequote(info, p->info, sizeof(info));
4283
dequote(make_model, p->make_model, sizeof(make_model));
4284
else if (p->type & CUPS_PRINTER_CLASS)
4286
if (p->num_printers > 0 && p->printers[0]->make_model)
4287
strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
4289
strlcpy(make_model, "Local Printer Class", sizeof(make_model));
4292
strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
4294
strlcpy(make_model, "Local System V Printer", sizeof(make_model));
4296
if (get_auth_info_required(p, packet, sizeof(packet)))
4297
snprintf(air, sizeof(air), " auth-info-required=%s", packet);
4302
* Send a packet to each browse address...
4305
for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
4309
* Send the browse packet to one or more interfaces...
4312
if (!strcmp(b->iface, "*"))
4315
* Send to all local interfaces...
4320
for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
4322
iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
4325
* Only send to local, IPv4 interfaces...
4328
if (!iface->is_local || !iface->port ||
4329
iface->address.addr.sa_family != AF_INET)
4332
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
4333
iface->hostname, iface->port,
4334
(p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4337
snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
4338
type, p->state, uri, location, info, make_model,
4339
p->browse_attrs ? p->browse_attrs : "", air);
4341
bytes = strlen(packet);
4343
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4344
"cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
4345
iface->name, packet);
4347
iface->broadcast.ipv4.sin_port = htons(BrowsePort);
4349
sendto(BrowseSocket, packet, bytes, 0,
4350
(struct sockaddr *)&(iface->broadcast),
4351
httpAddrLength(&(iface->broadcast)));
4354
else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
4357
* Send to the named interface using the IPv4 address...
4361
if (strcmp(b->iface, iface->name))
4366
else if (iface->address.addr.sa_family == AF_INET && iface->port)
4369
iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
4373
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
4374
iface->hostname, iface->port,
4375
(p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
4378
snprintf(packet, sizeof(packet),
4379
"%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
4380
type, p->state, uri, location, info, make_model,
4381
p->browse_attrs ? p->browse_attrs : "", air);
4383
bytes = strlen(packet);
4385
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4386
"cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
4387
iface->name, packet);
4389
iface->broadcast.ipv4.sin_port = htons(BrowsePort);
4391
sendto(BrowseSocket, packet, bytes, 0,
4392
(struct sockaddr *)&(iface->broadcast),
4393
httpAddrLength(&(iface->broadcast)));
4400
* Send the browse packet to the indicated address using
4401
* the default server name...
4404
snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
4405
type, p->state, p->uri, location, info, make_model,
4406
p->browse_attrs ? p->browse_attrs : "", air);
4408
bytes = strlen(packet);
4409
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4410
"cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
4412
if (sendto(BrowseSocket, packet, bytes, 0,
4413
(struct sockaddr *)&(b->to),
4414
httpAddrLength(&(b->to))) <= 0)
4417
* Unable to send browse packet, so remove this address from the
4421
cupsdLogMessage(CUPSD_LOG_ERROR,
4422
"cupsdSendBrowseList: sendto failed for browser "
4424
(int)(b - Browsers + 1), strerror(errno));
4427
memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
4438
* 'ldap_search_rec()' - LDAP Search with reconnect
4441
static int /* O - Return code */
4442
ldap_search_rec(LDAP *ld, /* I - LDAP handler */
4443
char *base, /* I - Base dn */
4444
int scope, /* I - LDAP search scope */
4445
char *filter, /* I - Filter string */
4446
char *attrs[], /* I - Requested attributes */
4447
int attrsonly, /* I - Return only attributes? */
4448
LDAPMessage **res) /* I - LDAP handler */
4450
int rc; /* Return code */
4451
LDAP *ldr; /* LDAP handler after reconnect */
4454
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4455
rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
4456
NULL, LDAP_NO_LIMIT, res);
4458
rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
4459
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4462
* If we have a connection problem try again...
4465
if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4467
cupsdLogMessage(CUPSD_LOG_ERROR,
4468
"LDAP search failed with status %d: %s",
4469
rc, ldap_err2string(rc));
4470
cupsdLogMessage(CUPSD_LOG_INFO,
4471
"We try the LDAP search once again after reconnecting to "
4474
ldr = ldap_reconnect();
4476
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4477
rc = ldap_search_ext_s(ldr, base, scope, filter, attrs, attrsonly, NULL,
4478
NULL, NULL, LDAP_NO_LIMIT, res);
4480
rc = ldap_search_s(ldr, base, scope, filter, attrs, attrsonly, res);
4481
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4484
if (rc == LDAP_NO_SUCH_OBJECT)
4485
cupsdLogMessage(CUPSD_LOG_DEBUG,
4486
"ldap_search_rec: LDAP entry/object not found");
4487
else if (rc != LDAP_SUCCESS)
4488
cupsdLogMessage(CUPSD_LOG_ERROR,
4489
"ldap_search_rec: LDAP search failed with status %d: %s",
4490
rc, ldap_err2string(rc));
4492
if (rc != LDAP_SUCCESS)
4500
* 'ldap_freeres()' - Free LDAPMessage
4504
ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
4506
int rc; /* Return value */
4509
rc = ldap_msgfree(entry);
4511
cupsdLogMessage(CUPSD_LOG_WARN, "Can't free LDAPMessage!");
4513
cupsdLogMessage(CUPSD_LOG_DEBUG2, "Freeing LDAPMessage was unnecessary");
4518
* 'ldap_getval_char()' - Get first LDAP value and convert to string
4521
static int /* O - Return code */
4522
ldap_getval_firststring(
4523
LDAP *ld, /* I - LDAP handler */
4524
LDAPMessage *entry, /* I - LDAP message or search result */
4525
char *attr, /* I - the wanted attribute */
4526
char *retval, /* O - String to return */
4527
unsigned long maxsize) /* I - Max string size */
4529
char *dn; /* LDAP DN */
4530
int rc = 0; /* Return code */
4531
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4532
struct berval **bval; /* LDAP value array */
4533
unsigned long size; /* String size */
4537
* Get value from LDAPMessage...
4540
if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
4543
dn = ldap_get_dn(ld, entry);
4544
cupsdLogMessage(CUPSD_LOG_WARN,
4545
"Failed to get LDAP value %s for %s!",
4552
* Check size and copy value into our string...
4556
if (size < (bval[0]->bv_len + 1))
4559
dn = ldap_get_dn(ld, entry);
4560
cupsdLogMessage(CUPSD_LOG_WARN,
4561
"Attribute %s is too big! (dn: %s)",
4566
size = bval[0]->bv_len + 1;
4568
strlcpy(retval, bval[0]->bv_val, size);
4569
ldap_value_free_len(bval);
4572
char **value; /* LDAP value */
4575
* Get value from LDAPMessage...
4578
if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
4581
dn = ldap_get_dn(ld, entry);
4582
cupsdLogMessage(CUPSD_LOG_WARN, "Failed to get LDAP value %s for %s!",
4588
strlcpy(retval, *value, maxsize);
4589
ldap_value_free(value);
4591
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4598
* 'send_ldap_ou()' - Send LDAP ou registrations.
4602
send_ldap_ou(char *ou, /* I - Servername/ou to register */
4603
char *basedn, /* I - Our base dn */
4604
char *descstring) /* I - Description for ou */
4606
int i; /* Looping var... */
4607
LDAPMod mods[3]; /* The 3 attributes we will be adding */
4608
LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
4609
LDAPMessage *res, /* Search result token */
4610
*e; /* Current entry from search */
4611
int rc; /* LDAP status */
4612
int rcmod; /* LDAP status for modifications */
4613
char dn[1024], /* DN of the organizational unit we are adding */
4614
*desc[2], /* Change records */
4616
char old_desc[1024]; /* Old description */
4617
static const char * const objectClass_values[] =
4618
{ /* The 2 objectClass's we use in */
4619
"top", /* our LDAP entries */
4620
"organizationalUnit",
4623
static const char * const ou_attrs[] =/* CUPS LDAP attributes */
4630
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
4633
* Reconnect if LDAP Handle is invalid...
4636
if (!BrowseLDAPHandle)
4638
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4639
"send_ldap_ou: LDAP Handle is invalid. Try reconnecting...");
4645
* Prepare ldap search...
4648
snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
4649
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
4653
desc[0] = descstring;
4656
mods[0].mod_type = "ou";
4657
mods[0].mod_values = ou_value;
4658
mods[1].mod_type = "description";
4659
mods[1].mod_values = desc;
4660
mods[2].mod_type = "objectClass";
4661
mods[2].mod_values = (char **)objectClass_values;
4663
rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4664
(char **)ou_attrs, 0, &res);
4667
* If ldap search was not successfull then exit function...
4670
if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4674
* Check if we need to insert or update the LDAP entry...
4677
if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4678
rc != LDAP_NO_SUCH_OBJECT)
4681
* Printserver has already been registered, check if
4682
* modification is required...
4685
e = ldap_first_entry(BrowseLDAPHandle, res);
4688
* Get the required values from this entry...
4691
if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
4692
sizeof(old_desc)) == -1)
4696
* Check if modification is required...
4699
if ( strcmp(desc[0], old_desc) == 0 )
4702
* LDAP entry for the printer exists.
4703
* Printer has already been registered,
4704
* no modifications required...
4706
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4707
"send_ldap_ou: No updates required for %s", ou);
4712
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4713
"send_ldap_ou: Replace entry for %s", ou);
4715
for (i = 0; i < 3; i ++)
4717
pmods[i] = mods + i;
4718
pmods[i]->mod_op = LDAP_MOD_REPLACE;
4722
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4723
if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4724
NULL)) != LDAP_SUCCESS)
4726
if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4727
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4729
cupsdLogMessage(CUPSD_LOG_ERROR,
4730
"LDAP modify for %s failed with status %d: %s",
4731
ou, rcmod, ldap_err2string(rcmod));
4732
if (rcmod == LDAP_SERVER_DOWN)
4740
* Printserver has never been registered,
4741
* add registration...
4744
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4745
"send_ldap_ou: Add entry for %s", ou);
4747
for (i = 0; i < 3; i ++)
4749
pmods[i] = mods + i;
4750
pmods[i]->mod_op = LDAP_MOD_ADD;
4754
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4755
if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4756
NULL)) != LDAP_SUCCESS)
4758
if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4759
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4761
cupsdLogMessage(CUPSD_LOG_ERROR,
4762
"LDAP add for %s failed with status %d: %s",
4763
ou, rcmod, ldap_err2string(rcmod));
4764
if (rcmod == LDAP_SERVER_DOWN)
4769
if (rc == LDAP_SUCCESS)
4775
* 'send_ldap_browse()' - Send LDAP printer registrations.
4779
send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
4781
int i; /* Looping var... */
4782
LDAPMod mods[7]; /* The 7 attributes we will be adding */
4783
LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
4784
LDAPMessage *res, /* Search result token */
4785
*e; /* Current entry from search */
4786
char *cn_value[2], /* Change records */
4792
typestring[255], /* String to hold printer-type */
4793
dn[1024]; /* DN of the printer we are adding */
4794
int rc; /* LDAP status */
4795
int rcmod; /* LDAP status for modifications */
4796
char old_uri[HTTP_MAX_URI], /* Printer URI */
4797
old_location[1024], /* Printer location */
4798
old_info[1024], /* Printer information */
4799
old_make_model[1024], /* Printer make and model */
4800
old_type_string[30]; /* Temporary type number */
4801
int old_type; /* Printer type */
4802
static const char * const objectClass_values[] =
4803
{ /* The 3 objectClass's we use in */
4804
"top", /* our LDAP entries */
4811
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
4814
* Exit function if LDAP updates has been disabled...
4817
if (!BrowseLDAPUpdate)
4819
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4820
"send_ldap_browse: Updates temporary disabled; "
4826
* Reconnect if LDAP Handle is invalid...
4829
if (!BrowseLDAPHandle)
4831
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4832
"send_ldap_browse: LDAP Handle is invalid. Try "
4839
* Everything in ldap is ** so we fudge around it...
4842
sprintf(typestring, "%u", p->type);
4844
cn_value[0] = p->name;
4846
info[0] = p->info ? p->info : "Unknown";
4848
location[0] = p->location ? p->location : "Unknown";
4850
make_model[0] = p->make_model ? p->make_model : "Unknown";
4851
make_model[1] = NULL;
4852
type[0] = typestring;
4858
* Get ldap entry for printer ...
4861
snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4863
cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
4865
rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4866
(char **)ldap_attrs, 0, &res);
4869
* If ldap search was not successfull then exit function
4870
* and temporary disable LDAP updates...
4873
if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4875
if (BrowseLDAPUpdate &&
4876
(rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
4878
BrowseLDAPUpdate = FALSE;
4879
cupsdLogMessage(CUPSD_LOG_INFO,
4880
"LDAP update temporary disabled");
4887
* Fill modification array...
4890
mods[0].mod_type = "cn";
4891
mods[0].mod_values = cn_value;
4892
mods[1].mod_type = "printerDescription";
4893
mods[1].mod_values = info;
4894
mods[2].mod_type = "printerURI";
4895
mods[2].mod_values = uri;
4896
mods[3].mod_type = "printerLocation";
4897
mods[3].mod_values = location;
4898
mods[4].mod_type = "printerMakeAndModel";
4899
mods[4].mod_values = make_model;
4900
mods[5].mod_type = "printerType";
4901
mods[5].mod_values = type;
4902
mods[6].mod_type = "objectClass";
4903
mods[6].mod_values = (char **)objectClass_values;
4906
* Check if we need to insert or update the LDAP entry...
4909
if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4910
rc != LDAP_NO_SUCH_OBJECT)
4913
* Printer has already been registered, check if
4914
* modification is required...
4917
e = ldap_first_entry(BrowseLDAPHandle, res);
4920
* Get the required values from this entry...
4923
if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
4924
old_info, sizeof(old_info)) == -1)
4927
if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
4928
old_location, sizeof(old_location)) == -1)
4931
if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
4932
old_make_model, sizeof(old_make_model)) == -1)
4935
if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
4936
old_type_string, sizeof(old_type_string)) == -1)
4939
old_type = atoi(old_type_string);
4941
if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
4942
sizeof(old_uri)) == -1)
4946
* Check if modification is required...
4949
if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
4950
!strcmp(location[0], old_location) &&
4951
!strcmp(make_model[0], old_make_model) && p->type == old_type)
4954
* LDAP entry for the printer exists. Printer has already been registered,
4955
* no modifications required...
4958
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4959
"send_ldap_browse: No updates required for %s", p->name);
4964
* LDAP entry for the printer exists. Printer has already been registered,
4965
* modify the current registration...
4968
cupsdLogMessage(CUPSD_LOG_DEBUG2,
4969
"send_ldap_browse: Replace entry for %s", p->name);
4971
for (i = 0; i < 7; i ++)
4973
pmods[i] = mods + i;
4974
pmods[i]->mod_op = LDAP_MOD_REPLACE;
4978
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4979
if ((rcmod = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4980
NULL)) != LDAP_SUCCESS)
4982
if ((rcmod = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4983
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4985
cupsdLogMessage(CUPSD_LOG_ERROR,
4986
"LDAP modify for %s failed with status %d: %s",
4987
p->name, rcmod, ldap_err2string(rcmod));
4988
if (rcmod == LDAP_SERVER_DOWN)
4996
* No LDAP entry exists for the printer. Printer has never been registered,
4997
* add the current registration...
5000
send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
5002
cupsdLogMessage(CUPSD_LOG_DEBUG2,
5003
"send_ldap_browse: Add entry for %s", p->name);
5005
for (i = 0; i < 7; i ++)
5007
pmods[i] = mods + i;
5008
pmods[i]->mod_op = LDAP_MOD_ADD;
5012
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5013
if ((rcmod = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
5014
NULL)) != LDAP_SUCCESS)
5016
if ((rcmod = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
5017
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5019
cupsdLogMessage(CUPSD_LOG_ERROR,
5020
"LDAP add for %s failed with status %d: %s",
5021
p->name, rcmod, ldap_err2string(rcmod));
5022
if (rcmod == LDAP_SERVER_DOWN)
5027
if (rc == LDAP_SUCCESS)
5033
* 'ldap_dereg_printer()' - Delete printer from directory
5037
ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
5039
char dn[1024]; /* DN of the printer */
5040
int rc; /* LDAP status */
5043
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
5047
* Reconnect if LDAP Handle is invalid...
5050
if (!BrowseLDAPHandle)
5057
* Get dn for printer and delete LDAP entry...
5060
snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
5062
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
5064
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5065
if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5066
NULL)) != LDAP_SUCCESS)
5068
if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5069
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5071
cupsdLogMessage(CUPSD_LOG_WARN,
5072
"LDAP delete for %s failed with status %d: %s",
5073
p->name, rc, ldap_err2string(rc));
5076
* If we had a connection problem (connection timed out, etc.)
5077
* we should reconnect and try again to delete the entry...
5080
if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
5082
cupsdLogMessage(CUPSD_LOG_INFO,
5083
"Retry deleting LDAP entry for %s after a reconnect...", p->name);
5086
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5087
if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5088
NULL)) != LDAP_SUCCESS)
5090
if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5091
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5092
cupsdLogMessage(CUPSD_LOG_WARN,
5093
"LDAP delete for %s failed with status %d: %s",
5094
p->name, rc, ldap_err2string(rc));
5101
* 'ldap_dereg_ou()' - Remove the organizational unit.
5105
ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
5106
char *basedn) /* I - Dase dn */
5108
char dn[1024]; /* DN of the printer */
5109
int rc; /* LDAP status */
5112
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
5115
* Reconnect if LDAP Handle is invalid...
5118
if (!BrowseLDAPHandle)
5125
* Get dn for printer and delete LDAP entry...
5128
snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
5129
cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
5131
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5132
if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5133
NULL)) != LDAP_SUCCESS)
5135
if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5136
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5138
cupsdLogMessage(CUPSD_LOG_WARN,
5139
"LDAP delete for %s failed with status %d: %s",
5140
ou, rc, ldap_err2string(rc));
5143
* If we had a connection problem (connection timed out, etc.)
5144
* we should reconnect and try again to delete the entry...
5147
if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
5149
cupsdLogMessage(CUPSD_LOG_INFO,
5150
"Retry deleting LDAP entry for %s after a reconnect...", ou);
5152
# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
5153
if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
5154
NULL)) != LDAP_SUCCESS)
5156
if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
5157
# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
5158
cupsdLogMessage(CUPSD_LOG_WARN,
5159
"LDAP delete for %s failed with status %d: %s",
5160
ou, rc, ldap_err2string(rc));
5164
#endif /* HAVE_LDAP */
5169
* 'send_slp_browse()' - Register the specified printer with SLP.
5173
send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
5175
char srvurl[HTTP_MAX_URI], /* Printer service URI */
5176
attrs[8192], /* Printer attributes */
5177
finishings[1024], /* Finishings to support */
5178
make_model[IPP_MAX_NAME * 2],
5179
/* Make and model, quoted */
5180
location[IPP_MAX_NAME * 2],
5181
/* Location, quoted */
5182
info[IPP_MAX_NAME * 2], /* Info, quoted */
5183
*src, /* Pointer to original string */
5184
*dst; /* Pointer to destination string */
5185
ipp_attribute_t *authentication; /* uri-authentication-supported value */
5186
SLPError error; /* SLP error, if any */
5189
cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
5193
* Make the SLP service URL that conforms to the IANA
5194
* 'printer:' template.
5197
snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
5199
cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
5202
* Figure out the finishings string...
5205
if (p->type & CUPS_PRINTER_STAPLE)
5206
strcpy(finishings, "staple");
5208
finishings[0] = '\0';
5210
if (p->type & CUPS_PRINTER_BIND)
5213
strlcat(finishings, ",bind", sizeof(finishings));
5215
strcpy(finishings, "bind");
5218
if (p->type & CUPS_PRINTER_PUNCH)
5221
strlcat(finishings, ",punch", sizeof(finishings));
5223
strcpy(finishings, "punch");
5226
if (p->type & CUPS_PRINTER_COVER)
5229
strlcat(finishings, ",cover", sizeof(finishings));
5231
strcpy(finishings, "cover");
5234
if (p->type & CUPS_PRINTER_SORT)
5237
strlcat(finishings, ",sort", sizeof(finishings));
5239
strcpy(finishings, "sort");
5243
strcpy(finishings, "none");
5246
* Quote any commas in the make and model, location, and info strings...
5249
for (src = p->make_model, dst = make_model;
5250
src && *src && dst < (make_model + sizeof(make_model) - 2);)
5252
if (*src == ',' || *src == '\\' || *src == ')')
5261
strcpy(make_model, "Unknown");
5263
for (src = p->location, dst = location;
5264
src && *src && dst < (location + sizeof(location) - 2);)
5266
if (*src == ',' || *src == '\\' || *src == ')')
5275
strcpy(location, "Unknown");
5277
for (src = p->info, dst = info;
5278
src && *src && dst < (info + sizeof(info) - 2);)
5280
if (*src == ',' || *src == '\\' || *src == ')')
5289
strcpy(info, "Unknown");
5292
* Get the authentication value...
5295
authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
5299
* Make the SLP attribute string list that conforms to
5300
* the IANA 'printer:' template.
5303
snprintf(attrs, sizeof(attrs),
5304
"(printer-uri-supported=%s),"
5305
"(uri-authentication-supported=%s>),"
5307
"(uri-security-supported=tls>),"
5309
"(uri-security-supported=none>),"
5310
#endif /* HAVE_SSL */
5311
"(printer-name=%s),"
5312
"(printer-location=%s),"
5313
"(printer-info=%s),"
5314
"(printer-more-info=%s),"
5315
"(printer-make-and-model=%s),"
5316
"(printer-type=%d),"
5317
"(charset-supported=utf-8),"
5318
"(natural-language-configured=%s),"
5319
"(natural-language-supported=de,en,es,fr,it),"
5320
"(color-supported=%s),"
5321
"(finishings-supported=%s),"
5322
"(sides-supported=one-sided%s),"
5323
"(multiple-document-jobs-supported=true)"
5324
"(ipp-versions-supported=1.0,1.1)",
5325
p->uri, authentication->values[0].string.text, p->name, location,
5326
info, p->uri, make_model, p->type, DefaultLanguage,
5327
p->type & CUPS_PRINTER_COLOR ? "true" : "false",
5329
p->type & CUPS_PRINTER_DUPLEX ?
5330
",two-sided-long-edge,two-sided-short-edge" : "");
5332
cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
5335
* Register the printer with the SLP server...
5338
error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
5339
SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
5341
if (error != SLP_OK)
5342
cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
5348
* 'slp_attr_callback()' - SLP attribute callback
5351
static SLPBoolean /* O - SLP_TRUE for success */
5353
SLPHandle hslp, /* I - SLP handle */
5354
const char *attrlist, /* I - Attribute list */
5355
SLPError errcode, /* I - Parsing status for this attr */
5356
void *cookie) /* I - Current printer */
5358
char *tmp = 0; /* Temporary string */
5359
cupsd_printer_t *p = (cupsd_printer_t*)cookie;
5360
/* Current printer */
5363
(void)hslp; /* anti-compiler-warning-code */
5366
* Bail if there was an error
5369
if (errcode != SLP_OK)
5373
* Parse the attrlist to obtain things needed to build CUPS browse packet
5376
memset(p, 0, sizeof(cupsd_printer_t));
5378
if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
5380
if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
5382
if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
5384
if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
5385
p->type = atoi(tmp);
5387
p->type = CUPS_PRINTER_REMOTE;
5389
cupsdClearString(&tmp);
5396
* 'slp_dereg_printer()' - SLPDereg() the specified printer
5400
slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
5402
char srvurl[HTTP_MAX_URI]; /* Printer service URI */
5405
cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
5407
if (!(p->type & CUPS_PRINTER_REMOTE))
5410
* Make the SLP service URL that conforms to the IANA
5411
* 'printer:' template.
5414
snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
5417
* Deregister the printer...
5420
SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
5426
* 'slp_get_attr()' - Get an attribute from an SLP registration.
5429
static int /* O - 0 on success */
5430
slp_get_attr(const char *attrlist, /* I - Attribute list string */
5431
const char *tag, /* I - Name of attribute */
5432
char **valbuf) /* O - Value */
5434
char *ptr1, /* Pointer into string */
5438
cupsdClearString(valbuf);
5440
if ((ptr1 = strstr(attrlist, tag)) != NULL)
5442
ptr1 += strlen(tag);
5444
if ((ptr2 = strchr(ptr1,')')) != NULL)
5450
*valbuf = calloc(ptr2 - ptr1 + 1, 1);
5451
strncpy(*valbuf, ptr1, ptr2 - ptr1);
5454
* Dequote the value...
5457
for (ptr1 = *valbuf; *ptr1; ptr1 ++)
5458
if (*ptr1 == '\\' && ptr1[1])
5459
_cups_strcpy(ptr1, ptr1 + 1);
5470
* 'slp_reg_callback()' - Empty SLPRegReport.
5474
slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
5475
SLPError errcode, /* I - Error code, if any */
5476
void *cookie) /* I - App data */
5487
* 'slp_url_callback()' - SLP service url callback
5490
static SLPBoolean /* O - TRUE = OK, FALSE = error */
5492
SLPHandle hslp, /* I - SLP handle */
5493
const char *srvurl, /* I - URL of service */
5494
unsigned short lifetime, /* I - Life of service */
5495
SLPError errcode, /* I - Existing error code */
5496
void *cookie) /* I - Pointer to service list */
5498
slpsrvurl_t *s, /* New service entry */
5499
**head; /* Pointer to head of entry */
5503
* Let the compiler know we won't be using these vars...
5510
* Bail if there was an error
5513
if (errcode != SLP_OK)
5517
* Grab the head of the list...
5520
head = (slpsrvurl_t**)cookie;
5523
* Allocate a *temporary* slpsrvurl_t to hold this entry.
5526
if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
5530
* Copy the SLP service URL...
5533
strlcpy(s->url, srvurl, sizeof(s->url));
5536
* Link the SLP service URL into the head of the list
5546
#endif /* HAVE_LIBSLP */
5550
* 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
5554
update_cups_browse(void)
5556
int i; /* Looping var */
5557
int auth; /* Authorization status */
5558
int len; /* Length of name string */
5559
int bytes; /* Number of bytes left */
5560
char packet[1541], /* Broadcast packet */
5561
*pptr; /* Pointer into packet */
5562
socklen_t srclen; /* Length of source address */
5563
http_addr_t srcaddr; /* Source address */
5564
char srcname[1024]; /* Source hostname */
5565
unsigned address[4]; /* Source address */
5566
unsigned type; /* Printer type */
5567
unsigned state; /* Printer state */
5568
char uri[HTTP_MAX_URI], /* Printer URI */
5569
host[HTTP_MAX_URI], /* Host portion of URI */
5570
resource[HTTP_MAX_URI], /* Resource portion of URI */
5571
info[IPP_MAX_NAME], /* Information string */
5572
location[IPP_MAX_NAME], /* Location string */
5573
make_model[IPP_MAX_NAME];/* Make and model string */
5574
int num_attrs; /* Number of attributes */
5575
cups_option_t *attrs; /* Attributes */
5579
* Read a packet from the browse socket...
5582
srclen = sizeof(srcaddr);
5583
if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
5584
(struct sockaddr *)&srcaddr, &srclen)) < 0)
5587
* "Connection refused" is returned under Linux if the destination port
5588
* or address is unreachable from a previous sendto(); check for the
5589
* error here and ignore it for now...
5592
if (errno != ECONNREFUSED && errno != EAGAIN)
5594
cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
5596
cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
5599
closesocket(BrowseSocket);
5601
close(BrowseSocket);
5604
cupsdRemoveSelect(BrowseSocket);
5607
BrowseLocalProtocols &= ~BROWSE_CUPS;
5608
BrowseRemoteProtocols &= ~BROWSE_CUPS;
5614
packet[bytes] = '\0';
5617
* If we're about to sleep, ignore incoming browse packets.
5624
* Figure out where it came from...
5628
if (srcaddr.addr.sa_family == AF_INET6)
5630
address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
5631
address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
5632
address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
5633
address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
5636
#endif /* AF_INET6 */
5641
address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
5644
if (HostNameLookups)
5645
httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
5647
httpAddrString(&srcaddr, srcname, sizeof(srcname));
5649
len = strlen(srcname);
5657
if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
5660
* Access from localhost (127.0.0.1) is always allowed...
5663
auth = CUPSD_AUTH_ALLOW;
5668
* Do authorization checks on the domain/address...
5671
switch (BrowseACL->order_type)
5674
auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
5677
case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
5678
auth = CUPSD_AUTH_ALLOW;
5680
if (cupsdCheckAuth(address, srcname, len,
5681
BrowseACL->num_deny, BrowseACL->deny))
5682
auth = CUPSD_AUTH_DENY;
5684
if (cupsdCheckAuth(address, srcname, len,
5685
BrowseACL->num_allow, BrowseACL->allow))
5686
auth = CUPSD_AUTH_ALLOW;
5689
case CUPSD_AUTH_DENY : /* Order Allow,Deny */
5690
auth = CUPSD_AUTH_DENY;
5692
if (cupsdCheckAuth(address, srcname, len,
5693
BrowseACL->num_allow, BrowseACL->allow))
5694
auth = CUPSD_AUTH_ALLOW;
5696
if (cupsdCheckAuth(address, srcname, len,
5697
BrowseACL->num_deny, BrowseACL->deny))
5698
auth = CUPSD_AUTH_DENY;
5704
auth = CUPSD_AUTH_ALLOW;
5706
if (auth == CUPSD_AUTH_DENY)
5708
cupsdLogMessage(CUPSD_LOG_DEBUG,
5709
"update_cups_browse: Refused %d bytes from %s", bytes,
5714
cupsdLogMessage(CUPSD_LOG_DEBUG2,
5715
"update_cups_browse: (%d bytes from %s) %s", bytes,
5722
if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
5724
cupsdLogMessage(CUPSD_LOG_WARN,
5725
"update_cups_browse: Garbled browse packet - %s", packet);
5729
strcpy(location, "Location Unknown");
5730
strcpy(info, "No Information Available");
5731
make_model[0] = '\0';
5735
if ((pptr = strchr(packet, '\"')) != NULL)
5738
* Have extended information; can't use sscanf for it because not all
5739
* sscanf's allow empty strings with %[^\"]...
5742
for (i = 0, pptr ++;
5743
i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
5745
location[i] = *pptr;
5753
while (*pptr && isspace(*pptr & 255))
5758
for (i = 0, pptr ++;
5759
i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
5768
while (*pptr && isspace(*pptr & 255))
5773
for (i = 0, pptr ++;
5774
i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
5776
make_model[i] = *pptr;
5781
make_model[i] = '\0';
5784
num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
5790
DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
5791
"location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
5792
type, state, uri, location, info, make_model));
5795
* Pull the URI apart to see if this is a local or remote printer...
5798
if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
5800
cupsFreeOptions(num_attrs, attrs);
5808
for (i = 0; i < NumRelays; i ++)
5809
if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
5810
if (sendto(BrowseSocket, packet, bytes, 0,
5811
(struct sockaddr *)&(Relays[i].to),
5812
httpAddrLength(&(Relays[i].to))) <= 0)
5814
cupsdLogMessage(CUPSD_LOG_ERROR,
5815
"update_cups_browse: sendto failed for relay %d - %s.",
5816
i + 1, strerror(errno));
5817
cupsFreeOptions(num_attrs, attrs);
5822
* Process the browse data...
5825
process_browse_data(uri, host, resource, (cups_ptype_t)type,
5826
(ipp_pstate_t)state, location, info, make_model,
5832
* 'update_lpd()' - Update the LPD configuration as needed.
5836
update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
5843
* Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
5844
* setting for backwards-compatibility.
5847
if (onoff && !get_hostconfig("CUPS_LPD"))
5849
#endif /* __APPLE__ */
5851
if (!strncmp(LPDConfigFile, "xinetd:///", 10))
5854
* Enable/disable LPD via the xinetd.d config file for cups-lpd...
5857
char newfile[1024]; /* New cups-lpd.N file */
5858
cups_file_t *ofp, /* Original file pointer */
5859
*nfp; /* New file pointer */
5860
char line[1024]; /* Line from file */
5863
snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
5865
if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
5867
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5868
LPDConfigFile + 9, strerror(errno));
5872
if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5874
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5875
newfile, strerror(errno));
5881
* Copy all of the lines from the cups-lpd file...
5884
while (cupsFileGets(ofp, line, sizeof(line)))
5888
cupsFilePrintf(nfp, "%s\n", line);
5889
snprintf(line, sizeof(line), "\tdisable = %s",
5890
onoff ? "no" : "yes");
5892
else if (!strstr(line, "disable ="))
5893
cupsFilePrintf(nfp, "%s\n", line);
5898
rename(newfile, LPDConfigFile + 9);
5901
else if (!strncmp(LPDConfigFile, "launchd:///", 11))
5904
* Enable/disable LPD via the launchctl command...
5907
char *argv[5], /* Arguments for command */
5908
*envp[MAX_ENV]; /* Environment for command */
5909
int pid; /* Process ID */
5912
cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
5913
argv[0] = (char *)"launchctl";
5914
argv[1] = (char *)(onoff ? "load" : "unload");
5915
argv[2] = (char *)"-w";
5916
argv[3] = LPDConfigFile + 10;
5919
cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
5922
#endif /* __APPLE__ */
5924
cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
5929
* 'update_polling()' - Read status messages from the poll daemons.
5933
update_polling(void)
5935
char *ptr, /* Pointer to end of line in buffer */
5936
message[1024]; /* Pointer to message text */
5937
int loglevel; /* Log level for message */
5940
while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
5941
message, sizeof(message))) != NULL)
5943
if (loglevel == CUPSD_LOG_INFO)
5944
cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
5946
if (!strchr(PollStatusBuffer->buffer, '\n'))
5950
if (ptr == NULL && !PollStatusBuffer->bufused)
5953
* All polling processes have died; stop polling...
5956
cupsdLogMessage(CUPSD_LOG_ERROR,
5957
"update_polling: all polling processes have exited!");
5964
* 'update_smb()' - Update the SMB configuration as needed.
5968
update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
5973
if (!strncmp(SMBConfigFile, "samba:///", 9))
5976
* Enable/disable SMB via the specified smb.conf config file...
5979
char newfile[1024]; /* New smb.conf.N file */
5980
cups_file_t *ofp, /* Original file pointer */
5981
*nfp; /* New file pointer */
5982
char line[1024]; /* Line from file */
5983
int in_printers; /* In [printers] section? */
5986
snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
5988
if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
5990
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5991
SMBConfigFile + 8, strerror(errno));
5995
if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5997
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5998
newfile, strerror(errno));
6004
* Copy all of the lines from the smb.conf file...
6009
while (cupsFileGets(ofp, line, sizeof(line)))
6011
if (in_printers && strstr(line, "printable ="))
6012
snprintf(line, sizeof(line), " printable = %s",
6013
onoff ? "yes" : "no");
6015
cupsFilePrintf(nfp, "%s\n", line);
6018
in_printers = !strcmp(line, "[printers]");
6023
rename(newfile, SMBConfigFile + 8);
6026
cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
6031
* End of "$Id: dirsvc.c 9503 2011-01-22 00:07:22Z mike $".