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