1 #include "includes.h"
2 #include "../librpc/ndr/libndr.h"
3 #include "ndr_dns_utils.h"
4 
5 
6 /**
7   push a dns/nbt string list to the wire
8 */
ndr_push_dns_string_list(struct ndr_push * ndr,struct ndr_token_list * string_list,int ndr_flags,const char * s,bool is_nbt)9 enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
10 					   struct ndr_token_list *string_list,
11 					   int ndr_flags,
12 					   const char *s,
13 					   bool is_nbt)
14 {
15 	const char *start = s;
16 	bool use_compression;
17 	size_t max_length;
18 	if (is_nbt) {
19 		use_compression = true;
20 		/*
21 		 * Max length is longer in NBT/Wins, because Windows counts
22 		 * the semi-decompressed size of the netbios name (16 bytes)
23 		 * rather than the wire size of 32, which is what you'd expect
24 		 * if it followed RFC1002 (it uses the short form in
25 		 * [MS-WINSRA]). In other words the maximum size of the
26 		 * "scope" is 237, not 221.
27 		 *
28 		 * We make the size limit slightly larger than 255 + 16,
29 		 * because the 237 scope limit is already enforced in the
30 		 * winsserver code with a specific return value; bailing out
31 		 * here would muck with that.
32 		 */
33 		max_length = 274;
34 	} else {
35 		use_compression = !(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION);
36 		max_length = 255;
37 	}
38 
39 	if (!(ndr_flags & NDR_SCALARS)) {
40 		return NDR_ERR_SUCCESS;
41 	}
42 
43 	while (s && *s) {
44 		enum ndr_err_code ndr_err;
45 		char *compname;
46 		size_t complen;
47 		uint32_t offset;
48 
49 		if (use_compression) {
50 			/* see if we have pushed the remaining string already,
51 			 * if so we use a label pointer to this string
52 			 */
53 			ndr_err = ndr_token_retrieve_cmp_fn(string_list, s,
54 							    &offset,
55 							    (comparison_fn_t)strcmp,
56 							    false);
57 			if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
58 				uint8_t b[2];
59 
60 				if (offset > 0x3FFF) {
61 					return ndr_push_error(ndr, NDR_ERR_STRING,
62 							      "offset for dns string " \
63 							      "label pointer " \
64 							      "%u[%08X] > 0x00003FFF",
65 							      offset, offset);
66 				}
67 
68 				b[0] = 0xC0 | (offset>>8);
69 				b[1] = (offset & 0xFF);
70 
71 				return ndr_push_bytes(ndr, b, 2);
72 			}
73 		}
74 
75 		complen = strcspn(s, ".");
76 
77 		/* the length must fit into 6 bits (i.e. <= 63) */
78 		if (complen > 0x3F) {
79 			return ndr_push_error(ndr, NDR_ERR_STRING,
80 					      "component length %u[%08X] > " \
81 					      "0x0000003F",
82 					      (unsigned)complen,
83 					      (unsigned)complen);
84 		}
85 
86 		if (complen == 0 && s[complen] == '.') {
87 			return ndr_push_error(ndr, NDR_ERR_STRING,
88 					      "component length is 0 "
89 					      "(consecutive dots)");
90 		}
91 
92 		if (is_nbt && s[complen] == '.' && s[complen + 1] == '\0') {
93 			/* nbt names are sometimes usernames, and we need to
94 			 * keep a trailing dot to ensure it is byte-identical,
95 			 * (not just semantically identical given DNS
96 			 * semantics). */
97 			complen++;
98 		}
99 
100 		compname = talloc_asprintf(ndr, "%c%*.*s",
101 						(unsigned char)complen,
102 						(unsigned char)complen,
103 						(unsigned char)complen, s);
104 		NDR_ERR_HAVE_NO_MEMORY(compname);
105 
106 		/* remember the current component + the rest of the string
107 		 * so it can be reused later
108 		 */
109 		if (use_compression) {
110 			NDR_CHECK(ndr_token_store(ndr, string_list, s,
111 						  ndr->offset));
112 		}
113 
114 		/* push just this component into the blob */
115 		NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
116 					 complen+1));
117 		talloc_free(compname);
118 
119 		s += complen;
120 		if (*s == '.') {
121 			s++;
122 		}
123 		if (s - start > max_length) {
124 			return ndr_push_error(ndr, NDR_ERR_STRING,
125 					      "name > %zu character long",
126 					      max_length);
127 		}
128 	}
129 
130 	/* if we reach the end of the string and have pushed the last component
131 	 * without using a label pointer, we need to terminate the string
132 	 */
133 	return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
134 }
135