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