Print this page
NEX-16159 Time spent sharing SMB filesystems could be reduced by optimizing smb_getdataset for default mount points (lint fix)
Reviewed by: Jean McCormack <jean.mccormack@nexenta.com>
NEX-16159 Time spent sharing SMB filesystems could be reduced by optimizing smb_getdataset for default mount points
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-2346 SMB server debug logging cleanup after NEX-2314
NEX-816 smbadm dumps core during first join attempt
SMB-50 User-mode SMB server
Includes work by these authors:
Thomas Keiser <thomas.keiser@nexenta.com>
Albert Lee <trisk@nexenta.com>
re #12435 rb3958 r10 is added 2 times to panic info
re #12393 rb3935 Kerberos and smbd disagree about who is our AD server
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/smbsrv/libsmb/common/smb_util.c
+++ new/usr/src/lib/smbsrv/libsmb/common/smb_util.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 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
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.
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 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 - * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
23 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 #include <ctype.h>
27 27 #include <stdio.h>
28 28 #include <stdarg.h>
29 29 #include <unistd.h>
30 30 #include <sys/fcntl.h>
31 31 #include <string.h>
32 32 #include <strings.h>
33 33 #include <stdlib.h>
34 34 #include <pthread.h>
35 35 #include <sys/varargs.h>
36 36 #include <sys/types.h>
37 37 #include <sys/mnttab.h>
38 38 #include <tiuser.h>
39 39 #include <netconfig.h>
40 40 #include <netdir.h>
41 41 #include <sys/systeminfo.h>
42 42 #include <sys/utsname.h>
43 43 #include <libzfs.h>
44 44 #include <dlfcn.h>
45 45 #include <time.h>
46 46 #include <syslog.h>
47 47 #include <smbsrv/string.h>
48 48 #include <smbsrv/libsmb.h>
49 49
50 50 #define SMB_LIB_ALT "/usr/lib/smbsrv/libsmbex.so"
51 51
52 52 static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
53 53
54 54 extern int __multi_innetgr();
55 55 extern int __netdir_getbyaddr_nosrv(struct netconfig *,
56 56 struct nd_hostservlist **, struct netbuf *);
57 57
58 58 #define C2H(c) "0123456789ABCDEF"[(c)]
59 59 #define H2C(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
60 60 ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
61 61 ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
62 62 '\0')
63 63 #define DEFAULT_SBOX_SIZE 256
64 64
65 65 /*
66 66 *
67 67 * hexdump
68 68 *
69 69 * Simple hex dump display function. Displays nbytes of buffer in hex and
70 70 * printable format. Non-printing characters are shown as '.'. It is safe
71 71 * to pass a null pointer. Each line begins with the offset. If nbytes is
72 72 * 0, the line will be blank except for the offset. Example output:
73 73 *
74 74 * 00000000 54 68 69 73 20 69 73 20 61 20 70 72 6F 67 72 61 This is a progra
75 75 * 00000010 6D 20 74 65 73 74 2E 00 m test..
76 76 *
77 77 */
78 78 void
79 79 hexdump_offset(unsigned char *buffer, int nbytes, unsigned long *start)
80 80 {
81 81 static char *hex = "0123456789ABCDEF";
82 82 int i, count;
83 83 int offset;
84 84 unsigned char *p;
85 85 char ascbuf[64];
86 86 char hexbuf[64];
87 87 char *ap = ascbuf;
88 88 char *hp = hexbuf;
89 89
90 90 if ((p = buffer) == NULL)
91 91 return;
92 92
93 93 offset = *start;
94 94
95 95 *ap = '\0';
96 96 *hp = '\0';
97 97 count = 0;
98 98
99 99 for (i = 0; i < nbytes; ++i) {
100 100 if (i && (i % 16) == 0) {
101 101 smb_tracef("%06X %s %s", offset, hexbuf, ascbuf);
102 102 ap = ascbuf;
103 103 hp = hexbuf;
104 104 count = 0;
105 105 offset += 16;
106 106 }
107 107
108 108 ap += sprintf(ap, "%c",
109 109 (*p >= 0x20 && *p < 0x7F) ? *p : '.');
110 110 hp += sprintf(hp, " %c%c",
111 111 hex[(*p >> 4) & 0x0F], hex[(*p & 0x0F)]);
112 112 ++p;
113 113 ++count;
114 114 }
115 115
116 116 if (count) {
117 117 smb_tracef("%06X %-48s %s", offset, hexbuf, ascbuf);
118 118 offset += count;
119 119 }
120 120
121 121 *start = offset;
122 122 }
123 123
124 124 void
125 125 hexdump(unsigned char *buffer, int nbytes)
126 126 {
127 127 unsigned long start = 0;
128 128
129 129 hexdump_offset(buffer, nbytes, &start);
130 130 }
131 131
132 132 /*
133 133 * bintohex
134 134 *
135 135 * Converts the given binary data (srcbuf) to
136 136 * its equivalent hex chars (hexbuf).
137 137 *
138 138 * hexlen should be at least twice as srclen.
139 139 * if hexbuf is not big enough returns 0.
140 140 * otherwise returns number of valid chars in
141 141 * hexbuf which is srclen * 2.
142 142 */
143 143 size_t
144 144 bintohex(const char *srcbuf, size_t srclen,
145 145 char *hexbuf, size_t hexlen)
146 146 {
147 147 size_t outlen;
148 148 char c;
149 149
150 150 outlen = srclen << 1;
151 151
152 152 if (hexlen < outlen)
153 153 return (0);
154 154
155 155 while (srclen-- > 0) {
156 156 c = *srcbuf++;
157 157 *hexbuf++ = C2H(c & 0xF);
158 158 *hexbuf++ = C2H((c >> 4) & 0xF);
159 159 }
160 160
161 161 return (outlen);
162 162 }
163 163
164 164 /*
165 165 * hextobin
166 166 *
167 167 * Converts hex to binary.
168 168 *
169 169 * Assuming hexbuf only contains hex digits (chars)
170 170 * this function convert every two bytes of hexbuf
171 171 * to one byte and put it in dstbuf.
172 172 *
173 173 * hexlen should be an even number.
174 174 * dstlen should be at least half of hexlen.
175 175 *
176 176 * Returns 0 if sizes are not correct, otherwise
177 177 * returns the number of converted bytes in dstbuf
178 178 * which is half of hexlen.
179 179 */
180 180 size_t
181 181 hextobin(const char *hexbuf, size_t hexlen,
182 182 char *dstbuf, size_t dstlen)
183 183 {
184 184 size_t outlen;
185 185
186 186 if ((hexlen % 2) != 0)
187 187 return (0);
188 188
189 189 outlen = hexlen >> 1;
190 190 if (dstlen < outlen)
191 191 return (0);
192 192
193 193 while (hexlen > 0) {
194 194 *dstbuf = H2C(*hexbuf) & 0x0F;
195 195 hexbuf++;
196 196 *dstbuf++ |= (H2C(*hexbuf) << 4) & 0xF0;
197 197 hexbuf++;
198 198
199 199 hexlen -= 2;
200 200 }
201 201
202 202 return (outlen);
203 203 }
204 204
205 205 /*
206 206 * Trim leading and trailing characters in the set defined by class
207 207 * from a buffer containing a null-terminated string.
208 208 * For example, if the input buffer contained "ABtext23" and class
209 209 * contains "ABC123", the buffer will contain "text" on return.
210 210 *
211 211 * This function modifies the contents of buf in place and returns
212 212 * a pointer to buf.
213 213 */
214 214 char *
215 215 strtrim(char *buf, const char *class)
216 216 {
217 217 char *p = buf;
218 218 char *q = buf;
219 219
220 220 if (buf == NULL)
221 221 return (NULL);
222 222
223 223 p += strspn(p, class);
224 224
225 225 if (p != buf) {
226 226 while ((*q = *p++) != '\0')
227 227 ++q;
228 228 }
229 229
230 230 while (q != buf) {
231 231 --q;
232 232 if (strspn(q, class) == 0)
233 233 return (buf);
234 234 *q = '\0';
235 235 }
236 236
237 237 return (buf);
238 238 }
239 239
240 240 /*
241 241 * Strip the characters in the set defined by class from a buffer
242 242 * containing a null-terminated string.
243 243 * For example, if the input buffer contained "XYA 1textZ string3"
244 244 * and class contains "123XYZ", the buffer will contain "A text string"
245 245 * on return.
246 246 *
247 247 * This function modifies the contents of buf in place and returns
248 248 * a pointer to buf.
249 249 */
250 250 char *
251 251 strstrip(char *buf, const char *class)
252 252 {
253 253 char *p = buf;
254 254 char *q = buf;
255 255
256 256 if (buf == NULL)
257 257 return (NULL);
258 258
259 259 while (*p) {
260 260 p += strspn(p, class);
261 261 *q++ = *p++;
262 262 }
263 263
264 264 *q = '\0';
265 265 return (buf);
266 266 }
267 267
268 268 /*
269 269 * trim_whitespace
270 270 *
271 271 * Trim leading and trailing whitespace chars (as defined by isspace)
272 272 * from a buffer. Example; if the input buffer contained " text ",
273 273 * it will contain "text", when we return. We assume that the buffer
274 274 * contains a null terminated string. A pointer to the buffer is
275 275 * returned.
276 276 */
277 277 char *
278 278 trim_whitespace(char *buf)
279 279 {
280 280 char *p = buf;
281 281 char *q = buf;
282 282
283 283 if (buf == NULL)
284 284 return (NULL);
285 285
286 286 while (*p && isspace(*p))
287 287 ++p;
288 288
289 289 while ((*q = *p++) != 0)
290 290 ++q;
291 291
292 292 if (q != buf) {
293 293 while ((--q, isspace(*q)) != 0)
294 294 *q = '\0';
295 295 }
296 296
297 297 return (buf);
298 298 }
299 299
300 300 /*
301 301 * This is the hash mechanism used to encrypt passwords for commands like
302 302 * SamrSetUserInformation. It uses a 256 byte s-box.
303 303 */
304 304 void
305 305 rand_hash(
306 306 unsigned char *data,
307 307 size_t datalen,
308 308 unsigned char *key,
309 309 size_t keylen)
310 310 {
311 311 unsigned char sbox[DEFAULT_SBOX_SIZE];
312 312 unsigned char tmp;
313 313 unsigned char index_i = 0;
314 314 unsigned char index_j = 0;
315 315 unsigned char j = 0;
316 316 int i;
317 317
318 318 for (i = 0; i < DEFAULT_SBOX_SIZE; ++i)
319 319 sbox[i] = (unsigned char)i;
320 320
321 321 for (i = 0; i < DEFAULT_SBOX_SIZE; ++i) {
322 322 j += (sbox[i] + key[i % keylen]);
323 323
324 324 tmp = sbox[i];
325 325 sbox[i] = sbox[j];
326 326 sbox[j] = tmp;
327 327 }
328 328
329 329 for (i = 0; i < datalen; ++i) {
330 330 index_i++;
331 331 index_j += sbox[index_i];
332 332
333 333 tmp = sbox[index_i];
334 334 sbox[index_i] = sbox[index_j];
335 335 sbox[index_j] = tmp;
336 336
337 337 tmp = sbox[index_i] + sbox[index_j];
338 338 data[i] = data[i] ^ sbox[tmp];
339 339 }
340 340 }
341 341
342 342 /*
343 343 * smb_chk_hostaccess
344 344 *
345 345 * Determines whether the specified host is in the given access list.
346 346 *
347 347 * We match on aliases of the hostname as well as on the canonical name.
348 348 * Names in the access list may be either hosts or netgroups; they're
349 349 * not distinguished syntactically. We check for hosts first because
350 350 * it's cheaper (just M*N strcmp()s), then try netgroups.
351 351 *
352 352 * Function returns:
353 353 * -1 for "all" (list is empty "" or "*")
354 354 * 0 not found (host is not in the list or list is NULL)
355 355 * 1 found
356 356 *
357 357 */
358 358 int
359 359 smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
360 360 {
361 361 char addr[INET_ADDRSTRLEN];
362 362 char buff[256];
363 363 char *cstr = access_list, *gr = access_list;
364 364 char *host;
365 365 int clres;
366 366 int i;
367 367 int nentries = 0;
368 368 int off;
369 369 int response;
370 370 int sbr = 0;
371 371 struct nd_hostservlist *clnames;
372 372 struct in_addr inaddr;
373 373 struct sockaddr_in sa;
374 374 struct sockaddr_in6 sa6;
375 375 struct netbuf buf;
376 376 struct netconfig *config;
377 377 struct netent n, *np;
378 378
379 379 if (access_list == NULL)
380 380 return (0);
381 381
382 382 /* If access list is empty or "*" - then it's "all" */
383 383 if (*access_list == '\0' || strcmp(access_list, "*") == 0)
384 384 return (-1);
385 385
386 386 switch (ipaddr->a_family) {
387 387 case AF_INET:
388 388 inaddr.s_addr = ipaddr->a_ipv4;
389 389 sa.sin_family = AF_INET;
390 390 sa.sin_port = 0;
391 391 sa.sin_addr = inaddr;
392 392 buf.len = buf.maxlen = sizeof (sa);
393 393 buf.buf = (char *)&sa;
394 394 config = getnetconfigent("tcp");
395 395 break;
396 396 case AF_INET6:
397 397 sa6.sin6_family = AF_INET6;
398 398 sa6.sin6_port = 0;
399 399 sa6.sin6_addr = ipaddr->a_ipv6;
400 400 buf.len = buf.maxlen = sizeof (sa6);
401 401 buf.buf = (char *)&sa6;
402 402 config = getnetconfigent("tcp6");
403 403 break;
404 404 default:
405 405 return (1);
406 406 }
407 407
408 408 if (config == NULL)
409 409 return (1);
410 410
411 411 /* Try to lookup client hostname */
412 412 clres = __netdir_getbyaddr_nosrv(config, &clnames, &buf);
413 413 freenetconfigent(config);
414 414
415 415 for (;;) {
416 416 if ((cstr = strpbrk(cstr, "[]:")) != NULL) {
417 417 switch (*cstr) {
418 418 case '[':
419 419 case ']':
420 420 sbr = !sbr;
421 421 cstr++;
422 422 continue;
423 423 case ':':
424 424 if (sbr) {
425 425 cstr++;
426 426 continue;
427 427 }
428 428 *cstr = '\0';
429 429 }
430 430 }
431 431
432 432 /*
433 433 * If the list name has a '-' prepended then a match of
434 434 * the following name implies failure instead of success.
435 435 */
436 436 if (*gr == '-') {
437 437 response = 0;
438 438 gr++;
439 439 } else {
440 440 response = 1;
441 441 }
442 442
443 443 /*
444 444 * First check if we have '@' entry, as it doesn't
445 445 * require client hostname.
446 446 */
447 447 if (*gr == '@') {
448 448 gr++;
449 449
450 450 if (!isdigit(*gr) && *gr != '[') {
451 451 /* Netname support */
452 452 if ((np = getnetbyname_r(gr, &n, buff,
453 453 sizeof (buff))) != NULL &&
454 454 np->n_net != 0) {
455 455 while ((np->n_net & 0xFF000000u) == 0)
456 456 np->n_net <<= 8;
457 457 np->n_net = htonl(np->n_net);
458 458 if (inet_ntop(AF_INET, &np->n_net, addr,
459 459 INET_ADDRSTRLEN) == NULL)
460 460 break;
461 461 if (inet_matchaddr(buf.buf, addr) == 1)
462 462 return (response);
463 463 }
464 464 } else {
465 465 if (inet_matchaddr(buf.buf, gr) == 1)
466 466 return (response);
467 467 }
468 468
469 469 if (cstr == NULL)
470 470 break;
471 471
472 472 gr = ++cstr;
473 473
474 474 continue;
475 475 }
476 476
477 477 /*
478 478 * No other checks can be performed if client address
479 479 * can't be resolved.
480 480 */
481 481 if (clres) {
482 482 if (cstr == NULL)
483 483 break;
484 484
485 485 gr = ++cstr;
486 486
487 487 continue;
488 488 }
489 489
490 490 /* Otherwise loop through all client hostname aliases */
491 491 for (i = 0; i < clnames->h_cnt; i++) {
492 492 host = clnames->h_hostservs[i].h_host;
493 493 /*
494 494 * If the list name begins with a dot then
495 495 * do a domain name suffix comparison.
496 496 * A single dot matches any name with no
497 497 * suffix.
498 498 */
499 499 if (*gr == '.') {
500 500 if (*(gr + 1) == '\0') {
501 501 if (strchr(host, '.') == NULL)
502 502 return (response);
503 503 } else {
504 504 off = strlen(host) - strlen(gr);
505 505 if (off > 0 &&
506 506 strcasecmp(host + off, gr) == 0) {
507 507 return (response);
508 508 }
509 509 }
510 510 } else {
511 511 /* Just do a hostname match */
512 512 if (strcasecmp(gr, host) == 0)
513 513 return (response);
514 514 }
515 515 }
516 516
517 517 nentries++;
518 518
519 519 if (cstr == NULL)
520 520 break;
521 521
522 522 gr = ++cstr;
523 523 }
524 524
525 525 if (clres)
526 526 return (0);
527 527
528 528 return (smb_netgroup_match(clnames, access_list, nentries));
529 529 }
530 530
531 531 /*
532 532 * smb_netgroup_match
533 533 *
534 534 * Check whether any of the hostnames in clnames are
535 535 * members (or non-members) of the netgroups in glist.
536 536 * Since the innetgr lookup is rather expensive, the
537 537 * result is cached. The cached entry is valid only
538 538 * for VALID_TIME seconds. This works well because
539 539 * typically these lookups occur in clusters when
540 540 * a client is mounting.
541 541 *
542 542 * Note that this routine establishes a host membership
543 543 * in a list of netgroups - we've no idea just which
544 544 * netgroup in the list it is a member of.
545 545 *
546 546 * glist is a character array containing grc strings
547 547 * representing netgroup names (optionally prefixed
548 548 * with '-'). Each string is ended with '\0' and
549 549 * followed immediately by the next string.
550 550 */
551 551 static boolean_t
552 552 smb_netgroup_match(struct nd_hostservlist *clnames, char *glist, int grc)
553 553 {
554 554 char **grl;
555 555 char *gr;
556 556 int nhosts = clnames->h_cnt;
557 557 char *host;
558 558 int i, j, n;
559 559 boolean_t response;
560 560 boolean_t belong = B_FALSE;
561 561 static char *domain = NULL;
562 562
563 563 if (domain == NULL) {
564 564 int ssize;
565 565
566 566 domain = malloc(SYS_NMLN);
567 567 if (domain == NULL)
568 568 return (B_FALSE);
569 569
570 570 ssize = sysinfo(SI_SRPC_DOMAIN, domain, SYS_NMLN);
571 571 if (ssize > SYS_NMLN) {
572 572 free(domain);
573 573 domain = malloc(ssize);
574 574 if (domain == NULL)
575 575 return (B_FALSE);
576 576 ssize = sysinfo(SI_SRPC_DOMAIN, domain, ssize);
577 577 }
578 578 /* Check for error in syscall or NULL domain name */
579 579 if (ssize <= 1)
580 580 return (B_FALSE);
581 581 }
582 582
583 583 grl = calloc(grc, sizeof (char *));
584 584 if (grl == NULL)
585 585 return (B_FALSE);
586 586
587 587 for (i = 0, gr = glist; i < grc && !belong; ) {
588 588 /*
589 589 * If the netgroup name has a '-' prepended
590 590 * then a match of this name implies a failure
591 591 * instead of success.
592 592 */
593 593 response = (*gr != '-') ? B_TRUE : B_FALSE;
594 594
595 595 /*
596 596 * Subsequent names with or without a '-' (but no mix)
597 597 * can be grouped together for a single check.
598 598 */
599 599 for (n = 0; i < grc; i++, n++, gr += strlen(gr) + 1) {
600 600 if ((response && *gr == '-') ||
601 601 (!response && *gr != '-'))
602 602 break;
603 603
604 604 grl[n] = response ? gr : gr + 1;
605 605 }
606 606
607 607 /*
608 608 * Check the netgroup for each
609 609 * of the hosts names (usually just one).
610 610 */
611 611 for (j = 0; j < nhosts && !belong; j++) {
612 612 host = clnames->h_hostservs[j].h_host;
613 613 if (__multi_innetgr(n, grl, 1, &host, 0, NULL,
614 614 1, &domain))
615 615 belong = B_TRUE;
616 616 }
617 617 }
618 618
619 619 free(grl);
|
↓ open down ↓ |
586 lines elided |
↑ open up ↑ |
620 620 return (belong ? response : B_FALSE);
621 621 }
622 622
623 623 /*
624 624 * Resolve the ZFS dataset from a path.
625 625 * Returns,
626 626 * 0 = On success.
627 627 * -1 = Failure to open /etc/mnttab file or to get ZFS dataset.
628 628 */
629 629 int
630 -smb_getdataset(const char *path, char *dataset, size_t len)
630 +smb_getdataset(libzfs_handle_t *libhdl, const char *path, char *dataset,
631 + size_t len)
631 632 {
632 633 char tmppath[MAXPATHLEN];
633 634 char *cp;
634 635 FILE *fp;
635 636 struct mnttab mnttab;
636 637 struct mnttab mntpref;
637 638 int rc = -1;
638 639
640 + /*
641 + * Optimisation: if the path is the default mountpoint then
642 + * the dataset name can be determined from path.
643 + * Attempt to open dataset by derived name and, if successful,
644 + * check if its mountpoint matches path.
645 + */
646 + if (libhdl != NULL) {
647 + zfs_handle_t *hdl;
648 + char mountpnt[ZFS_MAXPROPLEN];
649 + char *dsname = (char *)path + strspn(path, "/");
650 +
651 + hdl = zfs_open(libhdl, dsname, ZFS_TYPE_FILESYSTEM);
652 + if (hdl != NULL) {
653 + if ((zfs_prop_get(hdl, ZFS_PROP_MOUNTPOINT, mountpnt,
654 + sizeof (mountpnt), NULL, NULL, 0, B_FALSE) == 0) &&
655 + (strcmp(mountpnt, path) == 0)) {
656 + zfs_close(hdl);
657 + (void) strlcpy(dataset, dsname, len);
658 + return (0);
659 + }
660 + zfs_close(hdl);
661 + }
662 + }
663 +
664 + /*
665 + * Couldn't find a filesystem optimistically, use mnttab
666 + */
639 667 if ((fp = fopen(MNTTAB, "r")) == NULL)
640 668 return (-1);
641 669
642 670 (void) memset(&mnttab, '\0', sizeof (mnttab));
643 671 (void) strlcpy(tmppath, path, MAXPATHLEN);
644 672 cp = tmppath;
645 673
646 674 while (*cp != '\0') {
647 675 resetmnttab(fp);
648 676 (void) memset(&mntpref, '\0', sizeof (mntpref));
649 677 mntpref.mnt_mountp = tmppath;
650 678
651 679 if (getmntany(fp, &mnttab, &mntpref) == 0) {
652 680 if (mnttab.mnt_fstype == NULL)
653 681 break;
654 682
655 683 if (strcmp(mnttab.mnt_fstype, "zfs") != 0)
656 684 break;
657 685 /*
658 686 * Ensure that there are no leading slashes
659 687 * (required for zfs_open).
660 688 */
661 689 cp = mnttab.mnt_special;
662 690 cp += strspn(cp, "/");
663 691 (void) strlcpy(dataset, cp, len);
664 692 rc = 0;
665 693 break;
666 694 }
667 695
668 696 if (strcmp(tmppath, "/") == 0)
669 697 break;
670 698
671 699 if ((cp = strrchr(tmppath, '/')) == NULL)
672 700 break;
673 701
674 702 /*
675 703 * The path has multiple components.
676 704 * Remove the last component and try again.
677 705 */
678 706 *cp = '\0';
679 707 if (tmppath[0] == '\0')
680 708 (void) strcpy(tmppath, "/");
681 709
682 710 cp = tmppath;
683 711 }
684 712
685 713 (void) fclose(fp);
686 714 return (rc);
687 715 }
688 716
689 717 /*
690 718 * smb_dlopen
691 719 *
692 720 * Check to see if an interposer library exists. If it exists
693 721 * and reports a valid version number and key (UUID), return
694 722 * a handle to the library. Otherwise, return NULL.
695 723 */
696 724 void *
697 725 smb_dlopen(void)
698 726 {
699 727 uuid_t uuid;
700 728 void *interposer_hdl;
701 729 typedef int (*smbex_versionfn_t)(smbex_version_t *);
702 730 smbex_versionfn_t getversion;
703 731 smbex_version_t *version;
704 732
705 733 bzero(&uuid, sizeof (uuid_t));
706 734 if (uuid_parse(SMBEX_KEY, uuid) < 0)
707 735 return (NULL);
708 736
709 737 interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
710 738 if (interposer_hdl == NULL)
711 739 return (NULL);
712 740
713 741 bzero(&getversion, sizeof (smbex_versionfn_t));
714 742 getversion = (smbex_versionfn_t)dlsym(interposer_hdl,
715 743 "smbex_get_version");
716 744 if ((getversion == NULL) ||
717 745 (version = malloc(sizeof (smbex_version_t))) == NULL) {
718 746 (void) dlclose(interposer_hdl);
719 747 return (NULL);
720 748 }
721 749 bzero(version, sizeof (smbex_version_t));
722 750
723 751 if ((getversion(version) != 0) ||
724 752 (version->v_version != SMBEX_VERSION) ||
725 753 (uuid_compare(version->v_uuid, uuid) != 0)) {
726 754 free(version);
727 755 (void) dlclose(interposer_hdl);
728 756 return (NULL);
729 757 }
730 758
731 759 free(version);
732 760 return (interposer_hdl);
733 761 }
734 762
735 763 /*
736 764 * smb_dlclose
737 765 *
738 766 * Closes handle to the interposed library.
739 767 */
740 768 void
741 769 smb_dlclose(void *handle)
742 770 {
743 771 if (handle)
744 772 (void) dlclose(handle);
745 773 }
746 774
747 775 /*
748 776 * This function is a wrapper for getnameinfo() to look up a hostname given an
749 777 * IP address. The hostname returned by this function is used for constructing
750 778 * the service principal name field of KRB AP-REQs. Hence, it should be
751 779 * converted to lowercase for RFC 4120 section 6.2.1 conformance.
752 780 */
753 781 int
754 782 smb_getnameinfo(smb_inaddr_t *ip, char *hostname, int hostlen, int flags)
755 783 {
756 784 socklen_t salen;
757 785 struct sockaddr_in6 sin6;
758 786 struct sockaddr_in sin;
759 787 void *sp;
760 788 int rc;
761 789
762 790 if (ip->a_family == AF_INET) {
763 791 salen = sizeof (struct sockaddr_in);
764 792 sin.sin_family = ip->a_family;
765 793 sin.sin_port = 0;
766 794 sin.sin_addr.s_addr = ip->a_ipv4;
767 795 sp = &sin;
768 796 } else {
769 797 salen = sizeof (struct sockaddr_in6);
770 798 sin6.sin6_family = ip->a_family;
771 799 sin6.sin6_port = 0;
772 800 (void) memcpy(&sin6.sin6_addr.s6_addr, &ip->a_ipv6,
773 801 sizeof (sin6.sin6_addr.s6_addr));
774 802 sp = &sin6;
775 803 }
776 804
777 805 if ((rc = (getnameinfo((struct sockaddr *)sp, salen,
778 806 hostname, hostlen, NULL, 0, flags))) == 0)
779 807 (void) smb_strlwr(hostname);
780 808
781 809 return (rc);
782 810 }
783 811
784 812 /*
785 813 * A share name is considered invalid if it contains control
786 814 * characters or any of the following characters (MSDN 236388).
787 815 *
788 816 * " / \ [ ] : | < > + ; , ? * =
789 817 */
790 818 uint32_t
791 819 smb_name_validate_share(const char *sharename)
792 820 {
793 821 const char *invalid = "\"/\\[]:|<>+;,?*=";
794 822 const char *p;
795 823
796 824 if (sharename == NULL)
797 825 return (ERROR_INVALID_PARAMETER);
798 826
799 827 if (strpbrk(sharename, invalid) != NULL)
800 828 return (ERROR_INVALID_NAME);
801 829
802 830 for (p = sharename; *p != '\0'; p++) {
803 831 if (iscntrl(*p))
804 832 return (ERROR_INVALID_NAME);
805 833 }
806 834
807 835 return (ERROR_SUCCESS);
808 836 }
809 837
810 838 /*
811 839 * User and group names are limited to 256 characters, cannot be terminated
812 840 * by '.' and must not contain control characters or any of the following
813 841 * characters.
814 842 *
815 843 * " / \ [ ] < > + ; , ? * = @
816 844 */
817 845 uint32_t
818 846 smb_name_validate_account(const char *name)
819 847 {
820 848 const char *invalid = "\"/\\[]<>+;,?*=@";
821 849 const char *p;
822 850 int len;
823 851
824 852 if ((name == NULL) || (*name == '\0'))
825 853 return (ERROR_INVALID_PARAMETER);
826 854
827 855 len = strlen(name);
828 856 if ((len > MAXNAMELEN) || (name[len - 1] == '.'))
829 857 return (ERROR_INVALID_NAME);
830 858
831 859 if (strpbrk(name, invalid) != NULL)
832 860 return (ERROR_INVALID_NAME);
833 861
834 862 for (p = name; *p != '\0'; p++) {
835 863 if (iscntrl(*p))
836 864 return (ERROR_INVALID_NAME);
837 865 }
838 866
839 867 return (ERROR_SUCCESS);
840 868 }
841 869
842 870 /*
843 871 * Check a domain name for RFC 1035 and 1123 compliance. Domain names may
844 872 * contain alphanumeric characters, hyphens and dots. The first and last
845 873 * character of a label must be alphanumeric. Interior characters may be
846 874 * alphanumeric or hypens.
847 875 *
848 876 * Domain names should not contain underscores but we allow them because
849 877 * Windows names are often in non-compliance with this rule.
850 878 */
851 879 uint32_t
852 880 smb_name_validate_domain(const char *domain)
853 881 {
854 882 boolean_t new_label = B_TRUE;
855 883 const char *p;
856 884 char label_terminator;
857 885
858 886 if (domain == NULL)
859 887 return (ERROR_INVALID_PARAMETER);
860 888
861 889 if (*domain == '\0')
862 890 return (ERROR_INVALID_NAME);
863 891
864 892 label_terminator = *domain;
865 893
866 894 for (p = domain; *p != '\0'; ++p) {
867 895 if (new_label) {
868 896 if (!isalnum(*p))
869 897 return (ERROR_INVALID_NAME);
870 898 new_label = B_FALSE;
871 899 label_terminator = *p;
872 900 continue;
873 901 }
874 902
875 903 if (*p == '.') {
876 904 if (!isalnum(label_terminator))
877 905 return (ERROR_INVALID_NAME);
878 906 new_label = B_TRUE;
879 907 label_terminator = *p;
880 908 continue;
881 909 }
882 910
883 911 label_terminator = *p;
884 912
885 913 if (isalnum(*p) || *p == '-' || *p == '_')
886 914 continue;
887 915
888 916 return (ERROR_INVALID_NAME);
889 917 }
890 918
891 919 if (!isalnum(label_terminator))
892 920 return (ERROR_INVALID_NAME);
893 921
894 922 return (ERROR_SUCCESS);
895 923 }
896 924
897 925 /*
898 926 * A NetBIOS domain name can contain letters (a-zA-Z), numbers (0-9) and
899 927 * hyphens.
900 928 *
901 929 * It cannot:
902 930 * - be blank or longer than 15 chracters
903 931 * - contain all numbers
904 932 * - be the same as the computer name
905 933 */
906 934 uint32_t
907 935 smb_name_validate_nbdomain(const char *name)
908 936 {
909 937 char netbiosname[NETBIOS_NAME_SZ];
910 938 const char *p;
911 939 int len;
912 940
913 941 if (name == NULL)
914 942 return (ERROR_INVALID_PARAMETER);
915 943
916 944 len = strlen(name);
917 945 if (len == 0 || len >= NETBIOS_NAME_SZ)
918 946 return (ERROR_INVALID_NAME);
919 947
920 948 if (strspn(name, "0123456789") == len)
921 949 return (ERROR_INVALID_NAME);
922 950
923 951 if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) {
924 952 if (smb_strcasecmp(name, netbiosname, 0) == 0)
925 953 return (ERROR_INVALID_NAME);
926 954 }
927 955
928 956 for (p = name; *p != '\0'; ++p) {
929 957 if (isalnum(*p) || *p == '-' || *p == '_')
930 958 continue;
931 959
932 960 return (ERROR_INVALID_NAME);
933 961 }
934 962
935 963 return (ERROR_SUCCESS);
936 964 }
937 965
938 966 /*
939 967 * A workgroup name can contain 1 to 15 characters but cannot be the same
940 968 * as the NetBIOS name. The name must begin with a letter or number.
941 969 *
942 970 * The name cannot consist entirely of spaces or dots, which is covered
943 971 * by the requirement that the name must begin with an alphanumeric
944 972 * character.
945 973 *
946 974 * The name must not contain control characters or any of the following
947 975 * characters.
948 976 *
949 977 * " / \ [ ] : | < > + = ; , ?
950 978 */
951 979 uint32_t
952 980 smb_name_validate_workgroup(const char *workgroup)
953 981 {
954 982 char netbiosname[NETBIOS_NAME_SZ];
955 983 const char *invalid = "\"/\\[]:|<>+=;,?";
956 984 const char *p;
957 985
958 986 if (workgroup == NULL)
959 987 return (ERROR_INVALID_PARAMETER);
960 988
961 989 if (*workgroup == '\0' || (!isalnum(*workgroup)))
962 990 return (ERROR_INVALID_NAME);
963 991
964 992 if (strlen(workgroup) >= NETBIOS_NAME_SZ)
965 993 return (ERROR_INVALID_NAME);
966 994
967 995 if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) {
968 996 if (smb_strcasecmp(workgroup, netbiosname, 0) == 0)
969 997 return (ERROR_INVALID_NAME);
970 998 }
971 999
972 1000 if (strpbrk(workgroup, invalid) != NULL)
973 1001 return (ERROR_INVALID_NAME);
974 1002
975 1003 for (p = workgroup; *p != '\0'; p++) {
976 1004 if (iscntrl(*p))
977 1005 return (ERROR_INVALID_NAME);
978 1006 }
979 1007
980 1008 return (ERROR_SUCCESS);
981 1009 }
982 1010
983 1011 /*
984 1012 * Check for invalid characters in the given path. The list of invalid
985 1013 * characters includes control characters and the following:
986 1014 *
987 1015 * " / \ [ ] : | < > + ; , ? * =
988 1016 *
989 1017 * Since this is checking a path not each component, '/' is accepted
990 1018 * as separator not an invalid character, except as the first character
991 1019 * since this is supposed to be a relative path.
992 1020 */
993 1021 uint32_t
994 1022 smb_name_validate_rpath(const char *relpath)
995 1023 {
996 1024 char *invalid = "\"\\[]:|<>+;,?*=";
997 1025 char *cp;
998 1026
999 1027 if ((relpath == NULL) || (*relpath == '\0') || (*relpath == '/'))
1000 1028 return (ERROR_INVALID_NAME);
1001 1029
1002 1030 if (strpbrk(relpath, invalid))
1003 1031 return (ERROR_INVALID_NAME);
1004 1032
1005 1033 for (cp = (char *)relpath; *cp != '\0'; cp++) {
1006 1034 if (iscntrl(*cp))
1007 1035 return (ERROR_INVALID_NAME);
1008 1036 }
1009 1037
1010 1038 return (ERROR_SUCCESS);
1011 1039 }
1012 1040
1013 1041 /*
1014 1042 * Parse a string to obtain the account and domain names as separate strings.
1015 1043 *
1016 1044 * Names containing a backslash ('\') are known as qualified or composite
1017 1045 * names. The string preceding the backslash should be the domain name
1018 1046 * and the string following the slash should be a name within that domain.
1019 1047 *
1020 1048 * Names that do not contain a backslash are known as isolated names.
1021 1049 * An isolated name may be a single label, such as john, or may be in
1022 1050 * user principal name (UPN) form, such as john@example.com.
1023 1051 *
1024 1052 * domain\name
1025 1053 * domain/name
1026 1054 * name
1027 1055 * name@domain
1028 1056 *
1029 1057 * If we encounter any of the forms above in arg, the @, / or \ separator
1030 1058 * is replaced by \0 and the name and domain pointers are set to point to
1031 1059 * the appropriate components in arg. Otherwise, name and domain pointers
1032 1060 * will be set to NULL.
1033 1061 */
1034 1062 void
1035 1063 smb_name_parse(char *arg, char **account, char **domain)
1036 1064 {
1037 1065 char *p;
1038 1066
1039 1067 *account = NULL;
1040 1068 *domain = NULL;
1041 1069
1042 1070 if ((p = strpbrk(arg, "/\\@")) != NULL) {
1043 1071 if (*p == '@') {
1044 1072 *p = '\0';
1045 1073 ++p;
1046 1074 *domain = p;
1047 1075 *account = arg;
1048 1076 } else {
1049 1077 *p = '\0';
1050 1078 ++p;
1051 1079 *account = p;
1052 1080 *domain = arg;
1053 1081 }
1054 1082 }
1055 1083 }
1056 1084
1057 1085 /*
1058 1086 * The txid is an arbitrary transaction. A new txid is returned on each call.
1059 1087 *
1060 1088 * 0 or -1 are not assigned so that they can be used to detect
1061 1089 * invalid conditions.
1062 1090 */
1063 1091 uint32_t
1064 1092 smb_get_txid(void)
1065 1093 {
1066 1094 static mutex_t txmutex;
1067 1095 static uint32_t txid;
1068 1096 uint32_t txid_ret;
1069 1097
1070 1098 (void) mutex_lock(&txmutex);
1071 1099
1072 1100 if (txid == 0)
1073 1101 txid = time(NULL);
1074 1102
1075 1103 do {
1076 1104 ++txid;
1077 1105 } while (txid == 0 || txid == (uint32_t)-1);
1078 1106
1079 1107 txid_ret = txid;
1080 1108 (void) mutex_unlock(&txmutex);
1081 1109
1082 1110 return (txid_ret);
1083 1111 }
|
↓ open down ↓ |
435 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX