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