15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
21*12508Samw@Sun.COM
225331Samw /*
23*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245331Samw */
255331Samw
265331Samw /*
278334SJose.Borrego@Sun.COM * Client NDR RPC interface.
285331Samw */
295331Samw
3010717Samw@Sun.COM #include <sys/types.h>
315331Samw #include <sys/errno.h>
3211963SAfshin.Ardakani@Sun.COM #include <sys/tzfile.h>
3310717Samw@Sun.COM #include <time.h>
345331Samw #include <strings.h>
358334SJose.Borrego@Sun.COM #include <assert.h>
3610717Samw@Sun.COM #include <thread.h>
3711963SAfshin.Ardakani@Sun.COM #include <unistd.h>
3811963SAfshin.Ardakani@Sun.COM #include <syslog.h>
3910717Samw@Sun.COM #include <synch.h>
405331Samw #include <smbsrv/libsmb.h>
415331Samw #include <smbsrv/libsmbrdr.h>
428334SJose.Borrego@Sun.COM #include <smbsrv/libmlrpc.h>
438334SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h>
4411337SWilliam.Krier@Sun.COM #include <smbsrv/ndl/srvsvc.ndl>
4511963SAfshin.Ardakani@Sun.COM #include <mlsvc.h>
465331Samw
4710717Samw@Sun.COM /*
4810717Samw@Sun.COM * Server info cache entry expiration in seconds.
4910717Samw@Sun.COM */
5010717Samw@Sun.COM #define NDR_SVINFO_TIMEOUT 1800
5110717Samw@Sun.COM
5210717Samw@Sun.COM typedef struct ndr_svinfo {
5310717Samw@Sun.COM list_node_t svi_lnd;
5410717Samw@Sun.COM time_t svi_tcached;
5510717Samw@Sun.COM char svi_server[MAXNAMELEN];
5610717Samw@Sun.COM char svi_domain[MAXNAMELEN];
5710717Samw@Sun.COM srvsvc_server_info_t svi_svinfo;
5810717Samw@Sun.COM } ndr_svinfo_t;
5910717Samw@Sun.COM
6010717Samw@Sun.COM typedef struct ndr_svlist {
6110717Samw@Sun.COM list_t svl_list;
6210717Samw@Sun.COM mutex_t svl_mtx;
6310717Samw@Sun.COM boolean_t svl_init;
6410717Samw@Sun.COM } ndr_svlist_t;
6510717Samw@Sun.COM
6610717Samw@Sun.COM static ndr_svlist_t ndr_svlist;
6710717Samw@Sun.COM
688334SJose.Borrego@Sun.COM static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
698334SJose.Borrego@Sun.COM static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
708334SJose.Borrego@Sun.COM static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
718334SJose.Borrego@Sun.COM static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
728334SJose.Borrego@Sun.COM static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
738334SJose.Borrego@Sun.COM static void ndr_xa_release(ndr_client_t *);
745331Samw
7510717Samw@Sun.COM static int ndr_svinfo_lookup(char *, char *, srvsvc_server_info_t *);
7610717Samw@Sun.COM static boolean_t ndr_svinfo_match(const char *, const char *, const
7710717Samw@Sun.COM ndr_svinfo_t *);
7810717Samw@Sun.COM static boolean_t ndr_svinfo_expired(ndr_svinfo_t *);
7910717Samw@Sun.COM
8010717Samw@Sun.COM /*
8110717Samw@Sun.COM * Initialize the RPC client interface: create the server info cache.
8210717Samw@Sun.COM */
8310717Samw@Sun.COM void
ndr_rpc_init(void)8410717Samw@Sun.COM ndr_rpc_init(void)
8510717Samw@Sun.COM {
8610717Samw@Sun.COM (void) mutex_lock(&ndr_svlist.svl_mtx);
8710717Samw@Sun.COM
8810717Samw@Sun.COM if (!ndr_svlist.svl_init) {
8910717Samw@Sun.COM list_create(&ndr_svlist.svl_list, sizeof (ndr_svinfo_t),
9010717Samw@Sun.COM offsetof(ndr_svinfo_t, svi_lnd));
9110717Samw@Sun.COM ndr_svlist.svl_init = B_TRUE;
9210717Samw@Sun.COM }
9310717Samw@Sun.COM
9410717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
9510717Samw@Sun.COM }
9610717Samw@Sun.COM
9710717Samw@Sun.COM /*
9810717Samw@Sun.COM * Terminate the RPC client interface: flush and destroy the server info
9910717Samw@Sun.COM * cache.
10010717Samw@Sun.COM */
10110717Samw@Sun.COM void
ndr_rpc_fini(void)10210717Samw@Sun.COM ndr_rpc_fini(void)
10310717Samw@Sun.COM {
10410717Samw@Sun.COM ndr_svinfo_t *svi;
10510717Samw@Sun.COM
10610717Samw@Sun.COM (void) mutex_lock(&ndr_svlist.svl_mtx);
10710717Samw@Sun.COM
10810717Samw@Sun.COM if (ndr_svlist.svl_init) {
10910717Samw@Sun.COM while ((svi = list_head(&ndr_svlist.svl_list)) != NULL) {
11010717Samw@Sun.COM list_remove(&ndr_svlist.svl_list, svi);
11110717Samw@Sun.COM free(svi->svi_svinfo.sv_name);
11210717Samw@Sun.COM free(svi->svi_svinfo.sv_comment);
11310717Samw@Sun.COM free(svi);
11410717Samw@Sun.COM }
11510717Samw@Sun.COM
11610717Samw@Sun.COM list_destroy(&ndr_svlist.svl_list);
11710717Samw@Sun.COM ndr_svlist.svl_init = B_FALSE;
11810717Samw@Sun.COM }
11910717Samw@Sun.COM
12010717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
12110717Samw@Sun.COM }
12210717Samw@Sun.COM
1235331Samw /*
1248334SJose.Borrego@Sun.COM * This call must be made to initialize an RPC client structure and bind
1258334SJose.Borrego@Sun.COM * to the remote service before any RPCs can be exchanged with that service.
1265331Samw *
1278334SJose.Borrego@Sun.COM * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
1288334SJose.Borrego@Sun.COM * with the client context for an instance of the interface. The handle
1298334SJose.Borrego@Sun.COM * is zeroed to ensure that it doesn't look like a valid handle -
1308334SJose.Borrego@Sun.COM * handle content is provided by the remove service.
1315331Samw *
1328334SJose.Borrego@Sun.COM * The client points to this top-level handle so that we know when to
1338334SJose.Borrego@Sun.COM * unbind and teardown the connection. As each handle is initialized it
1348334SJose.Borrego@Sun.COM * will inherit a reference to the client context.
1355331Samw */
1365331Samw int
ndr_rpc_bind(mlsvc_handle_t * handle,char * server,char * domain,char * username,const char * service)1378334SJose.Borrego@Sun.COM ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
1388334SJose.Borrego@Sun.COM char *username, const char *service)
1395331Samw {
1408334SJose.Borrego@Sun.COM ndr_client_t *clnt;
1418334SJose.Borrego@Sun.COM ndr_service_t *svc;
14210717Samw@Sun.COM srvsvc_server_info_t svinfo;
1438334SJose.Borrego@Sun.COM int fid;
1448334SJose.Borrego@Sun.COM int rc;
1455331Samw
1468334SJose.Borrego@Sun.COM if (handle == NULL || server == NULL ||
1478334SJose.Borrego@Sun.COM domain == NULL || username == NULL)
1485331Samw return (-1);
1495331Samw
1508334SJose.Borrego@Sun.COM if ((svc = ndr_svc_lookup_name(service)) == NULL)
1518334SJose.Borrego@Sun.COM return (-1);
1525331Samw
15310717Samw@Sun.COM /*
15410717Samw@Sun.COM * Set the default based on the assumption that most
15510717Samw@Sun.COM * servers will be Windows 2000 or later.
15610717Samw@Sun.COM * Don't lookup the svinfo if this is a SRVSVC request
15710717Samw@Sun.COM * because the SRVSVC is used to get the server info.
15811337SWilliam.Krier@Sun.COM * None of the SRVSVC calls depend on the server info.
15910717Samw@Sun.COM */
16011337SWilliam.Krier@Sun.COM bzero(&svinfo, sizeof (srvsvc_server_info_t));
16111337SWilliam.Krier@Sun.COM svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
16211337SWilliam.Krier@Sun.COM svinfo.sv_version_major = 5;
16311337SWilliam.Krier@Sun.COM svinfo.sv_version_minor = 0;
16411337SWilliam.Krier@Sun.COM svinfo.sv_type = SV_TYPE_DEFAULT;
16511337SWilliam.Krier@Sun.COM svinfo.sv_os = NATIVE_OS_WIN2000;
16610717Samw@Sun.COM
16711337SWilliam.Krier@Sun.COM if (strcasecmp(service, "SRVSVC") != 0)
16811337SWilliam.Krier@Sun.COM (void) ndr_svinfo_lookup(server, domain, &svinfo);
16910717Samw@Sun.COM
1708334SJose.Borrego@Sun.COM if ((clnt = malloc(sizeof (ndr_client_t))) == NULL)
1718334SJose.Borrego@Sun.COM return (-1);
1725331Samw
1738334SJose.Borrego@Sun.COM fid = smbrdr_open_pipe(server, domain, username, svc->endpoint);
1748334SJose.Borrego@Sun.COM if (fid < 0) {
1758334SJose.Borrego@Sun.COM free(clnt);
1765331Samw return (-1);
1775331Samw }
1785331Samw
1798334SJose.Borrego@Sun.COM bzero(clnt, sizeof (ndr_client_t));
1808334SJose.Borrego@Sun.COM clnt->handle = &handle->handle;
1818334SJose.Borrego@Sun.COM clnt->fid = fid;
1828334SJose.Borrego@Sun.COM
1838334SJose.Borrego@Sun.COM ndr_svc_binding_pool_init(&clnt->binding_list,
1848334SJose.Borrego@Sun.COM clnt->binding_pool, NDR_N_BINDING_POOL);
1858334SJose.Borrego@Sun.COM
1868334SJose.Borrego@Sun.COM clnt->xa_init = ndr_xa_init;
1878334SJose.Borrego@Sun.COM clnt->xa_exchange = ndr_xa_exchange;
1888334SJose.Borrego@Sun.COM clnt->xa_read = ndr_xa_read;
1898334SJose.Borrego@Sun.COM clnt->xa_preserve = ndr_xa_preserve;
1908334SJose.Borrego@Sun.COM clnt->xa_destruct = ndr_xa_destruct;
1918334SJose.Borrego@Sun.COM clnt->xa_release = ndr_xa_release;
1925331Samw
1938334SJose.Borrego@Sun.COM bzero(&handle->handle, sizeof (ndr_hdid_t));
1948334SJose.Borrego@Sun.COM handle->clnt = clnt;
19511337SWilliam.Krier@Sun.COM bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
1965331Samw
1978334SJose.Borrego@Sun.COM if (ndr_rpc_get_heap(handle) == NULL) {
1988334SJose.Borrego@Sun.COM free(clnt);
1995331Samw return (-1);
2008334SJose.Borrego@Sun.COM }
2018334SJose.Borrego@Sun.COM
2028334SJose.Borrego@Sun.COM rc = ndr_clnt_bind(clnt, service, &clnt->binding);
2038334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) {
2048334SJose.Borrego@Sun.COM (void) smbrdr_close_pipe(fid);
2058334SJose.Borrego@Sun.COM ndr_heap_destroy(clnt->heap);
2068334SJose.Borrego@Sun.COM free(clnt);
2078334SJose.Borrego@Sun.COM handle->clnt = NULL;
2088334SJose.Borrego@Sun.COM return (-1);
2098334SJose.Borrego@Sun.COM }
2105331Samw
2115331Samw return (0);
2125331Samw }
2135331Samw
2145331Samw /*
2158334SJose.Borrego@Sun.COM * Unbind and close the pipe to an RPC service.
2168334SJose.Borrego@Sun.COM *
2178334SJose.Borrego@Sun.COM * If the heap has been preserved we need to go through an xa release.
2188334SJose.Borrego@Sun.COM * The heap is preserved during an RPC call because that's where data
2198334SJose.Borrego@Sun.COM * returned from the server is stored.
2205331Samw *
2218334SJose.Borrego@Sun.COM * Otherwise we destroy the heap directly.
2228334SJose.Borrego@Sun.COM */
2238334SJose.Borrego@Sun.COM void
ndr_rpc_unbind(mlsvc_handle_t * handle)2248334SJose.Borrego@Sun.COM ndr_rpc_unbind(mlsvc_handle_t *handle)
2258334SJose.Borrego@Sun.COM {
2268334SJose.Borrego@Sun.COM ndr_client_t *clnt = handle->clnt;
2278334SJose.Borrego@Sun.COM
2288334SJose.Borrego@Sun.COM if (clnt->heap_preserved)
2298334SJose.Borrego@Sun.COM ndr_clnt_free_heap(clnt);
2308334SJose.Borrego@Sun.COM else
2318334SJose.Borrego@Sun.COM ndr_heap_destroy(clnt->heap);
2328334SJose.Borrego@Sun.COM
2338334SJose.Borrego@Sun.COM (void) smbrdr_close_pipe(clnt->fid);
2348334SJose.Borrego@Sun.COM free(handle->clnt);
2358334SJose.Borrego@Sun.COM bzero(handle, sizeof (mlsvc_handle_t));
2368334SJose.Borrego@Sun.COM }
2378334SJose.Borrego@Sun.COM
2388334SJose.Borrego@Sun.COM /*
2398334SJose.Borrego@Sun.COM * Call the RPC function identified by opnum. The remote service is
2408334SJose.Borrego@Sun.COM * identified by the handle, which should have been initialized by
2418334SJose.Borrego@Sun.COM * ndr_rpc_bind.
2428334SJose.Borrego@Sun.COM *
2438334SJose.Borrego@Sun.COM * If the RPC call is successful (returns 0), the caller must call
2448334SJose.Borrego@Sun.COM * ndr_rpc_release to release the heap. Otherwise, we release the
2458334SJose.Borrego@Sun.COM * heap here.
2465331Samw */
2475331Samw int
ndr_rpc_call(mlsvc_handle_t * handle,int opnum,void * params)2488334SJose.Borrego@Sun.COM ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
2498334SJose.Borrego@Sun.COM {
2508334SJose.Borrego@Sun.COM ndr_client_t *clnt = handle->clnt;
2518334SJose.Borrego@Sun.COM int rc;
2528334SJose.Borrego@Sun.COM
2538334SJose.Borrego@Sun.COM if (ndr_rpc_get_heap(handle) == NULL)
2548334SJose.Borrego@Sun.COM return (-1);
2558334SJose.Borrego@Sun.COM
2568334SJose.Borrego@Sun.COM rc = ndr_clnt_call(clnt->binding, opnum, params);
2578334SJose.Borrego@Sun.COM
25811337SWilliam.Krier@Sun.COM /*
25911337SWilliam.Krier@Sun.COM * Always clear the nonull flag to ensure
26011337SWilliam.Krier@Sun.COM * it is not applied to subsequent calls.
26111337SWilliam.Krier@Sun.COM */
26211337SWilliam.Krier@Sun.COM clnt->nonull = B_FALSE;
26311337SWilliam.Krier@Sun.COM
2648334SJose.Borrego@Sun.COM if (NDR_DRC_IS_FAULT(rc)) {
2658334SJose.Borrego@Sun.COM ndr_rpc_release(handle);
2668334SJose.Borrego@Sun.COM return (-1);
2678334SJose.Borrego@Sun.COM }
2688334SJose.Borrego@Sun.COM
2698334SJose.Borrego@Sun.COM return (0);
2708334SJose.Borrego@Sun.COM }
2718334SJose.Borrego@Sun.COM
2728334SJose.Borrego@Sun.COM /*
27311337SWilliam.Krier@Sun.COM * Outgoing strings should not be null terminated.
27411337SWilliam.Krier@Sun.COM */
27511337SWilliam.Krier@Sun.COM void
ndr_rpc_set_nonull(mlsvc_handle_t * handle)27611337SWilliam.Krier@Sun.COM ndr_rpc_set_nonull(mlsvc_handle_t *handle)
27711337SWilliam.Krier@Sun.COM {
27811337SWilliam.Krier@Sun.COM handle->clnt->nonull = B_TRUE;
27911337SWilliam.Krier@Sun.COM }
28011337SWilliam.Krier@Sun.COM
28111337SWilliam.Krier@Sun.COM /*
28211337SWilliam.Krier@Sun.COM * Return a reference to the server info.
28311337SWilliam.Krier@Sun.COM */
28411337SWilliam.Krier@Sun.COM const srvsvc_server_info_t *
ndr_rpc_server_info(mlsvc_handle_t * handle)28511337SWilliam.Krier@Sun.COM ndr_rpc_server_info(mlsvc_handle_t *handle)
28611337SWilliam.Krier@Sun.COM {
28711337SWilliam.Krier@Sun.COM return (&handle->svinfo);
28811337SWilliam.Krier@Sun.COM }
28911337SWilliam.Krier@Sun.COM
29011337SWilliam.Krier@Sun.COM /*
29111337SWilliam.Krier@Sun.COM * Return the RPC server OS level.
2928334SJose.Borrego@Sun.COM */
29310717Samw@Sun.COM uint32_t
ndr_rpc_server_os(mlsvc_handle_t * handle)2948334SJose.Borrego@Sun.COM ndr_rpc_server_os(mlsvc_handle_t *handle)
2955331Samw {
29611337SWilliam.Krier@Sun.COM return (handle->svinfo.sv_os);
2978334SJose.Borrego@Sun.COM }
2988334SJose.Borrego@Sun.COM
29910504SKeyur.Desai@Sun.COM /*
30010504SKeyur.Desai@Sun.COM * Get the session key from a bound RPC client handle.
30110504SKeyur.Desai@Sun.COM *
30210504SKeyur.Desai@Sun.COM * The key returned is the 16-byte "user session key"
30310504SKeyur.Desai@Sun.COM * established by the underlying authentication protocol
30410504SKeyur.Desai@Sun.COM * (either Kerberos or NTLM). This key is needed for
30510504SKeyur.Desai@Sun.COM * SAM RPC calls such as SamrSetInformationUser, etc.
30610504SKeyur.Desai@Sun.COM * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
30710504SKeyur.Desai@Sun.COM *
30810504SKeyur.Desai@Sun.COM * Returns zero (success) or an errno.
30910504SKeyur.Desai@Sun.COM */
31010504SKeyur.Desai@Sun.COM int
ndr_rpc_get_ssnkey(mlsvc_handle_t * handle,unsigned char * ssn_key,size_t len)31110504SKeyur.Desai@Sun.COM ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
31210504SKeyur.Desai@Sun.COM unsigned char *ssn_key, size_t len)
31310504SKeyur.Desai@Sun.COM {
31410504SKeyur.Desai@Sun.COM ndr_client_t *clnt = handle->clnt;
31510504SKeyur.Desai@Sun.COM int rc;
31610504SKeyur.Desai@Sun.COM
31710504SKeyur.Desai@Sun.COM if (clnt == NULL)
31810504SKeyur.Desai@Sun.COM return (EINVAL);
31910504SKeyur.Desai@Sun.COM
32010504SKeyur.Desai@Sun.COM rc = smbrdr_get_ssnkey(clnt->fid, ssn_key, len);
32110504SKeyur.Desai@Sun.COM return (rc);
32210504SKeyur.Desai@Sun.COM }
32310504SKeyur.Desai@Sun.COM
3248334SJose.Borrego@Sun.COM void *
ndr_rpc_malloc(mlsvc_handle_t * handle,size_t size)3258334SJose.Borrego@Sun.COM ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
3268334SJose.Borrego@Sun.COM {
3278334SJose.Borrego@Sun.COM ndr_heap_t *heap;
3288334SJose.Borrego@Sun.COM
3298334SJose.Borrego@Sun.COM if ((heap = ndr_rpc_get_heap(handle)) == NULL)
3308334SJose.Borrego@Sun.COM return (NULL);
3318334SJose.Borrego@Sun.COM
3328334SJose.Borrego@Sun.COM return (ndr_heap_malloc(heap, size));
3338334SJose.Borrego@Sun.COM }
3348334SJose.Borrego@Sun.COM
3358334SJose.Borrego@Sun.COM ndr_heap_t *
ndr_rpc_get_heap(mlsvc_handle_t * handle)3368334SJose.Borrego@Sun.COM ndr_rpc_get_heap(mlsvc_handle_t *handle)
3378334SJose.Borrego@Sun.COM {
3388334SJose.Borrego@Sun.COM ndr_client_t *clnt = handle->clnt;
3398334SJose.Borrego@Sun.COM
3408334SJose.Borrego@Sun.COM if (clnt->heap == NULL)
3418334SJose.Borrego@Sun.COM clnt->heap = ndr_heap_create();
3428334SJose.Borrego@Sun.COM
3438334SJose.Borrego@Sun.COM return (clnt->heap);
3445331Samw }
3455331Samw
3465331Samw /*
3478334SJose.Borrego@Sun.COM * Must be called by RPC clients to free the heap after a successful RPC
3488334SJose.Borrego@Sun.COM * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
3498334SJose.Borrego@Sun.COM * of any data returned by the RPC prior to calling this function because
3508334SJose.Borrego@Sun.COM * returned data is in the heap.
3515331Samw */
3525331Samw void
ndr_rpc_release(mlsvc_handle_t * handle)3538334SJose.Borrego@Sun.COM ndr_rpc_release(mlsvc_handle_t *handle)
3548334SJose.Borrego@Sun.COM {
3558334SJose.Borrego@Sun.COM ndr_client_t *clnt = handle->clnt;
3568334SJose.Borrego@Sun.COM
3578334SJose.Borrego@Sun.COM if (clnt->heap_preserved)
3588334SJose.Borrego@Sun.COM ndr_clnt_free_heap(clnt);
3598334SJose.Borrego@Sun.COM else
3608334SJose.Borrego@Sun.COM ndr_heap_destroy(clnt->heap);
3618334SJose.Borrego@Sun.COM
3628334SJose.Borrego@Sun.COM clnt->heap = NULL;
3638334SJose.Borrego@Sun.COM }
3648334SJose.Borrego@Sun.COM
3658334SJose.Borrego@Sun.COM /*
3668334SJose.Borrego@Sun.COM * Returns true if the handle is null.
3678334SJose.Borrego@Sun.COM * Otherwise returns false.
3688334SJose.Borrego@Sun.COM */
3698334SJose.Borrego@Sun.COM boolean_t
ndr_is_null_handle(mlsvc_handle_t * handle)3708334SJose.Borrego@Sun.COM ndr_is_null_handle(mlsvc_handle_t *handle)
3715331Samw {
3728334SJose.Borrego@Sun.COM static ndr_hdid_t zero_handle;
3738334SJose.Borrego@Sun.COM
3748334SJose.Borrego@Sun.COM if (handle == NULL || handle->clnt == NULL)
3758334SJose.Borrego@Sun.COM return (B_TRUE);
3768334SJose.Borrego@Sun.COM
3778334SJose.Borrego@Sun.COM if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
3788334SJose.Borrego@Sun.COM return (B_TRUE);
3798334SJose.Borrego@Sun.COM
3808334SJose.Borrego@Sun.COM return (B_FALSE);
3818334SJose.Borrego@Sun.COM }
3828334SJose.Borrego@Sun.COM
3838334SJose.Borrego@Sun.COM /*
3848334SJose.Borrego@Sun.COM * Returns true if the handle is the top level bind handle.
3858334SJose.Borrego@Sun.COM * Otherwise returns false.
3868334SJose.Borrego@Sun.COM */
3878334SJose.Borrego@Sun.COM boolean_t
ndr_is_bind_handle(mlsvc_handle_t * handle)3888334SJose.Borrego@Sun.COM ndr_is_bind_handle(mlsvc_handle_t *handle)
3898334SJose.Borrego@Sun.COM {
3908334SJose.Borrego@Sun.COM return (handle->clnt->handle == &handle->handle);
3915331Samw }
3925331Samw
3935331Samw /*
3948334SJose.Borrego@Sun.COM * Pass the client reference from parent to child.
3955331Samw */
3968334SJose.Borrego@Sun.COM void
ndr_inherit_handle(mlsvc_handle_t * child,mlsvc_handle_t * parent)3978334SJose.Borrego@Sun.COM ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
3988334SJose.Borrego@Sun.COM {
3998334SJose.Borrego@Sun.COM child->clnt = parent->clnt;
40011337SWilliam.Krier@Sun.COM bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
4018334SJose.Borrego@Sun.COM }
4028334SJose.Borrego@Sun.COM
4038334SJose.Borrego@Sun.COM void
ndr_rpc_status(mlsvc_handle_t * handle,int opnum,DWORD status)4048334SJose.Borrego@Sun.COM ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
4055331Samw {
4068334SJose.Borrego@Sun.COM ndr_service_t *svc;
4078334SJose.Borrego@Sun.COM char *name = "NDR RPC";
4088334SJose.Borrego@Sun.COM char *s = "unknown";
4098334SJose.Borrego@Sun.COM
410*12508Samw@Sun.COM switch (NT_SC_SEVERITY(status)) {
411*12508Samw@Sun.COM case NT_STATUS_SEVERITY_SUCCESS:
4128334SJose.Borrego@Sun.COM s = "success";
413*12508Samw@Sun.COM break;
414*12508Samw@Sun.COM case NT_STATUS_SEVERITY_INFORMATIONAL:
415*12508Samw@Sun.COM s = "info";
416*12508Samw@Sun.COM break;
417*12508Samw@Sun.COM case NT_STATUS_SEVERITY_WARNING:
418*12508Samw@Sun.COM s = "warning";
419*12508Samw@Sun.COM break;
420*12508Samw@Sun.COM case NT_STATUS_SEVERITY_ERROR:
4218334SJose.Borrego@Sun.COM s = "error";
422*12508Samw@Sun.COM break;
423*12508Samw@Sun.COM }
4248334SJose.Borrego@Sun.COM
4258334SJose.Borrego@Sun.COM if (handle) {
4268334SJose.Borrego@Sun.COM svc = handle->clnt->binding->service;
4278334SJose.Borrego@Sun.COM name = svc->name;
4288334SJose.Borrego@Sun.COM }
4295331Samw
4308334SJose.Borrego@Sun.COM smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
4318334SJose.Borrego@Sun.COM name, opnum, s, xlate_nt_status(status), status);
4328334SJose.Borrego@Sun.COM }
4338334SJose.Borrego@Sun.COM
4348334SJose.Borrego@Sun.COM /*
4358334SJose.Borrego@Sun.COM * The following functions provide the client callback interface.
4368334SJose.Borrego@Sun.COM * If the caller hasn't provided a heap, create one here.
4378334SJose.Borrego@Sun.COM */
4388334SJose.Borrego@Sun.COM static int
ndr_xa_init(ndr_client_t * clnt,ndr_xa_t * mxa)4398334SJose.Borrego@Sun.COM ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
4408334SJose.Borrego@Sun.COM {
44111337SWilliam.Krier@Sun.COM ndr_stream_t *recv_nds = &mxa->recv_nds;
44211337SWilliam.Krier@Sun.COM ndr_stream_t *send_nds = &mxa->send_nds;
44311337SWilliam.Krier@Sun.COM ndr_heap_t *heap = clnt->heap;
44411337SWilliam.Krier@Sun.COM int rc;
4458334SJose.Borrego@Sun.COM
4468334SJose.Borrego@Sun.COM if (heap == NULL) {
4478334SJose.Borrego@Sun.COM if ((heap = ndr_heap_create()) == NULL)
4485331Samw return (-1);
4498334SJose.Borrego@Sun.COM
4508334SJose.Borrego@Sun.COM clnt->heap = heap;
4515331Samw }
4525331Samw
4535331Samw mxa->heap = heap;
4545331Samw
45511337SWilliam.Krier@Sun.COM rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
45611337SWilliam.Krier@Sun.COM if (rc == 0)
45711337SWilliam.Krier@Sun.COM rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
45811337SWilliam.Krier@Sun.COM NDR_MODE_RETURN_RECV, heap);
45911337SWilliam.Krier@Sun.COM
46011337SWilliam.Krier@Sun.COM if (rc != 0) {
46111337SWilliam.Krier@Sun.COM nds_destruct(&mxa->recv_nds);
46211337SWilliam.Krier@Sun.COM nds_destruct(&mxa->send_nds);
46311337SWilliam.Krier@Sun.COM ndr_heap_destroy(mxa->heap);
46411337SWilliam.Krier@Sun.COM mxa->heap = NULL;
46511337SWilliam.Krier@Sun.COM clnt->heap = NULL;
46611337SWilliam.Krier@Sun.COM return (-1);
46711337SWilliam.Krier@Sun.COM }
46811337SWilliam.Krier@Sun.COM
46911337SWilliam.Krier@Sun.COM if (clnt->nonull)
47011337SWilliam.Krier@Sun.COM NDS_SETF(send_nds, NDS_F_NONULL);
47111337SWilliam.Krier@Sun.COM
4725331Samw return (0);
4735331Samw }
4745331Samw
4755331Samw /*
4765331Samw * This is the entry pointy for an RPC client call exchange with
4775331Samw * a server, which will result in an smbrdr SmbTransact request.
4785331Samw *
4795331Samw * SmbTransact should return the number of bytes received, which
4805331Samw * we record as the PDU size, or a negative error code.
4815331Samw */
4825331Samw static int
ndr_xa_exchange(ndr_client_t * clnt,ndr_xa_t * mxa)4838334SJose.Borrego@Sun.COM ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
4845331Samw {
4858334SJose.Borrego@Sun.COM ndr_stream_t *recv_nds = &mxa->recv_nds;
4868334SJose.Borrego@Sun.COM ndr_stream_t *send_nds = &mxa->send_nds;
4878334SJose.Borrego@Sun.COM int nbytes;
4885331Samw
4898334SJose.Borrego@Sun.COM nbytes = smbrdr_transact(clnt->fid,
4908334SJose.Borrego@Sun.COM (char *)send_nds->pdu_base_offset, send_nds->pdu_size,
4918334SJose.Borrego@Sun.COM (char *)recv_nds->pdu_base_offset, recv_nds->pdu_max_size);
4925331Samw
4938334SJose.Borrego@Sun.COM if (nbytes < 0) {
4948334SJose.Borrego@Sun.COM recv_nds->pdu_size = 0;
4958334SJose.Borrego@Sun.COM return (-1);
4968334SJose.Borrego@Sun.COM }
4975331Samw
4988334SJose.Borrego@Sun.COM recv_nds->pdu_size = nbytes;
4998334SJose.Borrego@Sun.COM return (nbytes);
5005331Samw }
5015331Samw
5025331Samw /*
5035331Samw * This entry point will be invoked if the xa-exchange response contained
5045331Samw * only the first fragment of a multi-fragment response. The RPC client
5055331Samw * code will then make repeated xa-read requests to obtain the remaining
5065331Samw * fragments, which will result in smbrdr SmbReadX requests.
5075331Samw *
5085331Samw * SmbReadX should return the number of bytes received, in which case we
5095331Samw * expand the PDU size to include the received data, or a negative error
5105331Samw * code.
5115331Samw */
5125331Samw static int
ndr_xa_read(ndr_client_t * clnt,ndr_xa_t * mxa)5138334SJose.Borrego@Sun.COM ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
5145331Samw {
5158334SJose.Borrego@Sun.COM ndr_stream_t *nds = &mxa->recv_nds;
5165331Samw int len;
5178334SJose.Borrego@Sun.COM int nbytes;
5185331Samw
5198334SJose.Borrego@Sun.COM if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
5205331Samw return (-1);
5215331Samw
5228334SJose.Borrego@Sun.COM nbytes = smbrdr_readx(clnt->fid,
5238334SJose.Borrego@Sun.COM (char *)nds->pdu_base_offset + nds->pdu_size, len);
5245331Samw
5258334SJose.Borrego@Sun.COM if (nbytes < 0)
5265331Samw return (-1);
5275331Samw
5288334SJose.Borrego@Sun.COM nds->pdu_size += nbytes;
5295331Samw
5308334SJose.Borrego@Sun.COM if (nds->pdu_size > nds->pdu_max_size) {
5318334SJose.Borrego@Sun.COM nds->pdu_size = nds->pdu_max_size;
5325331Samw return (-1);
5335331Samw }
5345331Samw
5358334SJose.Borrego@Sun.COM return (nbytes);
5365331Samw }
5375331Samw
5385331Samw /*
5398334SJose.Borrego@Sun.COM * Preserve the heap so that the client application has access to data
5408334SJose.Borrego@Sun.COM * returned from the server after an RPC call.
5415331Samw */
5428334SJose.Borrego@Sun.COM static void
ndr_xa_preserve(ndr_client_t * clnt,ndr_xa_t * mxa)5438334SJose.Borrego@Sun.COM ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
5445331Samw {
5458334SJose.Borrego@Sun.COM assert(clnt->heap == mxa->heap);
5465331Samw
5478334SJose.Borrego@Sun.COM clnt->heap_preserved = B_TRUE;
5485331Samw mxa->heap = NULL;
5495331Samw }
5505331Samw
5515331Samw /*
5528334SJose.Borrego@Sun.COM * Dispose of the transaction streams. If the heap has not been
5538334SJose.Borrego@Sun.COM * preserved, we can destroy it here.
5545331Samw */
5558334SJose.Borrego@Sun.COM static void
ndr_xa_destruct(ndr_client_t * clnt,ndr_xa_t * mxa)5568334SJose.Borrego@Sun.COM ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
5575331Samw {
5588334SJose.Borrego@Sun.COM nds_destruct(&mxa->recv_nds);
5598334SJose.Borrego@Sun.COM nds_destruct(&mxa->send_nds);
5608334SJose.Borrego@Sun.COM
5618334SJose.Borrego@Sun.COM if (!clnt->heap_preserved) {
5628334SJose.Borrego@Sun.COM ndr_heap_destroy(mxa->heap);
5638334SJose.Borrego@Sun.COM mxa->heap = NULL;
5648334SJose.Borrego@Sun.COM clnt->heap = NULL;
5655331Samw }
5665331Samw }
5675331Samw
5685331Samw /*
5698334SJose.Borrego@Sun.COM * Dispose of a preserved heap.
5705331Samw */
5715331Samw static void
ndr_xa_release(ndr_client_t * clnt)5728334SJose.Borrego@Sun.COM ndr_xa_release(ndr_client_t *clnt)
5735331Samw {
5748334SJose.Borrego@Sun.COM if (clnt->heap_preserved) {
5758334SJose.Borrego@Sun.COM ndr_heap_destroy(clnt->heap);
5768334SJose.Borrego@Sun.COM clnt->heap = NULL;
5778334SJose.Borrego@Sun.COM clnt->heap_preserved = B_FALSE;
5785331Samw }
5795331Samw }
58010717Samw@Sun.COM
58110717Samw@Sun.COM /*
58210717Samw@Sun.COM * Lookup platform, type and version information about a server.
58310717Samw@Sun.COM * If the cache doesn't already contain the data, contact the server and
58410717Samw@Sun.COM * cache the response before returning the server info to the caller.
58511337SWilliam.Krier@Sun.COM *
58611337SWilliam.Krier@Sun.COM * We don't provide the name or comment for now, which avoids the need
58711337SWilliam.Krier@Sun.COM * to deal with unnecessary memory management.
58810717Samw@Sun.COM */
58910717Samw@Sun.COM static int
ndr_svinfo_lookup(char * server,char * domain,srvsvc_server_info_t * svinfo)59010717Samw@Sun.COM ndr_svinfo_lookup(char *server, char *domain, srvsvc_server_info_t *svinfo)
59110717Samw@Sun.COM {
59211963SAfshin.Ardakani@Sun.COM static boolean_t timechecked = B_FALSE;
59310717Samw@Sun.COM ndr_svinfo_t *svi;
59410717Samw@Sun.COM
59510717Samw@Sun.COM (void) mutex_lock(&ndr_svlist.svl_mtx);
59611963SAfshin.Ardakani@Sun.COM if (!ndr_svlist.svl_init)
59711963SAfshin.Ardakani@Sun.COM return (-1);
59810717Samw@Sun.COM
59910717Samw@Sun.COM svi = list_head(&ndr_svlist.svl_list);
60010717Samw@Sun.COM while (svi != NULL) {
60110717Samw@Sun.COM if (ndr_svinfo_expired(svi)) {
60210717Samw@Sun.COM svi = list_head(&ndr_svlist.svl_list);
60310717Samw@Sun.COM continue;
60410717Samw@Sun.COM }
60510717Samw@Sun.COM
60610717Samw@Sun.COM if (ndr_svinfo_match(server, domain, svi)) {
60710717Samw@Sun.COM bcopy(&svi->svi_svinfo, svinfo,
60810717Samw@Sun.COM sizeof (srvsvc_server_info_t));
60911337SWilliam.Krier@Sun.COM svinfo->sv_name = NULL;
61011337SWilliam.Krier@Sun.COM svinfo->sv_comment = NULL;
61110717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
61210717Samw@Sun.COM return (0);
61310717Samw@Sun.COM }
61410717Samw@Sun.COM
61510717Samw@Sun.COM svi = list_next(&ndr_svlist.svl_list, svi);
61610717Samw@Sun.COM }
61710717Samw@Sun.COM
61810717Samw@Sun.COM if ((svi = malloc(sizeof (ndr_svinfo_t))) == NULL) {
61910717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
62010717Samw@Sun.COM return (-1);
62110717Samw@Sun.COM }
62210717Samw@Sun.COM
62310717Samw@Sun.COM if (srvsvc_net_server_getinfo(server, domain, &svi->svi_svinfo) < 0) {
62410717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
62510717Samw@Sun.COM free(svi);
62610717Samw@Sun.COM return (-1);
62710717Samw@Sun.COM }
62810717Samw@Sun.COM
62910717Samw@Sun.COM (void) time(&svi->svi_tcached);
63010717Samw@Sun.COM (void) strlcpy(svi->svi_server, server, MAXNAMELEN);
63110717Samw@Sun.COM (void) strlcpy(svi->svi_domain, domain, MAXNAMELEN);
63210717Samw@Sun.COM list_insert_tail(&ndr_svlist.svl_list, svi);
63310717Samw@Sun.COM bcopy(&svi->svi_svinfo, svinfo, sizeof (srvsvc_server_info_t));
63411337SWilliam.Krier@Sun.COM svinfo->sv_name = NULL;
63511337SWilliam.Krier@Sun.COM svinfo->sv_comment = NULL;
63611963SAfshin.Ardakani@Sun.COM
63711963SAfshin.Ardakani@Sun.COM if (!timechecked) {
63811963SAfshin.Ardakani@Sun.COM timechecked = B_TRUE;
63911963SAfshin.Ardakani@Sun.COM ndr_srvsvc_timecheck(server, domain);
64011963SAfshin.Ardakani@Sun.COM }
64111963SAfshin.Ardakani@Sun.COM
64210717Samw@Sun.COM (void) mutex_unlock(&ndr_svlist.svl_mtx);
64310717Samw@Sun.COM return (0);
64410717Samw@Sun.COM }
64510717Samw@Sun.COM
64610717Samw@Sun.COM static boolean_t
ndr_svinfo_match(const char * server,const char * domain,const ndr_svinfo_t * svi)64710717Samw@Sun.COM ndr_svinfo_match(const char *server, const char *domain,
64810717Samw@Sun.COM const ndr_svinfo_t *svi)
64910717Samw@Sun.COM {
65010966SJordan.Brown@Sun.COM if ((smb_strcasecmp(server, svi->svi_server, 0) == 0) &&
65110966SJordan.Brown@Sun.COM (smb_strcasecmp(domain, svi->svi_domain, 0) == 0)) {
65210717Samw@Sun.COM return (B_TRUE);
65310717Samw@Sun.COM }
65410717Samw@Sun.COM
65510717Samw@Sun.COM return (B_FALSE);
65610717Samw@Sun.COM }
65710717Samw@Sun.COM
65810717Samw@Sun.COM /*
65910717Samw@Sun.COM * If the server info in the cache has expired, discard it and return true.
66010717Samw@Sun.COM * Otherwise return false.
66110717Samw@Sun.COM *
66210717Samw@Sun.COM * This is a private function to support ndr_svinfo_lookup() that assumes
66310717Samw@Sun.COM * the list mutex is held.
66410717Samw@Sun.COM */
66510717Samw@Sun.COM static boolean_t
ndr_svinfo_expired(ndr_svinfo_t * svi)66610717Samw@Sun.COM ndr_svinfo_expired(ndr_svinfo_t *svi)
66710717Samw@Sun.COM {
66810717Samw@Sun.COM time_t tnow;
66910717Samw@Sun.COM
67010717Samw@Sun.COM (void) time(&tnow);
67110717Samw@Sun.COM
67210717Samw@Sun.COM if (difftime(tnow, svi->svi_tcached) > NDR_SVINFO_TIMEOUT) {
67310717Samw@Sun.COM list_remove(&ndr_svlist.svl_list, svi);
67410717Samw@Sun.COM free(svi->svi_svinfo.sv_name);
67510717Samw@Sun.COM free(svi->svi_svinfo.sv_comment);
67610717Samw@Sun.COM free(svi);
67710717Samw@Sun.COM return (B_TRUE);
67810717Samw@Sun.COM }
67910717Samw@Sun.COM
68010717Samw@Sun.COM return (B_FALSE);
68110717Samw@Sun.COM }
68211963SAfshin.Ardakani@Sun.COM
68311963SAfshin.Ardakani@Sun.COM /*
68411963SAfshin.Ardakani@Sun.COM * Compare the time here with the remote time on the server
68511963SAfshin.Ardakani@Sun.COM * and report clock skew.
68611963SAfshin.Ardakani@Sun.COM */
68711963SAfshin.Ardakani@Sun.COM void
ndr_srvsvc_timecheck(char * server,char * domain)68811963SAfshin.Ardakani@Sun.COM ndr_srvsvc_timecheck(char *server, char *domain)
68911963SAfshin.Ardakani@Sun.COM {
69011963SAfshin.Ardakani@Sun.COM char hostname[MAXHOSTNAMELEN];
69111963SAfshin.Ardakani@Sun.COM struct timeval dc_tv;
69211963SAfshin.Ardakani@Sun.COM struct tm dc_tm;
69311963SAfshin.Ardakani@Sun.COM struct tm *tm;
69411963SAfshin.Ardakani@Sun.COM time_t tnow;
69511963SAfshin.Ardakani@Sun.COM time_t tdiff;
69611963SAfshin.Ardakani@Sun.COM int priority;
69711963SAfshin.Ardakani@Sun.COM
69811963SAfshin.Ardakani@Sun.COM if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) {
69911963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed");
70011963SAfshin.Ardakani@Sun.COM return;
70111963SAfshin.Ardakani@Sun.COM }
70211963SAfshin.Ardakani@Sun.COM
70311963SAfshin.Ardakani@Sun.COM tnow = time(NULL);
70411963SAfshin.Ardakani@Sun.COM
70511963SAfshin.Ardakani@Sun.COM if (tnow > dc_tv.tv_sec)
70611963SAfshin.Ardakani@Sun.COM tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN;
70711963SAfshin.Ardakani@Sun.COM else
70811963SAfshin.Ardakani@Sun.COM tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN;
70911963SAfshin.Ardakani@Sun.COM
71011963SAfshin.Ardakani@Sun.COM if (tdiff != 0) {
71111963SAfshin.Ardakani@Sun.COM (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN);
71211963SAfshin.Ardakani@Sun.COM (void) gethostname(hostname, MAXHOSTNAMELEN);
71311963SAfshin.Ardakani@Sun.COM
71411963SAfshin.Ardakani@Sun.COM priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG;
71511963SAfshin.Ardakani@Sun.COM syslog(priority, "DC [%s] clock skew detected: %u minutes",
71611963SAfshin.Ardakani@Sun.COM server, tdiff);
71711963SAfshin.Ardakani@Sun.COM
71811963SAfshin.Ardakani@Sun.COM tm = gmtime(&dc_tv.tv_sec);
71911963SAfshin.Ardakani@Sun.COM syslog(priority, "%-8s UTC: %s", server, asctime(tm));
72011963SAfshin.Ardakani@Sun.COM tm = gmtime(&tnow);
72111963SAfshin.Ardakani@Sun.COM syslog(priority, "%-8s UTC: %s", hostname, asctime(tm));
72211963SAfshin.Ardakani@Sun.COM }
72311963SAfshin.Ardakani@Sun.COM }
724