14bff34e3Sthurlow /*
24bff34e3Sthurlow * Copyright (c) 2000, Boris Popov
34bff34e3Sthurlow * All rights reserved.
44bff34e3Sthurlow *
54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow * modification, are permitted provided that the following conditions
74bff34e3Sthurlow * are met:
84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow * documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow * must display the following acknowledgement:
154bff34e3Sthurlow * This product includes software developed by Boris Popov.
164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow * may be used to endorse or promote products derived from this software
184bff34e3Sthurlow * without specific prior written permission.
194bff34e3Sthurlow *
204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow * SUCH DAMAGE.
314bff34e3Sthurlow *
324bff34e3Sthurlow * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
334bff34e3Sthurlow */
344bff34e3Sthurlow
35*a547be5dSGordon Ross /*
36*a547be5dSGordon Ross * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37*a547be5dSGordon Ross */
38*a547be5dSGordon Ross
394bff34e3Sthurlow #include <sys/param.h>
404bff34e3Sthurlow #include <sys/socket.h>
414bff34e3Sthurlow #include <sys/time.h>
424bff34e3Sthurlow #include <ctype.h>
434bff34e3Sthurlow #include <netdb.h>
444bff34e3Sthurlow #include <errno.h>
454bff34e3Sthurlow #include <stdlib.h>
464bff34e3Sthurlow #include <string.h>
474bff34e3Sthurlow #include <strings.h>
484bff34e3Sthurlow #include <stdio.h>
494bff34e3Sthurlow #include <unistd.h>
504bff34e3Sthurlow #include <libintl.h>
514bff34e3Sthurlow
524bff34e3Sthurlow #include <netinet/in.h>
534bff34e3Sthurlow #include <arpa/inet.h>
544bff34e3Sthurlow #include <tsol/label.h>
554bff34e3Sthurlow
564bff34e3Sthurlow #define NB_NEEDRESOLVER
574bff34e3Sthurlow #include <netsmb/netbios.h>
584bff34e3Sthurlow #include <netsmb/smb_lib.h>
594bff34e3Sthurlow #include <netsmb/nb_lib.h>
604bff34e3Sthurlow #include <netsmb/mchain.h>
614bff34e3Sthurlow
62613a2f6bSGordon Ross #include "charsets.h"
639c9af259SGordon Ross #include "private.h"
649c9af259SGordon Ross
659c9af259SGordon Ross /*
669c9af259SGordon Ross * nbns request
679c9af259SGordon Ross */
689c9af259SGordon Ross struct nbns_rq {
699c9af259SGordon Ross int nr_opcode;
709c9af259SGordon Ross int nr_nmflags;
719c9af259SGordon Ross int nr_rcode;
729c9af259SGordon Ross int nr_qdcount;
739c9af259SGordon Ross int nr_ancount;
749c9af259SGordon Ross int nr_nscount;
759c9af259SGordon Ross int nr_arcount;
769c9af259SGordon Ross struct nb_name *nr_qdname;
779c9af259SGordon Ross uint16_t nr_qdtype;
789c9af259SGordon Ross uint16_t nr_qdclass;
799c9af259SGordon Ross struct in_addr nr_dest; /* receiver of query */
809c9af259SGordon Ross struct sockaddr_in nr_sender; /* sender of response */
819c9af259SGordon Ross int nr_rpnmflags;
829c9af259SGordon Ross int nr_rprcode;
839c9af259SGordon Ross uint16_t nr_rpancount;
849c9af259SGordon Ross uint16_t nr_rpnscount;
859c9af259SGordon Ross uint16_t nr_rparcount;
869c9af259SGordon Ross uint16_t nr_trnid;
879c9af259SGordon Ross struct nb_ctx *nr_nbd;
889c9af259SGordon Ross struct mbdata nr_rq;
899c9af259SGordon Ross struct mbdata nr_rp;
909c9af259SGordon Ross struct nb_ifdesc *nr_if;
919c9af259SGordon Ross int nr_flags;
929c9af259SGordon Ross int nr_fd;
939c9af259SGordon Ross int nr_maxretry;
949c9af259SGordon Ross };
959c9af259SGordon Ross typedef struct nbns_rq nbns_rq_t;
969c9af259SGordon Ross
974bff34e3Sthurlow static int nbns_rq_create(int opcode, struct nb_ctx *ctx,
984bff34e3Sthurlow struct nbns_rq **rqpp);
994bff34e3Sthurlow static void nbns_rq_done(struct nbns_rq *rqp);
1004bff34e3Sthurlow static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
1014bff34e3Sthurlow static int nbns_rq_prepare(struct nbns_rq *rqp);
1024bff34e3Sthurlow static int nbns_rq(struct nbns_rq *rqp);
1034bff34e3Sthurlow
104613a2f6bSGordon Ross /*
105613a2f6bSGordon Ross * Call NetBIOS name lookup and return a result in the
106613a2f6bSGordon Ross * same form as getaddrinfo(3) returns. Return code is
107613a2f6bSGordon Ross * zero or one of the EAI_xxx codes like getaddrinfo.
108613a2f6bSGordon Ross */
109613a2f6bSGordon Ross int
nbns_getaddrinfo(const char * name,struct nb_ctx * nbc,struct addrinfo ** res)110613a2f6bSGordon Ross nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
111613a2f6bSGordon Ross {
112613a2f6bSGordon Ross struct addrinfo *nai = NULL;
113613a2f6bSGordon Ross struct sockaddr *sap = NULL;
114613a2f6bSGordon Ross char *ucname = NULL;
115613a2f6bSGordon Ross int err;
116613a2f6bSGordon Ross
117613a2f6bSGordon Ross /*
118613a2f6bSGordon Ross * Try NetBIOS name lookup.
119613a2f6bSGordon Ross */
120613a2f6bSGordon Ross if (strlen(name) >= NB_NAMELEN) {
121613a2f6bSGordon Ross err = EAI_OVERFLOW;
122613a2f6bSGordon Ross goto out;
123613a2f6bSGordon Ross }
124613a2f6bSGordon Ross ucname = utf8_str_toupper(name);
125613a2f6bSGordon Ross if (ucname == NULL)
126613a2f6bSGordon Ross goto nomem;
127613a2f6bSGordon Ross
128613a2f6bSGordon Ross /* Note: this returns an NBERROR value. */
129613a2f6bSGordon Ross err = nbns_resolvename(ucname, nbc, &sap);
130613a2f6bSGordon Ross if (err) {
131613a2f6bSGordon Ross if (smb_verbose)
132613a2f6bSGordon Ross smb_error(dgettext(TEXT_DOMAIN,
133613a2f6bSGordon Ross "nbns_resolvename: %s"),
134613a2f6bSGordon Ross err, name);
135613a2f6bSGordon Ross err = EAI_NODATA;
136613a2f6bSGordon Ross goto out;
137613a2f6bSGordon Ross }
138613a2f6bSGordon Ross /* Note: sap allocated */
139613a2f6bSGordon Ross
140613a2f6bSGordon Ross /*
141613a2f6bSGordon Ross * Build the addrinfo struct to return.
142613a2f6bSGordon Ross */
143613a2f6bSGordon Ross nai = malloc(sizeof (*nai));
144613a2f6bSGordon Ross if (nai == NULL)
145613a2f6bSGordon Ross goto nomem;
146613a2f6bSGordon Ross bzero(nai, sizeof (*nai));
147613a2f6bSGordon Ross
148613a2f6bSGordon Ross nai->ai_flags = AI_CANONNAME;
149613a2f6bSGordon Ross nai->ai_family = sap->sa_family;
150613a2f6bSGordon Ross nai->ai_socktype = SOCK_STREAM;
151613a2f6bSGordon Ross nai->ai_canonname = ucname;
152613a2f6bSGordon Ross ucname = NULL;
153613a2f6bSGordon Ross
154613a2f6bSGordon Ross /*
155613a2f6bSGordon Ross * The type of this is really sockaddr_in,
156613a2f6bSGordon Ross * but is returned in the generic form.
157613a2f6bSGordon Ross * See nbns_resolvename.
158613a2f6bSGordon Ross */
159613a2f6bSGordon Ross nai->ai_addrlen = sizeof (struct sockaddr_in);
160613a2f6bSGordon Ross nai->ai_addr = sap;
161613a2f6bSGordon Ross
162613a2f6bSGordon Ross *res = nai;
163613a2f6bSGordon Ross return (0);
164613a2f6bSGordon Ross
165613a2f6bSGordon Ross nomem:
166613a2f6bSGordon Ross err = EAI_MEMORY;
167613a2f6bSGordon Ross out:
168613a2f6bSGordon Ross if (nai != NULL)
169613a2f6bSGordon Ross free(nai);
170613a2f6bSGordon Ross if (sap)
171613a2f6bSGordon Ross free(sap);
172613a2f6bSGordon Ross if (ucname)
173613a2f6bSGordon Ross free(ucname);
174613a2f6bSGordon Ross *res = NULL;
175613a2f6bSGordon Ross
176613a2f6bSGordon Ross return (err);
177613a2f6bSGordon Ross }
1784bff34e3Sthurlow
1794bff34e3Sthurlow int
nbns_resolvename(const char * name,struct nb_ctx * ctx,struct sockaddr ** adpp)1804bff34e3Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
1814bff34e3Sthurlow {
1824bff34e3Sthurlow struct nbns_rq *rqp;
1834bff34e3Sthurlow struct nb_name nn;
1844bff34e3Sthurlow struct nbns_rr rr;
1854bff34e3Sthurlow struct sockaddr_in *dest;
1864bff34e3Sthurlow int error, rdrcount, len;
1874bff34e3Sthurlow
188613a2f6bSGordon Ross if (strlen(name) >= NB_NAMELEN)
1894bff34e3Sthurlow return (NBERROR(NBERR_NAMETOOLONG));
1904bff34e3Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
1914bff34e3Sthurlow if (error)
1924bff34e3Sthurlow return (error);
1934bff34e3Sthurlow /*
1944bff34e3Sthurlow * Pad the name with blanks, but
1954bff34e3Sthurlow * leave the "type" byte NULL.
1964bff34e3Sthurlow * nb_name_encode adds the type.
1974bff34e3Sthurlow */
1984bff34e3Sthurlow bzero(&nn, sizeof (nn));
1994bff34e3Sthurlow snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
2004bff34e3Sthurlow nn.nn_type = NBT_SERVER;
2014bff34e3Sthurlow nn.nn_scope = ctx->nb_scope;
2024bff34e3Sthurlow rqp->nr_nmflags = NBNS_NMFLAG_RD;
2034bff34e3Sthurlow rqp->nr_qdname = &nn;
2044bff34e3Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
2054bff34e3Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2064bff34e3Sthurlow rqp->nr_qdcount = 1;
2074bff34e3Sthurlow rqp->nr_maxretry = 5;
2084bff34e3Sthurlow
2094bff34e3Sthurlow error = nbns_rq_prepare(rqp);
2104bff34e3Sthurlow if (error) {
2114bff34e3Sthurlow nbns_rq_done(rqp);
2124bff34e3Sthurlow return (error);
2134bff34e3Sthurlow }
2144bff34e3Sthurlow rdrcount = NBNS_MAXREDIRECTS;
2154bff34e3Sthurlow for (;;) {
2164bff34e3Sthurlow error = nbns_rq(rqp);
2174bff34e3Sthurlow if (error)
2184bff34e3Sthurlow break;
2194bff34e3Sthurlow if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
2204bff34e3Sthurlow /*
2214bff34e3Sthurlow * Not an authoritative answer. Query again
2224bff34e3Sthurlow * using the NS address in the 2nd record.
2234bff34e3Sthurlow */
2244bff34e3Sthurlow if (rdrcount-- == 0) {
2254bff34e3Sthurlow error = NBERROR(NBERR_TOOMANYREDIRECTS);
2264bff34e3Sthurlow break;
2274bff34e3Sthurlow }
2284bff34e3Sthurlow error = nbns_rq_getrr(rqp, &rr);
2294bff34e3Sthurlow if (error)
2304bff34e3Sthurlow break;
2314bff34e3Sthurlow error = nbns_rq_getrr(rqp, &rr);
2324bff34e3Sthurlow if (error)
2334bff34e3Sthurlow break;
2344bff34e3Sthurlow bcopy(rr.rr_data, &rqp->nr_dest, 4);
2354bff34e3Sthurlow continue;
2364bff34e3Sthurlow }
2374bff34e3Sthurlow if (rqp->nr_rpancount == 0) {
2384bff34e3Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND);
2394bff34e3Sthurlow break;
2404bff34e3Sthurlow }
2414bff34e3Sthurlow error = nbns_rq_getrr(rqp, &rr);
2424bff34e3Sthurlow if (error)
2434bff34e3Sthurlow break;
2444bff34e3Sthurlow len = sizeof (struct sockaddr_in);
2454bff34e3Sthurlow dest = malloc(len);
2464bff34e3Sthurlow if (dest == NULL)
2474bff34e3Sthurlow return (ENOMEM);
2484bff34e3Sthurlow bzero(dest, len);
2494bff34e3Sthurlow /*
250613a2f6bSGordon Ross * Solaris sockaddr_in doesn't a sin_len field.
2514bff34e3Sthurlow * dest->sin_len = len;
2524bff34e3Sthurlow */
253613a2f6bSGordon Ross dest->sin_family = AF_NETBIOS; /* nb_lib.h */
2544bff34e3Sthurlow bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
2554bff34e3Sthurlow *adpp = (struct sockaddr *)dest;
2564bff34e3Sthurlow ctx->nb_lastns = rqp->nr_sender;
2574bff34e3Sthurlow break;
2584bff34e3Sthurlow }
2594bff34e3Sthurlow nbns_rq_done(rqp);
2604bff34e3Sthurlow return (error);
2614bff34e3Sthurlow }
2624bff34e3Sthurlow
263613a2f6bSGordon Ross /*
264613a2f6bSGordon Ross * NB: system, workgroup are both NB_NAMELEN
265613a2f6bSGordon Ross */
2664bff34e3Sthurlow int
nbns_getnodestatus(struct nb_ctx * ctx,struct in_addr * targethost,char * system,char * workgroup)267613a2f6bSGordon Ross nbns_getnodestatus(struct nb_ctx *ctx,
268613a2f6bSGordon Ross struct in_addr *targethost, char *system, char *workgroup)
2694bff34e3Sthurlow {
2704bff34e3Sthurlow struct nbns_rq *rqp;
2714bff34e3Sthurlow struct nbns_rr rr;
2724bff34e3Sthurlow struct nb_name nn;
2734bff34e3Sthurlow struct nbns_nr *nrp;
2744bff34e3Sthurlow char nrtype;
2754bff34e3Sthurlow char *cp, *retname = NULL;
2764bff34e3Sthurlow unsigned char nrcount;
277613a2f6bSGordon Ross int error, i, foundserver = 0, foundgroup = 0;
2784bff34e3Sthurlow
2794bff34e3Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
2804bff34e3Sthurlow if (error)
2814bff34e3Sthurlow return (error);
2824bff34e3Sthurlow bzero(&nn, sizeof (nn));
2834bff34e3Sthurlow strcpy((char *)nn.nn_name, "*");
2844bff34e3Sthurlow nn.nn_scope = ctx->nb_scope;
2854bff34e3Sthurlow nn.nn_type = NBT_WKSTA;
2864bff34e3Sthurlow rqp->nr_nmflags = 0;
2874bff34e3Sthurlow rqp->nr_qdname = &nn;
2884bff34e3Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
2894bff34e3Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2904bff34e3Sthurlow rqp->nr_qdcount = 1;
2914bff34e3Sthurlow rqp->nr_maxretry = 2;
2924bff34e3Sthurlow
293613a2f6bSGordon Ross rqp->nr_dest = *targethost;
2944bff34e3Sthurlow error = nbns_rq_prepare(rqp);
2954bff34e3Sthurlow if (error) {
2964bff34e3Sthurlow nbns_rq_done(rqp);
2974bff34e3Sthurlow return (error);
2984bff34e3Sthurlow }
2994bff34e3Sthurlow
3004bff34e3Sthurlow /*
3014bff34e3Sthurlow * Darwin had a loop here, allowing redirect, etc.
3024bff34e3Sthurlow * but we only handle point-to-point for node status.
3034bff34e3Sthurlow */
3044bff34e3Sthurlow error = nbns_rq(rqp);
3054bff34e3Sthurlow if (error)
3064bff34e3Sthurlow goto out;
3074bff34e3Sthurlow if (rqp->nr_rpancount == 0) {
3084bff34e3Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND);
3094bff34e3Sthurlow goto out;
3104bff34e3Sthurlow }
3114bff34e3Sthurlow error = nbns_rq_getrr(rqp, &rr);
3124bff34e3Sthurlow if (error)
3134bff34e3Sthurlow goto out;
3144bff34e3Sthurlow
3154bff34e3Sthurlow /* Compiler didn't like cast on lvalue++ */
3164bff34e3Sthurlow nrcount = *((unsigned char *)rr.rr_data);
3174bff34e3Sthurlow rr.rr_data++;
3184bff34e3Sthurlow /* LINTED */
3194bff34e3Sthurlow for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
3204bff34e3Sthurlow i <= nrcount; ++i, ++nrp) {
3214bff34e3Sthurlow nrtype = nrp->ns_name[NB_NAMELEN-1];
3224bff34e3Sthurlow /* Terminate the string: */
3234bff34e3Sthurlow nrp->ns_name[NB_NAMELEN-1] = (char)0;
3244bff34e3Sthurlow /* Strip off trailing spaces */
3254bff34e3Sthurlow for (cp = &nrp->ns_name[NB_NAMELEN-2];
3264bff34e3Sthurlow cp >= nrp->ns_name; --cp) {
3274bff34e3Sthurlow if (*cp != (char)0x20)
3284bff34e3Sthurlow break;
3294bff34e3Sthurlow *cp = (char)0;
3304bff34e3Sthurlow }
3314bff34e3Sthurlow nrp->ns_flags = ntohs(nrp->ns_flags);
332613a2f6bSGordon Ross DPRINT(" %s[%02x] Flags 0x%x",
333613a2f6bSGordon Ross nrp->ns_name, nrtype, nrp->ns_flags);
3344bff34e3Sthurlow if (nrp->ns_flags & NBNS_GROUPFLG) {
3354bff34e3Sthurlow if (!foundgroup ||
3364bff34e3Sthurlow (foundgroup != NBT_WKSTA+1 &&
3374bff34e3Sthurlow nrtype == NBT_WKSTA)) {
338613a2f6bSGordon Ross strlcpy(workgroup, nrp->ns_name,
339613a2f6bSGordon Ross NB_NAMELEN);
3404bff34e3Sthurlow foundgroup = nrtype+1;
3414bff34e3Sthurlow }
3424bff34e3Sthurlow } else {
3434bff34e3Sthurlow /*
3444bff34e3Sthurlow * Track at least ONE name, in case
3454bff34e3Sthurlow * no server name is found
3464bff34e3Sthurlow */
3474bff34e3Sthurlow retname = nrp->ns_name;
3484bff34e3Sthurlow }
349613a2f6bSGordon Ross /*
350613a2f6bSGordon Ross * Keep the first NBT_SERVER name.
351613a2f6bSGordon Ross */
352613a2f6bSGordon Ross if (nrtype == NBT_SERVER && foundserver == 0) {
353613a2f6bSGordon Ross strlcpy(system, nrp->ns_name,
354613a2f6bSGordon Ross NB_NAMELEN);
3554bff34e3Sthurlow foundserver = 1;
3564bff34e3Sthurlow }
3574bff34e3Sthurlow }
358*a547be5dSGordon Ross if (foundserver == 0 && retname != NULL)
359613a2f6bSGordon Ross strlcpy(system, retname, NB_NAMELEN);
3604bff34e3Sthurlow ctx->nb_lastns = rqp->nr_sender;
3614bff34e3Sthurlow
3624bff34e3Sthurlow out:
3634bff34e3Sthurlow nbns_rq_done(rqp);
3644bff34e3Sthurlow return (error);
3654bff34e3Sthurlow }
3664bff34e3Sthurlow
3674bff34e3Sthurlow int
nbns_rq_create(int opcode,struct nb_ctx * ctx,struct nbns_rq ** rqpp)3684bff34e3Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
3694bff34e3Sthurlow {
3704bff34e3Sthurlow struct nbns_rq *rqp;
3714bff34e3Sthurlow static uint16_t trnid;
3724bff34e3Sthurlow int error;
3734bff34e3Sthurlow
3744bff34e3Sthurlow if (trnid == 0)
3754bff34e3Sthurlow trnid = getpid();
3764bff34e3Sthurlow rqp = malloc(sizeof (*rqp));
3774bff34e3Sthurlow if (rqp == NULL)
3784bff34e3Sthurlow return (ENOMEM);
3794bff34e3Sthurlow bzero(rqp, sizeof (*rqp));
38002d09e03SGordon Ross error = mb_init_sz(&rqp->nr_rq, NBDG_MAXSIZE);
3814bff34e3Sthurlow if (error) {
3824bff34e3Sthurlow free(rqp);
3834bff34e3Sthurlow return (error);
3844bff34e3Sthurlow }
3854bff34e3Sthurlow rqp->nr_opcode = opcode;
3864bff34e3Sthurlow rqp->nr_nbd = ctx;
3874bff34e3Sthurlow rqp->nr_trnid = trnid++;
3884bff34e3Sthurlow *rqpp = rqp;
3894bff34e3Sthurlow return (0);
3904bff34e3Sthurlow }
3914bff34e3Sthurlow
3924bff34e3Sthurlow void
nbns_rq_done(struct nbns_rq * rqp)3934bff34e3Sthurlow nbns_rq_done(struct nbns_rq *rqp)
3944bff34e3Sthurlow {
3954bff34e3Sthurlow if (rqp == NULL)
3964bff34e3Sthurlow return;
3974bff34e3Sthurlow if (rqp->nr_fd >= 0)
3984bff34e3Sthurlow close(rqp->nr_fd);
3994bff34e3Sthurlow mb_done(&rqp->nr_rq);
4004bff34e3Sthurlow mb_done(&rqp->nr_rp);
4014bff34e3Sthurlow if (rqp->nr_if)
4024bff34e3Sthurlow free(rqp->nr_if);
4034bff34e3Sthurlow free(rqp);
4044bff34e3Sthurlow }
4054bff34e3Sthurlow
4064bff34e3Sthurlow /*
4074bff34e3Sthurlow * Extract resource record from the packet. Assume that there is only
4084bff34e3Sthurlow * one mbuf.
4094bff34e3Sthurlow */
4104bff34e3Sthurlow int
nbns_rq_getrr(struct nbns_rq * rqp,struct nbns_rr * rrp)4114bff34e3Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
4124bff34e3Sthurlow {
4134bff34e3Sthurlow struct mbdata *mbp = &rqp->nr_rp;
4144bff34e3Sthurlow uchar_t *cp;
4154bff34e3Sthurlow int error, len;
4164bff34e3Sthurlow
4174bff34e3Sthurlow bzero(rrp, sizeof (*rrp));
4184bff34e3Sthurlow cp = (uchar_t *)mbp->mb_pos;
4194bff34e3Sthurlow len = nb_encname_len(cp);
4204bff34e3Sthurlow if (len < 1)
4214bff34e3Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
4224bff34e3Sthurlow rrp->rr_name = cp;
42302d09e03SGordon Ross error = md_get_mem(mbp, NULL, len, MB_MSYSTEM);
4244bff34e3Sthurlow if (error)
4254bff34e3Sthurlow return (error);
42602d09e03SGordon Ross md_get_uint16be(mbp, &rrp->rr_type);
42702d09e03SGordon Ross md_get_uint16be(mbp, &rrp->rr_class);
42802d09e03SGordon Ross md_get_uint32be(mbp, &rrp->rr_ttl);
42902d09e03SGordon Ross md_get_uint16be(mbp, &rrp->rr_rdlength);
4304bff34e3Sthurlow rrp->rr_data = (uchar_t *)mbp->mb_pos;
43102d09e03SGordon Ross error = md_get_mem(mbp, NULL, rrp->rr_rdlength, MB_MSYSTEM);
4324bff34e3Sthurlow return (error);
4334bff34e3Sthurlow }
4344bff34e3Sthurlow
4354bff34e3Sthurlow int
nbns_rq_prepare(struct nbns_rq * rqp)4364bff34e3Sthurlow nbns_rq_prepare(struct nbns_rq *rqp)
4374bff34e3Sthurlow {
4384bff34e3Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
4394bff34e3Sthurlow struct mbdata *mbp = &rqp->nr_rq;
4404bff34e3Sthurlow uint16_t ofr; /* opcode, flags, rcode */
441613a2f6bSGordon Ross int error;
4424bff34e3Sthurlow
44302d09e03SGordon Ross error = mb_init_sz(&rqp->nr_rp, NBDG_MAXSIZE);
4444bff34e3Sthurlow if (error)
4454bff34e3Sthurlow return (error);
4464bff34e3Sthurlow
4474bff34e3Sthurlow /*
4484bff34e3Sthurlow * When looked into the ethereal trace, 'nmblookup' command sets this
4494bff34e3Sthurlow * flag. We will also set.
4504bff34e3Sthurlow */
4514bff34e3Sthurlow mb_put_uint16be(mbp, rqp->nr_trnid);
4524bff34e3Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) |
4534bff34e3Sthurlow ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
4544bff34e3Sthurlow mb_put_uint16be(mbp, ofr);
4554bff34e3Sthurlow mb_put_uint16be(mbp, rqp->nr_qdcount);
4564bff34e3Sthurlow mb_put_uint16be(mbp, rqp->nr_ancount);
4574bff34e3Sthurlow mb_put_uint16be(mbp, rqp->nr_nscount);
45802d09e03SGordon Ross error = mb_put_uint16be(mbp, rqp->nr_arcount);
4594bff34e3Sthurlow if (rqp->nr_qdcount) {
4604bff34e3Sthurlow if (rqp->nr_qdcount > 1)
4614bff34e3Sthurlow return (EINVAL);
46202d09e03SGordon Ross (void) nb_name_encode(mbp, rqp->nr_qdname);
4634bff34e3Sthurlow mb_put_uint16be(mbp, rqp->nr_qdtype);
46402d09e03SGordon Ross error = mb_put_uint16be(mbp, rqp->nr_qdclass);
4654bff34e3Sthurlow }
46602d09e03SGordon Ross if (error)
46702d09e03SGordon Ross return (error);
46802d09e03SGordon Ross error = m_lineup(mbp->mb_top, &mbp->mb_top);
46902d09e03SGordon Ross if (error)
47002d09e03SGordon Ross return (error);
4714bff34e3Sthurlow if (ctx->nb_timo == 0)
4724bff34e3Sthurlow ctx->nb_timo = 1; /* by default 1 second */
4734bff34e3Sthurlow return (0);
4744bff34e3Sthurlow }
4754bff34e3Sthurlow
4764bff34e3Sthurlow static int
nbns_rq_recv(struct nbns_rq * rqp)4774bff34e3Sthurlow nbns_rq_recv(struct nbns_rq *rqp)
4784bff34e3Sthurlow {
4794bff34e3Sthurlow struct mbdata *mbp = &rqp->nr_rp;
4804bff34e3Sthurlow void *rpdata = mtod(mbp->mb_top, void *);
4814bff34e3Sthurlow fd_set rd, wr, ex;
4824bff34e3Sthurlow struct timeval tv;
4834bff34e3Sthurlow struct sockaddr_in sender;
4844bff34e3Sthurlow int s = rqp->nr_fd;
4854bff34e3Sthurlow int n, len;
4864bff34e3Sthurlow
4874bff34e3Sthurlow FD_ZERO(&rd);
4884bff34e3Sthurlow FD_ZERO(&wr);
4894bff34e3Sthurlow FD_ZERO(&ex);
4904bff34e3Sthurlow FD_SET(s, &rd);
4914bff34e3Sthurlow
4924bff34e3Sthurlow tv.tv_sec = rqp->nr_nbd->nb_timo;
4934bff34e3Sthurlow tv.tv_usec = 0;
4944bff34e3Sthurlow
4954bff34e3Sthurlow n = select(s + 1, &rd, &wr, &ex, &tv);
4964bff34e3Sthurlow if (n == -1)
4974bff34e3Sthurlow return (-1);
4984bff34e3Sthurlow if (n == 0)
4994bff34e3Sthurlow return (ETIMEDOUT);
5004bff34e3Sthurlow if (FD_ISSET(s, &rd) == 0)
5014bff34e3Sthurlow return (ETIMEDOUT);
5024bff34e3Sthurlow len = sizeof (sender);
5034bff34e3Sthurlow n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
5044bff34e3Sthurlow (struct sockaddr *)&sender, &len);
5054bff34e3Sthurlow if (n < 0)
5064bff34e3Sthurlow return (errno);
5074bff34e3Sthurlow mbp->mb_top->m_len = mbp->mb_count = n;
5084bff34e3Sthurlow rqp->nr_sender = sender;
5094bff34e3Sthurlow return (0);
5104bff34e3Sthurlow }
5114bff34e3Sthurlow
5124bff34e3Sthurlow static int
nbns_rq_opensocket(struct nbns_rq * rqp)5134bff34e3Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp)
5144bff34e3Sthurlow {
5154bff34e3Sthurlow struct sockaddr_in locaddr;
5164bff34e3Sthurlow int opt = 1, s;
5174bff34e3Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
5184bff34e3Sthurlow
5194bff34e3Sthurlow s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
5204bff34e3Sthurlow if (s < 0)
5214bff34e3Sthurlow return (errno);
5224bff34e3Sthurlow if (ctx->nb_flags & NBCF_BC_ENABLE) {
5234bff34e3Sthurlow if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
5244bff34e3Sthurlow sizeof (opt)) < 0)
5254bff34e3Sthurlow return (errno);
5264bff34e3Sthurlow }
5274bff34e3Sthurlow if (is_system_labeled())
5284bff34e3Sthurlow (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
5294bff34e3Sthurlow sizeof (opt));
5304bff34e3Sthurlow bzero(&locaddr, sizeof (locaddr));
5314bff34e3Sthurlow locaddr.sin_family = AF_INET;
5324bff34e3Sthurlow /* locaddr.sin_len = sizeof (locaddr); */
5334bff34e3Sthurlow if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
5344bff34e3Sthurlow return (errno);
5354bff34e3Sthurlow return (0);
5364bff34e3Sthurlow }
5374bff34e3Sthurlow
5384bff34e3Sthurlow static int
nbns_rq_send(struct nbns_rq * rqp,in_addr_t ina)5394bff34e3Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
5404bff34e3Sthurlow {
5414bff34e3Sthurlow struct sockaddr_in dest;
5424bff34e3Sthurlow struct mbdata *mbp = &rqp->nr_rq;
5434bff34e3Sthurlow int s = rqp->nr_fd;
5444bff34e3Sthurlow uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
5454bff34e3Sthurlow uint16_t *datap;
5464bff34e3Sthurlow uint8_t nmflags;
5474bff34e3Sthurlow int rc;
5484bff34e3Sthurlow
5494bff34e3Sthurlow bzero(&dest, sizeof (dest));
5504bff34e3Sthurlow dest.sin_family = AF_INET;
551613a2f6bSGordon Ross dest.sin_port = htons(IPPORT_NETBIOS_NS);
5524bff34e3Sthurlow dest.sin_addr.s_addr = ina;
5534bff34e3Sthurlow
5544bff34e3Sthurlow if (ina == INADDR_BROADCAST) {
5554bff34e3Sthurlow /* Turn on the broadcast bit. */
5564bff34e3Sthurlow nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
5574bff34e3Sthurlow /*LINTED*/
5584bff34e3Sthurlow datap = mtod(mbp->mb_top, uint16_t *);
5594bff34e3Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) |
5604bff34e3Sthurlow ((nmflags & 0x7F) << 4); /* rcode=0 */
5614bff34e3Sthurlow ofr_save = datap[1];
5624bff34e3Sthurlow datap[1] = htons(ofr);
5634bff34e3Sthurlow }
5644bff34e3Sthurlow
5654bff34e3Sthurlow rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
5664bff34e3Sthurlow (struct sockaddr *)&dest, sizeof (dest));
5674bff34e3Sthurlow
5684bff34e3Sthurlow if (ina == INADDR_BROADCAST) {
5694bff34e3Sthurlow /* Turn the broadcast bit back off. */
5704bff34e3Sthurlow datap[1] = ofr_save;
5714bff34e3Sthurlow }
5724bff34e3Sthurlow
5734bff34e3Sthurlow
5744bff34e3Sthurlow if (rc < 0)
5754bff34e3Sthurlow return (errno);
5764bff34e3Sthurlow
5774bff34e3Sthurlow return (0);
5784bff34e3Sthurlow }
5794bff34e3Sthurlow
5804bff34e3Sthurlow int
nbns_rq(struct nbns_rq * rqp)5814bff34e3Sthurlow nbns_rq(struct nbns_rq *rqp)
5824bff34e3Sthurlow {
5834bff34e3Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
5844bff34e3Sthurlow struct mbdata *mbp = &rqp->nr_rq;
5854bff34e3Sthurlow uint16_t ofr, rpid;
5864bff34e3Sthurlow int error, tries, maxretry;
5874bff34e3Sthurlow
5884bff34e3Sthurlow error = nbns_rq_opensocket(rqp);
5894bff34e3Sthurlow if (error)
5904bff34e3Sthurlow return (error);
5914bff34e3Sthurlow
5924bff34e3Sthurlow maxretry = rqp->nr_maxretry;
5934bff34e3Sthurlow for (tries = 0; tries < maxretry; tries++) {
5944bff34e3Sthurlow
5954bff34e3Sthurlow /*
5964bff34e3Sthurlow * Minor hack: If nr_dest is set, send there only.
5974bff34e3Sthurlow * Used by _getnodestatus, _resolvname redirects.
5984bff34e3Sthurlow */
5994bff34e3Sthurlow if (rqp->nr_dest.s_addr) {
6004bff34e3Sthurlow error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
6014bff34e3Sthurlow if (error) {
6024bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6034bff34e3Sthurlow "nbns error %d sending to %s"),
6044bff34e3Sthurlow 0, error, inet_ntoa(rqp->nr_dest));
6054bff34e3Sthurlow }
6064bff34e3Sthurlow goto do_recv;
6074bff34e3Sthurlow }
6084bff34e3Sthurlow
6094bff34e3Sthurlow if (ctx->nb_wins1) {
6104bff34e3Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins1);
6114bff34e3Sthurlow if (error) {
6124bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6134bff34e3Sthurlow "nbns error %d sending to wins1"),
6144bff34e3Sthurlow 0, error);
6154bff34e3Sthurlow }
6164bff34e3Sthurlow }
6174bff34e3Sthurlow
6184bff34e3Sthurlow if (ctx->nb_wins2 && (tries > 0)) {
6194bff34e3Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins2);
6204bff34e3Sthurlow if (error) {
6214bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6224bff34e3Sthurlow "nbns error %d sending to wins2"),
6234bff34e3Sthurlow 0, error);
6244bff34e3Sthurlow }
6254bff34e3Sthurlow }
6264bff34e3Sthurlow
6274bff34e3Sthurlow /*
6284bff34e3Sthurlow * If broadcast is enabled, start broadcasting
6294bff34e3Sthurlow * only after wins servers fail to respond, or
6304bff34e3Sthurlow * immediately if no WINS servers configured.
6314bff34e3Sthurlow */
6324bff34e3Sthurlow if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
6334bff34e3Sthurlow ((tries > 1) || (ctx->nb_wins1 == 0))) {
6344bff34e3Sthurlow error = nbns_rq_send(rqp, INADDR_BROADCAST);
6354bff34e3Sthurlow if (error) {
6364bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6374bff34e3Sthurlow "nbns error %d sending broadcast"),
6384bff34e3Sthurlow 0, error);
6394bff34e3Sthurlow }
6404bff34e3Sthurlow }
6414bff34e3Sthurlow
6424bff34e3Sthurlow /*
6434bff34e3Sthurlow * Wait for responses from ANY of the above.
6444bff34e3Sthurlow */
6454bff34e3Sthurlow do_recv:
6464bff34e3Sthurlow error = nbns_rq_recv(rqp);
6474bff34e3Sthurlow if (error == ETIMEDOUT)
6484bff34e3Sthurlow continue;
6494bff34e3Sthurlow if (error) {
6504bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6514bff34e3Sthurlow "nbns recv error %d"),
6524bff34e3Sthurlow 0, error);
6534bff34e3Sthurlow return (error);
6544bff34e3Sthurlow }
6554bff34e3Sthurlow
6564bff34e3Sthurlow mbp = &rqp->nr_rp;
6574bff34e3Sthurlow if (mbp->mb_count < 12)
6584bff34e3Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
65902d09e03SGordon Ross md_get_uint16be(mbp, &rpid);
6604bff34e3Sthurlow if (rpid != rqp->nr_trnid)
6614bff34e3Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
6624bff34e3Sthurlow break;
6634bff34e3Sthurlow }
664613a2f6bSGordon Ross if (tries == maxretry)
665613a2f6bSGordon Ross return (NBERROR(NBERR_HOSTNOTFOUND));
6664bff34e3Sthurlow
66702d09e03SGordon Ross md_get_uint16be(mbp, &ofr);
6684bff34e3Sthurlow rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
6694bff34e3Sthurlow rqp->nr_rprcode = ofr & 0xf;
6704bff34e3Sthurlow if (rqp->nr_rprcode)
6714bff34e3Sthurlow return (NBERROR(rqp->nr_rprcode));
67202d09e03SGordon Ross md_get_uint16be(mbp, &rpid); /* QDCOUNT */
67302d09e03SGordon Ross md_get_uint16be(mbp, &rqp->nr_rpancount);
67402d09e03SGordon Ross md_get_uint16be(mbp, &rqp->nr_rpnscount);
67502d09e03SGordon Ross md_get_uint16be(mbp, &rqp->nr_rparcount);
6764bff34e3Sthurlow return (0);
6774bff34e3Sthurlow }
678