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
netbios_first_level_name_encode(unsigned char * name,unsigned char * scope,unsigned char * out,int max_out)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
netbios_first_level_name_decode(char * in,char * name,char * scope)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
netbios_name_isvalid(char * in,char * out)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
dns_is_allowed(unsigned char c)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
domainname_is_valid(char * domain_name)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