/*
- * "$Id: usersys.c 4918 2006-01-12 05:14:40Z mike $"
+ * User, system, and password routines for CUPS.
*
- * User, system, and password routines for the Common UNIX Printing
- * System (CUPS).
+ * Copyright 2007-2017 by Apple Inc.
+ * Copyright 1997-2006 by Easy Software Products.
*
- * Copyright 1997-2006 by Easy Software Products.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * missing or damaged, see the license at "http://www.cups.org/".
*
- * These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
- *
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * Contents:
- *
- * cupsEncryption() - Get the default encryption settings.
- * cupsGetPassword() - Get a password from the user.
- * cupsServer() - Return the hostname of the default server.
- * cupsSetEncryption() - Set the encryption preference.
- * cupsSetPasswordCB() - Set the password callback for CUPS.
- * cupsSetServer() - Set the default server name.
- * cupsSetUser() - Set the default user name.
- * cupsUser() - Return the current users name.
- * _cupsGetPassword() - Get a password from the user.
+ * This file is subject to the Apple OS-Developed Software exception.
*/
/*
* Include necessary headers...
*/
-#include "http-private.h"
-#include "globals.h"
+#include "cups-private.h"
#include <stdlib.h>
+#include <sys/stat.h>
#ifdef WIN32
# include <windows.h>
+#else
+# include <pwd.h>
+# include <termios.h>
+# include <sys/utsname.h>
#endif /* WIN32 */
/*
- * 'cupsEncryption()' - Get the default encryption settings.
+ * Local constants...
+ */
+
+#ifdef __APPLE__
+# define kCUPSPrintingPrefs CFSTR("org.cups.PrintingPrefs")
+# define kAllowAnyRootKey CFSTR("AllowAnyRoot")
+# define kAllowExpiredCertsKey CFSTR("AllowExpiredCerts")
+# define kEncryptionKey CFSTR("Encryption")
+# define kGSSServiceNameKey CFSTR("GSSServiceName")
+# define kSSLOptionsKey CFSTR("SSLOptions")
+# define kTrustOnFirstUseKey CFSTR("TrustOnFirstUse")
+# define kValidateCertsKey CFSTR("ValidateCerts")
+#endif /* __APPLE__ */
+
+#define _CUPS_PASSCHAR '*' /* Character that is echoed for password */
+
+
+/*
+ * Local types...
+ */
+
+typedef struct _cups_client_conf_s /**** client.conf config data ****/
+{
+#ifdef HAVE_SSL
+ int ssl_options, /* SSLOptions values */
+ ssl_min_version,/* Minimum SSL/TLS version */
+ ssl_max_version;/* Maximum SSL/TLS version */
+#endif /* HAVE_SSL */
+ int trust_first, /* Trust on first use? */
+ any_root, /* Allow any (e.g., self-signed) root */
+ expired_certs, /* Allow expired certs */
+ validate_certs; /* Validate certificates */
+ http_encryption_t encryption; /* Encryption setting */
+ char user[65], /* User name */
+ server_name[256];
+ /* Server hostname */
+#ifdef HAVE_GSSAPI
+ char gss_service_name[32];
+ /* Kerberos service name */
+#endif /* HAVE_GSSAPI */
+} _cups_client_conf_t;
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef __APPLE__
+static int cups_apple_get_boolean(CFStringRef key, int *value);
+static int cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
+#endif /* __APPLE__ */
+static int cups_boolean_value(const char *value);
+static void cups_finalize_client_conf(_cups_client_conf_t *cc);
+static void cups_init_client_conf(_cups_client_conf_t *cc);
+static void cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
+static void cups_set_default_ipp_port(_cups_globals_t *cg);
+static void cups_set_encryption(_cups_client_conf_t *cc, const char *value);
+#ifdef HAVE_GSSAPI
+static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
+#endif /* HAVE_GSSAPI */
+static void cups_set_server_name(_cups_client_conf_t *cc, const char *value);
+#ifdef HAVE_SSL
+static void cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
+#endif /* HAVE_SSL */
+static void cups_set_user(_cups_client_conf_t *cc, const char *value);
+
+
+/*
+ * 'cupsEncryption()' - Get the current encryption settings.
*
* The default encryption setting comes from the CUPS_ENCRYPTION
- * environment variable, then the ~/.cupsrc file, and finally the
+ * environment variable, then the ~/.cups/client.conf file, and finally the
* /etc/cups/client.conf file. If not set, the default is
- * HTTP_ENCRYPT_IF_REQUESTED.
+ * @code HTTP_ENCRYPTION_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting via the
+ * @link cupsSetEncryption@ function need to do so in each thread for the same
+ * setting to be used.
*/
http_encryption_t /* O - Encryption settings */
cupsEncryption(void)
{
- cups_file_t *fp; /* client.conf file */
- char *encryption; /* CUPS_ENCRYPTION variable */
- const char *home; /* Home directory of user */
- char line[1024], /* Line from file */
- *value; /* Value on line */
- int linenum; /* Line number */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * First see if we have already set the encryption stuff...
- */
-
if (cg->encryption == (http_encryption_t)-1)
- {
- /*
- * Then see if the CUPS_ENCRYPTION environment variable is set...
- */
+ _cupsSetDefaults();
- if ((encryption = getenv("CUPS_ENCRYPTION")) == NULL)
- {
- /*
- * Next check to see if we have a $HOME/.cupsrc or client.conf file...
- */
+ return (cg->encryption);
+}
- if ((home = getenv("HOME")) != NULL)
- {
- snprintf(line, sizeof(line), "%s/.cupsrc", home);
- fp = cupsFileOpen(line, "r");
- }
- else
- fp = NULL;
- if (fp == NULL)
- {
- snprintf(line, sizeof(line), "%s/client.conf", cg->cups_serverroot);
- fp = cupsFileOpen(line, "r");
- }
+/*
+ * 'cupsGetPassword()' - Get a password from the user.
+ *
+ * Uses the current password callback function. Returns @code NULL@ if the
+ * user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+ * do so in each thread for the same function to be used.
+ *
+ * @exclude all@
+ */
- encryption = "IfRequested";
+const char * /* O - Password */
+cupsGetPassword(const char *prompt) /* I - Prompt string */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- if (fp != NULL)
- {
- /*
- * Read the config file and look for an Encryption line...
- */
- linenum = 0;
+ return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
+}
- while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL)
- if (!strcasecmp(line, "Encryption") && value)
- {
- /*
- * Got it!
- */
- encryption = value;
- break;
- }
+/*
+ * 'cupsGetPassword2()' - Get a password from the user using the current
+ * password callback.
+ *
+ * Uses the current password callback function. Returns @code NULL@ if the
+ * user does not provide a password.
+ *
+ * Note: The current password callback function is tracked separately for each
+ * thread in a program. Multi-threaded programs that override the setting via
+ * the @link cupsSetPasswordCB2@ function need to do so in each thread for the
+ * same function to be used.
+ *
+ * @since CUPS 1.4/macOS 10.6@
+ */
- cupsFileClose(fp);
- }
- }
+const char * /* O - Password */
+cupsGetPassword2(const char *prompt, /* I - Prompt string */
+ http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
+ const char *method, /* I - Request method ("GET", "POST", "PUT") */
+ const char *resource) /* I - Resource path */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * Set the encryption preference...
- */
- if (!strcasecmp(encryption, "never"))
- cg->encryption = HTTP_ENCRYPT_NEVER;
- else if (!strcasecmp(encryption, "always"))
- cg->encryption = HTTP_ENCRYPT_ALWAYS;
- else if (!strcasecmp(encryption, "required"))
- cg->encryption = HTTP_ENCRYPT_REQUIRED;
- else
- cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
- }
+ if (!http)
+ http = _cupsConnect();
- return (cg->encryption);
+ return ((cg->password_cb)(prompt, http, method, resource, cg->password_data));
}
/*
- * 'cupsGetPassword()' - Get a password from the user.
+ * 'cupsServer()' - Return the hostname/address of the current server.
+ *
+ * The default server comes from the CUPS_SERVER environment variable, then the
+ * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+ * set, the default is the local system - either "localhost" or a domain socket
+ * path.
+ *
+ * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+ * address, or a domain socket pathname.
*
- * Returns NULL if the user does not provide a password.
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server via the
+ * @link cupsSetServer@ function need to do so in each thread for the same
+ * server to be used.
*/
-const char * /* O - Password */
-cupsGetPassword(const char *prompt) /* I - Prompt string */
+const char * /* O - Server name */
+cupsServer(void)
{
- return ((*_cupsGlobals()->password_cb)(prompt));
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ if (!cg->server[0])
+ _cupsSetDefaults();
+
+ return (cg->server);
}
/*
- * 'cupsSetEncryption()' - Set the encryption preference.
+ * 'cupsSetClientCertCB()' - Set the client certificate callback.
+ *
+ * Pass @code NULL@ to restore the default callback.
+ *
+ * Note: The current certificate callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.5/macOS 10.7@
*/
void
-cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+cupsSetClientCertCB(
+ cups_client_cert_cb_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
{
- _cupsGlobals()->encryption = e;
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ cg->client_cert_cb = cb;
+ cg->client_cert_data = user_data;
}
/*
- * 'cupsServer()' - Return the hostname/address of the default server.
+ * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
+ * connections.
*
- * The returned value can be a fully-qualified hostname, a numeric
- * IPv4 or IPv6 address, or a domain socket pathname.
+ * Note: The default credentials are tracked separately for each thread in a
+ * program. Multi-threaded programs that override the setting need to do so in
+ * each thread for the same setting to be used.
+ *
+ * @since CUPS 1.5/macOS 10.7@
*/
-const char * /* O - Server name */
-cupsServer(void)
+int /* O - Status of call (0 = success) */
+cupsSetCredentials(
+ cups_array_t *credentials) /* I - Array of credentials */
{
- cups_file_t *fp; /* client.conf file */
- char *server; /* Pointer to server name */
- const char *home; /* Home directory of user */
- char *port; /* Port number */
- char line[1024], /* Line from file */
- *value; /* Value on line */
- int linenum; /* Line number in file */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- /*
- * First see if we have already set the server name...
- */
+ if (cupsArrayCount(credentials) < 1)
+ return (-1);
- if (!cg->server[0])
- {
- /*
- * Then see if the CUPS_SERVER environment variable is set...
- */
+#ifdef HAVE_SSL
+ _httpFreeCredentials(cg->tls_credentials);
+ cg->tls_credentials = _httpCreateCredentials(credentials);
+#endif /* HAVE_SSL */
- if ((server = getenv("CUPS_SERVER")) == NULL)
- {
- /*
- * Next check to see if we have a $HOME/.cupsrc or client.conf file...
- */
+ return (cg->tls_credentials ? 0 : -1);
+}
- if ((home = getenv("HOME")) != NULL)
- {
- snprintf(line, sizeof(line), "%s/.cupsrc", home);
- fp = cupsFileOpen(line, "r");
- }
- else
- fp = NULL;
- if (fp == NULL)
- {
- snprintf(line, sizeof(line), "%s/client.conf", cg->cups_serverroot);
- fp = cupsFileOpen(line, "r");
- }
+/*
+ * 'cupsSetEncryption()' - Set the encryption preference.
+ *
+ * The default encryption setting comes from the CUPS_ENCRYPTION
+ * environment variable, then the ~/.cups/client.conf file, and finally the
+ * /etc/cups/client.conf file. If not set, the default is
+ * @code HTTP_ENCRYPTION_IF_REQUESTED@.
+ *
+ * Note: The current encryption setting is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the setting need to do
+ * so in each thread for the same setting to be used.
+ */
-#ifdef CUPS_DEFAULT_DOMAINSOCKET
- if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0))
- server = CUPS_DEFAULT_DOMAINSOCKET;
- else
-#endif /* CUPS_DEFAULT_DOMAINSOCKET */
- server = "localhost";
+void
+cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- if (fp != NULL)
- {
- /*
- * Read the config file and look for a ServerName line...
- */
-
- linenum = 0;
- while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL)
- if (!strcasecmp(line, "ServerName") && value)
- {
- /*
- * Got it!
- */
-
- server = value;
- break;
- }
-
- cupsFileClose(fp);
- }
- }
- /*
- * Copy the server name over and set the port number, if any...
- */
+ cg->encryption = e;
- strlcpy(cg->server, server, sizeof(cg->server));
+ if (cg->http)
+ httpEncryption(cg->http, e);
+}
- if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
- !strchr(port, ']') && isdigit(port[1] & 255))
- {
- *port++ = '\0';
- ippSetPort(atoi(port));
- }
+/*
+ * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ *
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @exclude all@
+ */
- if (cg->server[0] == '/')
- strcpy(cg->servername, "localhost");
- else
- strlcpy(cg->servername, cg->server, sizeof(cg->servername));
- }
+void
+cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- return (cg->server);
+
+ if (cb == (cups_password_cb_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
+ else
+ cg->password_cb = (cups_password_cb2_t)cb;
+
+ cg->password_data = NULL;
}
/*
- * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+ * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
+ *
+ * Pass @code NULL@ to restore the default (console) password callback, which
+ * reads the password from the console. Programs should call either this
+ * function or @link cupsSetPasswordCB2@, as only one callback can be registered
+ * by a program per thread.
+ *
+ * Note: The current password callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
*
- * Pass NULL to restore the default (console) password callback.
+ * @since CUPS 1.4/macOS 10.6@
*/
void
-cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+cupsSetPasswordCB2(
+ cups_password_cb2_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
{
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
- if (cb == (const char *(*)(const char *))0)
- cg->password_cb = _cupsGetPassword;
+ if (cb == (cups_password_cb2_t)0)
+ cg->password_cb = (cups_password_cb2_t)_cupsGetPassword;
else
cg->password_cb = cb;
+
+ cg->password_data = user_data;
}
/*
- * 'cupsSetServer()' - Set the default server name.
+ * 'cupsSetServer()' - Set the default server name and port.
*
* The "server" string can be a fully-qualified hostname, a numeric
- * IPv4 or IPv6 address, or a domain socket pathname. Pass NULL to
- * restore the default server name.
+ * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
+ * addresses can be optionally followed by a colon and port number to override
+ * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
+ * default server name and port.
+ *
+ * Note: The current server is tracked separately for each thread in a program.
+ * Multi-threaded programs that override the server need to do so in each
+ * thread for the same server to be used.
*/
void
cupsSetServer(const char *server) /* I - Server name */
{
- char *port; /* Pointer to port */
+ char *options, /* Options */
+ *port; /* Pointer to port */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
{
strlcpy(cg->server, server, sizeof(cg->server));
+ if (cg->server[0] != '/' && (options = strrchr(cg->server, '/')) != NULL)
+ {
+ *options++ = '\0';
+
+ if (!strcmp(options, "version=1.0"))
+ cg->server_version = 10;
+ else if (!strcmp(options, "version=1.1"))
+ cg->server_version = 11;
+ else if (!strcmp(options, "version=2.0"))
+ cg->server_version = 20;
+ else if (!strcmp(options, "version=2.1"))
+ cg->server_version = 21;
+ else if (!strcmp(options, "version=2.2"))
+ cg->server_version = 22;
+ }
+ else
+ cg->server_version = 20;
+
if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL &&
!strchr(port, ']') && isdigit(port[1] & 255))
{
*port++ = '\0';
- ippSetPort(atoi(port));
+ cg->ipp_port = atoi(port);
}
+ if (!cg->ipp_port)
+ cups_set_default_ipp_port(cg);
+
if (cg->server[0] == '/')
- strcpy(cg->servername, "localhost");
+ strlcpy(cg->servername, "localhost", sizeof(cg->servername));
else
strlcpy(cg->servername, cg->server, sizeof(cg->servername));
}
else
{
- cg->server[0] = '\0';
- cg->servername[0] = '\0';
+ cg->server[0] = '\0';
+ cg->servername[0] = '\0';
+ cg->server_version = 20;
+ cg->ipp_port = 0;
}
+
+ if (cg->http)
+ {
+ httpClose(cg->http);
+ cg->http = NULL;
+ }
+}
+
+
+/*
+ * 'cupsSetServerCertCB()' - Set the server certificate callback.
+ *
+ * Pass @code NULL@ to restore the default callback.
+ *
+ * Note: The current credentials callback is tracked separately for each thread
+ * in a program. Multi-threaded programs that override the callback need to do
+ * so in each thread for the same callback to be used.
+ *
+ * @since CUPS 1.5/macOS 10.7@
+ */
+
+void
+cupsSetServerCertCB(
+ cups_server_cert_cb_t cb, /* I - Callback function */
+ void *user_data) /* I - User data pointer */
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ cg->server_cert_cb = cb;
+ cg->server_cert_data = user_data;
}
/*
* 'cupsSetUser()' - Set the default user name.
*
- * Pass NULL to restore the default user name.
+ * Pass @code NULL@ to restore the default user name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name need to do so
+ * in each thread for the same user name to be used.
*/
void
}
-#if defined(WIN32)
-/*
- * WIN32 username and password stuff.
- */
-
/*
- * 'cupsUser()' - Return the current user's name.
+ * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
+ *
+ * Setting the string to NULL forces the default value containing the CUPS
+ * version, IPP version, and operating system version and architecture.
+ *
+ * @since CUPS 1.7/macOS 10.9@
*/
-const char * /* O - User name */
-cupsUser(void)
+void
+cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
{
- _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Thread globals */
+#ifdef WIN32
+ SYSTEM_INFO sysinfo; /* System information */
+ OSVERSIONINFO version; /* OS version info */
+#else
+ struct utsname name; /* uname info */
+#endif /* WIN32 */
- if (!cg->user[0])
+ if (user_agent)
{
- DWORD size; /* Size of string */
-
-
- size = sizeof(cg->user);
- if (!GetUserName(cg->user, &size))
- {
- /*
- * Use the default username...
- */
-
- strcpy(cg->user, "unknown");
- }
+ strlcpy(cg->user_agent, user_agent, sizeof(cg->user_agent));
+ return;
}
- return (cg->user);
-}
-
+#ifdef WIN32
+ version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&version);
+ GetNativeSystemInfo(&sysinfo);
+
+ snprintf(cg->user_agent, sizeof(cg->user_agent),
+ CUPS_MINIMAL " (Windows %d.%d; %s) IPP/2.0",
+ version.dwMajorVersion, version.dwMinorVersion,
+ sysinfo.wProcessorArchitecture
+ == PROCESSOR_ARCHITECTURE_AMD64 ? "amd64" :
+ sysinfo.wProcessorArchitecture
+ == PROCESSOR_ARCHITECTURE_ARM ? "arm" :
+ sysinfo.wProcessorArchitecture
+ == PROCESSOR_ARCHITECTURE_IA64 ? "ia64" :
+ sysinfo.wProcessorArchitecture
+ == PROCESSOR_ARCHITECTURE_INTEL ? "intel" :
+ "unknown");
-/*
- * '_cupsGetPassword()' - Get a password from the user.
- */
+#else
+ uname(&name);
-const char * /* O - Password */
-_cupsGetPassword(const char *prompt) /* I - Prompt string */
-{
- return (NULL);
+ snprintf(cg->user_agent, sizeof(cg->user_agent),
+ CUPS_MINIMAL " (%s %s; %s) IPP/2.0",
+ name.sysname, name.release, name.machine);
+#endif /* WIN32 */
}
-#else
-/*
- * UNIX username and password stuff...
- */
-# include <pwd.h>
/*
* 'cupsUser()' - Return the current user's name.
+ *
+ * Note: The current user name is tracked separately for each thread in a
+ * program. Multi-threaded programs that override the user name with the
+ * @link cupsSetUser@ function need to do so in each thread for the same user
+ * name to be used.
*/
const char * /* O - User name */
cupsUser(void)
{
- struct passwd *pwd; /* User/password entry */
_cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
if (!cg->user[0])
- {
- /*
- * Rewind the password file...
- */
-
- setpwent();
+ _cupsSetDefaults();
- /*
- * Lookup the password entry for the current user.
- */
+ return (cg->user);
+}
- if ((pwd = getpwuid(getuid())) == NULL)
- strcpy(cg->user, "unknown"); /* Unknown user! */
- else
- {
- /*
- * Copy the username...
- */
- setpwent();
+/*
+ * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
+ *
+ * @since CUPS 1.7/macOS 10.9@
+ */
- strlcpy(cg->user, pwd->pw_name, sizeof(cg->user));
- }
+const char * /* O - User-Agent string */
+cupsUserAgent(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
- /*
- * Rewind the password file again...
- */
- setpwent();
- }
+ if (!cg->user_agent[0])
+ cupsSetUserAgent(NULL);
- return (cg->user);
+ return (cg->user_agent);
}
* '_cupsGetPassword()' - Get a password from the user.
*/
-const char * /* O - Password */
+const char * /* O - Password or @code NULL@ if none */
_cupsGetPassword(const char *prompt) /* I - Prompt string */
{
- return (getpass(prompt));
-}
-#endif /* WIN32 */
+#ifdef WIN32
+ HANDLE tty; /* Console handle */
+ DWORD mode; /* Console mode */
+ char passch, /* Current key press */
+ *passptr, /* Pointer into password string */
+ *passend; /* End of password string */
+ DWORD passbytes; /* Bytes read */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Thread globals */
-/*
- * End of "$Id: usersys.c 4918 2006-01-12 05:14:40Z mike $".
- */
+ /*
+ * Disable input echo and set raw input...
+ */
+
+ if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
+ return (NULL);
+
+ if (!GetConsoleMode(tty, &mode))
+ return (NULL);
+
+ if (!SetConsoleMode(tty, 0))
+ return (NULL);
+
+ /*
+ * Display the prompt...
+ */
+
+ printf("%s ", prompt);
+ fflush(stdout);
+
+ /*
+ * Read the password string from /dev/tty until we get interrupted or get a
+ * carriage return or newline...
+ */
+
+ passptr = cg->password;
+ passend = cg->password + sizeof(cg->password) - 1;
+
+ while (ReadFile(tty, &passch, 1, &passbytes, NULL))
+ {
+ if (passch == 0x0A || passch == 0x0D)
+ {
+ /*
+ * Enter/return...
+ */
+
+ break;
+ }
+ else if (passch == 0x08 || passch == 0x7F)
+ {
+ /*
+ * Backspace/delete (erase character)...
+ */
+
+ if (passptr > cg->password)
+ {
+ passptr --;
+ fputs("\010 \010", stdout);
+ }
+ else
+ putchar(0x07);
+ }
+ else if (passch == 0x15)
+ {
+ /*
+ * CTRL+U (erase line)
+ */
+
+ if (passptr > cg->password)
+ {
+ while (passptr > cg->password)
+ {
+ passptr --;
+ fputs("\010 \010", stdout);
+ }
+ }
+ else
+ putchar(0x07);
+ }
+ else if (passch == 0x03)
+ {
+ /*
+ * CTRL+C...
+ */
+
+ passptr = cg->password;
+ break;
+ }
+ else if ((passch & 255) < 0x20 || passptr >= passend)
+ putchar(0x07);
+ else
+ {
+ *passptr++ = passch;
+ putchar(_CUPS_PASSCHAR);
+ }
+
+ fflush(stdout);
+ }
+
+ putchar('\n');
+ fflush(stdout);
+
+ /*
+ * Cleanup...
+ */
+
+ SetConsoleMode(tty, mode);
+
+ /*
+ * Return the proper value...
+ */
+
+ if (passbytes == 1 && passptr > cg->password)
+ {
+ *passptr = '\0';
+ return (cg->password);
+ }
+ else
+ {
+ memset(cg->password, 0, sizeof(cg->password));
+ return (NULL);
+ }
+
+#else
+ int tty; /* /dev/tty - never read from stdin */
+ struct termios original, /* Original input mode */
+ noecho; /* No echo input mode */
+ char passch, /* Current key press */
+ *passptr, /* Pointer into password string */
+ *passend; /* End of password string */
+ ssize_t passbytes; /* Bytes read */
+ _cups_globals_t *cg = _cupsGlobals();
+ /* Thread globals */
+
+
+ /*
+ * Disable input echo and set raw input...
+ */
+
+ if ((tty = open("/dev/tty", O_RDONLY)) < 0)
+ return (NULL);
+
+ if (tcgetattr(tty, &original))
+ {
+ close(tty);
+ return (NULL);
+ }
+
+ noecho = original;
+ noecho.c_lflag &= (tcflag_t)~(ICANON | ECHO | ECHOE | ISIG);
+ noecho.c_cc[VMIN] = 1;
+ noecho.c_cc[VTIME] = 0;
+
+ if (tcsetattr(tty, TCSAFLUSH, &noecho))
+ {
+ close(tty);
+ return (NULL);
+ }
+
+ /*
+ * Display the prompt...
+ */
+
+ printf("%s ", prompt);
+ fflush(stdout);
+
+ /*
+ * Read the password string from /dev/tty until we get interrupted or get a
+ * carriage return or newline...
+ */
+
+ passptr = cg->password;
+ passend = cg->password + sizeof(cg->password) - 1;
+
+ while ((passbytes = read(tty, &passch, 1)) == 1)
+ {
+ if (passch == noecho.c_cc[VEOL] ||
+# ifdef VEOL2
+ passch == noecho.c_cc[VEOL2] ||
+# endif /* VEOL2 */
+ passch == 0x0A || passch == 0x0D)
+ {
+ /*
+ * Enter/return...
+ */
+
+ break;
+ }
+ else if (passch == noecho.c_cc[VERASE] ||
+ passch == 0x08 || passch == 0x7F)
+ {
+ /*
+ * Backspace/delete (erase character)...
+ */
+
+ if (passptr > cg->password)
+ {
+ passptr --;
+ fputs("\010 \010", stdout);
+ }
+ else
+ putchar(0x07);
+ }
+ else if (passch == noecho.c_cc[VKILL])
+ {
+ /*
+ * CTRL+U (erase line)
+ */
+
+ if (passptr > cg->password)
+ {
+ while (passptr > cg->password)
+ {
+ passptr --;
+ fputs("\010 \010", stdout);
+ }
+ }
+ else
+ putchar(0x07);
+ }
+ else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
+ passch == noecho.c_cc[VEOF])
+ {
+ /*
+ * CTRL+C, CTRL+D, or CTRL+Z...
+ */
+
+ passptr = cg->password;
+ break;
+ }
+ else if ((passch & 255) < 0x20 || passptr >= passend)
+ putchar(0x07);
+ else
+ {
+ *passptr++ = passch;
+ putchar(_CUPS_PASSCHAR);
+ }
+
+ fflush(stdout);
+ }
+
+ putchar('\n');
+ fflush(stdout);
+
+ /*
+ * Cleanup...
+ */
+
+ tcsetattr(tty, TCSAFLUSH, &original);
+ close(tty);
+
+ /*
+ * Return the proper value...
+ */
+
+ if (passbytes == 1 && passptr > cg->password)
+ {
+ *passptr = '\0';
+ return (cg->password);
+ }
+ else
+ {
+ memset(cg->password, 0, sizeof(cg->password));
+ return (NULL);
+ }
+#endif /* WIN32 */
+}
+
+
+#ifdef HAVE_GSSAPI
+/*
+ * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
+ */
+
+const char *
+_cupsGSSServiceName(void)
+{
+ _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */
+
+
+ if (!cg->gss_service_name[0])
+ _cupsSetDefaults();
+
+ return (cg->gss_service_name);
+}
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * '_cupsSetDefaults()' - Set the default server, port, and encryption.
+ */
+
+void
+_cupsSetDefaults(void)
+{
+ cups_file_t *fp; /* File */
+ const char *home; /* Home directory of user */
+ char filename[1024]; /* Filename */
+ _cups_client_conf_t cc; /* client.conf values */
+ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
+
+
+ DEBUG_puts("_cupsSetDefaults()");
+
+ /*
+ * Load initial client.conf values...
+ */
+
+ cups_init_client_conf(&cc);
+
+ /*
+ * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
+ * present.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ cups_read_client_conf(fp, &cc);
+ cupsFileClose(fp);
+ }
+
+# ifdef HAVE_GETEUID
+ if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL)
+# elif !defined(WIN32)
+ if (getuid() && (home = getenv("HOME")) != NULL)
+# else
+ if ((home = getenv("HOME")) != NULL)
+# endif /* HAVE_GETEUID */
+ {
+ /*
+ * Look for ~/.cups/client.conf...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
+ if ((fp = cupsFileOpen(filename, "r")) != NULL)
+ {
+ cups_read_client_conf(fp, &cc);
+ cupsFileClose(fp);
+ }
+ }
+
+ /*
+ * Finalize things so every client.conf value is set...
+ */
+
+ cups_finalize_client_conf(&cc);
+
+ if (cg->encryption == (http_encryption_t)-1)
+ cg->encryption = cc.encryption;
+
+ if (!cg->server[0] || !cg->ipp_port)
+ cupsSetServer(cc.server_name);
+
+ if (!cg->ipp_port)
+ cups_set_default_ipp_port(cg);
+
+ if (!cg->user[0])
+ strlcpy(cg->user, cc.user, sizeof(cg->user));
+
+#ifdef HAVE_GSSAPI
+ if (!cg->gss_service_name[0])
+ strlcpy(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name));
+#endif /* HAVE_GSSAPI */
+
+ if (cg->trust_first < 0)
+ cg->trust_first = cc.trust_first;
+
+ if (cg->any_root < 0)
+ cg->any_root = cc.any_root;
+
+ if (cg->expired_certs < 0)
+ cg->expired_certs = cc.expired_certs;
+
+ if (cg->validate_certs < 0)
+ cg->validate_certs = cc.validate_certs;
+
+#ifdef HAVE_SSL
+ _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
+#endif /* HAVE_SSL */
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
+ */
+
+static int /* O - 1 if set, 0 otherwise */
+cups_apple_get_boolean(
+ CFStringRef key, /* I - Key (name) */
+ int *value) /* O - Boolean value */
+{
+ Boolean bval, /* Preference value */
+ bval_set; /* Value is set? */
+
+
+ bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set);
+
+ if (bval_set)
+ *value = (int)bval;
+
+ return ((int)bval_set);
+}
+
+
+/*
+ * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
+ */
+
+static int /* O - 1 if set, 0 otherwise */
+cups_apple_get_string(
+ CFStringRef key, /* I - Key (name) */
+ char *value, /* O - String value */
+ size_t valsize) /* I - Size of value buffer */
+{
+ CFStringRef sval; /* String value */
+
+
+ if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL)
+ {
+ Boolean result = CFStringGetCString(sval, value, (CFIndex)valsize, kCFStringEncodingUTF8);
+
+ CFRelease(sval);
+
+ if (result)
+ return (1);
+ }
+
+ return (0);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * 'cups_boolean_value()' - Convert a string to a boolean value.
+ */
+
+static int /* O - Boolean value */
+cups_boolean_value(const char *value) /* I - String value */
+{
+ return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"));
+}
+
+
+/*
+ * 'cups_finalize_client_conf()' - Finalize client.conf values.
+ */
+
+static void
+cups_finalize_client_conf(
+ _cups_client_conf_t *cc) /* I - client.conf values */
+{
+ const char *value; /* Environment variable */
+
+
+ if ((value = getenv("CUPS_TRUSTFIRST")) != NULL)
+ cc->trust_first = cups_boolean_value(value);
+
+ if ((value = getenv("CUPS_ANYROOT")) != NULL)
+ cc->any_root = cups_boolean_value(value);
+
+ if ((value = getenv("CUPS_ENCRYPTION")) != NULL)
+ cups_set_encryption(cc, value);
+
+ if ((value = getenv("CUPS_EXPIREDCERTS")) != NULL)
+ cc->expired_certs = cups_boolean_value(value);
+
+#ifdef HAVE_GSSAPI
+ if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
+ cups_set_gss_service_name(cc, value);
+#endif /* HAVE_GSSAPI */
+
+ if ((value = getenv("CUPS_SERVER")) != NULL)
+ cups_set_server_name(cc, value);
+
+ if ((value = getenv("CUPS_USER")) != NULL)
+ cups_set_user(cc, value);
+
+ if ((value = getenv("CUPS_VALIDATECERTS")) != NULL)
+ cc->validate_certs = cups_boolean_value(value);
+
+ /*
+ * Then apply defaults for those values that haven't been set...
+ */
+
+ if (cc->trust_first < 0)
+ cc->trust_first = 1;
+
+ if (cc->any_root < 0)
+ cc->any_root = 1;
+
+ if (cc->encryption == (http_encryption_t)-1)
+ cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+ if (cc->expired_certs < 0)
+ cc->expired_certs = 0;
+
+#ifdef HAVE_GSSAPI
+ if (!cc->gss_service_name[0])
+ cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME);
+#endif /* HAVE_GSSAPI */
+
+ if (!cc->server_name[0])
+ {
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+ /*
+ * If we are compiled with domain socket support, only use the
+ * domain socket if it exists and has the right permissions...
+ */
+
+ if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK))
+ cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET);
+ else
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+ cups_set_server_name(cc, "localhost");
+ }
+
+ if (!cc->user[0])
+ {
+#ifdef WIN32
+ /*
+ * Get the current user name from the OS...
+ */
+
+ DWORD size; /* Size of string */
+
+ size = sizeof(cc->user);
+ if (!GetUserName(cc->user, &size))
+#else
+ /*
+ * Try the USER environment variable as the default username...
+ */
+
+ const char *envuser = getenv("USER");
+ /* Default username */
+ struct passwd *pw = NULL; /* Account information */
+
+ if (envuser)
+ {
+ /*
+ * Validate USER matches the current UID, otherwise don't allow it to
+ * override things... This makes sure that printing after doing su
+ * or sudo records the correct username.
+ */
+
+ if ((pw = getpwnam(envuser)) != NULL && pw->pw_uid != getuid())
+ pw = NULL;
+ }
+
+ if (!pw)
+ pw = getpwuid(getuid());
+
+ if (pw)
+ strlcpy(cc->user, pw->pw_name, sizeof(cc->user));
+ else
+#endif /* WIN32 */
+ {
+ /*
+ * Use the default "unknown" user name...
+ */
+
+ strlcpy(cc->user, "unknown", sizeof(cc->user));
+ }
+ }
+
+ if (cc->validate_certs < 0)
+ cc->validate_certs = 0;
+}
+
+
+/*
+ * 'cups_init_client_conf()' - Initialize client.conf values.
+ */
+
+static void
+cups_init_client_conf(
+ _cups_client_conf_t *cc) /* I - client.conf values */
+{
+ /*
+ * Clear all values to "not set"...
+ */
+
+ memset(cc, 0, sizeof(_cups_client_conf_t));
+
+ cc->encryption = (http_encryption_t)-1;
+ cc->trust_first = -1;
+ cc->any_root = -1;
+ cc->expired_certs = -1;
+ cc->validate_certs = -1;
+
+ /*
+ * Load settings from the org.cups.PrintingPrefs plist (which trump
+ * everything...)
+ */
+
+#if defined(__APPLE__) && defined(HAVE_SSL)
+ char sval[1024]; /* String value */
+ int bval; /* Boolean value */
+
+ if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
+ cc->any_root = bval;
+
+ if (cups_apple_get_boolean(kAllowExpiredCertsKey, &bval))
+ cc->expired_certs = bval;
+
+ if (cups_apple_get_string(kEncryptionKey, sval, sizeof(sval)))
+ cups_set_encryption(cc, sval);
+
+ if (cups_apple_get_string(kSSLOptionsKey, sval, sizeof(sval)))
+ cups_set_ssl_options(cc, sval);
+
+ if (cups_apple_get_boolean(kTrustOnFirstUseKey, &bval))
+ cc->trust_first = bval;
+
+ if (cups_apple_get_boolean(kValidateCertsKey, &bval))
+ cc->validate_certs = bval;
+#endif /* __APPLE__ && HAVE_SSL */
+}
+
+
+/*
+ * 'cups_read_client_conf()' - Read a client.conf file.
+ */
+
+static void
+cups_read_client_conf(
+ cups_file_t *fp, /* I - File to read */
+ _cups_client_conf_t *cc) /* I - client.conf values */
+{
+ int linenum; /* Current line number */
+ char line[1024], /* Line from file */
+ *value; /* Pointer into line */
+
+
+ /*
+ * Read from the file...
+ */
+
+ linenum = 0;
+ while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
+ {
+ if (!_cups_strcasecmp(line, "Encryption") && value)
+ cups_set_encryption(cc, value);
+#ifndef __APPLE__
+ /*
+ * The ServerName directive is not supported on macOS due to app
+ * sandboxing restrictions, i.e. not all apps request network access.
+ */
+ else if (!_cups_strcasecmp(line, "ServerName") && value)
+ cups_set_server_name(cc, value);
+#endif /* !__APPLE__ */
+ else if (!_cups_strcasecmp(line, "User") && value)
+ cups_set_user(cc, value);
+ else if (!_cups_strcasecmp(line, "TrustOnFirstUse") && value)
+ cc->trust_first = cups_boolean_value(value);
+ else if (!_cups_strcasecmp(line, "AllowAnyRoot") && value)
+ cc->any_root = cups_boolean_value(value);
+ else if (!_cups_strcasecmp(line, "AllowExpiredCerts") &&
+ value)
+ cc->expired_certs = cups_boolean_value(value);
+ else if (!_cups_strcasecmp(line, "ValidateCerts") && value)
+ cc->validate_certs = cups_boolean_value(value);
+#ifdef HAVE_GSSAPI
+ else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
+ cups_set_gss_service_name(cc, value);
+#endif /* HAVE_GSSAPI */
+#ifdef HAVE_SSL
+ else if (!_cups_strcasecmp(line, "SSLOptions") && value)
+ cups_set_ssl_options(cc, value);
+#endif /* HAVE_SSL */
+ }
+}
+
+
+/*
+ * 'cups_set_default_ipp_port()' - Set the default IPP port value.
+ */
+
+static void
+cups_set_default_ipp_port(
+ _cups_globals_t *cg) /* I - Global data */
+{
+ const char *ipp_port; /* IPP_PORT environment variable */
+
+
+ if ((ipp_port = getenv("IPP_PORT")) != NULL)
+ {
+ if ((cg->ipp_port = atoi(ipp_port)) <= 0)
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+ }
+ else
+ cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+}
+
+/*
+ * 'cups_set_encryption()' - Set the Encryption value.
+ */
+
+static void
+cups_set_encryption(
+ _cups_client_conf_t *cc, /* I - client.conf values */
+ const char *value) /* I - Value */
+{
+ if (!_cups_strcasecmp(value, "never"))
+ cc->encryption = HTTP_ENCRYPTION_NEVER;
+ else if (!_cups_strcasecmp(value, "always"))
+ cc->encryption = HTTP_ENCRYPTION_ALWAYS;
+ else if (!_cups_strcasecmp(value, "required"))
+ cc->encryption = HTTP_ENCRYPTION_REQUIRED;
+ else
+ cc->encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+}
+
+
+/*
+ * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
+ */
+
+#ifdef HAVE_GSSAPI
+static void
+cups_set_gss_service_name(
+ _cups_client_conf_t *cc, /* I - client.conf values */
+ const char *value) /* I - Value */
+{
+ strlcpy(cc->gss_service_name, value, sizeof(cc->gss_service_name));
+}
+#endif /* HAVE_GSSAPI */
+
+
+/*
+ * 'cups_set_server_name()' - Set the ServerName value.
+ */
+
+static void
+cups_set_server_name(
+ _cups_client_conf_t *cc, /* I - client.conf values */
+ const char *value) /* I - Value */
+{
+ strlcpy(cc->server_name, value, sizeof(cc->server_name));
+}
+
+
+/*
+ * 'cups_set_ssl_options()' - Set the SSLOptions value.
+ */
+
+#ifdef HAVE_SSL
+static void
+cups_set_ssl_options(
+ _cups_client_conf_t *cc, /* I - client.conf values */
+ const char *value) /* I - Value */
+{
+ /*
+ * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
+ */
+
+ int options = _HTTP_TLS_NONE, /* SSL/TLS options */
+ min_version = _HTTP_TLS_1_0, /* Minimum SSL/TLS version */
+ max_version = _HTTP_TLS_MAX; /* Maximum SSL/TLS version */
+ char temp[256], /* Copy of value */
+ *start, /* Start of option */
+ *end; /* End of option */
+
+
+ strlcpy(temp, value, sizeof(temp));
+
+ for (start = temp; *start; start = end)
+ {
+ /*
+ * Find end of keyword...
+ */
+
+ end = start;
+ while (*end && !_cups_isspace(*end))
+ end ++;
+
+ if (*end)
+ *end++ = '\0';
+
+ /*
+ * Compare...
+ */
+
+ if (!_cups_strcasecmp(start, "AllowRC4"))
+ options |= _HTTP_TLS_ALLOW_RC4;
+ else if (!_cups_strcasecmp(start, "AllowSSL3"))
+ min_version = _HTTP_TLS_SSL3;
+ else if (!_cups_strcasecmp(start, "AllowDH"))
+ options |= _HTTP_TLS_ALLOW_DH;
+ else if (!_cups_strcasecmp(start, "DenyCBC"))
+ options |= _HTTP_TLS_DENY_CBC;
+ else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
+ min_version = _HTTP_TLS_1_1;
+ else if (!_cups_strcasecmp(start, "MaxTLS1.0"))
+ max_version = _HTTP_TLS_1_0;
+ else if (!_cups_strcasecmp(start, "MaxTLS1.1"))
+ max_version = _HTTP_TLS_1_1;
+ else if (!_cups_strcasecmp(start, "MaxTLS1.2"))
+ max_version = _HTTP_TLS_1_2;
+ else if (!_cups_strcasecmp(start, "MaxTLS1.3"))
+ max_version = _HTTP_TLS_1_3;
+ else if (!_cups_strcasecmp(start, "MinTLS1.0"))
+ min_version = _HTTP_TLS_1_0;
+ else if (!_cups_strcasecmp(start, "MinTLS1.1"))
+ min_version = _HTTP_TLS_1_1;
+ else if (!_cups_strcasecmp(start, "MinTLS1.2"))
+ min_version = _HTTP_TLS_1_2;
+ else if (!_cups_strcasecmp(start, "MinTLS1.3"))
+ min_version = _HTTP_TLS_1_3;
+ else if (!_cups_strcasecmp(start, "None"))
+ options = _HTTP_TLS_NONE;
+ }
+
+ cc->ssl_options = options;
+ cc->ssl_max_version = max_version;
+ cc->ssl_min_version = min_version;
+
+ DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version));
+}
+#endif /* HAVE_SSL */
+
+
+/*
+ * 'cups_set_user()' - Set the User value.
+ */
+
+static void
+cups_set_user(
+ _cups_client_conf_t *cc, /* I - client.conf values */
+ const char *value) /* I - Value */
+{
+ strlcpy(cc->user, value, sizeof(cc->user));
+}