You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/kdeprint/cups/cupsdconf2/cups-util.c

558 lines
13 KiB

#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);
}