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 2008 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 #include <sys/types.h> 29 #include <stdarg.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <time.h> 33 #include <synch.h> 34 #include <syslog.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <errno.h> 38 #include <net/if.h> 39 #include <netdb.h> 40 #include <netinet/in.h> 41 #include <arpa/nameser.h> 42 #include <resolv.h> 43 #include <sys/sockio.h> 44 #include <smbsrv/smbinfo.h> 45 #include <smbsrv/netbios.h> 46 #include <smbsrv/libsmb.h> 47 48 static smb_ntdomain_t smbpdc_cache; 49 static mutex_t smbpdc_mtx; 50 static cond_t smbpdc_cv; 51 52 extern int getdomainname(char *, int); 53 54 /* 55 * smb_getdomaininfo 56 * 57 * Returns a pointer to the cached domain data. The caller can specify 58 * whether or not he is prepared to wait if the cache is not yet valid 59 * and for how long. The specified timeout is in seconds. 60 */ 61 smb_ntdomain_t * 62 smb_getdomaininfo(uint32_t timeout) 63 { 64 timestruc_t to; 65 int err; 66 67 if (timeout != 0) { 68 (void) mutex_lock(&smbpdc_mtx); 69 while (smbpdc_cache.ipaddr == 0) { 70 to.tv_sec = timeout; 71 to.tv_nsec = 0; 72 err = cond_reltimedwait(&smbpdc_cv, &smbpdc_mtx, &to); 73 if (err == ETIME) 74 break; 75 } 76 (void) mutex_unlock(&smbpdc_mtx); 77 } 78 79 if (smbpdc_cache.ipaddr != 0) 80 return (&smbpdc_cache); 81 else 82 return (0); 83 } 84 85 void 86 smb_logdomaininfo(smb_ntdomain_t *di) 87 { 88 char ipstr[16]; 89 90 (void) inet_ntop(AF_INET, (const void *)&di->ipaddr, ipstr, 91 sizeof (ipstr)); 92 syslog(LOG_DEBUG, "smbd: %s (%s:%s)", di->domain, di->server, ipstr); 93 } 94 95 /* 96 * smb_setdomaininfo 97 * 98 * Set the information for the specified domain. If the information is 99 * non-null, the notification event is raised to wakeup any threads 100 * blocking on the cache. 101 */ 102 void 103 smb_setdomaininfo(char *domain, char *server, uint32_t ipaddr) 104 { 105 char *p; 106 107 bzero(&smbpdc_cache, sizeof (smb_ntdomain_t)); 108 109 if (domain && server && ipaddr) { 110 (void) strlcpy(smbpdc_cache.domain, domain, SMB_PI_MAX_DOMAIN); 111 (void) strlcpy(smbpdc_cache.server, server, SMB_PI_MAX_DOMAIN); 112 113 /* 114 * Remove DNS domain name extension 115 * to avoid confusing NetBIOS. 116 */ 117 if ((p = strchr(smbpdc_cache.domain, '.')) != 0) 118 *p = '\0'; 119 120 if ((p = strchr(smbpdc_cache.server, '.')) != 0) 121 *p = '\0'; 122 123 (void) mutex_lock(&smbpdc_mtx); 124 smbpdc_cache.ipaddr = ipaddr; 125 (void) cond_broadcast(&smbpdc_cv); 126 (void) mutex_unlock(&smbpdc_mtx); 127 } 128 } 129 130 void 131 smb_load_kconfig(smb_kmod_cfg_t *kcfg) 132 { 133 int64_t citem; 134 135 bzero(kcfg, sizeof (smb_kmod_cfg_t)); 136 137 (void) smb_config_getnum(SMB_CI_MAX_BUFSIZE, &citem); 138 kcfg->skc_maxbufsize = (uint32_t)citem; 139 (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem); 140 kcfg->skc_maxworkers = (uint32_t)citem; 141 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem); 142 kcfg->skc_keepalive = (uint32_t)citem; 143 if ((kcfg->skc_keepalive != 0) && 144 (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN)) 145 kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN; 146 147 (void) smb_config_getnum(SMB_CI_OPLOCK_TIMEOUT, &citem); 148 kcfg->skc_oplock_timeout = (uint32_t)citem; 149 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem); 150 kcfg->skc_maxconnections = (uint32_t)citem; 151 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); 152 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); 153 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); 154 kcfg->skc_signing_check = smb_config_getbool(SMB_CI_SIGNING_CHECK); 155 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); 156 kcfg->skc_flush_required = smb_config_getbool(SMB_CI_FLUSH_REQUIRED); 157 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); 158 kcfg->skc_dirsymlink_enable = 159 !smb_config_getbool(SMB_CI_DIRSYMLINK_DISABLE); 160 kcfg->skc_announce_quota = smb_config_getbool(SMB_CI_ANNONCE_QUOTA); 161 kcfg->skc_secmode = smb_config_get_secmode(); 162 (void) smb_getdomainname(kcfg->skc_resource_domain, 163 sizeof (kcfg->skc_resource_domain)); 164 (void) smb_gethostname(kcfg->skc_hostname, sizeof (kcfg->skc_hostname), 165 1); 166 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, 167 sizeof (kcfg->skc_system_comment)); 168 } 169 170 /* 171 * Get the current system NetBIOS name. The hostname is truncated at 172 * the first `.` or 15 bytes, whichever occurs first, and converted 173 * to uppercase (by smb_gethostname). Text that appears after the 174 * first '.' is considered to be part of the NetBIOS scope. 175 * 176 * Returns 0 on success, otherwise -1 to indicate an error. 177 */ 178 int 179 smb_getnetbiosname(char *buf, size_t buflen) 180 { 181 if (smb_gethostname(buf, buflen, 1) != 0) 182 return (-1); 183 184 if (buflen >= NETBIOS_NAME_SZ) 185 buf[NETBIOS_NAME_SZ - 1] = '\0'; 186 187 return (0); 188 } 189 190 /* 191 * Get the current system node name. The returned name is guaranteed 192 * to be null-terminated (gethostname may not null terminate the name). 193 * If the hostname has been fully-qualified for some reason, the domain 194 * part will be removed. If the caller would like the name in upper 195 * case, it is folded to uppercase. 196 * 197 * If gethostname fails, the returned buffer will contain an empty 198 * string. 199 */ 200 int 201 smb_gethostname(char *buf, size_t buflen, int upcase) 202 { 203 char *p; 204 205 if (buf == NULL || buflen == 0) 206 return (-1); 207 208 if (gethostname(buf, buflen) != 0) { 209 *buf = '\0'; 210 return (-1); 211 } 212 213 buf[buflen - 1] = '\0'; 214 215 if ((p = strchr(buf, '.')) != NULL) 216 *p = '\0'; 217 218 if (upcase) 219 (void) utf8_strupr(buf); 220 221 return (0); 222 } 223 224 /* 225 * Obtain the fully-qualified name for this machine. If the 226 * hostname is fully-qualified, accept it. Otherwise, try to 227 * find an appropriate domain name to append to the hostname. 228 */ 229 int 230 smb_getfqhostname(char *buf, size_t buflen) 231 { 232 char hostname[MAXHOSTNAMELEN]; 233 char domain[MAXHOSTNAMELEN]; 234 235 hostname[0] = '\0'; 236 domain[0] = '\0'; 237 238 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) 239 return (-1); 240 241 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) 242 return (-1); 243 244 if (hostname[0] == '\0') 245 return (-1); 246 247 if (domain[0] == '\0') { 248 (void) strlcpy(buf, hostname, buflen); 249 return (0); 250 } 251 252 (void) snprintf(buf, buflen, "%s.%s", hostname, domain); 253 return (0); 254 } 255 256 /* 257 * smb_resolve_netbiosname 258 * 259 * Convert the fully-qualified domain name (i.e. fqdn) to a NETBIOS name. 260 * Upon success, the NETBIOS name will be returned via buf parameter. 261 * Returns 0 upon success. Otherwise, returns -1. 262 */ 263 int 264 smb_resolve_netbiosname(char *fqdn, char *buf, size_t buflen) 265 { 266 char *p; 267 268 if (!buf) 269 return (-1); 270 271 *buf = '\0'; 272 if (!fqdn) 273 return (-1); 274 275 (void) strlcpy(buf, fqdn, buflen); 276 if ((p = strchr(buf, '.')) != NULL) 277 *p = 0; 278 279 if (strlen(buf) >= NETBIOS_NAME_SZ) 280 buf[NETBIOS_NAME_SZ - 1] = '\0'; 281 282 return (0); 283 } 284 285 /* 286 * smb_getdomainname 287 * 288 * Returns NETBIOS name of the domain if the system is in domain 289 * mode. Or returns workgroup name if the system is in workgroup 290 * mode. 291 */ 292 int 293 smb_getdomainname(char *buf, size_t buflen) 294 { 295 char domain[MAXHOSTNAMELEN]; 296 int rc; 297 298 if (buf == NULL || buflen == 0) 299 return (-1); 300 301 *buf = '\0'; 302 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, domain, 303 sizeof (domain)); 304 305 if ((rc != SMBD_SMF_OK) || (*domain == '\0')) 306 return (-1); 307 308 (void) smb_resolve_netbiosname(domain, buf, buflen); 309 return (0); 310 } 311 312 /* 313 * smb_resolve_fqdn 314 * 315 * Converts the NETBIOS name of the domain (i.e. nbt_domain) to a fully 316 * qualified domain name. The domain from either the domain field or 317 * search list field of the /etc/resolv.conf will be returned via the 318 * buf parameter if the first label of the domain matches the given 319 * NETBIOS name. 320 * 321 * Returns -1 upon error. If a match is found, returns 1. Otherwise, 322 * returns 0. 323 */ 324 int 325 smb_resolve_fqdn(char *nbt_domain, char *buf, size_t buflen) 326 { 327 struct __res_state res_state; 328 int i, found = 0; 329 char *p; 330 int dlen; 331 332 if (!buf) 333 return (-1); 334 335 *buf = '\0'; 336 if (!nbt_domain) 337 return (-1); 338 339 bzero(&res_state, sizeof (struct __res_state)); 340 if (res_ninit(&res_state)) 341 return (-1); 342 343 if (*nbt_domain == '\0') { 344 if (*res_state.defdname == '\0') { 345 res_ndestroy(&res_state); 346 return (0); 347 } 348 349 (void) strlcpy(buf, res_state.defdname, buflen); 350 res_ndestroy(&res_state); 351 return (1); 352 } 353 354 dlen = strlen(nbt_domain); 355 if (!strncasecmp(nbt_domain, res_state.defdname, dlen)) { 356 (void) strlcpy(buf, res_state.defdname, buflen); 357 res_ndestroy(&res_state); 358 return (1); 359 } 360 361 for (i = 0; (p = res_state.dnsrch[i]) != NULL; i++) { 362 if (!strncasecmp(nbt_domain, p, dlen)) { 363 (void) strlcpy(buf, p, buflen); 364 found = 1; 365 break; 366 } 367 368 } 369 370 res_ndestroy(&res_state); 371 return (found); 372 } 373 374 /* 375 * smb_getfqdomainname 376 * 377 * If the domain_name property value is FQDN, it will be returned. 378 * In domain mode, the domain from either the domain field or 379 * search list field of the /etc/resolv.conf will be returned via the 380 * buf parameter if the first label of the domain matches the 381 * domain_name property. In workgroup mode, it returns the local 382 * domain. 383 * 384 * Returns 0 upon success. Otherwise, returns -1. 385 */ 386 int 387 smb_getfqdomainname(char *buf, size_t buflen) 388 { 389 char domain[MAXHOSTNAMELEN]; 390 int rc = 0; 391 392 if (buf == NULL || buflen == 0) 393 return (-1); 394 395 *buf = '\0'; 396 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 397 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, domain, 398 sizeof (domain)); 399 400 if ((rc != SMBD_SMF_OK) || (*domain == '\0')) 401 return (-1); 402 403 if (strchr(domain, '.') == NULL) { 404 if (smb_resolve_fqdn(domain, buf, buflen) != 1) 405 rc = -1; 406 } else { 407 (void) strlcpy(buf, domain, buflen); 408 } 409 } else { 410 if (smb_resolve_fqdn("", buf, buflen) != 1) 411 rc = -1; 412 } 413 414 return (rc); 415 } 416 417 418 419 /* 420 * Temporary fbt for dtrace until user space sdt enabled. 421 */ 422 void 423 smb_tracef(const char *fmt, ...) 424 { 425 va_list ap; 426 char buf[128]; 427 428 va_start(ap, fmt); 429 (void) vsnprintf(buf, 128, fmt, ap); 430 va_end(ap); 431 432 smb_trace(buf); 433 } 434 435 /* 436 * Temporary fbt for dtrace until user space sdt enabled. 437 */ 438 void 439 smb_trace(const char *s) 440 { 441 syslog(LOG_DEBUG, "%s", s); 442 } 443