static int make_certificate(cupsd_client_t *con);
int
cupsdEndTLS(cupsd_client_t *con)
{
SSL_CTX *context;
unsigned long error;
int status;
context = SSL_get_SSL_CTX(con->http.tls);
switch (SSL_shutdown(con->http.tls))
{
case 1 :
cupsdLogMessage(CUPSD_LOG_DEBUG,
"SSL shutdown successful!");
status = 1;
break;
case -1 :
cupsdLogMessage(CUPSD_LOG_ERROR,
"Fatal error during SSL shutdown!");
default :
while ((error = ERR_get_error()) != 0)
cupsdLogMessage(CUPSD_LOG_ERROR, "SSL shutdown failed: %s",
ERR_error_string(error, NULL));
status = 0;
break;
}
SSL_CTX_free(context);
SSL_free(con->http.tls);
con->http.tls = NULL;
return (status);
}
int
cupsdStartTLS(cupsd_client_t *con)
{
SSL_CTX *context;
BIO *bio;
unsigned long error;
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.",
con->http.fd);
if (access(ServerKey, 0) || access(ServerCertificate, 0))
{
if (!make_certificate(con))
return (0);
}
context = SSL_CTX_new(SSLv23_server_method());
SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
if (SSLOptions & CUPSD_SSL_NOEMPTY)
SSL_CTX_set_options(context, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM);
SSL_CTX_use_certificate_chain_file(context, ServerCertificate);
bio = BIO_new(_httpBIOMethods());
BIO_ctrl(bio, BIO_C_SET_FILE_PTR, 0, (char *)HTTP(con));
con->http.tls = SSL_new(context);
SSL_set_bio(con->http.tls, bio, bio);
if (SSL_accept(con->http.tls) != 1)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to encrypt connection from %s.",
con->http.hostname);
while ((error = ERR_get_error()) != 0)
cupsdLogMessage(CUPSD_LOG_ERROR, "%s", ERR_error_string(error, NULL));
SSL_CTX_free(context);
SSL_free(con->http.tls);
con->http.tls = NULL;
return (0);
}
cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.",
con->http.hostname);
return (1);
}
static int
make_certificate(cupsd_client_t *con)
{
#ifdef HAVE_WAITPID
int pid,
status;
char command[1024],
*argv[12],
*envp[MAX_ENV + 1],
infofile[1024],
seedfile[1024];
int envc,
bytes;
cups_file_t *fp;
int infofd;
if (!cupsFileFind("openssl", getenv("PATH"), 1, command, sizeof(command)))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"No SSL certificate and openssl command not found!");
return (0);
}
if (access("/dev/urandom", 0))
{
cupsdLogMessage(CUPSD_LOG_INFO,
"Seeding the random number generator...");
if ((fp = cupsTempFile2(seedfile, sizeof(seedfile))) == NULL)
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create seed file %s - %s",
seedfile, strerror(errno));
return (0);
}
for (bytes = 0; bytes < 262144; bytes ++)
cupsFilePutChar(fp, CUPS_RAND());
cupsFileClose(fp);
argv[0] = "openssl";
argv[1] = "rand";
argv[2] = "-rand";
argv[3] = seedfile;
argv[4] = "1";
argv[5] = NULL;
envc = cupsdLoadEnv(envp, MAX_ENV);
envp[envc] = NULL;
if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
NULL, &pid))
{
unlink(seedfile);
return (0);
}
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR)
{
status = 1;
break;
}
cupsdFinishProcess(pid, command, sizeof(command), NULL);
unlink(seedfile);
if (status)
{
if (WIFEXITED(status))
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to seed random number generator - "
"the openssl command stopped with status %d!",
WEXITSTATUS(status));
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to seed random number generator - "
"the openssl command crashed on signal %d!",
WTERMSIG(status));
return (0);
}
}
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, ".\n.\n.\n%s\n.\n%s\n%s\n",
ServerName, ServerName, ServerAdmin);
cupsFileClose(fp);
cupsdLogMessage(CUPSD_LOG_INFO,
"Generating SSL server key and certificate...");
argv[0] = "openssl";
argv[1] = "req";
argv[2] = "-new";
argv[3] = "-x509";
argv[4] = "-keyout";
argv[5] = ServerKey;
argv[6] = "-out";
argv[7] = ServerCertificate;
argv[8] = "-days";
argv[9] = "3650";
argv[10] = "-nodes";
argv[11] = 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 openssl command stopped with status %d!",
WEXITSTATUS(status));
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to create SSL server key and certificate - "
"the openssl command crashed on signal %d!",
WTERMSIG(status));
}
else
{
cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...",
ServerKey);
cupsdLogMessage(CUPSD_LOG_INFO,
"Created SSL server certificate file \"%s\"...",
ServerCertificate);
}
return (!status);
#else
return (0);
#endif
}