1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <strings.h> 29 #include <sys/param.h> 30 31 #include <smbsrv/libsmb.h> 32 #include <smbsrv/ndr.h> 33 #include <smbsrv/mlrpc.h> 34 35 #ifdef _BIG_ENDIAN 36 static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_BIG_ENDIAN; 37 #else 38 static const int mlrpc_native_byte_order = MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 39 #endif 40 41 int 42 mlrpc_encode_decode_common(struct mlrpc_xaction *mxa, int mode, unsigned opnum, 43 struct ndr_typeinfo *ti, void *datum) 44 { 45 struct mlndr_stream *mlnds; 46 int m_op = NDR_MODE_TO_M_OP(mode); 47 int rc; 48 49 if (m_op == NDR_M_OP_MARSHALL) 50 mlnds = &mxa->send_mlnds; 51 else 52 mlnds = &mxa->recv_mlnds; 53 54 /* 55 * Make sure that mlnds is in the correct mode 56 */ 57 if (!NDR_MODE_MATCH(mlnds, mode)) 58 return (MLRPC_DRC_FAULT_MODE_MISMATCH); 59 60 /* 61 * Perform the (un)marshalling 62 */ 63 if (mlndo_operation(mlnds, ti, opnum, datum)) 64 return (MLRPC_DRC_OK); 65 66 switch (mlnds->error) { 67 case NDR_ERR_MALLOC_FAILED: 68 rc = MLRPC_DRC_FAULT_OUT_OF_MEMORY; 69 break; 70 71 case NDR_ERR_SWITCH_VALUE_INVALID: 72 rc = MLRPC_DRC_FAULT_PARAM_0_INVALID; 73 break; 74 75 case NDR_ERR_UNDERFLOW: 76 rc = MLRPC_DRC_FAULT_RECEIVED_RUNT; 77 break; 78 79 case NDR_ERR_GROW_FAILED: 80 rc = MLRPC_DRC_FAULT_ENCODE_TOO_BIG; 81 break; 82 83 default: 84 if (m_op == NDR_M_OP_MARSHALL) 85 rc = MLRPC_DRC_FAULT_ENCODE_FAILED; 86 else 87 rc = MLRPC_DRC_FAULT_DECODE_FAILED; 88 break; 89 } 90 91 return (rc); 92 } 93 94 int 95 mlrpc_decode_call(struct mlrpc_xaction *mxa, void *params) 96 { 97 int rc; 98 99 rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_RECV, 100 mxa->opnum, mxa->binding->service->interface_ti, params); 101 102 return (rc + MLRPC_PTYPE_REQUEST); 103 } 104 105 int 106 mlrpc_encode_return(struct mlrpc_xaction *mxa, void *params) 107 { 108 int rc; 109 110 rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_SEND, 111 mxa->opnum, mxa->binding->service->interface_ti, params); 112 113 return (rc + MLRPC_PTYPE_RESPONSE); 114 } 115 116 int 117 mlrpc_encode_call(struct mlrpc_xaction *mxa, void *params) 118 { 119 int rc; 120 121 rc = mlrpc_encode_decode_common(mxa, NDR_MODE_CALL_SEND, 122 mxa->opnum, mxa->binding->service->interface_ti, params); 123 124 return (rc + MLRPC_PTYPE_REQUEST); 125 } 126 127 int 128 mlrpc_decode_return(struct mlrpc_xaction *mxa, void *params) 129 { 130 int rc; 131 132 rc = mlrpc_encode_decode_common(mxa, NDR_MODE_RETURN_RECV, 133 mxa->opnum, mxa->binding->service->interface_ti, params); 134 135 return (rc + MLRPC_PTYPE_RESPONSE); 136 } 137 138 int 139 mlrpc_decode_pdu_hdr(struct mlrpc_xaction *mxa) 140 { 141 mlrpcconn_common_header_t *hdr = &mxa->recv_hdr.common_hdr; 142 struct mlndr_stream *mlnds = &mxa->recv_mlnds; 143 int ptype; 144 int rc; 145 int charset; 146 int byte_order; 147 148 if (mlnds->m_op != NDR_M_OP_UNMARSHALL) 149 return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF); 150 151 /* 152 * All PDU headers are at least this big 153 */ 154 rc = MLNDS_GROW_PDU(mlnds, sizeof (mlrpcconn_common_header_t), 0); 155 if (!rc) 156 return (MLRPC_DRC_FAULT_RECEIVED_RUNT + 0xFF); 157 158 /* 159 * Peek at the first eight bytes to figure out what we're doing. 160 */ 161 rc = MLNDS_GET_PDU(mlnds, 0, 8, (char *)hdr, 0, 0); 162 if (!rc) 163 return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF); 164 165 /* 166 * Verify the protocol version. 167 */ 168 if ((hdr->rpc_vers != 5) || (hdr->rpc_vers_minor != 0)) 169 return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF); 170 171 /* 172 * Check for ASCII as the character set. This is an ASCII 173 * versus EBCDIC option and has nothing to do with Unicode. 174 */ 175 charset = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_CHAR_MASK; 176 if (charset != MLRPC_REPLAB_CHAR_ASCII) 177 return (MLRPC_DRC_FAULT_DECODE_FAILED + 0xFF); 178 179 /* 180 * Set the byte swap flag if the PDU byte-order 181 * is different from the local byte-order. 182 */ 183 byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK; 184 mlnds->swap = (byte_order != mlrpc_native_byte_order) ? 1 : 0; 185 186 ptype = hdr->ptype; 187 if (ptype == MLRPC_PTYPE_REQUEST && 188 (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) { 189 ptype = MLRPC_PTYPE_REQUEST_WITH; /* fake for sizing */ 190 } 191 192 mxa->ptype = hdr->ptype; 193 194 rc = mlrpc_encode_decode_common(mxa, 195 NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir), 196 ptype, &TYPEINFO(mlrpcconn_hdr), hdr); 197 198 return (rc + 0xFF); 199 } 200 201 /* 202 * Decode an RPC fragment header. Use mlrpc_decode_pdu_hdr() to process 203 * the first fragment header then this function to process additional 204 * fragment headers. 205 */ 206 void 207 mlrpc_decode_frag_hdr(struct mlndr_stream *mlnds, 208 mlrpcconn_common_header_t *hdr) 209 { 210 mlrpcconn_common_header_t *tmp; 211 uint8_t *pdu; 212 int byte_order; 213 214 pdu = (uint8_t *)mlnds->pdu_base_offset + mlnds->pdu_scan_offset; 215 bcopy(pdu, hdr, MLRPC_RSP_HDR_SIZE); 216 217 /* 218 * Swap non-byte fields if the PDU byte-order 219 * is different from the local byte-order. 220 */ 221 byte_order = hdr->packed_drep.intg_char_rep & MLRPC_REPLAB_INTG_MASK; 222 223 if (byte_order != mlrpc_native_byte_order) { 224 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 225 tmp = (mlrpcconn_common_header_t *)pdu; 226 227 mlnds_bswap(&tmp->frag_length, &hdr->frag_length, 228 sizeof (WORD)); 229 mlnds_bswap(&tmp->auth_length, &hdr->auth_length, 230 sizeof (WORD)); 231 mlnds_bswap(&tmp->call_id, &hdr->call_id, sizeof (DWORD)); 232 } 233 } 234 235 int 236 mlrpc_encode_pdu_hdr(struct mlrpc_xaction *mxa) 237 { 238 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 239 struct mlndr_stream *mlnds = &mxa->send_mlnds; 240 int ptype; 241 int rc; 242 243 if (mlnds->m_op != NDR_M_OP_MARSHALL) 244 return (MLRPC_DRC_FAULT_MODE_MISMATCH + 0xFF); 245 246 ptype = hdr->ptype; 247 if (ptype == MLRPC_PTYPE_REQUEST && 248 (hdr->pfc_flags & MLRPC_PFC_OBJECT_UUID) != 0) { 249 ptype = MLRPC_PTYPE_REQUEST_WITH; /* fake for sizing */ 250 } 251 252 rc = mlrpc_encode_decode_common(mxa, 253 NDR_M_OP_AND_DIR_TO_MODE(mlnds->m_op, mlnds->dir), 254 ptype, &TYPEINFO(mlrpcconn_hdr), hdr); 255 256 return (rc + 0xFF); 257 } 258 259 /* 260 * This is a hand-coded derivative of the automatically generated 261 * (un)marshalling routine for bind_ack headers. bind_ack headers 262 * have an interior conformant array, which is inconsistent with 263 * IDL/NDR rules. 264 */ 265 extern struct ndr_typeinfo ndt__uchar; 266 extern struct ndr_typeinfo ndt__ushort; 267 extern struct ndr_typeinfo ndt__ulong; 268 269 int mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref); 270 struct ndr_typeinfo ndt__mlrpcconn_bind_ack_hdr = { 271 1, /* NDR version */ 272 3, /* alignment */ 273 NDR_F_STRUCT, /* flags */ 274 mlndr__mlrpcconn_bind_ack_hdr, /* ndr_func */ 275 68, /* pdu_size_fixed_part */ 276 0, /* pdu_size_variable_part */ 277 68, /* c_size_fixed_part */ 278 0, /* c_size_variable_part */ 279 }; 280 281 /* 282 * [_no_reorder] 283 */ 284 int 285 mlndr__mlrpcconn_bind_ack_hdr(struct ndr_reference *encl_ref) 286 { 287 struct mlndr_stream *mlnds = encl_ref->stream; 288 struct mlrpcconn_bind_ack_hdr *val = /*LINTED E_BAD_PTR_CAST_ALIGN*/ 289 (struct mlrpcconn_bind_ack_hdr *)encl_ref->datum; 290 struct ndr_reference myref; 291 unsigned long offset; 292 293 bzero(&myref, sizeof (myref)); 294 myref.enclosing = encl_ref; 295 myref.stream = encl_ref->stream; 296 myref.packed_alignment = 0; 297 298 /* do all members in order */ 299 NDR_MEMBER(_mlrpcconn_common_header, common_hdr, 0UL); 300 NDR_MEMBER(_ushort, max_xmit_frag, 16UL); 301 NDR_MEMBER(_ushort, max_recv_frag, 18UL); 302 NDR_MEMBER(_ulong, assoc_group_id, 20UL); 303 304 /* port any is the conformant culprit */ 305 offset = 24UL; 306 307 switch (mlnds->m_op) { 308 case NDR_M_OP_MARSHALL: 309 val->sec_addr.length = 310 strlen((char *)val->sec_addr.port_spec) + 1; 311 break; 312 313 case NDR_M_OP_UNMARSHALL: 314 break; 315 316 default: 317 NDR_SET_ERROR(encl_ref, NDR_ERR_M_OP_INVALID); 318 return (0); 319 } 320 321 NDR_MEMBER(_ushort, sec_addr.length, offset); 322 NDR_MEMBER_ARR_WITH_DIMENSION(_uchar, sec_addr.port_spec, 323 offset+2UL, val->sec_addr.length); 324 325 offset += 2; 326 offset += val->sec_addr.length; 327 offset += (4 - offset) & 3; 328 329 NDR_MEMBER(_mlrpc_p_result_list, p_result_list, offset); 330 return (1); 331 } 332 333 unsigned 334 mlrpc_bind_ack_hdr_size(struct mlrpcconn_bind_ack_hdr *bahdr) 335 { 336 unsigned offset; 337 unsigned length; 338 339 /* port any is the conformant culprit */ 340 offset = 24UL; 341 342 length = strlen((char *)bahdr->sec_addr.port_spec) + 1; 343 344 offset += 2; 345 offset += length; 346 offset += (4 - offset) & 3; 347 offset += sizeof (bahdr->p_result_list); 348 return (offset); 349 } 350