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