1*6007Sthurlow /* 2*6007Sthurlow * Copyright (c) 2000, Boris Popov 3*6007Sthurlow * All rights reserved. 4*6007Sthurlow * 5*6007Sthurlow * Redistribution and use in source and binary forms, with or without 6*6007Sthurlow * modification, are permitted provided that the following conditions 7*6007Sthurlow * are met: 8*6007Sthurlow * 1. Redistributions of source code must retain the above copyright 9*6007Sthurlow * notice, this list of conditions and the following disclaimer. 10*6007Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 11*6007Sthurlow * notice, this list of conditions and the following disclaimer in the 12*6007Sthurlow * documentation and/or other materials provided with the distribution. 13*6007Sthurlow * 3. All advertising materials mentioning features or use of this software 14*6007Sthurlow * must display the following acknowledgement: 15*6007Sthurlow * This product includes software developed by Boris Popov. 16*6007Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 17*6007Sthurlow * may be used to endorse or promote products derived from this software 18*6007Sthurlow * without specific prior written permission. 19*6007Sthurlow * 20*6007Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21*6007Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22*6007Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23*6007Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24*6007Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25*6007Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26*6007Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27*6007Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28*6007Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29*6007Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30*6007Sthurlow * SUCH DAMAGE. 31*6007Sthurlow * 32*6007Sthurlow * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $ 33*6007Sthurlow */ 34*6007Sthurlow 35*6007Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 36*6007Sthurlow 37*6007Sthurlow #include <sys/param.h> 38*6007Sthurlow #include <sys/socket.h> 39*6007Sthurlow #include <sys/time.h> 40*6007Sthurlow #include <ctype.h> 41*6007Sthurlow #include <netdb.h> 42*6007Sthurlow #include <errno.h> 43*6007Sthurlow #include <stdlib.h> 44*6007Sthurlow #include <string.h> 45*6007Sthurlow #include <strings.h> 46*6007Sthurlow #include <stdio.h> 47*6007Sthurlow #include <unistd.h> 48*6007Sthurlow #include <libintl.h> 49*6007Sthurlow 50*6007Sthurlow #include <netinet/in.h> 51*6007Sthurlow #include <arpa/inet.h> 52*6007Sthurlow #include <tsol/label.h> 53*6007Sthurlow 54*6007Sthurlow #define NB_NEEDRESOLVER 55*6007Sthurlow #include <netsmb/netbios.h> 56*6007Sthurlow #include <netsmb/smb_lib.h> 57*6007Sthurlow #include <netsmb/nb_lib.h> 58*6007Sthurlow #include <netsmb/mchain.h> 59*6007Sthurlow 60*6007Sthurlow static int nbns_rq_create(int opcode, struct nb_ctx *ctx, 61*6007Sthurlow struct nbns_rq **rqpp); 62*6007Sthurlow static void nbns_rq_done(struct nbns_rq *rqp); 63*6007Sthurlow static int nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp); 64*6007Sthurlow static int nbns_rq_prepare(struct nbns_rq *rqp); 65*6007Sthurlow static int nbns_rq(struct nbns_rq *rqp); 66*6007Sthurlow 67*6007Sthurlow static struct nb_ifdesc *nb_iflist = NULL; 68*6007Sthurlow 69*6007Sthurlow int 70*6007Sthurlow nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp) 71*6007Sthurlow { 72*6007Sthurlow struct nbns_rq *rqp; 73*6007Sthurlow struct nb_name nn; 74*6007Sthurlow struct nbns_rr rr; 75*6007Sthurlow struct sockaddr_in *dest; 76*6007Sthurlow int error, rdrcount, len; 77*6007Sthurlow 78*6007Sthurlow if (strlen(name) > NB_NAMELEN) 79*6007Sthurlow return (NBERROR(NBERR_NAMETOOLONG)); 80*6007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); 81*6007Sthurlow if (error) 82*6007Sthurlow return (error); 83*6007Sthurlow /* 84*6007Sthurlow * Pad the name with blanks, but 85*6007Sthurlow * leave the "type" byte NULL. 86*6007Sthurlow * nb_name_encode adds the type. 87*6007Sthurlow */ 88*6007Sthurlow bzero(&nn, sizeof (nn)); 89*6007Sthurlow snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name); 90*6007Sthurlow nn.nn_type = NBT_SERVER; 91*6007Sthurlow nn.nn_scope = ctx->nb_scope; 92*6007Sthurlow rqp->nr_nmflags = NBNS_NMFLAG_RD; 93*6007Sthurlow rqp->nr_qdname = &nn; 94*6007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB; 95*6007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; 96*6007Sthurlow rqp->nr_qdcount = 1; 97*6007Sthurlow rqp->nr_maxretry = 5; 98*6007Sthurlow 99*6007Sthurlow error = nbns_rq_prepare(rqp); 100*6007Sthurlow if (error) { 101*6007Sthurlow nbns_rq_done(rqp); 102*6007Sthurlow return (error); 103*6007Sthurlow } 104*6007Sthurlow rdrcount = NBNS_MAXREDIRECTS; 105*6007Sthurlow for (;;) { 106*6007Sthurlow error = nbns_rq(rqp); 107*6007Sthurlow if (error) 108*6007Sthurlow break; 109*6007Sthurlow if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) { 110*6007Sthurlow /* 111*6007Sthurlow * Not an authoritative answer. Query again 112*6007Sthurlow * using the NS address in the 2nd record. 113*6007Sthurlow */ 114*6007Sthurlow if (rdrcount-- == 0) { 115*6007Sthurlow error = NBERROR(NBERR_TOOMANYREDIRECTS); 116*6007Sthurlow break; 117*6007Sthurlow } 118*6007Sthurlow error = nbns_rq_getrr(rqp, &rr); 119*6007Sthurlow if (error) 120*6007Sthurlow break; 121*6007Sthurlow error = nbns_rq_getrr(rqp, &rr); 122*6007Sthurlow if (error) 123*6007Sthurlow break; 124*6007Sthurlow bcopy(rr.rr_data, &rqp->nr_dest, 4); 125*6007Sthurlow continue; 126*6007Sthurlow } 127*6007Sthurlow if (rqp->nr_rpancount == 0) { 128*6007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND); 129*6007Sthurlow break; 130*6007Sthurlow } 131*6007Sthurlow error = nbns_rq_getrr(rqp, &rr); 132*6007Sthurlow if (error) 133*6007Sthurlow break; 134*6007Sthurlow len = sizeof (struct sockaddr_in); 135*6007Sthurlow dest = malloc(len); 136*6007Sthurlow if (dest == NULL) 137*6007Sthurlow return (ENOMEM); 138*6007Sthurlow bzero(dest, len); 139*6007Sthurlow /* 140*6007Sthurlow * Solaris sockaddr_in doesn't have this field. 141*6007Sthurlow * dest->sin_len = len; 142*6007Sthurlow */ 143*6007Sthurlow dest->sin_family = AF_INET; 144*6007Sthurlow bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4); 145*6007Sthurlow dest->sin_port = htons(SMB_TCP_PORT); 146*6007Sthurlow *adpp = (struct sockaddr *)dest; 147*6007Sthurlow ctx->nb_lastns = rqp->nr_sender; 148*6007Sthurlow break; 149*6007Sthurlow } 150*6007Sthurlow nbns_rq_done(rqp); 151*6007Sthurlow return (error); 152*6007Sthurlow } 153*6007Sthurlow 154*6007Sthurlow static char * 155*6007Sthurlow smb_optstrncpy(char *d, char *s, unsigned maxlen) 156*6007Sthurlow { 157*6007Sthurlow if (d && s) { 158*6007Sthurlow strncpy(d, s, maxlen); 159*6007Sthurlow d[maxlen] = (char)0; 160*6007Sthurlow } 161*6007Sthurlow return (d); 162*6007Sthurlow } 163*6007Sthurlow 164*6007Sthurlow 165*6007Sthurlow int 166*6007Sthurlow nbns_getnodestatus(struct sockaddr *targethost, 167*6007Sthurlow struct nb_ctx *ctx, char *system, char *workgroup) 168*6007Sthurlow { 169*6007Sthurlow struct nbns_rq *rqp; 170*6007Sthurlow struct nbns_rr rr; 171*6007Sthurlow struct nb_name nn; 172*6007Sthurlow struct nbns_nr *nrp; 173*6007Sthurlow char nrtype; 174*6007Sthurlow char *cp, *retname = NULL; 175*6007Sthurlow struct sockaddr_in *dest; 176*6007Sthurlow unsigned char nrcount; 177*6007Sthurlow int error, rdrcount, i, foundserver = 0, foundgroup = 0; 178*6007Sthurlow 179*6007Sthurlow if (targethost->sa_family != AF_INET) 180*6007Sthurlow return (EINVAL); 181*6007Sthurlow error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp); 182*6007Sthurlow if (error) 183*6007Sthurlow return (error); 184*6007Sthurlow bzero(&nn, sizeof (nn)); 185*6007Sthurlow strcpy((char *)nn.nn_name, "*"); 186*6007Sthurlow nn.nn_scope = ctx->nb_scope; 187*6007Sthurlow nn.nn_type = NBT_WKSTA; 188*6007Sthurlow rqp->nr_nmflags = 0; 189*6007Sthurlow rqp->nr_qdname = &nn; 190*6007Sthurlow rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT; 191*6007Sthurlow rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN; 192*6007Sthurlow rqp->nr_qdcount = 1; 193*6007Sthurlow rqp->nr_maxretry = 2; 194*6007Sthurlow 195*6007Sthurlow /* LINTED */ 196*6007Sthurlow dest = (struct sockaddr_in *)targethost; 197*6007Sthurlow rqp->nr_dest = dest->sin_addr; 198*6007Sthurlow 199*6007Sthurlow error = nbns_rq_prepare(rqp); 200*6007Sthurlow if (error) { 201*6007Sthurlow nbns_rq_done(rqp); 202*6007Sthurlow return (error); 203*6007Sthurlow } 204*6007Sthurlow 205*6007Sthurlow /* 206*6007Sthurlow * Darwin had a loop here, allowing redirect, etc. 207*6007Sthurlow * but we only handle point-to-point for node status. 208*6007Sthurlow */ 209*6007Sthurlow error = nbns_rq(rqp); 210*6007Sthurlow if (error) 211*6007Sthurlow goto out; 212*6007Sthurlow if (rqp->nr_rpancount == 0) { 213*6007Sthurlow error = NBERROR(NBERR_HOSTNOTFOUND); 214*6007Sthurlow goto out; 215*6007Sthurlow } 216*6007Sthurlow error = nbns_rq_getrr(rqp, &rr); 217*6007Sthurlow if (error) 218*6007Sthurlow goto out; 219*6007Sthurlow 220*6007Sthurlow /* Compiler didn't like cast on lvalue++ */ 221*6007Sthurlow nrcount = *((unsigned char *)rr.rr_data); 222*6007Sthurlow rr.rr_data++; 223*6007Sthurlow /* LINTED */ 224*6007Sthurlow for (i = 1, nrp = (struct nbns_nr *)rr.rr_data; 225*6007Sthurlow i <= nrcount; ++i, ++nrp) { 226*6007Sthurlow nrtype = nrp->ns_name[NB_NAMELEN-1]; 227*6007Sthurlow /* Terminate the string: */ 228*6007Sthurlow nrp->ns_name[NB_NAMELEN-1] = (char)0; 229*6007Sthurlow /* Strip off trailing spaces */ 230*6007Sthurlow for (cp = &nrp->ns_name[NB_NAMELEN-2]; 231*6007Sthurlow cp >= nrp->ns_name; --cp) { 232*6007Sthurlow if (*cp != (char)0x20) 233*6007Sthurlow break; 234*6007Sthurlow *cp = (char)0; 235*6007Sthurlow } 236*6007Sthurlow nrp->ns_flags = ntohs(nrp->ns_flags); 237*6007Sthurlow if (nrp->ns_flags & NBNS_GROUPFLG) { 238*6007Sthurlow if (!foundgroup || 239*6007Sthurlow (foundgroup != NBT_WKSTA+1 && 240*6007Sthurlow nrtype == NBT_WKSTA)) { 241*6007Sthurlow smb_optstrncpy(workgroup, nrp->ns_name, 242*6007Sthurlow SMB_MAXUSERNAMELEN); 243*6007Sthurlow foundgroup = nrtype+1; 244*6007Sthurlow } 245*6007Sthurlow } else { 246*6007Sthurlow /* 247*6007Sthurlow * Track at least ONE name, in case 248*6007Sthurlow * no server name is found 249*6007Sthurlow */ 250*6007Sthurlow retname = nrp->ns_name; 251*6007Sthurlow } 252*6007Sthurlow if (nrtype == NBT_SERVER) { 253*6007Sthurlow smb_optstrncpy(system, nrp->ns_name, 254*6007Sthurlow SMB_MAXSRVNAMELEN); 255*6007Sthurlow foundserver = 1; 256*6007Sthurlow } 257*6007Sthurlow } 258*6007Sthurlow if (!foundserver) 259*6007Sthurlow smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN); 260*6007Sthurlow ctx->nb_lastns = rqp->nr_sender; 261*6007Sthurlow 262*6007Sthurlow out: 263*6007Sthurlow nbns_rq_done(rqp); 264*6007Sthurlow return (error); 265*6007Sthurlow } 266*6007Sthurlow 267*6007Sthurlow int 268*6007Sthurlow nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp) 269*6007Sthurlow { 270*6007Sthurlow struct nbns_rq *rqp; 271*6007Sthurlow static uint16_t trnid; 272*6007Sthurlow int error; 273*6007Sthurlow 274*6007Sthurlow if (trnid == 0) 275*6007Sthurlow trnid = getpid(); 276*6007Sthurlow rqp = malloc(sizeof (*rqp)); 277*6007Sthurlow if (rqp == NULL) 278*6007Sthurlow return (ENOMEM); 279*6007Sthurlow bzero(rqp, sizeof (*rqp)); 280*6007Sthurlow error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE); 281*6007Sthurlow if (error) { 282*6007Sthurlow free(rqp); 283*6007Sthurlow return (error); 284*6007Sthurlow } 285*6007Sthurlow rqp->nr_opcode = opcode; 286*6007Sthurlow rqp->nr_nbd = ctx; 287*6007Sthurlow rqp->nr_trnid = trnid++; 288*6007Sthurlow *rqpp = rqp; 289*6007Sthurlow return (0); 290*6007Sthurlow } 291*6007Sthurlow 292*6007Sthurlow void 293*6007Sthurlow nbns_rq_done(struct nbns_rq *rqp) 294*6007Sthurlow { 295*6007Sthurlow if (rqp == NULL) 296*6007Sthurlow return; 297*6007Sthurlow if (rqp->nr_fd >= 0) 298*6007Sthurlow close(rqp->nr_fd); 299*6007Sthurlow mb_done(&rqp->nr_rq); 300*6007Sthurlow mb_done(&rqp->nr_rp); 301*6007Sthurlow if (rqp->nr_if) 302*6007Sthurlow free(rqp->nr_if); 303*6007Sthurlow free(rqp); 304*6007Sthurlow } 305*6007Sthurlow 306*6007Sthurlow /* 307*6007Sthurlow * Extract resource record from the packet. Assume that there is only 308*6007Sthurlow * one mbuf. 309*6007Sthurlow */ 310*6007Sthurlow int 311*6007Sthurlow nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) 312*6007Sthurlow { 313*6007Sthurlow struct mbdata *mbp = &rqp->nr_rp; 314*6007Sthurlow uchar_t *cp; 315*6007Sthurlow int error, len; 316*6007Sthurlow 317*6007Sthurlow bzero(rrp, sizeof (*rrp)); 318*6007Sthurlow cp = (uchar_t *)mbp->mb_pos; 319*6007Sthurlow len = nb_encname_len(cp); 320*6007Sthurlow if (len < 1) 321*6007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 322*6007Sthurlow rrp->rr_name = cp; 323*6007Sthurlow error = mb_get_mem(mbp, NULL, len); 324*6007Sthurlow if (error) 325*6007Sthurlow return (error); 326*6007Sthurlow mb_get_uint16be(mbp, &rrp->rr_type); 327*6007Sthurlow mb_get_uint16be(mbp, &rrp->rr_class); 328*6007Sthurlow mb_get_uint32be(mbp, &rrp->rr_ttl); 329*6007Sthurlow mb_get_uint16be(mbp, &rrp->rr_rdlength); 330*6007Sthurlow rrp->rr_data = (uchar_t *)mbp->mb_pos; 331*6007Sthurlow error = mb_get_mem(mbp, NULL, rrp->rr_rdlength); 332*6007Sthurlow return (error); 333*6007Sthurlow } 334*6007Sthurlow 335*6007Sthurlow int 336*6007Sthurlow nbns_rq_prepare(struct nbns_rq *rqp) 337*6007Sthurlow { 338*6007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 339*6007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 340*6007Sthurlow uint16_t ofr; /* opcode, flags, rcode */ 341*6007Sthurlow uchar_t *cp; 342*6007Sthurlow int len, error; 343*6007Sthurlow 344*6007Sthurlow /* 345*6007Sthurlow * Replacing with one argument. 346*6007Sthurlow * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); 347*6007Sthurlow */ 348*6007Sthurlow error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); 349*6007Sthurlow if (error) 350*6007Sthurlow return (error); 351*6007Sthurlow 352*6007Sthurlow /* 353*6007Sthurlow * When looked into the ethereal trace, 'nmblookup' command sets this 354*6007Sthurlow * flag. We will also set. 355*6007Sthurlow */ 356*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_trnid); 357*6007Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) | 358*6007Sthurlow ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */ 359*6007Sthurlow mb_put_uint16be(mbp, ofr); 360*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdcount); 361*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_ancount); 362*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_nscount); 363*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_arcount); 364*6007Sthurlow if (rqp->nr_qdcount) { 365*6007Sthurlow if (rqp->nr_qdcount > 1) 366*6007Sthurlow return (EINVAL); 367*6007Sthurlow len = nb_name_len(rqp->nr_qdname); 368*6007Sthurlow error = mb_fit(mbp, len, (char **)&cp); 369*6007Sthurlow if (error) 370*6007Sthurlow return (error); 371*6007Sthurlow nb_name_encode(rqp->nr_qdname, cp); 372*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdtype); 373*6007Sthurlow mb_put_uint16be(mbp, rqp->nr_qdclass); 374*6007Sthurlow } 375*6007Sthurlow m_lineup(mbp->mb_top, &mbp->mb_top); 376*6007Sthurlow if (ctx->nb_timo == 0) 377*6007Sthurlow ctx->nb_timo = 1; /* by default 1 second */ 378*6007Sthurlow return (0); 379*6007Sthurlow } 380*6007Sthurlow 381*6007Sthurlow static int 382*6007Sthurlow nbns_rq_recv(struct nbns_rq *rqp) 383*6007Sthurlow { 384*6007Sthurlow struct mbdata *mbp = &rqp->nr_rp; 385*6007Sthurlow void *rpdata = mtod(mbp->mb_top, void *); 386*6007Sthurlow fd_set rd, wr, ex; 387*6007Sthurlow struct timeval tv; 388*6007Sthurlow struct sockaddr_in sender; 389*6007Sthurlow int s = rqp->nr_fd; 390*6007Sthurlow int n, len; 391*6007Sthurlow 392*6007Sthurlow FD_ZERO(&rd); 393*6007Sthurlow FD_ZERO(&wr); 394*6007Sthurlow FD_ZERO(&ex); 395*6007Sthurlow FD_SET(s, &rd); 396*6007Sthurlow 397*6007Sthurlow tv.tv_sec = rqp->nr_nbd->nb_timo; 398*6007Sthurlow tv.tv_usec = 0; 399*6007Sthurlow 400*6007Sthurlow n = select(s + 1, &rd, &wr, &ex, &tv); 401*6007Sthurlow if (n == -1) 402*6007Sthurlow return (-1); 403*6007Sthurlow if (n == 0) 404*6007Sthurlow return (ETIMEDOUT); 405*6007Sthurlow if (FD_ISSET(s, &rd) == 0) 406*6007Sthurlow return (ETIMEDOUT); 407*6007Sthurlow len = sizeof (sender); 408*6007Sthurlow n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0, 409*6007Sthurlow (struct sockaddr *)&sender, &len); 410*6007Sthurlow if (n < 0) 411*6007Sthurlow return (errno); 412*6007Sthurlow mbp->mb_top->m_len = mbp->mb_count = n; 413*6007Sthurlow rqp->nr_sender = sender; 414*6007Sthurlow return (0); 415*6007Sthurlow } 416*6007Sthurlow 417*6007Sthurlow static int 418*6007Sthurlow nbns_rq_opensocket(struct nbns_rq *rqp) 419*6007Sthurlow { 420*6007Sthurlow struct sockaddr_in locaddr; 421*6007Sthurlow int opt = 1, s; 422*6007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 423*6007Sthurlow 424*6007Sthurlow s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0); 425*6007Sthurlow if (s < 0) 426*6007Sthurlow return (errno); 427*6007Sthurlow if (ctx->nb_flags & NBCF_BC_ENABLE) { 428*6007Sthurlow if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt, 429*6007Sthurlow sizeof (opt)) < 0) 430*6007Sthurlow return (errno); 431*6007Sthurlow } 432*6007Sthurlow if (is_system_labeled()) 433*6007Sthurlow (void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt, 434*6007Sthurlow sizeof (opt)); 435*6007Sthurlow bzero(&locaddr, sizeof (locaddr)); 436*6007Sthurlow locaddr.sin_family = AF_INET; 437*6007Sthurlow /* locaddr.sin_len = sizeof (locaddr); */ 438*6007Sthurlow if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0) 439*6007Sthurlow return (errno); 440*6007Sthurlow return (0); 441*6007Sthurlow } 442*6007Sthurlow 443*6007Sthurlow static int 444*6007Sthurlow nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina) 445*6007Sthurlow { 446*6007Sthurlow struct sockaddr_in dest; 447*6007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 448*6007Sthurlow int s = rqp->nr_fd; 449*6007Sthurlow uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */ 450*6007Sthurlow uint16_t *datap; 451*6007Sthurlow uint8_t nmflags; 452*6007Sthurlow int rc; 453*6007Sthurlow 454*6007Sthurlow bzero(&dest, sizeof (dest)); 455*6007Sthurlow dest.sin_family = AF_INET; 456*6007Sthurlow dest.sin_port = htons(NBNS_UDP_PORT); 457*6007Sthurlow dest.sin_addr.s_addr = ina; 458*6007Sthurlow 459*6007Sthurlow if (ina == INADDR_BROADCAST) { 460*6007Sthurlow /* Turn on the broadcast bit. */ 461*6007Sthurlow nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST; 462*6007Sthurlow /*LINTED*/ 463*6007Sthurlow datap = mtod(mbp->mb_top, uint16_t *); 464*6007Sthurlow ofr = ((rqp->nr_opcode & 0x1F) << 11) | 465*6007Sthurlow ((nmflags & 0x7F) << 4); /* rcode=0 */ 466*6007Sthurlow ofr_save = datap[1]; 467*6007Sthurlow datap[1] = htons(ofr); 468*6007Sthurlow } 469*6007Sthurlow 470*6007Sthurlow rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0, 471*6007Sthurlow (struct sockaddr *)&dest, sizeof (dest)); 472*6007Sthurlow 473*6007Sthurlow if (ina == INADDR_BROADCAST) { 474*6007Sthurlow /* Turn the broadcast bit back off. */ 475*6007Sthurlow datap[1] = ofr_save; 476*6007Sthurlow } 477*6007Sthurlow 478*6007Sthurlow 479*6007Sthurlow if (rc < 0) 480*6007Sthurlow return (errno); 481*6007Sthurlow 482*6007Sthurlow return (0); 483*6007Sthurlow } 484*6007Sthurlow 485*6007Sthurlow int 486*6007Sthurlow nbns_rq(struct nbns_rq *rqp) 487*6007Sthurlow { 488*6007Sthurlow struct nb_ctx *ctx = rqp->nr_nbd; 489*6007Sthurlow struct mbdata *mbp = &rqp->nr_rq; 490*6007Sthurlow uint16_t ofr, rpid; 491*6007Sthurlow uint8_t nmflags; 492*6007Sthurlow int error, tries, maxretry; 493*6007Sthurlow 494*6007Sthurlow error = nbns_rq_opensocket(rqp); 495*6007Sthurlow if (error) 496*6007Sthurlow return (error); 497*6007Sthurlow 498*6007Sthurlow maxretry = rqp->nr_maxretry; 499*6007Sthurlow for (tries = 0; tries < maxretry; tries++) { 500*6007Sthurlow 501*6007Sthurlow /* 502*6007Sthurlow * Minor hack: If nr_dest is set, send there only. 503*6007Sthurlow * Used by _getnodestatus, _resolvname redirects. 504*6007Sthurlow */ 505*6007Sthurlow if (rqp->nr_dest.s_addr) { 506*6007Sthurlow error = nbns_rq_send(rqp, rqp->nr_dest.s_addr); 507*6007Sthurlow if (error) { 508*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 509*6007Sthurlow "nbns error %d sending to %s"), 510*6007Sthurlow 0, error, inet_ntoa(rqp->nr_dest)); 511*6007Sthurlow } 512*6007Sthurlow goto do_recv; 513*6007Sthurlow } 514*6007Sthurlow 515*6007Sthurlow if (ctx->nb_wins1) { 516*6007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins1); 517*6007Sthurlow if (error) { 518*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 519*6007Sthurlow "nbns error %d sending to wins1"), 520*6007Sthurlow 0, error); 521*6007Sthurlow } 522*6007Sthurlow } 523*6007Sthurlow 524*6007Sthurlow if (ctx->nb_wins2 && (tries > 0)) { 525*6007Sthurlow error = nbns_rq_send(rqp, ctx->nb_wins2); 526*6007Sthurlow if (error) { 527*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 528*6007Sthurlow "nbns error %d sending to wins2"), 529*6007Sthurlow 0, error); 530*6007Sthurlow } 531*6007Sthurlow } 532*6007Sthurlow 533*6007Sthurlow /* 534*6007Sthurlow * If broadcast is enabled, start broadcasting 535*6007Sthurlow * only after wins servers fail to respond, or 536*6007Sthurlow * immediately if no WINS servers configured. 537*6007Sthurlow */ 538*6007Sthurlow if ((ctx->nb_flags & NBCF_BC_ENABLE) && 539*6007Sthurlow ((tries > 1) || (ctx->nb_wins1 == 0))) { 540*6007Sthurlow error = nbns_rq_send(rqp, INADDR_BROADCAST); 541*6007Sthurlow if (error) { 542*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 543*6007Sthurlow "nbns error %d sending broadcast"), 544*6007Sthurlow 0, error); 545*6007Sthurlow } 546*6007Sthurlow } 547*6007Sthurlow 548*6007Sthurlow /* 549*6007Sthurlow * Wait for responses from ANY of the above. 550*6007Sthurlow */ 551*6007Sthurlow do_recv: 552*6007Sthurlow error = nbns_rq_recv(rqp); 553*6007Sthurlow if (error == ETIMEDOUT) 554*6007Sthurlow continue; 555*6007Sthurlow if (error) { 556*6007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 557*6007Sthurlow "nbns recv error %d"), 558*6007Sthurlow 0, error); 559*6007Sthurlow return (error); 560*6007Sthurlow } 561*6007Sthurlow 562*6007Sthurlow mbp = &rqp->nr_rp; 563*6007Sthurlow if (mbp->mb_count < 12) 564*6007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 565*6007Sthurlow mb_get_uint16be(mbp, &rpid); 566*6007Sthurlow if (rpid != rqp->nr_trnid) 567*6007Sthurlow return (NBERROR(NBERR_INVALIDRESPONSE)); 568*6007Sthurlow break; 569*6007Sthurlow } 570*6007Sthurlow 571*6007Sthurlow mb_get_uint16be(mbp, &ofr); 572*6007Sthurlow rqp->nr_rpnmflags = (ofr >> 4) & 0x7F; 573*6007Sthurlow rqp->nr_rprcode = ofr & 0xf; 574*6007Sthurlow if (rqp->nr_rprcode) 575*6007Sthurlow return (NBERROR(rqp->nr_rprcode)); 576*6007Sthurlow mb_get_uint16be(mbp, &rpid); /* QDCOUNT */ 577*6007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rpancount); 578*6007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rpnscount); 579*6007Sthurlow mb_get_uint16be(mbp, &rqp->nr_rparcount); 580*6007Sthurlow return (0); 581*6007Sthurlow } 582