/* * samr_set_user_password * * Set the initial password for the user. * * Returns 0 if everything goes well, -1 if there is trouble generating a * key. */ static int samr_set_user_password(unsigned char *nt_key, BYTE *oem_password) { char hostname[NETBIOS_NAME_SZ]; randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ); /* * The new password is going to be the NetBIOS name of the system * in lower case. */ if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) return (-1); (void) smb_strlwr(hostname); /* * Generate the OEM password from the hostname and the user session * key(nt_key). */ /*LINTED E_BAD_PTR_CAST_ALIGN*/ (void) sam_oem_password((oem_password_t *)oem_password, (unsigned char *)hostname, nt_key); return (0); }
/* * Get the SAM account of the current system. * Returns 0 on success, otherwise, -1 to indicate an error. */ int smb_getsamaccount(char *buf, size_t buflen) { if (smb_getnetbiosname(buf, buflen - 1) != 0) return (-1); (void) strlcat(buf, "$", buflen); return (0); }
/* * DFS module initializationr: * * - creates the namespace cache * - gets system's NetBIOS name */ void dfs_init(void) { smb_cache_create(&dfs_nscache, 0, dfs_cache_cmp, free, bcopy, sizeof (dfs_nscnode_t)); if (smb_getnetbiosname(dfs_nbname, sizeof (dfs_nbname)) != 0) { syslog(LOG_ERR, "dfs: can't get machine name"); return; } bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops)); if ((dfs_intr_hdl = smb_dlopen()) == NULL) return; if ((dfs_intr_ops.dfsops_remote_count = (int (*)())dlsym(dfs_intr_hdl, "smb_dfs_remote_count")) == NULL) { smb_dlclose(dfs_intr_hdl); dfs_intr_hdl = NULL; bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops)); } }
/* * Looks up the given SID in local account databases: * * SMB Local users are looked up in /var/smb/smbpasswd * SMB Local groups are looked up in /var/smb/smbgroup.db * * If the account is found, its information is populated * in the passed smb_account_t structure. Caller must free * allocated memories by calling smb_account_free() upon * successful return. * * Return status: * * NT_STATUS_NOT_FOUND This is not a local account * NT_STATUS_NONE_MAPPED It's a local account but cannot be * translated. * other error status codes. */ uint32_t smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account) { char hostname[MAXHOSTNAMELEN]; smb_passwd_t smbpw; smb_group_t grp; smb_lwka_t *lwka; smb_domain_t di; uint32_t rid; uid_t id; int id_type; int rc; bzero(account, sizeof (smb_account_t)); if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO); if (smb_sid_cmp(sid, di.di_binsid)) { /* This is the local domain SID */ account->a_type = SidTypeDomain; account->a_name = strdup(""); account->a_domain = strdup(di.di_nbname); account->a_sid = smb_sid_dup(sid); account->a_domsid = smb_sid_dup(sid); account->a_rid = (uint32_t)-1; if (!smb_account_validate(account)) { smb_account_free(account); return (NT_STATUS_NO_MEMORY); } return (NT_STATUS_SUCCESS); } if (!smb_sid_indomain(di.di_binsid, sid)) { /* This is not a local SID */ return (NT_STATUS_NOT_FOUND); } if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) { account->a_type = lwka->lwka_type; account->a_name = strdup(lwka->lwka_name); } else { id_type = SMB_IDMAP_UNKNOWN; if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS) return (NT_STATUS_NONE_MAPPED); switch (id_type) { case SMB_IDMAP_USER: account->a_type = SidTypeUser; if (smb_pwd_getpwuid(id, &smbpw) == NULL) return (NT_STATUS_NO_SUCH_USER); account->a_name = strdup(smbpw.pw_name); break; case SMB_IDMAP_GROUP: account->a_type = SidTypeAlias; (void) smb_sid_getrid(sid, &rid); rc = smb_lgrp_getbyrid(rid, SMB_DOMAIN_LOCAL, &grp); if (rc != SMB_LGRP_SUCCESS) return (NT_STATUS_NO_SUCH_ALIAS); account->a_name = strdup(grp.sg_name); smb_lgrp_free(&grp); break; default: return (NT_STATUS_NONE_MAPPED); } } if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0) account->a_domain = strdup(hostname); account->a_sid = smb_sid_dup(sid); account->a_domsid = smb_sid_split(sid, &account->a_rid); if (!smb_account_validate(account)) { smb_account_free(account); return (NT_STATUS_NO_MEMORY); } return (NT_STATUS_SUCCESS); }
/* * 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)); }
/* * netr_server_samlogon * * NetrServerSamLogon RPC: interactive or network. It is assumed that * we have already authenticated with the PDC. If everything works, * we build a user info structure and return it, where the caller will * probably build an access token. * * Returns an NT status. There are numerous possibilities here. * For example: * NT_STATUS_INVALID_INFO_CLASS * NT_STATUS_INVALID_PARAMETER * NT_STATUS_ACCESS_DENIED * NT_STATUS_PASSWORD_MUST_CHANGE * NT_STATUS_NO_SUCH_USER * NT_STATUS_WRONG_PASSWORD * NT_STATUS_LOGON_FAILURE * NT_STATUS_ACCOUNT_RESTRICTION * NT_STATUS_INVALID_LOGON_HOURS * NT_STATUS_INVALID_WORKSTATION * NT_STATUS_INTERNAL_ERROR * NT_STATUS_PASSWORD_EXPIRED * NT_STATUS_ACCOUNT_DISABLED */ uint32_t netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, char *server, smb_logon_t *user_info, smb_token_t *token) { struct netr_SamLogon arg; struct netr_authenticator auth; struct netr_authenticator ret_auth; struct netr_logon_info1 info1; struct netr_logon_info2 info2; struct netr_validation_info3 *info3; ndr_heap_t *heap; int opnum; int rc, len; uint32_t status; bzero(&arg, sizeof (struct netr_SamLogon)); opnum = NETR_OPNUM_SamLogon; /* * Should we get the server and hostname from netr_info? */ len = strlen(server) + 4; arg.servername = ndr_rpc_malloc(netr_handle, len); arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ); if (arg.servername == NULL || arg.hostname == NULL) { ndr_rpc_release(netr_handle); return (NT_STATUS_INTERNAL_ERROR); } (void) snprintf((char *)arg.servername, len, "\\\\%s", server); if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) { ndr_rpc_release(netr_handle); return (NT_STATUS_INTERNAL_ERROR); } rc = netr_setup_authenticator(netr_info, &auth, &ret_auth); if (rc != SMBAUTH_SUCCESS) { ndr_rpc_release(netr_handle); return (NT_STATUS_INTERNAL_ERROR); } arg.auth = &auth; arg.ret_auth = &ret_auth; arg.validation_level = NETR_VALIDATION_LEVEL3; arg.logon_info.logon_level = user_info->lg_level; arg.logon_info.switch_value = user_info->lg_level; heap = ndr_rpc_get_heap(netr_handle); switch (user_info->lg_level) { case NETR_INTERACTIVE_LOGON: netr_setup_identity(heap, user_info, &info1.identity); netr_interactive_samlogon(netr_info, user_info, &info1); arg.logon_info.ru.info1 = &info1; break; case NETR_NETWORK_LOGON: if (user_info->lg_challenge_key.len < 8 || user_info->lg_challenge_key.val == NULL) { ndr_rpc_release(netr_handle); return (NT_STATUS_INVALID_PARAMETER); } netr_setup_identity(heap, user_info, &info2.identity); netr_network_samlogon(heap, netr_info, user_info, &info2); arg.logon_info.ru.info2 = &info2; break; default: ndr_rpc_release(netr_handle); return (NT_STATUS_INVALID_PARAMETER); } rc = ndr_rpc_call(netr_handle, opnum, &arg); if (rc != 0) { bzero(netr_info, sizeof (netr_info_t)); status = NT_STATUS_INVALID_PARAMETER; } else if (arg.status != 0) { status = NT_SC_VALUE(arg.status); /* * We need to validate the chain even though we have * a non-zero status. If the status is ACCESS_DENIED * this will trigger a new credential chain. However, * a valid credential is returned with some status * codes; for example, WRONG_PASSWORD. */ (void) netr_validate_chain(netr_info, arg.ret_auth); } else { status = netr_validate_chain(netr_info, arg.ret_auth); if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) { ndr_rpc_release(netr_handle); return (status); } info3 = arg.ru.info3; status = netr_setup_token(info3, user_info, netr_info, token); } ndr_rpc_release(netr_handle); return (status); }