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