1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21148c5f43SAlan Wright 22da6c28aaSamw /* 23148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24*b3700b07SGordon Ross * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25da6c28aaSamw */ 26da6c28aaSamw 27da6c28aaSamw /* 288d7e4166Sjose borrego * Client NDR RPC interface. 29da6c28aaSamw */ 30da6c28aaSamw 31a0aa776eSAlan Wright #include <sys/types.h> 32da6c28aaSamw #include <sys/errno.h> 33ed9aabc7SGordon Ross #include <sys/fcntl.h> 349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <sys/tzfile.h> 35a0aa776eSAlan Wright #include <time.h> 36da6c28aaSamw #include <strings.h> 378d7e4166Sjose borrego #include <assert.h> 38ed9aabc7SGordon Ross #include <errno.h> 39a0aa776eSAlan Wright #include <thread.h> 409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <unistd.h> 419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <syslog.h> 42a0aa776eSAlan Wright #include <synch.h> 43ed9aabc7SGordon Ross 44ed9aabc7SGordon Ross #include <netsmb/smbfs_api.h> 45da6c28aaSamw #include <smbsrv/libsmb.h> 46*b3700b07SGordon Ross #include <smbsrv/libsmbns.h> 478d7e4166Sjose borrego #include <smbsrv/libmlrpc.h> 488d7e4166Sjose borrego #include <smbsrv/libmlsvc.h> 49fe1c642dSBill Krier #include <smbsrv/ndl/srvsvc.ndl> 50ed9aabc7SGordon Ross #include <libsmbrdr.h> 519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <mlsvc.h> 52da6c28aaSamw 538d7e4166Sjose borrego static int ndr_xa_init(ndr_client_t *, ndr_xa_t *); 548d7e4166Sjose borrego static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *); 558d7e4166Sjose borrego static int ndr_xa_read(ndr_client_t *, ndr_xa_t *); 568d7e4166Sjose borrego static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *); 578d7e4166Sjose borrego static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *); 588d7e4166Sjose borrego static void ndr_xa_release(ndr_client_t *); 59da6c28aaSamw 60a0aa776eSAlan Wright 61da6c28aaSamw /* 628d7e4166Sjose borrego * This call must be made to initialize an RPC client structure and bind 638d7e4166Sjose borrego * to the remote service before any RPCs can be exchanged with that service. 64da6c28aaSamw * 658d7e4166Sjose borrego * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle 668d7e4166Sjose borrego * with the client context for an instance of the interface. The handle 678d7e4166Sjose borrego * is zeroed to ensure that it doesn't look like a valid handle - 688d7e4166Sjose borrego * handle content is provided by the remove service. 69da6c28aaSamw * 708d7e4166Sjose borrego * The client points to this top-level handle so that we know when to 718d7e4166Sjose borrego * unbind and teardown the connection. As each handle is initialized it 728d7e4166Sjose borrego * will inherit a reference to the client context. 73*b3700b07SGordon Ross * 74*b3700b07SGordon Ross * Returns 0 or an NT_STATUS: 75*b3700b07SGordon Ross * NT_STATUS_BAD_NETWORK_PATH (get server addr) 76*b3700b07SGordon Ross * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth) 77*b3700b07SGordon Ross * NT_STATUS_BAD_NETWORK_NAME (tcon, open) 78*b3700b07SGordon Ross * NT_STATUS_ACCESS_DENIED (open pipe) 79*b3700b07SGordon Ross * NT_STATUS_INVALID_PARAMETER (rpc bind) 80*b3700b07SGordon Ross * 81*b3700b07SGordon Ross * NT_STATUS_INTERNAL_ERROR (bad args etc) 82*b3700b07SGordon Ross * NT_STATUS_NO_MEMORY 83da6c28aaSamw */ 84*b3700b07SGordon Ross DWORD 858d7e4166Sjose borrego ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain, 868d7e4166Sjose borrego char *username, const char *service) 87da6c28aaSamw { 88ed9aabc7SGordon Ross struct smb_ctx *ctx = NULL; 89ed9aabc7SGordon Ross ndr_client_t *clnt = NULL; 908d7e4166Sjose borrego ndr_service_t *svc; 91a0aa776eSAlan Wright srvsvc_server_info_t svinfo; 92*b3700b07SGordon Ross DWORD status; 93ed9aabc7SGordon Ross int fd = -1; 94da6c28aaSamw int rc; 95da6c28aaSamw 96*b3700b07SGordon Ross if (handle == NULL || server == NULL || server[0] == '\0' || 978d7e4166Sjose borrego domain == NULL || username == NULL) 98*b3700b07SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 99da6c28aaSamw 100*b3700b07SGordon Ross /* In case the service was not registered... */ 1018d7e4166Sjose borrego if ((svc = ndr_svc_lookup_name(service)) == NULL) 102*b3700b07SGordon Ross return (NT_STATUS_INTERNAL_ERROR); 103da6c28aaSamw 104a0aa776eSAlan Wright /* 105a0aa776eSAlan Wright * Set the default based on the assumption that most 1061ed6b69aSGordon Ross * servers will be Windows 2000 or later. This used to 1071ed6b69aSGordon Ross * try to get the actual server version, but that RPC 1081ed6b69aSGordon Ross * is not necessarily allowed anymore, so don't bother. 109a0aa776eSAlan Wright */ 110fe1c642dSBill Krier bzero(&svinfo, sizeof (srvsvc_server_info_t)); 111fe1c642dSBill Krier svinfo.sv_platform_id = SV_PLATFORM_ID_NT; 112fe1c642dSBill Krier svinfo.sv_version_major = 5; 113fe1c642dSBill Krier svinfo.sv_version_minor = 0; 114fe1c642dSBill Krier svinfo.sv_type = SV_TYPE_DEFAULT; 115fe1c642dSBill Krier svinfo.sv_os = NATIVE_OS_WIN2000; 116a0aa776eSAlan Wright 1171ed6b69aSGordon Ross /* 1181ed6b69aSGordon Ross * Some callers pass this when they want a NULL session. 1191ed6b69aSGordon Ross * Todo: have callers pass an empty string for that. 1201ed6b69aSGordon Ross */ 1211ed6b69aSGordon Ross if (strcmp(username, MLSVC_ANON_USER) == 0) 1221ed6b69aSGordon Ross username = ""; 123a0aa776eSAlan Wright 124ed9aabc7SGordon Ross /* 125ed9aabc7SGordon Ross * Setup smbfs library handle, authenticate, connect to 126ed9aabc7SGordon Ross * the IPC$ share. This will reuse an existing connection 127ed9aabc7SGordon Ross * if the driver already has one for this combination of 128*b3700b07SGordon Ross * server, user, domain. It may return any of: 129*b3700b07SGordon Ross * NT_STATUS_BAD_NETWORK_PATH (get server addr) 130*b3700b07SGordon Ross * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth) 131*b3700b07SGordon Ross * NT_STATUS_BAD_NETWORK_NAME (tcon) 132ed9aabc7SGordon Ross */ 133*b3700b07SGordon Ross status = smbrdr_ctx_new(&ctx, server, domain, username); 134*b3700b07SGordon Ross if (status != NT_STATUS_SUCCESS) { 1351ed6b69aSGordon Ross syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new" 1361ed6b69aSGordon Ross "(Srv=%s Dom=%s User=%s), %s (0x%x)", 1371ed6b69aSGordon Ross server, domain, username, 138*b3700b07SGordon Ross xlate_nt_status(status), status); 139*b3700b07SGordon Ross /* Tell the DC Locator this DC failed. */ 140*b3700b07SGordon Ross smb_ddiscover_bad_dc(server); 141ed9aabc7SGordon Ross goto errout; 142da6c28aaSamw } 143da6c28aaSamw 144ed9aabc7SGordon Ross /* 145ed9aabc7SGordon Ross * Open the named pipe. 146ed9aabc7SGordon Ross */ 147ed9aabc7SGordon Ross fd = smb_fh_open(ctx, svc->endpoint, O_RDWR); 148ed9aabc7SGordon Ross if (fd < 0) { 149*b3700b07SGordon Ross rc = errno; 150ed9aabc7SGordon Ross syslog(LOG_DEBUG, "ndr_rpc_bind: " 151*b3700b07SGordon Ross "smb_fh_open (%s) err=%d", 152*b3700b07SGordon Ross svc->endpoint, rc); 153*b3700b07SGordon Ross switch (rc) { 154*b3700b07SGordon Ross case EACCES: 155*b3700b07SGordon Ross status = NT_STATUS_ACCESS_DENIED; 156*b3700b07SGordon Ross break; 157*b3700b07SGordon Ross default: 158*b3700b07SGordon Ross status = NT_STATUS_BAD_NETWORK_NAME; 159*b3700b07SGordon Ross break; 160*b3700b07SGordon Ross } 161ed9aabc7SGordon Ross goto errout; 162ed9aabc7SGordon Ross } 163ed9aabc7SGordon Ross 164ed9aabc7SGordon Ross /* 165ed9aabc7SGordon Ross * Setup the RPC client handle. 166ed9aabc7SGordon Ross */ 167*b3700b07SGordon Ross if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) { 168*b3700b07SGordon Ross status = NT_STATUS_NO_MEMORY; 1691ed6b69aSGordon Ross goto errout; 170*b3700b07SGordon Ross } 1718d7e4166Sjose borrego bzero(clnt, sizeof (ndr_client_t)); 172ed9aabc7SGordon Ross 1738d7e4166Sjose borrego clnt->handle = &handle->handle; 1748d7e4166Sjose borrego clnt->xa_init = ndr_xa_init; 1758d7e4166Sjose borrego clnt->xa_exchange = ndr_xa_exchange; 1768d7e4166Sjose borrego clnt->xa_read = ndr_xa_read; 1778d7e4166Sjose borrego clnt->xa_preserve = ndr_xa_preserve; 1788d7e4166Sjose borrego clnt->xa_destruct = ndr_xa_destruct; 1798d7e4166Sjose borrego clnt->xa_release = ndr_xa_release; 180ed9aabc7SGordon Ross clnt->xa_private = ctx; 181ed9aabc7SGordon Ross clnt->xa_fd = fd; 1828d7e4166Sjose borrego 183ed9aabc7SGordon Ross ndr_svc_binding_pool_init(&clnt->binding_list, 184ed9aabc7SGordon Ross clnt->binding_pool, NDR_N_BINDING_POOL); 185ed9aabc7SGordon Ross 186*b3700b07SGordon Ross if ((clnt->heap = ndr_heap_create()) == NULL) { 187*b3700b07SGordon Ross status = NT_STATUS_NO_MEMORY; 188ed9aabc7SGordon Ross goto errout; 189*b3700b07SGordon Ross } 190ed9aabc7SGordon Ross 191ed9aabc7SGordon Ross /* 192ed9aabc7SGordon Ross * Fill in the caller's handle. 193ed9aabc7SGordon Ross */ 1948d7e4166Sjose borrego bzero(&handle->handle, sizeof (ndr_hdid_t)); 1958d7e4166Sjose borrego handle->clnt = clnt; 196fe1c642dSBill Krier bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t)); 1978d7e4166Sjose borrego 198ed9aabc7SGordon Ross /* 199ed9aabc7SGordon Ross * Do the OtW RPC bind. 200ed9aabc7SGordon Ross */ 2018d7e4166Sjose borrego rc = ndr_clnt_bind(clnt, service, &clnt->binding); 202*b3700b07SGordon Ross switch (rc) { 203*b3700b07SGordon Ross case NDR_DRC_FAULT_OUT_OF_MEMORY: 204*b3700b07SGordon Ross status = NT_STATUS_NO_MEMORY; 205*b3700b07SGordon Ross break; 206*b3700b07SGordon Ross case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */ 207*b3700b07SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 208*b3700b07SGordon Ross break; 209*b3700b07SGordon Ross default: 2108d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) { 211*b3700b07SGordon Ross status = NT_STATUS_INVALID_PARAMETER; 212*b3700b07SGordon Ross break; 213*b3700b07SGordon Ross } 214*b3700b07SGordon Ross /* FALLTHROUGH */ 215*b3700b07SGordon Ross case NDR_DRC_OK: 216*b3700b07SGordon Ross return (NT_STATUS_SUCCESS); 2178d7e4166Sjose borrego } 218da6c28aaSamw 219*b3700b07SGordon Ross syslog(LOG_DEBUG, "ndr_rpc_bind: " 220*b3700b07SGordon Ross "ndr_clnt_bind, %s (0x%x)", 221*b3700b07SGordon Ross xlate_nt_status(status), status); 222ed9aabc7SGordon Ross 223ed9aabc7SGordon Ross errout: 224ed9aabc7SGordon Ross handle->clnt = NULL; 225ed9aabc7SGordon Ross if (clnt != NULL) { 226ed9aabc7SGordon Ross ndr_heap_destroy(clnt->heap); 227ed9aabc7SGordon Ross free(clnt); 228ed9aabc7SGordon Ross } 229ed9aabc7SGordon Ross if (ctx != NULL) { 230ed9aabc7SGordon Ross if (fd != -1) 231ed9aabc7SGordon Ross (void) smb_fh_close(fd); 232ed9aabc7SGordon Ross smbrdr_ctx_free(ctx); 233ed9aabc7SGordon Ross } 234ed9aabc7SGordon Ross 235*b3700b07SGordon Ross return (status); 236da6c28aaSamw } 237da6c28aaSamw 238da6c28aaSamw /* 2398d7e4166Sjose borrego * Unbind and close the pipe to an RPC service. 240da6c28aaSamw * 2418d7e4166Sjose borrego * If the heap has been preserved we need to go through an xa release. 2428d7e4166Sjose borrego * The heap is preserved during an RPC call because that's where data 2438d7e4166Sjose borrego * returned from the server is stored. 244da6c28aaSamw * 2458d7e4166Sjose borrego * Otherwise we destroy the heap directly. 246da6c28aaSamw */ 247da6c28aaSamw void 2488d7e4166Sjose borrego ndr_rpc_unbind(mlsvc_handle_t *handle) 249da6c28aaSamw { 2508d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt; 251ed9aabc7SGordon Ross struct smb_ctx *ctx = clnt->xa_private; 2528d7e4166Sjose borrego 2538d7e4166Sjose borrego if (clnt->heap_preserved) 2548d7e4166Sjose borrego ndr_clnt_free_heap(clnt); 2558d7e4166Sjose borrego else 2568d7e4166Sjose borrego ndr_heap_destroy(clnt->heap); 2578d7e4166Sjose borrego 258ed9aabc7SGordon Ross (void) smb_fh_close(clnt->xa_fd); 259ed9aabc7SGordon Ross smbrdr_ctx_free(ctx); 260ed9aabc7SGordon Ross free(clnt); 2618d7e4166Sjose borrego bzero(handle, sizeof (mlsvc_handle_t)); 262da6c28aaSamw } 263da6c28aaSamw 264da6c28aaSamw /* 2658d7e4166Sjose borrego * Call the RPC function identified by opnum. The remote service is 2668d7e4166Sjose borrego * identified by the handle, which should have been initialized by 2678d7e4166Sjose borrego * ndr_rpc_bind. 2688d7e4166Sjose borrego * 2698d7e4166Sjose borrego * If the RPC call is successful (returns 0), the caller must call 2708d7e4166Sjose borrego * ndr_rpc_release to release the heap. Otherwise, we release the 2718d7e4166Sjose borrego * heap here. 272da6c28aaSamw */ 2738d7e4166Sjose borrego int 2748d7e4166Sjose borrego ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) 275da6c28aaSamw { 2768d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt; 2778d7e4166Sjose borrego int rc; 2788d7e4166Sjose borrego 2798d7e4166Sjose borrego if (ndr_rpc_get_heap(handle) == NULL) 2808d7e4166Sjose borrego return (-1); 2818d7e4166Sjose borrego 2828d7e4166Sjose borrego rc = ndr_clnt_call(clnt->binding, opnum, params); 2838d7e4166Sjose borrego 284fe1c642dSBill Krier /* 285fe1c642dSBill Krier * Always clear the nonull flag to ensure 286fe1c642dSBill Krier * it is not applied to subsequent calls. 287fe1c642dSBill Krier */ 288fe1c642dSBill Krier clnt->nonull = B_FALSE; 289fe1c642dSBill Krier 2908d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) { 2918d7e4166Sjose borrego ndr_rpc_release(handle); 2928d7e4166Sjose borrego return (-1); 2938d7e4166Sjose borrego } 2948d7e4166Sjose borrego 2958d7e4166Sjose borrego return (0); 2968d7e4166Sjose borrego } 297da6c28aaSamw 298da6c28aaSamw /* 299fe1c642dSBill Krier * Outgoing strings should not be null terminated. 300fe1c642dSBill Krier */ 301fe1c642dSBill Krier void 302fe1c642dSBill Krier ndr_rpc_set_nonull(mlsvc_handle_t *handle) 303fe1c642dSBill Krier { 304fe1c642dSBill Krier handle->clnt->nonull = B_TRUE; 305fe1c642dSBill Krier } 306fe1c642dSBill Krier 307fe1c642dSBill Krier /* 308fe1c642dSBill Krier * Return a reference to the server info. 309fe1c642dSBill Krier */ 310fe1c642dSBill Krier const srvsvc_server_info_t * 311fe1c642dSBill Krier ndr_rpc_server_info(mlsvc_handle_t *handle) 312fe1c642dSBill Krier { 313fe1c642dSBill Krier return (&handle->svinfo); 314fe1c642dSBill Krier } 315fe1c642dSBill Krier 316fe1c642dSBill Krier /* 317fe1c642dSBill Krier * Return the RPC server OS level. 3188d7e4166Sjose borrego */ 319a0aa776eSAlan Wright uint32_t 3208d7e4166Sjose borrego ndr_rpc_server_os(mlsvc_handle_t *handle) 3218d7e4166Sjose borrego { 322fe1c642dSBill Krier return (handle->svinfo.sv_os); 3238d7e4166Sjose borrego } 3248d7e4166Sjose borrego 325e3f2c991SKeyur Desai /* 326e3f2c991SKeyur Desai * Get the session key from a bound RPC client handle. 327e3f2c991SKeyur Desai * 328e3f2c991SKeyur Desai * The key returned is the 16-byte "user session key" 329e3f2c991SKeyur Desai * established by the underlying authentication protocol 330e3f2c991SKeyur Desai * (either Kerberos or NTLM). This key is needed for 331e3f2c991SKeyur Desai * SAM RPC calls such as SamrSetInformationUser, etc. 332e3f2c991SKeyur Desai * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25. 333e3f2c991SKeyur Desai * 334e3f2c991SKeyur Desai * Returns zero (success) or an errno. 335e3f2c991SKeyur Desai */ 336e3f2c991SKeyur Desai int 337e3f2c991SKeyur Desai ndr_rpc_get_ssnkey(mlsvc_handle_t *handle, 338e3f2c991SKeyur Desai unsigned char *ssn_key, size_t len) 339e3f2c991SKeyur Desai { 340e3f2c991SKeyur Desai ndr_client_t *clnt = handle->clnt; 341e3f2c991SKeyur Desai int rc; 342e3f2c991SKeyur Desai 343e3f2c991SKeyur Desai if (clnt == NULL) 344e3f2c991SKeyur Desai return (EINVAL); 345e3f2c991SKeyur Desai 346ed9aabc7SGordon Ross rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len); 347e3f2c991SKeyur Desai return (rc); 348e3f2c991SKeyur Desai } 349e3f2c991SKeyur Desai 3508d7e4166Sjose borrego void * 3518d7e4166Sjose borrego ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size) 3528d7e4166Sjose borrego { 3538d7e4166Sjose borrego ndr_heap_t *heap; 3548d7e4166Sjose borrego 3558d7e4166Sjose borrego if ((heap = ndr_rpc_get_heap(handle)) == NULL) 3568d7e4166Sjose borrego return (NULL); 3578d7e4166Sjose borrego 3588d7e4166Sjose borrego return (ndr_heap_malloc(heap, size)); 3598d7e4166Sjose borrego } 3608d7e4166Sjose borrego 3618d7e4166Sjose borrego ndr_heap_t * 3628d7e4166Sjose borrego ndr_rpc_get_heap(mlsvc_handle_t *handle) 3638d7e4166Sjose borrego { 3648d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt; 3658d7e4166Sjose borrego 3668d7e4166Sjose borrego if (clnt->heap == NULL) 3678d7e4166Sjose borrego clnt->heap = ndr_heap_create(); 3688d7e4166Sjose borrego 3698d7e4166Sjose borrego return (clnt->heap); 3708d7e4166Sjose borrego } 3718d7e4166Sjose borrego 3728d7e4166Sjose borrego /* 3738d7e4166Sjose borrego * Must be called by RPC clients to free the heap after a successful RPC 3748d7e4166Sjose borrego * call, i.e. ndr_rpc_call returned 0. The caller should take a copy 3758d7e4166Sjose borrego * of any data returned by the RPC prior to calling this function because 3768d7e4166Sjose borrego * returned data is in the heap. 3778d7e4166Sjose borrego */ 3788d7e4166Sjose borrego void 3798d7e4166Sjose borrego ndr_rpc_release(mlsvc_handle_t *handle) 3808d7e4166Sjose borrego { 3818d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt; 3828d7e4166Sjose borrego 3838d7e4166Sjose borrego if (clnt->heap_preserved) 3848d7e4166Sjose borrego ndr_clnt_free_heap(clnt); 3858d7e4166Sjose borrego else 3868d7e4166Sjose borrego ndr_heap_destroy(clnt->heap); 3878d7e4166Sjose borrego 3888d7e4166Sjose borrego clnt->heap = NULL; 3898d7e4166Sjose borrego } 3908d7e4166Sjose borrego 3918d7e4166Sjose borrego /* 3928d7e4166Sjose borrego * Returns true if the handle is null. 3938d7e4166Sjose borrego * Otherwise returns false. 3948d7e4166Sjose borrego */ 3958d7e4166Sjose borrego boolean_t 3968d7e4166Sjose borrego ndr_is_null_handle(mlsvc_handle_t *handle) 3978d7e4166Sjose borrego { 3988d7e4166Sjose borrego static ndr_hdid_t zero_handle; 3998d7e4166Sjose borrego 4008d7e4166Sjose borrego if (handle == NULL || handle->clnt == NULL) 4018d7e4166Sjose borrego return (B_TRUE); 4028d7e4166Sjose borrego 4038d7e4166Sjose borrego if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t))) 4048d7e4166Sjose borrego return (B_TRUE); 4058d7e4166Sjose borrego 4068d7e4166Sjose borrego return (B_FALSE); 4078d7e4166Sjose borrego } 4088d7e4166Sjose borrego 4098d7e4166Sjose borrego /* 4108d7e4166Sjose borrego * Returns true if the handle is the top level bind handle. 4118d7e4166Sjose borrego * Otherwise returns false. 4128d7e4166Sjose borrego */ 4138d7e4166Sjose borrego boolean_t 4148d7e4166Sjose borrego ndr_is_bind_handle(mlsvc_handle_t *handle) 4158d7e4166Sjose borrego { 4168d7e4166Sjose borrego return (handle->clnt->handle == &handle->handle); 4178d7e4166Sjose borrego } 4188d7e4166Sjose borrego 4198d7e4166Sjose borrego /* 4208d7e4166Sjose borrego * Pass the client reference from parent to child. 4218d7e4166Sjose borrego */ 4228d7e4166Sjose borrego void 4238d7e4166Sjose borrego ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent) 4248d7e4166Sjose borrego { 4258d7e4166Sjose borrego child->clnt = parent->clnt; 426fe1c642dSBill Krier bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t)); 4278d7e4166Sjose borrego } 4288d7e4166Sjose borrego 4298d7e4166Sjose borrego void 4308d7e4166Sjose borrego ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status) 4318d7e4166Sjose borrego { 4328d7e4166Sjose borrego ndr_service_t *svc; 4338d7e4166Sjose borrego char *name = "NDR RPC"; 4348d7e4166Sjose borrego char *s = "unknown"; 4358d7e4166Sjose borrego 436148c5f43SAlan Wright switch (NT_SC_SEVERITY(status)) { 437148c5f43SAlan Wright case NT_STATUS_SEVERITY_SUCCESS: 4388d7e4166Sjose borrego s = "success"; 439148c5f43SAlan Wright break; 440148c5f43SAlan Wright case NT_STATUS_SEVERITY_INFORMATIONAL: 4418d7e4166Sjose borrego s = "info"; 442148c5f43SAlan Wright break; 443148c5f43SAlan Wright case NT_STATUS_SEVERITY_WARNING: 444148c5f43SAlan Wright s = "warning"; 445148c5f43SAlan Wright break; 446148c5f43SAlan Wright case NT_STATUS_SEVERITY_ERROR: 447148c5f43SAlan Wright s = "error"; 448148c5f43SAlan Wright break; 449148c5f43SAlan Wright } 4508d7e4166Sjose borrego 4518d7e4166Sjose borrego if (handle) { 4528d7e4166Sjose borrego svc = handle->clnt->binding->service; 4538d7e4166Sjose borrego name = svc->name; 4548d7e4166Sjose borrego } 4558d7e4166Sjose borrego 4568d7e4166Sjose borrego smb_tracef("%s[0x%02x]: %s: %s (0x%08x)", 4578d7e4166Sjose borrego name, opnum, s, xlate_nt_status(status), status); 4588d7e4166Sjose borrego } 4598d7e4166Sjose borrego 4608d7e4166Sjose borrego /* 4618d7e4166Sjose borrego * The following functions provide the client callback interface. 462da6c28aaSamw * If the caller hasn't provided a heap, create one here. 463da6c28aaSamw */ 4648d7e4166Sjose borrego static int 4658d7e4166Sjose borrego ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa) 4668d7e4166Sjose borrego { 4678d7e4166Sjose borrego ndr_stream_t *recv_nds = &mxa->recv_nds; 4688d7e4166Sjose borrego ndr_stream_t *send_nds = &mxa->send_nds; 4698d7e4166Sjose borrego ndr_heap_t *heap = clnt->heap; 470fe1c642dSBill Krier int rc; 4718d7e4166Sjose borrego 4728d7e4166Sjose borrego if (heap == NULL) { 4738d7e4166Sjose borrego if ((heap = ndr_heap_create()) == NULL) 474da6c28aaSamw return (-1); 4758d7e4166Sjose borrego 4768d7e4166Sjose borrego clnt->heap = heap; 477da6c28aaSamw } 478da6c28aaSamw 479da6c28aaSamw mxa->heap = heap; 480da6c28aaSamw 481fe1c642dSBill Krier rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap); 482fe1c642dSBill Krier if (rc == 0) 483fe1c642dSBill Krier rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT, 484b1352070SAlan Wright NDR_MODE_RETURN_RECV, heap); 485fe1c642dSBill Krier 486fe1c642dSBill Krier if (rc != 0) { 487fe1c642dSBill Krier nds_destruct(&mxa->recv_nds); 488fe1c642dSBill Krier nds_destruct(&mxa->send_nds); 489fe1c642dSBill Krier ndr_heap_destroy(mxa->heap); 490fe1c642dSBill Krier mxa->heap = NULL; 491fe1c642dSBill Krier clnt->heap = NULL; 492fe1c642dSBill Krier return (-1); 493fe1c642dSBill Krier } 494fe1c642dSBill Krier 495fe1c642dSBill Krier if (clnt->nonull) 496fe1c642dSBill Krier NDS_SETF(send_nds, NDS_F_NONULL); 497fe1c642dSBill Krier 498da6c28aaSamw return (0); 499da6c28aaSamw } 500da6c28aaSamw 501da6c28aaSamw /* 502da6c28aaSamw * This is the entry pointy for an RPC client call exchange with 503da6c28aaSamw * a server, which will result in an smbrdr SmbTransact request. 504da6c28aaSamw * 505da6c28aaSamw * SmbTransact should return the number of bytes received, which 506da6c28aaSamw * we record as the PDU size, or a negative error code. 507da6c28aaSamw */ 508da6c28aaSamw static int 5098d7e4166Sjose borrego ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa) 510da6c28aaSamw { 5118d7e4166Sjose borrego ndr_stream_t *recv_nds = &mxa->recv_nds; 5128d7e4166Sjose borrego ndr_stream_t *send_nds = &mxa->send_nds; 513ed9aabc7SGordon Ross int err, more, nbytes; 514da6c28aaSamw 515ed9aabc7SGordon Ross nbytes = recv_nds->pdu_max_size; 516ed9aabc7SGordon Ross err = smb_fh_xactnp(clnt->xa_fd, 517ed9aabc7SGordon Ross send_nds->pdu_size, (char *)send_nds->pdu_base_offset, 518ed9aabc7SGordon Ross &nbytes, (char *)recv_nds->pdu_base_offset, &more); 519ed9aabc7SGordon Ross if (err) { 5208d7e4166Sjose borrego recv_nds->pdu_size = 0; 5218d7e4166Sjose borrego return (-1); 5228d7e4166Sjose borrego } 523da6c28aaSamw 5248d7e4166Sjose borrego recv_nds->pdu_size = nbytes; 525ed9aabc7SGordon Ross return (0); 526da6c28aaSamw } 527da6c28aaSamw 528da6c28aaSamw /* 529da6c28aaSamw * This entry point will be invoked if the xa-exchange response contained 530da6c28aaSamw * only the first fragment of a multi-fragment response. The RPC client 531da6c28aaSamw * code will then make repeated xa-read requests to obtain the remaining 532da6c28aaSamw * fragments, which will result in smbrdr SmbReadX requests. 533da6c28aaSamw * 534da6c28aaSamw * SmbReadX should return the number of bytes received, in which case we 535da6c28aaSamw * expand the PDU size to include the received data, or a negative error 536da6c28aaSamw * code. 537da6c28aaSamw */ 538da6c28aaSamw static int 5398d7e4166Sjose borrego ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa) 540da6c28aaSamw { 5418d7e4166Sjose borrego ndr_stream_t *nds = &mxa->recv_nds; 542da6c28aaSamw int len; 5438d7e4166Sjose borrego int nbytes; 544da6c28aaSamw 5458d7e4166Sjose borrego if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0) 546da6c28aaSamw return (-1); 547da6c28aaSamw 548ed9aabc7SGordon Ross nbytes = smb_fh_read(clnt->xa_fd, 0, len, 549ed9aabc7SGordon Ross (char *)nds->pdu_base_offset + nds->pdu_size); 550da6c28aaSamw 5518d7e4166Sjose borrego if (nbytes < 0) 552da6c28aaSamw return (-1); 553da6c28aaSamw 5548d7e4166Sjose borrego nds->pdu_size += nbytes; 555da6c28aaSamw 5568d7e4166Sjose borrego if (nds->pdu_size > nds->pdu_max_size) { 5578d7e4166Sjose borrego nds->pdu_size = nds->pdu_max_size; 558da6c28aaSamw return (-1); 559da6c28aaSamw } 560da6c28aaSamw 5618d7e4166Sjose borrego return (nbytes); 562da6c28aaSamw } 563da6c28aaSamw 564da6c28aaSamw /* 5658d7e4166Sjose borrego * Preserve the heap so that the client application has access to data 5668d7e4166Sjose borrego * returned from the server after an RPC call. 567da6c28aaSamw */ 568da6c28aaSamw static void 5698d7e4166Sjose borrego ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa) 570da6c28aaSamw { 5718d7e4166Sjose borrego assert(clnt->heap == mxa->heap); 572da6c28aaSamw 5738d7e4166Sjose borrego clnt->heap_preserved = B_TRUE; 5748d7e4166Sjose borrego mxa->heap = NULL; 5758d7e4166Sjose borrego } 5768d7e4166Sjose borrego 5778d7e4166Sjose borrego /* 5788d7e4166Sjose borrego * Dispose of the transaction streams. If the heap has not been 5798d7e4166Sjose borrego * preserved, we can destroy it here. 5808d7e4166Sjose borrego */ 5818d7e4166Sjose borrego static void 5828d7e4166Sjose borrego ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa) 5838d7e4166Sjose borrego { 5848d7e4166Sjose borrego nds_destruct(&mxa->recv_nds); 5858d7e4166Sjose borrego nds_destruct(&mxa->send_nds); 5868d7e4166Sjose borrego 5878d7e4166Sjose borrego if (!clnt->heap_preserved) { 5888d7e4166Sjose borrego ndr_heap_destroy(mxa->heap); 5898d7e4166Sjose borrego mxa->heap = NULL; 5908d7e4166Sjose borrego clnt->heap = NULL; 5918d7e4166Sjose borrego } 5928d7e4166Sjose borrego } 5938d7e4166Sjose borrego 5948d7e4166Sjose borrego /* 5958d7e4166Sjose borrego * Dispose of a preserved heap. 5968d7e4166Sjose borrego */ 5978d7e4166Sjose borrego static void 5988d7e4166Sjose borrego ndr_xa_release(ndr_client_t *clnt) 5998d7e4166Sjose borrego { 6008d7e4166Sjose borrego if (clnt->heap_preserved) { 6018d7e4166Sjose borrego ndr_heap_destroy(clnt->heap); 6028d7e4166Sjose borrego clnt->heap = NULL; 6038d7e4166Sjose borrego clnt->heap_preserved = B_FALSE; 604da6c28aaSamw } 605da6c28aaSamw } 606a0aa776eSAlan Wright 6079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 6099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Compare the time here with the remote time on the server 6109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * and report clock skew. 6119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 6129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 6139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ndr_srvsvc_timecheck(char *server, char *domain) 6149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 6159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char hostname[MAXHOSTNAMELEN]; 6169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct timeval dc_tv; 6179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct tm dc_tm; 6189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct tm *tm; 6199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States time_t tnow; 6209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States time_t tdiff; 6219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int priority; 6229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) { 6249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed"); 6259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 6269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 6279fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tnow = time(NULL); 6299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (tnow > dc_tv.tv_sec) 6319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN; 6329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States else 6339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN; 6349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (tdiff != 0) { 6369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN); 6379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) gethostname(hostname, MAXHOSTNAMELEN); 6389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG; 6409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "DC [%s] clock skew detected: %u minutes", 6419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States server, tdiff); 6429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 6439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tm = gmtime(&dc_tv.tv_sec); 6449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "%-8s UTC: %s", server, asctime(tm)); 6459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tm = gmtime(&tnow); 6469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "%-8s UTC: %s", hostname, asctime(tm)); 6479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 6489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 649