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