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 <sys/tzfile.h>
35 #include <time.h>
36 #include <strings.h>
37 #include <assert.h>
38 #include <errno.h>
39 #include <thread.h>
40 #include <unistd.h>
41 #include <syslog.h>
42 #include <synch.h>
43
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>
51 #include <mlsvc.h>
52
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 *);
59
60
61 /*
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.
64 *
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.
69 *
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.
73 *
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)
80 *
81 * NT_STATUS_INTERNAL_ERROR (bad args etc)
82 * NT_STATUS_NO_MEMORY
83 */
84 DWORD
85 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
86 char *username, const char *service)
87 {
88 struct smb_ctx *ctx = NULL;
89 ndr_client_t *clnt = NULL;
90 ndr_service_t *svc;
91 srvsvc_server_info_t svinfo;
92 DWORD status;
93 int fd = -1;
94 int rc;
95
96 if (handle == NULL || server == NULL || server[0] == '\0' ||
97 domain == NULL || username == NULL)
98 return (NT_STATUS_INTERNAL_ERROR);
99
100 /* In case the service was not registered... */
101 if ((svc = ndr_svc_lookup_name(service)) == NULL)
102 return (NT_STATUS_INTERNAL_ERROR);
103
104 /*
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.
109 */
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;
116
117 /*
118 * Some callers pass this when they want a NULL session.
119 * Todo: have callers pass an empty string for that.
120 */
121 if (strcmp(username, MLSVC_ANON_USER) == 0)
122 username = "";
123
124 /*
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)
132 */
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);
141 goto errout;
142 }
143
144 /*
145 * Open the named pipe.
146 */
147 fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
148 if (fd < 0) {
149 rc = errno;
150 syslog(LOG_DEBUG, "ndr_rpc_bind: "
151 "smb_fh_open (%s) err=%d",
152 svc->endpoint, rc);
153 switch (rc) {
154 case EACCES:
155 status = NT_STATUS_ACCESS_DENIED;
156 break;
157 default:
158 status = NT_STATUS_BAD_NETWORK_NAME;
159 break;
160 }
161 goto errout;
162 }
163
164 /*
165 * Setup the RPC client handle.
166 */
167 if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
168 status = NT_STATUS_NO_MEMORY;
169 goto errout;
170 }
171 bzero(clnt, sizeof (ndr_client_t));
172
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;
181 clnt->xa_fd = fd;
182
183 ndr_svc_binding_pool_init(&clnt->binding_list,
184 clnt->binding_pool, NDR_N_BINDING_POOL);
185
186 if ((clnt->heap = ndr_heap_create()) == NULL) {
187 status = NT_STATUS_NO_MEMORY;
188 goto errout;
189 }
190
191 /*
192 * Fill in the caller's handle.
193 */
194 bzero(&handle->handle, sizeof (ndr_hdid_t));
195 handle->clnt = clnt;
196 bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
197
198 /*
199 * Do the OtW RPC bind.
200 */
201 rc = ndr_clnt_bind(clnt, service, &clnt->binding);
202 switch (rc) {
203 case NDR_DRC_FAULT_OUT_OF_MEMORY:
204 status = NT_STATUS_NO_MEMORY;
205 break;
206 case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
207 status = NT_STATUS_INTERNAL_ERROR;
208 break;
209 default:
210 if (NDR_DRC_IS_FAULT(rc)) {
211 status = NT_STATUS_INVALID_PARAMETER;
212 break;
213 }
214 /* FALLTHROUGH */
215 case NDR_DRC_OK:
216 return (NT_STATUS_SUCCESS);
217 }
218
219 syslog(LOG_DEBUG, "ndr_rpc_bind: "
220 "ndr_clnt_bind, %s (0x%x)",
221 xlate_nt_status(status), status);
222
223 errout:
224 handle->clnt = NULL;
225 if (clnt != NULL) {
226 ndr_heap_destroy(clnt->heap);
227 free(clnt);
228 }
229 if (ctx != NULL) {
230 if (fd != -1)
231 (void) smb_fh_close(fd);
232 smbrdr_ctx_free(ctx);
233 }
234
235 return (status);
236 }
237
238 /*
239 * Unbind and close the pipe to an RPC service.
240 *
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.
244 *
245 * Otherwise we destroy the heap directly.
246 */
247 void
248 ndr_rpc_unbind(mlsvc_handle_t *handle)
249 {
250 ndr_client_t *clnt = handle->clnt;
251 struct smb_ctx *ctx = clnt->xa_private;
252
253 if (clnt->heap_preserved)
254 ndr_clnt_free_heap(clnt);
255 else
256 ndr_heap_destroy(clnt->heap);
257
258 (void) smb_fh_close(clnt->xa_fd);
259 smbrdr_ctx_free(ctx);
260 free(clnt);
261 bzero(handle, sizeof (mlsvc_handle_t));
262 }
263
264 /*
265 * Call the RPC function identified by opnum. The remote service is
266 * identified by the handle, which should have been initialized by
267 * ndr_rpc_bind.
268 *
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
271 * heap here.
272 */
273 int
274 ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
275 {
276 ndr_client_t *clnt = handle->clnt;
277 int rc;
278
279 if (ndr_rpc_get_heap(handle) == NULL)
280 return (-1);
281
282 rc = ndr_clnt_call(clnt->binding, opnum, params);
283
284 /*
285 * Always clear the nonull flag to ensure
286 * it is not applied to subsequent calls.
287 */
288 clnt->nonull = B_FALSE;
289
290 if (NDR_DRC_IS_FAULT(rc)) {
291 ndr_rpc_release(handle);
292 return (-1);
293 }
294
295 return (0);
296 }
297
298 /*
299 * Outgoing strings should not be null terminated.
300 */
301 void
302 ndr_rpc_set_nonull(mlsvc_handle_t *handle)
303 {
304 handle->clnt->nonull = B_TRUE;
305 }
306
307 /*
308 * Return a reference to the server info.
309 */
310 const srvsvc_server_info_t *
311 ndr_rpc_server_info(mlsvc_handle_t *handle)
312 {
313 return (&handle->svinfo);
314 }
315
316 /*
317 * Return the RPC server OS level.
318 */
319 uint32_t
320 ndr_rpc_server_os(mlsvc_handle_t *handle)
321 {
322 return (handle->svinfo.sv_os);
323 }
324
325 /*
326 * Get the session key from a bound RPC client handle.
327 *
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.
333 *
334 * Returns zero (success) or an errno.
335 */
336 int
337 ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
338 unsigned char *ssn_key, size_t len)
339 {
340 ndr_client_t *clnt = handle->clnt;
341 int rc;
342
343 if (clnt == NULL)
344 return (EINVAL);
345
346 rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len);
347 return (rc);
348 }
349
350 void *
351 ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
352 {
353 ndr_heap_t *heap;
354
355 if ((heap = ndr_rpc_get_heap(handle)) == NULL)
356 return (NULL);
357
358 return (ndr_heap_malloc(heap, size));
359 }
360
361 ndr_heap_t *
362 ndr_rpc_get_heap(mlsvc_handle_t *handle)
363 {
364 ndr_client_t *clnt = handle->clnt;
365
366 if (clnt->heap == NULL)
367 clnt->heap = ndr_heap_create();
368
369 return (clnt->heap);
370 }
371
372 /*
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.
377 */
378 void
379 ndr_rpc_release(mlsvc_handle_t *handle)
380 {
381 ndr_client_t *clnt = handle->clnt;
382
383 if (clnt->heap_preserved)
384 ndr_clnt_free_heap(clnt);
385 else
386 ndr_heap_destroy(clnt->heap);
387
388 clnt->heap = NULL;
389 }
390
391 /*
392 * Returns true if the handle is null.
393 * Otherwise returns false.
394 */
395 boolean_t
396 ndr_is_null_handle(mlsvc_handle_t *handle)
397 {
398 static ndr_hdid_t zero_handle;
399
400 if (handle == NULL || handle->clnt == NULL)
401 return (B_TRUE);
402
403 if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
404 return (B_TRUE);
405
406 return (B_FALSE);
407 }
408
409 /*
410 * Returns true if the handle is the top level bind handle.
411 * Otherwise returns false.
412 */
413 boolean_t
414 ndr_is_bind_handle(mlsvc_handle_t *handle)
415 {
416 return (handle->clnt->handle == &handle->handle);
417 }
418
419 /*
420 * Pass the client reference from parent to child.
421 */
422 void
423 ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
424 {
425 child->clnt = parent->clnt;
426 bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
427 }
428
429 void
430 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
431 {
432 ndr_service_t *svc;
433 char *name = "NDR RPC";
434 char *s = "unknown";
435
436 switch (NT_SC_SEVERITY(status)) {
437 case NT_STATUS_SEVERITY_SUCCESS:
438 s = "success";
439 break;
440 case NT_STATUS_SEVERITY_INFORMATIONAL:
441 s = "info";
442 break;
443 case NT_STATUS_SEVERITY_WARNING:
444 s = "warning";
445 break;
446 case NT_STATUS_SEVERITY_ERROR:
447 s = "error";
448 break;
449 }
450
451 if (handle) {
452 svc = handle->clnt->binding->service;
453 name = svc->name;
454 }
455
456 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
457 name, opnum, s, xlate_nt_status(status), status);
458 }
459
460 /*
461 * The following functions provide the client callback interface.
462 * If the caller hasn't provided a heap, create one here.
463 */
464 static int
465 ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
466 {
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;
470 int rc;
471
472 if (heap == NULL) {
473 if ((heap = ndr_heap_create()) == NULL)
474 return (-1);
475
476 clnt->heap = heap;
477 }
478
479 mxa->heap = heap;
480
481 rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
482 if (rc == 0)
483 rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
484 NDR_MODE_RETURN_RECV, heap);
485
486 if (rc != 0) {
487 nds_destruct(&mxa->recv_nds);
488 nds_destruct(&mxa->send_nds);
489 ndr_heap_destroy(mxa->heap);
490 mxa->heap = NULL;
491 clnt->heap = NULL;
492 return (-1);
493 }
494
495 if (clnt->nonull)
496 NDS_SETF(send_nds, NDS_F_NONULL);
497
498 return (0);
499 }
500
501 /*
502 * This is the entry pointy for an RPC client call exchange with
503 * a server, which will result in an smbrdr SmbTransact request.
504 *
505 * SmbTransact should return the number of bytes received, which
506 * we record as the PDU size, or a negative error code.
507 */
508 static int
509 ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
510 {
511 ndr_stream_t *recv_nds = &mxa->recv_nds;
512 ndr_stream_t *send_nds = &mxa->send_nds;
513 int err, more, nbytes;
514
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);
519 if (err) {
520 recv_nds->pdu_size = 0;
521 return (-1);
522 }
523
524 recv_nds->pdu_size = nbytes;
525 return (0);
526 }
527
528 /*
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.
533 *
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
536 * code.
537 */
538 static int
539 ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
540 {
541 ndr_stream_t *nds = &mxa->recv_nds;
542 int len;
543 int nbytes;
544
545 if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
546 return (-1);
547
548 nbytes = smb_fh_read(clnt->xa_fd, 0, len,
549 (char *)nds->pdu_base_offset + nds->pdu_size);
550
551 if (nbytes < 0)
552 return (-1);
553
554 nds->pdu_size += nbytes;
555
556 if (nds->pdu_size > nds->pdu_max_size) {
557 nds->pdu_size = nds->pdu_max_size;
558 return (-1);
559 }
560
561 return (nbytes);
562 }
563
564 /*
565 * Preserve the heap so that the client application has access to data
566 * returned from the server after an RPC call.
567 */
568 static void
569 ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
570 {
571 assert(clnt->heap == mxa->heap);
572
573 clnt->heap_preserved = B_TRUE;
574 mxa->heap = NULL;
575 }
576
577 /*
578 * Dispose of the transaction streams. If the heap has not been
579 * preserved, we can destroy it here.
580 */
581 static void
582 ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
583 {
584 nds_destruct(&mxa->recv_nds);
585 nds_destruct(&mxa->send_nds);
586
587 if (!clnt->heap_preserved) {
588 ndr_heap_destroy(mxa->heap);
589 mxa->heap = NULL;
590 clnt->heap = NULL;
591 }
592 }
593
594 /*
595 * Dispose of a preserved heap.
596 */
597 static void
598 ndr_xa_release(ndr_client_t *clnt)
599 {
600 if (clnt->heap_preserved) {
601 ndr_heap_destroy(clnt->heap);
602 clnt->heap = NULL;
603 clnt->heap_preserved = B_FALSE;
604 }
605 }
606
607
608 /*
609 * Compare the time here with the remote time on the server
610 * and report clock skew.
611 */
612 void
613 ndr_srvsvc_timecheck(char *server, char *domain)
614 {
615 char hostname[MAXHOSTNAMELEN];
616 struct timeval dc_tv;
617 struct tm dc_tm;
618 struct tm *tm;
619 time_t tnow;
620 time_t tdiff;
621 int priority;
622
623 if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) {
624 syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed");
625 return;
626 }
627
628 tnow = time(NULL);
629
630 if (tnow > dc_tv.tv_sec)
631 tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN;
632 else
633 tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN;
634
635 if (tdiff != 0) {
636 (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN);
637 (void) gethostname(hostname, MAXHOSTNAMELEN);
638
639 priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG;
640 syslog(priority, "DC [%s] clock skew detected: %u minutes",
641 server, tdiff);
642
643 tm = gmtime(&dc_tv.tv_sec);
644 syslog(priority, "%-8s UTC: %s", server, asctime(tm));
645 tm = gmtime(&tnow);
646 syslog(priority, "%-8s UTC: %s", hostname, asctime(tm));
647 }
648 }
|
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 <libmlrpc/libmlrpc.h>
43 #include <netsmb/smbfs_api.h>
44
45 #include <smbsrv/libsmb.h>
46 #include <smbsrv/libmlsvc.h>
47 #include <libsmbrdr.h>
48 #include <mlsvc.h>
49
50
51 /*
52 * This call must be made to initialize an RPC client structure and bind
53 * to the remote service before any RPCs can be exchanged with that service.
54 *
55 * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
56 * with the client context for an instance of the interface. The handle
57 * is zeroed to ensure that it doesn't look like a valid handle -
58 * handle content is provided by the remove service.
59 *
60 * The client points to this top-level handle so that we know when to
61 * unbind and teardown the connection. As each handle is initialized it
62 * will inherit a reference to the client context.
63 *
64 * Returns 0 or an NT_STATUS: (failed in...)
65 *
66 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
67 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
68 * NT_STATUS_BAD_NETWORK_NAME (tcon)
69 * RPC_NT_SERVER_TOO_BUSY (open pipe)
70 * RPC_NT_SERVER_UNAVAILABLE (open pipe)
71 * NT_STATUS_ACCESS_DENIED (open pipe)
72 * NT_STATUS_INVALID_PARAMETER (rpc bind)
73 * NT_STATUS_INTERNAL_ERROR (bad args etc)
74 * NT_STATUS_NO_MEMORY
75 */
76 DWORD
77 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
78 char *username, const char *service)
79 {
80 struct smb_ctx *ctx = NULL;
81 ndr_service_t *svc;
82 DWORD status;
83 int rc;
84
85 if (handle == NULL || server == NULL || server[0] == '\0' ||
86 domain == NULL || username == NULL)
87 return (NT_STATUS_INTERNAL_ERROR);
88
89 /* In case the service was not registered... */
90 if ((svc = ndr_svc_lookup_name(service)) == NULL)
91 return (NT_STATUS_INTERNAL_ERROR);
92
93 /*
94 * Some callers pass this when they want a NULL session.
95 * Todo: have callers pass an empty string for that.
96 */
97 if (strcmp(username, MLSVC_ANON_USER) == 0)
98 username = "";
99
100 /*
101 * Setup smbfs library handle, authenticate, connect to
102 * the IPC$ share. This will reuse an existing connection
103 * if the driver already has one for this combination of
104 * server, user, domain. It may return any of:
105 * NT_STATUS_BAD_NETWORK_PATH (get server addr)
106 * NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
107 * NT_STATUS_BAD_NETWORK_NAME (tcon)
108 */
109 status = smbrdr_ctx_new(&ctx, server, domain, username);
110 if (status != NT_STATUS_SUCCESS) {
111 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
112 "(Srv=%s Dom=%s User=%s), %s (0x%x)",
113 server, domain, username,
114 xlate_nt_status(status), status);
115 /*
116 * If the error is one where changing to a new DC
117 * might help, try looking for a different DC.
118 */
119 switch (status) {
120 case NT_STATUS_BAD_NETWORK_PATH:
121 case NT_STATUS_BAD_NETWORK_NAME:
122 /* Look for a new DC */
123 smb_ddiscover_bad_dc(server);
124 default:
125 break;
126 }
127 return (status);
128 }
129
130 /*
131 * Setup the RPC client handle.
132 */
133 rc = mlrpc_clh_create(handle, ctx);
134 if (rc != 0) {
135 syslog(LOG_ERR, "ndr_rpc_bind: mlrpc_clh_create: rc=%d", rc);
136 smbrdr_ctx_free(ctx);
137 switch (rc) {
138 case ENOMEM:
139 return (NT_STATUS_NO_MEMORY);
140 case EINVAL:
141 return (NT_STATUS_INVALID_PARAMETER);
142 default:
143 return (NT_STATUS_INTERNAL_ERROR);
144 }
145 }
146
147 /*
148 * This does the pipe open and OtW RPC bind.
149 * Handles pipe open retries.
150 */
151 status = mlrpc_clh_bind(handle, svc);
152 if (status != 0) {
153 syslog(LOG_DEBUG, "ndr_rpc_bind: "
154 "mlrpc_clh_bind, %s (0x%x)",
155 xlate_nt_status(status), status);
156 switch (status) {
157 case RPC_NT_SERVER_TOO_BUSY:
158 /* Look for a new DC */
159 smb_ddiscover_bad_dc(server);
160 break;
161 default:
162 break;
163 }
164 ctx = mlrpc_clh_free(handle);
165 if (ctx != NULL) {
166 smbrdr_ctx_free(ctx);
167 }
168 }
169
170 return (status);
171 }
172
173 /*
174 * Unbind and close the pipe to an RPC service
175 * and cleanup the smb_ctx.
176 *
177 * The heap may or may not be destroyed (see mlrpc_clh_free)
178 */
179 void
180 ndr_rpc_unbind(mlsvc_handle_t *handle)
181 {
182 struct smb_ctx *ctx;
183
184 ctx = mlrpc_clh_free(handle);
185 if (ctx != NULL)
186 smbrdr_ctx_free(ctx);
187
188 bzero(handle, sizeof (mlsvc_handle_t));
189 }
190
191 void
192 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
193 {
194 ndr_service_t *svc;
195 char *name = "NDR RPC";
196 char *s = "unknown";
197
198 switch (NT_SC_SEVERITY(status)) {
199 case NT_STATUS_SEVERITY_SUCCESS:
200 s = "success";
201 break;
202 case NT_STATUS_SEVERITY_INFORMATIONAL:
203 s = "info";
204 break;
205 case NT_STATUS_SEVERITY_WARNING:
206 s = "warning";
207 break;
208 case NT_STATUS_SEVERITY_ERROR:
209 s = "error";
210 break;
211 }
212
213 if (handle) {
214 svc = handle->clnt->binding->service;
215 name = svc->name;
216 }
217
218 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
219 name, opnum, s, xlate_nt_status(status), status);
220 }
|