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