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