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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 27 */ 28 29 /* 30 * Functions to setup connections (TCP and/or NetBIOS) 31 * This has the fall-back logic for IP6, IP4, NBT 32 */ 33 34 #include <errno.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <netdb.h> 41 #include <libintl.h> 42 #include <xti.h> 43 #include <assert.h> 44 45 #include <sys/types.h> 46 #include <sys/time.h> 47 #include <sys/byteorder.h> 48 #include <sys/socket.h> 49 #include <sys/fcntl.h> 50 51 #include <netinet/in.h> 52 #include <netinet/tcp.h> 53 #include <arpa/inet.h> 54 #include <uuid/uuid.h> 55 56 #include <netsmb/smb.h> 57 #include <netsmb/smb_lib.h> 58 #include <netsmb/mchain.h> 59 #include <netsmb/netbios.h> 60 #include <netsmb/nb_lib.h> 61 #include <netsmb/smb_dev.h> 62 63 #include <cflib.h> 64 65 #include "charsets.h" 66 #include "private.h" 67 #include "smb_crypt.h" 68 69 static int 70 smb__ssnsetup(struct smb_ctx *ctx, 71 struct mbdata *mbc1, struct mbdata *mbc2); 72 73 int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *); 74 75 const char * 76 smb_iod_state_name(enum smbiod_state st) 77 { 78 const char *n = "(?)"; 79 80 switch (st) { 81 case SMBIOD_ST_UNINIT: 82 n = "UNINIT!"; 83 break; 84 case SMBIOD_ST_IDLE: 85 n = "IDLE"; 86 break; 87 case SMBIOD_ST_RECONNECT: 88 n = "RECONNECT"; 89 break; 90 case SMBIOD_ST_RCFAILED: 91 n = "RCFAILED"; 92 break; 93 case SMBIOD_ST_CONNECTED: 94 n = "CONNECTED"; 95 break; 96 case SMBIOD_ST_NEGOTIATED: 97 n = "NEGOTIATED"; 98 break; 99 case SMBIOD_ST_AUTHCONT: 100 n = "AUTHCONT"; 101 break; 102 case SMBIOD_ST_AUTHFAIL: 103 n = "AUTHFAIL"; 104 break; 105 case SMBIOD_ST_AUTHOK: 106 n = "AUTHOK"; 107 break; 108 case SMBIOD_ST_VCACTIVE: 109 n = "VCACTIVE"; 110 break; 111 case SMBIOD_ST_DEAD: 112 n = "DEAD"; 113 break; 114 } 115 116 return (n); 117 } 118 119 /* 120 * Make a new connection, or reconnect. 121 * 122 * This is called first from the door service thread in smbiod 123 * (so that can report success or failure to the door client) 124 * and thereafter it's called when we need to reconnect after a 125 * network outage (or whatever might cause connection loss). 126 */ 127 int 128 smb_iod_connect(smb_ctx_t *ctx) 129 { 130 smbioc_ossn_t *ossn = &ctx->ct_ssn; 131 smbioc_ssn_work_t *work = &ctx->ct_work; 132 char *uuid_str; 133 int err; 134 struct mbdata blob; 135 char *nego_buf = NULL; 136 uint32_t nego_len; 137 138 memset(&blob, 0, sizeof (blob)); 139 140 if (ctx->ct_srvname[0] == '\0') { 141 DPRINT("sername not set!"); 142 return (EINVAL); 143 } 144 DPRINT("server: %s", ctx->ct_srvname); 145 146 if (smb_debug) 147 dump_ctx("smb_iod_connect", ctx); 148 149 /* 150 * Get local machine name. 151 * Full name - not a NetBIOS name. 152 */ 153 if (ctx->ct_locname == NULL) { 154 err = smb_getlocalname(&ctx->ct_locname); 155 if (err) { 156 smb_error(dgettext(TEXT_DOMAIN, 157 "can't get local name"), err); 158 return (err); 159 } 160 } 161 162 /* 163 * Get local machine uuid. 164 */ 165 uuid_str = cf_get_client_uuid(); 166 if (uuid_str == NULL) { 167 err = EINVAL; 168 smb_error(dgettext(TEXT_DOMAIN, 169 "can't get local UUID"), err); 170 return (err); 171 } 172 (void) uuid_parse(uuid_str, ctx->ct_work.wk_cl_guid); 173 free(uuid_str); 174 uuid_str = NULL; 175 176 /* 177 * We're called with each IP address 178 * already copied into ct_srvaddr. 179 */ 180 ctx->ct_flags |= SMBCF_RESOLVED; 181 182 /* 183 * Ask the drvier to connect. 184 */ 185 DPRINT("Try ioctl connect..."); 186 if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_CONNECT, work) < 0) { 187 err = errno; 188 smb_error(dgettext(TEXT_DOMAIN, 189 "%s: connect failed"), 190 err, ossn->ssn_srvname); 191 return (err); 192 } 193 DPRINT("Connect OK, new state=%s", 194 smb_iod_state_name(work->wk_out_state)); 195 196 /* 197 * Setup a buffer to recv the nego. hint. 198 */ 199 nego_len = 4096; 200 err = mb_init_sz(&blob, nego_len); 201 if (err) 202 goto out; 203 nego_buf = blob.mb_top->m_data; 204 work->wk_u_auth_rbuf.lp_ptr = nego_buf; 205 work->wk_u_auth_rlen = nego_len; 206 207 /* 208 * Ask the driver for SMB negotiate 209 */ 210 DPRINT("Try ioctl negotiate..."); 211 if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_NEGOTIATE, work) < 0) { 212 err = errno; 213 smb_error(dgettext(TEXT_DOMAIN, 214 "%s: negotiate failed"), 215 err, ossn->ssn_srvname); 216 goto out; 217 } 218 DPRINT("Negotiate OK, new state=%s", 219 smb_iod_state_name(work->wk_out_state)); 220 221 nego_len = work->wk_u_auth_rlen; 222 blob.mb_top->m_len = nego_len; 223 224 if (smb_debug) { 225 DPRINT("Sec. blob: %d", nego_len); 226 smb_hexdump(nego_buf, nego_len); 227 } 228 229 /* 230 * Do SMB Session Setup (authenticate) 231 * Always "extended security" now (SPNEGO) 232 */ 233 DPRINT("Do session setup..."); 234 err = smb_ssnsetup_spnego(ctx, &blob); 235 if (err != 0) { 236 DPRINT("Session setup err=%d", err); 237 goto out; 238 } 239 240 /* 241 * Success! We return zero now, and our caller (normally 242 * the smbiod program) will then call smb_iod_work in a 243 * new thread to service this VC as long as necessary. 244 */ 245 DPRINT("Session setup OK"); 246 247 out: 248 mb_done(&blob); 249 250 return (err); 251 } 252 253 /* 254 * smb_ssnsetup_spnego 255 * 256 * This does an SMB session setup sequence using SPNEGO. 257 * The state changes seen during this sequence are there 258 * just to help track what's going on. 259 */ 260 int 261 smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb) 262 { 263 struct mbdata send_mb, recv_mb; 264 smbioc_ssn_work_t *work = &ctx->ct_work; 265 int err; 266 267 bzero(&send_mb, sizeof (send_mb)); 268 bzero(&recv_mb, sizeof (recv_mb)); 269 270 err = ssp_ctx_create_client(ctx, hint_mb); 271 if (err) 272 goto out; 273 274 /* NULL input indicates first call. */ 275 err = ssp_ctx_next_token(ctx, NULL, &send_mb); 276 if (err) { 277 DPRINT("smb__ssnsetup, ssp next, err=%d", err); 278 goto out; 279 } 280 for (;;) { 281 err = smb__ssnsetup(ctx, &send_mb, &recv_mb); 282 DPRINT("smb__ssnsetup rc=%d, new state=%s", err, 283 smb_iod_state_name(work->wk_out_state)); 284 285 if (err == 0) { 286 /* 287 * Session setup complete w/ success. 288 * Should have state AUTHOK 289 */ 290 if (work->wk_out_state != SMBIOD_ST_AUTHOK) { 291 DPRINT("Wrong state (expected AUTHOK)"); 292 } 293 break; 294 } 295 296 if (err != EINPROGRESS) { 297 /* 298 * Session setup complete w/ failure. 299 * Should have state AUTHFAIL 300 */ 301 if (work->wk_out_state != SMBIOD_ST_AUTHFAIL) { 302 DPRINT("Wrong state (expected AUTHFAIL)"); 303 } 304 goto out; 305 } 306 307 /* 308 * err == EINPROGRESS 309 * Session setup continuing. 310 * Should have state AUTHCONT 311 */ 312 if (work->wk_out_state != SMBIOD_ST_AUTHCONT) { 313 DPRINT("Wrong state (expected AUTHCONT)"); 314 } 315 316 /* middle calls get both in, out */ 317 err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb); 318 if (err) { 319 DPRINT("smb__ssnsetup, ssp next, err=%d", err); 320 goto out; 321 } 322 } 323 324 /* 325 * Only get here via break in the err==0 case above, 326 * so we're finalizing a successful session setup. 327 * 328 * NULL output token here indicates the final call. 329 */ 330 (void) ssp_ctx_next_token(ctx, &recv_mb, NULL); 331 332 /* 333 * The session key is in ctx->ct_ssnkey_buf 334 * (a.k.a. ct_work.wk_u_ssn_key_buf) 335 */ 336 337 out: 338 /* Done with ctx->ct_ssp_ctx */ 339 ssp_ctx_destroy(ctx); 340 341 return (err); 342 } 343 344 int smb_max_authtok_sz = 0x10000; 345 346 /* 347 * Session Setup function, calling the nsmb driver. 348 * 349 * Args 350 * send_mb: [in] outgoing blob data to send 351 * recv_mb: [out] received blob data buffer 352 */ 353 static int 354 smb__ssnsetup(struct smb_ctx *ctx, 355 struct mbdata *send_mb, struct mbdata *recv_mb) 356 { 357 smbioc_ossn_t *ossn = &ctx->ct_ssn; 358 smbioc_ssn_work_t *work = &ctx->ct_work; 359 mbuf_t *m; 360 int err; 361 362 /* Setup receive buffer for the auth data. */ 363 err = mb_init_sz(recv_mb, smb_max_authtok_sz); 364 if (err != 0) 365 return (err); 366 m = recv_mb->mb_top; 367 work->wk_u_auth_rbuf.lp_ptr = m->m_data; 368 work->wk_u_auth_rlen = m->m_maxlen; 369 370 /* ... and the auth data to send. */ 371 m = send_mb->mb_top; 372 work->wk_u_auth_wbuf.lp_ptr = m->m_data; 373 work->wk_u_auth_wlen = m->m_len; 374 375 DPRINT("Session setup ioctl..."); 376 if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) { 377 err = errno; 378 if (err != 0 && err != EINPROGRESS) { 379 smb_error(dgettext(TEXT_DOMAIN, 380 "%s: session setup "), 381 err, ossn->ssn_srvname); 382 } 383 } 384 DPRINT("Session setup ret %d", err); 385 386 /* Free the auth data we sent. */ 387 mb_done(send_mb); 388 389 /* Setup length of received auth data */ 390 m = recv_mb->mb_top; 391 m->m_len = work->wk_u_auth_rlen; 392 393 return (err); 394 } 395