15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*10966SJordan.Brown@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw #ifdef _KERNEL
275331Samw #include <sys/types.h>
285331Samw #include <sys/sunddi.h>
295331Samw #else
305331Samw #include <string.h>
315331Samw #endif
325331Samw #include <smbsrv/string.h>
335331Samw #include <smbsrv/netbios.h>
345331Samw 
355331Samw static int domainname_is_valid(char *domain_name);
365331Samw 
375331Samw /*
385331Samw  * Routines than support name compression.
395331Samw  *
405331Samw  *   The NetBIOS name representation in all NetBIOS packets (for NAME,
415331Samw  *   SESSION, and DATAGRAM services) is defined in the Domain Name
425331Samw  *   Service RFC 883[3] as "compressed" name messages.  This format is
435331Samw  *   called "second-level encoding" in the section entitled
445331Samw  *   "Representation of NetBIOS Names" in the Concepts and Methods
455331Samw  *   document.
465331Samw  *
475331Samw  *   For ease of description, the first two paragraphs from page 31,
485331Samw  *   the section titled "Domain name representation and compression",
495331Samw  *   of RFC 883 are replicated here:
505331Samw  *
515331Samw  *        Domain names messages are expressed in terms of a sequence
525331Samw  *        of labels.  Each label is represented as a one octet length
535331Samw  *        field followed by that number of octets.  Since every domain
545331Samw  *        name ends with the null label of the root, a compressed
555331Samw  *        domain name is terminated by a length byte of zero.  The
565331Samw  *        high order two bits of the length field must be zero, and
575331Samw  *        the remaining six bits of the length field limit the label
585331Samw  *        to 63 octets or less.
595331Samw  *
605331Samw  *        To simplify implementations, the total length of label
615331Samw  *        octets and label length octets that make up a domain name is
625331Samw  *        restricted to 255 octets or less.
635331Samw  *
645331Samw  *   The following is the uncompressed representation of the NetBIOS name
655331Samw  *   "FRED ", which is the 4 ASCII characters, F, R, E, D, followed by 12
665331Samw  *   space characters (0x20).  This name has the SCOPE_ID: "NETBIOS.COM"
675331Samw  *
685331Samw  *           EGFCEFEECACACACACACACACACACACACA.NETBIOS.COM
695331Samw  *
705331Samw  *   This uncompressed representation of names is called "first-level
715331Samw  *   encoding" in the section entitled "Representation of NetBIOS Names"
725331Samw  *   in the Concepts and Methods document.
735331Samw  *
745331Samw  *   The following is a pictographic representation of the compressed
755331Samw  *   representation of the previous uncompressed Domain Name
765331Samw  *   representation.
775331Samw  *
785331Samw  *                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
795331Samw  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
805331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
815331Samw  *   |      0x20     |    E (0x45)   |    G (0x47)   |    F (0x46)   |
825331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
835331Samw  *   |    C (0x43)   |    E (0x45)   |    F (0x46)   |    E (0x45)   |
845331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
855331Samw  *   |    E (0x45)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
865331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
875331Samw  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
885331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
895331Samw  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
905331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
915331Samw  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
925331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
935331Samw  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
945331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
955331Samw  *   |    A (0x41)   |    C (0x43)   |    A (0x41)   |    C (0x43)   |
965331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
975331Samw  *   |    A (0X41)   |      0x07     |    N (0x4E)   |    E (0x45)   |
985331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
995331Samw  *   |    T (0x54)   |    B (0x42)   |    I (0x49)   |    O (0x4F)   |
1005331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1015331Samw  *   |    S (0x53)   |      0x03     |    C (0x43)   |    O (0x4F)   |
1025331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1035331Samw  *   |    M (0x4D)   |      0x00     |
1045331Samw  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1055331Samw  *
1065331Samw  *   Each section of a domain name is called a label [7 (page 31)].  A
1075331Samw  *   label can be a maximum of 63 bytes.  The first byte of a label in
1085331Samw  *   compressed representation is the number of bytes in the label.  For
1095331Samw  *   the above example, the first 0x20 is the number of bytes in the
1105331Samw  *   left-most label, EGFCEFEECACACACACACACACACACACACA, of the domain
1115331Samw  *   name.  The bytes following the label length count are the characters
1125331Samw  *   of the label.  The following labels are in sequence after the first
1135331Samw  *   label, which is the encoded NetBIOS name, until a zero (0x00) length
1145331Samw  *   count.  The zero length count represents the root label, which is
1155331Samw  *   always null.
1165331Samw  *
1175331Samw  *   A label length count is actually a 6-bit field in the label length
1185331Samw  *   field.  The most significant 2 bits of the field, bits 7 and 6, are
1195331Samw  *   flags allowing an escape from the above compressed representation.
1205331Samw  *   If bits 7 and 6 are both set (11), the following 14 bits are an
1215331Samw  *   offset pointer into the full message to the actual label string from
1225331Samw  *   another domain name that belongs in this name.  This label pointer
1235331Samw  *   allows for a further compression of a domain name in a packet.
1245331Samw  *
1255331Samw  *   NetBIOS implementations can only use label string pointers in Name
1265331Samw  *   Service packets.  They cannot be used in Session or Datagram Service
1275331Samw  *   packets.
1285331Samw  *
1295331Samw  *   The other two possible values for bits 7 and 6 (01 and 10) of a label
1305331Samw  *   length field are reserved for future use by RFC 883[2 (page 32)].
1315331Samw  *
1325331Samw  *   Note that the first octet of a compressed name must contain one of
1335331Samw  *   the following bit patterns.  (An "x" indicates a bit whose value may
1345331Samw  *   be either 0 or 1.):
1355331Samw  *
1365331Samw  *           00100000 -  Netbios name, length must be 32 (decimal)
1375331Samw  *           11xxxxxx -  Label string pointer
1385331Samw  *           10xxxxxx -  Reserved
1395331Samw  *           01xxxxxx -  Reserved
1405331Samw  */
1415331Samw 
1425331Samw /*
1435331Samw  * netbios_first_level_name_encode
1445331Samw  *
1455331Samw  * Put test description here.
1465331Samw  *
1475331Samw  * Inputs:
1485331Samw  *	char *	in	-> Name to encode
1495331Samw  *	char *	out	-> Buffer to encode into.
1505331Samw  *	int	length	-> # of bytes to encode.
1515331Samw  *
1525331Samw  * Returns:
1535331Samw  *	Nothing
1545331Samw  */
1555331Samw int
1565331Samw netbios_first_level_name_encode(unsigned char *name, unsigned char *scope,
1575331Samw     unsigned char *out, int max_out)
1585331Samw {
1595331Samw 	unsigned char	ch, len;
1605331Samw 	unsigned char	 *in;
1615331Samw 	unsigned char	 *lp;
1625331Samw 	unsigned char	 *op = out;
1635331Samw 
1645331Samw 	if (max_out < 0x21)
1655331Samw 		return (-1);
1665331Samw 
1675331Samw 	in = name;
1685331Samw 	*op++ = 0x20;
1695331Samw 	for (len = 0; len < NETBIOS_NAME_SZ; len++) {
1705331Samw 		ch = *in++;
1715331Samw 		*op++ = 'A' + ((ch >> 4) & 0xF);
1725331Samw 		*op++ = 'A' + ((ch) & 0xF);
1735331Samw 	}
1745331Samw 
1755331Samw 	max_out -= 0x21;
1765331Samw 
1775331Samw 	in = scope;
1785331Samw 	len = 0;
1795331Samw 	lp = op++;
1805331Samw 	while (((ch = *in++) != 0) && (max_out-- > 1)) {
1815331Samw 		if (ch == 0) {
1825331Samw 			if ((*lp = len) != 0)
1835331Samw 				*op++ = 0;
1845331Samw 			break;
1855331Samw 		}
1865331Samw 		if (ch == '.') {
1875331Samw 			*lp = len;
1885331Samw 			lp = op++;
1895331Samw 			len = 0;
1905331Samw 		} else {
1915331Samw 			*op++ = ch;
1925331Samw 			len++;
1935331Samw 		}
1945331Samw 	}
1955331Samw 	*lp = len;
1965331Samw 	if (len != 0)
1975331Samw 		*op = 0;
1985331Samw 
1995331Samw 	/*LINTED E_PTRDIFF_OVERFLOW*/
2005331Samw 	return (op - out);
2015331Samw }
2025331Samw 
2035331Samw /*
2045331Samw  * smb_first_level_name_decode
2055331Samw  *
2065331Samw  * The null terminated string "in" is the name to decode. The output
2075331Samw  * is placed in the name_entry structure "name".
2085331Samw  *
2095331Samw  * The scope field is a series of length designated labels as described
2105331Samw  * in the "Domain name representation and compression" section of RFC883.
2115331Samw  * The two high order two bits of the length field must be zero, the
2125331Samw  * remaining six bits contain the field length. The total length of the
2135331Samw  * domain name is restricted to 255 octets but note that the trailing
2145331Samw  * root label and its dot are not printed. When converting the labels,
2155331Samw  * the length fields are replaced by dots.
2165331Samw  *
2175331Samw  * Returns the number of bytes scanned or -1 to indicate an error.
2185331Samw  */
2195331Samw int
2205331Samw netbios_first_level_name_decode(char *in, char *name, char *scope)
2215331Samw {
2225331Samw 	unsigned int	length, bytes;
2235331Samw 	char		c1, c2;
2245331Samw 	char		*cp;
2255331Samw 	char		*out;
2265331Samw 
2275331Samw 	cp = in;
2285331Samw 
2295331Samw 	if ((length = *cp++) != 0x20) {
2305331Samw 		return (-1);
2315331Samw 	}
2325331Samw 
2335331Samw 	out = name;
2345331Samw 	while (length > 0) {
2355331Samw 		c1 = *cp++;
2365331Samw 		c2 = *cp++;
2375331Samw 
2385331Samw 		if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') {
2395331Samw 			c1 -= 'A';
2405331Samw 			c2 -= 'A';
2415331Samw 			*out++ = (c1 << 4) | (c2);
2425331Samw 		} else {
2435331Samw 			return (-1);		/* conversion error */
2445331Samw 		}
2455331Samw 		length -= 2;
2465331Samw 	}
2475331Samw 
2485331Samw 	out = scope;
2495331Samw 	bytes = 0;
2505331Samw 	for (length = *cp++; length != 0; length = *cp++) {
2515331Samw 		if ((length & 0xc0) != 0x00) {
2525331Samw 			/*
2535331Samw 			 * This is a pointer or a reserved field. If it's
2545331Samw 			 * a pointer (16-bits) we have to skip the next byte.
2555331Samw 			 */
2565331Samw 			if ((length & 0xc0) == 0xc0) {
2575331Samw 				cp++;
2585331Samw 				continue;
2595331Samw 			}
2605331Samw 		}
2615331Samw 
2625331Samw 		/*
2635331Samw 		 * Replace the length with a '.', except for the first one.
2645331Samw 		 */
2655331Samw 		if (out != scope) {
2665331Samw 			*out++ = '.';
2675331Samw 			bytes++;
2685331Samw 		}
2695331Samw 
2705331Samw 		while (length-- > 0) {
2715331Samw 			if (bytes++ >= (NETBIOS_DOMAIN_NAME_MAX - 1)) {
2725331Samw 				return (-1);
2735331Samw 			}
2745331Samw 			*out++ = *cp++;
2755331Samw 		}
2765331Samw 	}
2775331Samw 	*out = 0;
2785331Samw 
2795331Samw 	/*
2805331Samw 	 * We are supposed to preserve all 8-bits of the domain name
2815331Samw 	 * but due to the single byte representation in the name cache
2825331Samw 	 * and UTF-8 encoding everywhere else, we restrict domain names
2835331Samw 	 * to Appendix 1 - Domain Name Syntax Specification in RFC883.
2845331Samw 	 */
2855331Samw 	if (domainname_is_valid(scope))	{
286*10966SJordan.Brown@Sun.COM 		(void) smb_strupr(scope);
2875331Samw 		/*LINTED E_PTRDIFF_OVERFLOW*/
2885331Samw 		return (cp - in);
2895331Samw 	}
2905331Samw 
2915331Samw 	scope[0] = '\0';
2925331Samw 	return (-1);
2935331Samw }
2945331Samw 
2955331Samw /*
2965331Samw  * smb_netbios_name_isvalid
2975331Samw  *
2985331Samw  * This function is provided to be used by session service
2995331Samw  * which runs in kernel in order to hide name_entry definition.
3005331Samw  *
3015331Samw  * It returns the decoded name in the provided buffer as 'out'
3025331Samw  * if it's not null.
3035331Samw  *
3045331Samw  * Returns 0 if decode fails, 1 if it succeeds.
3055331Samw  */
3065331Samw int
3075331Samw netbios_name_isvalid(char *in, char *out)
3085331Samw {
3095331Samw 	char name[NETBIOS_NAME_SZ];
3105331Samw 	char scope[NETBIOS_DOMAIN_NAME_MAX];
3115331Samw 
3125331Samw 	if (netbios_first_level_name_decode(in, name, scope) < 0)
3135331Samw 		return (0);
3145331Samw 
3155331Samw 	if (out)
3165331Samw 		(void) strlcpy(out, name, NETBIOS_NAME_SZ);
3175331Samw 
3185331Samw 	return (1);
3195331Samw }
3205331Samw 
3215331Samw /*
3225331Samw  * Characters that we allow in DNS domain names, in addition to
3235331Samw  * alphanumeric characters. This is not quite consistent with
3245331Samw  * RFC883. This is global so that it can be patched if there is
3255331Samw  * a need to change the valid characters in the field.
3265331Samw  */
3275331Samw unsigned char *dns_allowed = (unsigned char *)"-_";
3285331Samw 
3295331Samw /*
3305331Samw  * dns_is_allowed
3315331Samw  *
3325331Samw  * Check the dns_allowed characters and return true (1) if the character
3335331Samw  * is in the table. Otherwise return false (0).
3345331Samw  */
3355331Samw static int
3365331Samw dns_is_allowed(unsigned char c)
3375331Samw {
3385331Samw 	unsigned char *p = dns_allowed;
3395331Samw 
3405331Samw 	while (*p) {
3415331Samw 		if (c == *p++)
3425331Samw 			return (1);
3435331Samw 	}
3445331Samw 
3455331Samw 	return (0);
3465331Samw }
3475331Samw 
3485331Samw 
3495331Samw /*
3505331Samw  * domainname_is_valid
3515331Samw  *
3525331Samw  * Check the specified domain name for mostly compliance with RFC883
3535331Samw  * Appendix 1. Names may contain alphanumeric characters, hyphens,
3545331Samw  * underscores and dots. The first character after a dot must be an
3555331Samw  * alphabetic character. RFC883 doesn't mention underscores but we
3565331Samw  * allow it due to common use, and we don't check that labels end
3575331Samw  * with an alphanumeric character.
3585331Samw  *
3595331Samw  * Returns true (1) if the name is valid. Otherwise returns false (0).
3605331Samw  */
3615331Samw static int
3625331Samw domainname_is_valid(char *domain_name)
3635331Samw {
3645331Samw 	char *name;
3655331Samw 	int first_char = 1;
3665331Samw 
3675331Samw 	if (domain_name == 0)
3685331Samw 		return (0);
3695331Samw 
3705331Samw 	for (name = domain_name; *name != 0; ++name) {
3715331Samw 		if (*name == '.') {
3725331Samw 			first_char = 1;
3735331Samw 			continue;
3745331Samw 		}
3755331Samw 
3765331Samw 		if (first_char)	{
377*10966SJordan.Brown@Sun.COM 			if (smb_isalpha_ascii(*name) == 0)
3785331Samw 				return (0);
3795331Samw 
3805331Samw 			first_char = 0;
3815331Samw 			continue;
3825331Samw 		}
3835331Samw 
384*10966SJordan.Brown@Sun.COM 		if (smb_isalnum_ascii(*name) || dns_is_allowed(*name))
3855331Samw 			continue;
3865331Samw 
3875331Samw 		return (0);
3885331Samw 	}
3895331Samw 
3905331Samw 	return (1);
3915331Samw }
392