Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/adminutil.c
Line
Count
Source
1
/*
2
 * Administration utility API definitions for CUPS.
3
 *
4
 * Copyright 2007-2016 by Apple Inc.
5
 * Copyright 2001-2007 by Easy Software Products.
6
 *
7
 * These coded instructions, statements, and computer programs are the
8
 * property of Apple Inc. and are protected by Federal copyright
9
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10
 * which should have been included with this file.  If this file is
11
 * missing or damaged, see the license at "http://www.cups.org/".
12
 *
13
 * This file is subject to the Apple OS-Developed Software exception.
14
 */
15
16
/*
17
 * Include necessary headers...
18
 */
19
20
#include "cups-private.h"
21
#include "ppd.h"
22
#include "adminutil.h"
23
#include <fcntl.h>
24
#include <sys/stat.h>
25
#ifdef _WIN32
26
#else
27
#  include <unistd.h>
28
#  include <sys/wait.h>
29
#endif /* _WIN32 */
30
31
32
/*
33
 * Local functions...
34
 */
35
36
static int    do_samba_command(const char *command,
37
                       const char *address,
38
                       const char *subcommand,
39
           const char *authfile,
40
           FILE *logfile);
41
static http_status_t  get_cupsd_conf(http_t *http, _cups_globals_t *cg,
42
                     time_t last_update, char *name,
43
               size_t namelen, int *remote);
44
static void   invalidate_cupsd_cache(_cups_globals_t *cg);
45
static void   write_option(cups_file_t *dstfp, int order,
46
                   const char *name, const char *text,
47
             const char *attrname,
48
                   ipp_attribute_t *suppattr,
49
             ipp_attribute_t *defattr, int defval,
50
             int valcount);
51
52
53
/*
54
 * 'cupsAdminCreateWindowsPPD()' - Create the Windows PPD file for a printer.
55
 *
56
 * @deprecated@
57
 */
58
59
char *          /* O - PPD file or NULL */
60
cupsAdminCreateWindowsPPD(
61
    http_t     *http,     /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
62
    const char *dest,     /* I - Printer or class */
63
    char       *buffer,     /* I - Filename buffer */
64
    int        bufsize)     /* I - Size of filename buffer */
65
0
{
66
0
  const char    *src;   /* Source PPD filename */
67
0
  cups_file_t   *srcfp,   /* Source PPD file */
68
0
      *dstfp;   /* Destination PPD file */
69
0
  ipp_t     *request, /* IPP request */
70
0
      *response;  /* IPP response */
71
0
  ipp_attribute_t *suppattr,  /* IPP -supported attribute */
72
0
      *defattr; /* IPP -default attribute */
73
0
  cups_lang_t   *language;  /* Current language */
74
0
  char      line[256],  /* Line from PPD file */
75
0
      junk[256],  /* Extra junk to throw away */
76
0
      *ptr,   /* Pointer into line */
77
0
      uri[1024],  /* Printer URI */
78
0
      option[41], /* Option */
79
0
      choice[41]; /* Choice */
80
0
  int     jcloption,  /* In a JCL option? */
81
0
      jclorder, /* Next JCL order dependency */
82
0
      linenum;  /* Current line number */
83
0
  time_t    curtime;  /* Current time */
84
0
  struct tm   *curdate; /* Current date */
85
0
  static const char * const pattrs[] =  /* Printer attributes we want */
86
0
      {
87
0
        "job-hold-until-supported",
88
0
        "job-hold-until-default",
89
0
        "job-sheets-supported",
90
0
        "job-sheets-default",
91
0
        "job-priority-supported",
92
0
        "job-priority-default"
93
0
      };
94
95
96
 /*
97
  * Range check the input...
98
  */
99
100
0
  if (buffer)
101
0
    *buffer = '\0';
102
103
0
  if (!http)
104
0
    http = _cupsConnect();
105
106
0
  if (!http || !dest || !buffer || bufsize < 2)
107
0
    return (NULL);
108
109
 /*
110
  * Get the PPD file...
111
  */
112
113
0
  if ((src = cupsGetPPD2(http, dest)) == NULL)
114
0
    return (NULL);
115
116
 /*
117
  * Get the supported banner pages, etc. for the printer...
118
  */
119
120
0
  request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
121
122
0
  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
123
0
                   "localhost", 0, "/printers/%s", dest);
124
0
  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
125
0
               "printer-uri", NULL, uri);
126
127
0
  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
128
0
                "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
129
0
    NULL, pattrs);
130
131
 /*
132
  * Do the request and get back a response...
133
  */
134
135
0
  response = cupsDoRequest(http, request, "/");
136
0
  if (!response || cupsLastError() > IPP_STATUS_OK_CONFLICTING)
137
0
  {
138
0
    unlink(src);
139
0
    return (NULL);
140
0
  }
141
142
 /*
143
  * Open the original PPD file...
144
  */
145
146
0
  if ((srcfp = cupsFileOpen(src, "rb")) == NULL)
147
0
    return (NULL);
148
149
 /*
150
  * Create a temporary output file using the destination buffer...
151
  */
152
153
0
  if ((dstfp = cupsTempFile2(buffer, bufsize)) == NULL)
154
0
  {
155
0
    cupsFileClose(srcfp);
156
157
0
    unlink(src);
158
159
0
    return (NULL);
160
0
  }
161
162
 /*
163
  * Write a new header explaining that this isn't the original PPD...
164
  */
165
166
0
  cupsFilePuts(dstfp, "*PPD-Adobe: \"4.3\"\n");
167
168
0
  curtime = time(NULL);
169
0
  curdate = gmtime(&curtime);
170
171
0
  cupsFilePrintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 "
172
0
                        "for CUPS Windows Driver\n",
173
0
           curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday,
174
0
           curdate->tm_hour, curdate->tm_min, curdate->tm_sec);
175
176
 /*
177
  * Read the existing PPD file, converting all PJL commands to CUPS
178
  * job ticket comments...
179
  */
180
181
0
  jcloption = 0;
182
0
  jclorder  = 0;
183
0
  linenum   = 0;
184
0
  language  = cupsLangDefault();
185
186
0
  while (cupsFileGets(srcfp, line, sizeof(line)))
187
0
  {
188
0
    linenum ++;
189
190
0
    if (!strncmp(line, "*PPD-Adobe:", 11))
191
0
    {
192
     /*
193
      * Already wrote the PPD header...
194
      */
195
196
0
      continue;
197
0
    }
198
0
    else if (!strncmp(line, "*JCLBegin:", 10) ||
199
0
             !strncmp(line, "*JCLToPSInterpreter:", 20) ||
200
0
       !strncmp(line, "*JCLEnd:", 8) ||
201
0
       !strncmp(line, "*Protocols:", 11))
202
0
    {
203
     /*
204
      * Don't use existing JCL keywords; we'll create our own, below...
205
      */
206
207
0
      cupsFilePrintf(dstfp, "*%% Commented out for CUPS Windows Driver...\n"
208
0
                            "*%%%s\n", line + 1);
209
0
      continue;
210
0
    }
211
0
    else if (!strncmp(line, "*JCLOpenUI", 10))
212
0
    {
213
0
      jcloption = 1;
214
0
      cupsFilePrintf(dstfp, "%s\n", line);
215
0
    }
216
0
    else if (!strncmp(line, "*JCLCloseUI", 11))
217
0
    {
218
0
      jcloption = 0;
219
0
      cupsFilePrintf(dstfp, "%s\n", line);
220
0
    }
221
0
    else if (jcloption && !strncmp(line, "*OrderDependency:", 17))
222
0
    {
223
0
      for (ptr = line + 17; _cups_isspace(*ptr); ptr ++);
224
225
0
      ptr = strchr(ptr, ' ');
226
227
0
      if (ptr)
228
0
      {
229
0
  cupsFilePrintf(dstfp, "*OrderDependency: %d%s\n", jclorder, ptr);
230
0
  jclorder ++;
231
0
      }
232
0
      else
233
0
        cupsFilePrintf(dstfp, "%s\n", line);
234
0
    }
235
0
    else if (jcloption &&
236
0
             strncmp(line, "*End", 4) &&
237
0
             strncmp(line, "*Default", 8))
238
0
    {
239
0
      if ((ptr = strchr(line, ':')) == NULL)
240
0
      {
241
0
        snprintf(line, sizeof(line),
242
0
           _cupsLangString(language, _("Missing value on line %d.")),
243
0
     linenum);
244
0
        _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0);
245
246
0
        cupsFileClose(srcfp);
247
0
        cupsFileClose(dstfp);
248
249
0
  unlink(src);
250
0
  unlink(buffer);
251
252
0
        *buffer = '\0';
253
254
0
  return (NULL);
255
0
      }
256
257
0
      if ((ptr = strchr(ptr, '\"')) == NULL)
258
0
      {
259
0
        snprintf(line, sizeof(line),
260
0
           _cupsLangString(language,
261
0
                     _("Missing double quote on line %d.")),
262
0
           linenum);
263
0
        _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0);
264
265
0
        cupsFileClose(srcfp);
266
0
        cupsFileClose(dstfp);
267
268
0
  unlink(src);
269
0
  unlink(buffer);
270
271
0
        *buffer = '\0';
272
273
0
  return (NULL);
274
0
      }
275
276
0
      if (sscanf(line, "*%40s%*[ \t]%40[^:/]", option, choice) != 2)
277
0
      {
278
0
        snprintf(line, sizeof(line),
279
0
           _cupsLangString(language,
280
0
                     _("Bad option + choice on line %d.")),
281
0
           linenum);
282
0
        _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, line, 0);
283
284
0
        cupsFileClose(srcfp);
285
0
        cupsFileClose(dstfp);
286
287
0
  unlink(src);
288
0
  unlink(buffer);
289
290
0
        *buffer = '\0';
291
292
0
  return (NULL);
293
0
      }
294
295
0
      if (strchr(ptr + 1, '\"') == NULL)
296
0
      {
297
       /*
298
        * Skip remaining...
299
  */
300
301
0
  while (cupsFileGets(srcfp, junk, sizeof(junk)) != NULL)
302
0
  {
303
0
    linenum ++;
304
305
0
    if (!strncmp(junk, "*End", 4))
306
0
      break;
307
0
  }
308
0
      }
309
310
0
      snprintf(ptr + 1, sizeof(line) - (size_t)(ptr - line + 1),
311
0
               "%%cupsJobTicket: %s=%s\n\"\n*End", option, choice);
312
313
0
      cupsFilePrintf(dstfp, "*%% Changed for CUPS Windows Driver...\n%s\n",
314
0
                     line);
315
0
    }
316
0
    else
317
0
      cupsFilePrintf(dstfp, "%s\n", line);
318
0
  }
319
320
0
  cupsFileClose(srcfp);
321
0
  unlink(src);
322
323
0
  if (linenum == 0)
324
0
  {
325
0
    _cupsSetError(IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR, _("Empty PPD file."), 1);
326
327
0
    cupsFileClose(dstfp);
328
0
    unlink(buffer);
329
330
0
    *buffer = '\0';
331
332
0
    return (NULL);
333
0
  }
334
335
 /*
336
  * Now add the CUPS-specific attributes and options...
337
  */
338
339
0
  cupsFilePuts(dstfp, "\n*% CUPS Job Ticket support and options...\n");
340
0
  cupsFilePuts(dstfp, "*Protocols: PJL\n");
341
0
  cupsFilePuts(dstfp, "*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n");
342
0
  cupsFilePuts(dstfp, "*JCLToPSInterpreter: \"\"\n");
343
0
  cupsFilePuts(dstfp, "*JCLEnd: \"\"\n");
344
345
0
  cupsFilePuts(dstfp, "\n*OpenGroup: CUPS/CUPS Options\n\n");
346
347
0
  if ((defattr = ippFindAttribute(response, "job-hold-until-default",
348
0
                                  IPP_TAG_ZERO)) != NULL &&
349
0
      (suppattr = ippFindAttribute(response, "job-hold-until-supported",
350
0
                                   IPP_TAG_ZERO)) != NULL)
351
0
    write_option(dstfp, jclorder ++, "cupsJobHoldUntil", "Hold Until",
352
0
                 "job-hold-until", suppattr, defattr, 0, 1);
353
354
0
  if ((defattr = ippFindAttribute(response, "job-priority-default",
355
0
                                  IPP_TAG_INTEGER)) != NULL &&
356
0
      (suppattr = ippFindAttribute(response, "job-priority-supported",
357
0
                                   IPP_TAG_RANGE)) != NULL)
358
0
    write_option(dstfp, jclorder ++, "cupsJobPriority", "Priority",
359
0
                 "job-priority", suppattr, defattr, 0, 1);
360
361
0
  if ((defattr = ippFindAttribute(response, "job-sheets-default",
362
0
                                  IPP_TAG_ZERO)) != NULL &&
363
0
      (suppattr = ippFindAttribute(response, "job-sheets-supported",
364
0
                                   IPP_TAG_ZERO)) != NULL)
365
0
  {
366
0
    write_option(dstfp, jclorder ++, "cupsJobSheetsStart", "Start Banner",
367
0
                 "job-sheets", suppattr, defattr, 0, 2);
368
0
    write_option(dstfp, jclorder, "cupsJobSheetsEnd", "End Banner",
369
0
                 "job-sheets", suppattr, defattr, 1, 2);
370
0
  }
371
372
0
  cupsFilePuts(dstfp, "*CloseGroup: CUPS\n");
373
0
  cupsFileClose(dstfp);
374
375
0
  ippDelete(response);
376
377
0
  return (buffer);
378
0
}
379
380
381
/*
382
 * 'cupsAdminExportSamba()' - Export a printer to Samba.
383
 *
384
 * @deprecated@
385
 */
386
387
int         /* O - 1 on success, 0 on failure */
388
cupsAdminExportSamba(
389
    const char *dest,     /* I - Destination to export */
390
    const char *ppd,      /* I - PPD file */
391
    const char *samba_server,   /* I - Samba server */
392
    const char *samba_user,   /* I - Samba username */
393
    const char *samba_password,   /* I - Samba password */
394
    FILE       *logfile)    /* I - Log file, if any */
395
0
{
396
0
  int     status;   /* Status of Samba commands */
397
0
  int     have_drivers; /* Have drivers? */
398
0
  char      file[1024], /* File to test for */
399
0
      authfile[1024], /* Temporary authentication file */
400
0
      address[1024],  /* Address for command */
401
0
      subcmd[1024], /* Sub-command */
402
0
      message[1024];  /* Error message */
403
0
  cups_file_t   *fp;    /* Authentication file */
404
0
  cups_lang_t   *language;  /* Current language */
405
0
  _cups_globals_t *cg = _cupsGlobals();
406
          /* Global data */
407
408
409
 /*
410
  * Range check input...
411
  */
412
413
0
  if (!dest || !ppd || !samba_server || !samba_user || !samba_password)
414
0
  {
415
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
416
0
    return (0);
417
0
  }
418
419
 /*
420
  * Create a temporary authentication file for Samba...
421
  */
422
423
0
  if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL)
424
0
  {
425
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
426
0
    return (0);
427
0
  }
428
429
0
  cupsFilePrintf(fp, "username = %s\n", samba_user);
430
0
  cupsFilePrintf(fp, "password = %s\n", samba_password);
431
0
  cupsFileClose(fp);
432
433
 /*
434
  * See which drivers are available; the new CUPS v6 and Adobe drivers
435
  * depend on the Windows 2k PS driver, so copy that driver first:
436
  *
437
  * Files:
438
  *
439
  *     ps5ui.dll
440
  *     pscript.hlp
441
  *     pscript.ntf
442
  *     pscript5.dll
443
  */
444
445
0
  have_drivers = 0;
446
0
  language     = cupsLangDefault();
447
448
0
  snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", cg->cups_datadir);
449
0
  if (!access(file, 0))
450
0
  {
451
0
    have_drivers |= 1;
452
453
   /*
454
    * Windows 2k driver is installed; do the smbclient commands needed
455
    * to copy the Win2k drivers over...
456
    */
457
458
0
    snprintf(address, sizeof(address), "//%s/print$", samba_server);
459
460
0
    snprintf(subcmd, sizeof(subcmd),
461
0
             "mkdir W32X86;"
462
0
       "put %s W32X86/%s.ppd;"
463
0
       "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;"
464
0
       "put %s/drivers/pscript.hlp W32X86/pscript.hlp;"
465
0
       "put %s/drivers/pscript.ntf W32X86/pscript.ntf;"
466
0
       "put %s/drivers/pscript5.dll W32X86/pscript5.dll",
467
0
       ppd, dest, cg->cups_datadir, cg->cups_datadir,
468
0
       cg->cups_datadir, cg->cups_datadir);
469
470
0
    if ((status = do_samba_command("smbclient", address, subcmd,
471
0
                                   authfile, logfile)) != 0)
472
0
    {
473
0
      snprintf(message, sizeof(message),
474
0
               _cupsLangString(language,
475
0
                         _("Unable to copy Windows 2000 printer "
476
0
                           "driver files (%d).")), status);
477
478
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
479
480
0
      if (logfile)
481
0
  _cupsLangPuts(logfile, message);
482
483
0
      unlink(authfile);
484
485
0
      return (0);
486
0
    }
487
488
   /*
489
    * See if we also have the CUPS driver files; if so, use them!
490
    */
491
492
0
    snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", cg->cups_datadir);
493
0
    if (!access(file, 0))
494
0
    {
495
     /*
496
      * Copy the CUPS driver files over...
497
      */
498
499
0
      snprintf(subcmd, sizeof(subcmd),
500
0
               "put %s/drivers/cups6.ini W32X86/cups6.ini;"
501
0
               "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;"
502
0
         "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll",
503
0
         cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
504
505
0
      if ((status = do_samba_command("smbclient", address, subcmd,
506
0
                                     authfile, logfile)) != 0)
507
0
      {
508
0
  snprintf(message, sizeof(message),
509
0
           _cupsLangString(language,
510
0
                           _("Unable to copy CUPS printer driver "
511
0
           "files (%d).")), status);
512
513
0
  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
514
515
0
  if (logfile)
516
0
    _cupsLangPuts(logfile, message);
517
518
0
        unlink(authfile);
519
520
0
  return (0);
521
0
      }
522
523
     /*
524
      * Do the rpcclient command needed for the CUPS drivers...
525
      */
526
527
0
      snprintf(subcmd, sizeof(subcmd),
528
0
               "adddriver \"Windows NT x86\" \"%s:"
529
0
         "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
530
0
         "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
531
0
         "cups6.ini,cupsps6.dll,cupsui6.dll\"",
532
0
         dest, dest, dest);
533
0
    }
534
0
    else
535
0
    {
536
     /*
537
      * Don't have the CUPS drivers, so just use the standard Windows
538
      * drivers...
539
      */
540
541
0
      snprintf(subcmd, sizeof(subcmd),
542
0
               "adddriver \"Windows NT x86\" \"%s:"
543
0
         "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
544
0
         "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
545
0
         dest, dest, dest);
546
0
    }
547
548
0
    if ((status = do_samba_command("rpcclient", samba_server, subcmd,
549
0
                                   authfile, logfile)) != 0)
550
0
    {
551
0
      snprintf(message, sizeof(message),
552
0
               _cupsLangString(language,
553
0
                         _("Unable to install Windows 2000 printer "
554
0
               "driver files (%d).")), status);
555
556
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
557
558
0
      if (logfile)
559
0
  _cupsLangPuts(logfile, message);
560
561
0
      unlink(authfile);
562
563
0
      return (0);
564
0
    }
565
0
  }
566
567
 /*
568
  * See if we have the Win9x PS driver...
569
  */
570
571
0
  snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", cg->cups_datadir);
572
0
  if (!access(file, 0))
573
0
  {
574
0
    have_drivers |= 2;
575
576
   /*
577
    * Do the smbclient commands needed for the Adobe Win9x drivers...
578
    */
579
580
0
    snprintf(address, sizeof(address), "//%s/print$", samba_server);
581
582
0
    snprintf(subcmd, sizeof(subcmd),
583
0
             "mkdir WIN40;"
584
0
       "put %s WIN40/%s.PPD;"
585
0
       "put %s/drivers/ADFONTS.MFM WIN40/ADFONTS.MFM;"
586
0
       "put %s/drivers/ADOBEPS4.DRV WIN40/ADOBEPS4.DRV;"
587
0
       "put %s/drivers/ADOBEPS4.HLP WIN40/ADOBEPS4.HLP;"
588
0
       "put %s/drivers/ICONLIB.DLL WIN40/ICONLIB.DLL;"
589
0
       "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;",
590
0
       ppd, dest, cg->cups_datadir, cg->cups_datadir,
591
0
       cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
592
593
0
    if ((status = do_samba_command("smbclient", address, subcmd,
594
0
                                   authfile, logfile)) != 0)
595
0
    {
596
0
      snprintf(message, sizeof(message),
597
0
               _cupsLangString(language,
598
0
                         _("Unable to copy Windows 9x printer "
599
0
               "driver files (%d).")), status);
600
601
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
602
603
0
      if (logfile)
604
0
  _cupsLangPuts(logfile, message);
605
606
0
      unlink(authfile);
607
608
0
      return (0);
609
0
    }
610
611
   /*
612
    * Do the rpcclient commands needed for the Adobe Win9x drivers...
613
    */
614
615
0
    snprintf(subcmd, sizeof(subcmd),
616
0
       "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:"
617
0
       "ADOBEPS4.HLP:PSMON.DLL:RAW:"
618
0
       "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM,"
619
0
       "ICONLIB.DLL\"",
620
0
       dest, dest, dest);
621
622
0
    if ((status = do_samba_command("rpcclient", samba_server, subcmd,
623
0
                                   authfile, logfile)) != 0)
624
0
    {
625
0
      snprintf(message, sizeof(message),
626
0
               _cupsLangString(language,
627
0
                         _("Unable to install Windows 9x printer "
628
0
               "driver files (%d).")), status);
629
630
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
631
632
0
      if (logfile)
633
0
  _cupsLangPuts(logfile, message);
634
635
0
      unlink(authfile);
636
637
0
      return (0);
638
0
    }
639
0
  }
640
641
 /*
642
  * See if we have the 64-bit Windows PS driver...
643
  *
644
  * Files:
645
  *
646
  *     x64/ps5ui.dll
647
  *     x64/pscript.hlp
648
  *     x64/pscript.ntf
649
  *     x64/pscript5.dll
650
  */
651
652
0
  snprintf(file, sizeof(file), "%s/drivers/x64/pscript5.dll", cg->cups_datadir);
653
0
  if (!access(file, 0))
654
0
  {
655
0
    have_drivers |= 4;
656
657
   /*
658
    * 64-bit Windows driver is installed; do the smbclient commands needed
659
    * to copy the Win64 drivers over...
660
    */
661
662
0
    snprintf(address, sizeof(address), "//%s/print$", samba_server);
663
664
0
    snprintf(subcmd, sizeof(subcmd),
665
0
             "mkdir x64;"
666
0
       "put %s x64/%s.ppd;"
667
0
       "put %s/drivers/x64/ps5ui.dll x64/ps5ui.dll;"
668
0
       "put %s/drivers/x64/pscript.hlp x64/pscript.hlp;"
669
0
       "put %s/drivers/x64/pscript.ntf x64/pscript.ntf;"
670
0
       "put %s/drivers/x64/pscript5.dll x64/pscript5.dll",
671
0
       ppd, dest, cg->cups_datadir, cg->cups_datadir,
672
0
       cg->cups_datadir, cg->cups_datadir);
673
674
0
    if ((status = do_samba_command("smbclient", address, subcmd,
675
0
                                   authfile, logfile)) != 0)
676
0
    {
677
0
      snprintf(message, sizeof(message),
678
0
               _cupsLangString(language,
679
0
                         _("Unable to copy 64-bit Windows printer "
680
0
                           "driver files (%d).")), status);
681
682
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
683
684
0
      if (logfile)
685
0
  _cupsLangPuts(logfile, message);
686
687
0
      unlink(authfile);
688
689
0
      return (0);
690
0
    }
691
692
   /*
693
    * See if we also have the CUPS driver files; if so, use them!
694
    */
695
696
0
    snprintf(file, sizeof(file), "%s/drivers/x64/cupsps6.dll", cg->cups_datadir);
697
0
    if (!access(file, 0))
698
0
    {
699
     /*
700
      * Copy the CUPS driver files over...
701
      */
702
703
0
      snprintf(subcmd, sizeof(subcmd),
704
0
               "put %s/drivers/x64/cups6.ini x64/cups6.ini;"
705
0
               "put %s/drivers/x64/cupsps6.dll x64/cupsps6.dll;"
706
0
         "put %s/drivers/x64/cupsui6.dll x64/cupsui6.dll",
707
0
         cg->cups_datadir, cg->cups_datadir, cg->cups_datadir);
708
709
0
      if ((status = do_samba_command("smbclient", address, subcmd,
710
0
                                     authfile, logfile)) != 0)
711
0
      {
712
0
  snprintf(message, sizeof(message),
713
0
           _cupsLangString(language,
714
0
                           _("Unable to copy 64-bit CUPS printer driver "
715
0
           "files (%d).")), status);
716
717
0
  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
718
719
0
  if (logfile)
720
0
    _cupsLangPuts(logfile, message);
721
722
0
        unlink(authfile);
723
724
0
  return (0);
725
0
      }
726
727
     /*
728
      * Do the rpcclient command needed for the CUPS drivers...
729
      */
730
731
0
      snprintf(subcmd, sizeof(subcmd),
732
0
               "adddriver \"Windows x64\" \"%s:"
733
0
         "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
734
0
         "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf,"
735
0
         "cups6.ini,cupsps6.dll,cupsui6.dll\"",
736
0
         dest, dest, dest);
737
0
    }
738
0
    else
739
0
    {
740
     /*
741
      * Don't have the CUPS drivers, so just use the standard Windows
742
      * drivers...
743
      */
744
745
0
      snprintf(subcmd, sizeof(subcmd),
746
0
               "adddriver \"Windows x64\" \"%s:"
747
0
         "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:"
748
0
         "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"",
749
0
         dest, dest, dest);
750
0
    }
751
752
0
    if ((status = do_samba_command("rpcclient", samba_server, subcmd,
753
0
                                   authfile, logfile)) != 0)
754
0
    {
755
0
      snprintf(message, sizeof(message),
756
0
               _cupsLangString(language,
757
0
                         _("Unable to install Windows 2000 printer "
758
0
               "driver files (%d).")), status);
759
760
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
761
762
0
      if (logfile)
763
0
  _cupsLangPuts(logfile, message);
764
765
0
      unlink(authfile);
766
767
0
      return (0);
768
0
    }
769
0
  }
770
771
0
  if (logfile && !(have_drivers & 1))
772
0
  {
773
0
    if (!have_drivers)
774
0
      strlcpy(message,
775
0
              _cupsLangString(language,
776
0
                        _("No Windows printer drivers are installed.")),
777
0
              sizeof(message));
778
0
    else
779
0
      strlcpy(message,
780
0
              _cupsLangString(language,
781
0
                        _("Warning, no Windows 2000 printer drivers "
782
0
        "are installed.")),
783
0
              sizeof(message));
784
785
0
    _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, message, 0);
786
0
    _cupsLangPuts(logfile, message);
787
0
  }
788
789
0
  if (have_drivers == 0)
790
0
  {
791
0
    _cupsSetError(IPP_STATUS_ERROR_NOT_FOUND, message, 0);
792
793
0
    unlink(authfile);
794
795
0
    return (0);
796
0
  }
797
798
 /*
799
  * Finally, associate the drivers we just added with the queue...
800
  */
801
802
0
  snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest);
803
804
0
  if ((status = do_samba_command("rpcclient", samba_server, subcmd,
805
0
                                 authfile, logfile)) != 0)
806
0
  {
807
0
    snprintf(message, sizeof(message),
808
0
             _cupsLangString(language,
809
0
                 _("Unable to set Windows printer driver (%d).")),
810
0
                 status);
811
812
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
813
814
0
    if (logfile)
815
0
      _cupsLangPuts(logfile, message);
816
817
0
    unlink(authfile);
818
819
0
    return (0);
820
0
  }
821
822
0
  unlink(authfile);
823
824
0
  return (1);
825
0
}
826
827
828
/*
829
 * 'cupsAdminGetServerSettings()' - Get settings from the server.
830
 *
831
 * The returned settings should be freed with cupsFreeOptions() when
832
 * you are done with them.
833
 *
834
 * @since CUPS 1.3/macOS 10.5@
835
 */
836
837
int         /* O - 1 on success, 0 on failure */
838
cupsAdminGetServerSettings(
839
    http_t        *http,    /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
840
    int           *num_settings,  /* O - Number of settings */
841
    cups_option_t **settings)   /* O - Settings */
842
0
{
843
0
  int   i;      /* Looping var */
844
0
  cups_file_t *cupsd;     /* cupsd.conf file */
845
0
  char    cupsdconf[1024];  /* cupsd.conf filename */
846
0
  int   remote;     /* Remote cupsd.conf file? */
847
0
  http_status_t status;     /* Status of getting cupsd.conf */
848
0
  char    line[1024],   /* Line from cupsd.conf file */
849
0
    *value;     /* Value on line */
850
0
  cups_option_t *setting;   /* Current setting */
851
0
  _cups_globals_t *cg = _cupsGlobals(); /* Global data */
852
853
854
 /*
855
  * Range check input...
856
  */
857
858
0
  if (!http)
859
0
  {
860
   /*
861
    * See if we are connected to the same server...
862
    */
863
864
0
    if (cg->http)
865
0
    {
866
     /*
867
      * Compare the connection hostname, port, and encryption settings to
868
      * the cached defaults; these were initialized the first time we
869
      * connected...
870
      */
871
872
0
      if (strcmp(cg->http->hostname, cg->server) ||
873
0
          cg->ipp_port != httpAddrPort(cg->http->hostaddr) ||
874
0
    (cg->http->encryption != cg->encryption &&
875
0
     cg->http->encryption == HTTP_ENCRYPTION_NEVER))
876
0
      {
877
       /*
878
  * Need to close the current connection because something has changed...
879
  */
880
881
0
  httpClose(cg->http);
882
0
  cg->http = NULL;
883
0
      }
884
0
    }
885
886
   /*
887
    * (Re)connect as needed...
888
    */
889
890
0
    if (!cg->http)
891
0
    {
892
0
      if ((cg->http = httpConnect2(cupsServer(), ippPort(), NULL, AF_UNSPEC,
893
0
                                   cupsEncryption(), 1, 0, NULL)) == NULL)
894
0
      {
895
0
  if (errno)
896
0
    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, NULL, 0);
897
0
  else
898
0
    _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE,
899
0
      _("Unable to connect to host."), 1);
900
901
0
  if (num_settings)
902
0
    *num_settings = 0;
903
904
0
  if (settings)
905
0
    *settings = NULL;
906
907
0
  return (0);
908
0
      }
909
0
    }
910
911
0
    http = cg->http;
912
0
  }
913
914
0
  if (!http || !num_settings || !settings)
915
0
  {
916
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
917
918
0
    if (num_settings)
919
0
      *num_settings = 0;
920
921
0
    if (settings)
922
0
      *settings = NULL;
923
924
0
    return (0);
925
0
  }
926
927
0
  *num_settings = 0;
928
0
  *settings     = NULL;
929
930
 /*
931
  * Get the cupsd.conf file...
932
  */
933
934
0
  if ((status = get_cupsd_conf(http, cg, cg->cupsd_update, cupsdconf,
935
0
                               sizeof(cupsdconf), &remote)) == HTTP_STATUS_OK)
936
0
  {
937
0
    if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
938
0
    {
939
0
      char  message[1024];    /* Message string */
940
941
942
0
      snprintf(message, sizeof(message),
943
0
               _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
944
0
               cupsdconf, strerror(errno));
945
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
946
0
    }
947
0
  }
948
0
  else
949
0
    cupsd = NULL;
950
951
0
  if (cupsd)
952
0
  {
953
   /*
954
    * Read the file, keeping track of what settings are enabled...
955
    */
956
957
0
    int   remote_access = 0,  /* Remote access allowed? */
958
0
    remote_admin = 0, /* Remote administration allowed? */
959
0
    remote_any = 0,   /* Remote access from anywhere allowed? */
960
0
    browsing = 1,   /* Browsing enabled? */
961
0
    cancel_policy = 1,  /* Cancel-job policy set? */
962
0
    debug_logging = 0;  /* LogLevel debug set? */
963
0
    int   linenum = 0,    /* Line number in file */
964
0
    in_location = 0,  /* In a location section? */
965
0
    in_policy = 0,    /* In a policy section? */
966
0
    in_cancel_job = 0,  /* In a cancel-job section? */
967
0
    in_admin_location = 0;  /* In the /admin location? */
968
969
970
0
    invalidate_cupsd_cache(cg);
971
972
0
    cg->cupsd_update = time(NULL);
973
0
    httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
974
975
0
    while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
976
0
    {
977
0
      if (!value && strncmp(line, "</", 2))
978
0
        value = line + strlen(line);
979
980
0
      if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && value)
981
0
      {
982
0
  char  *port;      /* Pointer to port number, if any */
983
984
985
0
  if ((port = strrchr(value, ':')) != NULL)
986
0
    *port = '\0';
987
0
  else if (isdigit(*value & 255))
988
0
  {
989
   /*
990
    * Listen on a port number implies remote access...
991
    */
992
993
0
    remote_access = 1;
994
0
    continue;
995
0
  }
996
997
0
  if (_cups_strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")
998
0
#ifdef AF_LOCAL
999
0
            && *value != '/'
1000
0
#endif /* AF_LOCAL */
1001
0
#ifdef AF_INET6
1002
0
            && strcmp(value, "[::1]")
1003
0
#endif /* AF_INET6 */
1004
0
      )
1005
0
    remote_access = 1;
1006
0
      }
1007
0
      else if (!_cups_strcasecmp(line, "Browsing"))
1008
0
      {
1009
0
  browsing = !_cups_strcasecmp(value, "yes") ||
1010
0
             !_cups_strcasecmp(value, "on") ||
1011
0
             !_cups_strcasecmp(value, "true");
1012
0
      }
1013
0
      else if (!_cups_strcasecmp(line, "LogLevel"))
1014
0
      {
1015
0
  debug_logging = !_cups_strncasecmp(value, "debug", 5);
1016
0
      }
1017
0
      else if (!_cups_strcasecmp(line, "<Policy") &&
1018
0
               !_cups_strcasecmp(value, "default"))
1019
0
      {
1020
0
  in_policy = 1;
1021
0
      }
1022
0
      else if (!_cups_strcasecmp(line, "</Policy>"))
1023
0
      {
1024
0
  in_policy = 0;
1025
0
      }
1026
0
      else if (!_cups_strcasecmp(line, "<Limit") && in_policy && value)
1027
0
      {
1028
       /*
1029
  * See if the policy limit is for the Cancel-Job operation...
1030
  */
1031
1032
0
  char  *valptr;    /* Pointer into value */
1033
1034
1035
0
  while (*value)
1036
0
  {
1037
0
    for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
1038
1039
0
    if (*valptr)
1040
0
      *valptr++ = '\0';
1041
1042
0
          if (!_cups_strcasecmp(value, "cancel-job") ||
1043
0
              !_cups_strcasecmp(value, "all"))
1044
0
    {
1045
0
      in_cancel_job = 1;
1046
0
      break;
1047
0
    }
1048
1049
0
          for (value = valptr; _cups_isspace(*value); value ++);
1050
0
  }
1051
0
      }
1052
0
      else if (!_cups_strcasecmp(line, "</Limit>"))
1053
0
      {
1054
0
  in_cancel_job = 0;
1055
0
      }
1056
0
      else if (!_cups_strcasecmp(line, "Require") && in_cancel_job)
1057
0
      {
1058
0
  cancel_policy = 0;
1059
0
      }
1060
0
      else if (!_cups_strcasecmp(line, "<Location") && value)
1061
0
      {
1062
0
        in_admin_location = !_cups_strcasecmp(value, "/admin");
1063
0
  in_location       = 1;
1064
0
      }
1065
0
      else if (!_cups_strcasecmp(line, "</Location>"))
1066
0
      {
1067
0
  in_admin_location = 0;
1068
0
  in_location       = 0;
1069
0
      }
1070
0
      else if (!_cups_strcasecmp(line, "Allow") && value &&
1071
0
               _cups_strcasecmp(value, "localhost") &&
1072
0
               _cups_strcasecmp(value, "127.0.0.1")
1073
0
#ifdef AF_LOCAL
1074
0
         && *value != '/'
1075
0
#endif /* AF_LOCAL */
1076
0
#ifdef AF_INET6
1077
0
         && strcmp(value, "::1")
1078
0
#endif /* AF_INET6 */
1079
0
         )
1080
0
      {
1081
0
        if (in_admin_location)
1082
0
    remote_admin = 1;
1083
0
        else if (!_cups_strcasecmp(value, "all"))
1084
0
    remote_any = 1;
1085
0
      }
1086
0
      else if (line[0] != '<' && !in_location && !in_policy &&
1087
0
         _cups_strcasecmp(line, "Allow") &&
1088
0
               _cups_strcasecmp(line, "AuthType") &&
1089
0
         _cups_strcasecmp(line, "Deny") &&
1090
0
         _cups_strcasecmp(line, "Order") &&
1091
0
         _cups_strcasecmp(line, "Require") &&
1092
0
         _cups_strcasecmp(line, "Satisfy"))
1093
0
        cg->cupsd_num_settings = cupsAddOption(line, value,
1094
0
                                         cg->cupsd_num_settings,
1095
0
                 &(cg->cupsd_settings));
1096
0
    }
1097
1098
0
    cupsFileClose(cupsd);
1099
1100
0
    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
1101
0
                                           debug_logging ? "1" : "0",
1102
0
             cg->cupsd_num_settings,
1103
0
             &(cg->cupsd_settings));
1104
1105
0
    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
1106
0
                                           (remote_access && remote_admin) ?
1107
0
                 "1" : "0",
1108
0
             cg->cupsd_num_settings,
1109
0
             &(cg->cupsd_settings));
1110
1111
0
    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
1112
0
                                           remote_any ? "1" : "0",
1113
0
             cg->cupsd_num_settings,
1114
0
             &(cg->cupsd_settings));
1115
1116
0
    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
1117
0
                                           (remote_access && browsing) ? "1" :
1118
0
                                                                         "0",
1119
0
             cg->cupsd_num_settings,
1120
0
             &(cg->cupsd_settings));
1121
1122
0
    cg->cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
1123
0
                                           cancel_policy ? "1" : "0",
1124
0
             cg->cupsd_num_settings,
1125
0
             &(cg->cupsd_settings));
1126
0
  }
1127
0
  else if (status != HTTP_STATUS_NOT_MODIFIED)
1128
0
    invalidate_cupsd_cache(cg);
1129
1130
 /*
1131
  * Remove any temporary files and copy the settings array...
1132
  */
1133
1134
0
  if (remote)
1135
0
    unlink(cupsdconf);
1136
1137
0
  for (i = cg->cupsd_num_settings, setting = cg->cupsd_settings;
1138
0
       i > 0;
1139
0
       i --, setting ++)
1140
0
    *num_settings = cupsAddOption(setting->name, setting->value,
1141
0
                                  *num_settings, settings);
1142
1143
0
  return (cg->cupsd_num_settings > 0);
1144
0
}
1145
1146
1147
/*
1148
 * 'cupsAdminSetServerSettings()' - Set settings on the server.
1149
 *
1150
 * @since CUPS 1.3/macOS 10.5@
1151
 */
1152
1153
int         /* O - 1 on success, 0 on failure */
1154
cupsAdminSetServerSettings(
1155
    http_t        *http,    /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
1156
    int           num_settings,   /* I - Number of settings */
1157
    cups_option_t *settings)    /* I - Settings */
1158
0
{
1159
0
  int   i;      /* Looping var */
1160
0
  http_status_t status;     /* GET/PUT status */
1161
0
  const char  *server_port_env; /* SERVER_PORT env var */
1162
0
  int   server_port;    /* IPP port for server */
1163
0
  cups_file_t *cupsd;     /* cupsd.conf file */
1164
0
  char    cupsdconf[1024];  /* cupsd.conf filename */
1165
0
  int   remote;     /* Remote cupsd.conf file? */
1166
0
  char    tempfile[1024];   /* Temporary new cupsd.conf */
1167
0
  cups_file_t *temp;      /* Temporary file */
1168
0
  char    line[1024],   /* Line from cupsd.conf file */
1169
0
    *value;     /* Value on line */
1170
0
  int   linenum,    /* Line number in file */
1171
0
    in_location,    /* In a location section? */
1172
0
    in_policy,    /* In a policy section? */
1173
0
    in_default_policy,  /* In the default policy section? */
1174
0
    in_cancel_job,    /* In a cancel-job section? */
1175
0
    in_admin_location,  /* In the /admin location? */
1176
0
    in_conf_location, /* In the /admin/conf location? */
1177
0
    in_log_location,  /* In the /admin/log location? */
1178
0
    in_root_location; /* In the / location? */
1179
0
  const char  *val;     /* Setting value */
1180
0
  int   share_printers,   /* Share local printers */
1181
0
    remote_admin,   /* Remote administration allowed? */
1182
0
    remote_any,   /* Remote access from anywhere? */
1183
0
    user_cancel_any,  /* Cancel-job policy set? */
1184
0
    debug_logging;    /* LogLevel debug set? */
1185
0
  int   wrote_port_listen,  /* Wrote the port/listen lines? */
1186
0
    wrote_browsing,   /* Wrote the browsing lines? */
1187
0
    wrote_policy,   /* Wrote the policy? */
1188
0
    wrote_loglevel,   /* Wrote the LogLevel line? */
1189
0
    wrote_admin_location, /* Wrote the /admin location? */
1190
0
    wrote_conf_location,  /* Wrote the /admin/conf location? */
1191
0
    wrote_log_location, /* Wrote the /admin/log location? */
1192
0
    wrote_root_location;  /* Wrote the / location? */
1193
0
  int   indent;     /* Indentation */
1194
0
  int   cupsd_num_settings; /* New number of settings */
1195
0
  int   old_share_printers, /* Share local printers */
1196
0
    old_remote_admin, /* Remote administration allowed? */
1197
0
    old_remote_any,   /* Remote access from anywhere? */
1198
0
    old_user_cancel_any,  /* Cancel-job policy set? */
1199
0
    old_debug_logging;  /* LogLevel debug set? */
1200
0
  cups_option_t *cupsd_settings,  /* New settings */
1201
0
    *setting;   /* Current setting */
1202
0
  _cups_globals_t *cg = _cupsGlobals(); /* Global data */
1203
1204
1205
 /*
1206
  * Range check input...
1207
  */
1208
1209
0
  if (!http)
1210
0
    http = _cupsConnect();
1211
1212
0
  if (!http || !num_settings || !settings)
1213
0
  {
1214
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1215
1216
0
    return (0);
1217
0
  }
1218
1219
 /*
1220
  * Get the cupsd.conf file...
1221
  */
1222
1223
0
  if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf),
1224
0
                     &remote) == HTTP_STATUS_OK)
1225
0
  {
1226
0
    if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
1227
0
    {
1228
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
1229
0
      return (0);
1230
0
    }
1231
0
  }
1232
0
  else
1233
0
    return (0);
1234
1235
 /*
1236
  * Get current settings...
1237
  */
1238
1239
0
  if (!cupsAdminGetServerSettings(http, &cupsd_num_settings,
1240
0
          &cupsd_settings))
1241
0
    return (0);
1242
1243
0
  if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings,
1244
0
                           cupsd_settings)) != NULL)
1245
0
    old_debug_logging = atoi(val);
1246
0
  else
1247
0
    old_debug_logging = 0;
1248
1249
0
  DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d",
1250
0
                old_debug_logging));
1251
1252
0
  if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings,
1253
0
                           cupsd_settings)) != NULL)
1254
0
    old_remote_admin = atoi(val);
1255
0
  else
1256
0
    old_remote_admin = 0;
1257
1258
0
  DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d",
1259
0
                old_remote_admin));
1260
1261
0
  if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings,
1262
0
                           cupsd_settings)) != NULL)
1263
0
    old_remote_any = atoi(val);
1264
0
  else
1265
0
    old_remote_any = 0;
1266
1267
0
  DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d",
1268
0
                old_remote_any));
1269
1270
0
  if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings,
1271
0
                           cupsd_settings)) != NULL)
1272
0
    old_share_printers = atoi(val);
1273
0
  else
1274
0
    old_share_printers = 0;
1275
1276
0
  DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d",
1277
0
                old_share_printers));
1278
1279
0
  if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings,
1280
0
                           cupsd_settings)) != NULL)
1281
0
    old_user_cancel_any = atoi(val);
1282
0
  else
1283
0
    old_user_cancel_any = 0;
1284
1285
0
  DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d",
1286
0
                old_user_cancel_any));
1287
1288
0
  cupsFreeOptions(cupsd_num_settings, cupsd_settings);
1289
1290
 /*
1291
  * Get basic settings...
1292
  */
1293
1294
0
  if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
1295
0
                           settings)) != NULL)
1296
0
  {
1297
0
    debug_logging = atoi(val);
1298
1299
0
    if (debug_logging == old_debug_logging)
1300
0
    {
1301
     /*
1302
      * No change to this setting...
1303
      */
1304
1305
0
      debug_logging = -1;
1306
0
    }
1307
0
  }
1308
0
  else
1309
0
    debug_logging = -1;
1310
1311
0
  DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d",
1312
0
                debug_logging));
1313
1314
0
  if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, settings)) != NULL)
1315
0
  {
1316
0
    remote_any = atoi(val);
1317
1318
0
    if (remote_any == old_remote_any)
1319
0
    {
1320
     /*
1321
      * No change to this setting...
1322
      */
1323
1324
0
      remote_any = -1;
1325
0
    }
1326
0
  }
1327
0
  else
1328
0
    remote_any = -1;
1329
1330
0
  DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d", remote_any));
1331
1332
0
  if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
1333
0
                           settings)) != NULL)
1334
0
  {
1335
0
    remote_admin = atoi(val);
1336
1337
0
    if (remote_admin == old_remote_admin)
1338
0
    {
1339
     /*
1340
      * No change to this setting...
1341
      */
1342
1343
0
      remote_admin = -1;
1344
0
    }
1345
0
  }
1346
0
  else
1347
0
    remote_admin = -1;
1348
1349
0
  DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d",
1350
0
                remote_admin));
1351
1352
0
  if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
1353
0
                           settings)) != NULL)
1354
0
  {
1355
0
    share_printers = atoi(val);
1356
1357
0
    if (share_printers == old_share_printers)
1358
0
    {
1359
     /*
1360
      * No change to this setting...
1361
      */
1362
1363
0
      share_printers = -1;
1364
0
    }
1365
0
  }
1366
0
  else
1367
0
    share_printers = -1;
1368
1369
0
  DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d",
1370
0
                share_printers));
1371
1372
0
  if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
1373
0
                           settings)) != NULL)
1374
0
  {
1375
0
    user_cancel_any = atoi(val);
1376
1377
0
    if (user_cancel_any == old_user_cancel_any)
1378
0
    {
1379
     /*
1380
      * No change to this setting...
1381
      */
1382
1383
0
      user_cancel_any = -1;
1384
0
    }
1385
0
  }
1386
0
  else
1387
0
    user_cancel_any = -1;
1388
1389
0
  DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d",
1390
0
                user_cancel_any));
1391
1392
 /*
1393
  * Create a temporary file for the new cupsd.conf file...
1394
  */
1395
1396
0
  if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
1397
0
  {
1398
0
    cupsFileClose(cupsd);
1399
1400
0
    if (remote)
1401
0
      unlink(cupsdconf);
1402
1403
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
1404
0
    return (0);
1405
0
  }
1406
1407
 /*
1408
  * Copy the old file to the new, making changes along the way...
1409
  */
1410
1411
0
  cupsd_num_settings   = 0;
1412
0
  in_admin_location    = 0;
1413
0
  in_cancel_job        = 0;
1414
0
  in_conf_location     = 0;
1415
0
  in_default_policy    = 0;
1416
0
  in_location          = 0;
1417
0
  in_log_location      = 0;
1418
0
  in_policy            = 0;
1419
0
  in_root_location     = 0;
1420
0
  linenum              = 0;
1421
0
  wrote_admin_location = 0;
1422
0
  wrote_browsing       = 0;
1423
0
  wrote_conf_location  = 0;
1424
0
  wrote_log_location   = 0;
1425
0
  wrote_loglevel       = 0;
1426
0
  wrote_policy         = 0;
1427
0
  wrote_port_listen    = 0;
1428
0
  wrote_root_location  = 0;
1429
0
  indent               = 0;
1430
1431
0
  if ((server_port_env = getenv("SERVER_PORT")) != NULL)
1432
0
  {
1433
0
    if ((server_port = atoi(server_port_env)) <= 0)
1434
0
      server_port = ippPort();
1435
0
  }
1436
0
  else
1437
0
    server_port = ippPort();
1438
1439
0
  if (server_port <= 0)
1440
0
    server_port = IPP_PORT;
1441
1442
0
  while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
1443
0
  {
1444
0
    if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) &&
1445
0
        (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1446
0
    {
1447
0
      if (!wrote_port_listen)
1448
0
      {
1449
0
        wrote_port_listen = 1;
1450
1451
0
  if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1452
0
  {
1453
0
    cupsFilePuts(temp, "# Allow remote access\n");
1454
0
    cupsFilePrintf(temp, "Port %d\n", server_port);
1455
0
  }
1456
0
  else
1457
0
  {
1458
0
    cupsFilePuts(temp, "# Only listen for connections from the local "
1459
0
                       "machine.\n");
1460
0
    cupsFilePrintf(temp, "Listen localhost:%d\n", server_port);
1461
0
  }
1462
1463
0
#ifdef CUPS_DEFAULT_DOMAINSOCKET
1464
0
        if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) &&
1465
0
      !access(CUPS_DEFAULT_DOMAINSOCKET, 0))
1466
0
          cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1467
0
#endif /* CUPS_DEFAULT_DOMAINSOCKET */
1468
0
      }
1469
0
      else if (value && value[0] == '/'
1470
0
#ifdef CUPS_DEFAULT_DOMAINSOCKET
1471
0
               && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)
1472
0
#endif /* CUPS_DEFAULT_DOMAINSOCKET */
1473
0
               )
1474
0
        cupsFilePrintf(temp, "Listen %s\n", value);
1475
0
    }
1476
0
    else if ((!_cups_strcasecmp(line, "Browsing") ||
1477
0
              !_cups_strcasecmp(line, "BrowseLocalProtocols")) &&
1478
0
       share_printers >= 0)
1479
0
    {
1480
0
      if (!wrote_browsing)
1481
0
      {
1482
0
  int new_share_printers = (share_printers > 0 ||
1483
0
          (share_printers == -1 &&
1484
0
           old_share_printers > 0));
1485
1486
0
        wrote_browsing = 1;
1487
1488
0
        if (new_share_printers)
1489
0
  {
1490
0
    const char *localp = cupsGetOption("BrowseLocalProtocols",
1491
0
               num_settings, settings);
1492
1493
0
          if (!localp || !localp[0])
1494
0
      localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings,
1495
0
                             cupsd_settings);
1496
1497
0
    cupsFilePuts(temp, "# Share local printers on the local network.\n");
1498
0
    cupsFilePuts(temp, "Browsing On\n");
1499
1500
0
    if (!localp)
1501
0
      localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS;
1502
1503
0
    cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp);
1504
1505
0
    cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp,
1506
0
               cupsd_num_settings,
1507
0
               &cupsd_settings);
1508
0
        }
1509
0
  else
1510
0
  {
1511
0
    cupsFilePuts(temp, "# Disable printer sharing.\n");
1512
0
    cupsFilePuts(temp, "Browsing Off\n");
1513
0
  }
1514
0
      }
1515
0
    }
1516
0
    else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0)
1517
0
    {
1518
0
      wrote_loglevel = 1;
1519
1520
0
      if (debug_logging)
1521
0
      {
1522
0
        cupsFilePuts(temp,
1523
0
               "# Show troubleshooting information in error_log.\n");
1524
0
  cupsFilePuts(temp, "LogLevel debug\n");
1525
0
      }
1526
0
      else
1527
0
      {
1528
0
        cupsFilePuts(temp, "# Show general information in error_log.\n");
1529
0
  cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n");
1530
0
      }
1531
0
    }
1532
0
    else if (!_cups_strcasecmp(line, "<Policy"))
1533
0
    {
1534
0
      in_default_policy = !_cups_strcasecmp(value, "default");
1535
0
      in_policy         = 1;
1536
1537
0
      cupsFilePrintf(temp, "%s %s>\n", line, value);
1538
0
      indent += 2;
1539
0
    }
1540
0
    else if (!_cups_strcasecmp(line, "</Policy>"))
1541
0
    {
1542
0
      indent -= 2;
1543
0
      if (!wrote_policy && in_default_policy)
1544
0
      {
1545
0
  wrote_policy = 1;
1546
1547
0
        if (!user_cancel_any)
1548
0
    cupsFilePuts(temp, "  # Only the owner or an administrator can "
1549
0
                       "cancel a job...\n"
1550
0
                       "  <Limit Cancel-Job>\n"
1551
0
                       "    Order deny,allow\n"
1552
0
           "    Require user @OWNER "
1553
0
           CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
1554
0
           "  </Limit>\n");
1555
0
      }
1556
1557
0
      in_policy         = 0;
1558
0
      in_default_policy = 0;
1559
1560
0
      cupsFilePuts(temp, "</Policy>\n");
1561
0
    }
1562
0
    else if (!_cups_strcasecmp(line, "<Location"))
1563
0
    {
1564
0
      in_location = 1;
1565
0
      indent += 2;
1566
0
      if (!strcmp(value, "/admin"))
1567
0
  in_admin_location = 1;
1568
0
      else if (!strcmp(value, "/admin/conf"))
1569
0
  in_conf_location = 1;
1570
0
      else if (!strcmp(value, "/admin/log"))
1571
0
  in_log_location = 1;
1572
0
      else if (!strcmp(value, "/"))
1573
0
  in_root_location = 1;
1574
1575
0
      cupsFilePrintf(temp, "%s %s>\n", line, value);
1576
0
    }
1577
0
    else if (!_cups_strcasecmp(line, "</Location>"))
1578
0
    {
1579
0
      in_location = 0;
1580
0
      indent -= 2;
1581
0
      if (in_admin_location && remote_admin >= 0)
1582
0
      {
1583
0
  wrote_admin_location = 1;
1584
1585
0
  if (remote_admin)
1586
0
          cupsFilePuts(temp, "  # Allow remote administration...\n");
1587
0
  else if (remote_admin == 0)
1588
0
          cupsFilePuts(temp, "  # Restrict access to the admin pages...\n");
1589
1590
0
        cupsFilePuts(temp, "  Order allow,deny\n");
1591
1592
0
  if (remote_admin)
1593
0
    cupsFilePrintf(temp, "  Allow %s\n",
1594
0
                   remote_any > 0 ? "all" : "@LOCAL");
1595
0
      }
1596
0
      else if (in_conf_location && remote_admin >= 0)
1597
0
      {
1598
0
  wrote_conf_location = 1;
1599
1600
0
  if (remote_admin)
1601
0
          cupsFilePuts(temp, "  # Allow remote access to the configuration "
1602
0
                       "files...\n");
1603
0
  else
1604
0
          cupsFilePuts(temp, "  # Restrict access to the configuration "
1605
0
                       "files...\n");
1606
1607
0
        cupsFilePuts(temp, "  Order allow,deny\n");
1608
1609
0
  if (remote_admin)
1610
0
    cupsFilePrintf(temp, "  Allow %s\n",
1611
0
                   remote_any > 0 ? "all" : "@LOCAL");
1612
0
      }
1613
0
      else if (in_log_location && remote_admin >= 0)
1614
0
      {
1615
0
  wrote_log_location = 1;
1616
1617
0
  if (remote_admin)
1618
0
          cupsFilePuts(temp, "  # Allow remote access to the log "
1619
0
                       "files...\n");
1620
0
  else
1621
0
          cupsFilePuts(temp, "  # Restrict access to the log "
1622
0
                       "files...\n");
1623
1624
0
        cupsFilePuts(temp, "  Order allow,deny\n");
1625
1626
0
  if (remote_admin)
1627
0
    cupsFilePrintf(temp, "  Allow %s\n",
1628
0
                   remote_any > 0 ? "all" : "@LOCAL");
1629
0
      }
1630
0
      else if (in_root_location &&
1631
0
               (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1632
0
      {
1633
0
  wrote_root_location = 1;
1634
1635
0
  if (remote_admin > 0 && share_printers > 0)
1636
0
          cupsFilePuts(temp, "  # Allow shared printing and remote "
1637
0
                       "administration...\n");
1638
0
  else if (remote_admin > 0)
1639
0
          cupsFilePuts(temp, "  # Allow remote administration...\n");
1640
0
  else if (share_printers > 0)
1641
0
          cupsFilePuts(temp, "  # Allow shared printing...\n");
1642
0
  else if (remote_any > 0)
1643
0
          cupsFilePuts(temp, "  # Allow remote access...\n");
1644
0
  else
1645
0
          cupsFilePuts(temp, "  # Restrict access to the server...\n");
1646
1647
0
        cupsFilePuts(temp, "  Order allow,deny\n");
1648
1649
0
  if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1650
0
    cupsFilePrintf(temp, "  Allow %s\n",
1651
0
                   remote_any > 0 ? "all" : "@LOCAL");
1652
0
      }
1653
1654
0
      in_admin_location = 0;
1655
0
      in_conf_location  = 0;
1656
0
      in_log_location   = 0;
1657
0
      in_root_location  = 0;
1658
1659
0
      cupsFilePuts(temp, "</Location>\n");
1660
0
    }
1661
0
    else if (!_cups_strcasecmp(line, "<Limit"))
1662
0
    {
1663
0
      if (in_default_policy)
1664
0
      {
1665
       /*
1666
  * See if the policy limit is for the Cancel-Job operation...
1667
  */
1668
1669
0
  char  *valptr;    /* Pointer into value */
1670
1671
1672
0
  if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
1673
0
  {
1674
   /*
1675
    * Don't write anything for this limit section...
1676
    */
1677
1678
0
    in_cancel_job = 2;
1679
0
  }
1680
0
  else
1681
0
  {
1682
0
    cupsFilePrintf(temp, "%*s%s", indent, "", line);
1683
1684
0
    while (*value)
1685
0
    {
1686
0
      for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++);
1687
1688
0
      if (*valptr)
1689
0
        *valptr++ = '\0';
1690
1691
0
      if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0)
1692
0
      {
1693
       /*
1694
        * Write everything except for this definition...
1695
        */
1696
1697
0
        in_cancel_job = 1;
1698
0
      }
1699
0
      else
1700
0
        cupsFilePrintf(temp, " %s", value);
1701
1702
0
      for (value = valptr; _cups_isspace(*value); value ++);
1703
0
    }
1704
1705
0
    cupsFilePuts(temp, ">\n");
1706
0
  }
1707
0
      }
1708
0
      else
1709
0
        cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
1710
1711
0
      indent += 2;
1712
0
    }
1713
0
    else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job)
1714
0
    {
1715
0
      indent -= 2;
1716
1717
0
      if (in_cancel_job == 1)
1718
0
  cupsFilePuts(temp, "  </Limit>\n");
1719
1720
0
      wrote_policy = 1;
1721
1722
0
      if (!user_cancel_any)
1723
0
  cupsFilePuts(temp, "  # Only the owner or an administrator can cancel "
1724
0
         "a job...\n"
1725
0
         "  <Limit Cancel-Job>\n"
1726
0
         "    Order deny,allow\n"
1727
0
         "    Require user @OWNER "
1728
0
         CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
1729
0
         "  </Limit>\n");
1730
1731
0
      in_cancel_job = 0;
1732
0
    }
1733
0
    else if ((((in_admin_location || in_conf_location || in_root_location) &&
1734
0
               (remote_admin >= 0 || remote_any >= 0)) ||
1735
0
              (in_root_location && share_printers >= 0)) &&
1736
0
             (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") ||
1737
0
        !_cups_strcasecmp(line, "Order")))
1738
0
      continue;
1739
0
    else if (in_cancel_job == 2)
1740
0
      continue;
1741
0
    else if (line[0] == '<')
1742
0
    {
1743
0
      if (value)
1744
0
      {
1745
0
        cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value);
1746
0
  indent += 2;
1747
0
      }
1748
0
      else
1749
0
      {
1750
0
  if (line[1] == '/')
1751
0
    indent -= 2;
1752
1753
0
  cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1754
0
      }
1755
0
    }
1756
0
    else if (!in_policy && !in_location &&
1757
0
             (val = cupsGetOption(line, num_settings, settings)) != NULL)
1758
0
    {
1759
     /*
1760
      * Replace this directive's value with the new one...
1761
      */
1762
1763
0
      cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings,
1764
0
                                         &cupsd_settings);
1765
1766
     /*
1767
      * Write the new value in its place, without indentation since we
1768
      * only support setting root directives, not in sections...
1769
      */
1770
1771
0
      cupsFilePrintf(temp, "%s %s\n", line, val);
1772
0
    }
1773
0
    else if (value)
1774
0
    {
1775
0
      if (!in_policy && !in_location)
1776
0
      {
1777
       /*
1778
        * Record the non-policy, non-location directives that we find
1779
  * in the server settings, since we cache this info and record it
1780
  * in cupsAdminGetServerSettings()...
1781
  */
1782
1783
0
  cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings,
1784
0
                                           &cupsd_settings);
1785
0
      }
1786
1787
0
      cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value);
1788
0
    }
1789
0
    else
1790
0
      cupsFilePrintf(temp, "%*s%s\n", indent, "", line);
1791
0
  }
1792
1793
 /*
1794
  * Write any missing info...
1795
  */
1796
1797
0
  if (!wrote_browsing && share_printers >= 0)
1798
0
  {
1799
0
    if (share_printers > 0)
1800
0
    {
1801
0
      cupsFilePuts(temp, "# Share local printers on the local network.\n");
1802
0
      cupsFilePuts(temp, "Browsing On\n");
1803
0
    }
1804
0
    else
1805
0
    {
1806
0
      cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
1807
0
      cupsFilePuts(temp, "Browsing Off\n");
1808
0
    }
1809
0
  }
1810
1811
0
  if (!wrote_loglevel && debug_logging >= 0)
1812
0
  {
1813
0
    if (debug_logging)
1814
0
    {
1815
0
      cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
1816
0
      cupsFilePuts(temp, "LogLevel debug\n");
1817
0
    }
1818
0
    else
1819
0
    {
1820
0
      cupsFilePuts(temp, "# Show general information in error_log.\n");
1821
0
      cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n");
1822
0
    }
1823
0
  }
1824
1825
0
  if (!wrote_port_listen &&
1826
0
      (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1827
0
  {
1828
0
    if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1829
0
    {
1830
0
      cupsFilePuts(temp, "# Allow remote access\n");
1831
0
      cupsFilePrintf(temp, "Port %d\n", ippPort());
1832
0
    }
1833
0
    else
1834
0
    {
1835
0
      cupsFilePuts(temp,
1836
0
                   "# Only listen for connections from the local machine.\n");
1837
0
      cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
1838
0
    }
1839
1840
0
#ifdef CUPS_DEFAULT_DOMAINSOCKET
1841
0
    if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0))
1842
0
      cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n");
1843
0
#endif /* CUPS_DEFAULT_DOMAINSOCKET */
1844
0
  }
1845
1846
0
  if (!wrote_root_location &&
1847
0
      (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0))
1848
0
  {
1849
0
    if (remote_admin > 0 && share_printers > 0)
1850
0
      cupsFilePuts(temp,
1851
0
                   "# Allow shared printing and remote administration...\n");
1852
0
    else if (remote_admin > 0)
1853
0
      cupsFilePuts(temp, "# Allow remote administration...\n");
1854
0
    else if (share_printers > 0)
1855
0
      cupsFilePuts(temp, "# Allow shared printing...\n");
1856
0
    else if (remote_any > 0)
1857
0
      cupsFilePuts(temp, "# Allow remote access...\n");
1858
0
    else
1859
0
      cupsFilePuts(temp, "# Restrict access to the server...\n");
1860
1861
0
    cupsFilePuts(temp, "<Location />\n"
1862
0
                       "  Order allow,deny\n");
1863
1864
0
    if (remote_admin > 0 || remote_any > 0 || share_printers > 0)
1865
0
      cupsFilePrintf(temp, "  Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1866
1867
0
    cupsFilePuts(temp, "</Location>\n");
1868
0
  }
1869
1870
0
  if (!wrote_admin_location && remote_admin >= 0)
1871
0
  {
1872
0
    if (remote_admin)
1873
0
      cupsFilePuts(temp, "# Allow remote administration...\n");
1874
0
    else
1875
0
      cupsFilePuts(temp, "# Restrict access to the admin pages...\n");
1876
1877
0
    cupsFilePuts(temp, "<Location /admin>\n"
1878
0
                       "  Order allow,deny\n");
1879
1880
0
    if (remote_admin)
1881
0
      cupsFilePrintf(temp, "  Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1882
1883
0
    cupsFilePuts(temp, "</Location>\n");
1884
0
  }
1885
1886
0
  if (!wrote_conf_location && remote_admin >= 0)
1887
0
  {
1888
0
    if (remote_admin)
1889
0
      cupsFilePuts(temp,
1890
0
                   "# Allow remote access to the configuration files...\n");
1891
0
    else
1892
0
      cupsFilePuts(temp, "# Restrict access to the configuration files...\n");
1893
1894
0
    cupsFilePuts(temp, "<Location /admin/conf>\n"
1895
0
                       "  AuthType Default\n"
1896
0
                       "  Require user @SYSTEM\n"
1897
0
                       "  Order allow,deny\n");
1898
1899
0
    if (remote_admin)
1900
0
      cupsFilePrintf(temp, "  Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1901
1902
0
    cupsFilePuts(temp, "</Location>\n");
1903
0
  }
1904
1905
0
  if (!wrote_log_location && remote_admin >= 0)
1906
0
  {
1907
0
    if (remote_admin)
1908
0
      cupsFilePuts(temp,
1909
0
                   "# Allow remote access to the log files...\n");
1910
0
    else
1911
0
      cupsFilePuts(temp, "# Restrict access to the log files...\n");
1912
1913
0
    cupsFilePuts(temp, "<Location /admin/log>\n"
1914
0
                       "  AuthType Default\n"
1915
0
                       "  Require user @SYSTEM\n"
1916
0
                       "  Order allow,deny\n");
1917
1918
0
    if (remote_admin)
1919
0
      cupsFilePrintf(temp, "  Allow %s\n", remote_any > 0 ? "all" : "@LOCAL");
1920
1921
0
    cupsFilePuts(temp, "</Location>\n");
1922
0
  }
1923
1924
0
  if (!wrote_policy && user_cancel_any >= 0)
1925
0
  {
1926
0
    cupsFilePuts(temp, "<Policy default>\n"
1927
0
                       "  # Job-related operations must be done by the owner "
1928
0
           "or an administrator...\n"
1929
0
                       "  <Limit Send-Document Send-URI Hold-Job Release-Job "
1930
0
           "Restart-Job Purge-Jobs Set-Job-Attributes "
1931
0
           "Create-Job-Subscription Renew-Subscription "
1932
0
           "Cancel-Subscription Get-Notifications Reprocess-Job "
1933
0
           "Cancel-Current-Job Suspend-Current-Job Resume-Job "
1934
0
           "CUPS-Move-Job>\n"
1935
0
                       "    Require user @OWNER @SYSTEM\n"
1936
0
                       "    Order deny,allow\n"
1937
0
                       "  </Limit>\n"
1938
0
                       "  # All administration operations require an "
1939
0
           "administrator to authenticate...\n"
1940
0
           "  <Limit Pause-Printer Resume-Printer "
1941
0
                       "Set-Printer-Attributes Enable-Printer "
1942
0
           "Disable-Printer Pause-Printer-After-Current-Job "
1943
0
           "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer "
1944
0
           "Activate-Printer Restart-Printer Shutdown-Printer "
1945
0
           "Startup-Printer Promote-Job Schedule-Job-After "
1946
0
           "CUPS-Add-Printer CUPS-Delete-Printer "
1947
0
           "CUPS-Add-Class CUPS-Delete-Class "
1948
0
           "CUPS-Accept-Jobs CUPS-Reject-Jobs "
1949
0
           "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n"
1950
0
                       "    AuthType Default\n"
1951
0
           "    Require user @SYSTEM\n"
1952
0
                       "    Order deny,allow\n"
1953
0
                       "</Limit>\n");
1954
1955
0
    if (!user_cancel_any)
1956
0
      cupsFilePuts(temp, "  # Only the owner or an administrator can cancel "
1957
0
                         "a job...\n"
1958
0
                   "  <Limit Cancel-Job>\n"
1959
0
                   "    Order deny,allow\n"
1960
0
                   "    Require user @OWNER "
1961
0
       CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n"
1962
0
       "  </Limit>\n");
1963
1964
0
    cupsFilePuts(temp, "  <Limit All>\n"
1965
0
                       "  Order deny,allow\n"
1966
0
                       "  </Limit>\n"
1967
0
           "</Policy>\n");
1968
0
  }
1969
1970
0
  for (i = num_settings, setting = settings; i > 0; i --, setting ++)
1971
0
    if (setting->name[0] != '_' &&
1972
0
        _cups_strcasecmp(setting->name, "Listen") &&
1973
0
  _cups_strcasecmp(setting->name, "Port") &&
1974
0
        !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings))
1975
0
    {
1976
     /*
1977
      * Add this directive to the list of directives we have written...
1978
      */
1979
1980
0
      cupsd_num_settings = cupsAddOption(setting->name, setting->value,
1981
0
                                         cupsd_num_settings, &cupsd_settings);
1982
1983
     /*
1984
      * Write the new value, without indentation since we only support
1985
      * setting root directives, not in sections...
1986
      */
1987
1988
0
      cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value);
1989
0
    }
1990
1991
0
  cupsFileClose(cupsd);
1992
0
  cupsFileClose(temp);
1993
1994
 /*
1995
  * Upload the configuration file to the server...
1996
  */
1997
1998
0
  status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
1999
2000
0
  if (status == HTTP_STATUS_CREATED)
2001
0
  {
2002
   /*
2003
    * Updated OK, add the basic settings...
2004
    */
2005
2006
0
    if (debug_logging >= 0)
2007
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
2008
0
                                   debug_logging ? "1" : "0",
2009
0
           cupsd_num_settings, &cupsd_settings);
2010
0
    else
2011
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
2012
0
                                   old_debug_logging ? "1" : "0",
2013
0
           cupsd_num_settings, &cupsd_settings);
2014
2015
0
    if (remote_admin >= 0)
2016
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
2017
0
                                   remote_admin ? "1" : "0",
2018
0
           cupsd_num_settings, &cupsd_settings);
2019
0
    else
2020
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
2021
0
                                   old_remote_admin ? "1" : "0",
2022
0
           cupsd_num_settings, &cupsd_settings);
2023
2024
0
    if (remote_any >= 0)
2025
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
2026
0
           remote_any ? "1" : "0",
2027
0
           cupsd_num_settings, &cupsd_settings);
2028
0
    else
2029
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
2030
0
           old_remote_any ? "1" : "0",
2031
0
           cupsd_num_settings, &cupsd_settings);
2032
2033
0
    if (share_printers >= 0)
2034
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
2035
0
                                   share_printers ? "1" : "0",
2036
0
           cupsd_num_settings, &cupsd_settings);
2037
0
    else
2038
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
2039
0
                                   old_share_printers ? "1" : "0",
2040
0
           cupsd_num_settings, &cupsd_settings);
2041
2042
0
    if (user_cancel_any >= 0)
2043
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
2044
0
                                   user_cancel_any ? "1" : "0",
2045
0
           cupsd_num_settings, &cupsd_settings);
2046
0
    else
2047
0
      cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
2048
0
                                   old_user_cancel_any ? "1" : "0",
2049
0
           cupsd_num_settings, &cupsd_settings);
2050
2051
   /*
2052
    * Save the new values...
2053
    */
2054
2055
0
    invalidate_cupsd_cache(cg);
2056
2057
0
    cg->cupsd_num_settings = cupsd_num_settings;
2058
0
    cg->cupsd_settings     = cupsd_settings;
2059
0
    cg->cupsd_update       = time(NULL);
2060
2061
0
    httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname));
2062
0
  }
2063
0
  else
2064
0
    cupsFreeOptions(cupsd_num_settings, cupsd_settings);
2065
2066
 /*
2067
  * Remote our temp files and return...
2068
  */
2069
2070
0
  if (remote)
2071
0
    unlink(cupsdconf);
2072
2073
0
  unlink(tempfile);
2074
2075
0
  return (status == HTTP_STATUS_CREATED);
2076
0
}
2077
2078
2079
/*
2080
 * 'do_samba_command()' - Do a SAMBA command.
2081
 */
2082
2083
static int        /* O - Status of command */
2084
do_samba_command(const char *command, /* I - Command to run */
2085
                 const char *address, /* I - Address for command */
2086
                 const char *subcmd,  /* I - Sub-command */
2087
     const char *authfile,  /* I - Samba authentication file */
2088
     FILE *logfile)   /* I - Optional log file */
2089
0
{
2090
#ifdef _WIN32
2091
  return (1);       /* Always fail on Windows... */
2092
2093
#else
2094
0
  int   status;     /* Status of command */
2095
0
  int   pid;      /* Process ID of child */
2096
2097
2098
0
  if (logfile)
2099
0
    _cupsLangPrintf(logfile,
2100
0
                    _("Running command: %s %s -N -A %s -c \'%s\'"),
2101
0
              command, address, authfile, subcmd);
2102
2103
0
  if ((pid = fork()) == 0)
2104
0
  {
2105
   /*
2106
    * Child goes here, redirect stdin/out/err and execute the command...
2107
    */
2108
2109
0
    int fd = open("/dev/null", O_RDONLY);
2110
2111
0
    if (fd > 0)
2112
0
    {
2113
0
      dup2(fd, 0);
2114
0
      close(fd);
2115
0
    }
2116
2117
0
    if (logfile)
2118
0
      dup2(fileno(logfile), 1);
2119
0
    else if ((fd = open("/dev/null", O_WRONLY)) > 1)
2120
0
    {
2121
0
      dup2(fd, 1);
2122
0
      close(fd);
2123
0
    }
2124
2125
0
    dup2(1, 2);
2126
2127
0
    execlp(command, command, address, "-N", "-A", authfile, "-c", subcmd,
2128
0
           (char *)0);
2129
0
    exit(errno);
2130
0
  }
2131
0
  else if (pid < 0)
2132
0
  {
2133
0
    status = -1;
2134
2135
0
    if (logfile)
2136
0
      _cupsLangPrintf(logfile, _("Unable to run \"%s\": %s"),
2137
0
                      command, strerror(errno));
2138
0
  }
2139
0
  else
2140
0
  {
2141
   /*
2142
    * Wait for the process to complete...
2143
    */
2144
2145
0
    while (wait(&status) != pid);
2146
0
  }
2147
2148
0
  if (logfile)
2149
0
    _cupsLangPuts(logfile, "");
2150
2151
0
  DEBUG_printf(("9do_samba_command: status=%d", status));
2152
2153
0
  if (WIFEXITED(status))
2154
0
    return (WEXITSTATUS(status));
2155
0
  else
2156
0
    return (-WTERMSIG(status));
2157
0
#endif /* _WIN32 */
2158
0
}
2159
2160
2161
/*
2162
 * 'get_cupsd_conf()' - Get the current cupsd.conf file.
2163
 */
2164
2165
static http_status_t      /* O - Status of request */
2166
get_cupsd_conf(
2167
    http_t          *http,    /* I - Connection to server */
2168
    _cups_globals_t *cg,    /* I - Global data */
2169
    time_t          last_update,  /* I - Last update time for file */
2170
    char            *name,    /* I - Filename buffer */
2171
    size_t          namesize,   /* I - Size of filename buffer */
2172
    int             *remote)    /* O - Remote file? */
2173
0
{
2174
0
  int   fd;     /* Temporary file descriptor */
2175
0
#ifndef _WIN32
2176
0
  struct stat info;     /* cupsd.conf file information */
2177
0
#endif /* _WIN32 */
2178
0
  http_status_t status;     /* Status of getting cupsd.conf */
2179
0
  char    host[HTTP_MAX_HOST];  /* Hostname for connection */
2180
2181
2182
 /*
2183
  * See if we already have the data we need...
2184
  */
2185
2186
0
  httpGetHostname(http, host, sizeof(host));
2187
2188
0
  if (_cups_strcasecmp(cg->cupsd_hostname, host))
2189
0
    invalidate_cupsd_cache(cg);
2190
2191
0
  snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot);
2192
0
  *remote = 0;
2193
2194
0
#ifndef _WIN32
2195
0
  if (!_cups_strcasecmp(host, "localhost") && !access(name, R_OK))
2196
0
  {
2197
   /*
2198
    * Read the local file rather than using HTTP...
2199
    */
2200
2201
0
    if (stat(name, &info))
2202
0
    {
2203
0
      char  message[1024];    /* Message string */
2204
2205
2206
0
      snprintf(message, sizeof(message),
2207
0
               _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
2208
0
               name, strerror(errno));
2209
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, message, 0);
2210
2211
0
      *name = '\0';
2212
2213
0
      return (HTTP_STATUS_SERVER_ERROR);
2214
0
    }
2215
0
    else if (last_update && info.st_mtime <= last_update)
2216
0
      status = HTTP_STATUS_NOT_MODIFIED;
2217
0
    else
2218
0
      status = HTTP_STATUS_OK;
2219
0
  }
2220
0
  else
2221
0
#endif /* !_WIN32 */
2222
0
  {
2223
   /*
2224
    * Read cupsd.conf via a HTTP GET request...
2225
    */
2226
2227
0
    if ((fd = cupsTempFd(name, (int)namesize)) < 0)
2228
0
    {
2229
0
      *name = '\0';
2230
2231
0
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0);
2232
2233
0
      invalidate_cupsd_cache(cg);
2234
2235
0
      return (HTTP_STATUS_SERVER_ERROR);
2236
0
    }
2237
2238
0
    *remote = 1;
2239
2240
0
    httpClearFields(http);
2241
2242
0
    if (last_update)
2243
0
      httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE,
2244
0
                   httpGetDateString(last_update));
2245
2246
0
    status = cupsGetFd(http, "/admin/conf/cupsd.conf", fd);
2247
2248
0
    close(fd);
2249
2250
0
    if (status != HTTP_STATUS_OK)
2251
0
    {
2252
0
      unlink(name);
2253
0
      *name = '\0';
2254
0
    }
2255
0
  }
2256
2257
0
  return (status);
2258
0
}
2259
2260
2261
/*
2262
 * 'invalidate_cupsd_cache()' - Invalidate the cached cupsd.conf settings.
2263
 */
2264
2265
static void
2266
invalidate_cupsd_cache(
2267
    _cups_globals_t *cg)    /* I - Global data */
2268
0
{
2269
0
  cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
2270
2271
0
  cg->cupsd_hostname[0]  = '\0';
2272
0
  cg->cupsd_update       = 0;
2273
0
  cg->cupsd_num_settings = 0;
2274
0
  cg->cupsd_settings     = NULL;
2275
0
}
2276
2277
2278
/*
2279
 * 'write_option()' - Write a CUPS option to a PPD file.
2280
 */
2281
2282
static void
2283
write_option(cups_file_t     *dstfp,  /* I - PPD file */
2284
             int             order, /* I - Order dependency */
2285
             const char      *name, /* I - Option name */
2286
       const char      *text, /* I - Option text */
2287
             const char      *attrname, /* I - Attribute name */
2288
             ipp_attribute_t *suppattr, /* I - IPP -supported attribute */
2289
       ipp_attribute_t *defattr,  /* I - IPP -default attribute */
2290
       int             defval,  /* I - Default value number */
2291
       int             valcount)  /* I - Number of values */
2292
0
{
2293
0
  int i;        /* Looping var */
2294
2295
2296
0
  cupsFilePrintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n"
2297
0
                        "*OrderDependency: %d JCLSetup *%s\n",
2298
0
                 name, text, order, name);
2299
2300
0
  if (defattr->value_tag == IPP_TAG_INTEGER)
2301
0
  {
2302
   /*
2303
    * Do numeric options with a range or list...
2304
    */
2305
2306
0
    cupsFilePrintf(dstfp, "*Default%s: %d\n", name,
2307
0
                   defattr->values[defval].integer);
2308
2309
0
    if (suppattr->value_tag == IPP_TAG_RANGE)
2310
0
    {
2311
     /*
2312
      * List each number in the range...
2313
      */
2314
2315
0
      for (i = suppattr->values[0].range.lower;
2316
0
           i <= suppattr->values[0].range.upper;
2317
0
     i ++)
2318
0
      {
2319
0
        cupsFilePrintf(dstfp, "*%s %d: \"", name, i);
2320
2321
0
        if (valcount == 1)
2322
0
    cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n",
2323
0
                   attrname, i);
2324
0
        else if (defval == 0)
2325
0
    cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i);
2326
0
        else if (defval < (valcount - 1))
2327
0
    cupsFilePrintf(dstfp, ",%d\"\n", i);
2328
0
        else
2329
0
    cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", i);
2330
0
      }
2331
0
    }
2332
0
    else
2333
0
    {
2334
     /*
2335
      * List explicit numbers...
2336
      */
2337
2338
0
      for (i = 0; i < suppattr->num_values; i ++)
2339
0
      {
2340
0
        cupsFilePrintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer);
2341
2342
0
        if (valcount == 1)
2343
0
    cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname,
2344
0
            suppattr->values[i].integer);
2345
0
        else if (defval == 0)
2346
0
    cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname,
2347
0
            suppattr->values[i].integer);
2348
0
        else if (defval < (valcount - 1))
2349
0
    cupsFilePrintf(dstfp, ",%d\"\n", suppattr->values[i].integer);
2350
0
        else
2351
0
    cupsFilePrintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer);
2352
0
      }
2353
0
    }
2354
0
  }
2355
0
  else
2356
0
  {
2357
   /*
2358
    * Do text options with a list...
2359
    */
2360
2361
0
    cupsFilePrintf(dstfp, "*Default%s: %s\n", name,
2362
0
                   defattr->values[defval].string.text);
2363
2364
0
    for (i = 0; i < suppattr->num_values; i ++)
2365
0
    {
2366
0
      cupsFilePrintf(dstfp, "*%s %s: \"", name,
2367
0
                     suppattr->values[i].string.text);
2368
2369
0
      if (valcount == 1)
2370
0
  cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname,
2371
0
          suppattr->values[i].string.text);
2372
0
      else if (defval == 0)
2373
0
  cupsFilePrintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname,
2374
0
          suppattr->values[i].string.text);
2375
0
      else if (defval < (valcount - 1))
2376
0
  cupsFilePrintf(dstfp, ",%s\"\n", suppattr->values[i].string.text);
2377
0
      else
2378
0
  cupsFilePrintf(dstfp, ",%s\n\"\n*End\n",
2379
0
                 suppattr->values[i].string.text);
2380
0
    }
2381
0
  }
2382
2383
0
  cupsFilePrintf(dstfp, "*JCLCloseUI: *%s\n\n", name);
2384
0
}