xmllite: Use buffer offset instead of pointers.
[wine.git] / dlls / rpcrt4 / rpc_binding.c
bloba6cfb6aed1d30eec739f5b3480cab708977bfb14
1 /*
2 * RPC binding API
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
7 * Copyright 2006 CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "winerror.h"
33 #include "winternl.h"
34 #include "wine/unicode.h"
36 #include "rpc.h"
37 #include "rpcndr.h"
39 #include "wine/debug.h"
41 #include "rpc_binding.h"
42 #include "rpc_assoc.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
46 LPSTR RPCRT4_strndupA(LPCSTR src, INT slen)
48 DWORD len;
49 LPSTR s;
50 if (!src) return NULL;
51 if (slen == -1) slen = strlen(src);
52 len = slen;
53 s = HeapAlloc(GetProcessHeap(), 0, len+1);
54 memcpy(s, src, len);
55 s[len] = 0;
56 return s;
59 LPSTR RPCRT4_strdupWtoA(LPCWSTR src)
61 DWORD len;
62 LPSTR s;
63 if (!src) return NULL;
64 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
65 s = HeapAlloc(GetProcessHeap(), 0, len);
66 WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL);
67 return s;
70 LPWSTR RPCRT4_strdupAtoW(LPCSTR src)
72 DWORD len;
73 LPWSTR s;
74 if (!src) return NULL;
75 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
76 s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
77 MultiByteToWideChar(CP_ACP, 0, src, -1, s, len);
78 return s;
81 static LPWSTR RPCRT4_strndupAtoW(LPCSTR src, INT slen)
83 DWORD len;
84 LPWSTR s;
85 if (!src) return NULL;
86 len = MultiByteToWideChar(CP_ACP, 0, src, slen, NULL, 0);
87 s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
88 MultiByteToWideChar(CP_ACP, 0, src, slen, s, len);
89 return s;
92 LPWSTR RPCRT4_strndupW(LPCWSTR src, INT slen)
94 DWORD len;
95 LPWSTR s;
96 if (!src) return NULL;
97 if (slen == -1) slen = strlenW(src);
98 len = slen;
99 s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
100 memcpy(s, src, len*sizeof(WCHAR));
101 s[len] = 0;
102 return s;
105 void RPCRT4_strfree(LPSTR src)
107 HeapFree(GetProcessHeap(), 0, src);
110 static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
112 RpcBinding* NewBinding;
114 NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
115 NewBinding->refs = 1;
116 NewBinding->server = server;
118 *Binding = NewBinding;
120 return RPC_S_OK;
123 static RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPCSTR Protseq)
125 RpcBinding* NewBinding;
127 RPCRT4_AllocBinding(&NewBinding, server);
128 NewBinding->Protseq = RPCRT4_strdupA(Protseq);
130 TRACE("binding: %p\n", NewBinding);
131 *Binding = NewBinding;
133 return RPC_S_OK;
136 static RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPCWSTR Protseq)
138 RpcBinding* NewBinding;
140 RPCRT4_AllocBinding(&NewBinding, server);
141 NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
143 TRACE("binding: %p\n", NewBinding);
144 *Binding = NewBinding;
146 return RPC_S_OK;
149 static RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPCSTR NetworkAddr,
150 LPCSTR Endpoint, LPCSTR NetworkOptions)
152 RPC_STATUS status;
154 TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding,
155 debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
157 RPCRT4_strfree(Binding->NetworkAddr);
158 Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
159 RPCRT4_strfree(Binding->Endpoint);
160 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
161 HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions);
162 Binding->NetworkOptions = RPCRT4_strdupAtoW(NetworkOptions);
164 /* only attempt to get an association if the binding is complete */
165 if (Endpoint && Endpoint[0] != '\0')
167 status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
168 Binding->Endpoint, Binding->NetworkOptions,
169 &Binding->Assoc);
170 if (status != RPC_S_OK)
171 return status;
174 return RPC_S_OK;
177 static RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPCWSTR NetworkAddr,
178 LPCWSTR Endpoint, LPCWSTR NetworkOptions)
180 RPC_STATUS status;
182 TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding,
183 debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
185 RPCRT4_strfree(Binding->NetworkAddr);
186 Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr);
187 RPCRT4_strfree(Binding->Endpoint);
188 Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint);
189 HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions);
190 Binding->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
192 /* only attempt to get an association if the binding is complete */
193 if (Endpoint && Endpoint[0] != '\0')
195 status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
196 Binding->Endpoint, Binding->NetworkOptions,
197 &Binding->Assoc);
198 if (status != RPC_S_OK)
199 return status;
202 return RPC_S_OK;
205 RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint)
207 RPC_STATUS status;
209 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
211 RPCRT4_strfree(Binding->Endpoint);
212 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
214 if (Binding->Assoc) RpcAssoc_Release(Binding->Assoc);
215 Binding->Assoc = NULL;
216 status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr,
217 Binding->Endpoint, Binding->NetworkOptions,
218 &Binding->Assoc);
219 if (status != RPC_S_OK)
220 return status;
222 return RPC_S_OK;
225 RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid)
227 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid));
228 if (ObjectUuid) Binding->ObjectUuid = *ObjectUuid;
229 else UuidCreateNil(&Binding->ObjectUuid);
230 return RPC_S_OK;
233 RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
235 RpcBinding* NewBinding;
236 TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection);
238 RPCRT4_AllocBinding(&NewBinding, Connection->server);
239 NewBinding->Protseq = RPCRT4_strdupA(rpcrt4_conn_get_name(Connection));
240 NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr);
241 NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint);
242 NewBinding->FromConn = Connection;
244 TRACE("binding: %p\n", NewBinding);
245 *Binding = NewBinding;
247 return RPC_S_OK;
250 void RPCRT4_AddRefBinding(RpcBinding* Binding)
252 InterlockedIncrement(&Binding->refs);
255 RPC_STATUS RPCRT4_ReleaseBinding(RpcBinding* Binding)
257 if (InterlockedDecrement(&Binding->refs))
258 return RPC_S_OK;
260 TRACE("binding: %p\n", Binding);
261 if (Binding->Assoc) RpcAssoc_Release(Binding->Assoc);
262 RPCRT4_strfree(Binding->Endpoint);
263 RPCRT4_strfree(Binding->NetworkAddr);
264 RPCRT4_strfree(Binding->Protseq);
265 HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions);
266 HeapFree(GetProcessHeap(), 0, Binding->CookieAuth);
267 if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo);
268 if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS);
269 HeapFree(GetProcessHeap(), 0, Binding);
270 return RPC_S_OK;
273 RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection,
274 const RPC_SYNTAX_IDENTIFIER *TransferSyntax,
275 const RPC_SYNTAX_IDENTIFIER *InterfaceId)
277 TRACE("(Binding == ^%p)\n", Binding);
279 if (!Binding->server) {
280 return RpcAssoc_GetClientConnection(Binding->Assoc, InterfaceId,
281 TransferSyntax, Binding->AuthInfo, Binding->QOS, Binding->CookieAuth, Connection);
282 } else {
283 /* we already have a connection with acceptable binding, so use it */
284 if (Binding->FromConn) {
285 *Connection = Binding->FromConn;
286 return RPC_S_OK;
287 } else {
288 ERR("no connection in binding\n");
289 return RPC_S_INTERNAL_ERROR;
294 RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
296 TRACE("(Binding == ^%p)\n", Binding);
297 if (!Connection) return RPC_S_OK;
298 if (Binding->server) {
299 /* don't destroy a connection that is cached in the binding */
300 if (Binding->FromConn == Connection)
301 return RPC_S_OK;
302 return RPCRT4_ReleaseConnection(Connection);
304 else {
305 RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection);
306 return RPC_S_OK;
310 static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src)
312 DWORD len = strlen(dst), slen = strlen(src);
313 LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR));
314 if (!ndst)
316 HeapFree(GetProcessHeap(), 0, dst);
317 return NULL;
319 ndst[len] = ',';
320 memcpy(ndst+len+1, src, slen+1);
321 return ndst;
324 static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src)
326 DWORD len = strlenW(dst), slen = strlenW(src);
327 LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR));
328 if (!ndst)
330 HeapFree(GetProcessHeap(), 0, dst);
331 return NULL;
333 ndst[len] = ',';
334 memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR));
335 return ndst;
338 /* Copies the escaped version of a component into a string binding.
339 * Note: doesn't nul-terminate the string */
340 static RPC_CSTR escape_string_binding_component(RPC_CSTR string_binding,
341 const unsigned char *component)
343 for (; *component; component++) {
344 switch (*component) {
345 case '@':
346 case ':':
347 case '[':
348 case ']':
349 case '\\':
350 *string_binding++ = '\\';
351 *string_binding++ = *component;
352 break;
353 default:
354 *string_binding++ = *component;
355 break;
358 return string_binding;
361 static RPC_WSTR escape_string_binding_componentW(RPC_WSTR string_binding,
362 const WCHAR *component)
364 for (; *component; component++) {
365 switch (*component) {
366 case '@':
367 case ':':
368 case '[':
369 case ']':
370 case '\\':
371 *string_binding++ = '\\';
372 *string_binding++ = *component;
373 break;
374 default:
375 *string_binding++ = *component;
376 break;
379 return string_binding;
382 static const unsigned char *string_binding_find_delimiter(
383 const unsigned char *string_binding, unsigned char delim)
385 const unsigned char *next;
386 for (next = string_binding; *next; next++) {
387 if (*next == '\\') {
388 next++;
389 continue;
391 if (*next == delim)
392 return next;
394 return NULL;
397 static const WCHAR *string_binding_find_delimiterW(
398 const WCHAR *string_binding, WCHAR delim)
400 const WCHAR *next;
401 for (next = string_binding; *next; next++) {
402 if (*next == '\\') {
403 next++;
404 continue;
406 if (*next == delim)
407 return next;
409 return NULL;
412 static RPC_CSTR unescape_string_binding_component(
413 const unsigned char *string_binding, int len)
415 RPC_CSTR component, p;
417 if (len == -1) len = strlen((const char *)string_binding);
419 component = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*component));
420 if (!component) return NULL;
421 for (p = component; len > 0; string_binding++, len--) {
422 if (*string_binding == '\\') {
423 string_binding++;
424 len--;
425 *p++ = *string_binding;
426 } else {
427 *p++ = *string_binding;
430 *p = '\0';
431 return component;
434 static RPC_WSTR unescape_string_binding_componentW(
435 const WCHAR *string_binding, int len)
437 RPC_WSTR component, p;
439 if (len == -1) len = strlenW(string_binding);
441 component = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*component));
442 if (!component) return NULL;
443 for (p = component; len > 0; string_binding++, len--) {
444 if (*string_binding == '\\') {
445 string_binding++;
446 len--;
447 *p++ = *string_binding;
448 } else {
449 *p++ = *string_binding;
452 *p = '\0';
453 return component;
456 /***********************************************************************
457 * RpcStringBindingComposeA (RPCRT4.@)
459 RPC_STATUS WINAPI RpcStringBindingComposeA(RPC_CSTR ObjUuid, RPC_CSTR Protseq,
460 RPC_CSTR NetworkAddr, RPC_CSTR Endpoint,
461 RPC_CSTR Options, RPC_CSTR *StringBinding )
463 DWORD len = 1;
464 RPC_CSTR data;
466 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
467 debugstr_a( (char*)ObjUuid ), debugstr_a( (char*)Protseq ),
468 debugstr_a( (char*)NetworkAddr ), debugstr_a( (char*)Endpoint ),
469 debugstr_a( (char*)Options ), StringBinding );
471 /* overestimate for each component for escaping of delimiters */
472 if (ObjUuid && *ObjUuid) len += strlen((char*)ObjUuid) * 2 + 1;
473 if (Protseq && *Protseq) len += strlen((char*)Protseq) * 2 + 1;
474 if (NetworkAddr && *NetworkAddr) len += strlen((char*)NetworkAddr) * 2;
475 if (Endpoint && *Endpoint) len += strlen((char*)Endpoint) * 2 + 2;
476 if (Options && *Options) len += strlen((char*)Options) * 2 + 2;
478 data = HeapAlloc(GetProcessHeap(), 0, len);
479 *StringBinding = data;
481 if (ObjUuid && *ObjUuid) {
482 data = escape_string_binding_component(data, ObjUuid);
483 *data++ = '@';
485 if (Protseq && *Protseq) {
486 data = escape_string_binding_component(data, Protseq);
487 *data++ = ':';
489 if (NetworkAddr && *NetworkAddr)
490 data = escape_string_binding_component(data, NetworkAddr);
492 if ((Endpoint && *Endpoint) ||
493 (Options && *Options)) {
494 *data++ = '[';
495 if (Endpoint && *Endpoint) {
496 data = escape_string_binding_component(data, Endpoint);
497 if (Options && *Options) *data++ = ',';
499 if (Options && *Options) {
500 data = escape_string_binding_component(data, Options);
502 *data++ = ']';
504 *data = 0;
506 return RPC_S_OK;
509 /***********************************************************************
510 * RpcStringBindingComposeW (RPCRT4.@)
512 RPC_STATUS WINAPI RpcStringBindingComposeW( RPC_WSTR ObjUuid, RPC_WSTR Protseq,
513 RPC_WSTR NetworkAddr, RPC_WSTR Endpoint,
514 RPC_WSTR Options, RPC_WSTR* StringBinding )
516 DWORD len = 1;
517 RPC_WSTR data;
519 TRACE("(%s,%s,%s,%s,%s,%p)\n",
520 debugstr_w( ObjUuid ), debugstr_w( Protseq ),
521 debugstr_w( NetworkAddr ), debugstr_w( Endpoint ),
522 debugstr_w( Options ), StringBinding);
524 /* overestimate for each component for escaping of delimiters */
525 if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) * 2 + 1;
526 if (Protseq && *Protseq) len += strlenW(Protseq) * 2 + 1;
527 if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr) * 2;
528 if (Endpoint && *Endpoint) len += strlenW(Endpoint) * 2 + 2;
529 if (Options && *Options) len += strlenW(Options) * 2 + 2;
531 data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
532 *StringBinding = data;
534 if (ObjUuid && *ObjUuid) {
535 data = escape_string_binding_componentW(data, ObjUuid);
536 *data++ = '@';
538 if (Protseq && *Protseq) {
539 data = escape_string_binding_componentW(data, Protseq);
540 *data++ = ':';
542 if (NetworkAddr && *NetworkAddr) {
543 data = escape_string_binding_componentW(data, NetworkAddr);
545 if ((Endpoint && *Endpoint) ||
546 (Options && *Options)) {
547 *data++ = '[';
548 if (Endpoint && *Endpoint) {
549 data = escape_string_binding_componentW(data, Endpoint);
550 if (Options && *Options) *data++ = ',';
552 if (Options && *Options) {
553 data = escape_string_binding_componentW(data, Options);
555 *data++ = ']';
557 *data = 0;
559 return RPC_S_OK;
563 /***********************************************************************
564 * RpcStringBindingParseA (RPCRT4.@)
566 RPC_STATUS WINAPI RpcStringBindingParseA( RPC_CSTR StringBinding, RPC_CSTR *ObjUuid,
567 RPC_CSTR *Protseq, RPC_CSTR *NetworkAddr,
568 RPC_CSTR *Endpoint, RPC_CSTR *Options)
570 const unsigned char *data, *next;
571 static const char ep_opt[] = "endpoint=";
572 BOOL endpoint_already_found = FALSE;
574 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a((char*)StringBinding),
575 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
577 if (ObjUuid) *ObjUuid = NULL;
578 if (Protseq) *Protseq = NULL;
579 if (NetworkAddr) *NetworkAddr = NULL;
580 if (Endpoint) *Endpoint = NULL;
581 if (Options) *Options = NULL;
583 data = StringBinding;
585 next = string_binding_find_delimiter(data, '@');
586 if (next) {
587 UUID uuid;
588 RPC_STATUS status;
589 RPC_CSTR str_uuid = unescape_string_binding_component(data, next - data);
590 status = UuidFromStringA(str_uuid, &uuid);
591 if (status != RPC_S_OK) {
592 HeapFree(GetProcessHeap(), 0, str_uuid);
593 return status;
595 if (ObjUuid)
596 *ObjUuid = str_uuid;
597 else
598 HeapFree(GetProcessHeap(), 0, str_uuid);
599 data = next+1;
602 next = string_binding_find_delimiter(data, ':');
603 if (next) {
604 if (Protseq) *Protseq = unescape_string_binding_component(data, next - data);
605 data = next+1;
608 next = string_binding_find_delimiter(data, '[');
609 if (next) {
610 const unsigned char *close;
611 RPC_CSTR opt;
613 if (NetworkAddr) *NetworkAddr = unescape_string_binding_component(data, next - data);
614 data = next+1;
615 close = string_binding_find_delimiter(data, ']');
616 if (!close) goto fail;
618 /* tokenize options */
619 while (data < close) {
620 next = string_binding_find_delimiter(data, ',');
621 if (!next || next > close) next = close;
622 /* FIXME: this is kind of inefficient */
623 opt = unescape_string_binding_component(data, next - data);
624 data = next+1;
626 /* parse option */
627 next = string_binding_find_delimiter(opt, '=');
628 if (!next) {
629 /* not an option, must be an endpoint */
630 if (endpoint_already_found) goto fail;
631 if (Endpoint) *Endpoint = opt;
632 else HeapFree(GetProcessHeap(), 0, opt);
633 endpoint_already_found = TRUE;
634 } else {
635 if (strncmp((const char *)opt, ep_opt, strlen(ep_opt)) == 0) {
636 /* endpoint option */
637 if (endpoint_already_found) goto fail;
638 if (Endpoint) *Endpoint = unescape_string_binding_component(next+1, -1);
639 HeapFree(GetProcessHeap(), 0, opt);
640 endpoint_already_found = TRUE;
641 } else {
642 /* network option */
643 if (Options) {
644 if (*Options) {
645 /* FIXME: this is kind of inefficient */
646 *Options = (unsigned char*) RPCRT4_strconcatA( (char*)*Options, (char *)opt);
647 HeapFree(GetProcessHeap(), 0, opt);
648 } else
649 *Options = opt;
650 } else
651 HeapFree(GetProcessHeap(), 0, opt);
656 data = close+1;
657 if (*data) goto fail;
659 else if (NetworkAddr)
660 *NetworkAddr = unescape_string_binding_component(data, -1);
662 return RPC_S_OK;
664 fail:
665 if (ObjUuid) RpcStringFreeA(ObjUuid);
666 if (Protseq) RpcStringFreeA(Protseq);
667 if (NetworkAddr) RpcStringFreeA(NetworkAddr);
668 if (Endpoint) RpcStringFreeA(Endpoint);
669 if (Options) RpcStringFreeA(Options);
670 return RPC_S_INVALID_STRING_BINDING;
673 /***********************************************************************
674 * RpcStringBindingParseW (RPCRT4.@)
676 RPC_STATUS WINAPI RpcStringBindingParseW( RPC_WSTR StringBinding, RPC_WSTR *ObjUuid,
677 RPC_WSTR *Protseq, RPC_WSTR *NetworkAddr,
678 RPC_WSTR *Endpoint, RPC_WSTR *Options)
680 const WCHAR *data, *next;
681 static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0};
682 BOOL endpoint_already_found = FALSE;
684 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding),
685 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
687 if (ObjUuid) *ObjUuid = NULL;
688 if (Protseq) *Protseq = NULL;
689 if (NetworkAddr) *NetworkAddr = NULL;
690 if (Endpoint) *Endpoint = NULL;
691 if (Options) *Options = NULL;
693 data = StringBinding;
695 next = string_binding_find_delimiterW(data, '@');
696 if (next) {
697 UUID uuid;
698 RPC_STATUS status;
699 RPC_WSTR str_uuid = unescape_string_binding_componentW(data, next - data);
700 status = UuidFromStringW(str_uuid, &uuid);
701 if (status != RPC_S_OK) {
702 HeapFree(GetProcessHeap(), 0, str_uuid);
703 return status;
705 if (ObjUuid)
706 *ObjUuid = str_uuid;
707 else
708 HeapFree(GetProcessHeap(), 0, str_uuid);
709 data = next+1;
712 next = string_binding_find_delimiterW(data, ':');
713 if (next) {
714 if (Protseq) *Protseq = unescape_string_binding_componentW(data, next - data);
715 data = next+1;
718 next = string_binding_find_delimiterW(data, '[');
719 if (next) {
720 const WCHAR *close;
721 RPC_WSTR opt;
723 if (NetworkAddr) *NetworkAddr = unescape_string_binding_componentW(data, next - data);
724 data = next+1;
725 close = string_binding_find_delimiterW(data, ']');
726 if (!close) goto fail;
728 /* tokenize options */
729 while (data < close) {
730 next = string_binding_find_delimiterW(data, ',');
731 if (!next || next > close) next = close;
732 /* FIXME: this is kind of inefficient */
733 opt = unescape_string_binding_componentW(data, next - data);
734 data = next+1;
736 /* parse option */
737 next = string_binding_find_delimiterW(opt, '=');
738 if (!next) {
739 /* not an option, must be an endpoint */
740 if (endpoint_already_found) goto fail;
741 if (Endpoint) *Endpoint = opt;
742 else HeapFree(GetProcessHeap(), 0, opt);
743 endpoint_already_found = TRUE;
744 } else {
745 if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) {
746 /* endpoint option */
747 if (endpoint_already_found) goto fail;
748 if (Endpoint) *Endpoint = unescape_string_binding_componentW(next+1, -1);
749 HeapFree(GetProcessHeap(), 0, opt);
750 endpoint_already_found = TRUE;
751 } else {
752 /* network option */
753 if (Options) {
754 if (*Options) {
755 /* FIXME: this is kind of inefficient */
756 *Options = RPCRT4_strconcatW(*Options, opt);
757 HeapFree(GetProcessHeap(), 0, opt);
758 } else
759 *Options = opt;
760 } else
761 HeapFree(GetProcessHeap(), 0, opt);
766 data = close+1;
767 if (*data) goto fail;
768 } else if (NetworkAddr)
769 *NetworkAddr = unescape_string_binding_componentW(data, -1);
771 return RPC_S_OK;
773 fail:
774 if (ObjUuid) RpcStringFreeW(ObjUuid);
775 if (Protseq) RpcStringFreeW(Protseq);
776 if (NetworkAddr) RpcStringFreeW(NetworkAddr);
777 if (Endpoint) RpcStringFreeW(Endpoint);
778 if (Options) RpcStringFreeW(Options);
779 return RPC_S_INVALID_STRING_BINDING;
782 /***********************************************************************
783 * RpcBindingFree (RPCRT4.@)
785 RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding )
787 RPC_STATUS status;
788 TRACE("(%p) = %p\n", Binding, *Binding);
789 if (*Binding)
790 status = RPCRT4_ReleaseBinding(*Binding);
791 else
792 status = RPC_S_INVALID_BINDING;
793 if (status == RPC_S_OK) *Binding = NULL;
794 return status;
797 /***********************************************************************
798 * RpcBindingVectorFree (RPCRT4.@)
800 RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector )
802 ULONG c;
804 TRACE("(%p)\n", BindingVector);
805 for (c=0; c<(*BindingVector)->Count; c++) RpcBindingFree(&(*BindingVector)->BindingH[c]);
806 HeapFree(GetProcessHeap(), 0, *BindingVector);
807 *BindingVector = NULL;
808 return RPC_S_OK;
811 /***********************************************************************
812 * RpcBindingInqObject (RPCRT4.@)
814 RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
816 RpcBinding* bind = Binding;
818 TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid));
819 *ObjectUuid = bind->ObjectUuid;
820 return RPC_S_OK;
823 /***********************************************************************
824 * RpcBindingSetObject (RPCRT4.@)
826 RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
828 RpcBinding* bind = Binding;
830 TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid));
831 if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING;
832 return RPCRT4_SetBindingObject(Binding, ObjectUuid);
835 /***********************************************************************
836 * RpcBindingFromStringBindingA (RPCRT4.@)
838 RPC_STATUS WINAPI RpcBindingFromStringBindingA( RPC_CSTR StringBinding, RPC_BINDING_HANDLE* Binding )
840 RPC_STATUS ret;
841 RpcBinding* bind = NULL;
842 RPC_CSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
843 UUID Uuid;
845 TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding), Binding);
847 ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq,
848 &NetworkAddr, &Endpoint, &Options);
849 if (ret != RPC_S_OK) return ret;
851 ret = UuidFromStringA(ObjectUuid, &Uuid);
853 if (ret == RPC_S_OK)
854 ret = RPCRT4_CreateBindingA(&bind, FALSE, (char*)Protseq);
855 if (ret == RPC_S_OK) {
856 ret = RPCRT4_SetBindingObject(bind, &Uuid);
857 if (ret == RPC_S_OK)
858 ret = RPCRT4_CompleteBindingA(bind, (char*)NetworkAddr, (char*)Endpoint, (char*)Options);
860 if (ret == RPC_S_OK)
861 *Binding = (RPC_BINDING_HANDLE)bind;
862 else
863 RPCRT4_ReleaseBinding(bind);
866 RpcStringFreeA(&Options);
867 RpcStringFreeA(&Endpoint);
868 RpcStringFreeA(&NetworkAddr);
869 RpcStringFreeA(&Protseq);
870 RpcStringFreeA(&ObjectUuid);
872 return ret;
875 /***********************************************************************
876 * RpcBindingFromStringBindingW (RPCRT4.@)
878 RPC_STATUS WINAPI RpcBindingFromStringBindingW( RPC_WSTR StringBinding, RPC_BINDING_HANDLE* Binding )
880 RPC_STATUS ret;
881 RpcBinding* bind = NULL;
882 RPC_WSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
883 UUID Uuid;
885 TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding);
887 ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq,
888 &NetworkAddr, &Endpoint, &Options);
889 if (ret != RPC_S_OK) return ret;
891 ret = UuidFromStringW(ObjectUuid, &Uuid);
893 if (ret == RPC_S_OK)
894 ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq);
895 if (ret == RPC_S_OK) {
896 ret = RPCRT4_SetBindingObject(bind, &Uuid);
897 if (ret == RPC_S_OK)
898 ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options);
900 if (ret == RPC_S_OK)
901 *Binding = (RPC_BINDING_HANDLE)bind;
902 else
903 RPCRT4_ReleaseBinding(bind);
906 RpcStringFreeW(&Options);
907 RpcStringFreeW(&Endpoint);
908 RpcStringFreeW(&NetworkAddr);
909 RpcStringFreeW(&Protseq);
910 RpcStringFreeW(&ObjectUuid);
912 return ret;
915 /***********************************************************************
916 * RpcBindingToStringBindingA (RPCRT4.@)
918 RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, RPC_CSTR *StringBinding )
920 RPC_STATUS ret;
921 RpcBinding* bind = Binding;
922 RPC_CSTR ObjectUuid;
924 TRACE("(%p,%p)\n", Binding, StringBinding);
926 if (UuidIsNil(&bind->ObjectUuid, &ret))
927 ObjectUuid = NULL;
928 else
930 ret = UuidToStringA(&bind->ObjectUuid, &ObjectUuid);
931 if (ret != RPC_S_OK) return ret;
934 ret = RpcStringBindingComposeA(ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr,
935 (unsigned char*) bind->Endpoint, NULL, StringBinding);
937 RpcStringFreeA(&ObjectUuid);
939 return ret;
942 /***********************************************************************
943 * RpcBindingToStringBindingW (RPCRT4.@)
945 RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, RPC_WSTR *StringBinding )
947 RPC_STATUS ret;
948 unsigned char *str = NULL;
949 TRACE("(%p,%p)\n", Binding, StringBinding);
950 ret = RpcBindingToStringBindingA(Binding, &str);
951 *StringBinding = RPCRT4_strdupAtoW((char*)str);
952 RpcStringFreeA(&str);
953 return ret;
956 /***********************************************************************
957 * I_RpcBindingInqTransportType (RPCRT4.@)
959 RPC_STATUS WINAPI I_RpcBindingInqTransportType( RPC_BINDING_HANDLE Binding, unsigned int * Type )
962 FIXME( "(%p,%p): stub\n", Binding, Type);
963 *Type = TRANSPORT_TYPE_LPC;
964 return RPC_S_OK;
967 /***********************************************************************
968 * I_RpcBindingSetAsync (RPCRT4.@)
969 * NOTES
970 * Exists in win9x and winNT, but with different number of arguments
971 * (9x version has 3 arguments, NT has 2).
973 RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn)
975 RpcBinding* bind = Binding;
977 TRACE( "(%p,%p): stub\n", Binding, BlockingFn );
979 bind->BlockingFn = BlockingFn;
981 return RPC_S_OK;
984 /***********************************************************************
985 * RpcBindingCopy (RPCRT4.@)
987 RPC_STATUS RPC_ENTRY RpcBindingCopy(
988 RPC_BINDING_HANDLE SourceBinding,
989 RPC_BINDING_HANDLE* DestinationBinding)
991 RpcBinding *DestBinding;
992 RpcBinding *SrcBinding = SourceBinding;
993 RPC_STATUS status;
995 TRACE("(%p, %p)\n", SourceBinding, DestinationBinding);
997 status = RPCRT4_AllocBinding(&DestBinding, SrcBinding->server);
998 if (status != RPC_S_OK) return status;
1000 DestBinding->ObjectUuid = SrcBinding->ObjectUuid;
1001 DestBinding->BlockingFn = SrcBinding->BlockingFn;
1002 DestBinding->Protseq = RPCRT4_strndupA(SrcBinding->Protseq, -1);
1003 DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1);
1004 DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1);
1005 DestBinding->NetworkOptions = RPCRT4_strdupW(SrcBinding->NetworkOptions);
1006 DestBinding->CookieAuth = RPCRT4_strdupW(SrcBinding->CookieAuth);
1007 if (SrcBinding->Assoc) SrcBinding->Assoc->refs++;
1008 DestBinding->Assoc = SrcBinding->Assoc;
1010 if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo);
1011 DestBinding->AuthInfo = SrcBinding->AuthInfo;
1012 if (SrcBinding->QOS) RpcQualityOfService_AddRef(SrcBinding->QOS);
1013 DestBinding->QOS = SrcBinding->QOS;
1015 *DestinationBinding = DestBinding;
1016 return RPC_S_OK;
1019 /***********************************************************************
1020 * RpcBindingReset (RPCRT4.@)
1022 RPC_STATUS RPC_ENTRY RpcBindingReset(RPC_BINDING_HANDLE Binding)
1024 RpcBinding *bind = Binding;
1026 TRACE("(%p)\n", Binding);
1028 RPCRT4_strfree(bind->Endpoint);
1029 bind->Endpoint = NULL;
1030 if (bind->Assoc) RpcAssoc_Release(bind->Assoc);
1031 bind->Assoc = NULL;
1033 return RPC_S_OK;
1036 /***********************************************************************
1037 * RpcImpersonateClient (RPCRT4.@)
1039 * Impersonates the client connected via a binding handle so that security
1040 * checks are done in the context of the client.
1042 * PARAMS
1043 * BindingHandle [I] Handle to the binding to the client.
1045 * RETURNS
1046 * Success: RPS_S_OK.
1047 * Failure: RPC_STATUS value.
1049 * NOTES
1051 * If BindingHandle is NULL then the function impersonates the client
1052 * connected to the binding handle of the current thread.
1054 RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle)
1056 RpcBinding *bind;
1058 TRACE("(%p)\n", BindingHandle);
1060 if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle();
1061 if (!BindingHandle) return RPC_S_INVALID_BINDING;
1063 bind = BindingHandle;
1064 if (bind->FromConn)
1065 return rpcrt4_conn_impersonate_client(bind->FromConn);
1066 return RPC_S_WRONG_KIND_OF_BINDING;
1069 /***********************************************************************
1070 * RpcRevertToSelfEx (RPCRT4.@)
1072 * Stops impersonating the client connected to the binding handle so that security
1073 * checks are no longer done in the context of the client.
1075 * PARAMS
1076 * BindingHandle [I] Handle to the binding to the client.
1078 * RETURNS
1079 * Success: RPS_S_OK.
1080 * Failure: RPC_STATUS value.
1082 * NOTES
1084 * If BindingHandle is NULL then the function stops impersonating the client
1085 * connected to the binding handle of the current thread.
1087 RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle)
1089 RpcBinding *bind;
1091 TRACE("(%p)\n", BindingHandle);
1093 if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle();
1094 if (!BindingHandle) return RPC_S_INVALID_BINDING;
1096 bind = BindingHandle;
1097 if (bind->FromConn)
1098 return rpcrt4_conn_revert_to_self(bind->FromConn);
1099 return RPC_S_WRONG_KIND_OF_BINDING;
1102 static inline BOOL has_nt_auth_identity(ULONG AuthnLevel)
1104 switch (AuthnLevel)
1106 case RPC_C_AUTHN_GSS_NEGOTIATE:
1107 case RPC_C_AUTHN_WINNT:
1108 case RPC_C_AUTHN_GSS_KERBEROS:
1109 return TRUE;
1110 default:
1111 return FALSE;
1115 RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc,
1116 CredHandle cred, TimeStamp exp,
1117 ULONG cbMaxToken,
1118 RPC_AUTH_IDENTITY_HANDLE identity,
1119 RpcAuthInfo **ret)
1121 RpcAuthInfo *AuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo));
1122 if (!AuthInfo)
1123 return ERROR_OUTOFMEMORY;
1125 AuthInfo->refs = 1;
1126 AuthInfo->AuthnLevel = AuthnLevel;
1127 AuthInfo->AuthnSvc = AuthnSvc;
1128 AuthInfo->cred = cred;
1129 AuthInfo->exp = exp;
1130 AuthInfo->cbMaxToken = cbMaxToken;
1131 AuthInfo->identity = identity;
1132 AuthInfo->server_principal_name = NULL;
1134 /* duplicate the SEC_WINNT_AUTH_IDENTITY structure, if applicable, to
1135 * enable better matching in RpcAuthInfo_IsEqual */
1136 if (identity && has_nt_auth_identity(AuthnSvc))
1138 const SEC_WINNT_AUTH_IDENTITY_W *nt_identity = identity;
1139 AuthInfo->nt_identity = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo->nt_identity));
1140 if (!AuthInfo->nt_identity)
1142 HeapFree(GetProcessHeap(), 0, AuthInfo);
1143 return ERROR_OUTOFMEMORY;
1146 AuthInfo->nt_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1147 if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1148 AuthInfo->nt_identity->User = RPCRT4_strndupW(nt_identity->User, nt_identity->UserLength);
1149 else
1150 AuthInfo->nt_identity->User = RPCRT4_strndupAtoW((const char *)nt_identity->User, nt_identity->UserLength);
1151 AuthInfo->nt_identity->UserLength = nt_identity->UserLength;
1152 if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1153 AuthInfo->nt_identity->Domain = RPCRT4_strndupW(nt_identity->Domain, nt_identity->DomainLength);
1154 else
1155 AuthInfo->nt_identity->Domain = RPCRT4_strndupAtoW((const char *)nt_identity->Domain, nt_identity->DomainLength);
1156 AuthInfo->nt_identity->DomainLength = nt_identity->DomainLength;
1157 if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1158 AuthInfo->nt_identity->Password = RPCRT4_strndupW(nt_identity->Password, nt_identity->PasswordLength);
1159 else
1160 AuthInfo->nt_identity->Password = RPCRT4_strndupAtoW((const char *)nt_identity->Password, nt_identity->PasswordLength);
1161 AuthInfo->nt_identity->PasswordLength = nt_identity->PasswordLength;
1163 if ((nt_identity->User && !AuthInfo->nt_identity->User) ||
1164 (nt_identity->Domain && !AuthInfo->nt_identity->Domain) ||
1165 (nt_identity->Password && !AuthInfo->nt_identity->Password))
1167 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
1168 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain);
1169 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password);
1170 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity);
1171 HeapFree(GetProcessHeap(), 0, AuthInfo);
1172 return ERROR_OUTOFMEMORY;
1175 else
1176 AuthInfo->nt_identity = NULL;
1177 *ret = AuthInfo;
1178 return RPC_S_OK;
1181 ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo)
1183 return InterlockedIncrement(&AuthInfo->refs);
1186 ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo)
1188 ULONG refs = InterlockedDecrement(&AuthInfo->refs);
1190 if (!refs)
1192 FreeCredentialsHandle(&AuthInfo->cred);
1193 if (AuthInfo->nt_identity)
1195 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
1196 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain);
1197 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password);
1198 HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity);
1200 HeapFree(GetProcessHeap(), 0, AuthInfo->server_principal_name);
1201 HeapFree(GetProcessHeap(), 0, AuthInfo);
1204 return refs;
1207 BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2)
1209 if (AuthInfo1 == AuthInfo2)
1210 return TRUE;
1212 if (!AuthInfo1 || !AuthInfo2)
1213 return FALSE;
1215 if ((AuthInfo1->AuthnLevel != AuthInfo2->AuthnLevel) ||
1216 (AuthInfo1->AuthnSvc != AuthInfo2->AuthnSvc))
1217 return FALSE;
1219 if (AuthInfo1->identity == AuthInfo2->identity)
1220 return TRUE;
1222 if (!AuthInfo1->identity || !AuthInfo2->identity)
1223 return FALSE;
1225 if (has_nt_auth_identity(AuthInfo1->AuthnSvc))
1227 const SEC_WINNT_AUTH_IDENTITY_W *identity1 = AuthInfo1->nt_identity;
1228 const SEC_WINNT_AUTH_IDENTITY_W *identity2 = AuthInfo2->nt_identity;
1229 /* compare user names */
1230 if (identity1->UserLength != identity2->UserLength ||
1231 memcmp(identity1->User, identity2->User, identity1->UserLength))
1232 return FALSE;
1233 /* compare domain names */
1234 if (identity1->DomainLength != identity2->DomainLength ||
1235 memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength))
1236 return FALSE;
1237 /* compare passwords */
1238 if (identity1->PasswordLength != identity2->PasswordLength ||
1239 memcmp(identity1->Password, identity2->Password, identity1->PasswordLength))
1240 return FALSE;
1242 else
1243 return FALSE;
1245 return TRUE;
1248 static RPC_STATUS RpcQualityOfService_Create(const RPC_SECURITY_QOS *qos_src, BOOL unicode, RpcQualityOfService **qos_dst)
1250 RpcQualityOfService *qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos));
1252 if (!qos)
1253 return RPC_S_OUT_OF_RESOURCES;
1255 qos->refs = 1;
1256 qos->qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos->qos));
1257 if (!qos->qos) goto error;
1258 qos->qos->Version = qos_src->Version;
1259 qos->qos->Capabilities = qos_src->Capabilities;
1260 qos->qos->IdentityTracking = qos_src->IdentityTracking;
1261 qos->qos->ImpersonationType = qos_src->ImpersonationType;
1262 qos->qos->AdditionalSecurityInfoType = 0;
1264 if (qos_src->Version >= 2)
1266 const RPC_SECURITY_QOS_V2_W *qos_src2 = (const RPC_SECURITY_QOS_V2_W *)qos_src;
1267 qos->qos->AdditionalSecurityInfoType = qos_src2->AdditionalSecurityInfoType;
1268 if (qos_src2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1270 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_src = qos_src2->u.HttpCredentials;
1271 RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_dst;
1273 http_credentials_dst = HeapAlloc(GetProcessHeap(), 0, sizeof(*http_credentials_dst));
1274 qos->qos->u.HttpCredentials = http_credentials_dst;
1275 if (!http_credentials_dst) goto error;
1276 http_credentials_dst->TransportCredentials = NULL;
1277 http_credentials_dst->Flags = http_credentials_src->Flags;
1278 http_credentials_dst->AuthenticationTarget = http_credentials_src->AuthenticationTarget;
1279 http_credentials_dst->NumberOfAuthnSchemes = http_credentials_src->NumberOfAuthnSchemes;
1280 http_credentials_dst->AuthnSchemes = NULL;
1281 http_credentials_dst->ServerCertificateSubject = NULL;
1282 if (http_credentials_src->TransportCredentials)
1284 SEC_WINNT_AUTH_IDENTITY_W *cred_dst;
1285 cred_dst = http_credentials_dst->TransportCredentials = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cred_dst));
1286 if (!cred_dst) goto error;
1287 cred_dst->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1288 if (unicode)
1290 const SEC_WINNT_AUTH_IDENTITY_W *cred_src = http_credentials_src->TransportCredentials;
1291 cred_dst->UserLength = cred_src->UserLength;
1292 cred_dst->PasswordLength = cred_src->PasswordLength;
1293 cred_dst->DomainLength = cred_src->DomainLength;
1294 cred_dst->User = RPCRT4_strndupW(cred_src->User, cred_src->UserLength);
1295 cred_dst->Password = RPCRT4_strndupW(cred_src->Password, cred_src->PasswordLength);
1296 cred_dst->Domain = RPCRT4_strndupW(cred_src->Domain, cred_src->DomainLength);
1298 else
1300 const SEC_WINNT_AUTH_IDENTITY_A *cred_src = (const SEC_WINNT_AUTH_IDENTITY_A *)http_credentials_src->TransportCredentials;
1301 cred_dst->UserLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, NULL, 0);
1302 cred_dst->DomainLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, NULL, 0);
1303 cred_dst->PasswordLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, NULL, 0);
1304 cred_dst->User = HeapAlloc(GetProcessHeap(), 0, cred_dst->UserLength * sizeof(WCHAR));
1305 cred_dst->Password = HeapAlloc(GetProcessHeap(), 0, cred_dst->PasswordLength * sizeof(WCHAR));
1306 cred_dst->Domain = HeapAlloc(GetProcessHeap(), 0, cred_dst->DomainLength * sizeof(WCHAR));
1307 if (!cred_dst->Password || !cred_dst->Domain) goto error;
1308 MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, cred_dst->User, cred_dst->UserLength);
1309 MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, cred_dst->Domain, cred_dst->DomainLength);
1310 MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, cred_dst->Password, cred_dst->PasswordLength);
1313 if (http_credentials_src->NumberOfAuthnSchemes)
1315 http_credentials_dst->AuthnSchemes = HeapAlloc(GetProcessHeap(), 0, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes));
1316 if (!http_credentials_dst->AuthnSchemes) goto error;
1317 memcpy(http_credentials_dst->AuthnSchemes, http_credentials_src->AuthnSchemes, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes));
1319 if (http_credentials_src->ServerCertificateSubject)
1321 if (unicode)
1322 http_credentials_dst->ServerCertificateSubject =
1323 RPCRT4_strndupW(http_credentials_src->ServerCertificateSubject,
1324 strlenW(http_credentials_src->ServerCertificateSubject));
1325 else
1326 http_credentials_dst->ServerCertificateSubject =
1327 RPCRT4_strdupAtoW((char *)http_credentials_src->ServerCertificateSubject);
1328 if (!http_credentials_dst->ServerCertificateSubject) goto error;
1332 *qos_dst = qos;
1333 return RPC_S_OK;
1335 error:
1336 if (qos->qos)
1338 if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP &&
1339 qos->qos->u.HttpCredentials)
1341 if (qos->qos->u.HttpCredentials->TransportCredentials)
1343 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User);
1344 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain);
1345 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password);
1346 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials);
1348 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes);
1349 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject);
1350 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials);
1352 HeapFree(GetProcessHeap(), 0, qos->qos);
1354 HeapFree(GetProcessHeap(), 0, qos);
1355 return RPC_S_OUT_OF_RESOURCES;
1358 ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos)
1360 return InterlockedIncrement(&qos->refs);
1363 ULONG RpcQualityOfService_Release(RpcQualityOfService *qos)
1365 ULONG refs = InterlockedDecrement(&qos->refs);
1367 if (!refs)
1369 if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1371 if (qos->qos->u.HttpCredentials->TransportCredentials)
1373 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User);
1374 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain);
1375 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password);
1376 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials);
1378 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes);
1379 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject);
1380 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials);
1382 HeapFree(GetProcessHeap(), 0, qos->qos);
1383 HeapFree(GetProcessHeap(), 0, qos);
1385 return refs;
1388 BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2)
1390 if (qos1 == qos2)
1391 return TRUE;
1393 if (!qos1 || !qos2)
1394 return FALSE;
1396 TRACE("qos1 = { %d %d %d %d }, qos2 = { %d %d %d %d }\n",
1397 qos1->qos->Capabilities, qos1->qos->IdentityTracking,
1398 qos1->qos->ImpersonationType, qos1->qos->AdditionalSecurityInfoType,
1399 qos2->qos->Capabilities, qos2->qos->IdentityTracking,
1400 qos2->qos->ImpersonationType, qos2->qos->AdditionalSecurityInfoType);
1402 if ((qos1->qos->Capabilities != qos2->qos->Capabilities) ||
1403 (qos1->qos->IdentityTracking != qos2->qos->IdentityTracking) ||
1404 (qos1->qos->ImpersonationType != qos2->qos->ImpersonationType) ||
1405 (qos1->qos->AdditionalSecurityInfoType != qos2->qos->AdditionalSecurityInfoType))
1406 return FALSE;
1408 if (qos1->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1410 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials1 = qos1->qos->u.HttpCredentials;
1411 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials2 = qos2->qos->u.HttpCredentials;
1413 if (http_credentials1->Flags != http_credentials2->Flags)
1414 return FALSE;
1416 if (http_credentials1->AuthenticationTarget != http_credentials2->AuthenticationTarget)
1417 return FALSE;
1419 if (http_credentials1->NumberOfAuthnSchemes != http_credentials2->NumberOfAuthnSchemes)
1420 return FALSE;
1422 if ((!http_credentials1->AuthnSchemes && http_credentials2->AuthnSchemes) ||
1423 (http_credentials1->AuthnSchemes && !http_credentials2->AuthnSchemes))
1424 return FALSE;
1426 if (memcmp(http_credentials1->AuthnSchemes, http_credentials2->AuthnSchemes,
1427 http_credentials1->NumberOfAuthnSchemes * sizeof(http_credentials1->AuthnSchemes[0])))
1428 return FALSE;
1430 /* server certificate subject not currently used */
1432 if (http_credentials1->TransportCredentials != http_credentials2->TransportCredentials)
1434 const SEC_WINNT_AUTH_IDENTITY_W *identity1 = http_credentials1->TransportCredentials;
1435 const SEC_WINNT_AUTH_IDENTITY_W *identity2 = http_credentials2->TransportCredentials;
1437 if (!identity1 || !identity2)
1438 return FALSE;
1440 /* compare user names */
1441 if (identity1->UserLength != identity2->UserLength ||
1442 memcmp(identity1->User, identity2->User, identity1->UserLength))
1443 return FALSE;
1444 /* compare domain names */
1445 if (identity1->DomainLength != identity2->DomainLength ||
1446 memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength))
1447 return FALSE;
1448 /* compare passwords */
1449 if (identity1->PasswordLength != identity2->PasswordLength ||
1450 memcmp(identity1->Password, identity2->Password, identity1->PasswordLength))
1451 return FALSE;
1455 return TRUE;
1458 /***********************************************************************
1459 * RpcRevertToSelf (RPCRT4.@)
1461 RPC_STATUS WINAPI RpcRevertToSelf(void)
1463 TRACE("\n");
1464 return RpcRevertToSelfEx(NULL);
1467 /***********************************************************************
1468 * RpcMgmtSetComTimeout (RPCRT4.@)
1470 RPC_STATUS WINAPI RpcMgmtSetComTimeout(RPC_BINDING_HANDLE BindingHandle, unsigned int Timeout)
1472 FIXME("(%p, %d): stub\n", BindingHandle, Timeout);
1473 return RPC_S_OK;
1476 /***********************************************************************
1477 * RpcBindingInqAuthInfoExA (RPCRT4.@)
1479 RPCRTAPI RPC_STATUS RPC_ENTRY
1480 RpcBindingInqAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel,
1481 ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc,
1482 ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS )
1484 RPC_STATUS status;
1485 RPC_WSTR principal;
1487 TRACE("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel,
1488 AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1490 status = RpcBindingInqAuthInfoExW(Binding, ServerPrincName ? &principal : NULL, AuthnLevel,
1491 AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1492 if (status == RPC_S_OK && ServerPrincName)
1494 *ServerPrincName = (RPC_CSTR)RPCRT4_strdupWtoA(principal);
1495 RpcStringFreeW(&principal);
1496 if (!*ServerPrincName) return ERROR_OUTOFMEMORY;
1499 return status;
1502 /***********************************************************************
1503 * RpcBindingInqAuthInfoExW (RPCRT4.@)
1505 RPCRTAPI RPC_STATUS RPC_ENTRY
1506 RpcBindingInqAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel,
1507 ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc,
1508 ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS )
1510 RpcBinding *bind = Binding;
1512 TRACE("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel,
1513 AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1515 if (!bind->AuthInfo) return RPC_S_BINDING_HAS_NO_AUTH;
1517 if (SecurityQOS)
1519 FIXME("QOS not implemented\n");
1520 return RPC_S_INVALID_BINDING;
1523 if (ServerPrincName)
1525 if (bind->AuthInfo->server_principal_name)
1527 *ServerPrincName = RPCRT4_strdupW(bind->AuthInfo->server_principal_name);
1528 if (!*ServerPrincName) return ERROR_OUTOFMEMORY;
1530 else *ServerPrincName = NULL;
1532 if (AuthnLevel) *AuthnLevel = bind->AuthInfo->AuthnLevel;
1533 if (AuthnSvc) *AuthnSvc = bind->AuthInfo->AuthnSvc;
1534 if (AuthIdentity) *AuthIdentity = bind->AuthInfo->identity;
1535 if (AuthzSvc)
1537 FIXME("authorization service not implemented\n");
1538 *AuthzSvc = RPC_C_AUTHZ_NONE;
1541 return RPC_S_OK;
1544 /***********************************************************************
1545 * RpcBindingInqAuthInfoA (RPCRT4.@)
1547 RPCRTAPI RPC_STATUS RPC_ENTRY
1548 RpcBindingInqAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel,
1549 ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc )
1551 return RpcBindingInqAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity,
1552 AuthzSvc, 0, NULL);
1555 /***********************************************************************
1556 * RpcBindingInqAuthInfoW (RPCRT4.@)
1558 RPCRTAPI RPC_STATUS RPC_ENTRY
1559 RpcBindingInqAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel,
1560 ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc )
1562 return RpcBindingInqAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity,
1563 AuthzSvc, 0, NULL);
1566 /***********************************************************************
1567 * RpcBindingInqAuthClientA (RPCRT4.@)
1569 RPCRTAPI RPC_STATUS RPC_ENTRY
1570 RpcBindingInqAuthClientA( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1571 RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1572 ULONG *AuthzSvc )
1574 return RpcBindingInqAuthClientExA(ClientBinding, Privs, ServerPrincName, AuthnLevel,
1575 AuthnSvc, AuthzSvc, 0);
1578 /***********************************************************************
1579 * RpcBindingInqAuthClientW (RPCRT4.@)
1581 RPCRTAPI RPC_STATUS RPC_ENTRY
1582 RpcBindingInqAuthClientW( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1583 RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1584 ULONG *AuthzSvc )
1586 return RpcBindingInqAuthClientExW(ClientBinding, Privs, ServerPrincName, AuthnLevel,
1587 AuthnSvc, AuthzSvc, 0);
1590 /***********************************************************************
1591 * RpcBindingInqAuthClientExA (RPCRT4.@)
1593 RPCRTAPI RPC_STATUS RPC_ENTRY
1594 RpcBindingInqAuthClientExA( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1595 RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1596 ULONG *AuthzSvc, ULONG Flags )
1598 RPC_STATUS status;
1599 RPC_WSTR principal;
1601 TRACE("%p %p %p %p %p %p 0x%x\n", ClientBinding, Privs, ServerPrincName, AuthnLevel,
1602 AuthnSvc, AuthzSvc, Flags);
1604 status = RpcBindingInqAuthClientExW(ClientBinding, Privs, ServerPrincName ? &principal : NULL,
1605 AuthnLevel, AuthnSvc, AuthzSvc, Flags);
1606 if (status == RPC_S_OK && ServerPrincName)
1608 *ServerPrincName = (RPC_CSTR)RPCRT4_strdupWtoA(principal);
1609 if (!*ServerPrincName && principal) status = ERROR_OUTOFMEMORY;
1610 RpcStringFreeW(&principal);
1613 return status;
1616 /***********************************************************************
1617 * RpcBindingInqAuthClientExW (RPCRT4.@)
1619 RPCRTAPI RPC_STATUS RPC_ENTRY
1620 RpcBindingInqAuthClientExW( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1621 RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1622 ULONG *AuthzSvc, ULONG Flags )
1624 RpcBinding *bind = ClientBinding;
1626 TRACE("%p %p %p %p %p %p 0x%x\n", ClientBinding, Privs, ServerPrincName, AuthnLevel,
1627 AuthnSvc, AuthzSvc, Flags);
1629 if (!bind->FromConn) return RPC_S_INVALID_BINDING;
1631 return rpcrt4_conn_inquire_auth_client(bind->FromConn, Privs,
1632 ServerPrincName, AuthnLevel,
1633 AuthnSvc, AuthzSvc, Flags);
1636 /***********************************************************************
1637 * RpcBindingSetAuthInfoExA (RPCRT4.@)
1639 RPCRTAPI RPC_STATUS RPC_ENTRY
1640 RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName,
1641 ULONG AuthnLevel, ULONG AuthnSvc,
1642 RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr,
1643 RPC_SECURITY_QOS *SecurityQos )
1645 RpcBinding* bind = Binding;
1646 SECURITY_STATUS r;
1647 CredHandle cred;
1648 TimeStamp exp;
1649 ULONG package_count;
1650 ULONG i;
1651 PSecPkgInfoA packages;
1652 ULONG cbMaxToken;
1654 TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_a((const char*)ServerPrincName),
1655 AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos);
1657 if (SecurityQos)
1659 RPC_STATUS status;
1661 TRACE("SecurityQos { Version=%d, Capabilities=0x%x, IdentityTracking=%d, ImpersonationLevel=%d",
1662 SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType);
1663 if (SecurityQos->Version >= 2)
1665 const RPC_SECURITY_QOS_V2_A *SecurityQos2 = (const RPC_SECURITY_QOS_V2_A *)SecurityQos;
1666 TRACE(", AdditionalSecurityInfoType=%d", SecurityQos2->AdditionalSecurityInfoType);
1667 if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1668 TRACE(", { %p, 0x%x, %d, %d, %p(%u), %s }",
1669 SecurityQos2->u.HttpCredentials->TransportCredentials,
1670 SecurityQos2->u.HttpCredentials->Flags,
1671 SecurityQos2->u.HttpCredentials->AuthenticationTarget,
1672 SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes,
1673 SecurityQos2->u.HttpCredentials->AuthnSchemes,
1674 SecurityQos2->u.HttpCredentials->AuthnSchemes ? *SecurityQos2->u.HttpCredentials->AuthnSchemes : 0,
1675 SecurityQos2->u.HttpCredentials->ServerCertificateSubject);
1677 TRACE("}\n");
1678 status = RpcQualityOfService_Create(SecurityQos, FALSE, &bind->QOS);
1679 if (status != RPC_S_OK)
1680 return status;
1682 else
1684 if (bind->QOS) RpcQualityOfService_Release(bind->QOS);
1685 bind->QOS = NULL;
1688 if (AuthnSvc == RPC_C_AUTHN_DEFAULT)
1689 AuthnSvc = RPC_C_AUTHN_WINNT;
1691 /* FIXME: the mapping should probably be retrieved using SSPI somehow */
1692 if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
1693 AuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
1695 if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE))
1697 if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1698 bind->AuthInfo = NULL;
1699 return RPC_S_OK;
1702 if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
1704 FIXME("unknown AuthnLevel %u\n", AuthnLevel);
1705 return RPC_S_UNKNOWN_AUTHN_LEVEL;
1708 /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
1709 if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
1711 FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
1712 return RPC_S_UNKNOWN_AUTHZ_SERVICE;
1715 r = EnumerateSecurityPackagesA(&package_count, &packages);
1716 if (r != SEC_E_OK)
1718 ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r);
1719 return RPC_S_SEC_PKG_ERROR;
1722 for (i = 0; i < package_count; i++)
1723 if (packages[i].wRPCID == AuthnSvc)
1724 break;
1726 if (i == package_count)
1728 FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
1729 FreeContextBuffer(packages);
1730 return RPC_S_UNKNOWN_AUTHN_SERVICE;
1733 TRACE("found package %s for service %u\n", packages[i].Name, AuthnSvc);
1734 r = AcquireCredentialsHandleA(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
1735 AuthIdentity, NULL, NULL, &cred, &exp);
1736 cbMaxToken = packages[i].cbMaxToken;
1737 FreeContextBuffer(packages);
1738 if (r == ERROR_SUCCESS)
1740 RpcAuthInfo *new_auth_info;
1741 r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken,
1742 AuthIdentity, &new_auth_info);
1743 if (r == RPC_S_OK)
1745 new_auth_info->server_principal_name = RPCRT4_strdupAtoW((char *)ServerPrincName);
1746 if (!ServerPrincName || new_auth_info->server_principal_name)
1748 if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1749 bind->AuthInfo = new_auth_info;
1751 else
1753 RpcAuthInfo_Release(new_auth_info);
1754 r = ERROR_OUTOFMEMORY;
1757 else
1758 FreeCredentialsHandle(&cred);
1759 return r;
1761 else
1763 ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r);
1764 return RPC_S_SEC_PKG_ERROR;
1768 /***********************************************************************
1769 * RpcBindingSetAuthInfoExW (RPCRT4.@)
1771 RPCRTAPI RPC_STATUS RPC_ENTRY
1772 RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel,
1773 ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr,
1774 RPC_SECURITY_QOS *SecurityQos )
1776 RpcBinding* bind = Binding;
1777 SECURITY_STATUS r;
1778 CredHandle cred;
1779 TimeStamp exp;
1780 ULONG package_count;
1781 ULONG i;
1782 PSecPkgInfoW packages;
1783 ULONG cbMaxToken;
1785 TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w(ServerPrincName),
1786 AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos);
1788 if (SecurityQos)
1790 RPC_STATUS status;
1792 TRACE("SecurityQos { Version=%d, Capabilities=0x%x, IdentityTracking=%d, ImpersonationLevel=%d",
1793 SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType);
1794 if (SecurityQos->Version >= 2)
1796 const RPC_SECURITY_QOS_V2_W *SecurityQos2 = (const RPC_SECURITY_QOS_V2_W *)SecurityQos;
1797 TRACE(", AdditionalSecurityInfoType=%d", SecurityQos2->AdditionalSecurityInfoType);
1798 if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1799 TRACE(", { %p, 0x%x, %d, %d, %p(%u), %s }",
1800 SecurityQos2->u.HttpCredentials->TransportCredentials,
1801 SecurityQos2->u.HttpCredentials->Flags,
1802 SecurityQos2->u.HttpCredentials->AuthenticationTarget,
1803 SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes,
1804 SecurityQos2->u.HttpCredentials->AuthnSchemes,
1805 SecurityQos2->u.HttpCredentials->AuthnSchemes ? *SecurityQos2->u.HttpCredentials->AuthnSchemes : 0,
1806 debugstr_w(SecurityQos2->u.HttpCredentials->ServerCertificateSubject));
1808 TRACE("}\n");
1809 status = RpcQualityOfService_Create(SecurityQos, TRUE, &bind->QOS);
1810 if (status != RPC_S_OK)
1811 return status;
1813 else
1815 if (bind->QOS) RpcQualityOfService_Release(bind->QOS);
1816 bind->QOS = NULL;
1819 if (AuthnSvc == RPC_C_AUTHN_DEFAULT)
1820 AuthnSvc = RPC_C_AUTHN_WINNT;
1822 /* FIXME: the mapping should probably be retrieved using SSPI somehow */
1823 if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
1824 AuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
1826 if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE))
1828 if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1829 bind->AuthInfo = NULL;
1830 return RPC_S_OK;
1833 if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
1835 FIXME("unknown AuthnLevel %u\n", AuthnLevel);
1836 return RPC_S_UNKNOWN_AUTHN_LEVEL;
1839 /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
1840 if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
1842 FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
1843 return RPC_S_UNKNOWN_AUTHZ_SERVICE;
1846 r = EnumerateSecurityPackagesW(&package_count, &packages);
1847 if (r != SEC_E_OK)
1849 ERR("EnumerateSecurityPackagesW failed with error 0x%08x\n", r);
1850 return RPC_S_SEC_PKG_ERROR;
1853 for (i = 0; i < package_count; i++)
1854 if (packages[i].wRPCID == AuthnSvc)
1855 break;
1857 if (i == package_count)
1859 FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
1860 FreeContextBuffer(packages);
1861 return RPC_S_UNKNOWN_AUTHN_SERVICE;
1864 TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), AuthnSvc);
1865 r = AcquireCredentialsHandleW(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
1866 AuthIdentity, NULL, NULL, &cred, &exp);
1867 cbMaxToken = packages[i].cbMaxToken;
1868 FreeContextBuffer(packages);
1869 if (r == ERROR_SUCCESS)
1871 RpcAuthInfo *new_auth_info;
1872 r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken,
1873 AuthIdentity, &new_auth_info);
1874 if (r == RPC_S_OK)
1876 new_auth_info->server_principal_name = RPCRT4_strdupW(ServerPrincName);
1877 if (!ServerPrincName || new_auth_info->server_principal_name)
1879 if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1880 bind->AuthInfo = new_auth_info;
1882 else
1884 RpcAuthInfo_Release(new_auth_info);
1885 r = ERROR_OUTOFMEMORY;
1888 else
1889 FreeCredentialsHandle(&cred);
1890 return r;
1892 else
1894 ERR("AcquireCredentialsHandleW failed with error 0x%08x\n", r);
1895 return RPC_S_SEC_PKG_ERROR;
1899 /***********************************************************************
1900 * RpcBindingSetAuthInfoA (RPCRT4.@)
1902 RPCRTAPI RPC_STATUS RPC_ENTRY
1903 RpcBindingSetAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, ULONG AuthnLevel,
1904 ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr )
1906 TRACE("%p %s %u %u %p %u\n", Binding, debugstr_a((const char*)ServerPrincName),
1907 AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr);
1908 return RpcBindingSetAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL);
1911 /***********************************************************************
1912 * RpcBindingSetAuthInfoW (RPCRT4.@)
1914 RPCRTAPI RPC_STATUS RPC_ENTRY
1915 RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel,
1916 ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr )
1918 TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w(ServerPrincName),
1919 AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr);
1920 return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL);
1923 /***********************************************************************
1924 * RpcBindingSetOption (RPCRT4.@)
1926 RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG_PTR OptionValue)
1928 TRACE("(%p, %d, %ld)\n", BindingHandle, Option, OptionValue);
1930 switch (Option)
1932 case RPC_C_OPT_COOKIE_AUTH:
1934 RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR *cookie = (RPC_C_OPT_COOKIE_AUTH_DESCRIPTOR *)OptionValue;
1935 RpcBinding *binding = BindingHandle;
1936 int len = MultiByteToWideChar(CP_ACP, 0, cookie->Buffer, cookie->BufferSize, NULL, 0);
1937 WCHAR *str;
1939 if (!(str = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)))) return ERROR_OUTOFMEMORY;
1940 MultiByteToWideChar(CP_ACP, 0, cookie->Buffer, cookie->BufferSize, str, len);
1941 str[len] = 0;
1942 HeapFree(GetProcessHeap(), 0, binding->CookieAuth);
1943 binding->CookieAuth = str;
1944 break;
1946 default:
1947 FIXME("option %u not supported\n", Option);
1948 break;
1950 return RPC_S_OK;