1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * Client NDR RPC interface.
29 */
30
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/fcntl.h>
34 #include <time.h>
35 #include <strings.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <thread.h>
39 #include <syslog.h>
40 #include <synch.h>
41
42 #include <netsmb/smbfs_api.h>
43 #include <smbsrv/libsmb.h>
44 #include <smbsrv/libsmbns.h>
45 #include <smbsrv/libmlrpc.h>
46 #include <smbsrv/libmlsvc.h>
47 #include <smbsrv/ndl/srvsvc.ndl>
48 #include <libsmbrdr.h>
49 #include <mlsvc.h>
50
51 static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
52 static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
53 static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
54 static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
55 static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
56 static void ndr_xa_release(ndr_client_t *);
57
58
59 /*
60 * This call must be made to initialize an RPC client structure and bind
61 * to the remote service before any RPCs can be exchanged with that service.
62 *
63 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
64 * with the client context for an instance of the interface. The handle
65 * is zeroed to ensure that it doesn't look like a valid handle -
66 * handle content is provided by the remove service.
67 *
68 * The client points to this top-level handle so that we know when to
69 * unbind and teardown the connection. As each handle is initialized it
70 * will inherit a reference to the client context.
71 *
72 * Returns 0 or an NT_STATUS:
73 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
74 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
75 * NT_STATUS_BAD_NETWORK_NAME (tcon, open)
76 * NT_STATUS_ACCESS_DENIED (open pipe)
77 * NT_STATUS_INVALID_PARAMETER (rpc bind)
78 *
79 * NT_STATUS_INTERNAL_ERROR (bad args etc)
80 * NT_STATUS_NO_MEMORY
81 */
82 DWORD
83 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
84 char *username, const char *service)
85 {
86 struct smb_ctx *ctx = NULL;
87 ndr_client_t *clnt = NULL;
88 ndr_service_t *svc;
89 srvsvc_server_info_t svinfo;
90 DWORD status;
91 int fd = -1;
92 int rc;
93
94 if (handle == NULL || server == NULL || server[0] == '\0' ||
95 domain == NULL || username == NULL)
96 return (NT_STATUS_INTERNAL_ERROR);
97
98 /* In case the service was not registered... */
99 if ((svc = ndr_svc_lookup_name(service)) == NULL)
100 return (NT_STATUS_INTERNAL_ERROR);
101
102 /*
103 * Set the default based on the assumption that most
104 * servers will be Windows 2000 or later. This used to
105 * try to get the actual server version, but that RPC
106 * is not necessarily allowed anymore, so don't bother.
107 */
108 bzero(&svinfo, sizeof (srvsvc_server_info_t));
109 svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
110 svinfo.sv_version_major = 5;
111 svinfo.sv_version_minor = 0;
112 svinfo.sv_type = SV_TYPE_DEFAULT;
113 svinfo.sv_os = NATIVE_OS_WIN2000;
114
115 /*
116 * Some callers pass this when they want a NULL session.
117 * Todo: have callers pass an empty string for that.
118 */
119 if (strcmp(username, MLSVC_ANON_USER) == 0)
120 username = "";
121
122 /*
123 * Setup smbfs library handle, authenticate, connect to
124 * the IPC$ share. This will reuse an existing connection
125 * if the driver already has one for this combination of
126 * server, user, domain. It may return any of:
127 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
128 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
129 * NT_STATUS_BAD_NETWORK_NAME (tcon)
130 */
131 status = smbrdr_ctx_new(&ctx, server, domain, username);
132 if (status != NT_STATUS_SUCCESS) {
133 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
134 "(Srv=%s Dom=%s User=%s), %s (0x%x)",
135 server, domain, username,
136 xlate_nt_status(status), status);
137 /* Tell the DC Locator this DC failed. */
138 smb_ddiscover_bad_dc(server);
139 goto errout;
140 }
141
142 /*
143 * Open the named pipe.
144 */
145 fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
146 if (fd < 0) {
147 rc = errno;
148 syslog(LOG_DEBUG, "ndr_rpc_bind: "
149 "smb_fh_open (%s) err=%d",
150 svc->endpoint, rc);
151 switch (rc) {
152 case EACCES:
153 status = NT_STATUS_ACCESS_DENIED;
154 break;
155 default:
156 status = NT_STATUS_BAD_NETWORK_NAME;
157 break;
158 }
159 goto errout;
160 }
161
162 /*
163 * Setup the RPC client handle.
164 */
165 if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
166 status = NT_STATUS_NO_MEMORY;
167 goto errout;
168 }
169 bzero(clnt, sizeof (ndr_client_t));
170
171 clnt->handle = &handle->handle;
172 clnt->xa_init = ndr_xa_init;
173 clnt->xa_exchange = ndr_xa_exchange;
174 clnt->xa_read = ndr_xa_read;
175 clnt->xa_preserve = ndr_xa_preserve;
176 clnt->xa_destruct = ndr_xa_destruct;
177 clnt->xa_release = ndr_xa_release;
178 clnt->xa_private = ctx;
179 clnt->xa_fd = fd;
180
181 ndr_svc_binding_pool_init(&clnt->binding_list,
182 clnt->binding_pool, NDR_N_BINDING_POOL);
183
184 if ((clnt->heap = ndr_heap_create()) == NULL) {
185 status = NT_STATUS_NO_MEMORY;
186 goto errout;
187 }
188
189 /*
190 * Fill in the caller's handle.
191 */
192 bzero(&handle->handle, sizeof (ndr_hdid_t));
193 handle->clnt = clnt;
194 bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
195
196 /*
197 * Do the OtW RPC bind.
198 */
199 rc = ndr_clnt_bind(clnt, service, &clnt->binding);
200 switch (rc) {
201 case NDR_DRC_FAULT_OUT_OF_MEMORY:
202 status = NT_STATUS_NO_MEMORY;
203 break;
204 case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
205 status = NT_STATUS_INTERNAL_ERROR;
206 break;
207 default:
208 if (NDR_DRC_IS_FAULT(rc)) {
209 status = NT_STATUS_INVALID_PARAMETER;
210 break;
211 }
212 /* FALLTHROUGH */
213 case NDR_DRC_OK:
214 return (NT_STATUS_SUCCESS);
215 }
216
217 syslog(LOG_DEBUG, "ndr_rpc_bind: "
218 "ndr_clnt_bind, %s (0x%x)",
219 xlate_nt_status(status), status);
220
221 errout:
222 handle->clnt = NULL;
223 if (clnt != NULL) {
224 ndr_heap_destroy(clnt->heap);
225 free(clnt);
226 }
227 if (ctx != NULL) {
228 if (fd != -1)
229 (void) smb_fh_close(fd);
230 smbrdr_ctx_free(ctx);
231 }
232
233 return (status);
234 }
235
236 /*
237 * Unbind and close the pipe to an RPC service.
238 *
239 * If the heap has been preserved we need to go through an xa release.
240 * The heap is preserved during an RPC call because that's where data
241 * returned from the server is stored.
242 *
243 * Otherwise we destroy the heap directly.
244 */
245 void
246 ndr_rpc_unbind(mlsvc_handle_t *handle)
247 {
248 ndr_client_t *clnt = handle->clnt;
249 struct smb_ctx *ctx = clnt->xa_private;
250
251 if (clnt->heap_preserved)
252 ndr_clnt_free_heap(clnt);
253 else
254 ndr_heap_destroy(clnt->heap);
255
256 (void) smb_fh_close(clnt->xa_fd);
257 smbrdr_ctx_free(ctx);
258 free(clnt);
259 bzero(handle, sizeof (mlsvc_handle_t));
260 }
261
262 /*
263 * Call the RPC function identified by opnum. The remote service is
264 * identified by the handle, which should have been initialized by
265 * ndr_rpc_bind.
266 *
267 * If the RPC call is successful (returns 0), the caller must call
268 * ndr_rpc_release to release the heap. Otherwise, we release the
269 * heap here.
270 */
271 int
272 ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
273 {
274 ndr_client_t *clnt = handle->clnt;
275 int rc;
276
277 if (ndr_rpc_get_heap(handle) == NULL)
278 return (-1);
279
280 rc = ndr_clnt_call(clnt->binding, opnum, params);
281
282 /*
283 * Always clear the nonull flag to ensure
284 * it is not applied to subsequent calls.
285 */
286 clnt->nonull = B_FALSE;
287
288 if (NDR_DRC_IS_FAULT(rc)) {
289 ndr_rpc_release(handle);
290 return (-1);
291 }
292
293 return (0);
294 }
295
296 /*
297 * Outgoing strings should not be null terminated.
298 */
299 void
300 ndr_rpc_set_nonull(mlsvc_handle_t *handle)
301 {
302 handle->clnt->nonull = B_TRUE;
303 }
304
305 /*
306 * Return a reference to the server info.
307 */
308 const srvsvc_server_info_t *
309 ndr_rpc_server_info(mlsvc_handle_t *handle)
310 {
311 return (&handle->svinfo);
312 }
313
314 /*
315 * Return the RPC server OS level.
316 */
317 uint32_t
318 ndr_rpc_server_os(mlsvc_handle_t *handle)
319 {
320 return (handle->svinfo.sv_os);
321 }
322
323 /*
324 * Get the session key from a bound RPC client handle.
325 *
326 * The key returned is the 16-byte "user session key"
327 * established by the underlying authentication protocol
328 * (either Kerberos or NTLM). This key is needed for
329 * SAM RPC calls such as SamrSetInformationUser, etc.
330 * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
331 *
332 * Returns zero (success) or an errno.
333 */
334 int
335 ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
336 unsigned char *ssn_key, size_t len)
337 {
338 ndr_client_t *clnt = handle->clnt;
339 int rc;
340
341 if (clnt == NULL)
342 return (EINVAL);
343
344 rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len);
345 return (rc);
346 }
347
348 void *
349 ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
350 {
351 ndr_heap_t *heap;
352
353 if ((heap = ndr_rpc_get_heap(handle)) == NULL)
354 return (NULL);
355
356 return (ndr_heap_malloc(heap, size));
357 }
358
359 ndr_heap_t *
360 ndr_rpc_get_heap(mlsvc_handle_t *handle)
361 {
362 ndr_client_t *clnt = handle->clnt;
363
364 if (clnt->heap == NULL)
365 clnt->heap = ndr_heap_create();
366
367 return (clnt->heap);
368 }
369
370 /*
371 * Must be called by RPC clients to free the heap after a successful RPC
372 * call, i.e. ndr_rpc_call returned 0. The caller should take a copy
373 * of any data returned by the RPC prior to calling this function because
374 * returned data is in the heap.
375 */
376 void
377 ndr_rpc_release(mlsvc_handle_t *handle)
378 {
379 ndr_client_t *clnt = handle->clnt;
380
381 if (clnt->heap_preserved)
382 ndr_clnt_free_heap(clnt);
383 else
384 ndr_heap_destroy(clnt->heap);
385
386 clnt->heap = NULL;
387 }
388
389 /*
390 * Returns true if the handle is null.
391 * Otherwise returns false.
392 */
393 boolean_t
394 ndr_is_null_handle(mlsvc_handle_t *handle)
395 {
396 static ndr_hdid_t zero_handle;
397
398 if (handle == NULL || handle->clnt == NULL)
399 return (B_TRUE);
400
401 if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
402 return (B_TRUE);
403
404 return (B_FALSE);
405 }
406
407 /*
408 * Returns true if the handle is the top level bind handle.
409 * Otherwise returns false.
410 */
411 boolean_t
412 ndr_is_bind_handle(mlsvc_handle_t *handle)
413 {
414 return (handle->clnt->handle == &handle->handle);
415 }
416
417 /*
418 * Pass the client reference from parent to child.
419 */
420 void
421 ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
422 {
423 child->clnt = parent->clnt;
424 bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
425 }
426
427 void
428 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
429 {
430 ndr_service_t *svc;
431 char *name = "NDR RPC";
432 char *s = "unknown";
433
434 switch (NT_SC_SEVERITY(status)) {
435 case NT_STATUS_SEVERITY_SUCCESS:
436 s = "success";
437 break;
438 case NT_STATUS_SEVERITY_INFORMATIONAL:
439 s = "info";
440 break;
441 case NT_STATUS_SEVERITY_WARNING:
442 s = "warning";
443 break;
444 case NT_STATUS_SEVERITY_ERROR:
445 s = "error";
446 break;
447 }
448
449 if (handle) {
450 svc = handle->clnt->binding->service;
451 name = svc->name;
452 }
453
454 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
455 name, opnum, s, xlate_nt_status(status), status);
456 }
457
458 /*
459 * The following functions provide the client callback interface.
460 * If the caller hasn't provided a heap, create one here.
461 */
462 static int
463 ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
464 {
465 ndr_stream_t *recv_nds = &mxa->recv_nds;
466 ndr_stream_t *send_nds = &mxa->send_nds;
467 ndr_heap_t *heap = clnt->heap;
468 int rc;
469
470 if (heap == NULL) {
471 if ((heap = ndr_heap_create()) == NULL)
472 return (-1);
473
474 clnt->heap = heap;
475 }
476
477 mxa->heap = heap;
478
479 rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
480 if (rc == 0)
481 rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
482 NDR_MODE_RETURN_RECV, heap);
483
484 if (rc != 0) {
485 nds_destruct(&mxa->recv_nds);
486 nds_destruct(&mxa->send_nds);
487 ndr_heap_destroy(mxa->heap);
488 mxa->heap = NULL;
489 clnt->heap = NULL;
490 return (-1);
491 }
492
493 if (clnt->nonull)
494 NDS_SETF(send_nds, NDS_F_NONULL);
495
496 return (0);
497 }
498
499 /*
500 * This is the entry pointy for an RPC client call exchange with
501 * a server, which will result in an smbrdr SmbTransact request.
502 *
503 * SmbTransact should return the number of bytes received, which
504 * we record as the PDU size, or a negative error code.
505 */
506 static int
507 ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
508 {
509 ndr_stream_t *recv_nds = &mxa->recv_nds;
510 ndr_stream_t *send_nds = &mxa->send_nds;
511 int err, more, nbytes;
512
513 nbytes = recv_nds->pdu_max_size;
514 err = smb_fh_xactnp(clnt->xa_fd,
515 send_nds->pdu_size, (char *)send_nds->pdu_base_offset,
516 &nbytes, (char *)recv_nds->pdu_base_offset, &more);
517 if (err) {
518 recv_nds->pdu_size = 0;
519 return (-1);
520 }
521
522 recv_nds->pdu_size = nbytes;
523 return (0);
524 }
525
526 /*
527 * This entry point will be invoked if the xa-exchange response contained
528 * only the first fragment of a multi-fragment response. The RPC client
529 * code will then make repeated xa-read requests to obtain the remaining
530 * fragments, which will result in smbrdr SmbReadX requests.
531 *
532 * SmbReadX should return the number of bytes received, in which case we
533 * expand the PDU size to include the received data, or a negative error
534 * code.
535 */
536 static int
537 ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
538 {
539 ndr_stream_t *nds = &mxa->recv_nds;
540 int len;
541 int nbytes;
542
543 if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
544 return (-1);
545
546 nbytes = smb_fh_read(clnt->xa_fd, 0, len,
547 (char *)nds->pdu_base_offset + nds->pdu_size);
548
549 if (nbytes < 0)
550 return (-1);
551
552 nds->pdu_size += nbytes;
553
554 if (nds->pdu_size > nds->pdu_max_size) {
555 nds->pdu_size = nds->pdu_max_size;
556 return (-1);
557 }
558
559 return (nbytes);
560 }
561
562 /*
563 * Preserve the heap so that the client application has access to data
564 * returned from the server after an RPC call.
565 */
566 static void
567 ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
568 {
569 assert(clnt->heap == mxa->heap);
570
571 clnt->heap_preserved = B_TRUE;
572 mxa->heap = NULL;
573 }
574
575 /*
576 * Dispose of the transaction streams. If the heap has not been
577 * preserved, we can destroy it here.
578 */
579 static void
580 ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
581 {
582 nds_destruct(&mxa->recv_nds);
583 nds_destruct(&mxa->send_nds);
584
585 if (!clnt->heap_preserved) {
586 ndr_heap_destroy(mxa->heap);
587 mxa->heap = NULL;
588 clnt->heap = NULL;
589 }
590 }
591
592 /*
593 * Dispose of a preserved heap.
594 */
595 static void
596 ndr_xa_release(ndr_client_t *clnt)
597 {
598 if (clnt->heap_preserved) {
599 ndr_heap_destroy(clnt->heap);
600 clnt->heap = NULL;
601 clnt->heap_preserved = B_FALSE;
602 }
603 }