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