xref: /titanic_51/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
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