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