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 }