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