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;
|