~ubuntu-branches/ubuntu/utopic/cups/utopic

« back to all changes in this revision

Viewing changes to .pc/no-conffile-timestamp.patch/scheduler/dirsvc.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt, Till Kamppeter, Martin Pitt
  • Date: 2011-07-14 15:02:36 UTC
  • mfrom: (1.2.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110714150236-skkf0p5m6ccu5usu
Tags: 1.4.7-1
* New upstream version.

[ Till Kamppeter ]
* debian/patches/ubuntu-upstart.dpatch: Updated the patch to add support
  to the new device enumeration functionality of udev-configure-printer.
  This way we do not need to retrigger the printers. Retriggering is only
  needed if udev rules change. A fallback to the old bahavior is provided
  so that this CUPS package continues to work with older versions of
  udev-configure-printer.

[ Martin Pitt ]
* Update patches for new upstream release.
* Drop fix-broken-ipv6-uris.patch, applied upstream.
* debian/local/apparmor-profile: /var/run → /run transition. (LP: #810270)
* Drop debian/patches/ubuntu-upstart.dpatch and move the upstart script to
  debian/local/cups.upstart. In debian/rules, copy it to debian/, and remove
  that again during clean. This is a slightly easier workaround for a
  nonexisting "dh_installinit --sysvinit-only" option than the previous
  creation of the upstart file with an ubuntu specific dpatch.
* debian/patches/, debian/rules, debian/control, debian/source/format: Move
  to source format "3.0 (quilt)" and convert our dpatches to quilt patches.
  Drop dpatch build dependency.
* Move Ubuntu specific patches to debian/patches/ubuntu. In debian/rules,
  apply them when building on Ubuntu. Add "patch" build dependency.

Show diffs side-by-side

added added

removed removed

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