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