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
ndr_rpc_bind(mlsvc_handle_t * handle,char * server,char * domain,char * username,const char * service)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
ndr_rpc_unbind(mlsvc_handle_t * handle)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
ndr_rpc_call(mlsvc_handle_t * handle,int opnum,void * params)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
ndr_rpc_set_nonull(mlsvc_handle_t * handle)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 *
ndr_rpc_server_info(mlsvc_handle_t * handle)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
ndr_rpc_server_os(mlsvc_handle_t * handle)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
ndr_rpc_get_ssnkey(mlsvc_handle_t * handle,unsigned char * ssn_key,size_t len)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 *
ndr_rpc_malloc(mlsvc_handle_t * handle,size_t size)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 *
ndr_rpc_get_heap(mlsvc_handle_t * handle)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
ndr_rpc_release(mlsvc_handle_t * handle)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
ndr_is_null_handle(mlsvc_handle_t * handle)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
ndr_is_bind_handle(mlsvc_handle_t * handle)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
ndr_inherit_handle(mlsvc_handle_t * child,mlsvc_handle_t * parent)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
ndr_rpc_status(mlsvc_handle_t * handle,int opnum,DWORD status)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
ndr_xa_init(ndr_client_t * clnt,ndr_xa_t * mxa)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
ndr_xa_exchange(ndr_client_t * clnt,ndr_xa_t * mxa)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
ndr_xa_read(ndr_client_t * clnt,ndr_xa_t * mxa)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
ndr_xa_preserve(ndr_client_t * clnt,ndr_xa_t * mxa)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
ndr_xa_destruct(ndr_client_t * clnt,ndr_xa_t * mxa)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
ndr_xa_release(ndr_client_t * clnt)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
ndr_srvsvc_timecheck(char * server,char * domain)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