]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/dirsvc.c
Merge changes from CUPS 1.4svn-r8628.
[thirdparty/cups.git] / scheduler / dirsvc.c
CommitLineData
ef416fc2 1/*
b19ccc9e 2 * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $"
ef416fc2 3 *
4 * Directory services routines for the Common UNIX Printing System (CUPS).
5 *
d1c13e16 6 * Copyright 2007-2009 by Apple Inc.
b86bc4cf 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 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/".
ef416fc2 14 *
15 * Contents:
16 *
c5571a1d
MS
17 * cupsdDeregisterPrinter() - Stop sending broadcast information for a local
18 * printer and remove any pending references to
19 * remote printers.
20 * cupsdLoadRemoteCache() - Load the remote printer cache.
21 * cupsdRegisterPrinter() - Start sending broadcast information for a
22 * printer or update the broadcast contents.
23 * cupsdRestartPolling() - Restart polling servers as needed.
24 * cupsdSaveRemoteCache() - Save the remote printer cache.
25 * cupsdSendBrowseList() - Send new browsing information as necessary.
26 * ldap_rebind_proc() - Callback function for LDAP rebind
27 * ldap_connect() - Start new LDAP connection
28 * ldap_reconnect() - Reconnect to LDAP Server
29 * ldap_disconnect() - Disconnect from LDAP Server
30 * cupsdStartBrowsing() - Start sending and receiving broadcast
31 * information.
32 * cupsdStartPolling() - Start polling servers as needed.
33 * cupsdStopBrowsing() - Stop sending and receiving broadcast
34 * information.
35 * cupsdStopPolling() - Stop polling servers as needed.
36 * cupsdUpdateDNSSDName() - Update the computer name we use for
37 * browsing...
38 * cupsdUpdateLDAPBrowse() - Scan for new printers via LDAP...
39 * cupsdUpdateSLPBrowse() - Get browsing information via SLP.
40 * dequote() - Remote quotes from a string.
e07d4801 41 * dnssdAddAlias() - Add a DNS-SD alias name.
c5571a1d
MS
42 * dnssdBuildTxtRecord() - Build a TXT record from printer info.
43 * dnssdComparePrinters() - Compare the registered names of two printers.
44 * dnssdDeregisterPrinter() - Stop sending broadcast information for a
45 * printer.
46 * dnssdPackTxtRecord() - Pack an array of key/value pairs into the TXT
47 * record format.
48 * dnssdRegisterCallback() - DNSServiceRegister callback.
49 * dnssdRegisterPrinter() - Start sending broadcast information for a
50 * printer or update the broadcast contents.
f0ab5bff 51 * dnssdStop() - Stop all DNS-SD registrations.
c5571a1d
MS
52 * dnssdUpdate() - Handle DNS-SD queries.
53 * get_hostconfig() - Get an /etc/hostconfig service setting.
54 * is_local_queue() - Determine whether the URI points at a local
55 * queue.
56 * process_browse_data() - Process new browse data.
57 * process_implicit_classes() - Create/update implicit classes as needed.
58 * send_cups_browse() - Send new browsing information using the CUPS
59 * protocol.
60 * ldap_search_rec() - LDAP Search with reconnect
61 * ldap_freeres() - Free LDAPMessage
62 * ldap_getval_char() - Get first LDAP value and convert to string
63 * send_ldap_ou() - Send LDAP ou registrations.
64 * send_ldap_browse() - Send LDAP printer registrations.
65 * ldap_dereg_printer() - Delete printer from directory
66 * send_slp_browse() - Register the specified printer with SLP.
67 * slp_attr_callback() - SLP attribute callback
68 * slp_dereg_printer() - SLPDereg() the specified printer
69 * slp_get_attr() - Get an attribute from an SLP registration.
70 * slp_reg_callback() - Empty SLPRegReport.
71 * slp_url_callback() - SLP service url callback
72 * update_cups_browse() - Update the browse lists using the CUPS
73 * protocol.
74 * update_lpd() - Update the LPD configuration as needed.
75 * update_polling() - Read status messages from the poll daemons.
76 * update_smb() - Update the SMB configuration as needed.
ef416fc2 77 */
78
79/*
80 * Include necessary headers...
81 */
82
83#include "cupsd.h"
84#include <grp.h>
85
f7deaa1a 86#ifdef HAVE_DNSSD
87# include <dns_sd.h>
cc0d019f
MS
88# ifdef __APPLE__
89# include <nameser.h>
90# ifdef HAVE_COREFOUNDATION
91# include <CoreFoundation/CoreFoundation.h>
92# endif /* HAVE_COREFOUNDATION */
93# ifdef HAVE_SYSTEMCONFIGURATION
94# include <SystemConfiguration/SystemConfiguration.h>
95# endif /* HAVE_SYSTEMCONFIGURATION */
96# endif /* __APPLE__ */
f7deaa1a 97#endif /* HAVE_DNSSD */
98
ef416fc2 99
100/*
e00b005a 101 * Local functions...
ef416fc2 102 */
103
e00b005a 104static char *dequote(char *d, const char *s, int dlen);
178cb736
MS
105static char *get_auth_info_required(cupsd_printer_t *p, char *buffer,
106 size_t bufsize);
a603edef
MS
107#ifdef __APPLE__
108static int get_hostconfig(const char *name);
109#endif /* __APPLE__ */
b423cd4c 110static int is_local_queue(const char *uri, char *host, int hostlen,
111 char *resource, int resourcelen);
112static void process_browse_data(const char *uri, const char *host,
113 const char *resource, cups_ptype_t type,
e00b005a 114 ipp_pstate_t state, const char *location,
115 const char *info, const char *make_model,
116 int num_attrs, cups_option_t *attrs);
3dfe78b3 117static void process_implicit_classes(void);
e1d6a774 118static void send_cups_browse(cupsd_printer_t *p);
119#ifdef HAVE_LDAP
749b1e90
MS
120static LDAP *ldap_connect(void);
121static void ldap_reconnect(void);
122static void ldap_disconnect(LDAP *ld);
123static int ldap_search_rec(LDAP *ld, char *base, int scope,
124 char *filter, char *attrs[],
125 int attrsonly, LDAPMessage **res);
126static int ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
127 char *attr, char *retval,
128 unsigned long maxsize);
129static void ldap_freeres(LDAPMessage *entry);
130static void send_ldap_ou(char *ou, char *basedn, char *descstring);
e1d6a774 131static void send_ldap_browse(cupsd_printer_t *p);
749b1e90
MS
132static void ldap_dereg_printer(cupsd_printer_t *p);
133static void ldap_dereg_ou(char *ou, char *basedn);
134# ifdef HAVE_LDAP_REBIND_PROC
135# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
136static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
137 LDAP_CONST char *refsp,
138 ber_tag_t request,
139 ber_int_t msgid,
140 void *params);
141# else
142static int ldap_rebind_proc(LDAP *RebindLDAPHandle,
143 char **dnp,
144 char **passwdp,
145 int *authmethodp,
146 int freeit,
147 void *arg);
148# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
149# endif /* HAVE_LDAP_REBIND_PROC */
e1d6a774 150#endif /* HAVE_LDAP */
80ca4592 151#ifdef HAVE_LIBSLP
e1d6a774 152static void send_slp_browse(cupsd_printer_t *p);
80ca4592 153#endif /* HAVE_LIBSLP */
f899b121 154static void update_cups_browse(void);
2e4ff8af 155static void update_lpd(int onoff);
f899b121 156static void update_polling(void);
2e4ff8af 157static void update_smb(int onoff);
f899b121 158
e00b005a 159
7a14d768 160#ifdef HAVE_DNSSD
e07d4801
MS
161# ifdef HAVE_COREFOUNDATION
162static void dnssdAddAlias(const void *key, const void *value,
163 void *context);
164# endif /* HAVE_COREFOUNDATION */
7a14d768
MS
165static char *dnssdBuildTxtRecord(int *txt_len, cupsd_printer_t *p,
166 int for_lpd);
167static int dnssdComparePrinters(cupsd_printer_t *a, cupsd_printer_t *b);
168static void dnssdDeregisterPrinter(cupsd_printer_t *p);
169static char *dnssdPackTxtRecord(int *txt_len, char *keyvalue[][2],
170 int count);
171static void dnssdRegisterCallback(DNSServiceRef sdRef,
172 DNSServiceFlags flags,
173 DNSServiceErrorType errorCode,
174 const char *name, const char *regtype,
175 const char *domain, void *context);
176static void dnssdRegisterPrinter(cupsd_printer_t *p);
f0ab5bff 177static void dnssdStop(void);
75bd9771 178static void dnssdUpdate(void);
7a14d768
MS
179#endif /* HAVE_DNSSD */
180
749b1e90 181#ifdef HAVE_LDAP
b423cd4c 182static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
183 {
184 "printerDescription",
185 "printerLocation",
186 "printerMakeAndModel",
187 "printerType",
188 "printerURI",
189 NULL
190 };
749b1e90 191#endif /* HAVE_LDAP */
b423cd4c 192
ef416fc2 193#ifdef HAVE_LIBSLP
e00b005a 194/*
195 * SLP definitions...
196 */
197
ef416fc2 198/*
199 * SLP service name for CUPS...
200 */
201
202# define SLP_CUPS_SRVTYPE "service:printer"
203# define SLP_CUPS_SRVLEN 15
204
205
206/*
207 * Printer service URL structure
208 */
209
210typedef struct _slpsrvurl_s /**** SLP URL list ****/
211{
212 struct _slpsrvurl_s *next; /* Next URL in list */
213 char url[HTTP_MAX_URI];
214 /* URL */
215} slpsrvurl_t;
216
217
218/*
219 * Local functions...
220 */
221
222static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist,
223 SLPError errcode, void *cookie);
224static void slp_dereg_printer(cupsd_printer_t *p);
225static int slp_get_attr(const char *attrlist, const char *tag,
226 char **valbuf);
227static void slp_reg_callback(SLPHandle hslp, SLPError errcode,
228 void *cookie);
229static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl,
230 unsigned short lifetime,
231 SLPError errcode, void *cookie);
232#endif /* HAVE_LIBSLP */
233
f7deaa1a 234
235/*
236 * 'cupsdDeregisterPrinter()' - Stop sending broadcast information for a
237 * local printer and remove any pending
238 * references to remote printers.
239 */
240
241void
242cupsdDeregisterPrinter(
243 cupsd_printer_t *p, /* I - Printer to register */
244 int removeit) /* I - Printer being permanently removed */
245{
246 /*
7a14d768 247 * Only deregister if browsing is enabled and it's a local printer...
f7deaa1a 248 */
249
745129be
MS
250 cupsdLogMessage(CUPSD_LOG_DEBUG,
251 "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", p, p->name,
252 removeit);
253
f7deaa1a 254 if (!Browsing || !p->shared ||
f11a948a
MS
255 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
256 CUPS_PRINTER_SCANNER)))
f7deaa1a 257 return;
258
259 /*
260 * Announce the deletion...
261 */
262
0a682745 263 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
f7deaa1a 264 {
265 cups_ptype_t savedtype = p->type; /* Saved printer type */
266
267 p->type |= CUPS_PRINTER_DELETE;
268
269 send_cups_browse(p);
270
271 p->type = savedtype;
272 }
273
274#ifdef HAVE_LIBSLP
275 if (BrowseLocalProtocols & BROWSE_SLP)
276 slp_dereg_printer(p);
277#endif /* HAVE_LIBSLP */
278
749b1e90
MS
279#ifdef HAVE_LDAP
280 if (BrowseLocalProtocols & BROWSE_LDAP)
281 ldap_dereg_printer(p);
282#endif /* HAVE_LDAP */
283
f7deaa1a 284#ifdef HAVE_DNSSD
bdd6c45b 285 if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
f7deaa1a 286 dnssdDeregisterPrinter(p);
287#endif /* HAVE_DNSSD */
288}
289
ef416fc2 290
291/*
292 * 'cupsdLoadRemoteCache()' - Load the remote printer cache.
293 */
294
295void
296cupsdLoadRemoteCache(void)
297{
745129be 298 int i; /* Looping var */
ef416fc2 299 cups_file_t *fp; /* remote.cache file */
300 int linenum; /* Current line number */
d1c13e16 301 char line[4096], /* Line from file */
ef416fc2 302 *value, /* Pointer to value */
bd7854cb 303 *valueptr, /* Pointer into value */
304 scheme[32], /* Scheme portion of URI */
305 username[64], /* Username portion of URI */
306 host[HTTP_MAX_HOST],
307 /* Hostname portion of URI */
308 resource[HTTP_MAX_URI];
309 /* Resource portion of URI */
310 int port; /* Port number */
ef416fc2 311 cupsd_printer_t *p; /* Current printer */
312 time_t now; /* Current time */
313
314
411affcf 315 /*
7a14d768 316 * Don't load the cache if the remote protocols are disabled...
411affcf 317 */
318
7a14d768 319 if (!Browsing)
411affcf 320 {
321 cupsdLogMessage(CUPSD_LOG_DEBUG,
322 "cupsdLoadRemoteCache: Not loading remote cache.");
323 return;
324 }
325
ef416fc2 326 /*
327 * Open the remote.cache file...
328 */
329
330 snprintf(line, sizeof(line), "%s/remote.cache", CacheDir);
331 if ((fp = cupsFileOpen(line, "r")) == NULL)
332 return;
333
334 /*
335 * Read printer configurations until we hit EOF...
336 */
337
338 linenum = 0;
339 p = NULL;
340 now = time(NULL);
341
342 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
343 {
344 /*
345 * Decode the directive...
346 */
347
348 if (!strcasecmp(line, "<Printer") ||
349 !strcasecmp(line, "<DefaultPrinter"))
350 {
351 /*
352 * <Printer name> or <DefaultPrinter name>
353 */
354
355 if (p == NULL && value)
356 {
357 /*
358 * Add the printer and a base file type...
359 */
360
361 cupsdLogMessage(CUPSD_LOG_DEBUG,
362 "cupsdLoadRemoteCache: Loading printer %s...", value);
363
bd7854cb 364 if ((p = cupsdFindDest(value)) != NULL)
365 {
366 if (p->type & CUPS_PRINTER_CLASS)
367 {
368 cupsdLogMessage(CUPSD_LOG_WARN,
369 "Cached remote printer \"%s\" conflicts with "
370 "existing class!",
371 value);
372 p = NULL;
373 continue;
374 }
375 }
376 else
377 p = cupsdAddPrinter(value);
378
8ca02f3c 379 p->accepting = 1;
380 p->state = IPP_PRINTER_IDLE;
09a101d6 381 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
8ca02f3c 382 p->browse_time = now;
383 p->browse_expire = now + BrowseTimeout;
ef416fc2 384
385 /*
386 * Set the default printer as needed...
387 */
388
389 if (!strcasecmp(line, "<DefaultPrinter"))
390 DefaultPrinter = p;
391 }
392 else
393 {
394 cupsdLogMessage(CUPSD_LOG_ERROR,
395 "Syntax error on line %d of remote.cache.", linenum);
91c84a35 396 break;
ef416fc2 397 }
398 }
399 else if (!strcasecmp(line, "<Class") ||
400 !strcasecmp(line, "<DefaultClass"))
401 {
402 /*
403 * <Class name> or <DefaultClass name>
404 */
405
406 if (p == NULL && value)
407 {
408 /*
409 * Add the printer and a base file type...
410 */
411
412 cupsdLogMessage(CUPSD_LOG_DEBUG,
413 "cupsdLoadRemoteCache: Loading class %s...", value);
414
bd7854cb 415 if ((p = cupsdFindDest(value)) != NULL)
416 p->type = CUPS_PRINTER_CLASS;
417 else
418 p = cupsdAddClass(value);
419
8ca02f3c 420 p->accepting = 1;
421 p->state = IPP_PRINTER_IDLE;
09a101d6 422 p->type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
8ca02f3c 423 p->browse_time = now;
424 p->browse_expire = now + BrowseTimeout;
ef416fc2 425
426 /*
427 * Set the default printer as needed...
428 */
429
430 if (!strcasecmp(line, "<DefaultClass"))
431 DefaultPrinter = p;
432 }
433 else
434 {
435 cupsdLogMessage(CUPSD_LOG_ERROR,
436 "Syntax error on line %d of remote.cache.", linenum);
91c84a35 437 break;
ef416fc2 438 }
439 }
440 else if (!strcasecmp(line, "</Printer>") ||
441 !strcasecmp(line, "</Class>"))
442 {
443 if (p != NULL)
444 {
445 /*
446 * Close out the current printer...
447 */
448
449 cupsdSetPrinterAttrs(p);
450
451 p = NULL;
452 }
453 else
ef416fc2 454 cupsdLogMessage(CUPSD_LOG_ERROR,
455 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 456 }
457 else if (!p)
458 {
459 cupsdLogMessage(CUPSD_LOG_ERROR,
460 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 461 }
462 else if (!strcasecmp(line, "Info"))
463 {
464 if (value)
465 cupsdSetString(&p->info, value);
466 }
467 else if (!strcasecmp(line, "MakeModel"))
468 {
469 if (value)
470 cupsdSetString(&p->make_model, value);
471 }
472 else if (!strcasecmp(line, "Location"))
473 {
474 if (value)
475 cupsdSetString(&p->location, value);
476 }
477 else if (!strcasecmp(line, "DeviceURI"))
478 {
479 if (value)
4400e98d 480 {
bd7854cb 481 httpSeparateURI(HTTP_URI_CODING_ALL, value, scheme, sizeof(scheme),
482 username, sizeof(username), host, sizeof(host), &port,
483 resource, sizeof(resource));
484
485 cupsdSetString(&p->hostname, host);
4400e98d 486 cupsdSetString(&p->uri, value);
0af14961 487 cupsdSetDeviceURI(p, value);
4400e98d 488 }
ef416fc2 489 else
ef416fc2 490 cupsdLogMessage(CUPSD_LOG_ERROR,
491 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 492 }
b423cd4c 493 else if (!strcasecmp(line, "Option") && value)
494 {
495 /*
496 * Option name value
497 */
498
499 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
500
501 if (!*valueptr)
502 cupsdLogMessage(CUPSD_LOG_ERROR,
503 "Syntax error on line %d of remote.cache.", linenum);
504 else
505 {
506 for (; *valueptr && isspace(*valueptr & 255); *valueptr++ = '\0');
507
508 p->num_options = cupsAddOption(value, valueptr, p->num_options,
509 &(p->options));
510 }
511 }
0af14961
MS
512 else if (!strcasecmp(line, "Reason"))
513 {
745129be 514 if (value)
0af14961 515 {
745129be
MS
516 for (i = 0 ; i < p->num_reasons; i ++)
517 if (!strcmp(value, p->reasons[i]))
518 break;
519
520 if (i >= p->num_reasons &&
521 p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
522 {
523 p->reasons[p->num_reasons] = _cupsStrAlloc(value);
524 p->num_reasons ++;
525 }
0af14961
MS
526 }
527 else
528 cupsdLogMessage(CUPSD_LOG_ERROR,
529 "Syntax error on line %d of remote.cache.", linenum);
530 }
ef416fc2 531 else if (!strcasecmp(line, "State"))
532 {
533 /*
534 * Set the initial queue state...
535 */
536
537 if (value && !strcasecmp(value, "idle"))
538 p->state = IPP_PRINTER_IDLE;
539 else if (value && !strcasecmp(value, "stopped"))
745129be 540 {
ef416fc2 541 p->state = IPP_PRINTER_STOPPED;
745129be
MS
542 cupsdSetPrinterReasons(p, "+paused");
543 }
ef416fc2 544 else
ef416fc2 545 cupsdLogMessage(CUPSD_LOG_ERROR,
546 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 547 }
548 else if (!strcasecmp(line, "StateMessage"))
549 {
550 /*
551 * Set the initial queue state message...
552 */
553
554 if (value)
555 strlcpy(p->state_message, value, sizeof(p->state_message));
556 }
557 else if (!strcasecmp(line, "Accepting"))
558 {
559 /*
560 * Set the initial accepting state...
561 */
562
563 if (value &&
564 (!strcasecmp(value, "yes") ||
565 !strcasecmp(value, "on") ||
566 !strcasecmp(value, "true")))
567 p->accepting = 1;
568 else if (value &&
569 (!strcasecmp(value, "no") ||
570 !strcasecmp(value, "off") ||
571 !strcasecmp(value, "false")))
572 p->accepting = 0;
573 else
ef416fc2 574 cupsdLogMessage(CUPSD_LOG_ERROR,
575 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 576 }
577 else if (!strcasecmp(line, "Type"))
578 {
579 if (value)
580 p->type = atoi(value);
581 else
ef416fc2 582 cupsdLogMessage(CUPSD_LOG_ERROR,
583 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 584 }
585 else if (!strcasecmp(line, "BrowseTime"))
586 {
587 if (value)
588 {
589 time_t t = atoi(value);
590
8ca02f3c 591 if (t > p->browse_expire)
592 p->browse_expire = t;
ef416fc2 593 }
594 else
ef416fc2 595 cupsdLogMessage(CUPSD_LOG_ERROR,
596 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 597 }
598 else if (!strcasecmp(line, "JobSheets"))
599 {
600 /*
601 * Set the initial job sheets...
602 */
603
604 if (value)
605 {
606 for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
607
608 if (*valueptr)
609 *valueptr++ = '\0';
610
611 cupsdSetString(&p->job_sheets[0], value);
612
613 while (isspace(*valueptr & 255))
614 valueptr ++;
615
616 if (*valueptr)
617 {
618 for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++);
619
620 if (*valueptr)
1f0275e3 621 *valueptr = '\0';
ef416fc2 622
623 cupsdSetString(&p->job_sheets[1], value);
624 }
625 }
626 else
ef416fc2 627 cupsdLogMessage(CUPSD_LOG_ERROR,
628 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 629 }
630 else if (!strcasecmp(line, "AllowUser"))
631 {
632 if (value)
633 {
634 p->deny_users = 0;
635 cupsdAddPrinterUser(p, value);
636 }
637 else
ef416fc2 638 cupsdLogMessage(CUPSD_LOG_ERROR,
639 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 640 }
641 else if (!strcasecmp(line, "DenyUser"))
642 {
643 if (value)
644 {
645 p->deny_users = 1;
646 cupsdAddPrinterUser(p, value);
647 }
648 else
ef416fc2 649 cupsdLogMessage(CUPSD_LOG_ERROR,
650 "Syntax error on line %d of remote.cache.", linenum);
ef416fc2 651 }
652 else
653 {
654 /*
655 * Something else we don't understand...
656 */
657
658 cupsdLogMessage(CUPSD_LOG_ERROR,
659 "Unknown configuration directive %s on line %d of remote.cache.",
660 line, linenum);
661 }
662 }
663
664 cupsFileClose(fp);
665
666 /*
667 * Do auto-classing if needed...
668 */
669
3dfe78b3 670 process_implicit_classes();
ef416fc2 671}
672
673
f7deaa1a 674/*
675 * 'cupsdRegisterPrinter()' - Start sending broadcast information for a
676 * printer or update the broadcast contents.
677 */
678
679void
680cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
681{
745129be
MS
682 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", p,
683 p->name);
684
7a14d768 685 if (!Browsing || !BrowseLocalProtocols ||
f11a948a
MS
686 (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
687 CUPS_PRINTER_SCANNER)))
f7deaa1a 688 return;
689
690#ifdef HAVE_LIBSLP
691/* if (BrowseLocalProtocols & BROWSE_SLP)
692 slpRegisterPrinter(p); */
693#endif /* HAVE_LIBSLP */
694
695#ifdef HAVE_DNSSD
bdd6c45b 696 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
f7deaa1a 697 dnssdRegisterPrinter(p);
698#endif /* HAVE_DNSSD */
699}
700
701
d09495fa 702/*
703 * 'cupsdRestartPolling()' - Restart polling servers as needed.
704 */
705
706void
707cupsdRestartPolling(void)
708{
709 int i; /* Looping var */
710 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
711
712
713 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
714 if (pollp->pid)
715 kill(pollp->pid, SIGHUP);
716}
717
718
ef416fc2 719/*
e00b005a 720 * 'cupsdSaveRemoteCache()' - Save the remote printer cache.
ef416fc2 721 */
722
723void
e00b005a 724cupsdSaveRemoteCache(void)
ef416fc2 725{
e00b005a 726 int i; /* Looping var */
727 cups_file_t *fp; /* printers.conf file */
58dc1933
MS
728 char temp[1024], /* Temporary string */
729 value[2048]; /* Value string */
e00b005a 730 cupsd_printer_t *printer; /* Current printer class */
731 time_t curtime; /* Current time */
732 struct tm *curdate; /* Current date */
b423cd4c 733 cups_option_t *option; /* Current option */
ef416fc2 734
ef416fc2 735
736 /*
e00b005a 737 * Create the remote.cache file...
ef416fc2 738 */
739
e00b005a 740 snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir);
ef416fc2 741
e00b005a 742 if ((fp = cupsFileOpen(temp, "w")) == NULL)
ef416fc2 743 {
744 cupsdLogMessage(CUPSD_LOG_ERROR,
e00b005a 745 "Unable to save remote.cache - %s", strerror(errno));
ef416fc2 746 return;
747 }
e00b005a 748 else
f7deaa1a 749 cupsdLogMessage(CUPSD_LOG_DEBUG, "Saving remote.cache...");
ef416fc2 750
751 /*
e00b005a 752 * Restrict access to the file...
ef416fc2 753 */
754
e00b005a 755 fchown(cupsFileNumber(fp), getuid(), Group);
756 fchmod(cupsFileNumber(fp), ConfigFilePerm);
ef416fc2 757
e00b005a 758 /*
759 * Write a small header to the file...
760 */
ef416fc2 761
e00b005a 762 curtime = time(NULL);
763 curdate = localtime(&curtime);
764 strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate);
ef416fc2 765
e00b005a 766 cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n");
767 cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
ef416fc2 768
769 /*
e00b005a 770 * Write each local printer known to the system...
ef416fc2 771 */
772
e00b005a 773 for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers);
774 printer;
775 printer = (cupsd_printer_t *)cupsArrayNext(Printers))
ef416fc2 776 {
777 /*
e00b005a 778 * Skip local destinations...
ef416fc2 779 */
780
09a101d6 781 if (!(printer->type & CUPS_PRINTER_DISCOVERED))
e00b005a 782 continue;
ef416fc2 783
ef416fc2 784 /*
e00b005a 785 * Write printers as needed...
ef416fc2 786 */
787
e00b005a 788 if (printer == DefaultPrinter)
789 cupsFilePuts(fp, "<Default");
ef416fc2 790 else
e00b005a 791 cupsFilePutChar(fp, '<');
ef416fc2 792
e00b005a 793 if (printer->type & CUPS_PRINTER_CLASS)
794 cupsFilePrintf(fp, "Class %s>\n", printer->name);
795 else
796 cupsFilePrintf(fp, "Printer %s>\n", printer->name);
ef416fc2 797
8ca02f3c 798 cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_expire);
ef416fc2 799
e00b005a 800 if (printer->info)
58dc1933 801 cupsFilePutConf(fp, "Info", printer->info);
ef416fc2 802
e00b005a 803 if (printer->location)
58dc1933
MS
804 cupsFilePutConf(fp, "Location", printer->location);
805
806 if (printer->make_model)
807 cupsFilePutConf(fp, "MakeModel", printer->make_model);
ef416fc2 808
58dc1933 809 cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
ef416fc2 810
e00b005a 811 if (printer->state == IPP_PRINTER_STOPPED)
e00b005a 812 cupsFilePuts(fp, "State Stopped\n");
e00b005a 813 else
814 cupsFilePuts(fp, "State Idle\n");
ef416fc2 815
0af14961 816 for (i = 0; i < printer->num_reasons; i ++)
58dc1933
MS
817 cupsFilePutConf(fp, "Reason", printer->reasons[i]);
818
819 cupsFilePrintf(fp, "Type %d\n", printer->type);
0af14961 820
e00b005a 821 if (printer->accepting)
822 cupsFilePuts(fp, "Accepting Yes\n");
823 else
824 cupsFilePuts(fp, "Accepting No\n");
ef416fc2 825
58dc1933
MS
826 snprintf(value, sizeof(value), "%s %s", printer->job_sheets[0],
827 printer->job_sheets[1]);
828 cupsFilePutConf(fp, "JobSheets", value);
ef416fc2 829
e00b005a 830 for (i = 0; i < printer->num_users; i ++)
58dc1933
MS
831 cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
832 printer->users[i]);
ef416fc2 833
b423cd4c 834 for (i = printer->num_options, option = printer->options;
835 i > 0;
836 i --, option ++)
58dc1933
MS
837 {
838 snprintf(value, sizeof(value), "%s %s", option->name, option->value);
839 cupsFilePutConf(fp, "Option", value);
840 }
b423cd4c 841
e00b005a 842 if (printer->type & CUPS_PRINTER_CLASS)
843 cupsFilePuts(fp, "</Class>\n");
844 else
845 cupsFilePuts(fp, "</Printer>\n");
846 }
ef416fc2 847
e00b005a 848 cupsFileClose(fp);
849}
ef416fc2 850
ef416fc2 851
e00b005a 852/*
853 * 'cupsdSendBrowseList()' - Send new browsing information as necessary.
854 */
ef416fc2 855
e00b005a 856void
857cupsdSendBrowseList(void)
858{
859 int count; /* Number of dests to update */
860 cupsd_printer_t *p; /* Current printer */
861 time_t ut, /* Minimum update time */
862 to; /* Timeout time */
ef416fc2 863
e00b005a 864
1f0275e3 865 if (!Browsing || !Printers)
e00b005a 866 return;
867
868 /*
869 * Compute the update and timeout times...
870 */
871
b423cd4c 872 to = time(NULL);
873 ut = to - BrowseInterval;
e00b005a 874
875 /*
876 * Figure out how many printers need an update...
877 */
878
1f0275e3 879 if (BrowseInterval > 0 && BrowseLocalProtocols)
e00b005a 880 {
881 int max_count; /* Maximum number to update */
882
883
884 /*
885 * Throttle the number of printers we'll be updating this time
886 * around based on the number of queues that need updating and
887 * the maximum number of queues to update each second...
888 */
889
890 max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1;
891
892 for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers);
893 count < max_count && p != NULL;
894 p = (cupsd_printer_t *)cupsArrayNext(Printers))
f11a948a
MS
895 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
896 CUPS_PRINTER_SCANNER)) &&
e00b005a 897 p->shared && p->browse_time < ut)
898 count ++;
899
900 /*
901 * Loop through all of the printers and send local updates as needed...
902 */
903
904 if (BrowseNext)
905 p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext);
906 else
907 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
908
909 for (;
910 count > 0;
911 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ef416fc2 912 {
913 /*
e00b005a 914 * Check for wraparound...
ef416fc2 915 */
916
e00b005a 917 if (!p)
918 p = (cupsd_printer_t *)cupsArrayFirst(Printers);
ef416fc2 919
e00b005a 920 if (!p)
921 break;
f11a948a
MS
922 else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
923 CUPS_PRINTER_SCANNER)) ||
e00b005a 924 !p->shared)
925 continue;
926 else if (p->browse_time < ut)
927 {
928 /*
929 * Need to send an update...
930 */
ef416fc2 931
e00b005a 932 count --;
ef416fc2 933
e00b005a 934 p->browse_time = time(NULL);
ef416fc2 935
0a682745 936 if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
e1d6a774 937 send_cups_browse(p);
ef416fc2 938
e00b005a 939#ifdef HAVE_LIBSLP
940 if (BrowseLocalProtocols & BROWSE_SLP)
e1d6a774 941 send_slp_browse(p);
e00b005a 942#endif /* HAVE_LIBSLP */
b423cd4c 943
944#ifdef HAVE_LDAP
945 if (BrowseLocalProtocols & BROWSE_LDAP)
e1d6a774 946 send_ldap_browse(p);
b423cd4c 947#endif /* HAVE_LDAP */
e00b005a 948 }
ef416fc2 949 }
e00b005a 950
951 /*
952 * Save where we left off so that all printers get updated...
953 */
954
955 BrowseNext = p;
ef416fc2 956 }
957
958 /*
1f0275e3 959 * Loop through all of the printers and timeout old printers as needed...
ef416fc2 960 */
961
3dfe78b3 962 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
e00b005a 963 p;
964 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ef416fc2 965 {
e00b005a 966 /*
967 * If this is a remote queue, see if it needs to be timed out...
968 */
ef416fc2 969
1f0275e3
MS
970 if ((p->type & CUPS_PRINTER_DISCOVERED) &&
971 !(p->type & CUPS_PRINTER_IMPLICIT) &&
972 p->browse_expire < to)
ef416fc2 973 {
1f0275e3
MS
974 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
975 "%s \'%s\' deleted by directory services (timeout).",
976 (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer",
977 p->name);
978
979 cupsdLogMessage(CUPSD_LOG_DEBUG,
980 "Remote destination \"%s\" has timed out; "
981 "deleting it...",
e00b005a 982 p->name);
983
1f0275e3
MS
984 cupsArraySave(Printers);
985 cupsdDeletePrinter(p, 1);
986 cupsArrayRestore(Printers);
987 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
ef416fc2 988 }
989 }
e00b005a 990}
ef416fc2 991
ef416fc2 992
749b1e90
MS
993#ifdef HAVE_LDAP_REBIND_PROC
994# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
995/*
996 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
997 */
998
999static int
1000ldap_rebind_proc (LDAP *RebindLDAPHandle,
1001 LDAP_CONST char *refsp,
1002 ber_tag_t request,
1003 ber_int_t msgid,
1004 void *params)
1005{
1006 int rc;
1007
1008 /*
1009 * Bind to new LDAP server...
1010 */
1011
1012 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1013 "ldap_rebind_proc: Rebind to %s", refsp);
1014
1015# if LDAP_API_VERSION > 3000
1016 struct berval bval;
1017 bval.bv_val = BrowseLDAPPassword;
1018 bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1019
1020 rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
1021# else
1022 rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN,
1023 BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1024# endif /* LDAP_API_VERSION > 3000 */
1025
1026 return (rc);
1027}
1028
1029# else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1030
1031/*
1032 * 'ldap_rebind_proc()' - Callback function for LDAP rebind
1033 */
1034
1035static int
1036ldap_rebind_proc (LDAP *RebindLDAPHandle,
1037 char **dnp,
1038 char **passwdp,
1039 int *authmethodp,
1040 int freeit,
1041 void *arg)
1042{
1043 switch ( freeit ) {
1044
1045 case 1:
1046
1047 /*
1048 * Free current values...
1049 */
1050
1051 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1052 "ldap_rebind_proc: Free values...");
1053
1054 if ( dnp && *dnp ) {
1055 free( *dnp );
1056 }
1057 if ( passwdp && *passwdp ) {
1058 free( *passwdp );
1059 }
1060 break;
1061
1062 case 0:
1063
1064 /*
1065 * Return credentials for LDAP referal...
1066 */
1067
1068 cupsdLogMessage(CUPSD_LOG_DEBUG2,
1069 "ldap_rebind_proc: Return necessary values...");
1070
1071 *dnp = strdup(BrowseLDAPBindDN);
1072 *passwdp = strdup(BrowseLDAPPassword);
1073 *authmethodp = LDAP_AUTH_SIMPLE;
1074 break;
1075
1076 default:
1077
1078 /*
1079 * Should never happen...
1080 */
1081
1082 cupsdLogMessage(CUPSD_LOG_ERROR,
1083 "LDAP rebind has been called with wrong freeit value!");
1084 break;
1085
1086 }
1087
1088 return (LDAP_SUCCESS);
1089}
1090# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1091#endif /* HAVE_LDAP_REBIND_PROC */
1092
1093
1094#ifdef HAVE_LDAP
1095/*
1096 * 'ldap_connect()' - Start new LDAP connection
1097 */
1098
1099static LDAP *
1100ldap_connect(void)
1101{
1102 /*
1103 * Open LDAP handle...
1104 */
1105
1106 int rc; /* LDAP API status */
1107 int version = 3; /* LDAP version */
1108 struct berval bv = {0, ""}; /* SASL bind value */
1109 LDAP *TempBrowseLDAPHandle=NULL; /* Temporary LDAP Handle */
1110# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1111 int ldap_ssl = 0; /* LDAP SSL indicator */
1112 int ssl_err = 0; /* LDAP SSL error value */
1113# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1114
1115# ifdef HAVE_OPENLDAP
1116# ifdef HAVE_LDAP_SSL
1117
1118 /*
1119 * Set the certificate file to use for encrypted LDAP sessions...
1120 */
1121
1122 if (BrowseLDAPCACertFile)
1123 {
1124 cupsdLogMessage(CUPSD_LOG_DEBUG,
1125 "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
1126 BrowseLDAPCACertFile);
1127
1128 if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
1129 (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
1130 cupsdLogMessage(CUPSD_LOG_ERROR,
1131 "Unable to set CA certificate file for LDAP "
1132 "connections: %d - %s", rc, ldap_err2string(rc));
1133 }
1134
1135# endif /* HAVE_LDAP_SSL */
1136 /*
1137 * Initialize OPENLDAP connection...
1138 * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
1139 */
1140
1141 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1142 rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
1143 else
1144 rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
1145
1146# else /* HAVE_OPENLDAP */
1147
1148 int ldap_port = 0; /* LDAP port */
1149 char ldap_protocol[11], /* LDAP protocol */
1150 ldap_host[255]; /* LDAP host */
1151
1152 /*
1153 * Split LDAP URI into its components...
1154 */
1155
1156 if (! BrowseLDAPServer)
1157 {
1158 cupsdLogMessage(CUPSD_LOG_ERROR,
1159 "BrowseLDAPServer not configured! Disable LDAP browsing!");
1160 BrowseLocalProtocols &= ~BROWSE_LDAP;
1161 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1162 return (NULL);
1163 }
1164
1165 sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host, &ldap_port);
1166
1167 if (strcmp(ldap_protocol, "ldap") == 0) {
1168 ldap_ssl = 0;
1169 } else if (strcmp(ldap_protocol, "ldaps") == 0) {
1170 ldap_ssl = 1;
1171 } else {
1172 cupsdLogMessage(CUPSD_LOG_ERROR,
1173 "unrecognised ldap protocol (%s)!", ldap_protocol);
1174 cupsdLogMessage(CUPSD_LOG_ERROR,
1175 "Disable LDAP browsing!");
1176 BrowseLocalProtocols &= ~BROWSE_LDAP;
1177 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1178 return (NULL);
1179 }
1180
1181 if (ldap_port == 0)
1182 {
1183 if (ldap_ssl)
1184 ldap_port = LDAPS_PORT;
1185 else
1186 ldap_port = LDAP_PORT;
1187 }
1188
1189 cupsdLogMessage(CUPSD_LOG_DEBUG,
1190 "LDAP Connection Details: PROT:%s HOST:%s PORT:%d",
1191 ldap_protocol, ldap_host, ldap_port);
1192
1193 /*
1194 * Initialize LDAP connection...
1195 */
1196
1197 if (! ldap_ssl)
1198 {
1199 if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
1200 rc = LDAP_OPERATIONS_ERROR;
1201 else
1202 rc = LDAP_SUCCESS;
1203
1204# ifdef HAVE_LDAP_SSL
1205 }
1206 else
1207 {
1208
1209 /*
1210 * Initialize SSL LDAP connection...
1211 */
1212 if (BrowseLDAPCACertFile)
1213 {
1214 rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
1215 if (rc != LDAP_SUCCESS) {
1216 cupsdLogMessage(CUPSD_LOG_ERROR,
1217 "Failed to initialize LDAP SSL client!");
1218 rc = LDAP_OPERATIONS_ERROR;
1219 } else {
1220 if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port, 1)) == NULL)
1221 rc = LDAP_OPERATIONS_ERROR;
1222 else
1223 rc = LDAP_SUCCESS;
1224 }
1225 }
1226 else
1227 {
1228 cupsdLogMessage(CUPSD_LOG_ERROR,
1229 "LDAP SSL certificate file/database not configured!");
1230 rc = LDAP_OPERATIONS_ERROR;
1231 }
1232
1233# else /* HAVE_LDAP_SSL */
1234
1235 /*
1236 * Return error, because client libraries doesn't support SSL
1237 */
1238
1239 cupsdLogMessage(CUPSD_LOG_ERROR,
1240 "LDAP client libraries does not support TLS");
1241 rc = LDAP_OPERATIONS_ERROR;
1242
1243# endif /* HAVE_LDAP_SSL */
1244 }
1245# endif /* HAVE_OPENLDAP */
1246
1247 /*
1248 * Check return code from LDAP initialize...
1249 */
1250
1251 if (rc != LDAP_SUCCESS)
1252 {
1253 if ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))
1254 {
1255 cupsdLogMessage(CUPSD_LOG_ERROR,
1256 "Unable to initialize LDAP! Temporary disable LDAP browsing...");
1257 }
1258 else
1259 {
1260 cupsdLogMessage(CUPSD_LOG_ERROR,
1261 "Unable to initialize LDAP! Disable LDAP browsing!");
1262 BrowseLocalProtocols &= ~BROWSE_LDAP;
1263 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1264 }
1265
1266 ldap_disconnect(TempBrowseLDAPHandle);
1267 TempBrowseLDAPHandle = NULL;
1268 }
1269
1270 /*
1271 * Upgrade LDAP version...
1272 */
1273
1274 else if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
1275 (const void *)&version) != LDAP_SUCCESS)
1276 {
1277 cupsdLogMessage(CUPSD_LOG_ERROR,
1278 "Unable to set LDAP protocol version %d! Disable LDAP browsing!",
1279 version);
1280 BrowseLocalProtocols &= ~BROWSE_LDAP;
1281 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1282 ldap_disconnect(TempBrowseLDAPHandle);
1283 TempBrowseLDAPHandle = NULL;
1284 }
1285 else
1286 {
1287
1288 /*
1289 * Register LDAP rebind procedure...
1290 */
1291
1292# ifdef HAVE_LDAP_REBIND_PROC
1293# if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
1294
1295 rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
1296 if ( rc != LDAP_SUCCESS )
1297 cupsdLogMessage(CUPSD_LOG_ERROR,
1298 "Setting LDAP rebind function failed with status %d: %s",
1299 rc, ldap_err2string(rc));
1300
1301# else
1302
1303 ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
1304
1305# endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
1306# endif /* HAVE_LDAP_REBIND_PROC */
1307
1308 /*
1309 * Start LDAP bind...
1310 */
1311
1312# if LDAP_API_VERSION > 3000
1313 struct berval bval;
1314 bval.bv_val = BrowseLDAPPassword;
1315 bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
1316
1317 if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
1318 rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
1319 NULL, NULL);
1320 else
1321 rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
1322# else
1323 rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
1324 BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
1325# endif /* LDAP_API_VERSION > 3000 */
1326
1327 if (rc != LDAP_SUCCESS)
1328 {
1329 cupsdLogMessage(CUPSD_LOG_ERROR,
1330 "LDAP bind failed with error %d: %s",
1331 rc, ldap_err2string(rc));
1332# if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
1333 if (ldap_ssl && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
1334 {
1335 ssl_err = PORT_GetError();
1336 if (ssl_err != 0)
1337 cupsdLogMessage(CUPSD_LOG_ERROR,
1338 "LDAP SSL error %d: %s",
1339 ssl_err, ldapssl_err2string(ssl_err));
1340 }
1341# endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
1342 ldap_disconnect(TempBrowseLDAPHandle);
1343 TempBrowseLDAPHandle = NULL;
1344 }
1345 else
1346 {
1347 cupsdLogMessage(CUPSD_LOG_INFO,
1348 "LDAP connection established");
1349 }
1350
1351 }
1352 return (TempBrowseLDAPHandle);
1353}
1354
1355
1356/*
1357 * 'ldap_reconnect()' - Reconnect to LDAP Server
1358 */
1359
1360static void
1361ldap_reconnect(void)
1362{
1363 LDAP *TempBrowseLDAPHandle = NULL; /* Temp Handle to LDAP server */
1364
1365 cupsdLogMessage(CUPSD_LOG_INFO,
1366 "Try LDAP reconnect...");
1367
1368 /*
1369 * Get a new LDAP Handle and replace the global Handle
1370 * if the new connection was successful
1371 */
1372
1373 TempBrowseLDAPHandle = ldap_connect();
1374
1375 if (TempBrowseLDAPHandle != NULL)
1376 {
1377 if (BrowseLDAPHandle != NULL)
1378 {
1379 ldap_disconnect(BrowseLDAPHandle);
1380 }
1381 BrowseLDAPHandle = TempBrowseLDAPHandle;
1382 }
1383}
1384
1385
1386/*
1387 * 'ldap_disconnect()' - Disconnect from LDAP Server
1388 */
1389
1390static void
1391ldap_disconnect(LDAP *ld) /* I - LDAP handle */
1392{
1393 int rc; /* return code */
1394
1395 /*
1396 * Close LDAP handle...
1397 */
1398
1399# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
1400 rc = ldap_unbind_ext_s(ld, NULL, NULL);
1401# else
1402 rc = ldap_unbind_s(ld);
1403# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
1404 if (rc != LDAP_SUCCESS)
1405 cupsdLogMessage(CUPSD_LOG_ERROR,
1406 "Unbind from LDAP server failed with status %d: %s",
1407 rc, ldap_err2string(rc));
1408}
1409#endif /* HAVE_LDAP */
1410
1411
e00b005a 1412/*
e1d6a774 1413 * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
e00b005a 1414 */
ef416fc2 1415
e00b005a 1416void
e1d6a774 1417cupsdStartBrowsing(void)
e00b005a 1418{
e1d6a774 1419 int val; /* Socket option value */
1420 struct sockaddr_in addr; /* Broadcast address */
f7deaa1a 1421 cupsd_printer_t *p; /* Current printer */
ef416fc2 1422
ef416fc2 1423
e1d6a774 1424 BrowseNext = NULL;
ef416fc2 1425
e1d6a774 1426 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1427 return;
ef416fc2 1428
e1d6a774 1429 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS)
1430 {
1431 if (BrowseSocket < 0)
1432 {
1433 /*
1434 * Create the broadcast socket...
1435 */
ef416fc2 1436
e1d6a774 1437 if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1438 {
1439 cupsdLogMessage(CUPSD_LOG_ERROR,
bc44d920 1440 "Unable to create broadcast socket - %s.",
1441 strerror(errno));
e1d6a774 1442 BrowseLocalProtocols &= ~BROWSE_CUPS;
1443 BrowseRemoteProtocols &= ~BROWSE_CUPS;
49d87452
MS
1444
1445 if (FatalErrors & CUPSD_FATAL_BROWSE)
1446 cupsdEndProcess(getpid(), 0);
e1d6a774 1447 }
49d87452 1448 }
ef416fc2 1449
49d87452
MS
1450 if (BrowseSocket >= 0)
1451 {
ef416fc2 1452 /*
e1d6a774 1453 * Bind the socket to browse port...
ef416fc2 1454 */
1455
e1d6a774 1456 memset(&addr, 0, sizeof(addr));
1457 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1458 addr.sin_family = AF_INET;
1459 addr.sin_port = htons(BrowsePort);
1460
1461 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
ef416fc2 1462 {
e1d6a774 1463 cupsdLogMessage(CUPSD_LOG_ERROR,
bc44d920 1464 "Unable to bind broadcast socket - %s.",
1465 strerror(errno));
ef416fc2 1466
e1d6a774 1467#ifdef WIN32
1468 closesocket(BrowseSocket);
1469#else
1470 close(BrowseSocket);
1471#endif /* WIN32 */
ef416fc2 1472
e1d6a774 1473 BrowseSocket = -1;
1474 BrowseLocalProtocols &= ~BROWSE_CUPS;
1475 BrowseRemoteProtocols &= ~BROWSE_CUPS;
49d87452
MS
1476
1477 if (FatalErrors & CUPSD_FATAL_BROWSE)
1478 cupsdEndProcess(getpid(), 0);
e1d6a774 1479 }
1480 }
ef416fc2 1481
49d87452 1482 if (BrowseSocket >= 0)
e1d6a774 1483 {
49d87452
MS
1484 /*
1485 * Set the "broadcast" flag...
1486 */
1487
1488 val = 1;
1489 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1490 {
1491 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
1492 strerror(errno));
ef416fc2 1493
e1d6a774 1494#ifdef WIN32
49d87452 1495 closesocket(BrowseSocket);
e1d6a774 1496#else
49d87452 1497 close(BrowseSocket);
e1d6a774 1498#endif /* WIN32 */
ef416fc2 1499
49d87452
MS
1500 BrowseSocket = -1;
1501 BrowseLocalProtocols &= ~BROWSE_CUPS;
1502 BrowseRemoteProtocols &= ~BROWSE_CUPS;
e00b005a 1503
49d87452
MS
1504 if (FatalErrors & CUPSD_FATAL_BROWSE)
1505 cupsdEndProcess(getpid(), 0);
1506 }
1507 }
e00b005a 1508
49d87452
MS
1509 if (BrowseSocket >= 0)
1510 {
1511 /*
1512 * Close the socket on exec...
1513 */
e00b005a 1514
49d87452 1515 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
ef416fc2 1516
8ca02f3c 1517 /*
49d87452 1518 * Finally, add the socket to the input selection set as needed...
8ca02f3c 1519 */
ef416fc2 1520
49d87452
MS
1521 if (BrowseRemoteProtocols & BROWSE_CUPS)
1522 {
1523 /*
1524 * We only listen if we want remote printers...
1525 */
1526
1527 cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
1528 NULL, NULL);
1529 }
8ca02f3c 1530 }
e1d6a774 1531 }
1532 else
1533 BrowseSocket = -1;
ef416fc2 1534
7a14d768
MS
1535#ifdef HAVE_DNSSD
1536 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1537 {
1538 DNSServiceErrorType error; /* Error from service creation */
1539 cupsd_listener_t *lis; /* Current listening socket */
1540
1541
1542 /*
1543 * First create a "master" connection for all registrations...
1544 */
1545
1546 if ((error = DNSServiceCreateConnection(&DNSSDRef))
1547 != kDNSServiceErr_NoError)
49d87452 1548 {
7a14d768
MS
1549 cupsdLogMessage(CUPSD_LOG_ERROR,
1550 "Unable to create master DNS-SD reference: %d", error);
49d87452
MS
1551
1552 if (FatalErrors & CUPSD_FATAL_BROWSE)
1553 cupsdEndProcess(getpid(), 0);
1554 }
7a14d768
MS
1555 else
1556 {
1557 /*
1558 * Add the master connection to the select list...
1559 */
1560
1561 cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef),
75bd9771 1562 (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
7a14d768
MS
1563
1564 /*
1565 * Then get the port we use for registrations. If we are not listening
1566 * on any non-local ports, there is no sense sharing local printers via
1567 * Bonjour...
1568 */
1569
1570 DNSSDPort = 0;
1571
1572 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1573 lis;
1574 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1575 {
1576 if (httpAddrLocalhost(&(lis->address)))
1577 continue;
1578
1579 if (lis->address.addr.sa_family == AF_INET)
1580 {
1581 DNSSDPort = ntohs(lis->address.ipv4.sin_port);
1582 break;
1583 }
1584 else if (lis->address.addr.sa_family == AF_INET6)
1585 {
1586 DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
1587 break;
1588 }
1589 }
1590
1591 /*
1592 * Create an array to track the printers we share...
1593 */
1594
1595 if (BrowseRemoteProtocols & BROWSE_DNSSD)
1596 DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
1597 NULL);
1598
1599 /*
1600 * Set the computer name and register the web interface...
1601 */
1602
1603 cupsdUpdateDNSSDName();
1604 }
1605 }
1606#endif /* HAVE_DNSSD */
1607
e1d6a774 1608#ifdef HAVE_LIBSLP
1609 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1610 {
1611 /*
1612 * Open SLP handle...
1613 */
ef416fc2 1614
e1d6a774 1615 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1616 {
1617 cupsdLogMessage(CUPSD_LOG_ERROR,
1618 "Unable to open an SLP handle; disabling SLP browsing!");
1619 BrowseLocalProtocols &= ~BROWSE_SLP;
1620 BrowseRemoteProtocols &= ~BROWSE_SLP;
49d87452
MS
1621 BrowseSLPHandle = NULL;
1622
1623 if (FatalErrors & CUPSD_FATAL_BROWSE)
1624 cupsdEndProcess(getpid(), 0);
e1d6a774 1625 }
e00b005a 1626
e1d6a774 1627 BrowseSLPRefresh = 0;
1628 }
f301802f 1629 else
1630 BrowseSLPHandle = NULL;
e1d6a774 1631#endif /* HAVE_LIBSLP */
1632
749b1e90 1633#ifdef HAVE_LDAP
e1d6a774 1634 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1635 {
1636 if (!BrowseLDAPDN)
1637 {
1638 cupsdLogMessage(CUPSD_LOG_ERROR,
1639 "Need to set BrowseLDAPDN to use LDAP browsing!");
1640 BrowseLocalProtocols &= ~BROWSE_LDAP;
1641 BrowseRemoteProtocols &= ~BROWSE_LDAP;
49d87452
MS
1642
1643 if (FatalErrors & CUPSD_FATAL_BROWSE)
1644 cupsdEndProcess(getpid(), 0);
ef416fc2 1645 }
1646 else
1647 {
49d87452
MS
1648 /*
1649 * Open LDAP handle...
1650 */
1651
1652 if ((BrowseLDAPHandle = ldap_connect()) == NULL &&
1653 (FatalErrors & CUPSD_FATAL_BROWSE))
1654 cupsdEndProcess(getpid(), 0);
ef416fc2 1655 }
e1d6a774 1656
1657 BrowseLDAPRefresh = 0;
1658 }
749b1e90 1659#endif /* HAVE_LDAP */
f7deaa1a 1660
2e4ff8af
MS
1661 /*
1662 * Enable LPD and SMB printer sharing as needed through external programs...
1663 */
1664
1665 if (BrowseLocalProtocols & BROWSE_LPD)
1666 update_lpd(1);
1667
1668 if (BrowseLocalProtocols & BROWSE_SMB)
1669 update_smb(1);
1670
f7deaa1a 1671 /*
1672 * Register the individual printers
1673 */
1674
1675 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1676 p;
1677 p = (cupsd_printer_t *)cupsArrayNext(Printers))
f11a948a
MS
1678 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1679 CUPS_PRINTER_SCANNER)))
f7deaa1a 1680 cupsdRegisterPrinter(p);
ef416fc2 1681}
1682
1683
b423cd4c 1684/*
e1d6a774 1685 * 'cupsdStartPolling()' - Start polling servers as needed.
b423cd4c 1686 */
1687
e1d6a774 1688void
1689cupsdStartPolling(void)
b423cd4c 1690{
e1d6a774 1691 int i; /* Looping var */
1692 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1693 char polld[1024]; /* Poll daemon path */
07725fee 1694 char sport[255]; /* Server port */
1695 char bport[255]; /* Browser port */
1696 char interval[255]; /* Poll interval */
e1d6a774 1697 int statusfds[2]; /* Status pipe */
1698 char *argv[6]; /* Arguments */
1699 char *envp[100]; /* Environment */
b423cd4c 1700
b423cd4c 1701
1702 /*
e1d6a774 1703 * Don't do anything if we aren't polling...
b423cd4c 1704 */
1705
2abf387c 1706 if (NumPolled == 0 || BrowseSocket < 0)
e1d6a774 1707 {
1708 PollPipe = -1;
1709 PollStatusBuffer = NULL;
1710 return;
1711 }
b423cd4c 1712
e1d6a774 1713 /*
1714 * Setup string arguments for polld, port and interval options.
1715 */
b423cd4c 1716
e1d6a774 1717 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
b423cd4c 1718
e1d6a774 1719 sprintf(bport, "%d", BrowsePort);
b423cd4c 1720
e1d6a774 1721 if (BrowseInterval)
1722 sprintf(interval, "%d", BrowseInterval);
1723 else
1724 strcpy(interval, "30");
b423cd4c 1725
e1d6a774 1726 argv[0] = "cups-polld";
1727 argv[2] = sport;
1728 argv[3] = interval;
1729 argv[4] = bport;
1730 argv[5] = NULL;
b423cd4c 1731
e1d6a774 1732 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1733
1734 /*
1735 * Create a pipe that receives the status messages from each
1736 * polling daemon...
1737 */
1738
1739 if (cupsdOpenPipe(statusfds))
b423cd4c 1740 {
e1d6a774 1741 cupsdLogMessage(CUPSD_LOG_ERROR,
1742 "Unable to create polling status pipes - %s.",
1743 strerror(errno));
1744 PollPipe = -1;
1745 PollStatusBuffer = NULL;
1746 return;
1747 }
b423cd4c 1748
e1d6a774 1749 PollPipe = statusfds[0];
1750 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
b423cd4c 1751
e1d6a774 1752 /*
1753 * Run each polling daemon, redirecting stderr to the polling pipe...
1754 */
b423cd4c 1755
e1d6a774 1756 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
b423cd4c 1757 {
e1d6a774 1758 sprintf(sport, "%d", pollp->port);
b423cd4c 1759
e1d6a774 1760 argv[1] = pollp->hostname;
b423cd4c 1761
f7deaa1a 1762 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
38e73f87 1763 0, DefaultProfile, NULL, &(pollp->pid)) < 0)
b423cd4c 1764 {
b423cd4c 1765 cupsdLogMessage(CUPSD_LOG_ERROR,
e1d6a774 1766 "cupsdStartPolling: Unable to fork polling daemon - %s",
1767 strerror(errno));
1768 pollp->pid = 0;
1769 break;
1770 }
1771 else
1772 cupsdLogMessage(CUPSD_LOG_DEBUG,
1773 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1774 pollp->hostname, pollp->port, pollp->pid);
b423cd4c 1775 }
e1d6a774 1776
1777 close(statusfds[1]);
1778
1779 /*
1780 * Finally, add the pipe to the input selection set...
1781 */
1782
f899b121 1783 cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
b423cd4c 1784}
b423cd4c 1785
1786
ef416fc2 1787/*
e1d6a774 1788 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
ef416fc2 1789 */
1790
e1d6a774 1791void
1792cupsdStopBrowsing(void)
ef416fc2 1793{
f7deaa1a 1794 cupsd_printer_t *p; /* Current printer */
1795
1796
e1d6a774 1797 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1798 return;
ef416fc2 1799
f7deaa1a 1800 /*
1801 * De-register the individual printers
1802 */
1803
1804 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1805 p;
1806 p = (cupsd_printer_t *)cupsArrayNext(Printers))
f11a948a
MS
1807 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT |
1808 CUPS_PRINTER_SCANNER)))
f7deaa1a 1809 cupsdDeregisterPrinter(p, 1);
1810
1811 /*
1812 * Shut down browsing sockets...
1813 */
1814
e1d6a774 1815 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1816 BrowseSocket >= 0)
1817 {
1818 /*
1819 * Close the socket and remove it from the input selection set.
1820 */
ef416fc2 1821
e1d6a774 1822#ifdef WIN32
1823 closesocket(BrowseSocket);
1824#else
1825 close(BrowseSocket);
1826#endif /* WIN32 */
ef416fc2 1827
f7deaa1a 1828 cupsdRemoveSelect(BrowseSocket);
e1d6a774 1829 BrowseSocket = -1;
1830 }
ef416fc2 1831
7a14d768
MS
1832#ifdef HAVE_DNSSD
1833 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
f0ab5bff 1834 dnssdStop();
7a14d768
MS
1835#endif /* HAVE_DNSSD */
1836
e1d6a774 1837#ifdef HAVE_LIBSLP
1838 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1839 BrowseSLPHandle)
1840 {
1841 /*
1842 * Close SLP handle...
1843 */
ef416fc2 1844
e1d6a774 1845 SLPClose(BrowseSLPHandle);
1846 BrowseSLPHandle = NULL;
e00b005a 1847 }
e1d6a774 1848#endif /* HAVE_LIBSLP */
ef416fc2 1849
749b1e90 1850#ifdef HAVE_LDAP
e1d6a774 1851 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1852 BrowseLDAPHandle)
e00b005a 1853 {
749b1e90
MS
1854 ldap_dereg_ou(ServerName, BrowseLDAPDN);
1855 ldap_disconnect(BrowseLDAPHandle);
e1d6a774 1856 BrowseLDAPHandle = NULL;
e00b005a 1857 }
e1d6a774 1858#endif /* HAVE_OPENLDAP */
2e4ff8af
MS
1859
1860 /*
1861 * Disable LPD and SMB printer sharing as needed through external programs...
1862 */
1863
1864 if (BrowseLocalProtocols & BROWSE_LPD)
1865 update_lpd(0);
1866
1867 if (BrowseLocalProtocols & BROWSE_SMB)
1868 update_smb(0);
e1d6a774 1869}
ef416fc2 1870
ef416fc2 1871
e1d6a774 1872/*
1873 * 'cupsdStopPolling()' - Stop polling servers as needed.
1874 */
ef416fc2 1875
e1d6a774 1876void
1877cupsdStopPolling(void)
1878{
1879 int i; /* Looping var */
1880 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
ef416fc2 1881
ef416fc2 1882
e1d6a774 1883 if (PollPipe >= 0)
e00b005a 1884 {
e1d6a774 1885 cupsdStatBufDelete(PollStatusBuffer);
1886 close(PollPipe);
ef416fc2 1887
f7deaa1a 1888 cupsdRemoveSelect(PollPipe);
e1d6a774 1889
1890 PollPipe = -1;
1891 PollStatusBuffer = NULL;
e00b005a 1892 }
ef416fc2 1893
e1d6a774 1894 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1895 if (pollp->pid)
1896 cupsdEndProcess(pollp->pid, 0);
1897}
ef416fc2 1898
ef416fc2 1899
f899b121 1900#ifdef HAVE_DNSSD
7a14d768
MS
1901/*
1902 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1903 */
1904
1905void
1906cupsdUpdateDNSSDName(void)
1907{
1908 DNSServiceErrorType error; /* Error from service creation */
1909 char webif[1024]; /* Web interface share name */
1910#ifdef HAVE_COREFOUNDATION_H
38e73f87 1911 SCDynamicStoreRef sc; /* Context for dynamic store */
e07d4801 1912 CFDictionaryRef btmm; /* Back-to-My-Mac domains */
f11a948a 1913 CFStringRef nameRef; /* Host name CFString */
7a14d768 1914 char nameBuffer[1024]; /* C-string buffer */
7a14d768
MS
1915#endif /* HAVE_COREFOUNDATION_H */
1916
1917
1918 /*
1919 * Only share the web interface and printers when non-local listening is
1920 * enabled...
1921 */
1922
e07d4801 1923
7a14d768
MS
1924 if (!DNSSDPort)
1925 return;
1926
1927 /*
1928 * Get the computer name as a c-string...
1929 */
1930
1931#ifdef HAVE_COREFOUNDATION_H
38e73f87 1932 sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
7a14d768 1933
38e73f87 1934 if (sc)
7a14d768 1935 {
e07d4801
MS
1936 /*
1937 * Get the computer name from the dynamic store...
1938 */
1939
1940 cupsdClearString(&DNSSDName);
1941
f11a948a 1942 if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
38e73f87
MS
1943 {
1944 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1945 kCFStringEncodingUTF8))
e07d4801
MS
1946 {
1947 cupsdLogMessage(CUPSD_LOG_DEBUG,
f11a948a 1948 "Dynamic store host name is \"%s\".", nameBuffer);
38e73f87 1949 cupsdSetString(&DNSSDName, nameBuffer);
e07d4801 1950 }
ef416fc2 1951
38e73f87
MS
1952 CFRelease(nameRef);
1953 }
e07d4801
MS
1954
1955 if (!DNSSDName)
1956 {
1957 /*
1958 * Use the ServerName instead...
1959 */
1960
1961 cupsdLogMessage(CUPSD_LOG_DEBUG,
f11a948a 1962 "Using ServerName \"%s\" as host name.", ServerName);
38e73f87 1963 cupsdSetString(&DNSSDName, ServerName);
e07d4801
MS
1964 }
1965
1966 /*
1967 * Get any Back-to-My-Mac domains and add them as aliases...
1968 */
1969
1970 cupsdFreeAliases(DNSSDAlias);
1971 DNSSDAlias = NULL;
1972
1973 btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
1974 if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
1975 {
1976 cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
1977 (int)CFDictionaryGetCount(btmm));
1978 CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
1979 }
1980 else if (btmm)
1981 cupsdLogMessage(CUPSD_LOG_ERROR,
1982 "Bad Back to My Mac data in dynamic store!");
1983 else
1984 cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
1985
1986 if (btmm)
1987 CFRelease(btmm);
7a14d768 1988
38e73f87
MS
1989 CFRelease(sc);
1990 }
1991 else
7a14d768 1992#endif /* HAVE_COREFOUNDATION_H */
38e73f87 1993 cupsdSetString(&DNSSDName, ServerName);
7a14d768
MS
1994
1995 /*
b19ccc9e 1996 * Then (re)register the web interface if enabled...
7a14d768
MS
1997 */
1998
b19ccc9e
MS
1999 if (BrowseWebIF)
2000 {
2001 if (DNSSDName)
2002 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
2003 else
2004 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
2005
2006 if (WebIFRef)
2007 DNSServiceRefDeallocate(WebIFRef);
2008
2009 WebIFRef = DNSSDRef;
2010 if ((error = DNSServiceRegister(&WebIFRef,
2011 kDNSServiceFlagsShareConnection,
2012 0, webif, "_http._tcp", NULL,
2013 NULL, htons(DNSSDPort), 7,
2014 "\006path=/", dnssdRegisterCallback,
2015 NULL)) != kDNSServiceErr_NoError)
2016 cupsdLogMessage(CUPSD_LOG_ERROR,
2017 "DNS-SD web interface registration failed: %d", error);
2018 }
f899b121 2019}
2020#endif /* HAVE_DNSSD */
ef416fc2 2021
ef416fc2 2022
749b1e90 2023#ifdef HAVE_LDAP
f899b121 2024/*
2025 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
2026 */
2027
2028void
2029cupsdUpdateLDAPBrowse(void)
2030{
2031 char uri[HTTP_MAX_URI], /* Printer URI */
2032 host[HTTP_MAX_URI], /* Hostname */
2033 resource[HTTP_MAX_URI], /* Resource path */
2034 location[1024], /* Printer location */
2035 info[1024], /* Printer information */
2036 make_model[1024], /* Printer make and model */
749b1e90 2037 type_num[30]; /* Printer type number */
f899b121 2038 int type; /* Printer type */
2039 int rc; /* LDAP status */
2040 int limit; /* Size limit */
2041 LDAPMessage *res, /* LDAP search results */
2042 *e; /* Current entry from search */
ef416fc2 2043
f899b121 2044 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
ef416fc2 2045
f899b121 2046 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
ef416fc2 2047
749b1e90
MS
2048 /*
2049 * Reconnect if LDAP Handle is invalid...
2050 */
2051
2052 if (! BrowseLDAPHandle)
e1d6a774 2053 {
749b1e90 2054 ldap_reconnect();
f899b121 2055 return;
e1d6a774 2056 }
ef416fc2 2057
749b1e90
MS
2058 /*
2059 * Search for cups printers in LDAP directory...
2060 */
2061
2062 rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
2063 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
2064
2065 /*
2066 * If ldap search was successfull then exit function
2067 * and temporary disable LDAP updates...
2068 */
2069
2070 if (rc != LDAP_SUCCESS)
2071 {
2072 if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
2073 {
2074 BrowseLDAPUpdate = FALSE;
2075 cupsdLogMessage(CUPSD_LOG_INFO,
2076 "LDAP update temporary disabled");
2077 }
2078 return;
2079 }
2080
2081 /*
2082 * If LDAP updates were disabled, we will reenable them...
2083 */
2084
2085 if (! BrowseLDAPUpdate)
2086 {
2087 BrowseLDAPUpdate = TRUE;
2088 cupsdLogMessage(CUPSD_LOG_INFO,
2089 "LDAP update enabled");
2090 }
2091
2092 /*
2093 * Count LDAP entries and return if no entry exist...
2094 */
2095
f899b121 2096 limit = ldap_count_entries(BrowseLDAPHandle, res);
2097 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
2098 if (limit < 1)
749b1e90
MS
2099 {
2100 ldap_freeres(res);
f899b121 2101 return;
749b1e90 2102 }
ef416fc2 2103
e1d6a774 2104 /*
f899b121 2105 * Loop through the available printers...
e1d6a774 2106 */
ef416fc2 2107
f899b121 2108 for (e = ldap_first_entry(BrowseLDAPHandle, res);
2109 e;
2110 e = ldap_next_entry(BrowseLDAPHandle, e))
e00b005a 2111 {
f899b121 2112 /*
2113 * Get the required values from this entry...
2114 */
ef416fc2 2115
749b1e90
MS
2116 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2117 "printerDescription", info, sizeof(info)) == -1)
f899b121 2118 continue;
ef416fc2 2119
749b1e90
MS
2120 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2121 "printerLocation", location, sizeof(location)) == -1)
f899b121 2122 continue;
ef416fc2 2123
749b1e90
MS
2124 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2125 "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
f899b121 2126 continue;
ef416fc2 2127
749b1e90
MS
2128 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2129 "printerType", type_num, sizeof(type_num)) == -1)
f899b121 2130 continue;
ef416fc2 2131
749b1e90 2132 type = atoi(type_num);
ef416fc2 2133
749b1e90
MS
2134 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2135 "printerURI", uri, sizeof(uri)) == -1)
f899b121 2136 continue;
ef416fc2 2137
f899b121 2138 /*
2139 * Process the entry as browse data...
2140 */
2141
2142 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2143 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
2144 location, info, make_model, 0, NULL);
ef416fc2 2145
e00b005a 2146 }
749b1e90
MS
2147
2148 ldap_freeres(res);
f899b121 2149}
749b1e90 2150#endif /* HAVE_LDAP */
ef416fc2 2151
e1d6a774 2152
f899b121 2153#ifdef HAVE_LIBSLP
2154/*
2155 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
2156 */
ef416fc2 2157
f899b121 2158void
2159cupsdUpdateSLPBrowse(void)
2160{
2161 slpsrvurl_t *s, /* Temporary list of service URLs */
2162 *next; /* Next service in list */
2163 cupsd_printer_t p; /* Printer information */
2164 const char *uri; /* Pointer to printer URI */
2165 char host[HTTP_MAX_URI], /* Host portion of URI */
2166 resource[HTTP_MAX_URI]; /* Resource portion of URI */
e00b005a 2167
b423cd4c 2168
f899b121 2169 /*
2170 * Reset the refresh time...
2171 */
b423cd4c 2172
f899b121 2173 BrowseSLPRefresh = time(NULL) + BrowseInterval;
b423cd4c 2174
f899b121 2175 /*
2176 * Poll for remote printers using SLP...
2177 */
b423cd4c 2178
f899b121 2179 s = NULL;
b423cd4c 2180
f899b121 2181 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
2182 slp_url_callback, &s);
b423cd4c 2183
f899b121 2184 /*
2185 * Loop through the list of available printers...
2186 */
e1d6a774 2187
f899b121 2188 for (; s; s = next)
2189 {
2190 /*
2191 * Save the "next" pointer...
2192 */
b423cd4c 2193
f899b121 2194 next = s->next;
e1d6a774 2195
f899b121 2196 /*
2197 * Load a cupsd_printer_t structure with the SLP service attributes...
2198 */
e1d6a774 2199
f899b121 2200 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
ef416fc2 2201
f899b121 2202 /*
2203 * Process this printer entry...
2204 */
ef416fc2 2205
f899b121 2206 uri = s->url + SLP_CUPS_SRVLEN + 1;
ef416fc2 2207
f899b121 2208 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
2209 {
2210 /*
2211 * Pull the URI apart to see if this is a local or remote printer...
2212 */
ef416fc2 2213
f899b121 2214 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2215 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
2216 p.location, p.info, p.make_model, 0, NULL);
2217 }
ef416fc2 2218
f899b121 2219 /*
2220 * Free this listing...
2221 */
ef416fc2 2222
f899b121 2223 cupsdClearString(&p.info);
2224 cupsdClearString(&p.location);
2225 cupsdClearString(&p.make_model);
ef416fc2 2226
f899b121 2227 free(s);
2228 }
e1d6a774 2229}
f899b121 2230#endif /* HAVE_LIBSLP */
ef416fc2 2231
ef416fc2 2232
f7deaa1a 2233/*
f899b121 2234 * 'dequote()' - Remote quotes from a string.
f7deaa1a 2235 */
2236
f899b121 2237static char * /* O - Dequoted string */
2238dequote(char *d, /* I - Destination string */
2239 const char *s, /* I - Source string */
2240 int dlen) /* I - Destination length */
f7deaa1a 2241{
f899b121 2242 char *dptr; /* Pointer into destination */
f7deaa1a 2243
2244
f899b121 2245 if (s)
f7deaa1a 2246 {
f899b121 2247 for (dptr = d, dlen --; *s && dlen > 0; s ++)
2248 if (*s != '\"')
2249 {
2250 *dptr++ = *s;
2251 dlen --;
2252 }
f7deaa1a 2253
f899b121 2254 *dptr = '\0';
f7deaa1a 2255 }
f899b121 2256 else
2257 *d = '\0';
2258
2259 return (d);
f7deaa1a 2260}
f7deaa1a 2261
2262
7a14d768 2263#ifdef HAVE_DNSSD
e07d4801
MS
2264# ifdef HAVE_COREFOUNDATION
2265/*
2266 * 'dnssdAddAlias()' - Add a DNS-SD alias name.
2267 */
2268
2269static void
2270dnssdAddAlias(const void *key, /* I - Key */
2271 const void *value, /* I - Value (domain) */
2272 void *context) /* I - Unused */
2273{
2274 char valueStr[1024], /* Domain string */
2275 hostname[1024]; /* Complete hostname */
2276
2277
2278 (void)context;
2279
2280 if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
2281 CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
2282 kCFStringEncodingUTF8))
2283 {
2284 snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDName, valueStr);
2285 if (!DNSSDAlias)
2286 DNSSDAlias = cupsArrayNew(NULL, NULL);
2287
2288 cupsdAddAlias(DNSSDAlias, hostname);
2289 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
2290 hostname);
2291 }
2292 else
2293 cupsdLogMessage(CUPSD_LOG_ERROR,
2294 "Bad Back to My Mac domain in dynamic store!");
2295}
2296# endif /* HAVE_COREFOUNDATION */
2297
2298
a603edef 2299/*
7a14d768 2300 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
a603edef
MS
2301 */
2302
7a14d768
MS
2303static char * /* O - TXT record */
2304dnssdBuildTxtRecord(
2305 int *txt_len, /* O - TXT record length */
2306 cupsd_printer_t *p, /* I - Printer information */
2307 int for_lpd) /* I - 1 = LPD, 0 = IPP */
a603edef 2308{
178cb736 2309 int i; /* Looping var */
7a14d768
MS
2310 char type_str[32], /* Type to string buffer */
2311 state_str[32], /* State to string buffer */
2312 rp_str[1024], /* Queue name string buffer */
2313 air_str[1024], /* auth-info-required string buffer */
2314 *keyvalue[32][2]; /* Table of key/value pairs */
a603edef
MS
2315
2316
2317 /*
7a14d768 2318 * Load up the key value pairs...
a603edef
MS
2319 */
2320
7a14d768 2321 i = 0;
a603edef 2322
7a14d768
MS
2323 keyvalue[i ][0] = "txtvers";
2324 keyvalue[i++][1] = "1";
a603edef 2325
7a14d768
MS
2326 keyvalue[i ][0] = "qtotal";
2327 keyvalue[i++][1] = "1";
a603edef 2328
7a14d768
MS
2329 keyvalue[i ][0] = "rp";
2330 keyvalue[i++][1] = rp_str;
2331 if (for_lpd)
2332 strlcpy(rp_str, p->name, sizeof(rp_str));
2333 else
2334 snprintf(rp_str, sizeof(rp_str), "%s/%s",
2335 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
a603edef 2336
7a14d768
MS
2337 keyvalue[i ][0] = "ty";
2338 keyvalue[i++][1] = p->make_model;
a603edef 2339
7a14d768
MS
2340 if (p->location && *p->location != '\0')
2341 {
2342 keyvalue[i ][0] = "note";
2343 keyvalue[i++][1] = p->location;
a603edef
MS
2344 }
2345
7a14d768
MS
2346 keyvalue[i ][0] = "priority";
2347 keyvalue[i++][1] = for_lpd ? "100" : "0";
e1d6a774 2348
7a14d768
MS
2349 keyvalue[i ][0] = "product";
2350 keyvalue[i++][1] = p->product ? p->product : "Unknown";
e1d6a774 2351
7a14d768
MS
2352 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2353 snprintf(state_str, sizeof(state_str), "%d", p->state);
ef416fc2 2354
7a14d768
MS
2355 keyvalue[i ][0] = "printer-state";
2356 keyvalue[i++][1] = state_str;
ef416fc2 2357
7a14d768
MS
2358 keyvalue[i ][0] = "printer-type";
2359 keyvalue[i++][1] = type_str;
ef416fc2 2360
7a14d768
MS
2361 keyvalue[i ][0] = "Transparent";
2362 keyvalue[i++][1] = "T";
ef416fc2 2363
7a14d768
MS
2364 keyvalue[i ][0] = "Binary";
2365 keyvalue[i++][1] = "T";
ef416fc2 2366
7a14d768
MS
2367 if ((p->type & CUPS_PRINTER_FAX))
2368 {
2369 keyvalue[i ][0] = "Fax";
2370 keyvalue[i++][1] = "T";
2371 }
ed486911 2372
7a14d768
MS
2373 if ((p->type & CUPS_PRINTER_COLOR))
2374 {
2375 keyvalue[i ][0] = "Color";
2376 keyvalue[i++][1] = "T";
2377 }
ef416fc2 2378
7a14d768
MS
2379 if ((p->type & CUPS_PRINTER_DUPLEX))
2380 {
2381 keyvalue[i ][0] = "Duplex";
2382 keyvalue[i++][1] = "T";
2383 }
ed486911 2384
7a14d768
MS
2385 if ((p->type & CUPS_PRINTER_STAPLE))
2386 {
2387 keyvalue[i ][0] = "Staple";
2388 keyvalue[i++][1] = "T";
2389 }
e1d6a774 2390
7a14d768
MS
2391 if ((p->type & CUPS_PRINTER_COPIES))
2392 {
2393 keyvalue[i ][0] = "Copies";
2394 keyvalue[i++][1] = "T";
2395 }
ef416fc2 2396
7a14d768
MS
2397 if ((p->type & CUPS_PRINTER_COLLATE))
2398 {
2399 keyvalue[i ][0] = "Collate";
2400 keyvalue[i++][1] = "T";
2401 }
ef416fc2 2402
7a14d768 2403 if ((p->type & CUPS_PRINTER_PUNCH))
b423cd4c 2404 {
7a14d768
MS
2405 keyvalue[i ][0] = "Punch";
2406 keyvalue[i++][1] = "T";
b423cd4c 2407 }
2408
7a14d768 2409 if ((p->type & CUPS_PRINTER_BIND))
e1d6a774 2410 {
7a14d768
MS
2411 keyvalue[i ][0] = "Bind";
2412 keyvalue[i++][1] = "T";
e1d6a774 2413 }
b423cd4c 2414
7a14d768
MS
2415 if ((p->type & CUPS_PRINTER_SORT))
2416 {
2417 keyvalue[i ][0] = "Sort";
2418 keyvalue[i++][1] = "T";
2419 }
b423cd4c 2420
7a14d768
MS
2421 keyvalue[i ][0] = "pdl";
2422 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
b423cd4c 2423
178cb736 2424 if (get_auth_info_required(p, air_str, sizeof(air_str)))
b423cd4c 2425 {
7a14d768 2426 keyvalue[i ][0] = "air";
49d87452 2427 keyvalue[i++][1] = air_str;
ef416fc2 2428 }
ef416fc2 2429
e00b005a 2430 /*
7a14d768 2431 * Then pack them into a proper txt record...
e00b005a 2432 */
2433
7a14d768
MS
2434 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2435}
e00b005a 2436
e00b005a 2437
7a14d768
MS
2438/*
2439 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
2440 */
2441
2442static int /* O - Result of comparison */
2443dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
2444 cupsd_printer_t *b)/* I - Second printer */
2445{
2446 return (strcasecmp(a->reg_name, b->reg_name));
2447}
2448
2449
2450/*
2451 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2452 * printer.
2453 */
2454
2455static void
2456dnssdDeregisterPrinter(
2457 cupsd_printer_t *p) /* I - Printer */
2458{
2459 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2460
2461 /*
2462 * Closing the socket deregisters the service
2463 */
2464
2465 if (p->ipp_ref)
2466 {
2467 DNSServiceRefDeallocate(p->ipp_ref);
2468 p->ipp_ref = NULL;
e1d6a774 2469 }
e00b005a 2470
7a14d768 2471 if (p->ipp_txt)
e1d6a774 2472 {
e00b005a 2473 /*
7a14d768 2474 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
e00b005a 2475 */
2476
7a14d768
MS
2477 free(p->ipp_txt);
2478 p->ipp_txt = NULL;
2479 }
745129be
MS
2480
2481 if (p->printer_ref)
2482 {
2483 DNSServiceRefDeallocate(p->printer_ref);
2484 p->printer_ref = NULL;
2485 }
2486
2487 if (p->printer_txt)
2488 {
2489 /*
2490 * p->printer_txt is malloc'd, not _cupsStrAlloc'd...
2491 */
2492
2493 free(p->printer_txt);
2494 p->printer_txt = NULL;
2495 }
2496
2497 /*
2498 * Remove the printer from the array of DNS-SD printers, then clear the
2499 * registered name...
2500 */
2501
2502 cupsArrayRemove(DNSSDPrinters, p);
2503 cupsdClearString(&p->reg_name);
7a14d768 2504}
e00b005a 2505
d09495fa 2506
7a14d768
MS
2507/*
2508 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2509 * TXT record format.
2510 */
e00b005a 2511
7a14d768
MS
2512static char * /* O - TXT record */
2513dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2514 char *keyvalue[][2], /* I - Table of key value pairs */
2515 int count) /* I - Items in table */
2516{
2517 int i; /* Looping var */
2518 int length; /* Length of TXT record */
2519 int length2; /* Length of value */
2520 char *txtRecord; /* TXT record buffer */
2521 char *cursor; /* Looping pointer */
e00b005a 2522
e00b005a 2523
7a14d768
MS
2524 /*
2525 * Calculate the buffer size
2526 */
e00b005a 2527
7a14d768
MS
2528 for (length = i = 0; i < count; i++)
2529 length += 1 + strlen(keyvalue[i][0]) +
2530 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
e00b005a 2531
7a14d768
MS
2532 /*
2533 * Allocate and fill it
2534 */
e00b005a 2535
7a14d768
MS
2536 txtRecord = malloc(length);
2537 if (txtRecord)
2538 {
2539 *txt_len = length;
2540
2541 for (cursor = txtRecord, i = 0; i < count; i++)
e00b005a 2542 {
2543 /*
7a14d768 2544 * Drop in the p-string style length byte followed by the data
e00b005a 2545 */
2546
7a14d768
MS
2547 length = strlen(keyvalue[i][0]);
2548 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
e00b005a 2549
7a14d768 2550 *cursor++ = (unsigned char)(length + length2);
e00b005a 2551
7a14d768
MS
2552 memcpy(cursor, keyvalue[i][0], length);
2553 cursor += length;
e00b005a 2554
7a14d768
MS
2555 if (length2)
2556 {
2557 length2 --;
2558 *cursor++ = '=';
2559 memcpy(cursor, keyvalue[i][1], length2);
2560 cursor += length2;
2561 }
2562 }
2563 }
e00b005a 2564
7a14d768
MS
2565 return (txtRecord);
2566}
e00b005a 2567
e00b005a 2568
7a14d768
MS
2569/*
2570 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2571 */
e00b005a 2572
7a14d768
MS
2573static void
2574dnssdRegisterCallback(
2575 DNSServiceRef sdRef, /* I - DNS Service reference */
2576 DNSServiceFlags flags, /* I - Reserved for future use */
2577 DNSServiceErrorType errorCode, /* I - Error code */
2578 const char *name, /* I - Service name */
2579 const char *regtype, /* I - Service type */
2580 const char *domain, /* I - Domain. ".local" for now */
2581 void *context) /* I - User-defined context */
2582{
2583 cupsd_printer_t *p = (cupsd_printer_t *)context;
2584 /* Current printer */
3dfe78b3 2585
7a14d768 2586
745129be
MS
2587 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
2588 name, regtype, p ? p->name : "Web Interface",
2589 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
7a14d768
MS
2590
2591 if (errorCode)
2592 {
2593 cupsdLogMessage(CUPSD_LOG_ERROR,
2594 "DNSServiceRegister failed with error %d", (int)errorCode);
2595 return;
ef416fc2 2596 }
745129be 2597 else if (p && (!p->reg_name || strcasecmp(name, p->reg_name)))
ef416fc2 2598 {
7a14d768
MS
2599 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2600 name, p->name);
e00b005a 2601
7a14d768
MS
2602 cupsArrayRemove(DNSSDPrinters, p);
2603 cupsdSetString(&p->reg_name, name);
2604 cupsArrayAdd(DNSSDPrinters, p);
e00b005a 2605
7a14d768
MS
2606 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2607 }
2608}
d09495fa 2609
ef416fc2 2610
7a14d768
MS
2611/*
2612 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2613 * or update the broadcast contents.
2614 */
ef416fc2 2615
7a14d768
MS
2616static void
2617dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2618{
2619 DNSServiceErrorType se; /* dnssd errors */
2620 char *ipp_txt, /* IPP TXT record buffer */
2621 *printer_txt, /* LPD TXT record buffer */
2622 name[1024], /* Service name */
2623 *nameptr; /* Pointer into name */
2624 int ipp_len, /* IPP TXT record length */
2625 printer_len; /* LPD TXT record length */
7a14d768 2626 const char *regtype; /* Registration type */
ef416fc2 2627
ef416fc2 2628
7a14d768
MS
2629 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2630 !p->ipp_ref ? "new" : "update");
e00b005a 2631
7a14d768
MS
2632 /*
2633 * If per-printer sharing was just disabled make sure we're not
2634 * registered before returning.
2635 */
e00b005a 2636
7a14d768
MS
2637 if (!p->shared)
2638 {
2639 dnssdDeregisterPrinter(p);
2640 return;
2641 }
ef416fc2 2642
7a14d768
MS
2643 /*
2644 * The registered name takes the form of "<printer-info> @ <computer name>"...
2645 */
e00b005a 2646
7a14d768
MS
2647 if (p->info && strlen(p->info) > 0)
2648 {
2649 if (DNSSDName)
2650 snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
2651 else
2652 strlcpy(name, p->info, sizeof(name));
2653 }
2654 else if (DNSSDName)
2655 snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
2656 else
2657 strlcpy(name, p->name, sizeof(name));
ef416fc2 2658
7a14d768
MS
2659 /*
2660 * If an existing printer was renamed, unregister it and start over...
2661 */
ef416fc2 2662
7a14d768
MS
2663 if (p->reg_name && strcmp(p->reg_name, name))
2664 dnssdDeregisterPrinter(p);
ef416fc2 2665
7a14d768
MS
2666 if (!p->reg_name)
2667 {
2668 cupsdSetString(&p->reg_name, name);
2669 cupsArrayAdd(DNSSDPrinters, p);
2670 }
ef416fc2 2671
ef416fc2 2672 /*
7a14d768 2673 * Register IPP and (optionally) LPD...
ef416fc2 2674 */
2675
49d87452 2676 ipp_len = 0; /* anti-compiler-warning-code */
7a14d768 2677 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
ef416fc2 2678
745129be
MS
2679 if (p->ipp_ref &&
2680 (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len)))
2681 {
2682 /*
2683 * Update the existing registration...
2684 */
2685
2686 /* A TTL of 0 means use record's original value (Radar 3176248) */
2687 if ((se = DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt,
2688 0)) == kDNSServiceErr_NoError)
2689 {
2690 if (p->ipp_txt)
2691 free(p->ipp_txt);
2692
2693 p->ipp_txt = ipp_txt;
2694 p->ipp_len = ipp_len;
2695 ipp_txt = NULL;
2696 }
2697 else
2698 {
2699 /*
2700 * Failed to update record, lets close this reference and move on...
2701 */
2702
2703 cupsdLogMessage(CUPSD_LOG_ERROR,
2704 "Unable to update IPP DNS-SD record for %s - %d", p->name,
2705 se);
2706
2707 DNSServiceRefDeallocate(p->ipp_ref);
2708 p->ipp_ref = NULL;
2709 }
2710 }
2711
7a14d768 2712 if (!p->ipp_ref)
b423cd4c 2713 {
2714 /*
7a14d768 2715 * Initial registration. Use the _fax subtype for fax queues...
b423cd4c 2716 */
2717
7a14d768
MS
2718 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
2719 "_ipp._tcp,_cups";
b423cd4c 2720
7a14d768 2721 cupsdLogMessage(CUPSD_LOG_DEBUG,
38e73f87
MS
2722 "Registering DNS-SD printer %s with name \"%s\" and "
2723 "type \"%s\"", p->name, name, regtype);
b423cd4c 2724
7a14d768
MS
2725 /*
2726 * Register the queue, dropping characters as needed until we succeed...
2727 */
ef416fc2 2728
7a14d768
MS
2729 nameptr = name + strlen(name);
2730
2731 do
ef416fc2 2732 {
7a14d768
MS
2733 p->ipp_ref = DNSSDRef;
2734 if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
38e73f87 2735 0, name, regtype, NULL, NULL,
7a14d768
MS
2736 htons(DNSSDPort), ipp_len, ipp_txt,
2737 dnssdRegisterCallback,
2738 p)) == kDNSServiceErr_BadParam)
2739 {
2740 /*
2741 * Name is too long, drop trailing characters, taking into account
2742 * UTF-8 encoding...
2743 */
2744
2745 nameptr --;
2746
2747 while (nameptr > name && (*nameptr & 0xc0) == 0x80)
2748 nameptr --;
2749
2750 if (nameptr > name)
2751 *nameptr = '\0';
2752 }
2753 }
2754 while (se == kDNSServiceErr_BadParam && nameptr > name);
2755
2756 if (se == kDNSServiceErr_NoError)
2757 {
2758 p->ipp_txt = ipp_txt;
2759 p->ipp_len = ipp_len;
2760 ipp_txt = NULL;
ef416fc2 2761 }
7a14d768
MS
2762 else
2763 cupsdLogMessage(CUPSD_LOG_WARN,
2764 "DNS-SD IPP registration of \"%s\" failed: %d",
2765 p->name, se);
ef416fc2 2766 }
ef416fc2 2767
7a14d768
MS
2768 if (ipp_txt)
2769 free(ipp_txt);
2770
2771 if (BrowseLocalProtocols & BROWSE_LPD)
e00b005a 2772 {
49d87452 2773 printer_len = 0; /* anti-compiler-warning-code */
7a14d768 2774 printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
3dfe78b3 2775
745129be
MS
2776 if (p->printer_ref &&
2777 (printer_len != p->printer_len ||
2778 memcmp(printer_txt, p->printer_txt, printer_len)))
2779 {
2780 /*
2781 * Update the existing registration...
2782 */
2783
2784 /* A TTL of 0 means use record's original value (Radar 3176248) */
2785 if ((se = DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
2786 printer_txt,
2787 0)) == kDNSServiceErr_NoError)
2788 {
2789 if (p->printer_txt)
2790 free(p->printer_txt);
2791
2792 p->printer_txt = printer_txt;
2793 p->printer_len = printer_len;
2794 printer_txt = NULL;
2795 }
2796 else
2797 {
2798 /*
2799 * Failed to update record, lets close this reference and move on...
2800 */
2801
2802 cupsdLogMessage(CUPSD_LOG_ERROR,
2803 "Unable to update LPD DNS-SD record for %s - %d",
2804 p->name, se);
2805
2806 DNSServiceRefDeallocate(p->printer_ref);
2807 p->printer_ref = NULL;
2808 }
2809 }
2810
7a14d768
MS
2811 if (!p->printer_ref)
2812 {
2813 /*
2814 * Initial registration...
2815 */
ef416fc2 2816
7a14d768 2817 cupsdLogMessage(CUPSD_LOG_DEBUG,
38e73f87
MS
2818 "Registering DNS-SD printer %s with name \"%s\" and "
2819 "type \"_printer._tcp\"", p->name, name);
7a14d768
MS
2820
2821 p->printer_ref = DNSSDRef;
2822 if ((se = DNSServiceRegister(&p->printer_ref,
2823 kDNSServiceFlagsShareConnection,
38e73f87 2824 0, name, "_printer._tcp", NULL, NULL,
7a14d768
MS
2825 htons(515), printer_len, printer_txt,
2826 dnssdRegisterCallback,
2827 p)) == kDNSServiceErr_NoError)
2828 {
2829 p->printer_txt = printer_txt;
2830 p->printer_len = printer_len;
2831 printer_txt = NULL;
2832 }
2833 else
2834 cupsdLogMessage(CUPSD_LOG_WARN,
2835 "DNS-SD LPD registration of \"%s\" failed: %d",
2836 p->name, se);
2837 }
7a14d768
MS
2838
2839 if (printer_txt)
2840 free(printer_txt);
b423cd4c 2841 }
7a14d768 2842}
75bd9771
MS
2843
2844
f0ab5bff
MS
2845/*
2846 * 'dnssdStop()' - Stop all DNS-SD registrations.
2847 */
2848
2849static void
2850dnssdStop(void)
2851{
2852 cupsd_printer_t *p; /* Current printer */
2853
2854
2855 /*
2856 * De-register the individual printers
2857 */
2858
2859 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
2860 p;
2861 p = (cupsd_printer_t *)cupsArrayNext(Printers))
2862 dnssdDeregisterPrinter(p);
2863
2864 /*
2865 * Shutdown the rest of the service refs...
2866 */
2867
2868 if (WebIFRef)
2869 {
2870 DNSServiceRefDeallocate(WebIFRef);
2871 WebIFRef = NULL;
2872 }
2873
2874 if (RemoteRef)
2875 {
2876 DNSServiceRefDeallocate(RemoteRef);
2877 RemoteRef = NULL;
2878 }
2879
2880 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
2881
2882 DNSServiceRefDeallocate(DNSSDRef);
2883 DNSSDRef = NULL;
2884
2885 cupsArrayDelete(DNSSDPrinters);
2886 DNSSDPrinters = NULL;
2887
2888 DNSSDPort = 0;
2889}
2890
2891
75bd9771
MS
2892/*
2893 * 'dnssdUpdate()' - Handle DNS-SD queries.
2894 */
2895
2896static void
2897dnssdUpdate(void)
2898{
2899 DNSServiceErrorType sdErr; /* Service discovery error */
2900
2901
2902 if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
f0ab5bff 2903 {
75bd9771
MS
2904 cupsdLogMessage(CUPSD_LOG_ERROR,
2905 "DNS Service Discovery registration error %d!",
2906 sdErr);
f0ab5bff
MS
2907 dnssdStop();
2908 }
75bd9771 2909}
7a14d768 2910#endif /* HAVE_DNSSD */
b423cd4c 2911
b423cd4c 2912
178cb736
MS
2913/*
2914 * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
2915 */
2916
2917static char * /* O - String or NULL if none */
2918get_auth_info_required(
2919 cupsd_printer_t *p, /* I - Printer */
2920 char *buffer, /* I - Value buffer */
2921 size_t bufsize) /* I - Size of value buffer */
2922{
2923 cupsd_location_t *auth; /* Pointer to authentication element */
2924 char resource[1024]; /* Printer/class resource path */
2925
2926
2927 /*
2928 * If auth-info-required is set for this printer, return that...
2929 */
2930
2931 if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
2932 {
2933 int i; /* Looping var */
2934 char *bufptr; /* Pointer into buffer */
2935
2936 for (i = 0, bufptr = buffer; i < p->num_auth_info_required; i ++)
2937 {
2938 if (bufptr >= (buffer + bufsize - 2))
2939 break;
2940
2941 if (i)
2942 *bufptr++ = ',';
2943
2944 strlcpy(bufptr, p->auth_info_required[i], bufsize - (bufptr - buffer));
2945 bufptr += strlen(bufptr);
2946 }
2947
2948 return (buffer);
2949 }
2950
2951 /*
2952 * Figure out the authentication data requirements to advertise...
2953 */
2954
2955 if (p->type & CUPS_PRINTER_CLASS)
2956 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2957 else
2958 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
2959
2960 if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
2961 auth->type == CUPSD_AUTH_NONE)
2962 auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
2963
2964 if (auth)
2965 {
2966 int auth_type; /* Authentication type */
2967
2968 if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
2969 auth_type = DefaultAuthType;
2970
2971 switch (auth_type)
2972 {
2973 case CUPSD_AUTH_NONE :
2974 return (NULL);
2975
2976 case CUPSD_AUTH_NEGOTIATE :
2977 strlcpy(buffer, "negotiate", bufsize);
2978 break;
2979
2980 default :
2981 strlcpy(buffer, "username,password", bufsize);
2982 break;
2983 }
2984
2985 return (buffer);
2986 }
2987
2988 return (NULL);
2989}
2990
2991
7a14d768
MS
2992#ifdef __APPLE__
2993/*
2994 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
2995 */
2996
2997static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
2998get_hostconfig(const char *name) /* I - Name of service */
2999{
3000 cups_file_t *fp; /* Hostconfig file */
3001 char line[1024], /* Line from file */
3002 *ptr; /* Pointer to value */
3003 int state = 1; /* State of service */
ef416fc2 3004
ef416fc2 3005
3006 /*
7a14d768
MS
3007 * Try opening the /etc/hostconfig file; if we can't open it, assume that
3008 * the service is enabled/auto.
ef416fc2 3009 */
3010
7a14d768 3011 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
e00b005a 3012 {
3013 /*
7a14d768 3014 * Read lines from the file until we find the service...
e00b005a 3015 */
3016
7a14d768
MS
3017 while (cupsFileGets(fp, line, sizeof(line)))
3018 {
3019 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
3020 continue;
3021
3022 *ptr++ = '\0';
3023
3024 if (!strcasecmp(line, name))
ef416fc2 3025 {
7a14d768
MS
3026 /*
3027 * Found the service, see if it is set to "-NO-"...
3028 */
3029
3030 if (!strncasecmp(ptr, "-NO-", 4))
3031 state = 0;
3032 break;
ef416fc2 3033 }
7a14d768 3034 }
ef416fc2 3035
7a14d768
MS
3036 cupsFileClose(fp);
3037 }
ef416fc2 3038
7a14d768 3039 return (state);
ef416fc2 3040}
7a14d768 3041#endif /* __APPLE__ */
ef416fc2 3042
3043
f7deaa1a 3044/*
7a14d768 3045 * 'is_local_queue()' - Determine whether the URI points at a local queue.
f7deaa1a 3046 */
3047
7a14d768
MS
3048static int /* O - 1 = local, 0 = remote, -1 = bad URI */
3049is_local_queue(const char *uri, /* I - Printer URI */
3050 char *host, /* O - Host string */
3051 int hostlen, /* I - Length of host buffer */
3052 char *resource, /* O - Resource string */
3053 int resourcelen) /* I - Length of resource buffer */
f7deaa1a 3054{
7a14d768
MS
3055 char scheme[32], /* Scheme portion of URI */
3056 username[HTTP_MAX_URI]; /* Username portion of URI */
3057 int port; /* Port portion of URI */
3058 cupsd_netif_t *iface; /* Network interface */
f7deaa1a 3059
3060
3061 /*
7a14d768 3062 * Pull the URI apart to see if this is a local or remote printer...
f7deaa1a 3063 */
3064
7a14d768
MS
3065 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
3066 username, sizeof(username), host, hostlen, &port,
3067 resource, resourcelen) < HTTP_URI_OK)
3068 return (-1);
f7deaa1a 3069
7a14d768 3070 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
f7deaa1a 3071
7a14d768
MS
3072 /*
3073 * Check for local server addresses...
3074 */
f7deaa1a 3075
7a14d768
MS
3076 if (!strcasecmp(host, ServerName) && port == LocalPort)
3077 return (1);
f7deaa1a 3078
7a14d768 3079 cupsdNetIFUpdate();
f7deaa1a 3080
7a14d768
MS
3081 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3082 iface;
3083 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3084 if (!strcasecmp(host, iface->hostname) && port == iface->port)
3085 return (1);
f7deaa1a 3086
7a14d768
MS
3087 /*
3088 * If we get here, the printer is remote...
3089 */
f7deaa1a 3090
7a14d768
MS
3091 return (0);
3092}
f7deaa1a 3093
f7deaa1a 3094
7a14d768
MS
3095/*
3096 * 'process_browse_data()' - Process new browse data.
3097 */
f7deaa1a 3098
7a14d768
MS
3099static void
3100process_browse_data(
3101 const char *uri, /* I - URI of printer/class */
3102 const char *host, /* I - Hostname */
3103 const char *resource, /* I - Resource path */
3104 cups_ptype_t type, /* I - Printer type */
3105 ipp_pstate_t state, /* I - Printer state */
3106 const char *location, /* I - Printer location */
3107 const char *info, /* I - Printer information */
3108 const char *make_model, /* I - Printer make and model */
3109 int num_attrs, /* I - Number of attributes */
3110 cups_option_t *attrs) /* I - Attributes */
3111{
3112 int i; /* Looping var */
3113 int update; /* Update printer attributes? */
3114 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
3115 name[IPP_MAX_NAME], /* Name of printer */
3116 newname[IPP_MAX_NAME], /* New name of printer */
3117 *hptr, /* Pointer into hostname */
3118 *sptr; /* Pointer into ServerName */
1f0275e3 3119 const char *shortname; /* Short queue name (queue) */
7a14d768
MS
3120 char local_make_model[IPP_MAX_NAME];
3121 /* Local make and model */
3122 cupsd_printer_t *p; /* Printer information */
3123 const char *ipp_options, /* ipp-options value */
3124 *lease_duration; /* lease-duration value */
1f0275e3
MS
3125 int is_class; /* Is this queue a class? */
3126
f7deaa1a 3127
1f0275e3
MS
3128 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3129 "process_browse_data(uri=\"%s\", host=\"%s\", "
3130 "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
3131 "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
3132 uri, host, resource, type, state,
3133 location ? location : "(nil)", info ? info : "(nil)",
3134 make_model ? make_model : "(nil)", num_attrs, attrs);
f7deaa1a 3135
7a14d768
MS
3136 /*
3137 * Determine if the URI contains any illegal characters in it...
3138 */
f7deaa1a 3139
7a14d768
MS
3140 if (strncmp(uri, "ipp://", 6) || !host[0] ||
3141 (strncmp(resource, "/printers/", 10) &&
3142 strncmp(resource, "/classes/", 9)))
f7deaa1a 3143 {
1f0275e3 3144 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
7a14d768 3145 return;
f7deaa1a 3146 }
3147
7a14d768
MS
3148 if (strchr(resource, '?') ||
3149 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
3150 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
f7deaa1a 3151 {
1f0275e3 3152 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
7a14d768
MS
3153 resource);
3154 return;
f7deaa1a 3155 }
3156
7a14d768
MS
3157 /*
3158 * OK, this isn't a local printer; add any remote options...
3159 */
f7deaa1a 3160
7a14d768
MS
3161 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
3162
3163 if (BrowseRemoteOptions)
f7deaa1a 3164 {
7a14d768
MS
3165 if (BrowseRemoteOptions[0] == '?')
3166 {
3167 /*
3168 * Override server-supplied options...
3169 */
f7deaa1a 3170
7a14d768
MS
3171 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
3172 }
3173 else if (ipp_options)
3174 {
3175 /*
3176 * Combine the server and local options...
3177 */
f7deaa1a 3178
7a14d768
MS
3179 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
3180 BrowseRemoteOptions);
3181 }
3182 else
3183 {
3184 /*
3185 * Just use the local options...
3186 */
f7deaa1a 3187
7a14d768
MS
3188 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
3189 }
f7deaa1a 3190
7a14d768 3191 uri = finaluri;
f7deaa1a 3192 }
7a14d768 3193 else if (ipp_options)
7594b224 3194 {
7a14d768
MS
3195 /*
3196 * Just use the server-supplied options...
3197 */
7594b224 3198
7a14d768
MS
3199 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
3200 uri = finaluri;
7594b224 3201 }
3202
f7deaa1a 3203 /*
7a14d768 3204 * See if we already have it listed in the Printers list, and add it if not...
f7deaa1a 3205 */
3206
1f0275e3
MS
3207 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
3208 type &= ~CUPS_PRINTER_IMPLICIT;
3209 update = 0;
3210 hptr = strchr(host, '.');
3211 sptr = strchr(ServerName, '.');
3212 is_class = type & CUPS_PRINTER_CLASS;
f7deaa1a 3213
7a14d768 3214 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
f7deaa1a 3215 {
7a14d768
MS
3216 /*
3217 * Strip the common domain name components...
3218 */
f7deaa1a 3219
7a14d768
MS
3220 while (hptr != NULL)
3221 {
3222 if (!strcasecmp(hptr, sptr))
3223 {
3224 *hptr = '\0';
3225 break;
3226 }
3227 else
3228 hptr = strchr(hptr + 1, '.');
3229 }
3230 }
f7deaa1a 3231
1f0275e3 3232 if (is_class)
f7deaa1a 3233 {
3234 /*
7a14d768 3235 * Remote destination is a class...
f7deaa1a 3236 */
3237
7a14d768
MS
3238 if (!strncmp(resource, "/classes/", 9))
3239 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
3240 else
3241 return;
f7deaa1a 3242
1f0275e3
MS
3243 shortname = resource + 9;
3244 }
3245 else
3246 {
3247 /*
3248 * Remote destination is a printer...
3249 */
f7deaa1a 3250
1f0275e3
MS
3251 if (!strncmp(resource, "/printers/", 10))
3252 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
3253 else
3254 return;
f7deaa1a 3255
1f0275e3
MS
3256 shortname = resource + 10;
3257 }
f7deaa1a 3258
1f0275e3
MS
3259 if (hptr && !*hptr)
3260 *hptr = '.'; /* Resource FQDN */
f7deaa1a 3261
1f0275e3
MS
3262 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
3263 {
3264 /*
3265 * Long name doesn't exist, try short name...
3266 */
3267
3268 cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
3269 name);
3270
3271 if ((p = cupsdFindDest(shortname)) == NULL)
7a14d768
MS
3272 {
3273 /*
1f0275e3 3274 * Short name doesn't exist, use it for this shared queue.
7a14d768 3275 */
f7deaa1a 3276
1f0275e3
MS
3277 cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
3278 shortname);
3279 strlcpy(name, shortname, sizeof(name));
7a14d768 3280 }
1f0275e3 3281 else
f7deaa1a 3282 {
3283 /*
1f0275e3 3284 * Short name exists...
f7deaa1a 3285 */
3286
1f0275e3
MS
3287 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3288 "process_browse_data: %s found, type=%x, hostname=%s...",
3289 shortname, p->type, p->hostname ? p->hostname : "(nil)");
f7deaa1a 3290
1f0275e3
MS
3291 if (p->type & CUPS_PRINTER_IMPLICIT)
3292 p = NULL; /* Don't replace implicit classes */
3293 else if (p->hostname && strcasecmp(p->hostname, host))
3294 {
3295 /*
3296 * Short name exists but is for a different host. If this is a remote
3297 * queue, rename it and use the long name...
3298 */
f7deaa1a 3299
1f0275e3
MS
3300 if (p->type & CUPS_PRINTER_REMOTE)
3301 {
3302 cupsdLogMessage(CUPSD_LOG_DEBUG,
3303 "Renamed remote %s \"%s\" to \"%s@%s\"...",
3304 is_class ? "class" : "printer", p->name, p->name,
3305 p->hostname);
3306 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3307 "%s \'%s\' deleted by directory services.",
3308 is_class ? "Class" : "Printer", p->name);
3309
3310 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
3311 cupsdRenamePrinter(p, newname);
3312
3313 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3314 "%s \'%s\' added by directory services.",
3315 is_class ? "Class" : "Printer", p->name);
3316 }
f7deaa1a 3317
1f0275e3
MS
3318 /*
3319 * Force creation with long name...
3320 */
f7deaa1a 3321
1f0275e3
MS
3322 p = NULL;
3323 }
7a14d768
MS
3324 }
3325 }
5d6412a9 3326 else if (p)
1f0275e3
MS
3327 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3328 "process_browse_data: %s found, type=%x, hostname=%s...",
3329 name, p->type, p->hostname ? p->hostname : "(nil)");
3330
3331 if (!p)
7a14d768
MS
3332 {
3333 /*
1f0275e3 3334 * Queue doesn't exist; add it...
7a14d768 3335 */
f7deaa1a 3336
1f0275e3
MS
3337 if (is_class)
3338 p = cupsdAddClass(name);
7a14d768 3339 else
1f0275e3 3340 p = cupsdAddPrinter(name);
f7deaa1a 3341
0af14961
MS
3342 if (!p)
3343 return;
3344
1f0275e3 3345 cupsdClearString(&(p->hostname));
f7deaa1a 3346
1f0275e3
MS
3347 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
3348 is_class ? "class" : "printer", name);
f7deaa1a 3349
1f0275e3
MS
3350 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3351 "%s \'%s\' added by directory services.",
3352 is_class ? "Class" : "Printer", name);
f7deaa1a 3353
1f0275e3
MS
3354 /*
3355 * Force the URI to point to the real server...
3356 */
f7deaa1a 3357
1f0275e3
MS
3358 p->type = type & ~CUPS_PRINTER_REJECTING;
3359 p->accepting = 1;
f7deaa1a 3360
1f0275e3
MS
3361 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3362 }
f7deaa1a 3363
1f0275e3
MS
3364 if (!p->hostname)
3365 {
3366 /*
3367 * Hostname not set, so this must be a cached remote printer
3368 * that was created for a pending print job...
3369 */
f7deaa1a 3370
1f0275e3
MS
3371 cupsdSetString(&p->hostname, host);
3372 cupsdSetString(&p->uri, uri);
3373 cupsdSetString(&p->device_uri, uri);
3374 update = 1;
f7deaa1a 3375
1f0275e3 3376 cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
7a14d768 3377 }
f7deaa1a 3378
3379 /*
7a14d768 3380 * Update the state...
f7deaa1a 3381 */
3382
7a14d768
MS
3383 p->state = state;
3384 p->browse_time = time(NULL);
f7deaa1a 3385
7a14d768
MS
3386 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
3387 attrs)) != NULL)
f7deaa1a 3388 {
3389 /*
7a14d768
MS
3390 * Grab the lease-duration for the browse data; anything less then 1
3391 * second or more than 1 week gets the default BrowseTimeout...
f7deaa1a 3392 */
3393
7a14d768
MS
3394 i = atoi(lease_duration);
3395 if (i < 1 || i > 604800)
3396 i = BrowseTimeout;
3397
3398 p->browse_expire = p->browse_time + i;
3399 }
3400 else
3401 p->browse_expire = p->browse_time + BrowseTimeout;
f7deaa1a 3402
7a14d768
MS
3403 if (type & CUPS_PRINTER_REJECTING)
3404 {
3405 type &= ~CUPS_PRINTER_REJECTING;
f7deaa1a 3406
7a14d768 3407 if (p->accepting)
f7deaa1a 3408 {
7a14d768
MS
3409 update = 1;
3410 p->accepting = 0;
f7deaa1a 3411 }
7a14d768
MS
3412 }
3413 else if (!p->accepting)
3414 {
3415 update = 1;
3416 p->accepting = 1;
3417 }
f7deaa1a 3418
7a14d768
MS
3419 if (p->type != type)
3420 {
3421 p->type = type;
3422 update = 1;
3423 }
080811b1 3424
7a14d768
MS
3425 if (location && (!p->location || strcmp(p->location, location)))
3426 {
3427 cupsdSetString(&p->location, location);
3428 update = 1;
3429 }
080811b1 3430
7a14d768
MS
3431 if (info && (!p->info || strcmp(p->info, info)))
3432 {
3433 cupsdSetString(&p->info, info);
3434 update = 1;
080811b1 3435
7a14d768
MS
3436 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3437 }
f7deaa1a 3438
7a14d768
MS
3439 if (!make_model || !make_model[0])
3440 {
1f0275e3 3441 if (is_class)
7a14d768
MS
3442 snprintf(local_make_model, sizeof(local_make_model),
3443 "Remote Class on %s", host);
3444 else
3445 snprintf(local_make_model, sizeof(local_make_model),
3446 "Remote Printer on %s", host);
3447 }
3448 else
3449 snprintf(local_make_model, sizeof(local_make_model),
3450 "%s on %s", make_model, host);
f7deaa1a 3451
7a14d768
MS
3452 if (!p->make_model || strcmp(p->make_model, local_make_model))
3453 {
3454 cupsdSetString(&p->make_model, local_make_model);
3455 update = 1;
3456 }
080811b1 3457
7a14d768
MS
3458 if (p->num_options)
3459 {
3460 if (!update && !(type & CUPS_PRINTER_DELETE))
3461 {
3462 /*
3463 * See if we need to update the attributes...
3464 */
f7deaa1a 3465
7a14d768
MS
3466 if (p->num_options != num_attrs)
3467 update = 1;
3468 else
3469 {
3470 for (i = 0; i < num_attrs; i ++)
3471 if (strcmp(attrs[i].name, p->options[i].name) ||
3472 (!attrs[i].value != !p->options[i].value) ||
3473 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
3474 {
3475 update = 1;
3476 break;
3477 }
3478 }
3479 }
f7deaa1a 3480
3481 /*
7a14d768 3482 * Free the old options...
f7deaa1a 3483 */
3484
7a14d768
MS
3485 cupsFreeOptions(p->num_options, p->options);
3486 }
f7deaa1a 3487
7a14d768
MS
3488 p->num_options = num_attrs;
3489 p->options = attrs;
f7deaa1a 3490
7a14d768
MS
3491 if (type & CUPS_PRINTER_DELETE)
3492 {
3493 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3494 "%s \'%s\' deleted by directory services.",
1f0275e3 3495 is_class ? "Class" : "Printer", p->name);
f7deaa1a 3496
7a14d768
MS
3497 cupsdExpireSubscriptions(p, NULL);
3498
3499 cupsdDeletePrinter(p, 1);
3500 cupsdUpdateImplicitClasses();
3501 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
f7deaa1a 3502 }
7a14d768 3503 else if (update)
f7deaa1a 3504 {
7a14d768
MS
3505 cupsdSetPrinterAttrs(p);
3506 cupsdUpdateImplicitClasses();
3507 }
f7deaa1a 3508
7a14d768
MS
3509 /*
3510 * See if we have a default printer... If not, make the first network
3511 * default printer the default.
3512 */
f7deaa1a 3513
7a14d768
MS
3514 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
3515 {
3516 /*
3517 * Find the first network default printer and use it...
3518 */
f7deaa1a 3519
7a14d768
MS
3520 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3521 p;
3522 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3523 if (p->type & CUPS_PRINTER_DEFAULT)
3524 {
3525 DefaultPrinter = p;
3526 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3527 break;
3528 }
f7deaa1a 3529 }
3530
7a14d768
MS
3531 /*
3532 * Do auto-classing if needed...
3533 */
f7deaa1a 3534
7a14d768 3535 process_implicit_classes();
f7deaa1a 3536}
f7deaa1a 3537
3538
ef416fc2 3539/*
e00b005a 3540 * 'process_implicit_classes()' - Create/update implicit classes as needed.
ef416fc2 3541 */
3542
e00b005a 3543static void
3dfe78b3 3544process_implicit_classes(void)
ef416fc2 3545{
e00b005a 3546 int i; /* Looping var */
3547 int update; /* Update printer attributes? */
3548 char name[IPP_MAX_NAME], /* Name of printer */
3549 *hptr; /* Pointer into hostname */
3550 cupsd_printer_t *p, /* Printer information */
3551 *pclass, /* Printer class */
3552 *first; /* First printer in class */
3553 int offset, /* Offset of name */
3554 len; /* Length of name */
ef416fc2 3555
3556
e00b005a 3557 if (!ImplicitClasses || !Printers)
3558 return;
ef416fc2 3559
e00b005a 3560 /*
3561 * Loop through all available printers and create classes as needed...
3562 */
3563
3564 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
3565 update = 0, pclass = NULL, first = NULL;
3566 p != NULL;
3567 p = (cupsd_printer_t *)cupsArrayNext(Printers))
ef416fc2 3568 {
3569 /*
e00b005a 3570 * Skip implicit classes...
ef416fc2 3571 */
3572
e00b005a 3573 if (p->type & CUPS_PRINTER_IMPLICIT)
3574 {
3575 len = 0;
3576 continue;
3577 }
ef416fc2 3578
e00b005a 3579 /*
3580 * If len == 0, get the length of this printer name up to the "@"
3581 * sign (if any).
3582 */
ef416fc2 3583
e00b005a 3584 cupsArraySave(Printers);
ef416fc2 3585
e00b005a 3586 if (len > 0 &&
3587 !strncasecmp(p->name, name + offset, len) &&
3588 (p->name[len] == '\0' || p->name[len] == '@'))
3589 {
3590 /*
3591 * We have more than one printer with the same name; see if
3592 * we have a class, and if this printer is a member...
3593 */
ef416fc2 3594
e00b005a 3595 if (pclass && strcasecmp(pclass->name, name))
3596 {
3597 if (update)
3598 cupsdSetPrinterAttrs(pclass);
ef416fc2 3599
e00b005a 3600 update = 0;
3601 pclass = NULL;
3602 }
ef416fc2 3603
e00b005a 3604 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
3605 {
3606 /*
3607 * Need to add the class...
3608 */
ef416fc2 3609
e00b005a 3610 pclass = cupsdAddPrinter(name);
3611 cupsArrayAdd(ImplicitPrinters, pclass);
ef416fc2 3612
e00b005a 3613 pclass->type |= CUPS_PRINTER_IMPLICIT;
3614 pclass->accepting = 1;
3615 pclass->state = IPP_PRINTER_IDLE;
ef416fc2 3616
e00b005a 3617 cupsdSetString(&pclass->location, p->location);
3618 cupsdSetString(&pclass->info, p->info);
ef416fc2 3619
7594b224 3620 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
3621 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
3622
e00b005a 3623 update = 1;
ef416fc2 3624
7a14d768 3625 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
c277e2f8 3626
89d46774 3627 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
e00b005a 3628 name);
b423cd4c 3629 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3630 "Implicit class \'%s\' added by directory services.",
3631 name);
e00b005a 3632 }
ef416fc2 3633
e00b005a 3634 if (first != NULL)
3635 {
3636 for (i = 0; i < pclass->num_printers; i ++)
3637 if (pclass->printers[i] == first)
3638 break;
ef416fc2 3639
e00b005a 3640 if (i >= pclass->num_printers)
3641 {
3642 first->in_implicit_class = 1;
3643 cupsdAddPrinterToClass(pclass, first);
3644 }
ef416fc2 3645
e00b005a 3646 first = NULL;
3647 }
ef416fc2 3648
e00b005a 3649 for (i = 0; i < pclass->num_printers; i ++)
3650 if (pclass->printers[i] == p)
3651 break;
ef416fc2 3652
e00b005a 3653 if (i >= pclass->num_printers)
3654 {
3655 p->in_implicit_class = 1;
3656 cupsdAddPrinterToClass(pclass, p);
3657 update = 1;
3658 }
3659 }
3660 else
ef416fc2 3661 {
3662 /*
e00b005a 3663 * First time around; just get name length and mark it as first
3664 * in the list...
ef416fc2 3665 */
3666
e00b005a 3667 if ((hptr = strchr(p->name, '@')) != NULL)
3668 len = hptr - p->name;
3669 else
3670 len = strlen(p->name);
ef416fc2 3671
f0ab5bff
MS
3672 if (len >= sizeof(name))
3673 {
3674 /*
3675 * If the printer name length somehow is greater than we normally allow,
3676 * skip this printer...
3677 */
3678
3679 len = 0;
3680 cupsArrayRestore(Printers);
3681 continue;
3682 }
3683
e00b005a 3684 strncpy(name, p->name, len);
3685 name[len] = '\0';
3686 offset = 0;
ef416fc2 3687
e00b005a 3688 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
3689 !(first->type & CUPS_PRINTER_IMPLICIT))
3690 {
3691 /*
3692 * Can't use same name as a local printer; add "Any" to the
3693 * front of the name, unless we have explicitly disabled
3694 * the "ImplicitAnyClasses"...
3695 */
ef416fc2 3696
e00b005a 3697 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
3698 {
3699 /*
3700 * Add "Any" to the class name...
3701 */
3702
3703 strcpy(name, "Any");
3704 strncpy(name + 3, p->name, len);
3705 name[len + 3] = '\0';
3706 offset = 3;
3707 }
3708 else
3709 {
3710 /*
3711 * Don't create an implicit class if we have a local printer
3712 * with the same name...
3713 */
3714
3715 len = 0;
3716 cupsArrayRestore(Printers);
3717 continue;
3718 }
3719 }
3720
3721 first = p;
ef416fc2 3722 }
3723
e00b005a 3724 cupsArrayRestore(Printers);
3725 }
ef416fc2 3726
e00b005a 3727 /*
3728 * Update the last printer class as needed...
3729 */
ef416fc2 3730
e00b005a 3731 if (pclass && update)
3732 cupsdSetPrinterAttrs(pclass);
ef416fc2 3733}
3734
3735
e1d6a774 3736/*
3737 * 'send_cups_browse()' - Send new browsing information using the CUPS
7594b224 3738 * protocol.
e1d6a774 3739 */
3740
3741static void
3742send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
3743{
3744 int i; /* Looping var */
3745 cups_ptype_t type; /* Printer type */
3746 cupsd_dirsvc_addr_t *b; /* Browse address */
3747 int bytes; /* Length of packet */
3748 char packet[1453], /* Browse data packet */
3749 uri[1024], /* Printer URI */
3750 location[1024], /* printer-location */
3751 info[1024], /* printer-info */
178cb736 3752 make_model[1024],
e1d6a774 3753 /* printer-make-and-model */
178cb736 3754 air[1024]; /* auth-info-required */
e1d6a774 3755 cupsd_netif_t *iface; /* Network interface */
3756
3757
3758 /*
3759 * Figure out the printer type value...
3760 */
3761
3762 type = p->type | CUPS_PRINTER_REMOTE;
3763
3764 if (!p->accepting)
3765 type |= CUPS_PRINTER_REJECTING;
3766
3767 if (p == DefaultPrinter)
3768 type |= CUPS_PRINTER_DEFAULT;
3769
3770 /*
3771 * Remove quotes from printer-info, printer-location, and
3772 * printer-make-and-model attributes...
3773 */
3774
3775 dequote(location, p->location, sizeof(location));
3776 dequote(info, p->info, sizeof(info));
d6ae789d 3777
3778 if (p->make_model)
3779 dequote(make_model, p->make_model, sizeof(make_model));
3780 else if (p->type & CUPS_PRINTER_CLASS)
3781 {
3782 if (p->num_printers > 0 && p->printers[0]->make_model)
3783 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
3784 else
3785 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
3786 }
3787 else if (p->raw)
3788 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
3789 else
3790 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
e1d6a774 3791
178cb736
MS
3792 if (get_auth_info_required(p, packet, sizeof(packet)))
3793 snprintf(air, sizeof(air), " auth-info-required=%s", packet);
3794 else
3795 air[0] = '\0';
3796
e1d6a774 3797 /*
3798 * Send a packet to each browse address...
3799 */
3800
3801 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
3802 if (b->iface[0])
3803 {
3804 /*
3805 * Send the browse packet to one or more interfaces...
3806 */
3807
3808 if (!strcmp(b->iface, "*"))
3809 {
3810 /*
3811 * Send to all local interfaces...
3812 */
3813
3814 cupsdNetIFUpdate();
3815
3816 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3817 iface;
3818 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3819 {
3820 /*
3821 * Only send to local, IPv4 interfaces...
3822 */
3823
3824 if (!iface->is_local || !iface->port ||
3825 iface->address.addr.sa_family != AF_INET)
3826 continue;
3827
3828 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3829 iface->hostname, iface->port,
ed486911 3830 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
e1d6a774 3831 "/printers/%s",
3832 p->name);
178cb736 3833 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
e1d6a774 3834 type, p->state, uri, location, info, make_model,
178cb736 3835 p->browse_attrs ? p->browse_attrs : "", air);
e1d6a774 3836
3837 bytes = strlen(packet);
3838
3839 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3840 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3841 iface->name, packet);
3842
3843 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3844
3845 sendto(BrowseSocket, packet, bytes, 0,
3846 (struct sockaddr *)&(iface->broadcast),
d09495fa 3847 httpAddrLength(&(iface->broadcast)));
e1d6a774 3848 }
3849 }
3850 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
3851 {
3852 /*
3853 * Send to the named interface using the IPv4 address...
3854 */
3855
3856 while (iface)
3857 if (strcmp(b->iface, iface->name))
3858 {
3859 iface = NULL;
3860 break;
3861 }
3862 else if (iface->address.addr.sa_family == AF_INET && iface->port)
3863 break;
3864 else
3865 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
3866
3867 if (iface)
3868 {
3869 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3870 iface->hostname, iface->port,
b94498cf 3871 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
e1d6a774 3872 "/printers/%s",
3873 p->name);
178cb736
MS
3874 snprintf(packet, sizeof(packet),
3875 "%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
e1d6a774 3876 type, p->state, uri, location, info, make_model,
178cb736 3877 p->browse_attrs ? p->browse_attrs : "", air);
e1d6a774 3878
3879 bytes = strlen(packet);
3880
3881 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3882 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3883 iface->name, packet);
3884
3885 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3886
3887 sendto(BrowseSocket, packet, bytes, 0,
3888 (struct sockaddr *)&(iface->broadcast),
d09495fa 3889 httpAddrLength(&(iface->broadcast)));
e1d6a774 3890 }
3891 }
3892 }
3893 else
3894 {
3895 /*
3896 * Send the browse packet to the indicated address using
3897 * the default server name...
3898 */
3899
178cb736 3900 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s%s\n",
e1d6a774 3901 type, p->state, p->uri, location, info, make_model,
178cb736 3902 p->browse_attrs ? p->browse_attrs : "", air);
e1d6a774 3903
3904 bytes = strlen(packet);
3905 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3906 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
3907
3908 if (sendto(BrowseSocket, packet, bytes, 0,
3909 (struct sockaddr *)&(b->to),
d09495fa 3910 httpAddrLength(&(b->to))) <= 0)
e1d6a774 3911 {
3912 /*
3913 * Unable to send browse packet, so remove this address from the
3914 * list...
3915 */
3916
3917 cupsdLogMessage(CUPSD_LOG_ERROR,
3918 "cupsdSendBrowseList: sendto failed for browser "
3919 "%d - %s.",
3920 (int)(b - Browsers + 1), strerror(errno));
3921
3922 if (i > 1)
3923 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
3924
3925 b --;
3926 NumBrowsers --;
3927 }
3928 }
3929}
3930
3931
749b1e90
MS
3932#ifdef HAVE_LDAP
3933/*
3934 * 'ldap_search_rec()' - LDAP Search with reconnect
3935 */
3936
3937static int
3938ldap_search_rec(LDAP *ld, /* I - LDAP handler */
3939 char *base, /* I - Base dn */
3940 int scope, /* I - LDAP search scope */
3941 char *filter, /* I - Filter string */
3942 char *attrs[], /* I - Requested attributes */
3943 int attrsonly, /* I - Return only attributes? */
3944 LDAPMessage **res) /* I - LDAP handler */
3945{
3946 int rc; /* Return code */
3947
3948
3949# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3950 rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
3951 NULL, LDAP_NO_LIMIT, res);
3952# else
3953 rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
3954# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3955
3956 /*
3957 * If we have a connection problem try again...
3958 */
3959
3960 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
3961 {
3962 cupsdLogMessage(CUPSD_LOG_ERROR,
3963 "LDAP search failed with status %d: %s",
3964 rc, ldap_err2string(rc));
3965 cupsdLogMessage(CUPSD_LOG_INFO,
3966 "We try the LDAP search once again after reconnecting to "
3967 "the server");
3968 ldap_freeres(*res);
3969 ldap_reconnect();
3970
3971# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3972 rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL,
3973 NULL, NULL, LDAP_NO_LIMIT, res);
3974# else
3975 rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
3976# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3977 }
3978
3979 if (rc == LDAP_NO_SUCH_OBJECT)
3980 cupsdLogMessage(CUPSD_LOG_DEBUG,
3981 "ldap_search_rec: LDAP entry/object not found");
3982 else if (rc != LDAP_SUCCESS)
3983 cupsdLogMessage(CUPSD_LOG_ERROR,
3984 "ldap_search_rec: LDAP search failed with status %d: %s",
3985 rc, ldap_err2string(rc));
3986
3987 if (rc != LDAP_SUCCESS)
3988 ldap_freeres(*res);
3989
3990 return (rc);
3991}
3992
3993
3994/*
3995 * 'ldap_freeres()' - Free LDAPMessage
3996 */
3997
3998static void
3999ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
4000{
4001 int rc; /* Return value */
4002
4003
4004 rc = ldap_msgfree(entry);
4005 if (rc == -1)
4006 cupsdLogMessage(CUPSD_LOG_WARN,
4007 "Can't free LDAPMessage!");
4008 else if (rc == 0)
4009 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4010 "Freeing LDAPMessage was unnecessary");
4011}
4012
4013
4014/*
4015 * 'ldap_getval_char()' - Get first LDAP value and convert to string
4016 */
4017
4018static int
4019ldap_getval_firststring(
4020 LDAP *ld, /* I - LDAP handler */
4021 LDAPMessage *entry, /* I - LDAP message or search result */
4022 char *attr, /* I - the wanted attribute */
4023 char *retval, /* O - String to return */
4024 unsigned long maxsize) /* I - Max string size */
4025{
4026 char *dn; /* LDAP DN */
4027 int rc = 0; /* Return code */
4028# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4029 struct berval **bval; /* LDAP value array */
4030 unsigned long size; /* String size */
4031
4032
4033 /*
4034 * Get value from LDAPMessage...
4035 */
4036
4037 if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
4038 {
4039 rc = -1;
4040 dn = ldap_get_dn(ld, entry);
4041 cupsdLogMessage(CUPSD_LOG_WARN,
4042 "Failed to get LDAP value %s for %s!",
4043 attr, dn);
4044 ldap_memfree(dn);
4045 }
4046 else
4047 {
4048
4049 /*
4050 * Check size and copy value into our string...
4051 */
4052
4053 size = maxsize;
4054 if (size < bval[0]->bv_len)
4055 {
4056 rc = -1;
4057 dn = ldap_get_dn(ld, entry);
4058 cupsdLogMessage(CUPSD_LOG_WARN,
4059 "Attribute %s is too big! (dn: %s)",
4060 attr, dn);
4061 ldap_memfree(dn);
4062 }
4063 else
4064 size = bval[0]->bv_len;
4065
4066 strlcpy(retval, bval[0]->bv_val, size);
4067 ldap_value_free_len(bval);
4068 }
4069# else
4070 char **value; /* LDAP value */
4071
4072 /*
4073 * Get value from LDAPMessage...
4074 */
4075
4076 if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
4077 {
4078 rc = -1;
4079 dn = ldap_get_dn(ld, entry);
4080 cupsdLogMessage(CUPSD_LOG_WARN,
4081 "Failed to get LDAP value %s for %s!",
4082 attr, dn);
4083 ldap_memfree(dn);
4084 }
4085 else
4086 {
4087 strlcpy(retval, *value, maxsize);
4088 ldap_value_free(value);
4089 }
4090# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4091
4092 return (rc);
4093}
4094
4095
4096/*
4097 * 'send_ldap_ou()' - Send LDAP ou registrations.
4098 */
4099
4100static void
4101send_ldap_ou(char *ou, /* I - Servername/ou to register */
4102 char *basedn, /* I - Our base dn */
4103 char *descstring) /* I - Description for ou */
4104{
4105 int i; /* Looping var... */
4106 LDAPMod mods[3]; /* The 3 attributes we will be adding */
4107 LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
4108 LDAPMessage *res, /* Search result token */
4109 *e; /* Current entry from search */
4110 int rc; /* LDAP status */
4111 char dn[1024], /* DN of the organizational unit we are adding */
4112 *desc[2], /* Change records */
4113 *ou_value[2];
4114 char old_desc[1024]; /* Old description */
4115 static const char * const objectClass_values[] =
4116 { /* The 2 objectClass's we use in */
4117 "top", /* our LDAP entries */
4118 "organizationalUnit",
4119 NULL
4120 };
4121 static const char * const ou_attrs[] =/* CUPS LDAP attributes */
4122 {
4123 "description",
4124 NULL
4125 };
4126
4127
4128 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
4129
4130 /*
4131 * Reconnect if LDAP Handle is invalid...
4132 */
4133
4134 if (! BrowseLDAPHandle)
4135 {
4136 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4137 "send_ldap_ou: LDAP Handle is invalid. Try "
4138 "reconnecting...");
4139 ldap_reconnect();
4140 return;
4141 }
4142
4143 /*
4144 * Prepare ldap search...
4145 */
4146
4147 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
4148 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
4149
4150 ou_value[0] = ou;
4151 ou_value[1] = NULL;
4152 desc[0] = descstring;
4153 desc[1] = NULL;
4154
4155 mods[0].mod_type = "ou";
4156 mods[0].mod_values = ou_value;
4157 mods[1].mod_type = "description";
4158 mods[1].mod_values = desc;
4159 mods[2].mod_type = "objectClass";
4160 mods[2].mod_values = (char **)objectClass_values;
4161
4162 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4163 (char **)ou_attrs, 0, &res);
4164
4165 /*
4166 * If ldap search was not successfull then exit function...
4167 */
4168
4169 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4170 return;
4171
4172 /*
4173 * Check if we need to insert or update the LDAP entry...
4174 */
4175
4176 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4177 rc != LDAP_NO_SUCH_OBJECT)
4178 {
4179 /*
4180 * Printserver has already been registered, check if
4181 * modification is required...
4182 */
4183
4184 e = ldap_first_entry(BrowseLDAPHandle, res);
4185
4186 /*
4187 * Get the required values from this entry...
4188 */
4189
4190 if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
4191 sizeof(old_desc)) == -1)
4192 old_desc[0] = '\0';
4193
4194 /*
4195 * Check if modification is required...
4196 */
4197
4198 if ( strcmp(desc[0], old_desc) == 0 )
4199 {
4200 /*
4201 * LDAP entry for the printer exists.
4202 * Printer has already been registered,
4203 * no modifications required...
4204 */
4205 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4206 "send_ldap_ou: No updates required for %s", ou);
4207 }
4208 else
4209 {
4210
4211 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4212 "send_ldap_ou: Replace entry for %s", ou);
4213
4214 for (i = 0; i < 3; i ++)
4215 {
4216 pmods[i] = mods + i;
4217 pmods[i]->mod_op = LDAP_MOD_REPLACE;
4218 }
4219 pmods[i] = NULL;
4220
4221# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4222 if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4223 NULL)) != LDAP_SUCCESS)
4224# else
4225 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4226# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4227 {
4228 cupsdLogMessage(CUPSD_LOG_ERROR,
4229 "LDAP modify for %s failed with status %d: %s",
4230 ou, rc, ldap_err2string(rc));
4231 if ( LDAP_SERVER_DOWN == rc )
4232 ldap_reconnect();
4233 }
4234 }
4235 }
4236 else
4237 {
4238 /*
4239 * Printserver has never been registered,
4240 * add registration...
4241 */
4242
4243 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4244 "send_ldap_ou: Add entry for %s", ou);
4245
4246 for (i = 0; i < 3; i ++)
4247 {
4248 pmods[i] = mods + i;
4249 pmods[i]->mod_op = LDAP_MOD_ADD;
4250 }
4251 pmods[i] = NULL;
4252
4253# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4254 if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4255 NULL)) != LDAP_SUCCESS)
4256# else
4257 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4258# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4259 {
4260 cupsdLogMessage(CUPSD_LOG_ERROR,
4261 "LDAP add for %s failed with status %d: %s",
4262 ou, rc, ldap_err2string(rc));
4263 if ( LDAP_SERVER_DOWN == rc )
4264 ldap_reconnect();
4265 }
4266 }
4267
4268 ldap_freeres(res);
4269}
4270
4271
e1d6a774 4272/*
4273 * 'send_ldap_browse()' - Send LDAP printer registrations.
4274 */
4275
4276static void
4277send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
4278{
4279 int i; /* Looping var... */
4280 LDAPMod mods[7]; /* The 7 attributes we will be adding */
4281 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
749b1e90
MS
4282 LDAPMessage *res, /* Search result token */
4283 *e; /* Current entry from search */
e1d6a774 4284 char *cn_value[2], /* Change records */
4285 *uri[2],
4286 *info[2],
4287 *location[2],
4288 *make_model[2],
4289 *type[2],
4290 typestring[255], /* String to hold printer-type */
e1d6a774 4291 dn[1024]; /* DN of the printer we are adding */
4292 int rc; /* LDAP status */
749b1e90
MS
4293 char old_uri[HTTP_MAX_URI], /* Printer URI */
4294 old_location[1024], /* Printer location */
4295 old_info[1024], /* Printer information */
4296 old_make_model[1024], /* Printer make and model */
4297 old_type_string[30]; /* Temporary type number */
4298 int old_type; /* Printer type */
e1d6a774 4299 static const char * const objectClass_values[] =
4300 { /* The 3 objectClass's we use in */
4301 "top", /* our LDAP entries */
4302 "device",
4303 "cupsPrinter",
4304 NULL
4305 };
4306
749b1e90 4307
75bd9771 4308 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
e1d6a774 4309
749b1e90
MS
4310 /*
4311 * Exit function if LDAP updates has been disabled...
4312 */
4313
4314 if (!BrowseLDAPUpdate)
4315 {
4316 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4317 "send_ldap_browse: Updates temporary disabled; "
4318 "skipping...");
4319 return;
4320 }
4321
4322 /*
4323 * Reconnect if LDAP Handle is invalid...
4324 */
4325
4326 if (!BrowseLDAPHandle)
4327 {
4328 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4329 "send_ldap_browse: LDAP Handle is invalid. Try "
4330 "reconnecting...");
4331 ldap_reconnect();
4332 return;
4333 }
4334
e1d6a774 4335 /*
4336 * Everything in ldap is ** so we fudge around it...
4337 */
4338
4339 sprintf(typestring, "%u", p->type);
4340
ed486911 4341 cn_value[0] = p->name;
e1d6a774 4342 cn_value[1] = NULL;
ed486911 4343 info[0] = p->info ? p->info : "Unknown";
e1d6a774 4344 info[1] = NULL;
ed486911 4345 location[0] = p->location ? p->location : "Unknown";
e1d6a774 4346 location[1] = NULL;
ed486911 4347 make_model[0] = p->make_model ? p->make_model : "Unknown";
e1d6a774 4348 make_model[1] = NULL;
4349 type[0] = typestring;
4350 type[1] = NULL;
4351 uri[0] = p->uri;
4352 uri[1] = NULL;
4353
749b1e90
MS
4354 /*
4355 * Get ldap entry for printer ...
4356 */
e1d6a774 4357
749b1e90
MS
4358 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4359 BrowseLDAPDN);
4360 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
4361
4362 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4363 (char **)ldap_attrs, 0, &res);
4364
4365 /*
4366 * If ldap search was not successfull then exit function
4367 * and temporary disable LDAP updates...
4368 */
4369
4370 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4371 {
4372 if (BrowseLDAPUpdate &&
4373 (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
4374 {
4375 BrowseLDAPUpdate = FALSE;
4376 cupsdLogMessage(CUPSD_LOG_INFO,
4377 "LDAP update temporary disabled");
4378 }
4379
4380 return;
4381 }
4382
4383 /*
4384 * Fill modification array...
4385 */
e1d6a774 4386
749b1e90 4387 mods[0].mod_type = "cn";
e1d6a774 4388 mods[0].mod_values = cn_value;
749b1e90 4389 mods[1].mod_type = "printerDescription";
e1d6a774 4390 mods[1].mod_values = info;
749b1e90 4391 mods[2].mod_type = "printerURI";
e1d6a774 4392 mods[2].mod_values = uri;
749b1e90 4393 mods[3].mod_type = "printerLocation";
e1d6a774 4394 mods[3].mod_values = location;
749b1e90 4395 mods[4].mod_type = "printerMakeAndModel";
e1d6a774 4396 mods[4].mod_values = make_model;
749b1e90 4397 mods[5].mod_type = "printerType";
e1d6a774 4398 mods[5].mod_values = type;
749b1e90 4399 mods[6].mod_type = "objectClass";
e1d6a774 4400 mods[6].mod_values = (char **)objectClass_values;
4401
749b1e90
MS
4402 /*
4403 * Check if we need to insert or update the LDAP entry...
4404 */
e1d6a774 4405
749b1e90
MS
4406 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4407 rc != LDAP_NO_SUCH_OBJECT)
e1d6a774 4408 {
4409 /*
749b1e90
MS
4410 * Printer has already been registered, check if
4411 * modification is required...
e1d6a774 4412 */
4413
749b1e90 4414 e = ldap_first_entry(BrowseLDAPHandle, res);
e1d6a774 4415
749b1e90
MS
4416 /*
4417 * Get the required values from this entry...
4418 */
4419
4420 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
4421 old_info, sizeof(old_info)) == -1)
4422 old_info[0] = '\0';
4423
4424 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
4425 old_location, sizeof(old_location)) == -1)
4426 old_info[0] = '\0';
4427
4428 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
4429 old_make_model, sizeof(old_make_model)) == -1)
4430 old_info[0] = '\0';
4431
4432 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
4433 old_type_string, sizeof(old_type_string)) == -1)
4434 old_info[0] = '\0';
4435
4436 old_type = atoi(old_type_string);
4437
4438 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
4439 sizeof(old_uri)) == -1)
4440 old_info[0] = '\0';
4441
4442 /*
4443 * Check if modification is required...
4444 */
4445
4446 if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
4447 !strcmp(location[0], old_location) &&
4448 !strcmp(make_model[0], old_make_model) && p->type == old_type)
e1d6a774 4449 {
749b1e90
MS
4450 /*
4451 * LDAP entry for the printer exists. Printer has already been registered,
4452 * no modifications required...
4453 */
4454
4455 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4456 "send_ldap_browse: No updates required for %s", p->name);
e1d6a774 4457 }
749b1e90
MS
4458 else
4459 {
4460 /*
4461 * LDAP entry for the printer exists. Printer has already been registered,
4462 * modify the current registration...
4463 */
e1d6a774 4464
749b1e90
MS
4465 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4466 "send_ldap_browse: Replace entry for %s", p->name);
4467
4468 for (i = 0; i < 7; i ++)
4469 {
4470 pmods[i] = mods + i;
4471 pmods[i]->mod_op = LDAP_MOD_REPLACE;
4472 }
4473 pmods[i] = NULL;
4474
4475# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4476 if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4477 NULL)) != LDAP_SUCCESS)
4478# else
4479 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4480# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4481 {
4482 cupsdLogMessage(CUPSD_LOG_ERROR,
4483 "LDAP modify for %s failed with status %d: %s",
4484 p->name, rc, ldap_err2string(rc));
4485 if (rc == LDAP_SERVER_DOWN)
4486 ldap_reconnect();
4487 }
4488 }
e1d6a774 4489 }
4490 else
4491 {
4492 /*
749b1e90
MS
4493 * No LDAP entry exists for the printer. Printer has never been registered,
4494 * add the current registration...
e1d6a774 4495 */
4496
749b1e90
MS
4497 send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
4498
e1d6a774 4499 cupsdLogMessage(CUPSD_LOG_DEBUG2,
749b1e90 4500 "send_ldap_browse: Add entry for %s", p->name);
e1d6a774 4501
4502 for (i = 0; i < 7; i ++)
4503 {
4504 pmods[i] = mods + i;
ed486911 4505 pmods[i]->mod_op = LDAP_MOD_ADD;
e1d6a774 4506 }
4507 pmods[i] = NULL;
4508
749b1e90
MS
4509# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4510 if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4511 NULL)) != LDAP_SUCCESS)
4512# else
ed486911 4513 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
749b1e90
MS
4514# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4515 {
e1d6a774 4516 cupsdLogMessage(CUPSD_LOG_ERROR,
4517 "LDAP add for %s failed with status %d: %s",
4518 p->name, rc, ldap_err2string(rc));
749b1e90
MS
4519 if (rc == LDAP_SERVER_DOWN)
4520 ldap_reconnect();
4521 }
e1d6a774 4522 }
749b1e90
MS
4523
4524 ldap_freeres(res);
e1d6a774 4525}
749b1e90
MS
4526
4527
4528/*
4529 * 'ldap_dereg_printer()' - Delete printer from directory
4530 */
4531
4532static void
4533ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
4534{
4535 char dn[1024]; /* DN of the printer */
4536 int rc; /* LDAP status */
4537
4538
4539 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
4540 p->name);
4541
4542 /*
4543 * Reconnect if LDAP Handle is invalid...
4544 */
4545
4546 if (!BrowseLDAPHandle)
4547 {
4548 ldap_reconnect();
4549 return;
4550 }
4551
4552 /*
4553 * Get dn for printer and delete LDAP entry...
4554 */
4555
4556 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4557 BrowseLDAPDN);
4558 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
4559
4560# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4561 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4562 NULL)) != LDAP_SUCCESS)
4563# else
4564 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4565# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4566 {
4567 cupsdLogMessage(CUPSD_LOG_WARN,
4568 "LDAP delete for %s failed with status %d: %s",
4569 p->name, rc, ldap_err2string(rc));
4570
4571 /*
4572 * If we had a connection problem (connection timed out, etc.)
4573 * we should reconnect and try again to delete the entry...
4574 */
4575
4576 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4577 {
4578 cupsdLogMessage(CUPSD_LOG_INFO,
4579 "Retry deleting LDAP entry for %s after a reconnect...", p->name);
4580 ldap_reconnect();
4581
4582# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4583 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4584 NULL)) != LDAP_SUCCESS)
4585# else
4586 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4587# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4588 cupsdLogMessage(CUPSD_LOG_WARN,
4589 "LDAP delete for %s failed with status %d: %s",
4590 p->name, rc, ldap_err2string(rc));
4591 }
4592 }
4593}
4594
4595
4596static void
4597ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
4598 char *basedn) /* I - Dase dn */
4599{
4600 char dn[1024]; /* DN of the printer */
4601 int rc; /* LDAP status */
4602
4603
4604 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
4605
4606 /*
4607 * Reconnect if LDAP Handle is invalid...
4608 */
4609
4610 if (!BrowseLDAPHandle)
4611 {
4612 ldap_reconnect();
4613 return;
4614 }
4615
4616 /*
4617 * Get dn for printer and delete LDAP entry...
4618 */
4619
4620 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
4621 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
4622
4623# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4624 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4625 NULL)) != LDAP_SUCCESS)
4626# else
4627 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4628# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4629 {
4630 cupsdLogMessage(CUPSD_LOG_WARN,
4631 "LDAP delete for %s failed with status %d: %s",
4632 ou, rc, ldap_err2string(rc));
4633
4634 /*
4635 * If we had a connection problem (connection timed out, etc.)
4636 * we should reconnect and try again to delete the entry...
4637 */
4638
4639 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4640 {
4641 cupsdLogMessage(CUPSD_LOG_INFO,
4642 "Retry deleting LDAP entry for %s after a reconnect...", ou);
4643 ldap_reconnect();
4644# if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4645 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4646 NULL)) != LDAP_SUCCESS)
4647# else
4648 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4649# endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4650 cupsdLogMessage(CUPSD_LOG_WARN,
4651 "LDAP delete for %s failed with status %d: %s",
4652 ou, rc, ldap_err2string(rc));
4653 }
4654
4655 }
4656}
4657#endif /* HAVE_LDAP */
e1d6a774 4658
4659
4660#ifdef HAVE_LIBSLP
4661/*
4662 * 'send_slp_browse()' - Register the specified printer with SLP.
4663 */
4664
4665static void
4666send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
4667{
4668 char srvurl[HTTP_MAX_URI], /* Printer service URI */
4669 attrs[8192], /* Printer attributes */
4670 finishings[1024], /* Finishings to support */
4671 make_model[IPP_MAX_NAME * 2],
4672 /* Make and model, quoted */
4673 location[IPP_MAX_NAME * 2],
4674 /* Location, quoted */
4675 info[IPP_MAX_NAME * 2], /* Info, quoted */
4676 *src, /* Pointer to original string */
4677 *dst; /* Pointer to destination string */
4678 ipp_attribute_t *authentication; /* uri-authentication-supported value */
4679 SLPError error; /* SLP error, if any */
4680
4681
4682 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
4683 p->name);
4684
4685 /*
4686 * Make the SLP service URL that conforms to the IANA
4687 * 'printer:' template.
4688 */
4689
4690 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
4691
4692 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
4693
4694 /*
4695 * Figure out the finishings string...
4696 */
4697
4698 if (p->type & CUPS_PRINTER_STAPLE)
4699 strcpy(finishings, "staple");
4700 else
4701 finishings[0] = '\0';
4702
4703 if (p->type & CUPS_PRINTER_BIND)
4704 {
4705 if (finishings[0])
4706 strlcat(finishings, ",bind", sizeof(finishings));
4707 else
4708 strcpy(finishings, "bind");
4709 }
4710
4711 if (p->type & CUPS_PRINTER_PUNCH)
4712 {
4713 if (finishings[0])
4714 strlcat(finishings, ",punch", sizeof(finishings));
4715 else
4716 strcpy(finishings, "punch");
4717 }
4718
4719 if (p->type & CUPS_PRINTER_COVER)
4720 {
4721 if (finishings[0])
4722 strlcat(finishings, ",cover", sizeof(finishings));
4723 else
4724 strcpy(finishings, "cover");
4725 }
4726
4727 if (p->type & CUPS_PRINTER_SORT)
4728 {
4729 if (finishings[0])
4730 strlcat(finishings, ",sort", sizeof(finishings));
4731 else
4732 strcpy(finishings, "sort");
4733 }
4734
4735 if (!finishings[0])
4736 strcpy(finishings, "none");
4737
4738 /*
4739 * Quote any commas in the make and model, location, and info strings...
4740 */
4741
4742 for (src = p->make_model, dst = make_model;
4743 src && *src && dst < (make_model + sizeof(make_model) - 2);)
4744 {
4745 if (*src == ',' || *src == '\\' || *src == ')')
4746 *dst++ = '\\';
4747
4748 *dst++ = *src++;
4749 }
4750
4751 *dst = '\0';
4752
4753 if (!make_model[0])
4754 strcpy(make_model, "Unknown");
4755
4756 for (src = p->location, dst = location;
4757 src && *src && dst < (location + sizeof(location) - 2);)
4758 {
4759 if (*src == ',' || *src == '\\' || *src == ')')
4760 *dst++ = '\\';
4761
4762 *dst++ = *src++;
4763 }
4764
4765 *dst = '\0';
4766
4767 if (!location[0])
4768 strcpy(location, "Unknown");
4769
4770 for (src = p->info, dst = info;
4771 src && *src && dst < (info + sizeof(info) - 2);)
4772 {
4773 if (*src == ',' || *src == '\\' || *src == ')')
4774 *dst++ = '\\';
4775
4776 *dst++ = *src++;
4777 }
4778
4779 *dst = '\0';
4780
4781 if (!info[0])
4782 strcpy(info, "Unknown");
4783
4784 /*
4785 * Get the authentication value...
4786 */
4787
4788 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
4789 IPP_TAG_KEYWORD);
4790
4791 /*
4792 * Make the SLP attribute string list that conforms to
4793 * the IANA 'printer:' template.
4794 */
4795
4796 snprintf(attrs, sizeof(attrs),
4797 "(printer-uri-supported=%s),"
4798 "(uri-authentication-supported=%s>),"
4799#ifdef HAVE_SSL
4800 "(uri-security-supported=tls>),"
4801#else
4802 "(uri-security-supported=none>),"
4803#endif /* HAVE_SSL */
4804 "(printer-name=%s),"
4805 "(printer-location=%s),"
4806 "(printer-info=%s),"
4807 "(printer-more-info=%s),"
4808 "(printer-make-and-model=%s),"
4809 "(printer-type=%d),"
4810 "(charset-supported=utf-8),"
4811 "(natural-language-configured=%s),"
4812 "(natural-language-supported=de,en,es,fr,it),"
4813 "(color-supported=%s),"
4814 "(finishings-supported=%s),"
4815 "(sides-supported=one-sided%s),"
4816 "(multiple-document-jobs-supported=true)"
4817 "(ipp-versions-supported=1.0,1.1)",
4818 p->uri, authentication->values[0].string.text, p->name, location,
4819 info, p->uri, make_model, p->type, DefaultLanguage,
4820 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
4821 finishings,
4822 p->type & CUPS_PRINTER_DUPLEX ?
4823 ",two-sided-long-edge,two-sided-short-edge" : "");
4824
4825 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
4826
4827 /*
4828 * Register the printer with the SLP server...
4829 */
4830
4831 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
4832 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
4833
4834 if (error != SLP_OK)
4835 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
4836 error);
4837}
4838
4839
ef416fc2 4840/*
4841 * 'slp_attr_callback()' - SLP attribute callback
4842 */
4843
4844static SLPBoolean /* O - SLP_TRUE for success */
4845slp_attr_callback(
4846 SLPHandle hslp, /* I - SLP handle */
4847 const char *attrlist, /* I - Attribute list */
4848 SLPError errcode, /* I - Parsing status for this attr */
4849 void *cookie) /* I - Current printer */
4850{
b423cd4c 4851 char *tmp = 0; /* Temporary string */
ef416fc2 4852 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
b423cd4c 4853 /* Current printer */
ef416fc2 4854
4855
b423cd4c 4856 (void)hslp; /* anti-compiler-warning-code */
ef416fc2 4857
4858 /*
4859 * Bail if there was an error
4860 */
4861
4862 if (errcode != SLP_OK)
4863 return (SLP_TRUE);
4864
4865 /*
4866 * Parse the attrlist to obtain things needed to build CUPS browse packet
4867 */
4868
4869 memset(p, 0, sizeof(cupsd_printer_t));
4870
ef416fc2 4871 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
4872 return (SLP_FALSE);
4873 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
4874 return (SLP_FALSE);
4875 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
4876 return (SLP_FALSE);
b423cd4c 4877 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
4878 p->type = atoi(tmp);
4879 else
4880 p->type = CUPS_PRINTER_REMOTE;
ef416fc2 4881
4882 cupsdClearString(&tmp);
4883
4884 return (SLP_TRUE);
4885}
4886
4887
4888/*
4889 * 'slp_dereg_printer()' - SLPDereg() the specified printer
4890 */
4891
4892static void
4893slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
4894{
4895 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
4896
4897
4898 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
4899
4900 if (!(p->type & CUPS_PRINTER_REMOTE))
4901 {
4902 /*
4903 * Make the SLP service URL that conforms to the IANA
4904 * 'printer:' template.
4905 */
4906
4907 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
4908
4909 /*
4910 * Deregister the printer...
4911 */
4912
4913 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
4914 }
4915}
4916
4917
4918/*
4919 * 'slp_get_attr()' - Get an attribute from an SLP registration.
4920 */
4921
4922static int /* O - 0 on success */
4923slp_get_attr(const char *attrlist, /* I - Attribute list string */
4924 const char *tag, /* I - Name of attribute */
4925 char **valbuf) /* O - Value */
4926{
4927 char *ptr1, /* Pointer into string */
4928 *ptr2; /* ... */
4929
4930
4931 cupsdClearString(valbuf);
4932
4933 if ((ptr1 = strstr(attrlist, tag)) != NULL)
4934 {
4935 ptr1 += strlen(tag);
4936
4937 if ((ptr2 = strchr(ptr1,')')) != NULL)
4938 {
4939 /*
4940 * Copy the value...
4941 */
4942
4943 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
4944 strncpy(*valbuf, ptr1, ptr2 - ptr1);
4945
4946 /*
4947 * Dequote the value...
4948 */
4949
4950 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
4951 if (*ptr1 == '\\' && ptr1[1])
4952 _cups_strcpy(ptr1, ptr1 + 1);
4953
4954 return (0);
4955 }
4956 }
4957
4958 return (-1);
4959}
4960
4961
4962/*
4963 * 'slp_reg_callback()' - Empty SLPRegReport.
4964 */
4965
4966static void
4967slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
4968 SLPError errcode, /* I - Error code, if any */
4969 void *cookie) /* I - App data */
4970{
4971 (void)hslp;
4972 (void)errcode;
4973 (void)cookie;
4974
4975 return;
4976}
4977
4978
4979/*
4980 * 'slp_url_callback()' - SLP service url callback
4981 */
4982
4983static SLPBoolean /* O - TRUE = OK, FALSE = error */
4984slp_url_callback(
4985 SLPHandle hslp, /* I - SLP handle */
4986 const char *srvurl, /* I - URL of service */
4987 unsigned short lifetime, /* I - Life of service */
4988 SLPError errcode, /* I - Existing error code */
4989 void *cookie) /* I - Pointer to service list */
4990{
4991 slpsrvurl_t *s, /* New service entry */
4992 **head; /* Pointer to head of entry */
4993
4994
4995 /*
4996 * Let the compiler know we won't be using these vars...
4997 */
4998
4999 (void)hslp;
5000 (void)lifetime;
5001
5002 /*
5003 * Bail if there was an error
5004 */
5005
5006 if (errcode != SLP_OK)
5007 return (SLP_TRUE);
5008
5009 /*
5010 * Grab the head of the list...
5011 */
5012
5013 head = (slpsrvurl_t**)cookie;
5014
5015 /*
5016 * Allocate a *temporary* slpsrvurl_t to hold this entry.
5017 */
5018
5019 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
5020 return (SLP_FALSE);
5021
5022 /*
5023 * Copy the SLP service URL...
5024 */
5025
5026 strlcpy(s->url, srvurl, sizeof(s->url));
5027
5028 /*
5029 * Link the SLP service URL into the head of the list
5030 */
5031
5032 if (*head)
5033 s->next = *head;
5034
5035 *head = s;
5036
5037 return (SLP_TRUE);
5038}
5039#endif /* HAVE_LIBSLP */
5040
5041
5042/*
f899b121 5043 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
5044 */
5045
5046static void
5047update_cups_browse(void)
5048{
5049 int i; /* Looping var */
5050 int auth; /* Authorization status */
5051 int len; /* Length of name string */
5052 int bytes; /* Number of bytes left */
5053 char packet[1541], /* Broadcast packet */
5054 *pptr; /* Pointer into packet */
5055 socklen_t srclen; /* Length of source address */
5056 http_addr_t srcaddr; /* Source address */
5057 char srcname[1024]; /* Source hostname */
5058 unsigned address[4]; /* Source address */
5059 unsigned type; /* Printer type */
5060 unsigned state; /* Printer state */
5061 char uri[HTTP_MAX_URI], /* Printer URI */
5062 host[HTTP_MAX_URI], /* Host portion of URI */
5063 resource[HTTP_MAX_URI], /* Resource portion of URI */
5064 info[IPP_MAX_NAME], /* Information string */
5065 location[IPP_MAX_NAME], /* Location string */
5066 make_model[IPP_MAX_NAME];/* Make and model string */
5067 int num_attrs; /* Number of attributes */
5068 cups_option_t *attrs; /* Attributes */
5069
5070
5071 /*
5072 * Read a packet from the browse socket...
5073 */
5074
5075 srclen = sizeof(srcaddr);
5076 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
5077 (struct sockaddr *)&srcaddr, &srclen)) < 0)
5078 {
5079 /*
5080 * "Connection refused" is returned under Linux if the destination port
5081 * or address is unreachable from a previous sendto(); check for the
5082 * error here and ignore it for now...
5083 */
5084
5085 if (errno != ECONNREFUSED && errno != EAGAIN)
5086 {
5087 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
5088 strerror(errno));
7a14d768
MS
5089 cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
5090
5091#ifdef WIN32
5092 closesocket(BrowseSocket);
5093#else
5094 close(BrowseSocket);
5095#endif /* WIN32 */
5096
5097 cupsdRemoveSelect(BrowseSocket);
5098 BrowseSocket = -1;
f899b121 5099
7a14d768
MS
5100 BrowseLocalProtocols &= ~BROWSE_CUPS;
5101 BrowseRemoteProtocols &= ~BROWSE_CUPS;
f899b121 5102 }
5103
5104 return;
5105 }
5106
5107 packet[bytes] = '\0';
5108
5109 /*
5110 * If we're about to sleep, ignore incoming browse packets.
5111 */
5112
5113 if (Sleeping)
5114 return;
5115
5116 /*
5117 * Figure out where it came from...
5118 */
5119
5120#ifdef AF_INET6
5121 if (srcaddr.addr.sa_family == AF_INET6)
5122 {
5123 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
5124 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
5125 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
5126 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
5127 }
5128 else
5129#endif /* AF_INET6 */
5130 {
5131 address[0] = 0;
5132 address[1] = 0;
5133 address[2] = 0;
5134 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
5135 }
5136
5137 if (HostNameLookups)
5138 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
5139 else
5140 httpAddrString(&srcaddr, srcname, sizeof(srcname));
5141
5142 len = strlen(srcname);
5143
5144 /*
5145 * Do ACL stuff...
5146 */
5147
5148 if (BrowseACL)
5149 {
5150 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
5151 {
5152 /*
5153 * Access from localhost (127.0.0.1) is always allowed...
5154 */
5155
5bd77a73 5156 auth = CUPSD_AUTH_ALLOW;
f899b121 5157 }
5158 else
5159 {
5160 /*
5161 * Do authorization checks on the domain/address...
5162 */
5163
5164 switch (BrowseACL->order_type)
5165 {
5166 default :
5bd77a73 5167 auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
f899b121 5168 break;
5169
5bd77a73
MS
5170 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
5171 auth = CUPSD_AUTH_ALLOW;
f899b121 5172
5173 if (cupsdCheckAuth(address, srcname, len,
5174 BrowseACL->num_deny, BrowseACL->deny))
5bd77a73 5175 auth = CUPSD_AUTH_DENY;
f899b121 5176
5177 if (cupsdCheckAuth(address, srcname, len,
5178 BrowseACL->num_allow, BrowseACL->allow))
5bd77a73 5179 auth = CUPSD_AUTH_ALLOW;
f899b121 5180 break;
5181
5bd77a73
MS
5182 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
5183 auth = CUPSD_AUTH_DENY;
f899b121 5184
5185 if (cupsdCheckAuth(address, srcname, len,
5186 BrowseACL->num_allow, BrowseACL->allow))
5bd77a73 5187 auth = CUPSD_AUTH_ALLOW;
f899b121 5188
5189 if (cupsdCheckAuth(address, srcname, len,
5190 BrowseACL->num_deny, BrowseACL->deny))
5bd77a73 5191 auth = CUPSD_AUTH_DENY;
f899b121 5192 break;
5193 }
5194 }
5195 }
5196 else
5bd77a73 5197 auth = CUPSD_AUTH_ALLOW;
f899b121 5198
5bd77a73 5199 if (auth == CUPSD_AUTH_DENY)
f899b121 5200 {
5201 cupsdLogMessage(CUPSD_LOG_DEBUG,
5202 "update_cups_browse: Refused %d bytes from %s", bytes,
5203 srcname);
5204 return;
5205 }
5206
5207 cupsdLogMessage(CUPSD_LOG_DEBUG2,
5208 "update_cups_browse: (%d bytes from %s) %s", bytes,
5209 srcname, packet);
5210
5211 /*
5212 * Parse packet...
5213 */
5214
5215 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
5216 {
5217 cupsdLogMessage(CUPSD_LOG_WARN,
5218 "update_cups_browse: Garbled browse packet - %s", packet);
5219 return;
5220 }
5221
5222 strcpy(location, "Location Unknown");
5223 strcpy(info, "No Information Available");
5224 make_model[0] = '\0';
5225 num_attrs = 0;
5226 attrs = NULL;
5227
5228 if ((pptr = strchr(packet, '\"')) != NULL)
5229 {
5230 /*
5231 * Have extended information; can't use sscanf for it because not all
5232 * sscanf's allow empty strings with %[^\"]...
5233 */
5234
5235 for (i = 0, pptr ++;
5236 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
5237 i ++, pptr ++)
5238 location[i] = *pptr;
5239
5240 if (i)
5241 location[i] = '\0';
5242
5243 if (*pptr == '\"')
5244 pptr ++;
5245
5246 while (*pptr && isspace(*pptr & 255))
5247 pptr ++;
5248
5249 if (*pptr == '\"')
5250 {
5251 for (i = 0, pptr ++;
5252 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
5253 i ++, pptr ++)
5254 info[i] = *pptr;
5255
5256 info[i] = '\0';
5257
5258 if (*pptr == '\"')
5259 pptr ++;
5260
5261 while (*pptr && isspace(*pptr & 255))
5262 pptr ++;
5263
5264 if (*pptr == '\"')
5265 {
5266 for (i = 0, pptr ++;
5267 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
5268 i ++, pptr ++)
5269 make_model[i] = *pptr;
5270
5271 if (*pptr == '\"')
5272 pptr ++;
5273
5274 make_model[i] = '\0';
5275
5276 if (*pptr)
5277 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
5278 }
5279 }
5280 }
5281
5282 DEBUG_puts(packet);
5283 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
5284 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
5285 type, state, uri, location, info, make_model));
5286
5287 /*
5288 * Pull the URI apart to see if this is a local or remote printer...
5289 */
5290
5291 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
5292 {
5293 cupsFreeOptions(num_attrs, attrs);
5294 return;
5295 }
5296
5297 /*
5298 * Do relaying...
5299 */
5300
5301 for (i = 0; i < NumRelays; i ++)
5302 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
5303 if (sendto(BrowseSocket, packet, bytes, 0,
5304 (struct sockaddr *)&(Relays[i].to),
5305 httpAddrLength(&(Relays[i].to))) <= 0)
5306 {
5307 cupsdLogMessage(CUPSD_LOG_ERROR,
5308 "update_cups_browse: sendto failed for relay %d - %s.",
5309 i + 1, strerror(errno));
5310 cupsFreeOptions(num_attrs, attrs);
5311 return;
5312 }
5313
5314 /*
5315 * Process the browse data...
5316 */
5317
5318 process_browse_data(uri, host, resource, (cups_ptype_t)type,
5319 (ipp_pstate_t)state, location, info, make_model,
5320 num_attrs, attrs);
5321}
5322
5323
2e4ff8af
MS
5324/*
5325 * 'update_lpd()' - Update the LPD configuration as needed.
5326 */
5327
5328static void
5329update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
5330{
5331 if (!LPDConfigFile)
5332 return;
5333
a603edef
MS
5334#ifdef __APPLE__
5335 /*
5336 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
5337 * setting for backwards-compatibility.
5338 */
5339
5340 if (onoff && !get_hostconfig("CUPS_LPD"))
5341 onoff = 0;
5342#endif /* __APPLE__ */
5343
2e4ff8af
MS
5344 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
5345 {
5346 /*
5347 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
5348 */
5349
5350 char newfile[1024]; /* New cups-lpd.N file */
5351 cups_file_t *ofp, /* Original file pointer */
5352 *nfp; /* New file pointer */
5353 char line[1024]; /* Line from file */
5354
5355
5356 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
5357
5358 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
5359 {
5360 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5361 LPDConfigFile + 9, strerror(errno));
5362 return;
5363 }
5364
5365 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5366 {
5367 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5368 newfile, strerror(errno));
5369 cupsFileClose(ofp);
5370 return;
5371 }
5372
5373 /*
5374 * Copy all of the lines from the cups-lpd file...
5375 */
5376
5377 while (cupsFileGets(ofp, line, sizeof(line)))
5378 {
5379 if (line[0] == '{')
5380 {
5381 cupsFilePrintf(nfp, "%s\n", line);
5382 snprintf(line, sizeof(line), "\tdisable = %s",
5383 onoff ? "no" : "yes");
5384 }
568fa3fa
MS
5385 else if (!strstr(line, "disable ="))
5386 cupsFilePrintf(nfp, "%s\n", line);
2e4ff8af
MS
5387 }
5388
5389 cupsFileClose(nfp);
5390 cupsFileClose(ofp);
5391 rename(newfile, LPDConfigFile + 9);
5392 }
568fa3fa 5393#ifdef __APPLE__
2e4ff8af
MS
5394 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
5395 {
5396 /*
5397 * Enable/disable LPD via the launchctl command...
5398 */
5399
5400 char *argv[5], /* Arguments for command */
5401 *envp[MAX_ENV]; /* Environment for command */
5402 int pid; /* Process ID */
5403
5404
5405 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
5406 argv[0] = (char *)"launchctl";
5407 argv[1] = (char *)(onoff ? "load" : "unload");
5408 argv[2] = (char *)"-w";
5409 argv[3] = LPDConfigFile + 10;
5410 argv[4] = NULL;
5411
a4924f6c 5412 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
38e73f87 5413 NULL, NULL, &pid);
2e4ff8af 5414 }
568fa3fa
MS
5415#endif /* __APPLE__ */
5416 else
5417 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
2e4ff8af
MS
5418}
5419
5420
f899b121 5421/*
5422 * 'update_polling()' - Read status messages from the poll daemons.
5423 */
5424
5425static void
5426update_polling(void)
5427{
5428 char *ptr, /* Pointer to end of line in buffer */
5429 message[1024]; /* Pointer to message text */
5430 int loglevel; /* Log level for message */
5431
5432
5433 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
5434 message, sizeof(message))) != NULL)
f0ab5bff
MS
5435 {
5436 if (loglevel == CUPSD_LOG_INFO)
5437 cupsdLogMessage(CUPSD_LOG_INFO, "%s", message);
5438
f899b121 5439 if (!strchr(PollStatusBuffer->buffer, '\n'))
5440 break;
f0ab5bff 5441 }
f899b121 5442
5443 if (ptr == NULL && !PollStatusBuffer->bufused)
5444 {
5445 /*
5446 * All polling processes have died; stop polling...
5447 */
5448
5449 cupsdLogMessage(CUPSD_LOG_ERROR,
5450 "update_polling: all polling processes have exited!");
5451 cupsdStopPolling();
5452 }
5453}
5454
5455
5456/*
2e4ff8af
MS
5457 * 'update_smb()' - Update the SMB configuration as needed.
5458 */
5459
5460static void
5461update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
5462{
5463 if (!SMBConfigFile)
5464 return;
5465
5466 if (!strncmp(SMBConfigFile, "samba:///", 9))
5467 {
5468 /*
5469 * Enable/disable SMB via the specified smb.conf config file...
5470 */
5471
5472 char newfile[1024]; /* New smb.conf.N file */
5473 cups_file_t *ofp, /* Original file pointer */
5474 *nfp; /* New file pointer */
5475 char line[1024]; /* Line from file */
5476 int in_printers; /* In [printers] section? */
5477
5478
5479 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
5480
5481 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
5482 {
5483 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5484 SMBConfigFile + 8, strerror(errno));
5485 return;
5486 }
5487
5488 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5489 {
5490 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5491 newfile, strerror(errno));
5492 cupsFileClose(ofp);
5493 return;
5494 }
5495
5496 /*
5497 * Copy all of the lines from the smb.conf file...
5498 */
5499
5500 in_printers = 0;
5501
5502 while (cupsFileGets(ofp, line, sizeof(line)))
5503 {
5504 if (in_printers && strstr(line, "printable ="))
5505 snprintf(line, sizeof(line), " printable = %s",
5506 onoff ? "yes" : "no");
5507
5508 cupsFilePrintf(nfp, "%s\n", line);
5509
5510 if (line[0] == '[')
5511 in_printers = !strcmp(line, "[printers]");
5512 }
5513
5514 cupsFileClose(nfp);
5515 cupsFileClose(ofp);
5516 rename(newfile, SMBConfigFile + 8);
5517 }
568fa3fa
MS
5518 else
5519 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
2e4ff8af
MS
5520}
5521
5522
5523/*
b19ccc9e 5524 * End of "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $".
ef416fc2 5525 */