summaryrefslogtreecommitdiff
path: root/usr/src/lib/smbsrv/libmlsvc/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/smbsrv/libmlsvc/common')
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c19
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h2
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c195
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c25
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c5
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c298
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c16
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c425
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.h48
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c335
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c11
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c34
12 files changed, 694 insertions, 719 deletions
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
index df29495ed1..043ee29549 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -88,7 +89,8 @@ static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *,
*
* On success 0 is returned. Otherwise a -ve error code.
*/
-int lsar_open(char *server, char *domain, char *username,
+int
+lsar_open(char *server, char *domain, char *username,
mlsvc_handle_t *domain_handle)
{
if (server == NULL || domain == NULL)
@@ -109,11 +111,6 @@ int lsar_open(char *server, char *domain, char *username,
* function via lsar_open to ensure that the appropriate connection is
* in place.
*
- * I'm not sure if it makes a difference whether we use GENERIC_EXECUTE
- * or STANDARD_RIGHTS_EXECUTE. For a long time I used the standard bit
- * and then I added the generic bit while working on privileges because
- * NT sets that bit. I don't think it matters.
- *
* Returns 0 on success. Otherwise non-zero to indicate a failure.
*/
int
@@ -141,15 +138,7 @@ lsar_open_policy2(char *server, char *domain, char *username,
(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
arg.attributes.length = sizeof (struct mslsa_object_attributes);
-
- if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) {
- arg.desiredAccess = MAXIMUM_ALLOWED;
- } else {
- arg.desiredAccess = GENERIC_EXECUTE
- | STANDARD_RIGHTS_EXECUTE
- | POLICY_VIEW_LOCAL_INFORMATION
- | POLICY_LOOKUP_NAMES;
- }
+ arg.desiredAccess = MAXIMUM_ALLOWED;
if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) {
ndr_rpc_unbind(lsa_handle);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
index 8a5d55785b..d693d8825c 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SMBSRV_MLSVC_H
@@ -33,6 +34,7 @@ extern "C" {
#endif
int smb_dclocator_init(void);
+void smbrdr_initialize(void);
void dssetup_initialize(void);
void srvsvc_initialize(void);
void wkssvc_initialize(void);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
index bbeb99630d..0a52a43e65 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -49,27 +49,6 @@
#include <libsmbrdr.h>
#include <mlsvc.h>
-/*
- * Server info cache entry expiration in seconds.
- */
-#define NDR_SVINFO_TIMEOUT 1800
-
-typedef struct ndr_svinfo {
- list_node_t svi_lnd;
- time_t svi_tcached;
- char svi_server[MAXNAMELEN];
- char svi_domain[MAXNAMELEN];
- srvsvc_server_info_t svi_svinfo;
-} ndr_svinfo_t;
-
-typedef struct ndr_svlist {
- list_t svl_list;
- mutex_t svl_mtx;
- boolean_t svl_init;
-} ndr_svlist_t;
-
-static ndr_svlist_t ndr_svlist;
-
static int ndr_xa_init(ndr_client_t *, ndr_xa_t *);
static int ndr_xa_exchange(ndr_client_t *, ndr_xa_t *);
static int ndr_xa_read(ndr_client_t *, ndr_xa_t *);
@@ -77,53 +56,6 @@ static void ndr_xa_preserve(ndr_client_t *, ndr_xa_t *);
static void ndr_xa_destruct(ndr_client_t *, ndr_xa_t *);
static void ndr_xa_release(ndr_client_t *);
-static int ndr_svinfo_lookup(char *, char *, srvsvc_server_info_t *);
-static boolean_t ndr_svinfo_match(const char *, const char *, const
- ndr_svinfo_t *);
-static boolean_t ndr_svinfo_expired(ndr_svinfo_t *);
-
-/*
- * Initialize the RPC client interface: create the server info cache.
- */
-void
-ndr_rpc_init(void)
-{
- (void) mutex_lock(&ndr_svlist.svl_mtx);
-
- if (!ndr_svlist.svl_init) {
- list_create(&ndr_svlist.svl_list, sizeof (ndr_svinfo_t),
- offsetof(ndr_svinfo_t, svi_lnd));
- ndr_svlist.svl_init = B_TRUE;
- }
-
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
-}
-
-/*
- * Terminate the RPC client interface: flush and destroy the server info
- * cache.
- */
-void
-ndr_rpc_fini(void)
-{
- ndr_svinfo_t *svi;
-
- (void) mutex_lock(&ndr_svlist.svl_mtx);
-
- if (ndr_svlist.svl_init) {
- while ((svi = list_head(&ndr_svlist.svl_list)) != NULL) {
- list_remove(&ndr_svlist.svl_list, svi);
- free(svi->svi_svinfo.sv_name);
- free(svi->svi_svinfo.sv_comment);
- free(svi);
- }
-
- list_destroy(&ndr_svlist.svl_list);
- ndr_svlist.svl_init = B_FALSE;
- }
-
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
-}
/*
* This call must be made to initialize an RPC client structure and bind
@@ -158,10 +90,9 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
/*
* Set the default based on the assumption that most
- * servers will be Windows 2000 or later.
- * Don't lookup the svinfo if this is a SRVSVC request
- * because the SRVSVC is used to get the server info.
- * None of the SRVSVC calls depend on the server info.
+ * servers will be Windows 2000 or later. This used to
+ * try to get the actual server version, but that RPC
+ * is not necessarily allowed anymore, so don't bother.
*/
bzero(&svinfo, sizeof (srvsvc_server_info_t));
svinfo.sv_platform_id = SV_PLATFORM_ID_NT;
@@ -170,8 +101,12 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
svinfo.sv_type = SV_TYPE_DEFAULT;
svinfo.sv_os = NATIVE_OS_WIN2000;
- if (strcasecmp(service, "SRVSVC") != 0)
- (void) ndr_svinfo_lookup(server, domain, &svinfo);
+ /*
+ * Some callers pass this when they want a NULL session.
+ * Todo: have callers pass an empty string for that.
+ */
+ if (strcmp(username, MLSVC_ANON_USER) == 0)
+ username = "";
/*
* Setup smbfs library handle, authenticate, connect to
@@ -180,9 +115,10 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
* server, user, domain.
*/
if ((rc = smbrdr_ctx_new(&ctx, server, domain, username)) != 0) {
- syslog(LOG_ERR, "ndr_rpc_bind: "
- "smbrdr_ctx_new(S=%s, D=%s, U=%s), err=%d",
- server, domain, username, rc);
+ syslog(LOG_ERR, "ndr_rpc_bind: smbrdr_ctx_new"
+ "(Srv=%s Dom=%s User=%s), %s (0x%x)",
+ server, domain, username,
+ xlate_nt_status(rc), rc);
goto errout;
}
@@ -200,7 +136,7 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain,
* Setup the RPC client handle.
*/
if ((clnt = malloc(sizeof (ndr_client_t))) == NULL)
- return (-1);
+ goto errout;
bzero(clnt, sizeof (ndr_client_t));
clnt->handle = &handle->handle;
@@ -623,107 +559,6 @@ ndr_xa_release(ndr_client_t *clnt)
}
}
-/*
- * Lookup platform, type and version information about a server.
- * If the cache doesn't already contain the data, contact the server and
- * cache the response before returning the server info to the caller.
- *
- * We don't provide the name or comment for now, which avoids the need
- * to deal with unnecessary memory management.
- */
-static int
-ndr_svinfo_lookup(char *server, char *domain, srvsvc_server_info_t *svinfo)
-{
- static boolean_t timechecked = B_FALSE;
- ndr_svinfo_t *svi;
-
- (void) mutex_lock(&ndr_svlist.svl_mtx);
- if (!ndr_svlist.svl_init)
- return (-1);
-
- svi = list_head(&ndr_svlist.svl_list);
- while (svi != NULL) {
- if (ndr_svinfo_expired(svi)) {
- svi = list_head(&ndr_svlist.svl_list);
- continue;
- }
-
- if (ndr_svinfo_match(server, domain, svi)) {
- bcopy(&svi->svi_svinfo, svinfo,
- sizeof (srvsvc_server_info_t));
- svinfo->sv_name = NULL;
- svinfo->sv_comment = NULL;
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
- return (0);
- }
-
- svi = list_next(&ndr_svlist.svl_list, svi);
- }
-
- if ((svi = malloc(sizeof (ndr_svinfo_t))) == NULL) {
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
- return (-1);
- }
-
- if (srvsvc_net_server_getinfo(server, domain, &svi->svi_svinfo) < 0) {
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
- free(svi);
- return (-1);
- }
-
- (void) time(&svi->svi_tcached);
- (void) strlcpy(svi->svi_server, server, MAXNAMELEN);
- (void) strlcpy(svi->svi_domain, domain, MAXNAMELEN);
- list_insert_tail(&ndr_svlist.svl_list, svi);
- bcopy(&svi->svi_svinfo, svinfo, sizeof (srvsvc_server_info_t));
- svinfo->sv_name = NULL;
- svinfo->sv_comment = NULL;
-
- if (!timechecked) {
- timechecked = B_TRUE;
- ndr_srvsvc_timecheck(server, domain);
- }
-
- (void) mutex_unlock(&ndr_svlist.svl_mtx);
- return (0);
-}
-
-static boolean_t
-ndr_svinfo_match(const char *server, const char *domain,
- const ndr_svinfo_t *svi)
-{
- if ((smb_strcasecmp(server, svi->svi_server, 0) == 0) &&
- (smb_strcasecmp(domain, svi->svi_domain, 0) == 0)) {
- return (B_TRUE);
- }
-
- return (B_FALSE);
-}
-
-/*
- * If the server info in the cache has expired, discard it and return true.
- * Otherwise return false.
- *
- * This is a private function to support ndr_svinfo_lookup() that assumes
- * the list mutex is held.
- */
-static boolean_t
-ndr_svinfo_expired(ndr_svinfo_t *svi)
-{
- time_t tnow;
-
- (void) time(&tnow);
-
- if (difftime(tnow, svi->svi_tcached) > NDR_SVINFO_TIMEOUT) {
- list_remove(&ndr_svlist.svl_list, svi);
- free(svi->svi_svinfo.sv_name);
- free(svi->svi_svinfo.sv_comment);
- free(svi);
- return (B_TRUE);
- }
-
- return (B_FALSE);
-}
/*
* Compare the time here with the remote time on the server
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c
index 32f87fbbe6..00040f5482 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <syslog.h>
@@ -65,7 +65,7 @@ static pthread_t smb_dclocator_thr;
static void *smb_ddiscover_service(void *);
static void smb_ddiscover_main(char *, char *);
-static boolean_t smb_ddiscover_dns(char *, char *, smb_domainex_t *);
+static uint32_t smb_ddiscover_dns(char *, char *, smb_domainex_t *);
static boolean_t smb_ddiscover_nbt(char *, char *, smb_domainex_t *);
static boolean_t smb_ddiscover_domain_match(char *, char *, uint32_t);
static uint32_t smb_ddiscover_qinfo(char *, char *, smb_domainex_t *);
@@ -235,26 +235,27 @@ static void
smb_ddiscover_main(char *domain, char *server)
{
smb_domainex_t dxi;
- boolean_t discovered;
+ uint32_t status;
bzero(&dxi, sizeof (smb_domainex_t));
if (smb_domain_start_update() != SMB_DOMAIN_SUCCESS)
return;
- if (SMB_IS_FQDN(domain))
- discovered = smb_ddiscover_dns(domain, server, &dxi);
- else
- discovered = smb_ddiscover_nbt(domain, server, &dxi);
+ status = smb_ddiscover_dns(domain, server, &dxi);
+ if (status != 0 && !SMB_IS_FQDN(domain)) {
+ if (smb_ddiscover_nbt(domain, server, &dxi))
+ status = 0;
+ }
- if (discovered)
+ if (status == 0)
smb_domain_update(&dxi);
smb_domain_end_update();
smb_domainex_free(&dxi);
- if (discovered)
+ if (status == 0)
smb_domain_save();
}
@@ -262,16 +263,16 @@ smb_ddiscover_main(char *domain, char *server)
* Discovers a DC for the specified domain via DNS. If a DC is found
* primary and trusted domains information will be queried.
*/
-static boolean_t
+static uint32_t
smb_ddiscover_dns(char *domain, char *server, smb_domainex_t *dxi)
{
uint32_t status;
if (!smb_ads_lookup_msdcs(domain, server, dxi->d_dc, MAXHOSTNAMELEN))
- return (B_FALSE);
+ return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
status = smb_ddiscover_qinfo(domain, dxi->d_dc, dxi);
- return (status == NT_STATUS_SUCCESS);
+ return (status);
}
/*
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
index f1d11a6cfe..0fbe2a6890 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/errno.h>
@@ -60,7 +60,7 @@ mlsvc_init(void)
return (rc);
smb_quota_init();
- ndr_rpc_init();
+ smbrdr_initialize();
srvsvc_initialize();
wkssvc_initialize();
lsarpc_initialize();
@@ -89,7 +89,6 @@ mlsvc_fini(void)
svcctl_finalize();
logr_finalize();
netdfs_finalize();
- ndr_rpc_fini();
smb_quota_fini();
}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index e9ff66635b..45973ab820 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -19,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -40,19 +40,26 @@
#include <smbsrv/libsmb.h>
#include <smbsrv/libsmbns.h>
#include <smbsrv/libmlsvc.h>
+#include <smbsrv/ntaccess.h>
#include <smbsrv/smbinfo.h>
#include <libsmbrdr.h>
#include <lsalib.h>
#include <samlib.h>
#include <smbsrv/netrauth.h>
-/* Domain join support (using MS-RPC) */
-static boolean_t mlsvc_ntjoin_support = B_FALSE;
-
extern int netr_open(char *, char *, mlsvc_handle_t *);
extern int netr_close(mlsvc_handle_t *);
extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
+static DWORD
+mlsvc_join_rpc(smb_domainex_t *dxi,
+ char *admin_user, char *admin_pw,
+ char *machine_name, char *machine_pw);
+static DWORD
+mlsvc_join_noauth(smb_domainex_t *dxi,
+ char *machine_name, char *machine_pw);
+
+
DWORD
mlsvc_netlogon(char *server, char *domain)
{
@@ -66,79 +73,268 @@ mlsvc_netlogon(char *server, char *domain)
"credential chain");
(void) netr_close(&netr_handle);
} else {
- status = NT_STATUS_OPEN_FAILED;
+ syslog(LOG_NOTICE, "Failed to connect to %s "
+ "for domain %s", server, domain);
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
return (status);
}
/*
- * Joins the specified domain by creating a machine account on
- * the selected domain controller.
+ * Join the specified domain. The method varies depending on whether
+ * we're using "secure join" (using an administrative account to join)
+ * or "unsecure join" (using a pre-created machine account). In the
+ * latter case, the machine account is created "by hand" before this
+ * machine attempts to join, and we just change the password from the
+ * (weak) default password for a new machine account to a random one.
*
- * Disconnect any existing connection with the domain controller.
- * This will ensure that no stale connection will be used, it will
- * also pickup any configuration changes in either side by trying
- * to establish a new connection.
+ * Note that the caller has already done "DC discovery" and passes the
+ * domain info. in the first arg.
*
* Returns NT status codes.
*/
DWORD
-mlsvc_join(smb_domainex_t *dxi, char *user, char *plain_text)
+mlsvc_join(smb_domainex_t *dxi, char *admin_user, char *admin_pw)
{
- int erc;
+ char machine_name[SMB_SAMACCT_MAXLEN];
+ char machine_pw[NETR_MACHINE_ACCT_PASSWD_MAX];
+ unsigned char passwd_hash[SMBAUTH_HASH_SZ];
+ smb_domain_t *di = &dxi->d_primary;
DWORD status;
- char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
- smb_adjoin_status_t err;
- smb_domain_t *domain;
-
- machine_passwd[0] = '\0';
+ int rc;
- domain = &dxi->d_primary;
+ /*
+ * Domain join support: AD (Kerberos+LDAP) or MS-RPC?
+ * Leave the AD code path disabled until it can be
+ * fixed up so that the SMB server is in complete
+ * control of which AD server we talk to. See:
+ * NX 12427 (Re-enable Kerberos+LDAP with...)
+ */
+ boolean_t ads_enabled = smb_config_get_ads_enable();
- mlsvc_disconnect(dxi->d_dc);
+ if (smb_getsamaccount(machine_name, sizeof (machine_name)) != 0)
+ return (NT_STATUS_INTERNAL_ERROR);
- erc = smbrdr_logon(dxi->d_dc, domain->di_nbname, user);
+ (void) smb_gen_random_passwd(machine_pw, sizeof (machine_pw));
- if (erc == AUTH_USER_GRANT) {
- if (mlsvc_ntjoin_support == B_FALSE) {
+ /*
+ * A non-null user means we do "secure join".
+ */
+ if (admin_user != NULL && admin_user[0] != '\0') {
+ /*
+ * Doing "secure join", so authenticate as the
+ * specified user (with admin. rights).
+ */
+ (void) smb_auth_ntlm_hash(admin_pw, passwd_hash);
+ smb_ipc_set(admin_user, passwd_hash);
- if ((err = smb_ads_join(domain->di_fqname, user,
- plain_text, machine_passwd,
- sizeof (machine_passwd))) == SMB_ADJOIN_SUCCESS) {
- status = NT_STATUS_SUCCESS;
- } else {
+ /*
+ * If enabled, try to join using AD Services.
+ * The ADS code needs work. Not enabled yet.
+ */
+ status = NT_STATUS_UNSUCCESSFUL;
+ if (ads_enabled) {
+ smb_adjoin_status_t err;
+ err = smb_ads_join(di->di_fqname,
+ admin_user, admin_pw, machine_pw);
+ if (err != SMB_ADJOIN_SUCCESS) {
smb_ads_join_errmsg(err);
- status = NT_STATUS_UNSUCCESSFUL;
- }
- } else {
-
- status = sam_create_trust_account(dxi->d_dc,
- domain->di_nbname);
- if (status == NT_STATUS_SUCCESS) {
- (void) smb_getnetbiosname(machine_passwd,
- sizeof (machine_passwd));
- (void) smb_strlwr(machine_passwd);
+ } else {
+ status = NT_STATUS_SUCCESS;
}
}
- if (status == NT_STATUS_SUCCESS) {
- erc = smb_setdomainprops(NULL, dxi->d_dc,
- machine_passwd);
- if (erc != 0) {
- syslog(LOG_NOTICE,
- "Failed to update configuration");
- bzero(machine_passwd, sizeof (machine_passwd));
- return (NT_STATUS_UNSUCCESSFUL);
- }
-
- status = mlsvc_netlogon(dxi->d_dc, domain->di_nbname);
+ /*
+ * If ADS was disabled or gave an error,
+ * fall-back and try to join using RPC.
+ */
+ if (status != NT_STATUS_SUCCESS) {
+ status = mlsvc_join_rpc(dxi,
+ admin_user, admin_pw,
+ machine_name, machine_pw);
}
+
} else {
- status = NT_STATUS_LOGON_FAILURE;
+ /*
+ * Doing "Unsecure join" (pre-created account)
+ */
+ bzero(passwd_hash, sizeof (passwd_hash));
+ smb_ipc_set(MLSVC_ANON_USER, passwd_hash);
+
+ status = mlsvc_join_noauth(dxi, machine_name, machine_pw);
}
- bzero(machine_passwd, sizeof (machine_passwd));
+ if (status != NT_STATUS_SUCCESS)
+ goto out;
+
+ /*
+ * Make sure we can authenticate using the
+ * (new, or updated) machine account.
+ */
+ (void) smb_auth_ntlm_hash(machine_pw, passwd_hash);
+ smb_ipc_set(machine_name, passwd_hash);
+ rc = smbrdr_logon(dxi->d_dc, di->di_nbname, machine_name);
+ if (rc != 0) {
+ syslog(LOG_NOTICE, "Authenticate with "
+ "new/updated machine account: %s",
+ strerror(rc));
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ goto out;
+ }
+
+ /*
+ * Store the new machine account password.
+ */
+ rc = smb_setdomainprops(NULL, dxi->d_dc, machine_pw);
+ if (rc != 0) {
+ syslog(LOG_NOTICE,
+ "Failed to save machine account password");
+ status = NT_STATUS_INTERNAL_DB_ERROR;
+ goto out;
+ }
+
+ /*
+ * Update idmap config
+ */
+ if (smb_config_set_idmap_domain(di->di_fqname) != 0)
+ syslog(LOG_NOTICE, "Failed to set idmap domain name");
+ if (smb_config_refresh_idmap() != 0)
+ syslog(LOG_NOTICE, "Failed to refresh idmap service");
+
+ /*
+ * Note: The caller (smbd) saves the "secmode" and
+ * domain info (via smb_config_setdomaininfo) and
+ * and does smb_ipc_commit (or rollback).
+ */
+ status = 0;
+
+out:
+ /* Avoid leaving cleartext passwords around. */
+ bzero(machine_pw, sizeof (machine_pw));
+ bzero(passwd_hash, sizeof (passwd_hash));
+
+ return (status);
+}
+
+static DWORD
+mlsvc_join_rpc(smb_domainex_t *dxi,
+ char *admin_user, char *admin_pw,
+ char *machine_name, char *machine_pw)
+{
+ mlsvc_handle_t samr_handle;
+ mlsvc_handle_t domain_handle;
+ mlsvc_handle_t user_handle;
+ smb_account_t ainfo;
+ char *server = dxi->d_dc;
+ smb_domain_t *di = &dxi->d_primary;
+ DWORD account_flags;
+ DWORD rid;
+ DWORD status;
+ int rc;
+
+ /* Caller did smb_ipc_set() so we don't need the pw for now. */
+ _NOTE(ARGUNUSED(admin_pw));
+
+ rc = samr_open(server, di->di_nbname, admin_user,
+ MAXIMUM_ALLOWED, &samr_handle);
+ if (rc != 0) {
+ syslog(LOG_NOTICE, "sam_connect to server %s failed", server);
+ return (RPC_NT_SERVER_UNAVAILABLE);
+ }
+ /* have samr_handle */
+
+ status = samr_open_domain(&samr_handle, MAXIMUM_ALLOWED,
+ (struct samr_sid *)di->di_binsid, &domain_handle);
+ if (status != NT_STATUS_SUCCESS)
+ goto out_samr_handle;
+ /* have domain_handle */
+
+ account_flags = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
+ status = samr_create_user(&domain_handle, machine_name,
+ account_flags, &rid, &user_handle);
+ if (status == NT_STATUS_USER_EXISTS) {
+ status = samr_lookup_domain_names(&domain_handle,
+ machine_name, &ainfo);
+ if (status != NT_STATUS_SUCCESS)
+ goto out_domain_handle;
+ status = samr_open_user(&domain_handle, MAXIMUM_ALLOWED,
+ ainfo.a_rid, &user_handle);
+ }
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_NOTICE,
+ "Create or open machine account: %s",
+ xlate_nt_status(status));
+ goto out_domain_handle;
+ }
+
+ /*
+ * The account exists, and we have user_handle open
+ * on that account. Set the password and flags.
+ */
+
+ status = netr_set_user_password(&user_handle, machine_pw);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_NOTICE,
+ "Set machine account password: %s",
+ xlate_nt_status(status));
+ goto out_user_handle;
+ }
+
+ account_flags |= SAMR_AF_DONT_EXPIRE_PASSWD;
+ status = netr_set_user_control(&user_handle, account_flags);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_NOTICE,
+ "Set machine account control flags: %s",
+ xlate_nt_status(status));
+ goto out_user_handle;
+ }
+
+out_user_handle:
+ (void) samr_close_handle(&user_handle);
+out_domain_handle:
+ (void) samr_close_handle(&domain_handle);
+out_samr_handle:
+ (void) samr_close_handle(&samr_handle);
+
+ return (status);
+}
+
+/*
+ * Doing "Unsecure join" (using a pre-created machine account).
+ * All we need to do is change the password from the default
+ * to a random string.
+ *
+ * Note: this is a work in progres. Nexenta issue 11960
+ * (allow joining an AD domain using a pre-created computer account)
+ * It turns out that to change the machine account password,
+ * we need to use a different RPC call, performed over the
+ * NetLogon secure channel. (See netr_server_password_set2)
+ */
+static DWORD
+mlsvc_join_noauth(smb_domainex_t *dxi,
+ char *machine_name, char *machine_pw)
+{
+ char old_pw[SMB_SAMACCT_MAXLEN];
+ DWORD status;
+
+ /*
+ * Compose the current (default) password for the
+ * pre-created machine account, which is just the
+ * account name in lower case, truncated to 14
+ * characters.
+ */
+ if (smb_gethostname(old_pw, sizeof (old_pw), SMB_CASE_LOWER) != 0)
+ return (NT_STATUS_INTERNAL_ERROR);
+ old_pw[14] = '\0';
+
+ status = netr_change_password(dxi->d_dc, machine_name,
+ old_pw, machine_pw);
+ if (status != NT_STATUS_SUCCESS) {
+ syslog(LOG_NOTICE,
+ "Change machine account password: %s",
+ xlate_nt_status(status));
+ }
return (status);
}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
index 96fc566706..4b0224261b 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -104,6 +105,12 @@ netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
rc = netr_server_authenticate2(netr_handle, netr_info);
if (rc == 0) {
+ /*
+ * TODO: (later) When joining a domain using a
+ * pre-created machine account, should do:
+ * netr_server_password_set(&netr_handle, netr_info);
+ * Nexenta issue 11960
+ */
smb_update_netlogon_seqnum();
netr_info->flags |= NETR_FLG_VALID;
@@ -490,7 +497,7 @@ netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
arg.servername = (unsigned char *)netr_info->server;
arg.account_name = (unsigned char *)account_name;
- arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
+ arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
arg.hostname = (unsigned char *)netr_info->hostname;
/*
@@ -509,7 +516,7 @@ netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
return (-1);
}
- (void) memcpy(&arg.uas_new_password, &new_password,
+ (void) memcpy(&arg.owf_password, &new_password,
NETR_OWF_PASSWORD_SZ);
if (ndr_rpc_call(netr_handle, opnum, &arg) != 0)
@@ -569,3 +576,8 @@ netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
NETR_DESKEY_LEN, &old_password[8], 8);
return (rv);
}
+
+/*
+ * Todo: need netr_server_password_set2()
+ * used by "unsecure join". (NX 11960)
+ */
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
index 601283fa5e..1a2233ce39 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -28,6 +29,10 @@
* functions.
*/
+#include <sys/types.h>
+#include <sys/isa_defs.h>
+#include <sys/byteorder.h>
+
#include <alloca.h>
#include <smbsrv/libsmb.h>
@@ -36,128 +41,32 @@
#include <lsalib.h>
#include <samlib.h>
+#ifdef _LITTLE_ENDIAN
+/* little-endian values on little-endian */
+#define htolel(x) ((uint32_t)(x))
+#define letohl(x) ((uint32_t)(x))
+#else /* (BYTE_ORDER == LITTLE_ENDIAN) */
+/* little-endian values on big-endian (swap) */
+#define letohl(x) BSWAP_32(x)
+#define htolel(x) BSWAP_32(x)
+#endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
+
/*
* Valid values for the OEM OWF password encryption.
*/
-#define SAM_PASSWORD_516 516
#define SAM_KEYLEN 16
-extern DWORD samr_set_user_info(mlsvc_handle_t *);
-static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *);
-
-/*
- * sam_create_trust_account
- *
- * Create a trust account for this system.
- *
- * SAMR_AF_WORKSTATION_TRUST_ACCOUNT: servers and workstations.
- * SAMR_AF_SERVER_TRUST_ACCOUNT: domain controllers.
- *
- * Returns NT status codes.
- */
-DWORD
-sam_create_trust_account(char *server, char *domain)
-{
- char account_name[SMB_SAMACCT_MAXLEN];
- DWORD status;
-
- if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
- return (NT_STATUS_INTERNAL_ERROR);
-
- /*
- * The trust account value here should match
- * the value that will be used when the user
- * information is set on this account.
- */
- status = sam_create_account(server, domain, account_name,
- SAMR_AF_WORKSTATION_TRUST_ACCOUNT);
-
- /*
- * Based on network traces, a Windows 2000 client will
- * always try to create the computer account first.
- * If it existed, then check the user permission to join
- * the domain.
- */
-
- if (status == NT_STATUS_USER_EXISTS)
- status = sam_check_user(server, domain, account_name);
-
- return (status);
-}
+static void samr_fill_userpw(struct samr_user_password *, const char *);
+static void samr_make_encrypted_password(
+ struct samr_encr_passwd *epw,
+ char *new_pw_clear,
+ uint8_t *crypt_key);
/*
- * sam_create_account
- *
- * Create the specified domain account in the SAM database on the
- * domain controller.
- *
- * Account flags:
- * SAMR_AF_NORMAL_ACCOUNT
- * SAMR_AF_WORKSTATION_TRUST_ACCOUNT
- * SAMR_AF_SERVER_TRUST_ACCOUNT
- *
- * Returns NT status codes.
+ * Todo: Implement "unjoin" domain, which would use the
+ * sam_remove_trust_account code below.
*/
-DWORD
-sam_create_account(char *server, char *domain_name, char *account_name,
- DWORD account_flags)
-{
- mlsvc_handle_t samr_handle;
- mlsvc_handle_t domain_handle;
- mlsvc_handle_t user_handle;
- union samr_user_info sui;
- struct samr_sid *sid;
- DWORD rid;
- DWORD status;
- int rc;
- char user[SMB_USERNAME_MAXLEN];
-
- smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
-
- rc = samr_open(server, domain_name, user, SAM_CONNECT_CREATE_ACCOUNT,
- &samr_handle);
-
- if (rc != 0) {
- status = NT_STATUS_OPEN_FAILED;
- smb_tracef("SamCreateAccount[%s\\%s]: %s",
- domain_name, account_name, xlate_nt_status(status));
- return (status);
- }
-
- sid = sam_get_domain_sid(&samr_handle, server, domain_name);
-
- status = samr_open_domain(&samr_handle,
- SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle);
-
- if (status == NT_STATUS_SUCCESS) {
- status = samr_create_user(&domain_handle, account_name,
- account_flags, &rid, &user_handle);
-
- if (status == NT_STATUS_SUCCESS) {
- (void) samr_query_user_info(&user_handle,
- SAMR_QUERY_USER_CONTROL_INFO, &sui);
-
- (void) samr_get_user_pwinfo(&user_handle);
- (void) samr_set_user_info(&user_handle);
- (void) samr_close_handle(&user_handle);
- } else if (status != NT_STATUS_USER_EXISTS) {
- smb_tracef("SamCreateAccount[%s]: %s",
- account_name, xlate_nt_status(status));
- }
-
- (void) samr_close_handle(&domain_handle);
- } else {
- smb_tracef("SamCreateAccount[%s]: open domain failed",
- account_name);
- status = (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
- }
-
- (void) samr_close_handle(&samr_handle);
- free(sid);
- return (status);
-}
-
/*
* sam_remove_trust_account
@@ -194,7 +103,7 @@ sam_delete_account(char *server, char *domain_name, char *account_name)
mlsvc_handle_t domain_handle;
mlsvc_handle_t user_handle;
smb_account_t ainfo;
- struct samr_sid *sid;
+ smb_sid_t *sid;
DWORD access_mask;
DWORD status;
int rc;
@@ -204,93 +113,44 @@ sam_delete_account(char *server, char *domain_name, char *account_name)
rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
&samr_handle);
-
if (rc != 0)
- return (NT_STATUS_OPEN_FAILED);
-
- sid = sam_get_domain_sid(&samr_handle, server, domain_name);
- status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid,
- &domain_handle);
- free(sid);
- if (status != NT_STATUS_SUCCESS) {
- (void) samr_close_handle(&samr_handle);
- return (status);
- }
+ return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
- status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
- if (status == NT_STATUS_SUCCESS) {
- access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
- status = samr_open_user(&domain_handle, access_mask,
- ainfo.a_rid, &user_handle);
- if (status == NT_STATUS_SUCCESS) {
- if (samr_delete_user(&user_handle) != 0)
- (void) samr_close_handle(&user_handle);
- }
+ sid = samr_lookup_domain(&samr_handle, domain_name);
+ if (sid == NULL) {
+ status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ goto out_samr_hdl;
}
- (void) samr_close_handle(&domain_handle);
- (void) samr_close_handle(&samr_handle);
- return (status);
-}
-
-/*
- * sam_check_user
- *
- * Check to see if user have permission to access computer account.
- * The user being checked is the specified user for joining the Solaris
- * host to the domain.
- */
-DWORD
-sam_check_user(char *server, char *domain_name, char *account_name)
-{
- mlsvc_handle_t samr_handle;
- mlsvc_handle_t domain_handle;
- mlsvc_handle_t user_handle;
- smb_account_t ainfo;
- struct samr_sid *sid;
- DWORD access_mask;
- DWORD status;
- int rc;
- char user[SMB_USERNAME_MAXLEN];
-
- smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
-
- rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
- &samr_handle);
+ status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
+ (struct samr_sid *)sid, &domain_handle);
+ if (status != NT_STATUS_SUCCESS)
+ goto out_sid_ptr;
- if (rc != 0)
- return (NT_STATUS_OPEN_FAILED);
+ status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
+ if (status != NT_STATUS_SUCCESS)
+ goto out_dom_hdl;
- sid = sam_get_domain_sid(&samr_handle, server, domain_name);
- status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid,
- &domain_handle);
- free(sid);
- if (status != NT_STATUS_SUCCESS) {
- (void) samr_close_handle(&samr_handle);
- return (status);
- }
+ access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
+ status = samr_open_user(&domain_handle, access_mask,
+ ainfo.a_rid, &user_handle);
+ if (status != NT_STATUS_SUCCESS)
+ goto out_dom_hdl;
- status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
- if (status == NT_STATUS_SUCCESS) {
- /*
- * Win2000 client uses this access mask. The
- * following SAMR user specific rights bits are
- * set: set password, set attributes, and get
- * attributes.
- */
-
- access_mask = 0xb0;
- status = samr_open_user(&domain_handle,
- access_mask, ainfo.a_rid, &user_handle);
- if (status == NT_STATUS_SUCCESS)
- (void) samr_close_handle(&user_handle);
- }
+ status = samr_delete_user(&user_handle);
+ (void) samr_close_handle(&user_handle);
+out_dom_hdl:
(void) samr_close_handle(&domain_handle);
+out_sid_ptr:
+ free(sid);
+out_samr_hdl:
(void) samr_close_handle(&samr_handle);
+
return (status);
}
+
/*
* sam_lookup_name
*
@@ -372,54 +232,169 @@ sam_get_local_domains(char *server, char *domain_name)
}
/*
- * sam_oem_password
+ * Set the account control flags on some account for which we
+ * have already opened a SAM handle with appropriate rights,
+ * passed in here as sam_handle, along with the new flags.
+ */
+DWORD
+netr_set_user_control(
+ mlsvc_handle_t *user_handle,
+ DWORD UserAccountControl)
+{
+ struct samr_SetUserInfo16 info;
+
+ info.UserAccountControl = UserAccountControl;
+ return (samr_set_user_info(user_handle, 16, &info));
+}
+
+/*
+ * Set the password on some account, for which we have already
+ * opened a SAM handle with appropriate rights, passed in here
+ * as sam_handle, along with the new password as cleartext.
*
- * Generate an OEM password.
+ * This builds a struct SAMPR_USER_INTERNAL5_INFORMATION [MS-SAMR]
+ * containing the new password, encrypted with our session key.
*/
-int
-sam_oem_password(oem_password_t *oem_password, unsigned char *new_password,
- unsigned char *old_password)
+DWORD
+netr_set_user_password(
+ mlsvc_handle_t *user_handle,
+ char *new_pw_clear)
+{
+ unsigned char ssn_key[SMBAUTH_HASH_SZ];
+ struct samr_SetUserInfo24 info;
+
+ if (ndr_rpc_get_ssnkey(user_handle, ssn_key, SMBAUTH_HASH_SZ))
+ return (NT_STATUS_INTERNAL_ERROR);
+
+ (void) memset(&info, 0, sizeof (info));
+ samr_make_encrypted_password(&info.encr_pw, new_pw_clear, ssn_key);
+
+ /* Rather not leave the session key around. */
+ (void) memset(ssn_key, 0, sizeof (ssn_key));
+
+ return (samr_set_user_info(user_handle, 24, &info));
+}
+
+/*
+ * Change a password like NetUserChangePassword(),
+ * but where we already know which AD server to use,
+ * so we don't request the domain name or search for
+ * an AD server for that domain here.
+ */
+DWORD
+netr_change_password(
+ char *server,
+ char *account,
+ char *old_pw_clear,
+ char *new_pw_clear)
{
- smb_wchar_t *unicode_password;
- int length;
+ struct samr_encr_passwd epw;
+ struct samr_encr_hash old_hash;
+ uint8_t old_nt_hash[SAMR_PWHASH_LEN];
+ uint8_t new_nt_hash[SAMR_PWHASH_LEN];
+ mlsvc_handle_t handle;
+ DWORD rc;
+
+ /*
+ * Create an RPC handle to this server, bound to SAMR.
+ */
+ rc = ndr_rpc_bind(&handle, server, "", "", "SAMR");
+ if (rc)
+ return (RPC_NT_SERVER_UNAVAILABLE);
+
+ /*
+ * Encrypt the new p/w (plus random filler) with the
+ * old password, and send the old p/w encrypted with
+ * the new p/w hash to prove we know the old p/w.
+ * Details: [MS-SAMR 3.1.5.10.3]
+ */
+ (void) smb_auth_ntlm_hash(old_pw_clear, old_nt_hash);
+ (void) smb_auth_ntlm_hash(new_pw_clear, new_nt_hash);
+ samr_make_encrypted_password(&epw, new_pw_clear, old_nt_hash);
-#ifdef PBSHORTCUT
- assert(sizeof (oem_password_t) == SAM_PASSWORD_516);
-#endif /* PBSHORTCUT */
+ (void) smb_auth_DES(old_hash.data, SAMR_PWHASH_LEN,
+ new_nt_hash, 14, /* key */
+ old_nt_hash, SAMR_PWHASH_LEN);
- length = strlen((char const *)new_password);
- unicode_password = alloca((length + 1) * sizeof (smb_wchar_t));
+ /*
+ * Finally, ready to try the OtW call.
+ */
+ rc = samr_change_password(
+ &handle, server, account,
+ &epw, &old_hash);
- length = smb_auth_qnd_unicode((unsigned short *)unicode_password,
- (char *)new_password, length);
- oem_password->length = length;
+ /* Avoid leaving cleartext (or equivalent) around. */
+ (void) memset(old_nt_hash, 0, sizeof (old_nt_hash));
+ (void) memset(new_nt_hash, 0, sizeof (new_nt_hash));
- (void) memcpy(&oem_password->data[512 - length],
- unicode_password, length);
+ ndr_rpc_unbind(&handle);
+ return (rc);
+}
- rand_hash((unsigned char *)oem_password, sizeof (oem_password_t),
- old_password, SAM_KEYLEN);
+/*
+ * Build an encrypted password, as used by samr_set_user_info
+ * and samr_change_password. Note: This builds the unencrypted
+ * form in one union arm, and encrypts it in the other union arm.
+ */
+void
+samr_make_encrypted_password(
+ struct samr_encr_passwd *epw,
+ char *new_pw_clear,
+ uint8_t *crypt_key)
+{
+ union {
+ struct samr_user_password u;
+ struct samr_encr_passwd e;
+ } pwu;
+
+ samr_fill_userpw(&pwu.u, new_pw_clear);
- return (0);
+ (void) smb_auth_RC4(pwu.e.data, sizeof (pwu.e.data),
+ crypt_key, SAMR_PWHASH_LEN,
+ pwu.e.data, sizeof (pwu.e.data));
+
+ (void) memcpy(epw->data, pwu.e.data, sizeof (pwu.e.data));
+ (void) memset(pwu.e.data, 0, sizeof (pwu.e.data));
}
-static struct samr_sid *
-sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name)
+/*
+ * This fills in a samr_user_password (a.k.a. SAMPR_USER_PASSWORD
+ * in the MS Net API) which has the new password "right justified"
+ * in the buffer, and any space on the left filled with random junk
+ * to improve the quality of the encryption that is subsequently
+ * applied to this buffer before it goes over the wire.
+ */
+static void
+samr_fill_userpw(struct samr_user_password *upw, const char *new_pw)
{
- smb_sid_t *sid = NULL;
- smb_domainex_t domain;
-
- if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000) {
- if (!smb_domain_getinfo(&domain)) {
- if (lsa_query_account_domain_info(server, domain_name,
- &domain.d_primary) != NT_STATUS_SUCCESS)
- return (NULL);
- }
-
- sid = smb_sid_fromstr(domain.d_primary.di_sid);
- } else {
- sid = samr_lookup_domain(samr_handle, domain_name);
- }
+ smb_wchar_t *pbuf;
+ uint32_t pwlen_bytes;
+ size_t pwlen_wchars;
+
+ /*
+ * First fill the whole buffer with the random junk.
+ * (Slightly less random when debugging:)
+ */
+#ifdef DEBUG
+ (void) memset(upw->Buffer, '*', sizeof (upw->Buffer));
+#else
+ randomize((char *)upw->Buffer, sizeof (upw->Buffer));
+#endif
+
+ /*
+ * Now overwrite the last pwlen characters of
+ * that buffer with the password, and set the
+ * length field so the receiving end knows where
+ * the junk ends and the real password starts.
+ */
+ pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2;
+ if (pwlen_wchars > SAMR_USER_PWLEN)
+ pwlen_wchars = SAMR_USER_PWLEN;
+ pwlen_bytes = pwlen_wchars * 2;
+
+ pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars];
+ (void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars);
- return ((struct samr_sid *)sid);
+ /* Yes, this is in Bytes, not wchars. */
+ upw->Length = htolel(pwlen_bytes);
}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
index 3a3932e40f..7e8e1a458d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
@@ -21,6 +21,7 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
#ifndef _SAMLIB_H
@@ -71,9 +72,9 @@ DWORD sam_check_user(char *, char *, char *);
/*
* samr_open.c
*/
-int samr_open(char *, char *, char *, DWORD, mlsvc_handle_t *);
-int samr_connect(char *, char *, char *, DWORD, mlsvc_handle_t *);
-int samr_close_handle(mlsvc_handle_t *);
+DWORD samr_open(char *, char *, char *, DWORD, mlsvc_handle_t *);
+DWORD samr_connect(char *, char *, char *, DWORD, mlsvc_handle_t *);
+void samr_close_handle(mlsvc_handle_t *);
DWORD samr_open_domain(mlsvc_handle_t *, DWORD, struct samr_sid *,
mlsvc_handle_t *);
DWORD samr_open_user(mlsvc_handle_t *, DWORD, DWORD, mlsvc_handle_t *);
@@ -112,7 +113,7 @@ union samr_user_info {
} info9;
struct info16 {
- DWORD unknown;
+ DWORD acct_ctrl;
} info16;
};
@@ -120,16 +121,39 @@ union samr_user_info {
smb_sid_t *samr_lookup_domain(mlsvc_handle_t *, char *);
DWORD samr_enum_local_domains(mlsvc_handle_t *);
uint32_t samr_lookup_domain_names(mlsvc_handle_t *, char *, smb_account_t *);
-int samr_query_user_info(mlsvc_handle_t *, WORD, union samr_user_info *);
+DWORD samr_query_user_info(mlsvc_handle_t *, WORD, union samr_user_info *);
DWORD samr_get_user_pwinfo(mlsvc_handle_t *);
-typedef struct oem_password {
- BYTE data[512];
- DWORD length;
-} oem_password_t;
-
-
-int sam_oem_password(oem_password_t *, unsigned char *, unsigned char *);
+DWORD
+samr_change_password(
+ mlsvc_handle_t *handle,
+ char *server,
+ char *account,
+ struct samr_encr_passwd *newpw,
+ struct samr_encr_hash *oldpw);
+
+DWORD
+samr_set_user_info(
+ mlsvc_handle_t *user_handle,
+ int info_level,
+ void *info_buf);
+
+DWORD
+netr_set_user_control(
+ mlsvc_handle_t *user_handle,
+ DWORD UserAccountControl);
+
+DWORD
+netr_set_user_password(
+ mlsvc_handle_t *user_handle,
+ char *new_pw_clear);
+
+DWORD
+netr_change_password(
+ char *server,
+ char *account,
+ char *old_password,
+ char *new_password);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
index e19d1dfb03..fc2956f226 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -51,8 +52,6 @@
#include <smbsrv/smb_sid.h>
#include <samlib.h>
-/*LINTED E_STATIC_UNUSED*/
-static DWORD samr_connect1(char *, char *, char *, DWORD, mlsvc_handle_t *);
static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *);
@@ -62,9 +61,6 @@ typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD,
static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
union samr_user_info *);
-static void samr_set_user_unknowns(struct samr_SetUserInfo23 *);
-static void samr_set_user_logon_hours(struct samr_SetUserInfo *);
-static int samr_set_user_password(unsigned char *, BYTE *);
/*
* samr_open
@@ -78,17 +74,16 @@ static int samr_set_user_password(unsigned char *, BYTE *);
*
* On success 0 is returned. Otherwise a -ve error code.
*/
-int
+DWORD
samr_open(char *server, char *domain, char *username, DWORD access_mask,
mlsvc_handle_t *samr_handle)
{
smb_domainex_t di;
- int rc;
+ DWORD status;
if (server == NULL || domain == NULL) {
if (!smb_domain_getinfo(&di))
- return (-1);
-
+ return (NT_STATUS_INTERNAL_ERROR);
server = di.d_dc;
domain = di.d_primary.di_nbname;
}
@@ -96,8 +91,10 @@ samr_open(char *server, char *domain, char *username, DWORD access_mask,
if (username == NULL)
username = MLSVC_ANON_USER;
- rc = samr_connect(server, domain, username, access_mask, samr_handle);
- return (rc);
+ status = samr_connect(server, domain, username, access_mask,
+ samr_handle);
+
+ return (status);
}
@@ -116,7 +113,7 @@ samr_open(char *server, char *domain, char *username, DWORD access_mask,
* something other than an RPC protocol error. We don't use the original
* connect call because all supported servers should support SamrConnect2.
*/
-int
+DWORD
samr_connect(char *server, char *domain, char *username, DWORD access_mask,
mlsvc_handle_t *samr_handle)
{
@@ -130,60 +127,19 @@ samr_connect(char *server, char *domain, char *username, DWORD access_mask,
DWORD status;
int i;
- if (ndr_rpc_bind(samr_handle, server, domain, username, "SAMR") < 0)
- return (-1);
+ status = ndr_rpc_bind(samr_handle, server, domain, username, "SAMR");
+ if (status)
+ return (status);
for (i = 0; i < n_op; ++i) {
status = (*samr_connop[i])(server, domain, username,
access_mask, samr_handle);
if (status == NT_STATUS_SUCCESS)
- return (0);
+ return (status);
}
ndr_rpc_unbind(samr_handle);
- return (-1);
-}
-
-/*
- * samr_connect1
- *
- * Original SAMR connect call; probably used on Windows NT 3.51.
- * Windows 95 uses this call with the srvmgr tools update.
- * Servername appears to be a dword rather than a string.
- * The first word contains '\' and the second word contains 0x001,
- * (which is probably uninitialized junk: 0x0001005c.
- */
-/*ARGSUSED*/
-static DWORD
-samr_connect1(char *server, char *domain, char *username, DWORD access_mask,
- mlsvc_handle_t *samr_handle)
-{
- struct samr_Connect arg;
- int opnum;
- DWORD status;
-
- bzero(&arg, sizeof (struct samr_Connect));
- opnum = SAMR_OPNUM_Connect;
- status = NT_STATUS_SUCCESS;
-
- arg.servername = ndr_rpc_malloc(samr_handle, sizeof (DWORD));
- *(arg.servername) = 0x0001005c;
- arg.access_mask = access_mask;
-
- if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
- status = NT_STATUS_UNSUCCESSFUL;
- } else if (arg.status != 0) {
- status = NT_SC_VALUE(arg.status);
- } else {
- (void) memcpy(&samr_handle->handle, &arg.handle,
- sizeof (ndr_hdid_t));
-
- if (ndr_is_null_handle(samr_handle))
- status = NT_STATUS_INVALID_HANDLE;
- }
-
- ndr_rpc_release(samr_handle);
return (status);
}
@@ -293,23 +249,14 @@ samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
int len;
int opnum;
DWORD status;
- smb_domainex_t dinfo;
bzero(&arg, sizeof (struct samr_Connect5));
opnum = SAMR_OPNUM_Connect5;
status = NT_STATUS_SUCCESS;
- if (!smb_domain_getinfo(&dinfo))
- return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
-
- len = strlen(server) + strlen(dinfo.d_primary.di_fqname) + 4;
+ len = strlen(server) + 4;
arg.servername = ndr_rpc_malloc(samr_handle, len);
-
- if (*dinfo.d_primary.di_fqname != '\0')
- (void) snprintf((char *)arg.servername, len, "\\\\%s.%s",
- server, dinfo.d_primary.di_fqname);
- else
- (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
arg.unknown2_00000001 = 0x00000001;
@@ -342,14 +289,14 @@ samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
* If the handle being closed is the top level connect handle, we unbind.
* Then we zero out the handle to invalidate it.
*/
-int
+void
samr_close_handle(mlsvc_handle_t *samr_handle)
{
struct samr_CloseHandle arg;
int opnum;
if (ndr_is_null_handle(samr_handle))
- return (-1);
+ return;
opnum = SAMR_OPNUM_CloseHandle;
bzero(&arg, sizeof (struct samr_CloseHandle));
@@ -362,7 +309,6 @@ samr_close_handle(mlsvc_handle_t *samr_handle)
ndr_rpc_unbind(samr_handle);
bzero(samr_handle, sizeof (mlsvc_handle_t));
- return (0);
}
/*
@@ -591,8 +537,8 @@ samr_create_user(mlsvc_handle_t *domain_handle, char *username,
status = NT_SC_VALUE(arg.status);
if (status != NT_STATUS_USER_EXISTS) {
- smb_tracef("SamrCreateUser[%s]: %s", username,
- xlate_nt_status(status));
+ smb_tracef("SamrCreateUser[%s]: %s",
+ username, xlate_nt_status(status));
}
} else {
ndr_inherit_handle(user_handle, domain_handle);
@@ -637,8 +583,7 @@ samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name)
sizeof (samr_handle_t));
length = smb_wcequiv_strlen(domain_name);
- if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000)
- length += sizeof (smb_wchar_t);
+ length += sizeof (smb_wchar_t);
arg.domain_name.length = length;
arg.domain_name.allosize = length;
@@ -727,8 +672,7 @@ samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
arg.total = 1;
length = smb_wcequiv_strlen(name);
- if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000)
- length += sizeof (smb_wchar_t);
+ length += sizeof (smb_wchar_t);
arg.name.length = length;
arg.name.allosize = length;
@@ -760,18 +704,17 @@ samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
* Query information on a specific user. The handle must be a valid
* user handle obtained via samr_open_user.
*
- * Returns 0 on success, otherwise returns -ve error code.
+ * Returns 0 on success, otherwise returns NT status code.
*/
-int
+DWORD
samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
union samr_user_info *user_info)
{
struct samr_QueryUserInfo arg;
int opnum;
- int rc;
if (ndr_is_null_handle(user_handle) || user_info == 0)
- return (-1);
+ return (NT_STATUS_INTERNAL_ERROR);
opnum = SAMR_OPNUM_QueryUserInfo;
bzero(&arg, sizeof (struct samr_QueryUserInfo));
@@ -780,18 +723,13 @@ samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
sizeof (samr_handle_t));
arg.switch_value = switch_value;
- if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
- ndr_rpc_release(user_handle);
- return (-1);
- }
+ if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
+ arg.status = RPC_NT_CALL_FAILED;
- if (arg.status != 0)
- rc = -1;
- else
- rc = samr_setup_user_info(switch_value, &arg, user_info);
+ if (arg.status == 0)
+ (void) samr_setup_user_info(switch_value, &arg, user_info);
- ndr_rpc_release(user_handle);
- return (rc);
+ return (arg.status);
}
/*
@@ -846,6 +784,8 @@ samr_setup_user_info(WORD switch_value,
return (0);
case 16:
+ user_info->info16.acct_ctrl =
+ arg->ru.info16.UserAccountControl;
return (0);
default:
@@ -945,6 +885,10 @@ samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
return (status);
}
+DECL_FIXUP_STRUCT(samr_SetUserInfo_u);
+DECL_FIXUP_STRUCT(samr_SetUserInfo_s);
+DECL_FIXUP_STRUCT(samr_SetUserInfo);
+
/*
* samr_set_user_info
*
@@ -952,138 +896,129 @@ samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
* NT status codes observed so far:
* NT_STATUS_WRONG_PASSWORD
*/
-/*ARGSUSED*/
DWORD
-samr_set_user_info(mlsvc_handle_t *user_handle)
+samr_set_user_info(
+ mlsvc_handle_t *user_handle,
+ int info_level,
+ void *info_buf)
{
- unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ];
struct samr_SetUserInfo arg;
+ uint16_t usize, tsize;
int opnum;
- DWORD status = 0;
if (ndr_is_null_handle(user_handle))
- return (NT_STATUS_INVALID_PARAMETER);
+ return (NT_STATUS_INTERNAL_ERROR);
- if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key)))
- return (NT_STATUS_INVALID_PARAMETER);
+ /*
+ * Only support a few levels
+ * MS-SAMR: UserInternal4Information
+ */
+ switch (info_level) {
+ case 16: /* samr_SetUserInfo16 */
+ usize = sizeof (struct samr_SetUserInfo16);
+ break;
+ case 21: /* samr_SetUserInfo21 */
+ usize = sizeof (struct samr_SetUserInfo21);
+ break;
+ case 23: /* samr_SetUserInfo23 */
+ usize = sizeof (struct samr_SetUserInfo23);
+ break;
+ case 24: /* samr_SetUserInfo24 */
+ usize = sizeof (struct samr_SetUserInfo24);
+ break;
+ default:
+ return (NT_STATUS_INVALID_LEVEL);
+ }
+
+ /*
+ * OK, now this gets really ugly, because
+ * ndrgen doesn't do unions correctly.
+ */
+ FIXUP_PDU_SIZE(samr_SetUserInfo_u, usize);
+ tsize = usize + (2 * sizeof (WORD));
+ FIXUP_PDU_SIZE(samr_SetUserInfo_s, tsize);
+ tsize += sizeof (ndr_request_hdr_t) + sizeof (DWORD);
+ FIXUP_PDU_SIZE(samr_SetUserInfo, tsize);
opnum = SAMR_OPNUM_SetUserInfo;
- bzero(&arg, sizeof (struct samr_SetUserInfo));
+ bzero(&arg, sizeof (arg));
(void) memcpy(&arg.user_handle, &user_handle->handle,
sizeof (samr_handle_t));
+ arg.info.info_level = info_level;
+ arg.info.switch_value = info_level;
+ (void) memcpy(&arg.info.ru, info_buf, usize);
- arg.info.index = SAMR_SET_USER_INFO_23;
- arg.info.switch_value = SAMR_SET_USER_INFO_23;
-
- samr_set_user_unknowns(&arg.info.ru.info23);
- samr_set_user_logon_hours(&arg);
-
- if (samr_set_user_password(ssn_key, arg.info.ru.info23.password) < 0)
- status = NT_STATUS_INTERNAL_ERROR;
-
- if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
- status = NT_STATUS_INVALID_PARAMETER;
- } else if (arg.status != 0) {
+ if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
+ arg.status = RPC_NT_CALL_FAILED;
+ else if (arg.status != 0)
ndr_rpc_status(user_handle, opnum, arg.status);
- status = NT_SC_VALUE(arg.status);
- }
ndr_rpc_release(user_handle);
- return (status);
-}
-
-static void
-samr_set_user_unknowns(struct samr_SetUserInfo23 *info)
-{
- bzero(info, sizeof (struct samr_SetUserInfo23));
-
- info->sd.length = 0;
- info->sd.data = 0;
- info->user_rid = 0;
- info->group_rid = DOMAIN_GROUP_RID_USERS;
-
- /*
- * The trust account value used here should probably
- * match the one used to create the trust account.
- */
- info->acct_info = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
- info->flags = 0x09F827FA;
+ return (arg.status);
}
/*
- * samr_set_user_logon_hours
- *
- * SamrSetUserInfo appears to contain some logon hours information, which
- * looks like a varying, conformant array. The top level contains a value
- * (units), which probably indicates the how to interpret the array. The
- * array definition looks like it contains a maximum size, an initial
- * offset and a bit length (units/8), followed by the bitmap.
- *
- * (info)
- * +-------+
- * | units |
- * +-------+ (hours)
- * | hours |-->+-----------+
- * +-------+ | max_is |
- * +-----------+
- * | first_is |
- * +-----------+
- * | length_is |
- * +------------------------+
- * | bitmap[length_is] |
- * +---------+--------------+
- *
- * 10080 minutes/week => 10080/8 = 1260 (0x04EC) bytes.
- * 168 hours/week => 168/8 = 21 (0xA8) bytes.
- * In the netmon examples seen so far, all bits are set to 1, i.e.
- * an array containing 0xff. This is probably the default setting.
- *
- * ndrgen has a problem with complex [size_is] statements (length/8).
- * So, for now, we fake it using two separate components.
+ * Client side wrapper for SamrUnicodeChangePasswordUser2
+ * [MS-SAMR 3.1.5.10.3]
*/
-static void
-samr_set_user_logon_hours(struct samr_SetUserInfo *sui)
-{
- sui->logon_hours.size = SAMR_HOURS_MAX_SIZE;
- sui->logon_hours.first = 0;
- sui->logon_hours.length = SAMR_SET_USER_HOURS_SZ;
- (void) memset(sui->logon_hours.bitmap, 0xFF, SAMR_SET_USER_HOURS_SZ);
-
- sui->info.ru.info23.logon_info.units = SAMR_HOURS_PER_WEEK;
- sui->info.ru.info23.logon_info.hours =
- (DWORD)(uintptr_t)sui->logon_hours.bitmap;
-}
-/*
- * 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)
+DWORD
+samr_change_password(
+ mlsvc_handle_t *handle,
+ char *server,
+ char *account,
+ struct samr_encr_passwd *newpw,
+ struct samr_encr_hash *oldpw)
{
- char hostname[NETBIOS_NAME_SZ];
+ static struct samr_encr_passwd zero_newpw;
+ static struct samr_encr_hash zero_oldpw;
+ struct samr_ChangePasswordUser2 arg;
+ int opnum = SAMR_OPNUM_ChangePasswordUser2;
+ char *slashserver;
+ int len;
- randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ);
+ (void) memset(&arg, 0, sizeof (arg));
- /*
- * 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);
+ /* Need server name with slashes */
+ len = 2 + strlen(server) + 1;
+ slashserver = ndr_rpc_malloc(handle, len);
+ if (slashserver == NULL)
+ return (NT_STATUS_NO_MEMORY);
+ (void) snprintf(slashserver, len, "\\\\%s", server);
- (void) smb_strlwr(hostname);
+ arg.servername = ndr_rpc_malloc(handle, sizeof (samr_string_t));
+ if (arg.servername == NULL)
+ return (NT_STATUS_NO_MEMORY);
+ len = smb_wcequiv_strlen(slashserver);
+ if (len < 1)
+ return (NT_STATUS_INVALID_PARAMETER);
+ len += 2; /* the WC null */
+ arg.servername->length = len;
+ arg.servername->allosize = len;
+ arg.servername->str = (uint8_t *)slashserver;
+
+ arg.username = ndr_rpc_malloc(handle, sizeof (samr_string_t));
+ if (arg.username == NULL)
+ return (NT_STATUS_NO_MEMORY);
+ len = smb_wcequiv_strlen(account);
+ if (len < 1)
+ return (NT_STATUS_INVALID_PARAMETER);
+ len += 2; /* the WC null */
+ arg.username->length = len;
+ arg.username->allosize = len;
+ arg.username->str = (uint8_t *)account;
- /*
- * 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);
+ arg.nt_newpw = newpw;
+ arg.nt_oldpw = oldpw;
+
+ arg.lm_newpw = &zero_newpw;
+ arg.lm_oldpw = &zero_oldpw;
+
+ if (ndr_rpc_call(handle, opnum, &arg) != 0)
+ arg.status = RPC_NT_CALL_FAILED;
+ else if (arg.status != 0)
+ ndr_rpc_status(handle, opnum, arg.status);
+
+ ndr_rpc_release(handle);
+ return (arg.status);
}
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c
index a057e922b7..8e0753c0e3 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -1141,15 +1142,15 @@ samr_s_CreateUser(void *arg, ndr_xa_t *mxa)
}
/*
- * samr_s_ChangeUserPasswd
+ * samr_s_ChangePasswordUser2
*/
/*ARGSUSED*/
static int
-samr_s_ChangeUserPasswd(void *arg, ndr_xa_t *mxa)
+samr_s_ChangePasswordUser2(void *arg, ndr_xa_t *mxa)
{
- struct samr_ChangeUserPasswd *param = arg;
+ struct samr_ChangePasswordUser2 *param = arg;
- bzero(param, sizeof (struct samr_ChangeUserPasswd));
+ bzero(param, sizeof (*param));
param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
return (NDR_DRC_OK);
}
@@ -1860,7 +1861,7 @@ static ndr_stub_table_t samr_stub_table[] = {
{ samr_s_Connect2, SAMR_OPNUM_Connect2 },
{ samr_s_GetUserPwInfo, SAMR_OPNUM_GetUserPwInfo },
{ samr_s_CreateUser, SAMR_OPNUM_CreateUser },
- { samr_s_ChangeUserPasswd, SAMR_OPNUM_ChangeUserPasswd },
+ { samr_s_ChangePasswordUser2, SAMR_OPNUM_ChangePasswordUser2 },
{ samr_s_GetDomainPwInfo, SAMR_OPNUM_GetDomainPwInfo },
{ samr_s_SetUserInfo, SAMR_OPNUM_SetUserInfo },
{ samr_s_Connect4, SAMR_OPNUM_Connect4 },
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c b/usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c
index 746acdf413..ab127b6150 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smbrdr_glue.c
@@ -20,8 +20,8 @@
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
*/
/*
@@ -44,6 +44,12 @@
#include <assert.h>
+void
+smbrdr_initialize(void)
+{
+ (void) smb_lib_init();
+}
+
/*
* mlsvc_disconnect
*
@@ -79,11 +85,9 @@ smbrdr_logon(char *srv, char *dom, char *user)
int err;
err = smbrdr_ctx_new(&ctx, srv, dom, user);
- if (err) {
- return (-1);
- }
- smb_ctx_free(ctx);
- return (AUTH_USER_GRANT);
+ if (err == 0)
+ smb_ctx_free(ctx);
+ return (err);
}
void
@@ -111,12 +115,8 @@ smbrdr_ctx_new(struct smb_ctx **ctx_p, char *server,
assert(domain != NULL);
assert(user != NULL);
- /* Some callers pass this when they want a NULL session. */
- if (strcmp(user, "IPC$") == 0)
- user = "";
-
if ((err = smb_ctx_alloc(&ctx)) != 0)
- return (err);
+ return (NT_STATUS_NO_MEMORY);
/*
* Set server, share, domain, user
@@ -150,12 +150,18 @@ smbrdr_ctx_new(struct smb_ctx **ctx_p, char *server,
* Do lookup, connect, session setup, tree connect.
* Or find and reuse a session/tree, if one exists.
*/
- if ((err = smb_ctx_resolve(ctx)) != 0)
+ if ((err = smb_ctx_resolve(ctx)) != 0) {
+ err = NT_STATUS_BAD_NETWORK_PATH;
goto errout;
- if ((err = smb_ctx_get_ssn(ctx)) != 0)
+ }
+ if ((err = smb_ctx_get_ssn(ctx)) != 0) {
+ err = NT_STATUS_NETWORK_ACCESS_DENIED;
goto errout;
- if ((err = smb_ctx_get_tree(ctx)) != 0)
+ }
+ if ((err = smb_ctx_get_tree(ctx)) != 0) {
+ err = NT_STATUS_BAD_NETWORK_NAME;
goto errout;
+ }
/* Success! */
*ctx_p = ctx;