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