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