Import and merge Wine-20041201
[reactos.git] / reactos / lib / 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 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * TODO:
23 * - a whole lot
24 */
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winerror.h"
35 #include "winreg.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_message.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
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(LPWSTR 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(LPSTR 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 LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen)
85 {
86 DWORD len;
87 LPWSTR s;
88 if (!src) return NULL;
89 if (slen == -1) slen = strlenW(src);
90 len = slen;
91 s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
92 memcpy(s, src, len*sizeof(WCHAR));
93 s[len] = 0;
94 return s;
95 }
96
97 void RPCRT4_strfree(LPSTR src)
98 {
99 if (src) HeapFree(GetProcessHeap(), 0, src);
100 }
101
102 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
103 {
104 RpcConnection* NewConnection;
105
106 NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection));
107 NewConnection->server = server;
108 NewConnection->Protseq = RPCRT4_strdupA(Protseq);
109 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
110 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
111 NewConnection->Used = Binding;
112 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
113
114 TRACE("connection: %p\n", NewConnection);
115 *Connection = NewConnection;
116
117 return RPC_S_OK;
118 }
119
120 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
121 {
122 TRACE("connection: %p\n", Connection);
123
124 RPCRT4_CloseConnection(Connection);
125 RPCRT4_strfree(Connection->Endpoint);
126 RPCRT4_strfree(Connection->NetworkAddr);
127 RPCRT4_strfree(Connection->Protseq);
128 HeapFree(GetProcessHeap(), 0, Connection);
129 return RPC_S_OK;
130 }
131
132 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
133 {
134 TRACE("(Connection == ^%p)\n", Connection);
135 if (!Connection->conn) {
136 if (Connection->server) { /* server */
137 /* protseq=ncalrpc: supposed to use NT LPC ports,
138 * but we'll implement it with named pipes for now */
139 if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
140 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
141 LPSTR pname;
142 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
143 strcat(strcpy(pname, prefix), Connection->Endpoint);
144 TRACE("listening on %s\n", pname);
145 Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX,
146 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES,
147 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
148 HeapFree(GetProcessHeap(), 0, pname);
149 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
150 Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
151 if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
152 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
153 if (GetLastError() == ERROR_PIPE_CONNECTED) {
154 SetEvent(Connection->ovl.hEvent);
155 return RPC_S_OK;
156 } else if (GetLastError() == ERROR_IO_PENDING) {
157 return RPC_S_OK;
158 }
159 return RPC_S_SERVER_UNAVAILABLE;
160 }
161 }
162 /* protseq=ncacn_np: named pipes */
163 else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
164 static LPCSTR prefix = "\\\\.";
165 LPSTR pname;
166 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
167 strcat(strcpy(pname, prefix), Connection->Endpoint);
168 TRACE("listening on %s\n", pname);
169 Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX,
170 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
171 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
172 HeapFree(GetProcessHeap(), 0, pname);
173 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
174 Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
175 if (!ConnectNamedPipe(Connection->conn, &Connection->ovl)) {
176 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
177 if (GetLastError() == ERROR_PIPE_CONNECTED) {
178 SetEvent(Connection->ovl.hEvent);
179 return RPC_S_OK;
180 }
181 return RPC_S_SERVER_UNAVAILABLE;
182 }
183 }
184 else {
185 ERR("protseq %s not supported\n", Connection->Protseq);
186 return RPC_S_PROTSEQ_NOT_SUPPORTED;
187 }
188 }
189 else { /* client */
190 /* protseq=ncalrpc: supposed to use NT LPC ports,
191 * but we'll implement it with named pipes for now */
192 if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
193 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
194 LPSTR pname;
195 HANDLE conn;
196 DWORD err;
197 DWORD dwMode;
198
199 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
200 strcat(strcpy(pname, prefix), Connection->Endpoint);
201 TRACE("connecting to %s\n", pname);
202 while (TRUE) {
203 if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
204 conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
205 OPEN_EXISTING, 0, 0);
206 if (conn != INVALID_HANDLE_VALUE) break;
207 err = GetLastError();
208 if (err == ERROR_PIPE_BUSY) continue;
209 TRACE("connection failed, error=%lx\n", err);
210 HeapFree(GetProcessHeap(), 0, pname);
211 return RPC_S_SERVER_TOO_BUSY;
212 } else {
213 err = GetLastError();
214 TRACE("connection failed, error=%lx\n", err);
215 HeapFree(GetProcessHeap(), 0, pname);
216 return RPC_S_SERVER_UNAVAILABLE;
217 }
218 }
219
220 /* success */
221 HeapFree(GetProcessHeap(), 0, pname);
222 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
223 /* pipe is connected; change to message-read mode. */
224 dwMode = PIPE_READMODE_MESSAGE;
225 SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
226 Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
227 Connection->conn = conn;
228 }
229 /* protseq=ncacn_np: named pipes */
230 else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
231 static LPCSTR prefix = "\\\\.";
232 LPSTR pname;
233 HANDLE conn;
234 DWORD err;
235 DWORD dwMode;
236
237 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
238 strcat(strcpy(pname, prefix), Connection->Endpoint);
239 TRACE("connecting to %s\n", pname);
240 conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
241 OPEN_EXISTING, 0, 0);
242 if (conn == INVALID_HANDLE_VALUE) {
243 err = GetLastError();
244 /* we don't need to handle ERROR_PIPE_BUSY here,
245 * the doc says that it is returned to the app */
246 TRACE("connection failed, error=%lx\n", err);
247 HeapFree(GetProcessHeap(), 0, pname);
248 if (err == ERROR_PIPE_BUSY)
249 return RPC_S_SERVER_TOO_BUSY;
250 else
251 return RPC_S_SERVER_UNAVAILABLE;
252 }
253
254 /* success */
255 HeapFree(GetProcessHeap(), 0, pname);
256 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
257 /* pipe is connected; change to message-read mode. */
258 dwMode = PIPE_READMODE_MESSAGE;
259 SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
260 Connection->ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
261 Connection->conn = conn;
262 } else {
263 ERR("protseq %s not supported\n", Connection->Protseq);
264 return RPC_S_PROTSEQ_NOT_SUPPORTED;
265 }
266 }
267 }
268 return RPC_S_OK;
269 }
270
271 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
272 {
273 TRACE("(Connection == ^%p)\n", Connection);
274 if (Connection->conn) {
275 CancelIo(Connection->conn);
276 CloseHandle(Connection->conn);
277 Connection->conn = 0;
278 }
279 if (Connection->ovl.hEvent) {
280 CloseHandle(Connection->ovl.hEvent);
281 Connection->ovl.hEvent = 0;
282 }
283 return RPC_S_OK;
284 }
285
286 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
287 {
288 RpcConnection* NewConnection;
289 RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
290 OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL);
291 if (err == RPC_S_OK) {
292 /* because of the way named pipes work, we'll transfer the connected pipe
293 * to the child, then reopen the server binding to continue listening */
294 NewConnection->conn = OldConnection->conn;
295 NewConnection->ovl = OldConnection->ovl;
296 OldConnection->conn = 0;
297 memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl));
298 *Connection = NewConnection;
299 RPCRT4_OpenConnection(OldConnection);
300 }
301 return err;
302 }
303
304 RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
305 {
306 RpcBinding* NewBinding;
307
308 NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
309 NewBinding->refs = 1;
310 NewBinding->server = server;
311
312 *Binding = NewBinding;
313
314 return RPC_S_OK;
315 }
316
317 RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
318 {
319 RpcBinding* NewBinding;
320
321 RPCRT4_AllocBinding(&NewBinding, server);
322 NewBinding->Protseq = RPCRT4_strdupA(Protseq);
323
324 TRACE("binding: %p\n", NewBinding);
325 *Binding = NewBinding;
326
327 return RPC_S_OK;
328 }
329
330 RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq)
331 {
332 RpcBinding* NewBinding;
333
334 RPCRT4_AllocBinding(&NewBinding, server);
335 NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
336
337 TRACE("binding: %p\n", NewBinding);
338 *Binding = NewBinding;
339
340 return RPC_S_OK;
341 }
342
343 RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
344 {
345 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
346 debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
347
348 RPCRT4_strfree(Binding->NetworkAddr);
349 Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
350 RPCRT4_strfree(Binding->Endpoint);
351 if (Endpoint) {
352 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
353 } else {
354 Binding->Endpoint = RPCRT4_strdupA("");
355 }
356 if (!Binding->Endpoint) ERR("out of memory?\n");
357
358 return RPC_S_OK;
359 }
360
361 RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions)
362 {
363 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
364 debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
365
366 RPCRT4_strfree(Binding->NetworkAddr);
367 Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr);
368 RPCRT4_strfree(Binding->Endpoint);
369 if (Endpoint) {
370 Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint);
371 } else {
372 Binding->Endpoint = RPCRT4_strdupA("");
373 }
374 if (!Binding->Endpoint) ERR("out of memory?\n");
375
376 return RPC_S_OK;
377 }
378
379 RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint)
380 {
381 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
382
383 RPCRT4_strfree(Binding->Endpoint);
384 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
385
386 return RPC_S_OK;
387 }
388
389 RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid)
390 {
391 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid));
392 if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID));
393 else UuidCreateNil(&Binding->ObjectUuid);
394 return RPC_S_OK;
395 }
396
397 RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
398 {
399 RpcBinding* NewBinding;
400 TRACE("(*RpcBinding == ^%p, Connection == ^%p)\n", *Binding, Connection);
401
402 RPCRT4_AllocBinding(&NewBinding, Connection->server);
403 NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq);
404 NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr);
405 NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint);
406 NewBinding->FromConn = Connection;
407
408 TRACE("binding: %p\n", NewBinding);
409 *Binding = NewBinding;
410
411 return RPC_S_OK;
412 }
413
414 RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding)
415 {
416 InterlockedIncrement(&OldBinding->refs);
417 *Binding = OldBinding;
418 return RPC_S_OK;
419 }
420
421 RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding)
422 {
423 if (InterlockedDecrement(&Binding->refs))
424 return RPC_S_OK;
425
426 TRACE("binding: %p\n", Binding);
427 /* FIXME: release connections */
428 RPCRT4_strfree(Binding->Endpoint);
429 RPCRT4_strfree(Binding->NetworkAddr);
430 RPCRT4_strfree(Binding->Protseq);
431 HeapFree(GetProcessHeap(), 0, Binding);
432 return RPC_S_OK;
433 }
434
435 RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection,
436 PRPC_SYNTAX_IDENTIFIER TransferSyntax,
437 PRPC_SYNTAX_IDENTIFIER InterfaceId)
438 {
439 RpcConnection* NewConnection;
440 RPC_STATUS status;
441
442 TRACE("(Binding == ^%p)\n", Binding);
443
444 /* if we try to bind a new interface and the connection is already opened,
445 * close the current connection and create a new with the new binding. */
446 if (!Binding->server && Binding->FromConn &&
447 memcmp(&Binding->FromConn->ActiveInterface, InterfaceId,
448 sizeof(RPC_SYNTAX_IDENTIFIER))) {
449
450 TRACE("releasing pre-existing connection\n");
451 RPCRT4_DestroyConnection(Binding->FromConn);
452 Binding->FromConn = NULL;
453 } else {
454 /* we already have an connection with acceptable binding, so use it */
455 if (Binding->FromConn) {
456 *Connection = Binding->FromConn;
457 return RPC_S_OK;
458 }
459 }
460
461 /* create a new connection */
462 RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding);
463 *Connection = NewConnection;
464 status = RPCRT4_OpenConnection(NewConnection);
465 if (status != RPC_S_OK) {
466 return status;
467 }
468
469 /* we need to send a binding packet if we are client. */
470 if (!(*Connection)->server) {
471 RpcPktHdr *hdr;
472 DWORD count;
473 BYTE *response;
474 RpcPktHdr *response_hdr;
475
476 TRACE("sending bind request to server\n");
477
478 hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
479 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
480 InterfaceId, TransferSyntax);
481
482 status = RPCRT4_Send(*Connection, hdr, NULL, 0);
483 if (status != RPC_S_OK) {
484 RPCRT4_DestroyConnection(*Connection);
485 return status;
486 }
487
488 response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE);
489 if (response == NULL) {
490 WARN("Can't allocate memory for binding response\n");
491 RPCRT4_DestroyConnection(*Connection);
492 return E_OUTOFMEMORY;
493 }
494
495 /* get a reply */
496 if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) {
497 WARN("ReadFile failed with error %ld\n", GetLastError());
498 RPCRT4_DestroyConnection(*Connection);
499 return RPC_S_PROTOCOL_ERROR;
500 }
501
502 if (count < sizeof(response_hdr->common)) {
503 WARN("received invalid header\n");
504 RPCRT4_DestroyConnection(*Connection);
505 return RPC_S_PROTOCOL_ERROR;
506 }
507
508 response_hdr = (RpcPktHdr*)response;
509
510 if (response_hdr->common.rpc_ver != RPC_VER_MAJOR ||
511 response_hdr->common.rpc_ver_minor != RPC_VER_MINOR ||
512 response_hdr->common.ptype != PKT_BIND_ACK) {
513 WARN("invalid protocol version or rejection packet\n");
514 RPCRT4_DestroyConnection(*Connection);
515 return RPC_S_PROTOCOL_ERROR;
516 }
517
518 if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) {
519 WARN("server doesn't allow large enough packets\n");
520 RPCRT4_DestroyConnection(*Connection);
521 return RPC_S_PROTOCOL_ERROR;
522 }
523
524 /* FIXME: do more checks? */
525
526 (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
527 (*Connection)->ActiveInterface = *InterfaceId;
528 }
529
530 return RPC_S_OK;
531 }
532
533 RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
534 {
535 TRACE("(Binding == ^%p)\n", Binding);
536 if (!Connection) return RPC_S_OK;
537 if (Binding->FromConn == Connection) return RPC_S_OK;
538 return RPCRT4_DestroyConnection(Connection);
539 }
540
541 /* utility functions for string composing and parsing */
542 static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src)
543 {
544 unsigned len = strlen(src);
545 memcpy(data, src, len*sizeof(CHAR));
546 return len;
547 }
548
549 static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src)
550 {
551 unsigned len = strlenW(src);
552 memcpy(data, src, len*sizeof(WCHAR));
553 return len;
554 }
555
556 static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src)
557 {
558 DWORD len = strlen(dst), slen = strlen(src);
559 LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR));
560 if (!ndst)
561 {
562 HeapFree(GetProcessHeap(), 0, dst);
563 return NULL;
564 }
565 ndst[len] = ',';
566 memcpy(ndst+len+1, src, slen+1);
567 return ndst;
568 }
569
570 static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src)
571 {
572 DWORD len = strlenW(dst), slen = strlenW(src);
573 LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR));
574 if (!ndst)
575 {
576 HeapFree(GetProcessHeap(), 0, dst);
577 return NULL;
578 }
579 ndst[len] = ',';
580 memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR));
581 return ndst;
582 }
583
584
585 /***********************************************************************
586 * RpcStringBindingComposeA (RPCRT4.@)
587 */
588 RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq,
589 unsigned char *NetworkAddr, unsigned char *Endpoint,
590 unsigned char *Options, unsigned char** StringBinding )
591 {
592 DWORD len = 1;
593 LPSTR data;
594
595 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
596 debugstr_a( ObjUuid ), debugstr_a( Protseq ),
597 debugstr_a( NetworkAddr ), debugstr_a( Endpoint ),
598 debugstr_a( Options ), StringBinding );
599
600 if (ObjUuid && *ObjUuid) len += strlen(ObjUuid) + 1;
601 if (Protseq && *Protseq) len += strlen(Protseq) + 1;
602 if (NetworkAddr && *NetworkAddr) len += strlen(NetworkAddr);
603 if (Endpoint && *Endpoint) len += strlen(Endpoint) + 2;
604 if (Options && *Options) len += strlen(Options) + 2;
605
606 data = HeapAlloc(GetProcessHeap(), 0, len);
607 *StringBinding = data;
608
609 if (ObjUuid && *ObjUuid) {
610 data += RPCRT4_strcopyA(data, ObjUuid);
611 *data++ = '@';
612 }
613 if (Protseq && *Protseq) {
614 data += RPCRT4_strcopyA(data, Protseq);
615 *data++ = ':';
616 }
617 if (NetworkAddr && *NetworkAddr)
618 data += RPCRT4_strcopyA(data, NetworkAddr);
619
620 if ((Endpoint && *Endpoint) ||
621 (Options && *Options)) {
622 *data++ = '[';
623 if (Endpoint && *Endpoint) {
624 data += RPCRT4_strcopyA(data, Endpoint);
625 if (Options && *Options) *data++ = ',';
626 }
627 if (Options && *Options) {
628 data += RPCRT4_strcopyA(data, Options);
629 }
630 *data++ = ']';
631 }
632 *data = 0;
633
634 return RPC_S_OK;
635 }
636
637 /***********************************************************************
638 * RpcStringBindingComposeW (RPCRT4.@)
639 */
640 RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq,
641 LPWSTR NetworkAddr, LPWSTR Endpoint,
642 LPWSTR Options, LPWSTR* StringBinding )
643 {
644 DWORD len = 1;
645 LPWSTR data;
646
647 TRACE("(%s,%s,%s,%s,%s,%p)\n",
648 debugstr_w( ObjUuid ), debugstr_w( Protseq ),
649 debugstr_w( NetworkAddr ), debugstr_w( Endpoint ),
650 debugstr_w( Options ), StringBinding);
651
652 if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1;
653 if (Protseq && *Protseq) len += strlenW(Protseq) + 1;
654 if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr);
655 if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2;
656 if (Options && *Options) len += strlenW(Options) + 2;
657
658 data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
659 *StringBinding = data;
660
661 if (ObjUuid && *ObjUuid) {
662 data += RPCRT4_strcopyW(data, ObjUuid);
663 *data++ = '@';
664 }
665 if (Protseq && *Protseq) {
666 data += RPCRT4_strcopyW(data, Protseq);
667 *data++ = ':';
668 }
669 if (NetworkAddr && *NetworkAddr) {
670 data += RPCRT4_strcopyW(data, NetworkAddr);
671 }
672 if ((Endpoint && *Endpoint) ||
673 (Options && *Options)) {
674 *data++ = '[';
675 if (Endpoint && *Endpoint) {
676 data += RPCRT4_strcopyW(data, Endpoint);
677 if (Options && *Options) *data++ = ',';
678 }
679 if (Options && *Options) {
680 data += RPCRT4_strcopyW(data, Options);
681 }
682 *data++ = ']';
683 }
684 *data = 0;
685
686 return RPC_S_OK;
687 }
688
689
690 /***********************************************************************
691 * RpcStringBindingParseA (RPCRT4.@)
692 */
693 RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid,
694 unsigned char **Protseq, unsigned char **NetworkAddr,
695 unsigned char **Endpoint, unsigned char **Options)
696 {
697 CHAR *data, *next;
698 static const char ep_opt[] = "endpoint=";
699
700 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding),
701 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
702
703 if (ObjUuid) *ObjUuid = NULL;
704 if (Protseq) *Protseq = NULL;
705 if (NetworkAddr) *NetworkAddr = NULL;
706 if (Endpoint) *Endpoint = NULL;
707 if (Options) *Options = NULL;
708
709 data = StringBinding;
710
711 next = strchr(data, '@');
712 if (next) {
713 if (ObjUuid) *ObjUuid = RPCRT4_strndupA(data, next - data);
714 data = next+1;
715 }
716
717 next = strchr(data, ':');
718 if (next) {
719 if (Protseq) *Protseq = RPCRT4_strndupA(data, next - data);
720 data = next+1;
721 }
722
723 next = strchr(data, '[');
724 if (next) {
725 CHAR *close, *opt;
726
727 if (NetworkAddr) *NetworkAddr = RPCRT4_strndupA(data, next - data);
728 data = next+1;
729 close = strchr(data, ']');
730 if (!close) goto fail;
731
732 /* tokenize options */
733 while (data < close) {
734 next = strchr(data, ',');
735 if (!next || next > close) next = close;
736 /* FIXME: this is kind of inefficient */
737 opt = RPCRT4_strndupA(data, next - data);
738 data = next+1;
739
740 /* parse option */
741 next = strchr(opt, '=');
742 if (!next) {
743 /* not an option, must be an endpoint */
744 if (*Endpoint) goto fail;
745 *Endpoint = opt;
746 } else {
747 if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) {
748 /* endpoint option */
749 if (*Endpoint) goto fail;
750 *Endpoint = RPCRT4_strdupA(next+1);
751 HeapFree(GetProcessHeap(), 0, opt);
752 } else {
753 /* network option */
754 if (*Options) {
755 /* FIXME: this is kind of inefficient */
756 *Options = RPCRT4_strconcatA(*Options, opt);
757 HeapFree(GetProcessHeap(), 0, opt);
758 } else
759 *Options = opt;
760 }
761 }
762 }
763
764 data = close+1;
765 if (*data) goto fail;
766 }
767 else if (NetworkAddr)
768 *NetworkAddr = RPCRT4_strdupA(data);
769
770 return RPC_S_OK;
771
772 fail:
773 if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid);
774 if (Protseq) RpcStringFreeA((unsigned char**)Protseq);
775 if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr);
776 if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint);
777 if (Options) RpcStringFreeA((unsigned char**)Options);
778 return RPC_S_INVALID_STRING_BINDING;
779 }
780
781 /***********************************************************************
782 * RpcStringBindingParseW (RPCRT4.@)
783 */
784 RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid,
785 LPWSTR *Protseq, LPWSTR *NetworkAddr,
786 LPWSTR *Endpoint, LPWSTR *Options)
787 {
788 WCHAR *data, *next;
789 static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0};
790
791 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding),
792 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
793
794 if (ObjUuid) *ObjUuid = NULL;
795 if (Protseq) *Protseq = NULL;
796 if (NetworkAddr) *NetworkAddr = NULL;
797 if (Endpoint) *Endpoint = NULL;
798 if (Options) *Options = NULL;
799
800 data = StringBinding;
801
802 next = strchrW(data, '@');
803 if (next) {
804 if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data);
805 data = next+1;
806 }
807
808 next = strchrW(data, ':');
809 if (next) {
810 if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data);
811 data = next+1;
812 }
813
814 next = strchrW(data, '[');
815 if (next) {
816 WCHAR *close, *opt;
817
818 if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data);
819 data = next+1;
820 close = strchrW(data, ']');
821 if (!close) goto fail;
822
823 /* tokenize options */
824 while (data < close) {
825 next = strchrW(data, ',');
826 if (!next || next > close) next = close;
827 /* FIXME: this is kind of inefficient */
828 opt = RPCRT4_strndupW(data, next - data);
829 data = next+1;
830
831 /* parse option */
832 next = strchrW(opt, '=');
833 if (!next) {
834 /* not an option, must be an endpoint */
835 if (*Endpoint) goto fail;
836 *Endpoint = opt;
837 } else {
838 if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) {
839 /* endpoint option */
840 if (*Endpoint) goto fail;
841 *Endpoint = RPCRT4_strdupW(next+1);
842 HeapFree(GetProcessHeap(), 0, opt);
843 } else {
844 /* network option */
845 if (*Options) {
846 /* FIXME: this is kind of inefficient */
847 *Options = RPCRT4_strconcatW(*Options, opt);
848 HeapFree(GetProcessHeap(), 0, opt);
849 } else
850 *Options = opt;
851 }
852 }
853 }
854
855 data = close+1;
856 if (*data) goto fail;
857 } else if (NetworkAddr)
858 *NetworkAddr = RPCRT4_strdupW(data);
859
860 return RPC_S_OK;
861
862 fail:
863 if (ObjUuid) RpcStringFreeW(ObjUuid);
864 if (Protseq) RpcStringFreeW(Protseq);
865 if (NetworkAddr) RpcStringFreeW(NetworkAddr);
866 if (Endpoint) RpcStringFreeW(Endpoint);
867 if (Options) RpcStringFreeW(Options);
868 return RPC_S_INVALID_STRING_BINDING;
869 }
870
871 /***********************************************************************
872 * RpcBindingFree (RPCRT4.@)
873 */
874 RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding )
875 {
876 RPC_STATUS status;
877 TRACE("(%p) = %p\n", Binding, *Binding);
878 status = RPCRT4_DestroyBinding(*Binding);
879 if (status == RPC_S_OK) *Binding = 0;
880 return status;
881 }
882
883 /***********************************************************************
884 * RpcBindingVectorFree (RPCRT4.@)
885 */
886 RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector )
887 {
888 RPC_STATUS status;
889 unsigned long c;
890
891 TRACE("(%p)\n", BindingVector);
892 for (c=0; c<(*BindingVector)->Count; c++) {
893 status = RpcBindingFree(&(*BindingVector)->BindingH[c]);
894 }
895 HeapFree(GetProcessHeap(), 0, *BindingVector);
896 *BindingVector = NULL;
897 return RPC_S_OK;
898 }
899
900 /***********************************************************************
901 * RpcBindingInqObject (RPCRT4.@)
902 */
903 RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
904 {
905 RpcBinding* bind = (RpcBinding*)Binding;
906
907 TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid));
908 memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID));
909 return RPC_S_OK;
910 }
911
912 /***********************************************************************
913 * RpcBindingSetObject (RPCRT4.@)
914 */
915 RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
916 {
917 RpcBinding* bind = (RpcBinding*)Binding;
918
919 TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid));
920 if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING;
921 return RPCRT4_SetBindingObject(Binding, ObjectUuid);
922 }
923
924 /***********************************************************************
925 * RpcBindingFromStringBindingA (RPCRT4.@)
926 */
927 RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding )
928 {
929 RPC_STATUS ret;
930 RpcBinding* bind = NULL;
931 unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options;
932 UUID Uuid;
933
934 TRACE("(%s,%p)\n", debugstr_a(StringBinding), Binding);
935
936 ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq,
937 &NetworkAddr, &Endpoint, &Options);
938 if (ret != RPC_S_OK) return ret;
939
940 ret = UuidFromStringA(ObjectUuid, &Uuid);
941
942 if (ret == RPC_S_OK)
943 ret = RPCRT4_CreateBindingA(&bind, FALSE, Protseq);
944 if (ret == RPC_S_OK)
945 ret = RPCRT4_SetBindingObject(bind, &Uuid);
946 if (ret == RPC_S_OK)
947 ret = RPCRT4_CompleteBindingA(bind, NetworkAddr, Endpoint, Options);
948
949 RpcStringFreeA((unsigned char**)&Options);
950 RpcStringFreeA((unsigned char**)&Endpoint);
951 RpcStringFreeA((unsigned char**)&NetworkAddr);
952 RpcStringFreeA((unsigned char**)&Protseq);
953 RpcStringFreeA((unsigned char**)&ObjectUuid);
954
955 if (ret == RPC_S_OK)
956 *Binding = (RPC_BINDING_HANDLE)bind;
957 else
958 RPCRT4_DestroyBinding(bind);
959
960 return ret;
961 }
962
963 /***********************************************************************
964 * RpcBindingFromStringBindingW (RPCRT4.@)
965 */
966 RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding )
967 {
968 RPC_STATUS ret;
969 RpcBinding* bind = NULL;
970 LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
971 UUID Uuid;
972
973 TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding);
974
975 ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq,
976 &NetworkAddr, &Endpoint, &Options);
977 if (ret != RPC_S_OK) return ret;
978
979 ret = UuidFromStringW(ObjectUuid, &Uuid);
980
981 if (ret == RPC_S_OK)
982 ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq);
983 if (ret == RPC_S_OK)
984 ret = RPCRT4_SetBindingObject(bind, &Uuid);
985 if (ret == RPC_S_OK)
986 ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options);
987
988 RpcStringFreeW(&Options);
989 RpcStringFreeW(&Endpoint);
990 RpcStringFreeW(&NetworkAddr);
991 RpcStringFreeW(&Protseq);
992 RpcStringFreeW(&ObjectUuid);
993
994 if (ret == RPC_S_OK)
995 *Binding = (RPC_BINDING_HANDLE)bind;
996 else
997 RPCRT4_DestroyBinding(bind);
998
999 return ret;
1000 }
1001
1002 /***********************************************************************
1003 * RpcBindingToStringBindingA (RPCRT4.@)
1004 */
1005 RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding )
1006 {
1007 RPC_STATUS ret;
1008 RpcBinding* bind = (RpcBinding*)Binding;
1009 LPSTR ObjectUuid;
1010
1011 TRACE("(%p,%p)\n", Binding, StringBinding);
1012
1013 ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid);
1014 if (ret != RPC_S_OK) return ret;
1015
1016 ret = RpcStringBindingComposeA(ObjectUuid, bind->Protseq, bind->NetworkAddr,
1017 bind->Endpoint, NULL, StringBinding);
1018
1019 RpcStringFreeA((unsigned char**)&ObjectUuid);
1020
1021 return ret;
1022 }
1023
1024 /***********************************************************************
1025 * RpcBindingToStringBindingW (RPCRT4.@)
1026 */
1027 RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding )
1028 {
1029 RPC_STATUS ret;
1030 unsigned char *str = NULL;
1031 TRACE("(%p,%p)\n", Binding, StringBinding);
1032 ret = RpcBindingToStringBindingA(Binding, &str);
1033 *StringBinding = RPCRT4_strdupAtoW(str);
1034 RpcStringFreeA((unsigned char**)&str);
1035 return ret;
1036 }
1037
1038 /***********************************************************************
1039 * I_RpcBindingSetAsync (RPCRT4.@)
1040 * NOTES
1041 * Exists in win9x and winNT, but with different number of arguments
1042 * (9x version has 3 arguments, NT has 2).
1043 */
1044 RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn)
1045 {
1046 RpcBinding* bind = (RpcBinding*)Binding;
1047
1048 TRACE( "(%p,%p): stub\n", Binding, BlockingFn );
1049
1050 bind->BlockingFn = BlockingFn;
1051
1052 return RPC_S_OK;
1053 }
1054
1055 /***********************************************************************
1056 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1057 */
1058 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) {
1059 UNICODE_STRING protseqW;
1060
1061 if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */
1062
1063 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, protseq)) {
1064 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1065 RtlFreeUnicodeString(&protseqW);
1066 return ret;
1067 } else return RPC_S_OUT_OF_MEMORY;
1068 }
1069
1070 /***********************************************************************
1071 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1072 *
1073 * Checks if the given protocol sequence is known by the RPC system.
1074 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1075 *
1076 * We currently support:
1077 * ncalrpc local-only rpc over LPC (LPC is not really used)
1078 * ncacn_np rpc over named pipes
1079 */
1080 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) {
1081 static const WCHAR protseqsW[][15] = {
1082 {'n','c','a','l','r','p','c',0},
1083 {'n','c','a','c','n','_','n','p',0}
1084 };
1085 static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]);
1086 int i;
1087
1088 if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */
1089
1090 for (i = 0; i < count; i++) {
1091 if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK;
1092 }
1093
1094 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq));
1095 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1096 }