msi/test: Uninstall the test product when skipping patch tests.
[wine] / dlls / rpcrt4 / rpc_binding.c
1 /*
2  * RPC binding API
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003 Mike Hearn
6  * Copyright 2004 Filip Navara
7  * Copyright 2006 CodeWeavers
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28
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"
35
36 #include "rpc.h"
37 #include "rpcndr.h"
38
39 #include "wine/debug.h"
40
41 #include "rpc_binding.h"
42 #include "rpc_assoc.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
45
46 LPSTR RPCRT4_strndupA(LPCSTR src, INT slen)
47 {
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;
57 }
58
59 LPSTR RPCRT4_strdupWtoA(LPCWSTR src)
60 {
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;
68 }
69
70 LPWSTR RPCRT4_strdupAtoW(LPCSTR src)
71 {
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;
79 }
80
81 static LPWSTR RPCRT4_strndupAtoW(LPCSTR src, INT slen)
82 {
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;
90 }
91
92 LPWSTR RPCRT4_strndupW(LPCWSTR src, INT slen)
93 {
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;
103 }
104
105 void RPCRT4_strfree(LPSTR src)
106 {
107   HeapFree(GetProcessHeap(), 0, src);
108 }
109
110 static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
111 {
112   RpcBinding* NewBinding;
113
114   NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
115   NewBinding->refs = 1;
116   NewBinding->server = server;
117
118   *Binding = NewBinding;
119
120   return RPC_S_OK;
121 }
122
123 static RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPCSTR Protseq)
124 {
125   RpcBinding* NewBinding;
126
127   RPCRT4_AllocBinding(&NewBinding, server);
128   NewBinding->Protseq = RPCRT4_strdupA(Protseq);
129
130   TRACE("binding: %p\n", NewBinding);
131   *Binding = NewBinding;
132
133   return RPC_S_OK;
134 }
135
136 static RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPCWSTR Protseq)
137 {
138   RpcBinding* NewBinding;
139
140   RPCRT4_AllocBinding(&NewBinding, server);
141   NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
142
143   TRACE("binding: %p\n", NewBinding);
144   *Binding = NewBinding;
145
146   return RPC_S_OK;
147 }
148
149 static RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPCSTR NetworkAddr,
150                                           LPCSTR Endpoint, LPCSTR NetworkOptions)
151 {
152   RPC_STATUS status;
153
154   TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding,
155    debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
156
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);
163
164   /* only attempt to get an association if the binding is complete */
165   if (Endpoint && Endpoint[0] != '\0')
166   {
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;
172   }
173
174   return RPC_S_OK;
175 }
176
177 static RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPCWSTR NetworkAddr,
178                                           LPCWSTR Endpoint, LPCWSTR NetworkOptions)
179 {
180   RPC_STATUS status;
181
182   TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding, 
183    debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
184
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);
191
192   /* only attempt to get an association if the binding is complete */
193   if (Endpoint && Endpoint[0] != '\0')
194   {
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;
200   }
201
202   return RPC_S_OK;
203 }
204
205 RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint)
206 {
207   RPC_STATUS status;
208
209   TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
210
211   RPCRT4_strfree(Binding->Endpoint);
212   Binding->Endpoint = RPCRT4_strdupA(Endpoint);
213
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;
221
222   return RPC_S_OK;
223 }
224
225 RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid)
226 {
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;
231 }
232
233 RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
234 {
235   RpcBinding* NewBinding;
236   TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection);
237
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;
243
244   TRACE("binding: %p\n", NewBinding);
245   *Binding = NewBinding;
246
247   return RPC_S_OK;
248 }
249
250 void RPCRT4_AddRefBinding(RpcBinding* Binding)
251 {
252   InterlockedIncrement(&Binding->refs);
253 }
254
255 RPC_STATUS RPCRT4_ReleaseBinding(RpcBinding* Binding)
256 {
257   if (InterlockedDecrement(&Binding->refs))
258     return RPC_S_OK;
259
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   if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo);
267   if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS);
268   HeapFree(GetProcessHeap(), 0, Binding);
269   return RPC_S_OK;
270 }
271
272 RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection,
273                               const RPC_SYNTAX_IDENTIFIER *TransferSyntax,
274                               const RPC_SYNTAX_IDENTIFIER *InterfaceId)
275 {
276   TRACE("(Binding == ^%p)\n", Binding);
277
278   if (!Binding->server) {
279      return RpcAssoc_GetClientConnection(Binding->Assoc, InterfaceId,
280          TransferSyntax, Binding->AuthInfo, Binding->QOS, Connection);
281   } else {
282     /* we already have a connection with acceptable binding, so use it */
283     if (Binding->FromConn) {
284       *Connection = Binding->FromConn;
285       return RPC_S_OK;
286     } else {
287        ERR("no connection in binding\n");
288        return RPC_S_INTERNAL_ERROR;
289     }
290   }
291 }
292
293 RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
294 {
295   TRACE("(Binding == ^%p)\n", Binding);
296   if (!Connection) return RPC_S_OK;
297   if (Binding->server) {
298     /* don't destroy a connection that is cached in the binding */
299     if (Binding->FromConn == Connection)
300       return RPC_S_OK;
301     return RPCRT4_DestroyConnection(Connection);
302   }
303   else {
304     RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection);
305     return RPC_S_OK;
306   }
307 }
308
309 static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src)
310 {
311   DWORD len = strlen(dst), slen = strlen(src);
312   LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR));
313   if (!ndst)
314   {
315     HeapFree(GetProcessHeap(), 0, dst);
316     return NULL;
317   }
318   ndst[len] = ',';
319   memcpy(ndst+len+1, src, slen+1);
320   return ndst;
321 }
322
323 static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src)
324 {
325   DWORD len = strlenW(dst), slen = strlenW(src);
326   LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR));
327   if (!ndst) 
328   {
329     HeapFree(GetProcessHeap(), 0, dst);
330     return NULL;
331   }
332   ndst[len] = ',';
333   memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR));
334   return ndst;
335 }
336
337 /* Copies the escaped version of a component into a string binding.
338  * Note: doesn't nul-terminate the string */
339 static RPC_CSTR escape_string_binding_component(RPC_CSTR string_binding,
340                                                 const unsigned char *component)
341 {
342   for (; *component; component++) {
343     switch (*component) {
344       case '@':
345       case ':':
346       case '[':
347       case ']':
348       case '\\':
349         *string_binding++ = '\\';
350         *string_binding++ = *component;
351         break;
352       default:
353         *string_binding++ = *component;
354         break;
355     }
356   }
357   return string_binding;
358 }
359
360 static RPC_WSTR escape_string_binding_componentW(RPC_WSTR string_binding,
361                                                  const WCHAR *component)
362 {
363   for (; *component; component++) {
364     switch (*component) {
365       case '@':
366       case ':':
367       case '[':
368       case ']':
369       case '\\':
370         *string_binding++ = '\\';
371         *string_binding++ = *component;
372         break;
373       default:
374         *string_binding++ = *component;
375         break;
376     }
377   }
378   return string_binding;
379 }
380
381 static const unsigned char *string_binding_find_delimiter(
382     const unsigned char *string_binding, unsigned char delim)
383 {
384   const unsigned char *next;
385   for (next = string_binding; *next; next++) {
386     if (*next == '\\') {
387       next++;
388       continue;
389     }
390     if (*next == delim)
391       return next;
392   }
393   return NULL;
394 }
395
396 static const WCHAR *string_binding_find_delimiterW(
397     const WCHAR *string_binding, WCHAR delim)
398 {
399   const WCHAR *next;
400   for (next = string_binding; *next; next++) {
401     if (*next == '\\') {
402       next++;
403       continue;
404     }
405     if (*next == delim)
406       return next;
407   }
408   return NULL;
409 }
410
411 static RPC_CSTR unescape_string_binding_component(
412     const unsigned char *string_binding, int len)
413 {
414   RPC_CSTR component, p;
415
416   if (len == -1) len = strlen((const char *)string_binding);
417
418   component = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*component));
419   if (!component) return NULL;
420   for (p = component; len > 0; string_binding++, len--) {
421     if (*string_binding == '\\') {
422       string_binding++;
423       len--;
424       *p++ = *string_binding;
425     } else {
426       *p++ = *string_binding;
427     }
428   }
429   *p = '\0';
430   return component;
431 }
432
433 static RPC_WSTR unescape_string_binding_componentW(
434     const WCHAR *string_binding, int len)
435 {
436   RPC_WSTR component, p;
437
438   if (len == -1) len = strlenW(string_binding);
439
440   component = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(*component));
441   if (!component) return NULL;
442   for (p = component; len > 0; string_binding++, len--) {
443     if (*string_binding == '\\') {
444       string_binding++;
445       len--;
446       *p++ = *string_binding;
447     } else {
448       *p++ = *string_binding;
449     }
450   }
451   *p = '\0';
452   return component;
453 }
454
455 /***********************************************************************
456  *             RpcStringBindingComposeA (RPCRT4.@)
457  */
458 RPC_STATUS WINAPI RpcStringBindingComposeA(RPC_CSTR ObjUuid, RPC_CSTR Protseq,
459                                            RPC_CSTR NetworkAddr, RPC_CSTR Endpoint,
460                                            RPC_CSTR Options, RPC_CSTR *StringBinding )
461 {
462   DWORD len = 1;
463   RPC_CSTR data;
464
465   TRACE( "(%s,%s,%s,%s,%s,%p)\n",
466         debugstr_a( (char*)ObjUuid ), debugstr_a( (char*)Protseq ),
467         debugstr_a( (char*)NetworkAddr ), debugstr_a( (char*)Endpoint ),
468         debugstr_a( (char*)Options ), StringBinding );
469
470   /* overestimate for each component for escaping of delimiters */
471   if (ObjUuid && *ObjUuid) len += strlen((char*)ObjUuid) * 2 + 1;
472   if (Protseq && *Protseq) len += strlen((char*)Protseq) * 2 + 1;
473   if (NetworkAddr && *NetworkAddr) len += strlen((char*)NetworkAddr) * 2;
474   if (Endpoint && *Endpoint) len += strlen((char*)Endpoint) * 2 + 2;
475   if (Options && *Options) len += strlen((char*)Options) * 2 + 2;
476
477   data = HeapAlloc(GetProcessHeap(), 0, len);
478   *StringBinding = data;
479
480   if (ObjUuid && *ObjUuid) {
481     data = escape_string_binding_component(data, ObjUuid);
482     *data++ = '@';
483   }
484   if (Protseq && *Protseq) {
485     data = escape_string_binding_component(data, Protseq);
486     *data++ = ':';
487   }
488   if (NetworkAddr && *NetworkAddr)
489     data = escape_string_binding_component(data, NetworkAddr);
490
491   if ((Endpoint && *Endpoint) ||
492       (Options && *Options)) {
493     *data++ = '[';
494     if (Endpoint && *Endpoint) {
495       data = escape_string_binding_component(data, Endpoint);
496       if (Options && *Options) *data++ = ',';
497     }
498     if (Options && *Options) {
499       data = escape_string_binding_component(data, Options);
500     }
501     *data++ = ']';
502   }
503   *data = 0;
504
505   return RPC_S_OK;
506 }
507
508 /***********************************************************************
509  *             RpcStringBindingComposeW (RPCRT4.@)
510  */
511 RPC_STATUS WINAPI RpcStringBindingComposeW( RPC_WSTR ObjUuid, RPC_WSTR Protseq,
512                                             RPC_WSTR NetworkAddr, RPC_WSTR Endpoint,
513                                             RPC_WSTR Options, RPC_WSTR* StringBinding )
514 {
515   DWORD len = 1;
516   RPC_WSTR data;
517
518   TRACE("(%s,%s,%s,%s,%s,%p)\n",
519        debugstr_w( ObjUuid ), debugstr_w( Protseq ),
520        debugstr_w( NetworkAddr ), debugstr_w( Endpoint ),
521        debugstr_w( Options ), StringBinding);
522
523   /* overestimate for each component for escaping of delimiters */
524   if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) * 2 + 1;
525   if (Protseq && *Protseq) len += strlenW(Protseq) * 2 + 1;
526   if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr) * 2;
527   if (Endpoint && *Endpoint) len += strlenW(Endpoint) * 2 + 2;
528   if (Options && *Options) len += strlenW(Options) * 2 + 2;
529
530   data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
531   *StringBinding = data;
532
533   if (ObjUuid && *ObjUuid) {
534     data = escape_string_binding_componentW(data, ObjUuid);
535     *data++ = '@';
536   }
537   if (Protseq && *Protseq) {
538     data = escape_string_binding_componentW(data, Protseq);
539     *data++ = ':';
540   }
541   if (NetworkAddr && *NetworkAddr) {
542     data = escape_string_binding_componentW(data, NetworkAddr);
543   }
544   if ((Endpoint && *Endpoint) ||
545       (Options && *Options)) {
546     *data++ = '[';
547     if (Endpoint && *Endpoint) {
548       data = escape_string_binding_componentW(data, Endpoint);
549       if (Options && *Options) *data++ = ',';
550     }
551     if (Options && *Options) {
552       data = escape_string_binding_componentW(data, Options);
553     }
554     *data++ = ']';
555   }
556   *data = 0;
557
558   return RPC_S_OK;
559 }
560
561
562 /***********************************************************************
563  *             RpcStringBindingParseA (RPCRT4.@)
564  */
565 RPC_STATUS WINAPI RpcStringBindingParseA( RPC_CSTR StringBinding, RPC_CSTR *ObjUuid,
566                                           RPC_CSTR *Protseq, RPC_CSTR *NetworkAddr,
567                                           RPC_CSTR *Endpoint, RPC_CSTR *Options)
568 {
569   const unsigned char *data, *next;
570   static const char ep_opt[] = "endpoint=";
571   BOOL endpoint_already_found = FALSE;
572
573   TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a((char*)StringBinding),
574        ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
575
576   if (ObjUuid) *ObjUuid = NULL;
577   if (Protseq) *Protseq = NULL;
578   if (NetworkAddr) *NetworkAddr = NULL;
579   if (Endpoint) *Endpoint = NULL;
580   if (Options) *Options = NULL;
581
582   data = StringBinding;
583
584   next = string_binding_find_delimiter(data, '@');
585   if (next) {
586     UUID uuid;
587     RPC_STATUS status;
588     RPC_CSTR str_uuid = unescape_string_binding_component(data, next - data);
589     status = UuidFromStringA(str_uuid, &uuid);
590     if (status != RPC_S_OK) {
591       HeapFree(GetProcessHeap(), 0, str_uuid);
592       return status;
593     }
594     if (ObjUuid)
595       *ObjUuid = str_uuid;
596     else
597       HeapFree(GetProcessHeap(), 0, str_uuid);
598     data = next+1;
599   }
600
601   next = string_binding_find_delimiter(data, ':');
602   if (next) {
603     if (Protseq) *Protseq = unescape_string_binding_component(data, next - data);
604     data = next+1;
605   }
606
607   next = string_binding_find_delimiter(data, '[');
608   if (next) {
609     const unsigned char *close;
610     RPC_CSTR opt;
611
612     if (NetworkAddr) *NetworkAddr = unescape_string_binding_component(data, next - data);
613     data = next+1;
614     close = string_binding_find_delimiter(data, ']');
615     if (!close) goto fail;
616
617     /* tokenize options */
618     while (data < close) {
619       next = string_binding_find_delimiter(data, ',');
620       if (!next || next > close) next = close;
621       /* FIXME: this is kind of inefficient */
622       opt = unescape_string_binding_component(data, next - data);
623       data = next+1;
624
625       /* parse option */
626       next = string_binding_find_delimiter(opt, '=');
627       if (!next) {
628         /* not an option, must be an endpoint */
629         if (endpoint_already_found) goto fail;
630         if (Endpoint) *Endpoint = opt;
631         else HeapFree(GetProcessHeap(), 0, opt);
632         endpoint_already_found = TRUE;
633       } else {
634         if (strncmp((const char *)opt, ep_opt, strlen(ep_opt)) == 0) {
635           /* endpoint option */
636           if (endpoint_already_found) goto fail;
637           if (Endpoint) *Endpoint = unescape_string_binding_component(next+1, -1);
638           HeapFree(GetProcessHeap(), 0, opt);
639           endpoint_already_found = TRUE;
640         } else {
641           /* network option */
642           if (Options) {
643             if (*Options) {
644               /* FIXME: this is kind of inefficient */
645               *Options = (unsigned char*) RPCRT4_strconcatA( (char*)*Options, (char *)opt);
646               HeapFree(GetProcessHeap(), 0, opt);
647             } else
648               *Options = opt;
649           } else
650             HeapFree(GetProcessHeap(), 0, opt);
651         }
652       }
653     }
654
655     data = close+1;
656     if (*data) goto fail;
657   }
658   else if (NetworkAddr) 
659     *NetworkAddr = unescape_string_binding_component(data, -1);
660
661   return RPC_S_OK;
662
663 fail:
664   if (ObjUuid) RpcStringFreeA(ObjUuid);
665   if (Protseq) RpcStringFreeA(Protseq);
666   if (NetworkAddr) RpcStringFreeA(NetworkAddr);
667   if (Endpoint) RpcStringFreeA(Endpoint);
668   if (Options) RpcStringFreeA(Options);
669   return RPC_S_INVALID_STRING_BINDING;
670 }
671
672 /***********************************************************************
673  *             RpcStringBindingParseW (RPCRT4.@)
674  */
675 RPC_STATUS WINAPI RpcStringBindingParseW( RPC_WSTR StringBinding, RPC_WSTR *ObjUuid,
676                                           RPC_WSTR *Protseq, RPC_WSTR *NetworkAddr,
677                                           RPC_WSTR *Endpoint, RPC_WSTR *Options)
678 {
679   const WCHAR *data, *next;
680   static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0};
681   BOOL endpoint_already_found = FALSE;
682
683   TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding),
684        ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
685
686   if (ObjUuid) *ObjUuid = NULL;
687   if (Protseq) *Protseq = NULL;
688   if (NetworkAddr) *NetworkAddr = NULL;
689   if (Endpoint) *Endpoint = NULL;
690   if (Options) *Options = NULL;
691
692   data = StringBinding;
693
694   next = string_binding_find_delimiterW(data, '@');
695   if (next) {
696     UUID uuid;
697     RPC_STATUS status;
698     RPC_WSTR str_uuid = unescape_string_binding_componentW(data, next - data);
699     status = UuidFromStringW(str_uuid, &uuid);
700     if (status != RPC_S_OK) {
701       HeapFree(GetProcessHeap(), 0, str_uuid);
702       return status;
703     }
704     if (ObjUuid)
705       *ObjUuid = str_uuid;
706     else
707       HeapFree(GetProcessHeap(), 0, str_uuid);
708     data = next+1;
709   }
710
711   next = string_binding_find_delimiterW(data, ':');
712   if (next) {
713     if (Protseq) *Protseq = unescape_string_binding_componentW(data, next - data);
714     data = next+1;
715   }
716
717   next = string_binding_find_delimiterW(data, '[');
718   if (next) {
719     const WCHAR *close;
720     RPC_WSTR opt;
721
722     if (NetworkAddr) *NetworkAddr = unescape_string_binding_componentW(data, next - data);
723     data = next+1;
724     close = string_binding_find_delimiterW(data, ']');
725     if (!close) goto fail;
726
727     /* tokenize options */
728     while (data < close) {
729       next = string_binding_find_delimiterW(data, ',');
730       if (!next || next > close) next = close;
731       /* FIXME: this is kind of inefficient */
732       opt = unescape_string_binding_componentW(data, next - data);
733       data = next+1;
734
735       /* parse option */
736       next = string_binding_find_delimiterW(opt, '=');
737       if (!next) {
738         /* not an option, must be an endpoint */
739         if (endpoint_already_found) goto fail;
740         if (Endpoint) *Endpoint = opt;
741         else HeapFree(GetProcessHeap(), 0, opt);
742         endpoint_already_found = TRUE;
743       } else {
744         if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) {
745           /* endpoint option */
746           if (endpoint_already_found) goto fail;
747           if (Endpoint) *Endpoint = unescape_string_binding_componentW(next+1, -1);
748           HeapFree(GetProcessHeap(), 0, opt);
749           endpoint_already_found = TRUE;
750         } else {
751           /* network option */
752           if (Options) {
753             if (*Options) {
754               /* FIXME: this is kind of inefficient */
755               *Options = RPCRT4_strconcatW(*Options, opt);
756               HeapFree(GetProcessHeap(), 0, opt);
757             } else
758               *Options = opt;
759           } else
760             HeapFree(GetProcessHeap(), 0, opt);
761         }
762       }
763     }
764
765     data = close+1;
766     if (*data) goto fail;
767   } else if (NetworkAddr) 
768     *NetworkAddr = unescape_string_binding_componentW(data, -1);
769
770   return RPC_S_OK;
771
772 fail:
773   if (ObjUuid) RpcStringFreeW(ObjUuid);
774   if (Protseq) RpcStringFreeW(Protseq);
775   if (NetworkAddr) RpcStringFreeW(NetworkAddr);
776   if (Endpoint) RpcStringFreeW(Endpoint);
777   if (Options) RpcStringFreeW(Options);
778   return RPC_S_INVALID_STRING_BINDING;
779 }
780
781 /***********************************************************************
782  *             RpcBindingFree (RPCRT4.@)
783  */
784 RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding )
785 {
786   RPC_STATUS status;
787   TRACE("(%p) = %p\n", Binding, *Binding);
788   if (*Binding)
789     status = RPCRT4_ReleaseBinding(*Binding);
790   else
791     status = RPC_S_INVALID_BINDING;
792   if (status == RPC_S_OK) *Binding = NULL;
793   return status;
794 }
795   
796 /***********************************************************************
797  *             RpcBindingVectorFree (RPCRT4.@)
798  */
799 RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector )
800 {
801   RPC_STATUS status;
802   ULONG c;
803
804   TRACE("(%p)\n", BindingVector);
805   for (c=0; c<(*BindingVector)->Count; c++) {
806     status = RpcBindingFree(&(*BindingVector)->BindingH[c]);
807   }
808   HeapFree(GetProcessHeap(), 0, *BindingVector);
809   *BindingVector = NULL;
810   return RPC_S_OK;
811 }
812   
813 /***********************************************************************
814  *             RpcBindingInqObject (RPCRT4.@)
815  */
816 RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
817 {
818   RpcBinding* bind = Binding;
819
820   TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid));
821   *ObjectUuid = bind->ObjectUuid;
822   return RPC_S_OK;
823 }
824
825 /***********************************************************************
826  *             RpcBindingSetObject (RPCRT4.@)
827  */
828 RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
829 {
830   RpcBinding* bind = Binding;
831
832   TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid));
833   if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING;
834   return RPCRT4_SetBindingObject(Binding, ObjectUuid);
835 }
836
837 /***********************************************************************
838  *             RpcBindingFromStringBindingA (RPCRT4.@)
839  */
840 RPC_STATUS WINAPI RpcBindingFromStringBindingA( RPC_CSTR StringBinding, RPC_BINDING_HANDLE* Binding )
841 {
842   RPC_STATUS ret;
843   RpcBinding* bind = NULL;
844   RPC_CSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
845   UUID Uuid;
846
847   TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding), Binding);
848
849   ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq,
850                               &NetworkAddr, &Endpoint, &Options);
851   if (ret != RPC_S_OK) return ret;
852
853   ret = UuidFromStringA(ObjectUuid, &Uuid);
854
855   if (ret == RPC_S_OK)
856     ret = RPCRT4_CreateBindingA(&bind, FALSE, (char*)Protseq);
857   if (ret != RPC_S_OK) return ret;
858   ret = RPCRT4_SetBindingObject(bind, &Uuid);
859   if (ret == RPC_S_OK)
860     ret = RPCRT4_CompleteBindingA(bind, (char*)NetworkAddr, (char*)Endpoint, (char*)Options);
861
862   RpcStringFreeA(&Options);
863   RpcStringFreeA(&Endpoint);
864   RpcStringFreeA(&NetworkAddr);
865   RpcStringFreeA(&Protseq);
866   RpcStringFreeA(&ObjectUuid);
867
868   if (ret == RPC_S_OK) 
869     *Binding = (RPC_BINDING_HANDLE)bind;
870   else 
871     RPCRT4_ReleaseBinding(bind);
872
873   return ret;
874 }
875
876 /***********************************************************************
877  *             RpcBindingFromStringBindingW (RPCRT4.@)
878  */
879 RPC_STATUS WINAPI RpcBindingFromStringBindingW( RPC_WSTR StringBinding, RPC_BINDING_HANDLE* Binding )
880 {
881   RPC_STATUS ret;
882   RpcBinding* bind = NULL;
883   RPC_WSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
884   UUID Uuid;
885
886   TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding);
887
888   ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq,
889                               &NetworkAddr, &Endpoint, &Options);
890   if (ret != RPC_S_OK) return ret;
891
892   ret = UuidFromStringW(ObjectUuid, &Uuid);
893
894   if (ret == RPC_S_OK)
895     ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq);
896   if (ret != RPC_S_OK) return ret;
897   ret = RPCRT4_SetBindingObject(bind, &Uuid);
898   if (ret == RPC_S_OK)
899     ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options);
900
901   RpcStringFreeW(&Options);
902   RpcStringFreeW(&Endpoint);
903   RpcStringFreeW(&NetworkAddr);
904   RpcStringFreeW(&Protseq);
905   RpcStringFreeW(&ObjectUuid);
906
907   if (ret == RPC_S_OK)
908     *Binding = (RPC_BINDING_HANDLE)bind;
909   else
910     RPCRT4_ReleaseBinding(bind);
911
912   return ret;
913 }
914   
915 /***********************************************************************
916  *             RpcBindingToStringBindingA (RPCRT4.@)
917  */
918 RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, RPC_CSTR *StringBinding )
919 {
920   RPC_STATUS ret;
921   RpcBinding* bind = Binding;
922   RPC_CSTR ObjectUuid;
923
924   TRACE("(%p,%p)\n", Binding, StringBinding);
925
926   if (UuidIsNil(&bind->ObjectUuid, &ret))
927     ObjectUuid = NULL;
928   else
929   {
930     ret = UuidToStringA(&bind->ObjectUuid, &ObjectUuid);
931     if (ret != RPC_S_OK) return ret;
932   }
933
934   ret = RpcStringBindingComposeA(ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr,
935                                  (unsigned char*) bind->Endpoint, NULL, StringBinding);
936
937   RpcStringFreeA(&ObjectUuid);
938
939   return ret;
940 }
941   
942 /***********************************************************************
943  *             RpcBindingToStringBindingW (RPCRT4.@)
944  */
945 RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, RPC_WSTR *StringBinding )
946 {
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;
954 }
955
956 /***********************************************************************
957  *             I_RpcBindingInqTransportType (RPCRT4.@)
958  */
959 RPC_STATUS WINAPI I_RpcBindingInqTransportType( RPC_BINDING_HANDLE Binding, unsigned int * Type )
960 {
961
962   FIXME( "(%p,%p): stub\n", Binding, Type);
963   *Type = TRANSPORT_TYPE_LPC;
964   return RPC_S_OK;
965 }
966
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).
972  */
973 RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn)
974 {
975   RpcBinding* bind = Binding;
976
977   TRACE( "(%p,%p): stub\n", Binding, BlockingFn );
978
979   bind->BlockingFn = BlockingFn;
980
981   return RPC_S_OK;
982 }
983
984 /***********************************************************************
985  *             RpcBindingCopy (RPCRT4.@)
986  */
987 RPC_STATUS RPC_ENTRY RpcBindingCopy(
988   RPC_BINDING_HANDLE SourceBinding,
989   RPC_BINDING_HANDLE* DestinationBinding)
990 {
991   RpcBinding *DestBinding;
992   RpcBinding *SrcBinding = SourceBinding;
993   RPC_STATUS status;
994
995   TRACE("(%p, %p)\n", SourceBinding, DestinationBinding);
996
997   status = RPCRT4_AllocBinding(&DestBinding, SrcBinding->server);
998   if (status != RPC_S_OK) return status;
999
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   if (SrcBinding->Assoc) SrcBinding->Assoc->refs++;
1007   DestBinding->Assoc = SrcBinding->Assoc;
1008
1009   if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo);
1010   DestBinding->AuthInfo = SrcBinding->AuthInfo;
1011   if (SrcBinding->QOS) RpcQualityOfService_AddRef(SrcBinding->QOS);
1012   DestBinding->QOS = SrcBinding->QOS;
1013
1014   *DestinationBinding = DestBinding;
1015   return RPC_S_OK;
1016 }
1017
1018 /***********************************************************************
1019  *             RpcBindingReset (RPCRT4.@)
1020  */
1021 RPC_STATUS RPC_ENTRY RpcBindingReset(RPC_BINDING_HANDLE Binding)
1022 {
1023     RpcBinding *bind = Binding;
1024
1025     TRACE("(%p)\n", Binding);
1026
1027     RPCRT4_strfree(bind->Endpoint);
1028     bind->Endpoint = NULL;
1029     if (bind->Assoc) RpcAssoc_Release(bind->Assoc);
1030     bind->Assoc = NULL;
1031
1032     return RPC_S_OK;
1033 }
1034
1035 /***********************************************************************
1036  *             RpcImpersonateClient (RPCRT4.@)
1037  *
1038  * Impersonates the client connected via a binding handle so that security
1039  * checks are done in the context of the client.
1040  *
1041  * PARAMS
1042  *  BindingHandle [I] Handle to the binding to the client.
1043  *
1044  * RETURNS
1045  *  Success: RPS_S_OK.
1046  *  Failure: RPC_STATUS value.
1047  *
1048  * NOTES
1049  *
1050  * If BindingHandle is NULL then the function impersonates the client
1051  * connected to the binding handle of the current thread.
1052  */
1053 RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle)
1054 {
1055     RpcBinding *bind;
1056
1057     TRACE("(%p)\n", BindingHandle);
1058
1059     if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle();
1060     if (!BindingHandle) return RPC_S_INVALID_BINDING;
1061
1062     bind = BindingHandle;
1063     if (bind->FromConn)
1064         return rpcrt4_conn_impersonate_client(bind->FromConn);
1065     return RPC_S_WRONG_KIND_OF_BINDING;
1066 }
1067
1068 /***********************************************************************
1069  *             RpcRevertToSelfEx (RPCRT4.@)
1070  *
1071  * Stops impersonating the client connected to the binding handle so that security
1072  * checks are no longer done in the context of the client.
1073  *
1074  * PARAMS
1075  *  BindingHandle [I] Handle to the binding to the client.
1076  *
1077  * RETURNS
1078  *  Success: RPS_S_OK.
1079  *  Failure: RPC_STATUS value.
1080  *
1081  * NOTES
1082  *
1083  * If BindingHandle is NULL then the function stops impersonating the client
1084  * connected to the binding handle of the current thread.
1085  */
1086 RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle)
1087 {
1088     RpcBinding *bind;
1089
1090     TRACE("(%p)\n", BindingHandle);
1091
1092     if (!BindingHandle) BindingHandle = I_RpcGetCurrentCallHandle();
1093     if (!BindingHandle) return RPC_S_INVALID_BINDING;
1094
1095     bind = BindingHandle;
1096     if (bind->FromConn)
1097         return rpcrt4_conn_revert_to_self(bind->FromConn);
1098     return RPC_S_WRONG_KIND_OF_BINDING;
1099 }
1100
1101 static inline BOOL has_nt_auth_identity(ULONG AuthnLevel)
1102 {
1103     switch (AuthnLevel)
1104     {
1105     case RPC_C_AUTHN_GSS_NEGOTIATE:
1106     case RPC_C_AUTHN_WINNT:
1107     case RPC_C_AUTHN_GSS_KERBEROS:
1108         return TRUE;
1109     default:
1110         return FALSE;
1111     }
1112 }
1113
1114 RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc,
1115                               CredHandle cred, TimeStamp exp,
1116                               ULONG cbMaxToken,
1117                               RPC_AUTH_IDENTITY_HANDLE identity,
1118                               RpcAuthInfo **ret)
1119 {
1120     RpcAuthInfo *AuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo));
1121     if (!AuthInfo)
1122         return ERROR_OUTOFMEMORY;
1123
1124     AuthInfo->refs = 1;
1125     AuthInfo->AuthnLevel = AuthnLevel;
1126     AuthInfo->AuthnSvc = AuthnSvc;
1127     AuthInfo->cred = cred;
1128     AuthInfo->exp = exp;
1129     AuthInfo->cbMaxToken = cbMaxToken;
1130     AuthInfo->identity = identity;
1131     AuthInfo->server_principal_name = NULL;
1132
1133     /* duplicate the SEC_WINNT_AUTH_IDENTITY structure, if applicable, to
1134      * enable better matching in RpcAuthInfo_IsEqual */
1135     if (identity && has_nt_auth_identity(AuthnSvc))
1136     {
1137         const SEC_WINNT_AUTH_IDENTITY_W *nt_identity = identity;
1138         AuthInfo->nt_identity = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo->nt_identity));
1139         if (!AuthInfo->nt_identity)
1140         {
1141             HeapFree(GetProcessHeap(), 0, AuthInfo);
1142             return ERROR_OUTOFMEMORY;
1143         }
1144
1145         AuthInfo->nt_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1146         if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1147             AuthInfo->nt_identity->User = RPCRT4_strndupW(nt_identity->User, nt_identity->UserLength);
1148         else
1149             AuthInfo->nt_identity->User = RPCRT4_strndupAtoW((const char *)nt_identity->User, nt_identity->UserLength);
1150         AuthInfo->nt_identity->UserLength = nt_identity->UserLength;
1151         if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1152             AuthInfo->nt_identity->Domain = RPCRT4_strndupW(nt_identity->Domain, nt_identity->DomainLength);
1153         else
1154             AuthInfo->nt_identity->Domain = RPCRT4_strndupAtoW((const char *)nt_identity->Domain, nt_identity->DomainLength);
1155         AuthInfo->nt_identity->DomainLength = nt_identity->DomainLength;
1156         if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
1157             AuthInfo->nt_identity->Password = RPCRT4_strndupW(nt_identity->Password, nt_identity->PasswordLength);
1158         else
1159             AuthInfo->nt_identity->Password = RPCRT4_strndupAtoW((const char *)nt_identity->Password, nt_identity->PasswordLength);
1160         AuthInfo->nt_identity->PasswordLength = nt_identity->PasswordLength;
1161
1162         if ((nt_identity->User && !AuthInfo->nt_identity->User) ||
1163             (nt_identity->Domain && !AuthInfo->nt_identity->Domain) ||
1164             (nt_identity->Password && !AuthInfo->nt_identity->Password))
1165         {
1166             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
1167             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain);
1168             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password);
1169             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity);
1170             HeapFree(GetProcessHeap(), 0, AuthInfo);
1171             return ERROR_OUTOFMEMORY;
1172         }
1173     }
1174     else
1175         AuthInfo->nt_identity = NULL;
1176     *ret = AuthInfo;
1177     return RPC_S_OK;
1178 }
1179
1180 ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo)
1181 {
1182     return InterlockedIncrement(&AuthInfo->refs);
1183 }
1184
1185 ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo)
1186 {
1187     ULONG refs = InterlockedDecrement(&AuthInfo->refs);
1188
1189     if (!refs)
1190     {
1191         FreeCredentialsHandle(&AuthInfo->cred);
1192         if (AuthInfo->nt_identity)
1193         {
1194             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User);
1195             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain);
1196             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password);
1197             HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity);
1198         }
1199         HeapFree(GetProcessHeap(), 0, AuthInfo->server_principal_name);
1200         HeapFree(GetProcessHeap(), 0, AuthInfo);
1201     }
1202
1203     return refs;
1204 }
1205
1206 BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2)
1207 {
1208     if (AuthInfo1 == AuthInfo2)
1209         return TRUE;
1210
1211     if (!AuthInfo1 || !AuthInfo2)
1212         return FALSE;
1213
1214     if ((AuthInfo1->AuthnLevel != AuthInfo2->AuthnLevel) ||
1215         (AuthInfo1->AuthnSvc != AuthInfo2->AuthnSvc))
1216         return FALSE;
1217
1218     if (AuthInfo1->identity == AuthInfo2->identity)
1219         return TRUE;
1220
1221     if (!AuthInfo1->identity || !AuthInfo2->identity)
1222         return FALSE;
1223
1224     if (has_nt_auth_identity(AuthInfo1->AuthnSvc))
1225     {
1226         const SEC_WINNT_AUTH_IDENTITY_W *identity1 = AuthInfo1->nt_identity;
1227         const SEC_WINNT_AUTH_IDENTITY_W *identity2 = AuthInfo2->nt_identity;
1228         /* compare user names */
1229         if (identity1->UserLength != identity2->UserLength ||
1230             memcmp(identity1->User, identity2->User, identity1->UserLength))
1231             return FALSE;
1232         /* compare domain names */
1233         if (identity1->DomainLength != identity2->DomainLength ||
1234             memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength))
1235             return FALSE;
1236         /* compare passwords */
1237         if (identity1->PasswordLength != identity2->PasswordLength ||
1238             memcmp(identity1->Password, identity2->Password, identity1->PasswordLength))
1239             return FALSE;
1240     }
1241     else
1242         return FALSE;
1243
1244     return TRUE;
1245 }
1246
1247 static RPC_STATUS RpcQualityOfService_Create(const RPC_SECURITY_QOS *qos_src, BOOL unicode, RpcQualityOfService **qos_dst)
1248 {
1249     RpcQualityOfService *qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos));
1250
1251     if (!qos)
1252         return RPC_S_OUT_OF_RESOURCES;
1253
1254     qos->refs = 1;
1255     qos->qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos->qos));
1256     if (!qos->qos) goto error;
1257     qos->qos->Version = qos_src->Version;
1258     qos->qos->Capabilities = qos_src->Capabilities;
1259     qos->qos->IdentityTracking = qos_src->IdentityTracking;
1260     qos->qos->ImpersonationType = qos_src->ImpersonationType;
1261     qos->qos->AdditionalSecurityInfoType = 0;
1262
1263     if (qos_src->Version >= 2)
1264     {
1265         const RPC_SECURITY_QOS_V2_W *qos_src2 = (const RPC_SECURITY_QOS_V2_W *)qos_src;
1266         qos->qos->AdditionalSecurityInfoType = qos_src2->AdditionalSecurityInfoType;
1267         if (qos_src2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1268         {
1269             const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_src = qos_src2->u.HttpCredentials;
1270             RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_dst;
1271
1272             http_credentials_dst = HeapAlloc(GetProcessHeap(), 0, sizeof(*http_credentials_dst));
1273             qos->qos->u.HttpCredentials = http_credentials_dst;
1274             if (!http_credentials_dst) goto error;
1275             http_credentials_dst->TransportCredentials = NULL;
1276             http_credentials_dst->Flags = http_credentials_src->Flags;
1277             http_credentials_dst->AuthenticationTarget = http_credentials_src->AuthenticationTarget;
1278             http_credentials_dst->NumberOfAuthnSchemes = http_credentials_src->NumberOfAuthnSchemes;
1279             http_credentials_dst->AuthnSchemes = NULL;
1280             http_credentials_dst->ServerCertificateSubject = NULL;
1281             if (http_credentials_src->TransportCredentials)
1282             {
1283                 SEC_WINNT_AUTH_IDENTITY_W *cred_dst;
1284                 cred_dst = http_credentials_dst->TransportCredentials = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cred_dst));
1285                 if (!cred_dst) goto error;
1286                 cred_dst->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1287                 if (unicode)
1288                 {
1289                     const SEC_WINNT_AUTH_IDENTITY_W *cred_src = http_credentials_src->TransportCredentials;
1290                     cred_dst->UserLength = cred_src->UserLength;
1291                     cred_dst->PasswordLength = cred_src->PasswordLength;
1292                     cred_dst->DomainLength = cred_src->DomainLength;
1293                     cred_dst->User = RPCRT4_strndupW(cred_src->User, cred_src->UserLength);
1294                     cred_dst->Password = RPCRT4_strndupW(cred_src->Password, cred_src->PasswordLength);
1295                     cred_dst->Domain = RPCRT4_strndupW(cred_src->Domain, cred_src->DomainLength);
1296                 }
1297                 else
1298                 {
1299                     const SEC_WINNT_AUTH_IDENTITY_A *cred_src = (const SEC_WINNT_AUTH_IDENTITY_A *)http_credentials_src->TransportCredentials;
1300                     cred_dst->UserLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, NULL, 0);
1301                     cred_dst->DomainLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, NULL, 0);
1302                     cred_dst->PasswordLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, NULL, 0);
1303                     cred_dst->User = HeapAlloc(GetProcessHeap(), 0, cred_dst->UserLength * sizeof(WCHAR));
1304                     cred_dst->Password = HeapAlloc(GetProcessHeap(), 0, cred_dst->PasswordLength * sizeof(WCHAR));
1305                     cred_dst->Domain = HeapAlloc(GetProcessHeap(), 0, cred_dst->DomainLength * sizeof(WCHAR));
1306                     if (!cred_dst->Password || !cred_dst->Domain) goto error;
1307                     MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, cred_dst->User, cred_dst->UserLength);
1308                     MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, cred_dst->Domain, cred_dst->DomainLength);
1309                     MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, cred_dst->Password, cred_dst->PasswordLength);
1310                 }
1311             }
1312             if (http_credentials_src->NumberOfAuthnSchemes)
1313             {
1314                 http_credentials_dst->AuthnSchemes = HeapAlloc(GetProcessHeap(), 0, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes));
1315                 if (!http_credentials_dst->AuthnSchemes) goto error;
1316                 memcpy(http_credentials_dst->AuthnSchemes, http_credentials_src->AuthnSchemes, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes));
1317             }
1318             if (http_credentials_src->ServerCertificateSubject)
1319             {
1320                 if (unicode)
1321                     http_credentials_dst->ServerCertificateSubject =
1322                         RPCRT4_strndupW(http_credentials_src->ServerCertificateSubject,
1323                                         strlenW(http_credentials_src->ServerCertificateSubject));
1324                 else
1325                     http_credentials_dst->ServerCertificateSubject =
1326                         RPCRT4_strdupAtoW((char *)http_credentials_src->ServerCertificateSubject);
1327                 if (!http_credentials_dst->ServerCertificateSubject) goto error;
1328             }
1329         }
1330     }
1331     *qos_dst = qos;
1332     return RPC_S_OK;
1333
1334 error:
1335     if (qos->qos)
1336     {
1337         if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP &&
1338             qos->qos->u.HttpCredentials)
1339         {
1340             if (qos->qos->u.HttpCredentials->TransportCredentials)
1341             {
1342                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User);
1343                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain);
1344                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password);
1345                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials);
1346             }
1347             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes);
1348             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject);
1349             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials);
1350         }
1351         HeapFree(GetProcessHeap(), 0, qos->qos);
1352     }
1353     HeapFree(GetProcessHeap(), 0, qos);
1354     return RPC_S_OUT_OF_RESOURCES;
1355 }
1356
1357 ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos)
1358 {
1359     return InterlockedIncrement(&qos->refs);
1360 }
1361
1362 ULONG RpcQualityOfService_Release(RpcQualityOfService *qos)
1363 {
1364     ULONG refs = InterlockedDecrement(&qos->refs);
1365
1366     if (!refs)
1367     {
1368         if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1369         {
1370             if (qos->qos->u.HttpCredentials->TransportCredentials)
1371             {
1372                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User);
1373                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain);
1374                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password);
1375                 HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials);
1376             }
1377             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes);
1378             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject);
1379             HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials);
1380         }
1381         HeapFree(GetProcessHeap(), 0, qos->qos);
1382         HeapFree(GetProcessHeap(), 0, qos);
1383     }
1384     return refs;
1385 }
1386
1387 BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2)
1388 {
1389     if (qos1 == qos2)
1390         return TRUE;
1391
1392     if (!qos1 || !qos2)
1393         return FALSE;
1394
1395     TRACE("qos1 = { %d %d %d %d }, qos2 = { %d %d %d %d }\n",
1396         qos1->qos->Capabilities, qos1->qos->IdentityTracking,
1397         qos1->qos->ImpersonationType, qos1->qos->AdditionalSecurityInfoType,
1398         qos2->qos->Capabilities, qos2->qos->IdentityTracking,
1399         qos2->qos->ImpersonationType, qos2->qos->AdditionalSecurityInfoType);
1400
1401     if ((qos1->qos->Capabilities != qos2->qos->Capabilities) ||
1402         (qos1->qos->IdentityTracking != qos2->qos->IdentityTracking) ||
1403         (qos1->qos->ImpersonationType != qos2->qos->ImpersonationType) ||
1404         (qos1->qos->AdditionalSecurityInfoType != qos2->qos->AdditionalSecurityInfoType))
1405         return FALSE;
1406
1407     if (qos1->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1408     {
1409         const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials1 = qos1->qos->u.HttpCredentials;
1410         const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials2 = qos2->qos->u.HttpCredentials;
1411
1412         if (http_credentials1->Flags != http_credentials2->Flags)
1413             return FALSE;
1414
1415         if (http_credentials1->AuthenticationTarget != http_credentials2->AuthenticationTarget)
1416             return FALSE;
1417
1418         /* authentication schemes and server certificate subject not currently used */
1419
1420         if (http_credentials1->TransportCredentials != http_credentials2->TransportCredentials)
1421         {
1422             const SEC_WINNT_AUTH_IDENTITY_W *identity1 = http_credentials1->TransportCredentials;
1423             const SEC_WINNT_AUTH_IDENTITY_W *identity2 = http_credentials2->TransportCredentials;
1424
1425             if (!identity1 || !identity2)
1426                 return FALSE;
1427
1428             /* compare user names */
1429             if (identity1->UserLength != identity2->UserLength ||
1430                 memcmp(identity1->User, identity2->User, identity1->UserLength))
1431                 return FALSE;
1432             /* compare domain names */
1433             if (identity1->DomainLength != identity2->DomainLength ||
1434                 memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength))
1435                 return FALSE;
1436             /* compare passwords */
1437             if (identity1->PasswordLength != identity2->PasswordLength ||
1438                 memcmp(identity1->Password, identity2->Password, identity1->PasswordLength))
1439                 return FALSE;
1440         }
1441     }
1442
1443     return TRUE;
1444 }
1445
1446 /***********************************************************************
1447  *             RpcRevertToSelf (RPCRT4.@)
1448  */
1449 RPC_STATUS WINAPI RpcRevertToSelf(void)
1450 {
1451     TRACE("\n");
1452     return RpcRevertToSelfEx(NULL);
1453 }
1454
1455 /***********************************************************************
1456  *             RpcMgmtSetComTimeout (RPCRT4.@)
1457  */
1458 RPC_STATUS WINAPI RpcMgmtSetComTimeout(RPC_BINDING_HANDLE BindingHandle, unsigned int Timeout)
1459 {
1460     FIXME("(%p, %d): stub\n", BindingHandle, Timeout);
1461     return RPC_S_OK;
1462 }
1463
1464 /***********************************************************************
1465  *             RpcBindingInqAuthInfoExA (RPCRT4.@)
1466  */
1467 RPCRTAPI RPC_STATUS RPC_ENTRY
1468 RpcBindingInqAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel,
1469                           ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc,
1470                           ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS )
1471 {
1472     RPC_STATUS status;
1473     RPC_WSTR principal;
1474
1475     TRACE("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel,
1476           AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1477
1478     status = RpcBindingInqAuthInfoExW(Binding, ServerPrincName ? &principal : NULL, AuthnLevel,
1479                                       AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1480     if (status == RPC_S_OK && ServerPrincName)
1481     {
1482         *ServerPrincName = (RPC_CSTR)RPCRT4_strdupWtoA(principal);
1483         RpcStringFreeW(&principal);
1484         if (!*ServerPrincName) return ERROR_OUTOFMEMORY;
1485     }
1486
1487     return status;
1488 }
1489
1490 /***********************************************************************
1491  *             RpcBindingInqAuthInfoExW (RPCRT4.@)
1492  */
1493 RPCRTAPI RPC_STATUS RPC_ENTRY
1494 RpcBindingInqAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel,
1495                           ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc,
1496                           ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS )
1497 {
1498     RpcBinding *bind = Binding;
1499
1500     TRACE("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel,
1501           AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS);
1502
1503     if (!bind->AuthInfo) return RPC_S_BINDING_HAS_NO_AUTH;
1504
1505     if (SecurityQOS)
1506     {
1507         FIXME("QOS not implemented\n");
1508         return RPC_S_INVALID_BINDING;
1509     }
1510
1511     if (ServerPrincName)
1512     {
1513         if (bind->AuthInfo->server_principal_name)
1514         {
1515             *ServerPrincName = RPCRT4_strdupW(bind->AuthInfo->server_principal_name);
1516             if (!*ServerPrincName) return ERROR_OUTOFMEMORY;
1517         }
1518         else *ServerPrincName = NULL;
1519     }
1520     if (AuthnLevel) *AuthnLevel = bind->AuthInfo->AuthnLevel;
1521     if (AuthnSvc) *AuthnSvc = bind->AuthInfo->AuthnSvc;
1522     if (AuthIdentity) *AuthIdentity = bind->AuthInfo->identity;
1523     if (AuthzSvc)
1524     {
1525         FIXME("authorization service not implemented\n");
1526         *AuthzSvc = RPC_C_AUTHZ_NONE;
1527     }
1528
1529     return RPC_S_OK;
1530 }
1531
1532 /***********************************************************************
1533  *             RpcBindingInqAuthInfoA (RPCRT4.@)
1534  */
1535 RPCRTAPI RPC_STATUS RPC_ENTRY
1536 RpcBindingInqAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel,
1537                         ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc )
1538 {
1539     return RpcBindingInqAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity,
1540                                     AuthzSvc, 0, NULL);
1541 }
1542
1543 /***********************************************************************
1544  *             RpcBindingInqAuthInfoW (RPCRT4.@)
1545  */
1546 RPCRTAPI RPC_STATUS RPC_ENTRY
1547 RpcBindingInqAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel,
1548                         ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc )
1549 {
1550     return RpcBindingInqAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity,
1551                                     AuthzSvc, 0, NULL);
1552 }
1553
1554 /***********************************************************************
1555  *             RpcBindingInqAuthClientA (RPCRT4.@)
1556  */
1557 RPCRTAPI RPC_STATUS RPC_ENTRY
1558 RpcBindingInqAuthClientA( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1559                           RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1560                           ULONG *AuthzSvc )
1561 {
1562     return RpcBindingInqAuthClientExA(ClientBinding, Privs, ServerPrincName, AuthnLevel,
1563                                       AuthnSvc, AuthzSvc, 0);
1564 }
1565
1566 /***********************************************************************
1567  *             RpcBindingInqAuthClientW (RPCRT4.@)
1568  */
1569 RPCRTAPI RPC_STATUS RPC_ENTRY
1570 RpcBindingInqAuthClientW( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1571                           RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1572                           ULONG *AuthzSvc )
1573 {
1574     return RpcBindingInqAuthClientExW(ClientBinding, Privs, ServerPrincName, AuthnLevel,
1575                                       AuthnSvc, AuthzSvc, 0);
1576 }
1577
1578 /***********************************************************************
1579  *             RpcBindingInqAuthClientExA (RPCRT4.@)
1580  */
1581 RPCRTAPI RPC_STATUS RPC_ENTRY
1582 RpcBindingInqAuthClientExA( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1583                             RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1584                             ULONG *AuthzSvc, ULONG Flags )
1585 {
1586     RPC_STATUS status;
1587     RPC_WSTR principal;
1588
1589     TRACE("%p %p %p %p %p %p 0x%x\n", ClientBinding, Privs, ServerPrincName, AuthnLevel,
1590           AuthnSvc, AuthzSvc, Flags);
1591
1592     status = RpcBindingInqAuthClientExW(ClientBinding, Privs, ServerPrincName ? &principal : NULL,
1593                                         AuthnLevel, AuthnSvc, AuthzSvc, Flags);
1594     if (status == RPC_S_OK && ServerPrincName)
1595     {
1596         *ServerPrincName = (RPC_CSTR)RPCRT4_strdupWtoA(principal);
1597         if (!*ServerPrincName && principal) status = ERROR_OUTOFMEMORY;
1598         RpcStringFreeW(&principal);
1599     }
1600
1601     return status;
1602 }
1603
1604 /***********************************************************************
1605  *             RpcBindingInqAuthClientExW (RPCRT4.@)
1606  */
1607 RPCRTAPI RPC_STATUS RPC_ENTRY
1608 RpcBindingInqAuthClientExW( RPC_BINDING_HANDLE ClientBinding, RPC_AUTHZ_HANDLE *Privs,
1609                             RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, ULONG *AuthnSvc,
1610                             ULONG *AuthzSvc, ULONG Flags )
1611 {
1612     RpcBinding *bind = ClientBinding;
1613
1614     TRACE("%p %p %p %p %p %p 0x%x\n", ClientBinding, Privs, ServerPrincName, AuthnLevel,
1615           AuthnSvc, AuthzSvc, Flags);
1616
1617     if (!bind->FromConn) return RPC_S_INVALID_BINDING;
1618
1619     return rpcrt4_conn_inquire_auth_client(bind->FromConn, Privs,
1620                                            ServerPrincName, AuthnLevel,
1621                                            AuthnSvc, AuthzSvc, Flags);
1622 }
1623
1624 /***********************************************************************
1625  *             RpcBindingSetAuthInfoExA (RPCRT4.@)
1626  */
1627 RPCRTAPI RPC_STATUS RPC_ENTRY
1628 RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName,
1629                           ULONG AuthnLevel, ULONG AuthnSvc,
1630                           RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr,
1631                           RPC_SECURITY_QOS *SecurityQos )
1632 {
1633   RpcBinding* bind = Binding;
1634   SECURITY_STATUS r;
1635   CredHandle cred;
1636   TimeStamp exp;
1637   ULONG package_count;
1638   ULONG i;
1639   PSecPkgInfoA packages;
1640   ULONG cbMaxToken;
1641
1642   TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_a((const char*)ServerPrincName),
1643         AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos);
1644
1645   if (SecurityQos)
1646   {
1647       RPC_STATUS status;
1648
1649       TRACE("SecurityQos { Version=%d, Capabilities=0x%x, IdentityTracking=%d, ImpersonationLevel=%d",
1650             SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType);
1651       if (SecurityQos->Version >= 2)
1652       {
1653           const RPC_SECURITY_QOS_V2_A *SecurityQos2 = (const RPC_SECURITY_QOS_V2_A *)SecurityQos;
1654           TRACE(", AdditionalSecurityInfoType=%d", SecurityQos2->AdditionalSecurityInfoType);
1655           if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1656               TRACE(", { %p, 0x%x, %d, %d, %p, %s }",
1657                     SecurityQos2->u.HttpCredentials->TransportCredentials,
1658                     SecurityQos2->u.HttpCredentials->Flags,
1659                     SecurityQos2->u.HttpCredentials->AuthenticationTarget,
1660                     SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes,
1661                     SecurityQos2->u.HttpCredentials->AuthnSchemes,
1662                     SecurityQos2->u.HttpCredentials->ServerCertificateSubject);
1663       }
1664       TRACE("}\n");
1665       status = RpcQualityOfService_Create(SecurityQos, FALSE, &bind->QOS);
1666       if (status != RPC_S_OK)
1667           return status;
1668   }
1669   else
1670   {
1671       if (bind->QOS) RpcQualityOfService_Release(bind->QOS);
1672       bind->QOS = NULL;
1673   }
1674
1675   if (AuthnSvc == RPC_C_AUTHN_DEFAULT)
1676     AuthnSvc = RPC_C_AUTHN_WINNT;
1677
1678   /* FIXME: the mapping should probably be retrieved using SSPI somehow */
1679   if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
1680     AuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
1681
1682   if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE))
1683   {
1684     if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1685     bind->AuthInfo = NULL;
1686     return RPC_S_OK;
1687   }
1688
1689   if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
1690   {
1691     FIXME("unknown AuthnLevel %u\n", AuthnLevel);
1692     return RPC_S_UNKNOWN_AUTHN_LEVEL;
1693   }
1694
1695   /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
1696   if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
1697   {
1698     FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
1699     return RPC_S_UNKNOWN_AUTHZ_SERVICE;
1700   }
1701
1702   r = EnumerateSecurityPackagesA(&package_count, &packages);
1703   if (r != SEC_E_OK)
1704   {
1705     ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r);
1706     return RPC_S_SEC_PKG_ERROR;
1707   }
1708
1709   for (i = 0; i < package_count; i++)
1710     if (packages[i].wRPCID == AuthnSvc)
1711         break;
1712
1713   if (i == package_count)
1714   {
1715     FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
1716     FreeContextBuffer(packages);
1717     return RPC_S_UNKNOWN_AUTHN_SERVICE;
1718   }
1719
1720   TRACE("found package %s for service %u\n", packages[i].Name, AuthnSvc);
1721   r = AcquireCredentialsHandleA(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
1722                                 AuthIdentity, NULL, NULL, &cred, &exp);
1723   cbMaxToken = packages[i].cbMaxToken;
1724   FreeContextBuffer(packages);
1725   if (r == ERROR_SUCCESS)
1726   {
1727     RpcAuthInfo *new_auth_info;
1728     r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken,
1729                            AuthIdentity, &new_auth_info);
1730     if (r == RPC_S_OK)
1731     {
1732       new_auth_info->server_principal_name = RPCRT4_strdupAtoW((char *)ServerPrincName);
1733       if (new_auth_info->server_principal_name)
1734       {
1735         if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1736         bind->AuthInfo = new_auth_info;
1737       }
1738       else
1739       {
1740         RpcAuthInfo_Release(new_auth_info);
1741         r = ERROR_OUTOFMEMORY;
1742       }
1743     }
1744     else
1745       FreeCredentialsHandle(&cred);
1746     return r;
1747   }
1748   else
1749   {
1750     ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r);
1751     return RPC_S_SEC_PKG_ERROR;
1752   }
1753 }
1754
1755 /***********************************************************************
1756  *             RpcBindingSetAuthInfoExW (RPCRT4.@)
1757  */
1758 RPCRTAPI RPC_STATUS RPC_ENTRY
1759 RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel,
1760                           ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr,
1761                           RPC_SECURITY_QOS *SecurityQos )
1762 {
1763   RpcBinding* bind = Binding;
1764   SECURITY_STATUS r;
1765   CredHandle cred;
1766   TimeStamp exp;
1767   ULONG package_count;
1768   ULONG i;
1769   PSecPkgInfoW packages;
1770   ULONG cbMaxToken;
1771
1772   TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w(ServerPrincName),
1773         AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos);
1774
1775   if (SecurityQos)
1776   {
1777       RPC_STATUS status;
1778
1779       TRACE("SecurityQos { Version=%d, Capabilities=0x%x, IdentityTracking=%d, ImpersonationLevel=%d",
1780             SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType);
1781       if (SecurityQos->Version >= 2)
1782       {
1783           const RPC_SECURITY_QOS_V2_W *SecurityQos2 = (const RPC_SECURITY_QOS_V2_W *)SecurityQos;
1784           TRACE(", AdditionalSecurityInfoType=%d", SecurityQos2->AdditionalSecurityInfoType);
1785           if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)
1786               TRACE(", { %p, 0x%x, %d, %d, %p, %s }",
1787                     SecurityQos2->u.HttpCredentials->TransportCredentials,
1788                     SecurityQos2->u.HttpCredentials->Flags,
1789                     SecurityQos2->u.HttpCredentials->AuthenticationTarget,
1790                     SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes,
1791                     SecurityQos2->u.HttpCredentials->AuthnSchemes,
1792                     debugstr_w(SecurityQos2->u.HttpCredentials->ServerCertificateSubject));
1793       }
1794       TRACE("}\n");
1795       status = RpcQualityOfService_Create(SecurityQos, TRUE, &bind->QOS);
1796       if (status != RPC_S_OK)
1797           return status;
1798   }
1799   else
1800   {
1801       if (bind->QOS) RpcQualityOfService_Release(bind->QOS);
1802       bind->QOS = NULL;
1803   }
1804
1805   if (AuthnSvc == RPC_C_AUTHN_DEFAULT)
1806     AuthnSvc = RPC_C_AUTHN_WINNT;
1807
1808   /* FIXME: the mapping should probably be retrieved using SSPI somehow */
1809   if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT)
1810     AuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
1811
1812   if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE))
1813   {
1814     if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1815     bind->AuthInfo = NULL;
1816     return RPC_S_OK;
1817   }
1818
1819   if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
1820   {
1821     FIXME("unknown AuthnLevel %u\n", AuthnLevel);
1822     return RPC_S_UNKNOWN_AUTHN_LEVEL;
1823   }
1824
1825   /* RPC_C_AUTHN_WINNT ignores the AuthzSvr parameter */
1826   if (AuthzSvr && AuthnSvc != RPC_C_AUTHN_WINNT)
1827   {
1828     FIXME("unsupported AuthzSvr %u\n", AuthzSvr);
1829     return RPC_S_UNKNOWN_AUTHZ_SERVICE;
1830   }
1831
1832   r = EnumerateSecurityPackagesW(&package_count, &packages);
1833   if (r != SEC_E_OK)
1834   {
1835     ERR("EnumerateSecurityPackagesW failed with error 0x%08x\n", r);
1836     return RPC_S_SEC_PKG_ERROR;
1837   }
1838
1839   for (i = 0; i < package_count; i++)
1840     if (packages[i].wRPCID == AuthnSvc)
1841         break;
1842
1843   if (i == package_count)
1844   {
1845     FIXME("unsupported AuthnSvc %u\n", AuthnSvc);
1846     FreeContextBuffer(packages);
1847     return RPC_S_UNKNOWN_AUTHN_SERVICE;
1848   }
1849
1850   TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), AuthnSvc);
1851   r = AcquireCredentialsHandleW(NULL, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL,
1852                                 AuthIdentity, NULL, NULL, &cred, &exp);
1853   cbMaxToken = packages[i].cbMaxToken;
1854   FreeContextBuffer(packages);
1855   if (r == ERROR_SUCCESS)
1856   {
1857     RpcAuthInfo *new_auth_info;
1858     r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken,
1859                            AuthIdentity, &new_auth_info);
1860     if (r == RPC_S_OK)
1861     {
1862       new_auth_info->server_principal_name = RPCRT4_strdupW(ServerPrincName);
1863       if (!ServerPrincName || new_auth_info->server_principal_name)
1864       {
1865         if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo);
1866         bind->AuthInfo = new_auth_info;
1867       }
1868       else
1869       {
1870         RpcAuthInfo_Release(new_auth_info);
1871         r = ERROR_OUTOFMEMORY;
1872       }
1873     }
1874     else
1875       FreeCredentialsHandle(&cred);
1876     return r;
1877   }
1878   else
1879   {
1880     ERR("AcquireCredentialsHandleW failed with error 0x%08x\n", r);
1881     return RPC_S_SEC_PKG_ERROR;
1882   }
1883 }
1884
1885 /***********************************************************************
1886  *             RpcBindingSetAuthInfoA (RPCRT4.@)
1887  */
1888 RPCRTAPI RPC_STATUS RPC_ENTRY
1889 RpcBindingSetAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, ULONG AuthnLevel,
1890                         ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr )
1891 {
1892     TRACE("%p %s %u %u %p %u\n", Binding, debugstr_a((const char*)ServerPrincName),
1893           AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr);
1894     return RpcBindingSetAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL);
1895 }
1896
1897 /***********************************************************************
1898  *             RpcBindingSetAuthInfoW (RPCRT4.@)
1899  */
1900 RPCRTAPI RPC_STATUS RPC_ENTRY
1901 RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel,
1902                         ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr )
1903 {
1904     TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w(ServerPrincName),
1905           AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr);
1906     return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL);
1907 }
1908
1909 /***********************************************************************
1910  *             RpcBindingSetOption (RPCRT4.@)
1911  */
1912 RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG_PTR OptionValue)
1913 {
1914     FIXME("(%p, %d, %ld): stub\n", BindingHandle, Option, OptionValue);
1915     return RPC_S_OK;
1916 }