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