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