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