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