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