ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

rpc_message.c
Go to the documentation of this file.
00001 /*
00002  * RPC messages
00003  *
00004  * Copyright 2001-2002 Ove Kåven, TransGaming Technologies
00005  * Copyright 2004 Filip Navara
00006  * Copyright 2006 CodeWeavers
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include <stdarg.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 
00027 #include "windef.h"
00028 #include "winbase.h"
00029 #include "winerror.h"
00030 #include "winuser.h"
00031 
00032 #include "rpc.h"
00033 #include "rpcndr.h"
00034 #include "rpcdcep.h"
00035 
00036 #include "wine/debug.h"
00037 
00038 #include "rpc_binding.h"
00039 #include "rpc_defs.h"
00040 #include "rpc_message.h"
00041 #include "ncastatus.h"
00042 
00043 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
00044 
00045 /* note: the DCE/RPC spec says the alignment amount should be 4, but
00046  * MS/RPC servers seem to always use 16 */
00047 #define AUTH_ALIGNMENT 16
00048 
00049 /* gets the amount needed to round a value up to the specified alignment */
00050 #define ROUND_UP_AMOUNT(value, alignment) \
00051     (((alignment) - (((value) % (alignment)))) % (alignment))
00052 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
00053 
00054 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg);
00055 
00056 DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header)
00057 {
00058   static const DWORD header_sizes[] = {
00059     sizeof(Header->request), 0, sizeof(Header->response),
00060     sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind),
00061     sizeof(Header->bind_ack), sizeof(Header->bind_nack),
00062     0, 0, sizeof(Header->auth3), 0, 0, 0, sizeof(Header->http)
00063   };
00064   ULONG ret = 0;
00065   
00066   if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) {
00067     ret = header_sizes[Header->common.ptype];
00068     if (ret == 0)
00069       FIXME("unhandled packet type %u\n", Header->common.ptype);
00070     if (Header->common.flags & RPC_FLG_OBJECT_UUID)
00071       ret += sizeof(UUID);
00072   } else {
00073     WARN("invalid packet type %u\n", Header->common.ptype);
00074   }
00075 
00076   return ret;
00077 }
00078 
00079 static int packet_has_body(const RpcPktHdr *Header)
00080 {
00081     return (Header->common.ptype == PKT_FAULT) ||
00082            (Header->common.ptype == PKT_REQUEST) ||
00083            (Header->common.ptype == PKT_RESPONSE);
00084 }
00085 
00086 static int packet_has_auth_verifier(const RpcPktHdr *Header)
00087 {
00088     return !(Header->common.ptype == PKT_BIND_NACK) &&
00089            !(Header->common.ptype == PKT_SHUTDOWN);
00090 }
00091 
00092 static int packet_does_auth_negotiation(const RpcPktHdr *Header)
00093 {
00094     switch (Header->common.ptype)
00095     {
00096     case PKT_BIND:
00097     case PKT_BIND_ACK:
00098     case PKT_AUTH3:
00099     case PKT_ALTER_CONTEXT:
00100     case PKT_ALTER_CONTEXT_RESP:
00101         return TRUE;
00102     default:
00103         return FALSE;
00104     }
00105 }
00106 
00107 static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType,
00108                                      ULONG DataRepresentation)
00109 {
00110   Header->common.rpc_ver = RPC_VER_MAJOR;
00111   Header->common.rpc_ver_minor = RPC_VER_MINOR;
00112   Header->common.ptype = PacketType;
00113   Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation));
00114   Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation));
00115   Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation));
00116   Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation));
00117   Header->common.auth_len = 0;
00118   Header->common.call_id = 1;
00119   Header->common.flags = 0;
00120   /* Flags and fragment length are computed in RPCRT4_Send. */
00121 }                              
00122 
00123 static RpcPktHdr *RPCRT4_BuildRequestHeader(ULONG DataRepresentation,
00124                                      ULONG BufferLength,
00125                                      unsigned short ProcNum,
00126                                      UUID *ObjectUuid)
00127 {
00128   RpcPktHdr *header;
00129   BOOL has_object;
00130   RPC_STATUS status;
00131 
00132   has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status));
00133   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00134                      sizeof(header->request) + (has_object ? sizeof(UUID) : 0));
00135   if (header == NULL) {
00136     return NULL;
00137   }
00138 
00139   RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation);
00140   header->common.frag_len = sizeof(header->request);
00141   header->request.alloc_hint = BufferLength;
00142   header->request.context_id = 0;
00143   header->request.opnum = ProcNum;
00144   if (has_object) {
00145     header->common.flags |= RPC_FLG_OBJECT_UUID;
00146     header->common.frag_len += sizeof(UUID);
00147     memcpy(&header->request + 1, ObjectUuid, sizeof(UUID));
00148   }
00149 
00150   return header;
00151 }
00152 
00153 RpcPktHdr *RPCRT4_BuildResponseHeader(ULONG DataRepresentation, ULONG BufferLength)
00154 {
00155   RpcPktHdr *header;
00156 
00157   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response));
00158   if (header == NULL) {
00159     return NULL;
00160   }
00161 
00162   RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation);
00163   header->common.frag_len = sizeof(header->response);
00164   header->response.alloc_hint = BufferLength;
00165 
00166   return header;
00167 }
00168 
00169 RpcPktHdr *RPCRT4_BuildFaultHeader(ULONG DataRepresentation, RPC_STATUS Status)
00170 {
00171   RpcPktHdr *header;
00172 
00173   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault));
00174   if (header == NULL) {
00175     return NULL;
00176   }
00177 
00178   RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation);
00179   header->common.frag_len = sizeof(header->fault);
00180   header->fault.status = Status;
00181 
00182   return header;
00183 }
00184 
00185 RpcPktHdr *RPCRT4_BuildBindHeader(ULONG DataRepresentation,
00186                                   unsigned short MaxTransmissionSize,
00187                                   unsigned short MaxReceiveSize,
00188                                   ULONG  AssocGroupId,
00189                                   const RPC_SYNTAX_IDENTIFIER *AbstractId,
00190                                   const RPC_SYNTAX_IDENTIFIER *TransferId)
00191 {
00192   RpcPktHdr *header;
00193   RpcContextElement *ctxt_elem;
00194 
00195   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00196                      sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1]));
00197   if (header == NULL) {
00198     return NULL;
00199   }
00200   ctxt_elem = (RpcContextElement *)(&header->bind + 1);
00201 
00202   RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation);
00203   header->common.frag_len = sizeof(header->bind) + FIELD_OFFSET(RpcContextElement, transfer_syntaxes[1]);
00204   header->bind.max_tsize = MaxTransmissionSize;
00205   header->bind.max_rsize = MaxReceiveSize;
00206   header->bind.assoc_gid = AssocGroupId;
00207   header->bind.num_elements = 1;
00208   ctxt_elem->num_syntaxes = 1;
00209   ctxt_elem->abstract_syntax = *AbstractId;
00210   ctxt_elem->transfer_syntaxes[0] = *TransferId;
00211 
00212   return header;
00213 }
00214 
00215 static RpcPktHdr *RPCRT4_BuildAuthHeader(ULONG DataRepresentation)
00216 {
00217   RpcPktHdr *header;
00218 
00219   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
00220                      sizeof(header->auth3));
00221   if (header == NULL)
00222     return NULL;
00223 
00224   RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation);
00225   header->common.frag_len = sizeof(header->auth3);
00226 
00227   return header;
00228 }
00229 
00230 RpcPktHdr *RPCRT4_BuildBindNackHeader(ULONG DataRepresentation,
00231                                       unsigned char RpcVersion,
00232                                       unsigned char RpcVersionMinor,
00233                                       unsigned short RejectReason)
00234 {
00235   RpcPktHdr *header;
00236 
00237   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(RpcPktHdr, bind_nack.protocols[1]));
00238   if (header == NULL) {
00239     return NULL;
00240   }
00241 
00242   RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation);
00243   header->common.frag_len = FIELD_OFFSET(RpcPktHdr, bind_nack.protocols[1]);
00244   header->bind_nack.reject_reason = RejectReason;
00245   header->bind_nack.protocols_count = 1;
00246   header->bind_nack.protocols[0].rpc_ver = RpcVersion;
00247   header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor;
00248 
00249   return header;
00250 }
00251 
00252 RpcPktHdr *RPCRT4_BuildBindAckHeader(ULONG DataRepresentation,
00253                                      unsigned short MaxTransmissionSize,
00254                                      unsigned short MaxReceiveSize,
00255                                      ULONG AssocGroupId,
00256                                      LPCSTR ServerAddress,
00257                                      unsigned char ResultCount,
00258                                      const RpcResult *Results)
00259 {
00260   RpcPktHdr *header;
00261   ULONG header_size;
00262   RpcAddressString *server_address;
00263   RpcResultList *results;
00264 
00265   header_size = sizeof(header->bind_ack) +
00266                 ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) +
00267                 FIELD_OFFSET(RpcResultList, results[ResultCount]);
00268 
00269   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size);
00270   if (header == NULL) {
00271     return NULL;
00272   }
00273 
00274   RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation);
00275   header->common.frag_len = header_size;
00276   header->bind_ack.max_tsize = MaxTransmissionSize;
00277   header->bind_ack.max_rsize = MaxReceiveSize;
00278   header->bind_ack.assoc_gid = AssocGroupId;
00279   server_address = (RpcAddressString*)(&header->bind_ack + 1);
00280   server_address->length = strlen(ServerAddress) + 1;
00281   strcpy(server_address->string, ServerAddress);
00282   /* results is 4-byte aligned */
00283   results = (RpcResultList*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
00284   results->num_results = ResultCount;
00285   memcpy(&results->results[0], Results, ResultCount * sizeof(*Results));
00286 
00287   return header;
00288 }
00289 
00290 RpcPktHdr *RPCRT4_BuildHttpHeader(ULONG DataRepresentation,
00291                                   unsigned short flags,
00292                                   unsigned short num_data_items,
00293                                   unsigned int payload_size)
00294 {
00295   RpcPktHdr *header;
00296 
00297   header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->http) + payload_size);
00298   if (header == NULL) {
00299       ERR("failed to allocate memory\n");
00300     return NULL;
00301   }
00302 
00303   RPCRT4_BuildCommonHeader(header, PKT_HTTP, DataRepresentation);
00304   /* since the packet isn't current sent using RPCRT4_Send, set the flags
00305    * manually here */
00306   header->common.flags = RPC_FLG_FIRST|RPC_FLG_LAST;
00307   header->common.call_id = 0;
00308   header->common.frag_len = sizeof(header->http) + payload_size;
00309   header->http.flags = flags;
00310   header->http.num_data_items = num_data_items;
00311 
00312   return header;
00313 }
00314 
00315 #define WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, type, value) \
00316     do { \
00317         *(unsigned int *)(payload) = (type); \
00318         (payload) += 4; \
00319         *(unsigned int *)(payload) = (value); \
00320         (payload) += 4; \
00321     } while (0)
00322 
00323 #define WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, type, uuid) \
00324     do { \
00325         *(unsigned int *)(payload) = (type); \
00326         (payload) += 4; \
00327         *(UUID *)(payload) = (uuid); \
00328         (payload) += sizeof(UUID); \
00329     } while (0)
00330 
00331 #define WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted, flow_control_increment, uuid) \
00332     do { \
00333         *(unsigned int *)(payload) = 0x00000001; \
00334         (payload) += 4; \
00335         *(unsigned int *)(payload) = (bytes_transmitted); \
00336         (payload) += 4; \
00337         *(unsigned int *)(payload) = (flow_control_increment); \
00338         (payload) += 4; \
00339         *(UUID *)(payload) = (uuid); \
00340         (payload) += sizeof(UUID); \
00341     } while (0)
00342 
00343 RpcPktHdr *RPCRT4_BuildHttpConnectHeader(unsigned short flags, int out_pipe,
00344                                          const UUID *connection_uuid,
00345                                          const UUID *pipe_uuid,
00346                                          const UUID *association_uuid)
00347 {
00348   RpcPktHdr *header;
00349   unsigned int size;
00350   char *payload;
00351 
00352   size = 8 + 4 + sizeof(UUID) + 4 + sizeof(UUID) + 8;
00353   if (!out_pipe)
00354     size += 8 + 4 + sizeof(UUID);
00355 
00356   header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, flags,
00357                                   out_pipe ? 4 : 6, size);
00358   if (!header) return NULL;
00359   payload = (char *)(&header->http+1);
00360 
00361   /* FIXME: what does this part of the payload do? */
00362   WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000006, 0x00000001);
00363 
00364   WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *connection_uuid);
00365   WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x00000003, *pipe_uuid);
00366 
00367   if (out_pipe)
00368     /* FIXME: what does this part of the payload do? */
00369     WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000000, 0x00010000);
00370   else
00371   {
00372     /* FIXME: what does this part of the payload do? */
00373     WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000004, 0x40000000);
00374     /* FIXME: what does this part of the payload do? */
00375     WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x00000005, 0x000493e0);
00376 
00377     WRITE_HTTP_PAYLOAD_FIELD_UUID(payload, 0x0000000c, *association_uuid);
00378   }
00379 
00380   return header;
00381 }
00382 
00383 RpcPktHdr *RPCRT4_BuildHttpFlowControlHeader(BOOL server, ULONG bytes_transmitted,
00384                                              ULONG flow_control_increment,
00385                                              const UUID *pipe_uuid)
00386 {
00387   RpcPktHdr *header;
00388   char *payload;
00389 
00390   header = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x2, 2,
00391                                   5 * sizeof(ULONG) + sizeof(UUID));
00392   if (!header) return NULL;
00393   payload = (char *)(&header->http+1);
00394 
00395   WRITE_HTTP_PAYLOAD_FIELD_UINT32(payload, 0x0000000d, (server ? 0x0 : 0x3));
00396 
00397   WRITE_HTTP_PAYLOAD_FIELD_FLOW_CONTROL(payload, bytes_transmitted,
00398                                         flow_control_increment, *pipe_uuid);
00399   return header;
00400 }
00401 
00402 VOID RPCRT4_FreeHeader(RpcPktHdr *Header)
00403 {
00404   HeapFree(GetProcessHeap(), 0, Header);
00405 }
00406 
00407 NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status)
00408 {
00409     switch (status)
00410     {
00411     case ERROR_INVALID_HANDLE:              return NCA_S_FAULT_CONTEXT_MISMATCH;
00412     case ERROR_OUTOFMEMORY:                 return NCA_S_FAULT_REMOTE_NO_MEMORY;
00413     case RPC_S_NOT_LISTENING:               return NCA_S_SERVER_TOO_BUSY;
00414     case RPC_S_UNKNOWN_IF:                  return NCA_S_UNK_IF;
00415     case RPC_S_SERVER_TOO_BUSY:             return NCA_S_SERVER_TOO_BUSY;
00416     case RPC_S_CALL_FAILED:                 return NCA_S_FAULT_UNSPEC;
00417     case RPC_S_CALL_FAILED_DNE:             return NCA_S_MANAGER_NOT_ENTERED;
00418     case RPC_S_PROTOCOL_ERROR:              return NCA_S_PROTO_ERROR;
00419     case RPC_S_UNSUPPORTED_TYPE:            return NCA_S_UNSUPPORTED_TYPE;
00420     case RPC_S_INVALID_TAG:                 return NCA_S_FAULT_INVALID_TAG;
00421     case RPC_S_INVALID_BOUND:               return NCA_S_FAULT_INVALID_BOUND;
00422     case RPC_S_PROCNUM_OUT_OF_RANGE:        return NCA_S_OP_RNG_ERROR;
00423     case RPC_X_SS_HANDLES_MISMATCH:         return NCA_S_FAULT_CONTEXT_MISMATCH;
00424     case RPC_S_CALL_CANCELLED:              return NCA_S_FAULT_CANCEL;
00425     case RPC_S_COMM_FAILURE:                return NCA_S_COMM_FAILURE;
00426     case RPC_X_WRONG_PIPE_ORDER:            return NCA_S_FAULT_PIPE_ORDER;
00427     case RPC_X_PIPE_CLOSED:                 return NCA_S_FAULT_PIPE_CLOSED;
00428     case RPC_X_PIPE_DISCIPLINE_ERROR:       return NCA_S_FAULT_PIPE_DISCIPLINE;
00429     case RPC_X_PIPE_EMPTY:                  return NCA_S_FAULT_PIPE_EMPTY;
00430     case STATUS_FLOAT_DIVIDE_BY_ZERO:       return NCA_S_FAULT_FP_DIV_ZERO;
00431     case STATUS_FLOAT_INVALID_OPERATION:    return NCA_S_FAULT_FP_ERROR;
00432     case STATUS_FLOAT_OVERFLOW:             return NCA_S_FAULT_FP_OVERFLOW;
00433     case STATUS_FLOAT_UNDERFLOW:            return NCA_S_FAULT_FP_UNDERFLOW;
00434     case STATUS_INTEGER_DIVIDE_BY_ZERO:     return NCA_S_FAULT_INT_DIV_BY_ZERO;
00435     case STATUS_INTEGER_OVERFLOW:           return NCA_S_FAULT_INT_OVERFLOW;
00436     default:                                return status;
00437     }
00438 }
00439 
00440 static RPC_STATUS NCA2RPC_STATUS(NCA_STATUS status)
00441 {
00442     switch (status)
00443     {
00444     case NCA_S_COMM_FAILURE:            return RPC_S_COMM_FAILURE;
00445     case NCA_S_OP_RNG_ERROR:            return RPC_S_PROCNUM_OUT_OF_RANGE;
00446     case NCA_S_UNK_IF:                  return RPC_S_UNKNOWN_IF;
00447     case NCA_S_YOU_CRASHED:             return RPC_S_CALL_FAILED;
00448     case NCA_S_PROTO_ERROR:             return RPC_S_PROTOCOL_ERROR;
00449     case NCA_S_OUT_ARGS_TOO_BIG:        return ERROR_NOT_ENOUGH_SERVER_MEMORY;
00450     case NCA_S_SERVER_TOO_BUSY:         return RPC_S_SERVER_TOO_BUSY;
00451     case NCA_S_UNSUPPORTED_TYPE:        return RPC_S_UNSUPPORTED_TYPE;
00452     case NCA_S_FAULT_INT_DIV_BY_ZERO:   return RPC_S_ZERO_DIVIDE;
00453     case NCA_S_FAULT_ADDR_ERROR:        return RPC_S_ADDRESS_ERROR;
00454     case NCA_S_FAULT_FP_DIV_ZERO:       return RPC_S_FP_DIV_ZERO;
00455     case NCA_S_FAULT_FP_UNDERFLOW:      return RPC_S_FP_UNDERFLOW;
00456     case NCA_S_FAULT_FP_OVERFLOW:       return RPC_S_FP_OVERFLOW;
00457     case NCA_S_FAULT_INVALID_TAG:       return RPC_S_INVALID_TAG;
00458     case NCA_S_FAULT_INVALID_BOUND:     return RPC_S_INVALID_BOUND;
00459     case NCA_S_RPC_VERSION_MISMATCH:    return RPC_S_PROTOCOL_ERROR;
00460     case NCA_S_UNSPEC_REJECT:           return RPC_S_CALL_FAILED_DNE;
00461     case NCA_S_BAD_ACTID:               return RPC_S_CALL_FAILED_DNE;
00462     case NCA_S_WHO_ARE_YOU_FAILED:      return RPC_S_CALL_FAILED;
00463     case NCA_S_MANAGER_NOT_ENTERED:     return RPC_S_CALL_FAILED_DNE;
00464     case NCA_S_FAULT_CANCEL:            return RPC_S_CALL_CANCELLED;
00465     case NCA_S_FAULT_ILL_INST:          return RPC_S_ADDRESS_ERROR;
00466     case NCA_S_FAULT_FP_ERROR:          return RPC_S_FP_OVERFLOW;
00467     case NCA_S_FAULT_INT_OVERFLOW:      return RPC_S_ADDRESS_ERROR;
00468     case NCA_S_FAULT_UNSPEC:            return RPC_S_CALL_FAILED;
00469     case NCA_S_FAULT_PIPE_EMPTY:        return RPC_X_PIPE_EMPTY;
00470     case NCA_S_FAULT_PIPE_CLOSED:       return RPC_X_PIPE_CLOSED;
00471     case NCA_S_FAULT_PIPE_ORDER:        return RPC_X_WRONG_PIPE_ORDER;
00472     case NCA_S_FAULT_PIPE_DISCIPLINE:   return RPC_X_PIPE_DISCIPLINE_ERROR;
00473     case NCA_S_FAULT_PIPE_COMM_ERROR:   return RPC_S_COMM_FAILURE;
00474     case NCA_S_FAULT_PIPE_MEMORY:       return ERROR_OUTOFMEMORY;
00475     case NCA_S_FAULT_CONTEXT_MISMATCH:  return ERROR_INVALID_HANDLE;
00476     case NCA_S_FAULT_REMOTE_NO_MEMORY:  return ERROR_NOT_ENOUGH_SERVER_MEMORY;
00477     default:                            return status;
00478     }
00479 }
00480 
00481 /* assumes the common header fields have already been validated */
00482 BOOL RPCRT4_IsValidHttpPacket(RpcPktHdr *hdr, unsigned char *data,
00483                               unsigned short data_len)
00484 {
00485   unsigned short i;
00486   BYTE *p = data;
00487 
00488   for (i = 0; i < hdr->http.num_data_items; i++)
00489   {
00490     ULONG type;
00491 
00492     if (data_len < sizeof(ULONG))
00493       return FALSE;
00494 
00495     type = *(ULONG *)p;
00496     p += sizeof(ULONG);
00497     data_len -= sizeof(ULONG);
00498 
00499     switch (type)
00500     {
00501       case 0x3:
00502       case 0xc:
00503         if (data_len < sizeof(GUID))
00504           return FALSE;
00505         p += sizeof(GUID);
00506         data_len -= sizeof(GUID);
00507         break;
00508       case 0x0:
00509       case 0x2:
00510       case 0x4:
00511       case 0x5:
00512       case 0x6:
00513       case 0xd:
00514         if (data_len < sizeof(ULONG))
00515           return FALSE;
00516         p += sizeof(ULONG);
00517         data_len -= sizeof(ULONG);
00518         break;
00519       case 0x1:
00520         if (data_len < 24)
00521           return FALSE;
00522         p += 24;
00523         data_len -= 24;
00524         break;
00525       default:
00526         FIXME("unimplemented type 0x%x\n", type);
00527         break;
00528     }
00529   }
00530   return TRUE;
00531 }
00532 
00533 /* assumes the HTTP packet has been validated */
00534 static unsigned char *RPCRT4_NextHttpHeaderField(unsigned char *data)
00535 {
00536   ULONG type;
00537 
00538   type = *(ULONG *)data;
00539   data += sizeof(ULONG);
00540 
00541   switch (type)
00542   {
00543     case 0x3:
00544     case 0xc:
00545       return data + sizeof(GUID);
00546     case 0x0:
00547     case 0x2:
00548     case 0x4:
00549     case 0x5:
00550     case 0x6:
00551     case 0xd:
00552       return data + sizeof(ULONG);
00553     case 0x1:
00554       return data + 24;
00555     default:
00556       FIXME("unimplemented type 0x%x\n", type);
00557       return data;
00558   }
00559 }
00560 
00561 #define READ_HTTP_PAYLOAD_FIELD_TYPE(data) *(ULONG *)(data)
00562 #define GET_HTTP_PAYLOAD_FIELD_DATA(data) ((data) + sizeof(ULONG))
00563 
00564 /* assumes the HTTP packet has been validated */
00565 RPC_STATUS RPCRT4_ParseHttpPrepareHeader1(RpcPktHdr *header,
00566                                           unsigned char *data, ULONG *field1)
00567 {
00568   ULONG type;
00569   if (header->http.flags != 0x0)
00570   {
00571     ERR("invalid flags 0x%x\n", header->http.flags);
00572     return RPC_S_PROTOCOL_ERROR;
00573   }
00574   if (header->http.num_data_items != 1)
00575   {
00576     ERR("invalid number of data items %d\n", header->http.num_data_items);
00577     return RPC_S_PROTOCOL_ERROR;
00578   }
00579   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00580   if (type != 0x00000002)
00581   {
00582     ERR("invalid type 0x%08x\n", type);
00583     return RPC_S_PROTOCOL_ERROR;
00584   }
00585   *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
00586   return RPC_S_OK;
00587 }
00588 
00589 /* assumes the HTTP packet has been validated */
00590 RPC_STATUS RPCRT4_ParseHttpPrepareHeader2(RpcPktHdr *header,
00591                                           unsigned char *data, ULONG *field1,
00592                                           ULONG *bytes_until_next_packet,
00593                                           ULONG *field3)
00594 {
00595   ULONG type;
00596   if (header->http.flags != 0x0)
00597   {
00598     ERR("invalid flags 0x%x\n", header->http.flags);
00599     return RPC_S_PROTOCOL_ERROR;
00600   }
00601   if (header->http.num_data_items != 3)
00602   {
00603     ERR("invalid number of data items %d\n", header->http.num_data_items);
00604     return RPC_S_PROTOCOL_ERROR;
00605   }
00606 
00607   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00608   if (type != 0x00000006)
00609   {
00610     ERR("invalid type for field 1: 0x%08x\n", type);
00611     return RPC_S_PROTOCOL_ERROR;
00612   }
00613   *field1 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
00614   data = RPCRT4_NextHttpHeaderField(data);
00615 
00616   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00617   if (type != 0x00000000)
00618   {
00619     ERR("invalid type for field 2: 0x%08x\n", type);
00620     return RPC_S_PROTOCOL_ERROR;
00621   }
00622   *bytes_until_next_packet = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
00623   data = RPCRT4_NextHttpHeaderField(data);
00624 
00625   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00626   if (type != 0x00000002)
00627   {
00628     ERR("invalid type for field 3: 0x%08x\n", type);
00629     return RPC_S_PROTOCOL_ERROR;
00630   }
00631   *field3 = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
00632 
00633   return RPC_S_OK;
00634 }
00635 
00636 RPC_STATUS RPCRT4_ParseHttpFlowControlHeader(RpcPktHdr *header,
00637                                              unsigned char *data, BOOL server,
00638                                              ULONG *bytes_transmitted,
00639                                              ULONG *flow_control_increment,
00640                                              UUID *pipe_uuid)
00641 {
00642   ULONG type;
00643   if (header->http.flags != 0x2)
00644   {
00645     ERR("invalid flags 0x%x\n", header->http.flags);
00646     return RPC_S_PROTOCOL_ERROR;
00647   }
00648   if (header->http.num_data_items != 2)
00649   {
00650     ERR("invalid number of data items %d\n", header->http.num_data_items);
00651     return RPC_S_PROTOCOL_ERROR;
00652   }
00653 
00654   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00655   if (type != 0x0000000d)
00656   {
00657     ERR("invalid type for field 1: 0x%08x\n", type);
00658     return RPC_S_PROTOCOL_ERROR;
00659   }
00660   if (*(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data) != (server ? 0x3 : 0x0))
00661   {
00662     ERR("invalid type for 0xd field data: 0x%08x\n", *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data));
00663     return RPC_S_PROTOCOL_ERROR;
00664   }
00665   data = RPCRT4_NextHttpHeaderField(data);
00666 
00667   type = READ_HTTP_PAYLOAD_FIELD_TYPE(data);
00668   if (type != 0x00000001)
00669   {
00670     ERR("invalid type for field 2: 0x%08x\n", type);
00671     return RPC_S_PROTOCOL_ERROR;
00672   }
00673   *bytes_transmitted = *(ULONG *)GET_HTTP_PAYLOAD_FIELD_DATA(data);
00674   *flow_control_increment = *(ULONG *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 4);
00675   *pipe_uuid = *(UUID *)(GET_HTTP_PAYLOAD_FIELD_DATA(data) + 8);
00676 
00677   return RPC_S_OK;
00678 }
00679 
00680 
00681 RPC_STATUS RPCRT4_default_secure_packet(RpcConnection *Connection,
00682     enum secure_packet_direction dir,
00683     RpcPktHdr *hdr, unsigned int hdr_size,
00684     unsigned char *stub_data, unsigned int stub_data_size,
00685     RpcAuthVerifier *auth_hdr,
00686     unsigned char *auth_value, unsigned int auth_value_size)
00687 {
00688     SecBufferDesc message;
00689     SecBuffer buffers[4];
00690     SECURITY_STATUS sec_status;
00691 
00692     message.ulVersion = SECBUFFER_VERSION;
00693     message.cBuffers = sizeof(buffers)/sizeof(buffers[0]);
00694     message.pBuffers = buffers;
00695 
00696     buffers[0].cbBuffer = hdr_size;
00697     buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
00698     buffers[0].pvBuffer = hdr;
00699     buffers[1].cbBuffer = stub_data_size;
00700     buffers[1].BufferType = SECBUFFER_DATA;
00701     buffers[1].pvBuffer = stub_data;
00702     buffers[2].cbBuffer = sizeof(*auth_hdr);
00703     buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM;
00704     buffers[2].pvBuffer = auth_hdr;
00705     buffers[3].cbBuffer = auth_value_size;
00706     buffers[3].BufferType = SECBUFFER_TOKEN;
00707     buffers[3].pvBuffer = auth_value;
00708 
00709     if (dir == SECURE_PACKET_SEND)
00710     {
00711         if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
00712         {
00713             sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */);
00714             if (sec_status != SEC_E_OK)
00715             {
00716                 ERR("EncryptMessage failed with 0x%08x\n", sec_status);
00717                 return RPC_S_SEC_PKG_ERROR;
00718             }
00719         }
00720         else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
00721         {
00722             sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */);
00723             if (sec_status != SEC_E_OK)
00724             {
00725                 ERR("MakeSignature failed with 0x%08x\n", sec_status);
00726                 return RPC_S_SEC_PKG_ERROR;
00727             }
00728         }
00729     }
00730     else if (dir == SECURE_PACKET_RECEIVE)
00731     {
00732         if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr))
00733         {
00734             sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0);
00735             if (sec_status != SEC_E_OK)
00736             {
00737                 ERR("DecryptMessage failed with 0x%08x\n", sec_status);
00738                 return RPC_S_SEC_PKG_ERROR;
00739             }
00740         }
00741         else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE)
00742         {
00743             sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL);
00744             if (sec_status != SEC_E_OK)
00745             {
00746                 ERR("VerifySignature failed with 0x%08x\n", sec_status);
00747                 return RPC_S_SEC_PKG_ERROR;
00748             }
00749         }
00750     }
00751 
00752     return RPC_S_OK;
00753 }
00754          
00755 /***********************************************************************
00756  *           RPCRT4_SendWithAuth (internal)
00757  * 
00758  * Transmit a packet with authorization data over connection in acceptable fragments.
00759  */
00760 RPC_STATUS RPCRT4_SendWithAuth(RpcConnection *Connection, RpcPktHdr *Header,
00761                                void *Buffer, unsigned int BufferLength,
00762                                const void *Auth, unsigned int AuthLength)
00763 {
00764   PUCHAR buffer_pos;
00765   DWORD hdr_size;
00766   LONG count;
00767   unsigned char *pkt;
00768   LONG alen;
00769   RPC_STATUS status;
00770 
00771   RPCRT4_SetThreadCurrentConnection(Connection);
00772 
00773   buffer_pos = Buffer;
00774   /* The packet building functions save the packet header size, so we can use it. */
00775   hdr_size = Header->common.frag_len;
00776   if (AuthLength)
00777     Header->common.auth_len = AuthLength;
00778   else if (Connection->AuthInfo && packet_has_auth_verifier(Header))
00779   {
00780     if ((Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(Header))
00781       Header->common.auth_len = Connection->encryption_auth_len;
00782     else
00783       Header->common.auth_len = Connection->signature_auth_len;
00784   }
00785   else
00786     Header->common.auth_len = 0;
00787   Header->common.flags |= RPC_FLG_FIRST;
00788   Header->common.flags &= ~RPC_FLG_LAST;
00789 
00790   alen = RPC_AUTH_VERIFIER_LEN(&Header->common);
00791 
00792   while (!(Header->common.flags & RPC_FLG_LAST)) {
00793     unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0;
00794     unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len;
00795 
00796     /* decide if we need to split the packet into fragments */
00797    if (pkt_size <= Connection->MaxTransmissionSize) {
00798      Header->common.flags |= RPC_FLG_LAST;
00799      Header->common.frag_len = pkt_size;
00800     } else {
00801       auth_pad_len = 0;
00802       /* make sure packet payload will be a multiple of 16 */
00803       Header->common.frag_len =
00804         ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) +
00805         hdr_size + alen;
00806     }
00807 
00808     pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len);
00809 
00810     memcpy(pkt, Header, hdr_size);
00811 
00812     /* fragment consisted of header only and is the last one */
00813     if (hdr_size == Header->common.frag_len)
00814       goto write;
00815 
00816     memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen);
00817 
00818     /* add the authorization info */
00819     if (Header->common.auth_len)
00820     {
00821       RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen];
00822 
00823       auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc;
00824       auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel;
00825       auth_hdr->auth_pad_length = auth_pad_len;
00826       auth_hdr->auth_reserved = 0;
00827       /* a unique number... */
00828       auth_hdr->auth_context_id = Connection->auth_context_id;
00829 
00830       if (AuthLength)
00831         memcpy(auth_hdr + 1, Auth, AuthLength);
00832       else
00833       {
00834         status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_SEND,
00835             (RpcPktHdr *)pkt, hdr_size,
00836             pkt + hdr_size, Header->common.frag_len - hdr_size - alen,
00837             auth_hdr,
00838             (unsigned char *)(auth_hdr + 1), Header->common.auth_len);
00839         if (status != RPC_S_OK)
00840         {
00841           HeapFree(GetProcessHeap(), 0, pkt);
00842           RPCRT4_SetThreadCurrentConnection(NULL);
00843           return status;
00844         }
00845       }
00846     }
00847 
00848 write:
00849     count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len);
00850     HeapFree(GetProcessHeap(), 0, pkt);
00851     if (count<0) {
00852       WARN("rpcrt4_conn_write failed (auth)\n");
00853       RPCRT4_SetThreadCurrentConnection(NULL);
00854       return RPC_S_CALL_FAILED;
00855     }
00856 
00857     buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len;
00858     BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len;
00859     Header->common.flags &= ~RPC_FLG_FIRST;
00860   }
00861 
00862   RPCRT4_SetThreadCurrentConnection(NULL);
00863   return RPC_S_OK;
00864 }
00865 
00866 /***********************************************************************
00867  *           RPCRT4_default_authorize (internal)
00868  *
00869  * Authorize a client connection.
00870  */
00871 RPC_STATUS RPCRT4_default_authorize(RpcConnection *conn, BOOL first_time,
00872                                     unsigned char *in_buffer,
00873                                     unsigned int in_size,
00874                                     unsigned char *out_buffer,
00875                                     unsigned int *out_size)
00876 {
00877   SECURITY_STATUS r;
00878   SecBufferDesc out_desc;
00879   SecBufferDesc inp_desc;
00880   SecPkgContext_Sizes secctx_sizes;
00881   BOOL continue_needed;
00882   ULONG context_req;
00883   SecBuffer in, out;
00884 
00885   if (!out_buffer)
00886   {
00887     *out_size = conn->AuthInfo->cbMaxToken;
00888     return RPC_S_OK;
00889   }
00890 
00891   in.BufferType = SECBUFFER_TOKEN;
00892   in.pvBuffer = in_buffer;
00893   in.cbBuffer = in_size;
00894 
00895   out.BufferType = SECBUFFER_TOKEN;
00896   out.pvBuffer = out_buffer;
00897   out.cbBuffer = *out_size;
00898 
00899   out_desc.ulVersion = 0;
00900   out_desc.cBuffers = 1;
00901   out_desc.pBuffers = &out;
00902 
00903   inp_desc.ulVersion = 0;
00904   inp_desc.cBuffers = 1;
00905   inp_desc.pBuffers = &in;
00906 
00907   if (conn->server)
00908   {
00909       context_req = ASC_REQ_CONNECTION | ASC_REQ_USE_DCE_STYLE |
00910                     ASC_REQ_DELEGATE;
00911 
00912       if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
00913           context_req |= ASC_REQ_INTEGRITY;
00914       else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
00915           context_req |= ASC_REQ_CONFIDENTIALITY | ASC_REQ_INTEGRITY;
00916 
00917       r = AcceptSecurityContext(&conn->AuthInfo->cred,
00918                                 first_time ? NULL : &conn->ctx,
00919                                 &inp_desc, context_req, SECURITY_NETWORK_DREP,
00920                                 &conn->ctx,
00921                                 &out_desc, &conn->attr, &conn->exp);
00922       if (r == SEC_E_OK || r == SEC_I_COMPLETE_NEEDED)
00923       {
00924           /* authorisation done, so nothing more to send */
00925           out.cbBuffer = 0;
00926       }
00927   }
00928   else
00929   {
00930       context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
00931                     ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
00932 
00933       if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY)
00934           context_req |= ISC_REQ_INTEGRITY;
00935       else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
00936           context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY;
00937 
00938       r = InitializeSecurityContextW(&conn->AuthInfo->cred,
00939                                      first_time ? NULL: &conn->ctx,
00940                                      first_time ? conn->AuthInfo->server_principal_name : NULL,
00941                                      context_req, 0, SECURITY_NETWORK_DREP,
00942                                      first_time ? NULL : &inp_desc, 0, &conn->ctx,
00943                                      &out_desc, &conn->attr, &conn->exp);
00944   }
00945   if (FAILED(r))
00946   {
00947       WARN("InitializeSecurityContext failed with error 0x%08x\n", r);
00948       goto failed;
00949   }
00950 
00951   TRACE("r = 0x%08x, attr = 0x%08x\n", r, conn->attr);
00952   continue_needed = ((r == SEC_I_CONTINUE_NEEDED) ||
00953                      (r == SEC_I_COMPLETE_AND_CONTINUE));
00954 
00955   if ((r == SEC_I_COMPLETE_NEEDED) || (r == SEC_I_COMPLETE_AND_CONTINUE))
00956   {
00957       TRACE("complete needed\n");
00958       r = CompleteAuthToken(&conn->ctx, &out_desc);
00959       if (FAILED(r))
00960       {
00961           WARN("CompleteAuthToken failed with error 0x%08x\n", r);
00962           goto failed;
00963       }
00964   }
00965 
00966   TRACE("cbBuffer = %d\n", out.cbBuffer);
00967 
00968   if (!continue_needed)
00969   {
00970       r = QueryContextAttributesA(&conn->ctx, SECPKG_ATTR_SIZES, &secctx_sizes);
00971       if (FAILED(r))
00972       {
00973           WARN("QueryContextAttributes failed with error 0x%08x\n", r);
00974           goto failed;
00975       }
00976       conn->signature_auth_len = secctx_sizes.cbMaxSignature;
00977       conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer;
00978   }
00979 
00980   *out_size = out.cbBuffer;
00981   return RPC_S_OK;
00982 
00983 failed:
00984   *out_size = 0;
00985   return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */
00986 }
00987 
00988 /***********************************************************************
00989  *           RPCRT4_ClientConnectionAuth (internal)
00990  */
00991 RPC_STATUS RPCRT4_ClientConnectionAuth(RpcConnection* conn, BYTE *challenge,
00992                                        ULONG count)
00993 {
00994   RpcPktHdr *resp_hdr;
00995   RPC_STATUS status;
00996   unsigned char *out_buffer;
00997   unsigned int out_len = 0;
00998 
00999   TRACE("challenge %s, %d bytes\n", challenge, count);
01000 
01001   status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, NULL, &out_len);
01002   if (status) return status;
01003   out_buffer = HeapAlloc(GetProcessHeap(), 0, out_len);
01004   if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
01005   status = rpcrt4_conn_authorize(conn, FALSE, challenge, count, out_buffer, &out_len);
01006   if (status) return status;
01007 
01008   resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION);
01009 
01010   if (resp_hdr)
01011     status = RPCRT4_SendWithAuth(conn, resp_hdr, NULL, 0, out_buffer, out_len);
01012   else
01013     status = RPC_S_OUT_OF_RESOURCES;
01014 
01015   HeapFree(GetProcessHeap(), 0, out_buffer);
01016   RPCRT4_FreeHeader(resp_hdr);
01017 
01018   return status;
01019 }
01020 
01021 /***********************************************************************
01022  *           RPCRT4_ServerConnectionAuth (internal)
01023  */
01024 RPC_STATUS RPCRT4_ServerConnectionAuth(RpcConnection* conn,
01025                                        BOOL start,
01026                                        RpcAuthVerifier *auth_data_in,
01027                                        ULONG auth_length_in,
01028                                        unsigned char **auth_data_out,
01029                                        ULONG *auth_length_out)
01030 {
01031     unsigned char *out_buffer;
01032     unsigned int out_size;
01033     RPC_STATUS status;
01034 
01035     if (start)
01036     {
01037         /* remove any existing authentication information */
01038         if (conn->AuthInfo)
01039         {
01040             RpcAuthInfo_Release(conn->AuthInfo);
01041             conn->AuthInfo = NULL;
01042         }
01043         if (SecIsValidHandle(&conn->ctx))
01044         {
01045             DeleteSecurityContext(&conn->ctx);
01046             SecInvalidateHandle(&conn->ctx);
01047         }
01048         if (auth_length_in >= sizeof(RpcAuthVerifier))
01049         {
01050             CredHandle cred;
01051             TimeStamp exp;
01052             ULONG max_token;
01053 
01054             status = RPCRT4_ServerGetRegisteredAuthInfo(
01055                 auth_data_in->auth_type, &cred, &exp, &max_token);
01056             if (status != RPC_S_OK)
01057             {
01058                 ERR("unknown authentication service %u\n", auth_data_in->auth_type);
01059                 return status;
01060             }
01061 
01062             status = RpcAuthInfo_Create(auth_data_in->auth_level,
01063                                         auth_data_in->auth_type, cred, exp,
01064                                         max_token, NULL, &conn->AuthInfo);
01065             if (status != RPC_S_OK)
01066                 return status;
01067 
01068             /* FIXME: should auth_data_in->auth_context_id be checked in the !start case? */
01069             conn->auth_context_id = auth_data_in->auth_context_id;
01070         }
01071     }
01072 
01073     if (auth_length_in < sizeof(RpcAuthVerifier))
01074         return RPC_S_OK;
01075 
01076     if (!conn->AuthInfo)
01077         /* should have filled in authentication info by now */
01078         return RPC_S_PROTOCOL_ERROR;
01079 
01080     status = rpcrt4_conn_authorize(
01081         conn, start, (unsigned char *)(auth_data_in + 1),
01082         auth_length_in - sizeof(RpcAuthVerifier), NULL, &out_size);
01083     if (status) return status;
01084 
01085     out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
01086     if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
01087 
01088     status = rpcrt4_conn_authorize(
01089         conn, start, (unsigned char *)(auth_data_in + 1),
01090         auth_length_in - sizeof(RpcAuthVerifier), out_buffer, &out_size);
01091     if (status != RPC_S_OK)
01092     {
01093         HeapFree(GetProcessHeap(), 0, out_buffer);
01094         return status;
01095     }
01096 
01097     if (out_size && !auth_length_out)
01098     {
01099         ERR("expected authentication to be complete but SSP returned data of "
01100             "%u bytes to be sent back to client\n", out_size);
01101         HeapFree(GetProcessHeap(), 0, out_buffer);
01102         return RPC_S_SEC_PKG_ERROR;
01103     }
01104     else
01105     {
01106         *auth_data_out = out_buffer;
01107         *auth_length_out = out_size;
01108     }
01109 
01110     return status;
01111 }
01112 
01113 /***********************************************************************
01114  *           RPCRT4_default_is_authorized (internal)
01115  *
01116  * Has a connection started the process of authorizing with the server?
01117  */
01118 BOOL RPCRT4_default_is_authorized(RpcConnection *Connection)
01119 {
01120     return Connection->AuthInfo && SecIsValidHandle(&Connection->ctx);
01121 }
01122 
01123 /***********************************************************************
01124  *           RPCRT4_default_impersonate_client (internal)
01125  *
01126  */
01127 RPC_STATUS RPCRT4_default_impersonate_client(RpcConnection *conn)
01128 {
01129     SECURITY_STATUS sec_status;
01130 
01131     TRACE("(%p)\n", conn);
01132 
01133     if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx))
01134         return RPC_S_NO_CONTEXT_AVAILABLE;
01135     sec_status = ImpersonateSecurityContext(&conn->ctx);
01136     if (sec_status != SEC_E_OK)
01137         WARN("ImpersonateSecurityContext returned 0x%08x\n", sec_status);
01138     switch (sec_status)
01139     {
01140     case SEC_E_UNSUPPORTED_FUNCTION:
01141         return RPC_S_CANNOT_SUPPORT;
01142     case SEC_E_NO_IMPERSONATION:
01143         return RPC_S_NO_CONTEXT_AVAILABLE;
01144     case SEC_E_OK:
01145         return RPC_S_OK;
01146     default:
01147         return RPC_S_SEC_PKG_ERROR;
01148     }
01149 }
01150 
01151 /***********************************************************************
01152  *           RPCRT4_default_revert_to_self (internal)
01153  *
01154  */
01155 RPC_STATUS RPCRT4_default_revert_to_self(RpcConnection *conn)
01156 {
01157     SECURITY_STATUS sec_status;
01158 
01159     TRACE("(%p)\n", conn);
01160 
01161     if (!conn->AuthInfo || !SecIsValidHandle(&conn->ctx))
01162         return RPC_S_NO_CONTEXT_AVAILABLE;
01163     sec_status = RevertSecurityContext(&conn->ctx);
01164     if (sec_status != SEC_E_OK)
01165         WARN("RevertSecurityContext returned 0x%08x\n", sec_status);
01166     switch (sec_status)
01167     {
01168     case SEC_E_UNSUPPORTED_FUNCTION:
01169         return RPC_S_CANNOT_SUPPORT;
01170     case SEC_E_NO_IMPERSONATION:
01171         return RPC_S_NO_CONTEXT_AVAILABLE;
01172     case SEC_E_OK:
01173         return RPC_S_OK;
01174     default:
01175         return RPC_S_SEC_PKG_ERROR;
01176     }
01177 }
01178 
01179 /***********************************************************************
01180  *           RPCRT4_default_inquire_auth_client (internal)
01181  *
01182  * Default function to retrieve the authentication details that the client
01183  * is using to call the server.
01184  */
01185 RPC_STATUS RPCRT4_default_inquire_auth_client(
01186     RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
01187     ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
01188 {
01189     if (!conn->AuthInfo) return RPC_S_BINDING_HAS_NO_AUTH;
01190 
01191     if (privs)
01192     {
01193         FIXME("privs not implemented\n");
01194         *privs = NULL;
01195     }
01196     if (server_princ_name)
01197     {
01198         *server_princ_name = RPCRT4_strdupW(conn->AuthInfo->server_principal_name);
01199         if (!*server_princ_name) return ERROR_OUTOFMEMORY;
01200     }
01201     if (authn_level) *authn_level = conn->AuthInfo->AuthnLevel;
01202     if (authn_svc) *authn_svc = conn->AuthInfo->AuthnSvc;
01203     if (authz_svc)
01204     {
01205         FIXME("authorization service not implemented\n");
01206         *authz_svc = RPC_C_AUTHZ_NONE;
01207     }
01208     if (flags)
01209         FIXME("flags 0x%x not implemented\n", flags);
01210 
01211     return RPC_S_OK;
01212 }
01213 
01214 /***********************************************************************
01215  *           RPCRT4_Send (internal)
01216  * 
01217  * Transmit a packet over connection in acceptable fragments.
01218  */
01219 RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header,
01220                        void *Buffer, unsigned int BufferLength)
01221 {
01222   RPC_STATUS r;
01223 
01224   if (packet_does_auth_negotiation(Header) &&
01225       Connection->AuthInfo &&
01226       !rpcrt4_conn_is_authorized(Connection))
01227   {
01228       unsigned int out_size = 0;
01229       unsigned char *out_buffer;
01230 
01231       r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, NULL, &out_size);
01232       if (r != RPC_S_OK) return r;
01233 
01234       out_buffer = HeapAlloc(GetProcessHeap(), 0, out_size);
01235       if (!out_buffer) return RPC_S_OUT_OF_RESOURCES;
01236 
01237       /* tack on a negotiate packet */
01238       r = rpcrt4_conn_authorize(Connection, TRUE, NULL, 0, out_buffer, &out_size);
01239       if (r == RPC_S_OK)
01240           r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, out_buffer, out_size);
01241 
01242       HeapFree(GetProcessHeap(), 0, out_buffer);
01243   }
01244   else
01245     r = RPCRT4_SendWithAuth(Connection, Header, Buffer, BufferLength, NULL, 0);
01246 
01247   return r;
01248 }
01249 
01250 /* validates version and frag_len fields */
01251 RPC_STATUS RPCRT4_ValidateCommonHeader(const RpcPktCommonHdr *hdr)
01252 {
01253   DWORD hdr_length;
01254 
01255   /* verify if the header really makes sense */
01256   if (hdr->rpc_ver != RPC_VER_MAJOR ||
01257       hdr->rpc_ver_minor != RPC_VER_MINOR)
01258   {
01259     WARN("unhandled packet version\n");
01260     return RPC_S_PROTOCOL_ERROR;
01261   }
01262 
01263   hdr_length = RPCRT4_GetHeaderSize((const RpcPktHdr*)hdr);
01264   if (hdr_length == 0)
01265   {
01266     WARN("header length == 0\n");
01267     return RPC_S_PROTOCOL_ERROR;
01268   }
01269 
01270   if (hdr->frag_len < hdr_length)
01271   {
01272     WARN("bad frag length %d\n", hdr->frag_len);
01273     return RPC_S_PROTOCOL_ERROR;
01274   }
01275 
01276   return RPC_S_OK;
01277 }
01278 
01279 /***********************************************************************
01280  *           RPCRT4_default_receive_fragment (internal)
01281  * 
01282  * Receive a fragment from a connection.
01283  */
01284 static RPC_STATUS RPCRT4_default_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
01285 {
01286   RPC_STATUS status;
01287   DWORD hdr_length;
01288   LONG dwRead;
01289   RpcPktCommonHdr common_hdr;
01290 
01291   *Header = NULL;
01292   *Payload = NULL;
01293 
01294   TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
01295 
01296   /* read packet common header */
01297   dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr));
01298   if (dwRead != sizeof(common_hdr)) {
01299     WARN("Short read of header, %d bytes\n", dwRead);
01300     status = RPC_S_CALL_FAILED;
01301     goto fail;
01302   }
01303 
01304   status = RPCRT4_ValidateCommonHeader(&common_hdr);
01305   if (status != RPC_S_OK) goto fail;
01306 
01307   hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
01308   if (hdr_length == 0) {
01309     WARN("header length == 0\n");
01310     status = RPC_S_PROTOCOL_ERROR;
01311     goto fail;
01312   }
01313 
01314   *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
01315   memcpy(*Header, &common_hdr, sizeof(common_hdr));
01316 
01317   /* read the rest of packet header */
01318   dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
01319   if (dwRead != hdr_length - sizeof(common_hdr)) {
01320     WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
01321     status = RPC_S_CALL_FAILED;
01322     goto fail;
01323   }
01324 
01325   if (common_hdr.frag_len - hdr_length)
01326   {
01327     *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
01328     if (!*Payload)
01329     {
01330       status = RPC_S_OUT_OF_RESOURCES;
01331       goto fail;
01332     }
01333 
01334     dwRead = rpcrt4_conn_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
01335     if (dwRead != common_hdr.frag_len - hdr_length)
01336     {
01337       WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
01338       status = RPC_S_CALL_FAILED;
01339       goto fail;
01340     }
01341   }
01342   else
01343     *Payload = NULL;
01344 
01345   /* success */
01346   status = RPC_S_OK;
01347 
01348 fail:
01349   if (status != RPC_S_OK) {
01350     RPCRT4_FreeHeader(*Header);
01351     *Header = NULL;
01352     HeapFree(GetProcessHeap(), 0, *Payload);
01353     *Payload = NULL;
01354   }
01355   return status;
01356 }
01357 
01358 static RPC_STATUS RPCRT4_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
01359 {
01360     if (Connection->ops->receive_fragment)
01361         return Connection->ops->receive_fragment(Connection, Header, Payload);
01362     else
01363         return RPCRT4_default_receive_fragment(Connection, Header, Payload);
01364 }
01365 
01366 /***********************************************************************
01367  *           RPCRT4_ReceiveWithAuth (internal)
01368  *
01369  * Receive a packet from connection, merge the fragments and return the auth
01370  * data.
01371  */
01372 RPC_STATUS RPCRT4_ReceiveWithAuth(RpcConnection *Connection, RpcPktHdr **Header,
01373                                   PRPC_MESSAGE pMsg,
01374                                   unsigned char **auth_data_out,
01375                                   ULONG *auth_length_out)
01376 {
01377   RPC_STATUS status;
01378   DWORD hdr_length;
01379   unsigned short first_flag;
01380   ULONG data_length;
01381   ULONG buffer_length;
01382   ULONG auth_length = 0;
01383   unsigned char *auth_data = NULL;
01384   RpcPktHdr *CurrentHeader = NULL;
01385   void *payload = NULL;
01386 
01387   *Header = NULL;
01388   pMsg->Buffer = NULL;
01389   if (auth_data_out) *auth_data_out = NULL;
01390   if (auth_length_out) *auth_length_out = 0;
01391 
01392   TRACE("(%p, %p, %p, %p)\n", Connection, Header, pMsg, auth_data_out);
01393 
01394   RPCRT4_SetThreadCurrentConnection(Connection);
01395 
01396   status = RPCRT4_receive_fragment(Connection, Header, &payload);
01397   if (status != RPC_S_OK) goto fail;
01398 
01399   hdr_length = RPCRT4_GetHeaderSize(*Header);
01400 
01401   /* read packet body */
01402   switch ((*Header)->common.ptype) {
01403   case PKT_RESPONSE:
01404     pMsg->BufferLength = (*Header)->response.alloc_hint;
01405     break;
01406   case PKT_REQUEST:
01407     pMsg->BufferLength = (*Header)->request.alloc_hint;
01408     break;
01409   default:
01410     pMsg->BufferLength = (*Header)->common.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&(*Header)->common);
01411   }
01412 
01413   TRACE("buffer length = %u\n", pMsg->BufferLength);
01414 
01415   pMsg->Buffer = I_RpcAllocate(pMsg->BufferLength);
01416   if (!pMsg->Buffer)
01417   {
01418     status = ERROR_OUTOFMEMORY;
01419     goto fail;
01420   }
01421 
01422   first_flag = RPC_FLG_FIRST;
01423   auth_length = (*Header)->common.auth_len;
01424   if (auth_length) {
01425     auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&(*Header)->common));
01426     if (!auth_data) {
01427       status = RPC_S_OUT_OF_RESOURCES;
01428       goto fail;
01429     }
01430   }
01431   CurrentHeader = *Header;
01432   buffer_length = 0;
01433   while (TRUE)
01434   {
01435     unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&CurrentHeader->common);
01436 
01437     /* verify header fields */
01438 
01439     if ((CurrentHeader->common.frag_len < hdr_length) ||
01440         (CurrentHeader->common.frag_len - hdr_length < header_auth_len)) {
01441       WARN("frag_len %d too small for hdr_length %d and auth_len %d\n",
01442         CurrentHeader->common.frag_len, hdr_length, CurrentHeader->common.auth_len);
01443       status = RPC_S_PROTOCOL_ERROR;
01444       goto fail;
01445     }
01446 
01447     if (CurrentHeader->common.auth_len != auth_length) {
01448       WARN("auth_len header field changed from %d to %d\n",
01449         auth_length, CurrentHeader->common.auth_len);
01450       status = RPC_S_PROTOCOL_ERROR;
01451       goto fail;
01452     }
01453 
01454     if ((CurrentHeader->common.flags & RPC_FLG_FIRST) != first_flag) {
01455       TRACE("invalid packet flags\n");
01456       status = RPC_S_PROTOCOL_ERROR;
01457       goto fail;
01458     }
01459 
01460     data_length = CurrentHeader->common.frag_len - hdr_length - header_auth_len;
01461     if (data_length + buffer_length > pMsg->BufferLength) {
01462       TRACE("allocation hint exceeded, new buffer length = %d\n",
01463         data_length + buffer_length);
01464       pMsg->BufferLength = data_length + buffer_length;
01465       status = I_RpcReAllocateBuffer(pMsg);
01466       if (status != RPC_S_OK) goto fail;
01467     }
01468 
01469     memcpy((unsigned char *)pMsg->Buffer + buffer_length, payload, data_length);
01470 
01471     if (header_auth_len) {
01472       if (header_auth_len < sizeof(RpcAuthVerifier) ||
01473           header_auth_len > RPC_AUTH_VERIFIER_LEN(&(*Header)->common)) {
01474         WARN("bad auth verifier length %d\n", header_auth_len);
01475         status = RPC_S_PROTOCOL_ERROR;
01476         goto fail;
01477       }
01478 
01479       /* FIXME: we should accumulate authentication data for the bind,
01480        * bind_ack, alter_context and alter_context_response if necessary.
01481        * however, the details of how this is done is very sketchy in the
01482        * DCE/RPC spec. for all other packet types that have authentication
01483        * verifier data then it is just duplicated in all the fragments */
01484       memcpy(auth_data, (unsigned char *)payload + data_length, header_auth_len);
01485 
01486       /* these packets are handled specially, not by the generic SecurePacket
01487        * function */
01488       if (!packet_does_auth_negotiation(*Header) && rpcrt4_conn_is_authorized(Connection))
01489       {
01490         status = rpcrt4_conn_secure_packet(Connection, SECURE_PACKET_RECEIVE,
01491             CurrentHeader, hdr_length,
01492             (unsigned char *)pMsg->Buffer + buffer_length, data_length,
01493             (RpcAuthVerifier *)auth_data,
01494             auth_data + sizeof(RpcAuthVerifier),
01495             header_auth_len - sizeof(RpcAuthVerifier));
01496         if (status != RPC_S_OK) goto fail;
01497       }
01498     }
01499 
01500     buffer_length += data_length;
01501     if (!(CurrentHeader->common.flags & RPC_FLG_LAST)) {
01502       TRACE("next header\n");
01503 
01504       if (*Header != CurrentHeader)
01505       {
01506           RPCRT4_FreeHeader(CurrentHeader);
01507           CurrentHeader = NULL;
01508       }
01509       HeapFree(GetProcessHeap(), 0, payload);
01510       payload = NULL;
01511 
01512       status = RPCRT4_receive_fragment(Connection, &CurrentHeader, &payload);
01513       if (status != RPC_S_OK) goto fail;
01514 
01515       first_flag = 0;
01516     } else {
01517       break;
01518     }
01519   }
01520   pMsg->BufferLength = buffer_length;
01521 
01522   /* success */
01523   status = RPC_S_OK;
01524 
01525 fail:
01526   RPCRT4_SetThreadCurrentConnection(NULL);
01527   if (CurrentHeader != *Header)
01528     RPCRT4_FreeHeader(CurrentHeader);
01529   if (status != RPC_S_OK) {
01530     I_RpcFree(pMsg->Buffer);
01531     pMsg->Buffer = NULL;
01532     RPCRT4_FreeHeader(*Header);
01533     *Header = NULL;
01534   }
01535   if (auth_data_out && status == RPC_S_OK) {
01536     *auth_length_out = auth_length;
01537     *auth_data_out = auth_data;
01538   }
01539   else
01540     HeapFree(GetProcessHeap(), 0, auth_data);
01541   HeapFree(GetProcessHeap(), 0, payload);
01542   return status;
01543 }
01544 
01545 /***********************************************************************
01546  *           RPCRT4_Receive (internal)
01547  *
01548  * Receive a packet from connection and merge the fragments.
01549  */
01550 static RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header,
01551                                  PRPC_MESSAGE pMsg)
01552 {
01553     return RPCRT4_ReceiveWithAuth(Connection, Header, pMsg, NULL, NULL);
01554 }
01555 
01556 /***********************************************************************
01557  *           I_RpcNegotiateTransferSyntax [RPCRT4.@]
01558  *
01559  * Negotiates the transfer syntax used by a client connection by connecting
01560  * to the server.
01561  *
01562  * PARAMS
01563  *  pMsg   [I] RPC Message structure.
01564  *  pAsync [I] Asynchronous state to set.
01565  *
01566  * RETURNS
01567  *  Success: RPC_S_OK.
01568  *  Failure: Any error code.
01569  */
01570 RPC_STATUS WINAPI I_RpcNegotiateTransferSyntax(PRPC_MESSAGE pMsg)
01571 {
01572   RpcBinding* bind = pMsg->Handle;
01573   RpcConnection* conn;
01574   RPC_STATUS status = RPC_S_OK;
01575 
01576   TRACE("(%p)\n", pMsg);
01577 
01578   if (!bind || bind->server)
01579   {
01580     ERR("no binding\n");
01581     return RPC_S_INVALID_BINDING;
01582   }
01583 
01584   /* if we already have a connection, we don't need to negotiate again */
01585   if (!pMsg->ReservedForRuntime)
01586   {
01587     RPC_CLIENT_INTERFACE *cif = pMsg->RpcInterfaceInformation;
01588     if (!cif) return RPC_S_INTERFACE_NOT_FOUND;
01589 
01590     if (!bind->Endpoint || !bind->Endpoint[0])
01591     {
01592       TRACE("automatically resolving partially bound binding\n");
01593       status = RpcEpResolveBinding(bind, cif);
01594       if (status != RPC_S_OK) return status;
01595     }
01596 
01597     status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax,
01598                                 &cif->InterfaceId);
01599 
01600     if (status == RPC_S_OK)
01601     {
01602       pMsg->ReservedForRuntime = conn;
01603       RPCRT4_AddRefBinding(bind);
01604     }
01605   }
01606 
01607   return status;
01608 }
01609 
01610 /***********************************************************************
01611  *           I_RpcGetBuffer [RPCRT4.@]
01612  *
01613  * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the
01614  * server interface.
01615  *
01616  * PARAMS
01617  *  pMsg [I/O] RPC message information.
01618  *
01619  * RETURNS
01620  *  Success: RPC_S_OK.
01621  *  Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid.
01622  *           RPC_S_SERVER_UNAVAILABLE if unable to connect to server.
01623  *           ERROR_OUTOFMEMORY if buffer allocation failed.
01624  *
01625  * NOTES
01626  *  The pMsg->BufferLength field determines the size of the buffer to allocate,
01627  *  in bytes.
01628  *
01629  *  Use I_RpcFreeBuffer() to unbind from the server and free the message buffer.
01630  *
01631  * SEE ALSO
01632  *  I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive().
01633  */
01634 RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg)
01635 {
01636   RPC_STATUS status;
01637   RpcBinding* bind = pMsg->Handle;
01638 
01639   TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
01640 
01641   if (!bind)
01642   {
01643     ERR("no binding\n");
01644     return RPC_S_INVALID_BINDING;
01645   }
01646 
01647   pMsg->Buffer = I_RpcAllocate(pMsg->BufferLength);
01648   TRACE("Buffer=%p\n", pMsg->Buffer);
01649 
01650   if (!pMsg->Buffer)
01651     return ERROR_OUTOFMEMORY;
01652 
01653   if (!bind->server)
01654   {
01655     status = I_RpcNegotiateTransferSyntax(pMsg);
01656     if (status != RPC_S_OK)
01657       I_RpcFree(pMsg->Buffer);
01658   }
01659   else
01660     status = RPC_S_OK;
01661 
01662   return status;
01663 }
01664 
01665 /***********************************************************************
01666  *           I_RpcReAllocateBuffer (internal)
01667  */
01668 static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg)
01669 {
01670   TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength);
01671   pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength);
01672 
01673   TRACE("Buffer=%p\n", pMsg->Buffer);
01674   return pMsg->Buffer ? RPC_S_OK : ERROR_OUTOFMEMORY;
01675 }
01676 
01677 /***********************************************************************
01678  *           I_RpcFreeBuffer [RPCRT4.@]
01679  *
01680  * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from
01681  * the server interface.
01682  *
01683  * PARAMS
01684  *  pMsg [I/O] RPC message information.
01685  *
01686  * RETURNS
01687  *  RPC_S_OK.
01688  *
01689  * SEE ALSO
01690  *  I_RpcGetBuffer(), I_RpcReceive().
01691  */
01692 RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg)
01693 {
01694   RpcBinding* bind = pMsg->Handle;
01695 
01696   TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer);
01697 
01698   if (!bind)
01699   {
01700     ERR("no binding\n");
01701     return RPC_S_INVALID_BINDING;
01702   }
01703 
01704   if (pMsg->ReservedForRuntime)
01705   {
01706     RpcConnection *conn = pMsg->ReservedForRuntime;
01707     RPCRT4_CloseBinding(bind, conn);
01708     RPCRT4_ReleaseBinding(bind);
01709     pMsg->ReservedForRuntime = NULL;
01710   }
01711   I_RpcFree(pMsg->Buffer);
01712   return RPC_S_OK;
01713 }
01714 
01715 static void CALLBACK async_apc_notifier_proc(ULONG_PTR ulParam)
01716 {
01717     RPC_ASYNC_STATE *state = (RPC_ASYNC_STATE *)ulParam;
01718     state->u.APC.NotificationRoutine(state, NULL, state->Event);
01719 }
01720 
01721 static DWORD WINAPI async_notifier_proc(LPVOID p)
01722 {
01723     RpcConnection *conn = p;
01724     RPC_ASYNC_STATE *state = conn->async_state;
01725 
01726     if (state && conn->ops->wait_for_incoming_data(conn) != -1)
01727     {
01728         state->Event = RpcCallComplete;
01729         switch (state->NotificationType)
01730         {
01731         case RpcNotificationTypeEvent:
01732             TRACE("RpcNotificationTypeEvent %p\n", state->u.hEvent);
01733             SetEvent(state->u.hEvent);
01734             break;
01735         case RpcNotificationTypeApc:
01736             TRACE("RpcNotificationTypeApc %p\n", state->u.APC.hThread);
01737             QueueUserAPC(async_apc_notifier_proc, state->u.APC.hThread, (ULONG_PTR)state);
01738             break;
01739         case RpcNotificationTypeIoc:
01740             TRACE("RpcNotificationTypeIoc %p, 0x%x, 0x%lx, %p\n",
01741                 state->u.IOC.hIOPort, state->u.IOC.dwNumberOfBytesTransferred,
01742                 state->u.IOC.dwCompletionKey, state->u.IOC.lpOverlapped);
01743             PostQueuedCompletionStatus(state->u.IOC.hIOPort,
01744                 state->u.IOC.dwNumberOfBytesTransferred,
01745                 state->u.IOC.dwCompletionKey,
01746                 state->u.IOC.lpOverlapped);
01747             break;
01748         case RpcNotificationTypeHwnd:
01749             TRACE("RpcNotificationTypeHwnd %p 0x%x\n", state->u.HWND.hWnd,
01750                 state->u.HWND.Msg);
01751             PostMessageW(state->u.HWND.hWnd, state->u.HWND.Msg, 0, 0);
01752             break;
01753         case RpcNotificationTypeCallback:
01754             TRACE("RpcNotificationTypeCallback %p\n", state->u.NotificationRoutine);
01755             state->u.NotificationRoutine(state, NULL, state->Event);
01756             break;
01757         case RpcNotificationTypeNone:
01758             TRACE("RpcNotificationTypeNone\n");
01759             break;
01760         default:
01761             FIXME("unknown NotificationType: %d/0x%x\n", state->NotificationType, state->NotificationType);
01762             break;
01763         }
01764     }
01765 
01766     return 0;
01767 }
01768 
01769 /***********************************************************************
01770  *           I_RpcSend [RPCRT4.@]
01771  *
01772  * Sends a message to the server.
01773  *
01774  * PARAMS
01775  *  pMsg [I/O] RPC message information.
01776  *
01777  * RETURNS
01778  *  Unknown.
01779  *
01780  * NOTES
01781  *  The buffer must have been allocated with I_RpcGetBuffer().
01782  *
01783  * SEE ALSO
01784  *  I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive().
01785  */
01786 RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg)
01787 {
01788   RpcBinding* bind = pMsg->Handle;
01789   RpcConnection* conn;
01790   RPC_STATUS status;
01791   RpcPktHdr *hdr;
01792 
01793   TRACE("(%p)\n", pMsg);
01794   if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
01795 
01796   conn = pMsg->ReservedForRuntime;
01797 
01798   hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation,
01799                                   pMsg->BufferLength,
01800                                   pMsg->ProcNum & ~RPC_FLAGS_VALID_BIT,
01801                                   &bind->ObjectUuid);
01802   if (!hdr)
01803     return ERROR_OUTOFMEMORY;
01804   hdr->common.call_id = conn->NextCallId++;
01805 
01806   status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength);
01807 
01808   RPCRT4_FreeHeader(hdr);
01809 
01810   if (status == RPC_S_OK && pMsg->RpcFlags & RPC_BUFFER_ASYNC)
01811   {
01812     if (!QueueUserWorkItem(async_notifier_proc, conn, WT_EXECUTEDEFAULT | WT_EXECUTELONGFUNCTION))
01813         status = RPC_S_OUT_OF_RESOURCES;
01814   }
01815 
01816   return status;
01817 }
01818 
01819 /* is this status something that the server can't recover from? */
01820 static inline BOOL is_hard_error(RPC_STATUS status)
01821 {
01822     switch (status)
01823     {
01824     case 0: /* user-defined fault */
01825     case ERROR_ACCESS_DENIED:
01826     case ERROR_INVALID_PARAMETER:
01827     case RPC_S_PROTOCOL_ERROR:
01828     case RPC_S_CALL_FAILED:
01829     case RPC_S_CALL_FAILED_DNE:
01830     case RPC_S_SEC_PKG_ERROR:
01831         return TRUE;
01832     default:
01833         return FALSE;
01834     }
01835 }
01836 
01837 /***********************************************************************
01838  *           I_RpcReceive [RPCRT4.@]
01839  */
01840 RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg)
01841 {
01842   RpcBinding* bind = pMsg->Handle;
01843   RPC_STATUS status;
01844   RpcPktHdr *hdr = NULL;
01845   RpcConnection *conn;
01846 
01847   TRACE("(%p)\n", pMsg);
01848   if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
01849 
01850   conn = pMsg->ReservedForRuntime;
01851   status = RPCRT4_Receive(conn, &hdr, pMsg);
01852   if (status != RPC_S_OK) {
01853     WARN("receive failed with error %x\n", status);
01854     goto fail;
01855   }
01856 
01857   switch (hdr->common.ptype) {
01858   case PKT_RESPONSE:
01859     break;
01860   case PKT_FAULT:
01861     ERR ("we got fault packet with status 0x%x\n", hdr->fault.status);
01862     status = NCA2RPC_STATUS(hdr->fault.status);
01863     if (is_hard_error(status))
01864         goto fail;
01865     break;
01866   default:
01867     WARN("bad packet type %d\n", hdr->common.ptype);
01868     status = RPC_S_PROTOCOL_ERROR;
01869     goto fail;
01870   }
01871 
01872   /* success */
01873   RPCRT4_FreeHeader(hdr);
01874   return status;
01875 
01876 fail:
01877   RPCRT4_FreeHeader(hdr);
01878   RPCRT4_DestroyConnection(conn);
01879   pMsg->ReservedForRuntime = NULL;
01880   return status;
01881 }
01882 
01883 /***********************************************************************
01884  *           I_RpcSendReceive [RPCRT4.@]
01885  *
01886  * Sends a message to the server and receives the response.
01887  *
01888  * PARAMS
01889  *  pMsg [I/O] RPC message information.
01890  *
01891  * RETURNS
01892  *  Success: RPC_S_OK.
01893  *  Failure: Any error code.
01894  *
01895  * NOTES
01896  *  The buffer must have been allocated with I_RpcGetBuffer().
01897  *
01898  * SEE ALSO
01899  *  I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive().
01900  */
01901 RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg)
01902 {
01903   RPC_STATUS status;
01904   void *original_buffer;
01905 
01906   TRACE("(%p)\n", pMsg);
01907 
01908   original_buffer = pMsg->Buffer;
01909   status = I_RpcSend(pMsg);
01910   if (status == RPC_S_OK)
01911     status = I_RpcReceive(pMsg);
01912   /* free the buffer replaced by a new buffer in I_RpcReceive */
01913   if (status == RPC_S_OK)
01914     I_RpcFree(original_buffer);
01915   return status;
01916 }
01917 
01918 /***********************************************************************
01919  *           I_RpcAsyncSetHandle [RPCRT4.@]
01920  *
01921  * Sets the asynchronous state of the handle contained in the RPC message
01922  * structure.
01923  *
01924  * PARAMS
01925  *  pMsg   [I] RPC Message structure.
01926  *  pAsync [I] Asynchronous state to set.
01927  *
01928  * RETURNS
01929  *  Success: RPC_S_OK.
01930  *  Failure: Any error code.
01931  */
01932 RPC_STATUS WINAPI I_RpcAsyncSetHandle(PRPC_MESSAGE pMsg, PRPC_ASYNC_STATE pAsync)
01933 {
01934     RpcBinding* bind = pMsg->Handle;
01935     RpcConnection *conn;
01936 
01937     TRACE("(%p, %p)\n", pMsg, pAsync);
01938 
01939     if (!bind || bind->server || !pMsg->ReservedForRuntime) return RPC_S_INVALID_BINDING;
01940 
01941     conn = pMsg->ReservedForRuntime;
01942     conn->async_state = pAsync;
01943 
01944     return RPC_S_OK;
01945 }
01946 
01947 /***********************************************************************
01948  *           I_RpcAsyncAbortCall [RPCRT4.@]
01949  *
01950  * Aborts an asynchronous call.
01951  *
01952  * PARAMS
01953  *  pAsync        [I] Asynchronous state.
01954  *  ExceptionCode [I] Exception code.
01955  *
01956  * RETURNS
01957  *  Success: RPC_S_OK.
01958  *  Failure: Any error code.
01959  */
01960 RPC_STATUS WINAPI I_RpcAsyncAbortCall(PRPC_ASYNC_STATE pAsync, ULONG ExceptionCode)
01961 {
01962     FIXME("(%p, %d): stub\n", pAsync, ExceptionCode);
01963     return RPC_S_INVALID_ASYNC_HANDLE;
01964 }

Generated on Sun May 27 2012 04:26:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.