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 2014 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)) 462 return (response); 463 } 464 } else { 465 if (inet_matchaddr(buf.buf, gr)) 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(const char *path, char *dataset, size_t len) 631 { 632 char tmppath[MAXPATHLEN]; 633 char *cp; 634 FILE *fp; 635 struct mnttab mnttab; 636 struct mnttab mntpref; 637 int rc = -1; 638 639 if ((fp = fopen(MNTTAB, "r")) == NULL) 640 return (-1); 641 642 (void) memset(&mnttab, '\0', sizeof (mnttab)); 643 (void) strlcpy(tmppath, path, MAXPATHLEN); 644 cp = tmppath; 645 646 while (*cp != '\0') { 647 resetmnttab(fp); 648 (void) memset(&mntpref, '\0', sizeof (mntpref)); 649 mntpref.mnt_mountp = tmppath; 650 651 if (getmntany(fp, &mnttab, &mntpref) == 0) { 652 if (mnttab.mnt_fstype == NULL) 653 break; 654 655 if (strcmp(mnttab.mnt_fstype, "zfs") != 0) 656 break; 657 /* 658 * Ensure that there are no leading slashes 659 * (required for zfs_open). 660 */ 661 cp = mnttab.mnt_special; 662 cp += strspn(cp, "/"); 663 (void) strlcpy(dataset, cp, len); 664 rc = 0; 665 break; 666 } 667 668 if (strcmp(tmppath, "/") == 0) 669 break; 670 671 if ((cp = strrchr(tmppath, '/')) == NULL) 672 break; 673 674 /* 675 * The path has multiple components. 676 * Remove the last component and try again. 677 */ 678 *cp = '\0'; 679 if (tmppath[0] == '\0') 680 (void) strcpy(tmppath, "/"); 681 682 cp = tmppath; 683 } 684 685 (void) fclose(fp); 686 return (rc); 687 } 688 689 /* 690 * smb_dlopen 691 * 692 * Check to see if an interposer library exists. If it exists 693 * and reports a valid version number and key (UUID), return 694 * a handle to the library. Otherwise, return NULL. 695 */ 696 void * 697 smb_dlopen(void) 698 { 699 uuid_t uuid; 700 void *interposer_hdl; 701 typedef int (*smbex_versionfn_t)(smbex_version_t *); 702 smbex_versionfn_t getversion; 703 smbex_version_t *version; 704 705 bzero(&uuid, sizeof (uuid_t)); 706 if (uuid_parse(SMBEX_KEY, uuid) < 0) 707 return (NULL); 708 709 interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL); 710 if (interposer_hdl == NULL) 711 return (NULL); 712 713 bzero(&getversion, sizeof (smbex_versionfn_t)); 714 getversion = (smbex_versionfn_t)dlsym(interposer_hdl, 715 "smbex_get_version"); 716 if ((getversion == NULL) || 717 (version = malloc(sizeof (smbex_version_t))) == NULL) { 718 (void) dlclose(interposer_hdl); 719 return (NULL); 720 } 721 bzero(version, sizeof (smbex_version_t)); 722 723 if ((getversion(version) != 0) || 724 (version->v_version != SMBEX_VERSION) || 725 (uuid_compare(version->v_uuid, uuid) != 0)) { 726 free(version); 727 (void) dlclose(interposer_hdl); 728 return (NULL); 729 } 730 731 free(version); 732 return (interposer_hdl); 733 } 734 735 /* 736 * smb_dlclose 737 * 738 * Closes handle to the interposed library. 739 */ 740 void 741 smb_dlclose(void *handle) 742 { 743 if (handle) 744 (void) dlclose(handle); 745 } 746 747 /* 748 * This function is a wrapper for getnameinfo() to look up a hostname given an 749 * IP address. The hostname returned by this function is used for constructing 750 * the service principal name field of KRB AP-REQs. Hence, it should be 751 * converted to lowercase for RFC 4120 section 6.2.1 conformance. 752 */ 753 int 754 smb_getnameinfo(smb_inaddr_t *ip, char *hostname, int hostlen, int flags) 755 { 756 socklen_t salen; 757 struct sockaddr_in6 sin6; 758 struct sockaddr_in sin; 759 void *sp; 760 int rc; 761 762 if (ip->a_family == AF_INET) { 763 salen = sizeof (struct sockaddr_in); 764 sin.sin_family = ip->a_family; 765 sin.sin_port = 0; 766 sin.sin_addr.s_addr = ip->a_ipv4; 767 sp = &sin; 768 } else { 769 salen = sizeof (struct sockaddr_in6); 770 sin6.sin6_family = ip->a_family; 771 sin6.sin6_port = 0; 772 (void) memcpy(&sin6.sin6_addr.s6_addr, &ip->a_ipv6, 773 sizeof (sin6.sin6_addr.s6_addr)); 774 sp = &sin6; 775 } 776 777 if ((rc = (getnameinfo((struct sockaddr *)sp, salen, 778 hostname, hostlen, NULL, 0, flags))) == 0) 779 (void) smb_strlwr(hostname); 780 781 return (rc); 782 } 783 784 /* 785 * A share name is considered invalid if it contains control 786 * characters or any of the following characters (MSDN 236388). 787 * 788 * " / \ [ ] : | < > + ; , ? * = 789 */ 790 uint32_t 791 smb_name_validate_share(const char *sharename) 792 { 793 const char *invalid = "\"/\\[]:|<>+;,?*="; 794 const char *p; 795 796 if (sharename == NULL) 797 return (ERROR_INVALID_PARAMETER); 798 799 if (strpbrk(sharename, invalid) != NULL) 800 return (ERROR_INVALID_NAME); 801 802 for (p = sharename; *p != '\0'; p++) { 803 if (iscntrl(*p)) 804 return (ERROR_INVALID_NAME); 805 } 806 807 return (ERROR_SUCCESS); 808 } 809 810 /* 811 * User and group names are limited to 256 characters, cannot be terminated 812 * by '.' and must not contain control characters or any of the following 813 * characters. 814 * 815 * " / \ [ ] < > + ; , ? * = @ 816 */ 817 uint32_t 818 smb_name_validate_account(const char *name) 819 { 820 const char *invalid = "\"/\\[]<>+;,?*=@"; 821 const char *p; 822 int len; 823 824 if ((name == NULL) || (*name == '\0')) 825 return (ERROR_INVALID_PARAMETER); 826 827 len = strlen(name); 828 if ((len > MAXNAMELEN) || (name[len - 1] == '.')) 829 return (ERROR_INVALID_NAME); 830 831 if (strpbrk(name, invalid) != NULL) 832 return (ERROR_INVALID_NAME); 833 834 for (p = name; *p != '\0'; p++) { 835 if (iscntrl(*p)) 836 return (ERROR_INVALID_NAME); 837 } 838 839 return (ERROR_SUCCESS); 840 } 841 842 /* 843 * Check a domain name for RFC 1035 and 1123 compliance. Domain names may 844 * contain alphanumeric characters, hyphens and dots. The first and last 845 * character of a label must be alphanumeric. Interior characters may be 846 * alphanumeric or hypens. 847 * 848 * Domain names should not contain underscores but we allow them because 849 * Windows names are often in non-compliance with this rule. 850 */ 851 uint32_t 852 smb_name_validate_domain(const char *domain) 853 { 854 boolean_t new_label = B_TRUE; 855 const char *p; 856 char label_terminator; 857 858 if (domain == NULL) 859 return (ERROR_INVALID_PARAMETER); 860 861 if (*domain == '\0') 862 return (ERROR_INVALID_NAME); 863 864 label_terminator = *domain; 865 866 for (p = domain; *p != '\0'; ++p) { 867 if (new_label) { 868 if (!isalnum(*p)) 869 return (ERROR_INVALID_NAME); 870 new_label = B_FALSE; 871 label_terminator = *p; 872 continue; 873 } 874 875 if (*p == '.') { 876 if (!isalnum(label_terminator)) 877 return (ERROR_INVALID_NAME); 878 new_label = B_TRUE; 879 label_terminator = *p; 880 continue; 881 } 882 883 label_terminator = *p; 884 885 if (isalnum(*p) || *p == '-' || *p == '_') 886 continue; 887 888 return (ERROR_INVALID_NAME); 889 } 890 891 if (!isalnum(label_terminator)) 892 return (ERROR_INVALID_NAME); 893 894 return (ERROR_SUCCESS); 895 } 896 897 /* 898 * A NetBIOS domain name can contain letters (a-zA-Z), numbers (0-9) and 899 * hyphens. 900 * 901 * It cannot: 902 * - be blank or longer than 15 chracters 903 * - contain all numbers 904 * - be the same as the computer name 905 */ 906 uint32_t 907 smb_name_validate_nbdomain(const char *name) 908 { 909 char netbiosname[NETBIOS_NAME_SZ]; 910 const char *p; 911 int len; 912 913 if (name == NULL) 914 return (ERROR_INVALID_PARAMETER); 915 916 len = strlen(name); 917 if (len == 0 || len >= NETBIOS_NAME_SZ) 918 return (ERROR_INVALID_NAME); 919 920 if (strspn(name, "0123456789") == len) 921 return (ERROR_INVALID_NAME); 922 923 if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) { 924 if (smb_strcasecmp(name, netbiosname, 0) == 0) 925 return (ERROR_INVALID_NAME); 926 } 927 928 for (p = name; *p != '\0'; ++p) { 929 if (isalnum(*p) || *p == '-' || *p == '_') 930 continue; 931 932 return (ERROR_INVALID_NAME); 933 } 934 935 return (ERROR_SUCCESS); 936 } 937 938 /* 939 * A workgroup name can contain 1 to 15 characters but cannot be the same 940 * as the NetBIOS name. The name must begin with a letter or number. 941 * 942 * The name cannot consist entirely of spaces or dots, which is covered 943 * by the requirement that the name must begin with an alphanumeric 944 * character. 945 * 946 * The name must not contain control characters or any of the following 947 * characters. 948 * 949 * " / \ [ ] : | < > + = ; , ? 950 */ 951 uint32_t 952 smb_name_validate_workgroup(const char *workgroup) 953 { 954 char netbiosname[NETBIOS_NAME_SZ]; 955 const char *invalid = "\"/\\[]:|<>+=;,?"; 956 const char *p; 957 958 if (workgroup == NULL) 959 return (ERROR_INVALID_PARAMETER); 960 961 if (*workgroup == '\0' || (!isalnum(*workgroup))) 962 return (ERROR_INVALID_NAME); 963 964 if (strlen(workgroup) >= NETBIOS_NAME_SZ) 965 return (ERROR_INVALID_NAME); 966 967 if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) { 968 if (smb_strcasecmp(workgroup, netbiosname, 0) == 0) 969 return (ERROR_INVALID_NAME); 970 } 971 972 if (strpbrk(workgroup, invalid) != NULL) 973 return (ERROR_INVALID_NAME); 974 975 for (p = workgroup; *p != '\0'; p++) { 976 if (iscntrl(*p)) 977 return (ERROR_INVALID_NAME); 978 } 979 980 return (ERROR_SUCCESS); 981 } 982 983 /* 984 * Check for invalid characters in the given path. The list of invalid 985 * characters includes control characters and the following: 986 * 987 * " / \ [ ] : | < > + ; , ? * = 988 * 989 * Since this is checking a path not each component, '/' is accepted 990 * as separator not an invalid character, except as the first character 991 * since this is supposed to be a relative path. 992 */ 993 uint32_t 994 smb_name_validate_rpath(const char *relpath) 995 { 996 char *invalid = "\"\\[]:|<>+;,?*="; 997 char *cp; 998 999 if ((relpath == NULL) || (*relpath == '\0') || (*relpath == '/')) 1000 return (ERROR_INVALID_NAME); 1001 1002 if (strpbrk(relpath, invalid)) 1003 return (ERROR_INVALID_NAME); 1004 1005 for (cp = (char *)relpath; *cp != '\0'; cp++) { 1006 if (iscntrl(*cp)) 1007 return (ERROR_INVALID_NAME); 1008 } 1009 1010 return (ERROR_SUCCESS); 1011 } 1012 1013 /* 1014 * Parse a string to obtain the account and domain names as separate strings. 1015 * 1016 * Names containing a backslash ('\') are known as qualified or composite 1017 * names. The string preceding the backslash should be the domain name 1018 * and the string following the slash should be a name within that domain. 1019 * 1020 * Names that do not contain a backslash are known as isolated names. 1021 * An isolated name may be a single label, such as john, or may be in 1022 * user principal name (UPN) form, such as john@example.com. 1023 * 1024 * domain\name 1025 * domain/name 1026 * name 1027 * name@domain 1028 * 1029 * If we encounter any of the forms above in arg, the @, / or \ separator 1030 * is replaced by \0 and the name and domain pointers are set to point to 1031 * the appropriate components in arg. Otherwise, name and domain pointers 1032 * will be set to NULL. 1033 */ 1034 void 1035 smb_name_parse(char *arg, char **account, char **domain) 1036 { 1037 char *p; 1038 1039 *account = NULL; 1040 *domain = NULL; 1041 1042 if ((p = strpbrk(arg, "/\\@")) != NULL) { 1043 if (*p == '@') { 1044 *p = '\0'; 1045 ++p; 1046 *domain = p; 1047 *account = arg; 1048 } else { 1049 *p = '\0'; 1050 ++p; 1051 *account = p; 1052 *domain = arg; 1053 } 1054 } 1055 } 1056 1057 /* 1058 * The txid is an arbitrary transaction. A new txid is returned on each call. 1059 * 1060 * 0 or -1 are not assigned so that they can be used to detect 1061 * invalid conditions. 1062 */ 1063 uint32_t 1064 smb_get_txid(void) 1065 { 1066 static mutex_t txmutex; 1067 static uint32_t txid; 1068 uint32_t txid_ret; 1069 1070 (void) mutex_lock(&txmutex); 1071 1072 if (txid == 0) 1073 txid = time(NULL); 1074 1075 do { 1076 ++txid; 1077 } while (txid == 0 || txid == (uint32_t)-1); 1078 1079 txid_ret = txid; 1080 (void) mutex_unlock(&txmutex); 1081 1082 return (txid_ret); 1083 } 1084