Print this page
1575 untangle libmlrpc ... (libmlrpc)


  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  *


 227  *
 228  * Otherwise we destroy the heap directly.
 229  */
 230 void
 231 ndr_rpc_unbind(mlsvc_handle_t *handle)
 232 {
 233         ndr_client_t *clnt = handle->clnt;
 234         struct smb_ctx *ctx = clnt->xa_private;
 235 
 236         if (clnt->heap_preserved)
 237                 ndr_clnt_free_heap(clnt);
 238         else
 239                 ndr_heap_destroy(clnt->heap);
 240 
 241         (void) smb_fh_close(clnt->xa_fd);
 242         smbrdr_ctx_free(ctx);
 243         free(clnt);
 244         bzero(handle, sizeof (mlsvc_handle_t));
 245 }
 246 
 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 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 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
 395 {
 396         ndr_service_t *svc;
 397         char *name = "NDR RPC";
 398         char *s = "unknown";
 399 
 400         switch (NT_SC_SEVERITY(status)) {
 401         case NT_STATUS_SEVERITY_SUCCESS:
 402                 s = "success";
 403                 break;
 404         case NT_STATUS_SEVERITY_INFORMATIONAL:
 405                 s = "info";
 406                 break;
 407         case NT_STATUS_SEVERITY_WARNING:
 408                 s = "warning";
 409                 break;
 410         case NT_STATUS_SEVERITY_ERROR:
 411                 s = "error";
 412                 break;
 413         }
 414 
 415         if (handle) {
 416                 svc = handle->clnt->binding->service;
 417                 name = svc->name;
 418         }
 419 
 420         smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
 421             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 }


  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 

  52 /*
  53  * This call must be made to initialize an RPC client structure and bind
  54  * to the remote service before any RPCs can be exchanged with that service.
  55  *
  56  * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle
  57  * with the client context for an instance of the interface.  The handle
  58  * is zeroed to ensure that it doesn't look like a valid handle -
  59  * handle content is provided by the remove service.
  60  *
  61  * The client points to this top-level handle so that we know when to
  62  * unbind and teardown the connection.  As each handle is initialized it
  63  * will inherit a reference to the client context.
  64  *
  65  * Returns 0 or an NT_STATUS:
  66  *      NT_STATUS_BAD_NETWORK_PATH      (get server addr)
  67  *      NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
  68  *      NT_STATUS_BAD_NETWORK_NAME      (tcon, open)
  69  *      NT_STATUS_ACCESS_DENIED         (open pipe)
  70  *      NT_STATUS_INVALID_PARAMETER     (rpc bind)
  71  *


 220  *
 221  * Otherwise we destroy the heap directly.
 222  */
 223 void
 224 ndr_rpc_unbind(mlsvc_handle_t *handle)
 225 {
 226         ndr_client_t *clnt = handle->clnt;
 227         struct smb_ctx *ctx = clnt->xa_private;
 228 
 229         if (clnt->heap_preserved)
 230                 ndr_clnt_free_heap(clnt);
 231         else
 232                 ndr_heap_destroy(clnt->heap);
 233 
 234         (void) smb_fh_close(clnt->xa_fd);
 235         smbrdr_ctx_free(ctx);
 236         free(clnt);
 237         bzero(handle, sizeof (mlsvc_handle_t));
 238 }
 239 





































 240 void













































































































 241 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
 242 {
 243         ndr_service_t *svc;
 244         char *name = "NDR RPC";
 245         char *s = "unknown";
 246 
 247         switch (NT_SC_SEVERITY(status)) {
 248         case NT_STATUS_SEVERITY_SUCCESS:
 249                 s = "success";
 250                 break;
 251         case NT_STATUS_SEVERITY_INFORMATIONAL:
 252                 s = "info";
 253                 break;
 254         case NT_STATUS_SEVERITY_WARNING:
 255                 s = "warning";
 256                 break;
 257         case NT_STATUS_SEVERITY_ERROR:
 258                 s = "error";
 259                 break;
 260         }
 261 
 262         if (handle) {
 263                 svc = handle->clnt->binding->service;
 264                 name = svc->name;
 265         }
 266 
 267         smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
 268             name, opnum, s, xlate_nt_status(status), status);



















































































































































 269 }