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*8271SGordon.Ross@Sun.COM #include "private.h" 59*8271SGordon.Ross@Sun.COM 60*8271SGordon.Ross@Sun.COM /* 61*8271SGordon.Ross@Sun.COM * nbns request 62*8271SGordon.Ross@Sun.COM */ 63*8271SGordon.Ross@Sun.COM struct nbns_rq { 64*8271SGordon.Ross@Sun.COM int nr_opcode; 65*8271SGordon.Ross@Sun.COM int nr_nmflags; 66*8271SGordon.Ross@Sun.COM int nr_rcode; 67*8271SGordon.Ross@Sun.COM int nr_qdcount; 68*8271SGordon.Ross@Sun.COM int nr_ancount; 69*8271SGordon.Ross@Sun.COM int nr_nscount; 70*8271SGordon.Ross@Sun.COM int nr_arcount; 71*8271SGordon.Ross@Sun.COM struct nb_name *nr_qdname; 72*8271SGordon.Ross@Sun.COM uint16_t nr_qdtype; 73*8271SGordon.Ross@Sun.COM uint16_t nr_qdclass; 74*8271SGordon.Ross@Sun.COM struct in_addr nr_dest; /* receiver of query */ 75*8271SGordon.Ross@Sun.COM struct sockaddr_in nr_sender; /* sender of response */ 76*8271SGordon.Ross@Sun.COM int nr_rpnmflags; 77*8271SGordon.Ross@Sun.COM int nr_rprcode; 78*8271SGordon.Ross@Sun.COM uint16_t nr_rpancount; 79*8271SGordon.Ross@Sun.COM uint16_t nr_rpnscount; 80*8271SGordon.Ross@Sun.COM uint16_t nr_rparcount; 81*8271SGordon.Ross@Sun.COM uint16_t nr_trnid; 82*8271SGordon.Ross@Sun.COM struct nb_ctx *nr_nbd; 83*8271SGordon.Ross@Sun.COM struct mbdata nr_rq; 84*8271SGordon.Ross@Sun.COM struct mbdata nr_rp; 85*8271SGordon.Ross@Sun.COM struct nb_ifdesc *nr_if; 86*8271SGordon.Ross@Sun.COM int nr_flags; 87*8271SGordon.Ross@Sun.COM int nr_fd; 88*8271SGordon.Ross@Sun.COM int nr_maxretry; 89*8271SGordon.Ross@Sun.COM }; 90*8271SGordon.Ross@Sun.COM typedef struct nbns_rq nbns_rq_t; 91*8271SGordon.Ross@Sun.COM 926007Sthurlow static int nbns_rq_create(int opcode, struct nb_ctx *ctx, 936007Sthurlow struct nbns_rq **rqpp); 946007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp); 956007Sthurlow static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp); 966007Sthurlow static int nbns_rq_prepare(struct nbns_rq *rqp); 976007Sthurlow static int nbns_rq(struct nbns_rq *rqp); 986007Sthurlow 996007Sthurlow static struct nb_ifdesc *nb_iflist = NULL; 1006007Sthurlow 1016007Sthurlow int 1026007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp) 1036007Sthurlow { 1046007Sthurlow struct nbns_rq *rqp; 1056007Sthurlow struct nb_name nn; 1066007Sthurlow struct nbns_rr rr; 1076007Sthurlow struct sockaddr_in *dest; 1086007Sthurlow int error, rdrcount, len; 1096007Sthurlow 1106007Sthurlow if (strlen(name) > NB_NAMELEN) 1116007Sthurlow return (NBERROR(NBERR_NAMETOOLONG)); 1126007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); 1136007Sthurlow if (error) 1146007Sthurlow return (error); 1156007Sthurlow /* 1166007Sthurlow * Pad the name with blanks, but 1176007Sthurlow * leave the "type" byte NULL. 1186007Sthurlow * nb_name_encode adds the type. 1196007Sthurlow */ 1206007Sthurlow bzero(&nn, sizeof (nn)); 1216007Sthurlow snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name); 1226007Sthurlow nn.nn_type = NBT_SERVER; 1236007Sthurlow nn.nn_scope = ctx->nb_scope; 1246007Sthurlow rqp->nr_nmflags = NBNS_NMFLAG_RD; 1256007Sthurlow rqp->nr_qdname = &nn; 1266007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB; 1276007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; 1286007Sthurlow rqp->nr_qdcount = 1; 1296007Sthurlow rqp->nr_maxretry = 5; 1306007Sthurlow 1316007Sthurlow error = nbns_rq_prepare(rqp); 1326007Sthurlow if (error) { 1336007Sthurlow nbns_rq_done(rqp); 1346007Sthurlow return (error); 1356007Sthurlow } 1366007Sthurlow rdrcount = NBNS_MAXREDIRECTS; 1376007Sthurlow for (;;) { 1386007Sthurlow error = nbns_rq(rqp); 1396007Sthurlow if (error) 1406007Sthurlow break; 1416007Sthurlow if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) { 1426007Sthurlow /* 1436007Sthurlow * Not an authoritative answer. Query again 1446007Sthurlow * using the NS address in the 2nd record. 1456007Sthurlow */ 1466007Sthurlow if (rdrcount-- == 0) { 1476007Sthurlow error = NBERROR(NBERR_TOOMANYREDIRECTS); 1486007Sthurlow break; 1496007Sthurlow } 1506007Sthurlow error = nbns_rq_getrr(rqp, &rr); 1516007Sthurlow if (error) 1526007Sthurlow break; 1536007Sthurlow error = nbns_rq_getrr(rqp, &rr); 1546007Sthurlow if (error) 1556007Sthurlow break; 1566007Sthurlow bcopy(rr.rr_data, &rqp->nr_dest, 4); 1576007Sthurlow continue; 1586007Sthurlow } 1596007Sthurlow if (rqp->nr_rpancount == 0) { 1606007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND); 1616007Sthurlow break; 1626007Sthurlow } 1636007Sthurlow error = nbns_rq_getrr(rqp, &rr); 1646007Sthurlow if (error) 1656007Sthurlow break; 1666007Sthurlow len = sizeof (struct sockaddr_in); 1676007Sthurlow dest = malloc(len); 1686007Sthurlow if (dest == NULL) 1696007Sthurlow return (ENOMEM); 1706007Sthurlow bzero(dest, len); 1716007Sthurlow /* 1726007Sthurlow * Solaris sockaddr_in doesn't have this field. 1736007Sthurlow * dest->sin_len = len; 1746007Sthurlow */ 1756007Sthurlow dest->sin_family = AF_INET; 1766007Sthurlow bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4); 1776007Sthurlow dest->sin_port = htons(SMB_TCP_PORT); 1786007Sthurlow *adpp = (struct sockaddr *)dest; 1796007Sthurlow ctx->nb_lastns = rqp->nr_sender; 1806007Sthurlow break; 1816007Sthurlow } 1826007Sthurlow nbns_rq_done(rqp); 1836007Sthurlow return (error); 1846007Sthurlow } 1856007Sthurlow 1866007Sthurlow static char * 1876007Sthurlow smb_optstrncpy(char *d, char *s, unsigned maxlen) 1886007Sthurlow { 1896007Sthurlow if (d && s) { 1906007Sthurlow strncpy(d, s, maxlen); 1916007Sthurlow d[maxlen] = (char)0; 1926007Sthurlow } 1936007Sthurlow return (d); 1946007Sthurlow } 1956007Sthurlow 1966007Sthurlow 1976007Sthurlow int 1986007Sthurlow nbns_getnodestatus(struct sockaddr *targethost, 1996007Sthurlow struct nb_ctx *ctx, char *system, char *workgroup) 2006007Sthurlow { 2016007Sthurlow struct nbns_rq *rqp; 2026007Sthurlow struct nbns_rr rr; 2036007Sthurlow struct nb_name nn; 2046007Sthurlow struct nbns_nr *nrp; 2056007Sthurlow char nrtype; 2066007Sthurlow char *cp, *retname = NULL; 2076007Sthurlow struct sockaddr_in *dest; 2086007Sthurlow unsigned char nrcount; 2096007Sthurlow int error, rdrcount, i, foundserver = 0, foundgroup = 0; 2106007Sthurlow 2116007Sthurlow if (targethost->sa_family != AF_INET) 2126007Sthurlow return (EINVAL); 2136007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); 2146007Sthurlow if (error) 2156007Sthurlow return (error); 2166007Sthurlow bzero(&nn, sizeof (nn)); 2176007Sthurlow strcpy((char *)nn.nn_name, "*"); 2186007Sthurlow nn.nn_scope = ctx->nb_scope; 2196007Sthurlow nn.nn_type = NBT_WKSTA; 2206007Sthurlow rqp->nr_nmflags = 0; 2216007Sthurlow rqp->nr_qdname = &nn; 2226007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT; 2236007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; 2246007Sthurlow rqp->nr_qdcount = 1; 2256007Sthurlow rqp->nr_maxretry = 2; 2266007Sthurlow 2276007Sthurlow /* LINTED */ 2286007Sthurlow dest = (struct sockaddr_in *)targethost; 2296007Sthurlow rqp->nr_dest = dest->sin_addr; 2306007Sthurlow 2316007Sthurlow error = nbns_rq_prepare(rqp); 2326007Sthurlow if (error) { 2336007Sthurlow nbns_rq_done(rqp); 2346007Sthurlow return (error); 2356007Sthurlow } 2366007Sthurlow 2376007Sthurlow /* 2386007Sthurlow * Darwin had a loop here, allowing redirect, etc. 2396007Sthurlow * but we only handle point-to-point for node status. 2406007Sthurlow */ 2416007Sthurlow error = nbns_rq(rqp); 2426007Sthurlow if (error) 2436007Sthurlow goto out; 2446007Sthurlow if (rqp->nr_rpancount == 0) { 2456007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND); 2466007Sthurlow goto out; 2476007Sthurlow } 2486007Sthurlow error = nbns_rq_getrr(rqp, &rr); 2496007Sthurlow if (error) 2506007Sthurlow goto out; 2516007Sthurlow 2526007Sthurlow /* Compiler didn't like cast on lvalue++ */ 2536007Sthurlow nrcount = *((unsigned char *)rr.rr_data); 2546007Sthurlow rr.rr_data++; 2556007Sthurlow /* LINTED */ 2566007Sthurlow for (i = 1, nrp = (struct nbns_nr *)rr.rr_data; 2576007Sthurlow i <= nrcount; ++i, ++nrp) { 2586007Sthurlow nrtype = nrp->ns_name[NB_NAMELEN-1]; 2596007Sthurlow /* Terminate the string: */ 2606007Sthurlow nrp->ns_name[NB_NAMELEN-1] = (char)0; 2616007Sthurlow /* Strip off trailing spaces */ 2626007Sthurlow for (cp = &nrp->ns_name[NB_NAMELEN-2]; 2636007Sthurlow cp >= nrp->ns_name; --cp) { 2646007Sthurlow if (*cp != (char)0x20) 2656007Sthurlow break; 2666007Sthurlow *cp = (char)0; 2676007Sthurlow } 2686007Sthurlow nrp->ns_flags = ntohs(nrp->ns_flags); 2696007Sthurlow if (nrp->ns_flags & NBNS_GROUPFLG) { 2706007Sthurlow if (!foundgroup || 2716007Sthurlow (foundgroup != NBT_WKSTA+1 && 2726007Sthurlow nrtype == NBT_WKSTA)) { 2736007Sthurlow smb_optstrncpy(workgroup, nrp->ns_name, 2746007Sthurlow SMB_MAXUSERNAMELEN); 2756007Sthurlow foundgroup = nrtype+1; 2766007Sthurlow } 2776007Sthurlow } else { 2786007Sthurlow /* 2796007Sthurlow * Track at least ONE name, in case 2806007Sthurlow * no server name is found 2816007Sthurlow */ 2826007Sthurlow retname = nrp->ns_name; 2836007Sthurlow } 2846007Sthurlow if (nrtype == NBT_SERVER) { 2856007Sthurlow smb_optstrncpy(system, nrp->ns_name, 2866007Sthurlow SMB_MAXSRVNAMELEN); 2876007Sthurlow foundserver = 1; 2886007Sthurlow } 2896007Sthurlow } 2906007Sthurlow if (!foundserver) 2916007Sthurlow smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN); 2926007Sthurlow ctx->nb_lastns = rqp->nr_sender; 2936007Sthurlow 2946007Sthurlow out: 2956007Sthurlow nbns_rq_done(rqp); 2966007Sthurlow return (error); 2976007Sthurlow } 2986007Sthurlow 2996007Sthurlow int 3006007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp) 3016007Sthurlow { 3026007Sthurlow struct nbns_rq *rqp; 3036007Sthurlow static uint16_t trnid; 3046007Sthurlow int error; 3056007Sthurlow 3066007Sthurlow if (trnid == 0) 3076007Sthurlow trnid = getpid(); 3086007Sthurlow rqp = malloc(sizeof (*rqp)); 3096007Sthurlow if (rqp == NULL) 3106007Sthurlow return (ENOMEM); 3116007Sthurlow bzero(rqp, sizeof (*rqp)); 3126007Sthurlow error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE); 3136007Sthurlow if (error) { 3146007Sthurlow free(rqp); 3156007Sthurlow return (error); 3166007Sthurlow } 3176007Sthurlow rqp->nr_opcode = opcode; 3186007Sthurlow rqp->nr_nbd = ctx; 3196007Sthurlow rqp->nr_trnid = trnid++; 3206007Sthurlow *rqpp = rqp; 3216007Sthurlow return (0); 3226007Sthurlow } 3236007Sthurlow 3246007Sthurlow void 3256007Sthurlow nbns_rq_done(struct nbns_rq *rqp) 3266007Sthurlow { 3276007Sthurlow if (rqp == NULL) 3286007Sthurlow return; 3296007Sthurlow if (rqp->nr_fd >= 0) 3306007Sthurlow close(rqp->nr_fd); 3316007Sthurlow mb_done(&rqp->nr_rq); 3326007Sthurlow mb_done(&rqp->nr_rp); 3336007Sthurlow if (rqp->nr_if) 3346007Sthurlow free(rqp->nr_if); 3356007Sthurlow free(rqp); 3366007Sthurlow } 3376007Sthurlow 3386007Sthurlow /* 3396007Sthurlow * Extract resource record from the packet. Assume that there is only 3406007Sthurlow * one mbuf. 3416007Sthurlow */ 3426007Sthurlow int 3436007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) 3446007Sthurlow { 3456007Sthurlow struct mbdata *mbp = &rqp->nr_rp; 3466007Sthurlow uchar_t *cp; 3476007Sthurlow int error, len; 3486007Sthurlow 3496007Sthurlow bzero(rrp, sizeof (*rrp)); 3506007Sthurlow cp = (uchar_t *)mbp->mb_pos; 3516007Sthurlow len = nb_encname_len(cp); 3526007Sthurlow if (len < 1) 3536007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 3546007Sthurlow rrp->rr_name = cp; 3556007Sthurlow error = mb_get_mem(mbp, NULL, len); 3566007Sthurlow if (error) 3576007Sthurlow return (error); 3586007Sthurlow mb_get_uint16be(mbp, &rrp->rr_type); 3596007Sthurlow mb_get_uint16be(mbp, &rrp->rr_class); 3606007Sthurlow mb_get_uint32be(mbp, &rrp->rr_ttl); 3616007Sthurlow mb_get_uint16be(mbp, &rrp->rr_rdlength); 3626007Sthurlow rrp->rr_data = (uchar_t *)mbp->mb_pos; 3636007Sthurlow error = mb_get_mem(mbp, NULL, rrp->rr_rdlength); 3646007Sthurlow return (error); 3656007Sthurlow } 3666007Sthurlow 3676007Sthurlow int 3686007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp) 3696007Sthurlow { 3706007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 3716007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 3726007Sthurlow uint16_t ofr; /* opcode, flags, rcode */ 3736007Sthurlow uchar_t *cp; 3746007Sthurlow int len, error; 3756007Sthurlow 3766007Sthurlow /* 3776007Sthurlow * Replacing with one argument. 3786007Sthurlow * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); 3796007Sthurlow */ 3806007Sthurlow error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); 3816007Sthurlow if (error) 3826007Sthurlow return (error); 3836007Sthurlow 3846007Sthurlow /* 3856007Sthurlow * When looked into the ethereal trace, 'nmblookup' command sets this 3866007Sthurlow * flag. We will also set. 3876007Sthurlow */ 3886007Sthurlow mb_put_uint16be(mbp, rqp->nr_trnid); 3896007Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) | 3906007Sthurlow ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */ 3916007Sthurlow mb_put_uint16be(mbp, ofr); 3926007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdcount); 3936007Sthurlow mb_put_uint16be(mbp, rqp->nr_ancount); 3946007Sthurlow mb_put_uint16be(mbp, rqp->nr_nscount); 3956007Sthurlow mb_put_uint16be(mbp, rqp->nr_arcount); 3966007Sthurlow if (rqp->nr_qdcount) { 3976007Sthurlow if (rqp->nr_qdcount > 1) 3986007Sthurlow return (EINVAL); 3996007Sthurlow len = nb_name_len(rqp->nr_qdname); 4006007Sthurlow error = mb_fit(mbp, len, (char **)&cp); 4016007Sthurlow if (error) 4026007Sthurlow return (error); 4036007Sthurlow nb_name_encode(rqp->nr_qdname, cp); 4046007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdtype); 4056007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdclass); 4066007Sthurlow } 4076007Sthurlow m_lineup(mbp->mb_top, &mbp->mb_top); 4086007Sthurlow if (ctx->nb_timo == 0) 4096007Sthurlow ctx->nb_timo = 1; /* by default 1 second */ 4106007Sthurlow return (0); 4116007Sthurlow } 4126007Sthurlow 4136007Sthurlow static int 4146007Sthurlow nbns_rq_recv(struct nbns_rq *rqp) 4156007Sthurlow { 4166007Sthurlow struct mbdata *mbp = &rqp->nr_rp; 4176007Sthurlow void *rpdata = mtod(mbp->mb_top, void *); 4186007Sthurlow fd_set rd, wr, ex; 4196007Sthurlow struct timeval tv; 4206007Sthurlow struct sockaddr_in sender; 4216007Sthurlow int s = rqp->nr_fd; 4226007Sthurlow int n, len; 4236007Sthurlow 4246007Sthurlow FD_ZERO(&rd); 4256007Sthurlow FD_ZERO(&wr); 4266007Sthurlow FD_ZERO(&ex); 4276007Sthurlow FD_SET(s, &rd); 4286007Sthurlow 4296007Sthurlow tv.tv_sec = rqp->nr_nbd->nb_timo; 4306007Sthurlow tv.tv_usec = 0; 4316007Sthurlow 4326007Sthurlow n = select(s + 1, &rd, &wr, &ex, &tv); 4336007Sthurlow if (n == -1) 4346007Sthurlow return (-1); 4356007Sthurlow if (n == 0) 4366007Sthurlow return (ETIMEDOUT); 4376007Sthurlow if (FD_ISSET(s, &rd) == 0) 4386007Sthurlow return (ETIMEDOUT); 4396007Sthurlow len = sizeof (sender); 4406007Sthurlow n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0, 4416007Sthurlow (struct sockaddr *)&sender, &len); 4426007Sthurlow if (n < 0) 4436007Sthurlow return (errno); 4446007Sthurlow mbp->mb_top->m_len = mbp->mb_count = n; 4456007Sthurlow rqp->nr_sender = sender; 4466007Sthurlow return (0); 4476007Sthurlow } 4486007Sthurlow 4496007Sthurlow static int 4506007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp) 4516007Sthurlow { 4526007Sthurlow struct sockaddr_in locaddr; 4536007Sthurlow int opt = 1, s; 4546007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 4556007Sthurlow 4566007Sthurlow s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0); 4576007Sthurlow if (s < 0) 4586007Sthurlow return (errno); 4596007Sthurlow if (ctx->nb_flags & NBCF_BC_ENABLE) { 4606007Sthurlow if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, 4616007Sthurlow sizeof (opt)) < 0) 4626007Sthurlow return (errno); 4636007Sthurlow } 4646007Sthurlow if (is_system_labeled()) 4656007Sthurlow (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt, 4666007Sthurlow sizeof (opt)); 4676007Sthurlow bzero(&locaddr, sizeof (locaddr)); 4686007Sthurlow locaddr.sin_family = AF_INET; 4696007Sthurlow /* locaddr.sin_len = sizeof (locaddr); */ 4706007Sthurlow if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0) 4716007Sthurlow return (errno); 4726007Sthurlow return (0); 4736007Sthurlow } 4746007Sthurlow 4756007Sthurlow static int 4766007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina) 4776007Sthurlow { 4786007Sthurlow struct sockaddr_in dest; 4796007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 4806007Sthurlow int s = rqp->nr_fd; 4816007Sthurlow uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */ 4826007Sthurlow uint16_t *datap; 4836007Sthurlow uint8_t nmflags; 4846007Sthurlow int rc; 4856007Sthurlow 4866007Sthurlow bzero(&dest, sizeof (dest)); 4876007Sthurlow dest.sin_family = AF_INET; 4886007Sthurlow dest.sin_port = htons(NBNS_UDP_PORT); 4896007Sthurlow dest.sin_addr.s_addr = ina; 4906007Sthurlow 4916007Sthurlow if (ina == INADDR_BROADCAST) { 4926007Sthurlow /* Turn on the broadcast bit. */ 4936007Sthurlow nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST; 4946007Sthurlow /*LINTED*/ 4956007Sthurlow datap = mtod(mbp->mb_top, uint16_t *); 4966007Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) | 4976007Sthurlow ((nmflags & 0x7F) << 4); /* rcode=0 */ 4986007Sthurlow ofr_save = datap[1]; 4996007Sthurlow datap[1] = htons(ofr); 5006007Sthurlow } 5016007Sthurlow 5026007Sthurlow rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0, 5036007Sthurlow (struct sockaddr *)&dest, sizeof (dest)); 5046007Sthurlow 5056007Sthurlow if (ina == INADDR_BROADCAST) { 5066007Sthurlow /* Turn the broadcast bit back off. */ 5076007Sthurlow datap[1] = ofr_save; 5086007Sthurlow } 5096007Sthurlow 5106007Sthurlow 5116007Sthurlow if (rc < 0) 5126007Sthurlow return (errno); 5136007Sthurlow 5146007Sthurlow return (0); 5156007Sthurlow } 5166007Sthurlow 5176007Sthurlow int 5186007Sthurlow nbns_rq(struct nbns_rq *rqp) 5196007Sthurlow { 5206007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 5216007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 5226007Sthurlow uint16_t ofr, rpid; 5236007Sthurlow uint8_t nmflags; 5246007Sthurlow int error, tries, maxretry; 5256007Sthurlow 5266007Sthurlow error = nbns_rq_opensocket(rqp); 5276007Sthurlow if (error) 5286007Sthurlow return (error); 5296007Sthurlow 5306007Sthurlow maxretry = rqp->nr_maxretry; 5316007Sthurlow for (tries = 0; tries < maxretry; tries++) { 5326007Sthurlow 5336007Sthurlow /* 5346007Sthurlow * Minor hack: If nr_dest is set, send there only. 5356007Sthurlow * Used by _getnodestatus, _resolvname redirects. 5366007Sthurlow */ 5376007Sthurlow if (rqp->nr_dest.s_addr) { 5386007Sthurlow error = nbns_rq_send(rqp, rqp->nr_dest.s_addr); 5396007Sthurlow if (error) { 5406007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5416007Sthurlow "nbns error %d sending to %s"), 5426007Sthurlow 0, error, inet_ntoa(rqp->nr_dest)); 5436007Sthurlow } 5446007Sthurlow goto do_recv; 5456007Sthurlow } 5466007Sthurlow 5476007Sthurlow if (ctx->nb_wins1) { 5486007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins1); 5496007Sthurlow if (error) { 5506007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5516007Sthurlow "nbns error %d sending to wins1"), 5526007Sthurlow 0, error); 5536007Sthurlow } 5546007Sthurlow } 5556007Sthurlow 5566007Sthurlow if (ctx->nb_wins2 && (tries > 0)) { 5576007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins2); 5586007Sthurlow if (error) { 5596007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5606007Sthurlow "nbns error %d sending to wins2"), 5616007Sthurlow 0, error); 5626007Sthurlow } 5636007Sthurlow } 5646007Sthurlow 5656007Sthurlow /* 5666007Sthurlow * If broadcast is enabled, start broadcasting 5676007Sthurlow * only after wins servers fail to respond, or 5686007Sthurlow * immediately if no WINS servers configured. 5696007Sthurlow */ 5706007Sthurlow if ((ctx->nb_flags & NBCF_BC_ENABLE) && 5716007Sthurlow ((tries > 1) || (ctx->nb_wins1 == 0))) { 5726007Sthurlow error = nbns_rq_send(rqp, INADDR_BROADCAST); 5736007Sthurlow if (error) { 5746007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5756007Sthurlow "nbns error %d sending broadcast"), 5766007Sthurlow 0, error); 5776007Sthurlow } 5786007Sthurlow } 5796007Sthurlow 5806007Sthurlow /* 5816007Sthurlow * Wait for responses from ANY of the above. 5826007Sthurlow */ 5836007Sthurlow do_recv: 5846007Sthurlow error = nbns_rq_recv(rqp); 5856007Sthurlow if (error == ETIMEDOUT) 5866007Sthurlow continue; 5876007Sthurlow if (error) { 5886007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 5896007Sthurlow "nbns recv error %d"), 5906007Sthurlow 0, error); 5916007Sthurlow return (error); 5926007Sthurlow } 5936007Sthurlow 5946007Sthurlow mbp = &rqp->nr_rp; 5956007Sthurlow if (mbp->mb_count < 12) 5966007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 5976007Sthurlow mb_get_uint16be(mbp, &rpid); 5986007Sthurlow if (rpid != rqp->nr_trnid) 5996007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 6006007Sthurlow break; 6016007Sthurlow } 6026007Sthurlow 6036007Sthurlow mb_get_uint16be(mbp, &ofr); 6046007Sthurlow rqp->nr_rpnmflags = (ofr >> 4) & 0x7F; 6056007Sthurlow rqp->nr_rprcode = ofr & 0xf; 6066007Sthurlow if (rqp->nr_rprcode) 6076007Sthurlow return (NBERROR(rqp->nr_rprcode)); 6086007Sthurlow mb_get_uint16be(mbp, &rpid); /* QDCOUNT */ 6096007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rpancount); 6106007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rpnscount); 6116007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rparcount); 6126007Sthurlow return (0); 6136007Sthurlow } 614