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