4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Client NDR RPC interface.
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/fcntl.h>
34 #include <sys/tzfile.h>
44 #include <netsmb/smbfs_api.h>
45 #include <smbsrv/libsmb.h>
46 #include <smbsrv/libsmbns.h>
47 #include <smbsrv/libmlrpc.h>
48 #include <smbsrv/libmlsvc.h>
49 #include <smbsrv/ndl/srvsvc.ndl>
50 #include <libsmbrdr.h>
53 static int ndr_xa_init(ndr_client_t
*, ndr_xa_t
*);
54 static int ndr_xa_exchange(ndr_client_t
*, ndr_xa_t
*);
55 static int ndr_xa_read(ndr_client_t
*, ndr_xa_t
*);
56 static void ndr_xa_preserve(ndr_client_t
*, ndr_xa_t
*);
57 static void ndr_xa_destruct(ndr_client_t
*, ndr_xa_t
*);
58 static void ndr_xa_release(ndr_client_t
*);
62 * This call must be made to initialize an RPC client structure and bind
63 * to the remote service before any RPCs can be exchanged with that service.
65 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
66 * with the client context for an instance of the interface. The handle
67 * is zeroed to ensure that it doesn't look like a valid handle -
68 * handle content is provided by the remove service.
70 * The client points to this top-level handle so that we know when to
71 * unbind and teardown the connection. As each handle is initialized it
72 * will inherit a reference to the client context.
74 * Returns 0 or an NT_STATUS:
75 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
76 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
77 * NT_STATUS_BAD_NETWORK_NAME (tcon, open)
78 * NT_STATUS_ACCESS_DENIED (open pipe)
79 * NT_STATUS_INVALID_PARAMETER (rpc bind)
81 * NT_STATUS_INTERNAL_ERROR (bad args etc)
85 ndr_rpc_bind(mlsvc_handle_t
*handle
, char *server
, char *domain
,
86 char *username
, const char *service
)
88 struct smb_ctx
*ctx
= NULL
;
89 ndr_client_t
*clnt
= NULL
;
91 srvsvc_server_info_t svinfo
;
96 if (handle
== NULL
|| server
== NULL
|| server
[0] == '\0' ||
97 domain
== NULL
|| username
== NULL
)
98 return (NT_STATUS_INTERNAL_ERROR
);
100 /* In case the service was not registered... */
101 if ((svc
= ndr_svc_lookup_name(service
)) == NULL
)
102 return (NT_STATUS_INTERNAL_ERROR
);
105 * Set the default based on the assumption that most
106 * servers will be Windows 2000 or later. This used to
107 * try to get the actual server version, but that RPC
108 * is not necessarily allowed anymore, so don't bother.
110 bzero(&svinfo
, sizeof (srvsvc_server_info_t
));
111 svinfo
.sv_platform_id
= SV_PLATFORM_ID_NT
;
112 svinfo
.sv_version_major
= 5;
113 svinfo
.sv_version_minor
= 0;
114 svinfo
.sv_type
= SV_TYPE_DEFAULT
;
115 svinfo
.sv_os
= NATIVE_OS_WIN2000
;
118 * Some callers pass this when they want a NULL session.
119 * Todo: have callers pass an empty string for that.
121 if (strcmp(username
, MLSVC_ANON_USER
) == 0)
125 * Setup smbfs library handle, authenticate, connect to
126 * the IPC$ share. This will reuse an existing connection
127 * if the driver already has one for this combination of
128 * server, user, domain. It may return any of:
129 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
130 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
131 * NT_STATUS_BAD_NETWORK_NAME (tcon)
133 status
= smbrdr_ctx_new(&ctx
, server
, domain
, username
);
134 if (status
!= NT_STATUS_SUCCESS
) {
135 syslog(LOG_ERR
, "ndr_rpc_bind: smbrdr_ctx_new"
136 "(Srv=%s Dom=%s User=%s), %s (0x%x)",
137 server
, domain
, username
,
138 xlate_nt_status(status
), status
);
139 /* Tell the DC Locator this DC failed. */
140 smb_ddiscover_bad_dc(server
);
145 * Open the named pipe.
147 fd
= smb_fh_open(ctx
, svc
->endpoint
, O_RDWR
);
150 syslog(LOG_DEBUG
, "ndr_rpc_bind: "
151 "smb_fh_open (%s) err=%d",
155 status
= NT_STATUS_ACCESS_DENIED
;
158 status
= NT_STATUS_BAD_NETWORK_NAME
;
165 * Setup the RPC client handle.
167 if ((clnt
= malloc(sizeof (ndr_client_t
))) == NULL
) {
168 status
= NT_STATUS_NO_MEMORY
;
171 bzero(clnt
, sizeof (ndr_client_t
));
173 clnt
->handle
= &handle
->handle
;
174 clnt
->xa_init
= ndr_xa_init
;
175 clnt
->xa_exchange
= ndr_xa_exchange
;
176 clnt
->xa_read
= ndr_xa_read
;
177 clnt
->xa_preserve
= ndr_xa_preserve
;
178 clnt
->xa_destruct
= ndr_xa_destruct
;
179 clnt
->xa_release
= ndr_xa_release
;
180 clnt
->xa_private
= ctx
;
183 ndr_svc_binding_pool_init(&clnt
->binding_list
,
184 clnt
->binding_pool
, NDR_N_BINDING_POOL
);
186 if ((clnt
->heap
= ndr_heap_create()) == NULL
) {
187 status
= NT_STATUS_NO_MEMORY
;
192 * Fill in the caller's handle.
194 bzero(&handle
->handle
, sizeof (ndr_hdid_t
));
196 bcopy(&svinfo
, &handle
->svinfo
, sizeof (srvsvc_server_info_t
));
199 * Do the OtW RPC bind.
201 rc
= ndr_clnt_bind(clnt
, service
, &clnt
->binding
);
203 case NDR_DRC_FAULT_OUT_OF_MEMORY
:
204 status
= NT_STATUS_NO_MEMORY
;
206 case NDR_DRC_FAULT_API_SERVICE_INVALID
: /* not registered */
207 status
= NT_STATUS_INTERNAL_ERROR
;
210 if (NDR_DRC_IS_FAULT(rc
)) {
211 status
= NT_STATUS_INVALID_PARAMETER
;
216 return (NT_STATUS_SUCCESS
);
219 syslog(LOG_DEBUG
, "ndr_rpc_bind: "
220 "ndr_clnt_bind, %s (0x%x)",
221 xlate_nt_status(status
), status
);
226 ndr_heap_destroy(clnt
->heap
);
231 (void) smb_fh_close(fd
);
232 smbrdr_ctx_free(ctx
);
239 * Unbind and close the pipe to an RPC service.
241 * If the heap has been preserved we need to go through an xa release.
242 * The heap is preserved during an RPC call because that's where data
243 * returned from the server is stored.
245 * Otherwise we destroy the heap directly.
248 ndr_rpc_unbind(mlsvc_handle_t
*handle
)
250 ndr_client_t
*clnt
= handle
->clnt
;
251 struct smb_ctx
*ctx
= clnt
->xa_private
;
253 if (clnt
->heap_preserved
)
254 ndr_clnt_free_heap(clnt
);
256 ndr_heap_destroy(clnt
->heap
);
258 (void) smb_fh_close(clnt
->xa_fd
);
259 smbrdr_ctx_free(ctx
);
261 bzero(handle
, sizeof (mlsvc_handle_t
));
265 * Call the RPC function identified by opnum. The remote service is
266 * identified by the handle, which should have been initialized by
269 * If the RPC call is successful (returns 0), the caller must call
270 * ndr_rpc_release to release the heap. Otherwise, we release the
274 ndr_rpc_call(mlsvc_handle_t
*handle
, int opnum
, void *params
)
276 ndr_client_t
*clnt
= handle
->clnt
;
279 if (ndr_rpc_get_heap(handle
) == NULL
)
282 rc
= ndr_clnt_call(clnt
->binding
, opnum
, params
);
285 * Always clear the nonull flag to ensure
286 * it is not applied to subsequent calls.
288 clnt
->nonull
= B_FALSE
;
290 if (NDR_DRC_IS_FAULT(rc
)) {
291 ndr_rpc_release(handle
);
299 * Outgoing strings should not be null terminated.
302 ndr_rpc_set_nonull(mlsvc_handle_t
*handle
)
304 handle
->clnt
->nonull
= B_TRUE
;
308 * Return a reference to the server info.
310 const srvsvc_server_info_t
*
311 ndr_rpc_server_info(mlsvc_handle_t
*handle
)
313 return (&handle
->svinfo
);
317 * Return the RPC server OS level.
320 ndr_rpc_server_os(mlsvc_handle_t
*handle
)
322 return (handle
->svinfo
.sv_os
);
326 * Get the session key from a bound RPC client handle.
328 * The key returned is the 16-byte "user session key"
329 * established by the underlying authentication protocol
330 * (either Kerberos or NTLM). This key is needed for
331 * SAM RPC calls such as SamrSetInformationUser, etc.
332 * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
334 * Returns zero (success) or an errno.
337 ndr_rpc_get_ssnkey(mlsvc_handle_t
*handle
,
338 unsigned char *ssn_key
, size_t len
)
340 ndr_client_t
*clnt
= handle
->clnt
;
346 rc
= smb_fh_getssnkey(clnt
->xa_fd
, ssn_key
, len
);
351 ndr_rpc_malloc(mlsvc_handle_t
*handle
, size_t size
)
355 if ((heap
= ndr_rpc_get_heap(handle
)) == NULL
)
358 return (ndr_heap_malloc(heap
, size
));
362 ndr_rpc_get_heap(mlsvc_handle_t
*handle
)
364 ndr_client_t
*clnt
= handle
->clnt
;
366 if (clnt
->heap
== NULL
)
367 clnt
->heap
= ndr_heap_create();
373 * Must be called by RPC clients to free the heap after a successful RPC
374 * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
375 * of any data returned by the RPC prior to calling this function because
376 * returned data is in the heap.
379 ndr_rpc_release(mlsvc_handle_t
*handle
)
381 ndr_client_t
*clnt
= handle
->clnt
;
383 if (clnt
->heap_preserved
)
384 ndr_clnt_free_heap(clnt
);
386 ndr_heap_destroy(clnt
->heap
);
392 * Returns true if the handle is null.
393 * Otherwise returns false.
396 ndr_is_null_handle(mlsvc_handle_t
*handle
)
398 static ndr_hdid_t zero_handle
;
400 if (handle
== NULL
|| handle
->clnt
== NULL
)
403 if (!memcmp(&handle
->handle
, &zero_handle
, sizeof (ndr_hdid_t
)))
410 * Returns true if the handle is the top level bind handle.
411 * Otherwise returns false.
414 ndr_is_bind_handle(mlsvc_handle_t
*handle
)
416 return (handle
->clnt
->handle
== &handle
->handle
);
420 * Pass the client reference from parent to child.
423 ndr_inherit_handle(mlsvc_handle_t
*child
, mlsvc_handle_t
*parent
)
425 child
->clnt
= parent
->clnt
;
426 bcopy(&parent
->svinfo
, &child
->svinfo
, sizeof (srvsvc_server_info_t
));
430 ndr_rpc_status(mlsvc_handle_t
*handle
, int opnum
, DWORD status
)
433 char *name
= "NDR RPC";
436 switch (NT_SC_SEVERITY(status
)) {
437 case NT_STATUS_SEVERITY_SUCCESS
:
440 case NT_STATUS_SEVERITY_INFORMATIONAL
:
443 case NT_STATUS_SEVERITY_WARNING
:
446 case NT_STATUS_SEVERITY_ERROR
:
452 svc
= handle
->clnt
->binding
->service
;
456 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
457 name
, opnum
, s
, xlate_nt_status(status
), status
);
461 * The following functions provide the client callback interface.
462 * If the caller hasn't provided a heap, create one here.
465 ndr_xa_init(ndr_client_t
*clnt
, ndr_xa_t
*mxa
)
467 ndr_stream_t
*recv_nds
= &mxa
->recv_nds
;
468 ndr_stream_t
*send_nds
= &mxa
->send_nds
;
469 ndr_heap_t
*heap
= clnt
->heap
;
473 if ((heap
= ndr_heap_create()) == NULL
)
481 rc
= nds_initialize(send_nds
, 0, NDR_MODE_CALL_SEND
, heap
);
483 rc
= nds_initialize(recv_nds
, NDR_PDU_SIZE_HINT_DEFAULT
,
484 NDR_MODE_RETURN_RECV
, heap
);
487 nds_destruct(&mxa
->recv_nds
);
488 nds_destruct(&mxa
->send_nds
);
489 ndr_heap_destroy(mxa
->heap
);
496 NDS_SETF(send_nds
, NDS_F_NONULL
);
502 * This is the entry pointy for an RPC client call exchange with
503 * a server, which will result in an smbrdr SmbTransact request.
505 * SmbTransact should return the number of bytes received, which
506 * we record as the PDU size, or a negative error code.
509 ndr_xa_exchange(ndr_client_t
*clnt
, ndr_xa_t
*mxa
)
511 ndr_stream_t
*recv_nds
= &mxa
->recv_nds
;
512 ndr_stream_t
*send_nds
= &mxa
->send_nds
;
513 int err
, more
, nbytes
;
515 nbytes
= recv_nds
->pdu_max_size
;
516 err
= smb_fh_xactnp(clnt
->xa_fd
,
517 send_nds
->pdu_size
, (char *)send_nds
->pdu_base_offset
,
518 &nbytes
, (char *)recv_nds
->pdu_base_offset
, &more
);
520 recv_nds
->pdu_size
= 0;
524 recv_nds
->pdu_size
= nbytes
;
529 * This entry point will be invoked if the xa-exchange response contained
530 * only the first fragment of a multi-fragment response. The RPC client
531 * code will then make repeated xa-read requests to obtain the remaining
532 * fragments, which will result in smbrdr SmbReadX requests.
534 * SmbReadX should return the number of bytes received, in which case we
535 * expand the PDU size to include the received data, or a negative error
539 ndr_xa_read(ndr_client_t
*clnt
, ndr_xa_t
*mxa
)
541 ndr_stream_t
*nds
= &mxa
->recv_nds
;
545 if ((len
= (nds
->pdu_max_size
- nds
->pdu_size
)) < 0)
548 nbytes
= smb_fh_read(clnt
->xa_fd
, 0, len
,
549 (char *)nds
->pdu_base_offset
+ nds
->pdu_size
);
554 nds
->pdu_size
+= nbytes
;
556 if (nds
->pdu_size
> nds
->pdu_max_size
) {
557 nds
->pdu_size
= nds
->pdu_max_size
;
565 * Preserve the heap so that the client application has access to data
566 * returned from the server after an RPC call.
569 ndr_xa_preserve(ndr_client_t
*clnt
, ndr_xa_t
*mxa
)
571 assert(clnt
->heap
== mxa
->heap
);
573 clnt
->heap_preserved
= B_TRUE
;
578 * Dispose of the transaction streams. If the heap has not been
579 * preserved, we can destroy it here.
582 ndr_xa_destruct(ndr_client_t
*clnt
, ndr_xa_t
*mxa
)
584 nds_destruct(&mxa
->recv_nds
);
585 nds_destruct(&mxa
->send_nds
);
587 if (!clnt
->heap_preserved
) {
588 ndr_heap_destroy(mxa
->heap
);
595 * Dispose of a preserved heap.
598 ndr_xa_release(ndr_client_t
*clnt
)
600 if (clnt
->heap_preserved
) {
601 ndr_heap_destroy(clnt
->heap
);
603 clnt
->heap_preserved
= B_FALSE
;
609 * Compare the time here with the remote time on the server
610 * and report clock skew.
613 ndr_srvsvc_timecheck(char *server
, char *domain
)
615 char hostname
[MAXHOSTNAMELEN
];
616 struct timeval dc_tv
;
623 if (srvsvc_net_remote_tod(server
, domain
, &dc_tv
, &dc_tm
) < 0) {
624 syslog(LOG_DEBUG
, "srvsvc_net_remote_tod failed");
630 if (tnow
> dc_tv
.tv_sec
)
631 tdiff
= (tnow
- dc_tv
.tv_sec
) / SECSPERMIN
;
633 tdiff
= (dc_tv
.tv_sec
- tnow
) / SECSPERMIN
;
636 (void) strlcpy(hostname
, "localhost", MAXHOSTNAMELEN
);
637 (void) gethostname(hostname
, MAXHOSTNAMELEN
);
639 priority
= (tdiff
> 2) ? LOG_NOTICE
: LOG_DEBUG
;
640 syslog(priority
, "DC [%s] clock skew detected: %u minutes",
643 tm
= gmtime(&dc_tv
.tv_sec
);
644 syslog(priority
, "%-8s UTC: %s", server
, asctime(tm
));
646 syslog(priority
, "%-8s UTC: %s", hostname
, asctime(tm
));