1*da6c28aaSamw /* 2*da6c28aaSamw * CDDL HEADER START 3*da6c28aaSamw * 4*da6c28aaSamw * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 7*da6c28aaSamw * 8*da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10*da6c28aaSamw * See the License for the specific language governing permissions 11*da6c28aaSamw * and limitations under the License. 12*da6c28aaSamw * 13*da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14*da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16*da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*da6c28aaSamw * 19*da6c28aaSamw * CDDL HEADER END 20*da6c28aaSamw */ 21*da6c28aaSamw /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*da6c28aaSamw * Use is subject to license terms. 24*da6c28aaSamw */ 25*da6c28aaSamw 26*da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*da6c28aaSamw 28*da6c28aaSamw /* 29*da6c28aaSamw * Main startup code for SMB/NETBIOS and some utility routines 30*da6c28aaSamw * for the NETBIOS layer. 31*da6c28aaSamw */ 32*da6c28aaSamw 33*da6c28aaSamw #include <synch.h> 34*da6c28aaSamw #include <unistd.h> 35*da6c28aaSamw #include <syslog.h> 36*da6c28aaSamw #include <string.h> 37*da6c28aaSamw #include <strings.h> 38*da6c28aaSamw #include <sys/socket.h> 39*da6c28aaSamw 40*da6c28aaSamw #include <smbns_netbios.h> 41*da6c28aaSamw 42*da6c28aaSamw netbios_status_t nb_status; 43*da6c28aaSamw 44*da6c28aaSamw static pthread_t smb_nbns_thr; /* name service */ 45*da6c28aaSamw static pthread_t smb_nbds_thr; /* dgram service */ 46*da6c28aaSamw static pthread_t smb_nbts_thr; /* timer */ 47*da6c28aaSamw static pthread_t smb_nbbs_thr; /* browser */ 48*da6c28aaSamw 49*da6c28aaSamw static void *smb_netbios_timer(void *); 50*da6c28aaSamw 51*da6c28aaSamw void 52*da6c28aaSamw smb_netbios_chg_status(uint32_t status, int set) 53*da6c28aaSamw { 54*da6c28aaSamw (void) mutex_lock(&nb_status.mtx); 55*da6c28aaSamw if (set) 56*da6c28aaSamw nb_status.state |= status; 57*da6c28aaSamw else 58*da6c28aaSamw nb_status.state &= ~status; 59*da6c28aaSamw (void) cond_broadcast(&nb_status.cv); 60*da6c28aaSamw (void) mutex_unlock(&nb_status.mtx); 61*da6c28aaSamw } 62*da6c28aaSamw 63*da6c28aaSamw void 64*da6c28aaSamw smb_netbios_shutdown(void) 65*da6c28aaSamw { 66*da6c28aaSamw smb_netbios_chg_status(NETBIOS_SHUTTING_DOWN, 1); 67*da6c28aaSamw 68*da6c28aaSamw (void) pthread_join(smb_nbts_thr, 0); 69*da6c28aaSamw (void) pthread_join(smb_nbbs_thr, 0); 70*da6c28aaSamw (void) pthread_join(smb_nbns_thr, 0); 71*da6c28aaSamw (void) pthread_join(smb_nbds_thr, 0); 72*da6c28aaSamw 73*da6c28aaSamw nb_status.state = NETBIOS_SHUT_DOWN; 74*da6c28aaSamw } 75*da6c28aaSamw 76*da6c28aaSamw void 77*da6c28aaSamw smb_netbios_start() 78*da6c28aaSamw { 79*da6c28aaSamw int rc; 80*da6c28aaSamw mutex_t *mp; 81*da6c28aaSamw cond_t *cvp; 82*da6c28aaSamw 83*da6c28aaSamw /* Startup Netbios named; port 137 */ 84*da6c28aaSamw rc = pthread_create(&smb_nbns_thr, 0, 85*da6c28aaSamw smb_netbios_name_service_daemon, 0); 86*da6c28aaSamw if (rc) 87*da6c28aaSamw return; 88*da6c28aaSamw 89*da6c28aaSamw mp = &nb_status.mtx; 90*da6c28aaSamw cvp = &nb_status.cv; 91*da6c28aaSamw 92*da6c28aaSamw (void) mutex_lock(mp); 93*da6c28aaSamw 94*da6c28aaSamw while (!(nb_status.state & (NETBIOS_NAME_SVC_RUNNING | 95*da6c28aaSamw NETBIOS_NAME_SVC_FAILED))) { 96*da6c28aaSamw (void) cond_wait(cvp, mp); 97*da6c28aaSamw } 98*da6c28aaSamw 99*da6c28aaSamw if (nb_status.state & NETBIOS_NAME_SVC_FAILED) { 100*da6c28aaSamw (void) mutex_unlock(mp); 101*da6c28aaSamw (void) fprintf(stderr, 102*da6c28aaSamw "smbd: Netbios Name service startup failed!"); 103*da6c28aaSamw smb_netbios_shutdown(); 104*da6c28aaSamw return; 105*da6c28aaSamw } 106*da6c28aaSamw (void) mutex_unlock(mp); 107*da6c28aaSamw 108*da6c28aaSamw (void) fprintf(stderr, "smbd: Netbios Name service started."); 109*da6c28aaSamw smb_netbios_name_config(); 110*da6c28aaSamw 111*da6c28aaSamw /* Startup Netbios datagram service; port 138 */ 112*da6c28aaSamw rc = pthread_create(&smb_nbds_thr, 0, 113*da6c28aaSamw smb_netbios_datagram_service_daemon, 0); 114*da6c28aaSamw if (rc == 0) { 115*da6c28aaSamw (void) mutex_lock(mp); 116*da6c28aaSamw while (!(nb_status.state & (NETBIOS_DATAGRAM_SVC_RUNNING | 117*da6c28aaSamw NETBIOS_DATAGRAM_SVC_FAILED))) { 118*da6c28aaSamw (void) cond_wait(cvp, mp); 119*da6c28aaSamw } 120*da6c28aaSamw 121*da6c28aaSamw if (nb_status.state & NETBIOS_DATAGRAM_SVC_FAILED) { 122*da6c28aaSamw (void) mutex_unlock(mp); 123*da6c28aaSamw (void) fprintf(stderr, "smbd: Netbios Datagram service " 124*da6c28aaSamw "startup failed!"); 125*da6c28aaSamw smb_netbios_shutdown(); 126*da6c28aaSamw return; 127*da6c28aaSamw } 128*da6c28aaSamw (void) mutex_unlock(mp); 129*da6c28aaSamw } else { 130*da6c28aaSamw smb_netbios_shutdown(); 131*da6c28aaSamw return; 132*da6c28aaSamw } 133*da6c28aaSamw 134*da6c28aaSamw (void) fprintf(stderr, "smbd: Netbios Datagram service started."); 135*da6c28aaSamw 136*da6c28aaSamw /* Startup Netbios browser service */ 137*da6c28aaSamw rc = pthread_create(&smb_nbbs_thr, 0, smb_browser_daemon, 0); 138*da6c28aaSamw if (rc) { 139*da6c28aaSamw smb_netbios_shutdown(); 140*da6c28aaSamw return; 141*da6c28aaSamw } 142*da6c28aaSamw 143*da6c28aaSamw (void) fprintf(stderr, "smbd: Netbios Browser client started."); 144*da6c28aaSamw 145*da6c28aaSamw /* Startup Our internal, 1 second resolution, timer */ 146*da6c28aaSamw rc = pthread_create(&smb_nbts_thr, 0, smb_netbios_timer, 0); 147*da6c28aaSamw if (rc == 0) { 148*da6c28aaSamw (void) mutex_lock(mp); 149*da6c28aaSamw while (!(nb_status.state & (NETBIOS_TIMER_RUNNING | 150*da6c28aaSamw NETBIOS_TIMER_FAILED))) { 151*da6c28aaSamw (void) cond_wait(cvp, mp); 152*da6c28aaSamw } 153*da6c28aaSamw 154*da6c28aaSamw if (nb_status.state & NETBIOS_TIMER_FAILED) { 155*da6c28aaSamw (void) mutex_unlock(mp); 156*da6c28aaSamw smb_netbios_shutdown(); 157*da6c28aaSamw return; 158*da6c28aaSamw } 159*da6c28aaSamw (void) mutex_unlock(mp); 160*da6c28aaSamw } else { 161*da6c28aaSamw smb_netbios_shutdown(); 162*da6c28aaSamw return; 163*da6c28aaSamw } 164*da6c28aaSamw 165*da6c28aaSamw (void) fprintf(stderr, "smbd: Netbios Timer service started."); 166*da6c28aaSamw } 167*da6c28aaSamw 168*da6c28aaSamw /*ARGSUSED*/ 169*da6c28aaSamw static void * 170*da6c28aaSamw smb_netbios_timer(void *arg) 171*da6c28aaSamw { 172*da6c28aaSamw static unsigned int ticks; 173*da6c28aaSamw 174*da6c28aaSamw smb_netbios_chg_status(NETBIOS_TIMER_RUNNING, 1); 175*da6c28aaSamw 176*da6c28aaSamw while ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) { 177*da6c28aaSamw (void) sleep(1); 178*da6c28aaSamw 179*da6c28aaSamw if (nb_status.state & NETBIOS_DATAGRAM_SVC_RUNNING) 180*da6c28aaSamw smb_netbios_datagram_tick(); 181*da6c28aaSamw else 182*da6c28aaSamw break; 183*da6c28aaSamw 184*da6c28aaSamw if (nb_status.state & NETBIOS_NAME_SVC_RUNNING) { 185*da6c28aaSamw smb_netbios_name_tick(); 186*da6c28aaSamw 187*da6c28aaSamw /* every 10 minutes */ 188*da6c28aaSamw if ((ticks % 600) == 0) 189*da6c28aaSamw smb_netbios_cache_clean(); 190*da6c28aaSamw } 191*da6c28aaSamw else 192*da6c28aaSamw break; 193*da6c28aaSamw } 194*da6c28aaSamw 195*da6c28aaSamw nb_status.state &= ~NETBIOS_TIMER_RUNNING; 196*da6c28aaSamw if ((nb_status.state & NETBIOS_SHUTTING_DOWN) == 0) { 197*da6c28aaSamw /* either name or datagram service has failed */ 198*da6c28aaSamw smb_netbios_shutdown(); 199*da6c28aaSamw } 200*da6c28aaSamw 201*da6c28aaSamw return (0); 202*da6c28aaSamw } 203*da6c28aaSamw 204*da6c28aaSamw int 205*da6c28aaSamw smb_first_level_name_encode(struct name_entry *name, 206*da6c28aaSamw unsigned char *out, int max_out) 207*da6c28aaSamw { 208*da6c28aaSamw return (netbios_first_level_name_encode(name->name, name->scope, 209*da6c28aaSamw out, max_out)); 210*da6c28aaSamw } 211*da6c28aaSamw 212*da6c28aaSamw int 213*da6c28aaSamw smb_first_level_name_decode(unsigned char *in, struct name_entry *name) 214*da6c28aaSamw { 215*da6c28aaSamw return (netbios_first_level_name_decode((char *)in, (char *)name->name, 216*da6c28aaSamw (char *)name->scope)); 217*da6c28aaSamw } 218*da6c28aaSamw 219*da6c28aaSamw /* 220*da6c28aaSamw * smb_encode_netbios_name 221*da6c28aaSamw * 222*da6c28aaSamw * Set up the name and scope fields in the destination name_entry structure. 223*da6c28aaSamw * The name is padded with spaces to 15 bytes. The suffix is copied into the 224*da6c28aaSamw * last byte, i.e. "netbiosname <suffix>". The scope is copied and folded 225*da6c28aaSamw * to uppercase. 226*da6c28aaSamw */ 227*da6c28aaSamw void 228*da6c28aaSamw smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope, 229*da6c28aaSamw struct name_entry *dest) 230*da6c28aaSamw { 231*da6c28aaSamw char tmp_name[NETBIOS_NAME_SZ]; 232*da6c28aaSamw mts_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 233*da6c28aaSamw unsigned int cpid; 234*da6c28aaSamw int len; 235*da6c28aaSamw size_t rc; 236*da6c28aaSamw 237*da6c28aaSamw len = 0; 238*da6c28aaSamw rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 239*da6c28aaSamw 240*da6c28aaSamw if (rc != (size_t)-1) { 241*da6c28aaSamw wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 242*da6c28aaSamw cpid = oem_get_smb_cpid(); 243*da6c28aaSamw rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid); 244*da6c28aaSamw if (rc > 0) 245*da6c28aaSamw len = strlen(tmp_name); 246*da6c28aaSamw } 247*da6c28aaSamw 248*da6c28aaSamw (void) memset(dest->name, ' ', NETBIOS_NAME_SZ - 1); 249*da6c28aaSamw if (len) { 250*da6c28aaSamw (void) utf8_strupr(tmp_name); 251*da6c28aaSamw (void) memcpy(dest->name, tmp_name, len); 252*da6c28aaSamw } 253*da6c28aaSamw dest->name[NETBIOS_NAME_SZ - 1] = suffix; 254*da6c28aaSamw 255*da6c28aaSamw if (scope == NULL) { 256*da6c28aaSamw smb_config_rdlock(); 257*da6c28aaSamw (void) strlcpy((char *)dest->scope, 258*da6c28aaSamw smb_config_getstr(SMB_CI_NBSCOPE), NETBIOS_DOMAIN_NAME_MAX); 259*da6c28aaSamw smb_config_unlock(); 260*da6c28aaSamw } else { 261*da6c28aaSamw (void) strlcpy((char *)dest->scope, (const char *)scope, 262*da6c28aaSamw NETBIOS_DOMAIN_NAME_MAX); 263*da6c28aaSamw } 264*da6c28aaSamw (void) utf8_strupr((char *)dest->scope); 265*da6c28aaSamw } 266*da6c28aaSamw 267*da6c28aaSamw void 268*da6c28aaSamw smb_init_name_struct(unsigned char *name, char suffix, unsigned char *scope, 269*da6c28aaSamw uint32_t ipaddr, unsigned short port, uint32_t attr, 270*da6c28aaSamw uint32_t addr_attr, struct name_entry *dest) 271*da6c28aaSamw { 272*da6c28aaSamw bzero(dest, sizeof (struct name_entry)); 273*da6c28aaSamw smb_encode_netbios_name(name, suffix, scope, dest); 274*da6c28aaSamw 275*da6c28aaSamw switch (smb_node_type) { 276*da6c28aaSamw case 'H': 277*da6c28aaSamw dest->attributes = attr | NAME_ATTR_OWNER_TYPE_HNODE; 278*da6c28aaSamw break; 279*da6c28aaSamw case 'M': 280*da6c28aaSamw dest->attributes = attr | NAME_ATTR_OWNER_TYPE_MNODE; 281*da6c28aaSamw break; 282*da6c28aaSamw case 'P': 283*da6c28aaSamw dest->attributes = attr | NAME_ATTR_OWNER_TYPE_PNODE; 284*da6c28aaSamw break; 285*da6c28aaSamw case 'B': 286*da6c28aaSamw default: 287*da6c28aaSamw dest->attributes = attr | NAME_ATTR_OWNER_TYPE_BNODE; 288*da6c28aaSamw break; 289*da6c28aaSamw } 290*da6c28aaSamw 291*da6c28aaSamw dest->addr_list.refresh_ttl = dest->addr_list.ttl = 292*da6c28aaSamw TO_SECONDS(DEFAULT_TTL); 293*da6c28aaSamw 294*da6c28aaSamw dest->addr_list.sin.sin_family = AF_INET; 295*da6c28aaSamw dest->addr_list.sinlen = sizeof (dest->addr_list.sin); 296*da6c28aaSamw dest->addr_list.sin.sin_addr.s_addr = ipaddr; 297*da6c28aaSamw dest->addr_list.sin.sin_port = port; 298*da6c28aaSamw dest->addr_list.attributes = addr_attr; 299*da6c28aaSamw dest->addr_list.forw = dest->addr_list.back = &dest->addr_list; 300*da6c28aaSamw } 301