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

@@ -29,37 +29,27 @@
  */
 
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/fcntl.h>
-#include <sys/tzfile.h>
 #include <time.h>
 #include <strings.h>
 #include <assert.h>
 #include <errno.h>
 #include <thread.h>
-#include <unistd.h>
 #include <syslog.h>
 #include <synch.h>
 
+#include <libmlrpc/libmlrpc.h>
 #include <netsmb/smbfs_api.h>
+
 #include <smbsrv/libsmb.h>
-#include <smbsrv/libsmbns.h>
-#include <smbsrv/libmlrpc.h>
 #include <smbsrv/libmlsvc.h>
-#include <smbsrv/ndl/srvsvc.ndl>
 #include <libsmbrdr.h>
 #include <mlsvc.h>
 
-static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
-static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
-static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
-static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
-static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
-static void ndr_xa_release(ndr_client_t *);
 
-
 /*
  * This call must be made to initialize an RPC client structure and bind
  * to the remote service before any RPCs can be exchanged with that service.
  *
  * The mlsvc_handle_t is a wrapper that is used to associate an RPC handle

@@ -69,30 +59,29 @@
  *
  * The client points to this top-level handle so that we know when to
  * unbind and teardown the connection.  As each handle is initialized it
  * will inherit a reference to the client context.
  *
- * Returns 0 or an NT_STATUS:
+ * Returns 0 or an NT_STATUS:           (failed in...)
+ *
  *      NT_STATUS_BAD_NETWORK_PATH      (get server addr)
  *      NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
- *      NT_STATUS_BAD_NETWORK_NAME      (tcon, open)
+ *      NT_STATUS_BAD_NETWORK_NAME      (tcon)
+ *      RPC_NT_SERVER_TOO_BUSY          (open pipe)
+ *      RPC_NT_SERVER_UNAVAILABLE       (open pipe)
  *      NT_STATUS_ACCESS_DENIED         (open pipe)
  *      NT_STATUS_INVALID_PARAMETER     (rpc bind)
- *
  *      NT_STATUS_INTERNAL_ERROR        (bad args etc)
  *      NT_STATUS_NO_MEMORY
  */
 DWORD
 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
     char *username, const char *service)
 {
         struct smb_ctx          *ctx = NULL;
-        ndr_client_t            *clnt = NULL;
         ndr_service_t           *svc;
-        srvsvc_server_info_t    svinfo;
         DWORD                   status;
-        int                     fd = -1;
         int                     rc;
 
         if (handle == NULL || server == NULL || server[0] == '\0' ||
             domain == NULL || username == NULL)
                 return (NT_STATUS_INTERNAL_ERROR);

@@ -100,23 +89,10 @@
         /* In case the service was not registered... */
         if ((svc = ndr_svc_lookup_name(service)) == NULL)
                 return (NT_STATUS_INTERNAL_ERROR);
 
         /*
-         * Set the default based on the assumption that most
-         * servers will be Windows 2000 or later.  This used to
-         * try to get the actual server version, but that RPC
-         * is not necessarily allowed anymore, so don't bother.
-         */
-        bzero(&svinfo, sizeof (srvsvc_server_info_t));
-        svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
-        svinfo.sv_version_major = 5;
-        svinfo.sv_version_minor = 0;
-        svinfo.sv_type = SV_TYPE_DEFAULT;
-        svinfo.sv_os = NATIVE_OS_WIN2000;
-
-        /*
          * Some callers pass this when they want a NULL session.
          * Todo: have callers pass an empty string for that.
          */
         if (strcmp(username, MLSVC_ANON_USER) == 0)
                 username = "";

@@ -134,301 +110,87 @@
         if (status != NT_STATUS_SUCCESS) {
                 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
                     "(Srv=%s Dom=%s User=%s), %s (0x%x)",
                     server, domain, username,
                     xlate_nt_status(status), status);
-                /* Tell the DC Locator this DC failed. */
-                smb_ddiscover_bad_dc(server);
-                goto errout;
-        }
-
         /*
-         * Open the named pipe.
+                 * If the error is one where changing to a new DC
+                 * might help, try looking for a different DC.
          */
-        fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
-        if (fd < 0) {
-                rc = errno;
-                syslog(LOG_DEBUG, "ndr_rpc_bind: "
-                    "smb_fh_open (%s) err=%d",
-                    svc->endpoint, rc);
-                switch (rc) {
-                case EACCES:
-                        status = NT_STATUS_ACCESS_DENIED;
-                        break;
+                switch (status) {
+                case NT_STATUS_BAD_NETWORK_PATH:
+                case NT_STATUS_BAD_NETWORK_NAME:
+                        /* Look for a new DC */
+                        smb_ddiscover_bad_dc(server);
                 default:
-                        status = NT_STATUS_BAD_NETWORK_NAME;
                         break;
                 }
-                goto errout;
+                return (status);
         }
 
         /*
          * Setup the RPC client handle.
          */
-        if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
-                status = NT_STATUS_NO_MEMORY;
-                goto errout;
+        rc = mlrpc_clh_create(handle, ctx);
+        if (rc != 0) {
+                syslog(LOG_ERR, "ndr_rpc_bind: mlrpc_clh_create: rc=%d", rc);
+                smbrdr_ctx_free(ctx);
+                switch (rc) {
+                case ENOMEM:
+                        return (NT_STATUS_NO_MEMORY);
+                case EINVAL:
+                        return (NT_STATUS_INVALID_PARAMETER);
+                default:
+                        return (NT_STATUS_INTERNAL_ERROR);
         }
-        bzero(clnt, sizeof (ndr_client_t));
-
-        clnt->handle = &handle->handle;
-        clnt->xa_init = ndr_xa_init;
-        clnt->xa_exchange = ndr_xa_exchange;
-        clnt->xa_read = ndr_xa_read;
-        clnt->xa_preserve = ndr_xa_preserve;
-        clnt->xa_destruct = ndr_xa_destruct;
-        clnt->xa_release = ndr_xa_release;
-        clnt->xa_private = ctx;
-        clnt->xa_fd = fd;
-
-        ndr_svc_binding_pool_init(&clnt->binding_list,
-            clnt->binding_pool, NDR_N_BINDING_POOL);
-
-        if ((clnt->heap = ndr_heap_create()) == NULL) {
-                status = NT_STATUS_NO_MEMORY;
-                goto errout;
         }
 
         /*
-         * Fill in the caller's handle.
+         * This does the pipe open and OtW RPC bind.
+         * Handles pipe open retries.
          */
-        bzero(&handle->handle, sizeof (ndr_hdid_t));
-        handle->clnt = clnt;
-        bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
-
-        /*
-         * Do the OtW RPC bind.
-         */
-        rc = ndr_clnt_bind(clnt, service, &clnt->binding);
-        switch (rc) {
-        case NDR_DRC_FAULT_OUT_OF_MEMORY:
-                status = NT_STATUS_NO_MEMORY;
+        status = mlrpc_clh_bind(handle, svc);
+        if (status != 0) {
+                syslog(LOG_DEBUG, "ndr_rpc_bind: "
+                    "mlrpc_clh_bind, %s (0x%x)",
+                    xlate_nt_status(status), status);
+                switch (status) {
+                case RPC_NT_SERVER_TOO_BUSY:
+                        /* Look for a new DC */
+                        smb_ddiscover_bad_dc(server);
                 break;
-        case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
-                status = NT_STATUS_INTERNAL_ERROR;
-                break;
         default:
-                if (NDR_DRC_IS_FAULT(rc)) {
-                        status = NT_STATUS_INVALID_PARAMETER;
                         break;
                 }
-                /* FALLTHROUGH */
-        case NDR_DRC_OK:
-                return (NT_STATUS_SUCCESS);
-        }
-
-        syslog(LOG_DEBUG, "ndr_rpc_bind: "
-            "ndr_clnt_bind, %s (0x%x)",
-            xlate_nt_status(status), status);
-
-errout:
-        handle->clnt = NULL;
-        if (clnt != NULL) {
-                ndr_heap_destroy(clnt->heap);
-                free(clnt);
-        }
+                ctx = mlrpc_clh_free(handle);
         if (ctx != NULL) {
-                if (fd != -1)
-                        (void) smb_fh_close(fd);
                 smbrdr_ctx_free(ctx);
         }
+        }
 
         return (status);
 }
 
 /*
- * Unbind and close the pipe to an RPC service.
+ * Unbind and close the pipe to an RPC service
+ * and cleanup the smb_ctx.
  *
- * If the heap has been preserved we need to go through an xa release.
- * The heap is preserved during an RPC call because that's where data
- * returned from the server is stored.
- *
- * Otherwise we destroy the heap directly.
+ * The heap may or may not be destroyed (see mlrpc_clh_free)
  */
 void
 ndr_rpc_unbind(mlsvc_handle_t *handle)
 {
-        ndr_client_t *clnt = handle->clnt;
-        struct smb_ctx *ctx = clnt->xa_private;
+        struct smb_ctx *ctx;
 
-        if (clnt->heap_preserved)
-                ndr_clnt_free_heap(clnt);
-        else
-                ndr_heap_destroy(clnt->heap);
-
-        (void) smb_fh_close(clnt->xa_fd);
+        ctx = mlrpc_clh_free(handle);
+        if (ctx != NULL)
         smbrdr_ctx_free(ctx);
-        free(clnt);
+
         bzero(handle, sizeof (mlsvc_handle_t));
 }
 
-/*
- * Call the RPC function identified by opnum.  The remote service is
- * identified by the handle, which should have been initialized by
- * ndr_rpc_bind.
- *
- * If the RPC call is successful (returns 0), the caller must call
- * ndr_rpc_release to release the heap.  Otherwise, we release the
- * heap here.
- */
-int
-ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params)
-{
-        ndr_client_t *clnt = handle->clnt;
-        int rc;
-
-        if (ndr_rpc_get_heap(handle) == NULL)
-                return (-1);
-
-        rc = ndr_clnt_call(clnt->binding, opnum, params);
-
-        /*
-         * Always clear the nonull flag to ensure
-         * it is not applied to subsequent calls.
-         */
-        clnt->nonull = B_FALSE;
-
-        if (NDR_DRC_IS_FAULT(rc)) {
-                ndr_rpc_release(handle);
-                return (-1);
-        }
-
-        return (0);
-}
-
-/*
- * Outgoing strings should not be null terminated.
- */
 void
-ndr_rpc_set_nonull(mlsvc_handle_t *handle)
-{
-        handle->clnt->nonull = B_TRUE;
-}
-
-/*
- * Return a reference to the server info.
- */
-const srvsvc_server_info_t *
-ndr_rpc_server_info(mlsvc_handle_t *handle)
-{
-        return (&handle->svinfo);
-}
-
-/*
- * Return the RPC server OS level.
- */
-uint32_t
-ndr_rpc_server_os(mlsvc_handle_t *handle)
-{
-        return (handle->svinfo.sv_os);
-}
-
-/*
- * Get the session key from a bound RPC client handle.
- *
- * The key returned is the 16-byte "user session key"
- * established by the underlying authentication protocol
- * (either Kerberos or NTLM).  This key is needed for
- * SAM RPC calls such as SamrSetInformationUser, etc.
- * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
- *
- * Returns zero (success) or an errno.
- */
-int
-ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
-        unsigned char *ssn_key, size_t len)
-{
-        ndr_client_t *clnt = handle->clnt;
-        int rc;
-
-        if (clnt == NULL)
-                return (EINVAL);
-
-        rc = smb_fh_getssnkey(clnt->xa_fd, ssn_key, len);
-        return (rc);
-}
-
-void *
-ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
-{
-        ndr_heap_t *heap;
-
-        if ((heap = ndr_rpc_get_heap(handle)) == NULL)
-                return (NULL);
-
-        return (ndr_heap_malloc(heap, size));
-}
-
-ndr_heap_t *
-ndr_rpc_get_heap(mlsvc_handle_t *handle)
-{
-        ndr_client_t *clnt = handle->clnt;
-
-        if (clnt->heap == NULL)
-                clnt->heap = ndr_heap_create();
-
-        return (clnt->heap);
-}
-
-/*
- * Must be called by RPC clients to free the heap after a successful RPC
- * call, i.e. ndr_rpc_call returned 0.  The caller should take a copy
- * of any data returned by the RPC prior to calling this function because
- * returned data is in the heap.
- */
-void
-ndr_rpc_release(mlsvc_handle_t *handle)
-{
-        ndr_client_t *clnt = handle->clnt;
-
-        if (clnt->heap_preserved)
-                ndr_clnt_free_heap(clnt);
-        else
-                ndr_heap_destroy(clnt->heap);
-
-        clnt->heap = NULL;
-}
-
-/*
- * Returns true if the handle is null.
- * Otherwise returns false.
- */
-boolean_t
-ndr_is_null_handle(mlsvc_handle_t *handle)
-{
-        static ndr_hdid_t zero_handle;
-
-        if (handle == NULL || handle->clnt == NULL)
-                return (B_TRUE);
-
-        if (!memcmp(&handle->handle, &zero_handle, sizeof (ndr_hdid_t)))
-                return (B_TRUE);
-
-        return (B_FALSE);
-}
-
-/*
- * Returns true if the handle is the top level bind handle.
- * Otherwise returns false.
- */
-boolean_t
-ndr_is_bind_handle(mlsvc_handle_t *handle)
-{
-        return (handle->clnt->handle == &handle->handle);
-}
-
-/*
- * Pass the client reference from parent to child.
- */
-void
-ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent)
-{
-        child->clnt = parent->clnt;
-        bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t));
-}
-
-void
 ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status)
 {
         ndr_service_t *svc;
         char *name = "NDR RPC";
         char *s = "unknown";

@@ -453,196 +215,6 @@
                 name = svc->name;
         }
 
         smb_tracef("%s[0x%02x]: %s: %s (0x%08x)",
             name, opnum, s, xlate_nt_status(status), status);
-}
-
-/*
- * The following functions provide the client callback interface.
- * If the caller hasn't provided a heap, create one here.
- */
-static int
-ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa)
-{
-        ndr_stream_t    *recv_nds = &mxa->recv_nds;
-        ndr_stream_t    *send_nds = &mxa->send_nds;
-        ndr_heap_t      *heap = clnt->heap;
-        int             rc;
-
-        if (heap == NULL) {
-                if ((heap = ndr_heap_create()) == NULL)
-                        return (-1);
-
-                clnt->heap = heap;
-        }
-
-        mxa->heap = heap;
-
-        rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap);
-        if (rc == 0)
-                rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT,
-                    NDR_MODE_RETURN_RECV, heap);
-
-        if (rc != 0) {
-                nds_destruct(&mxa->recv_nds);
-                nds_destruct(&mxa->send_nds);
-                ndr_heap_destroy(mxa->heap);
-                mxa->heap = NULL;
-                clnt->heap = NULL;
-                return (-1);
-        }
-
-        if (clnt->nonull)
-                NDS_SETF(send_nds, NDS_F_NONULL);
-
-        return (0);
-}
-
-/*
- * This is the entry pointy for an RPC client call exchange with
- * a server, which will result in an smbrdr SmbTransact request.
- *
- * SmbTransact should return the number of bytes received, which
- * we record as the PDU size, or a negative error code.
- */
-static int
-ndr_xa_exchange(ndr_client_t *clnt, ndr_xa_t *mxa)
-{
-        ndr_stream_t *recv_nds = &mxa->recv_nds;
-        ndr_stream_t *send_nds = &mxa->send_nds;
-        int err, more, nbytes;
-
-        nbytes = recv_nds->pdu_max_size;
-        err = smb_fh_xactnp(clnt->xa_fd,
-            send_nds->pdu_size, (char *)send_nds->pdu_base_offset,
-            &nbytes, (char *)recv_nds->pdu_base_offset, &more);
-        if (err) {
-                recv_nds->pdu_size = 0;
-                return (-1);
-        }
-
-        recv_nds->pdu_size = nbytes;
-        return (0);
-}
-
-/*
- * This entry point will be invoked if the xa-exchange response contained
- * only the first fragment of a multi-fragment response.  The RPC client
- * code will then make repeated xa-read requests to obtain the remaining
- * fragments, which will result in smbrdr SmbReadX requests.
- *
- * SmbReadX should return the number of bytes received, in which case we
- * expand the PDU size to include the received data, or a negative error
- * code.
- */
-static int
-ndr_xa_read(ndr_client_t *clnt, ndr_xa_t *mxa)
-{
-        ndr_stream_t *nds = &mxa->recv_nds;
-        int len;
-        int nbytes;
-
-        if ((len = (nds->pdu_max_size - nds->pdu_size)) < 0)
-                return (-1);
-
-        nbytes = smb_fh_read(clnt->xa_fd, 0, len,
-            (char *)nds->pdu_base_offset + nds->pdu_size);
-
-        if (nbytes < 0)
-                return (-1);
-
-        nds->pdu_size += nbytes;
-
-        if (nds->pdu_size > nds->pdu_max_size) {
-                nds->pdu_size = nds->pdu_max_size;
-                return (-1);
-        }
-
-        return (nbytes);
-}
-
-/*
- * Preserve the heap so that the client application has access to data
- * returned from the server after an RPC call.
- */
-static void
-ndr_xa_preserve(ndr_client_t *clnt, ndr_xa_t *mxa)
-{
-        assert(clnt->heap == mxa->heap);
-
-        clnt->heap_preserved = B_TRUE;
-        mxa->heap = NULL;
-}
-
-/*
- * Dispose of the transaction streams.  If the heap has not been
- * preserved, we can destroy it here.
- */
-static void
-ndr_xa_destruct(ndr_client_t *clnt, ndr_xa_t *mxa)
-{
-        nds_destruct(&mxa->recv_nds);
-        nds_destruct(&mxa->send_nds);
-
-        if (!clnt->heap_preserved) {
-                ndr_heap_destroy(mxa->heap);
-                mxa->heap = NULL;
-                clnt->heap = NULL;
-        }
-}
-
-/*
- * Dispose of a preserved heap.
- */
-static void
-ndr_xa_release(ndr_client_t *clnt)
-{
-        if (clnt->heap_preserved) {
-                ndr_heap_destroy(clnt->heap);
-                clnt->heap = NULL;
-                clnt->heap_preserved = B_FALSE;
-        }
-}
-
-
-/*
- * Compare the time here with the remote time on the server
- * and report clock skew.
- */
-void
-ndr_srvsvc_timecheck(char *server, char *domain)
-{
-        char                    hostname[MAXHOSTNAMELEN];
-        struct timeval          dc_tv;
-        struct tm               dc_tm;
-        struct tm               *tm;
-        time_t                  tnow;
-        time_t                  tdiff;
-        int                     priority;
-
-        if (srvsvc_net_remote_tod(server, domain, &dc_tv, &dc_tm) < 0) {
-                syslog(LOG_DEBUG, "srvsvc_net_remote_tod failed");
-                return;
-        }
-
-        tnow = time(NULL);
-
-        if (tnow > dc_tv.tv_sec)
-                tdiff = (tnow - dc_tv.tv_sec) / SECSPERMIN;
-        else
-                tdiff = (dc_tv.tv_sec - tnow) / SECSPERMIN;
-
-        if (tdiff != 0) {
-                (void) strlcpy(hostname, "localhost", MAXHOSTNAMELEN);
-                (void) gethostname(hostname, MAXHOSTNAMELEN);
-
-                priority = (tdiff > 2) ? LOG_NOTICE : LOG_DEBUG;
-                syslog(priority, "DC [%s] clock skew detected: %u minutes",
-                    server, tdiff);
-
-                tm = gmtime(&dc_tv.tv_sec);
-                syslog(priority, "%-8s  UTC: %s", server, asctime(tm));
-                tm = gmtime(&tnow);
-                syslog(priority, "%-8s  UTC: %s", hostname, asctime(tm));
-        }
 }