1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22bbf6f00cSJordan Brown * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24b819cea2SGordon Ross * 25b819cea2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 26da6c28aaSamw */ 27da6c28aaSamw 28b819cea2SGordon Ross #if defined(_KERNEL) || defined(_FAKE_KERNEL) 29da6c28aaSamw #include <sys/types.h> 30da6c28aaSamw #include <sys/sunddi.h> 31da6c28aaSamw #else 32da6c28aaSamw #include <string.h> 33da6c28aaSamw #endif 34da6c28aaSamw #include <smbsrv/string.h> 35da6c28aaSamw #include <smbsrv/netbios.h> 36da6c28aaSamw 37da6c28aaSamw /* 38da6c28aaSamw * Routines than support name compression. 39da6c28aaSamw * 40da6c28aaSamw * The NetBIOS name representation in all NetBIOS packets (for NAME, 41da6c28aaSamw * SESSION, and DATAGRAM services) is defined in the Domain Name 42da6c28aaSamw * Service RFC 883[3] as "compressed" name messages. This format is 43da6c28aaSamw * called "second-level encoding" in the section entitled 44da6c28aaSamw * "Representation of NetBIOS Names" in the Concepts and Methods 45da6c28aaSamw * document. 46da6c28aaSamw * 47da6c28aaSamw * For ease of description, the first two paragraphs from page 31, 48da6c28aaSamw * the section titled "Domain name representation and compression", 49da6c28aaSamw * of RFC 883 are replicated here: 50da6c28aaSamw * 51da6c28aaSamw * Domain names messages are expressed in terms of a sequence 52da6c28aaSamw * of labels. Each label is represented as a one octet length 53da6c28aaSamw * field followed by that number of octets. Since every domain 54da6c28aaSamw * name ends with the null label of the root, a compressed 55da6c28aaSamw * domain name is terminated by a length byte of zero. The 56da6c28aaSamw * high order two bits of the length field must be zero, and 57da6c28aaSamw * the remaining six bits of the length field limit the label 58da6c28aaSamw * to 63 octets or less. 59da6c28aaSamw * 60da6c28aaSamw * To simplify implementations, the total length of label 61da6c28aaSamw * octets and label length octets that make up a domain name is 62da6c28aaSamw * restricted to 255 octets or less. 63da6c28aaSamw * 64da6c28aaSamw * The following is the uncompressed representation of the NetBIOS name 65da6c28aaSamw * "FRED ", which is the 4 ASCII characters, F, R, E, D, followed by 12 66da6c28aaSamw * space characters (0x20). This name has the SCOPE_ID: "NETBIOS.COM" 67da6c28aaSamw * 68da6c28aaSamw * EGFCEFEECACACACACACACACACACACACA.NETBIOS.COM 69da6c28aaSamw * 70da6c28aaSamw * This uncompressed representation of names is called "first-level 71da6c28aaSamw * encoding" in the section entitled "Representation of NetBIOS Names" 72da6c28aaSamw * in the Concepts and Methods document. 73da6c28aaSamw * 74da6c28aaSamw * The following is a pictographic representation of the compressed 75da6c28aaSamw * representation of the previous uncompressed Domain Name 76da6c28aaSamw * representation. 77da6c28aaSamw * 78da6c28aaSamw * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 79da6c28aaSamw * 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 80da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 81da6c28aaSamw * | 0x20 | E (0x45) | G (0x47) | F (0x46) | 82da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 83da6c28aaSamw * | C (0x43) | E (0x45) | F (0x46) | E (0x45) | 84da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 85da6c28aaSamw * | E (0x45) | C (0x43) | A (0x41) | C (0x43) | 86da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 87da6c28aaSamw * | A (0x41) | C (0x43) | A (0x41) | C (0x43) | 88da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 89da6c28aaSamw * | A (0x41) | C (0x43) | A (0x41) | C (0x43) | 90da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 91da6c28aaSamw * | A (0x41) | C (0x43) | A (0x41) | C (0x43) | 92da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 93da6c28aaSamw * | A (0x41) | C (0x43) | A (0x41) | C (0x43) | 94da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 95da6c28aaSamw * | A (0x41) | C (0x43) | A (0x41) | C (0x43) | 96da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 97da6c28aaSamw * | A (0X41) | 0x07 | N (0x4E) | E (0x45) | 98da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 99da6c28aaSamw * | T (0x54) | B (0x42) | I (0x49) | O (0x4F) | 100da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 101da6c28aaSamw * | S (0x53) | 0x03 | C (0x43) | O (0x4F) | 102da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 103da6c28aaSamw * | M (0x4D) | 0x00 | 104da6c28aaSamw * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 105da6c28aaSamw * 106da6c28aaSamw * Each section of a domain name is called a label [7 (page 31)]. A 107da6c28aaSamw * label can be a maximum of 63 bytes. The first byte of a label in 108da6c28aaSamw * compressed representation is the number of bytes in the label. For 109da6c28aaSamw * the above example, the first 0x20 is the number of bytes in the 110da6c28aaSamw * left-most label, EGFCEFEECACACACACACACACACACACACA, of the domain 111da6c28aaSamw * name. The bytes following the label length count are the characters 112da6c28aaSamw * of the label. The following labels are in sequence after the first 113da6c28aaSamw * label, which is the encoded NetBIOS name, until a zero (0x00) length 114da6c28aaSamw * count. The zero length count represents the root label, which is 115da6c28aaSamw * always null. 116da6c28aaSamw * 117da6c28aaSamw * A label length count is actually a 6-bit field in the label length 118da6c28aaSamw * field. The most significant 2 bits of the field, bits 7 and 6, are 119da6c28aaSamw * flags allowing an escape from the above compressed representation. 120da6c28aaSamw * If bits 7 and 6 are both set (11), the following 14 bits are an 121da6c28aaSamw * offset pointer into the full message to the actual label string from 122da6c28aaSamw * another domain name that belongs in this name. This label pointer 123da6c28aaSamw * allows for a further compression of a domain name in a packet. 124da6c28aaSamw * 125da6c28aaSamw * NetBIOS implementations can only use label string pointers in Name 126da6c28aaSamw * Service packets. They cannot be used in Session or Datagram Service 127da6c28aaSamw * packets. 128da6c28aaSamw * 129da6c28aaSamw * The other two possible values for bits 7 and 6 (01 and 10) of a label 130da6c28aaSamw * length field are reserved for future use by RFC 883[2 (page 32)]. 131da6c28aaSamw * 132da6c28aaSamw * Note that the first octet of a compressed name must contain one of 133da6c28aaSamw * the following bit patterns. (An "x" indicates a bit whose value may 134da6c28aaSamw * be either 0 or 1.): 135da6c28aaSamw * 136da6c28aaSamw * 00100000 - Netbios name, length must be 32 (decimal) 137da6c28aaSamw * 11xxxxxx - Label string pointer 138da6c28aaSamw * 10xxxxxx - Reserved 139da6c28aaSamw * 01xxxxxx - Reserved 140da6c28aaSamw */ 141da6c28aaSamw 142da6c28aaSamw /* 143da6c28aaSamw * netbios_first_level_name_encode 144da6c28aaSamw * 145da6c28aaSamw * Put test description here. 146da6c28aaSamw * 147da6c28aaSamw * Inputs: 148da6c28aaSamw * char * in -> Name to encode 149da6c28aaSamw * char * out -> Buffer to encode into. 150da6c28aaSamw * int length -> # of bytes to encode. 151da6c28aaSamw * 152da6c28aaSamw * Returns: 153da6c28aaSamw * Nothing 154da6c28aaSamw */ 155da6c28aaSamw int 156da6c28aaSamw netbios_first_level_name_encode(unsigned char *name, unsigned char *scope, 157da6c28aaSamw unsigned char *out, int max_out) 158da6c28aaSamw { 159da6c28aaSamw unsigned char ch, len; 160da6c28aaSamw unsigned char *in; 161da6c28aaSamw unsigned char *lp; 162da6c28aaSamw unsigned char *op = out; 163da6c28aaSamw 164da6c28aaSamw if (max_out < 0x21) 165da6c28aaSamw return (-1); 166da6c28aaSamw 167da6c28aaSamw in = name; 168da6c28aaSamw *op++ = 0x20; 169da6c28aaSamw for (len = 0; len < NETBIOS_NAME_SZ; len++) { 170da6c28aaSamw ch = *in++; 171da6c28aaSamw *op++ = 'A' + ((ch >> 4) & 0xF); 172da6c28aaSamw *op++ = 'A' + ((ch) & 0xF); 173da6c28aaSamw } 174da6c28aaSamw 175da6c28aaSamw max_out -= 0x21; 176da6c28aaSamw 177da6c28aaSamw in = scope; 178da6c28aaSamw len = 0; 179da6c28aaSamw lp = op++; 180da6c28aaSamw while (((ch = *in++) != 0) && (max_out-- > 1)) { 181da6c28aaSamw if (ch == 0) { 182da6c28aaSamw if ((*lp = len) != 0) 183da6c28aaSamw *op++ = 0; 184da6c28aaSamw break; 185da6c28aaSamw } 186da6c28aaSamw if (ch == '.') { 187da6c28aaSamw *lp = len; 188da6c28aaSamw lp = op++; 189da6c28aaSamw len = 0; 190da6c28aaSamw } else { 191da6c28aaSamw *op++ = ch; 192da6c28aaSamw len++; 193da6c28aaSamw } 194da6c28aaSamw } 195da6c28aaSamw *lp = len; 196da6c28aaSamw if (len != 0) 197da6c28aaSamw *op = 0; 198da6c28aaSamw 199da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 200da6c28aaSamw return (op - out); 201da6c28aaSamw } 202da6c28aaSamw 203da6c28aaSamw /* 204da6c28aaSamw * smb_first_level_name_decode 205da6c28aaSamw * 206da6c28aaSamw * The null terminated string "in" is the name to decode. The output 207da6c28aaSamw * is placed in the name_entry structure "name". 208da6c28aaSamw * 209da6c28aaSamw * The scope field is a series of length designated labels as described 210da6c28aaSamw * in the "Domain name representation and compression" section of RFC883. 211da6c28aaSamw * The two high order two bits of the length field must be zero, the 212da6c28aaSamw * remaining six bits contain the field length. The total length of the 213da6c28aaSamw * domain name is restricted to 255 octets but note that the trailing 214da6c28aaSamw * root label and its dot are not printed. When converting the labels, 215da6c28aaSamw * the length fields are replaced by dots. 216da6c28aaSamw * 217da6c28aaSamw * Returns the number of bytes scanned or -1 to indicate an error. 218da6c28aaSamw */ 219da6c28aaSamw int 220da6c28aaSamw netbios_first_level_name_decode(char *in, char *name, char *scope) 221da6c28aaSamw { 222*b3988cf6SGordon Ross unsigned int length; 223da6c28aaSamw char c1, c2; 224da6c28aaSamw char *cp; 225da6c28aaSamw char *out; 226da6c28aaSamw 227da6c28aaSamw cp = in; 228da6c28aaSamw 229da6c28aaSamw if ((length = *cp++) != 0x20) { 230da6c28aaSamw return (-1); 231da6c28aaSamw } 232da6c28aaSamw 233da6c28aaSamw out = name; 234da6c28aaSamw while (length > 0) { 235da6c28aaSamw c1 = *cp++; 236da6c28aaSamw c2 = *cp++; 237da6c28aaSamw 238da6c28aaSamw if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') { 239da6c28aaSamw c1 -= 'A'; 240da6c28aaSamw c2 -= 'A'; 241da6c28aaSamw *out++ = (c1 << 4) | (c2); 242da6c28aaSamw } else { 243da6c28aaSamw return (-1); /* conversion error */ 244da6c28aaSamw } 245da6c28aaSamw length -= 2; 246da6c28aaSamw } 247da6c28aaSamw 248da6c28aaSamw /* 249*b3988cf6SGordon Ross * Don't bother decoding the scope. Not supported. 250da6c28aaSamw */ 251*b3988cf6SGordon Ross if ((length = *cp++) != 0) 252da6c28aaSamw return (-1); 253*b3988cf6SGordon Ross scope[0] = '\0'; 254da6c28aaSamw 255da6c28aaSamw /*LINTED E_PTRDIFF_OVERFLOW*/ 256da6c28aaSamw return (cp - in); 257da6c28aaSamw } 258da6c28aaSamw 259da6c28aaSamw /* 260da6c28aaSamw * smb_netbios_name_isvalid 261da6c28aaSamw * 262da6c28aaSamw * This function is provided to be used by session service 263da6c28aaSamw * which runs in kernel in order to hide name_entry definition. 264da6c28aaSamw * 265da6c28aaSamw * It returns the decoded name in the provided buffer as 'out' 266da6c28aaSamw * if it's not null. 267da6c28aaSamw * 268da6c28aaSamw * Returns 0 if decode fails, 1 if it succeeds. 269da6c28aaSamw */ 270da6c28aaSamw int 271da6c28aaSamw netbios_name_isvalid(char *in, char *out) 272da6c28aaSamw { 273da6c28aaSamw char name[NETBIOS_NAME_SZ]; 274da6c28aaSamw char scope[NETBIOS_DOMAIN_NAME_MAX]; 275da6c28aaSamw 276da6c28aaSamw if (netbios_first_level_name_decode(in, name, scope) < 0) 277da6c28aaSamw return (0); 278da6c28aaSamw 279da6c28aaSamw if (out) 280da6c28aaSamw (void) strlcpy(out, name, NETBIOS_NAME_SZ); 281da6c28aaSamw 282da6c28aaSamw return (1); 283da6c28aaSamw } 284