xref: /onnv-gate/usr/src/lib/libsmbfs/smb/nbns_rq.c (revision 10023:71bf38dba3d6)
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*10023SGordon.Ross@Sun.COM #include "charsets.h"
598271SGordon.Ross@Sun.COM #include "private.h"
608271SGordon.Ross@Sun.COM 
618271SGordon.Ross@Sun.COM /*
628271SGordon.Ross@Sun.COM  * nbns request
638271SGordon.Ross@Sun.COM  */
648271SGordon.Ross@Sun.COM struct nbns_rq {
658271SGordon.Ross@Sun.COM 	int		nr_opcode;
668271SGordon.Ross@Sun.COM 	int		nr_nmflags;
678271SGordon.Ross@Sun.COM 	int		nr_rcode;
688271SGordon.Ross@Sun.COM 	int		nr_qdcount;
698271SGordon.Ross@Sun.COM 	int		nr_ancount;
708271SGordon.Ross@Sun.COM 	int		nr_nscount;
718271SGordon.Ross@Sun.COM 	int		nr_arcount;
728271SGordon.Ross@Sun.COM 	struct nb_name	*nr_qdname;
738271SGordon.Ross@Sun.COM 	uint16_t	nr_qdtype;
748271SGordon.Ross@Sun.COM 	uint16_t	nr_qdclass;
758271SGordon.Ross@Sun.COM 	struct in_addr	nr_dest;	/* receiver of query */
768271SGordon.Ross@Sun.COM 	struct sockaddr_in nr_sender;	/* sender of response */
778271SGordon.Ross@Sun.COM 	int		nr_rpnmflags;
788271SGordon.Ross@Sun.COM 	int		nr_rprcode;
798271SGordon.Ross@Sun.COM 	uint16_t	nr_rpancount;
808271SGordon.Ross@Sun.COM 	uint16_t	nr_rpnscount;
818271SGordon.Ross@Sun.COM 	uint16_t	nr_rparcount;
828271SGordon.Ross@Sun.COM 	uint16_t	nr_trnid;
838271SGordon.Ross@Sun.COM 	struct nb_ctx	*nr_nbd;
848271SGordon.Ross@Sun.COM 	struct mbdata	nr_rq;
858271SGordon.Ross@Sun.COM 	struct mbdata	nr_rp;
868271SGordon.Ross@Sun.COM 	struct nb_ifdesc *nr_if;
878271SGordon.Ross@Sun.COM 	int		nr_flags;
888271SGordon.Ross@Sun.COM 	int		nr_fd;
898271SGordon.Ross@Sun.COM 	int		nr_maxretry;
908271SGordon.Ross@Sun.COM };
918271SGordon.Ross@Sun.COM typedef struct nbns_rq nbns_rq_t;
928271SGordon.Ross@Sun.COM 
936007Sthurlow static int  nbns_rq_create(int opcode, struct nb_ctx *ctx,
946007Sthurlow     struct nbns_rq **rqpp);
956007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp);
966007Sthurlow static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
976007Sthurlow static int  nbns_rq_prepare(struct nbns_rq *rqp);
986007Sthurlow static int  nbns_rq(struct nbns_rq *rqp);
996007Sthurlow 
100*10023SGordon.Ross@Sun.COM /*
101*10023SGordon.Ross@Sun.COM  * Call NetBIOS name lookup and return a result in the
102*10023SGordon.Ross@Sun.COM  * same form as getaddrinfo(3) returns.  Return code is
103*10023SGordon.Ross@Sun.COM  * zero or one of the EAI_xxx codes like getaddrinfo.
104*10023SGordon.Ross@Sun.COM  */
105*10023SGordon.Ross@Sun.COM int
106*10023SGordon.Ross@Sun.COM nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
107*10023SGordon.Ross@Sun.COM {
108*10023SGordon.Ross@Sun.COM 	struct addrinfo *nai = NULL;
109*10023SGordon.Ross@Sun.COM 	struct sockaddr *sap = NULL;
110*10023SGordon.Ross@Sun.COM 	char *ucname = NULL;
111*10023SGordon.Ross@Sun.COM 	int err;
112*10023SGordon.Ross@Sun.COM 
113*10023SGordon.Ross@Sun.COM 	/*
114*10023SGordon.Ross@Sun.COM 	 * Try NetBIOS name lookup.
115*10023SGordon.Ross@Sun.COM 	 */
116*10023SGordon.Ross@Sun.COM 	if (strlen(name) >= NB_NAMELEN) {
117*10023SGordon.Ross@Sun.COM 		err = EAI_OVERFLOW;
118*10023SGordon.Ross@Sun.COM 		goto out;
119*10023SGordon.Ross@Sun.COM 	}
120*10023SGordon.Ross@Sun.COM 	ucname = utf8_str_toupper(name);
121*10023SGordon.Ross@Sun.COM 	if (ucname == NULL)
122*10023SGordon.Ross@Sun.COM 		goto nomem;
123*10023SGordon.Ross@Sun.COM 
124*10023SGordon.Ross@Sun.COM 	/* Note: this returns an NBERROR value. */
125*10023SGordon.Ross@Sun.COM 	err = nbns_resolvename(ucname, nbc, &sap);
126*10023SGordon.Ross@Sun.COM 	if (err) {
127*10023SGordon.Ross@Sun.COM 		if (smb_verbose)
128*10023SGordon.Ross@Sun.COM 			smb_error(dgettext(TEXT_DOMAIN,
129*10023SGordon.Ross@Sun.COM 			    "nbns_resolvename: %s"),
130*10023SGordon.Ross@Sun.COM 			    err, name);
131*10023SGordon.Ross@Sun.COM 		err = EAI_NODATA;
132*10023SGordon.Ross@Sun.COM 		goto out;
133*10023SGordon.Ross@Sun.COM 	}
134*10023SGordon.Ross@Sun.COM 	/* Note: sap allocated */
135*10023SGordon.Ross@Sun.COM 
136*10023SGordon.Ross@Sun.COM 	/*
137*10023SGordon.Ross@Sun.COM 	 * Build the addrinfo struct to return.
138*10023SGordon.Ross@Sun.COM 	 */
139*10023SGordon.Ross@Sun.COM 	nai = malloc(sizeof (*nai));
140*10023SGordon.Ross@Sun.COM 	if (nai == NULL)
141*10023SGordon.Ross@Sun.COM 		goto nomem;
142*10023SGordon.Ross@Sun.COM 	bzero(nai, sizeof (*nai));
143*10023SGordon.Ross@Sun.COM 
144*10023SGordon.Ross@Sun.COM 	nai->ai_flags = AI_CANONNAME;
145*10023SGordon.Ross@Sun.COM 	nai->ai_family = sap->sa_family;
146*10023SGordon.Ross@Sun.COM 	nai->ai_socktype = SOCK_STREAM;
147*10023SGordon.Ross@Sun.COM 	nai->ai_canonname = ucname;
148*10023SGordon.Ross@Sun.COM 	ucname = NULL;
149*10023SGordon.Ross@Sun.COM 
150*10023SGordon.Ross@Sun.COM 	/*
151*10023SGordon.Ross@Sun.COM 	 * The type of this is really sockaddr_in,
152*10023SGordon.Ross@Sun.COM 	 * but is returned in the generic form.
153*10023SGordon.Ross@Sun.COM 	 * See nbns_resolvename.
154*10023SGordon.Ross@Sun.COM 	 */
155*10023SGordon.Ross@Sun.COM 	nai->ai_addrlen = sizeof (struct sockaddr_in);
156*10023SGordon.Ross@Sun.COM 	nai->ai_addr = sap;
157*10023SGordon.Ross@Sun.COM 
158*10023SGordon.Ross@Sun.COM 	*res = nai;
159*10023SGordon.Ross@Sun.COM 	return (0);
160*10023SGordon.Ross@Sun.COM 
161*10023SGordon.Ross@Sun.COM nomem:
162*10023SGordon.Ross@Sun.COM 	err = EAI_MEMORY;
163*10023SGordon.Ross@Sun.COM out:
164*10023SGordon.Ross@Sun.COM 	if (nai != NULL)
165*10023SGordon.Ross@Sun.COM 		free(nai);
166*10023SGordon.Ross@Sun.COM 	if (sap)
167*10023SGordon.Ross@Sun.COM 		free(sap);
168*10023SGordon.Ross@Sun.COM 	if (ucname)
169*10023SGordon.Ross@Sun.COM 		free(ucname);
170*10023SGordon.Ross@Sun.COM 	*res = NULL;
171*10023SGordon.Ross@Sun.COM 
172*10023SGordon.Ross@Sun.COM 	return (err);
173*10023SGordon.Ross@Sun.COM }
1746007Sthurlow 
1756007Sthurlow int
1766007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
1776007Sthurlow {
1786007Sthurlow 	struct nbns_rq *rqp;
1796007Sthurlow 	struct nb_name nn;
1806007Sthurlow 	struct nbns_rr rr;
1816007Sthurlow 	struct sockaddr_in *dest;
1826007Sthurlow 	int error, rdrcount, len;
1836007Sthurlow 
184*10023SGordon.Ross@Sun.COM 	if (strlen(name) >= NB_NAMELEN)
1856007Sthurlow 		return (NBERROR(NBERR_NAMETOOLONG));
1866007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
1876007Sthurlow 	if (error)
1886007Sthurlow 		return (error);
1896007Sthurlow 	/*
1906007Sthurlow 	 * Pad the name with blanks, but
1916007Sthurlow 	 * leave the "type" byte NULL.
1926007Sthurlow 	 * nb_name_encode adds the type.
1936007Sthurlow 	 */
1946007Sthurlow 	bzero(&nn, sizeof (nn));
1956007Sthurlow 	snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
1966007Sthurlow 	nn.nn_type = NBT_SERVER;
1976007Sthurlow 	nn.nn_scope = ctx->nb_scope;
1986007Sthurlow 	rqp->nr_nmflags = NBNS_NMFLAG_RD;
1996007Sthurlow 	rqp->nr_qdname = &nn;
2006007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
2016007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2026007Sthurlow 	rqp->nr_qdcount = 1;
2036007Sthurlow 	rqp->nr_maxretry = 5;
2046007Sthurlow 
2056007Sthurlow 	error = nbns_rq_prepare(rqp);
2066007Sthurlow 	if (error) {
2076007Sthurlow 		nbns_rq_done(rqp);
2086007Sthurlow 		return (error);
2096007Sthurlow 	}
2106007Sthurlow 	rdrcount = NBNS_MAXREDIRECTS;
2116007Sthurlow 	for (;;) {
2126007Sthurlow 		error = nbns_rq(rqp);
2136007Sthurlow 		if (error)
2146007Sthurlow 			break;
2156007Sthurlow 		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
2166007Sthurlow 			/*
2176007Sthurlow 			 * Not an authoritative answer.  Query again
2186007Sthurlow 			 * using the NS address in the 2nd record.
2196007Sthurlow 			 */
2206007Sthurlow 			if (rdrcount-- == 0) {
2216007Sthurlow 				error = NBERROR(NBERR_TOOMANYREDIRECTS);
2226007Sthurlow 				break;
2236007Sthurlow 			}
2246007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
2256007Sthurlow 			if (error)
2266007Sthurlow 				break;
2276007Sthurlow 			error = nbns_rq_getrr(rqp, &rr);
2286007Sthurlow 			if (error)
2296007Sthurlow 				break;
2306007Sthurlow 			bcopy(rr.rr_data, &rqp->nr_dest, 4);
2316007Sthurlow 			continue;
2326007Sthurlow 		}
2336007Sthurlow 		if (rqp->nr_rpancount == 0) {
2346007Sthurlow 			error = NBERROR(NBERR_HOSTNOTFOUND);
2356007Sthurlow 			break;
2366007Sthurlow 		}
2376007Sthurlow 		error = nbns_rq_getrr(rqp, &rr);
2386007Sthurlow 		if (error)
2396007Sthurlow 			break;
2406007Sthurlow 		len = sizeof (struct sockaddr_in);
2416007Sthurlow 		dest = malloc(len);
2426007Sthurlow 		if (dest == NULL)
2436007Sthurlow 			return (ENOMEM);
2446007Sthurlow 		bzero(dest, len);
2456007Sthurlow 		/*
246*10023SGordon.Ross@Sun.COM 		 * Solaris sockaddr_in doesn't a sin_len field.
2476007Sthurlow 		 * dest->sin_len = len;
2486007Sthurlow 		 */
249*10023SGordon.Ross@Sun.COM 		dest->sin_family = AF_NETBIOS;	/* nb_lib.h */
2506007Sthurlow 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
2516007Sthurlow 		*adpp = (struct sockaddr *)dest;
2526007Sthurlow 		ctx->nb_lastns = rqp->nr_sender;
2536007Sthurlow 		break;
2546007Sthurlow 	}
2556007Sthurlow 	nbns_rq_done(rqp);
2566007Sthurlow 	return (error);
2576007Sthurlow }
2586007Sthurlow 
259*10023SGordon.Ross@Sun.COM /*
260*10023SGordon.Ross@Sun.COM  * NB: system, workgroup are both NB_NAMELEN
261*10023SGordon.Ross@Sun.COM  */
2626007Sthurlow int
263*10023SGordon.Ross@Sun.COM nbns_getnodestatus(struct nb_ctx *ctx,
264*10023SGordon.Ross@Sun.COM     struct in_addr *targethost, char *system, char *workgroup)
2656007Sthurlow {
2666007Sthurlow 	struct nbns_rq *rqp;
2676007Sthurlow 	struct nbns_rr rr;
2686007Sthurlow 	struct nb_name nn;
2696007Sthurlow 	struct nbns_nr *nrp;
2706007Sthurlow 	char nrtype;
2716007Sthurlow 	char *cp, *retname = NULL;
2726007Sthurlow 	unsigned char nrcount;
273*10023SGordon.Ross@Sun.COM 	int error, i, foundserver = 0, foundgroup = 0;
2746007Sthurlow 
2756007Sthurlow 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
2766007Sthurlow 	if (error)
2776007Sthurlow 		return (error);
2786007Sthurlow 	bzero(&nn, sizeof (nn));
2796007Sthurlow 	strcpy((char *)nn.nn_name, "*");
2806007Sthurlow 	nn.nn_scope = ctx->nb_scope;
2816007Sthurlow 	nn.nn_type = NBT_WKSTA;
2826007Sthurlow 	rqp->nr_nmflags = 0;
2836007Sthurlow 	rqp->nr_qdname = &nn;
2846007Sthurlow 	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
2856007Sthurlow 	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2866007Sthurlow 	rqp->nr_qdcount = 1;
2876007Sthurlow 	rqp->nr_maxretry = 2;
2886007Sthurlow 
289*10023SGordon.Ross@Sun.COM 	rqp->nr_dest = *targethost;
2906007Sthurlow 	error = nbns_rq_prepare(rqp);
2916007Sthurlow 	if (error) {
2926007Sthurlow 		nbns_rq_done(rqp);
2936007Sthurlow 		return (error);
2946007Sthurlow 	}
2956007Sthurlow 
2966007Sthurlow 	/*
2976007Sthurlow 	 * Darwin had a loop here, allowing redirect, etc.
2986007Sthurlow 	 * but we only handle point-to-point for node status.
2996007Sthurlow 	 */
3006007Sthurlow 	error = nbns_rq(rqp);
3016007Sthurlow 	if (error)
3026007Sthurlow 		goto out;
3036007Sthurlow 	if (rqp->nr_rpancount == 0) {
3046007Sthurlow 		error = NBERROR(NBERR_HOSTNOTFOUND);
3056007Sthurlow 		goto out;
3066007Sthurlow 	}
3076007Sthurlow 	error = nbns_rq_getrr(rqp, &rr);
3086007Sthurlow 	if (error)
3096007Sthurlow 		goto out;
3106007Sthurlow 
3116007Sthurlow 	/* Compiler didn't like cast on lvalue++ */
3126007Sthurlow 	nrcount = *((unsigned char *)rr.rr_data);
3136007Sthurlow 	rr.rr_data++;
3146007Sthurlow 	/* LINTED */
3156007Sthurlow 	for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
3166007Sthurlow 	    i <= nrcount; ++i, ++nrp) {
3176007Sthurlow 		nrtype = nrp->ns_name[NB_NAMELEN-1];
3186007Sthurlow 		/* Terminate the string: */
3196007Sthurlow 		nrp->ns_name[NB_NAMELEN-1] = (char)0;
3206007Sthurlow 		/* Strip off trailing spaces */
3216007Sthurlow 		for (cp = &nrp->ns_name[NB_NAMELEN-2];
3226007Sthurlow 		    cp >= nrp->ns_name; --cp) {
3236007Sthurlow 			if (*cp != (char)0x20)
3246007Sthurlow 				break;
3256007Sthurlow 			*cp = (char)0;
3266007Sthurlow 		}
3276007Sthurlow 		nrp->ns_flags = ntohs(nrp->ns_flags);
328*10023SGordon.Ross@Sun.COM 		DPRINT(" %s[%02x] Flags 0x%x",
329*10023SGordon.Ross@Sun.COM 		    nrp->ns_name, nrtype, nrp->ns_flags);
3306007Sthurlow 		if (nrp->ns_flags & NBNS_GROUPFLG) {
3316007Sthurlow 			if (!foundgroup ||
3326007Sthurlow 			    (foundgroup != NBT_WKSTA+1 &&
3336007Sthurlow 			    nrtype == NBT_WKSTA)) {
334*10023SGordon.Ross@Sun.COM 				strlcpy(workgroup, nrp->ns_name,
335*10023SGordon.Ross@Sun.COM 				    NB_NAMELEN);
3366007Sthurlow 				foundgroup = nrtype+1;
3376007Sthurlow 			}
3386007Sthurlow 		} else {
3396007Sthurlow 			/*
3406007Sthurlow 			 * Track at least ONE name, in case
3416007Sthurlow 			 * no server name is found
3426007Sthurlow 			 */
3436007Sthurlow 			retname = nrp->ns_name;
3446007Sthurlow 		}
345*10023SGordon.Ross@Sun.COM 		/*
346*10023SGordon.Ross@Sun.COM 		 * Keep the first NBT_SERVER name.
347*10023SGordon.Ross@Sun.COM 		 */
348*10023SGordon.Ross@Sun.COM 		if (nrtype == NBT_SERVER && foundserver == 0) {
349*10023SGordon.Ross@Sun.COM 			strlcpy(system, nrp->ns_name,
350*10023SGordon.Ross@Sun.COM 			    NB_NAMELEN);
3516007Sthurlow 			foundserver = 1;
3526007Sthurlow 		}
3536007Sthurlow 	}
3546007Sthurlow 	if (!foundserver)
355*10023SGordon.Ross@Sun.COM 		strlcpy(system, retname, NB_NAMELEN);
3566007Sthurlow 	ctx->nb_lastns = rqp->nr_sender;
3576007Sthurlow 
3586007Sthurlow out:
3596007Sthurlow 	nbns_rq_done(rqp);
3606007Sthurlow 	return (error);
3616007Sthurlow }
3626007Sthurlow 
3636007Sthurlow int
3646007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
3656007Sthurlow {
3666007Sthurlow 	struct nbns_rq *rqp;
3676007Sthurlow 	static uint16_t trnid;
3686007Sthurlow 	int error;
3696007Sthurlow 
3706007Sthurlow 	if (trnid == 0)
3716007Sthurlow 		trnid = getpid();
3726007Sthurlow 	rqp = malloc(sizeof (*rqp));
3736007Sthurlow 	if (rqp == NULL)
3746007Sthurlow 		return (ENOMEM);
3756007Sthurlow 	bzero(rqp, sizeof (*rqp));
3766007Sthurlow 	error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
3776007Sthurlow 	if (error) {
3786007Sthurlow 		free(rqp);
3796007Sthurlow 		return (error);
3806007Sthurlow 	}
3816007Sthurlow 	rqp->nr_opcode = opcode;
3826007Sthurlow 	rqp->nr_nbd = ctx;
3836007Sthurlow 	rqp->nr_trnid = trnid++;
3846007Sthurlow 	*rqpp = rqp;
3856007Sthurlow 	return (0);
3866007Sthurlow }
3876007Sthurlow 
3886007Sthurlow void
3896007Sthurlow nbns_rq_done(struct nbns_rq *rqp)
3906007Sthurlow {
3916007Sthurlow 	if (rqp == NULL)
3926007Sthurlow 		return;
3936007Sthurlow 	if (rqp->nr_fd >= 0)
3946007Sthurlow 		close(rqp->nr_fd);
3956007Sthurlow 	mb_done(&rqp->nr_rq);
3966007Sthurlow 	mb_done(&rqp->nr_rp);
3976007Sthurlow 	if (rqp->nr_if)
3986007Sthurlow 		free(rqp->nr_if);
3996007Sthurlow 	free(rqp);
4006007Sthurlow }
4016007Sthurlow 
4026007Sthurlow /*
4036007Sthurlow  * Extract resource record from the packet. Assume that there is only
4046007Sthurlow  * one mbuf.
4056007Sthurlow  */
4066007Sthurlow int
4076007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
4086007Sthurlow {
4096007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
4106007Sthurlow 	uchar_t *cp;
4116007Sthurlow 	int error, len;
4126007Sthurlow 
4136007Sthurlow 	bzero(rrp, sizeof (*rrp));
4146007Sthurlow 	cp = (uchar_t *)mbp->mb_pos;
4156007Sthurlow 	len = nb_encname_len(cp);
4166007Sthurlow 	if (len < 1)
4176007Sthurlow 		return (NBERROR(NBERR_INVALIDRESPONSE));
4186007Sthurlow 	rrp->rr_name = cp;
4196007Sthurlow 	error = mb_get_mem(mbp, NULL, len);
4206007Sthurlow 	if (error)
4216007Sthurlow 		return (error);
4226007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_type);
4236007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_class);
4246007Sthurlow 	mb_get_uint32be(mbp, &rrp->rr_ttl);
4256007Sthurlow 	mb_get_uint16be(mbp, &rrp->rr_rdlength);
4266007Sthurlow 	rrp->rr_data = (uchar_t *)mbp->mb_pos;
4276007Sthurlow 	error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
4286007Sthurlow 	return (error);
4296007Sthurlow }
4306007Sthurlow 
4316007Sthurlow int
4326007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp)
4336007Sthurlow {
4346007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
4356007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
4366007Sthurlow 	uint16_t ofr; /* opcode, flags, rcode */
437*10023SGordon.Ross@Sun.COM 	int error;
4386007Sthurlow 
4396007Sthurlow 	/*
4406007Sthurlow 	 * Replacing with one argument.
4416007Sthurlow 	 * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
4426007Sthurlow 	 */
4436007Sthurlow 	error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
4446007Sthurlow 	if (error)
4456007Sthurlow 		return (error);
4466007Sthurlow 
4476007Sthurlow 	/*
4486007Sthurlow 	 * When looked into the ethereal trace, 'nmblookup' command sets this
4496007Sthurlow 	 * flag. We will also set.
4506007Sthurlow 	 */
4516007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_trnid);
4526007Sthurlow 	ofr = ((rqp->nr_opcode & 0x1F) << 11) |
4536007Sthurlow 	    ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
4546007Sthurlow 	mb_put_uint16be(mbp, ofr);
4556007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_qdcount);
4566007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_ancount);
4576007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_nscount);
4586007Sthurlow 	mb_put_uint16be(mbp, rqp->nr_arcount);
4596007Sthurlow 	if (rqp->nr_qdcount) {
4606007Sthurlow 		if (rqp->nr_qdcount > 1)
4616007Sthurlow 			return (EINVAL);
462*10023SGordon.Ross@Sun.COM 		nb_name_encode(mbp, rqp->nr_qdname);
4636007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdtype);
4646007Sthurlow 		mb_put_uint16be(mbp, rqp->nr_qdclass);
4656007Sthurlow 	}
4666007Sthurlow 	m_lineup(mbp->mb_top, &mbp->mb_top);
4676007Sthurlow 	if (ctx->nb_timo == 0)
4686007Sthurlow 		ctx->nb_timo = 1;	/* by default 1 second */
4696007Sthurlow 	return (0);
4706007Sthurlow }
4716007Sthurlow 
4726007Sthurlow static int
4736007Sthurlow nbns_rq_recv(struct nbns_rq *rqp)
4746007Sthurlow {
4756007Sthurlow 	struct mbdata *mbp = &rqp->nr_rp;
4766007Sthurlow 	void *rpdata = mtod(mbp->mb_top, void *);
4776007Sthurlow 	fd_set rd, wr, ex;
4786007Sthurlow 	struct timeval tv;
4796007Sthurlow 	struct sockaddr_in sender;
4806007Sthurlow 	int s = rqp->nr_fd;
4816007Sthurlow 	int n, len;
4826007Sthurlow 
4836007Sthurlow 	FD_ZERO(&rd);
4846007Sthurlow 	FD_ZERO(&wr);
4856007Sthurlow 	FD_ZERO(&ex);
4866007Sthurlow 	FD_SET(s, &rd);
4876007Sthurlow 
4886007Sthurlow 	tv.tv_sec = rqp->nr_nbd->nb_timo;
4896007Sthurlow 	tv.tv_usec = 0;
4906007Sthurlow 
4916007Sthurlow 	n = select(s + 1, &rd, &wr, &ex, &tv);
4926007Sthurlow 	if (n == -1)
4936007Sthurlow 		return (-1);
4946007Sthurlow 	if (n == 0)
4956007Sthurlow 		return (ETIMEDOUT);
4966007Sthurlow 	if (FD_ISSET(s, &rd) == 0)
4976007Sthurlow 		return (ETIMEDOUT);
4986007Sthurlow 	len = sizeof (sender);
4996007Sthurlow 	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
5006007Sthurlow 	    (struct sockaddr *)&sender, &len);
5016007Sthurlow 	if (n < 0)
5026007Sthurlow 		return (errno);
5036007Sthurlow 	mbp->mb_top->m_len = mbp->mb_count = n;
5046007Sthurlow 	rqp->nr_sender = sender;
5056007Sthurlow 	return (0);
5066007Sthurlow }
5076007Sthurlow 
5086007Sthurlow static int
5096007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp)
5106007Sthurlow {
5116007Sthurlow 	struct sockaddr_in locaddr;
5126007Sthurlow 	int opt = 1, s;
5136007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
5146007Sthurlow 
5156007Sthurlow 	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
5166007Sthurlow 	if (s < 0)
5176007Sthurlow 		return (errno);
5186007Sthurlow 	if (ctx->nb_flags & NBCF_BC_ENABLE) {
5196007Sthurlow 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
5206007Sthurlow 		    sizeof (opt)) < 0)
5216007Sthurlow 			return (errno);
5226007Sthurlow 	}
5236007Sthurlow 	if (is_system_labeled())
5246007Sthurlow 		(void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
5256007Sthurlow 		    sizeof (opt));
5266007Sthurlow 	bzero(&locaddr, sizeof (locaddr));
5276007Sthurlow 	locaddr.sin_family = AF_INET;
5286007Sthurlow 	/* locaddr.sin_len = sizeof (locaddr); */
5296007Sthurlow 	if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
5306007Sthurlow 		return (errno);
5316007Sthurlow 	return (0);
5326007Sthurlow }
5336007Sthurlow 
5346007Sthurlow static int
5356007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
5366007Sthurlow {
5376007Sthurlow 	struct sockaddr_in dest;
5386007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
5396007Sthurlow 	int s = rqp->nr_fd;
5406007Sthurlow 	uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
5416007Sthurlow 	uint16_t *datap;
5426007Sthurlow 	uint8_t nmflags;
5436007Sthurlow 	int rc;
5446007Sthurlow 
5456007Sthurlow 	bzero(&dest, sizeof (dest));
5466007Sthurlow 	dest.sin_family = AF_INET;
547*10023SGordon.Ross@Sun.COM 	dest.sin_port = htons(IPPORT_NETBIOS_NS);
5486007Sthurlow 	dest.sin_addr.s_addr = ina;
5496007Sthurlow 
5506007Sthurlow 	if (ina == INADDR_BROADCAST) {
5516007Sthurlow 		/* Turn on the broadcast bit. */
5526007Sthurlow 		nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
5536007Sthurlow 		/*LINTED*/
5546007Sthurlow 		datap = mtod(mbp->mb_top, uint16_t *);
5556007Sthurlow 		ofr = ((rqp->nr_opcode & 0x1F) << 11) |
5566007Sthurlow 		    ((nmflags & 0x7F) << 4); /* rcode=0 */
5576007Sthurlow 		ofr_save = datap[1];
5586007Sthurlow 		datap[1] = htons(ofr);
5596007Sthurlow 	}
5606007Sthurlow 
5616007Sthurlow 	rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
5626007Sthurlow 	    (struct sockaddr *)&dest, sizeof (dest));
5636007Sthurlow 
5646007Sthurlow 	if (ina == INADDR_BROADCAST) {
5656007Sthurlow 		/* Turn the broadcast bit back off. */
5666007Sthurlow 		datap[1] = ofr_save;
5676007Sthurlow 	}
5686007Sthurlow 
5696007Sthurlow 
5706007Sthurlow 	if (rc < 0)
5716007Sthurlow 		return (errno);
5726007Sthurlow 
5736007Sthurlow 	return (0);
5746007Sthurlow }
5756007Sthurlow 
5766007Sthurlow int
5776007Sthurlow nbns_rq(struct nbns_rq *rqp)
5786007Sthurlow {
5796007Sthurlow 	struct nb_ctx *ctx = rqp->nr_nbd;
5806007Sthurlow 	struct mbdata *mbp = &rqp->nr_rq;
5816007Sthurlow 	uint16_t ofr, rpid;
5826007Sthurlow 	int error, tries, maxretry;
5836007Sthurlow 
5846007Sthurlow 	error = nbns_rq_opensocket(rqp);
5856007Sthurlow 	if (error)
5866007Sthurlow 		return (error);
5876007Sthurlow 
5886007Sthurlow 	maxretry = rqp->nr_maxretry;
5896007Sthurlow 	for (tries = 0; tries < maxretry; tries++) {
5906007Sthurlow 
5916007Sthurlow 		/*
5926007Sthurlow 		 * Minor hack: If nr_dest is set, send there only.
5936007Sthurlow 		 * Used by _getnodestatus, _resolvname redirects.
5946007Sthurlow 		 */
5956007Sthurlow 		if (rqp->nr_dest.s_addr) {
5966007Sthurlow 			error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
5976007Sthurlow 			if (error) {
5986007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
5996007Sthurlow 				    "nbns error %d sending to %s"),
6006007Sthurlow 				    0, error, inet_ntoa(rqp->nr_dest));
6016007Sthurlow 			}
6026007Sthurlow 			goto do_recv;
6036007Sthurlow 		}
6046007Sthurlow 
6056007Sthurlow 		if (ctx->nb_wins1) {
6066007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins1);
6076007Sthurlow 			if (error) {
6086007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
6096007Sthurlow 				    "nbns error %d sending to wins1"),
6106007Sthurlow 				    0, error);
6116007Sthurlow 			}
6126007Sthurlow 		}
6136007Sthurlow 
6146007Sthurlow 		if (ctx->nb_wins2 && (tries > 0)) {
6156007Sthurlow 			error = nbns_rq_send(rqp, ctx->nb_wins2);
6166007Sthurlow 			if (error) {
6176007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
6186007Sthurlow 				    "nbns error %d sending to wins2"),
6196007Sthurlow 				    0, error);
6206007Sthurlow 			}
6216007Sthurlow 		}
6226007Sthurlow 
6236007Sthurlow 		/*
6246007Sthurlow 		 * If broadcast is enabled, start broadcasting
6256007Sthurlow 		 * only after wins servers fail to respond, or
6266007Sthurlow 		 * immediately if no WINS servers configured.
6276007Sthurlow 		 */
6286007Sthurlow 		if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
6296007Sthurlow 		    ((tries > 1) || (ctx->nb_wins1 == 0))) {
6306007Sthurlow 			error = nbns_rq_send(rqp, INADDR_BROADCAST);
6316007Sthurlow 			if (error) {
6326007Sthurlow 				smb_error(dgettext(TEXT_DOMAIN,
6336007Sthurlow 				    "nbns error %d sending broadcast"),
6346007Sthurlow 				    0, error);
6356007Sthurlow 			}
6366007Sthurlow 		}
6376007Sthurlow 
6386007Sthurlow 		/*
6396007Sthurlow 		 * Wait for responses from ANY of the above.
6406007Sthurlow 		 */
6416007Sthurlow do_recv:
6426007Sthurlow 		error = nbns_rq_recv(rqp);
6436007Sthurlow 		if (error == ETIMEDOUT)
6446007Sthurlow 			continue;
6456007Sthurlow 		if (error) {
6466007Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
6476007Sthurlow 			    "nbns recv error %d"),
6486007Sthurlow 			    0, error);
6496007Sthurlow 			return (error);
6506007Sthurlow 		}
6516007Sthurlow 
6526007Sthurlow 		mbp = &rqp->nr_rp;
6536007Sthurlow 		if (mbp->mb_count < 12)
6546007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
6556007Sthurlow 		mb_get_uint16be(mbp, &rpid);
6566007Sthurlow 		if (rpid != rqp->nr_trnid)
6576007Sthurlow 			return (NBERROR(NBERR_INVALIDRESPONSE));
6586007Sthurlow 		break;
6596007Sthurlow 	}
660*10023SGordon.Ross@Sun.COM 	if (tries == maxretry)
661*10023SGordon.Ross@Sun.COM 		return (NBERROR(NBERR_HOSTNOTFOUND));
6626007Sthurlow 
6636007Sthurlow 	mb_get_uint16be(mbp, &ofr);
6646007Sthurlow 	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
6656007Sthurlow 	rqp->nr_rprcode = ofr & 0xf;
6666007Sthurlow 	if (rqp->nr_rprcode)
6676007Sthurlow 		return (NBERROR(rqp->nr_rprcode));
6686007Sthurlow 	mb_get_uint16be(mbp, &rpid);	/* QDCOUNT */
6696007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpancount);
6706007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rpnscount);
6716007Sthurlow 	mb_get_uint16be(mbp, &rqp->nr_rparcount);
6726007Sthurlow 	return (0);
6736007Sthurlow }
674