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-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
NEX-16805 Add smbutil discon command
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
re #12739 rb4173 AD join with lmauth_level=2 fails
re #12394 rb3934 Even NULL sessions should use SPNEGO
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libsmbfs/smb/ctx.c
+++ new/usr/src/lib/libsmbfs/smb/ctx.c
1 1 /*
2 2 * Copyright (c) 2000, Boris Popov
3 3 * All rights reserved.
4 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6 6 * modification, are permitted provided that the following conditions
7 7 * are met:
8 8 * 1. Redistributions of source code must retain the above copyright
9 9 * notice, this list of conditions and the following disclaimer.
10 10 * 2. Redistributions in binary form must reproduce the above copyright
11 11 * notice, this list of conditions and the following disclaimer in the
12 12 * documentation and/or other materials provided with the distribution.
13 13 * 3. All advertising materials mentioning features or use of this software
14 14 * must display the following acknowledgement:
15 15 * This product includes software developed by Boris Popov.
16 16 * 4. Neither the name of the author nor the names of any co-contributors
17 17 * may be used to endorse or promote products derived from this software
18 18 * without specific prior written permission.
19 19 *
20 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
27 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 30 * SUCH DAMAGE.
31 31 *
32 32 * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
33 33 */
34 34
35 35 /*
36 36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37 - * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
37 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
38 38 */
39 39
40 40 #include <sys/param.h>
41 41 #include <sys/ioctl.h>
42 42 #include <sys/time.h>
43 43 #include <sys/mount.h>
44 44 #include <sys/types.h>
45 45 #include <sys/byteorder.h>
46 46
47 47 #include <fcntl.h>
48 48 #include <ctype.h>
49 49 #include <errno.h>
50 50 #include <stdio.h>
51 51 #include <string.h>
52 52 #include <strings.h>
53 53 #include <stdlib.h>
54 54 #include <pwd.h>
55 55 #include <grp.h>
56 56 #include <unistd.h>
57 57 #include <libintl.h>
58 58 #include <assert.h>
59 59 #include <nss_dbdefs.h>
60 60
61 61 #include <cflib.h>
62 62 #include <netsmb/smb_lib.h>
63 63 #include <netsmb/netbios.h>
64 64 #include <netsmb/nb_lib.h>
65 65 #include <netsmb/smb_dev.h>
66 66
67 67 #include "charsets.h"
68 68 #include "private.h"
69 69 #include "ntlm.h"
70 70
71 71 #ifndef FALSE
72 72 #define FALSE 0
73 73 #endif
74 74 #ifndef TRUE
75 75 #define TRUE 1
76 76 #endif
77 77
78 78 #define SMB_AT_DEFAULT (SMB_AT_KRB5 | SMB_AT_NTLM2)
79 79 #define SMB_AT_MINAUTH (SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
80 80
81 81 struct nv {
82 82 char *name;
83 83 int value;
84 84 };
85 85
86 86 /* These two may be set by commands. */
87 87 int smb_debug, smb_verbose;
88 88
89 89 /*
90 90 * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
91 91 */
92 92 const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
93 93
94 94 /*
95 95 * Defaults for new contexts (connections to servers).
96 96 * These are set by smbfs_set_default_...
97 97 */
98 98 static char default_domain[SMBIOC_MAX_NAME];
99 99 static char default_user[SMBIOC_MAX_NAME];
100 100
101 101
102 102 /*
103 103 * Give the RPC library a callback hook that will be
104 104 * called whenever we destroy or reinit an smb_ctx_t.
105 105 * The name rpc_cleanup_smbctx() is legacy, and was
106 106 * originally a direct call into the RPC code.
107 107 */
108 108 static smb_ctx_close_hook_t close_hook;
109 109 static void
110 110 rpc_cleanup_smbctx(struct smb_ctx *ctx)
111 111 {
112 112 if (close_hook)
113 113 (*close_hook)(ctx);
114 114 }
115 115 void
116 116 smb_ctx_set_close_hook(smb_ctx_close_hook_t hook)
117 117 {
118 118 close_hook = hook;
119 119 }
120 120
121 121 void
122 122 dump_ctx_flags(int flags)
123 123 {
124 124 printf(" Flags: ");
125 125 if (flags == 0)
126 126 printf("0");
127 127 if (flags & SMBCF_NOPWD)
128 128 printf("NOPWD ");
129 129 if (flags & SMBCF_SRIGHTS)
130 130 printf("SRIGHTS ");
131 131 if (flags & SMBCF_LOCALE)
132 132 printf("LOCALE ");
133 133 if (flags & SMBCF_CMD_DOM)
134 134 printf("CMD_DOM ");
135 135 if (flags & SMBCF_CMD_USR)
136 136 printf("CMD_USR ");
137 137 if (flags & SMBCF_CMD_PW)
138 138 printf("CMD_PW ");
139 139 if (flags & SMBCF_RESOLVED)
140 140 printf("RESOLVED ");
|
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
141 141 if (flags & SMBCF_KCBAD)
142 142 printf("KCBAD ");
143 143 if (flags & SMBCF_KCFOUND)
144 144 printf("KCFOUND ");
145 145 if (flags & SMBCF_BROWSEOK)
146 146 printf("BROWSEOK ");
147 147 if (flags & SMBCF_AUTHREQ)
148 148 printf("AUTHREQ ");
149 149 if (flags & SMBCF_KCSAVE)
150 150 printf("KCSAVE ");
151 - if (flags & SMBCF_XXX)
152 - printf("XXX ");
153 - if (flags & SMBCF_SSNACTIVE)
154 - printf("SSNACTIVE ");
155 151 if (flags & SMBCF_KCDOMAIN)
156 152 printf("KCDOMAIN ");
157 153 printf("\n");
158 154 }
159 155
160 156 void
161 157 dump_iod_ssn(smb_iod_ssn_t *is)
162 158 {
163 159 static const char zeros[NTLM_HASH_SZ] = {0};
164 160 struct smbioc_ossn *ssn = &is->iod_ossn;
165 161
166 162 printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
167 163 dump_sockaddr(&ssn->ssn_srvaddr.sa);
168 164 printf(" dom=\"%s\", user=\"%s\"\n",
169 165 ssn->ssn_domain, ssn->ssn_user);
170 166 printf(" ct_vopt=0x%x, ct_owner=%d\n",
171 167 ssn->ssn_vopt, ssn->ssn_owner);
168 + printf(" ct_minver=0x%x, ct_maxver=0x%x\n",
169 + ssn->ssn_minver, ssn->ssn_maxver);
172 170 printf(" ct_authflags=0x%x\n", is->iod_authflags);
173 171
174 172 printf(" ct_nthash:");
175 173 if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
176 174 smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
177 175 else
178 176 printf(" {0}\n");
179 177
180 178 printf(" ct_lmhash:");
181 179 if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
182 180 smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
183 181 else
184 182 printf(" {0}\n");
185 183 }
186 184
187 185 void
188 186 dump_ctx(char *where, struct smb_ctx *ctx)
189 187 {
190 188 printf("context %s:\n", where);
191 189 dump_ctx_flags(ctx->ct_flags);
192 190
193 191 if (ctx->ct_locname)
194 192 printf(" localname=\"%s\"", ctx->ct_locname);
195 193 else
196 194 printf(" localname=NULL");
197 195
198 196 if (ctx->ct_fullserver)
199 197 printf(" fullserver=\"%s\"", ctx->ct_fullserver);
200 198 else
201 199 printf(" fullserver=NULL");
202 200
203 201 if (ctx->ct_srvaddr_s)
204 202 printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
205 203 else
206 204 printf(" srvaddr_s=NULL\n");
207 205
208 206 if (ctx->ct_addrinfo)
209 207 dump_addrinfo(ctx->ct_addrinfo);
210 208 else
211 209 printf(" ct_addrinfo = NULL\n");
212 210
213 211 dump_iod_ssn(&ctx->ct_iod_ssn);
214 212
215 213 printf(" share_name=\"%s\", share_type=%d\n",
216 214 ctx->ct_origshare ? ctx->ct_origshare : "",
217 215 ctx->ct_shtype_req);
218 216
219 217 printf(" ct_home=\"%s\"\n", ctx->ct_home);
220 218 printf(" ct_rpath=\"%s\"\n", ctx->ct_rpath);
221 219 }
222 220
223 221 int
224 222 smb_ctx_alloc(struct smb_ctx **ctx_pp)
225 223 {
226 224 smb_ctx_t *ctx;
227 225 int err;
228 226
229 227 ctx = malloc(sizeof (*ctx));
230 228 if (ctx == NULL)
231 229 return (ENOMEM);
232 230 err = smb_ctx_init(ctx);
233 231 if (err != 0) {
234 232 free(ctx);
235 233 return (err);
236 234 }
237 235 *ctx_pp = ctx;
238 236 return (0);
239 237 }
240 238
241 239 /*
242 240 * Initialize an smb_ctx struct (defaults)
243 241 */
244 242 int
245 243 smb_ctx_init(struct smb_ctx *ctx)
246 244 {
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
247 245 int error;
248 246
249 247 bzero(ctx, sizeof (*ctx));
250 248
251 249 error = nb_ctx_create(&ctx->ct_nb);
252 250 if (error)
253 251 return (error);
254 252
255 253 ctx->ct_dev_fd = -1;
256 254 ctx->ct_door_fd = -1;
257 - ctx->ct_tran_fd = -1;
258 255 ctx->ct_parsedlevel = SMBL_NONE;
259 256 ctx->ct_minlevel = SMBL_NONE;
260 257 ctx->ct_maxlevel = SMBL_PATH;
261 258
262 259 /* Fill in defaults */
263 - ctx->ct_vopt = SMBVOPT_EXT_SEC;
260 + ctx->ct_vopt = SMBVOPT_SIGNING_ENABLED;
264 261 ctx->ct_owner = SMBM_ANY_OWNER;
265 262 ctx->ct_authflags = SMB_AT_DEFAULT;
266 263 ctx->ct_minauth = SMB_AT_MINAUTH;
264 + ctx->ct_maxver = SMB2_DIALECT_MAX;
267 265
268 266 /*
269 267 * Default domain, user, ...
270 268 */
271 269 strlcpy(ctx->ct_domain, default_domain,
272 270 sizeof (ctx->ct_domain));
273 271 strlcpy(ctx->ct_user, default_user,
274 272 sizeof (ctx->ct_user));
275 273
276 274 return (0);
277 275 }
278 276
279 277 /*
280 278 * "Scan" the command line args to find the server name,
281 279 * user name, and share name, as needed. We need these
282 280 * before reading the RC files and/or sharectl values.
283 281 *
284 282 * The sequence for getting all the members filled in
285 283 * has some tricky aspects. Here's how it works:
286 284 *
287 285 * The search order for options is as follows:
288 286 * command line options
289 287 * values parsed from UNC path (cmd)
290 288 * values from RC file (per-user)
291 289 * values from SMF (system-wide)
292 290 * built-in defaults
293 291 *
294 292 * Normally, one would simply get all the values starting with
295 293 * the bottom of the above list and working to the top, and
296 294 * overwriting values as you go. But we need an exception.
297 295 *
298 296 * In this function, we parse the UNC path and command line options,
299 297 * because we need (at least) the server name when we're getting the
300 298 * SMF and RC file values. However, values we get from the command
301 299 * should not be overwritten by SMF or RC file parsing, so we mark
302 300 * values from the command as "from CMD" and the RC file parser
303 301 * leaves in place any values so marked. See: SMBCF_CMD_*
304 302 *
305 303 * The semantics of these flags are: "This value came from the
306 304 * current command instance, not from sources that may apply to
307 305 * multiple commands." (Different from the old "FROMUSR" flag.)
308 306 *
309 307 * Note that smb_ctx_opt() is called later to handle the
310 308 * remaining options, which should be ignored here.
311 309 * The (magic) leading ":" in cf_getopt() makes it
312 310 * ignore options not in the options string.
313 311 */
314 312 int
315 313 smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
316 314 int minlevel, int maxlevel, int sharetype)
317 315 {
318 316 int ind, opt, error = 0;
319 317 int aflg = 0, uflg = 0;
320 318 const char *arg;
321 319
322 320 /*
323 321 * Parse options, if any. Values from here too
324 322 * are marked as "from CMD".
325 323 */
|
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
326 324 if (argv == NULL)
327 325 return (0);
328 326
329 327 ctx->ct_minlevel = minlevel;
330 328 ctx->ct_maxlevel = maxlevel;
331 329 ctx->ct_shtype_req = sharetype;
332 330
333 331 cf_opt_lock();
334 332 /* Careful: no return/goto before cf_opt_unlock! */
335 333 while (error == 0) {
336 - opt = cf_getopt(argc, argv, STDPARAM_OPT);
334 + /*
335 + * Leading ':' tells this to skip unknown opts.
336 + * Just get -A and -U here so we know the user
337 + * for config file parsing.
338 + */
339 + opt = cf_getopt(argc, argv, ":AU:");
337 340 if (opt == -1)
338 341 break;
339 342 arg = cf_optarg;
340 343 /* NB: handle most in smb_ctx_opt */
341 344 switch (opt) {
342 345 case 'A':
343 346 aflg = 1;
344 347 error = smb_ctx_setuser(ctx, "", TRUE);
345 348 ctx->ct_flags |= SMBCF_NOPWD;
346 349 break;
347 350 case 'U':
348 351 uflg = 1;
349 352 error = smb_ctx_setuser(ctx, arg, TRUE);
350 353 break;
351 354 default:
352 355 DPRINT("skip opt=%c", opt);
353 356 break;
354 357 }
355 358 }
356 359 ind = cf_optind;
357 360 arg = argv[ind];
358 361 cf_optind = cf_optreset = 1;
359 362 cf_opt_unlock();
360 363
361 364 if (error)
362 365 return (error);
363 366
364 367 if (aflg && uflg) {
365 368 printf(gettext("-A and -U flags are exclusive.\n"));
366 369 return (EINVAL);
367 370 }
368 371
369 372 /*
370 373 * Parse the UNC path. Values from here are
371 374 * marked as "from CMD".
372 375 */
373 376 for (; ind < argc; ind++) {
374 377 arg = argv[ind];
375 378 if (strncmp(arg, "//", 2) != 0)
376 379 continue;
377 380 error = smb_ctx_parseunc(ctx, arg,
378 381 minlevel, maxlevel, sharetype, &arg);
379 382 if (error)
380 383 return (error);
381 384 break;
382 385 }
383 386
384 387 return (error);
385 388 }
386 389
387 390 void
388 391 smb_ctx_free(smb_ctx_t *ctx)
389 392 {
390 393 smb_ctx_done(ctx);
|
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
391 394 free(ctx);
392 395 }
393 396
394 397 void
395 398 smb_ctx_done(struct smb_ctx *ctx)
396 399 {
397 400
398 401 rpc_cleanup_smbctx(ctx);
399 402
400 403 if (ctx->ct_dev_fd != -1) {
401 - close(ctx->ct_dev_fd);
404 + nsmb_close(ctx->ct_dev_fd);
402 405 ctx->ct_dev_fd = -1;
403 406 }
404 407 if (ctx->ct_door_fd != -1) {
405 408 close(ctx->ct_door_fd);
406 409 ctx->ct_door_fd = -1;
407 410 }
408 - if (ctx->ct_tran_fd != -1) {
409 - close(ctx->ct_tran_fd);
410 - ctx->ct_tran_fd = -1;
411 - }
412 411 if (ctx->ct_srvaddr_s) {
413 412 free(ctx->ct_srvaddr_s);
414 413 ctx->ct_srvaddr_s = NULL;
415 414 }
416 415 if (ctx->ct_nb) {
417 416 nb_ctx_done(ctx->ct_nb);
418 417 ctx->ct_nb = NULL;
419 418 }
420 419 if (ctx->ct_locname) {
421 420 free(ctx->ct_locname);
422 421 ctx->ct_locname = NULL;
423 422 }
424 423 if (ctx->ct_origshare) {
425 424 free(ctx->ct_origshare);
426 425 ctx->ct_origshare = NULL;
427 426 }
428 427 if (ctx->ct_fullserver) {
429 428 free(ctx->ct_fullserver);
430 429 ctx->ct_fullserver = NULL;
431 430 }
432 431 if (ctx->ct_addrinfo) {
433 432 freeaddrinfo(ctx->ct_addrinfo);
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
434 433 ctx->ct_addrinfo = NULL;
435 434 }
436 435 if (ctx->ct_home) {
437 436 free(ctx->ct_home);
438 437 ctx->ct_home = NULL;
439 438 }
440 439 if (ctx->ct_rpath) {
441 440 free(ctx->ct_rpath);
442 441 ctx->ct_rpath = NULL;
443 442 }
444 - if (ctx->ct_srv_OS) {
445 - free(ctx->ct_srv_OS);
446 - ctx->ct_srv_OS = NULL;
443 + if (ctx->ct_ssnkey_buf) {
444 + free(ctx->ct_ssnkey_buf);
445 + ctx->ct_ssnkey_buf = NULL;
447 446 }
448 - if (ctx->ct_srv_LM) {
449 - free(ctx->ct_srv_LM);
450 - ctx->ct_srv_LM = NULL;
451 - }
452 - if (ctx->ct_mackey) {
453 - free(ctx->ct_mackey);
454 - ctx->ct_mackey = NULL;
455 - }
456 447 }
457 448
458 449 /*
459 450 * Parse the UNC path. Here we expect something like
460 451 * "//[[domain;]user[:password]@]host[/share[/path]]"
461 452 * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
462 453 * Values found here are marked as "from CMD".
463 454 */
464 455 int
465 456 smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
466 457 int minlevel, int maxlevel, int sharetype,
467 458 const char **next)
468 459 {
469 460 char tmp[1024];
470 461 char *host, *share, *path;
471 462 char *dom, *usr, *pw, *p;
472 463 int error;
473 464
474 465 /*
475 466 * This may be called outside of _scan_argv,
476 467 * so make sure these get initialized.
477 468 */
478 469 ctx->ct_minlevel = minlevel;
479 470 ctx->ct_maxlevel = maxlevel;
480 471 ctx->ct_shtype_req = sharetype;
481 472 ctx->ct_parsedlevel = SMBL_NONE;
482 473
483 474 dom = usr = pw = host = NULL;
484 475
485 476 /* Work on a temporary copy, fix back slashes. */
486 477 strlcpy(tmp, unc, sizeof (tmp));
487 478 for (p = tmp; *p; p++)
488 479 if (*p == '\\')
489 480 *p = '/';
490 481
491 482 if (tmp[0] != '/' || tmp[1] != '/') {
492 483 smb_error(dgettext(TEXT_DOMAIN,
493 484 "UNC should start with '//'"), 0);
494 485 error = EINVAL;
495 486 goto out;
496 487 }
497 488 p = tmp + 2; /* user@host... */
498 489
499 490 /* Find the share part, if any. */
500 491 share = strchr(p, '/');
501 492 if (share)
502 493 *share = '\0';
503 494 (void) unpercent(p); /* host component */
504 495
505 496 /*
506 497 * Parse the "host" stuff right to left:
507 498 * 1: trailing "@hostname" (or whole field)
508 499 * 2: trailing ":password"
509 500 * 3: trailing "domain;user" (or just user)
510 501 */
511 502 host = strrchr(p, '@');
512 503 if (host == NULL) {
513 504 host = p; /* no user@ prefix */
514 505 } else {
515 506 *host++ = '\0';
516 507
517 508 /* may have [[domain;]user[:passwd]] */
518 509 pw = strchr(p, ':');
519 510 if (pw)
520 511 *pw++ = '\0';
521 512 usr = strchr(p, ';');
522 513 if (usr) {
523 514 *usr++ = '\0';
524 515 dom = p;
525 516 } else
526 517 usr = p;
527 518 }
528 519
529 520 if (*host == '\0') {
530 521 smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
531 522 error = EINVAL;
532 523 goto out;
533 524 }
534 525 error = smb_ctx_setfullserver(ctx, host);
535 526 if (error)
536 527 goto out;
537 528 ctx->ct_parsedlevel = SMBL_VC;
538 529
539 530 if (dom != NULL) {
540 531 error = smb_ctx_setdomain(ctx, dom, TRUE);
541 532 if (error)
542 533 goto out;
543 534 }
544 535 if (usr != NULL) {
545 536 if (*usr == '\0') {
546 537 smb_error(dgettext(TEXT_DOMAIN,
547 538 "empty user name"), 0);
548 539 error = EINVAL;
549 540 goto out;
550 541 }
551 542 if (ctx->ct_maxlevel < SMBL_VC) {
552 543 smb_error(dgettext(TEXT_DOMAIN,
553 544 "no user name required"), 0);
554 545 error = EINVAL;
555 546 goto out;
556 547 }
557 548 error = smb_ctx_setuser(ctx, usr, TRUE);
558 549 if (error)
559 550 goto out;
560 551 }
561 552 if (pw != NULL) {
562 553 error = smb_ctx_setpassword(ctx, pw, TRUE);
563 554 if (error)
564 555 goto out;
565 556 }
566 557
567 558 if (share != NULL) {
568 559 /* restore the slash */
569 560 *share = '/';
570 561 p = share + 1;
571 562
572 563 /* Find the path part, if any. */
573 564 path = strchr(p, '/');
574 565 if (path)
575 566 *path = '\0';
576 567 (void) unpercent(p); /* share component */
577 568
578 569 if (*p == '\0') {
579 570 smb_error(dgettext(TEXT_DOMAIN,
580 571 "empty share name"), 0);
581 572 error = EINVAL;
582 573 goto out;
583 574 }
584 575 if (ctx->ct_maxlevel < SMBL_SHARE) {
585 576 smb_error(dgettext(TEXT_DOMAIN,
586 577 "no share name required"), 0);
587 578 error = EINVAL;
588 579 goto out;
589 580 }
590 581
591 582 /*
592 583 * Special case UNC names like:
593 584 * //host/PIPE/endpoint
594 585 * to have share: IPC$
595 586 */
596 587 if (strcasecmp(p, "PIPE") == 0) {
597 588 sharetype = USE_IPC;
598 589 p = "IPC$";
599 590 }
600 591 error = smb_ctx_setshare(ctx, p, sharetype);
601 592 if (error)
602 593 goto out;
603 594 ctx->ct_parsedlevel = SMBL_SHARE;
604 595
605 596 if (path) {
606 597 /* restore the slash */
607 598 *path = '/';
608 599 p = path + 1;
609 600 (void) unpercent(p); /* remainder */
610 601 free(ctx->ct_rpath);
611 602 ctx->ct_rpath = strdup(path);
612 603 }
613 604 } else if (ctx->ct_minlevel >= SMBL_SHARE) {
614 605 smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
615 606 error = EINVAL;
616 607 goto out;
617 608 }
618 609
619 610 if (next)
620 611 *next = NULL;
621 612
622 613 out:
623 614 if (error == 0 && smb_debug > 0)
624 615 dump_ctx("after smb_ctx_parseunc", ctx);
625 616
626 617 return (error);
627 618 }
628 619
629 620 #ifdef KICONV_SUPPORT
630 621 int
631 622 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
632 623 {
633 624 char *cp, *servercs, *localcs;
634 625 int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
635 626 int scslen, lcslen, error;
636 627
637 628 cp = strchr(arg, ':');
638 629 lcslen = cp ? (cp - arg) : 0;
639 630 if (lcslen == 0 || lcslen >= cslen) {
640 631 smb_error(dgettext(TEXT_DOMAIN,
641 632 "invalid local charset specification (%s)"), 0, arg);
642 633 return (EINVAL);
643 634 }
644 635 scslen = (size_t)strlen(++cp);
645 636 if (scslen == 0 || scslen >= cslen) {
646 637 smb_error(dgettext(TEXT_DOMAIN,
647 638 "invalid server charset specification (%s)"), 0, arg);
648 639 return (EINVAL);
649 640 }
650 641 localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
651 642 localcs[lcslen] = 0;
652 643 servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
653 644 error = nls_setrecode(localcs, servercs);
654 645 if (error == 0)
655 646 return (0);
656 647 smb_error(dgettext(TEXT_DOMAIN,
657 648 "can't initialize iconv support (%s:%s)"),
658 649 error, localcs, servercs);
659 650 localcs[0] = 0;
660 651 servercs[0] = 0;
661 652 return (error);
662 653 }
663 654 #endif /* KICONV_SUPPORT */
664 655
665 656 int
666 657 smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
667 658 {
668 659 ctx->ct_authflags = flags;
669 660 return (0);
670 661 }
671 662
672 663 int
673 664 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
674 665 {
675 666 char *p = strdup(name);
676 667
677 668 if (p == NULL)
678 669 return (ENOMEM);
679 670 if (ctx->ct_fullserver)
680 671 free(ctx->ct_fullserver);
681 672 ctx->ct_fullserver = p;
682 673 return (0);
683 674 }
684 675
685 676 int
686 677 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
687 678 {
688 679 strlcpy(ctx->ct_srvname, name,
689 680 sizeof (ctx->ct_srvname));
690 681 return (0);
691 682 }
692 683
693 684 int
694 685 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
695 686 {
696 687
697 688 if (strlen(name) >= sizeof (ctx->ct_user)) {
698 689 smb_error(dgettext(TEXT_DOMAIN,
699 690 "user name '%s' too long"), 0, name);
700 691 return (ENAMETOOLONG);
701 692 }
702 693
703 694 /*
704 695 * Don't overwrite a value from the command line
705 696 * with one from anywhere else.
706 697 */
707 698 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
708 699 return (0);
709 700
710 701 strlcpy(ctx->ct_user, name,
711 702 sizeof (ctx->ct_user));
712 703
713 704 /* Mark this as "from the command line". */
714 705 if (from_cmd)
715 706 ctx->ct_flags |= SMBCF_CMD_USR;
716 707
717 708 return (0);
718 709 }
719 710
720 711 /*
721 712 * Don't overwrite a domain name from the
722 713 * command line with one from anywhere else.
723 714 * See smb_ctx_init() for notes about this.
724 715 */
725 716 int
726 717 smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
727 718 {
728 719
729 720 if (strlen(name) >= sizeof (ctx->ct_domain)) {
730 721 smb_error(dgettext(TEXT_DOMAIN,
731 722 "workgroup name '%s' too long"), 0, name);
732 723 return (ENAMETOOLONG);
733 724 }
734 725
735 726 /*
736 727 * Don't overwrite a value from the command line
737 728 * with one from anywhere else.
738 729 */
739 730 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
740 731 return (0);
741 732
742 733 strlcpy(ctx->ct_domain, name,
743 734 sizeof (ctx->ct_domain));
744 735
745 736 /* Mark this as "from the command line". */
746 737 if (from_cmd)
747 738 ctx->ct_flags |= SMBCF_CMD_DOM;
748 739
749 740 return (0);
750 741 }
751 742
752 743 int
753 744 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
754 745 {
755 746 int err;
756 747
757 748 if (passwd == NULL)
758 749 return (EINVAL);
759 750 if (strlen(passwd) >= sizeof (ctx->ct_password)) {
760 751 smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
761 752 return (ENAMETOOLONG);
762 753 }
763 754
764 755 /*
765 756 * If called again after comand line parsing,
766 757 * don't overwrite a value from the command line
767 758 * with one from any stored config.
768 759 */
769 760 if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
770 761 return (0);
771 762
772 763 memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
773 764 if (strncmp(passwd, "$$1", 3) == 0)
774 765 (void) smb_simpledecrypt(ctx->ct_password, passwd);
775 766 else
776 767 strlcpy(ctx->ct_password, passwd,
777 768 sizeof (ctx->ct_password));
778 769
779 770 /*
780 771 * Compute LM hash, NT hash.
781 772 */
782 773 if (ctx->ct_password[0]) {
783 774 err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
784 775 if (err != 0)
785 776 return (err);
786 777 err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
787 778 if (err != 0)
788 779 return (err);
789 780 }
790 781
791 782 /* Mark this as "from the command line". */
792 783 if (from_cmd)
793 784 ctx->ct_flags |= SMBCF_CMD_PW;
794 785
795 786 return (0);
796 787 }
797 788
798 789 /*
799 790 * Use this to set NTLM auth. info (hashes)
800 791 * when we don't have the password.
801 792 */
802 793 int
803 794 smb_ctx_setpwhash(smb_ctx_t *ctx,
804 795 const uchar_t *nthash, const uchar_t *lmhash)
805 796 {
806 797
807 798 /* Need ct_password to be non-null. */
808 799 if (ctx->ct_password[0] == '\0')
809 800 strlcpy(ctx->ct_password, "$HASH",
810 801 sizeof (ctx->ct_password));
811 802
812 803 /*
813 804 * Compute LM hash, NT hash.
814 805 */
815 806 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
816 807
817 808 /* The LM hash is optional */
818 809 if (lmhash) {
819 810 memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
820 811 }
821 812
822 813 return (0);
823 814 }
824 815
825 816 int
826 817 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
827 818 {
828 819 if (strlen(share) >= SMBIOC_MAX_NAME) {
829 820 smb_error(dgettext(TEXT_DOMAIN,
830 821 "share name '%s' too long"), 0, share);
831 822 return (ENAMETOOLONG);
832 823 }
833 824 if (ctx->ct_origshare)
834 825 free(ctx->ct_origshare);
835 826 if ((ctx->ct_origshare = strdup(share)) == NULL)
836 827 return (ENOMEM);
837 828
838 829 ctx->ct_shtype_req = stype;
839 830
840 831 return (0);
841 832 }
842 833
843 834 int
844 835 smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
845 836 {
846 837 if (addr == NULL || addr[0] == 0)
847 838 return (EINVAL);
848 839 if (ctx->ct_srvaddr_s)
849 840 free(ctx->ct_srvaddr_s);
850 841 if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
851 842 return (ENOMEM);
852 843 return (0);
853 844 }
854 845
855 846 /*
856 847 * API for library caller to set signing enabled, required
857 848 * Note: if not enable, ignore require
858 849 */
859 850 int
860 851 smb_ctx_setsigning(struct smb_ctx *ctx, int enable, int require)
|
↓ open down ↓ |
395 lines elided |
↑ open up ↑ |
861 852 {
862 853 ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
863 854 if (enable) {
864 855 ctx->ct_vopt |= SMBVOPT_SIGNING_ENABLED;
865 856 if (require)
866 857 ctx->ct_vopt |= SMBVOPT_SIGNING_REQUIRED;
867 858 }
868 859 return (0);
869 860 }
870 861
862 +/*
863 + * Handle .nsmbrc "minver" option.
864 + * Must be <= maxver
865 + */
866 +int
867 +smb_ctx_setminver(struct smb_ctx *ctx, int ver)
868 +{
869 + if (ver < 0 || ver > ctx->ct_maxver)
870 + return (EINVAL);
871 + ctx->ct_minver = (uint16_t)ver;
872 + return (0);
873 +}
874 +
875 +/*
876 + * Handle .nsmbrc "maxver" option.
877 + * Must be >= minver
878 + *
879 + * Any "too high" value is just clamped, so the caller
880 + * doesn't need to know what's the highest we support.
881 + */
882 +int
883 +smb_ctx_setmaxver(struct smb_ctx *ctx, int ver)
884 +{
885 + if (ver < 1 || ver < ctx->ct_minver)
886 + return (EINVAL);
887 + if (ver > SMB2_DIALECT_MAX)
888 + ver = SMB2_DIALECT_MAX;
889 + ctx->ct_maxver = (uint16_t)ver;
890 + return (0);
891 +}
892 +
871 893 static int
872 894 smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
873 895 {
874 896 struct group gr;
875 897 struct passwd pw;
876 898 char buf[NSS_BUFLEN_PASSWD];
877 899 char *cp;
878 900
879 901 cp = strchr(pair, ':');
880 902 if (cp) {
881 903 *cp++ = '\0';
882 904 if (*cp && gid) {
883 905 if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
884 906 *gid = gr.gr_gid;
885 907 } else
886 908 smb_error(dgettext(TEXT_DOMAIN,
887 909 "Invalid group name %s, ignored"), 0, cp);
888 910 }
889 911 }
890 912 if (*pair) {
891 913 if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
|
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
892 914 *uid = pw.pw_uid;
893 915 } else
894 916 smb_error(dgettext(TEXT_DOMAIN,
895 917 "Invalid user name %s, ignored"), 0, pair);
896 918 }
897 919
898 920 return (0);
899 921 }
900 922
901 923 /*
902 - * Suport a securty options arg, i.e. -S noext,lm,ntlm
924 + * Suport a securty options arg, i.e. -S lm,ntlm
903 925 * for testing various type of authenticators.
904 926 */
905 927 static struct nv
906 928 sectype_table[] = {
907 - /* noext - handled below */
908 929 { "anon", SMB_AT_ANON },
909 930 { "lm", SMB_AT_LM1 },
910 931 { "ntlm", SMB_AT_NTLM1 },
911 932 { "ntlm2", SMB_AT_NTLM2 },
912 933 { "krb5", SMB_AT_KRB5 },
913 934 { NULL, 0 },
914 935 };
915 936 int
916 937 smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
917 938 {
918 939 const char *sep = ":;,";
919 940 const char *p = arg;
920 941 struct nv *nv;
921 942 int nlen, tlen;
922 943 int authflags = 0;
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
923 944
924 945 for (;;) {
925 946 /* skip separators */
926 947 tlen = strspn(p, sep);
927 948 p += tlen;
928 949
929 950 nlen = strcspn(p, sep);
930 951 if (nlen == 0)
931 952 break;
932 953
933 - if (nlen == 5 && 0 == strncmp(p, "noext", nlen)) {
934 - /* Don't offer extended security. */
935 - ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
936 - p += nlen;
937 - continue;
938 - }
939 -
940 954 /* This is rarely called, so not optimized. */
941 955 for (nv = sectype_table; nv->name; nv++) {
942 956 tlen = strlen(nv->name);
943 957 if (tlen == nlen && 0 == strncmp(p, nv->name, tlen))
944 958 break;
945 959 }
946 960 if (nv->name == NULL) {
947 961 smb_error(dgettext(TEXT_DOMAIN,
948 962 "%s: invalid security options"), 0, p);
949 963 return (EINVAL);
950 964 }
951 965 authflags |= nv->value;
952 966 p += nlen;
953 967 }
954 968
955 969 if (authflags)
956 970 ctx->ct_authflags = authflags;
957 971
958 972 return (0);
959 973 }
960 974
961 975 /*
962 976 * Commands use this with getopt. See:
963 977 * STDPARAM_OPT, STDPARAM_ARGS
964 978 * Called after smb_ctx_readrc().
965 979 */
966 980 int
967 981 smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
968 982 {
969 983 int error = 0;
970 984 char *p, *cp;
971 985 char tmp[1024];
972 986
973 987 switch (opt) {
974 988 case 'A':
975 989 case 'U':
976 990 /* Handled in smb_ctx_init() */
977 991 break;
978 992 case 'I':
979 993 error = smb_ctx_setsrvaddr(ctx, arg);
980 994 break;
981 995 case 'M':
982 996 /* share connect rights - ignored */
983 997 ctx->ct_flags |= SMBCF_SRIGHTS;
984 998 break;
985 999 case 'N':
986 1000 ctx->ct_flags |= SMBCF_NOPWD;
987 1001 break;
988 1002 case 'O':
989 1003 p = strdup(arg);
990 1004 cp = strchr(p, '/');
991 1005 if (cp)
992 1006 *cp = '\0';
993 1007 error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
994 1008 free(p);
995 1009 break;
996 1010 case 'P':
997 1011 /* ctx->ct_vopt |= SMBCOPT_PERMANENT; */
998 1012 break;
999 1013 case 'R':
1000 1014 /* retry count - ignored */
1001 1015 break;
1002 1016 case 'S':
1003 1017 /* Security options (undocumented, just for tests) */
1004 1018 error = smb_parse_secopts(ctx, arg);
1005 1019 break;
1006 1020 case 'T':
1007 1021 /* timeout - ignored */
1008 1022 break;
1009 1023 case 'D': /* domain */
1010 1024 case 'W': /* workgroup (legacy alias) */
1011 1025 error = smb_ctx_setdomain(ctx, tmp, TRUE);
1012 1026 break;
1013 1027 }
1014 1028 return (error);
1015 1029 }
1016 1030
1017 1031
1018 1032 /*
1019 1033 * Original code injected iconv tables into the kernel.
1020 1034 * Not sure if we'll need this or not... REVISIT
1021 1035 */
1022 1036 #ifdef KICONV_SUPPORT
1023 1037 static int
1024 1038 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
1025 1039 {
1026 1040 int error = 0;
1027 1041
1028 1042 error = kiconv_add_xlat_table(to, from, tbl);
1029 1043 if (error && error != EEXIST) {
1030 1044 smb_error(dgettext(TEXT_DOMAIN,
1031 1045 "can not setup kernel iconv table (%s:%s)"),
1032 1046 error, from, to);
1033 1047 return (error);
1034 1048 }
1035 1049 return (error);
1036 1050 }
1037 1051 #endif /* KICONV_SUPPORT */
1038 1052
1039 1053 /*
1040 1054 * Verify context info. before connect operation(s),
1041 1055 * lookup specified server and try to fill all forgotten fields.
1042 1056 * Legacy name used by commands.
1043 1057 */
1044 1058 int
1045 1059 smb_ctx_resolve(struct smb_ctx *ctx)
1046 1060 {
1047 1061 struct smbioc_ossn *ssn = &ctx->ct_ssn;
1048 1062 int error = 0;
1049 1063 #ifdef KICONV_SUPPORT
1050 1064 uchar_t cstbl[256];
1051 1065 uint_t i;
1052 1066 #endif
1053 1067
1054 1068 if (smb_debug)
1055 1069 dump_ctx("before smb_ctx_resolve", ctx);
1056 1070
1057 1071 ctx->ct_flags &= ~SMBCF_RESOLVED;
1058 1072
1059 1073 if (ctx->ct_fullserver == NULL) {
1060 1074 smb_error(dgettext(TEXT_DOMAIN,
1061 1075 "no server name specified"), 0);
1062 1076 return (EINVAL);
1063 1077 }
1064 1078
1065 1079 if (ctx->ct_minlevel >= SMBL_SHARE &&
1066 1080 ctx->ct_origshare == NULL) {
1067 1081 smb_error(dgettext(TEXT_DOMAIN,
1068 1082 "no share name specified for %s@%s"),
1069 1083 0, ssn->ssn_user, ctx->ct_fullserver);
1070 1084 return (EINVAL);
1071 1085 }
1072 1086 error = nb_ctx_resolve(ctx->ct_nb);
1073 1087 if (error)
1074 1088 return (error);
1075 1089 #ifdef KICONV_SUPPORT
1076 1090 if (ssn->ioc_localcs[0] == 0)
1077 1091 strcpy(ssn->ioc_localcs, "default"); /* XXX: locale name ? */
1078 1092 error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
1079 1093 if (error)
1080 1094 return (error);
1081 1095 error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
1082 1096 if (error)
1083 1097 return (error);
1084 1098 if (ssn->ioc_servercs[0] != 0) {
1085 1099 for (i = 0; i < sizeof (cstbl); i++)
1086 1100 cstbl[i] = i;
1087 1101 nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
1088 1102 error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
1089 1103 cstbl);
1090 1104 if (error)
1091 1105 return (error);
1092 1106 for (i = 0; i < sizeof (cstbl); i++)
1093 1107 cstbl[i] = i;
1094 1108 nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
1095 1109 error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
1096 1110 cstbl);
1097 1111 if (error)
1098 1112 return (error);
1099 1113 }
1100 1114 #endif /* KICONV_SUPPORT */
1101 1115
1102 1116 /*
1103 1117 * Lookup the IP address and fill in ct_addrinfo.
1104 1118 *
1105 1119 * Note: smb_ctx_getaddr() returns a EAI_xxx
1106 1120 * error value like getaddrinfo(3), but this
1107 1121 * function needs to return an errno value.
1108 1122 */
1109 1123 error = smb_ctx_getaddr(ctx);
|
↓ open down ↓ |
160 lines elided |
↑ open up ↑ |
1110 1124 if (error) {
1111 1125 const char *ais = gai_strerror(error);
1112 1126 smb_error(dgettext(TEXT_DOMAIN,
1113 1127 "can't resolve name\"%s\", %s"),
1114 1128 0, ctx->ct_fullserver, ais);
1115 1129 return (ENODATA);
1116 1130 }
1117 1131 assert(ctx->ct_addrinfo != NULL);
1118 1132
1119 1133 /*
1134 + * Empty user name means an explicit request for
1135 + * NULL session setup, which is a special case.
1136 + * (No SMB signing, per [MS-SMB] 3.3.5.3)
1137 + */
1138 + if (ctx->ct_user[0] == '\0') {
1139 + /* Null user should have null domain too. */
1140 + ctx->ct_domain[0] = '\0';
1141 + ctx->ct_authflags = SMB_AT_ANON;
1142 + ctx->ct_vopt |= SMBVOPT_ANONYMOUS;
1143 + ctx->ct_vopt &= ~SMBVOPT_SIGNING_REQUIRED;
1144 + }
1145 +
1146 + /*
1120 1147 * If we have a user name but no password,
1121 1148 * check for a keychain entry.
1122 1149 * XXX: Only for auth NTLM?
1123 1150 */
1124 1151 if (ctx->ct_user[0] != '\0') {
1125 1152 /*
1126 1153 * Have a user name.
1127 1154 * If we don't have a p/w yet,
1128 1155 * try the keychain.
1129 1156 */
1130 - if (ctx->ct_password[0] == '\0')
1131 - (void) smb_get_keychain(ctx);
1157 + if (ctx->ct_password[0] == '\0' &&
1158 + smb_get_keychain(ctx) == 0) {
1159 + strlcpy(ctx->ct_password, "$HASH",
1160 + sizeof (ctx->ct_password));
1161 + }
1162 +
1132 1163 /*
1133 1164 * Mask out disallowed auth types.
1134 1165 */
1135 1166 ctx->ct_authflags &= ctx->ct_minauth;
1136 1167 }
1168 +
1137 1169 if (ctx->ct_authflags == 0) {
1138 1170 smb_error(dgettext(TEXT_DOMAIN,
1139 1171 "no valid auth. types"), 0);
1140 1172 return (ENOTSUP);
1141 1173 }
1142 1174
1143 1175 ctx->ct_flags |= SMBCF_RESOLVED;
1144 1176 if (smb_debug)
1145 1177 dump_ctx("after smb_ctx_resolve", ctx);
1146 1178
1147 1179 return (0);
1148 1180 }
1149 1181
1182 +/*
1183 + * Note: The next three have NODIRECT binding so the
1184 + * "fksmbcl" development tool can provide its own.
1185 + */
1150 1186 int
1151 1187 smb_open_driver()
1152 1188 {
1153 1189 int fd;
1154 1190
1155 1191 fd = open("/dev/"NSMB_NAME, O_RDWR);
1156 1192 if (fd < 0) {
1157 1193 return (-1);
1158 1194 }
1159 1195
1160 1196 /* This handle controls per-process resources. */
1161 1197 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1162 1198
1163 1199 return (fd);
1164 1200 }
1165 1201
1166 1202 int
1203 +nsmb_close(int fd)
1204 +{
1205 + return (close(fd));
1206 +}
1207 +
1208 +int
1209 +nsmb_ioctl(int fd, int cmd, void *arg)
1210 +{
1211 + return (ioctl(fd, cmd, arg));
1212 +}
1213 +
1214 +
1215 +int
1167 1216 smb_ctx_gethandle(struct smb_ctx *ctx)
1168 1217 {
1169 1218 int fd, err;
1170 1219 uint32_t version;
1171 1220
1172 1221 if (ctx->ct_dev_fd != -1) {
1173 1222 rpc_cleanup_smbctx(ctx);
1174 - close(ctx->ct_dev_fd);
1223 + nsmb_close(ctx->ct_dev_fd);
1175 1224 ctx->ct_dev_fd = -1;
1176 - ctx->ct_flags &= ~SMBCF_SSNACTIVE;
1177 1225 }
1178 1226
1179 1227 fd = smb_open_driver();
1180 1228 if (fd < 0) {
1181 1229 err = errno;
1182 1230 smb_error(dgettext(TEXT_DOMAIN,
1183 1231 "failed to open driver"), err);
1184 1232 return (err);
1185 1233 }
1186 1234
1187 1235 /*
1188 1236 * Check the driver version (paranoia)
1189 1237 */
1190 - if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1238 + if (nsmb_ioctl(fd, SMBIOC_GETVERS, &version) < 0)
1191 1239 version = 0;
1192 1240 if (version != NSMB_VERSION) {
1193 1241 smb_error(dgettext(TEXT_DOMAIN,
1194 1242 "incorrect driver version"), 0);
1195 - close(fd);
1243 + nsmb_close(fd);
1196 1244 return (ENODEV);
1197 1245 }
1198 1246
1199 1247 ctx->ct_dev_fd = fd;
1200 1248 return (0);
1201 1249 }
1202 1250
1203 1251
1204 1252 /*
1205 1253 * Find or create a connection + logon session
1206 1254 */
1207 1255 int
1208 1256 smb_ctx_get_ssn(struct smb_ctx *ctx)
1209 1257 {
1210 1258 int err = 0;
1211 1259
1212 1260 if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
1213 1261 return (EINVAL);
1214 1262
1215 - if (ctx->ct_dev_fd < 0) {
1216 - if ((err = smb_ctx_gethandle(ctx)))
1217 - return (err);
1218 - }
1219 -
1220 1263 /*
1221 1264 * Check whether the driver already has a VC
1222 1265 * we can use. If so, we're done!
1223 1266 */
1224 1267 err = smb_ctx_findvc(ctx);
1225 1268 if (err == 0) {
1226 1269 DPRINT("found an existing VC");
1227 1270 } else {
1228 1271 /*
1272 + * If we're authenticating (real user, not NULL session)
1273 + * and we don't yet have a password, return EAUTH and
1274 + * the caller will prompt for it and call again.
1275 + */
1276 + if (ctx->ct_user[0] != '\0' &&
1277 + ctx->ct_password[0] == '\0')
1278 + return (EAUTH);
1279 +
1280 + /*
1229 1281 * This calls the IOD to create a new session.
1230 1282 */
1231 1283 DPRINT("setup a new VC");
1232 1284 err = smb_ctx_newvc(ctx);
1233 1285 if (err != 0)
1234 1286 return (err);
1235 1287
1236 1288 /*
1237 1289 * Call findvc again. The new VC sould be
1238 1290 * found in the driver this time.
1239 1291 */
1240 1292 err = smb_ctx_findvc(ctx);
1241 1293 }
1242 1294
1243 1295 return (err);
1244 1296 }
1245 1297
1246 1298 /*
1247 1299 * Find or create a tree connection
1248 1300 */
1249 1301 int
1250 1302 smb_ctx_get_tree(struct smb_ctx *ctx)
1251 1303 {
1252 1304 smbioc_tcon_t *tcon = NULL;
1253 1305 int cmd, err = 0;
1254 1306
1255 1307 if (ctx->ct_dev_fd < 0 ||
1256 1308 ctx->ct_origshare == NULL) {
1257 1309 return (EINVAL);
1258 1310 }
1259 1311
1260 1312 cmd = SMBIOC_TREE_CONNECT;
1261 1313 tcon = malloc(sizeof (*tcon));
1262 1314 if (tcon == NULL)
1263 1315 return (ENOMEM);
1264 1316 bzero(tcon, sizeof (*tcon));
1265 1317 tcon->tc_flags = SMBLK_CREATE;
1266 1318 tcon->tc_opt = 0;
1267 1319
1268 1320 /* The share name */
1269 1321 strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
|
↓ open down ↓ |
31 lines elided |
↑ open up ↑ |
1270 1322 sizeof (tcon->tc_sh.sh_name));
1271 1323
1272 1324 /* The share "use" type. */
1273 1325 tcon->tc_sh.sh_use = ctx->ct_shtype_req;
1274 1326
1275 1327 /*
1276 1328 * Todo: share passwords for share-level security.
1277 1329 *
1278 1330 * The driver does the actual TCON call.
1279 1331 */
1280 - if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1332 + if (nsmb_ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
1281 1333 err = errno;
1282 1334 goto out;
1283 1335 }
1284 1336
1285 1337 /*
1286 1338 * Check the returned share type
1287 1339 */
1288 1340 DPRINT("ret. sh_type: \"%d\"", tcon->tc_sh.sh_type);
1289 1341 if (ctx->ct_shtype_req != USE_WILDCARD &&
1290 1342 ctx->ct_shtype_req != tcon->tc_sh.sh_type) {
1291 1343 smb_error(dgettext(TEXT_DOMAIN,
1292 1344 "%s: incompatible share type"),
1293 1345 0, ctx->ct_origshare);
1294 1346 }
1295 1347
1296 1348 out:
1297 1349 if (tcon != NULL)
1298 1350 free(tcon);
1299 1351
1300 1352 return (err);
|
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1301 1353 }
1302 1354
1303 1355 /*
1304 1356 * Return the hflags2 word for an smb_ctx.
1305 1357 */
1306 1358 int
1307 1359 smb_ctx_flags2(struct smb_ctx *ctx)
1308 1360 {
1309 1361 uint16_t flags2;
1310 1362
1311 - if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1363 + if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
1312 1364 smb_error(dgettext(TEXT_DOMAIN,
1313 1365 "can't get flags2 for a session"), errno);
1314 1366 return (-1);
1315 1367 }
1316 1368 return (flags2);
1317 1369 }
1318 1370
1319 1371 /*
1320 1372 * Get the transport level session key.
1321 1373 * Must already have an active SMB session.
1322 1374 */
1323 1375 int
1324 1376 smb_fh_getssnkey(int dev_fd, uchar_t *key, size_t len)
1325 1377 {
1326 1378 if (len < SMBIOC_HASH_SZ)
1327 1379 return (EINVAL);
1328 1380
1329 - if (ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1381 + if (nsmb_ioctl(dev_fd, SMBIOC_GETSSNKEY, key) == -1)
1330 1382 return (errno);
1331 1383
1332 1384 return (0);
1333 1385 }
1334 1386
1335 1387 /*
1336 1388 * RC file parsing stuff
1337 1389 */
1338 1390
1339 1391 static struct nv
1340 1392 minauth_table[] = {
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
1341 1393 /* Allowed auth. types */
1342 1394 { "kerberos", SMB_AT_KRB5 },
1343 1395 { "ntlmv2", SMB_AT_KRB5|SMB_AT_NTLM2 },
1344 1396 { "ntlm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
1345 1397 { "lm", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
1346 1398 { "none", SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
1347 1399 SMB_AT_ANON },
1348 1400 { NULL }
1349 1401 };
1350 1402
1403 +int
1404 +smb_cf_minauth_from_str(char *str)
1405 +{
1406 + struct nv *nvp;
1351 1407
1408 + for (nvp = minauth_table; nvp->name; nvp++)
1409 + if (strcmp(nvp->name, str) == 0)
1410 + return (nvp->value);
1411 + return (-1);
1412 +}
1413 +
1414 +
1415 +static struct nv
1416 +smbver_table[] = {
1417 + { "2.1", SMB2_DIALECT_0210 },
1418 + { "1", 1 },
1419 + { NULL, 0 }
1420 +};
1421 +
1422 +int
1423 +smb_cf_version_from_str(char *str)
1424 +{
1425 + struct nv *nvp;
1426 +
1427 + for (nvp = smbver_table; nvp->name; nvp++)
1428 + if (strcmp(nvp->name, str) == 0)
1429 + return (nvp->value);
1430 + return (-1);
1431 +}
1432 +
1352 1433 /*
1353 1434 * level values:
1354 1435 * 0 - default
1355 1436 * 1 - server
1356 1437 * 2 - server:user
1357 1438 * 3 - server:user:share
1358 1439 */
1359 1440 static int
1360 1441 smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
1361 1442 {
1362 1443 char *p;
1444 + int ival;
1363 1445 int error;
1446 + int minver, maxver;
1364 1447
1365 1448 #ifdef KICONV_SUPPORT
1366 1449 if (level > 0) {
1367 1450 rc_getstringptr(smb_rc, sname, "charsets", &p);
1368 1451 if (p) {
1369 1452 error = smb_ctx_setcharset(ctx, p);
1370 1453 if (error)
1371 1454 smb_error(dgettext(TEXT_DOMAIN,
1372 1455 "charset specification in the section '%s' ignored"),
1373 1456 error, sname);
1374 1457 }
1375 1458 }
1376 1459 #endif
1377 1460
1378 1461 if (level <= 1) {
1379 1462 /* Section is: [default] or [server] */
1380 1463
1464 + /*
1465 + * Handle min_protocol, max_protocol
1466 + * (SMB protocol versions)
1467 + */
1468 + minver = -1;
1469 + rc_getstringptr(smb_rc, sname, "min_protocol", &p);
1470 + if (p != NULL) {
1471 + minver = smb_cf_version_from_str(p);
1472 + if (minver == -1) {
1473 + smb_error(dgettext(TEXT_DOMAIN,
1474 +"invalid min_protocol value \"%s\" specified in the section %s"),
1475 + 0, p, sname);
1476 + }
1477 + }
1478 + maxver = -1;
1479 + rc_getstringptr(smb_rc, sname, "max_protocol", &p);
1480 + if (p != NULL) {
1481 + maxver = smb_cf_version_from_str(p);
1482 + if (maxver == -1) {
1483 + smb_error(dgettext(TEXT_DOMAIN,
1484 +"invalid max_protocol value \"%s\" specified in the section %s"),
1485 + 0, p, sname);
1486 + }
1487 + }
1488 +
1489 + /*
1490 + * If setting both min/max protocol,
1491 + * validate against each other
1492 + */
1493 + if (minver != -1 && maxver != -1) {
1494 + if (minver > maxver) {
1495 + smb_error(dgettext(TEXT_DOMAIN,
1496 +"invalid min/max protocol combination in the section %s"),
1497 + 0, sname);
1498 + } else {
1499 + ctx->ct_minver = minver;
1500 + ctx->ct_maxver = maxver;
1501 + }
1502 + }
1503 +
1504 + /*
1505 + * Setting just min or max, validate against
1506 + * current settings
1507 + */
1508 + if (minver != -1) {
1509 + if (minver > ctx->ct_maxver) {
1510 + smb_error(dgettext(TEXT_DOMAIN,
1511 +"invalid min/max protocol combination in the section %s"),
1512 + 0, sname);
1513 + } else {
1514 + ctx->ct_minver = minver;
1515 + }
1516 + }
1517 + if (maxver != -1) {
1518 + if (maxver < ctx->ct_minver) {
1519 + smb_error(dgettext(TEXT_DOMAIN,
1520 +"invalid min/max protocol combination in the section %s"),
1521 + 0, sname);
1522 + } else {
1523 + ctx->ct_maxver = maxver;
1524 + }
1525 + }
1526 +
1381 1527 rc_getstringptr(smb_rc, sname, "minauth", &p);
1382 1528 if (p) {
1383 1529 /*
1384 1530 * "minauth" was set in this section; override
1385 1531 * the current minimum authentication setting.
1386 1532 */
1387 - struct nv *nvp;
1388 - for (nvp = minauth_table; nvp->name; nvp++)
1389 - if (strcmp(p, nvp->name) == 0)
1390 - break;
1391 - if (nvp->name)
1392 - ctx->ct_minauth = nvp->value;
1393 - else {
1533 + ival = smb_cf_minauth_from_str(p);
1534 + if (ival != -1) {
1535 + ctx->ct_minauth = ival;
1536 + } else {
1394 1537 /*
1395 1538 * Unknown minimum authentication level.
1396 1539 */
1397 1540 smb_error(dgettext(TEXT_DOMAIN,
1398 1541 "invalid minimum authentication level \"%s\" specified in the section %s"),
1399 1542 0, p, sname);
1400 1543 return (EINVAL);
1401 1544 }
1402 1545 }
1403 1546
1404 1547 rc_getstringptr(smb_rc, sname, "signing", &p);
1405 1548 if (p) {
1406 1549 /*
1407 1550 * "signing" was set in this section; override
1408 1551 * the current signing settings. Note:
1409 1552 * setsigning flags are: enable, require
1410 1553 */
1411 1554 if (strcmp(p, "disabled") == 0) {
1412 1555 (void) smb_ctx_setsigning(ctx, FALSE, FALSE);
1413 1556 } else if (strcmp(p, "enabled") == 0) {
1414 1557 (void) smb_ctx_setsigning(ctx, TRUE, FALSE);
1415 1558 } else if (strcmp(p, "required") == 0) {
1416 1559 (void) smb_ctx_setsigning(ctx, TRUE, TRUE);
1417 1560 } else {
1418 1561 /*
1419 1562 * Unknown "signing" value.
1420 1563 */
1421 1564 smb_error(dgettext(TEXT_DOMAIN,
1422 1565 "invalid signing policy \"%s\" specified in the section %s"),
1423 1566 0, p, sname);
1424 1567 return (EINVAL);
1425 1568 }
1426 1569 }
1427 1570
1428 1571 /*
1429 1572 * Domain name. Allow both keywords:
1430 1573 * "workgroup", "domain"
1431 1574 *
1432 1575 * Note: these are NOT marked "from CMD".
1433 1576 * See long comment at smb_ctx_init()
1434 1577 */
1435 1578 rc_getstringptr(smb_rc, sname, "workgroup", &p);
1436 1579 if (p) {
1437 1580 error = smb_ctx_setdomain(ctx, p, 0);
1438 1581 if (error)
1439 1582 smb_error(dgettext(TEXT_DOMAIN,
1440 1583 "workgroup specification in the "
1441 1584 "section '%s' ignored"), error, sname);
1442 1585 }
1443 1586 rc_getstringptr(smb_rc, sname, "domain", &p);
1444 1587 if (p) {
1445 1588 error = smb_ctx_setdomain(ctx, p, 0);
1446 1589 if (error)
1447 1590 smb_error(dgettext(TEXT_DOMAIN,
1448 1591 "domain specification in the "
1449 1592 "section '%s' ignored"), error, sname);
1450 1593 }
1451 1594
1452 1595 rc_getstringptr(smb_rc, sname, "user", &p);
1453 1596 if (p) {
1454 1597 error = smb_ctx_setuser(ctx, p, 0);
1455 1598 if (error)
1456 1599 smb_error(dgettext(TEXT_DOMAIN,
1457 1600 "user specification in the "
1458 1601 "section '%s' ignored"), error, sname);
1459 1602 }
1460 1603 }
1461 1604
1462 1605 if (level == 1) {
1463 1606 /* Section is: [server] */
1464 1607 rc_getstringptr(smb_rc, sname, "addr", &p);
1465 1608 if (p) {
1466 1609 error = smb_ctx_setsrvaddr(ctx, p);
1467 1610 if (error) {
1468 1611 smb_error(dgettext(TEXT_DOMAIN,
1469 1612 "invalid address specified in section %s"),
1470 1613 0, sname);
1471 1614 return (error);
1472 1615 }
1473 1616 }
1474 1617 }
1475 1618
1476 1619 rc_getstringptr(smb_rc, sname, "password", &p);
1477 1620 if (p) {
1478 1621 error = smb_ctx_setpassword(ctx, p, 0);
1479 1622 if (error)
1480 1623 smb_error(dgettext(TEXT_DOMAIN,
1481 1624 "password specification in the section '%s' ignored"),
1482 1625 error, sname);
1483 1626 }
1484 1627
1485 1628 return (0);
1486 1629 }
1487 1630
1488 1631 /*
1489 1632 * read rc file as follows:
1490 1633 * 0: read [default] section
1491 1634 * 1: override with [server] section
1492 1635 * 2: override with [server:user] section
1493 1636 * 3: override with [server:user:share] section
1494 1637 * Since absence of rcfile is not fatal, silently ignore this fact.
1495 1638 * smb_rc file should be closed by caller.
1496 1639 */
1497 1640 int
1498 1641 smb_ctx_readrc(struct smb_ctx *ctx)
1499 1642 {
1500 1643 char pwbuf[NSS_BUFLEN_PASSWD];
1501 1644 struct passwd pw;
1502 1645 char *sname = NULL;
1503 1646 int sname_max;
1504 1647 int err = 0;
1505 1648
1506 1649 /*
1507 1650 * If the user name is not specified some other way,
1508 1651 * use the current user name. Also save the homedir.
1509 1652 * NB: ct_home=NULL is allowed, and we don't want to
1510 1653 * bail out with an error for a missing ct_home.
1511 1654 */
1512 1655 if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
1513 1656 if (ctx->ct_user[0] == 0)
1514 1657 (void) smb_ctx_setuser(ctx, pw.pw_name, B_FALSE);
1515 1658 if (ctx->ct_home == NULL)
1516 1659 ctx->ct_home = strdup(pw.pw_dir);
1517 1660 }
1518 1661
1519 1662 if ((err = smb_open_rcfile(ctx->ct_home)) != 0) {
1520 1663 DPRINT("smb_open_rcfile, err=%d", err);
1521 1664 /* ignore any error here */
1522 1665 return (0);
1523 1666 }
1524 1667
1525 1668 sname_max = 3 * SMBIOC_MAX_NAME + 4;
1526 1669 sname = malloc(sname_max);
1527 1670 if (sname == NULL) {
1528 1671 err = ENOMEM;
1529 1672 goto done;
1530 1673 }
1531 1674
1532 1675 /*
1533 1676 * default parameters (level=0)
1534 1677 */
1535 1678 smb_ctx_readrcsection(ctx, "default", 0);
1536 1679 nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
1537 1680
1538 1681 /*
1539 1682 * If we don't have a server name, we can't read any of the
1540 1683 * [server...] sections.
1541 1684 */
1542 1685 if (ctx->ct_fullserver == NULL)
1543 1686 goto done;
1544 1687 /*
1545 1688 * SERVER parameters.
1546 1689 */
1547 1690 smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
1548 1691
1549 1692 /*
1550 1693 * If we don't have a user name, we can't read any of the
1551 1694 * [server:user...] sections.
1552 1695 */
1553 1696 if (ctx->ct_user[0] == 0)
1554 1697 goto done;
1555 1698 /*
1556 1699 * SERVER:USER parameters
1557 1700 */
1558 1701 snprintf(sname, sname_max, "%s:%s",
1559 1702 ctx->ct_fullserver,
1560 1703 ctx->ct_user);
1561 1704 smb_ctx_readrcsection(ctx, sname, 2);
1562 1705
1563 1706
1564 1707 /*
1565 1708 * If we don't have a share name, we can't read any of the
1566 1709 * [server:user:share] sections.
1567 1710 */
1568 1711 if (ctx->ct_origshare == NULL)
1569 1712 goto done;
1570 1713 /*
1571 1714 * SERVER:USER:SHARE parameters
1572 1715 */
1573 1716 snprintf(sname, sname_max, "%s:%s:%s",
1574 1717 ctx->ct_fullserver,
1575 1718 ctx->ct_user,
1576 1719 ctx->ct_origshare);
1577 1720 smb_ctx_readrcsection(ctx, sname, 3);
1578 1721
1579 1722 done:
1580 1723 if (sname)
1581 1724 free(sname);
1582 1725 smb_close_rcfile();
1583 1726 if (smb_debug)
1584 1727 dump_ctx("after smb_ctx_readrc", ctx);
1585 1728 if (err)
1586 1729 DPRINT("err=%d\n", err);
1587 1730
1588 1731 return (err);
1589 1732 }
1590 1733
1591 1734 void
1592 1735 smbfs_set_default_domain(const char *domain)
1593 1736 {
1594 1737 strlcpy(default_domain, domain, sizeof (default_domain));
1595 1738 }
1596 1739
1597 1740 void
1598 1741 smbfs_set_default_user(const char *user)
1599 1742 {
1600 1743 strlcpy(default_user, user, sizeof (default_user));
1601 1744 }
|
↓ open down ↓ |
198 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX