patch to fix NetServerEnum with multiple workgroup lists kindly supplied.
[Samba.git] / source / libsmb / namequery.c
blobd1b1ae7d3e5c976b7af299d22011d7c46789f8bf
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 name query routines
5 Copyright (C) Andrew Tridgell 1994-1995
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 extern pstring scope;
26 extern int DEBUGLEVEL;
29 /****************************************************************************
30 interpret a node status response
31 ****************************************************************************/
32 static void _interpret_node_status(char *p, char *master,char *rname)
34 int level = (master||rname)?4:0;
35 int numnames = CVAL(p,0);
36 DEBUG(level,("received %d names\n",numnames));
38 if (rname) *rname = 0;
39 if (master) *master = 0;
41 p += 1;
42 while (numnames--)
44 char qname[17];
45 int type;
46 fstring flags;
47 int i;
48 *flags = 0;
49 StrnCpy(qname,p,15);
50 type = CVAL(p,15);
51 p += 16;
53 strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
54 if ((p[0] & 0x60) == 0x00) strcat(flags,"B ");
55 if ((p[0] & 0x60) == 0x20) strcat(flags,"P ");
56 if ((p[0] & 0x60) == 0x40) strcat(flags,"M ");
57 if ((p[0] & 0x60) == 0x60) strcat(flags,"_ ");
58 if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
59 if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
60 if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
61 if (p[0] & 0x02) strcat(flags,"<PERMANENT> ");
63 if (master && !*master && type == 0x1d) {
64 StrnCpy(master,qname,15);
65 trim_string(master,NULL," ");
68 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
69 StrnCpy(rname,qname,15);
70 trim_string(rname,NULL," ");
73 for (i = strlen( qname) ; --i >= 0 ; ) {
74 if (!isprint(qname[i])) qname[i] = '.';
76 DEBUG(level,("\t%-15s <%02x> - %s\n",qname,type,flags));
77 p+=2;
79 DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
80 IVAL(p,20),IVAL(p,24)));
84 /****************************************************************************
85 do a netbios name status query on a host
87 the "master" parameter is a hack used for finding workgroups.
88 **************************************************************************/
89 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
90 struct in_addr to_ip,char *master,char *rname,
91 void (*fn)())
93 BOOL found=False;
94 int retries = 2;
95 int retry_time = 5000;
96 struct timeval tval;
97 struct packet_struct p;
98 struct packet_struct *p2;
99 struct nmb_packet *nmb = &p.packet.nmb;
100 static int name_trn_id = 0;
102 bzero((char *)&p,sizeof(p));
104 if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
105 (getpid()%(unsigned)100);
106 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
108 nmb->header.name_trn_id = name_trn_id;
109 nmb->header.opcode = 0;
110 nmb->header.response = False;
111 nmb->header.nm_flags.bcast = False;
112 nmb->header.nm_flags.recursion_available = 0;
113 nmb->header.nm_flags.recursion_desired = 1;
114 nmb->header.nm_flags.trunc = False;
115 nmb->header.nm_flags.authoritative = False;
116 nmb->header.rcode = 0;
117 nmb->header.qdcount = 1;
118 nmb->header.ancount = 0;
119 nmb->header.nscount = 0;
120 nmb->header.arcount = 0;
122 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
124 nmb->question.question_type = 0x21;
125 nmb->question.question_class = 0x1;
127 p.ip = to_ip;
128 p.port = NMB_PORT;
129 p.fd = fd;
130 p.timestamp = time(NULL);
131 p.packet_type = NMB_PACKET;
133 GetTimeOfDay(&tval);
135 if (!send_packet(&p))
136 return(False);
138 retries--;
140 while (1)
142 struct timeval tval2;
143 GetTimeOfDay(&tval2);
144 if (TvalDiff(&tval,&tval2) > retry_time) {
145 if (!retries) break;
146 if (!found && !send_packet(&p))
147 return False;
148 GetTimeOfDay(&tval);
149 retries--;
152 if ((p2=receive_packet(fd,NMB_PACKET,90)))
154 struct nmb_packet *nmb2 = &p2->packet.nmb;
155 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
156 !nmb2->header.response) {
157 /* its not for us - maybe deal with it later */
158 if (fn)
159 fn(p2);
160 else
161 free_packet(p2);
162 continue;
165 if (nmb2->header.opcode != 0 ||
166 nmb2->header.nm_flags.bcast ||
167 nmb2->header.rcode ||
168 !nmb2->header.ancount ||
169 nmb2->answers->rr_type != 0x21) {
170 /* XXXX what do we do with this? could be a redirect, but
171 we'll discard it for the moment */
172 free_packet(p2);
173 continue;
176 _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
177 free_packet(p2);
178 return(True);
183 DEBUG(0,("No status response (this is not unusual)\n"));
185 return(False);
189 /****************************************************************************
190 do a netbios name query to find someones IP
191 ****************************************************************************/
192 BOOL name_query(int fd,char *name,int name_type,
193 BOOL bcast,BOOL recurse,
194 struct in_addr to_ip, struct in_addr *ip,void (*fn)())
196 BOOL found=False;
197 int retries = 3;
198 int retry_time = bcast?250:2000;
199 struct timeval tval;
200 struct packet_struct p;
201 struct packet_struct *p2;
202 struct nmb_packet *nmb = &p.packet.nmb;
203 static int name_trn_id = 0;
205 bzero((char *)&p,sizeof(p));
207 if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
208 (getpid()%(unsigned)100);
209 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
211 nmb->header.name_trn_id = name_trn_id;
212 nmb->header.opcode = 0;
213 nmb->header.response = False;
214 nmb->header.nm_flags.bcast = bcast;
215 nmb->header.nm_flags.recursion_available = 0;
216 nmb->header.nm_flags.recursion_desired = 1;
217 nmb->header.nm_flags.trunc = False;
218 nmb->header.nm_flags.authoritative = False;
219 nmb->header.rcode = 0;
220 nmb->header.qdcount = 1;
221 nmb->header.ancount = 0;
222 nmb->header.nscount = 0;
223 nmb->header.arcount = 0;
225 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
227 nmb->question.question_type = 0x20;
228 nmb->question.question_class = 0x1;
230 p.ip = to_ip;
231 p.port = NMB_PORT;
232 p.fd = fd;
233 p.timestamp = time(NULL);
234 p.packet_type = NMB_PACKET;
236 GetTimeOfDay(&tval);
238 if (!send_packet(&p))
239 return(False);
241 retries--;
243 while (1)
245 struct timeval tval2;
246 GetTimeOfDay(&tval2);
247 if (TvalDiff(&tval,&tval2) > retry_time) {
248 if (!retries) break;
249 if (!found && !send_packet(&p))
250 return False;
251 GetTimeOfDay(&tval);
252 retries--;
255 if ((p2=receive_packet(fd,NMB_PACKET,90)))
257 struct nmb_packet *nmb2 = &p2->packet.nmb;
258 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
259 !nmb2->header.response) {
260 /* its not for us - maybe deal with it later
261 (put it on the queue?) */
262 if (fn)
263 fn(p2);
264 else
265 free_packet(p2);
266 continue;
269 if (nmb2->header.opcode != 0 ||
270 nmb2->header.nm_flags.bcast ||
271 nmb2->header.rcode ||
272 !nmb2->header.ancount) {
273 /* XXXX what do we do with this? could be a redirect, but
274 we'll discard it for the moment */
275 free_packet(p2);
276 continue;
279 if (ip) {
280 putip((char *)ip,&nmb2->answers->rdata[2]);
281 DEBUG(fn?3:2,("Got a positive name query response from %s",
282 inet_ntoa(p2->ip)));
283 DEBUG(fn?3:2,(" (%s)\n",inet_ntoa(*ip)));
285 found=True; retries=0;
286 free_packet(p2);
287 if (fn) break;
291 return(found);