Print this page
1575 untangle libmlrpc ... (smbsrv)
1575 untangle libmlrpc ... (libmlrpc)
1575 untangle libmlrpc ... pre2:
 Get rid of ndr_rpc_server_{info,os}
1575 untangle libmlrpc ... pre1:
 Move srvsvc_timecheck where it belongs


  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 }