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