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