r5358: - added initial WINS server code. It passes most of the NBT-WINS test, but...
[kamenim/samba.git] / source4 / libcli / nbt / nbtname.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    manipulate nbt name structures
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 /*
24   see rfc1002 for the detailed format of compressed names
25 */
26
27 #include "includes.h"
28 #include "system/iconv.h"
29 #include "librpc/gen_ndr/ndr_nbt.h"
30
31 /* don't allow an unlimited number of name components */
32 #define MAX_COMPONENTS 10
33
34 /*
35   pull one component of a compressed name
36 */
37 static NTSTATUS ndr_pull_component(struct ndr_pull *ndr, uint8_t **component,
38                                    uint32_t *offset, uint32_t *max_offset)
39 {
40         uint8_t len;
41         uint_t loops = 0;
42         while (loops < 5) {
43                 if (*offset >= ndr->data_size) {
44                         return NT_STATUS_BAD_NETWORK_NAME;
45                 }
46                 len = ndr->data[*offset];
47                 if (len == 0) {
48                         *offset += 1;
49                         *max_offset = MAX(*max_offset, *offset);
50                         *component = NULL;
51                         return NT_STATUS_OK;
52                 }
53                 if ((len & 0xC0) == 0xC0) {
54                         /* its a label pointer */
55                         if (1 + *offset >= ndr->data_size) {
56                                 return NT_STATUS_BAD_NETWORK_NAME;
57                         }
58                         *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset];
59                         *max_offset = MAX(*max_offset, *offset + 1);
60                         loops++;
61                         continue;
62                 }
63                 if ((len & 0xC0) != 0) {
64                         /* its a reserved length field */
65                         return NT_STATUS_BAD_NETWORK_NAME;
66                 }
67                 if (*offset + len + 2 > ndr->data_size) {
68                         return NT_STATUS_BAD_NETWORK_NAME;
69                 }
70                 *component = (uint8_t*)talloc_strndup(ndr, &ndr->data[1 + *offset], len);
71                 NT_STATUS_HAVE_NO_MEMORY(*component);
72                 *offset += len + 1;
73                 *max_offset = MAX(*max_offset, *offset);
74                 return NT_STATUS_OK;
75         }
76
77         /* too many pointers */
78         return NT_STATUS_BAD_NETWORK_NAME;
79 }
80
81 /*
82   decompress a 'compressed' name component
83  */
84 static NTSTATUS decompress_name(char *name, enum nbt_name_type *type)
85 {
86         int i;
87         for (i=0;name[2*i];i++) {
88                 uint8_t c1 = name[2*i];
89                 uint8_t c2 = name[1+(2*i)];
90                 if (c1 < 'A' || c1 > 'P' ||
91                     c2 < 'A' || c2 > 'P') {
92                         return NT_STATUS_BAD_NETWORK_NAME;
93                 }
94                 name[i] = ((c1-'A')<<4) | (c2-'A');                 
95         }
96         name[i] = 0;
97         if (i == 16) {
98                 *type = (enum nbt_name_type)(name[15]);
99                 name[15] = 0;
100                 i--;
101         } else {
102                 *type = NBT_NAME_CLIENT;
103         }
104
105         /* trim trailing spaces */
106         for (;i>0 && name[i-1]==' ';i--) {
107                 name[i-1] = 0;
108         }
109         
110         return NT_STATUS_OK;
111 }
112
113
114 /*
115   compress a name component
116  */
117 static uint8_t *compress_name(TALLOC_CTX *mem_ctx, 
118                               const uint8_t *name, enum nbt_name_type type)
119 {
120         uint8_t *cname;
121         int i;
122         uint8_t pad_char;
123
124         if (strlen(name) > 15) {
125                 return NULL;
126         }
127
128         cname = talloc_array(mem_ctx, uint8_t, 33);
129         if (cname == NULL) return NULL;
130
131         for (i=0;name[i];i++) {
132                 cname[2*i]   = 'A' + (name[i]>>4);
133                 cname[1+2*i] = 'A' + (name[i]&0xF);
134         }
135         if (name[0] == '*') {
136                 pad_char = 0;
137         } else {
138                 pad_char = ' ';
139         }
140         for (;i<15;i++) {
141                 cname[2*i]   = 'A' + (pad_char>>4);
142                 cname[1+2*i] = 'A' + (pad_char&0xF);
143         }
144
145         pad_char = type;
146         cname[2*i]   = 'A' + (pad_char>>4);
147         cname[1+2*i] = 'A' + (pad_char&0xF);
148
149         cname[32] = 0;
150         return cname;
151 }
152
153 /*
154   pull a nbt name from the wire
155 */
156 NTSTATUS ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r)
157 {
158         NTSTATUS status;
159         uint_t num_components;
160         uint32_t offset = ndr->offset;
161         uint32_t max_offset = offset;
162         uint8_t *components[MAX_COMPONENTS];
163         int i;
164         uint8_t *scope;
165
166         if (!(ndr_flags & NDR_SCALARS)) {
167                 return NT_STATUS_OK;
168         }
169
170         /* break up name into a list of components */
171         for (num_components=0;num_components<MAX_COMPONENTS;num_components++) {
172                 status = ndr_pull_component(ndr, &components[num_components], 
173                                             &offset, &max_offset);
174                 NT_STATUS_NOT_OK_RETURN(status);
175                 if (components[num_components] == NULL) break;
176         }
177         if (num_components == MAX_COMPONENTS ||
178             num_components == 0) {
179                 return NT_STATUS_BAD_NETWORK_NAME;
180         }
181
182         ndr->offset = max_offset;
183
184         /* the first component is limited to 16 bytes in the DOS charset,
185            which is 32 in the 'compressed' form */
186         if (strlen(components[0]) > 32) {
187                 return NT_STATUS_BAD_NETWORK_NAME;
188         }
189
190         /* decompress the first component */
191         status = decompress_name(components[0], &r->type);
192         NT_STATUS_NOT_OK_RETURN(status);
193
194         r->name = components[0];
195
196         /* combine the remaining components into the scope */
197         scope = components[1];
198         for (i=2;i<num_components;i++) {
199                 scope = talloc_asprintf_append(scope, ".%s", components[i]);
200                 NT_STATUS_HAVE_NO_MEMORY(scope);
201         }
202
203         r->scope = scope;
204
205         return NT_STATUS_OK;
206 }
207
208 /*
209   push a nbt name to the wire
210 */
211 NTSTATUS ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, struct nbt_name *r)
212 {
213         uint_t num_components;
214         uint8_t *components[MAX_COMPONENTS];
215         char *dscope=NULL, *p;
216         uint8_t *cname;
217         int i;
218
219         if (!(ndr_flags & NDR_SCALARS)) {
220                 return NT_STATUS_OK;
221         }
222
223         if (r->scope) {
224                 dscope = talloc_strdup(ndr, r->scope);
225                 NT_STATUS_HAVE_NO_MEMORY(dscope);
226         }
227
228         cname = compress_name(ndr, r->name, r->type);
229         NT_STATUS_HAVE_NO_MEMORY(cname);
230
231         /* form the base components */
232         components[0] = cname;
233         num_components = 1;
234
235         while (dscope && (p=strchr(dscope, '.')) && 
236                num_components < MAX_COMPONENTS) {
237                 *p = 0;
238                 components[num_components] = dscope;
239                 dscope = p+1;
240                 num_components++;
241         }
242         if (dscope && num_components < MAX_COMPONENTS) {
243                 components[num_components++] = dscope;
244         }
245         if (num_components == MAX_COMPONENTS) {
246                 return NT_STATUS_BAD_NETWORK_NAME;
247         }
248                 
249         /* push the components */
250         for (i=0;i<num_components;i++) {
251                 uint8_t len = strlen(components[i]);
252                 NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, len));
253                 NDR_CHECK(ndr_push_bytes(ndr, components[i], len));
254         }
255         NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 0));
256
257         return NT_STATUS_OK;
258 }
259
260
261 /*
262   copy a nbt name structure
263 */
264 NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname)
265 {
266         *newname = *name;
267         newname->name = talloc_strdup(mem_ctx, newname->name);
268         NT_STATUS_HAVE_NO_MEMORY(newname->name);
269         newname->scope = talloc_strdup(mem_ctx, newname->scope);
270         if (name->scope) {
271                 NT_STATUS_HAVE_NO_MEMORY(newname->scope);
272         }
273         return NT_STATUS_OK;
274 }
275
276 /*
277   push a nbt name into a blob
278 */
279 NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name)
280 {
281         return ndr_push_struct_blob(blob, mem_ctx, name, 
282                                     (ndr_push_flags_fn_t)ndr_push_nbt_name);
283 }
284
285
286 /*
287   pull a nbt name from a blob
288 */
289 NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name)
290 {
291         return ndr_pull_struct_blob(blob, mem_ctx, name, 
292                                     (ndr_pull_flags_fn_t)ndr_pull_nbt_name);
293 }
294
295
296 /*
297   choose a name to use when calling a server in a NBT session request.
298   we use heuristics to see if the name we have been given is a IP
299   address, or a too-long name. If it is then use *SMBSERVER, or a
300   truncated name
301 */
302 void nbt_choose_called_name(TALLOC_CTX *mem_ctx,
303                             struct nbt_name *n, const char *name, int type)
304 {
305         n->scope = NULL;
306         n->type = type;
307
308         if (is_ipaddress(name)) {
309                 n->name = "*SMBSERVER";
310                 return;
311         }
312         if (strlen(name) > 15) {
313                 const char *p = strchr(name, '.');
314                 if (p - name > 15) {
315                         n->name = "*SMBSERVER";
316                         return;
317                 }
318                 n->name = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name));
319                 return;
320         }
321
322         n->name = talloc_strdup(mem_ctx, name);
323 }
324
325
326 /*
327   escape a string into a form containing only a small set of characters,
328   the rest is hex encoded. This is similar to URL encoding
329 */
330 static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s)
331 {
332         int i, len;
333         char *ret;
334         const char *valid_chars = "_-.$@";
335
336         for (len=i=0;s[i];i++,len++) {
337                 if (!isalnum(s[i]) && !strchr(valid_chars, s[i])) {
338                         len += 2;
339                 }
340         }
341
342         ret = talloc_array(mem_ctx, char, len+1);
343         if (ret == NULL) return NULL;
344
345         for (len=i=0;s[i];i++) {
346                 if (isalnum(s[i]) || strchr(valid_chars, s[i])) {
347                         ret[len++] = s[i];
348                 } else {
349                         snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]);
350                         len += 3;
351                 }
352         }
353         ret[len] = 0;
354
355         return ret;
356 }
357
358
359 /*
360   form a string for a NBT name
361 */
362 char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name)
363 {
364         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
365         char *ret;
366         if (name->scope) {              
367                 ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s",
368                                       nbt_hex_encode(tmp_ctx, name->name),
369                                       name->type, 
370                                       nbt_hex_encode(tmp_ctx, name->scope));
371         } else {
372                 ret = talloc_asprintf(mem_ctx, "%s<%02x>", 
373                                       nbt_hex_encode(tmp_ctx, name->name), 
374                                       name->type);
375         }
376         talloc_free(tmp_ctx);
377         return ret;
378 }
379