15772Sas200622 /* 25772Sas200622 * CDDL HEADER START 35772Sas200622 * 45772Sas200622 * The contents of this file are subject to the terms of the 55772Sas200622 * Common Development and Distribution License (the "License"). 65772Sas200622 * You may not use this file except in compliance with the License. 75772Sas200622 * 85772Sas200622 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95772Sas200622 * or http://www.opensolaris.org/os/licensing. 105772Sas200622 * See the License for the specific language governing permissions 115772Sas200622 * and limitations under the License. 125772Sas200622 * 135772Sas200622 * When distributing Covered Code, include this CDDL HEADER in each 145772Sas200622 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155772Sas200622 * If applicable, add the following below this CDDL HEADER, with the 165772Sas200622 * fields enclosed by brackets "[]" replaced with your own identifying 175772Sas200622 * information: Portions Copyright [yyyy] [name of copyright owner] 185772Sas200622 * 195772Sas200622 * CDDL HEADER END 205772Sas200622 */ 215772Sas200622 /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235772Sas200622 * Use is subject to license terms. 245772Sas200622 */ 255772Sas200622 265772Sas200622 #pragma ident "%Z%%M% %I% %E% SMI" 275772Sas200622 285772Sas200622 /* 295772Sas200622 * Server side RPC handler. 305772Sas200622 */ 315772Sas200622 325772Sas200622 #include <sys/byteorder.h> 335772Sas200622 #include <thread.h> 345772Sas200622 #include <synch.h> 355772Sas200622 #include <stdlib.h> 365772Sas200622 #include <strings.h> 375772Sas200622 #include <string.h> 385772Sas200622 #include <time.h> 395772Sas200622 405772Sas200622 #include <smbsrv/libsmb.h> 415772Sas200622 #include <smbsrv/libmlrpc.h> 425772Sas200622 #include <smbsrv/mlsvc.h> 435772Sas200622 #include <smbsrv/ndr.h> 445772Sas200622 #include <smbsrv/mlrpc.h> 455772Sas200622 #include <smbsrv/mlsvc_util.h> 465772Sas200622 #include <smbsrv/ntsid.h> 475772Sas200622 #include <smbsrv/smb_winpipe.h> 485772Sas200622 495772Sas200622 /* 505772Sas200622 * Fragment size (5680: NT style). 515772Sas200622 */ 525772Sas200622 #define MLRPC_FRAG_SZ 5680 535772Sas200622 static unsigned long mlrpc_frag_size = MLRPC_FRAG_SZ; 545772Sas200622 555772Sas200622 /* 565772Sas200622 * Context table. 575772Sas200622 */ 585772Sas200622 #define CTXT_TABLE_ENTRIES 128 595772Sas200622 static struct mlsvc_rpc_context context_table[CTXT_TABLE_ENTRIES]; 605772Sas200622 static mutex_t mlrpc_context_lock; 615772Sas200622 625772Sas200622 static int mlrpc_s_process(struct mlrpc_xaction *); 635772Sas200622 static int mlrpc_s_bind(struct mlrpc_xaction *); 645772Sas200622 static int mlrpc_s_request(struct mlrpc_xaction *); 655772Sas200622 static void mlrpc_reply_prepare_hdr(struct mlrpc_xaction *); 665772Sas200622 static int mlrpc_s_alter_context(struct mlrpc_xaction *); 675772Sas200622 static void mlrpc_reply_bind_ack(struct mlrpc_xaction *); 685772Sas200622 static void mlrpc_reply_fault(struct mlrpc_xaction *, unsigned long); 695772Sas200622 static int mlrpc_build_reply(struct mlrpc_xaction *); 705772Sas200622 715772Sas200622 /* 725772Sas200622 * This is the RPC service server-side entry point. All MSRPC encoded 735772Sas200622 * messages should be passed through here. We use the same context 745772Sas200622 * structure as the client side but we don't need to set up the client 755772Sas200622 * side info. 765772Sas200622 */ 775772Sas200622 struct mlsvc_rpc_context * 785772Sas200622 mlrpc_process(int fid, smb_dr_user_ctx_t *user_ctx) 795772Sas200622 { 805772Sas200622 struct mlsvc_rpc_context *context; 815772Sas200622 struct mlrpc_xaction *mxa; 825772Sas200622 struct mlndr_stream *recv_mlnds; 835772Sas200622 struct mlndr_stream *send_mlnds; 845772Sas200622 unsigned char *pdu_base_addr; 855772Sas200622 char *data; 865772Sas200622 int datalen; 875772Sas200622 885772Sas200622 if ((context = mlrpc_lookup(fid)) == NULL) 895772Sas200622 return (NULL); 905772Sas200622 915772Sas200622 context->user_ctx = user_ctx; 925772Sas200622 data = context->inpipe->sp_data; 935772Sas200622 datalen = context->inpipe->sp_datalen; 945772Sas200622 955772Sas200622 mxa = (struct mlrpc_xaction *)malloc(sizeof (struct mlrpc_xaction)); 965772Sas200622 if (mxa == NULL) 975772Sas200622 return (NULL); 985772Sas200622 995772Sas200622 bzero(mxa, sizeof (struct mlrpc_xaction)); 1005772Sas200622 mxa->fid = fid; 1015772Sas200622 mxa->context = context; 1025772Sas200622 mxa->binding_list = context->binding; 1035772Sas200622 1045772Sas200622 if ((mxa->heap = mlrpc_heap_create()) == NULL) { 1055772Sas200622 free(mxa); 1065772Sas200622 return (NULL); 1075772Sas200622 } 1085772Sas200622 1095772Sas200622 recv_mlnds = &mxa->recv_mlnds; 1105772Sas200622 (void) mlnds_initialize(recv_mlnds, datalen, NDR_MODE_CALL_RECV, 1115772Sas200622 mxa->heap); 1125772Sas200622 1135772Sas200622 bcopy(data, recv_mlnds->pdu_base_addr, datalen); 1145772Sas200622 1155772Sas200622 send_mlnds = &mxa->send_mlnds; 1165772Sas200622 (void) mlnds_initialize(send_mlnds, 0, NDR_MODE_RETURN_SEND, mxa->heap); 1175772Sas200622 1185772Sas200622 (void) mlrpc_s_process(mxa); 1195772Sas200622 1205772Sas200622 /* 1215772Sas200622 * Different pointers for single frag vs multi frag responses. 1225772Sas200622 */ 1235772Sas200622 if (send_mlnds->pdu_base_addr_with_rpc_hdrs) 1245772Sas200622 pdu_base_addr = send_mlnds->pdu_base_addr_with_rpc_hdrs; 1255772Sas200622 else 1265772Sas200622 pdu_base_addr = send_mlnds->pdu_base_addr; 1275772Sas200622 1285772Sas200622 datalen = send_mlnds->pdu_size_with_rpc_hdrs; 1295772Sas200622 context->outpipe->sp_datalen = datalen; 1305772Sas200622 bcopy(pdu_base_addr, context->outpipe->sp_data, datalen); 1315772Sas200622 1325772Sas200622 mlnds_destruct(&mxa->recv_mlnds); 1335772Sas200622 mlnds_destruct(&mxa->send_mlnds); 1345772Sas200622 mlrpc_heap_destroy(mxa->heap); 1355772Sas200622 free(mxa); 1365772Sas200622 return (context); 1375772Sas200622 } 1385772Sas200622 1395772Sas200622 /* 1405772Sas200622 * Lookup the context for pipeid. If one exists, return a pointer to it. 1415772Sas200622 * Otherwise attempt to allocate a new context and return it. If the 1425772Sas200622 * context table is full, return a null pointer. 1435772Sas200622 */ 1445772Sas200622 struct mlsvc_rpc_context * 1455772Sas200622 mlrpc_lookup(int fid) 1465772Sas200622 { 1475772Sas200622 struct mlsvc_rpc_context *context; 1485772Sas200622 struct mlsvc_rpc_context *available = NULL; 1495772Sas200622 int i; 1505772Sas200622 1515772Sas200622 (void) mutex_lock(&mlrpc_context_lock); 1525772Sas200622 1535772Sas200622 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 1545772Sas200622 context = &context_table[i]; 1555772Sas200622 1565772Sas200622 if (available == NULL && context->fid == 0) { 1575772Sas200622 available = context; 1585772Sas200622 continue; 1595772Sas200622 } 1605772Sas200622 1615772Sas200622 if (context->fid == fid) { 1625772Sas200622 (void) mutex_unlock(&mlrpc_context_lock); 1635772Sas200622 return (context); 1645772Sas200622 } 1655772Sas200622 } 1665772Sas200622 1675772Sas200622 if (available) { 1685772Sas200622 bzero(available, sizeof (struct mlsvc_rpc_context)); 169*6030Sjb150015 available->inpipe = malloc(SMB_CTXT_PIPE_SZ); 170*6030Sjb150015 available->outpipe = malloc(SMB_CTXT_PIPE_SZ); 1715772Sas200622 1725772Sas200622 if (available->inpipe == NULL || available->outpipe == NULL) { 1735772Sas200622 free(available->inpipe); 1745772Sas200622 free(available->outpipe); 1755772Sas200622 bzero(available, sizeof (struct mlsvc_rpc_context)); 1765772Sas200622 (void) mutex_unlock(&mlrpc_context_lock); 1775772Sas200622 return (NULL); 1785772Sas200622 } 1795772Sas200622 1805772Sas200622 bzero(available->inpipe, sizeof (smb_pipe_t)); 1815772Sas200622 bzero(available->outpipe, sizeof (smb_pipe_t)); 1825772Sas200622 available->fid = fid; 1835772Sas200622 available->inpipe->sp_pipeid = fid; 1845772Sas200622 available->outpipe->sp_pipeid = fid; 1855772Sas200622 1865772Sas200622 mlrpc_binding_pool_initialize(&available->binding, 1875772Sas200622 available->binding_pool, CTXT_N_BINDING_POOL); 1885772Sas200622 } 1895772Sas200622 1905772Sas200622 (void) mutex_unlock(&mlrpc_context_lock); 1915772Sas200622 return (available); 1925772Sas200622 } 1935772Sas200622 1945772Sas200622 /* 1955772Sas200622 * This function should be called to release the context associated 1965772Sas200622 * with a fid when the client performs a close file. 1975772Sas200622 */ 1985772Sas200622 void 1995772Sas200622 mlrpc_release(int fid) 2005772Sas200622 { 2015772Sas200622 struct mlsvc_rpc_context *context; 2025772Sas200622 int i; 2035772Sas200622 2045772Sas200622 (void) mutex_lock(&mlrpc_context_lock); 2055772Sas200622 2065772Sas200622 for (i = 0; i < CTXT_TABLE_ENTRIES; ++i) { 2075772Sas200622 context = &context_table[i]; 2085772Sas200622 2095772Sas200622 if (context->fid == fid) { 2105772Sas200622 ndr_hdclose(fid); 2115772Sas200622 free(context->inpipe); 2125772Sas200622 free(context->outpipe); 2135772Sas200622 bzero(context, sizeof (struct mlsvc_rpc_context)); 2145772Sas200622 break; 2155772Sas200622 } 2165772Sas200622 } 2175772Sas200622 2185772Sas200622 (void) mutex_unlock(&mlrpc_context_lock); 2195772Sas200622 } 2205772Sas200622 2215772Sas200622 /* 2225772Sas200622 * This is the entry point for all server-side RPC processing. 2235772Sas200622 * It is assumed that the PDU has already been received. 2245772Sas200622 */ 2255772Sas200622 static int 2265772Sas200622 mlrpc_s_process(struct mlrpc_xaction *mxa) 2275772Sas200622 { 2285772Sas200622 int rc; 2295772Sas200622 2305772Sas200622 rc = mlrpc_decode_pdu_hdr(mxa); 2315772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 2325772Sas200622 return (-1); 2335772Sas200622 2345772Sas200622 (void) mlrpc_reply_prepare_hdr(mxa); 2355772Sas200622 2365772Sas200622 switch (mxa->ptype) { 2375772Sas200622 case MLRPC_PTYPE_BIND: 2385772Sas200622 rc = mlrpc_s_bind(mxa); 2395772Sas200622 break; 2405772Sas200622 2415772Sas200622 case MLRPC_PTYPE_REQUEST: 2425772Sas200622 rc = mlrpc_s_request(mxa); 2435772Sas200622 break; 2445772Sas200622 2455772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 2465772Sas200622 rc = mlrpc_s_alter_context(mxa); 2475772Sas200622 break; 2485772Sas200622 2495772Sas200622 default: 2505772Sas200622 rc = MLRPC_DRC_FAULT_RPCHDR_PTYPE_INVALID; 2515772Sas200622 break; 2525772Sas200622 } 2535772Sas200622 2545772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) 2555772Sas200622 mlrpc_reply_fault(mxa, rc); 2565772Sas200622 2575772Sas200622 (void) mlrpc_build_reply(mxa); 2585772Sas200622 return (rc); 2595772Sas200622 } 2605772Sas200622 2615772Sas200622 /* 2625772Sas200622 * Multiple p_cont_elem[]s, multiple transfer_syntaxes[] and multiple 2635772Sas200622 * p_results[] not supported. 2645772Sas200622 */ 2655772Sas200622 static int 2665772Sas200622 mlrpc_s_bind(struct mlrpc_xaction *mxa) 2675772Sas200622 { 2685772Sas200622 mlrpc_p_cont_list_t *cont_list; 2695772Sas200622 mlrpc_p_result_list_t *result_list; 2705772Sas200622 mlrpc_p_result_t *result; 2715772Sas200622 unsigned p_cont_id; 2725772Sas200622 struct mlrpc_binding *mbind; 2735772Sas200622 ndr_uuid_t *as_uuid; 2745772Sas200622 ndr_uuid_t *ts_uuid; 2755772Sas200622 char as_buf[64]; 2765772Sas200622 char ts_buf[64]; 2775772Sas200622 int as_vers; 2785772Sas200622 int ts_vers; 2795772Sas200622 struct mlndr_stream *send_mlnds; 2805772Sas200622 struct mlrpc_service *msvc; 2815772Sas200622 int rc; 2825772Sas200622 mlrpc_port_any_t *sec_addr; 2835772Sas200622 2845772Sas200622 /* acquire targets */ 2855772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 2865772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 2875772Sas200622 result = &result_list->p_results[0]; 2885772Sas200622 2895772Sas200622 /* 2905772Sas200622 * Set up temporary secondary address port. 2915772Sas200622 * We will correct this later (below). 2925772Sas200622 */ 2935772Sas200622 send_mlnds = &mxa->send_mlnds; 2945772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 2955772Sas200622 sec_addr->length = 13; 2965772Sas200622 (void) strcpy((char *)sec_addr->port_spec, "\\PIPE\\ntsvcs"); 2975772Sas200622 2985772Sas200622 result_list->n_results = 1; 2995772Sas200622 result_list->reserved = 0; 3005772Sas200622 result_list->reserved2 = 0; 3015772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 3025772Sas200622 result->reason = 0; 3035772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 3045772Sas200622 3055772Sas200622 /* sanity check */ 3065772Sas200622 if (cont_list->n_context_elem != 1 || 3075772Sas200622 cont_list->p_cont_elem[0].n_transfer_syn != 1) { 3085772Sas200622 mlndo_trace("mlrpc_s_bind: warning: multiple p_cont_elem"); 3095772Sas200622 } 3105772Sas200622 3115772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 3125772Sas200622 3135772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) { 3145772Sas200622 /* 3155772Sas200622 * Duplicate p_cont_id. 3165772Sas200622 * Send a bind_ack with a better error. 3175772Sas200622 */ 3185772Sas200622 mlndo_trace("mlrpc_s_bind: duplicate binding"); 3195772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 3205772Sas200622 } 3215772Sas200622 3225772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 3235772Sas200622 /* 3245772Sas200622 * No free binding slot 3255772Sas200622 */ 3265772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 3275772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 3285772Sas200622 mlndo_trace("mlrpc_s_bind: no resources"); 3295772Sas200622 return (MLRPC_DRC_OK); 3305772Sas200622 } 3315772Sas200622 3325772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 3335772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 3345772Sas200622 3355772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 3365772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 3375772Sas200622 3385772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 3395772Sas200622 if (!msvc) { 3405772Sas200622 mlrpc_uuid_to_str(as_uuid, as_buf); 3415772Sas200622 mlrpc_uuid_to_str(ts_uuid, ts_buf); 3425772Sas200622 3435772Sas200622 mlndo_printf(send_mlnds, 0, "mlrpc_s_bind: unknown service"); 3445772Sas200622 mlndo_printf(send_mlnds, 0, "abs=%s v%d, xfer=%s v%d", 3455772Sas200622 as_buf, as_vers, ts_buf, ts_vers); 3465772Sas200622 3475772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 3485772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 3495772Sas200622 return (MLRPC_DRC_OK); 3505772Sas200622 } 3515772Sas200622 3525772Sas200622 /* 3535772Sas200622 * We can now use the correct secondary address port. 3545772Sas200622 */ 3555772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 3565772Sas200622 sec_addr->length = strlen(msvc->sec_addr_port) + 1; 3575772Sas200622 (void) strlcpy((char *)sec_addr->port_spec, msvc->sec_addr_port, 3585772Sas200622 MLRPC_PORT_ANY_MAX_PORT_SPEC); 3595772Sas200622 3605772Sas200622 mbind->p_cont_id = p_cont_id; 3615772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 3625772Sas200622 /* mbind->context set by app */ 3635772Sas200622 mbind->service = msvc; 3645772Sas200622 mbind->instance_specific = 0; 3655772Sas200622 3665772Sas200622 mxa->binding = mbind; 3675772Sas200622 3685772Sas200622 if (msvc->bind_req) { 3695772Sas200622 /* 3705772Sas200622 * Call the service-specific bind() handler. If 3715772Sas200622 * this fails, we shouild send a specific error 3725772Sas200622 * on the bind ack. 3735772Sas200622 */ 3745772Sas200622 rc = (msvc->bind_req)(mxa); 3755772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 3765772Sas200622 mbind->service = 0; /* free binding slot */ 3775772Sas200622 mbind->which_side = 0; 3785772Sas200622 mbind->p_cont_id = 0; 3795772Sas200622 mbind->instance_specific = 0; 3805772Sas200622 return (rc); 3815772Sas200622 } 3825772Sas200622 } 3835772Sas200622 3845772Sas200622 result->transfer_syntax = 3855772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 3865772Sas200622 3875772Sas200622 /* 3885772Sas200622 * Special rejection of Windows 2000 DSSETUP interface. 3895772Sas200622 * This interface was introduced in Windows 2000 but has 3905772Sas200622 * been subsequently deprecated due to problems. 3915772Sas200622 */ 3925772Sas200622 if (strcmp(msvc->name, "DSSETUP") == 0) { 3935772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 3945772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 3955772Sas200622 } 3965772Sas200622 3975772Sas200622 return (MLRPC_DRC_BINDING_MADE); 3985772Sas200622 } 3995772Sas200622 4005772Sas200622 /* 4015772Sas200622 * mlrpc_s_alter_context 4025772Sas200622 * 4035772Sas200622 * The alter context request is used to request additional presentation 4045772Sas200622 * context for another interface and/or version. It's very similar to a 4055772Sas200622 * bind request. 4065772Sas200622 * 4075772Sas200622 * We don't fully support multiple contexts so, for now, we reject this 4085772Sas200622 * request. Windows 2000 clients attempt to use an alternate LSA context 4095772Sas200622 * when ACLs are modified. 4105772Sas200622 */ 4115772Sas200622 static int 4125772Sas200622 mlrpc_s_alter_context(struct mlrpc_xaction *mxa) 4135772Sas200622 { 4145772Sas200622 mlrpc_p_result_list_t *result_list; 4155772Sas200622 mlrpc_p_result_t *result; 4165772Sas200622 mlrpc_p_cont_list_t *cont_list; 4175772Sas200622 struct mlrpc_binding *mbind; 4185772Sas200622 struct mlrpc_service *msvc; 4195772Sas200622 unsigned p_cont_id; 4205772Sas200622 ndr_uuid_t *as_uuid; 4215772Sas200622 ndr_uuid_t *ts_uuid; 4225772Sas200622 int as_vers; 4235772Sas200622 int ts_vers; 4245772Sas200622 mlrpc_port_any_t *sec_addr; 4255772Sas200622 4265772Sas200622 result_list = &mxa->send_hdr.bind_ack_hdr.p_result_list; 4275772Sas200622 result_list->n_results = 1; 4285772Sas200622 result_list->reserved = 0; 4295772Sas200622 result_list->reserved2 = 0; 4305772Sas200622 4315772Sas200622 result = &result_list->p_results[0]; 4325772Sas200622 result->result = MLRPC_PCDR_ACCEPTANCE; 4335772Sas200622 result->reason = 0; 4345772Sas200622 bzero(&result->transfer_syntax, sizeof (result->transfer_syntax)); 4355772Sas200622 4365772Sas200622 if (mxa != NULL) { 4375772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 4385772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 4395772Sas200622 return (MLRPC_DRC_OK); 4405772Sas200622 } 4415772Sas200622 4425772Sas200622 cont_list = &mxa->recv_hdr.bind_hdr.p_context_elem; 4435772Sas200622 p_cont_id = cont_list->p_cont_elem[0].p_cont_id; 4445772Sas200622 4455772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) != NULL) 4465772Sas200622 return (MLRPC_DRC_FAULT_BIND_PCONT_BUSY); 4475772Sas200622 4485772Sas200622 if ((mbind = mlrpc_new_binding(mxa)) == NULL) { 4495772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 4505772Sas200622 result->reason = MLRPC_PPR_LOCAL_LIMIT_EXCEEDED; 4515772Sas200622 return (MLRPC_DRC_OK); 4525772Sas200622 } 4535772Sas200622 4545772Sas200622 as_uuid = &cont_list->p_cont_elem[0].abstract_syntax.if_uuid; 4555772Sas200622 as_vers = cont_list->p_cont_elem[0].abstract_syntax.if_version; 4565772Sas200622 4575772Sas200622 ts_uuid = &cont_list->p_cont_elem[0].transfer_syntaxes[0].if_uuid; 4585772Sas200622 ts_vers = cont_list->p_cont_elem[0].transfer_syntaxes[0].if_version; 4595772Sas200622 4605772Sas200622 msvc = mlrpc_find_service_by_uuids(as_uuid, as_vers, ts_uuid, ts_vers); 4615772Sas200622 if (msvc == 0) { 4625772Sas200622 result->result = MLRPC_PCDR_PROVIDER_REJECTION; 4635772Sas200622 result->reason = MLRPC_PPR_ABSTRACT_SYNTAX_NOT_SUPPORTED; 4645772Sas200622 return (MLRPC_DRC_OK); 4655772Sas200622 } 4665772Sas200622 4675772Sas200622 mbind->p_cont_id = p_cont_id; 4685772Sas200622 mbind->which_side = MLRPC_BIND_SIDE_SERVER; 4695772Sas200622 /* mbind->context set by app */ 4705772Sas200622 mbind->service = msvc; 4715772Sas200622 mbind->instance_specific = 0; 4725772Sas200622 mxa->binding = mbind; 4735772Sas200622 4745772Sas200622 sec_addr = &mxa->send_hdr.bind_ack_hdr.sec_addr; 4755772Sas200622 sec_addr->length = 0; 4765772Sas200622 bzero(sec_addr->port_spec, MLRPC_PORT_ANY_MAX_PORT_SPEC); 4775772Sas200622 4785772Sas200622 result->transfer_syntax = 4795772Sas200622 cont_list->p_cont_elem[0].transfer_syntaxes[0]; 4805772Sas200622 4815772Sas200622 return (MLRPC_DRC_BINDING_MADE); 4825772Sas200622 } 4835772Sas200622 4845772Sas200622 static int 4855772Sas200622 mlrpc_s_request(struct mlrpc_xaction *mxa) 4865772Sas200622 { 4875772Sas200622 struct mlrpc_binding *mbind; 4885772Sas200622 struct mlrpc_service *msvc; 4895772Sas200622 unsigned p_cont_id; 4905772Sas200622 int rc; 4915772Sas200622 4925772Sas200622 mxa->opnum = mxa->recv_hdr.request_hdr.opnum; 4935772Sas200622 p_cont_id = mxa->recv_hdr.request_hdr.p_cont_id; 4945772Sas200622 4955772Sas200622 if ((mbind = mlrpc_find_binding(mxa, p_cont_id)) == NULL) 4965772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID); 4975772Sas200622 4985772Sas200622 mxa->binding = mbind; 4995772Sas200622 msvc = mbind->service; 5005772Sas200622 5015772Sas200622 /* 5025772Sas200622 * Make room for the response hdr. 5035772Sas200622 */ 5045772Sas200622 mxa->send_mlnds.pdu_scan_offset = MLRPC_RSP_HDR_SIZE; 5055772Sas200622 5065772Sas200622 if (msvc->call_stub) 5075772Sas200622 rc = (*msvc->call_stub)(mxa); 5085772Sas200622 else 5095772Sas200622 rc = mlrpc_generic_call_stub(mxa); 5105772Sas200622 5115772Sas200622 if (MLRPC_DRC_IS_FAULT(rc)) { 5125772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: 0x%04x", 5135772Sas200622 msvc->name, mxa->opnum, rc); 5145772Sas200622 } 5155772Sas200622 5165772Sas200622 return (rc); 5175772Sas200622 } 5185772Sas200622 5195772Sas200622 /* 5205772Sas200622 * The transaction and the two mlnds streams use the same heap, which 5215772Sas200622 * should already exist at this point. The heap will also be available 5225772Sas200622 * to the stub. 5235772Sas200622 */ 5245772Sas200622 int 5255772Sas200622 mlrpc_generic_call_stub(struct mlrpc_xaction *mxa) 5265772Sas200622 { 5275772Sas200622 struct mlrpc_binding *mbind = mxa->binding; 5285772Sas200622 struct mlrpc_service *msvc = mbind->service; 5295772Sas200622 struct ndr_typeinfo *intf_ti = msvc->interface_ti; 5305772Sas200622 struct mlrpc_stub_table *ste; 5315772Sas200622 int opnum = mxa->opnum; 5325772Sas200622 unsigned p_len = intf_ti->c_size_fixed_part; 5335772Sas200622 char *param; 5345772Sas200622 int rc; 5355772Sas200622 5365772Sas200622 if (mxa->heap == NULL) { 5375772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: no heap", msvc->name, opnum); 5385772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 5395772Sas200622 } 5405772Sas200622 5415772Sas200622 if ((ste = mlrpc_find_stub_in_svc(msvc, opnum)) == NULL) { 5425772Sas200622 mlndo_printf(0, 0, "%s[0x%02x]: invalid opnum", 5435772Sas200622 msvc->name, opnum); 5445772Sas200622 return (MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID); 5455772Sas200622 } 5465772Sas200622 5475772Sas200622 if ((param = mlrpc_heap_malloc(mxa->heap, p_len)) == NULL) 5485772Sas200622 return (MLRPC_DRC_FAULT_OUT_OF_MEMORY); 5495772Sas200622 5505772Sas200622 bzero(param, p_len); 5515772Sas200622 5525772Sas200622 rc = mlrpc_decode_call(mxa, param); 5535772Sas200622 if (!MLRPC_DRC_IS_OK(rc)) 5545772Sas200622 return (rc); 5555772Sas200622 5565772Sas200622 rc = (*ste->func)(param, mxa); 5575772Sas200622 if (rc == MLRPC_DRC_OK) 5585772Sas200622 rc = mlrpc_encode_return(mxa, param); 5595772Sas200622 5605772Sas200622 return (rc); 5615772Sas200622 } 5625772Sas200622 5635772Sas200622 /* 5645772Sas200622 * We can perform some initial setup of the response header here. 5655772Sas200622 * We also need to cache some of the information from the bind 5665772Sas200622 * negotiation for use during subsequent RPC calls. 5675772Sas200622 */ 5685772Sas200622 static void 5695772Sas200622 mlrpc_reply_prepare_hdr(struct mlrpc_xaction *mxa) 5705772Sas200622 { 5715772Sas200622 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 5725772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 5735772Sas200622 5745772Sas200622 hdr->rpc_vers = 5; 5755772Sas200622 hdr->rpc_vers_minor = 0; 5765772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 5775772Sas200622 hdr->packed_drep = rhdr->packed_drep; 5785772Sas200622 hdr->frag_length = 0; 5795772Sas200622 hdr->auth_length = 0; 5805772Sas200622 hdr->call_id = rhdr->call_id; 5815772Sas200622 #ifdef _BIG_ENDIAN 5825772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 5835772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 5845772Sas200622 #else 5855772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 5865772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 5875772Sas200622 #endif 5885772Sas200622 5895772Sas200622 switch (mxa->ptype) { 5905772Sas200622 case MLRPC_PTYPE_BIND: 5915772Sas200622 hdr->ptype = MLRPC_PTYPE_BIND_ACK; 5925772Sas200622 mxa->send_hdr.bind_ack_hdr.max_xmit_frag = 5935772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 5945772Sas200622 mxa->send_hdr.bind_ack_hdr.max_recv_frag = 5955772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 5965772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = 5975772Sas200622 mxa->recv_hdr.bind_hdr.assoc_group_id; 5985772Sas200622 5995772Sas200622 if (mxa->send_hdr.bind_ack_hdr.assoc_group_id == 0) 6005772Sas200622 mxa->send_hdr.bind_ack_hdr.assoc_group_id = time(0); 6015772Sas200622 6025772Sas200622 /* 6035772Sas200622 * Save the maximum fragment sizes 6045772Sas200622 * for use with subsequent requests. 6055772Sas200622 */ 6065772Sas200622 mxa->context->max_xmit_frag = 6075772Sas200622 mxa->recv_hdr.bind_hdr.max_xmit_frag; 6085772Sas200622 6095772Sas200622 mxa->context->max_recv_frag = 6105772Sas200622 mxa->recv_hdr.bind_hdr.max_recv_frag; 6115772Sas200622 6125772Sas200622 break; 6135772Sas200622 6145772Sas200622 case MLRPC_PTYPE_REQUEST: 6155772Sas200622 hdr->ptype = MLRPC_PTYPE_RESPONSE; 6165772Sas200622 /* mxa->send_hdr.response_hdr.alloc_hint */ 6175772Sas200622 mxa->send_hdr.response_hdr.p_cont_id = 6185772Sas200622 mxa->recv_hdr.request_hdr.p_cont_id; 6195772Sas200622 mxa->send_hdr.response_hdr.cancel_count = 0; 6205772Sas200622 mxa->send_hdr.response_hdr.reserved = 0; 6215772Sas200622 break; 6225772Sas200622 6235772Sas200622 case MLRPC_PTYPE_ALTER_CONTEXT: 6245772Sas200622 hdr->ptype = MLRPC_PTYPE_ALTER_CONTEXT_RESP; 6255772Sas200622 /* 6265772Sas200622 * The max_xmit_frag, max_recv_frag 6275772Sas200622 * and assoc_group_id are ignored. 6285772Sas200622 */ 6295772Sas200622 break; 6305772Sas200622 6315772Sas200622 default: 6325772Sas200622 hdr->ptype = 0xFF; 6335772Sas200622 } 6345772Sas200622 } 6355772Sas200622 6365772Sas200622 /* 6375772Sas200622 * Finish and encode the bind acknowledge (MLRPC_PTYPE_BIND_ACK) header. 6385772Sas200622 * The frag_length is different from a regular RPC response. 6395772Sas200622 */ 6405772Sas200622 static void 6415772Sas200622 mlrpc_reply_bind_ack(struct mlrpc_xaction *mxa) 6425772Sas200622 { 6435772Sas200622 mlrpcconn_common_header_t *hdr; 6445772Sas200622 mlrpcconn_bind_ack_hdr_t *bahdr; 6455772Sas200622 6465772Sas200622 hdr = &mxa->send_hdr.common_hdr; 6475772Sas200622 bahdr = &mxa->send_hdr.bind_ack_hdr; 6485772Sas200622 hdr->frag_length = mlrpc_bind_ack_hdr_size(bahdr); 6495772Sas200622 } 6505772Sas200622 6515772Sas200622 /* 6525772Sas200622 * Signal an RPC fault. The stream is reset and we overwrite whatever 6535772Sas200622 * was in the response header with the fault information. 6545772Sas200622 */ 6555772Sas200622 static void 6565772Sas200622 mlrpc_reply_fault(struct mlrpc_xaction *mxa, unsigned long drc) 6575772Sas200622 { 6585772Sas200622 mlrpcconn_common_header_t *rhdr = &mxa->recv_hdr.common_hdr; 6595772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 6605772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 6615772Sas200622 unsigned long fault_status; 6625772Sas200622 6635772Sas200622 MLNDS_RESET(mlnds); 6645772Sas200622 6655772Sas200622 hdr->rpc_vers = 5; 6665772Sas200622 hdr->rpc_vers_minor = 0; 6675772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG + MLRPC_PFC_LAST_FRAG; 6685772Sas200622 hdr->packed_drep = rhdr->packed_drep; 6695772Sas200622 hdr->frag_length = sizeof (mxa->send_hdr.fault_hdr); 6705772Sas200622 hdr->auth_length = 0; 6715772Sas200622 hdr->call_id = rhdr->call_id; 6725772Sas200622 #ifdef _BIG_ENDIAN 6735772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 6745772Sas200622 | MLRPC_REPLAB_INTG_BIG_ENDIAN; 6755772Sas200622 #else 6765772Sas200622 hdr->packed_drep.intg_char_rep = MLRPC_REPLAB_CHAR_ASCII 6775772Sas200622 | MLRPC_REPLAB_INTG_LITTLE_ENDIAN; 6785772Sas200622 #endif 6795772Sas200622 6805772Sas200622 switch (drc & MLRPC_DRC_MASK_SPECIFIER) { 6815772Sas200622 case MLRPC_DRC_FAULT_OUT_OF_MEMORY: 6825772Sas200622 case MLRPC_DRC_FAULT_ENCODE_TOO_BIG: 6835772Sas200622 fault_status = MLRPC_FAULT_NCA_OUT_ARGS_TOO_BIG; 6845772Sas200622 break; 6855772Sas200622 6865772Sas200622 case MLRPC_DRC_FAULT_REQUEST_PCONT_INVALID: 6875772Sas200622 fault_status = MLRPC_FAULT_NCA_INVALID_PRES_CONTEXT_ID; 6885772Sas200622 break; 6895772Sas200622 6905772Sas200622 case MLRPC_DRC_FAULT_REQUEST_OPNUM_INVALID: 6915772Sas200622 fault_status = MLRPC_FAULT_NCA_OP_RNG_ERROR; 6925772Sas200622 break; 6935772Sas200622 6945772Sas200622 case MLRPC_DRC_FAULT_DECODE_FAILED: 6955772Sas200622 case MLRPC_DRC_FAULT_ENCODE_FAILED: 6965772Sas200622 fault_status = MLRPC_FAULT_NCA_PROTO_ERROR; 6975772Sas200622 break; 6985772Sas200622 6995772Sas200622 default: 7005772Sas200622 fault_status = MLRPC_FAULT_NCA_UNSPEC_REJECT; 7015772Sas200622 break; 7025772Sas200622 } 7035772Sas200622 7045772Sas200622 mxa->send_hdr.fault_hdr.common_hdr.ptype = MLRPC_PTYPE_FAULT; 7055772Sas200622 mxa->send_hdr.fault_hdr.status = fault_status; 7065772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = hdr->frag_length; 7075772Sas200622 } 7085772Sas200622 7095772Sas200622 static int 7105772Sas200622 mlrpc_build_reply(struct mlrpc_xaction *mxa) 7115772Sas200622 { 7125772Sas200622 mlrpcconn_common_header_t *hdr = &mxa->send_hdr.common_hdr; 7135772Sas200622 struct mlndr_stream *mlnds = &mxa->send_mlnds; 7145772Sas200622 unsigned long pdu_size; 7155772Sas200622 unsigned long frag_size; 7165772Sas200622 unsigned long pdu_data_size; 7175772Sas200622 unsigned long frag_data_size; 7185772Sas200622 uint32_t rem_dlen; 7195772Sas200622 uint32_t save_rem_dlen; 7205772Sas200622 uint32_t bytesoff; 7215772Sas200622 uint32_t cnt; 7225772Sas200622 uint32_t obytes; 7235772Sas200622 uint32_t num_ext_frags; 7245772Sas200622 uint16_t last_frag = 0; 7255772Sas200622 uchar_t *frag_startp; 7265772Sas200622 mlrpcconn_common_header_t *rpc_hdr; 7275772Sas200622 7285772Sas200622 hdr = &mxa->send_hdr.common_hdr; 7295772Sas200622 7305772Sas200622 frag_size = mlrpc_frag_size; 7315772Sas200622 pdu_size = mlnds->pdu_size; 7325772Sas200622 7335772Sas200622 if (pdu_size <= frag_size) { 7345772Sas200622 /* 7355772Sas200622 * Single fragment response. The PDU size may be zero 7365772Sas200622 * here (i.e. bind or fault response). So don't make 7375772Sas200622 * any assumptions about it until after the header is 7385772Sas200622 * encoded. 7395772Sas200622 */ 7405772Sas200622 switch (hdr->ptype) { 7415772Sas200622 case MLRPC_PTYPE_BIND_ACK: 7425772Sas200622 mlrpc_reply_bind_ack(mxa); 7435772Sas200622 break; 7445772Sas200622 7455772Sas200622 case MLRPC_PTYPE_FAULT: 7465772Sas200622 /* already setup */ 7475772Sas200622 break; 7485772Sas200622 7495772Sas200622 case MLRPC_PTYPE_RESPONSE: 7505772Sas200622 hdr->frag_length = pdu_size; 7515772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = 7525772Sas200622 hdr->frag_length; 7535772Sas200622 break; 7545772Sas200622 7555772Sas200622 default: 7565772Sas200622 hdr->frag_length = pdu_size; 7575772Sas200622 break; 7585772Sas200622 } 7595772Sas200622 7605772Sas200622 mlnds->pdu_scan_offset = 0; 7615772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 7625772Sas200622 7635772Sas200622 mlnds->pdu_size_with_rpc_hdrs = mlnds->pdu_size; 7645772Sas200622 mlnds->pdu_base_addr_with_rpc_hdrs = 0; 7655772Sas200622 return (0); 7665772Sas200622 } 7675772Sas200622 7685772Sas200622 /* 7695772Sas200622 * Multiple fragment response. 7705772Sas200622 */ 7715772Sas200622 hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 7725772Sas200622 hdr->frag_length = frag_size; 7735772Sas200622 mxa->send_hdr.response_hdr.alloc_hint = pdu_size - MLRPC_RSP_HDR_SIZE; 7745772Sas200622 mlnds->pdu_scan_offset = 0; 7755772Sas200622 7765772Sas200622 (void) mlrpc_encode_pdu_hdr(mxa); 7775772Sas200622 7785772Sas200622 /* 7795772Sas200622 * We need to update the 24-byte header in subsequent fragments. 7805772Sas200622 * 7815772Sas200622 * pdu_data_size: total data remaining to be handled 7825772Sas200622 * frag_size: total fragment size including header 7835772Sas200622 * frag_data_size: data in fragment 7845772Sas200622 * (i.e. frag_size - MLRPC_RSP_HDR_SIZE) 7855772Sas200622 */ 7865772Sas200622 pdu_data_size = pdu_size - MLRPC_RSP_HDR_SIZE; 7875772Sas200622 frag_data_size = frag_size - MLRPC_RSP_HDR_SIZE; 7885772Sas200622 7895772Sas200622 num_ext_frags = pdu_data_size / frag_data_size; 7905772Sas200622 7915772Sas200622 /* 7925772Sas200622 * We may need to stretch the pipe and insert an RPC header 7935772Sas200622 * at each frag boundary. The response will get chunked into 7945772Sas200622 * xdrlen sizes for each trans request. 7955772Sas200622 */ 7965772Sas200622 mlnds->pdu_base_addr_with_rpc_hdrs 7975772Sas200622 = malloc(pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE)); 7985772Sas200622 mlnds->pdu_size_with_rpc_hdrs = 7995772Sas200622 mlnds->pdu_size + (num_ext_frags * MLRPC_RSP_HDR_SIZE); 8005772Sas200622 8015772Sas200622 /* 8025772Sas200622 * Start stretching loop. 8035772Sas200622 */ 8045772Sas200622 bcopy(mlnds->pdu_base_addr, 8055772Sas200622 mlnds->pdu_base_addr_with_rpc_hdrs, frag_size); 8065772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 8075772Sas200622 rpc_hdr = (mlrpcconn_common_header_t *) 8085772Sas200622 mlnds->pdu_base_addr_with_rpc_hdrs; 8095772Sas200622 rpc_hdr->pfc_flags = MLRPC_PFC_FIRST_FRAG; 8105772Sas200622 rem_dlen = pdu_data_size - frag_size; 8115772Sas200622 bytesoff = frag_size; 8125772Sas200622 cnt = 1; 8135772Sas200622 while (num_ext_frags--) { 8145772Sas200622 /* first copy the RPC header to the front of the frag */ 8155772Sas200622 bcopy(mlnds->pdu_base_addr, mlnds->pdu_base_addr_with_rpc_hdrs + 8165772Sas200622 (cnt * frag_size), MLRPC_RSP_HDR_SIZE); 8175772Sas200622 8185772Sas200622 /* then copy the data portion of the frag */ 8195772Sas200622 save_rem_dlen = rem_dlen; 8205772Sas200622 if (rem_dlen >= (frag_size - MLRPC_RSP_HDR_SIZE)) { 8215772Sas200622 rem_dlen = rem_dlen - frag_size + MLRPC_RSP_HDR_SIZE; 8225772Sas200622 obytes = frag_size - MLRPC_RSP_HDR_SIZE; 8235772Sas200622 } else { 8245772Sas200622 last_frag = 1; /* this is the last one */ 8255772Sas200622 obytes = rem_dlen; 8265772Sas200622 } 8275772Sas200622 8285772Sas200622 frag_startp = mlnds->pdu_base_addr_with_rpc_hdrs + 8295772Sas200622 (cnt * frag_size); 8305772Sas200622 bcopy(mlnds->pdu_base_addr + bytesoff, 8315772Sas200622 frag_startp + MLRPC_RSP_HDR_SIZE, obytes); 8325772Sas200622 8335772Sas200622 /* set the FRAG FLAGS in the frag header spot */ 8345772Sas200622 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 8355772Sas200622 rpc_hdr = (mlrpcconn_common_header_t *)frag_startp; 8365772Sas200622 if (last_frag) { 8375772Sas200622 rpc_hdr->frag_length = save_rem_dlen; 8385772Sas200622 rpc_hdr->pfc_flags = MLRPC_PFC_LAST_FRAG; 8395772Sas200622 } else { 8405772Sas200622 rpc_hdr->pfc_flags = 0; 8415772Sas200622 } 8425772Sas200622 8435772Sas200622 bytesoff += (frag_size - MLRPC_RSP_HDR_SIZE); 8445772Sas200622 cnt++; 8455772Sas200622 } 8465772Sas200622 8475772Sas200622 return (0); 8485772Sas200622 } 849