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
35*12556SGordon.Ross@Sun.COM /*
36*12556SGordon.Ross@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
37*12556SGordon.Ross@Sun.COM */
38*12556SGordon.Ross@Sun.COM
396007Sthurlow #include <sys/param.h>
406007Sthurlow #include <sys/socket.h>
416007Sthurlow #include <sys/time.h>
426007Sthurlow #include <ctype.h>
436007Sthurlow #include <netdb.h>
446007Sthurlow #include <errno.h>
456007Sthurlow #include <stdlib.h>
466007Sthurlow #include <string.h>
476007Sthurlow #include <strings.h>
486007Sthurlow #include <stdio.h>
496007Sthurlow #include <unistd.h>
506007Sthurlow #include <libintl.h>
516007Sthurlow
526007Sthurlow #include <netinet/in.h>
536007Sthurlow #include <arpa/inet.h>
546007Sthurlow #include <tsol/label.h>
556007Sthurlow
566007Sthurlow #define NB_NEEDRESOLVER
576007Sthurlow #include <netsmb/netbios.h>
586007Sthurlow #include <netsmb/smb_lib.h>
596007Sthurlow #include <netsmb/nb_lib.h>
606007Sthurlow #include <netsmb/mchain.h>
616007Sthurlow
6210023SGordon.Ross@Sun.COM #include "charsets.h"
638271SGordon.Ross@Sun.COM #include "private.h"
648271SGordon.Ross@Sun.COM
658271SGordon.Ross@Sun.COM /*
668271SGordon.Ross@Sun.COM * nbns request
678271SGordon.Ross@Sun.COM */
688271SGordon.Ross@Sun.COM struct nbns_rq {
698271SGordon.Ross@Sun.COM int nr_opcode;
708271SGordon.Ross@Sun.COM int nr_nmflags;
718271SGordon.Ross@Sun.COM int nr_rcode;
728271SGordon.Ross@Sun.COM int nr_qdcount;
738271SGordon.Ross@Sun.COM int nr_ancount;
748271SGordon.Ross@Sun.COM int nr_nscount;
758271SGordon.Ross@Sun.COM int nr_arcount;
768271SGordon.Ross@Sun.COM struct nb_name *nr_qdname;
778271SGordon.Ross@Sun.COM uint16_t nr_qdtype;
788271SGordon.Ross@Sun.COM uint16_t nr_qdclass;
798271SGordon.Ross@Sun.COM struct in_addr nr_dest; /* receiver of query */
808271SGordon.Ross@Sun.COM struct sockaddr_in nr_sender; /* sender of response */
818271SGordon.Ross@Sun.COM int nr_rpnmflags;
828271SGordon.Ross@Sun.COM int nr_rprcode;
838271SGordon.Ross@Sun.COM uint16_t nr_rpancount;
848271SGordon.Ross@Sun.COM uint16_t nr_rpnscount;
858271SGordon.Ross@Sun.COM uint16_t nr_rparcount;
868271SGordon.Ross@Sun.COM uint16_t nr_trnid;
878271SGordon.Ross@Sun.COM struct nb_ctx *nr_nbd;
888271SGordon.Ross@Sun.COM struct mbdata nr_rq;
898271SGordon.Ross@Sun.COM struct mbdata nr_rp;
908271SGordon.Ross@Sun.COM struct nb_ifdesc *nr_if;
918271SGordon.Ross@Sun.COM int nr_flags;
928271SGordon.Ross@Sun.COM int nr_fd;
938271SGordon.Ross@Sun.COM int nr_maxretry;
948271SGordon.Ross@Sun.COM };
958271SGordon.Ross@Sun.COM typedef struct nbns_rq nbns_rq_t;
968271SGordon.Ross@Sun.COM
976007Sthurlow static int nbns_rq_create(int opcode, struct nb_ctx *ctx,
986007Sthurlow struct nbns_rq **rqpp);
996007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp);
1006007Sthurlow static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
1016007Sthurlow static int nbns_rq_prepare(struct nbns_rq *rqp);
1026007Sthurlow static int nbns_rq(struct nbns_rq *rqp);
1036007Sthurlow
10410023SGordon.Ross@Sun.COM /*
10510023SGordon.Ross@Sun.COM * Call NetBIOS name lookup and return a result in the
10610023SGordon.Ross@Sun.COM * same form as getaddrinfo(3) returns. Return code is
10710023SGordon.Ross@Sun.COM * zero or one of the EAI_xxx codes like getaddrinfo.
10810023SGordon.Ross@Sun.COM */
10910023SGordon.Ross@Sun.COM int
nbns_getaddrinfo(const char * name,struct nb_ctx * nbc,struct addrinfo ** res)11010023SGordon.Ross@Sun.COM nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
11110023SGordon.Ross@Sun.COM {
11210023SGordon.Ross@Sun.COM struct addrinfo *nai = NULL;
11310023SGordon.Ross@Sun.COM struct sockaddr *sap = NULL;
11410023SGordon.Ross@Sun.COM char *ucname = NULL;
11510023SGordon.Ross@Sun.COM int err;
11610023SGordon.Ross@Sun.COM
11710023SGordon.Ross@Sun.COM /*
11810023SGordon.Ross@Sun.COM * Try NetBIOS name lookup.
11910023SGordon.Ross@Sun.COM */
12010023SGordon.Ross@Sun.COM if (strlen(name) >= NB_NAMELEN) {
12110023SGordon.Ross@Sun.COM err = EAI_OVERFLOW;
12210023SGordon.Ross@Sun.COM goto out;
12310023SGordon.Ross@Sun.COM }
12410023SGordon.Ross@Sun.COM ucname = utf8_str_toupper(name);
12510023SGordon.Ross@Sun.COM if (ucname == NULL)
12610023SGordon.Ross@Sun.COM goto nomem;
12710023SGordon.Ross@Sun.COM
12810023SGordon.Ross@Sun.COM /* Note: this returns an NBERROR value. */
12910023SGordon.Ross@Sun.COM err = nbns_resolvename(ucname, nbc, &sap);
13010023SGordon.Ross@Sun.COM if (err) {
13110023SGordon.Ross@Sun.COM if (smb_verbose)
13210023SGordon.Ross@Sun.COM smb_error(dgettext(TEXT_DOMAIN,
13310023SGordon.Ross@Sun.COM "nbns_resolvename: %s"),
13410023SGordon.Ross@Sun.COM err, name);
13510023SGordon.Ross@Sun.COM err = EAI_NODATA;
13610023SGordon.Ross@Sun.COM goto out;
13710023SGordon.Ross@Sun.COM }
13810023SGordon.Ross@Sun.COM /* Note: sap allocated */
13910023SGordon.Ross@Sun.COM
14010023SGordon.Ross@Sun.COM /*
14110023SGordon.Ross@Sun.COM * Build the addrinfo struct to return.
14210023SGordon.Ross@Sun.COM */
14310023SGordon.Ross@Sun.COM nai = malloc(sizeof (*nai));
14410023SGordon.Ross@Sun.COM if (nai == NULL)
14510023SGordon.Ross@Sun.COM goto nomem;
14610023SGordon.Ross@Sun.COM bzero(nai, sizeof (*nai));
14710023SGordon.Ross@Sun.COM
14810023SGordon.Ross@Sun.COM nai->ai_flags = AI_CANONNAME;
14910023SGordon.Ross@Sun.COM nai->ai_family = sap->sa_family;
15010023SGordon.Ross@Sun.COM nai->ai_socktype = SOCK_STREAM;
15110023SGordon.Ross@Sun.COM nai->ai_canonname = ucname;
15210023SGordon.Ross@Sun.COM ucname = NULL;
15310023SGordon.Ross@Sun.COM
15410023SGordon.Ross@Sun.COM /*
15510023SGordon.Ross@Sun.COM * The type of this is really sockaddr_in,
15610023SGordon.Ross@Sun.COM * but is returned in the generic form.
15710023SGordon.Ross@Sun.COM * See nbns_resolvename.
15810023SGordon.Ross@Sun.COM */
15910023SGordon.Ross@Sun.COM nai->ai_addrlen = sizeof (struct sockaddr_in);
16010023SGordon.Ross@Sun.COM nai->ai_addr = sap;
16110023SGordon.Ross@Sun.COM
16210023SGordon.Ross@Sun.COM *res = nai;
16310023SGordon.Ross@Sun.COM return (0);
16410023SGordon.Ross@Sun.COM
16510023SGordon.Ross@Sun.COM nomem:
16610023SGordon.Ross@Sun.COM err = EAI_MEMORY;
16710023SGordon.Ross@Sun.COM out:
16810023SGordon.Ross@Sun.COM if (nai != NULL)
16910023SGordon.Ross@Sun.COM free(nai);
17010023SGordon.Ross@Sun.COM if (sap)
17110023SGordon.Ross@Sun.COM free(sap);
17210023SGordon.Ross@Sun.COM if (ucname)
17310023SGordon.Ross@Sun.COM free(ucname);
17410023SGordon.Ross@Sun.COM *res = NULL;
17510023SGordon.Ross@Sun.COM
17610023SGordon.Ross@Sun.COM return (err);
17710023SGordon.Ross@Sun.COM }
1786007Sthurlow
1796007Sthurlow int
nbns_resolvename(const char * name,struct nb_ctx * ctx,struct sockaddr ** adpp)1806007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
1816007Sthurlow {
1826007Sthurlow struct nbns_rq *rqp;
1836007Sthurlow struct nb_name nn;
1846007Sthurlow struct nbns_rr rr;
1856007Sthurlow struct sockaddr_in *dest;
1866007Sthurlow int error, rdrcount, len;
1876007Sthurlow
18810023SGordon.Ross@Sun.COM if (strlen(name) >= NB_NAMELEN)
1896007Sthurlow return (NBERROR(NBERR_NAMETOOLONG));
1906007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
1916007Sthurlow if (error)
1926007Sthurlow return (error);
1936007Sthurlow /*
1946007Sthurlow * Pad the name with blanks, but
1956007Sthurlow * leave the "type" byte NULL.
1966007Sthurlow * nb_name_encode adds the type.
1976007Sthurlow */
1986007Sthurlow bzero(&nn, sizeof (nn));
1996007Sthurlow snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
2006007Sthurlow nn.nn_type = NBT_SERVER;
2016007Sthurlow nn.nn_scope = ctx->nb_scope;
2026007Sthurlow rqp->nr_nmflags = NBNS_NMFLAG_RD;
2036007Sthurlow rqp->nr_qdname = &nn;
2046007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
2056007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2066007Sthurlow rqp->nr_qdcount = 1;
2076007Sthurlow rqp->nr_maxretry = 5;
2086007Sthurlow
2096007Sthurlow error = nbns_rq_prepare(rqp);
2106007Sthurlow if (error) {
2116007Sthurlow nbns_rq_done(rqp);
2126007Sthurlow return (error);
2136007Sthurlow }
2146007Sthurlow rdrcount = NBNS_MAXREDIRECTS;
2156007Sthurlow for (;;) {
2166007Sthurlow error = nbns_rq(rqp);
2176007Sthurlow if (error)
2186007Sthurlow break;
2196007Sthurlow if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
2206007Sthurlow /*
2216007Sthurlow * Not an authoritative answer. Query again
2226007Sthurlow * using the NS address in the 2nd record.
2236007Sthurlow */
2246007Sthurlow if (rdrcount-- == 0) {
2256007Sthurlow error = NBERROR(NBERR_TOOMANYREDIRECTS);
2266007Sthurlow break;
2276007Sthurlow }
2286007Sthurlow error = nbns_rq_getrr(rqp, &rr);
2296007Sthurlow if (error)
2306007Sthurlow break;
2316007Sthurlow error = nbns_rq_getrr(rqp, &rr);
2326007Sthurlow if (error)
2336007Sthurlow break;
2346007Sthurlow bcopy(rr.rr_data, &rqp->nr_dest, 4);
2356007Sthurlow continue;
2366007Sthurlow }
2376007Sthurlow if (rqp->nr_rpancount == 0) {
2386007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND);
2396007Sthurlow break;
2406007Sthurlow }
2416007Sthurlow error = nbns_rq_getrr(rqp, &rr);
2426007Sthurlow if (error)
2436007Sthurlow break;
2446007Sthurlow len = sizeof (struct sockaddr_in);
2456007Sthurlow dest = malloc(len);
2466007Sthurlow if (dest == NULL)
2476007Sthurlow return (ENOMEM);
2486007Sthurlow bzero(dest, len);
2496007Sthurlow /*
25010023SGordon.Ross@Sun.COM * Solaris sockaddr_in doesn't a sin_len field.
2516007Sthurlow * dest->sin_len = len;
2526007Sthurlow */
25310023SGordon.Ross@Sun.COM dest->sin_family = AF_NETBIOS; /* nb_lib.h */
2546007Sthurlow bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
2556007Sthurlow *adpp = (struct sockaddr *)dest;
2566007Sthurlow ctx->nb_lastns = rqp->nr_sender;
2576007Sthurlow break;
2586007Sthurlow }
2596007Sthurlow nbns_rq_done(rqp);
2606007Sthurlow return (error);
2616007Sthurlow }
2626007Sthurlow
26310023SGordon.Ross@Sun.COM /*
26410023SGordon.Ross@Sun.COM * NB: system, workgroup are both NB_NAMELEN
26510023SGordon.Ross@Sun.COM */
2666007Sthurlow int
nbns_getnodestatus(struct nb_ctx * ctx,struct in_addr * targethost,char * system,char * workgroup)26710023SGordon.Ross@Sun.COM nbns_getnodestatus(struct nb_ctx *ctx,
26810023SGordon.Ross@Sun.COM struct in_addr *targethost, char *system, char *workgroup)
2696007Sthurlow {
2706007Sthurlow struct nbns_rq *rqp;
2716007Sthurlow struct nbns_rr rr;
2726007Sthurlow struct nb_name nn;
2736007Sthurlow struct nbns_nr *nrp;
2746007Sthurlow char nrtype;
2756007Sthurlow char *cp, *retname = NULL;
2766007Sthurlow unsigned char nrcount;
27710023SGordon.Ross@Sun.COM int error, i, foundserver = 0, foundgroup = 0;
2786007Sthurlow
2796007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
2806007Sthurlow if (error)
2816007Sthurlow return (error);
2826007Sthurlow bzero(&nn, sizeof (nn));
2836007Sthurlow strcpy((char *)nn.nn_name, "*");
2846007Sthurlow nn.nn_scope = ctx->nb_scope;
2856007Sthurlow nn.nn_type = NBT_WKSTA;
2866007Sthurlow rqp->nr_nmflags = 0;
2876007Sthurlow rqp->nr_qdname = &nn;
2886007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
2896007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
2906007Sthurlow rqp->nr_qdcount = 1;
2916007Sthurlow rqp->nr_maxretry = 2;
2926007Sthurlow
29310023SGordon.Ross@Sun.COM rqp->nr_dest = *targethost;
2946007Sthurlow error = nbns_rq_prepare(rqp);
2956007Sthurlow if (error) {
2966007Sthurlow nbns_rq_done(rqp);
2976007Sthurlow return (error);
2986007Sthurlow }
2996007Sthurlow
3006007Sthurlow /*
3016007Sthurlow * Darwin had a loop here, allowing redirect, etc.
3026007Sthurlow * but we only handle point-to-point for node status.
3036007Sthurlow */
3046007Sthurlow error = nbns_rq(rqp);
3056007Sthurlow if (error)
3066007Sthurlow goto out;
3076007Sthurlow if (rqp->nr_rpancount == 0) {
3086007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND);
3096007Sthurlow goto out;
3106007Sthurlow }
3116007Sthurlow error = nbns_rq_getrr(rqp, &rr);
3126007Sthurlow if (error)
3136007Sthurlow goto out;
3146007Sthurlow
3156007Sthurlow /* Compiler didn't like cast on lvalue++ */
3166007Sthurlow nrcount = *((unsigned char *)rr.rr_data);
3176007Sthurlow rr.rr_data++;
3186007Sthurlow /* LINTED */
3196007Sthurlow for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
3206007Sthurlow i <= nrcount; ++i, ++nrp) {
3216007Sthurlow nrtype = nrp->ns_name[NB_NAMELEN-1];
3226007Sthurlow /* Terminate the string: */
3236007Sthurlow nrp->ns_name[NB_NAMELEN-1] = (char)0;
3246007Sthurlow /* Strip off trailing spaces */
3256007Sthurlow for (cp = &nrp->ns_name[NB_NAMELEN-2];
3266007Sthurlow cp >= nrp->ns_name; --cp) {
3276007Sthurlow if (*cp != (char)0x20)
3286007Sthurlow break;
3296007Sthurlow *cp = (char)0;
3306007Sthurlow }
3316007Sthurlow nrp->ns_flags = ntohs(nrp->ns_flags);
33210023SGordon.Ross@Sun.COM DPRINT(" %s[%02x] Flags 0x%x",
33310023SGordon.Ross@Sun.COM nrp->ns_name, nrtype, nrp->ns_flags);
3346007Sthurlow if (nrp->ns_flags & NBNS_GROUPFLG) {
3356007Sthurlow if (!foundgroup ||
3366007Sthurlow (foundgroup != NBT_WKSTA+1 &&
3376007Sthurlow nrtype == NBT_WKSTA)) {
33810023SGordon.Ross@Sun.COM strlcpy(workgroup, nrp->ns_name,
33910023SGordon.Ross@Sun.COM NB_NAMELEN);
3406007Sthurlow foundgroup = nrtype+1;
3416007Sthurlow }
3426007Sthurlow } else {
3436007Sthurlow /*
3446007Sthurlow * Track at least ONE name, in case
3456007Sthurlow * no server name is found
3466007Sthurlow */
3476007Sthurlow retname = nrp->ns_name;
3486007Sthurlow }
34910023SGordon.Ross@Sun.COM /*
35010023SGordon.Ross@Sun.COM * Keep the first NBT_SERVER name.
35110023SGordon.Ross@Sun.COM */
35210023SGordon.Ross@Sun.COM if (nrtype == NBT_SERVER && foundserver == 0) {
35310023SGordon.Ross@Sun.COM strlcpy(system, nrp->ns_name,
35410023SGordon.Ross@Sun.COM NB_NAMELEN);
3556007Sthurlow foundserver = 1;
3566007Sthurlow }
3576007Sthurlow }
358*12556SGordon.Ross@Sun.COM if (foundserver == 0 && retname != NULL)
35910023SGordon.Ross@Sun.COM strlcpy(system, retname, NB_NAMELEN);
3606007Sthurlow ctx->nb_lastns = rqp->nr_sender;
3616007Sthurlow
3626007Sthurlow out:
3636007Sthurlow nbns_rq_done(rqp);
3646007Sthurlow return (error);
3656007Sthurlow }
3666007Sthurlow
3676007Sthurlow int
nbns_rq_create(int opcode,struct nb_ctx * ctx,struct nbns_rq ** rqpp)3686007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
3696007Sthurlow {
3706007Sthurlow struct nbns_rq *rqp;
3716007Sthurlow static uint16_t trnid;
3726007Sthurlow int error;
3736007Sthurlow
3746007Sthurlow if (trnid == 0)
3756007Sthurlow trnid = getpid();
3766007Sthurlow rqp = malloc(sizeof (*rqp));
3776007Sthurlow if (rqp == NULL)
3786007Sthurlow return (ENOMEM);
3796007Sthurlow bzero(rqp, sizeof (*rqp));
38011332SGordon.Ross@Sun.COM error = mb_init_sz(&rqp->nr_rq, NBDG_MAXSIZE);
3816007Sthurlow if (error) {
3826007Sthurlow free(rqp);
3836007Sthurlow return (error);
3846007Sthurlow }
3856007Sthurlow rqp->nr_opcode = opcode;
3866007Sthurlow rqp->nr_nbd = ctx;
3876007Sthurlow rqp->nr_trnid = trnid++;
3886007Sthurlow *rqpp = rqp;
3896007Sthurlow return (0);
3906007Sthurlow }
3916007Sthurlow
3926007Sthurlow void
nbns_rq_done(struct nbns_rq * rqp)3936007Sthurlow nbns_rq_done(struct nbns_rq *rqp)
3946007Sthurlow {
3956007Sthurlow if (rqp == NULL)
3966007Sthurlow return;
3976007Sthurlow if (rqp->nr_fd >= 0)
3986007Sthurlow close(rqp->nr_fd);
3996007Sthurlow mb_done(&rqp->nr_rq);
4006007Sthurlow mb_done(&rqp->nr_rp);
4016007Sthurlow if (rqp->nr_if)
4026007Sthurlow free(rqp->nr_if);
4036007Sthurlow free(rqp);
4046007Sthurlow }
4056007Sthurlow
4066007Sthurlow /*
4076007Sthurlow * Extract resource record from the packet. Assume that there is only
4086007Sthurlow * one mbuf.
4096007Sthurlow */
4106007Sthurlow int
nbns_rq_getrr(struct nbns_rq * rqp,struct nbns_rr * rrp)4116007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
4126007Sthurlow {
4136007Sthurlow struct mbdata *mbp = &rqp->nr_rp;
4146007Sthurlow uchar_t *cp;
4156007Sthurlow int error, len;
4166007Sthurlow
4176007Sthurlow bzero(rrp, sizeof (*rrp));
4186007Sthurlow cp = (uchar_t *)mbp->mb_pos;
4196007Sthurlow len = nb_encname_len(cp);
4206007Sthurlow if (len < 1)
4216007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
4226007Sthurlow rrp->rr_name = cp;
42311332SGordon.Ross@Sun.COM error = md_get_mem(mbp, NULL, len, MB_MSYSTEM);
4246007Sthurlow if (error)
4256007Sthurlow return (error);
42611332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rrp->rr_type);
42711332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rrp->rr_class);
42811332SGordon.Ross@Sun.COM md_get_uint32be(mbp, &rrp->rr_ttl);
42911332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rrp->rr_rdlength);
4306007Sthurlow rrp->rr_data = (uchar_t *)mbp->mb_pos;
43111332SGordon.Ross@Sun.COM error = md_get_mem(mbp, NULL, rrp->rr_rdlength, MB_MSYSTEM);
4326007Sthurlow return (error);
4336007Sthurlow }
4346007Sthurlow
4356007Sthurlow int
nbns_rq_prepare(struct nbns_rq * rqp)4366007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp)
4376007Sthurlow {
4386007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
4396007Sthurlow struct mbdata *mbp = &rqp->nr_rq;
4406007Sthurlow uint16_t ofr; /* opcode, flags, rcode */
44110023SGordon.Ross@Sun.COM int error;
4426007Sthurlow
44311332SGordon.Ross@Sun.COM error = mb_init_sz(&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);
45811332SGordon.Ross@Sun.COM error = mb_put_uint16be(mbp, rqp->nr_arcount);
4596007Sthurlow if (rqp->nr_qdcount) {
4606007Sthurlow if (rqp->nr_qdcount > 1)
4616007Sthurlow return (EINVAL);
46211332SGordon.Ross@Sun.COM (void) nb_name_encode(mbp, rqp->nr_qdname);
4636007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdtype);
46411332SGordon.Ross@Sun.COM error = mb_put_uint16be(mbp, rqp->nr_qdclass);
4656007Sthurlow }
46611332SGordon.Ross@Sun.COM if (error)
46711332SGordon.Ross@Sun.COM return (error);
46811332SGordon.Ross@Sun.COM error = m_lineup(mbp->mb_top, &mbp->mb_top);
46911332SGordon.Ross@Sun.COM if (error)
47011332SGordon.Ross@Sun.COM return (error);
4716007Sthurlow if (ctx->nb_timo == 0)
4726007Sthurlow ctx->nb_timo = 1; /* by default 1 second */
4736007Sthurlow return (0);
4746007Sthurlow }
4756007Sthurlow
4766007Sthurlow static int
nbns_rq_recv(struct nbns_rq * rqp)4776007Sthurlow nbns_rq_recv(struct nbns_rq *rqp)
4786007Sthurlow {
4796007Sthurlow struct mbdata *mbp = &rqp->nr_rp;
4806007Sthurlow void *rpdata = mtod(mbp->mb_top, void *);
4816007Sthurlow fd_set rd, wr, ex;
4826007Sthurlow struct timeval tv;
4836007Sthurlow struct sockaddr_in sender;
4846007Sthurlow int s = rqp->nr_fd;
4856007Sthurlow int n, len;
4866007Sthurlow
4876007Sthurlow FD_ZERO(&rd);
4886007Sthurlow FD_ZERO(&wr);
4896007Sthurlow FD_ZERO(&ex);
4906007Sthurlow FD_SET(s, &rd);
4916007Sthurlow
4926007Sthurlow tv.tv_sec = rqp->nr_nbd->nb_timo;
4936007Sthurlow tv.tv_usec = 0;
4946007Sthurlow
4956007Sthurlow n = select(s + 1, &rd, &wr, &ex, &tv);
4966007Sthurlow if (n == -1)
4976007Sthurlow return (-1);
4986007Sthurlow if (n == 0)
4996007Sthurlow return (ETIMEDOUT);
5006007Sthurlow if (FD_ISSET(s, &rd) == 0)
5016007Sthurlow return (ETIMEDOUT);
5026007Sthurlow len = sizeof (sender);
5036007Sthurlow n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
5046007Sthurlow (struct sockaddr *)&sender, &len);
5056007Sthurlow if (n < 0)
5066007Sthurlow return (errno);
5076007Sthurlow mbp->mb_top->m_len = mbp->mb_count = n;
5086007Sthurlow rqp->nr_sender = sender;
5096007Sthurlow return (0);
5106007Sthurlow }
5116007Sthurlow
5126007Sthurlow static int
nbns_rq_opensocket(struct nbns_rq * rqp)5136007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp)
5146007Sthurlow {
5156007Sthurlow struct sockaddr_in locaddr;
5166007Sthurlow int opt = 1, s;
5176007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
5186007Sthurlow
5196007Sthurlow s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
5206007Sthurlow if (s < 0)
5216007Sthurlow return (errno);
5226007Sthurlow if (ctx->nb_flags & NBCF_BC_ENABLE) {
5236007Sthurlow if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
5246007Sthurlow sizeof (opt)) < 0)
5256007Sthurlow return (errno);
5266007Sthurlow }
5276007Sthurlow if (is_system_labeled())
5286007Sthurlow (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
5296007Sthurlow sizeof (opt));
5306007Sthurlow bzero(&locaddr, sizeof (locaddr));
5316007Sthurlow locaddr.sin_family = AF_INET;
5326007Sthurlow /* locaddr.sin_len = sizeof (locaddr); */
5336007Sthurlow if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
5346007Sthurlow return (errno);
5356007Sthurlow return (0);
5366007Sthurlow }
5376007Sthurlow
5386007Sthurlow static int
nbns_rq_send(struct nbns_rq * rqp,in_addr_t ina)5396007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
5406007Sthurlow {
5416007Sthurlow struct sockaddr_in dest;
5426007Sthurlow struct mbdata *mbp = &rqp->nr_rq;
5436007Sthurlow int s = rqp->nr_fd;
5446007Sthurlow uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
5456007Sthurlow uint16_t *datap;
5466007Sthurlow uint8_t nmflags;
5476007Sthurlow int rc;
5486007Sthurlow
5496007Sthurlow bzero(&dest, sizeof (dest));
5506007Sthurlow dest.sin_family = AF_INET;
55110023SGordon.Ross@Sun.COM dest.sin_port = htons(IPPORT_NETBIOS_NS);
5526007Sthurlow dest.sin_addr.s_addr = ina;
5536007Sthurlow
5546007Sthurlow if (ina == INADDR_BROADCAST) {
5556007Sthurlow /* Turn on the broadcast bit. */
5566007Sthurlow nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
5576007Sthurlow /*LINTED*/
5586007Sthurlow datap = mtod(mbp->mb_top, uint16_t *);
5596007Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) |
5606007Sthurlow ((nmflags & 0x7F) << 4); /* rcode=0 */
5616007Sthurlow ofr_save = datap[1];
5626007Sthurlow datap[1] = htons(ofr);
5636007Sthurlow }
5646007Sthurlow
5656007Sthurlow rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
5666007Sthurlow (struct sockaddr *)&dest, sizeof (dest));
5676007Sthurlow
5686007Sthurlow if (ina == INADDR_BROADCAST) {
5696007Sthurlow /* Turn the broadcast bit back off. */
5706007Sthurlow datap[1] = ofr_save;
5716007Sthurlow }
5726007Sthurlow
5736007Sthurlow
5746007Sthurlow if (rc < 0)
5756007Sthurlow return (errno);
5766007Sthurlow
5776007Sthurlow return (0);
5786007Sthurlow }
5796007Sthurlow
5806007Sthurlow int
nbns_rq(struct nbns_rq * rqp)5816007Sthurlow nbns_rq(struct nbns_rq *rqp)
5826007Sthurlow {
5836007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd;
5846007Sthurlow struct mbdata *mbp = &rqp->nr_rq;
5856007Sthurlow uint16_t ofr, rpid;
5866007Sthurlow int error, tries, maxretry;
5876007Sthurlow
5886007Sthurlow error = nbns_rq_opensocket(rqp);
5896007Sthurlow if (error)
5906007Sthurlow return (error);
5916007Sthurlow
5926007Sthurlow maxretry = rqp->nr_maxretry;
5936007Sthurlow for (tries = 0; tries < maxretry; tries++) {
5946007Sthurlow
5956007Sthurlow /*
5966007Sthurlow * Minor hack: If nr_dest is set, send there only.
5976007Sthurlow * Used by _getnodestatus, _resolvname redirects.
5986007Sthurlow */
5996007Sthurlow if (rqp->nr_dest.s_addr) {
6006007Sthurlow error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
6016007Sthurlow if (error) {
6026007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6036007Sthurlow "nbns error %d sending to %s"),
6046007Sthurlow 0, error, inet_ntoa(rqp->nr_dest));
6056007Sthurlow }
6066007Sthurlow goto do_recv;
6076007Sthurlow }
6086007Sthurlow
6096007Sthurlow if (ctx->nb_wins1) {
6106007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins1);
6116007Sthurlow if (error) {
6126007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6136007Sthurlow "nbns error %d sending to wins1"),
6146007Sthurlow 0, error);
6156007Sthurlow }
6166007Sthurlow }
6176007Sthurlow
6186007Sthurlow if (ctx->nb_wins2 && (tries > 0)) {
6196007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins2);
6206007Sthurlow if (error) {
6216007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6226007Sthurlow "nbns error %d sending to wins2"),
6236007Sthurlow 0, error);
6246007Sthurlow }
6256007Sthurlow }
6266007Sthurlow
6276007Sthurlow /*
6286007Sthurlow * If broadcast is enabled, start broadcasting
6296007Sthurlow * only after wins servers fail to respond, or
6306007Sthurlow * immediately if no WINS servers configured.
6316007Sthurlow */
6326007Sthurlow if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
6336007Sthurlow ((tries > 1) || (ctx->nb_wins1 == 0))) {
6346007Sthurlow error = nbns_rq_send(rqp, INADDR_BROADCAST);
6356007Sthurlow if (error) {
6366007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6376007Sthurlow "nbns error %d sending broadcast"),
6386007Sthurlow 0, error);
6396007Sthurlow }
6406007Sthurlow }
6416007Sthurlow
6426007Sthurlow /*
6436007Sthurlow * Wait for responses from ANY of the above.
6446007Sthurlow */
6456007Sthurlow do_recv:
6466007Sthurlow error = nbns_rq_recv(rqp);
6476007Sthurlow if (error == ETIMEDOUT)
6486007Sthurlow continue;
6496007Sthurlow if (error) {
6506007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
6516007Sthurlow "nbns recv error %d"),
6526007Sthurlow 0, error);
6536007Sthurlow return (error);
6546007Sthurlow }
6556007Sthurlow
6566007Sthurlow mbp = &rqp->nr_rp;
6576007Sthurlow if (mbp->mb_count < 12)
6586007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
65911332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rpid);
6606007Sthurlow if (rpid != rqp->nr_trnid)
6616007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE));
6626007Sthurlow break;
6636007Sthurlow }
66410023SGordon.Ross@Sun.COM if (tries == maxretry)
66510023SGordon.Ross@Sun.COM return (NBERROR(NBERR_HOSTNOTFOUND));
6666007Sthurlow
66711332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &ofr);
6686007Sthurlow rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
6696007Sthurlow rqp->nr_rprcode = ofr & 0xf;
6706007Sthurlow if (rqp->nr_rprcode)
6716007Sthurlow return (NBERROR(rqp->nr_rprcode));
67211332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rpid); /* QDCOUNT */
67311332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rqp->nr_rpancount);
67411332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rqp->nr_rpnscount);
67511332SGordon.Ross@Sun.COM md_get_uint16be(mbp, &rqp->nr_rparcount);
6766007Sthurlow return (0);
6776007Sthurlow }
678