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 <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; 208 case NT_STATUS_SEVERITY_ERROR: 209 s = "error"; 210 break; 211 } 212 213 if (handle) { 214 svc = handle->clnt->binding->service; 215 name = svc->name; 216 } 217 218 smb_tracef("%s[0x%02x]: %s: %s (0x%08x)", 219 name, opnum, s, xlate_nt_status(status), status); 220 } 221