summaryrefslogtreecommitdiff
path: root/cups
diff options
context:
space:
mode:
Diffstat (limited to 'cups')
-rw-r--r--cups/Makefile10
-rw-r--r--cups/globals.c8
-rw-r--r--cups/http-private.h3
-rw-r--r--cups/http.c88
-rw-r--r--cups/language-private.h2
-rw-r--r--cups/language.c18
-rwxr-xr-xcups/libcups.order1
-rw-r--r--cups/libcups2.def6
-rw-r--r--cups/libcups_s.exp7
-rw-r--r--cups/mark.c18
-rw-r--r--cups/ppd-private.h4
-rw-r--r--cups/pwg-file.c72
-rw-r--r--cups/pwg-ppd.c135
-rw-r--r--cups/pwg-private.h2
-rw-r--r--cups/sspi-private.h82
-rw-r--r--cups/sspi.c1472
-rw-r--r--cups/testi18n.c66
-rw-r--r--cups/testppd.c14
-rw-r--r--cups/transcode.c313
19 files changed, 1997 insertions, 324 deletions
diff --git a/cups/Makefile b/cups/Makefile
index cd557d57a..e3f6ec241 100644
--- a/cups/Makefile
+++ b/cups/Makefile
@@ -87,8 +87,7 @@ OBJS = \
testlang.o \
testppd.o \
testpwg.o \
- testsnmp.o \
- php_cups_wrap.o
+ testsnmp.o
#
@@ -355,15 +354,14 @@ libcups.so.2 libcups.sl.2: $(LIBOBJS)
libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER)
echo Creating export list for $@...
nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}' | \
- grep -v -e '^(_cupsConnect|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault|_httpWait)$$' | \
+ grep -v -e '^(_cupsConnect|_cupsCharset|_cupsEncodingName|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault|_httpWait)$$' | \
sort >t.exp
echo Linking $@...
$(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \
-install_name $(libdir)/$@ \
- -current_version 2.8.0 \
+ -current_version 2.9.0 \
-compatibility_version 2.0.0 \
-exported_symbols_list t.exp \
- -sectorder __TEXT __text $(LIBCUPSORDER) \
$(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \
$(COMMONLIBS) $(LIBZ)
$(RM) libcups.dylib t.exp
@@ -390,7 +388,7 @@ libcups_s.a: $(LIBOBJS) libcups_s.exp
libcups.la: $(LIBOBJS)
echo Linking $@...
$(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \
- -rpath $(LIBDIR) -version-info 2:8 $(LIBGSSAPI) $(SSLLIBS) \
+ -rpath $(LIBDIR) -version-info 2:9 $(LIBGSSAPI) $(SSLLIBS) \
$(DNSSDLIBS) $(COMMONLIBS) $(LIBZ)
diff --git a/cups/globals.c b/cups/globals.c
index 00a73691c..04afcab2c 100644
--- a/cups/globals.c
+++ b/cups/globals.c
@@ -68,7 +68,7 @@ _cupsGlobalLock(void)
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock(&cups_global_mutex);
#elif defined(WIN32)
- EnterCriticalSection(&cups_global_mutex->m_criticalSection);
+ EnterCriticalSection(&cups_global_mutex.m_criticalSection);
#endif /* HAVE_PTHREAD_H */
}
@@ -123,7 +123,7 @@ _cupsGlobalUnlock(void)
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock(&cups_global_mutex);
#elif defined(WIN32)
- LeaveCriticalSection(&cups_global_mutex->m_criticalSection);
+ LeaveCriticalSection(&cups_global_mutex.m_criticalSection);
#endif /* HAVE_PTHREAD_H */
}
@@ -147,7 +147,7 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */
switch (reason)
{
case DLL_PROCESS_ATTACH : /* Called on library initialization */
- InitializeCriticalSection(&cups_global_lock);
+ InitializeCriticalSection(&cups_global_mutex.m_criticalSection);
if ((cups_globals_key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return (FALSE);
@@ -163,7 +163,7 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */
cups_globals_free(cg);
TlsFree(cups_globals_key);
- DeleteCriticalSection(&cups_global_lock);
+ DeleteCriticalSection(&cups_global_mutex.m_criticalSection);
break;
default:
diff --git a/cups/http-private.h b/cups/http-private.h
index 50f094cba..78ebdf930 100644
--- a/cups/http-private.h
+++ b/cups/http-private.h
@@ -130,6 +130,9 @@ extern OSStatus _httpReadCDSA(SSLConnectionRef connection, void *data,
size_t *dataLength);
extern OSStatus _httpWriteCDSA(SSLConnectionRef connection, const void *data,
size_t *dataLength);
+
+# elif defined(HAVE_SSPISSL)
+# include "sspi-private.h"
# endif /* HAVE_LIBSSL */
diff --git a/cups/http.c b/cups/http.c
index 666c6458c..a83fc20cc 100644
--- a/cups/http.c
+++ b/cups/http.c
@@ -103,11 +103,13 @@
#include "cups-private.h"
#include <fcntl.h>
-#ifndef WIN32
+#ifdef WIN32
+# include <tchar.h>
+#else
# include <signal.h>
# include <sys/time.h>
# include <sys/resource.h>
-#endif /* !WIN32 */
+#endif /* WIN32 */
#ifdef HAVE_POLL
# include <sys/poll.h>
#endif /* HAVE_POLL */
@@ -1116,13 +1118,16 @@ httpGets(char *line, /* I - Line to read into */
*/
#ifdef WIN32
- if (WSAGetLastError() != http->error)
+ DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
+
+ if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+ continue;
+ else if (WSAGetLastError() != http->error)
{
http->error = WSAGetLastError();
continue;
}
- DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
#else
DEBUG_printf(("3httpGets: recv() error %d!", errno));
@@ -1437,8 +1442,11 @@ _httpPeek(http_t *http, /* I - Connection to server */
else if (bytes < 0)
{
#ifdef WIN32
- http->error = WSAGetLastError();
- return (-1);
+ if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ http->error = WSAGetLastError();
+ return (-1);
+ }
#else
if (errno != EINTR && errno != EAGAIN)
{
@@ -1472,7 +1480,10 @@ _httpPeek(http_t *http, /* I - Connection to server */
if (bytes < 0)
{
#ifdef WIN32
- http->error = WSAGetLastError();
+ if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+ bytes = 0;
+ else
+ http->error = WSAGetLastError();
#else
if (errno == EINTR || errno == EAGAIN)
bytes = 0;
@@ -1687,8 +1698,11 @@ httpRead2(http_t *http, /* I - Connection to server */
else if (bytes < 0)
{
#ifdef WIN32
- http->error = WSAGetLastError();
- return (-1);
+ if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ http->error = WSAGetLastError();
+ return (-1);
+ }
#else
if (errno != EINTR && errno != EAGAIN)
{
@@ -1738,7 +1752,9 @@ httpRead2(http_t *http, /* I - Connection to server */
CUPS_LLCAST length));
#ifdef WIN32
- bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0);
+ while ((bytes = (ssize_t) recv(http->fd, buffer, (int)length, 0)) < 0)
+ if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+ break;
#else
while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
if (errno != EINTR && errno != EAGAIN)
@@ -1761,7 +1777,10 @@ httpRead2(http_t *http, /* I - Connection to server */
else if (bytes < 0)
{
#ifdef WIN32
- http->error = WSAGetLastError();
+ if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+ bytes = 0;
+ else
+ http->error = WSAGetLastError();
#else
if (errno == EINTR || errno == EAGAIN)
bytes = 0;
@@ -2489,7 +2508,8 @@ _httpWait(http_t *http, /* I - Connection to server */
DEBUG_printf(("6_httpWait: select() returned %d...", nfds));
}
# ifdef WIN32
- while (nfds < 0 && WSAGetLastError() == WSAEINTR);
+ while (nfds < 0 && (WSAGetLastError() == WSAEINTR ||
+ WSAGetLastError() == WSAEWOULDBLOCK));
# else
while (nfds < 0 && (errno == EINTR || errno == EAGAIN));
# endif /* WIN32 */
@@ -3047,6 +3067,8 @@ http_read_ssl(http_t *http, /* I - Connection to server */
}
return (result);
+# elif defined(HAVE_SSPISSL)
+ return _sspiRead((_sspi_struct_t*) http->tls, buf, len);
# endif /* HAVE_LIBSSL */
}
#endif /* HAVE_SSL */
@@ -3244,6 +3266,11 @@ http_setup_ssl(http_t *http) /* I - Connection to server */
# elif defined(HAVE_CDSASSL)
OSStatus error; /* Error code */
http_tls_t *conn; /* CDSA connection information */
+# elif defined(HAVE_SSPISSL)
+ TCHAR username[256]; /* Username returned from GetUserName() */
+ TCHAR commonName[256]; /* Common name for certificate */
+ DWORD dwSize; /* 32 bit size */
+ _sspi_struct_t *conn; /* SSPI connection information */
# endif /* HAVE_LIBSSL */
@@ -3377,6 +3404,32 @@ http_setup_ssl(http_t *http) /* I - Connection to server */
return (-1);
}
+# elif defined(HAVE_SSPISSL)
+ conn = _sspiAlloc();
+
+ if (!conn)
+ return (-1);
+
+ conn->sock = http->fd;
+ dwSize = sizeof(username) / sizeof(TCHAR);
+ GetUserName(username, &dwSize);
+ _sntprintf_s(commonName, sizeof(commonName) / sizeof(TCHAR),
+ sizeof(commonName) / sizeof(TCHAR), TEXT("CN=%s"), username);
+
+ if (!_sspiGetCredentials(conn, L"ClientContainer", commonName, FALSE))
+ {
+ _sspiFree(conn);
+ return (-1);
+ }
+
+ _sspiSetAllowsAnyRoot(conn, TRUE);
+ _sspiSetAllowsExpiredCerts(conn, TRUE);
+
+ if (!_sspiConnect(conn, http->hostname))
+ {
+ _sspiFree(conn);
+ return (-1);
+ }
# endif /* HAVE_CDSASSL */
http->tls = conn;
@@ -3435,6 +3488,11 @@ http_shutdown_ssl(http_t *http) /* I - Connection to server */
CFRelease(conn->certsArray);
free(conn);
+# elif defined(HAVE_SSPISSL)
+ _sspi_struct_t *conn; /* SSPI connection information */
+
+ conn = (_sspi_struct_t*)(http->tls);
+ _sspiFree(conn);
# endif /* HAVE_LIBSSL */
http->tls = NULL;
@@ -3577,7 +3635,9 @@ http_write(http_t *http, /* I - Connection to server */
if (bytes < 0)
{
#ifdef WIN32
- if (WSAGetLastError() != http->error)
+ if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+ continue;
+ else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET)
{
http->error = WSAGetLastError();
continue;
@@ -3730,6 +3790,8 @@ http_write_ssl(http_t *http, /* I - Connection to server */
result = -1;
break;
}
+# elif defined(HAVE_SSPISSL)
+ return _sspiWrite((_sspi_struct_t*) http->tls, (void*) buf, len);
# endif /* HAVE_LIBSSL */
DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result));
diff --git a/cups/language-private.h b/cups/language-private.h
index 1defb8c22..934032eee 100644
--- a/cups/language-private.h
+++ b/cups/language-private.h
@@ -87,8 +87,6 @@ extern const char *_cupsAppleLanguage(const char *locale, char *language,
size_t langsize);
# endif /* __APPLE__ */
extern void _cupsCharmapFlush(void);
-extern void _cupsCharmapFree(const cups_encoding_t encoding);
-extern void *_cupsCharmapGet(const cups_encoding_t encoding);
extern const char *_cupsEncodingName(cups_encoding_t encoding);
extern void _cupsLangPrintError(const char *message);
extern int _cupsLangPrintf(FILE *fp, const char *message, ...)
diff --git a/cups/language.c b/cups/language.c
index 00b2de3ad..8ce4bc7d1 100644
--- a/cups/language.c
+++ b/cups/language.c
@@ -71,12 +71,12 @@ static const char * const lang_encodings[] =
"iso-8859-8", "iso-8859-9",
"iso-8859-10", "utf-8",
"iso-8859-13", "iso-8859-14",
- "iso-8859-15", "windows-874",
- "windows-1250", "windows-1251",
- "windows-1252", "windows-1253",
- "windows-1254", "windows-1255",
- "windows-1256", "windows-1257",
- "windows-1258", "koi8-r",
+ "iso-8859-15", "cp874",
+ "cp1250", "cp1251",
+ "cp1252", "cp1253",
+ "cp1254", "cp1255",
+ "cp1256", "cp1257",
+ "cp1258", "koi8-r",
"koi8-u", "iso-8859-11",
"iso-8859-16", "mac-roman",
"unknown", "unknown",
@@ -96,9 +96,9 @@ static const char * const lang_encodings[] =
"unknown", "unknown",
"unknown", "unknown",
"unknown", "unknown",
- "windows-932", "windows-936",
- "windows-949", "windows-950",
- "windows-1361", "unknown",
+ "cp932", "cp936",
+ "cp949", "cp950",
+ "cp1361", "unknown",
"unknown", "unknown",
"unknown", "unknown",
"unknown", "unknown",
diff --git a/cups/libcups.order b/cups/libcups.order
index 92820f7c2..e69de29bb 100755
--- a/cups/libcups.order
+++ b/cups/libcups.order
@@ -1 +0,0 @@
-single module:dyld_stub_binding_helper
diff --git a/cups/libcups2.def b/cups/libcups2.def
index 825d12e68..722a8ad95 100644
--- a/cups/libcups2.def
+++ b/cups/libcups2.def
@@ -1,10 +1,6 @@
LIBRARY libcups2
VERSION 2.8
EXPORTS
-_cupsCharmapFlush
-_cupsCharmapFree
-_cupsCharmapGet
-_cupsEncodingName
_cupsGetPassword
_cupsGlobals
_cupsLangPrintf
@@ -46,8 +42,10 @@ _pwgMediaForPPD
_pwgMediaForPWG
_pwgMediaForSize
_pwgCreateWithPPD
+_pwgGetBin
_pwgGetInputSlot
_pwgGetMediaType
+_pwgGetOutputBin
_pwgGetPageSize
_pwgGetSize
_pwgGetSource
diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp
index 35037ea5b..db57eea66 100644
--- a/cups/libcups_s.exp
+++ b/cups/libcups_s.exp
@@ -1,11 +1,8 @@
_cups_debug_fd
-_cupsCharmapFlush
-_cupsCharmapFree
-_cupsCharmapGet
-_cupsEncodingName
_cupsGet1284Values
_cupsGetPassword
_cupsGlobals
+_cupsLangPrintError
_cupsLangPrintf
_cupsLangPuts
_cupsLangString
@@ -67,8 +64,10 @@ _pwgMediaForPPD
_pwgMediaForPWG
_pwgMediaForSize
_pwgCreateWithPPD
+_pwgGetBin
_pwgGetInputSlot
_pwgGetMediaType
+_pwgGetOutputBin
_pwgGetPageSize
_pwgGetSize
_pwgGetSource
diff --git a/cups/mark.c b/cups/mark.c
index 9ef999b7f..e75544b72 100644
--- a/cups/mark.c
+++ b/cups/mark.c
@@ -161,10 +161,14 @@ cupsMarkOptions(
* Mark it...
*/
- if ((!page_size || !page_size[0]) &&
- (ppd_keyword = _pwgGetPageSize((_pwg_t *)ppd->pwg, NULL, s,
- NULL)) != NULL)
- ppd_mark_option(ppd, "PageSize", ppd_keyword);
+ if (!page_size || !page_size[0])
+ {
+ if (!strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s))
+ ppd_mark_option(ppd, "PageSize", s);
+ else if ((ppd_keyword = _pwgGetPageSize((_pwg_t *)ppd->pwg, NULL, s,
+ NULL)) != NULL)
+ ppd_mark_option(ppd, "PageSize", ppd_keyword);
+ }
if (!cupsGetOption("InputSlot", num_options, options) &&
(ppd_keyword = _pwgGetInputSlot((_pwg_t *)ppd->pwg, NULL, s)) != NULL)
@@ -286,8 +290,10 @@ cupsMarkOptions(
}
else if (!strcasecmp(optptr->name, "output-bin"))
{
- if (!cupsGetOption("OutputBin", num_options, options))
- ppd_mark_option(ppd, "OutputBin", optptr->value);
+ if (!cupsGetOption("OutputBin", num_options, options) &&
+ (ppd_keyword = _pwgGetOutputBin((_pwg_t *)ppd->pwg,
+ optptr->value)) != NULL)
+ ppd_mark_option(ppd, "OutputBin", ppd_keyword);
}
else if (!strcasecmp(optptr->name, "multiple-document-handling"))
{
diff --git a/cups/ppd-private.h b/cups/ppd-private.h
index f7ade9407..2867fc83e 100644
--- a/cups/ppd-private.h
+++ b/cups/ppd-private.h
@@ -80,10 +80,12 @@ extern char *_ppdNormalizeMakeAndModel(const char *make_and_model,
extern int _ppdParseOptions(const char *s, int num_options,
cups_option_t **options);
extern _pwg_t *_pwgCreateWithPPD(ppd_file_t *ppd);
+extern const char *_pwgGetBin(_pwg_t *pwg, const char *output_bin);
extern const char *_pwgGetInputSlot(_pwg_t *pwg, ipp_t *job,
const char *keyword);
extern const char *_pwgGetMediaType(_pwg_t *pwg, ipp_t *job,
const char *keyword);
+extern const char *_pwgGetOutputBin(_pwg_t *pwg, const char *keyword);
extern const char *_pwgGetPageSize(_pwg_t *pwg, ipp_t *job,
const char *keyword, int *exact);
extern _pwg_size_t *_pwgGetSize(_pwg_t *pwg, const char *page_size);
@@ -92,7 +94,7 @@ extern const char *_pwgGetType(_pwg_t *pwg, const char *media_type);
extern const char *_pwgInputSlotForSource(const char *media_source,
char *name, size_t namesize);
extern _pwg_media_t *_pwgMediaForPPD(const char *ppd);
-extern const char *_pwgMediaTypeForType(const char *media_source,
+extern const char *_pwgMediaTypeForType(const char *media_type,
char *name, size_t namesize);
extern const char *_pwgPageSizeForMedia(_pwg_media_t *media,
char *name, size_t namesize);
diff --git a/cups/pwg-file.c b/cups/pwg-file.c
index b81339289..8e4a4835e 100644
--- a/cups/pwg-file.c
+++ b/cups/pwg-file.c
@@ -42,6 +42,7 @@ _pwgCreateWithFile(const char *filename)/* I - File to read */
_pwg_size_t *size; /* Current size */
_pwg_map_t *map; /* Current map */
int linenum, /* Current line number */
+ num_bins, /* Number of bins in file */
num_sizes, /* Number of sizes in file */
num_sources, /* Number of sources in file */
num_types; /* Number of types in file */
@@ -90,6 +91,7 @@ _pwgCreateWithFile(const char *filename)/* I - File to read */
*/
linenum = 0;
+ num_bins = 0;
num_sizes = 0;
num_sources = 0;
num_types = 0;
@@ -105,6 +107,54 @@ _pwgCreateWithFile(const char *filename)/* I - File to read */
_cupsSetError(IPP_INTERNAL_ERROR, _("Bad PWG mapping file."), 1);
goto create_error;
}
+ else if (!strcasecmp(line, "NumBins"))
+ {
+ if (num_bins > 0)
+ {
+ DEBUG_puts("_pwgCreateWithFile: NumBins listed multiple times.");
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PWG mapping file."), 1);
+ goto create_error;
+ }
+
+ if ((num_bins = atoi(value)) <= 0 || num_bins > 65536)
+ {
+ DEBUG_printf(("_pwgCreateWithFile: Bad NumBins value %d on line %d.",
+ num_sizes, linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PWG mapping file."), 1);
+ goto create_error;
+ }
+
+ if ((pwg->bins = calloc(num_bins, sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_pwgCreateWithFile: Unable to allocate %d bins.",
+ num_sizes));
+ _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno), 0);
+ goto create_error;
+ }
+ }
+ else if (!strcasecmp(line, "Bin"))
+ {
+ if (sscanf(value, "%127s%40s", pwg_keyword, ppd_keyword) != 2)
+ {
+ DEBUG_printf(("_pwgCreateWithFile: Bad Bin on line %d.", linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PWG mapping file."), 1);
+ goto create_error;
+ }
+
+ if (pwg->num_bins >= num_bins)
+ {
+ DEBUG_printf(("_pwgCreateWithFile: Too many Bin's on line %d.",
+ linenum));
+ _cupsSetError(IPP_INTERNAL_ERROR, _("Bad PWG mapping file."), 1);
+ goto create_error;
+ }
+
+ map = pwg->bins + pwg->num_bins;
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(ppd_keyword);
+
+ pwg->num_bins ++;
+ }
else if (!strcasecmp(line, "NumSizes"))
{
if (num_sizes > 0)
@@ -354,6 +404,17 @@ _pwgDestroy(_pwg_t *pwg) /* I - PWG mapping data */
* Free memory as needed...
*/
+ if (pwg->bins)
+ {
+ for (i = pwg->num_bins, map = pwg->bins; i > 0; i --, map ++)
+ {
+ _cupsStrFree(map->pwg);
+ _cupsStrFree(map->ppd);
+ }
+
+ free(pwg->bins);
+ }
+
if (pwg->sizes)
{
for (i = pwg->num_sizes, size = pwg->sizes; i > 0; i --, size ++)
@@ -438,6 +499,17 @@ _pwgWriteFile(_pwg_t *pwg, /* I - PWG mapping data */
cupsFilePuts(fp, "#CUPS-PWGPPD\n");
/*
+ * Output bins...
+ */
+
+ if (pwg->num_bins > 0)
+ {
+ cupsFilePrintf(fp, "NumBins %d\n", pwg->num_bins);
+ for (i = pwg->num_bins, map = pwg->bins; i > 0; i --, map ++)
+ cupsFilePrintf(fp, "Bin %s %s\n", map->pwg, map->ppd);
+ }
+
+ /*
* Media sizes...
*/
diff --git a/cups/pwg-ppd.c b/cups/pwg-ppd.c
index ca3d88fb8..714304483 100644
--- a/cups/pwg-ppd.c
+++ b/cups/pwg-ppd.c
@@ -16,10 +16,14 @@
* Contents:
*
* _pwgCreateWithPPD() - Create PWG mapping data from a PPD file.
+ * _pwgGetBin() - Get the PWG output-bin keyword associated with a
+ * PPD OutputBin.
* _pwgGetInputSlot() - Get the PPD InputSlot associated with the job
* attributes or a keyword string.
* _pwgGetMediaType() - Get the PPD MediaType associated with the job
* attributes or a keyword string.
+ * _pwgGetOutputBin() - Get the PPD OutputBin associated with the
+ * keyword string.
* _pwgGetPageSize() - Get the PPD PageSize associated with the job
* attributes or a keyword string.
* _pwgGetSize() - Get the PWG size associated with a PPD PageSize.
@@ -61,7 +65,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
int i, j; /* Looping vars */
_pwg_t *pwg; /* PWG mapping data */
ppd_option_t *input_slot, /* InputSlot option */
- *media_type; /* MediaType option */
+ *media_type, /* MediaType option */
+ *output_bin; /* OutputBin option */
ppd_choice_t *choice; /* Current InputSlot/MediaType */
_pwg_map_t *map; /* Current source/type map */
ppd_size_t *ppd_size; /* Current PPD size */
@@ -327,6 +332,35 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
}
}
+
+ /*
+ * Copy and convert OutputBin data...
+ */
+
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ if ((pwg->bins = calloc(output_bin->num_choices,
+ sizeof(_pwg_map_t))) == NULL)
+ {
+ DEBUG_printf(("_pwgCreateWithPPD: Unable to allocate %d _pwg_map_t's "
+ "for OutputBin.", output_bin->num_choices));
+ goto create_error;
+ }
+
+ pwg->num_bins = output_bin->num_choices;
+
+ for (i = output_bin->num_choices, choice = output_bin->choices,
+ map = pwg->bins;
+ i > 0;
+ i --, choice ++, map ++)
+ {
+ pwg_unppdize_name(choice->choice, pwg_keyword, sizeof(pwg_keyword));
+
+ map->pwg = _cupsStrAlloc(pwg_keyword);
+ map->ppd = _cupsStrAlloc(choice->choice);
+ }
+ }
+
return (pwg);
/*
@@ -343,6 +377,38 @@ _pwgCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */
/*
+ * '_pwgGetBin()' - Get the PWG output-bin keyword associated with a PPD
+ * OutputBin.
+ */
+
+const char * /* O - output-bin or NULL */
+_pwgGetBin(_pwg_t *pwg, /* I - PWG mapping data */
+ const char *output_bin) /* I - PPD OutputBin string */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pwg || !output_bin)
+ return (NULL);
+
+ /*
+ * Look up the OutputBin string...
+ */
+
+
+ for (i = 0; i < pwg->num_bins; i ++)
+ if (!strcasecmp(output_bin, pwg->bins[i].ppd))
+ return (pwg->bins[i].pwg);
+
+ return (NULL);
+}
+
+
+/*
* '_pwgGetInputSlot()' - Get the PPD InputSlot associated with the job
* attributes or a keyword string.
*/
@@ -443,6 +509,38 @@ _pwgGetMediaType(_pwg_t *pwg, /* I - PWG mapping data */
/*
+ * '_pwgGetOutputBin()' - Get the PPD OutputBin associated with the keyword
+ * string.
+ */
+
+const char * /* O - PPD OutputBin or NULL */
+_pwgGetOutputBin(_pwg_t *pwg, /* I - PWG mapping data */
+ const char *output_bin)/* I - Keyword string */
+{
+ int i; /* Looping var */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!pwg || !output_bin)
+ return (NULL);
+
+ /*
+ * Look up the OutputBin string...
+ */
+
+
+ for (i = 0; i < pwg->num_bins; i ++)
+ if (!strcasecmp(output_bin, pwg->bins[i].pwg))
+ return (pwg->bins[i].ppd);
+
+ return (NULL);
+}
+
+
+/*
* '_pwgGetPageSize()' - Get the PPD PageSize associated with the job
* attributes or a keyword string.
*/
@@ -619,6 +717,13 @@ _pwgGetSize(_pwg_t *pwg, /* I - PWG mapping data */
_pwg_size_t *size; /* Current size */
+ /*
+ * Range check input...
+ */
+
+ if (!pwg || !page_size)
+ return (NULL);
+
if (!strncasecmp(page_size, "Custom.", 7))
{
/*
@@ -706,6 +811,13 @@ _pwgGetSource(_pwg_t *pwg, /* I - PWG mapping data */
_pwg_map_t *source; /* Current source */
+ /*
+ * Range check input...
+ */
+
+ if (!pwg || !input_slot)
+ return (NULL);
+
for (i = pwg->num_sources, source = pwg->sources; i > 0; i --, source ++)
if (!strcasecmp(input_slot, source->ppd))
return (source->pwg);
@@ -726,6 +838,13 @@ _pwgGetType(_pwg_t *pwg, /* I - PWG mapping data */
_pwg_map_t *type; /* Current type */
+ /*
+ * Range check input...
+ */
+
+ if (!pwg || !media_type)
+ return (NULL);
+
for (i = pwg->num_types, type = pwg->types; i > 0; i --, type ++)
if (!strcasecmp(media_type, type->ppd))
return (type->pwg);
@@ -744,6 +863,13 @@ _pwgInputSlotForSource(
char *name, /* I - Name buffer */
size_t namesize) /* I - Size of name buffer */
{
+ /*
+ * Range check input...
+ */
+
+ if (!media_source || !name || namesize < PPD_MAX_NAME)
+ return (NULL);
+
if (strcasecmp(media_source, "main"))
strlcpy(name, "Cassette", namesize);
else if (strcasecmp(media_source, "alternate"))
@@ -783,6 +909,13 @@ _pwgMediaTypeForType(
char *name, /* I - Name buffer */
size_t namesize) /* I - Size of name buffer */
{
+ /*
+ * Range check input...
+ */
+
+ if (!media_type || !name || namesize < PPD_MAX_NAME)
+ return (NULL);
+
if (strcasecmp(media_type, "auto"))
strlcpy(name, "Auto", namesize);
else if (strcasecmp(media_type, "cardstock"))
diff --git a/cups/pwg-private.h b/cups/pwg-private.h
index fa266a2bf..623fc5801 100644
--- a/cups/pwg-private.h
+++ b/cups/pwg-private.h
@@ -80,6 +80,8 @@ typedef struct _pwg_size_s /**** Size element - PPD to/from PWG */
typedef struct _pwg_s /**** PWG-PPD conversion data ****/
{
+ int num_bins; /* Number of output bins */
+ _pwg_map_t *bins; /* Output bins */
int num_sizes; /* Number of media sizes */
_pwg_size_t *sizes; /* Media sizes */
int custom_max_width, /* Maximum custom width in 2540ths */
diff --git a/cups/sspi-private.h b/cups/sspi-private.h
new file mode 100644
index 000000000..e8f36c2d1
--- /dev/null
+++ b/cups/sspi-private.h
@@ -0,0 +1,82 @@
+/*
+ * Private SSPI definitions for CUPS.
+ *
+ * Copyright 2010 by Apple Inc.
+ *
+ * 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+#ifndef _CUPS_SSPI_PRIVATE_H_
+# define _CUPS_SSPI_PRIVATE_H_
+
+/*
+ * Include necessary headers...
+ */
+
+# include <config.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <wincrypt.h>
+# include <wintrust.h>
+# include <schannel.h>
+# define SECURITY_WIN32
+# include <security.h>
+# include <sspi.h>
+
+/*
+ * C++ magic...
+ */
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+typedef struct /**** SSPI/SSL data structure ****/
+{
+ SOCKET sock; /* TCP/IP socket */
+ CredHandle creds; /* Credentials */
+ CtxtHandle context; /* SSL context */
+ BOOL contextInitialized; /* Is context init'd? */
+ SecPkgContext_StreamSizes streamSizes; /* SSL data stream sizes */
+ BYTE *decryptBuffer; /* Data pre-decryption*/
+ size_t decryptBufferLength; /* Length of decrypt buffer */
+ size_t decryptBufferUsed; /* Bytes used in buffer */
+ BYTE *readBuffer; /* Data post-decryption */
+ size_t readBufferLength; /* Length of read buffer */
+ size_t readBufferUsed; /* Bytes used in buffer */
+ DWORD certFlags; /* Cert verification flags */
+} _sspi_struct_t;
+
+
+/*
+ * Prototypes...
+ */
+_sspi_struct_t *_sspiAlloc(void);
+BOOL _sspiAccept(_sspi_struct_t *conn);
+BOOL _sspiConnect(_sspi_struct_t *conn,
+ const CHAR *hostname);
+void _sspiFree(_sspi_struct_t *conn);
+BOOL _sspiGetCredentials(_sspi_struct_t *conn,
+ const LPWSTR containerName,
+ const TCHAR *commonName,
+ BOOL server);
+int _sspiPending(_sspi_struct_t *conn);
+int _sspiRead(_sspi_struct_t *conn,
+ void *buf, size_t len);
+void _sspiSetAllowsAnyRoot(_sspi_struct_t *conn,
+ BOOL allow);
+void _sspiSetAllowsExpiredCerts(_sspi_struct_t *conn,
+ BOOL allow);
+int _sspiWrite(_sspi_struct_t *conn,
+ void *buf, size_t len);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+#endif /* !_CUPS_SSPI_PRIVATE_H_ */
diff --git a/cups/sspi.c b/cups/sspi.c
new file mode 100644
index 000000000..7f8a07300
--- /dev/null
+++ b/cups/sspi.c
@@ -0,0 +1,1472 @@
+/*
+ * Windows SSPI SSL implementation for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 2010 by Apple Inc.
+ *
+ * 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
+ * file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ * Contents:
+ *
+ * _sspiAlloc() - Allocate and initialize SSPI/SSL data structure
+ * _sspiAccept() - Accept a new SSL connection
+ * _sspiConnect() - Connect an SSL connection
+ * _sspiFree() - Close and deallocate SSPI/SSL connection
+ * _sspiGetCredentials() - Get credentials associated with connection
+ * _sspiPending() - Return number of bytes available to read
+ * _sspiRead() - Read a buffer of bytes
+ * _sspiSetAllowsAnyRoot() - Set client policy for untrusted root certs
+ * _sspiSetAllowsExpiredCerts() - Set client policy for expired certs
+ * _sspiWrite() - Write a buffer of bytes
+ * sspi_verify_certificate() - Verify a server certificate
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "sspi-private.h"
+#include "debug-private.h"
+
+
+/* required to link this library for certificate functions */
+#pragma comment(lib, "Crypt32.lib")
+#pragma comment(lib, "Secur32.lib")
+#pragma comment(lib, "Ws2_32.lib")
+
+
+#if !defined(SECURITY_FLAG_IGNORE_UNKNOWN_CA)
+# define SECURITY_FLAG_IGNORE_UNKNOWN_CA 0x00000100 /* Untrusted root */
+#endif
+
+#if !defined(SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
+# define SECURITY_FLAG_IGNORE_CERT_DATE_INVALID 0x00002000 /* Expired X509 Cert. */
+#endif
+
+static DWORD sspi_verify_certificate(PCCERT_CONTEXT serverCert,
+ const CHAR *serverName,
+ DWORD dwCertFlags);
+
+
+/*
+ * 'sspi_alloc()' - Allocate SSPI ssl object
+ */
+_sspi_struct_t* /* O - New SSPI/SSL object */
+_sspiAlloc(void)
+{
+ _sspi_struct_t *conn = calloc(sizeof(_sspi_struct_t), 1);
+
+ if (conn)
+ conn->sock = INVALID_SOCKET;
+
+ return (conn);
+}
+
+
+/*
+ * '_sspiGetCredentials()' - Retrieve an SSL/TLS certificate from the system store
+ * If one cannot be found, one is created.
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiGetCredentials(_sspi_struct_t *conn,
+ /* I - Client connection */
+ const LPWSTR container,
+ /* I - Cert container name */
+ const TCHAR *cn, /* I - Common name of certificate */
+ BOOL isServer)
+ /* I - Is caller a server? */
+{
+ HCERTSTORE store = NULL; /* Certificate store */
+ PCCERT_CONTEXT storedContext = NULL;
+ /* Context created from the store */
+ PCCERT_CONTEXT createdContext = NULL;
+ /* Context created by us */
+ DWORD dwSize = 0; /* 32 bit size */
+ PBYTE p = NULL; /* Temporary storage */
+ HCRYPTPROV hProv = (HCRYPTPROV) NULL;
+ /* Handle to a CSP */
+ CERT_NAME_BLOB sib; /* Arbitrary array of bytes */
+ SCHANNEL_CRED SchannelCred; /* Schannel credential data */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS Status; /* Status */
+ HCRYPTKEY hKey = (HCRYPTKEY) NULL;
+ /* Handle to crypto key */
+ CRYPT_KEY_PROV_INFO kpi; /* Key container info */
+ SYSTEMTIME et; /* System time */
+ CERT_EXTENSIONS exts; /* Array of cert extensions */
+ CRYPT_KEY_PROV_INFO ckp; /* Handle to crypto key */
+ BOOL ok = TRUE; /* Return value */
+
+ if (!conn)
+ return (FALSE);
+ if (!cn)
+ return (FALSE);
+
+ if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
+ PROV_RSA_FULL,
+ CRYPT_NEWKEYSET | CRYPT_MACHINE_KEYSET))
+ {
+ if (GetLastError() == NTE_EXISTS)
+ {
+ if (!CryptAcquireContextW(&hProv, (LPWSTR) container, MS_DEF_PROV_W,
+ PROV_RSA_FULL, CRYPT_MACHINE_KEYSET))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CryptAcquireContext failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+ }
+
+ store = CertOpenStore(CERT_STORE_PROV_SYSTEM,
+ X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
+ hProv,
+ CERT_SYSTEM_STORE_LOCAL_MACHINE |
+ CERT_STORE_NO_CRYPT_RELEASE_FLAG |
+ CERT_STORE_OPEN_EXISTING_FLAG,
+ L"MY");
+
+ if (!store)
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertOpenSystemStore failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ dwSize = 0;
+
+ if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR,
+ NULL, NULL, &dwSize, NULL))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x\n",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ p = (PBYTE) malloc(dwSize);
+
+ if (!p)
+ {
+ DEBUG_printf(("_sspiGetCredentials: malloc failed for %d bytes", dwSize));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ if (!CertStrToName(X509_ASN_ENCODING, cn, CERT_OID_NAME_STR, NULL,
+ p, &dwSize, NULL))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertStrToName failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ sib.cbData = dwSize;
+ sib.pbData = p;
+
+ storedContext = CertFindCertificateInStore(store, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_SUBJECT_NAME, &sib, NULL);
+
+ if (!storedContext)
+ {
+ /*
+ * If we couldn't find the context, then we'll
+ * create a new one
+ */
+ if (!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CryptGenKey failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ ZeroMemory(&kpi, sizeof(kpi));
+ kpi.pwszContainerName = (LPWSTR) container;
+ kpi.pwszProvName = MS_DEF_PROV_W;
+ kpi.dwProvType = PROV_RSA_FULL;
+ kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
+ kpi.dwKeySpec = AT_KEYEXCHANGE;
+
+ GetSystemTime(&et);
+ et.wYear += 10;
+
+ ZeroMemory(&exts, sizeof(exts));
+
+ createdContext = CertCreateSelfSignCertificate(hProv, &sib, 0, &kpi, NULL, NULL,
+ &et, &exts);
+
+ if (!createdContext)
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertCreateSelfSignCertificate failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ if (!CertAddCertificateContextToStore(store, createdContext,
+ CERT_STORE_ADD_REPLACE_EXISTING,
+ &storedContext))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertAddCertificateContextToStore failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ ZeroMemory(&ckp, sizeof(ckp));
+ ckp.pwszContainerName = (LPWSTR) container;
+ ckp.pwszProvName = MS_DEF_PROV_W;
+ ckp.dwProvType = PROV_RSA_FULL;
+ ckp.dwFlags = CRYPT_MACHINE_KEYSET;
+ ckp.dwKeySpec = AT_KEYEXCHANGE;
+
+ if (!CertSetCertificateContextProperty(storedContext,
+ CERT_KEY_PROV_INFO_PROP_ID,
+ 0, &ckp))
+ {
+ DEBUG_printf(("_sspiGetCredentials: CertSetCertificateContextProperty failed: %x",
+ GetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ ZeroMemory(&SchannelCred, sizeof(SchannelCred));
+
+ SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
+ SchannelCred.cCreds = 1;
+ SchannelCred.paCred = &storedContext;
+
+ /*
+ * SSPI doesn't seem to like it if grbitEnabledProtocols
+ * is set for a client
+ */
+ if (isServer)
+ SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1;
+
+ /*
+ * Create an SSPI credential.
+ */
+ Status = AcquireCredentialsHandle(NULL, UNISP_NAME,
+ isServer ? SECPKG_CRED_INBOUND:SECPKG_CRED_OUTBOUND,
+ NULL, &SchannelCred, NULL, NULL, &conn->creds,
+ &tsExpiry);
+ if (Status != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiGetCredentials: AcquireCredentialsHandle failed: %x", Status));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+cleanup:
+
+ /*
+ * Cleanup
+ */
+ if (hKey)
+ CryptDestroyKey(hKey);
+
+ if (createdContext)
+ CertFreeCertificateContext(createdContext);
+
+ if (storedContext)
+ CertFreeCertificateContext(storedContext);
+
+ if (p)
+ free(p);
+
+ if (store)
+ CertCloseStore(store, 0);
+
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiConnect()' - Make an SSL connection. This function
+ * assumes a TCP/IP connection has already
+ * been successfully made
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiConnect(_sspi_struct_t *conn, /* I - Client connection */
+ const CHAR *hostname) /* I - Server hostname */
+{
+ PCCERT_CONTEXT serverCert; /* Server certificate */
+ DWORD dwSSPIFlags; /* SSL connection attributes we want */
+ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS scRet; /* Status */
+ DWORD cbData; /* Data count */
+ SecBufferDesc inBuffer; /* Array of SecBuffer structs */
+ SecBuffer inBuffers[2]; /* Security package buffer */
+ SecBufferDesc outBuffer; /* Array of SecBuffer structs */
+ SecBuffer outBuffers[1]; /* Security package buffer */
+ BOOL ok = TRUE; /* Return value */
+
+ serverCert = NULL;
+
+ dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ /*
+ * Initiate a ClientHello message and generate a token.
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType = SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = InitializeSecurityContext(&conn->creds, NULL, TEXT(""), dwSSPIFlags,
+ 0, SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+ &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+
+ if (scRet != SEC_I_CONTINUE_NEEDED)
+ {
+ DEBUG_printf(("_sspiConnect: InitializeSecurityContext(1) failed: %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * Send response to server if there is one.
+ */
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((cbData == SOCKET_ERROR) || !cbData)
+ {
+ DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ DeleteSecurityContext(&conn->context);
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
+
+ /*
+ * Free output buffer.
+ */
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+
+ dwSSPIFlags = ISC_REQ_MANUAL_CRED_VALIDATION |
+ ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Loop until the handshake is finished or an error occurs.
+ */
+ scRet = SEC_I_CONTINUE_NEEDED;
+
+ while(scRet == SEC_I_CONTINUE_NEEDED ||
+ scRet == SEC_E_INCOMPLETE_MESSAGE ||
+ scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
+ {
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer, conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiConnect: unable to allocate %d byte decrypt buffer",
+ conn->decryptBufferLength));
+ SetLastError(E_OUTOFMEMORY);
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ cbData = recv(conn->sock, conn->decryptBuffer + conn->decryptBufferUsed,
+ (int) (conn->decryptBufferLength - conn->decryptBufferUsed), 0);
+
+ if (cbData == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiConnect: recv failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ else if (cbData == 0)
+ {
+ DEBUG_printf(("_sspiConnect: server unexpectedly disconnected"));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data received",
+ cbData));
+
+ conn->decryptBufferUsed += cbData;
+ }
+
+ /*
+ * Set up the input buffers. Buffer 0 is used to pass in data
+ * received from the server. Schannel will consume some or all
+ * of this. Leftover data (if any) will be placed in buffer 1 and
+ * given a buffer type of SECBUFFER_EXTRA.
+ */
+ inBuffers[0].pvBuffer = conn->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ inBuffers[0].BufferType = SECBUFFER_TOKEN;
+
+ inBuffers[1].pvBuffer = NULL;
+ inBuffers[1].cbBuffer = 0;
+ inBuffers[1].BufferType = SECBUFFER_EMPTY;
+
+ inBuffer.cBuffers = 2;
+ inBuffer.pBuffers = inBuffers;
+ inBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Set up the output buffers. These are initialized to NULL
+ * so as to make it less likely we'll attempt to free random
+ * garbage later.
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType= SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Call InitializeSecurityContext.
+ */
+ scRet = InitializeSecurityContext(&conn->creds, &conn->context, NULL, dwSSPIFlags,
+ 0, SECURITY_NATIVE_DREP, &inBuffer, 0, NULL,
+ &outBuffer, &dwSSPIOutFlags, &tsExpiry);
+
+ /*
+ * If InitializeSecurityContext was successful (or if the error was
+ * one of the special extended ones), send the contends of the output
+ * buffer to the server.
+ */
+ if (scRet == SEC_E_OK ||
+ scRet == SEC_I_CONTINUE_NEEDED ||
+ FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
+ {
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ cbData = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((cbData == SOCKET_ERROR) || !cbData)
+ {
+ DEBUG_printf(("_sspiConnect: send failed: %d", WSAGetLastError()));
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ DeleteSecurityContext(&conn->context);
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiConnect: %d bytes of handshake data sent", cbData));
+
+ /*
+ * Free output buffer.
+ */
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+ }
+
+ /*
+ * If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
+ * then we need to read more data from the server and try again.
+ */
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE)
+ continue;
+
+ /*
+ * If InitializeSecurityContext returned SEC_E_OK, then the
+ * handshake completed successfully.
+ */
+ if (scRet == SEC_E_OK)
+ {
+ /*
+ * If the "extra" buffer contains data, this is encrypted application
+ * protocol layer stuff. It needs to be saved. The application layer
+ * will later decrypt it with DecryptMessage.
+ */
+ DEBUG_printf(("_sspiConnect: Handshake was successful"));
+
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ if (conn->decryptBufferLength < inBuffers[1].cbBuffer)
+ {
+ conn->decryptBuffer = realloc(conn->decryptBuffer, inBuffers[1].cbBuffer);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiConnect: unable to allocate %d bytes for decrypt buffer",
+ inBuffers[1].cbBuffer));
+ SetLastError(E_OUTOFMEMORY);
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ memmove(conn->decryptBuffer,
+ conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
+ inBuffers[1].cbBuffer);
+
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+
+ DEBUG_printf(("_sspiConnect: %d bytes of app data was bundled with handshake data",
+ conn->decryptBufferUsed));
+ }
+ else
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Bail out to quit
+ */
+ break;
+ }
+
+ /*
+ * Check for fatal error.
+ */
+ if (FAILED(scRet))
+ {
+ DEBUG_printf(("_sspiConnect: InitializeSecurityContext(2) failed: %x", scRet));
+ ok = FALSE;
+ break;
+ }
+
+ /*
+ * If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
+ * then the server just requested client authentication.
+ */
+ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ /*
+ * Unimplemented
+ */
+ DEBUG_printf(("_sspiConnect: server requested client credentials"));
+ ok = FALSE;
+ break;
+ }
+
+ /*
+ * Copy any leftover data from the "extra" buffer, and go around
+ * again.
+ */
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memmove(conn->decryptBuffer,
+ conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer),
+ inBuffers[1].cbBuffer);
+
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+
+ if (ok)
+ {
+ conn->contextInitialized = TRUE;
+
+ /*
+ * Get the server cert
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (VOID*) &serverCert );
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_REMOTE_CERT_CONTEXT): %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ scRet = sspi_verify_certificate(serverCert, hostname, conn->certFlags);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: sspi_verify_certificate failed: %x", scRet));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * Find out how big the header/trailer will be:
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiConnect: QueryContextAttributes failed(SECPKG_ATTR_STREAM_SIZES): %x", scRet));
+ ok = FALSE;
+ }
+ }
+
+cleanup:
+
+ if (serverCert)
+ CertFreeCertificateContext(serverCert);
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiAccept()' - Accept an SSL/TLS connection
+ */
+BOOL /* O - 1 on success, 0 on failure */
+_sspiAccept(_sspi_struct_t *conn) /* I - Client connection */
+{
+ DWORD dwSSPIFlags; /* SSL connection attributes we want */
+ DWORD dwSSPIOutFlags; /* SSL connection attributes we got */
+ TimeStamp tsExpiry; /* Time stamp */
+ SECURITY_STATUS scRet; /* SSPI Status */
+ SecBufferDesc inBuffer; /* Array of SecBuffer structs */
+ SecBuffer inBuffers[2]; /* Security package buffer */
+ SecBufferDesc outBuffer; /* Array of SecBuffer structs */
+ SecBuffer outBuffers[1]; /* Security package buffer */
+ DWORD num = 0; /* 32 bit status value */
+ BOOL fInitContext = TRUE;
+ /* Has the context been init'd? */
+ BOOL ok = TRUE; /* Return value */
+
+ if (!conn)
+ return (FALSE);
+
+ dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
+ ASC_REQ_REPLAY_DETECT |
+ ASC_REQ_CONFIDENTIALITY |
+ ASC_REQ_EXTENDED_ERROR |
+ ASC_REQ_ALLOCATE_MEMORY |
+ ASC_REQ_STREAM;
+
+ conn->decryptBufferUsed = 0;
+
+ /*
+ * Set OutBuffer for AcceptSecurityContext call
+ */
+ outBuffer.cBuffers = 1;
+ outBuffer.pBuffers = outBuffers;
+ outBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = SEC_I_CONTINUE_NEEDED;
+
+ while (scRet == SEC_I_CONTINUE_NEEDED ||
+ scRet == SEC_E_INCOMPLETE_MESSAGE ||
+ scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if ((conn->decryptBufferUsed == 0) || (scRet == SEC_E_INCOMPLETE_MESSAGE))
+ {
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
+ conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiAccept: unable to allocate %d byte decrypt buffer",
+ conn->decryptBufferLength));
+ ok = FALSE;
+ goto cleanup;
+ }
+ }
+
+ for (;;)
+ {
+ num = recv(conn->sock,
+ conn->decryptBuffer + conn->decryptBufferUsed,
+ (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
+ 0);
+
+ if ((num == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
+ Sleep(1);
+ else
+ break;
+ }
+
+ if (num == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiAccept: recv failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+ else if (num == 0)
+ {
+ DEBUG_printf(("_sspiAccept: client disconnected"));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiAccept: received %d (handshake) bytes from client",
+ num));
+ conn->decryptBufferUsed += num;
+ }
+
+ /*
+ * InBuffers[1] is for getting extra data that
+ * SSPI/SCHANNEL doesn't proccess on this
+ * run around the loop.
+ */
+ inBuffers[0].pvBuffer = conn->decryptBuffer;
+ inBuffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ inBuffers[0].BufferType = SECBUFFER_TOKEN;
+
+ inBuffers[1].pvBuffer = NULL;
+ inBuffers[1].cbBuffer = 0;
+ inBuffers[1].BufferType = SECBUFFER_EMPTY;
+
+ inBuffer.cBuffers = 2;
+ inBuffer.pBuffers = inBuffers;
+ inBuffer.ulVersion = SECBUFFER_VERSION;
+
+ /*
+ * Initialize these so if we fail, pvBuffer contains NULL,
+ * so we don't try to free random garbage at the quit
+ */
+ outBuffers[0].pvBuffer = NULL;
+ outBuffers[0].BufferType = SECBUFFER_TOKEN;
+ outBuffers[0].cbBuffer = 0;
+
+ scRet = AcceptSecurityContext(&conn->creds, (fInitContext?NULL:&conn->context),
+ &inBuffer, dwSSPIFlags, SECURITY_NATIVE_DREP,
+ (fInitContext?&conn->context:NULL), &outBuffer,
+ &dwSSPIOutFlags, &tsExpiry);
+
+ fInitContext = FALSE;
+
+ if (scRet == SEC_E_OK ||
+ scRet == SEC_I_CONTINUE_NEEDED ||
+ (FAILED(scRet) && ((dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR) != 0)))
+ {
+ if (outBuffers[0].cbBuffer && outBuffers[0].pvBuffer)
+ {
+ /*
+ * Send response to server if there is one
+ */
+ num = send(conn->sock, outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
+
+ if ((num == SOCKET_ERROR) || (num == 0))
+ {
+ DEBUG_printf(("_sspiAccept: handshake send failed: %d", WSAGetLastError()));
+ ok = FALSE;
+ goto cleanup;
+ }
+
+ DEBUG_printf(("_sspiAccept: send %d handshake bytes to client",
+ outBuffers[0].cbBuffer));
+
+ FreeContextBuffer(outBuffers[0].pvBuffer);
+ outBuffers[0].pvBuffer = NULL;
+ }
+ }
+
+ if (scRet == SEC_E_OK)
+ {
+ /*
+ * If there's extra data then save it for
+ * next time we go to decrypt
+ */
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memcpy(conn->decryptBuffer,
+ (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
+ inBuffers[1].cbBuffer);
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+
+ ok = TRUE;
+ break;
+ }
+ else if (FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE))
+ {
+ DEBUG_printf(("_sspiAccept: AcceptSecurityContext failed: %x", scRet));
+ ok = FALSE;
+ break;
+ }
+
+ if (scRet != SEC_E_INCOMPLETE_MESSAGE &&
+ scRet != SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ if (inBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memcpy(conn->decryptBuffer,
+ (LPBYTE) (conn->decryptBuffer + (conn->decryptBufferUsed - inBuffers[1].cbBuffer)),
+ inBuffers[1].cbBuffer);
+ conn->decryptBufferUsed = inBuffers[1].cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ conn->contextInitialized = TRUE;
+
+ /*
+ * Find out how big the header will be:
+ */
+ scRet = QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->streamSizes);
+
+ if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiAccept: QueryContextAttributes failed: %x", scRet));
+ ok = FALSE;
+ }
+ }
+
+cleanup:
+
+ return (ok);
+}
+
+
+/*
+ * '_sspiSetAllowsAnyRoot()' - Set the client cert policy for untrusted root certs
+ */
+void
+_sspiSetAllowsAnyRoot(_sspi_struct_t *conn,
+ /* I - Client connection */
+ BOOL allow)
+ /* I - Allow any root */
+{
+ conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_UNKNOWN_CA :
+ conn->certFlags & ~SECURITY_FLAG_IGNORE_UNKNOWN_CA;
+}
+
+
+/*
+ * '_sspiSetAllowsExpiredCerts()' - Set the client cert policy for expired root certs
+ */
+void
+_sspiSetAllowsExpiredCerts(_sspi_struct_t *conn,
+ /* I - Client connection */
+ BOOL allow)
+ /* I - Allow expired certs */
+{
+ conn->certFlags = (allow) ? conn->certFlags | SECURITY_FLAG_IGNORE_CERT_DATE_INVALID :
+ conn->certFlags & ~SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
+}
+
+
+/*
+ * '_sspiWrite()' - Write a buffer to an ssl socket
+ */
+int /* O - Bytes written or SOCKET_ERROR */
+_sspiWrite(_sspi_struct_t *conn, /* I - Client connection */
+ void *buf, /* I - Buffer */
+ size_t len) /* I - Buffer length */
+{
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[4] = { 0 }; /* Security package buffer */
+ BYTE *buffer = NULL; /* Scratch buffer */
+ int bufferLen; /* Buffer length */
+ size_t bytesLeft; /* Bytes left to write */
+ int index = 0; /* Index into buffer */
+ int num = 0; /* Return value */
+
+ if (!conn || !buf || !len)
+ {
+ WSASetLastError(WSAEINVAL);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ bufferLen = conn->streamSizes.cbMaximumMessage +
+ conn->streamSizes.cbHeader +
+ conn->streamSizes.cbTrailer;
+
+ buffer = (BYTE*) malloc(bufferLen);
+
+ if (!buffer)
+ {
+ DEBUG_printf(("_sspiWrite: buffer alloc of %d bytes failed", bufferLen));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ bytesLeft = len;
+
+ while (bytesLeft)
+ {
+ size_t chunk = min(conn->streamSizes.cbMaximumMessage, /* Size of data to write */
+ bytesLeft);
+ SECURITY_STATUS scRet; /* SSPI status */
+
+ /*
+ * Copy user data into the buffer, starting
+ * just past the header
+ */
+ memcpy(buffer + conn->streamSizes.cbHeader,
+ ((BYTE*) buf) + index,
+ chunk);
+
+ /*
+ * Setup the SSPI buffers
+ */
+ message.ulVersion = SECBUFFER_VERSION;
+ message.cBuffers = 4;
+ message.pBuffers = buffers;
+ buffers[0].pvBuffer = buffer;
+ buffers[0].cbBuffer = conn->streamSizes.cbHeader;
+ buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
+ buffers[1].pvBuffer = buffer + conn->streamSizes.cbHeader;
+ buffers[1].cbBuffer = (unsigned long) chunk;
+ buffers[1].BufferType = SECBUFFER_DATA;
+ buffers[2].pvBuffer = buffer + conn->streamSizes.cbHeader + chunk;
+ buffers[2].cbBuffer = conn->streamSizes.cbTrailer;
+ buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
+ buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ /*
+ * Encrypt the data
+ */
+ scRet = EncryptMessage(&conn->context, 0, &message, 0);
+
+ if (FAILED(scRet))
+ {
+ DEBUG_printf(("_sspiWrite: EncryptMessage failed: %x", scRet));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * Send the data. Remember the size of
+ * the total data to send is the size
+ * of the header, the size of the data
+ * the caller passed in and the size
+ * of the trailer
+ */
+ num = send(conn->sock,
+ buffer,
+ buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer,
+ 0);
+
+ if ((num == SOCKET_ERROR) || (num == 0))
+ {
+ DEBUG_printf(("_sspiWrite: send failed: %ld", WSAGetLastError()));
+ goto cleanup;
+ }
+
+ bytesLeft -= (int) chunk;
+ index += (int) chunk;
+ }
+
+ num = (int) len;
+
+cleanup:
+
+ if (buffer)
+ free(buffer);
+
+ return (num);
+}
+
+
+/*
+ * '_sspiRead()' - Read a buffer from an ssl socket
+ */
+int /* O - Bytes read or SOCKET_ERROR */
+_sspiRead(_sspi_struct_t *conn, /* I - Client connection */
+ void *buf, /* I - Buffer */
+ size_t len) /* I - Buffer length */
+{
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[4] = { 0 }; /* Security package buffer */
+ int num = 0; /* Return value */
+
+ if (!conn)
+ {
+ WSASetLastError(WSAEINVAL);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * If there are bytes that have already been
+ * decrypted and have not yet been read, return
+ * those
+ */
+ if (buf && (conn->readBufferUsed > 0))
+ {
+ int bytesToCopy = (int) min(conn->readBufferUsed, len); /* Amount of bytes to copy */
+ /* from read buffer */
+
+ memcpy(buf, conn->readBuffer, bytesToCopy);
+ conn->readBufferUsed -= bytesToCopy;
+
+ if (conn->readBufferUsed > 0)
+ /*
+ * If the caller didn't request all the bytes
+ * we have in the buffer, then move the unread
+ * bytes down
+ */
+ memmove(conn->readBuffer,
+ conn->readBuffer + bytesToCopy,
+ conn->readBufferUsed);
+
+ num = bytesToCopy;
+ }
+ else
+ {
+ PSecBuffer pDataBuffer; /* Data buffer */
+ PSecBuffer pExtraBuffer; /* Excess data buffer */
+ SECURITY_STATUS scRet; /* SSPI status */
+ int i; /* Loop control variable */
+
+ /*
+ * Initialize security buffer structs
+ */
+ message.ulVersion = SECBUFFER_VERSION;
+ message.cBuffers = 4;
+ message.pBuffers = buffers;
+
+ do
+ {
+ /*
+ * If there is not enough space in the
+ * buffer, then increase it's size
+ */
+ if (conn->decryptBufferLength <= conn->decryptBufferUsed)
+ {
+ conn->decryptBufferLength += 4096;
+ conn->decryptBuffer = (BYTE*) realloc(conn->decryptBuffer,
+ conn->decryptBufferLength);
+
+ if (!conn->decryptBuffer)
+ {
+ DEBUG_printf(("_sspiRead: unable to allocate %d byte buffer",
+ conn->decryptBufferLength));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ }
+
+ buffers[0].pvBuffer = conn->decryptBuffer;
+ buffers[0].cbBuffer = (unsigned long) conn->decryptBufferUsed;
+ buffers[0].BufferType = SECBUFFER_DATA;
+ buffers[1].BufferType = SECBUFFER_EMPTY;
+ buffers[2].BufferType = SECBUFFER_EMPTY;
+ buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ scRet = DecryptMessage(&conn->context, &message, 0, NULL);
+
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE)
+ {
+ if (buf)
+ {
+ num = recv(conn->sock,
+ conn->decryptBuffer + conn->decryptBufferUsed,
+ (int)(conn->decryptBufferLength - conn->decryptBufferUsed),
+ 0);
+ if (num == SOCKET_ERROR)
+ {
+ DEBUG_printf(("_sspiRead: recv failed: %d", WSAGetLastError()));
+ goto cleanup;
+ }
+ else if (num == 0)
+ {
+ DEBUG_printf(("_sspiRead: server disconnected"));
+ goto cleanup;
+ }
+
+ conn->decryptBufferUsed += num;
+ }
+ else
+ {
+ num = (int) conn->readBufferUsed;
+ goto cleanup;
+ }
+ }
+ }
+ while (scRet == SEC_E_INCOMPLETE_MESSAGE);
+
+ if (scRet == SEC_I_CONTEXT_EXPIRED)
+ {
+ DEBUG_printf(("_sspiRead: context expired"));
+ WSASetLastError(WSAECONNRESET);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ else if (scRet != SEC_E_OK)
+ {
+ DEBUG_printf(("_sspiRead: DecryptMessage failed: %lx", scRet));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * The decryption worked. Now, locate data buffer.
+ */
+ pDataBuffer = NULL;
+ pExtraBuffer = NULL;
+ for (i = 1; i < 4; i++)
+ {
+ if (buffers[i].BufferType == SECBUFFER_DATA)
+ pDataBuffer = &buffers[i];
+ else if (!pExtraBuffer && (buffers[i].BufferType == SECBUFFER_EXTRA))
+ pExtraBuffer = &buffers[i];
+ }
+
+ /*
+ * If a data buffer is found, then copy
+ * the decrypted bytes to the passed-in
+ * buffer
+ */
+ if (pDataBuffer)
+ {
+ int bytesToCopy = min(pDataBuffer->cbBuffer, (int) len);
+ /* Number of bytes to copy into buf */
+ int bytesToSave = pDataBuffer->cbBuffer - bytesToCopy;
+ /* Number of bytes to save in our read buffer */
+
+ if (bytesToCopy)
+ memcpy(buf, pDataBuffer->pvBuffer, bytesToCopy);
+
+ /*
+ * If there are more decrypted bytes than can be
+ * copied to the passed in buffer, then save them
+ */
+ if (bytesToSave)
+ {
+ if ((int)(conn->readBufferLength - conn->readBufferUsed) < bytesToSave)
+ {
+ conn->readBufferLength = conn->readBufferUsed + bytesToSave;
+ conn->readBuffer = realloc(conn->readBuffer,
+ conn->readBufferLength);
+
+ if (!conn->readBuffer)
+ {
+ DEBUG_printf(("_sspiRead: unable to allocate %d bytes", conn->readBufferLength));
+ WSASetLastError(E_OUTOFMEMORY);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+ }
+
+ memcpy(((BYTE*) conn->readBuffer) + conn->readBufferUsed,
+ ((BYTE*) pDataBuffer->pvBuffer) + bytesToCopy,
+ bytesToSave);
+
+ conn->readBufferUsed += bytesToSave;
+ }
+
+ num = (buf) ? bytesToCopy : (int) conn->readBufferUsed;
+ }
+ else
+ {
+ DEBUG_printf(("_sspiRead: unable to find data buffer"));
+ WSASetLastError(WSASYSCALLFAILURE);
+ num = SOCKET_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * If the decryption process left extra bytes,
+ * then save those back in decryptBuffer. They will
+ * be processed the next time through the loop.
+ */
+ if (pExtraBuffer)
+ {
+ memmove(conn->decryptBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
+ conn->decryptBufferUsed = pExtraBuffer->cbBuffer;
+ }
+ else
+ {
+ conn->decryptBufferUsed = 0;
+ }
+ }
+
+cleanup:
+
+ return (num);
+}
+
+
+/*
+ * '_sspiPending()' - Returns the number of available bytes
+ */
+int /* O - Number of available bytes */
+_sspiPending(_sspi_struct_t *conn) /* I - Client connection */
+{
+ return (_sspiRead(conn, NULL, 0));
+}
+
+
+/*
+ * '_sspiFree()' - Close a connection and free resources
+ */
+void
+_sspiFree(_sspi_struct_t *conn) /* I - Client connection */
+{
+ if (!conn)
+ return;
+
+ if (conn->contextInitialized)
+ {
+ SecBufferDesc message; /* Array of SecBuffer struct */
+ SecBuffer buffers[1] = { 0 };
+ /* Security package buffer */
+ DWORD dwType; /* Type */
+ DWORD status; /* Status */
+
+ /*
+ * Notify schannel that we are about to close the connection.
+ */
+ dwType = SCHANNEL_SHUTDOWN;
+
+ buffers[0].pvBuffer = &dwType;
+ buffers[0].BufferType = SECBUFFER_TOKEN;
+ buffers[0].cbBuffer = sizeof(dwType);
+
+ message.cBuffers = 1;
+ message.pBuffers = buffers;
+ message.ulVersion = SECBUFFER_VERSION;
+
+ status = ApplyControlToken(&conn->context, &message);
+
+ if (SUCCEEDED(status))
+ {
+ PBYTE pbMessage; /* Message buffer */
+ DWORD cbMessage; /* Message buffer count */
+ DWORD cbData; /* Data count */
+ DWORD dwSSPIFlags; /* SSL attributes we requested */
+ DWORD dwSSPIOutFlags; /* SSL attributes we received */
+ TimeStamp tsExpiry; /* Time stamp */
+
+ dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
+ ASC_REQ_REPLAY_DETECT |
+ ASC_REQ_CONFIDENTIALITY |
+ ASC_REQ_EXTENDED_ERROR |
+ ASC_REQ_ALLOCATE_MEMORY |
+ ASC_REQ_STREAM;
+
+ buffers[0].pvBuffer = NULL;
+ buffers[0].BufferType = SECBUFFER_TOKEN;
+ buffers[0].cbBuffer = 0;
+
+ message.cBuffers = 1;
+ message.pBuffers = buffers;
+ message.ulVersion = SECBUFFER_VERSION;
+
+ status = AcceptSecurityContext(&conn->creds, &conn->context, NULL,
+ dwSSPIFlags, SECURITY_NATIVE_DREP, NULL,
+ &message, &dwSSPIOutFlags, &tsExpiry);
+
+ if (SUCCEEDED(status))
+ {
+ pbMessage = buffers[0].pvBuffer;
+ cbMessage = buffers[0].cbBuffer;
+
+ /*
+ * Send the close notify message to the client.
+ */
+ if (pbMessage && cbMessage)
+ {
+ cbData = send(conn->sock, pbMessage, cbMessage, 0);
+ if ((cbData == SOCKET_ERROR) || (cbData == 0))
+ {
+ status = WSAGetLastError();
+ DEBUG_printf(("_sspiFree: sending close notify failed: %d", status));
+ }
+ else
+ {
+ FreeContextBuffer(pbMessage);
+ }
+ }
+ }
+ else
+ {
+ DEBUG_printf(("_sspiFree: AcceptSecurityContext failed: %x", status));
+ }
+ }
+ else
+ {
+ DEBUG_printf(("_sspiFree: ApplyControlToken failed: %x", status));
+ }
+
+ DeleteSecurityContext(&conn->context);
+ conn->contextInitialized = FALSE;
+ }
+
+ if (conn->decryptBuffer)
+ {
+ free(conn->decryptBuffer);
+ conn->decryptBuffer = NULL;
+ }
+
+ if (conn->readBuffer)
+ {
+ free(conn->readBuffer);
+ conn->readBuffer = NULL;
+ }
+
+ if (conn->sock != INVALID_SOCKET)
+ {
+ closesocket(conn->sock);
+ conn->sock = INVALID_SOCKET;
+ }
+
+ free(conn);
+}
+
+
+/*
+ * 'sspi_verify_certificate()' - Verify a server certificate
+ */
+static DWORD /* 0 - Error code (0 == No error) */
+sspi_verify_certificate(PCCERT_CONTEXT serverCert,
+ /* I - Server certificate */
+ const CHAR *serverName,
+ /* I - Server name */
+ DWORD dwCertFlags)
+ /* I - Verification flags */
+{
+ HTTPSPolicyCallbackData httpsPolicy;
+ /* HTTPS Policy Struct */
+ CERT_CHAIN_POLICY_PARA policyPara;
+ /* Cert chain policy parameters */
+ CERT_CHAIN_POLICY_STATUS policyStatus;
+ /* Cert chain policy status */
+ CERT_CHAIN_PARA chainPara;
+ /* Used for searching and matching criteria */
+ PCCERT_CHAIN_CONTEXT chainContext = NULL;
+ /* Certificate chain */
+ PWSTR serverNameUnicode = NULL;
+ /* Unicode server name */
+ LPSTR rgszUsages[] = { szOID_PKIX_KP_SERVER_AUTH,
+ szOID_SERVER_GATED_CRYPTO,
+ szOID_SGC_NETSCAPE };
+ /* How are we using this certificate? */
+ DWORD cUsages = sizeof(rgszUsages) / sizeof(LPSTR);
+ /* Number of ites in rgszUsages */
+ DWORD count; /* 32 bit count variable */
+ DWORD status; /* Return value */
+
+ if (!serverCert)
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ /*
+ * Convert server name to unicode.
+ */
+ if (!serverName || (strlen(serverName) == 0))
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, NULL, 0);
+ serverNameUnicode = LocalAlloc(LMEM_FIXED, count * sizeof(WCHAR));
+ if (!serverNameUnicode)
+ {
+ status = SEC_E_INSUFFICIENT_MEMORY;
+ goto cleanup;
+ }
+ count = MultiByteToWideChar(CP_ACP, 0, serverName, -1, serverNameUnicode, count);
+ if (count == 0)
+ {
+ status = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ /*
+ * Build certificate chain.
+ */
+ ZeroMemory(&chainPara, sizeof(chainPara));
+ chainPara.cbSize = sizeof(chainPara);
+ chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ chainPara.RequestedUsage.Usage.cUsageIdentifier = cUsages;
+ chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
+
+ if (!CertGetCertificateChain(NULL, serverCert, NULL, serverCert->hCertStore,
+ &chainPara, 0, NULL, &chainContext))
+ {
+ status = GetLastError();
+ DEBUG_printf(("CertGetCertificateChain returned 0x%x\n", status));
+ goto cleanup;
+ }
+
+ /*
+ * Validate certificate chain.
+ */
+ ZeroMemory(&httpsPolicy, sizeof(HTTPSPolicyCallbackData));
+ httpsPolicy.cbStruct = sizeof(HTTPSPolicyCallbackData);
+ httpsPolicy.dwAuthType = AUTHTYPE_SERVER;
+ httpsPolicy.fdwChecks = dwCertFlags;
+ httpsPolicy.pwszServerName = serverNameUnicode;
+
+ memset(&policyPara, 0, sizeof(policyPara));
+ policyPara.cbSize = sizeof(policyPara);
+ policyPara.pvExtraPolicyPara = &httpsPolicy;
+
+ memset(&policyStatus, 0, sizeof(policyStatus));
+ policyStatus.cbSize = sizeof(policyStatus);
+
+ if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chainContext,
+ &policyPara, &policyStatus))
+ {
+ status = GetLastError();
+ DEBUG_printf(("CertVerifyCertificateChainPolicy returned %d", status));
+ goto cleanup;
+ }
+
+ if (policyStatus.dwError)
+ {
+ status = policyStatus.dwError;
+ goto cleanup;
+ }
+
+ status = SEC_E_OK;
+
+cleanup:
+
+ if (chainContext)
+ CertFreeCertificateChain(chainContext);
+
+ if (serverNameUnicode)
+ LocalFree(serverNameUnicode);
+
+ return (status);
+}
diff --git a/cups/testi18n.c b/cups/testi18n.c
index 76a06cc33..fa5491970 100644
--- a/cups/testi18n.c
+++ b/cups/testi18n.c
@@ -199,16 +199,6 @@ main(int argc, /* I - Argument Count */
}
/*
- * Make sure we have a symbolic link from the data directory to a
- * "charmaps" directory, and then point the library at it...
- */
-
- if (access("charmaps", 0))
- symlink("../data", "charmaps");
-
- putenv("CUPS_DATADIR=.");
-
- /*
* Start with some conversion tests from a UTF-8 test file.
*/
@@ -270,62 +260,6 @@ main(int argc, /* I - Argument Count */
fclose(fp);
/*
- * Test charmap load for ISO-8859-1...
- */
-
- fputs("_cupsCharmapGet(CUPS_ISO8859_1): ", stdout);
-
- if (!_cupsCharmapGet(CUPS_ISO8859_1))
- {
- errors ++;
- puts("FAIL");
- }
- else
- puts("PASS");
-
- /*
- * Test charmap load for Windows-932 (Shift-JIS)...
- */
-
- fputs("_cupsCharmapGet(CUPS_WINDOWS_932): ", stdout);
-
- if (!_cupsCharmapGet(CUPS_WINDOWS_932))
- {
- errors ++;
- puts("FAIL");
- }
- else
- puts("PASS");
-
- /*
- * Test VBCS charmap load for EUC-JP...
- */
-
- fputs("_cupsCharmapGet(CUPS_EUC_JP): ", stdout);
-
- if (!_cupsCharmapGet(CUPS_EUC_JP))
- {
- errors ++;
- puts("FAIL");
- }
- else
- puts("PASS");
-
- /*
- * Test VBCS charmap load for EUC-TW...
- */
-
- fputs("_cupsCharmapGet(CUPS_EUC_TW): ", stdout);
-
- if (!_cupsCharmapGet(CUPS_EUC_TW))
- {
- errors ++;
- puts("FAIL");
- }
- else
- puts("PASS");
-
- /*
* Test UTF-8 to legacy charset (ISO 8859-1)...
*/
diff --git a/cups/testppd.c b/cups/testppd.c
index db3037b67..9fe4d562b 100644
--- a/cups/testppd.c
+++ b/cups/testppd.c
@@ -441,6 +441,20 @@ main(int argc, /* I - Number of command-line arguments */
else
puts("PASS");
+ fputs("cupsMarkOptions(media=A4): ", stdout);
+ num_options = cupsAddOption("media", "A4", 0, &options);
+ cupsMarkOptions(ppd, num_options, options);
+ cupsFreeOptions(num_options, options);
+
+ size = ppdPageSize(ppd, NULL);
+ if (!size || strcmp(size->name, "A4"))
+ {
+ printf("FAIL (%s)\n", size ? size->name : "unknown");
+ status ++;
+ }
+ else
+ puts("PASS");
+
/*
* Test localization...
*/
diff --git a/cups/transcode.c b/cups/transcode.c
index 3a00fcd9a..7b98f2518 100644
--- a/cups/transcode.c
+++ b/cups/transcode.c
@@ -17,23 +17,10 @@
* Contents:
*
* _cupsCharmapFlush() - Flush all character set maps out of cache.
- * _cupsCharmapFree() - Free a character set map.
- * _cupsCharmapGet() - Get a character set map.
* cupsCharsetToUTF8() - Convert legacy character set to UTF-8.
* cupsUTF8ToCharset() - Convert UTF-8 to legacy character set.
* cupsUTF8ToUTF32() - Convert UTF-8 to UTF-32.
* cupsUTF32ToUTF8() - Convert UTF-32 to UTF-8.
- * compare_wide() - Compare key for wide (VBCS) match.
- * conv_sbcs_to_utf8() - Convert legacy SBCS to UTF-8.
- * conv_utf8_to_sbcs() - Convert UTF-8 to legacy SBCS.
- * conv_utf8_to_vbcs() - Convert UTF-8 to legacy DBCS/VBCS.
- * conv_vbcs_to_utf8() - Convert legacy DBCS/VBCS to UTF-8.
- * free_sbcs_charmap() - Free memory used by a single byte character set.
- * free_vbcs_charmap() - Free memory used by a variable byte character set.
- * get_charmap() - Lookup or get a character set map (private).
- * get_charmap_count() - Count lines in a charmap file.
- * get_sbcs_charmap() - Get SBCS Charmap.
- * get_vbcs_charmap() - Get DBCS/VBCS Charmap.
*/
/*
@@ -43,49 +30,25 @@
#include "cups-private.h"
#include <limits.h>
#include <time.h>
+#ifdef HAVE_ICONV_H
+# include <iconv.h>
+#endif /* HAVE_ICONV_H */
/*
* Local globals...
*/
+#ifdef HAVE_ICONV_H
static _cups_mutex_t map_mutex = _CUPS_MUTEX_INITIALIZER;
/* Mutex to control access to maps */
-static _cups_cmap_t *cmap_cache = NULL;
- /* SBCS Charmap Cache */
-static _cups_vmap_t *vmap_cache = NULL;
- /* VBCS Charmap Cache */
-
-
-/*
- * Local functions...
- */
-
-static int compare_wide(const void *k1, const void *k2);
-static int conv_sbcs_to_utf8(cups_utf8_t *dest,
- const cups_sbcs_t *src,
- int maxout,
- const cups_encoding_t encoding);
-static int conv_utf8_to_sbcs(cups_sbcs_t *dest,
- const cups_utf8_t *src,
- int maxout,
- const cups_encoding_t encoding);
-static int conv_utf8_to_vbcs(cups_sbcs_t *dest,
- const cups_utf8_t *src,
- int maxout,
- const cups_encoding_t encoding);
-static int conv_vbcs_to_utf8(cups_utf8_t *dest,
- const cups_sbcs_t *src,
- int maxout,
- const cups_encoding_t encoding);
-static void free_sbcs_charmap(_cups_cmap_t *sbcs);
-static void free_vbcs_charmap(_cups_vmap_t *vbcs);
-static void *get_charmap(const cups_encoding_t encoding);
-static int get_charmap_count(cups_file_t *fp);
-static _cups_cmap_t *get_sbcs_charmap(const cups_encoding_t encoding,
- const char *filename);
-static _cups_vmap_t *get_vbcs_charmap(const cups_encoding_t encoding,
- const char *filename);
+static iconv_t map_from_utf8 = (iconv_t)-1;
+ /* Convert from UTF-8 to charset */
+static iconv_t map_to_utf8 = (iconv_t)-1;
+ /* Convert from charset to UTF-8 */
+static cups_encoding_t map_encoding = CUPS_AUTO_ENCODING;
+ /* Which charset is cached */
+#endif /* HAVE_ICONV_H */
/*
@@ -95,151 +58,39 @@ static _cups_vmap_t *get_vbcs_charmap(const cups_encoding_t encoding,
void
_cupsCharmapFlush(void)
{
- _cups_cmap_t *cmap, /* Legacy SBCS / Unicode Charset Map */
- *cnext; /* Next Legacy SBCS Charset Map */
- _cups_vmap_t *vmap, /* Legacy VBCS / Unicode Charset Map */
- *vnext; /* Next Legacy VBCS Charset Map */
-
-
- _cupsMutexLock(&map_mutex);
-
- /*
- * Loop through SBCS charset map cache, free all memory...
- */
-
- for (cmap = cmap_cache; cmap; cmap = cnext)
+#ifdef HAVE_ICONV_H
+ if (map_from_utf8 != (iconv_t)-1)
{
- cnext = cmap->next;
-
- free_sbcs_charmap(cmap);
+ iconv_close(map_from_utf8);
+ map_from_utf8 = (iconv_t)-1;
}
- cmap_cache = NULL;
-
- /*
- * Loop through DBCS/VBCS charset map cache, free all memory...
- */
-
- for (vmap = vmap_cache; vmap; vmap = vnext)
- {
- vnext = vmap->next;
-
- free_vbcs_charmap(vmap);
- }
-
- vmap_cache = NULL;
-
- _cupsMutexUnlock(&map_mutex);
-}
-
-
-/*
- * '_cupsCharmapFree()' - Free a character set map.
- *
- * This does not actually free; use '_cupsCharmapFlush()' for that.
- */
-
-void
-_cupsCharmapFree(
- const cups_encoding_t encoding) /* I - Encoding */
-{
- _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */
- _cups_vmap_t *vmap; /* Legacy VBCS / Unicode Charset Map */
-
-
- /*
- * See if we already have this SBCS charset map loaded...
- */
-
- _cupsMutexLock(&map_mutex);
-
- for (cmap = cmap_cache; cmap; cmap = cmap->next)
- {
- if (cmap->encoding == encoding)
- {
- if (cmap->used > 0)
- cmap->used --;
- break;
- }
- }
-
- /*
- * See if we already have this DBCS/VBCS charset map loaded...
- */
-
- for (vmap = vmap_cache; vmap; vmap = vmap->next)
- {
- if (vmap->encoding == encoding)
- {
- if (vmap->used > 0)
- vmap->used --;
- break;
- }
- }
-
- _cupsMutexUnlock(&map_mutex);
-}
-
-
-/*
- * '_cupsCharmapGet()' - Get a character set map.
- *
- * This code handles single-byte (SBCS), double-byte (DBCS), and
- * variable-byte (VBCS) character sets _without_ charset escapes...
- * This code does not handle multiple-byte character sets (MBCS)
- * (such as ISO-2022-JP) with charset switching via escapes...
- */
-
-void * /* O - Charset map pointer */
-_cupsCharmapGet(
- const cups_encoding_t encoding) /* I - Encoding */
-{
- void *charmap; /* Charset map pointer */
-
-
- DEBUG_printf(("7_cupsCharmapGet(encoding=%d)", encoding));
-
- /*
- * Check for valid arguments...
- */
-
- if (encoding < 0 || encoding >= CUPS_ENCODING_VBCS_END)
+ if (map_to_utf8 != (iconv_t)-1)
{
- DEBUG_puts("8_cupsCharmapGet: Bad encoding, returning NULL!");
- return (NULL);
+ iconv_close(map_to_utf8);
+ map_to_utf8 = (iconv_t)-1;
}
- /*
- * Lookup or get the charset map pointer and return...
- */
-
- _cupsMutexLock(&map_mutex);
-
- charmap = get_charmap(encoding);
-
- _cupsMutexUnlock(&map_mutex);
-
- return (charmap);
+ map_encoding = CUPS_AUTO_ENCODING;
+#endif /* HAVE_ICONV_H */
}
/*
* 'cupsCharsetToUTF8()' - Convert legacy character set to UTF-8.
- *
- * This code handles single-byte (SBCS), double-byte (DBCS), and
- * variable-byte (VBCS) character sets _without_ charset escapes...
- * This code does not handle multiple-byte character sets (MBCS)
- * (such as ISO-2022-JP) with charset switching via escapes...
*/
int /* O - Count or -1 on error */
cupsCharsetToUTF8(
- cups_utf8_t *dest, /* O - Target string */
- const char *src, /* I - Source string */
- const int maxout, /* I - Max output */
+ cups_utf8_t *dest, /* O - Target string */
+ const char *src, /* I - Source string */
+ const int maxout, /* I - Max output */
const cups_encoding_t encoding) /* I - Encoding */
{
- int bytes; /* Number of bytes converted */
+ cups_utf8_t *destptr; /* Pointer into UTF-8 buffer */
+ int bytes; /* Number of bytes converted */
+ size_t srclen, /* Length of source string */
+ outBytesLeft; /* Bytes remaining in output buffer */
/*
@@ -249,11 +100,11 @@ cupsCharsetToUTF8(
DEBUG_printf(("2cupsCharsetToUTF8(dest=%p, src=\"%s\", maxout=%d, encoding=%d)",
dest, src, maxout, encoding));
- if (dest)
- *dest = '\0';
-
- if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING)
+ if (!dest || !src || maxout < 1)
{
+ if (dest)
+ *dest = '\0';
+
DEBUG_puts("3cupsCharsetToUTF8: Bad arguments, returning -1");
return (-1);
}
@@ -262,8 +113,8 @@ cupsCharsetToUTF8(
* Handle identity conversions...
*/
- if (encoding == CUPS_UTF8 ||
- encoding < 0 || encoding >= CUPS_ENCODING_VBCS_END)
+ if (encoding == CUPS_UTF8 || encoding <= CUPS_US_ASCII ||
+ encoding >= CUPS_ENCODING_VBCS_END)
{
strlcpy((char *)dest, src, maxout);
return ((int)strlen((char *)dest));
@@ -273,14 +124,14 @@ cupsCharsetToUTF8(
* Handle ISO-8859-1 to UTF-8 directly...
*/
+ destptr = dest;
+
if (encoding == CUPS_ISO8859_1)
{
int ch; /* Character from string */
- cups_utf8_t *destptr, /* Pointer into UTF-8 buffer */
- *destend; /* End of UTF-8 buffer */
+ cups_utf8_t *destend; /* End of UTF-8 buffer */
- destptr = dest;
destend = dest + maxout - 2;
while (*src && destptr < destend)
@@ -305,26 +156,46 @@ cupsCharsetToUTF8(
* Convert input legacy charset to UTF-8...
*/
+#ifdef HAVE_ICONV_H
_cupsMutexLock(&map_mutex);
- if (encoding < CUPS_ENCODING_SBCS_END)
- bytes = conv_sbcs_to_utf8(dest, (cups_sbcs_t *)src, maxout, encoding);
- else
- bytes = conv_vbcs_to_utf8(dest, (cups_sbcs_t *)src, maxout, encoding);
+ if (map_encoding != encoding)
+ {
+ _cupsCharmapFlush();
+
+ map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
+ map_to_utf8 = iconv_open("UTF-8", _cupsEncodingName(encoding));
+ map_encoding = encoding;
+ }
+
+ if (map_to_utf8 != (iconv_t)-1)
+ {
+ srclen = strlen(src);
+ outBytesLeft = maxout - 1;
+ bytes = (int)iconv(map_to_utf8, (char **)&src, &srclen,
+ (char **)&destptr, &outBytesLeft);
+ *destptr = '\0';
+
+ _cupsMutexUnlock(&map_mutex);
+
+ return ((int)(destptr - dest));
+ }
_cupsMutexUnlock(&map_mutex);
+#endif /* HAVE_ICONV_H */
- return (bytes);
+ /*
+ * No iconv() support, so error out...
+ */
+
+ *destptr = '\0';
+
+ return (-1);
}
/*
* 'cupsUTF8ToCharset()' - Convert UTF-8 to legacy character set.
- *
- * This code handles single-byte (SBCS), double-byte (DBCS), and
- * variable-byte (VBCS) character sets _without_ charset escapes...
- * This code does not handle multiple-byte character sets (MBCS)
- * (such as ISO-2022-JP) with charset switching via escapes...
*/
int /* O - Count or -1 on error */
@@ -334,14 +205,17 @@ cupsUTF8ToCharset(
const int maxout, /* I - Max output */
const cups_encoding_t encoding) /* I - Encoding */
{
- int bytes; /* Number of bytes converted */
+ char *destptr; /* Pointer into destination */
+ int bytes; /* Number of bytes converted */
+ size_t srclen, /* Length of source string */
+ outBytesLeft; /* Bytes remaining in output buffer */
/*
* Check for valid arguments...
*/
- if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING)
+ if (!dest || !src || maxout < 1)
{
if (dest)
*dest = '\0';
@@ -353,8 +227,8 @@ cupsUTF8ToCharset(
* Handle identity conversions...
*/
- if (encoding == CUPS_UTF8 ||
- encoding < 0 || encoding >= CUPS_ENCODING_VBCS_END)
+ if (encoding == CUPS_UTF8 || encoding <= CUPS_US_ASCII ||
+ encoding >= CUPS_ENCODING_VBCS_END)
{
strlcpy(dest, (char *)src, maxout);
return ((int)strlen(dest));
@@ -364,14 +238,14 @@ cupsUTF8ToCharset(
* Handle UTF-8 to ISO-8859-1 directly...
*/
+ destptr = dest;
+
if (encoding == CUPS_ISO8859_1)
{
int ch; /* Character from string */
- char *destptr, /* Pointer into ISO-8859-1 buffer */
- *destend; /* End of ISO-8859-1 buffer */
+ char *destend; /* End of ISO-8859-1 buffer */
- destptr = dest;
destend = dest + maxout - 1;
while (*src && destptr < destend)
@@ -399,20 +273,45 @@ cupsUTF8ToCharset(
return ((int)(destptr - dest));
}
+#ifdef HAVE_ICONV_H
/*
* Convert input UTF-8 to legacy charset...
*/
_cupsMutexLock(&map_mutex);
- if (encoding < CUPS_ENCODING_SBCS_END)
- bytes = conv_utf8_to_sbcs((cups_sbcs_t *)dest, src, maxout, encoding);
- else
- bytes = conv_utf8_to_vbcs((cups_sbcs_t *)dest, src, maxout, encoding);
+ if (map_encoding != encoding)
+ {
+ _cupsCharmapFlush();
+
+ map_from_utf8 = iconv_open(_cupsEncodingName(encoding), "UTF-8");
+ map_to_utf8 = iconv_open("UTF-8", _cupsEncodingName(encoding));
+ map_encoding = encoding;
+ }
+
+ if (map_from_utf8 != (iconv_t)-1)
+ {
+ srclen = strlen((char *)src);
+ outBytesLeft = maxout - 1;
+ bytes = (int)iconv(map_from_utf8, (char **)&src, &srclen,
+ &destptr, &outBytesLeft);
+ *destptr = '\0';
+
+ _cupsMutexUnlock(&map_mutex);
+
+ return ((int)(destptr - dest));
+ }
_cupsMutexUnlock(&map_mutex);
+#endif /* HAVE_ICONV_H */
+
+ /*
+ * No iconv() support, so error out...
+ */
+
+ *destptr = '\0';
- return (bytes);
+ return (-1);
}