xref: /onnv-gate/usr/src/lib/libsmbfs/smb/nbns_rq.c (revision 6007:d57e38e8fdd1)
1*6007Sthurlow /*
2*6007Sthurlow  * Copyright (c) 2000, Boris Popov
3*6007Sthurlow  * All rights reserved.
4*6007Sthurlow  *
5*6007Sthurlow  * Redistribution and use in source and binary forms, with or without
6*6007Sthurlow  * modification, are permitted provided that the following conditions
7*6007Sthurlow  * are met:
8*6007Sthurlow  * 1. Redistributions of source code must retain the above copyright
9*6007Sthurlow  *    notice, this list of conditions and the following disclaimer.
10*6007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
11*6007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
12*6007Sthurlow  *    documentation and/or other materials provided with the distribution.
13*6007Sthurlow  * 3. All advertising materials mentioning features or use of this software
14*6007Sthurlow  *    must display the following acknowledgement:
15*6007Sthurlow  *    This product includes software developed by Boris Popov.
16*6007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
17*6007Sthurlow  *    may be used to endorse or promote products derived from this software
18*6007Sthurlow  *    without specific prior written permission.
19*6007Sthurlow  *
20*6007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*6007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*6007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*6007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*6007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*6007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*6007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*6007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*6007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*6007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*6007Sthurlow  * SUCH DAMAGE.
31*6007Sthurlow  *
32*6007Sthurlow  * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
33*6007Sthurlow  */
34*6007Sthurlow 
35*6007Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*6007Sthurlow 
37*6007Sthurlow #include <sys/param.h>
38*6007Sthurlow #include <sys/socket.h>
39*6007Sthurlow #include <sys/time.h>
40*6007Sthurlow #include <ctype.h>
41*6007Sthurlow #include <netdb.h>
42*6007Sthurlow #include <errno.h>
43*6007Sthurlow #include <stdlib.h>
44*6007Sthurlow #include <string.h>
45*6007Sthurlow #include <strings.h>
46*6007Sthurlow #include <stdio.h>
47*6007Sthurlow #include <unistd.h>
48*6007Sthurlow #include <libintl.h>
49*6007Sthurlow 
50*6007Sthurlow #include <netinet/in.h>
51*6007Sthurlow #include <arpa/inet.h>
52*6007Sthurlow #include <tsol/label.h>
53*6007Sthurlow 
54*6007Sthurlow #define	NB_NEEDRESOLVER
55*6007Sthurlow #include <netsmb/netbios.h>
56*6007Sthurlow #include <netsmb/smb_lib.h>
57*6007Sthurlow #include <netsmb/nb_lib.h>
58*6007Sthurlow #include <netsmb/mchain.h>
59*6007Sthurlow 
60*6007Sthurlow static int  nbns_rq_create(int opcode, struct nb_ctx *ctx,
61*6007Sthurlow     struct nbns_rq **rqpp);
62*6007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp);
63*6007Sthurlow static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
64*6007Sthurlow static int  nbns_rq_prepare(struct nbns_rq *rqp);
65*6007Sthurlow static int  nbns_rq(struct nbns_rq *rqp);
66*6007Sthurlow 
67*6007Sthurlow static struct nb_ifdesc *nb_iflist = NULL;
68*6007Sthurlow 
69*6007Sthurlow int
70*6007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
71*6007Sthurlow {
72*6007Sthurlow 	struct nbns_rq *rqp;
73*6007Sthurlow 	struct nb_name nn;
74*6007Sthurlow 	struct nbns_rr rr;
75*6007Sthurlow 	struct sockaddr_in *dest;
76*6007Sthurlow 	int error, rdrcount, len;
77*6007Sthurlow 
78*6007Sthurlow 	if (strlen(name) > NB_NAMELEN)
79*6007Sthurlow 		return (NBERROR(NBERR_NAMETOOLONG));
80*6007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
81*6007Sthurlow 	if (error)
82*6007Sthurlow 		return (error);
83*6007Sthurlow 	/*
84*6007Sthurlow 	 * Pad the name with blanks, but
85*6007Sthurlow 	 * leave the "type" byte NULL.
86*6007Sthurlow 	 * nb_name_encode adds the type.
87*6007Sthurlow 	 */
88*6007Sthurlow 	bzero(&nn, sizeof (nn));
89*6007Sthurlow 	snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
90*6007Sthurlow 	nn.nn_type = NBT_SERVER;
91*6007Sthurlow 	nn.nn_scope = ctx->nb_scope;
92*6007Sthurlow 	rqp->nr_nmflags = NBNS_NMFLAG_RD;
93*6007Sthurlow 	rqp->nr_qdname = &nn;
94*6007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
95*6007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
96*6007Sthurlow 	rqp->nr_qdcount = 1;
97*6007Sthurlow 	rqp->nr_maxretry = 5;
98*6007Sthurlow 
99*6007Sthurlow 	error = nbns_rq_prepare(rqp);
100*6007Sthurlow 	if (error) {
101*6007Sthurlow 		nbns_rq_done(rqp);
102*6007Sthurlow 		return (error);
103*6007Sthurlow 	}
104*6007Sthurlow 	rdrcount = NBNS_MAXREDIRECTS;
105*6007Sthurlow 	for (;;) {
106*6007Sthurlow 		error = nbns_rq(rqp);
107*6007Sthurlow 		if (error)
108*6007Sthurlow 			break;
109*6007Sthurlow 		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
110*6007Sthurlow 			/*
111*6007Sthurlow 			 * Not an authoritative answer.  Query again
112*6007Sthurlow 			 * using the NS address in the 2nd record.
113*6007Sthurlow 			 */
114*6007Sthurlow 			if (rdrcount-- == 0) {
115*6007Sthurlow 				error = NBERROR(NBERR_TOOMANYREDIRECTS);
116*6007Sthurlow 				break;
117*6007Sthurlow 			}
118*6007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
119*6007Sthurlow 			if (error)
120*6007Sthurlow 				break;
121*6007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
122*6007Sthurlow 			if (error)
123*6007Sthurlow 				break;
124*6007Sthurlow 			bcopy(rr.rr_data, &rqp->nr_dest, 4);
125*6007Sthurlow 			continue;
126*6007Sthurlow 		}
127*6007Sthurlow 		if (rqp->nr_rpancount == 0) {
128*6007Sthurlow 			error = NBERROR(NBERR_HOSTNOTFOUND);
129*6007Sthurlow 			break;
130*6007Sthurlow 		}
131*6007Sthurlow 		error = nbns_rq_getrr(rqp, &rr);
132*6007Sthurlow 		if (error)
133*6007Sthurlow 			break;
134*6007Sthurlow 		len = sizeof (struct sockaddr_in);
135*6007Sthurlow 		dest = malloc(len);
136*6007Sthurlow 		if (dest == NULL)
137*6007Sthurlow 			return (ENOMEM);
138*6007Sthurlow 		bzero(dest, len);
139*6007Sthurlow 		/*
140*6007Sthurlow 		 * Solaris sockaddr_in doesn't have this field.
141*6007Sthurlow 		 * dest->sin_len = len;
142*6007Sthurlow 		 */
143*6007Sthurlow 		dest->sin_family = AF_INET;
144*6007Sthurlow 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
145*6007Sthurlow 		dest->sin_port = htons(SMB_TCP_PORT);
146*6007Sthurlow 		*adpp = (struct sockaddr *)dest;
147*6007Sthurlow 		ctx->nb_lastns = rqp->nr_sender;
148*6007Sthurlow 		break;
149*6007Sthurlow 	}
150*6007Sthurlow 	nbns_rq_done(rqp);
151*6007Sthurlow 	return (error);
152*6007Sthurlow }
153*6007Sthurlow 
154*6007Sthurlow static char *
155*6007Sthurlow smb_optstrncpy(char *d, char *s, unsigned maxlen)
156*6007Sthurlow {
157*6007Sthurlow 	if (d && s) {
158*6007Sthurlow 		strncpy(d, s, maxlen);
159*6007Sthurlow 		d[maxlen] = (char)0;
160*6007Sthurlow 	}
161*6007Sthurlow 	return (d);
162*6007Sthurlow }
163*6007Sthurlow 
164*6007Sthurlow 
165*6007Sthurlow int
166*6007Sthurlow nbns_getnodestatus(struct sockaddr *targethost,
167*6007Sthurlow     struct nb_ctx *ctx, char *system, char *workgroup)
168*6007Sthurlow {
169*6007Sthurlow 	struct nbns_rq *rqp;
170*6007Sthurlow 	struct nbns_rr rr;
171*6007Sthurlow 	struct nb_name nn;
172*6007Sthurlow 	struct nbns_nr *nrp;
173*6007Sthurlow 	char nrtype;
174*6007Sthurlow 	char *cp, *retname = NULL;
175*6007Sthurlow 	struct sockaddr_in *dest;
176*6007Sthurlow 	unsigned char nrcount;
177*6007Sthurlow 	int error, rdrcount, i, foundserver = 0, foundgroup = 0;
178*6007Sthurlow 
179*6007Sthurlow 	if (targethost->sa_family != AF_INET)
180*6007Sthurlow 		return (EINVAL);
181*6007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
182*6007Sthurlow 	if (error)
183*6007Sthurlow 		return (error);
184*6007Sthurlow 	bzero(&nn, sizeof (nn));
185*6007Sthurlow 	strcpy((char *)nn.nn_name, "*");
186*6007Sthurlow 	nn.nn_scope = ctx->nb_scope;
187*6007Sthurlow 	nn.nn_type = NBT_WKSTA;
188*6007Sthurlow 	rqp->nr_nmflags = 0;
189*6007Sthurlow 	rqp->nr_qdname = &nn;
190*6007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
191*6007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
192*6007Sthurlow 	rqp->nr_qdcount = 1;
193*6007Sthurlow 	rqp->nr_maxretry = 2;
194*6007Sthurlow 
195*6007Sthurlow 	/* LINTED */
196*6007Sthurlow 	dest = (struct sockaddr_in *)targethost;
197*6007Sthurlow 	rqp->nr_dest = dest->sin_addr;
198*6007Sthurlow 
199*6007Sthurlow 	error = nbns_rq_prepare(rqp);
200*6007Sthurlow 	if (error) {
201*6007Sthurlow 		nbns_rq_done(rqp);
202*6007Sthurlow 		return (error);
203*6007Sthurlow 	}
204*6007Sthurlow 
205*6007Sthurlow 	/*
206*6007Sthurlow 	 * Darwin had a loop here, allowing redirect, etc.
207*6007Sthurlow 	 * but we only handle point-to-point for node status.
208*6007Sthurlow 	 */
209*6007Sthurlow 	error = nbns_rq(rqp);
210*6007Sthurlow 	if (error)
211*6007Sthurlow 		goto out;
212*6007Sthurlow 	if (rqp->nr_rpancount == 0) {
213*6007Sthurlow 		error = NBERROR(NBERR_HOSTNOTFOUND);
214*6007Sthurlow 		goto out;
215*6007Sthurlow 	}
216*6007Sthurlow 	error = nbns_rq_getrr(rqp, &rr);
217*6007Sthurlow 	if (error)
218*6007Sthurlow 		goto out;
219*6007Sthurlow 
220*6007Sthurlow 	/* Compiler didn't like cast on lvalue++ */
221*6007Sthurlow 	nrcount = *((unsigned char *)rr.rr_data);
222*6007Sthurlow 	rr.rr_data++;
223*6007Sthurlow 	/* LINTED */
224*6007Sthurlow 	for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
225*6007Sthurlow 	    i <= nrcount; ++i, ++nrp) {
226*6007Sthurlow 		nrtype = nrp->ns_name[NB_NAMELEN-1];
227*6007Sthurlow 		/* Terminate the string: */
228*6007Sthurlow 		nrp->ns_name[NB_NAMELEN-1] = (char)0;
229*6007Sthurlow 		/* Strip off trailing spaces */
230*6007Sthurlow 		for (cp = &nrp->ns_name[NB_NAMELEN-2];
231*6007Sthurlow 		    cp >= nrp->ns_name; --cp) {
232*6007Sthurlow 			if (*cp != (char)0x20)
233*6007Sthurlow 				break;
234*6007Sthurlow 			*cp = (char)0;
235*6007Sthurlow 		}
236*6007Sthurlow 		nrp->ns_flags = ntohs(nrp->ns_flags);
237*6007Sthurlow 		if (nrp->ns_flags & NBNS_GROUPFLG) {
238*6007Sthurlow 			if (!foundgroup ||
239*6007Sthurlow 			    (foundgroup != NBT_WKSTA+1 &&
240*6007Sthurlow 			    nrtype == NBT_WKSTA)) {
241*6007Sthurlow 				smb_optstrncpy(workgroup, nrp->ns_name,
242*6007Sthurlow 				    SMB_MAXUSERNAMELEN);
243*6007Sthurlow 				foundgroup = nrtype+1;
244*6007Sthurlow 			}
245*6007Sthurlow 		} else {
246*6007Sthurlow 			/*
247*6007Sthurlow 			 * Track at least ONE name, in case
248*6007Sthurlow 			 * no server name is found
249*6007Sthurlow 			 */
250*6007Sthurlow 			retname = nrp->ns_name;
251*6007Sthurlow 		}
252*6007Sthurlow 		if (nrtype == NBT_SERVER) {
253*6007Sthurlow 			smb_optstrncpy(system, nrp->ns_name,
254*6007Sthurlow 			    SMB_MAXSRVNAMELEN);
255*6007Sthurlow 			foundserver = 1;
256*6007Sthurlow 		}
257*6007Sthurlow 	}
258*6007Sthurlow 	if (!foundserver)
259*6007Sthurlow 		smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
260*6007Sthurlow 	ctx->nb_lastns = rqp->nr_sender;
261*6007Sthurlow 
262*6007Sthurlow out:
263*6007Sthurlow 	nbns_rq_done(rqp);
264*6007Sthurlow 	return (error);
265*6007Sthurlow }
266*6007Sthurlow 
267*6007Sthurlow int
268*6007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
269*6007Sthurlow {
270*6007Sthurlow 	struct nbns_rq *rqp;
271*6007Sthurlow 	static uint16_t trnid;
272*6007Sthurlow 	int error;
273*6007Sthurlow 
274*6007Sthurlow 	if (trnid == 0)
275*6007Sthurlow 		trnid = getpid();
276*6007Sthurlow 	rqp = malloc(sizeof (*rqp));
277*6007Sthurlow 	if (rqp == NULL)
278*6007Sthurlow 		return (ENOMEM);
279*6007Sthurlow 	bzero(rqp, sizeof (*rqp));
280*6007Sthurlow 	error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
281*6007Sthurlow 	if (error) {
282*6007Sthurlow 		free(rqp);
283*6007Sthurlow 		return (error);
284*6007Sthurlow 	}
285*6007Sthurlow 	rqp->nr_opcode = opcode;
286*6007Sthurlow 	rqp->nr_nbd = ctx;
287*6007Sthurlow 	rqp->nr_trnid = trnid++;
288*6007Sthurlow 	*rqpp = rqp;
289*6007Sthurlow 	return (0);
290*6007Sthurlow }
291*6007Sthurlow 
292*6007Sthurlow void
293*6007Sthurlow nbns_rq_done(struct nbns_rq *rqp)
294*6007Sthurlow {
295*6007Sthurlow 	if (rqp == NULL)
296*6007Sthurlow 		return;
297*6007Sthurlow 	if (rqp->nr_fd >= 0)
298*6007Sthurlow 		close(rqp->nr_fd);
299*6007Sthurlow 	mb_done(&rqp->nr_rq);
300*6007Sthurlow 	mb_done(&rqp->nr_rp);
301*6007Sthurlow 	if (rqp->nr_if)
302*6007Sthurlow 		free(rqp->nr_if);
303*6007Sthurlow 	free(rqp);
304*6007Sthurlow }
305*6007Sthurlow 
306*6007Sthurlow /*
307*6007Sthurlow  * Extract resource record from the packet. Assume that there is only
308*6007Sthurlow  * one mbuf.
309*6007Sthurlow  */
310*6007Sthurlow int
311*6007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
312*6007Sthurlow {
313*6007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
314*6007Sthurlow 	uchar_t *cp;
315*6007Sthurlow 	int error, len;
316*6007Sthurlow 
317*6007Sthurlow 	bzero(rrp, sizeof (*rrp));
318*6007Sthurlow 	cp = (uchar_t *)mbp->mb_pos;
319*6007Sthurlow 	len = nb_encname_len(cp);
320*6007Sthurlow 	if (len < 1)
321*6007Sthurlow 		return (NBERROR(NBERR_INVALIDRESPONSE));
322*6007Sthurlow 	rrp->rr_name = cp;
323*6007Sthurlow 	error = mb_get_mem(mbp, NULL, len);
324*6007Sthurlow 	if (error)
325*6007Sthurlow 		return (error);
326*6007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_type);
327*6007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_class);
328*6007Sthurlow 	mb_get_uint32be(mbp, &rrp->rr_ttl);
329*6007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_rdlength);
330*6007Sthurlow 	rrp->rr_data = (uchar_t *)mbp->mb_pos;
331*6007Sthurlow 	error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
332*6007Sthurlow 	return (error);
333*6007Sthurlow }
334*6007Sthurlow 
335*6007Sthurlow int
336*6007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp)
337*6007Sthurlow {
338*6007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
339*6007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
340*6007Sthurlow 	uint16_t ofr; /* opcode, flags, rcode */
341*6007Sthurlow 	uchar_t *cp;
342*6007Sthurlow 	int len, error;
343*6007Sthurlow 
344*6007Sthurlow 	/*
345*6007Sthurlow 	 * Replacing with one argument.
346*6007Sthurlow 	 * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
347*6007Sthurlow 	 */
348*6007Sthurlow 	error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
349*6007Sthurlow 	if (error)
350*6007Sthurlow 		return (error);
351*6007Sthurlow 
352*6007Sthurlow 	/*
353*6007Sthurlow 	 * When looked into the ethereal trace, 'nmblookup' command sets this
354*6007Sthurlow 	 * flag. We will also set.
355*6007Sthurlow 	 */
356*6007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_trnid);
357*6007Sthurlow 	ofr = ((rqp->nr_opcode & 0x1F) << 11) |
358*6007Sthurlow 	    ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
359*6007Sthurlow 	mb_put_uint16be(mbp, ofr);
360*6007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_qdcount);
361*6007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_ancount);
362*6007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_nscount);
363*6007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_arcount);
364*6007Sthurlow 	if (rqp->nr_qdcount) {
365*6007Sthurlow 		if (rqp->nr_qdcount > 1)
366*6007Sthurlow 			return (EINVAL);
367*6007Sthurlow 		len = nb_name_len(rqp->nr_qdname);
368*6007Sthurlow 		error = mb_fit(mbp, len, (char **)&cp);
369*6007Sthurlow 		if (error)
370*6007Sthurlow 			return (error);
371*6007Sthurlow 		nb_name_encode(rqp->nr_qdname, cp);
372*6007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdtype);
373*6007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdclass);
374*6007Sthurlow 	}
375*6007Sthurlow 	m_lineup(mbp->mb_top, &mbp->mb_top);
376*6007Sthurlow 	if (ctx->nb_timo == 0)
377*6007Sthurlow 		ctx->nb_timo = 1;	/* by default 1 second */
378*6007Sthurlow 	return (0);
379*6007Sthurlow }
380*6007Sthurlow 
381*6007Sthurlow static int
382*6007Sthurlow nbns_rq_recv(struct nbns_rq *rqp)
383*6007Sthurlow {
384*6007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
385*6007Sthurlow 	void *rpdata = mtod(mbp->mb_top, void *);
386*6007Sthurlow 	fd_set rd, wr, ex;
387*6007Sthurlow 	struct timeval tv;
388*6007Sthurlow 	struct sockaddr_in sender;
389*6007Sthurlow 	int s = rqp->nr_fd;
390*6007Sthurlow 	int n, len;
391*6007Sthurlow 
392*6007Sthurlow 	FD_ZERO(&rd);
393*6007Sthurlow 	FD_ZERO(&wr);
394*6007Sthurlow 	FD_ZERO(&ex);
395*6007Sthurlow 	FD_SET(s, &rd);
396*6007Sthurlow 
397*6007Sthurlow 	tv.tv_sec = rqp->nr_nbd->nb_timo;
398*6007Sthurlow 	tv.tv_usec = 0;
399*6007Sthurlow 
400*6007Sthurlow 	n = select(s + 1, &rd, &wr, &ex, &tv);
401*6007Sthurlow 	if (n == -1)
402*6007Sthurlow 		return (-1);
403*6007Sthurlow 	if (n == 0)
404*6007Sthurlow 		return (ETIMEDOUT);
405*6007Sthurlow 	if (FD_ISSET(s, &rd) == 0)
406*6007Sthurlow 		return (ETIMEDOUT);
407*6007Sthurlow 	len = sizeof (sender);
408*6007Sthurlow 	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
409*6007Sthurlow 	    (struct sockaddr *)&sender, &len);
410*6007Sthurlow 	if (n < 0)
411*6007Sthurlow 		return (errno);
412*6007Sthurlow 	mbp->mb_top->m_len = mbp->mb_count = n;
413*6007Sthurlow 	rqp->nr_sender = sender;
414*6007Sthurlow 	return (0);
415*6007Sthurlow }
416*6007Sthurlow 
417*6007Sthurlow static int
418*6007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp)
419*6007Sthurlow {
420*6007Sthurlow 	struct sockaddr_in locaddr;
421*6007Sthurlow 	int opt = 1, s;
422*6007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
423*6007Sthurlow 
424*6007Sthurlow 	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
425*6007Sthurlow 	if (s < 0)
426*6007Sthurlow 		return (errno);
427*6007Sthurlow 	if (ctx->nb_flags & NBCF_BC_ENABLE) {
428*6007Sthurlow 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
429*6007Sthurlow 		    sizeof (opt)) < 0)
430*6007Sthurlow 			return (errno);
431*6007Sthurlow 	}
432*6007Sthurlow 	if (is_system_labeled())
433*6007Sthurlow 		(void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
434*6007Sthurlow 		    sizeof (opt));
435*6007Sthurlow 	bzero(&locaddr, sizeof (locaddr));
436*6007Sthurlow 	locaddr.sin_family = AF_INET;
437*6007Sthurlow 	/* locaddr.sin_len = sizeof (locaddr); */
438*6007Sthurlow 	if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
439*6007Sthurlow 		return (errno);
440*6007Sthurlow 	return (0);
441*6007Sthurlow }
442*6007Sthurlow 
443*6007Sthurlow static int
444*6007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
445*6007Sthurlow {
446*6007Sthurlow 	struct sockaddr_in dest;
447*6007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
448*6007Sthurlow 	int s = rqp->nr_fd;
449*6007Sthurlow 	uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
450*6007Sthurlow 	uint16_t *datap;
451*6007Sthurlow 	uint8_t nmflags;
452*6007Sthurlow 	int rc;
453*6007Sthurlow 
454*6007Sthurlow 	bzero(&dest, sizeof (dest));
455*6007Sthurlow 	dest.sin_family = AF_INET;
456*6007Sthurlow 	dest.sin_port = htons(NBNS_UDP_PORT);
457*6007Sthurlow 	dest.sin_addr.s_addr = ina;
458*6007Sthurlow 
459*6007Sthurlow 	if (ina == INADDR_BROADCAST) {
460*6007Sthurlow 		/* Turn on the broadcast bit. */
461*6007Sthurlow 		nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
462*6007Sthurlow 		/*LINTED*/
463*6007Sthurlow 		datap = mtod(mbp->mb_top, uint16_t *);
464*6007Sthurlow 		ofr = ((rqp->nr_opcode & 0x1F) << 11) |
465*6007Sthurlow 		    ((nmflags & 0x7F) << 4); /* rcode=0 */
466*6007Sthurlow 		ofr_save = datap[1];
467*6007Sthurlow 		datap[1] = htons(ofr);
468*6007Sthurlow 	}
469*6007Sthurlow 
470*6007Sthurlow 	rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
471*6007Sthurlow 	    (struct sockaddr *)&dest, sizeof (dest));
472*6007Sthurlow 
473*6007Sthurlow 	if (ina == INADDR_BROADCAST) {
474*6007Sthurlow 		/* Turn the broadcast bit back off. */
475*6007Sthurlow 		datap[1] = ofr_save;
476*6007Sthurlow 	}
477*6007Sthurlow 
478*6007Sthurlow 
479*6007Sthurlow 	if (rc < 0)
480*6007Sthurlow 		return (errno);
481*6007Sthurlow 
482*6007Sthurlow 	return (0);
483*6007Sthurlow }
484*6007Sthurlow 
485*6007Sthurlow int
486*6007Sthurlow nbns_rq(struct nbns_rq *rqp)
487*6007Sthurlow {
488*6007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
489*6007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
490*6007Sthurlow 	uint16_t ofr, rpid;
491*6007Sthurlow 	uint8_t nmflags;
492*6007Sthurlow 	int error, tries, maxretry;
493*6007Sthurlow 
494*6007Sthurlow 	error = nbns_rq_opensocket(rqp);
495*6007Sthurlow 	if (error)
496*6007Sthurlow 		return (error);
497*6007Sthurlow 
498*6007Sthurlow 	maxretry = rqp->nr_maxretry;
499*6007Sthurlow 	for (tries = 0; tries < maxretry; tries++) {
500*6007Sthurlow 
501*6007Sthurlow 		/*
502*6007Sthurlow 		 * Minor hack: If nr_dest is set, send there only.
503*6007Sthurlow 		 * Used by _getnodestatus, _resolvname redirects.
504*6007Sthurlow 		 */
505*6007Sthurlow 		if (rqp->nr_dest.s_addr) {
506*6007Sthurlow 			error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
507*6007Sthurlow 			if (error) {
508*6007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
509*6007Sthurlow 				    "nbns error %d sending to %s"),
510*6007Sthurlow 				    0, error, inet_ntoa(rqp->nr_dest));
511*6007Sthurlow 			}
512*6007Sthurlow 			goto do_recv;
513*6007Sthurlow 		}
514*6007Sthurlow 
515*6007Sthurlow 		if (ctx->nb_wins1) {
516*6007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins1);
517*6007Sthurlow 			if (error) {
518*6007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
519*6007Sthurlow 				    "nbns error %d sending to wins1"),
520*6007Sthurlow 				    0, error);
521*6007Sthurlow 			}
522*6007Sthurlow 		}
523*6007Sthurlow 
524*6007Sthurlow 		if (ctx->nb_wins2 && (tries > 0)) {
525*6007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins2);
526*6007Sthurlow 			if (error) {
527*6007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
528*6007Sthurlow 				    "nbns error %d sending to wins2"),
529*6007Sthurlow 				    0, error);
530*6007Sthurlow 			}
531*6007Sthurlow 		}
532*6007Sthurlow 
533*6007Sthurlow 		/*
534*6007Sthurlow 		 * If broadcast is enabled, start broadcasting
535*6007Sthurlow 		 * only after wins servers fail to respond, or
536*6007Sthurlow 		 * immediately if no WINS servers configured.
537*6007Sthurlow 		 */
538*6007Sthurlow 		if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
539*6007Sthurlow 		    ((tries > 1) || (ctx->nb_wins1 == 0))) {
540*6007Sthurlow 			error = nbns_rq_send(rqp, INADDR_BROADCAST);
541*6007Sthurlow 			if (error) {
542*6007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
543*6007Sthurlow 				    "nbns error %d sending broadcast"),
544*6007Sthurlow 				    0, error);
545*6007Sthurlow 			}
546*6007Sthurlow 		}
547*6007Sthurlow 
548*6007Sthurlow 		/*
549*6007Sthurlow 		 * Wait for responses from ANY of the above.
550*6007Sthurlow 		 */
551*6007Sthurlow do_recv:
552*6007Sthurlow 		error = nbns_rq_recv(rqp);
553*6007Sthurlow 		if (error == ETIMEDOUT)
554*6007Sthurlow 			continue;
555*6007Sthurlow 		if (error) {
556*6007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
557*6007Sthurlow 			    "nbns recv error %d"),
558*6007Sthurlow 			    0, error);
559*6007Sthurlow 			return (error);
560*6007Sthurlow 		}
561*6007Sthurlow 
562*6007Sthurlow 		mbp = &rqp->nr_rp;
563*6007Sthurlow 		if (mbp->mb_count < 12)
564*6007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
565*6007Sthurlow 		mb_get_uint16be(mbp, &rpid);
566*6007Sthurlow 		if (rpid != rqp->nr_trnid)
567*6007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
568*6007Sthurlow 		break;
569*6007Sthurlow 	}
570*6007Sthurlow 
571*6007Sthurlow 	mb_get_uint16be(mbp, &ofr);
572*6007Sthurlow 	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
573*6007Sthurlow 	rqp->nr_rprcode = ofr & 0xf;
574*6007Sthurlow 	if (rqp->nr_rprcode)
575*6007Sthurlow 		return (NBERROR(rqp->nr_rprcode));
576*6007Sthurlow 	mb_get_uint16be(mbp, &rpid);	/* QDCOUNT */
577*6007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpancount);
578*6007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpnscount);
579*6007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rparcount);
580*6007Sthurlow 	return (0);
581*6007Sthurlow }
582