diff options
Diffstat (limited to 'tdeprint/cups/cupsdconf2/cups-util.c')
-rw-r--r-- | tdeprint/cups/cupsdconf2/cups-util.c | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/tdeprint/cups/cupsdconf2/cups-util.c b/tdeprint/cups/cupsdconf2/cups-util.c new file mode 100644 index 000000000..eadd6b629 --- /dev/null +++ b/tdeprint/cups/cupsdconf2/cups-util.c @@ -0,0 +1,557 @@ +#include <stdio.h> +#include <cups/ipp.h> +#include <cups/http.h> +#include <cups/cups.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#define CUPS_SERVERROOT "/etc/cups" +static http_t *cups_server; +static ipp_status_t last_error; +static char authstring[HTTP_MAX_VALUE]; +static char pwdstring[33]; +static int cups_local_auth(http_t *http); + +const char* cupsGetConf( void ); +int cupsPutConf( const char* ); + +const char * /* O - Filename for PPD file */ +cupsGetConf(void) +{ + int fd; /* PPD file */ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + char resource[HTTP_MAX_URI]; /* Resource name */ + const char *password; /* Password string */ + char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ + nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ + plain[255], /* Plaintext username:password */ + encode[512]; /* Encoded username:password */ + http_status_t status; /* HTTP status from server */ + char prompt[1024]; /* Prompt string */ + int digest_tries; /* Number of tries with Digest */ + static char filename[HTTP_MAX_URI]; /* Local filename */ +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + const char *fqdn = 0; +#else + char fqdn[ HTTP_MAX_URI ]; /* Server name buffer */ +#endif + + + /* + * Connect to the correct server as needed... + */ + + if ((cups_server = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + + /* + * Get a temp file... + */ + + if ((fd = cupsTempFd(filename, sizeof(filename))) < 0) + { + /* + * Can't open file; close the server connection and return NULL... + */ + + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + return (NULL); + } + + /* + * And send a request to the HTTP server... + */ + + snprintf(resource, sizeof(resource), "/admin/conf/cupsd.conf"); + + digest_tries = 0; + + do + { + httpClearFields(cups_server); + httpSetField(cups_server, HTTP_FIELD_HOST, cupsServer()); + httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring); + + if (httpGet(cups_server, resource)) + { + if (httpReconnect(cups_server)) + { + status = HTTP_ERROR; + break; + } + else + { + status = HTTP_UNAUTHORIZED; + continue; + } + } + + while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + const char *www_authenticate; + fprintf(stderr,"cupsGetConf: unauthorized...\n"); + + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(cups_server)) + continue; + + /* + * See if we should retry the current digest password... + */ + +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + www_authenticate = cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE]; +#else + www_authenticate = httpGetField( cups_server, HTTP_FIELD_WWW_AUTHENTICATE ); +#endif + if (strncmp(www_authenticate, "Basic", 5) == 0 || + digest_tries > 1 || !pwdstring[0]) + { + /* + * Nope - get a password from the user... + */ +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + fqdn = cups_server->hostname; +#else + httpGetHostname( cups_server, fqdn, sizeof( fqdn ) ); +#endif + + snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), fqdn ); + + if ((password = cupsGetPassword(prompt)) == NULL) + break; + if (!password[0]) + break; + + strncpy(pwdstring, password, sizeof(pwdstring) - 1); + pwdstring[sizeof(pwdstring) - 1] = '\0'; + + digest_tries = 0; + } + else + digest_tries ++; + + /* + * Got a password; encode it for the server... + */ + +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + www_authenticate = cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE]; +#else + www_authenticate = httpGetField( cups_server, HTTP_FIELD_WWW_AUTHENTICATE ); +#endif + if (strncmp(www_authenticate, "Basic", 5) == 0) + { + /* + * Basic authentication... + */ + + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring); +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2 + httpEncode64_2(encode, sizeof(encode), plain, sizeof(plain)); +#else + httpEncode64(encode, plain); +#endif + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + } + else + { + /* + * Digest authentication... + */ + + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); + + httpMD5(cupsUser(), realm, pwdstring, encode); + httpMD5Final(nonce, "GET", resource, encode); + snprintf(authstring, sizeof(authstring), + "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " + "response=\"%s\"", cupsUser(), realm, nonce, encode); + } + + continue; + } +#ifdef HAVE_LIBSSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * Upgrade with encryption... + */ + + httpEncryption(cups_server, HTTP_ENCRYPT_REQUIRED); + + /* + * Try again, this time with encryption enabled... + */ + + continue; + } +#endif /* HAVE_LIBSSL */ + } + while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); + + /* + * See if we actually got the file or an error... + */ + + if (status != HTTP_OK) + { + close(fd); + unlink(filename); + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + return (NULL); + } + + /* + * OK, we need to copy the file... + */ + + while ((bytes = +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + httpRead +#else + httpRead2 +#endif + (cups_server, buffer, sizeof(buffer))) > 0) + { + write(fd, buffer, bytes); + } + + close(fd); + + return (filename); +} + +int /* O - Status of operation */ +cupsPutConf(const char *name) /* I - Name of the config file to send */ +{ + int fd; /* PPD file */ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + char resource[HTTP_MAX_URI]; /* Resource name */ + const char *password; /* Password string */ + char realm[HTTP_MAX_VALUE], /* realm="xyz" string */ + nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ + plain[255], /* Plaintext username:password */ + encode[512]; /* Encoded username:password */ + http_status_t status; /* HTTP status from server */ + char prompt[1024]; /* Prompt string */ + int digest_tries; /* Number of tries with Digest */ +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + const char *fqdn = 0; +#else + char fqdn[ HTTP_MAX_URI ]; /* Server name buffer */ +#endif + + if (name == NULL) + return 0; + + /* + * Connect to the correct server as needed... + */ + + if ((cups_server = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return 0; + } + + /* + * Open the local config file... + */ + + if ((fd = open(name, O_RDONLY)) < 0) + { + /* + * Can't open file; close the server connection and return NULL... + */ + + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + return 0; + } + + /* + * And send a request to the HTTP server... + */ + + strncpy(resource, "/admin/conf/cupsd.conf", sizeof(resource)); + + digest_tries = 0; + + do + { + httpClearFields(cups_server); + httpSetField(cups_server, HTTP_FIELD_HOST, cupsServer()); + httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring); + httpSetField(cups_server, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); + + if (httpPut(cups_server, resource)) + { + if (httpReconnect(cups_server)) + { + status = HTTP_ERROR; + break; + } + else + { + status = HTTP_UNAUTHORIZED; + continue; + } + } + + /* send the file now */ + lseek(fd, 0, SEEK_SET); + status = HTTP_CONTINUE; + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + if (httpCheck(cups_server)) + { + if ((status = httpUpdate(cups_server)) != HTTP_CONTINUE) + break; + } + else +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + httpWrite +#else + httpWrite2 +#endif + (cups_server, buffer, bytes); + + if (status == HTTP_CONTINUE) + { +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + httpWrite +#else + httpWrite2 +#endif + (cups_server, buffer, 0); + while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE); + } + + if (status == HTTP_UNAUTHORIZED) + { + const char *www_authenticate; + fprintf(stderr,"cupsPutConf: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(cups_server)) + continue; + + /* + * See if we should retry the current digest password... + */ + +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + www_authenticate = cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE]; +#else + www_authenticate = httpGetField( cups_server, HTTP_FIELD_WWW_AUTHENTICATE ); +#endif + if (strncmp(www_authenticate, "Basic", 5) == 0 || + digest_tries > 1 || !pwdstring[0]) + { + /* + * Nope - get a password from the user... + */ + + +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + fqdn = cups_server->hostname; +#else + httpGetHostname( cups_server, fqdn, sizeof( fqdn ) ); +#endif + snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), fqdn ); + + if ((password = cupsGetPassword(prompt)) == NULL) + break; + if (!password[0]) + break; + + strncpy(pwdstring, password, sizeof(pwdstring) - 1); + pwdstring[sizeof(pwdstring) - 1] = '\0'; + + digest_tries = 0; + } + else + digest_tries ++; + + /* + * Got a password; encode it for the server... + */ + +#if CUPS_VERSION_MAJOR - 0 <= 1 && CUPS_VERSION_MINOR - 0 < 2 + www_authenticate = cups_server->fields[HTTP_FIELD_WWW_AUTHENTICATE]; +#else + www_authenticate = httpGetField( cups_server, HTTP_FIELD_WWW_AUTHENTICATE ); +#endif + if (strncmp(www_authenticate, "Basic", 5) == 0) + { + /* + * Basic authentication... + */ + + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), pwdstring); +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2 + httpEncode64_2(encode, sizeof(encode), plain, sizeof(plain)); +#else + httpEncode64(encode, plain); +#endif + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + } + else + { + /* + * Digest authentication... + */ + + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); + httpGetSubField(cups_server, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); + + httpMD5(cupsUser(), realm, pwdstring, encode); + httpMD5Final(nonce, "GET", resource, encode); + snprintf(authstring, sizeof(authstring), + "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " + "response=\"%s\"", cupsUser(), realm, nonce, encode); + } + + continue; + } +#ifdef HAVE_LIBSSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * Upgrade with encryption... + */ + + httpEncryption(cups_server, HTTP_ENCRYPT_REQUIRED); + + /* + * Try again, this time with encryption enabled... + */ + + continue; + } +#endif /* HAVE_LIBSSL */ + } + while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); + + /* + * See if we actually got the file or an error... + */ + + if (status != HTTP_CREATED) + { + httpFlush(cups_server); + httpClose(cups_server); + cups_server = NULL; + close(fd); + return 0; + } + + close(fd); + + return 1; +} + +static int /* O - 1 if available, 0 if not */ +cups_local_auth(http_t *http) /* I - Connection */ +{ + int pid; /* Current process ID */ + FILE *fp; /* Certificate file */ + char filename[1024], /* Certificate filename */ + certificate[33];/* Certificate string */ + const char *root; /* Server root directory */ + + + /* + * See if we are accessing localhost... + the struct has changed in newer versions - PiggZ (adam@piggz.co.uk) + */ +#if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR >= 2 + if (!httpAddrLocalhost(http)) +#else + if (ntohl(*(int*)&http->hostaddr.sin_addr) != 0x7f000001 && + strcasecmp(http->hostname, "localhost") != 0) +#endif + return (0); + + /* + * Try opening a certificate file for this PID. If that fails, + * try the root certificate... + */ + + if ((root = getenv("CUPS_SERVERROOT")) == NULL) + root = CUPS_SERVERROOT; + + pid = getpid(); + snprintf(filename, sizeof(filename), "%s/certs/%d", root, pid); + if ((fp = fopen(filename, "r")) == NULL && pid > 0) + { + snprintf(filename, sizeof(filename), "%s/certs/0", root); + fp = fopen(filename, "r"); + } + + if (fp == NULL) + return (0); + + /* + * Read the certificate from the file... + */ + + fgets(certificate, sizeof(certificate), fp); + fclose(fp); + + /* + * Set the authorization string and return... + */ + + snprintf(authstring, sizeof(authstring), "Local %s", certificate); + + return (1); +} + |