/* * smb_match_netlogon_seqnum * * A sequence number is associated with each machine password property * update and the netlogon credential chain setup. If the * sequence numbers don't match, a NETLOGON credential chain * establishment is required. * * Returns 0 if kpasswd_seqnum equals to netlogon_seqnum. Otherwise, * returns -1. */ boolean_t smb_match_netlogon_seqnum(void) { int64_t setpasswd_seqnum; int64_t netlogon_seqnum; (void) mutex_lock(&seqnum_mtx); (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &setpasswd_seqnum); (void) smb_config_getnum(SMB_CI_NETLOGON_SEQNUM, &netlogon_seqnum); (void) mutex_unlock(&seqnum_mtx); return (setpasswd_seqnum == netlogon_seqnum); }
/* * smb_auth_validate_nt * * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against * stored user's password, passed in smbpw * * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2 */ boolean_t smb_auth_validate_nt( unsigned char *challenge, uint32_t clen, smb_passwd_t *smbpw, unsigned char *passwd, int pwdlen, char *domain, char *username, uchar_t *session_key) { int64_t lmlevel; boolean_t ok; if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK) return (B_FALSE); if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ)) return (B_FALSE); if (pwdlen > SMBAUTH_LM_RESP_SZ) ok = smb_ntlmv2_password_ok(challenge, clen, smbpw->pw_nthash, passwd, pwdlen, domain, username, session_key); else ok = smb_ntlm_password_ok(challenge, clen, smbpw->pw_nthash, passwd, session_key); return (ok); }
/* * smb_auth_validate_lm * * Validates given LM/LMv2 client response, passed in passwd arg, against * stored user's password, passed in smbpw * * If LM level <=3 server accepts LM responses, otherwise LMv2 */ boolean_t smb_auth_validate_lm( unsigned char *challenge, uint32_t clen, smb_passwd_t *smbpw, unsigned char *passwd, int pwdlen, char *domain, char *username) { boolean_t ok = B_FALSE; int64_t lmlevel; if (pwdlen != SMBAUTH_LM_RESP_SZ) return (B_FALSE); if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK) return (B_FALSE); if (lmlevel <= 3) { ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash, passwd); } if (!ok) ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash, passwd, domain, username); return (ok); }
/* * smb_update_netlogon_seqnum * * This function should only be called upon a successful netlogon * credential chain establishment to set the sequence number of the * netlogon to match with that of the kpasswd. */ void smb_update_netlogon_seqnum(void) { int64_t num; (void) mutex_lock(&seqnum_mtx); (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); (void) smb_config_setnum(SMB_CI_NETLOGON_SEQNUM, num); (void) mutex_unlock(&seqnum_mtx); }
/* * smb_set_machine_passwd * * This function should be used when setting the machine password property. * The associated sequence number is incremented. */ static int smb_set_machine_passwd(char *passwd) { int64_t num; int rc = -1; if (smb_config_set(SMB_CI_MACHINE_PASSWD, passwd) != SMBD_SMF_OK) return (-1); (void) mutex_lock(&seqnum_mtx); (void) smb_config_getnum(SMB_CI_KPASSWD_SEQNUM, &num); if (smb_config_setnum(SMB_CI_KPASSWD_SEQNUM, ++num) == SMBD_SMF_OK) rc = 0; (void) mutex_unlock(&seqnum_mtx); return (rc); }
/* * smb_pwd_update * * Updates the password entry of the given user if the user already * has an entry, otherwise it'll add an entry for the user with * given password and control information. */ static int smb_pwd_update(const char *name, const char *password, int control) { struct stat64 stbuf; FILE *src, *dst; int tempfd; int err = SMB_PWE_SUCCESS; smb_pwbuf_t pwbuf; smb_passwd_t smbpw; boolean_t newent = B_TRUE; boolean_t user_disable = B_FALSE; char uxbuf[1024]; struct passwd uxpw; int64_t lm_level; err = smb_pwd_lock(); if (err != SMB_PWE_SUCCESS) return (err); if (stat64(SMB_PASSWD, &stbuf) < 0) { err = SMB_PWE_STAT_FAILED; goto passwd_exit; } if ((tempfd = open(SMB_PASSTEMP, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) { err = SMB_PWE_OPEN_FAILED; goto passwd_exit; } if ((dst = fdopen(tempfd, "wF")) == NULL) { err = SMB_PWE_OPEN_FAILED; goto passwd_exit; } if ((src = fopen(SMB_PASSWD, "rF")) == NULL) { err = SMB_PWE_OPEN_FAILED; (void) fclose(dst); (void) unlink(SMB_PASSTEMP); goto passwd_exit; } if (smb_config_getnum(SMB_CI_LM_LEVEL, &lm_level) != SMBD_SMF_OK) lm_level = 4; if (lm_level >= 4) control |= SMB_PWC_NOLM; pwbuf.pw_pwd = &smbpw; /* * copy old password entries to temporary file while replacing * the entry that matches "name" */ while (smb_pwd_fgetent(src, &pwbuf, SMB_PWD_GETF_ALL) != NULL) { if (strcmp(smbpw.pw_name, name) == 0) { err = smb_pwd_chgpwent(&smbpw, password, control); if (err == SMB_PWE_USER_DISABLE) user_disable = B_TRUE; err = smb_pwd_fputent(dst, &pwbuf); newent = B_FALSE; } else { err = smb_pwd_fputent(dst, &pwbuf); } if (err != SMB_PWE_SUCCESS) { (void) fclose(src); (void) fclose(dst); goto passwd_exit; } } if (newent) { if (getpwnam_r(name, &uxpw, uxbuf, sizeof (uxbuf))) { bzero(&smbpw, sizeof (smb_passwd_t)); (void) strlcpy(smbpw.pw_name, uxpw.pw_name, sizeof (smbpw.pw_name)); smbpw.pw_uid = uxpw.pw_uid; (void) smb_pwd_chgpwent(&smbpw, password, control); err = smb_pwd_fputent(dst, &pwbuf); } else { err = SMB_PWE_USER_UNKNOWN; } if (err != SMB_PWE_SUCCESS) { (void) fclose(src); (void) fclose(dst); goto passwd_exit; } } (void) fclose(src); if (fclose(dst) != 0) { err = SMB_PWE_CLOSE_FAILED; goto passwd_exit; /* Don't trust the temporary file */ } /* Rename temp to passwd */ if (unlink(SMB_OPASSWD) && access(SMB_OPASSWD, 0) == 0) { err = SMB_PWE_UPDATE_FAILED; (void) unlink(SMB_PASSTEMP); goto passwd_exit; } if (link(SMB_PASSWD, SMB_OPASSWD) == -1) { err = SMB_PWE_UPDATE_FAILED; (void) unlink(SMB_PASSTEMP); goto passwd_exit; } if (rename(SMB_PASSTEMP, SMB_PASSWD) == -1) { err = SMB_PWE_UPDATE_FAILED; (void) unlink(SMB_PASSTEMP); goto passwd_exit; } (void) chmod(SMB_PASSWD, 0400); passwd_exit: (void) smb_pwd_unlock(); if ((err == SMB_PWE_SUCCESS) && user_disable) err = SMB_PWE_USER_DISABLE; return (err); }
/* * Some older clients (Windows 98) only handle the low byte * of the max workers value. If the low byte is less than * SMB_PI_MAX_WORKERS_MIN set it to SMB_PI_MAX_WORKERS_MIN. */ void smb_load_kconfig(smb_kmod_cfg_t *kcfg) { struct utsname uts; int64_t citem; int rc; bzero(kcfg, sizeof (smb_kmod_cfg_t)); (void) smb_config_getnum(SMB_CI_MAX_WORKERS, &citem); kcfg->skc_maxworkers = (uint32_t)citem; if ((kcfg->skc_maxworkers & 0xFF) < SMB_PI_MAX_WORKERS_MIN) { kcfg->skc_maxworkers &= ~0xFF; kcfg->skc_maxworkers += SMB_PI_MAX_WORKERS_MIN; } (void) smb_config_getnum(SMB_CI_KEEPALIVE, &citem); kcfg->skc_keepalive = (uint32_t)citem; if ((kcfg->skc_keepalive != 0) && (kcfg->skc_keepalive < SMB_PI_KEEP_ALIVE_MIN)) kcfg->skc_keepalive = SMB_PI_KEEP_ALIVE_MIN; (void) smb_config_getnum(SMB_CI_MAX_CONNECTIONS, &citem); kcfg->skc_maxconnections = (uint32_t)citem; kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); kcfg->skc_netbios_enable = smb_config_getbool(SMB_CI_NETBIOS_ENABLE); kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE); kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE); kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS); kcfg->skc_max_protocol = smb_config_get_max_protocol(); kcfg->skc_secmode = smb_config_get_secmode(); rc = smb_config_getnum(SMB_CI_MAXIMUM_CREDITS, &citem); if (rc != SMBD_SMF_OK) citem = SMB_PI_MAX_CREDITS; if (citem < SMB_PI_MIN_CREDITS) citem = SMB_PI_MIN_CREDITS; if (citem > SMB_PI_MAX_CREDITS) citem = SMB_PI_MAX_CREDITS; kcfg->skc_maximum_credits = (uint16_t)citem; rc = smb_config_getnum(SMB_CI_INITIAL_CREDITS, &citem); if (rc != SMBD_SMF_OK) citem = SMB_PI_MIN_CREDITS; if (citem < SMB_PI_MIN_CREDITS) citem = SMB_PI_MIN_CREDITS; if (citem > kcfg->skc_maximum_credits) citem = kcfg->skc_maximum_credits; kcfg->skc_initial_credits = (uint16_t)citem; (void) smb_getdomainname(kcfg->skc_nbdomain, sizeof (kcfg->skc_nbdomain)); (void) smb_getfqdomainname(kcfg->skc_fqdn, sizeof (kcfg->skc_fqdn)); (void) smb_getnetbiosname(kcfg->skc_hostname, sizeof (kcfg->skc_hostname)); (void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment, sizeof (kcfg->skc_system_comment)); smb_config_get_version(&kcfg->skc_version); kcfg->skc_execflags = smb_config_get_execinfo(NULL, NULL, 0); if (smb_config_get_localuuid(kcfg->skc_machine_uuid) < 0) { syslog(LOG_ERR, "smb_load_kconfig: no machine_uuid"); uuid_generate_time(kcfg->skc_machine_uuid); } /* skc_negtok, skc_negtok_len: see smbd_authsvc.c */ (void) uname(&uts); (void) snprintf(kcfg->skc_native_os, sizeof (kcfg->skc_native_os), "%s %s %s", uts.sysname, uts.release, uts.version); (void) strlcpy(kcfg->skc_native_lm, "Native SMB service", sizeof (kcfg->skc_native_lm)); }
/* * Setup a new SMB client context. * * Get the SMB server's configuration stuff and * store it in the new client context object. */ int smbrdr_ctx_new(struct smb_ctx **ctx_p, char *server, char *domain, char *user) { struct smb_ctx *ctx = NULL; uchar_t nthash[SMBAUTH_HASH_SZ]; int64_t lmcl; int authflags, err; assert(server != NULL); assert(domain != NULL); assert(user != NULL); if ((err = smb_ctx_alloc(&ctx)) != 0) return (NT_STATUS_NO_MEMORY); /* * Set server, share, domain, user * (in the ctx handle). */ (void) smb_ctx_setfullserver(ctx, server); (void) smb_ctx_setshare(ctx, "IPC$", USE_IPC); (void) smb_ctx_setdomain(ctx, domain, B_TRUE); (void) smb_ctx_setuser(ctx, user, B_TRUE); /* * Set auth. info (hash) and type. */ if (user[0] == '\0') { authflags = SMB_AT_ANON; } else { (void) smb_config_getnum(SMB_CI_LM_LEVEL, &lmcl); if (lmcl <= 2) { /* Send NTLM */ authflags = SMB_AT_NTLM1; } else { /* Send NTLMv2 */ authflags = SMB_AT_NTLM2; } smb_ipc_get_passwd(nthash, sizeof (nthash)); (void) smb_ctx_setpwhash(ctx, nthash, NULL); } (void) smb_ctx_setauthflags(ctx, authflags); /* * Do lookup, connect, session setup, tree connect. * Or find and reuse a session/tree, if one exists. */ if ((err = smb_ctx_resolve(ctx)) != 0) { err = NT_STATUS_BAD_NETWORK_PATH; goto errout; } if ((err = smb_ctx_get_ssn(ctx)) != 0) { err = NT_STATUS_NETWORK_ACCESS_DENIED; goto errout; } if ((err = smb_ctx_get_tree(ctx)) != 0) { err = NT_STATUS_BAD_NETWORK_NAME; goto errout; } /* Success! */ *ctx_p = ctx; return (0); errout: smb_ctx_free(ctx); return (err); }