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*1ed6b69aSGordon Ross * Copyright 2012 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>
468d7e4166Sjose borrego #include <smbsrv/libmlrpc.h>
478d7e4166Sjose borrego #include <smbsrv/libmlsvc.h>
48fe1c642dSBill Krier #include <smbsrv/ndl/srvsvc.ndl>
49ed9aabc7SGordon Ross #include <libsmbrdr.h>
509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <mlsvc.h>
51da6c28aaSamw
528d7e4166Sjose borrego static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
538d7e4166Sjose borrego static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
548d7e4166Sjose borrego static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
558d7e4166Sjose borrego static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
568d7e4166Sjose borrego static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
578d7e4166Sjose borrego static void ndr_xa_release(ndr_client_t *);
58da6c28aaSamw
59a0aa776eSAlan Wright
60da6c28aaSamw /*
618d7e4166Sjose borrego * This call must be made to initialize an RPC client structure and bind
628d7e4166Sjose borrego * to the remote service before any RPCs can be exchanged with that service.
63da6c28aaSamw *
648d7e4166Sjose borrego * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
658d7e4166Sjose borrego * with the client context for an instance of the interface. The handle
668d7e4166Sjose borrego * is zeroed to ensure that it doesn't look like a valid handle -
678d7e4166Sjose borrego * handle content is provided by the remove service.
68da6c28aaSamw *
698d7e4166Sjose borrego * The client points to this top-level handle so that we know when to
708d7e4166Sjose borrego * unbind and teardown the connection. As each handle is initialized it
718d7e4166Sjose borrego * will inherit a reference to the client context.
72da6c28aaSamw */
73da6c28aaSamw int
ndr_rpc_bind(mlsvc_handle_t * handle,char * server,char * domain,char * username,const char * service)748d7e4166Sjose borrego ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
758d7e4166Sjose borrego char *username, const char *service)
76da6c28aaSamw {
77ed9aabc7SGordon Ross struct smb_ctx *ctx = NULL;
78ed9aabc7SGordon Ross ndr_client_t *clnt = NULL;
798d7e4166Sjose borrego ndr_service_t *svc;
80a0aa776eSAlan Wright srvsvc_server_info_t svinfo;
81ed9aabc7SGordon Ross int fd = -1;
82da6c28aaSamw int rc;
83da6c28aaSamw
848d7e4166Sjose borrego if (handle == NULL || server == NULL ||
858d7e4166Sjose borrego domain == NULL || username == NULL)
86da6c28aaSamw return (-1);
87da6c28aaSamw
888d7e4166Sjose borrego if ((svc = ndr_svc_lookup_name(service)) == NULL)
898d7e4166Sjose borrego return (-1);
90da6c28aaSamw
91a0aa776eSAlan Wright /*
92a0aa776eSAlan Wright * Set the default based on the assumption that most
93*1ed6b69aSGordon Ross * servers will be Windows 2000 or later. This used to
94*1ed6b69aSGordon Ross * try to get the actual server version, but that RPC
95*1ed6b69aSGordon Ross * is not necessarily allowed anymore, so don't bother.
96a0aa776eSAlan Wright */
97fe1c642dSBill Krier bzero(&svinfo, sizeof (srvsvc_server_info_t));
98fe1c642dSBill Krier svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
99fe1c642dSBill Krier svinfo.sv_version_major = 5;
100fe1c642dSBill Krier svinfo.sv_version_minor = 0;
101fe1c642dSBill Krier svinfo.sv_type = SV_TYPE_DEFAULT;
102fe1c642dSBill Krier svinfo.sv_os = NATIVE_OS_WIN2000;
103a0aa776eSAlan Wright
104*1ed6b69aSGordon Ross /*
105*1ed6b69aSGordon Ross * Some callers pass this when they want a NULL session.
106*1ed6b69aSGordon Ross * Todo: have callers pass an empty string for that.
107*1ed6b69aSGordon Ross */
108*1ed6b69aSGordon Ross if (strcmp(username, MLSVC_ANON_USER) == 0)
109*1ed6b69aSGordon Ross username = "";
110a0aa776eSAlan Wright
111ed9aabc7SGordon Ross /*
112ed9aabc7SGordon Ross * Setup smbfs library handle, authenticate, connect to
113ed9aabc7SGordon Ross * the IPC$ share. This will reuse an existing connection
114ed9aabc7SGordon Ross * if the driver already has one for this combination of
115ed9aabc7SGordon Ross * server, user, domain.
116ed9aabc7SGordon Ross */
117ed9aabc7SGordon Ross if ((rc = smbrdr_ctx_new(&ctx, server, domain, username)) != 0) {
118*1ed6b69aSGordon Ross syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
119*1ed6b69aSGordon Ross "(Srv=%s Dom=%s User=%s), %s (0x%x)",
120*1ed6b69aSGordon Ross server, domain, username,
121*1ed6b69aSGordon Ross xlate_nt_status(rc), rc);
122ed9aabc7SGordon Ross goto errout;
123da6c28aaSamw }
124da6c28aaSamw
125ed9aabc7SGordon Ross /*
126ed9aabc7SGordon Ross * Open the named pipe.
127ed9aabc7SGordon Ross */
128ed9aabc7SGordon Ross fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
129ed9aabc7SGordon Ross if (fd < 0) {
130ed9aabc7SGordon Ross syslog(LOG_DEBUG, "ndr_rpc_bind: "
131ed9aabc7SGordon Ross "smb_fh_open, err=%d", errno);
132ed9aabc7SGordon Ross goto errout;
133ed9aabc7SGordon Ross }
134ed9aabc7SGordon Ross
135ed9aabc7SGordon Ross /*
136ed9aabc7SGordon Ross * Setup the RPC client handle.
137ed9aabc7SGordon Ross */
138ed9aabc7SGordon Ross if ((clnt = malloc(sizeof (ndr_client_t))) == NULL)
139*1ed6b69aSGordon Ross goto errout;
1408d7e4166Sjose borrego bzero(clnt, sizeof (ndr_client_t));
141ed9aabc7SGordon Ross
1428d7e4166Sjose borrego clnt->handle = &handle->handle;
1438d7e4166Sjose borrego clnt->xa_init = ndr_xa_init;
1448d7e4166Sjose borrego clnt->xa_exchange = ndr_xa_exchange;
1458d7e4166Sjose borrego clnt->xa_read = ndr_xa_read;
1468d7e4166Sjose borrego clnt->xa_preserve = ndr_xa_preserve;
1478d7e4166Sjose borrego clnt->xa_destruct = ndr_xa_destruct;
1488d7e4166Sjose borrego clnt->xa_release = ndr_xa_release;
149ed9aabc7SGordon Ross clnt->xa_private = ctx;
150ed9aabc7SGordon Ross clnt->xa_fd = fd;
1518d7e4166Sjose borrego
152ed9aabc7SGordon Ross ndr_svc_binding_pool_init(&clnt->binding_list,
153ed9aabc7SGordon Ross clnt->binding_pool, NDR_N_BINDING_POOL);
154ed9aabc7SGordon Ross
155ed9aabc7SGordon Ross if ((clnt->heap = ndr_heap_create()) == NULL)
156ed9aabc7SGordon Ross goto errout;
157ed9aabc7SGordon Ross
158ed9aabc7SGordon Ross /*
159ed9aabc7SGordon Ross * Fill in the caller's handle.
160ed9aabc7SGordon Ross */
1618d7e4166Sjose borrego bzero(&handle->handle, sizeof (ndr_hdid_t));
1628d7e4166Sjose borrego handle->clnt = clnt;
163fe1c642dSBill Krier bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
1648d7e4166Sjose borrego
165ed9aabc7SGordon Ross /*
166ed9aabc7SGordon Ross * Do the OtW RPC bind.
167ed9aabc7SGordon Ross */
1688d7e4166Sjose borrego rc = ndr_clnt_bind(clnt, service, &clnt->binding);
1698d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) {
170ed9aabc7SGordon Ross syslog(LOG_DEBUG, "ndr_rpc_bind: "
171ed9aabc7SGordon Ross "ndr_clnt_bind, rc=0x%x", rc);
172ed9aabc7SGordon Ross goto errout;
1738d7e4166Sjose borrego }
174da6c28aaSamw
175ed9aabc7SGordon Ross /* Success! */
176da6c28aaSamw return (0);
177ed9aabc7SGordon Ross
178ed9aabc7SGordon Ross errout:
179ed9aabc7SGordon Ross handle->clnt = NULL;
180ed9aabc7SGordon Ross if (clnt != NULL) {
181ed9aabc7SGordon Ross ndr_heap_destroy(clnt->heap);
182ed9aabc7SGordon Ross free(clnt);
183ed9aabc7SGordon Ross }
184ed9aabc7SGordon Ross if (ctx != NULL) {
185ed9aabc7SGordon Ross if (fd != -1)
186ed9aabc7SGordon Ross (void) smb_fh_close(fd);
187ed9aabc7SGordon Ross smbrdr_ctx_free(ctx);
188ed9aabc7SGordon Ross }
189ed9aabc7SGordon Ross
190ed9aabc7SGordon Ross return (-1);
191da6c28aaSamw }
192da6c28aaSamw
193da6c28aaSamw /*
1948d7e4166Sjose borrego * Unbind and close the pipe to an RPC service.
195da6c28aaSamw *
1968d7e4166Sjose borrego * If the heap has been preserved we need to go through an xa release.
1978d7e4166Sjose borrego * The heap is preserved during an RPC call because that's where data
1988d7e4166Sjose borrego * returned from the server is stored.
199da6c28aaSamw *
2008d7e4166Sjose borrego * Otherwise we destroy the heap directly.
201da6c28aaSamw */
202da6c28aaSamw void
ndr_rpc_unbind(mlsvc_handle_t * handle)2038d7e4166Sjose borrego ndr_rpc_unbind(mlsvc_handle_t *handle)
204da6c28aaSamw {
2058d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt;
206ed9aabc7SGordon Ross struct smb_ctx *ctx = clnt->xa_private;
2078d7e4166Sjose borrego
2088d7e4166Sjose borrego if (clnt->heap_preserved)
2098d7e4166Sjose borrego ndr_clnt_free_heap(clnt);
2108d7e4166Sjose borrego else
2118d7e4166Sjose borrego ndr_heap_destroy(clnt->heap);
2128d7e4166Sjose borrego
213ed9aabc7SGordon Ross (void) smb_fh_close(clnt->xa_fd);
214ed9aabc7SGordon Ross smbrdr_ctx_free(ctx);
215ed9aabc7SGordon Ross free(clnt);
2168d7e4166Sjose borrego bzero(handle, sizeof (mlsvc_handle_t));
217da6c28aaSamw }
218da6c28aaSamw
219da6c28aaSamw /*
2208d7e4166Sjose borrego * Call the RPC function identified by opnum. The remote service is
2218d7e4166Sjose borrego * identified by the handle, which should have been initialized by
2228d7e4166Sjose borrego * ndr_rpc_bind.
2238d7e4166Sjose borrego *
2248d7e4166Sjose borrego * If the RPC call is successful (returns 0), the caller must call
2258d7e4166Sjose borrego * ndr_rpc_release to release the heap. Otherwise, we release the
2268d7e4166Sjose borrego * heap here.
227da6c28aaSamw */
2288d7e4166Sjose borrego int
ndr_rpc_call(mlsvc_handle_t * handle,int opnum,void * params)2298d7e4166Sjose borrego ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
230da6c28aaSamw {
2318d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt;
2328d7e4166Sjose borrego int rc;
2338d7e4166Sjose borrego
2348d7e4166Sjose borrego if (ndr_rpc_get_heap(handle) == NULL)
2358d7e4166Sjose borrego return (-1);
2368d7e4166Sjose borrego
2378d7e4166Sjose borrego rc = ndr_clnt_call(clnt->binding, opnum, params);
2388d7e4166Sjose borrego
239fe1c642dSBill Krier /*
240fe1c642dSBill Krier * Always clear the nonull flag to ensure
241fe1c642dSBill Krier * it is not applied to subsequent calls.
242fe1c642dSBill Krier */
243fe1c642dSBill Krier clnt->nonull = B_FALSE;
244fe1c642dSBill Krier
2458d7e4166Sjose borrego if (NDR_DRC_IS_FAULT(rc)) {
2468d7e4166Sjose borrego ndr_rpc_release(handle);
2478d7e4166Sjose borrego return (-1);
2488d7e4166Sjose borrego }
2498d7e4166Sjose borrego
2508d7e4166Sjose borrego return (0);
2518d7e4166Sjose borrego }
252da6c28aaSamw
253da6c28aaSamw /*
254fe1c642dSBill Krier * Outgoing strings should not be null terminated.
255fe1c642dSBill Krier */
256fe1c642dSBill Krier void
ndr_rpc_set_nonull(mlsvc_handle_t * handle)257fe1c642dSBill Krier ndr_rpc_set_nonull(mlsvc_handle_t *handle)
258fe1c642dSBill Krier {
259fe1c642dSBill Krier handle->clnt->nonull = B_TRUE;
260fe1c642dSBill Krier }
261fe1c642dSBill Krier
262fe1c642dSBill Krier /*
263fe1c642dSBill Krier * Return a reference to the server info.
264fe1c642dSBill Krier */
265fe1c642dSBill Krier const srvsvc_server_info_t *
ndr_rpc_server_info(mlsvc_handle_t * handle)266fe1c642dSBill Krier ndr_rpc_server_info(mlsvc_handle_t *handle)
267fe1c642dSBill Krier {
268fe1c642dSBill Krier return (&handle->svinfo);
269fe1c642dSBill Krier }
270fe1c642dSBill Krier
271fe1c642dSBill Krier /*
272fe1c642dSBill Krier * Return the RPC server OS level.
2738d7e4166Sjose borrego */
274a0aa776eSAlan Wright uint32_t
ndr_rpc_server_os(mlsvc_handle_t * handle)2758d7e4166Sjose borrego ndr_rpc_server_os(mlsvc_handle_t *handle)
2768d7e4166Sjose borrego {
277fe1c642dSBill Krier return (handle->svinfo.sv_os);
2788d7e4166Sjose borrego }
2798d7e4166Sjose borrego
280e3f2c991SKeyur Desai /*
281e3f2c991SKeyur Desai * Get the session key from a bound RPC client handle.
282e3f2c991SKeyur Desai *
283e3f2c991SKeyur Desai * The key returned is the 16-byte "user session key"
284e3f2c991SKeyur Desai * established by the underlying authentication protocol
285e3f2c991SKeyur Desai * (either Kerberos or NTLM). This key is needed for
286e3f2c991SKeyur Desai * SAM RPC calls such as SamrSetInformationUser, etc.
287e3f2c991SKeyur Desai * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
288e3f2c991SKeyur Desai *
289e3f2c991SKeyur Desai * Returns zero (success) or an errno.
290e3f2c991SKeyur Desai */
291e3f2c991SKeyur Desai int
ndr_rpc_get_ssnkey(mlsvc_handle_t * handle,unsigned char * ssn_key,size_t len)292e3f2c991SKeyur Desai ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
293e3f2c991SKeyur Desai unsigned char *ssn_key, size_t len)
294e3f2c991SKeyur Desai {
295e3f2c991SKeyur Desai ndr_client_t *clnt = handle->clnt;
296e3f2c991SKeyur Desai int rc;
297e3f2c991SKeyur Desai
298e3f2c991SKeyur Desai if (clnt == NULL)
299e3f2c991SKeyur Desai return (EINVAL);
300e3f2c991SKeyur Desai
301ed9aabc7SGordon Ross rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len);
302e3f2c991SKeyur Desai return (rc);
303e3f2c991SKeyur Desai }
304e3f2c991SKeyur Desai
3058d7e4166Sjose borrego void *
ndr_rpc_malloc(mlsvc_handle_t * handle,size_t size)3068d7e4166Sjose borrego ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
3078d7e4166Sjose borrego {
3088d7e4166Sjose borrego ndr_heap_t *heap;
3098d7e4166Sjose borrego
3108d7e4166Sjose borrego if ((heap = ndr_rpc_get_heap(handle)) == NULL)
3118d7e4166Sjose borrego return (NULL);
3128d7e4166Sjose borrego
3138d7e4166Sjose borrego return (ndr_heap_malloc(heap, size));
3148d7e4166Sjose borrego }
3158d7e4166Sjose borrego
3168d7e4166Sjose borrego ndr_heap_t *
ndr_rpc_get_heap(mlsvc_handle_t * handle)3178d7e4166Sjose borrego ndr_rpc_get_heap(mlsvc_handle_t *handle)
3188d7e4166Sjose borrego {
3198d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt;
3208d7e4166Sjose borrego
3218d7e4166Sjose borrego if (clnt->heap == NULL)
3228d7e4166Sjose borrego clnt->heap = ndr_heap_create();
3238d7e4166Sjose borrego
3248d7e4166Sjose borrego return (clnt->heap);
3258d7e4166Sjose borrego }
3268d7e4166Sjose borrego
3278d7e4166Sjose borrego /*
3288d7e4166Sjose borrego * Must be called by RPC clients to free the heap after a successful RPC
3298d7e4166Sjose borrego * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
3308d7e4166Sjose borrego * of any data returned by the RPC prior to calling this function because
3318d7e4166Sjose borrego * returned data is in the heap.
3328d7e4166Sjose borrego */
3338d7e4166Sjose borrego void
ndr_rpc_release(mlsvc_handle_t * handle)3348d7e4166Sjose borrego ndr_rpc_release(mlsvc_handle_t *handle)
3358d7e4166Sjose borrego {
3368d7e4166Sjose borrego ndr_client_t *clnt = handle->clnt;
3378d7e4166Sjose borrego
3388d7e4166Sjose borrego if (clnt->heap_preserved)
3398d7e4166Sjose borrego ndr_clnt_free_heap(clnt);
3408d7e4166Sjose borrego else
3418d7e4166Sjose borrego ndr_heap_destroy(clnt->heap);
3428d7e4166Sjose borrego
3438d7e4166Sjose borrego clnt->heap = NULL;
3448d7e4166Sjose borrego }
3458d7e4166Sjose borrego
3468d7e4166Sjose borrego /*
3478d7e4166Sjose borrego * Returns true if the handle is null.
3488d7e4166Sjose borrego * Otherwise returns false.
3498d7e4166Sjose borrego */
3508d7e4166Sjose borrego boolean_t
ndr_is_null_handle(mlsvc_handle_t * handle)3518d7e4166Sjose borrego ndr_is_null_handle(mlsvc_handle_t *handle)
3528d7e4166Sjose borrego {
3538d7e4166Sjose borrego static ndr_hdid_t zero_handle;
3548d7e4166Sjose borrego
3558d7e4166Sjose borrego if (handle == NULL || handle->clnt == NULL)
3568d7e4166Sjose borrego return (B_TRUE);
3578d7e4166Sjose borrego
3588d7e4166Sjose borrego if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
3598d7e4166Sjose borrego return (B_TRUE);
3608d7e4166Sjose borrego
3618d7e4166Sjose borrego return (B_FALSE);
3628d7e4166Sjose borrego }
3638d7e4166Sjose borrego
3648d7e4166Sjose borrego /*
3658d7e4166Sjose borrego * Returns true if the handle is the top level bind handle.
3668d7e4166Sjose borrego * Otherwise returns false.
3678d7e4166Sjose borrego */
3688d7e4166Sjose borrego boolean_t
ndr_is_bind_handle(mlsvc_handle_t * handle)3698d7e4166Sjose borrego ndr_is_bind_handle(mlsvc_handle_t *handle)
3708d7e4166Sjose borrego {
3718d7e4166Sjose borrego return (handle->clnt->handle == &handle->handle);
3728d7e4166Sjose borrego }
3738d7e4166Sjose borrego
3748d7e4166Sjose borrego /*
3758d7e4166Sjose borrego * Pass the client reference from parent to child.
3768d7e4166Sjose borrego */
3778d7e4166Sjose borrego void
ndr_inherit_handle(mlsvc_handle_t * child,mlsvc_handle_t * parent)3788d7e4166Sjose borrego ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
3798d7e4166Sjose borrego {
3808d7e4166Sjose borrego child->clnt = parent->clnt;
381fe1c642dSBill Krier bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
3828d7e4166Sjose borrego }
3838d7e4166Sjose borrego
3848d7e4166Sjose borrego void
ndr_rpc_status(mlsvc_handle_t * handle,int opnum,DWORD status)3858d7e4166Sjose borrego ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
3868d7e4166Sjose borrego {
3878d7e4166Sjose borrego ndr_service_t *svc;
3888d7e4166Sjose borrego char *name = "NDR RPC";
3898d7e4166Sjose borrego char *s = "unknown";
3908d7e4166Sjose borrego
391148c5f43SAlan Wright switch (NT_SC_SEVERITY(status)) {
392148c5f43SAlan Wright case NT_STATUS_SEVERITY_SUCCESS:
3938d7e4166Sjose borrego s = "success";
394148c5f43SAlan Wright break;
395148c5f43SAlan Wright case NT_STATUS_SEVERITY_INFORMATIONAL:
3968d7e4166Sjose borrego s = "info";
397148c5f43SAlan Wright break;
398148c5f43SAlan Wright case NT_STATUS_SEVERITY_WARNING:
399148c5f43SAlan Wright s = "warning";
400148c5f43SAlan Wright break;
401148c5f43SAlan Wright case NT_STATUS_SEVERITY_ERROR:
402148c5f43SAlan Wright s = "error";
403148c5f43SAlan Wright break;
404148c5f43SAlan Wright }
4058d7e4166Sjose borrego
4068d7e4166Sjose borrego if (handle) {
4078d7e4166Sjose borrego svc = handle->clnt->binding->service;
4088d7e4166Sjose borrego name = svc->name;
4098d7e4166Sjose borrego }
4108d7e4166Sjose borrego
4118d7e4166Sjose borrego smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
4128d7e4166Sjose borrego name, opnum, s, xlate_nt_status(status), status);
4138d7e4166Sjose borrego }
4148d7e4166Sjose borrego
4158d7e4166Sjose borrego /*
4168d7e4166Sjose borrego * The following functions provide the client callback interface.
417da6c28aaSamw * If the caller hasn't provided a heap, create one here.
418da6c28aaSamw */
4198d7e4166Sjose borrego static int
ndr_xa_init(ndr_client_t * clnt,ndr_xa_t * mxa)4208d7e4166Sjose borrego ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
4218d7e4166Sjose borrego {
4228d7e4166Sjose borrego ndr_stream_t *recv_nds = &mxa->recv_nds;
4238d7e4166Sjose borrego ndr_stream_t *send_nds = &mxa->send_nds;
4248d7e4166Sjose borrego ndr_heap_t *heap = clnt->heap;
425fe1c642dSBill Krier int rc;
4268d7e4166Sjose borrego
4278d7e4166Sjose borrego if (heap == NULL) {
4288d7e4166Sjose borrego if ((heap = ndr_heap_create()) == NULL)
429da6c28aaSamw return (-1);
4308d7e4166Sjose borrego
4318d7e4166Sjose borrego clnt->heap = heap;
432da6c28aaSamw }
433da6c28aaSamw
434da6c28aaSamw mxa->heap = heap;
435da6c28aaSamw
436fe1c642dSBill Krier rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
437fe1c642dSBill Krier if (rc == 0)
438fe1c642dSBill Krier rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
439b1352070SAlan Wright NDR_MODE_RETURN_RECV, heap);
440fe1c642dSBill Krier
441fe1c642dSBill Krier if (rc != 0) {
442fe1c642dSBill Krier nds_destruct(&mxa->recv_nds);
443fe1c642dSBill Krier nds_destruct(&mxa->send_nds);
444fe1c642dSBill Krier ndr_heap_destroy(mxa->heap);
445fe1c642dSBill Krier mxa->heap = NULL;
446fe1c642dSBill Krier clnt->heap = NULL;
447fe1c642dSBill Krier return (-1);
448fe1c642dSBill Krier }
449fe1c642dSBill Krier
450fe1c642dSBill Krier if (clnt->nonull)
451fe1c642dSBill Krier NDS_SETF(send_nds, NDS_F_NONULL);
452fe1c642dSBill Krier
453da6c28aaSamw return (0);
454da6c28aaSamw }
455da6c28aaSamw
456da6c28aaSamw /*
457da6c28aaSamw * This is the entry pointy for an RPC client call exchange with
458da6c28aaSamw * a server, which will result in an smbrdr SmbTransact request.
459da6c28aaSamw *
460da6c28aaSamw * SmbTransact should return the number of bytes received, which
461da6c28aaSamw * we record as the PDU size, or a negative error code.
462da6c28aaSamw */
463da6c28aaSamw static int
ndr_xa_exchange(ndr_client_t * clnt,ndr_xa_t * mxa)4648d7e4166Sjose borrego ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
465da6c28aaSamw {
4668d7e4166Sjose borrego ndr_stream_t *recv_nds = &mxa->recv_nds;
4678d7e4166Sjose borrego ndr_stream_t *send_nds = &mxa->send_nds;
468ed9aabc7SGordon Ross int err, more, nbytes;
469da6c28aaSamw
470ed9aabc7SGordon Ross nbytes = recv_nds->pdu_max_size;
471ed9aabc7SGordon Ross err = smb_fh_xactnp(clnt->xa_fd,
472ed9aabc7SGordon Ross send_nds->pdu_size, (char *)send_nds->pdu_base_offset,
473ed9aabc7SGordon Ross &nbytes, (char *)recv_nds->pdu_base_offset, &more);
474ed9aabc7SGordon Ross if (err) {
4758d7e4166Sjose borrego recv_nds->pdu_size = 0;
4768d7e4166Sjose borrego return (-1);
4778d7e4166Sjose borrego }
478da6c28aaSamw
4798d7e4166Sjose borrego recv_nds->pdu_size = nbytes;
480ed9aabc7SGordon Ross return (0);
481da6c28aaSamw }
482da6c28aaSamw
483da6c28aaSamw /*
484da6c28aaSamw * This entry point will be invoked if the xa-exchange response contained
485da6c28aaSamw * only the first fragment of a multi-fragment response. The RPC client
486da6c28aaSamw * code will then make repeated xa-read requests to obtain the remaining
487da6c28aaSamw * fragments, which will result in smbrdr SmbReadX requests.
488da6c28aaSamw *
489da6c28aaSamw * SmbReadX should return the number of bytes received, in which case we
490da6c28aaSamw * expand the PDU size to include the received data, or a negative error
491da6c28aaSamw * code.
492da6c28aaSamw */
493da6c28aaSamw static int
ndr_xa_read(ndr_client_t * clnt,ndr_xa_t * mxa)4948d7e4166Sjose borrego ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
495da6c28aaSamw {
4968d7e4166Sjose borrego ndr_stream_t *nds = &mxa->recv_nds;
497da6c28aaSamw int len;
4988d7e4166Sjose borrego int nbytes;
499da6c28aaSamw
5008d7e4166Sjose borrego if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
501da6c28aaSamw return (-1);
502da6c28aaSamw
503ed9aabc7SGordon Ross nbytes = smb_fh_read(clnt->xa_fd, 0, len,
504ed9aabc7SGordon Ross (char *)nds->pdu_base_offset + nds->pdu_size);
505da6c28aaSamw
5068d7e4166Sjose borrego if (nbytes < 0)
507da6c28aaSamw return (-1);
508da6c28aaSamw
5098d7e4166Sjose borrego nds->pdu_size += nbytes;
510da6c28aaSamw
5118d7e4166Sjose borrego if (nds->pdu_size > nds->pdu_max_size) {
5128d7e4166Sjose borrego nds->pdu_size = nds->pdu_max_size;
513da6c28aaSamw return (-1);
514da6c28aaSamw }
515da6c28aaSamw
5168d7e4166Sjose borrego return (nbytes);
517da6c28aaSamw }
518da6c28aaSamw
519da6c28aaSamw /*
5208d7e4166Sjose borrego * Preserve the heap so that the client application has access to data
5218d7e4166Sjose borrego * returned from the server after an RPC call.
522da6c28aaSamw */
523da6c28aaSamw static void
ndr_xa_preserve(ndr_client_t * clnt,ndr_xa_t * mxa)5248d7e4166Sjose borrego ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
525da6c28aaSamw {
5268d7e4166Sjose borrego assert(clnt->heap == mxa->heap);
527da6c28aaSamw
5288d7e4166Sjose borrego clnt->heap_preserved = B_TRUE;
5298d7e4166Sjose borrego mxa->heap = NULL;
5308d7e4166Sjose borrego }
5318d7e4166Sjose borrego
5328d7e4166Sjose borrego /*
5338d7e4166Sjose borrego * Dispose of the transaction streams. If the heap has not been
5348d7e4166Sjose borrego * preserved, we can destroy it here.
5358d7e4166Sjose borrego */
5368d7e4166Sjose borrego static void
ndr_xa_destruct(ndr_client_t * clnt,ndr_xa_t * mxa)5378d7e4166Sjose borrego ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
5388d7e4166Sjose borrego {
5398d7e4166Sjose borrego nds_destruct(&mxa->recv_nds);
5408d7e4166Sjose borrego nds_destruct(&mxa->send_nds);
5418d7e4166Sjose borrego
5428d7e4166Sjose borrego if (!clnt->heap_preserved) {
5438d7e4166Sjose borrego ndr_heap_destroy(mxa->heap);
5448d7e4166Sjose borrego mxa->heap = NULL;
5458d7e4166Sjose borrego clnt->heap = NULL;
5468d7e4166Sjose borrego }
5478d7e4166Sjose borrego }
5488d7e4166Sjose borrego
5498d7e4166Sjose borrego /*
5508d7e4166Sjose borrego * Dispose of a preserved heap.
5518d7e4166Sjose borrego */
5528d7e4166Sjose borrego static void
ndr_xa_release(ndr_client_t * clnt)5538d7e4166Sjose borrego ndr_xa_release(ndr_client_t *clnt)
5548d7e4166Sjose borrego {
5558d7e4166Sjose borrego if (clnt->heap_preserved) {
5568d7e4166Sjose borrego ndr_heap_destroy(clnt->heap);
5578d7e4166Sjose borrego clnt->heap = NULL;
5588d7e4166Sjose borrego clnt->heap_preserved = B_FALSE;
559da6c28aaSamw }
560da6c28aaSamw }
561a0aa776eSAlan Wright
5629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
5649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Compare the time here with the remote time on the server
5659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * and report clock skew.
5669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */
5679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
ndr_srvsvc_timecheck(char * server,char * domain)5689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ndr_srvsvc_timecheck(char *server, char *domain)
5699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
5709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char hostname[MAXHOSTNAMELEN];
5719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct timeval dc_tv;
5729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct tm dc_tm;
5739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States struct tm *tm;
5749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States time_t tnow;
5759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States time_t tdiff;
5769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int priority;
5779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) {
5799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed");
5809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return;
5819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
5829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tnow = time(NULL);
5849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (tnow > dc_tv.tv_sec)
5869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN;
5879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States else
5889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN;
5899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (tdiff != 0) {
5919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN);
5929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) gethostname(hostname, MAXHOSTNAMELEN);
5939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG;
5959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "DC [%s] clock skew detected: %u minutes",
5969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States server, tdiff);
5979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States
5989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tm = gmtime(&dc_tv.tv_sec);
5999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "%-8s UTC: %s", server, asctime(tm));
6009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States tm = gmtime(&tnow);
6019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(priority, "%-8s UTC: %s", hostname, asctime(tm));
6029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
6039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
604