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