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