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