static int /* O - 1 on success, 0 on failure */ make_certificate(cupsd_client_t *con) /* I - Client connection */ { # ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE int status = 0; /* Return status */ OSStatus err; /* Error code (if any) */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) char localname[1024];/* Local hostname */ # endif /* HAVE_DNSSD || HAVE_AVAHI */ const char *servername; /* Name of server in cert */ CFStringRef cfservername = NULL; /* CF string for server name */ SecIdentityRef ident = NULL; /* Identity */ SecKeyRef publicKey = NULL, /* Public key */ privateKey = NULL; /* Private key */ CFMutableDictionaryRef keyParams = NULL; /* Key generation parameters */ cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key and certificate."); # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) { snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); servername = localname; } else # endif /* HAVE_DNSSD || HAVE_AVAHI */ servername = con->servername; cfservername = CFStringCreateWithCString(kCFAllocatorDefault, servername, kCFStringEncodingUTF8); if (!cfservername) goto cleanup; /* * Create a public/private key pair... */ keyParams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!keyParams) goto cleanup; CFDictionaryAddValue(keyParams, kSecAttrKeyType, kSecAttrKeyTypeRSA); CFDictionaryAddValue(keyParams, kSecAttrKeySizeInBits, CFSTR("2048")); CFDictionaryAddValue(keyParams, kSecAttrLabel, CFSTR("CUPS Self-Signed Certificate")); err = SecKeyGeneratePair(keyParams, &publicKey, &privateKey); if (err != noErr) { cupsdLogMessage(CUPSD_LOG_DEBUG, "SecKeyGeneratePair returned %ld.", (long)err); goto cleanup; } /* * Create a self-signed certificate using the public/private key pair... */ CFIndex usageInt = kSecKeyUsageAll; CFNumberRef usage = CFNumberCreate(alloc, kCFNumberCFIndexType, &usageInt); CFDictionaryRef certParams = CFDictionaryCreateMutable(kCFAllocatorDefault, kSecCSRBasicContraintsPathLen, CFINT(0), kSecSubjectAltName, cfservername, kSecCertificateKeyUsage, usage, NULL, NULL); CFRelease(usage); const void *ca_o[] = { kSecOidOrganization, CFSTR("") }; const void *ca_cn[] = { kSecOidCommonName, cfservername }; CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); const void *ca_dn_array[2]; ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL); ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL); CFArrayRef subject = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL); SecCertificateRef cert = SecGenerateSelfSignedCertificate(subject, certParams, publicKey, privateKey); CFRelease(subject); CFRelease(certParams); if (!cert) { cupsdLogMessage(CUPSD_LOG_DEBUG, "SecGenerateSelfSignedCertificate failed."); goto cleanup; } ident = SecIdentityCreate(kCFAllocatorDefault, cert, privateKey); if (ident) cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server certificate file \"%s\".", ServerCertificate); /* * Cleanup and return... */ cleanup: if (cfservername) CFRelease(cfservername); if (keyParams) CFRelease(keyParams); if (ident) CFRelease(ident); if (cert) CFRelease(cert); if (publicKey) CFRelease(publicKey); if (privateKey) CFRelease(publicKey); if (!status) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key and certificate."); return (status); # else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ int pid, /* Process ID of command */ status; /* Status of command */ char command[1024], /* Command */ *argv[4], /* Command-line arguments */ *envp[MAX_ENV + 1], /* Environment variables */ keychain[1024], /* Keychain argument */ infofile[1024], /* Type-in information for cert */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) localname[1024], /* Local hostname */ # endif /* HAVE_DNSSD || HAVE_AVAHI */ *servername; /* Name of server in cert */ cups_file_t *fp; /* Seed/info file */ int infofd; /* Info file descriptor */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) { snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); servername = localname; } else # endif /* HAVE_DNSSD || HAVE_AVAHI */ servername = con->servername; /* * Run the "certtool" command to generate a self-signed certificate... */ if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) { cupsdLogMessage(CUPSD_LOG_ERROR, "No SSL certificate and certtool command not found."); return (0); } /* * Create a file with the certificate information fields... * * Note: This assumes that the default questions are asked by the certtool * command... */ if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create certificate information file %s - %s", infofile, strerror(errno)); return (0); } cupsFilePrintf(fp, "%s\n" /* Enter key and certificate label */ "r\n" /* Generate RSA key pair */ "2048\n" /* Key size in bits */ "y\n" /* OK (y = yes) */ "b\n" /* Usage (b=signing/encryption) */ "s\n" /* Sign with SHA1 */ "y\n" /* OK (y = yes) */ "%s\n" /* Common name */ "\n" /* Country (default) */ "\n" /* Organization (default) */ "\n" /* Organizational unit (default) */ "\n" /* State/Province (default) */ "%s\n" /* Email address */ "y\n", /* OK (y = yes) */ servername, servername, ServerAdmin); cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key and certificate."); snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); argv[0] = "certtool"; argv[1] = "c"; argv[2] = keychain; argv[3] = NULL; cupsdLoadEnv(envp, MAX_ENV); infofd = open(infofile, O_RDONLY); if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, NULL, &pid)) { close(infofd); unlink(infofile); return (0); } close(infofd); unlink(infofile); while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) { status = 1; break; } cupsdFinishProcess(pid, command, sizeof(command), NULL); if (status) { if (WIFEXITED(status)) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key and certificate - " "the certtool command stopped with status %d.", WEXITSTATUS(status)); else cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key and certificate - " "the certtool command crashed on signal %d.", WTERMSIG(status)); } else { cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server certificate file \"%s\".", ServerCertificate); } return (!status); # endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */ }
void * /* O - Profile or NULL on error */ cupsdCreateProfile(int job_id, /* I - Job ID or 0 for none */ int allow_networking)/* I - Allow networking off machine? */ { #ifdef HAVE_SANDBOX_H cups_file_t *fp; /* File pointer */ char profile[1024], /* File containing the profile */ bin[1024], /* Quoted ServerBin */ cache[1024], /* Quoted CacheDir */ domain[1024], /* Domain socket, if any */ request[1024], /* Quoted RequestRoot */ root[1024], /* Quoted ServerRoot */ state[1024], /* Quoted StateDir */ temp[1024]; /* Quoted TempDir */ const char *nodebug; /* " (with no-log)" for no debug */ cupsd_listener_t *lis; /* Current listening socket */ if (!UseSandboxing || Sandboxing == CUPSD_SANDBOXING_OFF) { /* * Only use sandbox profiles as root... */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking); return (NULL); } if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking); cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s", strerror(errno)); return (NULL); } fchown(cupsFileNumber(fp), RunUser, Group); fchmod(cupsFileNumber(fp), 0640); cupsd_requote(bin, ServerBin, sizeof(bin)); cupsd_requote(cache, CacheDir, sizeof(cache)); cupsd_requote(request, RequestRoot, sizeof(request)); cupsd_requote(root, ServerRoot, sizeof(root)); cupsd_requote(state, StateDir, sizeof(state)); cupsd_requote(temp, TempDir, sizeof(temp)); nodebug = LogLevel < CUPSD_LOG_DEBUG ? " (with no-log)" : ""; cupsFilePuts(fp, "(version 1)\n"); if (Sandboxing == CUPSD_SANDBOXING_STRICT) cupsFilePuts(fp, "(deny default)\n"); else cupsFilePuts(fp, "(allow default)\n"); if (LogLevel >= CUPSD_LOG_DEBUG) cupsFilePuts(fp, "(debug deny)\n"); cupsFilePuts(fp, "(import \"system.sb\")\n"); cupsFilePuts(fp, "(system-network)\n"); cupsFilePuts(fp, "(allow mach-per-user-lookup)\n"); cupsFilePuts(fp, "(allow ipc-posix-sem)\n"); cupsFilePuts(fp, "(allow ipc-posix-shm)\n"); cupsFilePuts(fp, "(allow ipc-sysv-shm)\n"); cupsFilePuts(fp, "(allow mach-lookup)\n"); if (!RunUser) cupsFilePrintf(fp, "(deny file-write* file-read-data file-read-metadata\n" " (regex" " #\"^/Users$\"" " #\"^/Users/\"" ")%s)\n", nodebug); cupsFilePrintf(fp, "(deny file-write*\n" " (regex" " #\"^%s$\"" /* ServerRoot */ " #\"^%s/\"" /* ServerRoot/... */ " #\"^/private/etc$\"" " #\"^/private/etc/\"" " #\"^/usr/local/etc$\"" " #\"^/usr/local/etc/\"" " #\"^/Library$\"" " #\"^/Library/\"" " #\"^/System$\"" " #\"^/System/\"" ")%s)\n", root, root, nodebug); /* Specifically allow applications to stat RequestRoot and some other system folders */ cupsFilePrintf(fp, "(allow file-read-metadata\n" " (regex" " #\"^/$\"" /* / */ " #\"^/usr$\"" /* /usr */ " #\"^/Library$\"" /* /Library */ " #\"^/Library/Printers$\"" /* /Library/Printers */ " #\"^%s$\"" /* RequestRoot */ "))\n", request); /* Read and write TempDir, CacheDir, and other common folders */ cupsFilePuts(fp, "(allow file-write* file-read-data file-read-metadata\n" " (regex" " #\"^/private/var/db/\"" " #\"^/private/var/folders/\"" " #\"^/private/var/lib/\"" " #\"^/private/var/log/\"" " #\"^/private/var/mysql/\"" " #\"^/private/var/run/\"" " #\"^/private/var/spool/\"" " #\"^/Library/Application Support/\"" " #\"^/Library/Caches/\"" " #\"^/Library/Logs/\"" " #\"^/Library/Preferences/\"" " #\"^/Library/WebServer/\"" " #\"^/Users/Shared/\"" "))\n"); cupsFilePrintf(fp, "(deny file-write*\n" " (regex #\"^%s$\")%s)\n", request, nodebug); cupsFilePrintf(fp, "(deny file-write* file-read-data file-read-metadata\n" " (regex #\"^%s/\")%s)\n", request, nodebug); cupsFilePrintf(fp, "(allow file-write* file-read-data file-read-metadata\n" " (regex" " #\"^%s$\"" /* TempDir */ " #\"^%s/\"" /* TempDir/... */ " #\"^%s$\"" /* CacheDir */ " #\"^%s/\"" /* CacheDir/... */ " #\"^%s$\"" /* StateDir */ " #\"^%s/\"" /* StateDir/... */ "))\n", temp, temp, cache, cache, state, state); /* Read common folders */ cupsFilePrintf(fp, "(allow file-read-data file-read-metadata\n" " (regex" " #\"^/AppleInternal$\"" " #\"^/AppleInternal/\"" " #\"^/bin$\"" /* /bin */ " #\"^/bin/\"" /* /bin/... */ " #\"^/private$\"" " #\"^/private/etc$\"" " #\"^/private/etc/\"" " #\"^/private/tmp$\"" " #\"^/private/tmp/\"" " #\"^/private/var$\"" " #\"^/private/var/db$\"" " #\"^/private/var/folders$\"" " #\"^/private/var/lib$\"" " #\"^/private/var/log$\"" " #\"^/private/var/mysql$\"" " #\"^/private/var/run$\"" " #\"^/private/var/spool$\"" " #\"^/private/var/tmp$\"" " #\"^/private/var/tmp/\"" " #\"^/usr/bin$\"" /* /usr/bin */ " #\"^/usr/bin/\"" /* /usr/bin/... */ " #\"^/usr/libexec/cups$\"" /* /usr/libexec/cups */ " #\"^/usr/libexec/cups/\"" /* /usr/libexec/cups/... */ " #\"^/usr/libexec/fax$\"" /* /usr/libexec/fax */ " #\"^/usr/libexec/fax/\"" /* /usr/libexec/fax/... */ " #\"^/usr/sbin$\"" /* /usr/sbin */ " #\"^/usr/sbin/\"" /* /usr/sbin/... */ " #\"^/Library$\"" /* /Library */ " #\"^/Library/\"" /* /Library/... */ " #\"^/System$\"" /* /System */ " #\"^/System/\"" /* /System/... */ " #\"^%s/Library$\"" /* RequestRoot/Library */ " #\"^%s/Library/\"" /* RequestRoot/Library/... */ " #\"^%s$\"" /* ServerBin */ " #\"^%s/\"" /* ServerBin/... */ " #\"^%s$\"" /* ServerRoot */ " #\"^%s/\"" /* ServerRoot/... */ "))\n", request, request, bin, bin, root, root); if (Sandboxing == CUPSD_SANDBOXING_RELAXED) { /* Limited write access to /Library/Printers/... */ cupsFilePuts(fp, "(allow file-write*\n" " (regex" " #\"^/Library/Printers/.*/\"" "))\n"); cupsFilePrintf(fp, "(deny file-write*\n" " (regex" " #\"^/Library/Printers/PPDs$\"" " #\"^/Library/Printers/PPDs/\"" " #\"^/Library/Printers/PPD Plugins$\"" " #\"^/Library/Printers/PPD Plugins/\"" ")%s)\n", nodebug); } /* Allow execution of child processes as long as the programs are not in a user directory */ cupsFilePuts(fp, "(allow process*)\n"); cupsFilePuts(fp, "(deny process-exec (regex #\"^/Users/\"))\n"); if (RunUser && getenv("CUPS_TESTROOT")) { /* Allow source directory access in "make test" environment */ char testroot[1024]; /* Root directory of test files */ cupsd_requote(testroot, getenv("CUPS_TESTROOT"), sizeof(testroot)); cupsFilePrintf(fp, "(allow file-write* file-read-data file-read-metadata\n" " (regex" " #\"^%s$\"" /* CUPS_TESTROOT */ " #\"^%s/\"" /* CUPS_TESTROOT/... */ "))\n", testroot, testroot); cupsFilePrintf(fp, "(allow process-exec\n" " (regex" " #\"^%s/\"" /* CUPS_TESTROOT/... */ "))\n", testroot); cupsFilePrintf(fp, "(allow sysctl*)\n"); } if (job_id) { /* Allow job filters to read the current job files... */ cupsFilePrintf(fp, "(allow file-read-data file-read-metadata\n" " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n", request, job_id, job_id); } else { /* Allow email notifications from notifiers... */ cupsFilePuts(fp, "(allow process-exec\n" " (literal \"/usr/sbin/sendmail\")\n" " (with no-sandbox))\n"); } /* Allow access to Bluetooth, USB, and notify_post. */ cupsFilePuts(fp, "(allow iokit*)\n"); cupsFilePuts(fp, "(allow distributed-notification-post)\n"); /* Allow outbound networking to local services */ cupsFilePuts(fp, "(allow network-outbound" "\n (regex #\"^/private/var/run/\" #\"^/private/tmp/\" #\"^/private/var/tmp/\")"); for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners)) { if (httpAddrFamily(&(lis->address)) == AF_LOCAL) { httpAddrString(&(lis->address), domain, sizeof(domain)); cupsFilePrintf(fp, "\n (literal \"%s\")", domain); } } if (allow_networking) { /* Allow TCP and UDP networking off the machine... */ cupsFilePuts(fp, "\n (remote tcp))\n"); cupsFilePuts(fp, "(allow network-bind)\n"); /* for LPD resvport */ cupsFilePuts(fp, "(allow network*\n" " (local udp \"*:*\")\n" " (remote udp \"*:*\"))\n"); /* Also allow access to device files... */ cupsFilePuts(fp, "(allow file-write* file-read-data file-read-metadata file-ioctl\n" " (regex #\"^/dev/\"))\n"); /* And allow kernel extensions to be loaded, e.g., SMB */ cupsFilePuts(fp, "(allow system-kext-load)\n"); } else { /* Only allow SNMP (UDP) and LPD (TCP) off the machine... */ cupsFilePuts(fp, ")\n"); cupsFilePuts(fp, "(allow network-outbound\n" " (remote udp \"*:161\")\n" " (remote tcp \"*:515\"))\n"); cupsFilePuts(fp, "(allow network-inbound\n" " (local udp \"localhost:*\"))\n"); } cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d,allow_networking=%d) = \"%s\"", job_id, allow_networking, profile); return ((void *)strdup(profile)); #else cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking); return (NULL); #endif /* HAVE_SANDBOX_H */ }
static void cups_create_localizations( http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo) /* I - Destination informations */ { http_t *http2; /* Connection for strings file */ http_status_t status; /* Request status */ ipp_attribute_t *attr; /* "printer-strings-uri" attribute */ char scheme[32], /* URI scheme */ userpass[256], /* Username/password info */ hostname[256], /* Hostname */ resource[1024], /* Resource */ http_hostname[256], /* Hostname of connection */ tempfile[1024]; /* Temporary filename */ int port; /* Port number */ http_encryption_t encryption; /* Encryption to use */ cups_file_t *temp; /* Temporary file */ /* * Create an empty message catalog... */ dinfo->localizations = _cupsMessageNew(NULL); /* * See if there are any localizations... */ if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri", IPP_TAG_URI)) == NULL) { /* * Nope... */ DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) " "value."); return; /* Nope */ } /* * Pull apart the URI and determine whether we need to try a different * server... */ if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_OK) { DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value " "\"%s\".", attr->values[0].string.text)); return; } httpGetHostname(http, http_hostname, sizeof(http_hostname)); if (!_cups_strcasecmp(http_hostname, hostname) && port == _httpAddrPort(http->hostaddr)) { /* * Use the same connection... */ http2 = http; } else { /* * Connect to the alternate host... */ if (!strcmp(scheme, "https")) encryption = HTTP_ENCRYPT_ALWAYS; else encryption = HTTP_ENCRYPT_IF_REQUESTED; if ((http2 = httpConnectEncrypt(hostname, port, encryption)) == NULL) { DEBUG_printf(("4cups_create_localizations: Unable to connect to " "%s:%d: %s", hostname, port, cupsLastErrorString())); return; } } /* * Get a temporary file... */ if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) { DEBUG_printf(("4cups_create_localizations: Unable to create temporary " "file: %s", cupsLastErrorString())); if (http2 != http) httpClose(http2); return; } status = cupsGetFd(http2, resource, cupsFileNumber(temp)); DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource, httpStatus(status))); if (status == HTTP_OK) { /* * Got the file, read it... */ char buffer[8192], /* Message buffer */ *id, /* ID string */ *str; /* Translated message */ _cups_message_t *m; /* Current message */ lseek(cupsFileNumber(temp), 0, SEEK_SET); while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str)) { if ((m = malloc(sizeof(_cups_message_t))) == NULL) break; m->id = strdup(id); m->str = strdup(str); if (m->id && m->str) cupsArrayAdd(dinfo->localizations, m); else { if (m->id) free(m->id); if (m->str) free(m->str); free(m); break; } } } DEBUG_printf(("4cups_create_localizations: %d messages loaded.", cupsArrayCount(dinfo->localizations))); /* * Cleanup... */ unlink(tempfile); cupsFileClose(temp); if (http2 != http) httpClose(http2); }
static int /* O - 1 on success, 0 on failure */ make_certificate(cupsd_client_t *con) /* I - Client connection */ { int pid, /* Process ID of command */ status; /* Status of command */ char command[1024], /* Command */ *argv[4], /* Command-line arguments */ *envp[MAX_ENV + 1], /* Environment variables */ keychain[1024], /* Keychain argument */ infofile[1024], /* Type-in information for cert */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) localname[1024], /* Local hostname */ # endif /* HAVE_DNSSD || HAVE_AVAHI */ *servername; /* Name of server in cert */ cups_file_t *fp; /* Seed/info file */ int infofd; /* Info file descriptor */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName) { snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); servername = localname; } else # endif /* HAVE_DNSSD || HAVE_AVAHI */ servername = con->servername; /* * Run the "certtool" command to generate a self-signed certificate... */ if (!cupsFileFind("certtool", getenv("PATH"), 1, command, sizeof(command))) { cupsdLogMessage(CUPSD_LOG_ERROR, "No SSL certificate and certtool command not found!"); return (0); } /* * Create a file with the certificate information fields... * * Note: This assumes that the default questions are asked by the certtool * command... */ if ((fp = cupsTempFile2(infofile, sizeof(infofile))) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create certificate information file %s - %s", infofile, strerror(errno)); return (0); } cupsFilePrintf(fp, "%s\n" /* Enter key and certificate label */ "r\n" /* Generate RSA key pair */ "2048\n" /* Key size in bits */ "y\n" /* OK (y = yes) */ "b\n" /* Usage (b=signing/encryption) */ "s\n" /* Sign with SHA1 */ "y\n" /* OK (y = yes) */ "%s\n" /* Common name */ "\n" /* Country (default) */ "\n" /* Organization (default) */ "\n" /* Organizational unit (default) */ "\n" /* State/Province (default) */ "%s\n" /* Email address */ "y\n", /* OK (y = yes) */ servername, servername, ServerAdmin); cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key and certificate..."); snprintf(keychain, sizeof(keychain), "k=%s", ServerCertificate); argv[0] = "certtool"; argv[1] = "c"; argv[2] = keychain; argv[3] = NULL; cupsdLoadEnv(envp, MAX_ENV); infofd = open(infofile, O_RDONLY); if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL, NULL, &pid)) { close(infofd); unlink(infofile); return (0); } close(infofd); unlink(infofile); while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) { status = 1; break; } cupsdFinishProcess(pid, command, sizeof(command), NULL); if (status) { if (WIFEXITED(status)) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key and certificate - " "the certtool command stopped with status %d!", WEXITSTATUS(status)); else cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create SSL server key and certificate - " "the certtool command crashed on signal %d!", WTERMSIG(status)); } else { cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server certificate file \"%s\"...", ServerCertificate); } return (!status); }
static int /* O - 0 on success, 1 on fail */ set_printer_options( http_t *http, /* I - Server connection */ char *printer, /* I - Printer */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ char *file) /* I - PPD file/interface script */ { ipp_t *request; /* IPP Request */ const char *ppdfile; /* PPD filename */ int ppdchanged; /* PPD changed? */ ppd_file_t *ppd; /* PPD file */ ppd_choice_t *choice; /* Marked choice */ char uri[HTTP_MAX_URI], /* URI for printer/class */ line[1024], /* Line from PPD file */ keyword[1024], /* Keyword from Default line */ *keyptr, /* Pointer into keyword... */ tempfile[1024]; /* Temporary filename */ cups_file_t *in, /* PPD file */ *out; /* Temporary file */ const char *protocol, /* Old protocol option */ *customval, /* Custom option value */ *boolval; /* Boolean value */ int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */ wrote_snmp_supplies = 0;/* Wrote cupsSNMPSupplies keyword? */ DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, " "options=%p, file=\"%s\")\n", http, printer, num_options, options, file)); /* * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which * requires the following attributes: * * attributes-charset * attributes-natural-language * printer-uri * requesting-user-name * other options */ if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS) request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); else request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); /* * Add the options... */ cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER); if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL) { if (!_cups_strcasecmp(protocol, "bcp")) ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", NULL, "bcp"); else if (!_cups_strcasecmp(protocol, "tbcp")) ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", NULL, "tbcp"); } if (file) ppdfile = file; else if (request->request.op.operation_id == CUPS_ADD_MODIFY_PRINTER) ppdfile = cupsGetPPD(printer); else ppdfile = NULL; if (ppdfile != NULL) { /* * Set default options in the PPD file... */ ppd = ppdOpenFile(ppdfile); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) { _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file")); ippDelete(request); if (ppdfile != file) unlink(ppdfile); return (1); } if ((in = cupsFileOpen(ppdfile, "r")) == NULL) { _cupsLangPrintf(stderr, _("lpadmin: Unable to open PPD file \"%s\" - %s"), ppdfile, strerror(errno)); ippDelete(request); if (ppdfile != file) unlink(ppdfile); cupsFileClose(out); unlink(tempfile); return (1); } ppdchanged = 0; while (cupsFileGets(in, line, sizeof(line))) { if (!strncmp(line, "*cupsIPPSupplies:", 17) && (boolval = cupsGetOption("cupsIPPSupplies", num_options, options)) != NULL) { wrote_ipp_supplies = 1; cupsFilePrintf(out, "*cupsIPPSupplies: %s\n", (!_cups_strcasecmp(boolval, "true") || !_cups_strcasecmp(boolval, "yes") || !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); } else if (!strncmp(line, "*cupsSNMPSupplies:", 18) && (boolval = cupsGetOption("cupsSNMPSupplies", num_options, options)) != NULL) { wrote_snmp_supplies = 1; cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n", (!_cups_strcasecmp(boolval, "true") || !_cups_strcasecmp(boolval, "yes") || !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); } else if (strncmp(line, "*Default", 8)) cupsFilePrintf(out, "%s\n", line); else { /* * Get default option name... */ strlcpy(keyword, line + 8, sizeof(keyword)); for (keyptr = keyword; *keyptr; keyptr ++) if (*keyptr == ':' || isspace(*keyptr & 255)) break; *keyptr++ = '\0'; while (isspace(*keyptr & 255)) keyptr ++; if (!strcmp(keyword, "PageRegion") || !strcmp(keyword, "PageSize") || !strcmp(keyword, "PaperDimension") || !strcmp(keyword, "ImageableArea")) { if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL) choice = ppdFindMarkedChoice(ppd, "PageRegion"); } else choice = ppdFindMarkedChoice(ppd, keyword); if (choice && strcmp(choice->choice, keyptr)) { if (strcmp(choice->choice, "Custom")) { cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice); ppdchanged = 1; } else if ((customval = cupsGetOption(keyword, num_options, options)) != NULL) { cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval); ppdchanged = 1; } else cupsFilePrintf(out, "%s\n", line); } else cupsFilePrintf(out, "%s\n", line); } } if (!wrote_ipp_supplies && (boolval = cupsGetOption("cupsIPPSupplies", num_options, options)) != NULL) { cupsFilePrintf(out, "*cupsIPPSupplies: %s\n", (!_cups_strcasecmp(boolval, "true") || !_cups_strcasecmp(boolval, "yes") || !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); } if (!wrote_snmp_supplies && (boolval = cupsGetOption("cupsSNMPSupplies", num_options, options)) != NULL) { cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n", (!_cups_strcasecmp(boolval, "true") || !_cups_strcasecmp(boolval, "yes") || !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); } cupsFileClose(in); cupsFileClose(out); ppdClose(ppd); /* * Do the request... */ ippDelete(cupsDoFileRequest(http, request, "/admin/", ppdchanged ? tempfile : file)); /* * Clean up temp files... (TODO: catch signals in case we CTRL-C during * lpadmin) */ if (ppdfile != file) unlink(ppdfile); unlink(tempfile); } else { /* * No PPD file - just set the options... */ ippDelete(cupsDoRequest(http, request, "/admin/")); } /* * Check the response... */ if (cupsLastError() > IPP_OK_CONFLICT) { _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); return (1); } else return (0); }
int /* O - 1 on success, 0 on failure */ cupsAdminSetServerSettings( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ int num_settings, /* I - Number of settings */ cups_option_t *settings) /* I - Settings */ { int i; /* Looping var */ http_status_t status; /* GET/PUT status */ const char *server_port_env; /* SERVER_PORT env var */ int server_port; /* IPP port for server */ cups_file_t *cupsd; /* cupsd.conf file */ char cupsdconf[1024]; /* cupsd.conf filename */ int remote; /* Remote cupsd.conf file? */ char tempfile[1024]; /* Temporary new cupsd.conf */ cups_file_t *temp; /* Temporary file */ char line[1024], /* Line from cupsd.conf file */ *value; /* Value on line */ int linenum, /* Line number in file */ in_location, /* In a location section? */ in_policy, /* In a policy section? */ in_default_policy, /* In the default policy section? */ in_cancel_job, /* In a cancel-job section? */ in_admin_location, /* In the /admin location? */ in_conf_location, /* In the /admin/conf location? */ in_log_location, /* In the /admin/log location? */ in_root_location; /* In the / location? */ const char *val; /* Setting value */ int share_printers, /* Share local printers */ remote_admin, /* Remote administration allowed? */ remote_any, /* Remote access from anywhere? */ user_cancel_any, /* Cancel-job policy set? */ debug_logging; /* LogLevel debug set? */ int wrote_port_listen, /* Wrote the port/listen lines? */ wrote_browsing, /* Wrote the browsing lines? */ wrote_policy, /* Wrote the policy? */ wrote_loglevel, /* Wrote the LogLevel line? */ wrote_admin_location, /* Wrote the /admin location? */ wrote_conf_location, /* Wrote the /admin/conf location? */ wrote_log_location, /* Wrote the /admin/log location? */ wrote_root_location; /* Wrote the / location? */ int indent; /* Indentation */ int cupsd_num_settings; /* New number of settings */ int old_share_printers, /* Share local printers */ old_remote_admin, /* Remote administration allowed? */ old_remote_any, /* Remote access from anywhere? */ old_user_cancel_any, /* Cancel-job policy set? */ old_debug_logging; /* LogLevel debug set? */ cups_option_t *cupsd_settings, /* New settings */ *setting; /* Current setting */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ /* * Range check input... */ if (!http) http = _cupsConnect(); if (!http || !num_settings || !settings) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (0); } /* * Get the cupsd.conf file... */ if (get_cupsd_conf(http, cg, 0, cupsdconf, sizeof(cupsdconf), &remote) == HTTP_STATUS_OK) { if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); return (0); } } else return (0); /* * Get current settings... */ if (!cupsAdminGetServerSettings(http, &cupsd_num_settings, &cupsd_settings)) return (0); if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, cupsd_num_settings, cupsd_settings)) != NULL) old_debug_logging = atoi(val); else old_debug_logging = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old debug_logging=%d", old_debug_logging)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, cupsd_num_settings, cupsd_settings)) != NULL) old_remote_admin = atoi(val); else old_remote_admin = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old remote_admin=%d", old_remote_admin)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, cupsd_num_settings, cupsd_settings)) != NULL) old_remote_any = atoi(val); else old_remote_any = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old remote_any=%d", old_remote_any)); if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, cupsd_num_settings, cupsd_settings)) != NULL) old_share_printers = atoi(val); else old_share_printers = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old share_printers=%d", old_share_printers)); if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, cupsd_num_settings, cupsd_settings)) != NULL) old_user_cancel_any = atoi(val); else old_user_cancel_any = 0; DEBUG_printf(("1cupsAdminSetServerSettings: old user_cancel_any=%d", old_user_cancel_any)); cupsFreeOptions(cupsd_num_settings, cupsd_settings); /* * Get basic settings... */ if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, settings)) != NULL) { debug_logging = atoi(val); if (debug_logging == old_debug_logging) { /* * No change to this setting... */ debug_logging = -1; } } else debug_logging = -1; DEBUG_printf(("1cupsAdminSetServerSettings: debug_logging=%d", debug_logging)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, settings)) != NULL) { remote_any = atoi(val); if (remote_any == old_remote_any) { /* * No change to this setting... */ remote_any = -1; } } else remote_any = -1; DEBUG_printf(("1cupsAdminSetServerSettings: remote_any=%d", remote_any)); if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, settings)) != NULL) { remote_admin = atoi(val); if (remote_admin == old_remote_admin) { /* * No change to this setting... */ remote_admin = -1; } } else remote_admin = -1; DEBUG_printf(("1cupsAdminSetServerSettings: remote_admin=%d", remote_admin)); if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, settings)) != NULL) { share_printers = atoi(val); if (share_printers == old_share_printers) { /* * No change to this setting... */ share_printers = -1; } } else share_printers = -1; DEBUG_printf(("1cupsAdminSetServerSettings: share_printers=%d", share_printers)); if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, settings)) != NULL) { user_cancel_any = atoi(val); if (user_cancel_any == old_user_cancel_any) { /* * No change to this setting... */ user_cancel_any = -1; } } else user_cancel_any = -1; DEBUG_printf(("1cupsAdminSetServerSettings: user_cancel_any=%d", user_cancel_any)); /* * Create a temporary file for the new cupsd.conf file... */ if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) { cupsFileClose(cupsd); if (remote) unlink(cupsdconf); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, NULL, 0); return (0); } /* * Copy the old file to the new, making changes along the way... */ cupsd_num_settings = 0; in_admin_location = 0; in_cancel_job = 0; in_conf_location = 0; in_default_policy = 0; in_location = 0; in_log_location = 0; in_policy = 0; in_root_location = 0; linenum = 0; wrote_admin_location = 0; wrote_browsing = 0; wrote_conf_location = 0; wrote_log_location = 0; wrote_loglevel = 0; wrote_policy = 0; wrote_port_listen = 0; wrote_root_location = 0; indent = 0; if ((server_port_env = getenv("SERVER_PORT")) != NULL) { if ((server_port = atoi(server_port_env)) <= 0) server_port = ippPort(); } else server_port = ippPort(); if (server_port <= 0) server_port = IPP_PORT; while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) { if ((!_cups_strcasecmp(line, "Port") || !_cups_strcasecmp(line, "Listen")) && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (!wrote_port_listen) { wrote_port_listen = 1; if (remote_admin > 0 || remote_any > 0 || share_printers > 0) { cupsFilePuts(temp, "# Allow remote access\n"); cupsFilePrintf(temp, "Port %d\n", server_port); } else { cupsFilePuts(temp, "# Only listen for connections from the local " "machine.\n"); cupsFilePrintf(temp, "Listen localhost:%d\n", server_port); } #ifdef CUPS_DEFAULT_DOMAINSOCKET if ((!value || strcmp(CUPS_DEFAULT_DOMAINSOCKET, value)) && !access(CUPS_DEFAULT_DOMAINSOCKET, 0)) cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); #endif /* CUPS_DEFAULT_DOMAINSOCKET */ } else if (value && value[0] == '/' #ifdef CUPS_DEFAULT_DOMAINSOCKET && strcmp(CUPS_DEFAULT_DOMAINSOCKET, value) #endif /* CUPS_DEFAULT_DOMAINSOCKET */ ) cupsFilePrintf(temp, "Listen %s\n", value); } else if ((!_cups_strcasecmp(line, "Browsing") || !_cups_strcasecmp(line, "BrowseLocalProtocols")) && share_printers >= 0) { if (!wrote_browsing) { int new_share_printers = (share_printers > 0 || (share_printers == -1 && old_share_printers > 0)); wrote_browsing = 1; if (new_share_printers) { const char *localp = cupsGetOption("BrowseLocalProtocols", num_settings, settings); if (!localp || !localp[0]) localp = cupsGetOption("BrowseLocalProtocols", cupsd_num_settings, cupsd_settings); cupsFilePuts(temp, "# Share local printers on the local network.\n"); cupsFilePuts(temp, "Browsing On\n"); if (!localp) localp = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS; cupsFilePrintf(temp, "BrowseLocalProtocols %s\n", localp); cupsd_num_settings = cupsAddOption("BrowseLocalProtocols", localp, cupsd_num_settings, &cupsd_settings); } else { cupsFilePuts(temp, "# Disable printer sharing.\n"); cupsFilePuts(temp, "Browsing Off\n"); } } } else if (!_cups_strcasecmp(line, "LogLevel") && debug_logging >= 0) { wrote_loglevel = 1; if (debug_logging) { cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); cupsFilePuts(temp, "LogLevel debug\n"); } else { cupsFilePuts(temp, "# Show general information in error_log.\n"); cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); } } else if (!_cups_strcasecmp(line, "<Policy")) { in_default_policy = !_cups_strcasecmp(value, "default"); in_policy = 1; cupsFilePrintf(temp, "%s %s>\n", line, value); indent += 2; } else if (!_cups_strcasecmp(line, "</Policy>")) { indent -= 2; if (!wrote_policy && in_default_policy) { wrote_policy = 1; if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can " "cancel a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); } in_policy = 0; in_default_policy = 0; cupsFilePuts(temp, "</Policy>\n"); } else if (!_cups_strcasecmp(line, "<Location")) { in_location = 1; indent += 2; if (!strcmp(value, "/admin")) in_admin_location = 1; else if (!strcmp(value, "/admin/conf")) in_conf_location = 1; else if (!strcmp(value, "/admin/log")) in_log_location = 1; else if (!strcmp(value, "/")) in_root_location = 1; cupsFilePrintf(temp, "%s %s>\n", line, value); } else if (!_cups_strcasecmp(line, "</Location>")) { in_location = 0; indent -= 2; if (in_admin_location && remote_admin >= 0) { wrote_admin_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote administration...\n"); else if (remote_admin == 0) cupsFilePuts(temp, " # Restrict access to the admin pages...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_conf_location && remote_admin >= 0) { wrote_conf_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote access to the configuration " "files...\n"); else cupsFilePuts(temp, " # Restrict access to the configuration " "files...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_log_location && remote_admin >= 0) { wrote_log_location = 1; if (remote_admin) cupsFilePuts(temp, " # Allow remote access to the log " "files...\n"); else cupsFilePuts(temp, " # Restrict access to the log " "files...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } else if (in_root_location && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { wrote_root_location = 1; if (remote_admin > 0 && share_printers > 0) cupsFilePuts(temp, " # Allow shared printing and remote " "administration...\n"); else if (remote_admin > 0) cupsFilePuts(temp, " # Allow remote administration...\n"); else if (share_printers > 0) cupsFilePuts(temp, " # Allow shared printing...\n"); else if (remote_any > 0) cupsFilePuts(temp, " # Allow remote access...\n"); else cupsFilePuts(temp, " # Restrict access to the server...\n"); cupsFilePuts(temp, " Order allow,deny\n"); if (remote_admin > 0 || remote_any > 0 || share_printers > 0) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); } in_admin_location = 0; in_conf_location = 0; in_log_location = 0; in_root_location = 0; cupsFilePuts(temp, "</Location>\n"); } else if (!_cups_strcasecmp(line, "<Limit")) { if (in_default_policy) { /* * See if the policy limit is for the Cancel-Job operation... */ char *valptr; /* Pointer into value */ if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) { /* * Don't write anything for this limit section... */ in_cancel_job = 2; } else { cupsFilePrintf(temp, "%*s%s", indent, "", line); while (*value) { for (valptr = value; *valptr && !_cups_isspace(*valptr); valptr ++); if (*valptr) *valptr++ = '\0'; if (!_cups_strcasecmp(value, "cancel-job") && user_cancel_any >= 0) { /* * Write everything except for this definition... */ in_cancel_job = 1; } else cupsFilePrintf(temp, " %s", value); for (value = valptr; _cups_isspace(*value); value ++); } cupsFilePuts(temp, ">\n"); } } else cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); indent += 2; } else if (!_cups_strcasecmp(line, "</Limit>") && in_cancel_job) { indent -= 2; if (in_cancel_job == 1) cupsFilePuts(temp, " </Limit>\n"); wrote_policy = 1; if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can cancel " "a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); in_cancel_job = 0; } else if ((((in_admin_location || in_conf_location || in_root_location) && (remote_admin >= 0 || remote_any >= 0)) || (in_root_location && share_printers >= 0)) && (!_cups_strcasecmp(line, "Allow") || !_cups_strcasecmp(line, "Deny") || !_cups_strcasecmp(line, "Order"))) continue; else if (in_cancel_job == 2) continue; else if (line[0] == '<') { if (value) { cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); indent += 2; } else { if (line[1] == '/') indent -= 2; cupsFilePrintf(temp, "%*s%s\n", indent, "", line); } } else if (!in_policy && !in_location && (val = cupsGetOption(line, num_settings, settings)) != NULL) { /* * Replace this directive's value with the new one... */ cupsd_num_settings = cupsAddOption(line, val, cupsd_num_settings, &cupsd_settings); /* * Write the new value in its place, without indentation since we * only support setting root directives, not in sections... */ cupsFilePrintf(temp, "%s %s\n", line, val); } else if (value) { if (!in_policy && !in_location) { /* * Record the non-policy, non-location directives that we find * in the server settings, since we cache this info and record it * in cupsAdminGetServerSettings()... */ cupsd_num_settings = cupsAddOption(line, value, cupsd_num_settings, &cupsd_settings); } cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value); } else cupsFilePrintf(temp, "%*s%s\n", indent, "", line); } /* * Write any missing info... */ if (!wrote_browsing && share_printers >= 0) { if (share_printers > 0) { cupsFilePuts(temp, "# Share local printers on the local network.\n"); cupsFilePuts(temp, "Browsing On\n"); } else { cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); cupsFilePuts(temp, "Browsing Off\n"); } } if (!wrote_loglevel && debug_logging >= 0) { if (debug_logging) { cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); cupsFilePuts(temp, "LogLevel debug\n"); } else { cupsFilePuts(temp, "# Show general information in error_log.\n"); cupsFilePuts(temp, "LogLevel " CUPS_DEFAULT_LOG_LEVEL "\n"); } } if (!wrote_port_listen && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (remote_admin > 0 || remote_any > 0 || share_printers > 0) { cupsFilePuts(temp, "# Allow remote access\n"); cupsFilePrintf(temp, "Port %d\n", ippPort()); } else { cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); } #ifdef CUPS_DEFAULT_DOMAINSOCKET if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0)) cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); #endif /* CUPS_DEFAULT_DOMAINSOCKET */ } if (!wrote_root_location && (remote_admin >= 0 || remote_any >= 0 || share_printers >= 0)) { if (remote_admin > 0 && share_printers > 0) cupsFilePuts(temp, "# Allow shared printing and remote administration...\n"); else if (remote_admin > 0) cupsFilePuts(temp, "# Allow remote administration...\n"); else if (share_printers > 0) cupsFilePuts(temp, "# Allow shared printing...\n"); else if (remote_any > 0) cupsFilePuts(temp, "# Allow remote access...\n"); else cupsFilePuts(temp, "# Restrict access to the server...\n"); cupsFilePuts(temp, "<Location />\n" " Order allow,deny\n"); if (remote_admin > 0 || remote_any > 0 || share_printers > 0) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_admin_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote administration...\n"); else cupsFilePuts(temp, "# Restrict access to the admin pages...\n"); cupsFilePuts(temp, "<Location /admin>\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_conf_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote access to the configuration files...\n"); else cupsFilePuts(temp, "# Restrict access to the configuration files...\n"); cupsFilePuts(temp, "<Location /admin/conf>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_log_location && remote_admin >= 0) { if (remote_admin) cupsFilePuts(temp, "# Allow remote access to the log files...\n"); else cupsFilePuts(temp, "# Restrict access to the log files...\n"); cupsFilePuts(temp, "<Location /admin/log>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order allow,deny\n"); if (remote_admin) cupsFilePrintf(temp, " Allow %s\n", remote_any > 0 ? "all" : "@LOCAL"); cupsFilePuts(temp, "</Location>\n"); } if (!wrote_policy && user_cancel_any >= 0) { cupsFilePuts(temp, "<Policy default>\n" " # Job-related operations must be done by the owner " "or an administrator...\n" " <Limit Send-Document Send-URI Hold-Job Release-Job " "Restart-Job Purge-Jobs Set-Job-Attributes " "Create-Job-Subscription Renew-Subscription " "Cancel-Subscription Get-Notifications Reprocess-Job " "Cancel-Current-Job Suspend-Current-Job Resume-Job " "CUPS-Move-Job>\n" " Require user @OWNER @SYSTEM\n" " Order deny,allow\n" " </Limit>\n" " # All administration operations require an " "administrator to authenticate...\n" " <Limit Pause-Printer Resume-Printer " "Set-Printer-Attributes Enable-Printer " "Disable-Printer Pause-Printer-After-Current-Job " "Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer " "Activate-Printer Restart-Printer Shutdown-Printer " "Startup-Printer Promote-Job Schedule-Job-After " "CUPS-Add-Printer CUPS-Delete-Printer " "CUPS-Add-Class CUPS-Delete-Class " "CUPS-Accept-Jobs CUPS-Reject-Jobs " "CUPS-Set-Default CUPS-Add-Device CUPS-Delete-Device>\n" " AuthType Default\n" " Require user @SYSTEM\n" " Order deny,allow\n" "</Limit>\n"); if (!user_cancel_any) cupsFilePuts(temp, " # Only the owner or an administrator can cancel " "a job...\n" " <Limit Cancel-Job>\n" " Order deny,allow\n" " Require user @OWNER " CUPS_DEFAULT_PRINTOPERATOR_AUTH "\n" " </Limit>\n"); cupsFilePuts(temp, " <Limit All>\n" " Order deny,allow\n" " </Limit>\n" "</Policy>\n"); } for (i = num_settings, setting = settings; i > 0; i --, setting ++) if (setting->name[0] != '_' && _cups_strcasecmp(setting->name, "Listen") && _cups_strcasecmp(setting->name, "Port") && !cupsGetOption(setting->name, cupsd_num_settings, cupsd_settings)) { /* * Add this directive to the list of directives we have written... */ cupsd_num_settings = cupsAddOption(setting->name, setting->value, cupsd_num_settings, &cupsd_settings); /* * Write the new value, without indentation since we only support * setting root directives, not in sections... */ cupsFilePrintf(temp, "%s %s\n", setting->name, setting->value); } cupsFileClose(cupsd); cupsFileClose(temp); /* * Upload the configuration file to the server... */ status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); if (status == HTTP_STATUS_CREATED) { /* * Updated OK, add the basic settings... */ if (debug_logging >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, debug_logging ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, old_debug_logging ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (remote_admin >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, remote_admin ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, old_remote_admin ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (remote_any >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, remote_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, old_remote_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (share_printers >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, share_printers ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, old_share_printers ? "1" : "0", cupsd_num_settings, &cupsd_settings); if (user_cancel_any >= 0) cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, user_cancel_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); else cupsd_num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, old_user_cancel_any ? "1" : "0", cupsd_num_settings, &cupsd_settings); /* * Save the new values... */ invalidate_cupsd_cache(cg); cg->cupsd_num_settings = cupsd_num_settings; cg->cupsd_settings = cupsd_settings; cg->cupsd_update = time(NULL); httpGetHostname(http, cg->cupsd_hostname, sizeof(cg->cupsd_hostname)); } else cupsFreeOptions(cupsd_num_settings, cupsd_settings); /* * Remote our temp files and return... */ if (remote) unlink(cupsdconf); unlink(tempfile); return (status == HTTP_STATUS_CREATED); }
void * /* O - Profile or NULL on error */ cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */ { #ifdef HAVE_SANDBOX_H cups_file_t *fp; /* File pointer */ char profile[1024], /* File containing the profile */ cache[1024], /* Quoted CacheDir */ request[1024], /* Quoted RequestRoot */ root[1024], /* Quoted ServerRoot */ temp[1024]; /* Quoted TempDir */ const char *nodebug; /* " (with no-log)" for no debug */ if (!UseProfiles) { /* * Only use sandbox profiles as root... */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL", job_id); return (NULL); } if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL) { cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL", job_id); cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s", strerror(errno)); return (NULL); } fchown(cupsFileNumber(fp), RunUser, Group); fchmod(cupsFileNumber(fp), 0640); cupsd_requote(cache, CacheDir, sizeof(cache)); cupsd_requote(request, RequestRoot, sizeof(request)); cupsd_requote(root, ServerRoot, sizeof(root)); cupsd_requote(temp, TempDir, sizeof(temp)); nodebug = LogLevel < CUPSD_LOG_DEBUG ? " (with no-log)" : ""; cupsFilePuts(fp, "(version 1)\n"); cupsFilePuts(fp, "(allow default)\n"); cupsFilePrintf(fp, "(deny file-write* file-read-data file-read-metadata\n" " (regex" " #\"^%s$\"" /* RequestRoot */ " #\"^%s/\"" /* RequestRoot/... */ ")%s)\n", request, request, nodebug); if (!RunUser) cupsFilePrintf(fp, "(deny file-write* file-read-data file-read-metadata\n" " (regex" " #\"^/Users$\"" " #\"^/Users/\"" ")%s)\n", nodebug); cupsFilePrintf(fp, "(deny file-write*\n" " (regex" " #\"^%s$\"" /* ServerRoot */ " #\"^%s/\"" /* ServerRoot/... */ " #\"^/private/etc$\"" " #\"^/private/etc/\"" " #\"^/usr/local/etc$\"" " #\"^/usr/local/etc/\"" " #\"^/Library$\"" " #\"^/Library/\"" " #\"^/System$\"" " #\"^/System/\"" ")%s)\n", root, root, nodebug); /* Specifically allow applications to stat RequestRoot */ cupsFilePrintf(fp, "(allow file-read-metadata\n" " (regex" " #\"^%s$\"" /* RequestRoot */ "))\n", request); cupsFilePrintf(fp, "(allow file-write* file-read-data file-read-metadata\n" " (regex" " #\"^%s$\"" /* TempDir */ " #\"^%s/\"" /* TempDir/... */ " #\"^%s$\"" /* CacheDir */ " #\"^%s/\"" /* CacheDir/... */ " #\"^%s/Library$\"" /* RequestRoot/Library */ " #\"^%s/Library/\"" /* RequestRoot/Library/... */ " #\"^/Library/Application Support/\"" " #\"^/Library/Caches/\"" " #\"^/Library/Preferences/\"" " #\"^/Library/Printers/.*/\"" " #\"^/Users/Shared/\"" "))\n", temp, temp, cache, cache, request, request); cupsFilePrintf(fp, "(deny file-write*\n" " (regex" " #\"^/Library/Printers/PPDs$\"" " #\"^/Library/Printers/PPDs/\"" " #\"^/Library/Printers/PPD Plugins$\"" " #\"^/Library/Printers/PPD Plugins/\"" ")%s)\n", nodebug); if (job_id) { /* * Allow job filters to read the spool file(s)... */ cupsFilePrintf(fp, "(allow file-read-data file-read-metadata\n" " (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n", request, job_id, job_id); } else { /* * Allow email notifications from notifiers... */ cupsFilePuts(fp, "(allow process-exec\n" " (literal \"/usr/sbin/sendmail\")\n" " (with no-sandbox)\n" ")\n"); } cupsFileClose(fp); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = \"%s\"", job_id, profile); return ((void *)strdup(profile)); #else cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL", job_id); return (NULL); #endif /* HAVE_SANDBOX_H */ }