4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
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.
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.
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
37 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 #include "rpc_binding.h"
45 #include "rpc_message.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(rpc
);
49 LPSTR
RPCRT4_strndupA(LPCSTR src
, INT slen
)
53 if (!src
) return NULL
;
54 if (slen
== -1) slen
= strlen(src
);
56 s
= HeapAlloc(GetProcessHeap(), 0, len
+1);
62 LPSTR
RPCRT4_strdupWtoA(LPWSTR src
)
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
);
73 LPWSTR
RPCRT4_strdupAtoW(LPSTR src
)
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
);
84 LPWSTR
RPCRT4_strndupW(LPWSTR src
, INT slen
)
88 if (!src
) return NULL
;
89 if (slen
== -1) slen
= strlenW(src
);
91 s
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
92 memcpy(s
, src
, len
*sizeof(WCHAR
));
97 void RPCRT4_strfree(LPSTR src
)
99 HeapFree(GetProcessHeap(), 0, src
);
102 RPC_STATUS
RPCRT4_CreateConnection(RpcConnection
** Connection
, BOOL server
, LPSTR Protseq
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
, RpcBinding
* Binding
)
104 RpcConnection
* NewConnection
;
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
;
114 TRACE("connection: %p\n", NewConnection
);
115 *Connection
= NewConnection
;
120 RPC_STATUS
RPCRT4_DestroyConnection(RpcConnection
* Connection
)
122 TRACE("connection: %p\n", Connection
);
124 RPCRT4_CloseConnection(Connection
);
125 RPCRT4_strfree(Connection
->Endpoint
);
126 RPCRT4_strfree(Connection
->NetworkAddr
);
127 RPCRT4_strfree(Connection
->Protseq
);
128 HeapFree(GetProcessHeap(), 0, Connection
);
132 RPC_STATUS
RPCRT4_OpenConnection(RpcConnection
* Connection
)
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\\";
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
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
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
[0].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
151 Connection
->ovl
[1].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
152 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
[0])) {
153 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
154 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
155 SetEvent(Connection
->ovl
[0].hEvent
);
157 } else if (GetLastError() == ERROR_IO_PENDING
) {
160 return RPC_S_SERVER_UNAVAILABLE
;
163 /* protseq=ncacn_np: named pipes */
164 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
165 static LPCSTR prefix
= "\\\\.";
167 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
168 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
169 TRACE("listening on %s\n", pname
);
170 Connection
->conn
= CreateNamedPipeA(pname
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
171 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
172 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
, 5000, NULL
);
173 HeapFree(GetProcessHeap(), 0, pname
);
174 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
175 Connection
->ovl
[0].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
176 Connection
->ovl
[1].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
177 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
[0])) {
178 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
179 SetEvent(Connection
->ovl
[0].hEvent
);
181 } else if (GetLastError() == ERROR_IO_PENDING
) {
184 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
185 return RPC_S_SERVER_UNAVAILABLE
;
189 ERR("protseq %s not supported\n", Connection
->Protseq
);
190 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
194 /* protseq=ncalrpc: supposed to use NT LPC ports,
195 * but we'll implement it with named pipes for now */
196 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
197 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
203 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
204 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
205 TRACE("connecting to %s\n", pname
);
207 if (WaitNamedPipeA(pname
, NMPWAIT_WAIT_FOREVER
)) {
208 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
209 OPEN_EXISTING
, 0, 0);
210 if (conn
!= INVALID_HANDLE_VALUE
) break;
211 err
= GetLastError();
212 if (err
== ERROR_PIPE_BUSY
) continue;
213 TRACE("connection failed, error=%lx\n", err
);
214 HeapFree(GetProcessHeap(), 0, pname
);
215 return RPC_S_SERVER_TOO_BUSY
;
217 err
= GetLastError();
218 WARN("connection failed, error=%lx\n", err
);
219 HeapFree(GetProcessHeap(), 0, pname
);
220 return RPC_S_SERVER_UNAVAILABLE
;
225 HeapFree(GetProcessHeap(), 0, pname
);
226 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
227 /* pipe is connected; change to message-read mode. */
228 dwMode
= PIPE_READMODE_MESSAGE
;
229 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
230 Connection
->ovl
[0].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
231 Connection
->ovl
[1].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
232 Connection
->conn
= conn
;
234 /* protseq=ncacn_np: named pipes */
235 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
236 static LPCSTR prefix
= "\\\\.";
242 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
243 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
244 TRACE("connecting to %s\n", pname
);
245 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
246 OPEN_EXISTING
, 0, 0);
247 if (conn
== INVALID_HANDLE_VALUE
) {
248 err
= GetLastError();
249 /* we don't need to handle ERROR_PIPE_BUSY here,
250 * the doc says that it is returned to the app */
251 WARN("connection failed, error=%lx\n", err
);
252 HeapFree(GetProcessHeap(), 0, pname
);
253 if (err
== ERROR_PIPE_BUSY
)
254 return RPC_S_SERVER_TOO_BUSY
;
256 return RPC_S_SERVER_UNAVAILABLE
;
260 HeapFree(GetProcessHeap(), 0, pname
);
261 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
262 /* pipe is connected; change to message-read mode. */
263 dwMode
= PIPE_READMODE_MESSAGE
;
264 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
265 Connection
->ovl
[0].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
266 Connection
->ovl
[1].hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
267 Connection
->conn
= conn
;
269 ERR("protseq %s not supported\n", Connection
->Protseq
);
270 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
277 RPC_STATUS
RPCRT4_CloseConnection(RpcConnection
* Connection
)
279 TRACE("(Connection == ^%p)\n", Connection
);
280 if (Connection
->conn
) {
281 FlushFileBuffers(Connection
->conn
);
282 CloseHandle(Connection
->conn
);
283 Connection
->conn
= 0;
285 if (Connection
->ovl
[0].hEvent
) {
286 CloseHandle(Connection
->ovl
[0].hEvent
);
287 Connection
->ovl
[0].hEvent
= 0;
289 if (Connection
->ovl
[1].hEvent
) {
290 CloseHandle(Connection
->ovl
[1].hEvent
);
291 Connection
->ovl
[1].hEvent
= 0;
296 RPC_STATUS
RPCRT4_SpawnConnection(RpcConnection
** Connection
, RpcConnection
* OldConnection
)
298 RpcConnection
* NewConnection
;
299 RPC_STATUS err
= RPCRT4_CreateConnection(&NewConnection
, OldConnection
->server
, OldConnection
->Protseq
,
300 OldConnection
->NetworkAddr
, OldConnection
->Endpoint
, NULL
, NULL
);
301 if (err
== RPC_S_OK
) {
302 /* because of the way named pipes work, we'll transfer the connected pipe
303 * to the child, then reopen the server binding to continue listening */
304 NewConnection
->conn
= OldConnection
->conn
;
305 NewConnection
->ovl
[0] = OldConnection
->ovl
[0];
306 NewConnection
->ovl
[1] = OldConnection
->ovl
[1];
307 OldConnection
->conn
= 0;
308 memset(&OldConnection
->ovl
, 0, sizeof(OldConnection
->ovl
));
309 *Connection
= NewConnection
;
310 RPCRT4_OpenConnection(OldConnection
);
315 static RPC_STATUS
RPCRT4_AllocBinding(RpcBinding
** Binding
, BOOL server
)
317 RpcBinding
* NewBinding
;
319 NewBinding
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcBinding
));
320 NewBinding
->refs
= 1;
321 NewBinding
->server
= server
;
323 *Binding
= NewBinding
;
328 RPC_STATUS
RPCRT4_CreateBindingA(RpcBinding
** Binding
, BOOL server
, LPSTR Protseq
)
330 RpcBinding
* NewBinding
;
332 RPCRT4_AllocBinding(&NewBinding
, server
);
333 NewBinding
->Protseq
= RPCRT4_strdupA(Protseq
);
335 TRACE("binding: %p\n", NewBinding
);
336 *Binding
= NewBinding
;
341 RPC_STATUS
RPCRT4_CreateBindingW(RpcBinding
** Binding
, BOOL server
, LPWSTR Protseq
)
343 RpcBinding
* NewBinding
;
345 RPCRT4_AllocBinding(&NewBinding
, server
);
346 NewBinding
->Protseq
= RPCRT4_strdupWtoA(Protseq
);
348 TRACE("binding: %p\n", NewBinding
);
349 *Binding
= NewBinding
;
354 RPC_STATUS
RPCRT4_CompleteBindingA(RpcBinding
* Binding
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
)
356 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
357 debugstr_a(NetworkAddr
), debugstr_a(Endpoint
), debugstr_a(NetworkOptions
));
359 RPCRT4_strfree(Binding
->NetworkAddr
);
360 Binding
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
361 RPCRT4_strfree(Binding
->Endpoint
);
363 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
365 Binding
->Endpoint
= RPCRT4_strdupA("");
367 if (!Binding
->Endpoint
) ERR("out of memory?\n");
372 RPC_STATUS
RPCRT4_CompleteBindingW(RpcBinding
* Binding
, LPWSTR NetworkAddr
, LPWSTR Endpoint
, LPWSTR NetworkOptions
)
374 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
375 debugstr_w(NetworkAddr
), debugstr_w(Endpoint
), debugstr_w(NetworkOptions
));
377 RPCRT4_strfree(Binding
->NetworkAddr
);
378 Binding
->NetworkAddr
= RPCRT4_strdupWtoA(NetworkAddr
);
379 RPCRT4_strfree(Binding
->Endpoint
);
381 Binding
->Endpoint
= RPCRT4_strdupWtoA(Endpoint
);
383 Binding
->Endpoint
= RPCRT4_strdupA("");
385 if (!Binding
->Endpoint
) ERR("out of memory?\n");
390 RPC_STATUS
RPCRT4_ResolveBinding(RpcBinding
* Binding
, LPSTR Endpoint
)
392 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding
, Endpoint
);
394 RPCRT4_strfree(Binding
->Endpoint
);
395 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
400 RPC_STATUS
RPCRT4_SetBindingObject(RpcBinding
* Binding
, UUID
* ObjectUuid
)
402 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding
, debugstr_guid(ObjectUuid
));
403 if (ObjectUuid
) memcpy(&Binding
->ObjectUuid
, ObjectUuid
, sizeof(UUID
));
404 else UuidCreateNil(&Binding
->ObjectUuid
);
408 RPC_STATUS
RPCRT4_MakeBinding(RpcBinding
** Binding
, RpcConnection
* Connection
)
410 RpcBinding
* NewBinding
;
411 TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding
, Connection
);
413 RPCRT4_AllocBinding(&NewBinding
, Connection
->server
);
414 NewBinding
->Protseq
= RPCRT4_strdupA(Connection
->Protseq
);
415 NewBinding
->NetworkAddr
= RPCRT4_strdupA(Connection
->NetworkAddr
);
416 NewBinding
->Endpoint
= RPCRT4_strdupA(Connection
->Endpoint
);
417 NewBinding
->FromConn
= Connection
;
419 TRACE("binding: %p\n", NewBinding
);
420 *Binding
= NewBinding
;
425 RPC_STATUS
RPCRT4_ExportBinding(RpcBinding
** Binding
, RpcBinding
* OldBinding
)
427 InterlockedIncrement(&OldBinding
->refs
);
428 *Binding
= OldBinding
;
432 RPC_STATUS
RPCRT4_DestroyBinding(RpcBinding
* Binding
)
434 if (InterlockedDecrement(&Binding
->refs
))
437 TRACE("binding: %p\n", Binding
);
438 /* FIXME: release connections */
439 RPCRT4_strfree(Binding
->Endpoint
);
440 RPCRT4_strfree(Binding
->NetworkAddr
);
441 RPCRT4_strfree(Binding
->Protseq
);
442 HeapFree(GetProcessHeap(), 0, Binding
);
446 RPC_STATUS
RPCRT4_OpenBinding(RpcBinding
* Binding
, RpcConnection
** Connection
,
447 PRPC_SYNTAX_IDENTIFIER TransferSyntax
,
448 PRPC_SYNTAX_IDENTIFIER InterfaceId
)
450 RpcConnection
* NewConnection
;
453 TRACE("(Binding == ^%p)\n", Binding
);
455 /* if we try to bind a new interface and the connection is already opened,
456 * close the current connection and create a new with the new binding. */
457 if (!Binding
->server
&& Binding
->FromConn
&&
458 memcmp(&Binding
->FromConn
->ActiveInterface
, InterfaceId
,
459 sizeof(RPC_SYNTAX_IDENTIFIER
))) {
461 TRACE("releasing pre-existing connection\n");
462 RPCRT4_DestroyConnection(Binding
->FromConn
);
463 Binding
->FromConn
= NULL
;
465 /* we already have a connection with acceptable binding, so use it */
466 if (Binding
->FromConn
) {
467 *Connection
= Binding
->FromConn
;
472 /* create a new connection */
473 RPCRT4_CreateConnection(&NewConnection
, Binding
->server
, Binding
->Protseq
, Binding
->NetworkAddr
, Binding
->Endpoint
, NULL
, Binding
);
474 *Connection
= NewConnection
;
475 status
= RPCRT4_OpenConnection(NewConnection
);
476 if (status
!= RPC_S_OK
) {
480 /* we need to send a binding packet if we are client. */
481 if (!(*Connection
)->server
) {
485 RpcPktHdr
*response_hdr
;
487 TRACE("sending bind request to server\n");
489 hdr
= RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION
,
490 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
,
491 InterfaceId
, TransferSyntax
);
493 status
= RPCRT4_Send(*Connection
, hdr
, NULL
, 0);
494 if (status
!= RPC_S_OK
) {
495 RPCRT4_DestroyConnection(*Connection
);
499 response
= HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE
);
500 if (response
== NULL
) {
501 WARN("Can't allocate memory for binding response\n");
502 RPCRT4_DestroyConnection(*Connection
);
503 return E_OUTOFMEMORY
;
507 if (!ReadFile(NewConnection
->conn
, response
, RPC_MAX_PACKET_SIZE
, &count
, NULL
)) {
508 WARN("ReadFile failed with error %ld\n", GetLastError());
509 RPCRT4_DestroyConnection(*Connection
);
510 return RPC_S_PROTOCOL_ERROR
;
513 if (count
< sizeof(response_hdr
->common
)) {
514 WARN("received invalid header\n");
515 RPCRT4_DestroyConnection(*Connection
);
516 return RPC_S_PROTOCOL_ERROR
;
519 response_hdr
= (RpcPktHdr
*)response
;
521 if (response_hdr
->common
.rpc_ver
!= RPC_VER_MAJOR
||
522 response_hdr
->common
.rpc_ver_minor
!= RPC_VER_MINOR
||
523 response_hdr
->common
.ptype
!= PKT_BIND_ACK
) {
524 WARN("invalid protocol version or rejection packet\n");
525 RPCRT4_DestroyConnection(*Connection
);
526 return RPC_S_PROTOCOL_ERROR
;
529 if (response_hdr
->bind_ack
.max_tsize
< RPC_MIN_PACKET_SIZE
) {
530 WARN("server doesn't allow large enough packets\n");
531 RPCRT4_DestroyConnection(*Connection
);
532 return RPC_S_PROTOCOL_ERROR
;
535 /* FIXME: do more checks? */
537 (*Connection
)->MaxTransmissionSize
= response_hdr
->bind_ack
.max_tsize
;
538 (*Connection
)->ActiveInterface
= *InterfaceId
;
544 RPC_STATUS
RPCRT4_CloseBinding(RpcBinding
* Binding
, RpcConnection
* Connection
)
546 TRACE("(Binding == ^%p)\n", Binding
);
547 if (!Connection
) return RPC_S_OK
;
548 if (Binding
->FromConn
== Connection
) return RPC_S_OK
;
549 return RPCRT4_DestroyConnection(Connection
);
552 /* utility functions for string composing and parsing */
553 static unsigned RPCRT4_strcopyA(LPSTR data
, LPCSTR src
)
555 unsigned len
= strlen(src
);
556 memcpy(data
, src
, len
*sizeof(CHAR
));
560 static unsigned RPCRT4_strcopyW(LPWSTR data
, LPCWSTR src
)
562 unsigned len
= strlenW(src
);
563 memcpy(data
, src
, len
*sizeof(WCHAR
));
567 static LPSTR
RPCRT4_strconcatA(LPSTR dst
, LPCSTR src
)
569 DWORD len
= strlen(dst
), slen
= strlen(src
);
570 LPSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(CHAR
));
573 HeapFree(GetProcessHeap(), 0, dst
);
577 memcpy(ndst
+len
+1, src
, slen
+1);
581 static LPWSTR
RPCRT4_strconcatW(LPWSTR dst
, LPCWSTR src
)
583 DWORD len
= strlenW(dst
), slen
= strlenW(src
);
584 LPWSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(WCHAR
));
587 HeapFree(GetProcessHeap(), 0, dst
);
591 memcpy(ndst
+len
+1, src
, (slen
+1)*sizeof(WCHAR
));
596 /***********************************************************************
597 * RpcStringBindingComposeA (RPCRT4.@)
599 RPC_STATUS WINAPI
RpcStringBindingComposeA(unsigned char *ObjUuid
, unsigned char *Protseq
,
600 unsigned char *NetworkAddr
, unsigned char *Endpoint
,
601 unsigned char *Options
, unsigned char** StringBinding
)
606 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
607 debugstr_a( (char*)ObjUuid
), debugstr_a( (char*)Protseq
),
608 debugstr_a( (char*)NetworkAddr
), debugstr_a( (char*)Endpoint
),
609 debugstr_a( (char*)Options
), StringBinding
);
611 if (ObjUuid
&& *ObjUuid
) len
+= strlen((char*)ObjUuid
) + 1;
612 if (Protseq
&& *Protseq
) len
+= strlen((char*)Protseq
) + 1;
613 if (NetworkAddr
&& *NetworkAddr
) len
+= strlen((char*)NetworkAddr
);
614 if (Endpoint
&& *Endpoint
) len
+= strlen((char*)Endpoint
) + 2;
615 if (Options
&& *Options
) len
+= strlen((char*)Options
) + 2;
617 data
= HeapAlloc(GetProcessHeap(), 0, len
);
618 *StringBinding
= (unsigned char*)data
;
620 if (ObjUuid
&& *ObjUuid
) {
621 data
+= RPCRT4_strcopyA(data
, (char*)ObjUuid
);
624 if (Protseq
&& *Protseq
) {
625 data
+= RPCRT4_strcopyA(data
, (char*)Protseq
);
628 if (NetworkAddr
&& *NetworkAddr
)
629 data
+= RPCRT4_strcopyA(data
, (char*)NetworkAddr
);
631 if ((Endpoint
&& *Endpoint
) ||
632 (Options
&& *Options
)) {
634 if (Endpoint
&& *Endpoint
) {
635 data
+= RPCRT4_strcopyA(data
, (char*)Endpoint
);
636 if (Options
&& *Options
) *data
++ = ',';
638 if (Options
&& *Options
) {
639 data
+= RPCRT4_strcopyA(data
, (char*)Options
);
648 /***********************************************************************
649 * RpcStringBindingComposeW (RPCRT4.@)
651 RPC_STATUS WINAPI
RpcStringBindingComposeW( LPWSTR ObjUuid
, LPWSTR Protseq
,
652 LPWSTR NetworkAddr
, LPWSTR Endpoint
,
653 LPWSTR Options
, LPWSTR
* StringBinding
)
658 TRACE("(%s,%s,%s,%s,%s,%p)\n",
659 debugstr_w( ObjUuid
), debugstr_w( Protseq
),
660 debugstr_w( NetworkAddr
), debugstr_w( Endpoint
),
661 debugstr_w( Options
), StringBinding
);
663 if (ObjUuid
&& *ObjUuid
) len
+= strlenW(ObjUuid
) + 1;
664 if (Protseq
&& *Protseq
) len
+= strlenW(Protseq
) + 1;
665 if (NetworkAddr
&& *NetworkAddr
) len
+= strlenW(NetworkAddr
);
666 if (Endpoint
&& *Endpoint
) len
+= strlenW(Endpoint
) + 2;
667 if (Options
&& *Options
) len
+= strlenW(Options
) + 2;
669 data
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
670 *StringBinding
= data
;
672 if (ObjUuid
&& *ObjUuid
) {
673 data
+= RPCRT4_strcopyW(data
, ObjUuid
);
676 if (Protseq
&& *Protseq
) {
677 data
+= RPCRT4_strcopyW(data
, Protseq
);
680 if (NetworkAddr
&& *NetworkAddr
) {
681 data
+= RPCRT4_strcopyW(data
, NetworkAddr
);
683 if ((Endpoint
&& *Endpoint
) ||
684 (Options
&& *Options
)) {
686 if (Endpoint
&& *Endpoint
) {
687 data
+= RPCRT4_strcopyW(data
, Endpoint
);
688 if (Options
&& *Options
) *data
++ = ',';
690 if (Options
&& *Options
) {
691 data
+= RPCRT4_strcopyW(data
, Options
);
701 /***********************************************************************
702 * RpcStringBindingParseA (RPCRT4.@)
704 RPC_STATUS WINAPI
RpcStringBindingParseA( unsigned char *StringBinding
, unsigned char **ObjUuid
,
705 unsigned char **Protseq
, unsigned char **NetworkAddr
,
706 unsigned char **Endpoint
, unsigned char **Options
)
709 static const char ep_opt
[] = "endpoint=";
711 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a((char*)StringBinding
),
712 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
714 if (ObjUuid
) *ObjUuid
= NULL
;
715 if (Protseq
) *Protseq
= NULL
;
716 if (NetworkAddr
) *NetworkAddr
= NULL
;
717 if (Endpoint
) *Endpoint
= NULL
;
718 if (Options
) *Options
= NULL
;
720 data
= (char*) StringBinding
;
722 next
= strchr(data
, '@');
724 if (ObjUuid
) *ObjUuid
= (unsigned char*)RPCRT4_strndupA(data
, next
- data
);
728 next
= strchr(data
, ':');
730 if (Protseq
) *Protseq
= (unsigned char*)RPCRT4_strndupA(data
, next
- data
);
734 next
= strchr(data
, '[');
738 if (NetworkAddr
) *NetworkAddr
= (unsigned char*)RPCRT4_strndupA(data
, next
- data
);
740 close
= strchr(data
, ']');
741 if (!close
) goto fail
;
743 /* tokenize options */
744 while (data
< close
) {
745 next
= strchr(data
, ',');
746 if (!next
|| next
> close
) next
= close
;
747 /* FIXME: this is kind of inefficient */
748 opt
= RPCRT4_strndupA(data
, next
- data
);
752 next
= strchr(opt
, '=');
754 /* not an option, must be an endpoint */
755 if (*Endpoint
) goto fail
;
756 *Endpoint
= (unsigned char*) opt
;
758 if (strncmp(opt
, ep_opt
, strlen(ep_opt
)) == 0) {
759 /* endpoint option */
760 if (*Endpoint
) goto fail
;
761 *Endpoint
= (unsigned char*) RPCRT4_strdupA(next
+1);
762 HeapFree(GetProcessHeap(), 0, opt
);
766 /* FIXME: this is kind of inefficient */
767 *Options
= (unsigned char*) RPCRT4_strconcatA( (char*)*Options
, opt
);
768 HeapFree(GetProcessHeap(), 0, opt
);
770 *Options
= (unsigned char*) opt
;
776 if (*data
) goto fail
;
778 else if (NetworkAddr
)
779 *NetworkAddr
= (unsigned char*)RPCRT4_strdupA(data
);
784 if (ObjUuid
) RpcStringFreeA((unsigned char**)ObjUuid
);
785 if (Protseq
) RpcStringFreeA((unsigned char**)Protseq
);
786 if (NetworkAddr
) RpcStringFreeA((unsigned char**)NetworkAddr
);
787 if (Endpoint
) RpcStringFreeA((unsigned char**)Endpoint
);
788 if (Options
) RpcStringFreeA((unsigned char**)Options
);
789 return RPC_S_INVALID_STRING_BINDING
;
792 /***********************************************************************
793 * RpcStringBindingParseW (RPCRT4.@)
795 RPC_STATUS WINAPI
RpcStringBindingParseW( LPWSTR StringBinding
, LPWSTR
*ObjUuid
,
796 LPWSTR
*Protseq
, LPWSTR
*NetworkAddr
,
797 LPWSTR
*Endpoint
, LPWSTR
*Options
)
800 static const WCHAR ep_opt
[] = {'e','n','d','p','o','i','n','t','=',0};
802 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding
),
803 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
805 if (ObjUuid
) *ObjUuid
= NULL
;
806 if (Protseq
) *Protseq
= NULL
;
807 if (NetworkAddr
) *NetworkAddr
= NULL
;
808 if (Endpoint
) *Endpoint
= NULL
;
809 if (Options
) *Options
= NULL
;
811 data
= StringBinding
;
813 next
= strchrW(data
, '@');
815 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupW(data
, next
- data
);
819 next
= strchrW(data
, ':');
821 if (Protseq
) *Protseq
= RPCRT4_strndupW(data
, next
- data
);
825 next
= strchrW(data
, '[');
829 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupW(data
, next
- data
);
831 close
= strchrW(data
, ']');
832 if (!close
) goto fail
;
834 /* tokenize options */
835 while (data
< close
) {
836 next
= strchrW(data
, ',');
837 if (!next
|| next
> close
) next
= close
;
838 /* FIXME: this is kind of inefficient */
839 opt
= RPCRT4_strndupW(data
, next
- data
);
843 next
= strchrW(opt
, '=');
845 /* not an option, must be an endpoint */
846 if (*Endpoint
) goto fail
;
849 if (strncmpW(opt
, ep_opt
, strlenW(ep_opt
)) == 0) {
850 /* endpoint option */
851 if (*Endpoint
) goto fail
;
852 *Endpoint
= RPCRT4_strdupW(next
+1);
853 HeapFree(GetProcessHeap(), 0, opt
);
857 /* FIXME: this is kind of inefficient */
858 *Options
= RPCRT4_strconcatW(*Options
, opt
);
859 HeapFree(GetProcessHeap(), 0, opt
);
867 if (*data
) goto fail
;
868 } else if (NetworkAddr
)
869 *NetworkAddr
= RPCRT4_strdupW(data
);
874 if (ObjUuid
) RpcStringFreeW(ObjUuid
);
875 if (Protseq
) RpcStringFreeW(Protseq
);
876 if (NetworkAddr
) RpcStringFreeW(NetworkAddr
);
877 if (Endpoint
) RpcStringFreeW(Endpoint
);
878 if (Options
) RpcStringFreeW(Options
);
879 return RPC_S_INVALID_STRING_BINDING
;
882 /***********************************************************************
883 * RpcBindingFree (RPCRT4.@)
885 RPC_STATUS WINAPI
RpcBindingFree( RPC_BINDING_HANDLE
* Binding
)
888 TRACE("(%p) = %p\n", Binding
, *Binding
);
889 status
= RPCRT4_DestroyBinding(*Binding
);
890 if (status
== RPC_S_OK
) *Binding
= 0;
894 /***********************************************************************
895 * RpcBindingVectorFree (RPCRT4.@)
897 RPC_STATUS WINAPI
RpcBindingVectorFree( RPC_BINDING_VECTOR
** BindingVector
)
902 TRACE("(%p)\n", BindingVector
);
903 for (c
=0; c
<(*BindingVector
)->Count
; c
++) {
904 status
= RpcBindingFree(&(*BindingVector
)->BindingH
[c
]);
906 HeapFree(GetProcessHeap(), 0, *BindingVector
);
907 *BindingVector
= NULL
;
911 /***********************************************************************
912 * RpcBindingInqObject (RPCRT4.@)
914 RPC_STATUS WINAPI
RpcBindingInqObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
916 RpcBinding
* bind
= (RpcBinding
*)Binding
;
918 TRACE("(%p,%p) = %s\n", Binding
, ObjectUuid
, debugstr_guid(&bind
->ObjectUuid
));
919 memcpy(ObjectUuid
, &bind
->ObjectUuid
, sizeof(UUID
));
923 /***********************************************************************
924 * RpcBindingSetObject (RPCRT4.@)
926 RPC_STATUS WINAPI
RpcBindingSetObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
928 RpcBinding
* bind
= (RpcBinding
*)Binding
;
930 TRACE("(%p,%s)\n", Binding
, debugstr_guid(ObjectUuid
));
931 if (bind
->server
) return RPC_S_WRONG_KIND_OF_BINDING
;
932 return RPCRT4_SetBindingObject(Binding
, ObjectUuid
);
935 /***********************************************************************
936 * RpcBindingFromStringBindingA (RPCRT4.@)
938 RPC_STATUS WINAPI
RpcBindingFromStringBindingA( unsigned char *StringBinding
, RPC_BINDING_HANDLE
* Binding
)
941 RpcBinding
* bind
= NULL
;
942 unsigned char *ObjectUuid
, *Protseq
, *NetworkAddr
, *Endpoint
, *Options
;
945 TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding
), Binding
);
947 ret
= RpcStringBindingParseA(StringBinding
, &ObjectUuid
, &Protseq
,
948 &NetworkAddr
, &Endpoint
, &Options
);
949 if (ret
!= RPC_S_OK
) return ret
;
951 ret
= UuidFromStringA(ObjectUuid
, &Uuid
);
954 ret
= RPCRT4_CreateBindingA(&bind
, FALSE
, (char*)Protseq
);
956 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
958 ret
= RPCRT4_CompleteBindingA(bind
, (char*)NetworkAddr
, (char*)Endpoint
, (char*)Options
);
960 RpcStringFreeA((unsigned char**)&Options
);
961 RpcStringFreeA((unsigned char**)&Endpoint
);
962 RpcStringFreeA((unsigned char**)&NetworkAddr
);
963 RpcStringFreeA((unsigned char**)&Protseq
);
964 RpcStringFreeA((unsigned char**)&ObjectUuid
);
967 *Binding
= (RPC_BINDING_HANDLE
)bind
;
969 RPCRT4_DestroyBinding(bind
);
974 /***********************************************************************
975 * RpcBindingFromStringBindingW (RPCRT4.@)
977 RPC_STATUS WINAPI
RpcBindingFromStringBindingW( LPWSTR StringBinding
, RPC_BINDING_HANDLE
* Binding
)
980 RpcBinding
* bind
= NULL
;
981 LPWSTR ObjectUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
;
984 TRACE("(%s,%p)\n", debugstr_w(StringBinding
), Binding
);
986 ret
= RpcStringBindingParseW(StringBinding
, &ObjectUuid
, &Protseq
,
987 &NetworkAddr
, &Endpoint
, &Options
);
988 if (ret
!= RPC_S_OK
) return ret
;
990 ret
= UuidFromStringW(ObjectUuid
, &Uuid
);
993 ret
= RPCRT4_CreateBindingW(&bind
, FALSE
, Protseq
);
995 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
997 ret
= RPCRT4_CompleteBindingW(bind
, NetworkAddr
, Endpoint
, Options
);
999 RpcStringFreeW(&Options
);
1000 RpcStringFreeW(&Endpoint
);
1001 RpcStringFreeW(&NetworkAddr
);
1002 RpcStringFreeW(&Protseq
);
1003 RpcStringFreeW(&ObjectUuid
);
1005 if (ret
== RPC_S_OK
)
1006 *Binding
= (RPC_BINDING_HANDLE
)bind
;
1008 RPCRT4_DestroyBinding(bind
);
1013 /***********************************************************************
1014 * RpcBindingToStringBindingA (RPCRT4.@)
1016 RPC_STATUS WINAPI
RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding
, unsigned char** StringBinding
)
1019 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1022 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1024 ret
= UuidToStringA(&bind
->ObjectUuid
, (unsigned char**)&ObjectUuid
);
1025 if (ret
!= RPC_S_OK
) return ret
;
1027 ret
= RpcStringBindingComposeA((unsigned char*) ObjectUuid
, (unsigned char*)bind
->Protseq
, (unsigned char*) bind
->NetworkAddr
,
1028 (unsigned char*) bind
->Endpoint
, NULL
, StringBinding
);
1030 RpcStringFreeA((unsigned char**)&ObjectUuid
);
1035 /***********************************************************************
1036 * RpcBindingToStringBindingW (RPCRT4.@)
1038 RPC_STATUS WINAPI
RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding
, unsigned short** StringBinding
)
1041 unsigned char *str
= NULL
;
1042 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1043 ret
= RpcBindingToStringBindingA(Binding
, &str
);
1044 *StringBinding
= RPCRT4_strdupAtoW((char*)str
);
1045 RpcStringFreeA((unsigned char**)&str
);
1049 /***********************************************************************
1050 * I_RpcBindingSetAsync (RPCRT4.@)
1052 * Exists in win9x and winNT, but with different number of arguments
1053 * (9x version has 3 arguments, NT has 2).
1055 RPC_STATUS WINAPI
I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding
, RPC_BLOCKING_FN BlockingFn
)
1057 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1059 TRACE( "(%p,%p): stub\n", Binding
, BlockingFn
);
1061 bind
->BlockingFn
= BlockingFn
;
1066 /***********************************************************************
1067 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1069 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidA(unsigned char *protseq
) {
1070 UNICODE_STRING protseqW
;
1072 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1074 if (RtlCreateUnicodeStringFromAsciiz(&protseqW
, (char*)protseq
)) {
1075 RPC_STATUS ret
= RpcNetworkIsProtseqValidW(protseqW
.Buffer
);
1076 RtlFreeUnicodeString(&protseqW
);
1078 } else return RPC_S_OUT_OF_MEMORY
;
1081 /***********************************************************************
1082 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1084 * Checks if the given protocol sequence is known by the RPC system.
1085 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1087 * We currently support:
1088 * ncalrpc local-only rpc over LPC (LPC is not really used)
1089 * ncacn_np rpc over named pipes
1091 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidW(LPWSTR protseq
) {
1092 static const WCHAR protseqsW
[][15] = {
1093 {'n','c','a','l','r','p','c',0},
1094 {'n','c','a','c','n','_','n','p',0}
1096 static const int count
= sizeof(protseqsW
) / sizeof(protseqsW
[0]);
1099 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1101 for (i
= 0; i
< count
; i
++) {
1102 if (!strcmpW(protseq
, protseqsW
[i
])) return RPC_S_OK
;
1105 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq
));
1106 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
1109 /***********************************************************************
1110 * RpcImpersonateClient (RPCRT4.@)
1112 * Impersonates the client connected via a binding handle so that security
1113 * checks are done in the context of the client.
1116 * BindingHandle [I] Handle to the binding to the client.
1119 * Success: RPS_S_OK.
1120 * Failure: RPC_STATUS value.
1124 * If BindingHandle is NULL then the function impersonates the client
1125 * connected to the binding handle of the current thread.
1127 RPC_STATUS WINAPI
RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle
)
1129 FIXME("(%p): stub\n", BindingHandle
);
1133 /***********************************************************************
1134 * RpcRevertToSelfEx (RPCRT4.@)
1136 * Stops impersonating the client connected to the binding handle so that security
1137 * checks are no longer done in the context of the client.
1140 * BindingHandle [I] Handle to the binding to the client.
1143 * Success: RPS_S_OK.
1144 * Failure: RPC_STATUS value.
1148 * If BindingHandle is NULL then the function stops impersonating the client
1149 * connected to the binding handle of the current thread.
1151 RPC_STATUS WINAPI
RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle
)
1153 FIXME("(%p): stub\n", BindingHandle
);