]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/dirsvc.c
Import CUPS 1.4svn-r7908.
[thirdparty/cups.git] / scheduler / dirsvc.c
1 /*
2 * "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z 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 return;
1426 }
1427
1428 /*
1429 * Bind the socket to browse port...
1430 */
1431
1432 memset(&addr, 0, sizeof(addr));
1433 addr.sin_addr.s_addr = htonl(INADDR_ANY);
1434 addr.sin_family = AF_INET;
1435 addr.sin_port = htons(BrowsePort);
1436
1437 if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
1438 {
1439 cupsdLogMessage(CUPSD_LOG_ERROR,
1440 "Unable to bind broadcast socket - %s.",
1441 strerror(errno));
1442
1443 #ifdef WIN32
1444 closesocket(BrowseSocket);
1445 #else
1446 close(BrowseSocket);
1447 #endif /* WIN32 */
1448
1449 BrowseSocket = -1;
1450 BrowseLocalProtocols &= ~BROWSE_CUPS;
1451 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1452 return;
1453 }
1454 }
1455
1456 /*
1457 * Set the "broadcast" flag...
1458 */
1459
1460 val = 1;
1461 if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
1462 {
1463 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
1464 strerror(errno));
1465
1466 #ifdef WIN32
1467 closesocket(BrowseSocket);
1468 #else
1469 close(BrowseSocket);
1470 #endif /* WIN32 */
1471
1472 BrowseSocket = -1;
1473 BrowseLocalProtocols &= ~BROWSE_CUPS;
1474 BrowseRemoteProtocols &= ~BROWSE_CUPS;
1475 return;
1476 }
1477
1478 /*
1479 * Close the socket on exec...
1480 */
1481
1482 fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC);
1483
1484 /*
1485 * Finally, add the socket to the input selection set as needed...
1486 */
1487
1488 if (BrowseRemoteProtocols & BROWSE_CUPS)
1489 {
1490 /*
1491 * We only listen if we want remote printers...
1492 */
1493
1494 cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
1495 NULL, NULL);
1496 }
1497 }
1498 else
1499 BrowseSocket = -1;
1500
1501 #ifdef HAVE_DNSSD
1502 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_DNSSD)
1503 {
1504 DNSServiceErrorType error; /* Error from service creation */
1505 cupsd_listener_t *lis; /* Current listening socket */
1506
1507
1508 /*
1509 * First create a "master" connection for all registrations...
1510 */
1511
1512 if ((error = DNSServiceCreateConnection(&DNSSDRef))
1513 != kDNSServiceErr_NoError)
1514 cupsdLogMessage(CUPSD_LOG_ERROR,
1515 "Unable to create master DNS-SD reference: %d", error);
1516 else
1517 {
1518 /*
1519 * Add the master connection to the select list...
1520 */
1521
1522 cupsdAddSelect(DNSServiceRefSockFD(DNSSDRef),
1523 (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
1524
1525 /*
1526 * Then get the port we use for registrations. If we are not listening
1527 * on any non-local ports, there is no sense sharing local printers via
1528 * Bonjour...
1529 */
1530
1531 DNSSDPort = 0;
1532
1533 for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
1534 lis;
1535 lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
1536 {
1537 if (httpAddrLocalhost(&(lis->address)))
1538 continue;
1539
1540 if (lis->address.addr.sa_family == AF_INET)
1541 {
1542 DNSSDPort = ntohs(lis->address.ipv4.sin_port);
1543 break;
1544 }
1545 else if (lis->address.addr.sa_family == AF_INET6)
1546 {
1547 DNSSDPort = ntohs(lis->address.ipv6.sin6_port);
1548 break;
1549 }
1550 }
1551
1552 /*
1553 * Create an array to track the printers we share...
1554 */
1555
1556 if (BrowseRemoteProtocols & BROWSE_DNSSD)
1557 DNSSDPrinters = cupsArrayNew((cups_array_func_t)dnssdComparePrinters,
1558 NULL);
1559
1560 /*
1561 * Set the computer name and register the web interface...
1562 */
1563
1564 cupsdUpdateDNSSDName();
1565 }
1566 }
1567 #endif /* HAVE_DNSSD */
1568
1569 #ifdef HAVE_LIBSLP
1570 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP)
1571 {
1572 /*
1573 * Open SLP handle...
1574 */
1575
1576 if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
1577 {
1578 cupsdLogMessage(CUPSD_LOG_ERROR,
1579 "Unable to open an SLP handle; disabling SLP browsing!");
1580 BrowseLocalProtocols &= ~BROWSE_SLP;
1581 BrowseRemoteProtocols &= ~BROWSE_SLP;
1582 }
1583
1584 BrowseSLPRefresh = 0;
1585 }
1586 else
1587 BrowseSLPHandle = NULL;
1588 #endif /* HAVE_LIBSLP */
1589
1590 #ifdef HAVE_LDAP
1591 if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
1592 {
1593 if (!BrowseLDAPDN)
1594 {
1595 cupsdLogMessage(CUPSD_LOG_ERROR,
1596 "Need to set BrowseLDAPDN to use LDAP browsing!");
1597 BrowseLocalProtocols &= ~BROWSE_LDAP;
1598 BrowseRemoteProtocols &= ~BROWSE_LDAP;
1599 }
1600 else
1601 {
1602 /* Open LDAP handle... */
1603 BrowseLDAPHandle = ldap_connect();
1604 }
1605
1606 BrowseLDAPRefresh = 0;
1607 }
1608 #endif /* HAVE_LDAP */
1609
1610 /*
1611 * Enable LPD and SMB printer sharing as needed through external programs...
1612 */
1613
1614 if (BrowseLocalProtocols & BROWSE_LPD)
1615 update_lpd(1);
1616
1617 if (BrowseLocalProtocols & BROWSE_SMB)
1618 update_smb(1);
1619
1620 /*
1621 * Register the individual printers
1622 */
1623
1624 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1625 p;
1626 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1627 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1628 cupsdRegisterPrinter(p);
1629 }
1630
1631
1632 /*
1633 * 'cupsdStartPolling()' - Start polling servers as needed.
1634 */
1635
1636 void
1637 cupsdStartPolling(void)
1638 {
1639 int i; /* Looping var */
1640 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1641 char polld[1024]; /* Poll daemon path */
1642 char sport[255]; /* Server port */
1643 char bport[255]; /* Browser port */
1644 char interval[255]; /* Poll interval */
1645 int statusfds[2]; /* Status pipe */
1646 char *argv[6]; /* Arguments */
1647 char *envp[100]; /* Environment */
1648
1649
1650 /*
1651 * Don't do anything if we aren't polling...
1652 */
1653
1654 if (NumPolled == 0 || BrowseSocket < 0)
1655 {
1656 PollPipe = -1;
1657 PollStatusBuffer = NULL;
1658 return;
1659 }
1660
1661 /*
1662 * Setup string arguments for polld, port and interval options.
1663 */
1664
1665 snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin);
1666
1667 sprintf(bport, "%d", BrowsePort);
1668
1669 if (BrowseInterval)
1670 sprintf(interval, "%d", BrowseInterval);
1671 else
1672 strcpy(interval, "30");
1673
1674 argv[0] = "cups-polld";
1675 argv[2] = sport;
1676 argv[3] = interval;
1677 argv[4] = bport;
1678 argv[5] = NULL;
1679
1680 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1681
1682 /*
1683 * Create a pipe that receives the status messages from each
1684 * polling daemon...
1685 */
1686
1687 if (cupsdOpenPipe(statusfds))
1688 {
1689 cupsdLogMessage(CUPSD_LOG_ERROR,
1690 "Unable to create polling status pipes - %s.",
1691 strerror(errno));
1692 PollPipe = -1;
1693 PollStatusBuffer = NULL;
1694 return;
1695 }
1696
1697 PollPipe = statusfds[0];
1698 PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]");
1699
1700 /*
1701 * Run each polling daemon, redirecting stderr to the polling pipe...
1702 */
1703
1704 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1705 {
1706 sprintf(sport, "%d", pollp->port);
1707
1708 argv[1] = pollp->hostname;
1709
1710 if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
1711 0, DefaultProfile, &(pollp->pid)) < 0)
1712 {
1713 cupsdLogMessage(CUPSD_LOG_ERROR,
1714 "cupsdStartPolling: Unable to fork polling daemon - %s",
1715 strerror(errno));
1716 pollp->pid = 0;
1717 break;
1718 }
1719 else
1720 cupsdLogMessage(CUPSD_LOG_DEBUG,
1721 "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d",
1722 pollp->hostname, pollp->port, pollp->pid);
1723 }
1724
1725 close(statusfds[1]);
1726
1727 /*
1728 * Finally, add the pipe to the input selection set...
1729 */
1730
1731 cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
1732 }
1733
1734
1735 /*
1736 * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information.
1737 */
1738
1739 void
1740 cupsdStopBrowsing(void)
1741 {
1742 cupsd_printer_t *p; /* Current printer */
1743
1744
1745 if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols))
1746 return;
1747
1748 /*
1749 * De-register the individual printers
1750 */
1751
1752 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
1753 p;
1754 p = (cupsd_printer_t *)cupsArrayNext(Printers))
1755 if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
1756 cupsdDeregisterPrinter(p, 1);
1757
1758 /*
1759 * Shut down browsing sockets...
1760 */
1761
1762 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) &&
1763 BrowseSocket >= 0)
1764 {
1765 /*
1766 * Close the socket and remove it from the input selection set.
1767 */
1768
1769 #ifdef WIN32
1770 closesocket(BrowseSocket);
1771 #else
1772 close(BrowseSocket);
1773 #endif /* WIN32 */
1774
1775 cupsdRemoveSelect(BrowseSocket);
1776 BrowseSocket = -1;
1777 }
1778
1779 #ifdef HAVE_DNSSD
1780 if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
1781 {
1782 if (WebIFRef)
1783 {
1784 DNSServiceRefDeallocate(WebIFRef);
1785 WebIFRef = NULL;
1786 }
1787
1788 if (RemoteRef)
1789 {
1790 DNSServiceRefDeallocate(RemoteRef);
1791 RemoteRef = NULL;
1792 }
1793
1794 cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDRef));
1795
1796 DNSServiceRefDeallocate(DNSSDRef);
1797 DNSSDRef = NULL;
1798
1799 cupsArrayDelete(DNSSDPrinters);
1800 DNSSDPrinters = NULL;
1801
1802 DNSSDPort = 0;
1803 }
1804 #endif /* HAVE_DNSSD */
1805
1806 #ifdef HAVE_LIBSLP
1807 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) &&
1808 BrowseSLPHandle)
1809 {
1810 /*
1811 * Close SLP handle...
1812 */
1813
1814 SLPClose(BrowseSLPHandle);
1815 BrowseSLPHandle = NULL;
1816 }
1817 #endif /* HAVE_LIBSLP */
1818
1819 #ifdef HAVE_LDAP
1820 if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
1821 BrowseLDAPHandle)
1822 {
1823 ldap_dereg_ou(ServerName, BrowseLDAPDN);
1824 ldap_disconnect(BrowseLDAPHandle);
1825 BrowseLDAPHandle = NULL;
1826 }
1827 #endif /* HAVE_OPENLDAP */
1828
1829 /*
1830 * Disable LPD and SMB printer sharing as needed through external programs...
1831 */
1832
1833 if (BrowseLocalProtocols & BROWSE_LPD)
1834 update_lpd(0);
1835
1836 if (BrowseLocalProtocols & BROWSE_SMB)
1837 update_smb(0);
1838 }
1839
1840
1841 /*
1842 * 'cupsdStopPolling()' - Stop polling servers as needed.
1843 */
1844
1845 void
1846 cupsdStopPolling(void)
1847 {
1848 int i; /* Looping var */
1849 cupsd_dirsvc_poll_t *pollp; /* Current polling server */
1850
1851
1852 if (PollPipe >= 0)
1853 {
1854 cupsdStatBufDelete(PollStatusBuffer);
1855 close(PollPipe);
1856
1857 cupsdRemoveSelect(PollPipe);
1858
1859 PollPipe = -1;
1860 PollStatusBuffer = NULL;
1861 }
1862
1863 for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++)
1864 if (pollp->pid)
1865 cupsdEndProcess(pollp->pid, 0);
1866 }
1867
1868
1869 #ifdef HAVE_DNSSD
1870 /*
1871 * 'cupsdUpdateDNSSDName()' - Update the computer name we use for browsing...
1872 */
1873
1874 void
1875 cupsdUpdateDNSSDName(void)
1876 {
1877 DNSServiceErrorType error; /* Error from service creation */
1878 char webif[1024]; /* Web interface share name */
1879 #ifdef HAVE_COREFOUNDATION_H
1880 CFStringRef nameRef; /* Computer name CFString */
1881 char nameBuffer[1024]; /* C-string buffer */
1882 CFStringEncoding nameEncoding; /* Computer name encoding */
1883 #endif /* HAVE_COREFOUNDATION_H */
1884
1885
1886 /*
1887 * Only share the web interface and printers when non-local listening is
1888 * enabled...
1889 */
1890
1891 if (!DNSSDPort)
1892 return;
1893
1894 /*
1895 * Get the computer name as a c-string...
1896 */
1897
1898 #ifdef HAVE_COREFOUNDATION_H
1899 cupsdClearString(&DNSSDName);
1900
1901 if ((nameRef = SCDynamicStoreCopyComputerName(NULL,
1902 &nameEncoding)) != NULL)
1903 {
1904 if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
1905 kCFStringEncodingUTF8))
1906 cupsdSetString(&DNSSDName, nameBuffer);
1907
1908 CFRelease(nameRef);
1909 }
1910
1911 #else
1912 cupsdSetString(&DNSSDName, ServerName);
1913 #endif /* HAVE_COREFOUNDATION_H */
1914
1915 /*
1916 * Then (re)register the web interface...
1917 */
1918
1919 if (DNSSDName)
1920 snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDName);
1921 else
1922 strlcpy(webif, "CUPS Web Interface", sizeof(webif));
1923
1924 if (WebIFRef)
1925 DNSServiceRefDeallocate(WebIFRef);
1926
1927 WebIFRef = DNSSDRef;
1928 if ((error = DNSServiceRegister(&WebIFRef,
1929 kDNSServiceFlagsShareConnection,
1930 0, webif, "_http._tcp", NULL,
1931 NULL, htons(DNSSDPort), 7,
1932 "\006path=/", dnssdRegisterCallback,
1933 NULL)) != kDNSServiceErr_NoError)
1934 cupsdLogMessage(CUPSD_LOG_ERROR,
1935 "DNS-SD web interface registration failed: %d", error);
1936 }
1937 #endif /* HAVE_DNSSD */
1938
1939
1940 #ifdef HAVE_LDAP
1941 /*
1942 * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
1943 */
1944
1945 void
1946 cupsdUpdateLDAPBrowse(void)
1947 {
1948 char uri[HTTP_MAX_URI], /* Printer URI */
1949 host[HTTP_MAX_URI], /* Hostname */
1950 resource[HTTP_MAX_URI], /* Resource path */
1951 location[1024], /* Printer location */
1952 info[1024], /* Printer information */
1953 make_model[1024], /* Printer make and model */
1954 type_num[30]; /* Printer type number */
1955 int type; /* Printer type */
1956 int rc; /* LDAP status */
1957 int limit; /* Size limit */
1958 LDAPMessage *res, /* LDAP search results */
1959 *e; /* Current entry from search */
1960
1961 cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
1962
1963 BrowseLDAPRefresh = time(NULL) + BrowseInterval;
1964
1965 /*
1966 * Reconnect if LDAP Handle is invalid...
1967 */
1968
1969 if (! BrowseLDAPHandle)
1970 {
1971 ldap_reconnect();
1972 return;
1973 }
1974
1975 /*
1976 * Search for cups printers in LDAP directory...
1977 */
1978
1979 rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
1980 "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
1981
1982 /*
1983 * If ldap search was successfull then exit function
1984 * and temporary disable LDAP updates...
1985 */
1986
1987 if (rc != LDAP_SUCCESS)
1988 {
1989 if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
1990 {
1991 BrowseLDAPUpdate = FALSE;
1992 cupsdLogMessage(CUPSD_LOG_INFO,
1993 "LDAP update temporary disabled");
1994 }
1995 return;
1996 }
1997
1998 /*
1999 * If LDAP updates were disabled, we will reenable them...
2000 */
2001
2002 if (! BrowseLDAPUpdate)
2003 {
2004 BrowseLDAPUpdate = TRUE;
2005 cupsdLogMessage(CUPSD_LOG_INFO,
2006 "LDAP update enabled");
2007 }
2008
2009 /*
2010 * Count LDAP entries and return if no entry exist...
2011 */
2012
2013 limit = ldap_count_entries(BrowseLDAPHandle, res);
2014 cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
2015 if (limit < 1)
2016 {
2017 ldap_freeres(res);
2018 return;
2019 }
2020
2021 /*
2022 * Loop through the available printers...
2023 */
2024
2025 for (e = ldap_first_entry(BrowseLDAPHandle, res);
2026 e;
2027 e = ldap_next_entry(BrowseLDAPHandle, e))
2028 {
2029 /*
2030 * Get the required values from this entry...
2031 */
2032
2033 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2034 "printerDescription", info, sizeof(info)) == -1)
2035 continue;
2036
2037 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2038 "printerLocation", location, sizeof(location)) == -1)
2039 continue;
2040
2041 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2042 "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
2043 continue;
2044
2045 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2046 "printerType", type_num, sizeof(type_num)) == -1)
2047 continue;
2048
2049 type = atoi(type_num);
2050
2051 if (ldap_getval_firststring(BrowseLDAPHandle, e,
2052 "printerURI", uri, sizeof(uri)) == -1)
2053 continue;
2054
2055 /*
2056 * Process the entry as browse data...
2057 */
2058
2059 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2060 process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
2061 location, info, make_model, 0, NULL);
2062
2063 }
2064
2065 ldap_freeres(res);
2066 }
2067 #endif /* HAVE_LDAP */
2068
2069
2070 #ifdef HAVE_LIBSLP
2071 /*
2072 * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
2073 */
2074
2075 void
2076 cupsdUpdateSLPBrowse(void)
2077 {
2078 slpsrvurl_t *s, /* Temporary list of service URLs */
2079 *next; /* Next service in list */
2080 cupsd_printer_t p; /* Printer information */
2081 const char *uri; /* Pointer to printer URI */
2082 char host[HTTP_MAX_URI], /* Host portion of URI */
2083 resource[HTTP_MAX_URI]; /* Resource portion of URI */
2084
2085
2086 /*
2087 * Reset the refresh time...
2088 */
2089
2090 BrowseSLPRefresh = time(NULL) + BrowseInterval;
2091
2092 /*
2093 * Poll for remote printers using SLP...
2094 */
2095
2096 s = NULL;
2097
2098 SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
2099 slp_url_callback, &s);
2100
2101 /*
2102 * Loop through the list of available printers...
2103 */
2104
2105 for (; s; s = next)
2106 {
2107 /*
2108 * Save the "next" pointer...
2109 */
2110
2111 next = s->next;
2112
2113 /*
2114 * Load a cupsd_printer_t structure with the SLP service attributes...
2115 */
2116
2117 SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p);
2118
2119 /*
2120 * Process this printer entry...
2121 */
2122
2123 uri = s->url + SLP_CUPS_SRVLEN + 1;
2124
2125 if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6))
2126 {
2127 /*
2128 * Pull the URI apart to see if this is a local or remote printer...
2129 */
2130
2131 if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
2132 process_browse_data(uri, host, resource, p.type, IPP_PRINTER_IDLE,
2133 p.location, p.info, p.make_model, 0, NULL);
2134 }
2135
2136 /*
2137 * Free this listing...
2138 */
2139
2140 cupsdClearString(&p.info);
2141 cupsdClearString(&p.location);
2142 cupsdClearString(&p.make_model);
2143
2144 free(s);
2145 }
2146 }
2147 #endif /* HAVE_LIBSLP */
2148
2149
2150 /*
2151 * 'dequote()' - Remote quotes from a string.
2152 */
2153
2154 static char * /* O - Dequoted string */
2155 dequote(char *d, /* I - Destination string */
2156 const char *s, /* I - Source string */
2157 int dlen) /* I - Destination length */
2158 {
2159 char *dptr; /* Pointer into destination */
2160
2161
2162 if (s)
2163 {
2164 for (dptr = d, dlen --; *s && dlen > 0; s ++)
2165 if (*s != '\"')
2166 {
2167 *dptr++ = *s;
2168 dlen --;
2169 }
2170
2171 *dptr = '\0';
2172 }
2173 else
2174 *d = '\0';
2175
2176 return (d);
2177 }
2178
2179
2180 #ifdef HAVE_DNSSD
2181 /*
2182 * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
2183 */
2184
2185 static char * /* O - TXT record */
2186 dnssdBuildTxtRecord(
2187 int *txt_len, /* O - TXT record length */
2188 cupsd_printer_t *p, /* I - Printer information */
2189 int for_lpd) /* I - 1 = LPD, 0 = IPP */
2190 {
2191 int i, j; /* Looping vars */
2192 char type_str[32], /* Type to string buffer */
2193 state_str[32], /* State to string buffer */
2194 rp_str[1024], /* Queue name string buffer */
2195 air_str[1024], /* auth-info-required string buffer */
2196 *keyvalue[32][2]; /* Table of key/value pairs */
2197
2198
2199 /*
2200 * Load up the key value pairs...
2201 */
2202
2203 i = 0;
2204
2205 keyvalue[i ][0] = "txtvers";
2206 keyvalue[i++][1] = "1";
2207
2208 keyvalue[i ][0] = "qtotal";
2209 keyvalue[i++][1] = "1";
2210
2211 keyvalue[i ][0] = "rp";
2212 keyvalue[i++][1] = rp_str;
2213 if (for_lpd)
2214 strlcpy(rp_str, p->name, sizeof(rp_str));
2215 else
2216 snprintf(rp_str, sizeof(rp_str), "%s/%s",
2217 (p->type & CUPS_PRINTER_CLASS) ? "classes" : "printers", p->name);
2218
2219 keyvalue[i ][0] = "ty";
2220 keyvalue[i++][1] = p->make_model;
2221
2222 if (p->location && *p->location != '\0')
2223 {
2224 keyvalue[i ][0] = "note";
2225 keyvalue[i++][1] = p->location;
2226 }
2227
2228 keyvalue[i ][0] = "priority";
2229 keyvalue[i++][1] = for_lpd ? "100" : "0";
2230
2231 keyvalue[i ][0] = "product";
2232 keyvalue[i++][1] = p->product ? p->product : "Unknown";
2233
2234 snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PRINTER_REMOTE);
2235 snprintf(state_str, sizeof(state_str), "%d", p->state);
2236
2237 keyvalue[i ][0] = "printer-state";
2238 keyvalue[i++][1] = state_str;
2239
2240 keyvalue[i ][0] = "printer-type";
2241 keyvalue[i++][1] = type_str;
2242
2243 keyvalue[i ][0] = "Transparent";
2244 keyvalue[i++][1] = "T";
2245
2246 keyvalue[i ][0] = "Binary";
2247 keyvalue[i++][1] = "T";
2248
2249 if ((p->type & CUPS_PRINTER_FAX))
2250 {
2251 keyvalue[i ][0] = "Fax";
2252 keyvalue[i++][1] = "T";
2253 }
2254
2255 if ((p->type & CUPS_PRINTER_COLOR))
2256 {
2257 keyvalue[i ][0] = "Color";
2258 keyvalue[i++][1] = "T";
2259 }
2260
2261 if ((p->type & CUPS_PRINTER_DUPLEX))
2262 {
2263 keyvalue[i ][0] = "Duplex";
2264 keyvalue[i++][1] = "T";
2265 }
2266
2267 if ((p->type & CUPS_PRINTER_STAPLE))
2268 {
2269 keyvalue[i ][0] = "Staple";
2270 keyvalue[i++][1] = "T";
2271 }
2272
2273 if ((p->type & CUPS_PRINTER_COPIES))
2274 {
2275 keyvalue[i ][0] = "Copies";
2276 keyvalue[i++][1] = "T";
2277 }
2278
2279 if ((p->type & CUPS_PRINTER_COLLATE))
2280 {
2281 keyvalue[i ][0] = "Collate";
2282 keyvalue[i++][1] = "T";
2283 }
2284
2285 if ((p->type & CUPS_PRINTER_PUNCH))
2286 {
2287 keyvalue[i ][0] = "Punch";
2288 keyvalue[i++][1] = "T";
2289 }
2290
2291 if ((p->type & CUPS_PRINTER_BIND))
2292 {
2293 keyvalue[i ][0] = "Bind";
2294 keyvalue[i++][1] = "T";
2295 }
2296
2297 if ((p->type & CUPS_PRINTER_SORT))
2298 {
2299 keyvalue[i ][0] = "Sort";
2300 keyvalue[i++][1] = "T";
2301 }
2302
2303 keyvalue[i ][0] = "pdl";
2304 keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
2305
2306 if (p->num_auth_info_required)
2307 {
2308 char *air = air_str; /* Pointer into string */
2309
2310
2311 for (j = 0; j < p->num_auth_info_required; j ++)
2312 {
2313 if (air >= (air_str + sizeof(air_str) - 2))
2314 break;
2315
2316 if (j)
2317 *air++ = ',';
2318
2319 strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
2320 air += strlen(air);
2321 }
2322
2323 keyvalue[i ][0] = "air";
2324 keyvalue[i++][1] = air;
2325 }
2326
2327 /*
2328 * Then pack them into a proper txt record...
2329 */
2330
2331 return (dnssdPackTxtRecord(txt_len, keyvalue, i));
2332 }
2333
2334
2335 /*
2336 * 'dnssdComparePrinters()' - Compare the registered names of two printers.
2337 */
2338
2339 static int /* O - Result of comparison */
2340 dnssdComparePrinters(cupsd_printer_t *a,/* I - First printer */
2341 cupsd_printer_t *b)/* I - Second printer */
2342 {
2343 return (strcasecmp(a->reg_name, b->reg_name));
2344 }
2345
2346
2347 /*
2348 * 'dnssdDeregisterPrinter()' - Stop sending broadcast information for a
2349 * printer.
2350 */
2351
2352 static void
2353 dnssdDeregisterPrinter(
2354 cupsd_printer_t *p) /* I - Printer */
2355 {
2356 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdDeregisterPrinter(%s)", p->name);
2357
2358 /*
2359 * Closing the socket deregisters the service
2360 */
2361
2362 if (p->ipp_ref)
2363 {
2364 DNSServiceRefDeallocate(p->ipp_ref);
2365 p->ipp_ref = NULL;
2366 }
2367
2368 cupsArrayRemove(DNSSDPrinters, p);
2369 cupsdClearString(&p->reg_name);
2370
2371 if (p->ipp_txt)
2372 {
2373 /*
2374 * p->ipp_txt is malloc'd, not _cupsStrAlloc'd...
2375 */
2376
2377 free(p->ipp_txt);
2378 p->ipp_txt = NULL;
2379 }
2380 }
2381
2382
2383 /*
2384 * 'dnssdPackTxtRecord()' - Pack an array of key/value pairs into the
2385 * TXT record format.
2386 */
2387
2388 static char * /* O - TXT record */
2389 dnssdPackTxtRecord(int *txt_len, /* O - TXT record length */
2390 char *keyvalue[][2], /* I - Table of key value pairs */
2391 int count) /* I - Items in table */
2392 {
2393 int i; /* Looping var */
2394 int length; /* Length of TXT record */
2395 int length2; /* Length of value */
2396 char *txtRecord; /* TXT record buffer */
2397 char *cursor; /* Looping pointer */
2398
2399
2400 /*
2401 * Calculate the buffer size
2402 */
2403
2404 for (length = i = 0; i < count; i++)
2405 length += 1 + strlen(keyvalue[i][0]) +
2406 (keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0);
2407
2408 /*
2409 * Allocate and fill it
2410 */
2411
2412 txtRecord = malloc(length);
2413 if (txtRecord)
2414 {
2415 *txt_len = length;
2416
2417 for (cursor = txtRecord, i = 0; i < count; i++)
2418 {
2419 /*
2420 * Drop in the p-string style length byte followed by the data
2421 */
2422
2423 length = strlen(keyvalue[i][0]);
2424 length2 = keyvalue[i][1] ? 1 + strlen(keyvalue[i][1]) : 0;
2425
2426 *cursor++ = (unsigned char)(length + length2);
2427
2428 memcpy(cursor, keyvalue[i][0], length);
2429 cursor += length;
2430
2431 if (length2)
2432 {
2433 length2 --;
2434 *cursor++ = '=';
2435 memcpy(cursor, keyvalue[i][1], length2);
2436 cursor += length2;
2437 }
2438 }
2439 }
2440
2441 return (txtRecord);
2442 }
2443
2444
2445 /*
2446 * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
2447 */
2448
2449 static void
2450 dnssdRegisterCallback(
2451 DNSServiceRef sdRef, /* I - DNS Service reference */
2452 DNSServiceFlags flags, /* I - Reserved for future use */
2453 DNSServiceErrorType errorCode, /* I - Error code */
2454 const char *name, /* I - Service name */
2455 const char *regtype, /* I - Service type */
2456 const char *domain, /* I - Domain. ".local" for now */
2457 void *context) /* I - User-defined context */
2458 {
2459 cupsd_printer_t *p = (cupsd_printer_t *)context;
2460 /* Current printer */
2461
2462
2463 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s",
2464 name, regtype, p ? p->name : "Web Interface");
2465
2466 if (errorCode)
2467 {
2468 cupsdLogMessage(CUPSD_LOG_ERROR,
2469 "DNSServiceRegister failed with error %d", (int)errorCode);
2470 return;
2471 }
2472 else if (p && strcasecmp(name, p->reg_name))
2473 {
2474 cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
2475 name, p->name);
2476
2477 cupsArrayRemove(DNSSDPrinters, p);
2478 cupsdSetString(&p->reg_name, name);
2479 cupsArrayAdd(DNSSDPrinters, p);
2480
2481 LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
2482 }
2483 }
2484
2485
2486 /*
2487 * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
2488 * or update the broadcast contents.
2489 */
2490
2491 static void
2492 dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
2493 {
2494 DNSServiceErrorType se; /* dnssd errors */
2495 char *ipp_txt, /* IPP TXT record buffer */
2496 *printer_txt, /* LPD TXT record buffer */
2497 name[1024], /* Service name */
2498 *nameptr; /* Pointer into name */
2499 int ipp_len, /* IPP TXT record length */
2500 printer_len; /* LPD TXT record length */
2501 char resource[1024]; /* Resource path for printer */
2502 const char *regtype; /* Registration type */
2503 const char *domain; /* Registration domain */
2504 cupsd_location_t *location, /* Printer location */
2505 *policy; /* Operation policy for Print-Job */
2506 unsigned address[4]; /* INADDR_ANY address */
2507
2508
2509 cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
2510 !p->ipp_ref ? "new" : "update");
2511
2512 /*
2513 * If per-printer sharing was just disabled make sure we're not
2514 * registered before returning.
2515 */
2516
2517 if (!p->shared)
2518 {
2519 dnssdDeregisterPrinter(p);
2520 return;
2521 }
2522
2523 /*
2524 * The registered name takes the form of "<printer-info> @ <computer name>"...
2525 */
2526
2527 if (p->info && strlen(p->info) > 0)
2528 {
2529 if (DNSSDName)
2530 snprintf(name, sizeof(name), "%s @ %s", p->info, DNSSDName);
2531 else
2532 strlcpy(name, p->info, sizeof(name));
2533 }
2534 else if (DNSSDName)
2535 snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDName);
2536 else
2537 strlcpy(name, p->name, sizeof(name));
2538
2539 /*
2540 * If an existing printer was renamed, unregister it and start over...
2541 */
2542
2543 if (p->reg_name && strcmp(p->reg_name, name))
2544 dnssdDeregisterPrinter(p);
2545
2546 if (!p->reg_name)
2547 {
2548 cupsdSetString(&p->reg_name, name);
2549 cupsArrayAdd(DNSSDPrinters, p);
2550 }
2551
2552 /*
2553 * If 'Allow printing from the Internet' is enabled (i.e. from any address)
2554 * let dnssd decide on the domain, otherwise restrict it to ".local".
2555 */
2556
2557 if (p->type & CUPS_PRINTER_CLASS)
2558 snprintf(resource, sizeof(resource), "/classes/%s", p->name);
2559 else
2560 snprintf(resource, sizeof(resource), "/printers/%s", p->name);
2561
2562 address[0] = address[1] = address[2] = address[3] = 0;
2563 location = cupsdFindBest(resource, HTTP_POST);
2564 policy = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB);
2565
2566 if ((location && !cupsdCheckAccess(address, "", 0, location)) ||
2567 (policy && !cupsdCheckAccess(address, "", 0, policy)))
2568 domain = "local.";
2569 else
2570 domain = NULL;
2571
2572 /*
2573 * Register IPP and (optionally) LPD...
2574 */
2575
2576 ipp_len = 0; /* anti-compiler-warning-code */
2577 ipp_txt = dnssdBuildTxtRecord(&ipp_len, p, 0);
2578
2579 if (!p->ipp_ref)
2580 {
2581 /*
2582 * Initial registration. Use the _fax subtype for fax queues...
2583 */
2584
2585 regtype = (p->type & CUPS_PRINTER_FAX) ? "_fax-ipp._tcp" :
2586 "_ipp._tcp,_cups";
2587
2588 cupsdLogMessage(CUPSD_LOG_DEBUG,
2589 "Registering DNS-SD printer %s with name \"%s\", "
2590 "type \"%s\", and domain \"%s\"", p->name, name, regtype,
2591 domain ? domain : "(null)");
2592
2593 /*
2594 * Register the queue, dropping characters as needed until we succeed...
2595 */
2596
2597 nameptr = name + strlen(name);
2598
2599 do
2600 {
2601 p->ipp_ref = DNSSDRef;
2602 if ((se = DNSServiceRegister(&p->ipp_ref, kDNSServiceFlagsShareConnection,
2603 0, name, regtype, domain, NULL,
2604 htons(DNSSDPort), ipp_len, ipp_txt,
2605 dnssdRegisterCallback,
2606 p)) == kDNSServiceErr_BadParam)
2607 {
2608 /*
2609 * Name is too long, drop trailing characters, taking into account
2610 * UTF-8 encoding...
2611 */
2612
2613 nameptr --;
2614
2615 while (nameptr > name && (*nameptr & 0xc0) == 0x80)
2616 nameptr --;
2617
2618 if (nameptr > name)
2619 *nameptr = '\0';
2620 }
2621 }
2622 while (se == kDNSServiceErr_BadParam && nameptr > name);
2623
2624 if (se == kDNSServiceErr_NoError)
2625 {
2626 p->ipp_txt = ipp_txt;
2627 p->ipp_len = ipp_len;
2628 ipp_txt = NULL;
2629 }
2630 else
2631 cupsdLogMessage(CUPSD_LOG_WARN,
2632 "DNS-SD IPP registration of \"%s\" failed: %d",
2633 p->name, se);
2634 }
2635 else if (ipp_len != p->ipp_len || memcmp(ipp_txt, p->ipp_txt, ipp_len))
2636 {
2637 /*
2638 * Update the existing registration...
2639 */
2640
2641 /* A TTL of 0 means use record's original value (Radar 3176248) */
2642 DNSServiceUpdateRecord(p->ipp_ref, NULL, 0, ipp_len, ipp_txt, 0);
2643
2644 if (p->ipp_txt)
2645 free(p->ipp_txt);
2646
2647 p->ipp_txt = ipp_txt;
2648 p->ipp_len = ipp_len;
2649 ipp_txt = NULL;
2650 }
2651
2652 if (ipp_txt)
2653 free(ipp_txt);
2654
2655 if (BrowseLocalProtocols & BROWSE_LPD)
2656 {
2657 printer_len = 0; /* anti-compiler-warning-code */
2658 printer_txt = dnssdBuildTxtRecord(&printer_len, p, 1);
2659
2660 if (!p->printer_ref)
2661 {
2662 /*
2663 * Initial registration...
2664 */
2665
2666 cupsdLogMessage(CUPSD_LOG_DEBUG,
2667 "Registering DNS-SD printer %s with name \"%s\", "
2668 "type \"_printer._tcp\", and domain \"%s\"", p->name,
2669 name, domain ? domain : "(null)");
2670
2671 p->printer_ref = DNSSDRef;
2672 if ((se = DNSServiceRegister(&p->printer_ref,
2673 kDNSServiceFlagsShareConnection,
2674 0, name, "_printer._tcp", domain, NULL,
2675 htons(515), printer_len, printer_txt,
2676 dnssdRegisterCallback,
2677 p)) == kDNSServiceErr_NoError)
2678 {
2679 p->printer_txt = printer_txt;
2680 p->printer_len = printer_len;
2681 printer_txt = NULL;
2682 }
2683 else
2684 cupsdLogMessage(CUPSD_LOG_WARN,
2685 "DNS-SD LPD registration of \"%s\" failed: %d",
2686 p->name, se);
2687 }
2688 else if (printer_len != p->printer_len ||
2689 memcmp(printer_txt, p->printer_txt, printer_len))
2690 {
2691 /*
2692 * Update the existing registration...
2693 */
2694
2695 /* A TTL of 0 means use record's original value (Radar 3176248) */
2696 DNSServiceUpdateRecord(p->printer_ref, NULL, 0, printer_len,
2697 printer_txt, 0);
2698
2699 if (p->printer_txt)
2700 free(p->printer_txt);
2701
2702 p->printer_txt = printer_txt;
2703 p->printer_len = printer_len;
2704 printer_txt = NULL;
2705 }
2706
2707 if (printer_txt)
2708 free(printer_txt);
2709 }
2710 }
2711
2712
2713 /*
2714 * 'dnssdUpdate()' - Handle DNS-SD queries.
2715 */
2716
2717 static void
2718 dnssdUpdate(void)
2719 {
2720 DNSServiceErrorType sdErr; /* Service discovery error */
2721
2722
2723 if ((sdErr = DNSServiceProcessResult(DNSSDRef)) != kDNSServiceErr_NoError)
2724 cupsdLogMessage(CUPSD_LOG_ERROR,
2725 "DNS Service Discovery registration error %d!",
2726 sdErr);
2727 }
2728 #endif /* HAVE_DNSSD */
2729
2730
2731 #ifdef __APPLE__
2732 /*
2733 * 'get_hostconfig()' - Get an /etc/hostconfig service setting.
2734 */
2735
2736 static int /* O - 1 for YES or AUTOMATIC, 0 for NO */
2737 get_hostconfig(const char *name) /* I - Name of service */
2738 {
2739 cups_file_t *fp; /* Hostconfig file */
2740 char line[1024], /* Line from file */
2741 *ptr; /* Pointer to value */
2742 int state = 1; /* State of service */
2743
2744
2745 /*
2746 * Try opening the /etc/hostconfig file; if we can't open it, assume that
2747 * the service is enabled/auto.
2748 */
2749
2750 if ((fp = cupsFileOpen("/etc/hostconfig", "r")) != NULL)
2751 {
2752 /*
2753 * Read lines from the file until we find the service...
2754 */
2755
2756 while (cupsFileGets(fp, line, sizeof(line)))
2757 {
2758 if (line[0] == '#' || (ptr = strchr(line, '=')) == NULL)
2759 continue;
2760
2761 *ptr++ = '\0';
2762
2763 if (!strcasecmp(line, name))
2764 {
2765 /*
2766 * Found the service, see if it is set to "-NO-"...
2767 */
2768
2769 if (!strncasecmp(ptr, "-NO-", 4))
2770 state = 0;
2771 break;
2772 }
2773 }
2774
2775 cupsFileClose(fp);
2776 }
2777
2778 return (state);
2779 }
2780 #endif /* __APPLE__ */
2781
2782
2783 /*
2784 * 'is_local_queue()' - Determine whether the URI points at a local queue.
2785 */
2786
2787 static int /* O - 1 = local, 0 = remote, -1 = bad URI */
2788 is_local_queue(const char *uri, /* I - Printer URI */
2789 char *host, /* O - Host string */
2790 int hostlen, /* I - Length of host buffer */
2791 char *resource, /* O - Resource string */
2792 int resourcelen) /* I - Length of resource buffer */
2793 {
2794 char scheme[32], /* Scheme portion of URI */
2795 username[HTTP_MAX_URI]; /* Username portion of URI */
2796 int port; /* Port portion of URI */
2797 cupsd_netif_t *iface; /* Network interface */
2798
2799
2800 /*
2801 * Pull the URI apart to see if this is a local or remote printer...
2802 */
2803
2804 if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
2805 username, sizeof(username), host, hostlen, &port,
2806 resource, resourcelen) < HTTP_URI_OK)
2807 return (-1);
2808
2809 DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName));
2810
2811 /*
2812 * Check for local server addresses...
2813 */
2814
2815 if (!strcasecmp(host, ServerName) && port == LocalPort)
2816 return (1);
2817
2818 cupsdNetIFUpdate();
2819
2820 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
2821 iface;
2822 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
2823 if (!strcasecmp(host, iface->hostname) && port == iface->port)
2824 return (1);
2825
2826 /*
2827 * If we get here, the printer is remote...
2828 */
2829
2830 return (0);
2831 }
2832
2833
2834 /*
2835 * 'process_browse_data()' - Process new browse data.
2836 */
2837
2838 static void
2839 process_browse_data(
2840 const char *uri, /* I - URI of printer/class */
2841 const char *host, /* I - Hostname */
2842 const char *resource, /* I - Resource path */
2843 cups_ptype_t type, /* I - Printer type */
2844 ipp_pstate_t state, /* I - Printer state */
2845 const char *location, /* I - Printer location */
2846 const char *info, /* I - Printer information */
2847 const char *make_model, /* I - Printer make and model */
2848 int num_attrs, /* I - Number of attributes */
2849 cups_option_t *attrs) /* I - Attributes */
2850 {
2851 int i; /* Looping var */
2852 int update; /* Update printer attributes? */
2853 char finaluri[HTTP_MAX_URI], /* Final URI for printer */
2854 name[IPP_MAX_NAME], /* Name of printer */
2855 newname[IPP_MAX_NAME], /* New name of printer */
2856 *hptr, /* Pointer into hostname */
2857 *sptr; /* Pointer into ServerName */
2858 const char *shortname; /* Short queue name (queue) */
2859 char local_make_model[IPP_MAX_NAME];
2860 /* Local make and model */
2861 cupsd_printer_t *p; /* Printer information */
2862 const char *ipp_options, /* ipp-options value */
2863 *lease_duration; /* lease-duration value */
2864 int is_class; /* Is this queue a class? */
2865
2866
2867 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2868 "process_browse_data(uri=\"%s\", host=\"%s\", "
2869 "resource=\"%s\", type=%x, state=%d, location=\"%s\", "
2870 "info=\"%s\", make_model=\"%s\", num_attrs=%d, attrs=%p)",
2871 uri, host, resource, type, state,
2872 location ? location : "(nil)", info ? info : "(nil)",
2873 make_model ? make_model : "(nil)", num_attrs, attrs);
2874
2875 /*
2876 * Determine if the URI contains any illegal characters in it...
2877 */
2878
2879 if (strncmp(uri, "ipp://", 6) || !host[0] ||
2880 (strncmp(resource, "/printers/", 10) &&
2881 strncmp(resource, "/classes/", 9)))
2882 {
2883 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad printer URI in browse data: %s", uri);
2884 return;
2885 }
2886
2887 if (strchr(resource, '?') ||
2888 (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) ||
2889 (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/')))
2890 {
2891 cupsdLogMessage(CUPSD_LOG_ERROR, "Bad resource in browse data: %s",
2892 resource);
2893 return;
2894 }
2895
2896 /*
2897 * OK, this isn't a local printer; add any remote options...
2898 */
2899
2900 ipp_options = cupsGetOption("ipp-options", num_attrs, attrs);
2901
2902 if (BrowseRemoteOptions)
2903 {
2904 if (BrowseRemoteOptions[0] == '?')
2905 {
2906 /*
2907 * Override server-supplied options...
2908 */
2909
2910 snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions);
2911 }
2912 else if (ipp_options)
2913 {
2914 /*
2915 * Combine the server and local options...
2916 */
2917
2918 snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options,
2919 BrowseRemoteOptions);
2920 }
2921 else
2922 {
2923 /*
2924 * Just use the local options...
2925 */
2926
2927 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions);
2928 }
2929
2930 uri = finaluri;
2931 }
2932 else if (ipp_options)
2933 {
2934 /*
2935 * Just use the server-supplied options...
2936 */
2937
2938 snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options);
2939 uri = finaluri;
2940 }
2941
2942 /*
2943 * See if we already have it listed in the Printers list, and add it if not...
2944 */
2945
2946 type |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
2947 type &= ~CUPS_PRINTER_IMPLICIT;
2948 update = 0;
2949 hptr = strchr(host, '.');
2950 sptr = strchr(ServerName, '.');
2951 is_class = type & CUPS_PRINTER_CLASS;
2952
2953 if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
2954 {
2955 /*
2956 * Strip the common domain name components...
2957 */
2958
2959 while (hptr != NULL)
2960 {
2961 if (!strcasecmp(hptr, sptr))
2962 {
2963 *hptr = '\0';
2964 break;
2965 }
2966 else
2967 hptr = strchr(hptr + 1, '.');
2968 }
2969 }
2970
2971 if (is_class)
2972 {
2973 /*
2974 * Remote destination is a class...
2975 */
2976
2977 if (!strncmp(resource, "/classes/", 9))
2978 snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
2979 else
2980 return;
2981
2982 shortname = resource + 9;
2983 }
2984 else
2985 {
2986 /*
2987 * Remote destination is a printer...
2988 */
2989
2990 if (!strncmp(resource, "/printers/", 10))
2991 snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
2992 else
2993 return;
2994
2995 shortname = resource + 10;
2996 }
2997
2998 if (hptr && !*hptr)
2999 *hptr = '.'; /* Resource FQDN */
3000
3001 if ((p = cupsdFindDest(name)) == NULL && BrowseShortNames)
3002 {
3003 /*
3004 * Long name doesn't exist, try short name...
3005 */
3006
3007 cupsdLogMessage(CUPSD_LOG_DEBUG, "process_browse_data: %s not found...",
3008 name);
3009
3010 if ((p = cupsdFindDest(shortname)) == NULL)
3011 {
3012 /*
3013 * Short name doesn't exist, use it for this shared queue.
3014 */
3015
3016 cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_browse_data: %s not found...",
3017 shortname);
3018 strlcpy(name, shortname, sizeof(name));
3019 }
3020 else
3021 {
3022 /*
3023 * Short name exists...
3024 */
3025
3026 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3027 "process_browse_data: %s found, type=%x, hostname=%s...",
3028 shortname, p->type, p->hostname ? p->hostname : "(nil)");
3029
3030 if (p->type & CUPS_PRINTER_IMPLICIT)
3031 p = NULL; /* Don't replace implicit classes */
3032 else if (p->hostname && strcasecmp(p->hostname, host))
3033 {
3034 /*
3035 * Short name exists but is for a different host. If this is a remote
3036 * queue, rename it and use the long name...
3037 */
3038
3039 if (p->type & CUPS_PRINTER_REMOTE)
3040 {
3041 cupsdLogMessage(CUPSD_LOG_DEBUG,
3042 "Renamed remote %s \"%s\" to \"%s@%s\"...",
3043 is_class ? "class" : "printer", p->name, p->name,
3044 p->hostname);
3045 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3046 "%s \'%s\' deleted by directory services.",
3047 is_class ? "Class" : "Printer", p->name);
3048
3049 snprintf(newname, sizeof(newname), "%s@%s", p->name, p->hostname);
3050 cupsdRenamePrinter(p, newname);
3051
3052 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3053 "%s \'%s\' added by directory services.",
3054 is_class ? "Class" : "Printer", p->name);
3055 }
3056
3057 /*
3058 * Force creation with long name...
3059 */
3060
3061 p = NULL;
3062 }
3063 }
3064 }
3065 else if (p)
3066 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3067 "process_browse_data: %s found, type=%x, hostname=%s...",
3068 name, p->type, p->hostname ? p->hostname : "(nil)");
3069
3070 if (!p)
3071 {
3072 /*
3073 * Queue doesn't exist; add it...
3074 */
3075
3076 if (is_class)
3077 p = cupsdAddClass(name);
3078 else
3079 p = cupsdAddPrinter(name);
3080
3081 cupsdClearString(&(p->hostname));
3082
3083 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added remote %s \"%s\"...",
3084 is_class ? "class" : "printer", name);
3085
3086 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3087 "%s \'%s\' added by directory services.",
3088 is_class ? "Class" : "Printer", name);
3089
3090 /*
3091 * Force the URI to point to the real server...
3092 */
3093
3094 p->type = type & ~CUPS_PRINTER_REJECTING;
3095 p->accepting = 1;
3096
3097 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
3098 }
3099
3100 if (!p)
3101 return;
3102
3103 if (!p->hostname)
3104 {
3105 /*
3106 * Hostname not set, so this must be a cached remote printer
3107 * that was created for a pending print job...
3108 */
3109
3110 cupsdSetString(&p->hostname, host);
3111 cupsdSetString(&p->uri, uri);
3112 cupsdSetString(&p->device_uri, uri);
3113 update = 1;
3114
3115 cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
3116 }
3117
3118 /*
3119 * Update the state...
3120 */
3121
3122 p->state = state;
3123 p->browse_time = time(NULL);
3124
3125 if ((lease_duration = cupsGetOption("lease-duration", num_attrs,
3126 attrs)) != NULL)
3127 {
3128 /*
3129 * Grab the lease-duration for the browse data; anything less then 1
3130 * second or more than 1 week gets the default BrowseTimeout...
3131 */
3132
3133 i = atoi(lease_duration);
3134 if (i < 1 || i > 604800)
3135 i = BrowseTimeout;
3136
3137 p->browse_expire = p->browse_time + i;
3138 }
3139 else
3140 p->browse_expire = p->browse_time + BrowseTimeout;
3141
3142 if (type & CUPS_PRINTER_REJECTING)
3143 {
3144 type &= ~CUPS_PRINTER_REJECTING;
3145
3146 if (p->accepting)
3147 {
3148 update = 1;
3149 p->accepting = 0;
3150 }
3151 }
3152 else if (!p->accepting)
3153 {
3154 update = 1;
3155 p->accepting = 1;
3156 }
3157
3158 if (p->type != type)
3159 {
3160 p->type = type;
3161 update = 1;
3162 }
3163
3164 if (location && (!p->location || strcmp(p->location, location)))
3165 {
3166 cupsdSetString(&p->location, location);
3167 update = 1;
3168 }
3169
3170 if (info && (!p->info || strcmp(p->info, info)))
3171 {
3172 cupsdSetString(&p->info, info);
3173 update = 1;
3174
3175 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3176 }
3177
3178 if (!make_model || !make_model[0])
3179 {
3180 if (is_class)
3181 snprintf(local_make_model, sizeof(local_make_model),
3182 "Remote Class on %s", host);
3183 else
3184 snprintf(local_make_model, sizeof(local_make_model),
3185 "Remote Printer on %s", host);
3186 }
3187 else
3188 snprintf(local_make_model, sizeof(local_make_model),
3189 "%s on %s", make_model, host);
3190
3191 if (!p->make_model || strcmp(p->make_model, local_make_model))
3192 {
3193 cupsdSetString(&p->make_model, local_make_model);
3194 update = 1;
3195 }
3196
3197 if (p->num_options)
3198 {
3199 if (!update && !(type & CUPS_PRINTER_DELETE))
3200 {
3201 /*
3202 * See if we need to update the attributes...
3203 */
3204
3205 if (p->num_options != num_attrs)
3206 update = 1;
3207 else
3208 {
3209 for (i = 0; i < num_attrs; i ++)
3210 if (strcmp(attrs[i].name, p->options[i].name) ||
3211 (!attrs[i].value != !p->options[i].value) ||
3212 (attrs[i].value && strcmp(attrs[i].value, p->options[i].value)))
3213 {
3214 update = 1;
3215 break;
3216 }
3217 }
3218 }
3219
3220 /*
3221 * Free the old options...
3222 */
3223
3224 cupsFreeOptions(p->num_options, p->options);
3225 }
3226
3227 p->num_options = num_attrs;
3228 p->options = attrs;
3229
3230 if (type & CUPS_PRINTER_DELETE)
3231 {
3232 cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL,
3233 "%s \'%s\' deleted by directory services.",
3234 is_class ? "Class" : "Printer", p->name);
3235
3236 cupsdExpireSubscriptions(p, NULL);
3237
3238 cupsdDeletePrinter(p, 1);
3239 cupsdUpdateImplicitClasses();
3240 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3241 }
3242 else if (update)
3243 {
3244 cupsdSetPrinterAttrs(p);
3245 cupsdUpdateImplicitClasses();
3246 }
3247
3248 /*
3249 * See if we have a default printer... If not, make the first network
3250 * default printer the default.
3251 */
3252
3253 if (DefaultPrinter == NULL && Printers != NULL && UseNetworkDefault)
3254 {
3255 /*
3256 * Find the first network default printer and use it...
3257 */
3258
3259 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
3260 p;
3261 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3262 if (p->type & CUPS_PRINTER_DEFAULT)
3263 {
3264 DefaultPrinter = p;
3265 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3266 break;
3267 }
3268 }
3269
3270 /*
3271 * Do auto-classing if needed...
3272 */
3273
3274 process_implicit_classes();
3275 }
3276
3277
3278 /*
3279 * 'process_implicit_classes()' - Create/update implicit classes as needed.
3280 */
3281
3282 static void
3283 process_implicit_classes(void)
3284 {
3285 int i; /* Looping var */
3286 int update; /* Update printer attributes? */
3287 char name[IPP_MAX_NAME], /* Name of printer */
3288 *hptr; /* Pointer into hostname */
3289 cupsd_printer_t *p, /* Printer information */
3290 *pclass, /* Printer class */
3291 *first; /* First printer in class */
3292 int offset, /* Offset of name */
3293 len; /* Length of name */
3294
3295
3296 if (!ImplicitClasses || !Printers)
3297 return;
3298
3299 /*
3300 * Loop through all available printers and create classes as needed...
3301 */
3302
3303 for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0,
3304 update = 0, pclass = NULL, first = NULL;
3305 p != NULL;
3306 p = (cupsd_printer_t *)cupsArrayNext(Printers))
3307 {
3308 /*
3309 * Skip implicit classes...
3310 */
3311
3312 if (p->type & CUPS_PRINTER_IMPLICIT)
3313 {
3314 len = 0;
3315 continue;
3316 }
3317
3318 /*
3319 * If len == 0, get the length of this printer name up to the "@"
3320 * sign (if any).
3321 */
3322
3323 cupsArraySave(Printers);
3324
3325 if (len > 0 &&
3326 !strncasecmp(p->name, name + offset, len) &&
3327 (p->name[len] == '\0' || p->name[len] == '@'))
3328 {
3329 /*
3330 * We have more than one printer with the same name; see if
3331 * we have a class, and if this printer is a member...
3332 */
3333
3334 if (pclass && strcasecmp(pclass->name, name))
3335 {
3336 if (update)
3337 cupsdSetPrinterAttrs(pclass);
3338
3339 update = 0;
3340 pclass = NULL;
3341 }
3342
3343 if (!pclass && (pclass = cupsdFindDest(name)) == NULL)
3344 {
3345 /*
3346 * Need to add the class...
3347 */
3348
3349 pclass = cupsdAddPrinter(name);
3350 cupsArrayAdd(ImplicitPrinters, pclass);
3351
3352 pclass->type |= CUPS_PRINTER_IMPLICIT;
3353 pclass->accepting = 1;
3354 pclass->state = IPP_PRINTER_IDLE;
3355
3356 cupsdSetString(&pclass->location, p->location);
3357 cupsdSetString(&pclass->info, p->info);
3358
3359 cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
3360 cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
3361
3362 update = 1;
3363
3364 cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP | CUPSD_DIRTY_REMOTE);
3365
3366 cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
3367 name);
3368 cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
3369 "Implicit class \'%s\' added by directory services.",
3370 name);
3371 }
3372
3373 if (first != NULL)
3374 {
3375 for (i = 0; i < pclass->num_printers; i ++)
3376 if (pclass->printers[i] == first)
3377 break;
3378
3379 if (i >= pclass->num_printers)
3380 {
3381 first->in_implicit_class = 1;
3382 cupsdAddPrinterToClass(pclass, first);
3383 }
3384
3385 first = NULL;
3386 }
3387
3388 for (i = 0; i < pclass->num_printers; i ++)
3389 if (pclass->printers[i] == p)
3390 break;
3391
3392 if (i >= pclass->num_printers)
3393 {
3394 p->in_implicit_class = 1;
3395 cupsdAddPrinterToClass(pclass, p);
3396 update = 1;
3397 }
3398 }
3399 else
3400 {
3401 /*
3402 * First time around; just get name length and mark it as first
3403 * in the list...
3404 */
3405
3406 if ((hptr = strchr(p->name, '@')) != NULL)
3407 len = hptr - p->name;
3408 else
3409 len = strlen(p->name);
3410
3411 strncpy(name, p->name, len);
3412 name[len] = '\0';
3413 offset = 0;
3414
3415 if ((first = (hptr ? cupsdFindDest(name) : p)) != NULL &&
3416 !(first->type & CUPS_PRINTER_IMPLICIT))
3417 {
3418 /*
3419 * Can't use same name as a local printer; add "Any" to the
3420 * front of the name, unless we have explicitly disabled
3421 * the "ImplicitAnyClasses"...
3422 */
3423
3424 if (ImplicitAnyClasses && len < (sizeof(name) - 4))
3425 {
3426 /*
3427 * Add "Any" to the class name...
3428 */
3429
3430 strcpy(name, "Any");
3431 strncpy(name + 3, p->name, len);
3432 name[len + 3] = '\0';
3433 offset = 3;
3434 }
3435 else
3436 {
3437 /*
3438 * Don't create an implicit class if we have a local printer
3439 * with the same name...
3440 */
3441
3442 len = 0;
3443 cupsArrayRestore(Printers);
3444 continue;
3445 }
3446 }
3447
3448 first = p;
3449 }
3450
3451 cupsArrayRestore(Printers);
3452 }
3453
3454 /*
3455 * Update the last printer class as needed...
3456 */
3457
3458 if (pclass && update)
3459 cupsdSetPrinterAttrs(pclass);
3460 }
3461
3462
3463 /*
3464 * 'send_cups_browse()' - Send new browsing information using the CUPS
3465 * protocol.
3466 */
3467
3468 static void
3469 send_cups_browse(cupsd_printer_t *p) /* I - Printer to send */
3470 {
3471 int i; /* Looping var */
3472 cups_ptype_t type; /* Printer type */
3473 cupsd_dirsvc_addr_t *b; /* Browse address */
3474 int bytes; /* Length of packet */
3475 char packet[1453], /* Browse data packet */
3476 uri[1024], /* Printer URI */
3477 location[1024], /* printer-location */
3478 info[1024], /* printer-info */
3479 make_model[1024];
3480 /* printer-make-and-model */
3481 cupsd_netif_t *iface; /* Network interface */
3482
3483
3484 /*
3485 * Figure out the printer type value...
3486 */
3487
3488 type = p->type | CUPS_PRINTER_REMOTE;
3489
3490 if (!p->accepting)
3491 type |= CUPS_PRINTER_REJECTING;
3492
3493 if (p == DefaultPrinter)
3494 type |= CUPS_PRINTER_DEFAULT;
3495
3496 /*
3497 * Remove quotes from printer-info, printer-location, and
3498 * printer-make-and-model attributes...
3499 */
3500
3501 dequote(location, p->location, sizeof(location));
3502 dequote(info, p->info, sizeof(info));
3503
3504 if (p->make_model)
3505 dequote(make_model, p->make_model, sizeof(make_model));
3506 else if (p->type & CUPS_PRINTER_CLASS)
3507 {
3508 if (p->num_printers > 0 && p->printers[0]->make_model)
3509 strlcpy(make_model, p->printers[0]->make_model, sizeof(make_model));
3510 else
3511 strlcpy(make_model, "Local Printer Class", sizeof(make_model));
3512 }
3513 else if (p->raw)
3514 strlcpy(make_model, "Local Raw Printer", sizeof(make_model));
3515 else
3516 strlcpy(make_model, "Local System V Printer", sizeof(make_model));
3517
3518 /*
3519 * Send a packet to each browse address...
3520 */
3521
3522 for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++)
3523 if (b->iface[0])
3524 {
3525 /*
3526 * Send the browse packet to one or more interfaces...
3527 */
3528
3529 if (!strcmp(b->iface, "*"))
3530 {
3531 /*
3532 * Send to all local interfaces...
3533 */
3534
3535 cupsdNetIFUpdate();
3536
3537 for (iface = (cupsd_netif_t *)cupsArrayFirst(NetIFList);
3538 iface;
3539 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
3540 {
3541 /*
3542 * Only send to local, IPv4 interfaces...
3543 */
3544
3545 if (!iface->is_local || !iface->port ||
3546 iface->address.addr.sa_family != AF_INET)
3547 continue;
3548
3549 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3550 iface->hostname, iface->port,
3551 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3552 "/printers/%s",
3553 p->name);
3554 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3555 type, p->state, uri, location, info, make_model,
3556 p->browse_attrs ? p->browse_attrs : "");
3557
3558 bytes = strlen(packet);
3559
3560 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3561 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3562 iface->name, packet);
3563
3564 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3565
3566 sendto(BrowseSocket, packet, bytes, 0,
3567 (struct sockaddr *)&(iface->broadcast),
3568 httpAddrLength(&(iface->broadcast)));
3569 }
3570 }
3571 else if ((iface = cupsdNetIFFind(b->iface)) != NULL)
3572 {
3573 /*
3574 * Send to the named interface using the IPv4 address...
3575 */
3576
3577 while (iface)
3578 if (strcmp(b->iface, iface->name))
3579 {
3580 iface = NULL;
3581 break;
3582 }
3583 else if (iface->address.addr.sa_family == AF_INET && iface->port)
3584 break;
3585 else
3586 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList);
3587
3588 if (iface)
3589 {
3590 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
3591 iface->hostname, iface->port,
3592 (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
3593 "/printers/%s",
3594 p->name);
3595 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3596 type, p->state, uri, location, info, make_model,
3597 p->browse_attrs ? p->browse_attrs : "");
3598
3599 bytes = strlen(packet);
3600
3601 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3602 "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes,
3603 iface->name, packet);
3604
3605 iface->broadcast.ipv4.sin_port = htons(BrowsePort);
3606
3607 sendto(BrowseSocket, packet, bytes, 0,
3608 (struct sockaddr *)&(iface->broadcast),
3609 httpAddrLength(&(iface->broadcast)));
3610 }
3611 }
3612 }
3613 else
3614 {
3615 /*
3616 * Send the browse packet to the indicated address using
3617 * the default server name...
3618 */
3619
3620 snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
3621 type, p->state, p->uri, location, info, make_model,
3622 p->browse_attrs ? p->browse_attrs : "");
3623
3624 bytes = strlen(packet);
3625 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3626 "cupsdSendBrowseList: (%d bytes) %s", bytes, packet);
3627
3628 if (sendto(BrowseSocket, packet, bytes, 0,
3629 (struct sockaddr *)&(b->to),
3630 httpAddrLength(&(b->to))) <= 0)
3631 {
3632 /*
3633 * Unable to send browse packet, so remove this address from the
3634 * list...
3635 */
3636
3637 cupsdLogMessage(CUPSD_LOG_ERROR,
3638 "cupsdSendBrowseList: sendto failed for browser "
3639 "%d - %s.",
3640 (int)(b - Browsers + 1), strerror(errno));
3641
3642 if (i > 1)
3643 memmove(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t));
3644
3645 b --;
3646 NumBrowsers --;
3647 }
3648 }
3649 }
3650
3651
3652 #ifdef HAVE_LDAP
3653 /*
3654 * 'ldap_search_rec()' - LDAP Search with reconnect
3655 */
3656
3657 static int
3658 ldap_search_rec(LDAP *ld, /* I - LDAP handler */
3659 char *base, /* I - Base dn */
3660 int scope, /* I - LDAP search scope */
3661 char *filter, /* I - Filter string */
3662 char *attrs[], /* I - Requested attributes */
3663 int attrsonly, /* I - Return only attributes? */
3664 LDAPMessage **res) /* I - LDAP handler */
3665 {
3666 int rc; /* Return code */
3667
3668
3669 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3670 rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
3671 NULL, LDAP_NO_LIMIT, res);
3672 # else
3673 rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
3674 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3675
3676 /*
3677 * If we have a connection problem try again...
3678 */
3679
3680 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
3681 {
3682 cupsdLogMessage(CUPSD_LOG_ERROR,
3683 "LDAP search failed with status %d: %s",
3684 rc, ldap_err2string(rc));
3685 cupsdLogMessage(CUPSD_LOG_INFO,
3686 "We try the LDAP search once again after reconnecting to "
3687 "the server");
3688 ldap_freeres(*res);
3689 ldap_reconnect();
3690
3691 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3692 rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL,
3693 NULL, NULL, LDAP_NO_LIMIT, res);
3694 # else
3695 rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
3696 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3697 }
3698
3699 if (rc == LDAP_NO_SUCH_OBJECT)
3700 cupsdLogMessage(CUPSD_LOG_DEBUG,
3701 "ldap_search_rec: LDAP entry/object not found");
3702 else if (rc != LDAP_SUCCESS)
3703 cupsdLogMessage(CUPSD_LOG_ERROR,
3704 "ldap_search_rec: LDAP search failed with status %d: %s",
3705 rc, ldap_err2string(rc));
3706
3707 if (rc != LDAP_SUCCESS)
3708 ldap_freeres(*res);
3709
3710 return (rc);
3711 }
3712
3713
3714 /*
3715 * 'ldap_freeres()' - Free LDAPMessage
3716 */
3717
3718 static void
3719 ldap_freeres(LDAPMessage *entry) /* I - LDAP handler */
3720 {
3721 int rc; /* Return value */
3722
3723
3724 rc = ldap_msgfree(entry);
3725 if (rc == -1)
3726 cupsdLogMessage(CUPSD_LOG_WARN,
3727 "Can't free LDAPMessage!");
3728 else if (rc == 0)
3729 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3730 "Freeing LDAPMessage was unnecessary");
3731 }
3732
3733
3734 /*
3735 * 'ldap_getval_char()' - Get first LDAP value and convert to string
3736 */
3737
3738 static int
3739 ldap_getval_firststring(
3740 LDAP *ld, /* I - LDAP handler */
3741 LDAPMessage *entry, /* I - LDAP message or search result */
3742 char *attr, /* I - the wanted attribute */
3743 char *retval, /* O - String to return */
3744 unsigned long maxsize) /* I - Max string size */
3745 {
3746 char *dn; /* LDAP DN */
3747 int rc = 0; /* Return code */
3748 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3749 struct berval **bval; /* LDAP value array */
3750 unsigned long size; /* String size */
3751
3752
3753 /*
3754 * Get value from LDAPMessage...
3755 */
3756
3757 if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
3758 {
3759 rc = -1;
3760 dn = ldap_get_dn(ld, entry);
3761 cupsdLogMessage(CUPSD_LOG_WARN,
3762 "Failed to get LDAP value %s for %s!",
3763 attr, dn);
3764 ldap_memfree(dn);
3765 }
3766 else
3767 {
3768
3769 /*
3770 * Check size and copy value into our string...
3771 */
3772
3773 size = maxsize;
3774 if (size < bval[0]->bv_len)
3775 {
3776 rc = -1;
3777 dn = ldap_get_dn(ld, entry);
3778 cupsdLogMessage(CUPSD_LOG_WARN,
3779 "Attribute %s is too big! (dn: %s)",
3780 attr, dn);
3781 ldap_memfree(dn);
3782 }
3783 else
3784 size = bval[0]->bv_len;
3785
3786 strlcpy(retval, bval[0]->bv_val, size);
3787 ldap_value_free_len(bval);
3788 }
3789 # else
3790 char **value; /* LDAP value */
3791
3792 /*
3793 * Get value from LDAPMessage...
3794 */
3795
3796 if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
3797 {
3798 rc = -1;
3799 dn = ldap_get_dn(ld, entry);
3800 cupsdLogMessage(CUPSD_LOG_WARN,
3801 "Failed to get LDAP value %s for %s!",
3802 attr, dn);
3803 ldap_memfree(dn);
3804 }
3805 else
3806 {
3807 strlcpy(retval, *value, maxsize);
3808 ldap_value_free(value);
3809 }
3810 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3811
3812 return (rc);
3813 }
3814
3815
3816 /*
3817 * 'send_ldap_ou()' - Send LDAP ou registrations.
3818 */
3819
3820 static void
3821 send_ldap_ou(char *ou, /* I - Servername/ou to register */
3822 char *basedn, /* I - Our base dn */
3823 char *descstring) /* I - Description for ou */
3824 {
3825 int i; /* Looping var... */
3826 LDAPMod mods[3]; /* The 3 attributes we will be adding */
3827 LDAPMod *pmods[4]; /* Pointers to the 3 attributes + NULL */
3828 LDAPMessage *res, /* Search result token */
3829 *e; /* Current entry from search */
3830 int rc; /* LDAP status */
3831 char dn[1024], /* DN of the organizational unit we are adding */
3832 *desc[2], /* Change records */
3833 *ou_value[2];
3834 char old_desc[1024]; /* Old description */
3835 static const char * const objectClass_values[] =
3836 { /* The 2 objectClass's we use in */
3837 "top", /* our LDAP entries */
3838 "organizationalUnit",
3839 NULL
3840 };
3841 static const char * const ou_attrs[] =/* CUPS LDAP attributes */
3842 {
3843 "description",
3844 NULL
3845 };
3846
3847
3848 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
3849
3850 /*
3851 * Reconnect if LDAP Handle is invalid...
3852 */
3853
3854 if (! BrowseLDAPHandle)
3855 {
3856 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3857 "send_ldap_ou: LDAP Handle is invalid. Try "
3858 "reconnecting...");
3859 ldap_reconnect();
3860 return;
3861 }
3862
3863 /*
3864 * Prepare ldap search...
3865 */
3866
3867 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
3868 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
3869
3870 ou_value[0] = ou;
3871 ou_value[1] = NULL;
3872 desc[0] = descstring;
3873 desc[1] = NULL;
3874
3875 mods[0].mod_type = "ou";
3876 mods[0].mod_values = ou_value;
3877 mods[1].mod_type = "description";
3878 mods[1].mod_values = desc;
3879 mods[2].mod_type = "objectClass";
3880 mods[2].mod_values = (char **)objectClass_values;
3881
3882 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
3883 (char **)ou_attrs, 0, &res);
3884
3885 /*
3886 * If ldap search was not successfull then exit function...
3887 */
3888
3889 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
3890 return;
3891
3892 /*
3893 * Check if we need to insert or update the LDAP entry...
3894 */
3895
3896 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
3897 rc != LDAP_NO_SUCH_OBJECT)
3898 {
3899 /*
3900 * Printserver has already been registered, check if
3901 * modification is required...
3902 */
3903
3904 e = ldap_first_entry(BrowseLDAPHandle, res);
3905
3906 /*
3907 * Get the required values from this entry...
3908 */
3909
3910 if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
3911 sizeof(old_desc)) == -1)
3912 old_desc[0] = '\0';
3913
3914 /*
3915 * Check if modification is required...
3916 */
3917
3918 if ( strcmp(desc[0], old_desc) == 0 )
3919 {
3920 /*
3921 * LDAP entry for the printer exists.
3922 * Printer has already been registered,
3923 * no modifications required...
3924 */
3925 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3926 "send_ldap_ou: No updates required for %s", ou);
3927 }
3928 else
3929 {
3930
3931 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3932 "send_ldap_ou: Replace entry for %s", ou);
3933
3934 for (i = 0; i < 3; i ++)
3935 {
3936 pmods[i] = mods + i;
3937 pmods[i]->mod_op = LDAP_MOD_REPLACE;
3938 }
3939 pmods[i] = NULL;
3940
3941 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3942 if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
3943 NULL)) != LDAP_SUCCESS)
3944 # else
3945 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3946 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3947 {
3948 cupsdLogMessage(CUPSD_LOG_ERROR,
3949 "LDAP modify for %s failed with status %d: %s",
3950 ou, rc, ldap_err2string(rc));
3951 if ( LDAP_SERVER_DOWN == rc )
3952 ldap_reconnect();
3953 }
3954 }
3955 }
3956 else
3957 {
3958 /*
3959 * Printserver has never been registered,
3960 * add registration...
3961 */
3962
3963 cupsdLogMessage(CUPSD_LOG_DEBUG2,
3964 "send_ldap_ou: Add entry for %s", ou);
3965
3966 for (i = 0; i < 3; i ++)
3967 {
3968 pmods[i] = mods + i;
3969 pmods[i]->mod_op = LDAP_MOD_ADD;
3970 }
3971 pmods[i] = NULL;
3972
3973 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
3974 if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
3975 NULL)) != LDAP_SUCCESS)
3976 # else
3977 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
3978 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
3979 {
3980 cupsdLogMessage(CUPSD_LOG_ERROR,
3981 "LDAP add for %s failed with status %d: %s",
3982 ou, rc, ldap_err2string(rc));
3983 if ( LDAP_SERVER_DOWN == rc )
3984 ldap_reconnect();
3985 }
3986 }
3987
3988 ldap_freeres(res);
3989 }
3990
3991
3992 /*
3993 * 'send_ldap_browse()' - Send LDAP printer registrations.
3994 */
3995
3996 static void
3997 send_ldap_browse(cupsd_printer_t *p) /* I - Printer to register */
3998 {
3999 int i; /* Looping var... */
4000 LDAPMod mods[7]; /* The 7 attributes we will be adding */
4001 LDAPMod *pmods[8]; /* Pointers to the 7 attributes + NULL */
4002 LDAPMessage *res, /* Search result token */
4003 *e; /* Current entry from search */
4004 char *cn_value[2], /* Change records */
4005 *uri[2],
4006 *info[2],
4007 *location[2],
4008 *make_model[2],
4009 *type[2],
4010 typestring[255], /* String to hold printer-type */
4011 dn[1024]; /* DN of the printer we are adding */
4012 int rc; /* LDAP status */
4013 char old_uri[HTTP_MAX_URI], /* Printer URI */
4014 old_location[1024], /* Printer location */
4015 old_info[1024], /* Printer information */
4016 old_make_model[1024], /* Printer make and model */
4017 old_type_string[30]; /* Temporary type number */
4018 int old_type; /* Printer type */
4019 static const char * const objectClass_values[] =
4020 { /* The 3 objectClass's we use in */
4021 "top", /* our LDAP entries */
4022 "device",
4023 "cupsPrinter",
4024 NULL
4025 };
4026
4027
4028 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
4029
4030 /*
4031 * Exit function if LDAP updates has been disabled...
4032 */
4033
4034 if (!BrowseLDAPUpdate)
4035 {
4036 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4037 "send_ldap_browse: Updates temporary disabled; "
4038 "skipping...");
4039 return;
4040 }
4041
4042 /*
4043 * Reconnect if LDAP Handle is invalid...
4044 */
4045
4046 if (!BrowseLDAPHandle)
4047 {
4048 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4049 "send_ldap_browse: LDAP Handle is invalid. Try "
4050 "reconnecting...");
4051 ldap_reconnect();
4052 return;
4053 }
4054
4055 /*
4056 * Everything in ldap is ** so we fudge around it...
4057 */
4058
4059 sprintf(typestring, "%u", p->type);
4060
4061 cn_value[0] = p->name;
4062 cn_value[1] = NULL;
4063 info[0] = p->info ? p->info : "Unknown";
4064 info[1] = NULL;
4065 location[0] = p->location ? p->location : "Unknown";
4066 location[1] = NULL;
4067 make_model[0] = p->make_model ? p->make_model : "Unknown";
4068 make_model[1] = NULL;
4069 type[0] = typestring;
4070 type[1] = NULL;
4071 uri[0] = p->uri;
4072 uri[1] = NULL;
4073
4074 /*
4075 * Get ldap entry for printer ...
4076 */
4077
4078 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4079 BrowseLDAPDN);
4080 cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
4081
4082 rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
4083 (char **)ldap_attrs, 0, &res);
4084
4085 /*
4086 * If ldap search was not successfull then exit function
4087 * and temporary disable LDAP updates...
4088 */
4089
4090 if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
4091 {
4092 if (BrowseLDAPUpdate &&
4093 (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
4094 {
4095 BrowseLDAPUpdate = FALSE;
4096 cupsdLogMessage(CUPSD_LOG_INFO,
4097 "LDAP update temporary disabled");
4098 }
4099
4100 return;
4101 }
4102
4103 /*
4104 * Fill modification array...
4105 */
4106
4107 mods[0].mod_type = "cn";
4108 mods[0].mod_values = cn_value;
4109 mods[1].mod_type = "printerDescription";
4110 mods[1].mod_values = info;
4111 mods[2].mod_type = "printerURI";
4112 mods[2].mod_values = uri;
4113 mods[3].mod_type = "printerLocation";
4114 mods[3].mod_values = location;
4115 mods[4].mod_type = "printerMakeAndModel";
4116 mods[4].mod_values = make_model;
4117 mods[5].mod_type = "printerType";
4118 mods[5].mod_values = type;
4119 mods[6].mod_type = "objectClass";
4120 mods[6].mod_values = (char **)objectClass_values;
4121
4122 /*
4123 * Check if we need to insert or update the LDAP entry...
4124 */
4125
4126 if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
4127 rc != LDAP_NO_SUCH_OBJECT)
4128 {
4129 /*
4130 * Printer has already been registered, check if
4131 * modification is required...
4132 */
4133
4134 e = ldap_first_entry(BrowseLDAPHandle, res);
4135
4136 /*
4137 * Get the required values from this entry...
4138 */
4139
4140 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
4141 old_info, sizeof(old_info)) == -1)
4142 old_info[0] = '\0';
4143
4144 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
4145 old_location, sizeof(old_location)) == -1)
4146 old_info[0] = '\0';
4147
4148 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
4149 old_make_model, sizeof(old_make_model)) == -1)
4150 old_info[0] = '\0';
4151
4152 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
4153 old_type_string, sizeof(old_type_string)) == -1)
4154 old_info[0] = '\0';
4155
4156 old_type = atoi(old_type_string);
4157
4158 if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
4159 sizeof(old_uri)) == -1)
4160 old_info[0] = '\0';
4161
4162 /*
4163 * Check if modification is required...
4164 */
4165
4166 if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
4167 !strcmp(location[0], old_location) &&
4168 !strcmp(make_model[0], old_make_model) && p->type == old_type)
4169 {
4170 /*
4171 * LDAP entry for the printer exists. Printer has already been registered,
4172 * no modifications required...
4173 */
4174
4175 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4176 "send_ldap_browse: No updates required for %s", p->name);
4177 }
4178 else
4179 {
4180 /*
4181 * LDAP entry for the printer exists. Printer has already been registered,
4182 * modify the current registration...
4183 */
4184
4185 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4186 "send_ldap_browse: Replace entry for %s", p->name);
4187
4188 for (i = 0; i < 7; i ++)
4189 {
4190 pmods[i] = mods + i;
4191 pmods[i]->mod_op = LDAP_MOD_REPLACE;
4192 }
4193 pmods[i] = NULL;
4194
4195 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4196 if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4197 NULL)) != LDAP_SUCCESS)
4198 # else
4199 if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4200 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4201 {
4202 cupsdLogMessage(CUPSD_LOG_ERROR,
4203 "LDAP modify for %s failed with status %d: %s",
4204 p->name, rc, ldap_err2string(rc));
4205 if (rc == LDAP_SERVER_DOWN)
4206 ldap_reconnect();
4207 }
4208 }
4209 }
4210 else
4211 {
4212 /*
4213 * No LDAP entry exists for the printer. Printer has never been registered,
4214 * add the current registration...
4215 */
4216
4217 send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
4218
4219 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4220 "send_ldap_browse: Add entry for %s", p->name);
4221
4222 for (i = 0; i < 7; i ++)
4223 {
4224 pmods[i] = mods + i;
4225 pmods[i]->mod_op = LDAP_MOD_ADD;
4226 }
4227 pmods[i] = NULL;
4228
4229 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4230 if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
4231 NULL)) != LDAP_SUCCESS)
4232 # else
4233 if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
4234 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4235 {
4236 cupsdLogMessage(CUPSD_LOG_ERROR,
4237 "LDAP add for %s failed with status %d: %s",
4238 p->name, rc, ldap_err2string(rc));
4239 if (rc == LDAP_SERVER_DOWN)
4240 ldap_reconnect();
4241 }
4242 }
4243
4244 ldap_freeres(res);
4245 }
4246
4247
4248 /*
4249 * 'ldap_dereg_printer()' - Delete printer from directory
4250 */
4251
4252 static void
4253 ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
4254 {
4255 char dn[1024]; /* DN of the printer */
4256 int rc; /* LDAP status */
4257
4258
4259 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
4260 p->name);
4261
4262 /*
4263 * Reconnect if LDAP Handle is invalid...
4264 */
4265
4266 if (!BrowseLDAPHandle)
4267 {
4268 ldap_reconnect();
4269 return;
4270 }
4271
4272 /*
4273 * Get dn for printer and delete LDAP entry...
4274 */
4275
4276 snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
4277 BrowseLDAPDN);
4278 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
4279
4280 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4281 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4282 NULL)) != LDAP_SUCCESS)
4283 # else
4284 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4285 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4286 {
4287 cupsdLogMessage(CUPSD_LOG_WARN,
4288 "LDAP delete for %s failed with status %d: %s",
4289 p->name, rc, ldap_err2string(rc));
4290
4291 /*
4292 * If we had a connection problem (connection timed out, etc.)
4293 * we should reconnect and try again to delete the entry...
4294 */
4295
4296 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4297 {
4298 cupsdLogMessage(CUPSD_LOG_INFO,
4299 "Retry deleting LDAP entry for %s after a reconnect...", p->name);
4300 ldap_reconnect();
4301
4302 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4303 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4304 NULL)) != LDAP_SUCCESS)
4305 # else
4306 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4307 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4308 cupsdLogMessage(CUPSD_LOG_WARN,
4309 "LDAP delete for %s failed with status %d: %s",
4310 p->name, rc, ldap_err2string(rc));
4311 }
4312 }
4313 }
4314
4315
4316 static void
4317 ldap_dereg_ou(char *ou, /* I - Organizational unit (servername) */
4318 char *basedn) /* I - Dase dn */
4319 {
4320 char dn[1024]; /* DN of the printer */
4321 int rc; /* LDAP status */
4322
4323
4324 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
4325
4326 /*
4327 * Reconnect if LDAP Handle is invalid...
4328 */
4329
4330 if (!BrowseLDAPHandle)
4331 {
4332 ldap_reconnect();
4333 return;
4334 }
4335
4336 /*
4337 * Get dn for printer and delete LDAP entry...
4338 */
4339
4340 snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
4341 cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
4342
4343 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4344 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4345 NULL)) != LDAP_SUCCESS)
4346 # else
4347 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4348 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4349 {
4350 cupsdLogMessage(CUPSD_LOG_WARN,
4351 "LDAP delete for %s failed with status %d: %s",
4352 ou, rc, ldap_err2string(rc));
4353
4354 /*
4355 * If we had a connection problem (connection timed out, etc.)
4356 * we should reconnect and try again to delete the entry...
4357 */
4358
4359 if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
4360 {
4361 cupsdLogMessage(CUPSD_LOG_INFO,
4362 "Retry deleting LDAP entry for %s after a reconnect...", ou);
4363 ldap_reconnect();
4364 # if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
4365 if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
4366 NULL)) != LDAP_SUCCESS)
4367 # else
4368 if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
4369 # endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
4370 cupsdLogMessage(CUPSD_LOG_WARN,
4371 "LDAP delete for %s failed with status %d: %s",
4372 ou, rc, ldap_err2string(rc));
4373 }
4374
4375 }
4376 }
4377 #endif /* HAVE_LDAP */
4378
4379
4380 #ifdef HAVE_LIBSLP
4381 /*
4382 * 'send_slp_browse()' - Register the specified printer with SLP.
4383 */
4384
4385 static void
4386 send_slp_browse(cupsd_printer_t *p) /* I - Printer to register */
4387 {
4388 char srvurl[HTTP_MAX_URI], /* Printer service URI */
4389 attrs[8192], /* Printer attributes */
4390 finishings[1024], /* Finishings to support */
4391 make_model[IPP_MAX_NAME * 2],
4392 /* Make and model, quoted */
4393 location[IPP_MAX_NAME * 2],
4394 /* Location, quoted */
4395 info[IPP_MAX_NAME * 2], /* Info, quoted */
4396 *src, /* Pointer to original string */
4397 *dst; /* Pointer to destination string */
4398 ipp_attribute_t *authentication; /* uri-authentication-supported value */
4399 SLPError error; /* SLP error, if any */
4400
4401
4402 cupsdLogMessage(CUPSD_LOG_DEBUG, "send_slp_browse(%p = \"%s\")", p,
4403 p->name);
4404
4405 /*
4406 * Make the SLP service URL that conforms to the IANA
4407 * 'printer:' template.
4408 */
4409
4410 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
4411
4412 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Service URL = \"%s\"", srvurl);
4413
4414 /*
4415 * Figure out the finishings string...
4416 */
4417
4418 if (p->type & CUPS_PRINTER_STAPLE)
4419 strcpy(finishings, "staple");
4420 else
4421 finishings[0] = '\0';
4422
4423 if (p->type & CUPS_PRINTER_BIND)
4424 {
4425 if (finishings[0])
4426 strlcat(finishings, ",bind", sizeof(finishings));
4427 else
4428 strcpy(finishings, "bind");
4429 }
4430
4431 if (p->type & CUPS_PRINTER_PUNCH)
4432 {
4433 if (finishings[0])
4434 strlcat(finishings, ",punch", sizeof(finishings));
4435 else
4436 strcpy(finishings, "punch");
4437 }
4438
4439 if (p->type & CUPS_PRINTER_COVER)
4440 {
4441 if (finishings[0])
4442 strlcat(finishings, ",cover", sizeof(finishings));
4443 else
4444 strcpy(finishings, "cover");
4445 }
4446
4447 if (p->type & CUPS_PRINTER_SORT)
4448 {
4449 if (finishings[0])
4450 strlcat(finishings, ",sort", sizeof(finishings));
4451 else
4452 strcpy(finishings, "sort");
4453 }
4454
4455 if (!finishings[0])
4456 strcpy(finishings, "none");
4457
4458 /*
4459 * Quote any commas in the make and model, location, and info strings...
4460 */
4461
4462 for (src = p->make_model, dst = make_model;
4463 src && *src && dst < (make_model + sizeof(make_model) - 2);)
4464 {
4465 if (*src == ',' || *src == '\\' || *src == ')')
4466 *dst++ = '\\';
4467
4468 *dst++ = *src++;
4469 }
4470
4471 *dst = '\0';
4472
4473 if (!make_model[0])
4474 strcpy(make_model, "Unknown");
4475
4476 for (src = p->location, dst = location;
4477 src && *src && dst < (location + sizeof(location) - 2);)
4478 {
4479 if (*src == ',' || *src == '\\' || *src == ')')
4480 *dst++ = '\\';
4481
4482 *dst++ = *src++;
4483 }
4484
4485 *dst = '\0';
4486
4487 if (!location[0])
4488 strcpy(location, "Unknown");
4489
4490 for (src = p->info, dst = info;
4491 src && *src && dst < (info + sizeof(info) - 2);)
4492 {
4493 if (*src == ',' || *src == '\\' || *src == ')')
4494 *dst++ = '\\';
4495
4496 *dst++ = *src++;
4497 }
4498
4499 *dst = '\0';
4500
4501 if (!info[0])
4502 strcpy(info, "Unknown");
4503
4504 /*
4505 * Get the authentication value...
4506 */
4507
4508 authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
4509 IPP_TAG_KEYWORD);
4510
4511 /*
4512 * Make the SLP attribute string list that conforms to
4513 * the IANA 'printer:' template.
4514 */
4515
4516 snprintf(attrs, sizeof(attrs),
4517 "(printer-uri-supported=%s),"
4518 "(uri-authentication-supported=%s>),"
4519 #ifdef HAVE_SSL
4520 "(uri-security-supported=tls>),"
4521 #else
4522 "(uri-security-supported=none>),"
4523 #endif /* HAVE_SSL */
4524 "(printer-name=%s),"
4525 "(printer-location=%s),"
4526 "(printer-info=%s),"
4527 "(printer-more-info=%s),"
4528 "(printer-make-and-model=%s),"
4529 "(printer-type=%d),"
4530 "(charset-supported=utf-8),"
4531 "(natural-language-configured=%s),"
4532 "(natural-language-supported=de,en,es,fr,it),"
4533 "(color-supported=%s),"
4534 "(finishings-supported=%s),"
4535 "(sides-supported=one-sided%s),"
4536 "(multiple-document-jobs-supported=true)"
4537 "(ipp-versions-supported=1.0,1.1)",
4538 p->uri, authentication->values[0].string.text, p->name, location,
4539 info, p->uri, make_model, p->type, DefaultLanguage,
4540 p->type & CUPS_PRINTER_COLOR ? "true" : "false",
4541 finishings,
4542 p->type & CUPS_PRINTER_DUPLEX ?
4543 ",two-sided-long-edge,two-sided-short-edge" : "");
4544
4545 cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs);
4546
4547 /*
4548 * Register the printer with the SLP server...
4549 */
4550
4551 error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
4552 SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0);
4553
4554 if (error != SLP_OK)
4555 cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
4556 error);
4557 }
4558
4559
4560 /*
4561 * 'slp_attr_callback()' - SLP attribute callback
4562 */
4563
4564 static SLPBoolean /* O - SLP_TRUE for success */
4565 slp_attr_callback(
4566 SLPHandle hslp, /* I - SLP handle */
4567 const char *attrlist, /* I - Attribute list */
4568 SLPError errcode, /* I - Parsing status for this attr */
4569 void *cookie) /* I - Current printer */
4570 {
4571 char *tmp = 0; /* Temporary string */
4572 cupsd_printer_t *p = (cupsd_printer_t*)cookie;
4573 /* Current printer */
4574
4575
4576 (void)hslp; /* anti-compiler-warning-code */
4577
4578 /*
4579 * Bail if there was an error
4580 */
4581
4582 if (errcode != SLP_OK)
4583 return (SLP_TRUE);
4584
4585 /*
4586 * Parse the attrlist to obtain things needed to build CUPS browse packet
4587 */
4588
4589 memset(p, 0, sizeof(cupsd_printer_t));
4590
4591 if (slp_get_attr(attrlist, "(printer-location=", &(p->location)))
4592 return (SLP_FALSE);
4593 if (slp_get_attr(attrlist, "(printer-info=", &(p->info)))
4594 return (SLP_FALSE);
4595 if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model)))
4596 return (SLP_FALSE);
4597 if (!slp_get_attr(attrlist, "(printer-type=", &tmp))
4598 p->type = atoi(tmp);
4599 else
4600 p->type = CUPS_PRINTER_REMOTE;
4601
4602 cupsdClearString(&tmp);
4603
4604 return (SLP_TRUE);
4605 }
4606
4607
4608 /*
4609 * 'slp_dereg_printer()' - SLPDereg() the specified printer
4610 */
4611
4612 static void
4613 slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */
4614 {
4615 char srvurl[HTTP_MAX_URI]; /* Printer service URI */
4616
4617
4618 cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name);
4619
4620 if (!(p->type & CUPS_PRINTER_REMOTE))
4621 {
4622 /*
4623 * Make the SLP service URL that conforms to the IANA
4624 * 'printer:' template.
4625 */
4626
4627 snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
4628
4629 /*
4630 * Deregister the printer...
4631 */
4632
4633 SLPDereg(BrowseSLPHandle, srvurl, slp_reg_callback, 0);
4634 }
4635 }
4636
4637
4638 /*
4639 * 'slp_get_attr()' - Get an attribute from an SLP registration.
4640 */
4641
4642 static int /* O - 0 on success */
4643 slp_get_attr(const char *attrlist, /* I - Attribute list string */
4644 const char *tag, /* I - Name of attribute */
4645 char **valbuf) /* O - Value */
4646 {
4647 char *ptr1, /* Pointer into string */
4648 *ptr2; /* ... */
4649
4650
4651 cupsdClearString(valbuf);
4652
4653 if ((ptr1 = strstr(attrlist, tag)) != NULL)
4654 {
4655 ptr1 += strlen(tag);
4656
4657 if ((ptr2 = strchr(ptr1,')')) != NULL)
4658 {
4659 /*
4660 * Copy the value...
4661 */
4662
4663 *valbuf = calloc(ptr2 - ptr1 + 1, 1);
4664 strncpy(*valbuf, ptr1, ptr2 - ptr1);
4665
4666 /*
4667 * Dequote the value...
4668 */
4669
4670 for (ptr1 = *valbuf; *ptr1; ptr1 ++)
4671 if (*ptr1 == '\\' && ptr1[1])
4672 _cups_strcpy(ptr1, ptr1 + 1);
4673
4674 return (0);
4675 }
4676 }
4677
4678 return (-1);
4679 }
4680
4681
4682 /*
4683 * 'slp_reg_callback()' - Empty SLPRegReport.
4684 */
4685
4686 static void
4687 slp_reg_callback(SLPHandle hslp, /* I - SLP handle */
4688 SLPError errcode, /* I - Error code, if any */
4689 void *cookie) /* I - App data */
4690 {
4691 (void)hslp;
4692 (void)errcode;
4693 (void)cookie;
4694
4695 return;
4696 }
4697
4698
4699 /*
4700 * 'slp_url_callback()' - SLP service url callback
4701 */
4702
4703 static SLPBoolean /* O - TRUE = OK, FALSE = error */
4704 slp_url_callback(
4705 SLPHandle hslp, /* I - SLP handle */
4706 const char *srvurl, /* I - URL of service */
4707 unsigned short lifetime, /* I - Life of service */
4708 SLPError errcode, /* I - Existing error code */
4709 void *cookie) /* I - Pointer to service list */
4710 {
4711 slpsrvurl_t *s, /* New service entry */
4712 **head; /* Pointer to head of entry */
4713
4714
4715 /*
4716 * Let the compiler know we won't be using these vars...
4717 */
4718
4719 (void)hslp;
4720 (void)lifetime;
4721
4722 /*
4723 * Bail if there was an error
4724 */
4725
4726 if (errcode != SLP_OK)
4727 return (SLP_TRUE);
4728
4729 /*
4730 * Grab the head of the list...
4731 */
4732
4733 head = (slpsrvurl_t**)cookie;
4734
4735 /*
4736 * Allocate a *temporary* slpsrvurl_t to hold this entry.
4737 */
4738
4739 if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
4740 return (SLP_FALSE);
4741
4742 /*
4743 * Copy the SLP service URL...
4744 */
4745
4746 strlcpy(s->url, srvurl, sizeof(s->url));
4747
4748 /*
4749 * Link the SLP service URL into the head of the list
4750 */
4751
4752 if (*head)
4753 s->next = *head;
4754
4755 *head = s;
4756
4757 return (SLP_TRUE);
4758 }
4759 #endif /* HAVE_LIBSLP */
4760
4761
4762 /*
4763 * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
4764 */
4765
4766 static void
4767 update_cups_browse(void)
4768 {
4769 int i; /* Looping var */
4770 int auth; /* Authorization status */
4771 int len; /* Length of name string */
4772 int bytes; /* Number of bytes left */
4773 char packet[1541], /* Broadcast packet */
4774 *pptr; /* Pointer into packet */
4775 socklen_t srclen; /* Length of source address */
4776 http_addr_t srcaddr; /* Source address */
4777 char srcname[1024]; /* Source hostname */
4778 unsigned address[4]; /* Source address */
4779 unsigned type; /* Printer type */
4780 unsigned state; /* Printer state */
4781 char uri[HTTP_MAX_URI], /* Printer URI */
4782 host[HTTP_MAX_URI], /* Host portion of URI */
4783 resource[HTTP_MAX_URI], /* Resource portion of URI */
4784 info[IPP_MAX_NAME], /* Information string */
4785 location[IPP_MAX_NAME], /* Location string */
4786 make_model[IPP_MAX_NAME];/* Make and model string */
4787 int num_attrs; /* Number of attributes */
4788 cups_option_t *attrs; /* Attributes */
4789
4790
4791 /*
4792 * Read a packet from the browse socket...
4793 */
4794
4795 srclen = sizeof(srcaddr);
4796 if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0,
4797 (struct sockaddr *)&srcaddr, &srclen)) < 0)
4798 {
4799 /*
4800 * "Connection refused" is returned under Linux if the destination port
4801 * or address is unreachable from a previous sendto(); check for the
4802 * error here and ignore it for now...
4803 */
4804
4805 if (errno != ECONNREFUSED && errno != EAGAIN)
4806 {
4807 cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
4808 strerror(errno));
4809 cupsdLogMessage(CUPSD_LOG_ERROR, "CUPS browsing turned off.");
4810
4811 #ifdef WIN32
4812 closesocket(BrowseSocket);
4813 #else
4814 close(BrowseSocket);
4815 #endif /* WIN32 */
4816
4817 cupsdRemoveSelect(BrowseSocket);
4818 BrowseSocket = -1;
4819
4820 BrowseLocalProtocols &= ~BROWSE_CUPS;
4821 BrowseRemoteProtocols &= ~BROWSE_CUPS;
4822 }
4823
4824 return;
4825 }
4826
4827 packet[bytes] = '\0';
4828
4829 /*
4830 * If we're about to sleep, ignore incoming browse packets.
4831 */
4832
4833 if (Sleeping)
4834 return;
4835
4836 /*
4837 * Figure out where it came from...
4838 */
4839
4840 #ifdef AF_INET6
4841 if (srcaddr.addr.sa_family == AF_INET6)
4842 {
4843 address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
4844 address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
4845 address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
4846 address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
4847 }
4848 else
4849 #endif /* AF_INET6 */
4850 {
4851 address[0] = 0;
4852 address[1] = 0;
4853 address[2] = 0;
4854 address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
4855 }
4856
4857 if (HostNameLookups)
4858 httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
4859 else
4860 httpAddrString(&srcaddr, srcname, sizeof(srcname));
4861
4862 len = strlen(srcname);
4863
4864 /*
4865 * Do ACL stuff...
4866 */
4867
4868 if (BrowseACL)
4869 {
4870 if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
4871 {
4872 /*
4873 * Access from localhost (127.0.0.1) is always allowed...
4874 */
4875
4876 auth = CUPSD_AUTH_ALLOW;
4877 }
4878 else
4879 {
4880 /*
4881 * Do authorization checks on the domain/address...
4882 */
4883
4884 switch (BrowseACL->order_type)
4885 {
4886 default :
4887 auth = CUPSD_AUTH_DENY; /* anti-compiler-warning-code */
4888 break;
4889
4890 case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
4891 auth = CUPSD_AUTH_ALLOW;
4892
4893 if (cupsdCheckAuth(address, srcname, len,
4894 BrowseACL->num_deny, BrowseACL->deny))
4895 auth = CUPSD_AUTH_DENY;
4896
4897 if (cupsdCheckAuth(address, srcname, len,
4898 BrowseACL->num_allow, BrowseACL->allow))
4899 auth = CUPSD_AUTH_ALLOW;
4900 break;
4901
4902 case CUPSD_AUTH_DENY : /* Order Allow,Deny */
4903 auth = CUPSD_AUTH_DENY;
4904
4905 if (cupsdCheckAuth(address, srcname, len,
4906 BrowseACL->num_allow, BrowseACL->allow))
4907 auth = CUPSD_AUTH_ALLOW;
4908
4909 if (cupsdCheckAuth(address, srcname, len,
4910 BrowseACL->num_deny, BrowseACL->deny))
4911 auth = CUPSD_AUTH_DENY;
4912 break;
4913 }
4914 }
4915 }
4916 else
4917 auth = CUPSD_AUTH_ALLOW;
4918
4919 if (auth == CUPSD_AUTH_DENY)
4920 {
4921 cupsdLogMessage(CUPSD_LOG_DEBUG,
4922 "update_cups_browse: Refused %d bytes from %s", bytes,
4923 srcname);
4924 return;
4925 }
4926
4927 cupsdLogMessage(CUPSD_LOG_DEBUG2,
4928 "update_cups_browse: (%d bytes from %s) %s", bytes,
4929 srcname, packet);
4930
4931 /*
4932 * Parse packet...
4933 */
4934
4935 if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
4936 {
4937 cupsdLogMessage(CUPSD_LOG_WARN,
4938 "update_cups_browse: Garbled browse packet - %s", packet);
4939 return;
4940 }
4941
4942 strcpy(location, "Location Unknown");
4943 strcpy(info, "No Information Available");
4944 make_model[0] = '\0';
4945 num_attrs = 0;
4946 attrs = NULL;
4947
4948 if ((pptr = strchr(packet, '\"')) != NULL)
4949 {
4950 /*
4951 * Have extended information; can't use sscanf for it because not all
4952 * sscanf's allow empty strings with %[^\"]...
4953 */
4954
4955 for (i = 0, pptr ++;
4956 i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
4957 i ++, pptr ++)
4958 location[i] = *pptr;
4959
4960 if (i)
4961 location[i] = '\0';
4962
4963 if (*pptr == '\"')
4964 pptr ++;
4965
4966 while (*pptr && isspace(*pptr & 255))
4967 pptr ++;
4968
4969 if (*pptr == '\"')
4970 {
4971 for (i = 0, pptr ++;
4972 i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
4973 i ++, pptr ++)
4974 info[i] = *pptr;
4975
4976 info[i] = '\0';
4977
4978 if (*pptr == '\"')
4979 pptr ++;
4980
4981 while (*pptr && isspace(*pptr & 255))
4982 pptr ++;
4983
4984 if (*pptr == '\"')
4985 {
4986 for (i = 0, pptr ++;
4987 i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
4988 i ++, pptr ++)
4989 make_model[i] = *pptr;
4990
4991 if (*pptr == '\"')
4992 pptr ++;
4993
4994 make_model[i] = '\0';
4995
4996 if (*pptr)
4997 num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
4998 }
4999 }
5000 }
5001
5002 DEBUG_puts(packet);
5003 DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
5004 "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
5005 type, state, uri, location, info, make_model));
5006
5007 /*
5008 * Pull the URI apart to see if this is a local or remote printer...
5009 */
5010
5011 if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
5012 {
5013 cupsFreeOptions(num_attrs, attrs);
5014 return;
5015 }
5016
5017 /*
5018 * Do relaying...
5019 */
5020
5021 for (i = 0; i < NumRelays; i ++)
5022 if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
5023 if (sendto(BrowseSocket, packet, bytes, 0,
5024 (struct sockaddr *)&(Relays[i].to),
5025 httpAddrLength(&(Relays[i].to))) <= 0)
5026 {
5027 cupsdLogMessage(CUPSD_LOG_ERROR,
5028 "update_cups_browse: sendto failed for relay %d - %s.",
5029 i + 1, strerror(errno));
5030 cupsFreeOptions(num_attrs, attrs);
5031 return;
5032 }
5033
5034 /*
5035 * Process the browse data...
5036 */
5037
5038 process_browse_data(uri, host, resource, (cups_ptype_t)type,
5039 (ipp_pstate_t)state, location, info, make_model,
5040 num_attrs, attrs);
5041 }
5042
5043
5044 /*
5045 * 'update_lpd()' - Update the LPD configuration as needed.
5046 */
5047
5048 static void
5049 update_lpd(int onoff) /* - 1 = turn on, 0 = turn off */
5050 {
5051 if (!LPDConfigFile)
5052 return;
5053
5054 #ifdef __APPLE__
5055 /*
5056 * Allow /etc/hostconfig CUPS_LPD service setting to override cupsd.conf
5057 * setting for backwards-compatibility.
5058 */
5059
5060 if (onoff && !get_hostconfig("CUPS_LPD"))
5061 onoff = 0;
5062 #endif /* __APPLE__ */
5063
5064 if (!strncmp(LPDConfigFile, "xinetd:///", 10))
5065 {
5066 /*
5067 * Enable/disable LPD via the xinetd.d config file for cups-lpd...
5068 */
5069
5070 char newfile[1024]; /* New cups-lpd.N file */
5071 cups_file_t *ofp, /* Original file pointer */
5072 *nfp; /* New file pointer */
5073 char line[1024]; /* Line from file */
5074
5075
5076 snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
5077
5078 if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
5079 {
5080 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5081 LPDConfigFile + 9, strerror(errno));
5082 return;
5083 }
5084
5085 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5086 {
5087 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5088 newfile, strerror(errno));
5089 cupsFileClose(ofp);
5090 return;
5091 }
5092
5093 /*
5094 * Copy all of the lines from the cups-lpd file...
5095 */
5096
5097 while (cupsFileGets(ofp, line, sizeof(line)))
5098 {
5099 if (line[0] == '{')
5100 {
5101 cupsFilePrintf(nfp, "%s\n", line);
5102 snprintf(line, sizeof(line), "\tdisable = %s",
5103 onoff ? "no" : "yes");
5104 }
5105 else if (!strstr(line, "disable ="))
5106 cupsFilePrintf(nfp, "%s\n", line);
5107 }
5108
5109 cupsFileClose(nfp);
5110 cupsFileClose(ofp);
5111 rename(newfile, LPDConfigFile + 9);
5112 }
5113 #ifdef __APPLE__
5114 else if (!strncmp(LPDConfigFile, "launchd:///", 11))
5115 {
5116 /*
5117 * Enable/disable LPD via the launchctl command...
5118 */
5119
5120 char *argv[5], /* Arguments for command */
5121 *envp[MAX_ENV]; /* Environment for command */
5122 int pid; /* Process ID */
5123
5124
5125 cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
5126 argv[0] = (char *)"launchctl";
5127 argv[1] = (char *)(onoff ? "load" : "unload");
5128 argv[2] = (char *)"-w";
5129 argv[3] = LPDConfigFile + 10;
5130 argv[4] = NULL;
5131
5132 cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
5133 NULL, &pid);
5134 }
5135 #endif /* __APPLE__ */
5136 else
5137 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown LPDConfigFile scheme!");
5138 }
5139
5140
5141 /*
5142 * 'update_polling()' - Read status messages from the poll daemons.
5143 */
5144
5145 static void
5146 update_polling(void)
5147 {
5148 char *ptr, /* Pointer to end of line in buffer */
5149 message[1024]; /* Pointer to message text */
5150 int loglevel; /* Log level for message */
5151
5152
5153 while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
5154 message, sizeof(message))) != NULL)
5155 if (!strchr(PollStatusBuffer->buffer, '\n'))
5156 break;
5157
5158 if (ptr == NULL && !PollStatusBuffer->bufused)
5159 {
5160 /*
5161 * All polling processes have died; stop polling...
5162 */
5163
5164 cupsdLogMessage(CUPSD_LOG_ERROR,
5165 "update_polling: all polling processes have exited!");
5166 cupsdStopPolling();
5167 }
5168 }
5169
5170
5171 /*
5172 * 'update_smb()' - Update the SMB configuration as needed.
5173 */
5174
5175 static void
5176 update_smb(int onoff) /* I - 1 = turn on, 0 = turn off */
5177 {
5178 if (!SMBConfigFile)
5179 return;
5180
5181 if (!strncmp(SMBConfigFile, "samba:///", 9))
5182 {
5183 /*
5184 * Enable/disable SMB via the specified smb.conf config file...
5185 */
5186
5187 char newfile[1024]; /* New smb.conf.N file */
5188 cups_file_t *ofp, /* Original file pointer */
5189 *nfp; /* New file pointer */
5190 char line[1024]; /* Line from file */
5191 int in_printers; /* In [printers] section? */
5192
5193
5194 snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
5195
5196 if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
5197 {
5198 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
5199 SMBConfigFile + 8, strerror(errno));
5200 return;
5201 }
5202
5203 if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
5204 {
5205 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
5206 newfile, strerror(errno));
5207 cupsFileClose(ofp);
5208 return;
5209 }
5210
5211 /*
5212 * Copy all of the lines from the smb.conf file...
5213 */
5214
5215 in_printers = 0;
5216
5217 while (cupsFileGets(ofp, line, sizeof(line)))
5218 {
5219 if (in_printers && strstr(line, "printable ="))
5220 snprintf(line, sizeof(line), " printable = %s",
5221 onoff ? "yes" : "no");
5222
5223 cupsFilePrintf(nfp, "%s\n", line);
5224
5225 if (line[0] == '[')
5226 in_printers = !strcmp(line, "[printers]");
5227 }
5228
5229 cupsFileClose(nfp);
5230 cupsFileClose(ofp);
5231 rename(newfile, SMBConfigFile + 8);
5232 }
5233 else
5234 cupsdLogMessage(CUPSD_LOG_INFO, "Unknown SMBConfigFile scheme!");
5235 }
5236
5237
5238 /*
5239 * End of "$Id: dirsvc.c 7676 2008-06-18 23:42:37Z mike $".
5240 */