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


  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 
  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  *
  72  *      NT_STATUS_INTERNAL_ERROR        (bad args etc)
  73  *      NT_STATUS_NO_MEMORY
  74  */
  75 DWORD
  76 ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
  77     char *username, const char *service)
  78 {
  79         struct smb_ctx          *ctx = NULL;
  80         ndr_client_t            *clnt = NULL;
  81         ndr_service_t           *svc;
  82         DWORD                   status;
  83         int                     fd = -1;
  84         int                     rc;
  85 
  86         if (handle == NULL || server == NULL || server[0] == '\0' ||
  87             domain == NULL || username == NULL)
  88                 return (NT_STATUS_INTERNAL_ERROR);
  89 
  90         /* In case the service was not registered... */
  91         if ((svc = ndr_svc_lookup_name(service)) == NULL)
  92                 return (NT_STATUS_INTERNAL_ERROR);
  93 
  94         /*
  95          * Some callers pass this when they want a NULL session.
  96          * Todo: have callers pass an empty string for that.
  97          */
  98         if (strcmp(username, MLSVC_ANON_USER) == 0)
  99                 username = "";
 100 
 101         /*
 102          * Setup smbfs library handle, authenticate, connect to
 103          * the IPC$ share.  This will reuse an existing connection
 104          * if the driver already has one for this combination of
 105          * server, user, domain.  It may return any of:
 106          *      NT_STATUS_BAD_NETWORK_PATH      (get server addr)
 107          *      NT_STATUS_NETWORK_ACCESS_DENIED (connect, auth)
 108          *      NT_STATUS_BAD_NETWORK_NAME      (tcon)
 109          */
 110         status = smbrdr_ctx_new(&ctx, server, domain, username);
 111         if (status != NT_STATUS_SUCCESS) {
 112                 syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
 113                     "(Srv=%s Dom=%s User=%s), %s (0x%x)",
 114                     server, domain, username,
 115                     xlate_nt_status(status), status);
 116                 /* Tell the DC Locator this DC failed. */
 117                 smb_ddiscover_bad_dc(server);
 118                 goto errout;
 119         }
 120 
 121         /*
 122          * Open the named pipe.

 123          */
 124         fd = smb_fh_open(ctx, svc->endpoint, O_RDWR);
 125         if (fd < 0) {
 126                 rc = errno;
 127                 syslog(LOG_DEBUG, "ndr_rpc_bind: "
 128                     "smb_fh_open (%s) err=%d",
 129                     svc->endpoint, rc);
 130                 switch (rc) {
 131                 case EACCES:
 132                         status = NT_STATUS_ACCESS_DENIED;
 133                         break;
 134                 default:
 135                         status = NT_STATUS_BAD_NETWORK_NAME;
 136                         break;
 137                 }
 138                 goto errout;
 139         }
 140 
 141         /*
 142          * Setup the RPC client handle.
 143          */
 144         if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) {
 145                 status = NT_STATUS_NO_MEMORY;
 146                 goto errout;








 147         }
 148         bzero(clnt, sizeof (ndr_client_t));
 149 
 150         clnt->handle = &handle->handle;
 151         clnt->xa_init = ndr_xa_init;
 152         clnt->xa_exchange = ndr_xa_exchange;
 153         clnt->xa_read = ndr_xa_read;
 154         clnt->xa_preserve = ndr_xa_preserve;
 155         clnt->xa_destruct = ndr_xa_destruct;
 156         clnt->xa_release = ndr_xa_release;
 157         clnt->xa_private = ctx;
 158         clnt->xa_fd = fd;
 159 
 160         ndr_svc_binding_pool_init(&clnt->binding_list,
 161             clnt->binding_pool, NDR_N_BINDING_POOL);
 162 
 163         if ((clnt->heap = ndr_heap_create()) == NULL) {
 164                 status = NT_STATUS_NO_MEMORY;
 165                 goto errout;
 166         }
 167 
 168         /*
 169          * Fill in the caller's handle.

 170          */
 171         bzero(&handle->handle, sizeof (ndr_hdid_t));
 172         handle->clnt = clnt;
 173 
 174         /*
 175          * Do the OtW RPC bind.
 176          */
 177         rc = ndr_clnt_bind(clnt, service, &clnt->binding);
 178         switch (rc) {
 179         case NDR_DRC_FAULT_OUT_OF_MEMORY:
 180                 status = NT_STATUS_NO_MEMORY;
 181                 break;
 182         case NDR_DRC_FAULT_API_SERVICE_INVALID: /* not registered */
 183                 status = NT_STATUS_INTERNAL_ERROR;
 184                 break;
 185         default:
 186                 if (NDR_DRC_IS_FAULT(rc)) {
 187                         status = NT_STATUS_INVALID_PARAMETER;
 188                         break;
 189                 }
 190                 /* FALLTHROUGH */
 191         case NDR_DRC_OK:
 192                 return (NT_STATUS_SUCCESS);
 193         }
 194 
 195         syslog(LOG_DEBUG, "ndr_rpc_bind: "
 196             "ndr_clnt_bind, %s (0x%x)",
 197             xlate_nt_status(status), status);
 198 
 199 errout:
 200         handle->clnt = NULL;
 201         if (clnt != NULL) {
 202                 ndr_heap_destroy(clnt->heap);
 203                 free(clnt);
 204         }
 205         if (ctx != NULL) {
 206                 if (fd != -1)
 207                         (void) smb_fh_close(fd);
 208                 smbrdr_ctx_free(ctx);
 209         }

 210 
 211         return (status);
 212 }
 213 
 214 /*
 215  * Unbind and close the pipe to an RPC service.

 216  *
 217  * If the heap has been preserved we need to go through an xa release.
 218  * The heap is preserved during an RPC call because that's where data
 219  * returned from the server is stored.
 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;


  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;