1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 227f667e74Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw /* 27*a0aa776eSAlan Wright * NetBIOS name resolution node types. 28da6c28aaSamw * 29*a0aa776eSAlan Wright * A B-node (broadcast node) uses broadcasts for name registration 30*a0aa776eSAlan Wright * and resolution. Routers typically do not forward broadcasts and 31*a0aa776eSAlan Wright * only computers on the local subnet will respond. 32da6c28aaSamw * 33*a0aa776eSAlan Wright * A P-node (peer-to-peer node) uses a NetBIOS name server (WINS) 34*a0aa776eSAlan Wright * to resolve NetBIOS names, which allows it to work across routers. 35*a0aa776eSAlan Wright * In order to function in a P-node environment, all computers must 36*a0aa776eSAlan Wright * be configured to use the NetBIOS name server because P-nodes do 37*a0aa776eSAlan Wright * not broadcast on the network. 38da6c28aaSamw * 39*a0aa776eSAlan Wright * A mixed node (M-node) behaves as a B-node by default. If it cannot 40*a0aa776eSAlan Wright * resolve the name via broadcast then it tries a NetBIOS name server 41*a0aa776eSAlan Wright * lookup (P-node). 42da6c28aaSamw * 43*a0aa776eSAlan Wright * A hybrid node (H-node) behaves as a P-node by default. If it cannot 44*a0aa776eSAlan Wright * resolve the name using a NetBIOS name server then it resorts to 45*a0aa776eSAlan Wright * broadcasts (B-node). 46da6c28aaSamw * 47*a0aa776eSAlan Wright * NetBIOS Name Service Protocols 48da6c28aaSamw * 49*a0aa776eSAlan Wright * A REQUEST packet is always sent to the well known UDP port 137. 50*a0aa776eSAlan Wright * The destination address is normally either the IP broadcast address or 51*a0aa776eSAlan Wright * the address of the NAME - the address of the NAME server it set up at 52*a0aa776eSAlan Wright * initialization time. In rare cases, a request packet will be sent to 53*a0aa776eSAlan Wright * an end node, e.g. a NAME QUERY REQUEST sent to "challenge" a node. 54da6c28aaSamw * 55*a0aa776eSAlan Wright * A RESPONSE packet is always sent to the source UDP port and source IP 56*a0aa776eSAlan Wright * address of the request packet. 57da6c28aaSamw * 58*a0aa776eSAlan Wright * A DEMAND packet must always be sent to the well known UDP port 137. 59*a0aa776eSAlan Wright * There is no restriction on the target IP address. 60da6c28aaSamw * 61*a0aa776eSAlan Wright * A transaction ID is a value composed from the requestor's IP address and 62*a0aa776eSAlan Wright * a unique 16 bit value generated by the originator of the transaction. 63da6c28aaSamw */ 64da6c28aaSamw 65da6c28aaSamw #include <unistd.h> 66da6c28aaSamw #include <syslog.h> 67da6c28aaSamw #include <stdlib.h> 68da6c28aaSamw #include <synch.h> 69da6c28aaSamw #include <errno.h> 70da6c28aaSamw #include <netdb.h> 71da6c28aaSamw #include <sys/socket.h> 72da6c28aaSamw #include <sys/sockio.h> 73da6c28aaSamw #include <arpa/inet.h> 74da6c28aaSamw #include <net/if_arp.h> 75da6c28aaSamw 76da6c28aaSamw #include <smbsrv/libsmbns.h> 77da6c28aaSamw #include <smbns_netbios.h> 78da6c28aaSamw 79*a0aa776eSAlan Wright /* 80*a0aa776eSAlan Wright * RFC 1002 4.2.1.1. HEADER 81*a0aa776eSAlan Wright */ 82*a0aa776eSAlan Wright #define QUESTION_TYPE_NETBIOS_GENERAL 0x20 83*a0aa776eSAlan Wright #define QUESTION_TYPE_NETBIOS_STATUS 0x21 84*a0aa776eSAlan Wright 85*a0aa776eSAlan Wright #define QUESTION_CLASS_INTERNET 0x0001 86da6c28aaSamw 87*a0aa776eSAlan Wright /* 88*a0aa776eSAlan Wright * RFC 1002 4.2.1.3. RESOURCE RECORD 89*a0aa776eSAlan Wright */ 90*a0aa776eSAlan Wright #define RR_TYPE_IP_ADDRESS_RESOURCE 0x0001 91*a0aa776eSAlan Wright #define RR_TYPE_NAME_SERVER_RESOURCE 0x0002 92*a0aa776eSAlan Wright #define RR_TYPE_NULL_RESOURCE 0x000A 93*a0aa776eSAlan Wright #define RR_TYPE_NETBIOS_RESOURCE 0x0020 94*a0aa776eSAlan Wright #define RR_TYPE_NETBIOS_STATUS 0x0021 95*a0aa776eSAlan Wright 96*a0aa776eSAlan Wright /* 97*a0aa776eSAlan Wright * 98*a0aa776eSAlan Wright * RESOURCE RECORD RR_CLASS field definitions 99*a0aa776eSAlan Wright */ 100*a0aa776eSAlan Wright #define RR_CLASS_INTERNET_CLASS 0x0001 101*a0aa776eSAlan Wright 102*a0aa776eSAlan Wright /* 103*a0aa776eSAlan Wright * NB_FLAGS field of the RESOURCE RECORD RDATA field for RR_TYPE of NB. 104*a0aa776eSAlan Wright */ 105*a0aa776eSAlan Wright #define RR_FLAGS_NB_ONT_MASK 0x6000 106*a0aa776eSAlan Wright #define RR_FLAGS_NB_ONT_B_NODE 0x0000 107*a0aa776eSAlan Wright #define RR_FLAGS_NB_ONT_P_NODE 0x2000 108*a0aa776eSAlan Wright #define RR_FLAGS_NB_ONT_M_NODE 0x4000 109*a0aa776eSAlan Wright #define RR_FLAGS_NB_ONT_RESERVED 0x6000 110*a0aa776eSAlan Wright #define RR_FLAGS_NB_GROUP_NAME 0x8000 111*a0aa776eSAlan Wright 112*a0aa776eSAlan Wright #define NAME_FLAGS_PERMANENT_NAME 0x0200 113*a0aa776eSAlan Wright #define NAME_FLAGS_ACTIVE_NAME 0x0400 114*a0aa776eSAlan Wright #define NAME_FLAGS_CONFLICT 0x0800 115*a0aa776eSAlan Wright #define NAME_FLAGS_DEREGISTER 0x1000 116*a0aa776eSAlan Wright #define NAME_FLAGS_ONT_MASK 0x6000 117*a0aa776eSAlan Wright #define NAME_FLAGS_ONT_B_NODE 0x0000 118*a0aa776eSAlan Wright #define NAME_FLAGS_ONT_P_NODE 0x2000 119*a0aa776eSAlan Wright #define NAME_FLAGS_ONT_M_NODE 0x4000 120*a0aa776eSAlan Wright #define NAME_FLAGS_ONT_RESERVED 0x6000 121*a0aa776eSAlan Wright #define NAME_FLAGS_GROUP_NAME 0x8000 122*a0aa776eSAlan Wright 123*a0aa776eSAlan Wright #define MAX_NETBIOS_REPLY_DATA_SIZE 500 124*a0aa776eSAlan Wright 125*a0aa776eSAlan Wright #define NAME_HEADER_SIZE 12 126da6c28aaSamw 127*a0aa776eSAlan Wright typedef struct nbt_name_reply { 128*a0aa776eSAlan Wright struct nbt_name_reply *forw; 129*a0aa776eSAlan Wright struct nbt_name_reply *back; 130*a0aa776eSAlan Wright struct name_packet *packet; 131*a0aa776eSAlan Wright addr_entry_t *addr; 132*a0aa776eSAlan Wright uint16_t name_trn_id; 133*a0aa776eSAlan Wright boolean_t reply_ready; 134*a0aa776eSAlan Wright } nbt_name_reply_t; 135*a0aa776eSAlan Wright 136*a0aa776eSAlan Wright static nbt_name_reply_t reply_queue; 137da6c28aaSamw static mutex_t rq_mtx; 138*a0aa776eSAlan Wright static cond_t rq_cv; 139da6c28aaSamw 140*a0aa776eSAlan Wright static mutex_t nbt_name_config_mtx; 141da6c28aaSamw 142da6c28aaSamw static name_queue_t delete_queue; 143da6c28aaSamw static name_queue_t refresh_queue; 144da6c28aaSamw 145da6c28aaSamw static int name_sock = 0; 146da6c28aaSamw 147da6c28aaSamw static int bcast_num = 0; 148da6c28aaSamw static int nbns_num = 0; 149*a0aa776eSAlan Wright static addr_entry_t smb_bcast_list[SMB_PI_MAX_NETWORKS]; 150*a0aa776eSAlan Wright static addr_entry_t smb_nbns[SMB_PI_MAX_WINS]; 151da6c28aaSamw 152*a0aa776eSAlan Wright static int smb_netbios_process_response(uint16_t, addr_entry_t *, 153da6c28aaSamw struct name_packet *, uint32_t); 154da6c28aaSamw 155*a0aa776eSAlan Wright static int smb_send_name_service_packet(addr_entry_t *addr, 156da6c28aaSamw struct name_packet *packet); 157da6c28aaSamw 158*a0aa776eSAlan Wright /* 159*a0aa776eSAlan Wright * Allocate a transaction id. 160*a0aa776eSAlan Wright */ 161*a0aa776eSAlan Wright static uint16_t 162*a0aa776eSAlan Wright smb_netbios_name_trn_id(void) 163*a0aa776eSAlan Wright { 164*a0aa776eSAlan Wright static uint16_t trn_id; 165*a0aa776eSAlan Wright static mutex_t trn_id_mtx; 166*a0aa776eSAlan Wright 167*a0aa776eSAlan Wright (void) mutex_lock(&trn_id_mtx); 168*a0aa776eSAlan Wright 169*a0aa776eSAlan Wright do { 170*a0aa776eSAlan Wright ++trn_id; 171*a0aa776eSAlan Wright } while (trn_id == 0 || trn_id == (uint16_t)-1); 172*a0aa776eSAlan Wright 173*a0aa776eSAlan Wright (void) mutex_unlock(&trn_id_mtx); 174*a0aa776eSAlan Wright return (trn_id); 175*a0aa776eSAlan Wright } 176*a0aa776eSAlan Wright 177da6c28aaSamw static int 178*a0aa776eSAlan Wright smb_end_node_challenge(nbt_name_reply_t *reply_info) 179da6c28aaSamw { 180da6c28aaSamw int rc; 181da6c28aaSamw uint32_t retry; 182*a0aa776eSAlan Wright uint16_t tid; 183da6c28aaSamw struct resource_record *answer; 184da6c28aaSamw struct name_question question; 185*a0aa776eSAlan Wright addr_entry_t *addr; 186da6c28aaSamw struct name_entry *destination; 187da6c28aaSamw struct name_packet packet; 188da6c28aaSamw struct timespec st; 189da6c28aaSamw 190da6c28aaSamw /* 191da6c28aaSamw * The response packet has in it the address of the presumed owner 192da6c28aaSamw * of the name. Challenge that owner. If owner either does not 193da6c28aaSamw * respond or indicates that he no longer owns the name, claim the 194da6c28aaSamw * name. Otherwise, the name cannot be claimed. 195da6c28aaSamw */ 196da6c28aaSamw 197da6c28aaSamw if ((answer = reply_info->packet->answer) == 0) 198da6c28aaSamw return (-1); 199da6c28aaSamw 200da6c28aaSamw destination = answer->name; 201da6c28aaSamw question.name = answer->name; 202da6c28aaSamw 203da6c28aaSamw packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST; 204da6c28aaSamw packet.qdcount = 1; /* question entries */ 205da6c28aaSamw packet.question = &question; 206da6c28aaSamw packet.ancount = 0; /* answer recs */ 207da6c28aaSamw packet.answer = NULL; 208da6c28aaSamw packet.nscount = 0; /* authority recs */ 209da6c28aaSamw packet.authority = NULL; 210da6c28aaSamw packet.arcount = 0; /* additional recs */ 211da6c28aaSamw packet.additional = NULL; 212da6c28aaSamw 213da6c28aaSamw addr = &destination->addr_list; 214da6c28aaSamw for (retry = 0; retry < UCAST_REQ_RETRY_COUNT; retry++) { 215*a0aa776eSAlan Wright tid = smb_netbios_name_trn_id(); 216da6c28aaSamw packet.name_trn_id = tid; 217da6c28aaSamw if (smb_send_name_service_packet(addr, &packet) >= 0) { 218da6c28aaSamw if ((rc = smb_netbios_process_response(tid, addr, 219da6c28aaSamw &packet, UCAST_REQ_RETRY_TIMEOUT)) != 0) 220da6c28aaSamw return (rc); 221da6c28aaSamw } 222da6c28aaSamw st.tv_sec = 0; 223da6c28aaSamw st.tv_nsec = (UCAST_REQ_RETRY_TIMEOUT * 1000000); 224da6c28aaSamw (void) nanosleep(&st, 0); 225da6c28aaSamw } 226da6c28aaSamw /* No reply */ 227da6c28aaSamw return (0); 228da6c28aaSamw } 229da6c28aaSamw 230*a0aa776eSAlan Wright static nbt_name_reply_t * 231*a0aa776eSAlan Wright smb_name_get_reply(uint16_t tid, uint32_t timeout) 232da6c28aaSamw { 233*a0aa776eSAlan Wright uint16_t info; 234da6c28aaSamw struct resource_record *answer; 235*a0aa776eSAlan Wright nbt_name_reply_t *reply; 236da6c28aaSamw uint32_t wait_time, to_save; /* in millisecond */ 237da6c28aaSamw struct timeval wt; 238da6c28aaSamw timestruc_t to; 239da6c28aaSamw 240da6c28aaSamw to_save = timeout; 241*a0aa776eSAlan Wright reply = malloc(sizeof (nbt_name_reply_t)); 242*a0aa776eSAlan Wright if (reply != NULL) { 243*a0aa776eSAlan Wright reply->reply_ready = B_FALSE; 244da6c28aaSamw reply->name_trn_id = tid; 245da6c28aaSamw (void) mutex_lock(&rq_mtx); 246da6c28aaSamw QUEUE_INSERT_TAIL(&reply_queue, reply); 247da6c28aaSamw (void) mutex_unlock(&rq_mtx); 248da6c28aaSamw 249da6c28aaSamw for (;;) { 250da6c28aaSamw (void) gettimeofday(&wt, 0); 251da6c28aaSamw wait_time = wt.tv_usec / 1000; 252da6c28aaSamw 253da6c28aaSamw to.tv_sec = 0; 254da6c28aaSamw to.tv_nsec = timeout * 1000000; 255*a0aa776eSAlan Wright (void) mutex_lock(&rq_mtx); 256*a0aa776eSAlan Wright (void) cond_reltimedwait(&rq_cv, &rq_mtx, &to); 257*a0aa776eSAlan Wright (void) mutex_unlock(&rq_mtx); 258da6c28aaSamw 259*a0aa776eSAlan Wright if (reply->reply_ready) { 260da6c28aaSamw info = reply->packet->info; 261da6c28aaSamw if (PACKET_TYPE(info) == WACK_RESPONSE) { 262da6c28aaSamw answer = reply->packet->answer; 263da6c28aaSamw wait_time = (answer) ? 264da6c28aaSamw TO_MILLISECONDS(answer->ttl) : 265da6c28aaSamw DEFAULT_TTL; 266da6c28aaSamw free(reply->addr); 267da6c28aaSamw free(reply->packet); 268da6c28aaSamw timeout = to_save + wait_time; 269*a0aa776eSAlan Wright reply->reply_ready = B_FALSE; 270da6c28aaSamw reply->name_trn_id = tid; 271da6c28aaSamw (void) mutex_lock(&rq_mtx); 272da6c28aaSamw QUEUE_INSERT_TAIL(&reply_queue, reply); 273da6c28aaSamw (void) mutex_unlock(&rq_mtx); 274da6c28aaSamw continue; 275da6c28aaSamw } 276da6c28aaSamw return (reply); 277da6c28aaSamw } 278da6c28aaSamw (void) gettimeofday(&wt, 0); 279da6c28aaSamw wait_time = (wt.tv_usec / 1000) - wait_time; 280da6c28aaSamw if (wait_time >= timeout) { 281da6c28aaSamw (void) mutex_lock(&rq_mtx); 282da6c28aaSamw QUEUE_CLIP(reply); 283da6c28aaSamw (void) mutex_unlock(&rq_mtx); 284da6c28aaSamw free(reply); 285da6c28aaSamw break; 286da6c28aaSamw } 287da6c28aaSamw timeout -= wait_time; 288da6c28aaSamw } 289da6c28aaSamw } 290da6c28aaSamw 291da6c28aaSamw return (0); 292da6c28aaSamw } 293da6c28aaSamw 294da6c28aaSamw static void 295*a0aa776eSAlan Wright smb_reply_ready(struct name_packet *packet, addr_entry_t *addr) 296da6c28aaSamw { 297*a0aa776eSAlan Wright nbt_name_reply_t *reply; 298da6c28aaSamw struct resource_record *answer; 299da6c28aaSamw 300da6c28aaSamw (void) mutex_lock(&rq_mtx); 301da6c28aaSamw for (reply = reply_queue.forw; reply != &reply_queue; 302da6c28aaSamw reply = reply->forw) { 303da6c28aaSamw if (reply->name_trn_id == packet->name_trn_id) { 304da6c28aaSamw QUEUE_CLIP(reply); 305da6c28aaSamw 306da6c28aaSamw reply->addr = addr; 307da6c28aaSamw reply->packet = packet; 308*a0aa776eSAlan Wright reply->reply_ready = B_TRUE; 309*a0aa776eSAlan Wright (void) cond_signal(&rq_cv); 310*a0aa776eSAlan Wright (void) mutex_unlock(&rq_mtx); 311da6c28aaSamw return; 312da6c28aaSamw } 313da6c28aaSamw } 314da6c28aaSamw (void) mutex_unlock(&rq_mtx); 315da6c28aaSamw 316da6c28aaSamw /* Presumably nobody is waiting any more... */ 317da6c28aaSamw free(addr); 318da6c28aaSamw 319da6c28aaSamw answer = packet->answer; 320da6c28aaSamw if (answer) 321da6c28aaSamw smb_netbios_name_freeaddrs(answer->name); 322da6c28aaSamw free(packet); 323da6c28aaSamw } 324da6c28aaSamw 325da6c28aaSamw static int 326*a0aa776eSAlan Wright smb_netbios_process_response(uint16_t tid, addr_entry_t *addr, 327da6c28aaSamw struct name_packet *packet, uint32_t timeout) 328da6c28aaSamw { 329da6c28aaSamw int rc = 0; 330*a0aa776eSAlan Wright uint16_t info; 331*a0aa776eSAlan Wright nbt_name_reply_t *reply; 332da6c28aaSamw struct resource_record *answer; 333da6c28aaSamw struct name_entry *name; 334da6c28aaSamw struct name_entry *entry; 335da6c28aaSamw struct name_question *question; 336da6c28aaSamw uint32_t ttl; 337da6c28aaSamw 338da6c28aaSamw if ((reply = smb_name_get_reply(tid, timeout)) == 0) { 339da6c28aaSamw return (0); /* No reply: retry */ 340da6c28aaSamw } 341da6c28aaSamw info = reply->packet->info; 342da6c28aaSamw answer = reply->packet->answer; 343da6c28aaSamw 344da6c28aaSamw /* response */ 345da6c28aaSamw switch (PACKET_TYPE(info)) { 346da6c28aaSamw case NAME_QUERY_RESPONSE: 347da6c28aaSamw if (POSITIVE_RESPONSE(info)) { 348da6c28aaSamw addr = &answer->name->addr_list; 349da6c28aaSamw do { 350da6c28aaSamw /* 351da6c28aaSamw * Make sure that remote name is not 352da6c28aaSamw * flagged local 353da6c28aaSamw */ 354da6c28aaSamw addr->attributes &= ~NAME_ATTR_LOCAL; 355da6c28aaSamw 356*a0aa776eSAlan Wright if (answer->ttl) 357*a0aa776eSAlan Wright addr->ttl = answer->ttl; 358*a0aa776eSAlan Wright else 359*a0aa776eSAlan Wright addr->ttl = DEFAULT_TTL; 360*a0aa776eSAlan Wright addr->refresh_ttl = TO_SECONDS(addr->ttl); 361*a0aa776eSAlan Wright addr->ttl = addr->refresh_ttl; 362*a0aa776eSAlan Wright 363da6c28aaSamw addr = addr->forw; 364da6c28aaSamw } while (addr != &answer->name->addr_list); 365*a0aa776eSAlan Wright smb_netbios_name_logf(answer->name); 366da6c28aaSamw (void) smb_netbios_cache_insert_list(answer->name); 367da6c28aaSamw rc = 1; 368da6c28aaSamw } else { 369da6c28aaSamw rc = -1; 370da6c28aaSamw } 371da6c28aaSamw break; 372da6c28aaSamw 373da6c28aaSamw case NAME_REGISTRATION_RESPONSE: 374da6c28aaSamw if (NEGATIVE_RESPONSE(info)) { 375da6c28aaSamw if (RCODE(info) == RCODE_CFT_ERR) { 376da6c28aaSamw if (answer == 0) { 377da6c28aaSamw rc = -RCODE(info); 378da6c28aaSamw break; 379da6c28aaSamw } 380da6c28aaSamw 381da6c28aaSamw name = answer->name; 382da6c28aaSamw entry = smb_netbios_cache_lookup(name); 383da6c28aaSamw if (entry) { 384da6c28aaSamw /* 385da6c28aaSamw * a name in the state "conflict 386da6c28aaSamw * detected" does not "logically" exist 387da6c28aaSamw * on that node. No further session 388da6c28aaSamw * will be accepted on that name. 389da6c28aaSamw * No datagrams can be sent against 390da6c28aaSamw * that name. 391da6c28aaSamw * Such an entry will not be used for 392da6c28aaSamw * purposes of processing incoming 393da6c28aaSamw * request packets. 394da6c28aaSamw * The only valid user NetBIOS operation 395da6c28aaSamw * against such a name is DELETE NAME. 396da6c28aaSamw */ 397da6c28aaSamw entry->attributes |= NAME_ATTR_CONFLICT; 398da6c28aaSamw syslog(LOG_DEBUG, 399*a0aa776eSAlan Wright "nbns: name conflict: %15.15s", 400da6c28aaSamw entry->name); 401da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 402da6c28aaSamw } 403da6c28aaSamw } 404da6c28aaSamw rc = -RCODE(info); 405da6c28aaSamw break; 406da6c28aaSamw } 407da6c28aaSamw 408da6c28aaSamw /* 409da6c28aaSamw * name can be added: 410da6c28aaSamw * adjust refresh timeout value, 411da6c28aaSamw * TTL, for this name 412da6c28aaSamw */ 413da6c28aaSamw question = packet->question; 414*a0aa776eSAlan Wright ttl = (answer && answer->ttl) ? answer->ttl : DEFAULT_TTL; 415*a0aa776eSAlan Wright ttl = TO_SECONDS(ttl); 416da6c28aaSamw if ((entry = smb_netbios_cache_lookup(question->name)) != 0) { 417da6c28aaSamw addr = &entry->addr_list; 418da6c28aaSamw do { 419da6c28aaSamw if ((addr->refresh_ttl == 0) || 420da6c28aaSamw (ttl < addr->refresh_ttl)) 421da6c28aaSamw addr->refresh_ttl = addr->ttl = ttl; 422da6c28aaSamw addr = addr->forw; 423da6c28aaSamw } while (addr != &entry->addr_list); 424da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 425da6c28aaSamw } 426da6c28aaSamw 427da6c28aaSamw rc = 1; 428da6c28aaSamw break; 429da6c28aaSamw 430da6c28aaSamw case NAME_RELEASE_RESPONSE: 431da6c28aaSamw rc = 1; 432da6c28aaSamw break; 433da6c28aaSamw 434da6c28aaSamw case END_NODE_CHALLENGE_REGISTRATION_REQUEST: 435da6c28aaSamw /* 436da6c28aaSamw * The response packet has in it the 437da6c28aaSamw * address of the presumed owner of the 438da6c28aaSamw * name. Challenge that owner. If 439da6c28aaSamw * owner either does not respond or 440da6c28aaSamw * indicates that he no longer owns the 441da6c28aaSamw * name, claim the name. Otherwise, 442da6c28aaSamw * the name cannot be claimed. 443da6c28aaSamw */ 444da6c28aaSamw rc = smb_end_node_challenge(reply); 445da6c28aaSamw break; 446da6c28aaSamw 447da6c28aaSamw default: 448da6c28aaSamw rc = 0; 449da6c28aaSamw break; 450da6c28aaSamw } 451da6c28aaSamw 452da6c28aaSamw if (answer) 453da6c28aaSamw smb_netbios_name_freeaddrs(answer->name); 454da6c28aaSamw free(reply->addr); 455da6c28aaSamw free(reply->packet); 456da6c28aaSamw free(reply); 457da6c28aaSamw return (rc); /* retry */ 458da6c28aaSamw } 459da6c28aaSamw 460da6c28aaSamw /* 461da6c28aaSamw * smb_name_buf_from_packet 462da6c28aaSamw * 463da6c28aaSamw * Description: 464da6c28aaSamw * Convert a NetBIOS Name Server Packet Block (npb) 465da6c28aaSamw * into the bits and bytes destined for the wire. 466da6c28aaSamw * The "buf" is used as a heap. 467da6c28aaSamw * 468da6c28aaSamw * Inputs: 469da6c28aaSamw * char * buf -> Buffer, from the wire 470da6c28aaSamw * unsigned n_buf -> Length of 'buf' 471da6c28aaSamw * name_packet *npb -> Packet block, decode into 472da6c28aaSamw * unsigned n_npb -> Max bytes in 'npb' 473da6c28aaSamw * 474da6c28aaSamw * Returns: 475da6c28aaSamw * >0 -> Encode successful, value is length of packet in "buf" 476da6c28aaSamw * -1 -> Hard error, can not possibly encode 477da6c28aaSamw * -2 -> Need more memory in buf -- it's too small 478da6c28aaSamw */ 479da6c28aaSamw static int 480*a0aa776eSAlan Wright smb_name_buf_from_packet(unsigned char *buf, int n_buf, 481da6c28aaSamw struct name_packet *npb) 482da6c28aaSamw { 483*a0aa776eSAlan Wright addr_entry_t *raddr; 484da6c28aaSamw unsigned char *heap = buf; 485da6c28aaSamw unsigned char *end_heap = heap + n_buf; 486da6c28aaSamw unsigned char *dnptrs[32]; 487da6c28aaSamw unsigned char comp_name_buf[MAX_NAME_LENGTH]; 488da6c28aaSamw unsigned int tmp; 489da6c28aaSamw int i, step; 490da6c28aaSamw 491da6c28aaSamw if (n_buf < NAME_HEADER_SIZE) 492da6c28aaSamw return (-1); /* no header, impossible */ 493da6c28aaSamw 494da6c28aaSamw dnptrs[0] = heap; 495da6c28aaSamw dnptrs[1] = 0; 496da6c28aaSamw 497da6c28aaSamw BE_OUT16(heap, npb->name_trn_id); 498da6c28aaSamw heap += 2; 499da6c28aaSamw 500da6c28aaSamw BE_OUT16(heap, npb->info); 501da6c28aaSamw heap += 2; 502da6c28aaSamw 503da6c28aaSamw BE_OUT16(heap, npb->qdcount); 504da6c28aaSamw heap += 2; 505da6c28aaSamw 506da6c28aaSamw BE_OUT16(heap, npb->ancount); 507da6c28aaSamw heap += 2; 508da6c28aaSamw 509da6c28aaSamw BE_OUT16(heap, npb->nscount); 510da6c28aaSamw heap += 2; 511da6c28aaSamw 512da6c28aaSamw BE_OUT16(heap, npb->arcount); 513da6c28aaSamw heap += 2; 514da6c28aaSamw 515da6c28aaSamw for (i = 0; i < npb->qdcount; i++) { 516da6c28aaSamw if ((heap + 34 + 4) > end_heap) 517da6c28aaSamw return (-2); 518da6c28aaSamw 519da6c28aaSamw (void) smb_first_level_name_encode(npb->question[i].name, 520da6c28aaSamw comp_name_buf, sizeof (comp_name_buf)); 521da6c28aaSamw (void) strcpy((char *)heap, (char *)comp_name_buf); 522da6c28aaSamw heap += strlen((char *)comp_name_buf) + 1; 523da6c28aaSamw 524da6c28aaSamw BE_OUT16(heap, npb->question[i].question_type); 525da6c28aaSamw heap += 2; 526da6c28aaSamw 527da6c28aaSamw BE_OUT16(heap, npb->question[i].question_class); 528da6c28aaSamw heap += 2; 529da6c28aaSamw } 530da6c28aaSamw 531da6c28aaSamw for (step = 1; step <= 3; step++) { 532da6c28aaSamw struct resource_record *nrr; 533da6c28aaSamw int n; 534da6c28aaSamw 535da6c28aaSamw /* truly ugly, but saves code copying */ 536da6c28aaSamw if (step == 1) { 537da6c28aaSamw n = npb->ancount; 538da6c28aaSamw nrr = npb->answer; 539da6c28aaSamw } else if (step == 2) { 540da6c28aaSamw n = npb->nscount; 541da6c28aaSamw nrr = npb->authority; 542da6c28aaSamw } else { /* step == 3 */ 543da6c28aaSamw n = npb->arcount; 544da6c28aaSamw nrr = npb->additional; 545da6c28aaSamw } 546da6c28aaSamw 547da6c28aaSamw for (i = 0; i < n; i++) { 548da6c28aaSamw if ((heap + 34 + 10) > end_heap) 549da6c28aaSamw return (-2); 550da6c28aaSamw 551da6c28aaSamw (void) smb_first_level_name_encode(nrr->name, 552da6c28aaSamw comp_name_buf, sizeof (comp_name_buf)); 553da6c28aaSamw (void) strcpy((char *)heap, (char *)comp_name_buf); 554da6c28aaSamw heap += strlen((char *)comp_name_buf) + 1; 555da6c28aaSamw 556da6c28aaSamw BE_OUT16(heap, nrr[i].rr_type); 557da6c28aaSamw heap += 2; 558da6c28aaSamw 559da6c28aaSamw BE_OUT16(heap, nrr[i].rr_class); 560da6c28aaSamw heap += 2; 561da6c28aaSamw 562da6c28aaSamw BE_OUT32(heap, nrr[i].ttl); 563da6c28aaSamw heap += 4; 564da6c28aaSamw 565da6c28aaSamw BE_OUT16(heap, nrr[i].rdlength); 566da6c28aaSamw heap += 2; 567da6c28aaSamw 568da6c28aaSamw if ((tmp = nrr[i].rdlength) > 0) { 569da6c28aaSamw if ((heap + tmp) > end_heap) 570da6c28aaSamw return (-2); 571da6c28aaSamw 572da6c28aaSamw if (nrr[i].rr_type == NAME_RR_TYPE_NB && 573da6c28aaSamw nrr[i].rr_class == NAME_RR_CLASS_IN && 574da6c28aaSamw tmp >= 6 && nrr[i].rdata == 0) { 575da6c28aaSamw tmp = nrr[i].name->attributes & 576da6c28aaSamw (NAME_ATTR_GROUP | 577da6c28aaSamw NAME_ATTR_OWNER_NODE_TYPE); 578da6c28aaSamw BE_OUT16(heap, tmp); 579da6c28aaSamw heap += 2; 580da6c28aaSamw 581da6c28aaSamw raddr = &nrr[i].name->addr_list; 582da6c28aaSamw (void) memcpy(heap, 583da6c28aaSamw &raddr->sin.sin_addr.s_addr, 584da6c28aaSamw sizeof (uint32_t)); 585da6c28aaSamw heap += 4; 586da6c28aaSamw } else { 587da6c28aaSamw bcopy(nrr[i].rdata, heap, tmp); 588da6c28aaSamw heap += tmp; 589da6c28aaSamw } 590da6c28aaSamw } 591da6c28aaSamw } 592da6c28aaSamw } 593da6c28aaSamw return (heap - buf); 594da6c28aaSamw } 595da6c28aaSamw 596da6c28aaSamw /* 597da6c28aaSamw * strnchr 598da6c28aaSamw * 599da6c28aaSamw * Lookup for character 'c' in first 'n' chars of string 's'. 600da6c28aaSamw * Returns pointer to the found char, otherwise returns 0. 601da6c28aaSamw */ 602da6c28aaSamw static char * 603da6c28aaSamw strnchr(const char *s, char c, int n) 604da6c28aaSamw { 605da6c28aaSamw char *ps = (char *)s; 606da6c28aaSamw char *es = (char *)s + n; 607da6c28aaSamw 608da6c28aaSamw while (ps < es && *ps) { 609da6c28aaSamw if (*ps == c) 610da6c28aaSamw return (ps); 611da6c28aaSamw 612da6c28aaSamw ++ps; 613da6c28aaSamw } 614da6c28aaSamw 615da6c28aaSamw if (*ps == '\0' && c == '\0') 616da6c28aaSamw return (ps); 617da6c28aaSamw 618da6c28aaSamw return (0); 619da6c28aaSamw } 620da6c28aaSamw 6217b59d02dSjb static boolean_t 622da6c28aaSamw is_multihome(char *name) 623da6c28aaSamw { 6247b59d02dSjb return (smb_nic_getnum(name) > 1); 625da6c28aaSamw } 626da6c28aaSamw 627da6c28aaSamw /* 628da6c28aaSamw * smb_netbios_getname 629da6c28aaSamw * 630da6c28aaSamw * Get the Netbios name part of the given record. 631da6c28aaSamw * Does some boundary checks. 632da6c28aaSamw * 633da6c28aaSamw * Returns the name length on success, otherwise 634da6c28aaSamw * returns 0. 635da6c28aaSamw */ 636da6c28aaSamw static int 637da6c28aaSamw smb_netbios_getname(char *name, char *buf, char *buf_end) 638da6c28aaSamw { 639da6c28aaSamw char *name_end; 640da6c28aaSamw int name_len; 641da6c28aaSamw 642da6c28aaSamw if (buf >= buf_end) { 643da6c28aaSamw /* no room for a NB name */ 644da6c28aaSamw return (0); 645da6c28aaSamw } 646da6c28aaSamw 647da6c28aaSamw name_end = strnchr(buf, '\0', buf_end - buf + 1); 648da6c28aaSamw if (name_end == 0) { 649da6c28aaSamw /* not a valid NB name */ 650da6c28aaSamw return (0); 651da6c28aaSamw } 652da6c28aaSamw 653da6c28aaSamw name_len = name_end - buf + 1; 654da6c28aaSamw 655da6c28aaSamw (void) strlcpy(name, buf, name_len); 656da6c28aaSamw return (name_len); 657da6c28aaSamw } 658da6c28aaSamw 659da6c28aaSamw /* 660da6c28aaSamw * smb_name_buf_to_packet 661da6c28aaSamw * 662*a0aa776eSAlan Wright * Convert the bits and bytes that came from the wire into a NetBIOS 663*a0aa776eSAlan Wright * Name Server Packet Block (npb). The "block" is used as a heap. 664da6c28aaSamw * 665*a0aa776eSAlan Wright * Returns a pointer to a name packet on success. Otherwise, returns 666*a0aa776eSAlan Wright * a NULL pointer. 667da6c28aaSamw */ 668da6c28aaSamw static struct name_packet * 669da6c28aaSamw smb_name_buf_to_packet(char *buf, int n_buf) 670da6c28aaSamw { 671da6c28aaSamw struct name_packet *npb; 672da6c28aaSamw unsigned char *heap; 673da6c28aaSamw unsigned char *scan = (unsigned char *)buf; 674da6c28aaSamw unsigned char *scan_end = scan + n_buf; 675da6c28aaSamw char name_buf[MAX_NAME_LENGTH]; 676da6c28aaSamw struct resource_record *nrr = 0; 677da6c28aaSamw int rc, i, n, nn, ns; 678*a0aa776eSAlan Wright uint16_t name_trn_id, info; 679*a0aa776eSAlan Wright uint16_t qdcount, ancount, nscount, arcount; 680*a0aa776eSAlan Wright addr_entry_t *next; 681da6c28aaSamw int name_len; 682da6c28aaSamw 683da6c28aaSamw if (n_buf < NAME_HEADER_SIZE) { 684da6c28aaSamw /* truncated header */ 685*a0aa776eSAlan Wright syslog(LOG_DEBUG, "nbns: short packet (%d bytes)", n_buf); 686*a0aa776eSAlan Wright return (NULL); 687da6c28aaSamw } 688da6c28aaSamw 689da6c28aaSamw name_trn_id = BE_IN16(scan); scan += 2; 690da6c28aaSamw info = BE_IN16(scan); scan += 2; 691da6c28aaSamw qdcount = BE_IN16(scan); scan += 2; 692da6c28aaSamw ancount = BE_IN16(scan); scan += 2; 693da6c28aaSamw nscount = BE_IN16(scan); scan += 2; 694da6c28aaSamw arcount = BE_IN16(scan); scan += 2; 695da6c28aaSamw 696da6c28aaSamw ns = sizeof (struct name_entry); 697da6c28aaSamw n = n_buf + sizeof (struct name_packet) + 698da6c28aaSamw ((unsigned)qdcount * (sizeof (struct name_question) + ns)) + 699da6c28aaSamw ((unsigned)ancount * (sizeof (struct resource_record) + ns)) + 700da6c28aaSamw ((unsigned)nscount * (sizeof (struct resource_record) + ns)) + 701da6c28aaSamw ((unsigned)arcount * (sizeof (struct resource_record) + ns)); 702da6c28aaSamw 703*a0aa776eSAlan Wright if ((npb = malloc(n)) == NULL) 704*a0aa776eSAlan Wright return (NULL); 705da6c28aaSamw 706*a0aa776eSAlan Wright bzero(npb, n); 707da6c28aaSamw heap = npb->block_data; 708da6c28aaSamw npb->name_trn_id = name_trn_id; 709da6c28aaSamw npb->info = info; 710da6c28aaSamw npb->qdcount = qdcount; 711da6c28aaSamw npb->ancount = ancount; 712da6c28aaSamw npb->nscount = nscount; 713da6c28aaSamw npb->arcount = arcount; 714da6c28aaSamw 715da6c28aaSamw /* scan is in position for question entries */ 716da6c28aaSamw 717da6c28aaSamw /* 718da6c28aaSamw * Measure the space needed for the tables 719da6c28aaSamw */ 720da6c28aaSamw if (qdcount > 0) { 721da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 722da6c28aaSamw npb->question = (struct name_question *)heap; 723da6c28aaSamw heap += qdcount * sizeof (struct name_question); 724da6c28aaSamw for (i = 0; i < qdcount; i++) { 725da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 726da6c28aaSamw npb->question[i].name = (struct name_entry *)heap; 727da6c28aaSamw heap += sizeof (struct name_entry); 728da6c28aaSamw } 729da6c28aaSamw } 730da6c28aaSamw 731da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 732da6c28aaSamw nrr = (struct resource_record *)heap; 733da6c28aaSamw 734da6c28aaSamw if (ancount > 0) { 735da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 736da6c28aaSamw npb->answer = (struct resource_record *)heap; 737da6c28aaSamw heap += ancount * sizeof (struct resource_record); 738da6c28aaSamw } 739da6c28aaSamw 740da6c28aaSamw if (nscount > 0) { 741da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 742da6c28aaSamw npb->authority = (struct resource_record *)heap; 743da6c28aaSamw heap += nscount * sizeof (struct resource_record); 744da6c28aaSamw } 745da6c28aaSamw 746da6c28aaSamw if (arcount > 0) { 747da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 748da6c28aaSamw npb->additional = (struct resource_record *)heap; 749da6c28aaSamw heap += arcount * sizeof (struct resource_record); 750da6c28aaSamw } 751da6c28aaSamw 752da6c28aaSamw /* 753da6c28aaSamw * Populate each resource_record's .name field. 754da6c28aaSamw * Done as a second pass so that all resource records 755da6c28aaSamw * (answer, authority, additional) are consecutive via nrr[i]. 756da6c28aaSamw */ 757da6c28aaSamw for (i = 0; i < (ancount + nscount + arcount); i++) { 758da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 759da6c28aaSamw nrr[i].name = (struct name_entry *)heap; 760da6c28aaSamw heap += sizeof (struct name_entry); 761da6c28aaSamw } 762da6c28aaSamw 763da6c28aaSamw 764da6c28aaSamw for (i = 0; i < npb->qdcount; i++) { 765da6c28aaSamw name_len = smb_netbios_getname(name_buf, (char *)scan, 766da6c28aaSamw (char *)scan_end); 767da6c28aaSamw if (name_len <= 0) { 768da6c28aaSamw free(npb); 769*a0aa776eSAlan Wright return (NULL); 770da6c28aaSamw } 771da6c28aaSamw 772da6c28aaSamw smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0, 773da6c28aaSamw npb->question[i].name); 774da6c28aaSamw rc = smb_first_level_name_decode((unsigned char *)name_buf, 775da6c28aaSamw npb->question[i].name); 776da6c28aaSamw if (rc < 0) { 777da6c28aaSamw /* Couldn't decode the question name */ 778da6c28aaSamw free(npb); 779*a0aa776eSAlan Wright return (NULL); 780da6c28aaSamw } 781da6c28aaSamw 782da6c28aaSamw scan += name_len; 783da6c28aaSamw if (scan + 4 > scan_end) { 784da6c28aaSamw /* no room for Question Type(2) and Class(2) fields */ 785da6c28aaSamw free(npb); 786*a0aa776eSAlan Wright return (NULL); 787da6c28aaSamw } 788da6c28aaSamw 789da6c28aaSamw npb->question[i].question_type = BE_IN16(scan); scan += 2; 790da6c28aaSamw npb->question[i].question_class = BE_IN16(scan); scan += 2; 791da6c28aaSamw } 792da6c28aaSamw 793da6c28aaSamw /* 794da6c28aaSamw * Cheat. Remaining sections are of the same resource_record 795da6c28aaSamw * format. Table space is consecutive. 796da6c28aaSamw */ 797da6c28aaSamw 798da6c28aaSamw for (i = 0; i < (ancount + nscount + arcount); i++) { 799da6c28aaSamw if (scan[0] == 0xc0) { 800da6c28aaSamw /* Namebuf is reused... */ 801da6c28aaSamw rc = 2; 802da6c28aaSamw } else { 803da6c28aaSamw name_len = smb_netbios_getname(name_buf, (char *)scan, 804da6c28aaSamw (char *)scan_end); 805da6c28aaSamw if (name_len <= 0) { 806da6c28aaSamw free(npb); 807*a0aa776eSAlan Wright return (NULL); 808da6c28aaSamw } 809da6c28aaSamw rc = name_len; 810da6c28aaSamw } 811da6c28aaSamw scan += rc; 812da6c28aaSamw 813da6c28aaSamw if (scan + 10 > scan_end) { 814da6c28aaSamw /* 815da6c28aaSamw * no room for RR_TYPE (2), RR_CLASS (2), TTL (4) and 816da6c28aaSamw * RDLENGTH (2) fields. 817da6c28aaSamw */ 818da6c28aaSamw free(npb); 819*a0aa776eSAlan Wright return (NULL); 820da6c28aaSamw } 821da6c28aaSamw 822da6c28aaSamw smb_init_name_struct(NETBIOS_EMPTY_NAME, 0, 0, 0, 0, 0, 0, 823da6c28aaSamw nrr[i].name); 824da6c28aaSamw if ((rc = smb_first_level_name_decode((unsigned char *)name_buf, 825da6c28aaSamw nrr[i].name)) < 0) { 826da6c28aaSamw free(npb); 827*a0aa776eSAlan Wright return (NULL); 828da6c28aaSamw } 829da6c28aaSamw 830da6c28aaSamw nrr[i].rr_type = BE_IN16(scan); scan += 2; 831da6c28aaSamw nrr[i].rr_class = BE_IN16(scan); scan += 2; 832da6c28aaSamw nrr[i].ttl = BE_IN32(scan); scan += 4; 833da6c28aaSamw nrr[i].rdlength = BE_IN16(scan); scan += 2; 834da6c28aaSamw 835da6c28aaSamw if ((n = nrr[i].rdlength) > 0) { 836da6c28aaSamw if ((scan + n) > scan_end) { 837da6c28aaSamw /* no room for RDATA */ 838da6c28aaSamw free(npb); 839*a0aa776eSAlan Wright return (NULL); 840da6c28aaSamw } 841da6c28aaSamw bcopy(scan, heap, n); 842da6c28aaSamw 843da6c28aaSamw nn = n; 844da6c28aaSamw if (nrr[i].rr_type == 0x0020 && 845da6c28aaSamw nrr[i].rr_class == 0x01 && n >= 6) { 846da6c28aaSamw while (nn) { 847da6c28aaSamw if (nn == 6) 848da6c28aaSamw next = &nrr[i].name->addr_list; 849da6c28aaSamw else { 850*a0aa776eSAlan Wright next = malloc( 851*a0aa776eSAlan Wright sizeof (addr_entry_t)); 852da6c28aaSamw if (next == 0) { 853da6c28aaSamw /* not enough memory */ 854da6c28aaSamw free(npb); 855*a0aa776eSAlan Wright return (NULL); 856da6c28aaSamw } 857da6c28aaSamw QUEUE_INSERT_TAIL( 858da6c28aaSamw &nrr[i].name->addr_list, 859da6c28aaSamw next); 860da6c28aaSamw } 861da6c28aaSamw nrr[i].name->attributes = 862da6c28aaSamw BE_IN16(scan); 863da6c28aaSamw next->sin.sin_family = AF_INET; 864da6c28aaSamw next->sinlen = sizeof (next->sin); 865da6c28aaSamw (void) memcpy( 866da6c28aaSamw &next->sin.sin_addr.s_addr, 867da6c28aaSamw scan + 2, sizeof (uint32_t)); 868da6c28aaSamw next->sin.sin_port = 869*a0aa776eSAlan Wright htons(IPPORT_NETBIOS_DGM); 870da6c28aaSamw nn -= 6; 871da6c28aaSamw scan += 6; 872da6c28aaSamw } 873da6c28aaSamw } else { 874da6c28aaSamw nrr[i].rdata = heap; 875da6c28aaSamw scan += n; 876da6c28aaSamw } 877da6c28aaSamw heap += n; 878da6c28aaSamw } 879da6c28aaSamw } 880da6c28aaSamw return (npb); 881da6c28aaSamw } 882da6c28aaSamw 883da6c28aaSamw /* 884da6c28aaSamw * smb_send_name_service_packet 885da6c28aaSamw * 886da6c28aaSamw * Description: 887da6c28aaSamw * 888da6c28aaSamw * Send out a name service packet to proper destination. 889da6c28aaSamw * 890da6c28aaSamw * Inputs: 891da6c28aaSamw * struct netbios_name *dest -> NETBIOS name of destination 892da6c28aaSamw * struct name_packet *packet -> Packet to send 893da6c28aaSamw * 894da6c28aaSamw * Returns: 895da6c28aaSamw * success -> >0 896da6c28aaSamw * failure -> <=0 897da6c28aaSamw */ 898da6c28aaSamw static int 899*a0aa776eSAlan Wright smb_send_name_service_packet(addr_entry_t *addr, struct name_packet *packet) 900da6c28aaSamw { 901da6c28aaSamw unsigned char buf[MAX_DATAGRAM_LENGTH]; 902da6c28aaSamw int len; 903da6c28aaSamw 904da6c28aaSamw if ((len = smb_name_buf_from_packet(buf, sizeof (buf), packet)) < 0) { 905da6c28aaSamw errno = EINVAL; 906da6c28aaSamw return (-1); 907da6c28aaSamw } 908da6c28aaSamw 909da6c28aaSamw return (sendto(name_sock, buf, len, MSG_EOR, 910da6c28aaSamw (struct sockaddr *)&addr->sin, addr->sinlen)); 911da6c28aaSamw } 912da6c28aaSamw 913da6c28aaSamw /* 914da6c28aaSamw * smb_netbios_send_rcv 915da6c28aaSamw * 916da6c28aaSamw * This function sends the given NetBIOS packet to the given 917da6c28aaSamw * address and get back the response. If send operation is not 918da6c28aaSamw * successful, it's repeated 'retries' times. 919da6c28aaSamw * 920da6c28aaSamw * Returns: 921da6c28aaSamw * 0 Unsuccessful send operation; no reply 922da6c28aaSamw * 1 Got reply 923da6c28aaSamw */ 924da6c28aaSamw static int 925*a0aa776eSAlan Wright smb_netbios_send_rcv(int bcast, addr_entry_t *destination, 926*a0aa776eSAlan Wright struct name_packet *packet, uint32_t retries, uint32_t timeout) 927da6c28aaSamw { 928da6c28aaSamw uint32_t retry; 929*a0aa776eSAlan Wright uint16_t tid; 930da6c28aaSamw struct timespec st; 931da6c28aaSamw int rc; 932da6c28aaSamw 933da6c28aaSamw for (retry = 0; retry < retries; retry++) { 934da6c28aaSamw if ((destination->flags & ADDR_FLAG_VALID) == 0) 935da6c28aaSamw return (0); 936da6c28aaSamw 937*a0aa776eSAlan Wright tid = smb_netbios_name_trn_id(); 938da6c28aaSamw packet->name_trn_id = tid; 939da6c28aaSamw if (smb_send_name_service_packet(destination, packet) >= 0) { 940da6c28aaSamw rc = smb_netbios_process_response(tid, destination, 941da6c28aaSamw packet, timeout); 942da6c28aaSamw 943da6c28aaSamw if ((rc > 0) || (bcast == BROADCAST)) 944da6c28aaSamw return (1); 945da6c28aaSamw 946da6c28aaSamw if (rc != 0) 947da6c28aaSamw return (0); 948da6c28aaSamw } 949da6c28aaSamw 950da6c28aaSamw st.tv_sec = 0; 951da6c28aaSamw st.tv_nsec = (timeout * 1000000); 952da6c28aaSamw (void) nanosleep(&st, 0); 953da6c28aaSamw } 954da6c28aaSamw 955da6c28aaSamw return (0); 956da6c28aaSamw } 957da6c28aaSamw 958da6c28aaSamw /* 959*a0aa776eSAlan Wright * RFC 1002 4.2.2. NAME REGISTRATION REQUEST 960da6c28aaSamw */ 961da6c28aaSamw static int 962da6c28aaSamw smb_send_name_registration_request(int bcast, struct name_question *question, 963da6c28aaSamw struct resource_record *additional) 964da6c28aaSamw { 965da6c28aaSamw int gotreply = 0; 966da6c28aaSamw uint32_t retries; 967da6c28aaSamw uint32_t timeout; 968*a0aa776eSAlan Wright addr_entry_t *destination; 969da6c28aaSamw struct name_packet packet; 970da6c28aaSamw unsigned char type; 971da6c28aaSamw int i, addr_num, rc; 972da6c28aaSamw 973da6c28aaSamw type = question->name->name[15]; 974*a0aa776eSAlan Wright if ((type != NBT_WKSTA) && (type != NBT_SERVER)) { 975*a0aa776eSAlan Wright syslog(LOG_DEBUG, "nbns: name registration bad type (0x%02x)", 976*a0aa776eSAlan Wright type); 977da6c28aaSamw smb_netbios_name_logf(question->name); 978da6c28aaSamw question->name->attributes &= ~NAME_ATTR_LOCAL; 979da6c28aaSamw return (-1); 980da6c28aaSamw } 981da6c28aaSamw 982da6c28aaSamw if (bcast == BROADCAST) { 983da6c28aaSamw if (bcast_num == 0) 984da6c28aaSamw return (0); 985da6c28aaSamw destination = smb_bcast_list; 986da6c28aaSamw addr_num = bcast_num; 987da6c28aaSamw retries = BCAST_REQ_RETRY_COUNT; 988da6c28aaSamw timeout = BCAST_REQ_RETRY_TIMEOUT; 989da6c28aaSamw packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_BROADCAST; 990da6c28aaSamw } else { 991da6c28aaSamw if (nbns_num == 0) 992da6c28aaSamw return (0); 993da6c28aaSamw destination = smb_nbns; 994da6c28aaSamw addr_num = nbns_num; 995da6c28aaSamw retries = UCAST_REQ_RETRY_COUNT; 996da6c28aaSamw timeout = UCAST_REQ_RETRY_TIMEOUT; 997da6c28aaSamw packet.info = NAME_REGISTRATION_REQUEST | NM_FLAGS_UNICAST; 998da6c28aaSamw } 999da6c28aaSamw 1000da6c28aaSamw packet.qdcount = 1; /* question entries */ 1001da6c28aaSamw packet.question = question; 1002da6c28aaSamw packet.ancount = 0; /* answer recs */ 1003da6c28aaSamw packet.answer = NULL; 1004da6c28aaSamw packet.nscount = 0; /* authority recs */ 1005da6c28aaSamw packet.authority = NULL; 1006da6c28aaSamw packet.arcount = 1; /* additional recs */ 1007da6c28aaSamw packet.additional = additional; 1008da6c28aaSamw 1009da6c28aaSamw if (IS_UNIQUE(question->name->attributes) && 1010da6c28aaSamw (is_multihome((char *)(question->name->name)))) 1011da6c28aaSamw packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST; 1012da6c28aaSamw 1013da6c28aaSamw for (i = 0; i < addr_num; i++) { 1014da6c28aaSamw /* 1015da6c28aaSamw * Only register with the Primary WINS server, 1016da6c28aaSamw * unless we got no reply. 1017da6c28aaSamw */ 1018da6c28aaSamw if ((bcast == UNICAST) && gotreply) 1019da6c28aaSamw break; 1020da6c28aaSamw 1021da6c28aaSamw rc = smb_netbios_send_rcv(bcast, &destination[i], &packet, 1022da6c28aaSamw retries, timeout); 1023da6c28aaSamw if (rc == 1) 1024da6c28aaSamw gotreply = 1; 1025da6c28aaSamw } 1026da6c28aaSamw 1027da6c28aaSamw return (gotreply); 1028da6c28aaSamw } 1029da6c28aaSamw 1030da6c28aaSamw /* 1031*a0aa776eSAlan Wright * RFC 1002 4.2.4. NAME REFRESH REQUEST 1032da6c28aaSamw */ 1033da6c28aaSamw /*ARGSUSED*/ 1034da6c28aaSamw static int 1035da6c28aaSamw smb_send_name_refresh_request(int bcast, struct name_question *question, 1036da6c28aaSamw struct resource_record *additional, int force) 1037da6c28aaSamw { 1038da6c28aaSamw int rc = 0; 1039da6c28aaSamw int gotreply = 0; 1040da6c28aaSamw uint32_t retries; 1041da6c28aaSamw uint32_t timeout; 1042*a0aa776eSAlan Wright addr_entry_t *addr; 1043*a0aa776eSAlan Wright addr_entry_t *destination; 1044da6c28aaSamw struct name_packet packet; 1045da6c28aaSamw unsigned char type; 1046da6c28aaSamw int i, addr_num, q_addrs = 0; 1047da6c28aaSamw 1048da6c28aaSamw type = question->name->name[15]; 1049*a0aa776eSAlan Wright if ((type != NBT_WKSTA) && (type != NBT_SERVER)) { 1050*a0aa776eSAlan Wright syslog(LOG_DEBUG, "nbns: name refresh bad type (0x%02x)", type); 1051da6c28aaSamw smb_netbios_name_logf(question->name); 1052da6c28aaSamw question->name->attributes &= ~NAME_ATTR_LOCAL; 1053da6c28aaSamw return (-1); 1054da6c28aaSamw } 1055da6c28aaSamw switch (bcast) { 1056da6c28aaSamw case BROADCAST : 1057da6c28aaSamw if (bcast_num == 0) 1058da6c28aaSamw return (-1); 1059da6c28aaSamw destination = smb_bcast_list; 1060da6c28aaSamw addr_num = bcast_num; 1061da6c28aaSamw retries = BCAST_REQ_RETRY_COUNT; 1062da6c28aaSamw timeout = BCAST_REQ_RETRY_TIMEOUT; 1063da6c28aaSamw packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_BROADCAST; 1064da6c28aaSamw break; 1065da6c28aaSamw 1066da6c28aaSamw case UNICAST : 1067da6c28aaSamw if (nbns_num == 0) 1068da6c28aaSamw return (-1); 1069da6c28aaSamw destination = smb_nbns; 1070da6c28aaSamw addr_num = nbns_num; 1071da6c28aaSamw retries = UCAST_REQ_RETRY_COUNT; 1072da6c28aaSamw timeout = UCAST_REQ_RETRY_TIMEOUT; 1073da6c28aaSamw packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST; 1074da6c28aaSamw break; 1075da6c28aaSamw 1076da6c28aaSamw default: 1077da6c28aaSamw destination = &question->name->addr_list; 1078da6c28aaSamw /* 1079da6c28aaSamw * the value of addr_num is irrelvant here, because 1080da6c28aaSamw * the code is going to do special_process so it doesn't 1081da6c28aaSamw * need the addr_num. We set a value here just to avoid 1082da6c28aaSamw * compiler warning. 1083da6c28aaSamw */ 1084da6c28aaSamw addr_num = 0; 1085da6c28aaSamw retries = UCAST_REQ_RETRY_COUNT; 1086da6c28aaSamw timeout = UCAST_REQ_RETRY_TIMEOUT; 1087da6c28aaSamw packet.info = NAME_REFRESH_REQUEST | NM_FLAGS_UNICAST; 1088da6c28aaSamw q_addrs = 1; 1089da6c28aaSamw break; 1090da6c28aaSamw } 1091da6c28aaSamw 1092da6c28aaSamw if (IS_UNIQUE(question->name->attributes) && 1093da6c28aaSamw (is_multihome((char *)(question->name->name)))) 1094da6c28aaSamw packet.info |= NAME_MULTIHOME_REGISTRATION_REQUEST; 1095da6c28aaSamw 1096da6c28aaSamw packet.qdcount = 1; /* question entries */ 1097da6c28aaSamw packet.question = question; 1098da6c28aaSamw packet.ancount = 0; /* answer recs */ 1099da6c28aaSamw packet.answer = NULL; 1100da6c28aaSamw packet.nscount = 0; /* authority recs */ 1101da6c28aaSamw packet.authority = NULL; 1102da6c28aaSamw packet.arcount = 1; /* additional recs */ 1103da6c28aaSamw packet.additional = additional; 1104da6c28aaSamw 1105da6c28aaSamw if (q_addrs) 1106da6c28aaSamw goto special_process; 1107da6c28aaSamw 1108da6c28aaSamw for (i = 0; i < addr_num; i++) { 1109da6c28aaSamw rc = smb_netbios_send_rcv(bcast, &destination[i], &packet, 1110da6c28aaSamw retries, timeout); 1111da6c28aaSamw if (rc == 1) 1112da6c28aaSamw gotreply = 1; 1113da6c28aaSamw } 1114da6c28aaSamw 1115da6c28aaSamw return (gotreply); 1116da6c28aaSamw 1117da6c28aaSamw special_process: 1118da6c28aaSamw addr = destination; 1119da6c28aaSamw do { 1120da6c28aaSamw rc = smb_netbios_send_rcv(bcast, addr, &packet, 1121da6c28aaSamw retries, timeout); 1122da6c28aaSamw if (rc == 1) 1123da6c28aaSamw gotreply = 1; 1124da6c28aaSamw addr = addr->forw; 1125da6c28aaSamw } while (addr != destination); 1126da6c28aaSamw 1127da6c28aaSamw return (gotreply); 1128da6c28aaSamw } 1129da6c28aaSamw 1130da6c28aaSamw /* 1131*a0aa776eSAlan Wright * RFC 1002 4.2.5. POSITIVE NAME REGISTRATION RESPONSE 1132*a0aa776eSAlan Wright * RFC 1002 4.2.6. NEGATIVE NAME REGISTRATION RESPONSE 1133da6c28aaSamw */ 1134da6c28aaSamw static int 1135*a0aa776eSAlan Wright smb_send_name_registration_response(addr_entry_t *addr, 1136*a0aa776eSAlan Wright struct name_packet *original_packet, uint16_t rcode) 1137da6c28aaSamw { 1138da6c28aaSamw struct name_packet packet; 1139da6c28aaSamw struct resource_record answer; 1140da6c28aaSamw 1141da6c28aaSamw bzero(&packet, sizeof (struct name_packet)); 1142da6c28aaSamw bzero(&answer, sizeof (struct resource_record)); 1143da6c28aaSamw 1144da6c28aaSamw packet.name_trn_id = original_packet->name_trn_id; 1145da6c28aaSamw packet.info = NAME_REGISTRATION_RESPONSE | NAME_NM_FLAGS_RA | 1146da6c28aaSamw (rcode & NAME_RCODE_MASK); 1147da6c28aaSamw packet.qdcount = 0; /* question entries */ 1148da6c28aaSamw packet.question = NULL; 1149da6c28aaSamw packet.ancount = 1; /* answer recs */ 1150da6c28aaSamw packet.answer = &answer; 1151da6c28aaSamw packet.nscount = 0; /* authority recs */ 1152da6c28aaSamw packet.authority = NULL; 1153da6c28aaSamw packet.arcount = 0; /* additional recs */ 1154da6c28aaSamw packet.additional = NULL; 1155da6c28aaSamw 1156da6c28aaSamw answer.name = original_packet->question->name; 1157da6c28aaSamw answer.rr_type = NAME_QUESTION_TYPE_NB; 1158da6c28aaSamw answer.rr_class = NAME_QUESTION_CLASS_IN; 1159da6c28aaSamw answer.ttl = original_packet->additional->ttl; 1160da6c28aaSamw answer.rdlength = original_packet->additional->rdlength; 1161da6c28aaSamw answer.rdata = original_packet->additional->rdata; 1162da6c28aaSamw 1163da6c28aaSamw return (smb_send_name_service_packet(addr, &packet)); 1164da6c28aaSamw } 1165da6c28aaSamw 1166da6c28aaSamw /* 1167*a0aa776eSAlan Wright * RFC 1002 4.2.9. NAME RELEASE REQUEST & DEMAND 1168da6c28aaSamw */ 1169da6c28aaSamw static int 1170da6c28aaSamw smb_send_name_release_request_and_demand(int bcast, 1171da6c28aaSamw struct name_question *question, struct resource_record *additional) 1172da6c28aaSamw { 1173da6c28aaSamw int gotreply = 0; 1174da6c28aaSamw int i, rc; 1175da6c28aaSamw int addr_num; 1176da6c28aaSamw uint32_t retries; 1177da6c28aaSamw uint32_t timeout; 1178*a0aa776eSAlan Wright addr_entry_t *destination; 1179da6c28aaSamw struct name_packet packet; 1180da6c28aaSamw 1181da6c28aaSamw if (bcast == BROADCAST) { 1182da6c28aaSamw if (bcast_num == 0) 1183da6c28aaSamw return (-1); 1184da6c28aaSamw destination = smb_bcast_list; 1185da6c28aaSamw addr_num = bcast_num; 1186da6c28aaSamw retries = 1; /* BCAST_REQ_RETRY_COUNT */ 1187da6c28aaSamw timeout = 100; /* BCAST_REQ_RETRY_TIMEOUT */ 1188da6c28aaSamw packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_BROADCAST; 1189da6c28aaSamw } else { 1190da6c28aaSamw if (nbns_num == 0) 1191da6c28aaSamw return (-1); 1192da6c28aaSamw destination = smb_nbns; 1193da6c28aaSamw addr_num = nbns_num; 1194da6c28aaSamw retries = 1; /* UCAST_REQ_RETRY_COUNT */ 1195da6c28aaSamw timeout = 100; /* UCAST_REQ_RETRY_TIMEOUT */ 1196da6c28aaSamw packet.info = NAME_RELEASE_REQUEST | NM_FLAGS_UNICAST; 1197da6c28aaSamw } 1198da6c28aaSamw 1199da6c28aaSamw packet.qdcount = 1; /* question entries */ 1200da6c28aaSamw packet.question = question; 1201da6c28aaSamw packet.ancount = 0; /* answer recs */ 1202da6c28aaSamw packet.answer = NULL; 1203da6c28aaSamw packet.nscount = 0; /* authority recs */ 1204da6c28aaSamw packet.authority = NULL; 1205da6c28aaSamw packet.arcount = 1; /* additional recs */ 1206da6c28aaSamw packet.additional = additional; 1207da6c28aaSamw 1208da6c28aaSamw for (i = 0; i < addr_num; i++) { 1209da6c28aaSamw rc = smb_netbios_send_rcv(bcast, &destination[i], &packet, 1210da6c28aaSamw retries, timeout); 1211da6c28aaSamw if (rc == 1) 1212da6c28aaSamw gotreply = 1; 1213da6c28aaSamw } 1214da6c28aaSamw 1215da6c28aaSamw return (gotreply); 1216da6c28aaSamw } 1217da6c28aaSamw 1218da6c28aaSamw /* 1219*a0aa776eSAlan Wright * RFC 1002 4.2.10. POSITIVE NAME RELEASE RESPONSE 1220*a0aa776eSAlan Wright * RFC 1002 4.2.11. NEGATIVE NAME RELEASE RESPONSE 1221da6c28aaSamw */ 1222da6c28aaSamw static int 1223da6c28aaSamw /* LINTED - E_STATIC_UNUSED */ 1224*a0aa776eSAlan Wright smb_send_name_release_response(addr_entry_t *addr, 1225*a0aa776eSAlan Wright struct name_packet *original_packet, uint16_t rcode) 1226da6c28aaSamw { 1227da6c28aaSamw struct name_packet packet; 1228da6c28aaSamw struct resource_record answer; 1229da6c28aaSamw 1230da6c28aaSamw bzero(&packet, sizeof (struct name_packet)); 1231da6c28aaSamw bzero(&answer, sizeof (struct resource_record)); 1232da6c28aaSamw 1233da6c28aaSamw packet.name_trn_id = original_packet->name_trn_id; 1234da6c28aaSamw packet.info = NAME_RELEASE_RESPONSE | (rcode & NAME_RCODE_MASK); 1235da6c28aaSamw packet.qdcount = 0; /* question entries */ 1236da6c28aaSamw packet.question = NULL; 1237da6c28aaSamw packet.ancount = 1; /* answer recs */ 1238da6c28aaSamw packet.answer = &answer; 1239da6c28aaSamw packet.nscount = 0; /* authority recs */ 1240da6c28aaSamw packet.authority = NULL; 1241da6c28aaSamw packet.arcount = 0; /* additional recs */ 1242da6c28aaSamw packet.additional = NULL; 1243da6c28aaSamw 1244da6c28aaSamw answer.name = original_packet->question->name; 1245da6c28aaSamw answer.rr_type = NAME_QUESTION_TYPE_NB; 1246da6c28aaSamw answer.rr_class = NAME_QUESTION_CLASS_IN; 1247da6c28aaSamw answer.ttl = original_packet->additional->ttl; 1248da6c28aaSamw answer.rdlength = original_packet->additional->rdlength; 1249da6c28aaSamw answer.rdata = original_packet->additional->rdata; 1250da6c28aaSamw 1251da6c28aaSamw return (smb_send_name_service_packet(addr, &packet)); 1252da6c28aaSamw } 1253da6c28aaSamw 1254da6c28aaSamw /* 1255*a0aa776eSAlan Wright * RFC 1002 4.2.12. NAME QUERY REQUEST 1256da6c28aaSamw */ 1257da6c28aaSamw static int 1258da6c28aaSamw smb_send_name_query_request(int bcast, struct name_question *question) 1259da6c28aaSamw { 1260da6c28aaSamw int rc = 0; 1261da6c28aaSamw uint32_t retry, retries; 1262da6c28aaSamw uint32_t timeout; 1263*a0aa776eSAlan Wright uint16_t tid; 1264*a0aa776eSAlan Wright addr_entry_t *destination; 1265da6c28aaSamw struct name_packet packet; 1266da6c28aaSamw int i, addr_num; 1267da6c28aaSamw struct timespec st; 1268da6c28aaSamw 1269da6c28aaSamw if (bcast == BROADCAST) { 1270da6c28aaSamw if (bcast_num == 0) 1271da6c28aaSamw return (-1); 1272da6c28aaSamw destination = smb_bcast_list; 1273da6c28aaSamw addr_num = bcast_num; 1274da6c28aaSamw retries = BCAST_REQ_RETRY_COUNT; 1275da6c28aaSamw timeout = BCAST_REQ_RETRY_TIMEOUT; 1276da6c28aaSamw packet.info = NAME_QUERY_REQUEST | NM_FLAGS_BROADCAST; 1277da6c28aaSamw } else { 1278da6c28aaSamw if (nbns_num == 0) 1279da6c28aaSamw return (-1); 1280da6c28aaSamw destination = smb_nbns; 1281da6c28aaSamw addr_num = nbns_num; 1282da6c28aaSamw retries = UCAST_REQ_RETRY_COUNT; 1283da6c28aaSamw timeout = UCAST_REQ_RETRY_TIMEOUT; 1284da6c28aaSamw packet.info = NAME_QUERY_REQUEST | NM_FLAGS_UNICAST; 1285da6c28aaSamw } 1286da6c28aaSamw packet.qdcount = 1; /* question entries */ 1287da6c28aaSamw packet.question = question; 1288da6c28aaSamw packet.ancount = 0; /* answer recs */ 1289da6c28aaSamw packet.answer = NULL; 1290da6c28aaSamw packet.nscount = 0; /* authority recs */ 1291da6c28aaSamw packet.authority = NULL; 1292da6c28aaSamw packet.arcount = 0; /* additional recs */ 1293da6c28aaSamw packet.additional = NULL; 1294da6c28aaSamw 1295da6c28aaSamw for (i = 0; i < addr_num; i++) { 1296da6c28aaSamw for (retry = 0; retry < retries; retry++) { 1297*a0aa776eSAlan Wright if ((destination[i].flags & ADDR_FLAG_VALID) == 0) 1298da6c28aaSamw break; 1299*a0aa776eSAlan Wright tid = smb_netbios_name_trn_id(); 1300da6c28aaSamw packet.name_trn_id = tid; 1301da6c28aaSamw 1302da6c28aaSamw if (smb_send_name_service_packet(&destination[i], 1303da6c28aaSamw &packet) >= 0) { 1304da6c28aaSamw if ((rc = smb_netbios_process_response(tid, 1305da6c28aaSamw &destination[i], 1306da6c28aaSamw &packet, timeout)) != 0) 1307da6c28aaSamw break; 1308da6c28aaSamw } 1309da6c28aaSamw st.tv_sec = 0; 1310da6c28aaSamw st.tv_nsec = (timeout * 1000000); 1311da6c28aaSamw (void) nanosleep(&st, 0); 1312da6c28aaSamw } 1313da6c28aaSamw } 1314da6c28aaSamw 1315da6c28aaSamw return (rc); 1316da6c28aaSamw } 1317da6c28aaSamw 1318da6c28aaSamw /* 1319*a0aa776eSAlan Wright * RFC 1002 4.2.13. POSITIVE NAME QUERY RESPONSE 1320*a0aa776eSAlan Wright * RFC 1002 4.2.14. NEGATIVE NAME QUERY RESPONSE 1321da6c28aaSamw */ 1322da6c28aaSamw static int 1323*a0aa776eSAlan Wright smb_send_name_query_response(addr_entry_t *addr, 1324da6c28aaSamw struct name_packet *original_packet, struct name_entry *entry, 1325*a0aa776eSAlan Wright uint16_t rcode) 1326da6c28aaSamw { 1327*a0aa776eSAlan Wright addr_entry_t *raddr; 1328da6c28aaSamw struct name_packet packet; 1329da6c28aaSamw struct resource_record answer; 1330*a0aa776eSAlan Wright uint16_t attr; 1331da6c28aaSamw unsigned char data[MAX_DATAGRAM_LENGTH]; 1332da6c28aaSamw unsigned char *scan = data; 133329bd2886SAlan Wright uint32_t ret_addr; 1334da6c28aaSamw 1335da6c28aaSamw packet.name_trn_id = original_packet->name_trn_id; 1336da6c28aaSamw packet.info = NAME_QUERY_RESPONSE | (rcode & NAME_RCODE_MASK); 1337da6c28aaSamw packet.qdcount = 0; /* question entries */ 1338da6c28aaSamw packet.question = NULL; 1339da6c28aaSamw packet.ancount = 1; /* answer recs */ 1340da6c28aaSamw packet.answer = &answer; 1341da6c28aaSamw packet.nscount = 0; /* authority recs */ 1342da6c28aaSamw packet.authority = NULL; 1343da6c28aaSamw packet.arcount = 0; /* additional recs */ 1344da6c28aaSamw packet.additional = NULL; 1345da6c28aaSamw 1346da6c28aaSamw answer.name = entry; 1347da6c28aaSamw answer.rr_class = NAME_QUESTION_CLASS_IN; 1348da6c28aaSamw answer.ttl = entry->addr_list.ttl; 1349da6c28aaSamw answer.rdata = data; 1350da6c28aaSamw if (rcode) { 1351da6c28aaSamw answer.rr_type = NAME_RR_TYPE_NULL; 1352da6c28aaSamw answer.rdlength = 0; 1353da6c28aaSamw bzero(data, 6); 1354da6c28aaSamw } else { 1355da6c28aaSamw answer.rdlength = 0; 1356da6c28aaSamw answer.rr_type = NAME_QUESTION_TYPE_NB; 1357da6c28aaSamw raddr = &entry->addr_list; 1358da6c28aaSamw scan = data; 1359da6c28aaSamw do { 1360da6c28aaSamw attr = entry->attributes & (NAME_ATTR_GROUP | 1361da6c28aaSamw NAME_ATTR_OWNER_NODE_TYPE); 1362da6c28aaSamw 1363da6c28aaSamw BE_OUT16(scan, attr); scan += 2; 136429bd2886SAlan Wright ret_addr = LE_32(raddr->sin.sin_addr.s_addr); 136529bd2886SAlan Wright *scan++ = ret_addr; 136629bd2886SAlan Wright *scan++ = ret_addr >> 8; 136729bd2886SAlan Wright *scan++ = ret_addr >> 16; 136829bd2886SAlan Wright *scan++ = ret_addr >> 24; 1369da6c28aaSamw 1370da6c28aaSamw answer.rdlength += 6; 1371da6c28aaSamw raddr = raddr->forw; 1372da6c28aaSamw } while (raddr != &entry->addr_list); 1373da6c28aaSamw } 1374da6c28aaSamw 1375da6c28aaSamw return (smb_send_name_service_packet(addr, &packet)); 1376da6c28aaSamw } 1377da6c28aaSamw 1378da6c28aaSamw /* 1379*a0aa776eSAlan Wright * RFC 1002 4.2.18. NODE STATUS RESPONSE 1380da6c28aaSamw */ 1381da6c28aaSamw static int 1382*a0aa776eSAlan Wright smb_send_node_status_response(addr_entry_t *addr, 1383da6c28aaSamw struct name_packet *original_packet) 1384da6c28aaSamw { 1385dc20a302Sas uint32_t net_ipaddr; 1386dc20a302Sas int64_t max_connections; 1387da6c28aaSamw struct arpreq arpreq; 1388da6c28aaSamw struct name_packet packet; 1389da6c28aaSamw struct resource_record answer; 1390da6c28aaSamw unsigned char *scan; 1391da6c28aaSamw unsigned char *scan_end; 1392da6c28aaSamw unsigned char data[MAX_NETBIOS_REPLY_DATA_SIZE]; 139355bf511dSas boolean_t scan_done = B_FALSE; 13947f667e74Sjose borrego smb_inaddr_t ipaddr; 1395da6c28aaSamw 1396da6c28aaSamw bzero(&packet, sizeof (struct name_packet)); 1397da6c28aaSamw bzero(&answer, sizeof (struct resource_record)); 1398da6c28aaSamw 1399da6c28aaSamw packet.name_trn_id = original_packet->name_trn_id; 1400da6c28aaSamw packet.info = NODE_STATUS_RESPONSE; 1401da6c28aaSamw packet.qdcount = 0; /* question entries */ 1402da6c28aaSamw packet.question = NULL; 1403da6c28aaSamw packet.ancount = 1; /* answer recs */ 1404da6c28aaSamw packet.answer = &answer; 1405da6c28aaSamw packet.nscount = 0; /* authority recs */ 1406da6c28aaSamw packet.authority = NULL; 1407da6c28aaSamw packet.arcount = 0; /* additional recs */ 1408da6c28aaSamw packet.additional = NULL; 1409da6c28aaSamw 1410da6c28aaSamw answer.name = original_packet->question->name; 1411da6c28aaSamw answer.rr_type = NAME_RR_TYPE_NBSTAT; 1412da6c28aaSamw answer.rr_class = NAME_QUESTION_CLASS_IN; 1413da6c28aaSamw answer.ttl = 0; 1414da6c28aaSamw answer.rdata = data; 1415da6c28aaSamw 1416da6c28aaSamw scan = smb_netbios_cache_status(data, MAX_NETBIOS_REPLY_DATA_SIZE, 1417da6c28aaSamw original_packet->question->name->scope); 1418da6c28aaSamw 1419da6c28aaSamw scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE; 1420da6c28aaSamw 14217f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; 14227f667e74Sjose borrego ipaddr.a_family = AF_INET; 1423fc724630SAlan Wright if (smb_nic_is_same_subnet(&ipaddr)) 14247b59d02dSjb net_ipaddr = addr->sin.sin_addr.s_addr; 1425da6c28aaSamw else 14267b59d02dSjb net_ipaddr = 0; 1427da6c28aaSamw 1428dc20a302Sas (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &max_connections); 1429dc20a302Sas 143055bf511dSas while (!scan_done) { 1431da6c28aaSamw if ((scan + 6) >= scan_end) { 1432da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1433da6c28aaSamw break; 1434da6c28aaSamw } 1435da6c28aaSamw 1436da6c28aaSamw if (net_ipaddr != 0) { 1437da6c28aaSamw struct sockaddr_in *s_in; 1438da6c28aaSamw int s; 1439da6c28aaSamw 1440da6c28aaSamw s = socket(AF_INET, SOCK_DGRAM, 0); 1441da6c28aaSamw /* LINTED - E_BAD_PTR_CAST_ALIGN */ 1442da6c28aaSamw s_in = (struct sockaddr_in *)&arpreq.arp_pa; 1443da6c28aaSamw s_in->sin_family = AF_INET; 1444da6c28aaSamw s_in->sin_addr.s_addr = net_ipaddr; 1445da6c28aaSamw if (ioctl(s, SIOCGARP, (caddr_t)&arpreq) < 0) { 1446da6c28aaSamw bzero(scan, 6); 1447da6c28aaSamw } else { 1448da6c28aaSamw bcopy(&arpreq.arp_ha.sa_data, scan, 6); 1449da6c28aaSamw } 1450da6c28aaSamw (void) close(s); 1451da6c28aaSamw } else { 1452da6c28aaSamw bzero(scan, 6); 1453da6c28aaSamw } 1454da6c28aaSamw scan += 6; 1455da6c28aaSamw 1456da6c28aaSamw if ((scan + 26) >= scan_end) { 1457da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1458da6c28aaSamw break; 1459da6c28aaSamw } 1460da6c28aaSamw bzero(scan, 26); 1461da6c28aaSamw scan += 26; 1462da6c28aaSamw 1463da6c28aaSamw if ((scan + 2) >= scan_end) { 1464da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1465da6c28aaSamw break; 1466da6c28aaSamw } 1467da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1468da6c28aaSamw 1469da6c28aaSamw if ((scan + 2) >= scan_end) { 1470da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1471da6c28aaSamw break; 1472da6c28aaSamw } 1473da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1474da6c28aaSamw 1475da6c28aaSamw if ((scan + 2) >= scan_end) { 1476da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1477da6c28aaSamw break; 1478da6c28aaSamw } 1479da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1480da6c28aaSamw 1481da6c28aaSamw if ((scan + 2) >= scan_end) { 1482da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1483da6c28aaSamw break; 1484da6c28aaSamw } 1485da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1486da6c28aaSamw 1487da6c28aaSamw if ((scan + 2) >= scan_end) { 1488da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1489da6c28aaSamw break; 1490da6c28aaSamw } 1491da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1492da6c28aaSamw 1493da6c28aaSamw if ((scan + 2) >= scan_end) { 1494da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1495da6c28aaSamw break; 1496da6c28aaSamw } 1497da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1498da6c28aaSamw 1499da6c28aaSamw if ((scan + 2) >= scan_end) { 1500da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1501da6c28aaSamw break; 1502da6c28aaSamw } 1503da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1504da6c28aaSamw 1505da6c28aaSamw if ((scan + 2) >= scan_end) { 1506da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1507da6c28aaSamw break; 1508da6c28aaSamw } 1509da6c28aaSamw BE_OUT16(scan, max_connections); scan += 2; 1510da6c28aaSamw 1511da6c28aaSamw if ((scan + 2) >= scan_end) { 1512da6c28aaSamw packet.info |= NAME_NM_FLAGS_TC; 1513da6c28aaSamw break; 1514da6c28aaSamw } 1515da6c28aaSamw 1516da6c28aaSamw BE_OUT16(scan, 0); scan += 2; 1517da6c28aaSamw 151855bf511dSas scan_done = B_TRUE; 1519da6c28aaSamw } 1520da6c28aaSamw answer.rdlength = scan - data; 1521da6c28aaSamw return (smb_send_name_service_packet(addr, &packet)); 1522da6c28aaSamw } 1523da6c28aaSamw 1524da6c28aaSamw static int 1525da6c28aaSamw smb_name_Bnode_add_name(struct name_entry *name) 1526da6c28aaSamw { 1527da6c28aaSamw struct name_question question; 1528da6c28aaSamw struct resource_record additional; 1529da6c28aaSamw unsigned char data[8]; 1530*a0aa776eSAlan Wright uint16_t attr; 1531*a0aa776eSAlan Wright addr_entry_t *addr; 1532da6c28aaSamw int rc = 0; 1533da6c28aaSamw 1534da6c28aaSamw addr = &name->addr_list; 1535da6c28aaSamw 1536da6c28aaSamw do { 1537da6c28aaSamw /* build name service packet */ 1538da6c28aaSamw question.name = name; 1539da6c28aaSamw /* 1540da6c28aaSamw * question.name->attributes |= NAME_NB_FLAGS_ONT_B; 1541da6c28aaSamw * This is commented because NAME_NB_FLAGS_ONT_B is 0 1542da6c28aaSamw */ 1543da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1544da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1545da6c28aaSamw 1546da6c28aaSamw additional.name = name; 1547da6c28aaSamw additional.rr_class = NAME_QUESTION_CLASS_IN; 1548da6c28aaSamw additional.ttl = 0; 1549da6c28aaSamw additional.rdata = data; 1550da6c28aaSamw additional.rdlength = 6; 1551da6c28aaSamw additional.rr_type = NAME_QUESTION_TYPE_NB; 1552da6c28aaSamw attr = name->attributes & (NAME_ATTR_GROUP | 1553da6c28aaSamw NAME_ATTR_OWNER_NODE_TYPE); 1554da6c28aaSamw 1555da6c28aaSamw BE_OUT16(&data[0], attr); 1556da6c28aaSamw (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr, 1557da6c28aaSamw sizeof (uint32_t)); 1558da6c28aaSamw 1559da6c28aaSamw rc |= smb_send_name_registration_request(BROADCAST, &question, 1560da6c28aaSamw &additional); 1561da6c28aaSamw addr = addr->forw; 1562da6c28aaSamw 1563da6c28aaSamw } while (addr != &name->addr_list); 1564da6c28aaSamw 1565da6c28aaSamw return (rc); 1566da6c28aaSamw } 1567da6c28aaSamw 1568da6c28aaSamw static int 1569da6c28aaSamw smb_name_Bnode_find_name(struct name_entry *name) 1570da6c28aaSamw { 1571da6c28aaSamw struct name_question question; 1572da6c28aaSamw 1573da6c28aaSamw question.name = name; 1574da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1575da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1576da6c28aaSamw 1577da6c28aaSamw return (smb_send_name_query_request(BROADCAST, &question)); 1578da6c28aaSamw } 1579da6c28aaSamw 1580da6c28aaSamw static int 1581da6c28aaSamw smb_name_Bnode_delete_name(struct name_entry *name) 1582da6c28aaSamw { 1583da6c28aaSamw struct name_question question; 1584da6c28aaSamw struct resource_record additional; 1585*a0aa776eSAlan Wright addr_entry_t *raddr; 1586*a0aa776eSAlan Wright unsigned char data[MAX_DATAGRAM_LENGTH]; 1587*a0aa776eSAlan Wright unsigned char *scan = data; 1588da6c28aaSamw uint32_t attr; 158929bd2886SAlan Wright uint32_t ret_addr; 1590da6c28aaSamw 1591da6c28aaSamw /* build packet */ 1592da6c28aaSamw question.name = name; 1593da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1594da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1595da6c28aaSamw 1596da6c28aaSamw additional.name = name; 1597da6c28aaSamw additional.rr_class = NAME_QUESTION_CLASS_IN; 1598da6c28aaSamw additional.ttl = 0; 1599da6c28aaSamw additional.rdata = data; 1600da6c28aaSamw additional.rdlength = 0; 1601da6c28aaSamw additional.rr_type = NAME_QUESTION_TYPE_NB; 1602da6c28aaSamw raddr = &name->addr_list; 1603da6c28aaSamw scan = data; 1604da6c28aaSamw do { 1605da6c28aaSamw attr = name->attributes & (NAME_ATTR_GROUP | 1606da6c28aaSamw NAME_ATTR_OWNER_NODE_TYPE); 1607da6c28aaSamw 1608da6c28aaSamw BE_OUT16(scan, attr); scan += 2; 160929bd2886SAlan Wright ret_addr = LE_32(raddr->sin.sin_addr.s_addr); 161029bd2886SAlan Wright *scan++ = ret_addr; 161129bd2886SAlan Wright *scan++ = ret_addr >> 8; 161229bd2886SAlan Wright *scan++ = ret_addr >> 16; 161329bd2886SAlan Wright *scan++ = ret_addr >> 24; 1614da6c28aaSamw 1615da6c28aaSamw additional.rdlength += 6; 1616da6c28aaSamw } while (raddr != &name->addr_list); 1617da6c28aaSamw 1618da6c28aaSamw return (smb_send_name_release_request_and_demand(BROADCAST, 1619da6c28aaSamw &question, &additional)); 1620da6c28aaSamw } 1621da6c28aaSamw 1622da6c28aaSamw static int 1623da6c28aaSamw smb_name_Pnode_add_name(struct name_entry *name) 1624da6c28aaSamw { 1625da6c28aaSamw struct name_question question; 1626da6c28aaSamw struct resource_record additional; 1627da6c28aaSamw unsigned char data[8]; 1628*a0aa776eSAlan Wright uint16_t attr; 1629*a0aa776eSAlan Wright addr_entry_t *addr; 1630da6c28aaSamw int rc = 0; 1631da6c28aaSamw 1632da6c28aaSamw /* build packet */ 1633da6c28aaSamw addr = &name->addr_list; 1634da6c28aaSamw do { 1635da6c28aaSamw question.name = name; 1636da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1637da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1638da6c28aaSamw 1639da6c28aaSamw additional.name = name; 1640da6c28aaSamw additional.rr_class = NAME_QUESTION_CLASS_IN; 1641da6c28aaSamw additional.ttl = 0; 1642da6c28aaSamw additional.rdata = data; 1643da6c28aaSamw additional.rdlength = 6; 1644da6c28aaSamw additional.rr_type = NAME_QUESTION_TYPE_NB; 1645da6c28aaSamw attr = name->attributes & 1646da6c28aaSamw (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE); 1647da6c28aaSamw 1648da6c28aaSamw BE_OUT16(&data[0], attr); 1649da6c28aaSamw (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr, 1650da6c28aaSamw sizeof (uint32_t)); 1651da6c28aaSamw 1652da6c28aaSamw rc |= smb_send_name_registration_request(UNICAST, &question, 1653da6c28aaSamw &additional); 1654da6c28aaSamw 1655da6c28aaSamw addr = addr->forw; 1656da6c28aaSamw 1657da6c28aaSamw } while (addr != &name->addr_list); 1658da6c28aaSamw 1659da6c28aaSamw return (rc); 1660da6c28aaSamw } 1661da6c28aaSamw 1662da6c28aaSamw static int 1663da6c28aaSamw smb_name_Pnode_refresh_name(struct name_entry *name) 1664da6c28aaSamw { 1665da6c28aaSamw struct name_question question; 1666da6c28aaSamw struct resource_record additional; 1667da6c28aaSamw unsigned char data[8]; 1668*a0aa776eSAlan Wright uint16_t attr; 1669*a0aa776eSAlan Wright addr_entry_t *addr; 1670da6c28aaSamw int rc = 0; 1671da6c28aaSamw 1672da6c28aaSamw /* build packet */ 1673da6c28aaSamw addr = &name->addr_list; 1674da6c28aaSamw do { 1675da6c28aaSamw question.name = name; 1676da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1677da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1678da6c28aaSamw 1679da6c28aaSamw additional.name = name; 1680da6c28aaSamw additional.rr_class = NAME_QUESTION_CLASS_IN; 1681da6c28aaSamw additional.ttl = 0; 1682da6c28aaSamw additional.rdata = data; 1683da6c28aaSamw additional.rdlength = 6; 1684da6c28aaSamw additional.rr_type = NAME_QUESTION_TYPE_NB; 1685da6c28aaSamw attr = name->attributes & 1686da6c28aaSamw (NAME_ATTR_GROUP | NAME_ATTR_OWNER_NODE_TYPE); 1687da6c28aaSamw 1688da6c28aaSamw BE_OUT16(&data[0], attr); 1689da6c28aaSamw (void) memcpy(&data[2], &addr->sin.sin_addr.s_addr, 1690da6c28aaSamw sizeof (uint32_t)); 1691da6c28aaSamw 1692da6c28aaSamw rc |= smb_send_name_refresh_request(UNICAST, &question, 1693da6c28aaSamw &additional, 1); 1694da6c28aaSamw 1695da6c28aaSamw addr = addr->forw; 1696da6c28aaSamw } while (addr != &name->addr_list); 1697da6c28aaSamw 1698da6c28aaSamw return (rc); 1699da6c28aaSamw } 1700da6c28aaSamw 1701da6c28aaSamw static int 1702da6c28aaSamw smb_name_Pnode_find_name(struct name_entry *name) 1703da6c28aaSamw { 1704da6c28aaSamw struct name_question question; 1705da6c28aaSamw 1706da6c28aaSamw /* 1707da6c28aaSamw * Host initiated processing for a P node 1708da6c28aaSamw */ 1709da6c28aaSamw question.name = name; 1710da6c28aaSamw question.name->attributes |= NAME_NB_FLAGS_ONT_P; 1711da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1712da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1713da6c28aaSamw 1714da6c28aaSamw return (smb_send_name_query_request(UNICAST, &question)); 1715da6c28aaSamw } 1716da6c28aaSamw 1717da6c28aaSamw static int 1718da6c28aaSamw smb_name_Pnode_delete_name(struct name_entry *name) 1719da6c28aaSamw { 1720da6c28aaSamw struct name_question question; 1721da6c28aaSamw struct resource_record additional; 1722*a0aa776eSAlan Wright addr_entry_t *raddr; 1723*a0aa776eSAlan Wright unsigned char data[MAX_DATAGRAM_LENGTH]; 1724*a0aa776eSAlan Wright unsigned char *scan = data; 1725da6c28aaSamw uint32_t attr; 172629bd2886SAlan Wright uint32_t ret_addr; 1727da6c28aaSamw 1728da6c28aaSamw /* build packet */ 1729da6c28aaSamw question.name = name; 1730da6c28aaSamw question.name->attributes |= NAME_NB_FLAGS_ONT_P; 1731da6c28aaSamw question.question_type = NAME_QUESTION_TYPE_NB; 1732da6c28aaSamw question.question_class = NAME_QUESTION_CLASS_IN; 1733da6c28aaSamw 1734da6c28aaSamw additional.name = name; 1735da6c28aaSamw additional.rr_class = NAME_QUESTION_CLASS_IN; 1736da6c28aaSamw additional.ttl = 0; 1737da6c28aaSamw additional.rdata = data; 1738da6c28aaSamw additional.rdlength = 0; 1739da6c28aaSamw additional.rr_type = NAME_QUESTION_TYPE_NB; 1740da6c28aaSamw raddr = &name->addr_list; 1741da6c28aaSamw do { 1742da6c28aaSamw scan = data; 1743da6c28aaSamw attr = name->attributes & (NAME_ATTR_GROUP | 1744da6c28aaSamw NAME_ATTR_OWNER_NODE_TYPE); 1745da6c28aaSamw 1746da6c28aaSamw BE_OUT16(scan, attr); scan += 2; 174729bd2886SAlan Wright ret_addr = LE_32(raddr->sin.sin_addr.s_addr); 174829bd2886SAlan Wright *scan++ = ret_addr; 174929bd2886SAlan Wright *scan++ = ret_addr >> 8; 175029bd2886SAlan Wright *scan++ = ret_addr >> 16; 175129bd2886SAlan Wright *scan++ = ret_addr >> 24; 1752da6c28aaSamw 1753da6c28aaSamw additional.rdlength = 6; 1754da6c28aaSamw raddr = raddr->forw; 1755da6c28aaSamw (void) smb_send_name_release_request_and_demand(UNICAST, 1756da6c28aaSamw &question, &additional); 1757da6c28aaSamw } while (raddr != &name->addr_list); 1758da6c28aaSamw 1759da6c28aaSamw return (1); 1760da6c28aaSamw } 1761da6c28aaSamw 1762da6c28aaSamw static int 1763da6c28aaSamw smb_name_Mnode_add_name(struct name_entry *name) 1764da6c28aaSamw { 1765da6c28aaSamw if (smb_name_Bnode_add_name(name) > 0) { 1766da6c28aaSamw if (nbns_num == 0) 1767da6c28aaSamw return (1); /* No name server configured */ 1768da6c28aaSamw 1769da6c28aaSamw return (smb_name_Pnode_add_name(name)); 1770da6c28aaSamw } 1771da6c28aaSamw return (-1); 1772da6c28aaSamw } 1773da6c28aaSamw 1774da6c28aaSamw static int 1775da6c28aaSamw smb_name_Hnode_add_name(struct name_entry *name) 1776da6c28aaSamw { 1777da6c28aaSamw if (nbns_num > 0) { 1778da6c28aaSamw if (smb_name_Pnode_add_name(name) == 1) 1779da6c28aaSamw return (1); 1780da6c28aaSamw } 1781da6c28aaSamw 1782da6c28aaSamw return (smb_name_Bnode_add_name(name)); 1783da6c28aaSamw } 1784da6c28aaSamw 1785da6c28aaSamw static int 1786da6c28aaSamw smb_name_Mnode_find_name(struct name_entry *name) 1787da6c28aaSamw { 1788da6c28aaSamw if (smb_name_Bnode_find_name(name) == 1) 1789da6c28aaSamw return (1); 1790da6c28aaSamw 1791da6c28aaSamw if (nbns_num == 0) 1792da6c28aaSamw return (1); /* No name server configured */ 1793da6c28aaSamw 1794da6c28aaSamw return (smb_name_Pnode_find_name(name)); 1795da6c28aaSamw } 1796da6c28aaSamw 1797da6c28aaSamw static int 1798da6c28aaSamw smb_name_Hnode_find_name(struct name_entry *name) 1799da6c28aaSamw { 1800da6c28aaSamw if (nbns_num > 0) 1801da6c28aaSamw if (smb_name_Pnode_find_name(name) == 1) 1802da6c28aaSamw return (1); 1803da6c28aaSamw 1804da6c28aaSamw return (smb_name_Bnode_find_name(name)); 1805da6c28aaSamw } 1806da6c28aaSamw 1807da6c28aaSamw static int 1808da6c28aaSamw smb_name_Mnode_delete_name(struct name_entry *name) 1809da6c28aaSamw { 1810da6c28aaSamw (void) smb_name_Bnode_delete_name(name); 1811da6c28aaSamw 1812da6c28aaSamw if (nbns_num == 0) 1813da6c28aaSamw return (-1); /* No name server configured */ 1814da6c28aaSamw 1815da6c28aaSamw if (smb_name_Pnode_delete_name(name) > 0) 1816da6c28aaSamw return (1); 1817da6c28aaSamw 1818da6c28aaSamw return (-1); 1819da6c28aaSamw } 1820da6c28aaSamw 1821da6c28aaSamw static int 1822da6c28aaSamw smb_name_Hnode_delete_name(struct name_entry *name) 1823da6c28aaSamw { 1824da6c28aaSamw if (nbns_num > 0) 1825da6c28aaSamw if (smb_name_Pnode_delete_name(name) > 0) 1826da6c28aaSamw return (1); 1827da6c28aaSamw 1828da6c28aaSamw return (smb_name_Bnode_delete_name(name)); 1829da6c28aaSamw } 1830da6c28aaSamw 1831da6c28aaSamw static void 1832*a0aa776eSAlan Wright smb_name_process_Bnode_packet(struct name_packet *packet, addr_entry_t *addr) 1833da6c28aaSamw { 1834da6c28aaSamw struct name_entry *name; 1835da6c28aaSamw struct name_entry *entry; 1836da6c28aaSamw struct name_question *question; 1837da6c28aaSamw struct resource_record *additional; 1838da6c28aaSamw 1839da6c28aaSamw question = packet->question; 1840da6c28aaSamw additional = packet->additional; 1841da6c28aaSamw 1842da6c28aaSamw switch (packet->info & NAME_OPCODE_OPCODE_MASK) { 1843da6c28aaSamw case NAME_OPCODE_REFRESH: 1844da6c28aaSamw /* Guard against malformed packets */ 1845da6c28aaSamw if ((question == 0) || (additional == 0)) 1846da6c28aaSamw break; 1847da6c28aaSamw if (additional->name->addr_list.sin.sin_addr.s_addr == 0) 1848da6c28aaSamw break; 1849da6c28aaSamw 1850da6c28aaSamw name = question->name; 1851da6c28aaSamw name->addr_list.ttl = additional->ttl; 1852da6c28aaSamw name->attributes = additional->name->attributes; 1853da6c28aaSamw name->addr_list.sin = additional->name->addr_list.sin; 1854da6c28aaSamw name->addr_list.forw = name->addr_list.back = &name->addr_list; 1855da6c28aaSamw 1856da6c28aaSamw if ((entry = smb_netbios_cache_lookup_addr(name)) != 0) { 1857da6c28aaSamw smb_netbios_cache_update_entry(entry, question->name); 1858da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1859da6c28aaSamw } 1860da6c28aaSamw else 1861da6c28aaSamw (void) smb_netbios_cache_insert(question->name); 1862da6c28aaSamw break; 1863da6c28aaSamw 1864da6c28aaSamw case NAME_OPCODE_QUERY: 1865da6c28aaSamw /* 1866da6c28aaSamw * This opcode covers both NAME_QUERY_REQUEST and 1867da6c28aaSamw * NODE_STATUS_REQUEST. They can be distinguished 1868da6c28aaSamw * based on the type of question entry. 1869da6c28aaSamw */ 1870da6c28aaSamw 1871da6c28aaSamw /* All query requests have to have question entry */ 1872da6c28aaSamw if (question == 0) 1873da6c28aaSamw break; 1874da6c28aaSamw 1875da6c28aaSamw if (question->question_type == NAME_QUESTION_TYPE_NB) { 1876da6c28aaSamw name = question->name; 1877da6c28aaSamw if ((entry = smb_netbios_cache_lookup(name)) != 0) { 1878da6c28aaSamw (void) smb_send_name_query_response(addr, 1879da6c28aaSamw packet, entry, 0); 1880da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1881da6c28aaSamw } 1882da6c28aaSamw } 1883da6c28aaSamw else 1884da6c28aaSamw if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) { 1885da6c28aaSamw /* 1886da6c28aaSamw * Name of "*" may be used to force node to 1887da6c28aaSamw * divulge status for administrative purposes 1888da6c28aaSamw */ 1889da6c28aaSamw name = question->name; 1890da6c28aaSamw entry = 0; 1891da6c28aaSamw if (NETBIOS_NAME_IS_STAR(name->name) || 1892da6c28aaSamw ((entry = smb_netbios_cache_lookup(name)) != 0)) { 1893da6c28aaSamw if (entry) 1894da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1895da6c28aaSamw /* 1896da6c28aaSamw * send only those names that are 1897da6c28aaSamw * in the same scope as the scope 1898da6c28aaSamw * field in the request packet 1899da6c28aaSamw */ 1900da6c28aaSamw (void) smb_send_node_status_response(addr, 1901da6c28aaSamw packet); 1902da6c28aaSamw } 1903da6c28aaSamw } 1904da6c28aaSamw break; 1905da6c28aaSamw 1906da6c28aaSamw default: 1907da6c28aaSamw break; 1908da6c28aaSamw } 1909da6c28aaSamw } 1910da6c28aaSamw 1911da6c28aaSamw static void 1912*a0aa776eSAlan Wright smb_name_process_Pnode_packet(struct name_packet *packet, addr_entry_t *addr) 1913da6c28aaSamw { 1914da6c28aaSamw struct name_entry *name; 1915da6c28aaSamw struct name_entry *entry; 1916da6c28aaSamw struct name_question *question; 1917da6c28aaSamw struct resource_record *additional; 1918da6c28aaSamw 1919da6c28aaSamw question = packet->question; 1920da6c28aaSamw additional = packet->additional; 1921da6c28aaSamw 1922da6c28aaSamw if (packet->info & NAME_NM_FLAGS_B) { 1923da6c28aaSamw /* 1924da6c28aaSamw * always ignore UDP broadcast packets 1925da6c28aaSamw */ 1926da6c28aaSamw return; 1927da6c28aaSamw } 1928da6c28aaSamw 1929da6c28aaSamw switch (packet->info & NAME_OPCODE_OPCODE_MASK) { 1930da6c28aaSamw case NAME_OPCODE_REFRESH: 1931da6c28aaSamw /* Guard against malformed packets */ 1932da6c28aaSamw if ((question == 0) || (additional == 0)) 1933da6c28aaSamw break; 1934da6c28aaSamw if (additional->name->addr_list.sin.sin_addr.s_addr == 0) 1935da6c28aaSamw break; 1936da6c28aaSamw 1937da6c28aaSamw name = question->name; 1938da6c28aaSamw name->addr_list.ttl = additional->ttl; 1939da6c28aaSamw name->attributes = additional->name->attributes; 1940da6c28aaSamw name->addr_list.sin = additional->name->addr_list.sin; 1941da6c28aaSamw name->addr_list.forw = name->addr_list.back = &name->addr_list; 1942da6c28aaSamw 1943da6c28aaSamw if ((entry = smb_netbios_cache_lookup(name)) != 0) { 1944da6c28aaSamw smb_netbios_cache_update_entry(entry, name); 1945da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1946da6c28aaSamw } 1947da6c28aaSamw else 1948da6c28aaSamw (void) smb_netbios_cache_insert(name); 1949da6c28aaSamw 1950da6c28aaSamw (void) smb_send_name_registration_response(addr, packet, 0); 1951da6c28aaSamw break; 1952da6c28aaSamw 1953da6c28aaSamw case NAME_OPCODE_QUERY: 1954da6c28aaSamw /* 1955da6c28aaSamw * This opcode covers both NAME_QUERY_REQUEST and 1956da6c28aaSamw * NODE_STATUS_REQUEST. They can be distinguished 1957da6c28aaSamw * based on the type of question entry. 1958da6c28aaSamw */ 1959da6c28aaSamw 1960da6c28aaSamw /* All query requests have to have question entry */ 1961da6c28aaSamw if (question == 0) 1962da6c28aaSamw break; 1963da6c28aaSamw 1964da6c28aaSamw if (question->question_type == NAME_QUESTION_TYPE_NB) { 1965da6c28aaSamw name = question->name; 1966da6c28aaSamw if ((entry = smb_netbios_cache_lookup(name)) != 0) { 1967da6c28aaSamw /* 1968da6c28aaSamw * send response to the IP address and port 1969da6c28aaSamw * number from which the request was received. 1970da6c28aaSamw */ 1971da6c28aaSamw (void) smb_send_name_query_response(addr, 1972da6c28aaSamw packet, entry, 0); 1973da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1974da6c28aaSamw } else { 1975da6c28aaSamw /* 1976da6c28aaSamw * send response to the requestor 1977da6c28aaSamw */ 1978da6c28aaSamw (void) smb_send_name_query_response(addr, 1979da6c28aaSamw packet, name, RCODE_NAM_ERR); 1980da6c28aaSamw } 1981da6c28aaSamw } 1982da6c28aaSamw else 1983da6c28aaSamw if (question->question_type == NAME_QUESTION_TYPE_NBSTAT) { 1984da6c28aaSamw /* 1985da6c28aaSamw * Name of "*" may be used to force node to 1986da6c28aaSamw * divulge status for administrative purposes 1987da6c28aaSamw */ 1988da6c28aaSamw name = question->name; 1989da6c28aaSamw entry = 0; 1990da6c28aaSamw if (NETBIOS_NAME_IS_STAR(name->name) || 1991da6c28aaSamw ((entry = smb_netbios_cache_lookup(name)) != 0)) { 1992da6c28aaSamw /* 1993da6c28aaSamw * send only those names that are 1994da6c28aaSamw * in the same scope as the scope 1995da6c28aaSamw * field in the request packet 1996da6c28aaSamw */ 1997da6c28aaSamw if (entry) 1998da6c28aaSamw smb_netbios_cache_unlock_entry(entry); 1999da6c28aaSamw (void) smb_send_node_status_response(addr, 2000da6c28aaSamw packet); 2001da6c28aaSamw } 2002da6c28aaSamw } 2003da6c28aaSamw break; 2004da6c28aaSamw 2005da6c28aaSamw default: 2006da6c28aaSamw break; 2007da6c28aaSamw } 2008da6c28aaSamw } 2009da6c28aaSamw 2010da6c28aaSamw static void 2011*a0aa776eSAlan Wright smb_name_process_Mnode_packet(struct name_packet *packet, addr_entry_t *addr) 2012da6c28aaSamw { 2013da6c28aaSamw if (packet->info & NAME_NM_FLAGS_B) 2014da6c28aaSamw smb_name_process_Bnode_packet(packet, addr); 2015da6c28aaSamw else 2016da6c28aaSamw smb_name_process_Pnode_packet(packet, addr); 2017da6c28aaSamw } 2018da6c28aaSamw 2019da6c28aaSamw static void 2020*a0aa776eSAlan Wright smb_name_process_Hnode_packet(struct name_packet *packet, addr_entry_t *addr) 2021da6c28aaSamw { 2022da6c28aaSamw if (packet->info & NAME_NM_FLAGS_B) 2023da6c28aaSamw smb_name_process_Bnode_packet(packet, addr); 2024da6c28aaSamw else 2025da6c28aaSamw smb_name_process_Pnode_packet(packet, addr); 2026da6c28aaSamw } 2027da6c28aaSamw 2028da6c28aaSamw 2029da6c28aaSamw /* 2030da6c28aaSamw * smb_netbios_name_tick 2031da6c28aaSamw * 2032da6c28aaSamw * Called once a second to handle name server timeouts. 2033da6c28aaSamw */ 2034da6c28aaSamw void 2035da6c28aaSamw smb_netbios_name_tick(void) 2036da6c28aaSamw { 2037da6c28aaSamw struct name_entry *name; 2038da6c28aaSamw struct name_entry *entry; 2039da6c28aaSamw 2040da6c28aaSamw (void) mutex_lock(&refresh_queue.mtx); 2041da6c28aaSamw smb_netbios_cache_refresh(&refresh_queue); 2042da6c28aaSamw 2043da6c28aaSamw while ((name = refresh_queue.head.forw) != &refresh_queue.head) { 2044da6c28aaSamw QUEUE_CLIP(name); 2045da6c28aaSamw if (IS_LOCAL(name->attributes)) { 2046da6c28aaSamw if (IS_UNIQUE(name->attributes)) { 2047da6c28aaSamw (void) smb_name_Pnode_refresh_name(name); 2048da6c28aaSamw } 2049da6c28aaSamw } else { 2050da6c28aaSamw entry = smb_name_find_name(name); 2051da6c28aaSamw smb_name_unlock_name(entry); 2052da6c28aaSamw } 2053da6c28aaSamw free(name); 2054da6c28aaSamw } 2055da6c28aaSamw (void) mutex_unlock(&refresh_queue.mtx); 2056da6c28aaSamw 2057da6c28aaSamw smb_netbios_cache_reset_ttl(); 2058da6c28aaSamw } 2059da6c28aaSamw 2060da6c28aaSamw /* 2061da6c28aaSamw * smb_name_find_name 2062da6c28aaSamw * 2063da6c28aaSamw * Lookup name cache for the given name. 2064da6c28aaSamw * If it's not in the cache it'll send a 2065da6c28aaSamw * name query request and then lookup the 2066da6c28aaSamw * cache again. Note that if a name is 2067da6c28aaSamw * returned it's locked and called MUST 2068da6c28aaSamw * unlock it by calling smb_name_unlock_name() 2069da6c28aaSamw */ 2070da6c28aaSamw struct name_entry * 2071da6c28aaSamw smb_name_find_name(struct name_entry *name) 2072da6c28aaSamw { 2073da6c28aaSamw struct name_entry *result; 2074da6c28aaSamw 2075da6c28aaSamw if ((result = smb_netbios_cache_lookup(name)) == 0) { 2076da6c28aaSamw switch (smb_node_type) { 2077da6c28aaSamw case 'B': 2078da6c28aaSamw (void) smb_name_Bnode_find_name(name); 2079da6c28aaSamw break; 2080da6c28aaSamw case 'P': 2081da6c28aaSamw (void) smb_name_Pnode_find_name(name); 2082da6c28aaSamw break; 2083da6c28aaSamw case 'M': 2084da6c28aaSamw (void) smb_name_Mnode_find_name(name); 2085da6c28aaSamw break; 2086da6c28aaSamw case 'H': 2087da6c28aaSamw default: 2088da6c28aaSamw (void) smb_name_Hnode_find_name(name); 2089da6c28aaSamw break; 2090da6c28aaSamw } 2091da6c28aaSamw return (smb_netbios_cache_lookup(name)); 2092da6c28aaSamw } 2093da6c28aaSamw 2094da6c28aaSamw return (result); 2095da6c28aaSamw } 2096da6c28aaSamw 2097da6c28aaSamw void 2098da6c28aaSamw smb_name_unlock_name(struct name_entry *name) 2099da6c28aaSamw { 2100da6c28aaSamw smb_netbios_cache_unlock_entry(name); 2101da6c28aaSamw } 2102da6c28aaSamw 2103da6c28aaSamw int 2104da6c28aaSamw smb_name_add_name(struct name_entry *name) 2105da6c28aaSamw { 2106da6c28aaSamw int rc = 1; 2107da6c28aaSamw 2108*a0aa776eSAlan Wright smb_netbios_name_logf(name); 2109da6c28aaSamw 2110da6c28aaSamw switch (smb_node_type) { 2111da6c28aaSamw case 'B': 2112da6c28aaSamw rc = smb_name_Bnode_add_name(name); 2113da6c28aaSamw break; 2114da6c28aaSamw case 'P': 2115da6c28aaSamw rc = smb_name_Pnode_add_name(name); 2116da6c28aaSamw break; 2117da6c28aaSamw case 'M': 2118da6c28aaSamw rc = smb_name_Mnode_add_name(name); 2119da6c28aaSamw break; 2120da6c28aaSamw case 'H': 2121da6c28aaSamw default: 2122da6c28aaSamw rc = smb_name_Hnode_add_name(name); 2123da6c28aaSamw break; 2124da6c28aaSamw } 2125da6c28aaSamw 2126da6c28aaSamw if (rc >= 0) 2127da6c28aaSamw (void) smb_netbios_cache_insert(name); 2128da6c28aaSamw 2129da6c28aaSamw return (rc); 2130da6c28aaSamw } 2131da6c28aaSamw 2132da6c28aaSamw int 2133da6c28aaSamw smb_name_delete_name(struct name_entry *name) 2134da6c28aaSamw { 2135da6c28aaSamw int rc; 2136da6c28aaSamw unsigned char type; 2137da6c28aaSamw 2138da6c28aaSamw type = name->name[15]; 2139*a0aa776eSAlan Wright if ((type != NBT_WKSTA) && (type != NBT_SERVER)) { 2140*a0aa776eSAlan Wright syslog(LOG_DEBUG, "nbns: name delete bad type (0x%02x)", type); 2141da6c28aaSamw smb_netbios_name_logf(name); 2142da6c28aaSamw name->attributes &= ~NAME_ATTR_LOCAL; 2143da6c28aaSamw return (-1); 2144da6c28aaSamw } 2145da6c28aaSamw 2146da6c28aaSamw smb_netbios_cache_delete(name); 2147da6c28aaSamw 2148da6c28aaSamw switch (smb_node_type) { 2149da6c28aaSamw case 'B': 2150da6c28aaSamw rc = smb_name_Bnode_delete_name(name); 2151da6c28aaSamw break; 2152da6c28aaSamw case 'P': 2153da6c28aaSamw rc = smb_name_Pnode_delete_name(name); 2154da6c28aaSamw break; 2155da6c28aaSamw case 'M': 2156da6c28aaSamw rc = smb_name_Mnode_delete_name(name); 2157da6c28aaSamw break; 2158da6c28aaSamw case 'H': 2159da6c28aaSamw default: 2160da6c28aaSamw rc = smb_name_Hnode_delete_name(name); 2161da6c28aaSamw break; 2162da6c28aaSamw } 2163da6c28aaSamw 2164da6c28aaSamw if (rc > 0) 2165da6c28aaSamw return (0); 2166da6c28aaSamw 2167da6c28aaSamw return (-1); 2168da6c28aaSamw } 2169da6c28aaSamw 2170da6c28aaSamw typedef struct { 2171*a0aa776eSAlan Wright addr_entry_t *addr; 2172da6c28aaSamw char *buf; 2173da6c28aaSamw int length; 2174da6c28aaSamw } worker_param_t; 2175da6c28aaSamw 2176da6c28aaSamw /* 2177da6c28aaSamw * smb_netbios_worker 2178da6c28aaSamw * 2179da6c28aaSamw * Process incoming request/response packets for Netbios 2180da6c28aaSamw * name service (on port 138). 2181da6c28aaSamw */ 2182da6c28aaSamw void * 2183da6c28aaSamw smb_netbios_worker(void *arg) 2184da6c28aaSamw { 2185da6c28aaSamw worker_param_t *p = (worker_param_t *)arg; 2186*a0aa776eSAlan Wright addr_entry_t *addr = p->addr; 2187da6c28aaSamw struct name_packet *packet; 2188da6c28aaSamw 2189*a0aa776eSAlan Wright if ((packet = smb_name_buf_to_packet(p->buf, p->length)) != NULL) { 2190da6c28aaSamw if (packet->info & NAME_OPCODE_R) { 2191da6c28aaSamw /* Reply packet */ 2192da6c28aaSamw smb_reply_ready(packet, addr); 2193da6c28aaSamw free(p->buf); 2194da6c28aaSamw free(p); 2195*a0aa776eSAlan Wright return (NULL); 2196da6c28aaSamw } 2197da6c28aaSamw 2198da6c28aaSamw /* Request packet */ 2199da6c28aaSamw switch (smb_node_type) { 2200da6c28aaSamw case 'B': 2201da6c28aaSamw smb_name_process_Bnode_packet(packet, addr); 2202da6c28aaSamw break; 2203da6c28aaSamw case 'P': 2204da6c28aaSamw smb_name_process_Pnode_packet(packet, addr); 2205da6c28aaSamw break; 2206da6c28aaSamw case 'M': 2207da6c28aaSamw smb_name_process_Mnode_packet(packet, addr); 2208da6c28aaSamw break; 2209da6c28aaSamw case 'H': 2210da6c28aaSamw default: 2211da6c28aaSamw smb_name_process_Hnode_packet(packet, addr); 2212da6c28aaSamw break; 2213da6c28aaSamw } 2214da6c28aaSamw 2215da6c28aaSamw if (packet->answer) 2216da6c28aaSamw smb_netbios_name_freeaddrs(packet->answer->name); 2217da6c28aaSamw free(packet); 22187b59d02dSjb } else { 2219*a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: packet decode failed"); 2220da6c28aaSamw } 2221da6c28aaSamw 2222da6c28aaSamw free(addr); 2223da6c28aaSamw free(p->buf); 2224da6c28aaSamw free(p); 2225*a0aa776eSAlan Wright return (NULL); 2226da6c28aaSamw } 2227da6c28aaSamw 2228*a0aa776eSAlan Wright /* 2229*a0aa776eSAlan Wright * Configure the node type. If a WINS server has been specified, 2230*a0aa776eSAlan Wright * act like an H-node. Otherwise, behave like a B-node. 2231*a0aa776eSAlan Wright */ 2232da6c28aaSamw static void 2233*a0aa776eSAlan Wright smb_netbios_node_config(void) 2234da6c28aaSamw { 2235*a0aa776eSAlan Wright static smb_cfg_id_t wins[SMB_PI_MAX_WINS] = { 2236*a0aa776eSAlan Wright SMB_CI_WINS_SRV1, 2237*a0aa776eSAlan Wright SMB_CI_WINS_SRV2 2238*a0aa776eSAlan Wright }; 2239*a0aa776eSAlan Wright char ipstr[16]; 2240*a0aa776eSAlan Wright uint32_t ipaddr; 2241*a0aa776eSAlan Wright int i; 2242*a0aa776eSAlan Wright 2243*a0aa776eSAlan Wright smb_node_type = SMB_NODETYPE_B; 2244*a0aa776eSAlan Wright nbns_num = 0; 2245*a0aa776eSAlan Wright bzero(smb_nbns, sizeof (addr_entry_t) * SMB_PI_MAX_WINS); 2246da6c28aaSamw 2247*a0aa776eSAlan Wright for (i = 0; i < SMB_PI_MAX_WINS; ++i) { 2248*a0aa776eSAlan Wright ipstr[0] = '\0'; 2249*a0aa776eSAlan Wright (void) smb_config_getstr(wins[i], ipstr, sizeof (ipstr)); 2250*a0aa776eSAlan Wright 2251*a0aa776eSAlan Wright if ((ipaddr = inet_addr(ipstr)) == INADDR_NONE) 2252*a0aa776eSAlan Wright continue; 2253*a0aa776eSAlan Wright 2254*a0aa776eSAlan Wright smb_node_type = SMB_NODETYPE_H; 2255da6c28aaSamw smb_nbns[nbns_num].flags = ADDR_FLAG_VALID; 2256da6c28aaSamw smb_nbns[nbns_num].sinlen = sizeof (struct sockaddr_in); 2257da6c28aaSamw smb_nbns[nbns_num].sin.sin_family = AF_INET; 2258da6c28aaSamw smb_nbns[nbns_num].sin.sin_addr.s_addr = ipaddr; 2259*a0aa776eSAlan Wright smb_nbns[nbns_num].sin.sin_port = htons(IPPORT_NETBIOS_NS); 2260*a0aa776eSAlan Wright nbns_num++; 22617b59d02dSjb } 22627b59d02dSjb } 22637b59d02dSjb 22647b59d02dSjb static void 22657b59d02dSjb smb_netbios_name_registration(void) 22667b59d02dSjb { 22677b59d02dSjb nbcache_iter_t nbc_iter; 22687b59d02dSjb struct name_entry *name; 22697b59d02dSjb int rc; 22707b59d02dSjb 22717b59d02dSjb rc = smb_netbios_cache_getfirst(&nbc_iter); 22727b59d02dSjb while (rc == 0) { 22737b59d02dSjb name = nbc_iter.nbc_entry; 22747b59d02dSjb (void) smb_netbios_name_logf(name); 22757b59d02dSjb if (IS_UNIQUE(name->attributes) && IS_LOCAL(name->attributes)) { 22767b59d02dSjb switch (smb_node_type) { 22777b59d02dSjb case SMB_NODETYPE_B: 22787b59d02dSjb (void) smb_name_Bnode_add_name(name); 22797b59d02dSjb break; 22807b59d02dSjb case SMB_NODETYPE_P: 22817b59d02dSjb (void) smb_name_Pnode_add_name(name); 22827b59d02dSjb break; 22837b59d02dSjb case SMB_NODETYPE_M: 22847b59d02dSjb (void) smb_name_Mnode_add_name(name); 22857b59d02dSjb break; 22867b59d02dSjb case SMB_NODETYPE_H: 22877b59d02dSjb default: 22887b59d02dSjb (void) smb_name_Hnode_add_name(name); 22897b59d02dSjb break; 22907b59d02dSjb } 22917b59d02dSjb } 22927b59d02dSjb free(name); 22937b59d02dSjb rc = smb_netbios_cache_getnext(&nbc_iter); 2294da6c28aaSamw } 2295da6c28aaSamw } 2296da6c28aaSamw 2297*a0aa776eSAlan Wright /* 2298*a0aa776eSAlan Wright * Note that the node configuration must be setup before calling 2299*a0aa776eSAlan Wright * smb_init_name_struct(). 2300*a0aa776eSAlan Wright */ 2301da6c28aaSamw void 2302da6c28aaSamw smb_netbios_name_config(void) 2303da6c28aaSamw { 2304*a0aa776eSAlan Wright addr_entry_t *bcast_entry; 2305*a0aa776eSAlan Wright struct name_entry name; 2306*a0aa776eSAlan Wright smb_niciter_t ni; 2307*a0aa776eSAlan Wright int rc; 2308*a0aa776eSAlan Wright 2309*a0aa776eSAlan Wright (void) mutex_lock(&nbt_name_config_mtx); 2310*a0aa776eSAlan Wright smb_netbios_node_config(); 2311da6c28aaSamw 2312da6c28aaSamw bcast_num = 0; 2313da6c28aaSamw bzero(smb_bcast_list, sizeof (addr_entry_t) * SMB_PI_MAX_NETWORKS); 2314da6c28aaSamw 23157b59d02dSjb rc = smb_nic_getfirst(&ni); 23167b59d02dSjb while (rc == 0) { 2317*a0aa776eSAlan Wright if ((ni.ni_nic.nic_smbflags & SMB_NICF_NBEXCL) || 2318*a0aa776eSAlan Wright (ni.ni_nic.nic_smbflags & SMB_NICF_ALIAS)) { 23197b59d02dSjb rc = smb_nic_getnext(&ni); 23207b59d02dSjb continue; 2321da6c28aaSamw } 2322da6c28aaSamw 2323*a0aa776eSAlan Wright bcast_entry = &smb_bcast_list[bcast_num]; 2324*a0aa776eSAlan Wright bcast_entry->flags = ADDR_FLAG_VALID; 2325*a0aa776eSAlan Wright bcast_entry->attributes = NAME_ATTR_LOCAL; 2326*a0aa776eSAlan Wright bcast_entry->sinlen = sizeof (struct sockaddr_in); 2327*a0aa776eSAlan Wright bcast_entry->sin.sin_family = AF_INET; 2328*a0aa776eSAlan Wright bcast_entry->sin.sin_port = htons(IPPORT_NETBIOS_NS); 2329*a0aa776eSAlan Wright bcast_entry->sin.sin_addr.s_addr = ni.ni_nic.nic_bcast; 2330*a0aa776eSAlan Wright bcast_num++; 2331da6c28aaSamw 23327b59d02dSjb smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host, 2333*a0aa776eSAlan Wright NBT_WKSTA, 0, ni.ni_nic.nic_ip.a_ipv4, 2334*a0aa776eSAlan Wright htons(IPPORT_NETBIOS_DGM), 23357b59d02dSjb NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name); 23367b59d02dSjb (void) smb_netbios_cache_insert(&name); 2337da6c28aaSamw 23387b59d02dSjb smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host, 2339*a0aa776eSAlan Wright NBT_SERVER, 0, ni.ni_nic.nic_ip.a_ipv4, 2340*a0aa776eSAlan Wright htons(IPPORT_NETBIOS_DGM), 2341da6c28aaSamw NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name); 23427b59d02dSjb (void) smb_netbios_cache_insert(&name); 2343*a0aa776eSAlan Wright 2344*a0aa776eSAlan Wright rc = smb_nic_getnext(&ni); 2345*a0aa776eSAlan Wright } 23467b59d02dSjb 23477b59d02dSjb smb_netbios_name_registration(); 2348*a0aa776eSAlan Wright (void) mutex_unlock(&nbt_name_config_mtx); 2349da6c28aaSamw } 2350da6c28aaSamw 2351da6c28aaSamw void 2352da6c28aaSamw smb_netbios_name_unconfig(void) 2353da6c28aaSamw { 2354da6c28aaSamw struct name_entry *name; 2355da6c28aaSamw 2356*a0aa776eSAlan Wright (void) mutex_lock(&nbt_name_config_mtx); 2357da6c28aaSamw (void) mutex_lock(&delete_queue.mtx); 2358da6c28aaSamw smb_netbios_cache_delete_locals(&delete_queue); 2359da6c28aaSamw 2360da6c28aaSamw while ((name = delete_queue.head.forw) != &delete_queue.head) { 2361da6c28aaSamw QUEUE_CLIP(name); 2362da6c28aaSamw (void) smb_name_delete_name(name); 2363da6c28aaSamw free(name); 2364da6c28aaSamw } 2365da6c28aaSamw (void) mutex_unlock(&delete_queue.mtx); 2366*a0aa776eSAlan Wright (void) mutex_unlock(&nbt_name_config_mtx); 2367da6c28aaSamw } 2368da6c28aaSamw 2369da6c28aaSamw void 2370da6c28aaSamw smb_netbios_name_reconfig(void) 2371da6c28aaSamw { 2372da6c28aaSamw smb_netbios_name_unconfig(); 2373da6c28aaSamw smb_netbios_name_config(); 2374da6c28aaSamw } 2375da6c28aaSamw 2376da6c28aaSamw /* 2377*a0aa776eSAlan Wright * NetBIOS Name Service (port 137) 2378da6c28aaSamw */ 2379da6c28aaSamw /*ARGSUSED*/ 2380da6c28aaSamw void * 2381*a0aa776eSAlan Wright smb_netbios_name_service(void *arg) 2382da6c28aaSamw { 2383da6c28aaSamw struct sockaddr_in sin; 2384*a0aa776eSAlan Wright addr_entry_t *addr; 2385da6c28aaSamw int len; 2386da6c28aaSamw int flag = 1; 2387*a0aa776eSAlan Wright char *buf; 2388da6c28aaSamw worker_param_t *worker_param; 23897f667e74Sjose borrego smb_inaddr_t ipaddr; 2390da6c28aaSamw 2391da6c28aaSamw /* 2392da6c28aaSamw * Initialize reply_queue 2393da6c28aaSamw */ 2394da6c28aaSamw bzero(&reply_queue, sizeof (reply_queue)); 2395da6c28aaSamw reply_queue.forw = reply_queue.back = &reply_queue; 2396da6c28aaSamw 2397da6c28aaSamw if ((name_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 2398*a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: socket failed: %m"); 2399*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR); 2400*a0aa776eSAlan Wright return (NULL); 2401da6c28aaSamw } 2402da6c28aaSamw 2403*a0aa776eSAlan Wright flag = 1; 2404*a0aa776eSAlan Wright (void) setsockopt(name_sock, SOL_SOCKET, SO_REUSEADDR, &flag, 2405*a0aa776eSAlan Wright sizeof (flag)); 2406*a0aa776eSAlan Wright flag = 1; 2407da6c28aaSamw (void) setsockopt(name_sock, SOL_SOCKET, SO_BROADCAST, &flag, 2408da6c28aaSamw sizeof (flag)); 2409da6c28aaSamw 2410da6c28aaSamw bzero(&sin, sizeof (struct sockaddr_in)); 2411da6c28aaSamw sin.sin_family = AF_INET; 2412*a0aa776eSAlan Wright sin.sin_port = htons(IPPORT_NETBIOS_NS); 2413da6c28aaSamw if (bind(name_sock, (struct sockaddr *)&sin, sizeof (sin)) != 0) { 2414*a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: bind(%d) failed: %m", 2415*a0aa776eSAlan Wright IPPORT_NETBIOS_NS); 2416da6c28aaSamw (void) close(name_sock); 2417*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR); 2418*a0aa776eSAlan Wright return (NULL); 2419da6c28aaSamw } 2420da6c28aaSamw 2421*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_NS_START); 2422da6c28aaSamw 2423*a0aa776eSAlan Wright while (smb_netbios_running()) { 2424*a0aa776eSAlan Wright buf = malloc(MAX_DATAGRAM_LENGTH); 2425*a0aa776eSAlan Wright addr = malloc(sizeof (addr_entry_t)); 2426*a0aa776eSAlan Wright if ((buf == NULL) || (addr == NULL)) { 2427*a0aa776eSAlan Wright /* Sleep for 10 seconds and try again */ 2428*a0aa776eSAlan Wright free(addr); 2429da6c28aaSamw free(buf); 2430*a0aa776eSAlan Wright smb_netbios_sleep(10); 2431da6c28aaSamw continue; 2432da6c28aaSamw } 2433*a0aa776eSAlan Wright ignore: bzero(addr, sizeof (addr_entry_t)); 2434da6c28aaSamw addr->sinlen = sizeof (addr->sin); 2435da6c28aaSamw addr->forw = addr->back = addr; 2436da6c28aaSamw 2437da6c28aaSamw if ((len = recvfrom(name_sock, buf, MAX_DATAGRAM_LENGTH, 2438da6c28aaSamw 0, (struct sockaddr *)&addr->sin, &addr->sinlen)) < 0) { 2439da6c28aaSamw if (errno == ENOMEM || errno == ENFILE || 2440da6c28aaSamw errno == EMFILE) { 2441*a0aa776eSAlan Wright /* Sleep for 10 seconds and try again */ 2442da6c28aaSamw free(buf); 2443da6c28aaSamw free(addr); 2444*a0aa776eSAlan Wright smb_netbios_sleep(10); 2445da6c28aaSamw continue; 2446da6c28aaSamw } 2447*a0aa776eSAlan Wright syslog(LOG_ERR, "nbns: recvfrom failed: %m"); 2448da6c28aaSamw free(buf); 2449da6c28aaSamw free(addr); 2450*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_ERROR); 2451da6c28aaSamw goto shutdown; 2452da6c28aaSamw } 2453da6c28aaSamw 2454da6c28aaSamw /* Ignore any incoming packets from myself... */ 24557f667e74Sjose borrego 24567f667e74Sjose borrego ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; 24577f667e74Sjose borrego ipaddr.a_family = AF_INET; 2458fc724630SAlan Wright if (smb_nic_is_local(&ipaddr)) 2459da6c28aaSamw goto ignore; 2460da6c28aaSamw 2461da6c28aaSamw /* 2462da6c28aaSamw * Launch a netbios worker to process the received packet. 2463da6c28aaSamw */ 2464*a0aa776eSAlan Wright worker_param = malloc(sizeof (worker_param_t)); 2465da6c28aaSamw if (worker_param) { 2466da6c28aaSamw pthread_t worker; 2467da6c28aaSamw pthread_attr_t tattr; 2468da6c28aaSamw 2469da6c28aaSamw worker_param->addr = addr; 2470da6c28aaSamw worker_param->buf = buf; 2471da6c28aaSamw worker_param->length = len; 2472da6c28aaSamw 2473da6c28aaSamw (void) pthread_attr_init(&tattr); 2474da6c28aaSamw (void) pthread_attr_setdetachstate(&tattr, 2475da6c28aaSamw PTHREAD_CREATE_DETACHED); 2476da6c28aaSamw (void) pthread_create(&worker, &tattr, 2477da6c28aaSamw smb_netbios_worker, worker_param); 2478da6c28aaSamw (void) pthread_attr_destroy(&tattr); 2479da6c28aaSamw } 2480da6c28aaSamw } 2481da6c28aaSamw 2482da6c28aaSamw shutdown: 2483*a0aa776eSAlan Wright smb_netbios_event(NETBIOS_EVENT_NS_STOP); 2484*a0aa776eSAlan Wright smb_netbios_wait(NETBIOS_EVENT_BROWSER_STOP); 2485da6c28aaSamw 2486*a0aa776eSAlan Wright if (!smb_netbios_error()) 2487da6c28aaSamw smb_netbios_name_unconfig(); 2488*a0aa776eSAlan Wright 2489da6c28aaSamw (void) close(name_sock); 2490*a0aa776eSAlan Wright return (NULL); 2491da6c28aaSamw } 2492