Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : NBT netbios routines and daemon - version 2
4 : Copyright (C) Andrew Tridgell 1994-1998
5 : Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6 : Copyright (C) Jeremy Allison 1994-2003
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 3 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, see <http://www.gnu.org/licenses/>.
20 :
21 : This file contains all the code to process NetBIOS requests coming
22 : in on port 137. It does not deal with the code needed to service
23 : WINS server requests, but only broadcast and unicast requests.
24 :
25 : */
26 :
27 : #include "includes.h"
28 : #include "nmbd/nmbd.h"
29 :
30 : /****************************************************************************
31 : Send a name release response.
32 : **************************************************************************/
33 :
34 0 : static void send_name_release_response(int rcode, struct packet_struct *p)
35 : {
36 0 : struct nmb_packet *nmb = &p->packet.nmb;
37 : char rdata[6];
38 :
39 0 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
40 :
41 0 : reply_netbios_packet(p, /* Packet to reply to. */
42 : rcode, /* Result code. */
43 : NMB_REL, /* nmbd type code. */
44 : NMB_NAME_RELEASE_OPCODE, /* opcode. */
45 : 0, /* ttl. */
46 : rdata, /* data to send. */
47 : 6); /* data length. */
48 0 : }
49 :
50 : /****************************************************************************
51 : Process a name release packet on a broadcast subnet.
52 : Ignore it if it's not one of our names.
53 : ****************************************************************************/
54 :
55 10 : void process_name_release_request(struct subnet_record *subrec,
56 : struct packet_struct *p)
57 : {
58 10 : struct nmb_packet *nmb = &p->packet.nmb;
59 : struct in_addr owner_ip;
60 10 : struct nmb_name *question = &nmb->question.question_name;
61 : unstring qname;
62 10 : bool bcast = nmb->header.nm_flags.bcast;
63 10 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
64 10 : bool group = (nb_flags & NB_GROUP) ? True : False;
65 : struct name_record *namerec;
66 10 : int rcode = 0;
67 :
68 10 : putip((char *)&owner_ip,&nmb->additional->rdata[2]);
69 :
70 10 : if(!bcast) {
71 : /* We should only get broadcast name release packets here.
72 : Anyone trying to release unicast should be going to a WINS
73 : server. If the code gets here, then either we are not a wins
74 : server and they sent it anyway, or we are a WINS server and
75 : the request was malformed. Either way, log an error here.
76 : and send an error reply back.
77 : */
78 0 : DEBUG(0,("process_name_release_request: unicast name release request \
79 : received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
80 : nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
81 :
82 0 : send_name_release_response(FMT_ERR, p);
83 10 : return;
84 : }
85 :
86 10 : DEBUG(3,("process_name_release_request: Name release on name %s, \
87 : subnet %s from owner IP %s\n",
88 : nmb_namestr(&nmb->question.question_name),
89 : subrec->subnet_name, inet_ntoa(owner_ip)));
90 :
91 : /* If someone is releasing a broadcast group name, just ignore it. */
92 10 : if( group && !ismyip_v4(owner_ip) )
93 5 : return;
94 :
95 : /*
96 : * Code to work around a bug in FTP OnNet software NBT implementation.
97 : * They do a broadcast name release for WORKGROUP<0> and WORKGROUP<1e>
98 : * names and *don't set the group bit* !!!!!
99 : */
100 :
101 5 : pull_ascii_nstring(qname, sizeof(qname), question->name);
102 5 : if( !group && !ismyip_v4(owner_ip) && strequal(qname, lp_workgroup()) &&
103 4 : ((question->name_type == 0x0) || (question->name_type == 0x1e))) {
104 0 : DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
105 : group release name %s from IP %s on subnet %s with no group bit set.\n",
106 : nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
107 0 : return;
108 : }
109 :
110 5 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
111 :
112 : /* We only care about someone trying to release one of our names. */
113 5 : if( namerec && ( (namerec->data.source == SELF_NAME)
114 0 : || (namerec->data.source == PERMANENT_NAME) ) ) {
115 0 : rcode = ACT_ERR;
116 0 : DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
117 : on subnet %s being rejected as it is one of our names.\n",
118 : nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
119 : }
120 :
121 5 : if(rcode == 0)
122 5 : return;
123 :
124 : /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
125 0 : send_name_release_response(rcode, p);
126 : }
127 :
128 : /****************************************************************************
129 : Send a name registration response.
130 : **************************************************************************/
131 :
132 12 : static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
133 : {
134 12 : struct nmb_packet *nmb = &p->packet.nmb;
135 : char rdata[6];
136 :
137 12 : memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
138 :
139 12 : reply_netbios_packet(p, /* Packet to reply to. */
140 : rcode, /* Result code. */
141 : NMB_REG, /* nmbd type code. */
142 : NMB_NAME_REG_OPCODE, /* opcode. */
143 : ttl, /* ttl. */
144 : rdata, /* data to send. */
145 : 6); /* data length. */
146 12 : }
147 :
148 : /****************************************************************************
149 : Process a name refresh request on a broadcast subnet.
150 : **************************************************************************/
151 :
152 0 : void process_name_refresh_request(struct subnet_record *subrec,
153 : struct packet_struct *p)
154 : {
155 0 : struct nmb_packet *nmb = &p->packet.nmb;
156 0 : struct nmb_name *question = &nmb->question.question_name;
157 0 : bool bcast = nmb->header.nm_flags.bcast;
158 : struct in_addr from_ip;
159 :
160 0 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
161 :
162 0 : if(!bcast) {
163 : /* We should only get broadcast name refresh packets here.
164 : Anyone trying to refresh unicast should be going to a WINS
165 : server. If the code gets here, then either we are not a wins
166 : server and they sent it anyway, or we are a WINS server and
167 : the request was malformed. Either way, log an error here.
168 : and send an error reply back.
169 : */
170 0 : DEBUG(0,("process_name_refresh_request: unicast name registration request \
171 : received for name %s from IP %s on subnet %s.\n",
172 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
173 0 : DEBUG(0,("Error - should be sent to WINS server\n"));
174 :
175 0 : send_name_registration_response(FMT_ERR, 0, p);
176 0 : return;
177 : }
178 :
179 : /* Just log a message. We really don't care about broadcast name refreshes. */
180 :
181 0 : DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
182 : IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
183 : }
184 :
185 : /****************************************************************************
186 : Process a name registration request on a broadcast subnet.
187 : **************************************************************************/
188 :
189 3522 : void process_name_registration_request(struct subnet_record *subrec,
190 : struct packet_struct *p)
191 : {
192 3522 : struct nmb_packet *nmb = &p->packet.nmb;
193 3522 : struct nmb_name *question = &nmb->question.question_name;
194 3522 : bool bcast = nmb->header.nm_flags.bcast;
195 3522 : uint16_t nb_flags = get_nb_flags(nmb->additional->rdata);
196 3522 : bool group = (nb_flags & NB_GROUP) ? True : False;
197 3522 : struct name_record *namerec = NULL;
198 3522 : int ttl = nmb->additional->ttl;
199 : struct in_addr from_ip;
200 :
201 3522 : putip((char *)&from_ip,&nmb->additional->rdata[2]);
202 :
203 3522 : if(!bcast) {
204 : /* We should only get broadcast name registration packets here.
205 : Anyone trying to register unicast should be going to a WINS
206 : server. If the code gets here, then either we are not a wins
207 : server and they sent it anyway, or we are a WINS server and
208 : the request was malformed. Either way, log an error here.
209 : and send an error reply back.
210 : */
211 0 : DEBUG(0,("process_name_registration_request: unicast name registration request \
212 : received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
213 : nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
214 :
215 0 : send_name_registration_response(FMT_ERR, 0, p);
216 12 : return;
217 : }
218 :
219 3522 : DEBUG(3,("process_name_registration_request: Name registration for name %s \
220 : IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
221 :
222 : /* See if the name already exists. */
223 3522 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
224 :
225 : /*
226 : * If the name being registered exists and is a WINS_PROXY_NAME
227 : * then delete the WINS proxy name entry so we don't reply erroneously
228 : * later to queries.
229 : */
230 :
231 3522 : if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME)) {
232 0 : remove_name_from_namelist( subrec, namerec );
233 0 : namerec = NULL;
234 : }
235 :
236 3522 : if (!group) {
237 : /* Unique name. */
238 :
239 2154 : if( (namerec != NULL)
240 12 : && ( (namerec->data.source == SELF_NAME)
241 0 : || (namerec->data.source == PERMANENT_NAME)
242 0 : || NAME_GROUP(namerec) ) ) {
243 : /* No-one can register one of Samba's names, nor can they
244 : register a name that's a group name as a unique name */
245 :
246 12 : send_name_registration_response(ACT_ERR, 0, p);
247 12 : return;
248 2142 : } else if(namerec != NULL) {
249 : /* Update the namelist record with the new information. */
250 0 : namerec->data.ip[0] = from_ip;
251 0 : update_name_ttl(namerec, ttl);
252 :
253 0 : DEBUG(3,("process_name_registration_request: Updated name record %s \
254 : with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
255 0 : return;
256 : }
257 : } else {
258 : /* Group name. */
259 :
260 1368 : if( (namerec != NULL)
261 319 : && !NAME_GROUP(namerec)
262 0 : && ( (namerec->data.source == SELF_NAME)
263 0 : || (namerec->data.source == PERMANENT_NAME) ) ) {
264 : /* Disallow group names when we have a unique name. */
265 0 : send_name_registration_response(ACT_ERR, 0, p);
266 0 : return;
267 : }
268 : }
269 : }
270 :
271 : /****************************************************************************
272 : This is used to sort names for a name status into a sensible order.
273 : We put our own names first, then in alphabetical order.
274 : **************************************************************************/
275 :
276 5530 : static int status_compare(char *n1,char *n2)
277 : {
278 : unstring name1, name2;
279 : int l1,l2,l3;
280 :
281 5530 : memset(name1, '\0', sizeof(name1));
282 5530 : memset(name2, '\0', sizeof(name2));
283 5530 : pull_ascii_nstring(name1, sizeof(name1), n1);
284 5530 : pull_ascii_nstring(name2, sizeof(name2), n2);
285 5530 : n1 = name1;
286 5530 : n2 = name2;
287 :
288 : /* It's a bit tricky because the names are space padded */
289 66116 : for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++)
290 : ;
291 62187 : for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++)
292 : ;
293 5530 : l3 = strlen(lp_netbios_name());
294 :
295 5530 : if ((l1==l3) && strncmp(n1,lp_netbios_name(),l3) == 0 &&
296 846 : (l2!=l3 || strncmp(n2,lp_netbios_name(),l3) != 0))
297 974 : return -1;
298 :
299 4556 : if ((l2==l3) && strncmp(n2,lp_netbios_name(),l3) == 0 &&
300 810 : (l1!=l3 || strncmp(n1,lp_netbios_name(),l3) != 0))
301 509 : return 1;
302 :
303 4047 : return memcmp(n1,n2,sizeof(name1));
304 : }
305 :
306 : /****************************************************************************
307 : Process a node status query
308 : ****************************************************************************/
309 :
310 52 : void process_node_status_request(struct subnet_record *subrec, struct packet_struct *p)
311 : {
312 52 : struct nmb_packet *nmb = &p->packet.nmb;
313 : unstring qname;
314 52 : int ques_type = nmb->question.question_name.name_type;
315 : char rdata[MAX_DGRAM_SIZE];
316 : char *countptr, *buf, *bufend, *buf0;
317 : int names_added,i;
318 52 : struct name_record *namerec = NULL;
319 :
320 52 : pull_ascii_nstring(qname, sizeof(qname), nmb->question.question_name.name);
321 :
322 52 : DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
323 : subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
324 :
325 52 : if(find_name_on_subnet(subrec, &nmb->question.question_name, FIND_SELF_NAME) == 0) {
326 0 : DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
327 : subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
328 : inet_ntoa(p->ip), subrec->subnet_name));
329 :
330 0 : return;
331 : }
332 :
333 : /* this is not an exact calculation. the 46 is for the stats buffer
334 : and the 60 is to leave room for the header etc */
335 52 : bufend = &rdata[MAX_DGRAM_SIZE-1] - (18 + 46 + 60);
336 52 : countptr = buf = rdata;
337 52 : buf += 1;
338 52 : buf0 = buf;
339 :
340 52 : names_added = 0;
341 :
342 52 : namerec = subrec->namelist;
343 :
344 655 : while (PTR_DIFF(bufend, buf) > 0) {
345 655 : if( (namerec->data.source == SELF_NAME) || (namerec->data.source == PERMANENT_NAME) ) {
346 655 : int name_type = namerec->name.name_type;
347 : unstring name;
348 :
349 655 : pull_ascii_nstring(name, sizeof(name), namerec->name.name);
350 655 : if (!strupper_m(name)) {
351 0 : DEBUG(2,("strupper_m %s failed\n", name));
352 0 : return;
353 : }
354 655 : if (!strequal(name,"*") &&
355 551 : !strequal(name,"__SAMBA__") &&
356 233 : (name_type < 0x1b || name_type >= 0x20 ||
357 122 : ques_type < 0x1b || ques_type >= 0x20 ||
358 61 : strequal(qname, name))) {
359 : /* Start with the name. */
360 : size_t len;
361 447 : push_ascii_nstring(buf, name);
362 447 : len = strlen(buf);
363 447 : memset(buf + len, ' ', MAX_NETBIOSNAME_LEN - len - 1);
364 447 : buf[MAX_NETBIOSNAME_LEN - 1] = '\0';
365 :
366 : /* Put the name type and netbios flags in the buffer. */
367 :
368 447 : buf[15] = name_type;
369 447 : set_nb_flags( &buf[16],namerec->data.nb_flags );
370 447 : buf[16] |= NB_ACTIVE; /* all our names are active */
371 :
372 447 : names_added++;
373 : }
374 : }
375 :
376 : /* Remove duplicate names. */
377 655 : if (names_added > 1) {
378 : /* TODO: should use a real type and
379 : TYPESAFE_QSORT() */
380 603 : qsort( buf0, names_added, 18, QSORT_CAST status_compare );
381 : }
382 :
383 3975 : for( i=1; i < names_added ; i++ ) {
384 3320 : if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
385 0 : names_added--;
386 0 : if (names_added == i)
387 0 : break;
388 0 : memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
389 0 : i--;
390 : }
391 : }
392 :
393 655 : buf = buf0 + 18*names_added;
394 :
395 655 : namerec = namerec->next;
396 :
397 655 : if (!namerec) {
398 : /* End of the subnet specific name list. Now
399 : add the names on the unicast subnet . */
400 52 : struct subnet_record *uni_subrec = unicast_subnet;
401 :
402 52 : if (uni_subrec != subrec) {
403 0 : subrec = uni_subrec;
404 0 : namerec = subrec->namelist;
405 : }
406 : }
407 655 : if (!namerec)
408 52 : break;
409 :
410 : }
411 :
412 52 : SCVAL(countptr,0,names_added);
413 :
414 : /* We don't send any stats as they could be used to attack
415 : the protocol. */
416 52 : memset(buf,'\0',46);
417 :
418 52 : buf += 46;
419 :
420 : /* Send a NODE STATUS RESPONSE */
421 52 : reply_netbios_packet(p, /* Packet to reply to. */
422 : 0, /* Result code. */
423 : NMB_STATUS, /* nmbd type code. */
424 : NMB_NAME_QUERY_OPCODE, /* opcode. */
425 : 0, /* ttl. */
426 : rdata, /* data to send. */
427 52 : PTR_DIFF(buf,rdata)); /* data length. */
428 : }
429 :
430 :
431 : /***************************************************************************
432 : Process a name query.
433 :
434 : For broadcast name queries:
435 :
436 : - Only reply if the query is for one of YOUR names.
437 : - NEVER send a negative response to a broadcast query.
438 :
439 : ****************************************************************************/
440 :
441 4396 : void process_name_query_request(struct subnet_record *subrec, struct packet_struct *p)
442 : {
443 4396 : struct nmb_packet *nmb = &p->packet.nmb;
444 4396 : struct nmb_name *question = &nmb->question.question_name;
445 4396 : int name_type = question->name_type;
446 4396 : bool bcast = nmb->header.nm_flags.bcast;
447 4396 : int ttl=0;
448 4396 : int rcode = 0;
449 4396 : char *prdata = NULL;
450 : char rdata[6];
451 4396 : bool success = False;
452 4396 : struct name_record *namerec = NULL;
453 4396 : int reply_data_len = 0;
454 : int i;
455 :
456 4396 : DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
457 : inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
458 :
459 : /* Look up the name in the cache - if the request is a broadcast request that
460 : came from a subnet we don't know about then search all the broadcast subnets
461 : for a match (as we don't know what interface the request came in on). */
462 :
463 4396 : if(subrec == remote_broadcast_subnet)
464 0 : namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
465 : else
466 4396 : namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
467 :
468 : /* Check if it is a name that expired */
469 4396 : if (namerec &&
470 827 : ((namerec->data.death_time != PERMANENT_TTL) &&
471 0 : (namerec->data.death_time < p->timestamp))) {
472 0 : DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
473 0 : namerec = NULL;
474 : }
475 :
476 4396 : if (namerec) {
477 : /*
478 : * Always respond to unicast queries.
479 : * Don't respond to broadcast queries unless the query is for
480 : * a name we own, a Primary Domain Controller name, or a WINS_PROXY
481 : * name with type 0 or 0x20. WINS_PROXY names are only ever added
482 : * into the namelist if we were configured as a WINS proxy.
483 : */
484 :
485 827 : if (!bcast ||
486 612 : (bcast && ((name_type == 0x1b) ||
487 612 : (namerec->data.source == SELF_NAME) ||
488 129 : (namerec->data.source == PERMANENT_NAME) ||
489 0 : ((namerec->data.source == WINS_PROXY_NAME) &&
490 0 : ((name_type == 0) || (name_type == 0x20)))))) {
491 : /* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
492 : or it's a Domain Master type. */
493 :
494 : /*
495 : * If this is a WINS_PROXY_NAME, then check that none of the IP
496 : * addresses we are returning is on the same broadcast subnet
497 : * as the requesting packet. If it is then don't reply as the
498 : * actual machine will be replying also and we don't want two
499 : * replies to a broadcast query.
500 : */
501 :
502 827 : if (namerec->data.source == WINS_PROXY_NAME) {
503 0 : for( i = 0; i < namerec->data.num_ips; i++) {
504 0 : if (same_net_v4(namerec->data.ip[i], subrec->myip, subrec->mask_ip)) {
505 0 : DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requester. Not replying.\n",
506 : nmb_namestr(&namerec->name), subrec->subnet_name ));
507 3569 : return;
508 : }
509 : }
510 : }
511 :
512 827 : ttl = (namerec->data.death_time != PERMANENT_TTL) ?
513 827 : namerec->data.death_time - p->timestamp : lp_max_ttl();
514 :
515 : /* Copy all known ip addresses into the return data. */
516 : /* Optimise for the common case of one IP address so
517 : we don't need a malloc. */
518 :
519 827 : if (namerec->data.num_ips == 1) {
520 827 : prdata = rdata;
521 : } else {
522 0 : if ((prdata = (char *)SMB_MALLOC( namerec->data.num_ips * 6 )) == NULL) {
523 0 : DEBUG(0,("process_name_query_request: malloc fail !\n"));
524 0 : return;
525 : }
526 : }
527 :
528 1654 : for (i = 0; i < namerec->data.num_ips; i++) {
529 827 : set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
530 827 : putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
531 : }
532 :
533 827 : sort_query_replies(prdata, i, p->ip);
534 :
535 827 : reply_data_len = namerec->data.num_ips * 6;
536 827 : success = True;
537 : }
538 : }
539 :
540 : /*
541 : * If a machine is broadcasting a name lookup request and we have lp_wins_proxy()
542 : * set we should initiate a WINS query here. On success we add the resolved name
543 : * into our namelist with a type of WINS_PROXY_NAME and then reply to the query.
544 : */
545 :
546 4396 : if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
547 0 : bcast && (subrec != remote_broadcast_subnet)) {
548 0 : make_wins_proxy_name_query_request( subrec, p, question );
549 0 : return;
550 : }
551 :
552 4396 : if (!success && bcast) {
553 3569 : if(prdata != rdata)
554 3569 : SAFE_FREE(prdata);
555 3569 : return; /* Never reply with a negative response to broadcasts. */
556 : }
557 :
558 : /*
559 : * Final check. From observation, if a unicast packet is sent
560 : * to a non-WINS server with the recursion desired bit set
561 : * then never send a negative response.
562 : */
563 :
564 827 : if(!success && !bcast && nmb->header.nm_flags.recursion_desired) {
565 0 : if(prdata != rdata)
566 0 : SAFE_FREE(prdata);
567 0 : return;
568 : }
569 :
570 827 : if (success) {
571 827 : rcode = 0;
572 827 : DEBUG(3,("OK\n"));
573 : } else {
574 0 : rcode = NAM_ERR;
575 0 : DEBUG(3,("UNKNOWN\n"));
576 : }
577 :
578 : /* See rfc1002.txt 4.2.13. */
579 :
580 827 : reply_netbios_packet(p, /* Packet to reply to. */
581 : rcode, /* Result code. */
582 : NMB_QUERY, /* nmbd type code. */
583 : NMB_NAME_QUERY_OPCODE, /* opcode. */
584 : ttl, /* ttl. */
585 : prdata, /* data to send. */
586 : reply_data_len); /* data length. */
587 :
588 827 : if(prdata != rdata)
589 0 : SAFE_FREE(prdata);
590 : }
|