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