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
hexdump_offset(unsigned char * buffer,int nbytes,unsigned long * start)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
hexdump(unsigned char * buffer,int nbytes)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
bintohex(const char * srcbuf,size_t srclen,char * hexbuf,size_t hexlen)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
hextobin(const char * hexbuf,size_t hexlen,char * dstbuf,size_t dstlen)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 *
strtrim(char * buf,const char * class)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 *
strstrip(char * buf,const char * class)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 *
trim_whitespace(char * buf)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
rand_hash(unsigned char * data,size_t datalen,unsigned char * key,size_t keylen)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
smb_chk_hostaccess(smb_inaddr_t * ipaddr,char * access_list)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
smb_netgroup_match(struct nd_hostservlist * clnames,char * glist,int grc)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
smb_getdataset(libzfs_handle_t * libhdl,const char * path,char * dataset,size_t len)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 *
smb_dlopen(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
smb_dlclose(void * handle)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
smb_getnameinfo(smb_inaddr_t * ip,char * hostname,int hostlen,int flags)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
smb_name_validate_share(const char * sharename)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
smb_name_validate_account(const char * name)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
smb_name_validate_domain(const char * domain)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
smb_name_validate_nbdomain(const char * name)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
smb_name_validate_workgroup(const char * workgroup)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
smb_name_validate_rpath(const char * relpath)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
smb_name_parse(char * arg,char ** account,char ** domain)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
smb_get_txid(void)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