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 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 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 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 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 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 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 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 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 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 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 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