Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15557 SMB client tries to connect twice
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12394 rb3934 Even NULL sessions should use SPNEGO
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libsmbfs/smb/connect.c
+++ new/usr/src/lib/libsmbfs/smb/connect.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 + *
26 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
26 27 */
27 28
28 29 /*
29 30 * Functions to setup connections (TCP and/or NetBIOS)
30 31 * This has the fall-back logic for IP6, IP4, NBT
31 32 */
32 33
33 34 #include <errno.h>
34 35 #include <stdio.h>
35 36 #include <string.h>
36 37 #include <strings.h>
37 38 #include <stdlib.h>
38 39 #include <unistd.h>
39 40 #include <netdb.h>
40 41 #include <libintl.h>
41 42 #include <xti.h>
42 43 #include <assert.h>
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
43 44
44 45 #include <sys/types.h>
45 46 #include <sys/time.h>
46 47 #include <sys/byteorder.h>
47 48 #include <sys/socket.h>
48 49 #include <sys/fcntl.h>
49 50
50 51 #include <netinet/in.h>
51 52 #include <netinet/tcp.h>
52 53 #include <arpa/inet.h>
54 +#include <uuid/uuid.h>
53 55
54 56 #include <netsmb/smb.h>
55 57 #include <netsmb/smb_lib.h>
58 +#include <netsmb/mchain.h>
56 59 #include <netsmb/netbios.h>
57 60 #include <netsmb/nb_lib.h>
58 61 #include <netsmb/smb_dev.h>
59 62
63 +#include <cflib.h>
64 +
60 65 #include "charsets.h"
61 66 #include "private.h"
67 +#include "smb_crypt.h"
62 68
63 -/*
64 - * SMB messages are up to 64K.
65 - * Let's leave room for two.
66 - */
67 -static int smb_tcpsndbuf = 0x20000;
68 -static int smb_tcprcvbuf = 0x20000;
69 -static int smb_connect_timeout = 30; /* seconds */
70 -int smb_recv_timeout = 30; /* seconds */
71 -
72 -int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
73 -int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
74 -int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
75 -
76 -/*
77 - * Internal set sockopt for int-sized options.
78 - * Borrowed from: libnsl/rpc/ti_opts.c
79 - */
80 69 static int
81 -smb_setopt_int(int fd, int level, int name, int val)
82 -{
83 - struct t_optmgmt oreq, ores;
84 - struct {
85 - struct t_opthdr oh;
86 - int ival;
87 - } opts;
70 +smb__ssnsetup(struct smb_ctx *ctx,
71 + struct mbdata *mbc1, struct mbdata *mbc2);
88 72
89 - /* opt header */
90 - opts.oh.len = sizeof (opts);
91 - opts.oh.level = level;
92 - opts.oh.name = name;
93 - opts.oh.status = 0;
94 - opts.ival = val;
73 +int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
95 74
96 - oreq.flags = T_NEGOTIATE;
97 - oreq.opt.buf = (void *)&opts;
98 - oreq.opt.len = sizeof (opts);
99 -
100 - ores.flags = 0;
101 - ores.opt.buf = NULL;
102 - ores.opt.maxlen = 0;
103 -
104 - if (t_optmgmt(fd, &oreq, &ores) < 0) {
105 - DPRINT("t_opgmgnt, t_errno = %d", t_errno);
106 - if (t_errno == TSYSERR)
107 - return (errno);
108 - return (EPROTO);
109 - }
110 - if (ores.flags != T_SUCCESS) {
111 - DPRINT("flags 0x%x, status 0x%x",
112 - (int)ores.flags, (int)opts.oh.status);
113 - return (EPROTO);
114 - }
115 -
116 - return (0);
117 -}
118 -
119 -static int
120 -smb_setopts(int fd)
75 +const char *
76 +smb_iod_state_name(enum smbiod_state st)
121 77 {
122 - int err;
78 + const char *n = "(?)";
123 79
124 - /*
125 - * Set various socket/TCP options.
126 - * Failures here are not fatal -
127 - * just log a complaint.
128 - *
129 - * We don't need these two:
130 - * SO_RCVTIMEO, SO_SNDTIMEO
131 - */
132 -
133 - err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
134 - if (err) {
135 - DPRINT("set SO_SNDBUF, err %d", err);
136 - }
137 -
138 - err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
139 - if (err) {
140 - DPRINT("set SO_RCVBUF, err %d", err);
141 - }
142 -
143 - err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
144 - if (err) {
145 - DPRINT("set SO_KEEPALIVE, err %d", err);
146 - }
147 -
148 - err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
149 - if (err) {
150 - DPRINT("set TCP_NODELAY, err %d", err);
151 - }
152 -
153 - /* Set the connect timeout (in milliseconds). */
154 - err = smb_setopt_int(fd, IPPROTO_TCP,
155 - TCP_CONN_ABORT_THRESHOLD,
156 - smb_connect_timeout * 1000);
157 - if (err) {
158 - DPRINT("set connect timeout, err %d", err);
159 - }
160 - return (0);
161 -}
162 -
163 -
164 -int
165 -conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
166 -{
167 - struct sockaddr_in6 sin6;
168 - char *dev = "/dev/tcp6";
169 - char paddrbuf[INET6_ADDRSTRLEN];
170 - struct t_call sndcall;
171 - int fd, err;
172 -
173 - if (sa->sa_family != AF_INET6) {
174 - DPRINT("bad af %d", sa->sa_family);
175 - return (EINVAL);
176 - }
177 - bcopy(sa, &sin6, sizeof (sin6));
178 - sin6.sin6_port = htons(port);
179 -
180 - DPRINT("tcp6: %s (%d)",
181 - inet_ntop(AF_INET6, &sin6.sin6_addr,
182 - paddrbuf, sizeof (paddrbuf)), port);
183 -
184 - fd = t_open(dev, O_RDWR, NULL);
185 - if (fd < 0) {
186 - /* Assume t_errno = TSYSERR */
187 - err = errno;
188 - perror(dev);
189 - return (err);
190 - }
191 - if ((err = smb_setopts(fd)) != 0)
192 - goto errout;
193 - if (t_bind(fd, NULL, NULL) < 0) {
194 - DPRINT("t_bind t_errno %d", t_errno);
195 - if (t_errno == TSYSERR)
196 - err = errno;
197 - else
198 - err = EPROTO;
199 - goto errout;
200 - }
201 - sndcall.addr.maxlen = sizeof (sin6);
202 - sndcall.addr.len = sizeof (sin6);
203 - sndcall.addr.buf = (void *) &sin6;
204 - sndcall.opt.len = 0;
205 - sndcall.udata.len = 0;
206 - if (t_connect(fd, &sndcall, NULL) < 0) {
207 - err = get_xti_err(fd);
208 - DPRINT("connect, err %d", err);
209 - goto errout;
210 - }
211 -
212 - DPRINT("tcp6: connected, fd=%d", fd);
213 - ctx->ct_tran_fd = fd;
214 - return (0);
215 -
216 -errout:
217 - close(fd);
218 - return (err);
219 -}
220 -
221 -/*
222 - * This is used for both SMB over TCP (port 445)
223 - * and NetBIOS - see conn_nbt().
224 - */
225 -int
226 -conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
227 -{
228 - struct sockaddr_in sin;
229 - char *dev = "/dev/tcp";
230 - char paddrbuf[INET_ADDRSTRLEN];
231 - struct t_call sndcall;
232 - int fd, err;
233 -
234 - if (sa->sa_family != AF_INET) {
235 - DPRINT("bad af %d", sa->sa_family);
236 - return (EINVAL);
237 - }
238 - bcopy(sa, &sin, sizeof (sin));
239 - sin.sin_port = htons(port);
240 -
241 - DPRINT("tcp4: %s (%d)",
242 - inet_ntop(AF_INET, &sin.sin_addr,
243 - paddrbuf, sizeof (paddrbuf)), port);
244 -
245 - fd = t_open(dev, O_RDWR, NULL);
246 - if (fd < 0) {
247 - /* Assume t_errno = TSYSERR */
248 - err = errno;
249 - perror(dev);
250 - return (err);
251 - }
252 - if ((err = smb_setopts(fd)) != 0)
253 - goto errout;
254 - if (t_bind(fd, NULL, NULL) < 0) {
255 - DPRINT("t_bind t_errno %d", t_errno);
256 - if (t_errno == TSYSERR)
257 - err = errno;
258 - else
259 - err = EPROTO;
260 - goto errout;
261 - }
262 - sndcall.addr.maxlen = sizeof (sin);
263 - sndcall.addr.len = sizeof (sin);
264 - sndcall.addr.buf = (void *) &sin;
265 - sndcall.opt.len = 0;
266 - sndcall.udata.len = 0;
267 - if (t_connect(fd, &sndcall, NULL) < 0) {
268 - err = get_xti_err(fd);
269 - DPRINT("connect, err %d", err);
270 - goto errout;
271 - }
272 -
273 - DPRINT("tcp4: connected, fd=%d", fd);
274 - ctx->ct_tran_fd = fd;
275 - return (0);
276 -
277 -errout:
278 - close(fd);
279 - return (err);
280 -}
281 -
282 -/*
283 - * Open a NetBIOS connection (session, port 139)
284 - *
285 - * The optional name parameter, if passed, means
286 - * we found the sockaddr via NetBIOS name lookup,
287 - * and can just use that for our session request.
288 - * Otherwise (if name is NULL), we're connecting
289 - * by IP address, and need to come up with the
290 - * NetBIOS name by other means.
291 - */
292 -int
293 -conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
294 -{
295 - struct sockaddr_in sin;
296 - struct sockaddr *sa;
297 - char server[NB_NAMELEN];
298 - char workgroup[NB_NAMELEN];
299 - int err, nberr, port;
300 -
301 - bcopy(saarg, &sin, sizeof (sin));
302 - sa = (struct sockaddr *)&sin;
303 -
304 - switch (sin.sin_family) {
305 - case AF_NETBIOS: /* our fake AF */
306 - sin.sin_family = AF_INET;
80 + switch (st) {
81 + case SMBIOD_ST_UNINIT:
82 + n = "UNINIT!";
307 83 break;
308 - case AF_INET:
84 + case SMBIOD_ST_IDLE:
85 + n = "IDLE";
309 86 break;
310 - default:
311 - DPRINT("bad af %d", sin.sin_family);
312 - return (EINVAL);
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;
313 114 }
314 - port = IPPORT_NETBIOS_SSN;
315 115
316 - /*
317 - * If we have a NetBIOS name, just use it.
318 - * This is the path taken when we've done a
319 - * NetBIOS name lookup on this name to get
320 - * the IP address in the passed sa. Otherwise,
321 - * we're connecting by IP address, and need to
322 - * figure out what NetBIOS name to use.
323 - */
324 - if (name) {
325 - strlcpy(server, name, sizeof (server));
326 - DPRINT("given name: %s", server);
327 - } else {
328 - /*
329 - *
330 - * Try a NetBIOS node status query,
331 - * which searches for a type=[20] name.
332 - * If that doesn't work, just use the
333 - * (fake) "*SMBSERVER" name.
334 - */
335 - DPRINT("try node status");
336 - server[0] = '\0';
337 - nberr = nbns_getnodestatus(ctx->ct_nb,
338 - &sin.sin_addr, server, workgroup);
339 - if (nberr == 0 && server[0] != '\0') {
340 - /* Found the name. Save for reconnect. */
341 - DPRINT("found name: %s", server);
342 - strlcpy(ctx->ct_srvname, server,
343 - sizeof (ctx->ct_srvname));
344 - } else {
345 - DPRINT("getnodestatus, nberr %d", nberr);
346 - strlcpy(server, "*SMBSERVER", sizeof (server));
347 - }
348 - }
349 -
350 - /*
351 - * Establish the TCP connection.
352 - * Careful to close it on errors.
353 - */
354 - if ((err = conn_tcp4(ctx, sa, port)) != 0) {
355 - DPRINT("TCP connect: err=%d", err);
356 - goto out;
357 - }
358 -
359 - /* Connected. Do NetBIOS session request. */
360 - err = nb_ssn_request(ctx, server);
361 - if (err)
362 - DPRINT("ssn_rq, err %d", err);
363 -
364 -out:
365 - if (err) {
366 - if (ctx->ct_tran_fd != -1) {
367 - close(ctx->ct_tran_fd);
368 - ctx->ct_tran_fd = -1;
369 - }
370 - }
371 - return (err);
116 + return (n);
372 117 }
373 118
374 119 /*
375 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).
376 126 */
377 127 int
378 128 smb_iod_connect(smb_ctx_t *ctx)
379 129 {
380 - struct sockaddr *sa;
381 - int err, err2;
130 + smbioc_ossn_t *ossn = &ctx->ct_ssn;
131 + smbioc_ssn_work_t *work = &ctx->ct_work;
132 + char *uuid_str;
133 + int err;
382 134 struct mbdata blob;
135 + char *nego_buf = NULL;
136 + uint32_t nego_len;
383 137
384 138 memset(&blob, 0, sizeof (blob));
385 139
386 140 if (ctx->ct_srvname[0] == '\0') {
387 141 DPRINT("sername not set!");
388 142 return (EINVAL);
389 143 }
390 144 DPRINT("server: %s", ctx->ct_srvname);
391 145
392 146 if (smb_debug)
393 147 dump_ctx("smb_iod_connect", ctx);
394 148
395 149 /*
396 - * This may be a reconnect, so
397 - * cleanup if necessary.
398 - */
399 - if (ctx->ct_tran_fd != -1) {
400 - close(ctx->ct_tran_fd);
401 - ctx->ct_tran_fd = -1;
402 - }
403 -
404 - /*
405 150 * Get local machine name.
406 151 * Full name - not a NetBIOS name.
407 152 */
408 153 if (ctx->ct_locname == NULL) {
409 154 err = smb_getlocalname(&ctx->ct_locname);
410 155 if (err) {
411 156 smb_error(dgettext(TEXT_DOMAIN,
412 157 "can't get local name"), err);
413 158 return (err);
414 159 }
415 160 }
416 161
417 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 + /*
418 177 * We're called with each IP address
419 178 * already copied into ct_srvaddr.
420 179 */
421 180 ctx->ct_flags |= SMBCF_RESOLVED;
422 181
423 - sa = &ctx->ct_srvaddr.sa;
424 - switch (sa->sa_family) {
425 -
426 - case AF_INET6:
427 - err = conn_tcp6(ctx, sa, IPPORT_SMB);
428 - break;
429 -
430 - case AF_INET:
431 - err = conn_tcp4(ctx, sa, IPPORT_SMB);
432 - /*
433 - * If port 445 was not listening, try port 139.
434 - * Note: Not doing NetBIOS name lookup here.
435 - * We already have the IP address.
436 - */
437 - switch (err) {
438 - case ECONNRESET:
439 - case ECONNREFUSED:
440 - err2 = conn_nbt(ctx, sa, NULL);
441 - if (err2 == 0)
442 - err = 0;
443 - }
444 - break;
445 -
446 - case AF_NETBIOS:
447 - /* Like AF_INET, but use NetBIOS ssn. */
448 - err = conn_nbt(ctx, sa, ctx->ct_srvname);
449 - break;
450 -
451 - default:
452 - DPRINT("skipped family %d", sa->sa_family);
453 - err = EPROTONOSUPPORT;
454 - break;
455 - }
456 -
457 -
458 - if (err) {
459 - DPRINT("connect, err=%d", err);
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);
460 191 return (err);
461 192 }
193 + DPRINT("Connect OK, new state=%s",
194 + smb_iod_state_name(work->wk_out_state));
462 195
463 196 /*
464 - * Do SMB Negotiate Protocol.
197 + * Setup a buffer to recv the nego. hint.
465 198 */
466 - err = smb_negprot(ctx, &blob);
199 + nego_len = 4096;
200 + err = mb_init_sz(&blob, nego_len);
467 201 if (err)
468 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;
469 206
470 207 /*
471 - * Empty user name means an explicit request for
472 - * NULL session setup, which is a special case.
473 - * If negotiate determined that we want to do
474 - * SMB signing, we have to turn that off for a
475 - * NULL session. [MS-SMB 3.3.5.3].
208 + * Ask the driver for SMB negotiate
476 209 */
477 - if (ctx->ct_user[0] == '\0') {
478 - /* Null user should have null domain too. */
479 - ctx->ct_domain[0] = '\0';
480 - ctx->ct_authflags = SMB_AT_ANON;
481 - ctx->ct_clnt_caps &= ~SMB_CAP_EXT_SECURITY;
482 - ctx->ct_vcflags &= ~SMBV_WILL_SIGN;
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;
483 217 }
218 + DPRINT("Negotiate OK, new state=%s",
219 + smb_iod_state_name(work->wk_out_state));
484 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 +
485 229 /*
486 230 * Do SMB Session Setup (authenticate)
487 - *
488 - * If the server negotiated extended security,
489 - * run the SPNEGO state machine, otherwise do
490 - * one of the old-style variants.
231 + * Always "extended security" now (SPNEGO)
491 232 */
492 - if (ctx->ct_clnt_caps & SMB_CAP_EXT_SECURITY) {
493 - err = smb_ssnsetup_spnego(ctx, &blob);
494 - } else {
495 - /*
496 - * Server did NOT negotiate extended security.
497 - * Try NTLMv2, NTLMv1, or ANON (if enabled).
498 - */
499 - if (ctx->ct_authflags & SMB_AT_NTLM2) {
500 - err = smb_ssnsetup_ntlm2(ctx);
501 - } else if (ctx->ct_authflags & SMB_AT_NTLM1) {
502 - err = smb_ssnsetup_ntlm1(ctx);
503 - } else if (ctx->ct_authflags & SMB_AT_ANON) {
504 - err = smb_ssnsetup_null(ctx);
505 - } else {
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) {
506 286 /*
507 - * Don't return EAUTH, because a new
508 - * password prompt will not help.
287 + * Session setup complete w/ success.
288 + * Should have state AUTHOK
509 289 */
510 - DPRINT("No NTLM authflags");
511 - err = ENOTSUP;
290 + if (work->wk_out_state != SMBIOD_ST_AUTHOK) {
291 + DPRINT("Wrong state (expected AUTHOK)");
292 + }
293 + break;
512 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 + }
513 322 }
514 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 signing key is in ctx->ct_mackey
334 + * (a.k.a. ct_work.wk_iods.is_u_mackey)
335 + * and session key is in ctx->ct_ssn_key
336 + * (a.k.a. ct_work.wk_iods.is_ssn_key)
337 + */
338 +
515 339 out:
516 - mb_done(&blob);
340 + /* Done with ctx->ct_ssp_ctx */
341 + ssp_ctx_destroy(ctx);
517 342
518 - if (err) {
519 - close(ctx->ct_tran_fd);
520 - ctx->ct_tran_fd = -1;
521 - } else {
522 - /* Tell library code we have a session. */
523 - ctx->ct_flags |= SMBCF_SSNACTIVE;
524 - DPRINT("tran_fd = %d", ctx->ct_tran_fd);
343 + return (err);
344 +}
345 +
346 +int smb_max_authtok_sz = 0x10000;
347 +
348 +/*
349 + * Session Setup function, calling the nsmb driver.
350 + *
351 + * Args
352 + * send_mb: [in] outgoing blob data to send
353 + * recv_mb: [out] received blob data buffer
354 + */
355 +static int
356 +smb__ssnsetup(struct smb_ctx *ctx,
357 + struct mbdata *send_mb, struct mbdata *recv_mb)
358 +{
359 + smbioc_ossn_t *ossn = &ctx->ct_ssn;
360 + smbioc_ssn_work_t *work = &ctx->ct_work;
361 + mbuf_t *m;
362 + int err;
363 +
364 + /* Setup receive buffer for the auth data. */
365 + err = mb_init_sz(recv_mb, smb_max_authtok_sz);
366 + if (err != 0)
367 + return (err);
368 + m = recv_mb->mb_top;
369 + work->wk_u_auth_rbuf.lp_ptr = m->m_data;
370 + work->wk_u_auth_rlen = m->m_maxlen;
371 +
372 + /* ... and the auth data to send. */
373 + m = send_mb->mb_top;
374 + work->wk_u_auth_wbuf.lp_ptr = m->m_data;
375 + work->wk_u_auth_wlen = m->m_len;
376 +
377 + DPRINT("Session setup ioctl...");
378 + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_IOD_SSNSETUP, work) < 0) {
379 + err = errno;
380 + if (err != 0 && err != EINPROGRESS) {
381 + smb_error(dgettext(TEXT_DOMAIN,
382 + "%s: session setup "),
383 + err, ossn->ssn_srvname);
384 + }
525 385 }
386 + DPRINT("Session setup ret %d", err);
526 387
388 + /* Free the auth data we sent. */
389 + mb_done(send_mb);
390 +
391 + /* Setup length of received auth data */
392 + m = recv_mb->mb_top;
393 + m->m_len = work->wk_u_auth_rlen;
394 +
527 395 return (err);
528 396 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX