xref: /onnv-gate/usr/src/lib/libsmbfs/smb/nbns_rq.c (revision 8271:792589b3384f)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
336007Sthurlow  */
346007Sthurlow 
356007Sthurlow #include <sys/param.h>
366007Sthurlow #include <sys/socket.h>
376007Sthurlow #include <sys/time.h>
386007Sthurlow #include <ctype.h>
396007Sthurlow #include <netdb.h>
406007Sthurlow #include <errno.h>
416007Sthurlow #include <stdlib.h>
426007Sthurlow #include <string.h>
436007Sthurlow #include <strings.h>
446007Sthurlow #include <stdio.h>
456007Sthurlow #include <unistd.h>
466007Sthurlow #include <libintl.h>
476007Sthurlow 
486007Sthurlow #include <netinet/in.h>
496007Sthurlow #include <arpa/inet.h>
506007Sthurlow #include <tsol/label.h>
516007Sthurlow 
526007Sthurlow #define	NB_NEEDRESOLVER
536007Sthurlow #include <netsmb/netbios.h>
546007Sthurlow #include <netsmb/smb_lib.h>
556007Sthurlow #include <netsmb/nb_lib.h>
566007Sthurlow #include <netsmb/mchain.h>
576007Sthurlow 
58*8271SGordon.Ross@Sun.COM #include "private.h"
59*8271SGordon.Ross@Sun.COM 
60*8271SGordon.Ross@Sun.COM /*
61*8271SGordon.Ross@Sun.COM  * nbns request
62*8271SGordon.Ross@Sun.COM  */
63*8271SGordon.Ross@Sun.COM struct nbns_rq {
64*8271SGordon.Ross@Sun.COM 	int		nr_opcode;
65*8271SGordon.Ross@Sun.COM 	int		nr_nmflags;
66*8271SGordon.Ross@Sun.COM 	int		nr_rcode;
67*8271SGordon.Ross@Sun.COM 	int		nr_qdcount;
68*8271SGordon.Ross@Sun.COM 	int		nr_ancount;
69*8271SGordon.Ross@Sun.COM 	int		nr_nscount;
70*8271SGordon.Ross@Sun.COM 	int		nr_arcount;
71*8271SGordon.Ross@Sun.COM 	struct nb_name	*nr_qdname;
72*8271SGordon.Ross@Sun.COM 	uint16_t	nr_qdtype;
73*8271SGordon.Ross@Sun.COM 	uint16_t	nr_qdclass;
74*8271SGordon.Ross@Sun.COM 	struct in_addr	nr_dest;	/* receiver of query */
75*8271SGordon.Ross@Sun.COM 	struct sockaddr_in nr_sender;	/* sender of response */
76*8271SGordon.Ross@Sun.COM 	int		nr_rpnmflags;
77*8271SGordon.Ross@Sun.COM 	int		nr_rprcode;
78*8271SGordon.Ross@Sun.COM 	uint16_t	nr_rpancount;
79*8271SGordon.Ross@Sun.COM 	uint16_t	nr_rpnscount;
80*8271SGordon.Ross@Sun.COM 	uint16_t	nr_rparcount;
81*8271SGordon.Ross@Sun.COM 	uint16_t	nr_trnid;
82*8271SGordon.Ross@Sun.COM 	struct nb_ctx	*nr_nbd;
83*8271SGordon.Ross@Sun.COM 	struct mbdata	nr_rq;
84*8271SGordon.Ross@Sun.COM 	struct mbdata	nr_rp;
85*8271SGordon.Ross@Sun.COM 	struct nb_ifdesc *nr_if;
86*8271SGordon.Ross@Sun.COM 	int		nr_flags;
87*8271SGordon.Ross@Sun.COM 	int		nr_fd;
88*8271SGordon.Ross@Sun.COM 	int		nr_maxretry;
89*8271SGordon.Ross@Sun.COM };
90*8271SGordon.Ross@Sun.COM typedef struct nbns_rq nbns_rq_t;
91*8271SGordon.Ross@Sun.COM 
926007Sthurlow static int  nbns_rq_create(int opcode, struct nb_ctx *ctx,
936007Sthurlow     struct nbns_rq **rqpp);
946007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp);
956007Sthurlow static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
966007Sthurlow static int  nbns_rq_prepare(struct nbns_rq *rqp);
976007Sthurlow static int  nbns_rq(struct nbns_rq *rqp);
986007Sthurlow 
996007Sthurlow static struct nb_ifdesc *nb_iflist = NULL;
1006007Sthurlow 
1016007Sthurlow int
1026007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
1036007Sthurlow {
1046007Sthurlow 	struct nbns_rq *rqp;
1056007Sthurlow 	struct nb_name nn;
1066007Sthurlow 	struct nbns_rr rr;
1076007Sthurlow 	struct sockaddr_in *dest;
1086007Sthurlow 	int error, rdrcount, len;
1096007Sthurlow 
1106007Sthurlow 	if (strlen(name) > NB_NAMELEN)
1116007Sthurlow 		return (NBERROR(NBERR_NAMETOOLONG));
1126007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
1136007Sthurlow 	if (error)
1146007Sthurlow 		return (error);
1156007Sthurlow 	/*
1166007Sthurlow 	 * Pad the name with blanks, but
1176007Sthurlow 	 * leave the "type" byte NULL.
1186007Sthurlow 	 * nb_name_encode adds the type.
1196007Sthurlow 	 */
1206007Sthurlow 	bzero(&nn, sizeof (nn));
1216007Sthurlow 	snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
1226007Sthurlow 	nn.nn_type = NBT_SERVER;
1236007Sthurlow 	nn.nn_scope = ctx->nb_scope;
1246007Sthurlow 	rqp->nr_nmflags = NBNS_NMFLAG_RD;
1256007Sthurlow 	rqp->nr_qdname = &nn;
1266007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
1276007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
1286007Sthurlow 	rqp->nr_qdcount = 1;
1296007Sthurlow 	rqp->nr_maxretry = 5;
1306007Sthurlow 
1316007Sthurlow 	error = nbns_rq_prepare(rqp);
1326007Sthurlow 	if (error) {
1336007Sthurlow 		nbns_rq_done(rqp);
1346007Sthurlow 		return (error);
1356007Sthurlow 	}
1366007Sthurlow 	rdrcount = NBNS_MAXREDIRECTS;
1376007Sthurlow 	for (;;) {
1386007Sthurlow 		error = nbns_rq(rqp);
1396007Sthurlow 		if (error)
1406007Sthurlow 			break;
1416007Sthurlow 		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
1426007Sthurlow 			/*
1436007Sthurlow 			 * Not an authoritative answer.  Query again
1446007Sthurlow 			 * using the NS address in the 2nd record.
1456007Sthurlow 			 */
1466007Sthurlow 			if (rdrcount-- == 0) {
1476007Sthurlow 				error = NBERROR(NBERR_TOOMANYREDIRECTS);
1486007Sthurlow 				break;
1496007Sthurlow 			}
1506007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
1516007Sthurlow 			if (error)
1526007Sthurlow 				break;
1536007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
1546007Sthurlow 			if (error)
1556007Sthurlow 				break;
1566007Sthurlow 			bcopy(rr.rr_data, &rqp->nr_dest, 4);
1576007Sthurlow 			continue;
1586007Sthurlow 		}
1596007Sthurlow 		if (rqp->nr_rpancount == 0) {
1606007Sthurlow 			error = NBERROR(NBERR_HOSTNOTFOUND);
1616007Sthurlow 			break;
1626007Sthurlow 		}
1636007Sthurlow 		error = nbns_rq_getrr(rqp, &rr);
1646007Sthurlow 		if (error)
1656007Sthurlow 			break;
1666007Sthurlow 		len = sizeof (struct sockaddr_in);
1676007Sthurlow 		dest = malloc(len);
1686007Sthurlow 		if (dest == NULL)
1696007Sthurlow 			return (ENOMEM);
1706007Sthurlow 		bzero(dest, len);
1716007Sthurlow 		/*
1726007Sthurlow 		 * Solaris sockaddr_in doesn't have this field.
1736007Sthurlow 		 * dest->sin_len = len;
1746007Sthurlow 		 */
1756007Sthurlow 		dest->sin_family = AF_INET;
1766007Sthurlow 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
1776007Sthurlow 		dest->sin_port = htons(SMB_TCP_PORT);
1786007Sthurlow 		*adpp = (struct sockaddr *)dest;
1796007Sthurlow 		ctx->nb_lastns = rqp->nr_sender;
1806007Sthurlow 		break;
1816007Sthurlow 	}
1826007Sthurlow 	nbns_rq_done(rqp);
1836007Sthurlow 	return (error);
1846007Sthurlow }
1856007Sthurlow 
1866007Sthurlow static char *
1876007Sthurlow smb_optstrncpy(char *d, char *s, unsigned maxlen)
1886007Sthurlow {
1896007Sthurlow 	if (d && s) {
1906007Sthurlow 		strncpy(d, s, maxlen);
1916007Sthurlow 		d[maxlen] = (char)0;
1926007Sthurlow 	}
1936007Sthurlow 	return (d);
1946007Sthurlow }
1956007Sthurlow 
1966007Sthurlow 
1976007Sthurlow int
1986007Sthurlow nbns_getnodestatus(struct sockaddr *targethost,
1996007Sthurlow     struct nb_ctx *ctx, char *system, char *workgroup)
2006007Sthurlow {
2016007Sthurlow 	struct nbns_rq *rqp;
2026007Sthurlow 	struct nbns_rr rr;
2036007Sthurlow 	struct nb_name nn;
2046007Sthurlow 	struct nbns_nr *nrp;
2056007Sthurlow 	char nrtype;
2066007Sthurlow 	char *cp, *retname = NULL;
2076007Sthurlow 	struct sockaddr_in *dest;
2086007Sthurlow 	unsigned char nrcount;
2096007Sthurlow 	int error, rdrcount, i, foundserver = 0, foundgroup = 0;
2106007Sthurlow 
2116007Sthurlow 	if (targethost->sa_family != AF_INET)
2126007Sthurlow 		return (EINVAL);
2136007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
2146007Sthurlow 	if (error)
2156007Sthurlow 		return (error);
2166007Sthurlow 	bzero(&nn, sizeof (nn));
2176007Sthurlow 	strcpy((char *)nn.nn_name, "*");
2186007Sthurlow 	nn.nn_scope = ctx->nb_scope;
2196007Sthurlow 	nn.nn_type = NBT_WKSTA;
2206007Sthurlow 	rqp->nr_nmflags = 0;
2216007Sthurlow 	rqp->nr_qdname = &nn;
2226007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
2236007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2246007Sthurlow 	rqp->nr_qdcount = 1;
2256007Sthurlow 	rqp->nr_maxretry = 2;
2266007Sthurlow 
2276007Sthurlow 	/* LINTED */
2286007Sthurlow 	dest = (struct sockaddr_in *)targethost;
2296007Sthurlow 	rqp->nr_dest = dest->sin_addr;
2306007Sthurlow 
2316007Sthurlow 	error = nbns_rq_prepare(rqp);
2326007Sthurlow 	if (error) {
2336007Sthurlow 		nbns_rq_done(rqp);
2346007Sthurlow 		return (error);
2356007Sthurlow 	}
2366007Sthurlow 
2376007Sthurlow 	/*
2386007Sthurlow 	 * Darwin had a loop here, allowing redirect, etc.
2396007Sthurlow 	 * but we only handle point-to-point for node status.
2406007Sthurlow 	 */
2416007Sthurlow 	error = nbns_rq(rqp);
2426007Sthurlow 	if (error)
2436007Sthurlow 		goto out;
2446007Sthurlow 	if (rqp->nr_rpancount == 0) {
2456007Sthurlow 		error = NBERROR(NBERR_HOSTNOTFOUND);
2466007Sthurlow 		goto out;
2476007Sthurlow 	}
2486007Sthurlow 	error = nbns_rq_getrr(rqp, &rr);
2496007Sthurlow 	if (error)
2506007Sthurlow 		goto out;
2516007Sthurlow 
2526007Sthurlow 	/* Compiler didn't like cast on lvalue++ */
2536007Sthurlow 	nrcount = *((unsigned char *)rr.rr_data);
2546007Sthurlow 	rr.rr_data++;
2556007Sthurlow 	/* LINTED */
2566007Sthurlow 	for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
2576007Sthurlow 	    i <= nrcount; ++i, ++nrp) {
2586007Sthurlow 		nrtype = nrp->ns_name[NB_NAMELEN-1];
2596007Sthurlow 		/* Terminate the string: */
2606007Sthurlow 		nrp->ns_name[NB_NAMELEN-1] = (char)0;
2616007Sthurlow 		/* Strip off trailing spaces */
2626007Sthurlow 		for (cp = &nrp->ns_name[NB_NAMELEN-2];
2636007Sthurlow 		    cp >= nrp->ns_name; --cp) {
2646007Sthurlow 			if (*cp != (char)0x20)
2656007Sthurlow 				break;
2666007Sthurlow 			*cp = (char)0;
2676007Sthurlow 		}
2686007Sthurlow 		nrp->ns_flags = ntohs(nrp->ns_flags);
2696007Sthurlow 		if (nrp->ns_flags & NBNS_GROUPFLG) {
2706007Sthurlow 			if (!foundgroup ||
2716007Sthurlow 			    (foundgroup != NBT_WKSTA+1 &&
2726007Sthurlow 			    nrtype == NBT_WKSTA)) {
2736007Sthurlow 				smb_optstrncpy(workgroup, nrp->ns_name,
2746007Sthurlow 				    SMB_MAXUSERNAMELEN);
2756007Sthurlow 				foundgroup = nrtype+1;
2766007Sthurlow 			}
2776007Sthurlow 		} else {
2786007Sthurlow 			/*
2796007Sthurlow 			 * Track at least ONE name, in case
2806007Sthurlow 			 * no server name is found
2816007Sthurlow 			 */
2826007Sthurlow 			retname = nrp->ns_name;
2836007Sthurlow 		}
2846007Sthurlow 		if (nrtype == NBT_SERVER) {
2856007Sthurlow 			smb_optstrncpy(system, nrp->ns_name,
2866007Sthurlow 			    SMB_MAXSRVNAMELEN);
2876007Sthurlow 			foundserver = 1;
2886007Sthurlow 		}
2896007Sthurlow 	}
2906007Sthurlow 	if (!foundserver)
2916007Sthurlow 		smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
2926007Sthurlow 	ctx->nb_lastns = rqp->nr_sender;
2936007Sthurlow 
2946007Sthurlow out:
2956007Sthurlow 	nbns_rq_done(rqp);
2966007Sthurlow 	return (error);
2976007Sthurlow }
2986007Sthurlow 
2996007Sthurlow int
3006007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
3016007Sthurlow {
3026007Sthurlow 	struct nbns_rq *rqp;
3036007Sthurlow 	static uint16_t trnid;
3046007Sthurlow 	int error;
3056007Sthurlow 
3066007Sthurlow 	if (trnid == 0)
3076007Sthurlow 		trnid = getpid();
3086007Sthurlow 	rqp = malloc(sizeof (*rqp));
3096007Sthurlow 	if (rqp == NULL)
3106007Sthurlow 		return (ENOMEM);
3116007Sthurlow 	bzero(rqp, sizeof (*rqp));
3126007Sthurlow 	error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
3136007Sthurlow 	if (error) {
3146007Sthurlow 		free(rqp);
3156007Sthurlow 		return (error);
3166007Sthurlow 	}
3176007Sthurlow 	rqp->nr_opcode = opcode;
3186007Sthurlow 	rqp->nr_nbd = ctx;
3196007Sthurlow 	rqp->nr_trnid = trnid++;
3206007Sthurlow 	*rqpp = rqp;
3216007Sthurlow 	return (0);
3226007Sthurlow }
3236007Sthurlow 
3246007Sthurlow void
3256007Sthurlow nbns_rq_done(struct nbns_rq *rqp)
3266007Sthurlow {
3276007Sthurlow 	if (rqp == NULL)
3286007Sthurlow 		return;
3296007Sthurlow 	if (rqp->nr_fd >= 0)
3306007Sthurlow 		close(rqp->nr_fd);
3316007Sthurlow 	mb_done(&rqp->nr_rq);
3326007Sthurlow 	mb_done(&rqp->nr_rp);
3336007Sthurlow 	if (rqp->nr_if)
3346007Sthurlow 		free(rqp->nr_if);
3356007Sthurlow 	free(rqp);
3366007Sthurlow }
3376007Sthurlow 
3386007Sthurlow /*
3396007Sthurlow  * Extract resource record from the packet. Assume that there is only
3406007Sthurlow  * one mbuf.
3416007Sthurlow  */
3426007Sthurlow int
3436007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
3446007Sthurlow {
3456007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
3466007Sthurlow 	uchar_t *cp;
3476007Sthurlow 	int error, len;
3486007Sthurlow 
3496007Sthurlow 	bzero(rrp, sizeof (*rrp));
3506007Sthurlow 	cp = (uchar_t *)mbp->mb_pos;
3516007Sthurlow 	len = nb_encname_len(cp);
3526007Sthurlow 	if (len < 1)
3536007Sthurlow 		return (NBERROR(NBERR_INVALIDRESPONSE));
3546007Sthurlow 	rrp->rr_name = cp;
3556007Sthurlow 	error = mb_get_mem(mbp, NULL, len);
3566007Sthurlow 	if (error)
3576007Sthurlow 		return (error);
3586007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_type);
3596007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_class);
3606007Sthurlow 	mb_get_uint32be(mbp, &rrp->rr_ttl);
3616007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_rdlength);
3626007Sthurlow 	rrp->rr_data = (uchar_t *)mbp->mb_pos;
3636007Sthurlow 	error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
3646007Sthurlow 	return (error);
3656007Sthurlow }
3666007Sthurlow 
3676007Sthurlow int
3686007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp)
3696007Sthurlow {
3706007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
3716007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
3726007Sthurlow 	uint16_t ofr; /* opcode, flags, rcode */
3736007Sthurlow 	uchar_t *cp;
3746007Sthurlow 	int len, error;
3756007Sthurlow 
3766007Sthurlow 	/*
3776007Sthurlow 	 * Replacing with one argument.
3786007Sthurlow 	 * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
3796007Sthurlow 	 */
3806007Sthurlow 	error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
3816007Sthurlow 	if (error)
3826007Sthurlow 		return (error);
3836007Sthurlow 
3846007Sthurlow 	/*
3856007Sthurlow 	 * When looked into the ethereal trace, 'nmblookup' command sets this
3866007Sthurlow 	 * flag. We will also set.
3876007Sthurlow 	 */
3886007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_trnid);
3896007Sthurlow 	ofr = ((rqp->nr_opcode & 0x1F) << 11) |
3906007Sthurlow 	    ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
3916007Sthurlow 	mb_put_uint16be(mbp, ofr);
3926007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_qdcount);
3936007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_ancount);
3946007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_nscount);
3956007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_arcount);
3966007Sthurlow 	if (rqp->nr_qdcount) {
3976007Sthurlow 		if (rqp->nr_qdcount > 1)
3986007Sthurlow 			return (EINVAL);
3996007Sthurlow 		len = nb_name_len(rqp->nr_qdname);
4006007Sthurlow 		error = mb_fit(mbp, len, (char **)&cp);
4016007Sthurlow 		if (error)
4026007Sthurlow 			return (error);
4036007Sthurlow 		nb_name_encode(rqp->nr_qdname, cp);
4046007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdtype);
4056007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdclass);
4066007Sthurlow 	}
4076007Sthurlow 	m_lineup(mbp->mb_top, &mbp->mb_top);
4086007Sthurlow 	if (ctx->nb_timo == 0)
4096007Sthurlow 		ctx->nb_timo = 1;	/* by default 1 second */
4106007Sthurlow 	return (0);
4116007Sthurlow }
4126007Sthurlow 
4136007Sthurlow static int
4146007Sthurlow nbns_rq_recv(struct nbns_rq *rqp)
4156007Sthurlow {
4166007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
4176007Sthurlow 	void *rpdata = mtod(mbp->mb_top, void *);
4186007Sthurlow 	fd_set rd, wr, ex;
4196007Sthurlow 	struct timeval tv;
4206007Sthurlow 	struct sockaddr_in sender;
4216007Sthurlow 	int s = rqp->nr_fd;
4226007Sthurlow 	int n, len;
4236007Sthurlow 
4246007Sthurlow 	FD_ZERO(&rd);
4256007Sthurlow 	FD_ZERO(&wr);
4266007Sthurlow 	FD_ZERO(&ex);
4276007Sthurlow 	FD_SET(s, &rd);
4286007Sthurlow 
4296007Sthurlow 	tv.tv_sec = rqp->nr_nbd->nb_timo;
4306007Sthurlow 	tv.tv_usec = 0;
4316007Sthurlow 
4326007Sthurlow 	n = select(s + 1, &rd, &wr, &ex, &tv);
4336007Sthurlow 	if (n == -1)
4346007Sthurlow 		return (-1);
4356007Sthurlow 	if (n == 0)
4366007Sthurlow 		return (ETIMEDOUT);
4376007Sthurlow 	if (FD_ISSET(s, &rd) == 0)
4386007Sthurlow 		return (ETIMEDOUT);
4396007Sthurlow 	len = sizeof (sender);
4406007Sthurlow 	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
4416007Sthurlow 	    (struct sockaddr *)&sender, &len);
4426007Sthurlow 	if (n < 0)
4436007Sthurlow 		return (errno);
4446007Sthurlow 	mbp->mb_top->m_len = mbp->mb_count = n;
4456007Sthurlow 	rqp->nr_sender = sender;
4466007Sthurlow 	return (0);
4476007Sthurlow }
4486007Sthurlow 
4496007Sthurlow static int
4506007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp)
4516007Sthurlow {
4526007Sthurlow 	struct sockaddr_in locaddr;
4536007Sthurlow 	int opt = 1, s;
4546007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
4556007Sthurlow 
4566007Sthurlow 	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
4576007Sthurlow 	if (s < 0)
4586007Sthurlow 		return (errno);
4596007Sthurlow 	if (ctx->nb_flags & NBCF_BC_ENABLE) {
4606007Sthurlow 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
4616007Sthurlow 		    sizeof (opt)) < 0)
4626007Sthurlow 			return (errno);
4636007Sthurlow 	}
4646007Sthurlow 	if (is_system_labeled())
4656007Sthurlow 		(void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
4666007Sthurlow 		    sizeof (opt));
4676007Sthurlow 	bzero(&locaddr, sizeof (locaddr));
4686007Sthurlow 	locaddr.sin_family = AF_INET;
4696007Sthurlow 	/* locaddr.sin_len = sizeof (locaddr); */
4706007Sthurlow 	if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
4716007Sthurlow 		return (errno);
4726007Sthurlow 	return (0);
4736007Sthurlow }
4746007Sthurlow 
4756007Sthurlow static int
4766007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
4776007Sthurlow {
4786007Sthurlow 	struct sockaddr_in dest;
4796007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
4806007Sthurlow 	int s = rqp->nr_fd;
4816007Sthurlow 	uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
4826007Sthurlow 	uint16_t *datap;
4836007Sthurlow 	uint8_t nmflags;
4846007Sthurlow 	int rc;
4856007Sthurlow 
4866007Sthurlow 	bzero(&dest, sizeof (dest));
4876007Sthurlow 	dest.sin_family = AF_INET;
4886007Sthurlow 	dest.sin_port = htons(NBNS_UDP_PORT);
4896007Sthurlow 	dest.sin_addr.s_addr = ina;
4906007Sthurlow 
4916007Sthurlow 	if (ina == INADDR_BROADCAST) {
4926007Sthurlow 		/* Turn on the broadcast bit. */
4936007Sthurlow 		nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
4946007Sthurlow 		/*LINTED*/
4956007Sthurlow 		datap = mtod(mbp->mb_top, uint16_t *);
4966007Sthurlow 		ofr = ((rqp->nr_opcode & 0x1F) << 11) |
4976007Sthurlow 		    ((nmflags & 0x7F) << 4); /* rcode=0 */
4986007Sthurlow 		ofr_save = datap[1];
4996007Sthurlow 		datap[1] = htons(ofr);
5006007Sthurlow 	}
5016007Sthurlow 
5026007Sthurlow 	rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
5036007Sthurlow 	    (struct sockaddr *)&dest, sizeof (dest));
5046007Sthurlow 
5056007Sthurlow 	if (ina == INADDR_BROADCAST) {
5066007Sthurlow 		/* Turn the broadcast bit back off. */
5076007Sthurlow 		datap[1] = ofr_save;
5086007Sthurlow 	}
5096007Sthurlow 
5106007Sthurlow 
5116007Sthurlow 	if (rc < 0)
5126007Sthurlow 		return (errno);
5136007Sthurlow 
5146007Sthurlow 	return (0);
5156007Sthurlow }
5166007Sthurlow 
5176007Sthurlow int
5186007Sthurlow nbns_rq(struct nbns_rq *rqp)
5196007Sthurlow {
5206007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
5216007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
5226007Sthurlow 	uint16_t ofr, rpid;
5236007Sthurlow 	uint8_t nmflags;
5246007Sthurlow 	int error, tries, maxretry;
5256007Sthurlow 
5266007Sthurlow 	error = nbns_rq_opensocket(rqp);
5276007Sthurlow 	if (error)
5286007Sthurlow 		return (error);
5296007Sthurlow 
5306007Sthurlow 	maxretry = rqp->nr_maxretry;
5316007Sthurlow 	for (tries = 0; tries < maxretry; tries++) {
5326007Sthurlow 
5336007Sthurlow 		/*
5346007Sthurlow 		 * Minor hack: If nr_dest is set, send there only.
5356007Sthurlow 		 * Used by _getnodestatus, _resolvname redirects.
5366007Sthurlow 		 */
5376007Sthurlow 		if (rqp->nr_dest.s_addr) {
5386007Sthurlow 			error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
5396007Sthurlow 			if (error) {
5406007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
5416007Sthurlow 				    "nbns error %d sending to %s"),
5426007Sthurlow 				    0, error, inet_ntoa(rqp->nr_dest));
5436007Sthurlow 			}
5446007Sthurlow 			goto do_recv;
5456007Sthurlow 		}
5466007Sthurlow 
5476007Sthurlow 		if (ctx->nb_wins1) {
5486007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins1);
5496007Sthurlow 			if (error) {
5506007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
5516007Sthurlow 				    "nbns error %d sending to wins1"),
5526007Sthurlow 				    0, error);
5536007Sthurlow 			}
5546007Sthurlow 		}
5556007Sthurlow 
5566007Sthurlow 		if (ctx->nb_wins2 && (tries > 0)) {
5576007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins2);
5586007Sthurlow 			if (error) {
5596007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
5606007Sthurlow 				    "nbns error %d sending to wins2"),
5616007Sthurlow 				    0, error);
5626007Sthurlow 			}
5636007Sthurlow 		}
5646007Sthurlow 
5656007Sthurlow 		/*
5666007Sthurlow 		 * If broadcast is enabled, start broadcasting
5676007Sthurlow 		 * only after wins servers fail to respond, or
5686007Sthurlow 		 * immediately if no WINS servers configured.
5696007Sthurlow 		 */
5706007Sthurlow 		if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
5716007Sthurlow 		    ((tries > 1) || (ctx->nb_wins1 == 0))) {
5726007Sthurlow 			error = nbns_rq_send(rqp, INADDR_BROADCAST);
5736007Sthurlow 			if (error) {
5746007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
5756007Sthurlow 				    "nbns error %d sending broadcast"),
5766007Sthurlow 				    0, error);
5776007Sthurlow 			}
5786007Sthurlow 		}
5796007Sthurlow 
5806007Sthurlow 		/*
5816007Sthurlow 		 * Wait for responses from ANY of the above.
5826007Sthurlow 		 */
5836007Sthurlow do_recv:
5846007Sthurlow 		error = nbns_rq_recv(rqp);
5856007Sthurlow 		if (error == ETIMEDOUT)
5866007Sthurlow 			continue;
5876007Sthurlow 		if (error) {
5886007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
5896007Sthurlow 			    "nbns recv error %d"),
5906007Sthurlow 			    0, error);
5916007Sthurlow 			return (error);
5926007Sthurlow 		}
5936007Sthurlow 
5946007Sthurlow 		mbp = &rqp->nr_rp;
5956007Sthurlow 		if (mbp->mb_count < 12)
5966007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
5976007Sthurlow 		mb_get_uint16be(mbp, &rpid);
5986007Sthurlow 		if (rpid != rqp->nr_trnid)
5996007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
6006007Sthurlow 		break;
6016007Sthurlow 	}
6026007Sthurlow 
6036007Sthurlow 	mb_get_uint16be(mbp, &ofr);
6046007Sthurlow 	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
6056007Sthurlow 	rqp->nr_rprcode = ofr & 0xf;
6066007Sthurlow 	if (rqp->nr_rprcode)
6076007Sthurlow 		return (NBERROR(rqp->nr_rprcode));
6086007Sthurlow 	mb_get_uint16be(mbp, &rpid);	/* QDCOUNT */
6096007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpancount);
6106007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpnscount);
6116007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rparcount);
6126007Sthurlow 	return (0);
6136007Sthurlow }
614