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