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