ReactOS  0.4.15-dev-1201-gb2cf5a4
schannel_wine.c
Go to the documentation of this file.
1 /* Copyright (C) 2005 Juan Lang
2  * Copyright 2008 Henri Verbeet
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * This file implements the schannel provider, or, the SSL/TLS implementations.
19  */
20 
21 #include "precomp.h"
22 
23 #include <wine/config.h>
24 
26 
27 #if defined(SONAME_LIBGNUTLS) || defined (HAVE_SECURITY_SECURITY_H) || defined (SONAME_LIBMBEDTLS)
28 
29 #define SCHAN_INVALID_HANDLE ~0UL
30 
31 enum schan_handle_type
32 {
33  SCHAN_HANDLE_CRED,
34  SCHAN_HANDLE_CTX,
35  SCHAN_HANDLE_FREE
36 };
37 
38 struct schan_handle
39 {
40  void *object;
41  enum schan_handle_type type;
42 };
43 
44 struct schan_context
45 {
47  ULONG req_ctx_attr;
48  const CERT_CONTEXT *cert;
49 };
50 
51 static struct schan_handle *schan_handle_table;
52 static struct schan_handle *schan_free_handles;
53 static SIZE_T schan_handle_table_size;
54 static SIZE_T schan_handle_count;
55 
56 /* Protocols enabled, only those may be used for the connection. */
57 static DWORD config_enabled_protocols;
58 
59 /* Protocols disabled by default. They are enabled for using, but disabled when caller asks for default settings. */
60 static DWORD config_default_disabled_protocols;
61 
62 static ULONG_PTR schan_alloc_handle(void *object, enum schan_handle_type type)
63 {
64  struct schan_handle *handle;
65 
66  if (schan_free_handles)
67  {
68  DWORD index = schan_free_handles - schan_handle_table;
69  /* Use a free handle */
70  handle = schan_free_handles;
71  if (handle->type != SCHAN_HANDLE_FREE)
72  {
73  ERR("Handle %d(%p) is in the free list, but has type %#x.\n", index, handle, handle->type);
74  return SCHAN_INVALID_HANDLE;
75  }
76  schan_free_handles = handle->object;
77  handle->object = object;
78  handle->type = type;
79 
80  return index;
81  }
82  if (!(schan_handle_count < schan_handle_table_size))
83  {
84  /* Grow the table */
85  SIZE_T new_size = schan_handle_table_size + (schan_handle_table_size >> 1);
86  struct schan_handle *new_table = HeapReAlloc(GetProcessHeap(), 0, schan_handle_table, new_size * sizeof(*schan_handle_table));
87  if (!new_table)
88  {
89  ERR("Failed to grow the handle table\n");
90  return SCHAN_INVALID_HANDLE;
91  }
92  schan_handle_table = new_table;
93  schan_handle_table_size = new_size;
94  }
95 
96  handle = &schan_handle_table[schan_handle_count++];
97  handle->object = object;
98  handle->type = type;
99 
100  return handle - schan_handle_table;
101 }
102 
103 static void *schan_free_handle(ULONG_PTR handle_idx, enum schan_handle_type type)
104 {
105  struct schan_handle *handle;
106  void *object;
107 
108  if (handle_idx == SCHAN_INVALID_HANDLE) return NULL;
109  if (handle_idx >= schan_handle_count) return NULL;
110  handle = &schan_handle_table[handle_idx];
111  if (handle->type != type)
112  {
113  ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type);
114  return NULL;
115  }
116 
117  object = handle->object;
118  handle->object = schan_free_handles;
119  handle->type = SCHAN_HANDLE_FREE;
120  schan_free_handles = handle;
121 
122  return object;
123 }
124 
125 static void *schan_get_object(ULONG_PTR handle_idx, enum schan_handle_type type)
126 {
127  struct schan_handle *handle;
128 
129  if (handle_idx == SCHAN_INVALID_HANDLE) return NULL;
130  if (handle_idx >= schan_handle_count) return NULL;
131  handle = &schan_handle_table[handle_idx];
132  if (handle->type != type)
133  {
134  ERR("Handle %ld(%p) is not of type %#x\n", handle_idx, handle, type);
135  return NULL;
136  }
137 
138  return handle->object;
139 }
140 
141 static void read_config(void)
142 {
143  DWORD enabled = 0, default_disabled = 0;
144  HKEY protocols_key, key;
145  WCHAR subkey_name[64];
146  unsigned i;
147  DWORD res;
148 
149  static BOOL config_read = FALSE;
150 
151  static const WCHAR protocol_config_key_name[] = {
152  'S','Y','S','T','E','M','\\',
153  'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
154  'C','o','n','t','r','o','l','\\',
155  'S','e','c','u','r','i','t','y','P','r','o','v','i','d','e','r','s','\\',
156  'S','C','H','A','N','N','E','L','\\',
157  'P','r','o','t','o','c','o','l','s',0 };
158 
159  static const WCHAR clientW[] = {'\\','C','l','i','e','n','t',0};
160  static const WCHAR enabledW[] = {'e','n','a','b','l','e','d',0};
161  static const WCHAR disabledbydefaultW[] = {'D','i','s','a','b','l','e','d','B','y','D','e','f','a','u','l','t',0};
162 
163  static const struct {
164  WCHAR key_name[20];
165  DWORD prot_client_flag;
166  BOOL enabled; /* If no config is present, enable the protocol */
167  BOOL disabled_by_default; /* Disable if caller asks for default protocol set */
168  } protocol_config_keys[] = {
169  {{'S','S','L',' ','2','.','0',0}, SP_PROT_SSL2_CLIENT, FALSE, TRUE}, /* NOTE: TRUE, TRUE on Windows */
170  {{'S','S','L',' ','3','.','0',0}, SP_PROT_SSL3_CLIENT, TRUE, FALSE},
171  {{'T','L','S',' ','1','.','0',0}, SP_PROT_TLS1_0_CLIENT, TRUE, FALSE},
172  {{'T','L','S',' ','1','.','1',0}, SP_PROT_TLS1_1_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ },
173  {{'T','L','S',' ','1','.','2',0}, SP_PROT_TLS1_2_CLIENT, TRUE, FALSE /* NOTE: not enabled by default on Windows */ }
174  };
175 
176  /* No need for thread safety */
177  if(config_read)
178  return;
179 
180  res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, protocol_config_key_name, 0, KEY_READ, &protocols_key);
181  if(res == ERROR_SUCCESS) {
182  DWORD type, size, value;
183 
184  for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
185  strcpyW(subkey_name, protocol_config_keys[i].key_name);
186  strcatW(subkey_name, clientW);
187  res = RegOpenKeyExW(protocols_key, subkey_name, 0, KEY_READ, &key);
188  if(res != ERROR_SUCCESS) {
189  if(protocol_config_keys[i].enabled)
190  enabled |= protocol_config_keys[i].prot_client_flag;
191  if(protocol_config_keys[i].disabled_by_default)
192  default_disabled |= protocol_config_keys[i].prot_client_flag;
193  continue;
194  }
195 
196  size = sizeof(value);
197  res = RegQueryValueExW(key, enabledW, NULL, &type, (BYTE*)&value, &size);
198  if(res == ERROR_SUCCESS) {
199  if(type == REG_DWORD && value)
200  enabled |= protocol_config_keys[i].prot_client_flag;
201  }else if(protocol_config_keys[i].enabled) {
202  enabled |= protocol_config_keys[i].prot_client_flag;
203  }
204 
205  size = sizeof(value);
206  res = RegQueryValueExW(key, disabledbydefaultW, NULL, &type, (BYTE*)&value, &size);
207  if(res == ERROR_SUCCESS) {
208  if(type != REG_DWORD || value)
209  default_disabled |= protocol_config_keys[i].prot_client_flag;
210  }else if(protocol_config_keys[i].disabled_by_default) {
211  default_disabled |= protocol_config_keys[i].prot_client_flag;
212  }
213 
214  RegCloseKey(key);
215  }
216  }else {
217  /* No config, enable all known protocols. */
218  for(i=0; i < sizeof(protocol_config_keys)/sizeof(*protocol_config_keys); i++) {
219  if(protocol_config_keys[i].enabled)
220  enabled |= protocol_config_keys[i].prot_client_flag;
221  if(protocol_config_keys[i].disabled_by_default)
222  default_disabled |= protocol_config_keys[i].prot_client_flag;
223  }
224  }
225 
226  RegCloseKey(protocols_key);
227 
228  config_enabled_protocols = enabled & schan_imp_enabled_protocols();
229  config_default_disabled_protocols = default_disabled;
230  config_read = TRUE;
231 
232  TRACE("enabled %x, disabled by default %x\n", config_enabled_protocols, config_default_disabled_protocols);
233 }
234 
235 static SECURITY_STATUS schan_QueryCredentialsAttributes(
236  PCredHandle phCredential, ULONG ulAttribute, VOID *pBuffer)
237 {
238  struct schan_credentials *cred;
240 
241  cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED);
242  if(!cred)
243  return SEC_E_INVALID_HANDLE;
244 
245  switch (ulAttribute)
246  {
248  if (pBuffer)
249  {
250  /* FIXME: get from CryptoAPI */
251  FIXME("SECPKG_ATTR_SUPPORTED_ALGS: stub\n");
253  }
254  else
256  break;
258  if (pBuffer)
259  {
261 
262  /* FIXME: get from CryptoAPI */
263  FIXME("SECPKG_ATTR_CIPHER_STRENGTHS: semi-stub\n");
264  r->dwMinimumCipherStrength = 40;
265  r->dwMaximumCipherStrength = 168;
266  ret = SEC_E_OK;
267  }
268  else
270  break;
272  if(pBuffer) {
273  /* Regardless of MSDN documentation, tests show that this attribute takes into account
274  * what protocols are enabled for given credential. */
275  ((SecPkgCred_SupportedProtocols*)pBuffer)->grbitProtocol = cred->enabled_protocols;
276  ret = SEC_E_OK;
277  }else {
279  }
280  break;
281  default:
283  }
284  return ret;
285 }
286 
287 static SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesA(
288  PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
289 {
291 
292  TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
293 
294  switch (ulAttribute)
295  {
297  FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
299  break;
300  default:
301  ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
302  pBuffer);
303  }
304  return ret;
305 }
306 
307 SECURITY_STATUS SEC_ENTRY schan_QueryCredentialsAttributesW(
308  PCredHandle phCredential, ULONG ulAttribute, PVOID pBuffer)
309 {
311 
312  TRACE("(%p, %d, %p)\n", phCredential, ulAttribute, pBuffer);
313 
314  switch (ulAttribute)
315  {
317  FIXME("SECPKG_CRED_ATTR_NAMES: stub\n");
319  break;
320  default:
321  ret = schan_QueryCredentialsAttributes(phCredential, ulAttribute,
322  pBuffer);
323  }
324  return ret;
325 }
326 
327 static SECURITY_STATUS schan_CheckCreds(const SCHANNEL_CRED *schanCred)
328 {
329  SECURITY_STATUS st;
330  DWORD i;
331 
332  TRACE("dwVersion = %d\n", schanCred->dwVersion);
333  TRACE("cCreds = %d\n", schanCred->cCreds);
334  TRACE("hRootStore = %p\n", schanCred->hRootStore);
335  TRACE("cMappers = %d\n", schanCred->cMappers);
336  TRACE("cSupportedAlgs = %d:\n", schanCred->cSupportedAlgs);
337  for (i = 0; i < schanCred->cSupportedAlgs; i++)
338  TRACE("%08x\n", schanCred->palgSupportedAlgs[i]);
339  TRACE("grbitEnabledProtocols = %08x\n", schanCred->grbitEnabledProtocols);
340  TRACE("dwMinimumCipherStrength = %d\n", schanCred->dwMinimumCipherStrength);
341  TRACE("dwMaximumCipherStrength = %d\n", schanCred->dwMaximumCipherStrength);
342  TRACE("dwSessionLifespan = %d\n", schanCred->dwSessionLifespan);
343  TRACE("dwFlags = %08x\n", schanCred->dwFlags);
344  TRACE("dwCredFormat = %d\n", schanCred->dwCredFormat);
345 
346  switch (schanCred->dwVersion)
347  {
348  case SCH_CRED_V3:
350  break;
351  default:
352  return SEC_E_INTERNAL_ERROR;
353  }
354 
355  if (schanCred->cCreds == 0)
357  else if (schanCred->cCreds > 1)
359  else
360  {
361  DWORD keySpec;
362  HCRYPTPROV csp;
363  BOOL ret, freeCSP;
364 
366  0, /* FIXME: what flags to use? */ NULL,
367  &csp, &keySpec, &freeCSP);
368  if (ret)
369  {
370  st = SEC_E_OK;
371  if (freeCSP)
372  CryptReleaseContext(csp, 0);
373  }
374  else
376  }
377  return st;
378 }
379 
380 static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred,
381  PCredHandle phCredential, PTimeStamp ptsExpiry)
382 {
383  struct schan_credentials *creds;
384  unsigned enabled_protocols;
387 
388  TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
389 
390  if (schanCred)
391  {
392  st = schan_CheckCreds(schanCred);
393  if (st != SEC_E_OK && st != SEC_E_NO_CREDENTIALS)
394  return st;
395 
396  st = SEC_E_OK;
397  }
398 
399  read_config();
400  if(schanCred && schanCred->grbitEnabledProtocols)
401  enabled_protocols = schanCred->grbitEnabledProtocols & config_enabled_protocols;
402  else
403  enabled_protocols = config_enabled_protocols & ~config_default_disabled_protocols;
404  if(!enabled_protocols) {
405  ERR("Could not find matching protocol\n");
407  }
408 
409  /* For now, the only thing I'm interested in is the direction of the
410  * connection, so just store it.
411  */
412  creds = HeapAlloc(GetProcessHeap(), 0, sizeof(*creds));
413  if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
414 
415  handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
416  if (handle == SCHAN_INVALID_HANDLE) goto fail;
417 
420  {
421  schan_free_handle(handle, SCHAN_HANDLE_CRED);
422  goto fail;
423  }
424 
426  phCredential->dwLower = handle;
427  phCredential->dwUpper = 0;
428 
429  /* Outbound credentials have no expiry */
430  if (ptsExpiry)
431  {
432  ptsExpiry->LowPart = 0;
433  ptsExpiry->HighPart = 0;
434  }
435 
436  return st;
437 
438 fail:
439  HeapFree(GetProcessHeap(), 0, creds);
440  return SEC_E_INTERNAL_ERROR;
441 }
442 
443 static SECURITY_STATUS schan_AcquireServerCredentials(const SCHANNEL_CRED *schanCred,
444  PCredHandle phCredential, PTimeStamp ptsExpiry)
445 {
446  SECURITY_STATUS st;
447 
448  TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
449 
450  if (!schanCred) return SEC_E_NO_CREDENTIALS;
451 
452  st = schan_CheckCreds(schanCred);
453  if (st == SEC_E_OK)
454  {
456  struct schan_credentials *creds;
457 
458  creds = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*creds));
459  if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
461 
462  handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
463  if (handle == SCHAN_INVALID_HANDLE)
464  {
465  HeapFree(GetProcessHeap(), 0, creds);
466  return SEC_E_INTERNAL_ERROR;
467  }
468 
469  phCredential->dwLower = handle;
470  phCredential->dwUpper = 0;
471 
472  /* FIXME: get expiry from cert */
473  }
474  return st;
475 }
476 
477 static SECURITY_STATUS schan_AcquireCredentialsHandle(ULONG fCredentialUse,
478  const SCHANNEL_CRED *schanCred, PCredHandle phCredential, PTimeStamp ptsExpiry)
479 {
481 
482  if (fCredentialUse == SECPKG_CRED_OUTBOUND)
483  ret = schan_AcquireClientCredentials(schanCred, phCredential,
484  ptsExpiry);
485  else
486  ret = schan_AcquireServerCredentials(schanCred, phCredential,
487  ptsExpiry);
488  return ret;
489 }
490 
491 SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleA(
492  SEC_CHAR *pszPrincipal, SEC_CHAR *pszPackage, ULONG fCredentialUse,
493  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
494  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
495 {
496  TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
497  debugstr_a(pszPrincipal), debugstr_a(pszPackage), fCredentialUse,
498  pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
499  return schan_AcquireCredentialsHandle(fCredentialUse,
500  pAuthData, phCredential, ptsExpiry);
501 }
502 
503 SECURITY_STATUS SEC_ENTRY schan_AcquireCredentialsHandleW(
504  SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse,
505  PLUID pLogonID, PVOID pAuthData, SEC_GET_KEY_FN pGetKeyFn,
506  PVOID pGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
507 {
508  TRACE("(%s, %s, 0x%08x, %p, %p, %p, %p, %p, %p)\n",
509  debugstr_w(pszPrincipal), debugstr_w(pszPackage), fCredentialUse,
510  pLogonID, pAuthData, pGetKeyFn, pGetKeyArgument, phCredential, ptsExpiry);
511  return schan_AcquireCredentialsHandle(fCredentialUse,
512  pAuthData, phCredential, ptsExpiry);
513 }
514 
515 SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle(
516  PCredHandle phCredential)
517 {
518  struct schan_credentials *creds;
519 
520  TRACE("phCredential %p\n", phCredential);
521 
522  if (!phCredential) return SEC_E_INVALID_HANDLE;
523 
524  creds = schan_free_handle(phCredential->dwLower, SCHAN_HANDLE_CRED);
525  if (!creds) return SEC_E_INVALID_HANDLE;
526 
527  if (creds->credential_use == SECPKG_CRED_OUTBOUND)
529  HeapFree(GetProcessHeap(), 0, creds);
530 
531  return SEC_E_OK;
532 }
533 
534 static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc desc,
535  int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *))
536 {
537  s->offset = 0;
538  s->limit = ~0UL;
539  s->desc = desc;
540  s->current_buffer_idx = -1;
541  s->allow_buffer_resize = FALSE;
542  s->get_next_buffer = get_next_buffer;
543 }
544 
545 static int schan_find_sec_buffer_idx(const SecBufferDesc *desc, unsigned int start_idx, ULONG buffer_type)
546 {
547  unsigned int i;
549 
550  for (i = start_idx; i < desc->cBuffers; ++i)
551  {
552  buffer = &desc->pBuffers[i];
553  if (buffer->BufferType == buffer_type) return i;
554  }
555 
556  return -1;
557 }
558 
559 static void schan_resize_current_buffer(const struct schan_buffers *s, SIZE_T min_size)
560 {
561  SecBuffer *b = &s->desc->pBuffers[s->current_buffer_idx];
562  SIZE_T new_size = b->cbBuffer ? b->cbBuffer * 2 : 128;
563  void *new_data;
564 
565  if (b->cbBuffer >= min_size || !s->allow_buffer_resize || min_size > UINT_MAX / 2) return;
566 
567  while (new_size < min_size) new_size *= 2;
568 
569  if (b->pvBuffer)
570  new_data = HeapReAlloc(GetProcessHeap(), 0, b->pvBuffer, new_size);
571  else
572  new_data = HeapAlloc(GetProcessHeap(), 0, new_size);
573 
574  if (!new_data)
575  {
576  TRACE("Failed to resize %p from %d to %ld\n", b->pvBuffer, b->cbBuffer, new_size);
577  return;
578  }
579 
580  b->cbBuffer = new_size;
581  b->pvBuffer = new_data;
582 }
583 
584 char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
585 {
586  SIZE_T max_count;
588 
589  if (!s->desc)
590  {
591  TRACE("No desc\n");
592  return NULL;
593  }
594 
595  if (s->current_buffer_idx == -1)
596  {
597  /* Initial buffer */
598  int buffer_idx = s->get_next_buffer(t, s);
599  if (buffer_idx == -1)
600  {
601  TRACE("No next buffer\n");
602  return NULL;
603  }
604  s->current_buffer_idx = buffer_idx;
605  }
606 
607  buffer = &s->desc->pBuffers[s->current_buffer_idx];
608  TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s->current_buffer_idx, buffer->cbBuffer, buffer->BufferType, buffer->pvBuffer);
609 
610  schan_resize_current_buffer(s, s->offset + *count);
611  max_count = buffer->cbBuffer - s->offset;
612  if (s->limit != ~0UL && s->limit < max_count)
613  max_count = s->limit;
614  if (!max_count)
615  {
616  int buffer_idx;
617 
618  s->allow_buffer_resize = FALSE;
619  buffer_idx = s->get_next_buffer(t, s);
620  if (buffer_idx == -1)
621  {
622  TRACE("No next buffer\n");
623  return NULL;
624  }
625  s->current_buffer_idx = buffer_idx;
626  s->offset = 0;
627  return schan_get_buffer(t, s, count);
628  }
629 
630  if (*count > max_count)
631  *count = max_count;
632  if (s->limit != ~0UL)
633  s->limit -= *count;
634 
635  return (char *)buffer->pvBuffer + s->offset;
636 }
637 
638 /* schan_pull
639  * Read data from the transport input buffer.
640  *
641  * t - The session transport object.
642  * buff - The buffer into which to store the read data. Must be at least
643  * *buff_len bytes in length.
644  * buff_len - On input, *buff_len is the desired length to read. On successful
645  * return, *buff_len is the number of bytes actually read.
646  *
647  * Returns:
648  * 0 on success, in which case:
649  * *buff_len == 0 indicates end of file.
650  * *buff_len > 0 indicates that some data was read. May be less than
651  * what was requested, in which case the caller should call again if/
652  * when they want more.
653  * EAGAIN when no data could be read without blocking
654  * another errno-style error value on failure
655  *
656  */
657 int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len)
658 {
659  char *b;
660  SIZE_T local_len = *buff_len;
661 
662  TRACE("Pull %lu bytes\n", local_len);
663 
664  *buff_len = 0;
665 
666  b = schan_get_buffer(t, &t->in, &local_len);
667  if (!b)
668  return EAGAIN;
669 
670  memcpy(buff, b, local_len);
671  t->in.offset += local_len;
672 
673  TRACE("Read %lu bytes\n", local_len);
674 
675  *buff_len = local_len;
676  return 0;
677 }
678 
679 /* schan_push
680  * Write data to the transport output buffer.
681  *
682  * t - The session transport object.
683  * buff - The buffer of data to write. Must be at least *buff_len bytes in length.
684  * buff_len - On input, *buff_len is the desired length to write. On successful
685  * return, *buff_len is the number of bytes actually written.
686  *
687  * Returns:
688  * 0 on success
689  * *buff_len will be > 0 indicating how much data was written. May be less
690  * than what was requested, in which case the caller should call again
691  if/when they want to write more.
692  * EAGAIN when no data could be written without blocking
693  * another errno-style error value on failure
694  *
695  */
696 int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len)
697 {
698  char *b;
699  SIZE_T local_len = *buff_len;
700 
701  TRACE("Push %lu bytes\n", local_len);
702 
703  *buff_len = 0;
704 
705  b = schan_get_buffer(t, &t->out, &local_len);
706  if (!b)
707  return EAGAIN;
708 
709  memcpy(b, buff, local_len);
710  t->out.offset += local_len;
711 
712  TRACE("Wrote %lu bytes\n", local_len);
713 
714  *buff_len = local_len;
715  return 0;
716 }
717 
719 {
720  return t->ctx->session;
721 }
722 
723 static int schan_init_sec_ctx_get_next_input_buffer(const struct schan_transport *t, struct schan_buffers *s)
724 {
725  if (s->current_buffer_idx != -1)
726  return -1;
727  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
728 }
729 
730 static int schan_init_sec_ctx_get_next_output_buffer(const struct schan_transport *t, struct schan_buffers *s)
731 {
732  if (s->current_buffer_idx == -1)
733  {
734  int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
735  if (t->ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY)
736  {
737  if (idx == -1)
738  {
739  idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_EMPTY);
740  if (idx != -1) s->desc->pBuffers[idx].BufferType = SECBUFFER_TOKEN;
741  }
742  if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer)
743  {
744  s->desc->pBuffers[idx].cbBuffer = 0;
745  s->allow_buffer_resize = TRUE;
746  }
747  }
748  return idx;
749  }
750 
751  return -1;
752 }
753 
754 static void dump_buffer_desc(SecBufferDesc *desc)
755 {
756  unsigned int i;
757 
758  if (!desc) return;
759  TRACE("Buffer desc %p:\n", desc);
760  for (i = 0; i < desc->cBuffers; ++i)
761  {
762  SecBuffer *b = &desc->pBuffers[i];
763  TRACE("\tbuffer %u: cbBuffer %d, BufferType %#x pvBuffer %p\n", i, b->cbBuffer, b->BufferType, b->pvBuffer);
764  }
765 }
766 
767 /***********************************************************************
768  * InitializeSecurityContextW
769  */
770 SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
771  PCredHandle phCredential, PCtxtHandle phContext, SEC_WCHAR *pszTargetName,
772  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
773  PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
774  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
775 {
776  struct schan_context *ctx;
777  struct schan_buffers *out_buffers;
778  struct schan_credentials *cred;
779  struct schan_transport transport;
780  SIZE_T expected_size = ~0UL;
782 
783  TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
784  debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
785  Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
786 
787  dump_buffer_desc(pInput);
788  dump_buffer_desc(pOutput);
789 
790  if (!phContext)
791  {
793 
794  if (!phCredential) return SEC_E_INVALID_HANDLE;
795 
796  cred = schan_get_object(phCredential->dwLower, SCHAN_HANDLE_CRED);
797  if (!cred) return SEC_E_INVALID_HANDLE;
798 
799  if (!(cred->credential_use & SECPKG_CRED_OUTBOUND))
800  {
801  WARN("Invalid credential use %#x\n", cred->credential_use);
802  return SEC_E_INVALID_HANDLE;
803  }
804 
805  ctx = HeapAlloc(GetProcessHeap(), 0, sizeof(*ctx));
806  if (!ctx) return SEC_E_INSUFFICIENT_MEMORY;
807 
808  ctx->cert = NULL;
809  handle = schan_alloc_handle(ctx, SCHAN_HANDLE_CTX);
810  if (handle == SCHAN_INVALID_HANDLE)
811  {
812  HeapFree(GetProcessHeap(), 0, ctx);
813  return SEC_E_INTERNAL_ERROR;
814  }
815 
816  if (!schan_imp_create_session(&ctx->session, cred))
817  {
818  schan_free_handle(handle, SCHAN_HANDLE_CTX);
819  HeapFree(GetProcessHeap(), 0, ctx);
820  return SEC_E_INTERNAL_ERROR;
821  }
822 
823  if (pszTargetName)
824  {
825  UINT len = WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, NULL, 0, NULL, NULL );
826  char *target = HeapAlloc( GetProcessHeap(), 0, len );
827 
828  if (target)
829  {
830  WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL );
832  HeapFree( GetProcessHeap(), 0, target );
833  }
834  }
835  phNewContext->dwLower = handle;
836  phNewContext->dwUpper = 0;
837  }
838  else
839  {
840  SIZE_T record_size = 0;
841  unsigned char *ptr;
842  SecBuffer *buffer;
843  int idx;
844 
845  if (!pInput)
847 
848  idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN);
849  if (idx == -1)
851 
852  buffer = &pInput->pBuffers[idx];
853  ptr = buffer->pvBuffer;
854  expected_size = 0;
855 
856  while (buffer->cbBuffer > expected_size + 5)
857  {
858  record_size = 5 + ((ptr[3] << 8) | ptr[4]);
859 
860  if (buffer->cbBuffer < expected_size + record_size)
861  break;
862 
863  expected_size += record_size;
864  ptr += record_size;
865  }
866 
867  if (!expected_size)
868  {
869  TRACE("Expected at least %lu bytes, but buffer only contains %u bytes.\n",
870  max(6, record_size), buffer->cbBuffer);
872  }
873 
874  TRACE("Using expected_size %lu.\n", expected_size);
875 
876  ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX);
877  }
878 
879  ctx->req_ctx_attr = fContextReq;
880 
881  transport.ctx = ctx;
882  init_schan_buffers(&transport.in, pInput, schan_init_sec_ctx_get_next_input_buffer);
883  transport.in.limit = expected_size;
884  init_schan_buffers(&transport.out, pOutput, schan_init_sec_ctx_get_next_output_buffer);
885  schan_imp_set_session_transport(ctx->session, &transport);
886 
887  /* Perform the TLS handshake */
888  ret = schan_imp_handshake(ctx->session);
889 
890  if(transport.in.offset && transport.in.offset != pInput->pBuffers[0].cbBuffer) {
891  if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY)
892  return SEC_E_INVALID_TOKEN;
893 
894  pInput->pBuffers[1].BufferType = SECBUFFER_EXTRA;
895  pInput->pBuffers[1].cbBuffer = pInput->pBuffers[0].cbBuffer-transport.in.offset;
896  }
897 
898  out_buffers = &transport.out;
899  if (out_buffers->current_buffer_idx != -1)
900  {
901  SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx];
902  buffer->cbBuffer = out_buffers->offset;
903  }
904 
905  *pfContextAttr = 0;
906  if (ctx->req_ctx_attr & ISC_REQ_ALLOCATE_MEMORY)
907  *pfContextAttr |= ISC_RET_ALLOCATED_MEMORY;
908 
909  return ret;
910 }
911 
912 /***********************************************************************
913  * InitializeSecurityContextA
914  */
915 SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextA(
916  PCredHandle phCredential, PCtxtHandle phContext, SEC_CHAR *pszTargetName,
917  ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
918  PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
919  PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
920 {
922  SEC_WCHAR *target_name = NULL;
923 
924  TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
925  debugstr_a(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
926  Reserved1, phNewContext, pOutput, pfContextAttr, ptsExpiry);
927 
928  if (pszTargetName)
929  {
930  INT len = MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, NULL, 0);
931  target_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(*target_name));
932  MultiByteToWideChar(CP_ACP, 0, pszTargetName, -1, target_name, len);
933  }
934 
935  ret = schan_InitializeSecurityContextW(phCredential, phContext, target_name,
936  fContextReq, Reserved1, TargetDataRep, pInput, Reserved2,
937  phNewContext, pOutput, pfContextAttr, ptsExpiry);
938 
939  HeapFree(GetProcessHeap(), 0, target_name);
940 
941  return ret;
942 }
943 
944 static
945 SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
946  PCtxtHandle context_handle, ULONG attribute, PVOID buffer)
947 {
948  struct schan_context *ctx;
949 
950  TRACE("context_handle %p, attribute %#x, buffer %p\n",
951  context_handle, attribute, buffer);
952 
953  if (!context_handle) return SEC_E_INVALID_HANDLE;
954  ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
955 
956  switch(attribute)
957  {
959  {
962  if (status == SEC_E_OK)
963  {
964  SecPkgContext_StreamSizes *stream_sizes = buffer;
965  SIZE_T mac_size = info.dwHashStrength;
966  unsigned int block_size = schan_imp_get_session_cipher_block_size(ctx->session);
967  unsigned int message_size = schan_imp_get_max_message_size(ctx->session);
968 
969  TRACE("Using %lu mac bytes, message size %u, block size %u\n",
970  mac_size, message_size, block_size);
971 
972  /* These are defined by the TLS RFC */
973  stream_sizes->cbHeader = 5;
974  stream_sizes->cbTrailer = mac_size + 256; /* Max 255 bytes padding + 1 for padding size */
975  stream_sizes->cbMaximumMessage = message_size;
976  stream_sizes->cbBuffers = 4;
977  stream_sizes->cbBlockSize = block_size;
978  }
979 
980  return status;
981  }
983  {
985 
986  if (!ctx->cert) {
989 
991  if(!cert_store)
992  return GetLastError();
993 
996  if(status != SEC_E_OK)
997  return status;
998  }
999 
1001  return SEC_E_OK;
1002  }
1004  {
1006  return schan_imp_get_connection_info(ctx->session, info);
1007  }
1008 
1009  default:
1010  FIXME("Unhandled attribute %#x\n", attribute);
1012  }
1013 }
1014 
1015 static
1016 SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesA(
1017  PCtxtHandle context_handle, ULONG attribute, PVOID buffer)
1018 {
1019  TRACE("context_handle %p, attribute %#x, buffer %p\n",
1020  context_handle, attribute, buffer);
1021 
1022  switch(attribute)
1023  {
1025  return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1027  return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1029  return schan_QueryContextAttributesW(context_handle, attribute, buffer);
1030 
1031  default:
1032  FIXME("Unhandled attribute %#x\n", attribute);
1034  }
1035 }
1036 
1037 static int schan_encrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s)
1038 {
1039  SecBuffer *b;
1040 
1041  if (s->current_buffer_idx == -1)
1042  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_HEADER);
1043 
1044  b = &s->desc->pBuffers[s->current_buffer_idx];
1045 
1046  if (b->BufferType == SECBUFFER_STREAM_HEADER)
1047  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1048 
1049  if (b->BufferType == SECBUFFER_DATA)
1050  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_STREAM_TRAILER);
1051 
1052  return -1;
1053 }
1054 
1055 static int schan_encrypt_message_get_next_buffer_token(const struct schan_transport *t, struct schan_buffers *s)
1056 {
1057  SecBuffer *b;
1058 
1059  if (s->current_buffer_idx == -1)
1060  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1061 
1062  b = &s->desc->pBuffers[s->current_buffer_idx];
1063 
1064  if (b->BufferType == SECBUFFER_TOKEN)
1065  {
1066  int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1067  if (idx != s->current_buffer_idx) return -1;
1068  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1069  }
1070 
1071  if (b->BufferType == SECBUFFER_DATA)
1072  {
1073  int idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_TOKEN);
1074  if (idx != -1)
1075  idx = schan_find_sec_buffer_idx(s->desc, idx + 1, SECBUFFER_TOKEN);
1076  return idx;
1077  }
1078 
1079  return -1;
1080 }
1081 
1082 static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle,
1083  ULONG quality, PSecBufferDesc message, ULONG message_seq_no)
1084 {
1085  struct schan_transport transport;
1086  struct schan_context *ctx;
1087  struct schan_buffers *b;
1089  SecBuffer *buffer;
1090  SIZE_T data_size;
1091  SIZE_T length;
1092  char *data;
1093  int idx;
1094 
1095  TRACE("context_handle %p, quality %d, message %p, message_seq_no %d\n",
1096  context_handle, quality, message, message_seq_no);
1097 
1098  if (!context_handle) return SEC_E_INVALID_HANDLE;
1099  ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
1100 
1101  dump_buffer_desc(message);
1102 
1103  idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_DATA);
1104  if (idx == -1)
1105  {
1106  WARN("No data buffer passed\n");
1107  return SEC_E_INTERNAL_ERROR;
1108  }
1109  buffer = &message->pBuffers[idx];
1110 
1111  data_size = buffer->cbBuffer;
1112  data = HeapAlloc(GetProcessHeap(), 0, data_size);
1113  memcpy(data, buffer->pvBuffer, data_size);
1114 
1115  transport.ctx = ctx;
1116  init_schan_buffers(&transport.in, NULL, NULL);
1117  if (schan_find_sec_buffer_idx(message, 0, SECBUFFER_STREAM_HEADER) != -1)
1118  init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer);
1119  else
1120  init_schan_buffers(&transport.out, message, schan_encrypt_message_get_next_buffer_token);
1121  schan_imp_set_session_transport(ctx->session, &transport);
1122 
1123  length = data_size;
1124  status = schan_imp_send(ctx->session, data, &length);
1125 
1126  TRACE("Sent %ld bytes.\n", length);
1127 
1128  if (length != data_size)
1130 
1131  b = &transport.out;
1132  b->desc->pBuffers[b->current_buffer_idx].cbBuffer = b->offset;
1133  HeapFree(GetProcessHeap(), 0, data);
1134 
1135  TRACE("Returning %#x.\n", status);
1136 
1137  return status;
1138 }
1139 
1140 static int schan_decrypt_message_get_next_buffer(const struct schan_transport *t, struct schan_buffers *s)
1141 {
1142  if (s->current_buffer_idx == -1)
1143  return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
1144 
1145  return -1;
1146 }
1147 
1148 static int schan_validate_decrypt_buffer_desc(PSecBufferDesc message)
1149 {
1150  int data_idx = -1;
1151  unsigned int empty_count = 0;
1152  unsigned int i;
1153 
1154  if (message->cBuffers < 4)
1155  {
1156  WARN("Less than four buffers passed\n");
1157  return -1;
1158  }
1159 
1160  for (i = 0; i < message->cBuffers; ++i)
1161  {
1162  SecBuffer *b = &message->pBuffers[i];
1163  if (b->BufferType == SECBUFFER_DATA)
1164  {
1165  if (data_idx != -1)
1166  {
1167  WARN("More than one data buffer passed\n");
1168  return -1;
1169  }
1170  data_idx = i;
1171  }
1172  else if (b->BufferType == SECBUFFER_EMPTY)
1173  ++empty_count;
1174  }
1175 
1176  if (data_idx == -1)
1177  {
1178  WARN("No data buffer passed\n");
1179  return -1;
1180  }
1181 
1182  if (empty_count < 3)
1183  {
1184  WARN("Less than three empty buffers passed\n");
1185  return -1;
1186  }
1187 
1188  return data_idx;
1189 }
1190 
1191 static void schan_decrypt_fill_buffer(PSecBufferDesc message, ULONG buffer_type, void *data, ULONG size)
1192 {
1193  int idx;
1194  SecBuffer *buffer;
1195 
1196  idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY);
1197  buffer = &message->pBuffers[idx];
1198 
1199  buffer->BufferType = buffer_type;
1200  buffer->pvBuffer = data;
1201  buffer->cbBuffer = size;
1202 }
1203 
1204 static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle,
1205  PSecBufferDesc message, ULONG message_seq_no, PULONG quality)
1206 {
1207  struct schan_transport transport;
1208  struct schan_context *ctx;
1209  SecBuffer *buffer;
1210  SIZE_T data_size;
1211  char *data;
1212  unsigned expected_size;
1213  SSIZE_T received = 0;
1214  int idx;
1215  unsigned char *buf_ptr;
1216 
1217  TRACE("context_handle %p, message %p, message_seq_no %d, quality %p\n",
1218  context_handle, message, message_seq_no, quality);
1219 
1220  if (!context_handle) return SEC_E_INVALID_HANDLE;
1221  ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
1222 
1223  dump_buffer_desc(message);
1224 
1225  idx = schan_validate_decrypt_buffer_desc(message);
1226  if (idx == -1)
1227  return SEC_E_INVALID_TOKEN;
1228  buffer = &message->pBuffers[idx];
1229  buf_ptr = buffer->pvBuffer;
1230 
1231  expected_size = 5 + ((buf_ptr[3] << 8) | buf_ptr[4]);
1232  if(buffer->cbBuffer < expected_size)
1233  {
1234  TRACE("Expected %u bytes, but buffer only contains %u bytes\n", expected_size, buffer->cbBuffer);
1235  buffer->BufferType = SECBUFFER_MISSING;
1236  buffer->cbBuffer = expected_size - buffer->cbBuffer;
1237 
1238  /* This is a bit weird, but windows does it too */
1239  idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY);
1240  buffer = &message->pBuffers[idx];
1241  buffer->BufferType = SECBUFFER_MISSING;
1242  buffer->cbBuffer = expected_size - buffer->cbBuffer;
1243 
1244  TRACE("Returning SEC_E_INCOMPLETE_MESSAGE\n");
1245  return SEC_E_INCOMPLETE_MESSAGE;
1246  }
1247 
1248  data_size = expected_size - 5;
1249  data = HeapAlloc(GetProcessHeap(), 0, data_size);
1250 
1251  transport.ctx = ctx;
1252  init_schan_buffers(&transport.in, message, schan_decrypt_message_get_next_buffer);
1253  transport.in.limit = expected_size;
1254  init_schan_buffers(&transport.out, NULL, NULL);
1255  schan_imp_set_session_transport(ctx->session, &transport);
1256 
1257  while (received < data_size)
1258  {
1259  SIZE_T length = data_size - received;
1261 
1263  break;
1264 
1265  if (status != SEC_E_OK)
1266  {
1267  HeapFree(GetProcessHeap(), 0, data);
1268  ERR("Returning %x\n", status);
1269  return status;
1270  }
1271 
1272  if (!length)
1273  break;
1274 
1275  received += length;
1276  }
1277 
1278  TRACE("Received %ld bytes\n", received);
1279 
1280  memcpy(buf_ptr + 5, data, received);
1281  HeapFree(GetProcessHeap(), 0, data);
1282 
1283  schan_decrypt_fill_buffer(message, SECBUFFER_DATA,
1284  buf_ptr + 5, received);
1285 
1286  schan_decrypt_fill_buffer(message, SECBUFFER_STREAM_TRAILER,
1287  buf_ptr + 5 + received, buffer->cbBuffer - 5 - received);
1288 
1289  if(buffer->cbBuffer > expected_size)
1290  schan_decrypt_fill_buffer(message, SECBUFFER_EXTRA,
1291  buf_ptr + expected_size, buffer->cbBuffer - expected_size);
1292 
1293  buffer->BufferType = SECBUFFER_STREAM_HEADER;
1294  buffer->cbBuffer = 5;
1295 
1296  return SEC_E_OK;
1297 }
1298 
1299 SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context_handle)
1300 {
1301  struct schan_context *ctx;
1302 
1303  TRACE("context_handle %p\n", context_handle);
1304 
1305  if (!context_handle) return SEC_E_INVALID_HANDLE;
1306 
1307  ctx = schan_free_handle(context_handle->dwLower, SCHAN_HANDLE_CTX);
1308  if (!ctx) return SEC_E_INVALID_HANDLE;
1309 
1310  if (ctx->cert)
1312  schan_imp_dispose_session(ctx->session);
1313  HeapFree(GetProcessHeap(), 0, ctx);
1314 
1315  return SEC_E_OK;
1316 }
1317 
1319  1,
1321  schan_QueryCredentialsAttributesA,
1322  schan_AcquireCredentialsHandleA,
1323  schan_FreeCredentialsHandle,
1324  NULL, /* Reserved2 */
1325  schan_InitializeSecurityContextA,
1326  NULL, /* AcceptSecurityContext */
1327  NULL, /* CompleteAuthToken */
1328  schan_DeleteSecurityContext,
1329  NULL, /* ApplyControlToken */
1330  schan_QueryContextAttributesA,
1331  NULL, /* ImpersonateSecurityContext */
1332  NULL, /* RevertSecurityContext */
1333  NULL, /* MakeSignature */
1334  NULL, /* VerifySignature */
1336  NULL, /* QuerySecurityPackageInfoA */
1337  NULL, /* Reserved3 */
1338  NULL, /* Reserved4 */
1339  NULL, /* ExportSecurityContext */
1340  NULL, /* ImportSecurityContextA */
1341  NULL, /* AddCredentialsA */
1342  NULL, /* Reserved8 */
1343  NULL, /* QuerySecurityContextToken */
1344  schan_EncryptMessage,
1345  schan_DecryptMessage,
1346  NULL, /* SetContextAttributesA */
1347 };
1348 
1350  1,
1352  schan_QueryCredentialsAttributesW,
1353  schan_AcquireCredentialsHandleW,
1354  schan_FreeCredentialsHandle,
1355  NULL, /* Reserved2 */
1356  schan_InitializeSecurityContextW,
1357  NULL, /* AcceptSecurityContext */
1358  NULL, /* CompleteAuthToken */
1359  schan_DeleteSecurityContext,
1360  NULL, /* ApplyControlToken */
1361  schan_QueryContextAttributesW,
1362  NULL, /* ImpersonateSecurityContext */
1363  NULL, /* RevertSecurityContext */
1364  NULL, /* MakeSignature */
1365  NULL, /* VerifySignature */
1367  NULL, /* QuerySecurityPackageInfoW */
1368  NULL, /* Reserved3 */
1369  NULL, /* Reserved4 */
1370  NULL, /* ExportSecurityContext */
1371  NULL, /* ImportSecurityContextW */
1372  NULL, /* AddCredentialsW */
1373  NULL, /* Reserved8 */
1374  NULL, /* QuerySecurityContextToken */
1375  schan_EncryptMessage,
1376  schan_DecryptMessage,
1377  NULL, /* SetContextAttributesW */
1378 };
1379 
1380 static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ',
1381  'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
1382 static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
1383 
1384 void SECUR32_initSchannelSP(void)
1385 {
1386  /* This is what Windows reports. This shouldn't break any applications
1387  * even though the functions are missing, because the wrapper will
1388  * return SEC_E_UNSUPPORTED_FUNCTION if our function is NULL.
1389  */
1390  static const LONG caps =
1399  static const short version = 1;
1400  static const LONG maxToken = 16384;
1401  SEC_WCHAR *uniSPName = (SEC_WCHAR *)UNISP_NAME_W,
1402  *schannel = (SEC_WCHAR *)SCHANNEL_NAME_W;
1403  const SecPkgInfoW info[] = {
1404  { caps, version, UNISP_RPC_ID, maxToken, uniSPName, uniSPName },
1405  { caps, version, UNISP_RPC_ID, maxToken, schannel,
1406  (SEC_WCHAR *)schannelComment },
1407  };
1408  SecureProvider *provider;
1409 
1410  if (!schan_imp_init())
1411  return;
1412 
1413  schan_handle_table = HeapAlloc(GetProcessHeap(), 0, 64 * sizeof(*schan_handle_table));
1414  if (!schan_handle_table)
1415  {
1416  ERR("Failed to allocate schannel handle table.\n");
1417  goto fail;
1418  }
1419  schan_handle_table_size = 64;
1420 
1421  provider = SECUR32_addProvider(&schanTableA, &schanTableW, schannelDllName);
1422  if (!provider)
1423  {
1424  ERR("Failed to add schannel provider.\n");
1425  goto fail;
1426  }
1427 
1428  SECUR32_addPackages(provider, sizeof(info) / sizeof(info[0]), NULL, info);
1429 
1430  return;
1431 
1432 fail:
1433  HeapFree(GetProcessHeap(), 0, schan_handle_table);
1434  schan_handle_table = NULL;
1435  schan_imp_deinit();
1436  return;
1437 }
1438 
1439 void SECUR32_deinitSchannelSP(void)
1440 {
1441  SIZE_T i = schan_handle_count;
1442 
1443  if (!schan_handle_table) return;
1444 
1445  /* deinitialized sessions first because a pointer to the credentials
1446  * may be stored for the session. */
1447  while (i--)
1448  {
1449  if (schan_handle_table[i].type == SCHAN_HANDLE_CTX)
1450  {
1451  struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX);
1452  schan_imp_dispose_session(ctx->session);
1453  HeapFree(GetProcessHeap(), 0, ctx);
1454  }
1455  }
1456  i = schan_handle_count;
1457  while (i--)
1458  {
1459  if (schan_handle_table[i].type != SCHAN_HANDLE_FREE)
1460  {
1461  struct schan_credentials *cred;
1462  cred = schan_free_handle(i, SCHAN_HANDLE_CRED);
1464  HeapFree(GetProcessHeap(), 0, cred);
1465  }
1466  }
1467  HeapFree(GetProcessHeap(), 0, schan_handle_table);
1468  schan_imp_deinit();
1469 }
1470 
1471 #else /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */
1472 
1474 {
1475  ERR("TLS library not found, SSL connections will fail\n");
1476 }
1477 
1479 
1480 #endif /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H || SONAME_LIBMBEDTLS */
#define SEC_E_INTERNAL_ERROR
Definition: winerror.h:2913
#define SCH_CRED_V3
Definition: schannel.h:21
unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) DECLSPEC_HIDDEN
#define SP_PROT_SSL3_CLIENT
Definition: schannel.h:30
#define SECPKG_ATTR_SUPPORTED_PROTOCOLS
Definition: schannel.h:74
void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd, const SecPkgInfoA *infoA, const SecPkgInfoW *infoW) DECLSPEC_HIDDEN
Definition: secur32_wine.c:362
#define max(a, b)
Definition: svc.c:63
Definition: tftpd.h:59
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED LPLOOKUPSERVICE_COMPLETION_ROUTINE HANDLE * handle
Definition: sock.c:82
#define SECPKG_CRED_OUTBOUND
Definition: sspi.h:291
SecurityFunctionTableW schanTableW
#define ERROR_SUCCESS
Definition: deptool.c:10
SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, SIZE_T *length) DECLSPEC_HIDDEN
#define WideCharToMultiByte
Definition: compat.h:111
#define SECBUFFER_STREAM_HEADER
Definition: sspi.h:166
WCHAR SEC_WCHAR
Definition: sspi.h:29
ULONG LowPart
Definition: sspi.h:75
#define schan_imp_init
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesA(PULONG pcPackages, PSecPkgInfoA *ppPackageInfo)
Definition: secur32_wine.c:199
#define SP_PROT_TLS1_0_CLIENT
Definition: schannel.h:32
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) DECLSPEC_HIDDEN
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
#define SP_PROT_TLS1_1_CLIENT
Definition: schannel.h:33
#define CP_ACP
Definition: compat.h:109
GLuint GLuint GLsizei count
Definition: gl.h:1545
DWORD dwVersion
Definition: schannel.h:88
BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
Definition: cert.c:371
#define WARN(fmt,...)
Definition: debug.h:112
struct schan_context * ctx
Definition: schannel_priv.h:82
#define SECPKG_ATTR_REMOTE_CERT_CONTEXT
Definition: schannel.h:69
r received
Definition: btrfs.c:2939
int current_buffer_idx
Definition: schannel_priv.h:75
GLdouble GLdouble t
Definition: gl.h:2047
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
#define SECBUFFER_DATA
Definition: sspi.h:160
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
LONG_PTR SSIZE_T
Definition: basetsd.h:183
GLuint buffer
Definition: glext.h:5915
#define ISC_RET_ALLOCATED_MEMORY
Definition: sspi.h:393
ULONG_PTR dwLower
Definition: sspi.h:53
#define SECPKG_FLAG_IMPERSONATION
Definition: sspi.h:134
#define SECPKG_CRED_ATTR_NAMES
Definition: sspi.h:246
DWORD cSupportedAlgs
Definition: schannel.h:94
DWORD dwCredFormat
Definition: schannel.h:101
#define SEC_E_UNSUPPORTED_FUNCTION
Definition: winerror.h:2911
SecureProvider * SECUR32_addProvider(const SecurityFunctionTableA *fnTableA, const SecurityFunctionTableW *fnTableW, PCWSTR moduleName) DECLSPEC_HIDDEN
Definition: secur32_wine.c:314
int32_t INT
Definition: typedefs.h:58
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: glext.h:7750
BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert, DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv, DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
Definition: cert.c:881
#define SECPKG_FLAG_INTEGRITY
Definition: sspi.h:126
#define SECBUFFER_EXTRA
Definition: sspi.h:164
static DWORD block_size(DWORD block)
Definition: jsutils.c:66
#define SP_PROT_TLS1_2_CLIENT
Definition: schannel.h:34
struct _test_info info[]
Definition: SetCursorPos.c:19
uint32_t ULONG_PTR
Definition: typedefs.h:65
PCCERT_CONTEXT * paCred
Definition: schannel.h:90
char * schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) DECLSPEC_HIDDEN
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ALG_ID * palgSupportedAlgs
Definition: schannel.h:95
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
#define CERT_STORE_CREATE_NEW_FLAG
Definition: wincrypt.h:2464
#define SEC_E_INSUFFICIENT_MEMORY
Definition: winerror.h:2909
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
struct schan_imp_session_opaque * schan_imp_session
Definition: schannel_priv.h:59
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags)
Definition: crypt.c:648
static const WCHAR desc[]
Definition: protectdata.c:36
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:111
#define SECBUFFER_MISSING
Definition: sspi.h:163
static PVOID ptr
Definition: dispmode.c:27
#define SCHANNEL_CRED_VERSION
Definition: schannel.h:22
unsigned int idx
Definition: utils.c:41
#define SECPKG_CRED_INBOUND
Definition: sspi.h:290
DWORD cMappers
Definition: schannel.h:92
#define CERT_STORE_PROV_MEMORY
Definition: wincrypt.h:2251
DWORD dwSessionLifespan
Definition: schannel.h:99
smooth NULL
Definition: ftsmooth.c:416
static const WCHAR version[]
Definition: asmname.c:66
PVOID pBuffer
DWORD grbitEnabledProtocols
Definition: schannel.h:96
BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
Definition: store.c:1127
void schan_imp_set_session_transport(schan_imp_session session, struct schan_transport *t) DECLSPEC_HIDDEN
#define SECBUFFER_EMPTY
Definition: sspi.h:159
Definition: arc.h:35
const SecBufferDesc * desc
Definition: schannel_priv.h:74
#define SEC_I_CONTINUE_NEEDED
Definition: winerror.h:2927
static BYTE cert[]
Definition: msg.c:1437
GLuint index
Definition: glext.h:6031
SECURITY_STATUS schan_imp_handshake(schan_imp_session session) DECLSPEC_HIDDEN
Definition: bcd.h:202
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesW(PULONG pcPackages, PSecPkgInfoW *ppPackageInfo)
Definition: secur32_wine.c:58
#define b
Definition: ke_i.h:79
LONG SECURITY_STATUS
Definition: sspi.h:34
#define SEC_ENTRY
Definition: stubs.c:6
HCERTSTORE hRootStore
Definition: schannel.h:91
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) DECLSPEC_HIDDEN
BOOL schan_imp_allocate_certificate_credentials(schan_credentials *) DECLSPEC_HIDDEN
#define SECPKG_FLAG_MULTI_REQUIRED
Definition: sspi.h:131
#define TRACE(s)
Definition: solgame.cpp:4
#define SP_PROT_SSL2_CLIENT
Definition: schannel.h:29
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
void schan_imp_dispose_session(schan_imp_session session) DECLSPEC_HIDDEN
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
#define CP_UNIXCP
Definition: compat.h:79
__wchar_t WCHAR
Definition: xmlstorage.h:180
schan_imp_session schan_session_for_transport(struct schan_transport *t) DECLSPEC_HIDDEN
#define debugstr_a
Definition: kernel32.h:31
PVOID *typedef PSecBuffer
Definition: ntsecpkg.h:440
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
SecurityFunctionTableA schanTableA
LONG HighPart
Definition: sspi.h:76
SECURITY_STATUS WINAPI schan_FreeContextBuffer(PVOID pvoid)
Definition: secur32_wine.c:221
unsigned long DWORD
Definition: ntddk_ex.h:95
int quality
Definition: jpeglib.h:992
void SECUR32_initSchannelSP(void)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
#define SECPKG_ATTR_STREAM_SIZES
Definition: sspi.h:525
#define SECBUFFER_STREAM_TRAILER
Definition: sspi.h:165
#define SEC_E_INVALID_HANDLE
Definition: winerror.h:2910
int ret
#define ISC_REQ_ALLOCATE_MEMORY
Definition: sspi.h:370
#define index(s, c)
Definition: various.h:29
#define UNISP_RPC_ID
Definition: schannel.h:82
HKEY key
Definition: reg.c:42
#define SECBUFFER_TOKEN
Definition: sspi.h:161
#define SEC_E_INVALID_TOKEN
Definition: winerror.h:2917
#define SECPKG_ATTR_CONNECTION_INFO
Definition: schannel.h:76
#define SECPKG_ATTR_CIPHER_STRENGTHS
Definition: schannel.h:73
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
void schan_imp_set_session_target(schan_imp_session session, const char *target) DECLSPEC_HIDDEN
GLsizei const GLfloat * value
Definition: glext.h:6069
#define SEC_E_OK
Definition: winerror.h:2356
DWORD dwFlags
Definition: schannel.h:100
unsigned char BYTE
Definition: xxhash.c:193
DWORD cert_store
Definition: store.c:344
#define SECPKG_FLAG_ACCEPT_WIN32_NAME
Definition: sspi.h:135
void schan_imp_free_certificate_credentials(schan_credentials *) DECLSPEC_HIDDEN
SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, SecPkgContext_ConnectionInfo *info) DECLSPEC_HIDDEN
#define ERR(fmt,...)
Definition: debug.h:110
int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) DECLSPEC_HIDDEN
ULONG_PTR SIZE_T
Definition: typedefs.h:80
void(SEC_ENTRY * SEC_GET_KEY_FN)(void *Arg, void *Principal, ULONG KeyVer, void **Key, SECURITY_STATUS *Status)
Definition: sspi.h:189
#define UINT_MAX
Definition: limits.h:41
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
CONTEXT ctx
#define SCHANNEL_NAME_W
Definition: schannel.h:11
#define SECPKG_FLAG_PRIVACY
Definition: sspi.h:127
#define SEC_E_NO_AUTHENTICATING_AUTHORITY
Definition: winerror.h:2926
#define SECPKG_FLAG_EXTENDED_ERROR
Definition: sspi.h:133
ULONG_PTR HCRYPTPROV
Definition: wincrypt.h:46
ULONG cbBuffer
Definition: sspi.h:153
#define HeapReAlloc
Definition: compat.h:593
WINE_UNICODE_INLINE WCHAR * strcatW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:242
unsigned int * PULONG
Definition: retypes.h:1
unsigned int UINT
Definition: ndis.h:50
#define SECPKG_ATTR_SUPPORTED_ALGS
Definition: schannel.h:72
CHAR SEC_CHAR
Definition: sspi.h:30
Definition: bcd.h:201
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(PCCERT_CONTEXT pCertContext)
Definition: cert.c:360
ULONG_PTR dwUpper
Definition: sspi.h:54
#define MultiByteToWideChar
Definition: compat.h:110
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE, PCCERT_CONTEXT *cert) DECLSPEC_HIDDEN
HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void *pvPara)
Definition: store.c:815
DWORD dwMaximumCipherStrength
Definition: schannel.h:98
#define UNISP_NAME_W
Definition: sspi.h:38
#define schan_imp_deinit
DWORD cCreds
Definition: schannel.h:89
unsigned int schan_imp_get_max_message_size(schan_imp_session session) DECLSPEC_HIDDEN
GLuint res
Definition: glext.h:9613
WINE_DEFAULT_DEBUG_CHANNEL(schannel)
unsigned int ULONG
Definition: retypes.h:1
GLenum target
Definition: glext.h:7315
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
DWORD dwMinimumCipherStrength
Definition: schannel.h:97
#define SEC_E_NO_CREDENTIALS
Definition: winerror.h:2923
#define SEC_E_UNKNOWN_CREDENTIALS
Definition: winerror.h:2922
void SECUR32_deinitSchannelSP(void)
DWORD schan_imp_enabled_protocols(void) DECLSPEC_HIDDEN
#define SECPKG_FLAG_CONNECTION
Definition: sspi.h:130
ULONG cBuffers
Definition: sspi.h:182
#define REG_DWORD
Definition: sdbapi.c:596
static SERVICE_STATUS status
Definition: service.c:31
#define UL
Definition: tui.h:82
static unsigned char buff[32768]
Definition: fatten.c:17
#define HeapFree(x, y, z)
Definition: compat.h:594
#define SEC_E_INCOMPLETE_MESSAGE
Definition: winerror.h:2934
void * object
Definition: jmemsys.h:48
SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, SIZE_T *length) DECLSPEC_HIDDEN
Definition: path.c:41
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define SECPKG_FLAG_STREAM
Definition: sspi.h:136
Definition: ps.c:97