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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <assert.h> 27 #include <sys/types.h> 28 #include <stdarg.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <time.h> 32 #include <synch.h> 33 #include <syslog.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <errno.h> 37 #include <net/if.h> 38 #include <netdb.h> 39 #include <netinet/in.h> 40 #include <arpa/nameser.h> 41 #include <resolv.h> 42 #include <sys/sockio.h> 43 #include <sys/socket.h> 44 #include <smbsrv/smbinfo.h> 45 #include <smbsrv/netbios.h> 46 #include <smbsrv/libsmb.h> 47 48 static mutex_t seqnum_mtx; 49 50 /* 51 * Some older clients (Windows 98) only handle the low byte 52 * of the max workers value. If the low byte is less than 53 * SMB_PI_MAX_WORKERS_MIN set it to SMB_PI_MAX_WORKERS_MIN. 54 */ 55 void 56 smb_load_kconfig(smb_kmod_cfg_t *kcfg) 57 { 58 int64_t citem; 59 60 bzero(kcfg, sizeof (smb_kmod_cfg_t)); 61 62 (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem); 63 kcfg->skc_maxworkers = (uint32_t)citem; 64 if ((kcfg->skc_maxworkers & 0xFF) < SMB_PI_MAX_WORKERS_MIN) { 65 kcfg->skc_maxworkers &= ~0xFF; 66 kcfg->skc_maxworkers += SMB_PI_MAX_WORKERS_MIN; 67 } 68 69 (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem); 70 kcfg->skc_keepalive = (uint32_t)citem; 71 if ((kcfg->skc_keepalive != 0) && 72 (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN)) 73 kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN; 74 75 (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem); 76 kcfg->skc_maxconnections = (uint32_t)citem; 77 kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); 78 kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); 79 kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); 80 kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE); 81 kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); 82 kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); 83 kcfg->skc_secmode = smb_config_get_secmode(); 84 (void) smb_getdomainname(kcfg->skc_nbdomain, 85 sizeof (kcfg->skc_nbdomain)); 86 (void) smb_getfqdomainname(kcfg->skc_fqdn, 87 sizeof (kcfg->skc_fqdn)); 88 (void) smb_getnetbiosname(kcfg->skc_hostname, 89 sizeof (kcfg->skc_hostname)); 90 (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, 91 sizeof (kcfg->skc_system_comment)); 92 } 93 94 /* 95 * Get the current system NetBIOS name. The hostname is truncated at 96 * the first `.` or 15 bytes, whichever occurs first, and converted 97 * to uppercase (by smb_gethostname). Text that appears after the 98 * first '.' is considered to be part of the NetBIOS scope. 99 * 100 * Returns 0 on success, otherwise -1 to indicate an error. 101 */ 102 int 103 smb_getnetbiosname(char *buf, size_t buflen) 104 { 105 if (smb_gethostname(buf, buflen, 1) != 0) 106 return (-1); 107 108 if (buflen >= NETBIOS_NAME_SZ) 109 buf[NETBIOS_NAME_SZ - 1] = '\0'; 110 111 return (0); 112 } 113 114 /* 115 * Get the SAM account of the current system. 116 * Returns 0 on success, otherwise, -1 to indicate an error. 117 */ 118 int 119 smb_getsamaccount(char *buf, size_t buflen) 120 { 121 if (smb_getnetbiosname(buf, buflen - 1) != 0) 122 return (-1); 123 124 (void) strlcat(buf, "$", buflen); 125 return (0); 126 } 127 128 /* 129 * Get the current system node name. The returned name is guaranteed 130 * to be null-terminated (gethostname may not null terminate the name). 131 * If the hostname has been fully-qualified for some reason, the domain 132 * part will be removed. If the caller would like the name in upper 133 * case, it is folded to uppercase. 134 * 135 * If gethostname fails, the returned buffer will contain an empty 136 * string. 137 */ 138 int 139 smb_gethostname(char *buf, size_t buflen, int upcase) 140 { 141 char *p; 142 143 if (buf == NULL || buflen == 0) 144 return (-1); 145 146 if (gethostname(buf, buflen) != 0) { 147 *buf = '\0'; 148 return (-1); 149 } 150 151 buf[buflen - 1] = '\0'; 152 153 if ((p = strchr(buf, '.')) != NULL) 154 *p = '\0'; 155 156 if (upcase) 157 (void) utf8_strupr(buf); 158 159 return (0); 160 } 161 162 /* 163 * Obtain the fully-qualified name for this machine. If the 164 * hostname is fully-qualified, accept it. Otherwise, try to 165 * find an appropriate domain name to append to the hostname. 166 */ 167 int 168 smb_getfqhostname(char *buf, size_t buflen) 169 { 170 char hostname[MAXHOSTNAMELEN]; 171 char domain[MAXHOSTNAMELEN]; 172 173 hostname[0] = '\0'; 174 domain[0] = '\0'; 175 176 if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) 177 return (-1); 178 179 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) 180 return (-1); 181 182 if (hostname[0] == '\0') 183 return (-1); 184 185 if (domain[0] == '\0') { 186 (void) strlcpy(buf, hostname, buflen); 187 return (0); 188 } 189 190 (void) snprintf(buf, buflen, "%s.%s", hostname, domain); 191 return (0); 192 } 193 194 /* 195 * smb_getdomainname 196 * 197 * Returns NETBIOS name of the domain if the system is in domain 198 * mode. Or returns workgroup name if the system is in workgroup 199 * mode. 200 */ 201 int 202 smb_getdomainname(char *buf, size_t buflen) 203 { 204 int rc; 205 206 if (buf == NULL || buflen == 0) 207 return (-1); 208 209 *buf = '\0'; 210 rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, buf, buflen); 211 212 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 213 return (-1); 214 215 return (0); 216 } 217 218 /* 219 * smb_getdomainsid 220 * 221 * Returns the domain SID if the system is in domain mode. 222 * Otherwise returns NULL. 223 * 224 * Note: Callers are responsible for freeing a returned SID. 225 */ 226 smb_sid_t * 227 smb_getdomainsid(void) 228 { 229 char buf[MAXHOSTNAMELEN]; 230 smb_sid_t *sid; 231 int security_mode; 232 int rc; 233 234 security_mode = smb_config_get_secmode(); 235 if (security_mode != SMB_SECMODE_DOMAIN) 236 return (NULL); 237 238 *buf = '\0'; 239 rc = smb_config_getstr(SMB_CI_DOMAIN_SID, buf, MAXHOSTNAMELEN); 240 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 241 return (NULL); 242 243 if ((sid = smb_sid_fromstr(buf)) == NULL) 244 return (NULL); 245 246 return (sid); 247 } 248 249 /* 250 * smb_getfqdomainname 251 * 252 * In the system is in domain mode, the dns_domain property value 253 * is returned. Otherwise, it returns the local domain obtained via 254 * resolver. 255 * 256 * Returns 0 upon success. Otherwise, returns -1. 257 */ 258 int 259 smb_getfqdomainname(char *buf, size_t buflen) 260 { 261 struct __res_state res_state; 262 int rc; 263 264 if (buf == NULL || buflen == 0) 265 return (-1); 266 267 *buf = '\0'; 268 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 269 rc = smb_config_getstr(SMB_CI_DOMAIN_FQDN, buf, buflen); 270 271 if ((rc != SMBD_SMF_OK) || (*buf == '\0')) 272 return (-1); 273 } else { 274 bzero(&res_state, sizeof (struct __res_state)); 275 if (res_ninit(&res_state)) 276 return (-1); 277 278 if (*res_state.defdname == '\0') { 279 res_ndestroy(&res_state); 280 return (-1); 281 } 282 283 (void) strlcpy(buf, res_state.defdname, buflen); 284 res_ndestroy(&res_state); 285 rc = 0; 286 } 287 288 return (rc); 289 } 290 291 292 /* 293 * smb_set_machine_passwd 294 * 295 * This function should be used when setting the machine password property. 296 * The associated sequence number is incremented. 297 */ 298 static int 299 smb_set_machine_passwd(char *passwd) 300 { 301 int64_t num; 302 int rc = -1; 303 304 if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK) 305 return (-1); 306 307 (void) mutex_lock(&seqnum_mtx); 308 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 309 if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num) 310 == SMBD_SMF_OK) 311 rc = 0; 312 (void) mutex_unlock(&seqnum_mtx); 313 return (rc); 314 } 315 316 /* 317 * smb_match_netlogon_seqnum 318 * 319 * A sequence number is associated with each machine password property 320 * update and the netlogon credential chain setup. If the 321 * sequence numbers don't match, a NETLOGON credential chain 322 * establishment is required. 323 * 324 * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise, 325 * returns -1. 326 */ 327 boolean_t 328 smb_match_netlogon_seqnum(void) 329 { 330 int64_t setpasswd_seqnum; 331 int64_t netlogon_seqnum; 332 333 (void) mutex_lock(&seqnum_mtx); 334 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum); 335 (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum); 336 (void) mutex_unlock(&seqnum_mtx); 337 return (setpasswd_seqnum == netlogon_seqnum); 338 } 339 340 /* 341 * smb_setdomainprops 342 * 343 * This function should be called after joining an AD to 344 * set all the domain related SMF properties. 345 * 346 * The kpasswd_domain property is the AD domain to which the system 347 * is joined via kclient. If this function is invoked by the SMB 348 * daemon, fqdn should be set to NULL. 349 */ 350 int 351 smb_setdomainprops(char *fqdn, char *server, char *passwd) 352 { 353 if (server == NULL || passwd == NULL) 354 return (-1); 355 356 if ((*server == '\0') || (*passwd == '\0')) 357 return (-1); 358 359 if (fqdn && (smb_config_set(SMB_CI_KPASSWD_DOMAIN, fqdn) != 0)) 360 return (-1); 361 362 if (smb_config_set(SMB_CI_KPASSWD_SRV, server) != 0) 363 return (-1); 364 365 if (smb_set_machine_passwd(passwd) != 0) { 366 syslog(LOG_ERR, "smb_setdomainprops: failed to set" 367 " machine account password"); 368 return (-1); 369 } 370 371 /* 372 * If we successfully create a trust account, we mark 373 * ourselves as a domain member in the environment so 374 * that we use the SAMLOGON version of the NETLOGON 375 * PDC location protocol. 376 */ 377 (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_TRUE); 378 379 return (0); 380 } 381 382 /* 383 * smb_update_netlogon_seqnum 384 * 385 * This function should only be called upon a successful netlogon 386 * credential chain establishment to set the sequence number of the 387 * netlogon to match with that of the kpasswd. 388 */ 389 void 390 smb_update_netlogon_seqnum(void) 391 { 392 int64_t num; 393 394 (void) mutex_lock(&seqnum_mtx); 395 (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); 396 (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num); 397 (void) mutex_unlock(&seqnum_mtx); 398 } 399 400 401 /* 402 * Temporary fbt for dtrace until user space sdt enabled. 403 */ 404 void 405 smb_tracef(const char *fmt, ...) 406 { 407 va_list ap; 408 char buf[128]; 409 410 va_start(ap, fmt); 411 (void) vsnprintf(buf, 128, fmt, ap); 412 va_end(ap); 413 414 smb_trace(buf); 415 } 416 417 /* 418 * Temporary fbt for dtrace until user space sdt enabled. 419 */ 420 void 421 smb_trace(const char *s) 422 { 423 syslog(LOG_DEBUG, "%s", s); 424 } 425 426 /* 427 * smb_tonetbiosname 428 * 429 * Creates a NetBIOS name based on the given name and suffix. 430 * NetBIOS name is 15 capital characters, padded with space if needed 431 * and the 16th byte is the suffix. 432 */ 433 void 434 smb_tonetbiosname(char *name, char *nb_name, char suffix) 435 { 436 char tmp_name[NETBIOS_NAME_SZ]; 437 mts_wchar_t wtmp_name[NETBIOS_NAME_SZ]; 438 unsigned int cpid; 439 int len; 440 size_t rc; 441 442 len = 0; 443 rc = mts_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ); 444 445 if (rc != (size_t)-1) { 446 wtmp_name[NETBIOS_NAME_SZ - 1] = 0; 447 cpid = oem_get_smb_cpid(); 448 rc = unicodestooems(tmp_name, wtmp_name, NETBIOS_NAME_SZ, cpid); 449 if (rc > 0) 450 len = strlen(tmp_name); 451 } 452 453 (void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1); 454 if (len) { 455 (void) utf8_strupr(tmp_name); 456 (void) memcpy(nb_name, tmp_name, len); 457 } 458 nb_name[NETBIOS_NAME_SZ - 1] = suffix; 459 } 460 461 int 462 smb_get_nameservers(smb_inaddr_t *ips, int sz) 463 { 464 union res_sockaddr_union set[MAXNS]; 465 int i, cnt; 466 struct __res_state res_state; 467 char ipstr[INET6_ADDRSTRLEN]; 468 469 if (ips == NULL) 470 return (0); 471 472 bzero(&res_state, sizeof (struct __res_state)); 473 if (res_ninit(&res_state) < 0) 474 return (0); 475 476 cnt = res_getservers(&res_state, set, MAXNS); 477 for (i = 0; i < cnt; i++) { 478 if (i >= sz) 479 break; 480 ips[i].a_family = AF_INET; 481 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, INADDRSZ); 482 if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, 483 INET_ADDRSTRLEN)) { 484 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 485 continue; 486 } 487 ips[i].a_family = AF_INET6; 488 bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, IPV6_ADDR_LEN); 489 if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, 490 INET6_ADDRSTRLEN)) { 491 syslog(LOG_DEBUG, "Found %s name server\n", ipstr); 492 } 493 } 494 res_ndestroy(&res_state); 495 return (i); 496 } 497 /* 498 * smb_gethostbyname 499 * 500 * Looks up a host by the given name. The host entry can come 501 * from any of the sources for hosts specified in the 502 * /etc/nsswitch.conf and the NetBIOS cache. 503 * 504 * XXX Invokes nbt_name_resolve API once the NBTD is integrated 505 * to look in the NetBIOS cache if getipnodebyname fails. 506 * 507 * Caller should invoke freehostent to free the returned hostent. 508 */ 509 struct hostent * 510 smb_gethostbyname(const char *name, int *err_num) 511 { 512 struct hostent *h; 513 514 h = getipnodebyname(name, AF_INET, 0, err_num); 515 if ((h == NULL) || h->h_length != INADDRSZ) 516 h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num); 517 return (h); 518 } 519 520 /* 521 * smb_gethostbyaddr 522 * 523 * Looks up a host by the given IP address. The host entry can come 524 * from any of the sources for hosts specified in the 525 * /etc/nsswitch.conf and the NetBIOS cache. 526 * 527 * XXX Invokes nbt API to resolve name by IP once the NBTD is integrated 528 * to look in the NetBIOS cache if getipnodebyaddr fails. 529 * 530 * Caller should invoke freehostent to free the returned hostent. 531 */ 532 struct hostent * 533 smb_gethostbyaddr(const char *addr, int len, int type, int *err_num) 534 { 535 struct hostent *h; 536 537 h = getipnodebyaddr(addr, len, type, err_num); 538 539 return (h); 540 } 541 542 /* 543 * Check to see if the given name is the hostname. 544 * It checks the hostname returned by OS and also both 545 * fully qualified and NetBIOS forms of the host name. 546 */ 547 boolean_t 548 smb_ishostname(const char *name) 549 { 550 char hostname[MAXHOSTNAMELEN]; 551 int rc; 552 553 if (strchr(name, '.') != NULL) 554 rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN); 555 else { 556 if (strlen(name) < NETBIOS_NAME_SZ) 557 rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN); 558 else 559 rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1); 560 } 561 562 if (rc != 0) 563 return (B_FALSE); 564 565 return (utf8_strcasecmp(name, hostname) == 0); 566 } 567