void * ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size) { ndr_heap_t *heap; if ((heap = ndr_rpc_get_heap(handle)) == NULL) return (NULL); return (ndr_heap_malloc(heap, size)); }
/* * samr_create_user * * Create a user in the domain specified by the domain handle. If this * call is successful, the server will return the RID for the user and * a user handle, which may be used to set or query the SAM. * * Observed status codes: * NT_STATUS_INVALID_PARAMETER * NT_STATUS_INVALID_ACCOUNT_NAME * NT_STATUS_ACCESS_DENIED * NT_STATUS_USER_EXISTS * * Returns 0 on success. Otherwise returns an NT status code. */ DWORD samr_create_user(mlsvc_handle_t *domain_handle, char *username, DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle) { struct samr_CreateUser arg; ndr_heap_t *heap; int opnum; int rc; DWORD status = 0; if (ndr_is_null_handle(domain_handle) || username == NULL || rid == NULL) { return (NT_STATUS_INVALID_PARAMETER); } opnum = SAMR_OPNUM_CreateUser; bzero(&arg, sizeof (struct samr_CreateUser)); (void) memcpy(&arg.handle, &domain_handle->handle, sizeof (ndr_hdid_t)); heap = ndr_rpc_get_heap(domain_handle); ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username); arg.account_flags = account_flags; arg.desired_access = 0xE00500B0; rc = ndr_rpc_call(domain_handle, opnum, &arg); if (rc != 0) { status = NT_STATUS_INVALID_PARAMETER; } else if (arg.status != 0) { status = NT_SC_VALUE(arg.status); if (status != NT_STATUS_USER_EXISTS) { smb_tracef("SamrCreateUser[%s]: %s", username, xlate_nt_status(status)); } } else { ndr_inherit_handle(user_handle, domain_handle); (void) memcpy(&user_handle->handle, &arg.user_handle, sizeof (ndr_hdid_t)); *rid = arg.rid; if (ndr_is_null_handle(user_handle)) status = NT_STATUS_INVALID_HANDLE; else status = 0; } ndr_rpc_release(domain_handle); return (status); }
/* * Call the RPC function identified by opnum. The remote service is * identified by the handle, which should have been initialized by * ndr_rpc_bind. * * If the RPC call is successful (returns 0), the caller must call * ndr_rpc_release to release the heap. Otherwise, we release the * heap here. */ int ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) { ndr_client_t *clnt = handle->clnt; int rc; if (ndr_rpc_get_heap(handle) == NULL) return (-1); rc = ndr_clnt_call(clnt->binding, opnum, params); /* * Always clear the nonull flag to ensure * it is not applied to subsequent calls. */ clnt->nonull = B_FALSE; if (NDR_DRC_IS_FAULT(rc)) { ndr_rpc_release(handle); return (-1); } return (0); }
/* * 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); }