diff options
author | Gordon Ross <gwr@nexenta.com> | 2012-12-16 22:41:29 -0500 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2014-11-18 14:17:36 -0500 |
commit | 1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f (patch) | |
tree | cbf5612fc6b3f93ddc715d40058879ef005f72de /usr/src | |
parent | 177d5b5f8c0e969013441207a0a705ae66b08cf7 (diff) | |
download | illumos-joyent-1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f.tar.gz |
5316 allow smbadm join to use RPC
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan McDonald <danmcd@nexenta.com>
Reviewed by: Thomas Keiser <thomas.keiser@nexenta.com>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
35 files changed, 1304 insertions, 1513 deletions
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c index 02ae8029cf..b8c2867489 100644 --- a/usr/src/cmd/idmap/idmapd/idmap_config.c +++ b/usr/src/cmd/idmap/idmapd/idmap_config.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 2013 Nexenta Systems, Inc. All rights reserved. */ @@ -1455,6 +1455,11 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, if (rc != 0) (*errors)++; + rc = get_val_bool(handles, "use_ads", + &pgcfg->use_ads, B_TRUE); + if (rc != 0) + (*errors)++; + rc = get_val_bool(handles, "use_lsa", &pgcfg->use_lsa, B_TRUE); if (rc != 0) @@ -1797,6 +1802,12 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) { ad_disc_t ad_ctx = handles->ad_ctx; + if (pgcfg->use_ads == B_FALSE) { + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "ADS disabled."); + return; + } + if (DBG(CONFIG, 1)) idmapdlog(LOG_DEBUG, "Running discovery."); @@ -1916,6 +1927,9 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags) changed += update_bool(&live_pgcfg->eph_map_unres_sids, &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping"); + changed += update_bool(&live_pgcfg->use_ads, + &new_pgcfg.use_ads, "use_ads"); + changed += update_bool(&live_pgcfg->use_lsa, &new_pgcfg.use_lsa, "use_lsa"); diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h index 66e5431031..31ae7b6ad1 100644 --- a/usr/src/cmd/idmap/idmapd/idmap_config.h +++ b/usr/src/cmd/idmap/idmapd/idmap_config.h @@ -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 2013 Nexenta Systems, Inc. All rights reserved. */ #ifndef _IDMAP_CONFIG_H @@ -108,6 +108,7 @@ typedef struct idmap_pg_config { char *nldap_winname_attr; int directory_based_mapping; /* enum */ boolean_t eph_map_unres_sids; + boolean_t use_ads; boolean_t use_lsa; boolean_t disable_cross_forest_trusts; } idmap_pg_config_t; diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c index 43c18b6293..3e5dde7ad8 100644 --- a/usr/src/cmd/idmap/idmapd/init.c +++ b/usr/src/cmd/idmap/idmapd/init.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /* @@ -119,8 +120,12 @@ reload_gcs() int num_trustfor = pgcfg->num_trusted_forests; ad_disc_domainsinforest_t *domain_in_forest; - if (pgcfg->domain_name == NULL) { - /* No domain name specified - workgroup mode. */ + if (pgcfg->use_ads == B_FALSE || + pgcfg->domain_name == NULL) { + /* + * ADS disabled, or no domain name specified. + * Not using adutils. (but still can use lsa) + */ new_gcs = NULL; new_num_gcs = 0; goto out; @@ -248,8 +253,12 @@ reload_dcs(void) int old_num_dcs = _idmapdstate.num_dcs; idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg; - if (pgcfg->domain_name == NULL) { - /* No domain name specified - workgroup mode. */ + if (pgcfg->use_ads == B_FALSE || + pgcfg->domain_name == NULL) { + /* + * ADS disabled, or no domain name specified. + * Not using adutils. (but still can use lsa) + */ new_dcs = NULL; new_num_dcs = 0; goto out; diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c index 7874a71bed..07887fa7a3 100644 --- a/usr/src/cmd/smbsrv/smbadm/smbadm.c +++ b/usr/src/cmd/smbsrv/smbadm/smbadm.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 2012 Nexenta Systems, Inc. All rights reserved. */ /* @@ -229,8 +229,14 @@ smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd) return; case HELP_JOIN: +#if 0 /* Don't document "-p" yet, still needs work (NX 11960) */ + (void) fprintf(fp, gettext("\t%s -p domain\n" + "\t%s -u username domain\n\t%s -w workgroup\n"), + cmd->name, cmd->name, cmd->name); +#else (void) fprintf(fp, gettext("\t%s -u username domain\n" "\t%s -w workgroup\n"), cmd->name, cmd->name); +#endif return; case HELP_LIST: @@ -457,45 +463,25 @@ smbadm_join(int argc, char **argv) uint32_t mode = 0; char option; - while ((option = getopt(argc, argv, "u:w:")) != -1) { + while ((option = getopt(argc, argv, "pu:w")) != -1) { + if (mode != 0) { + (void) fprintf(stderr, gettext( + "join options are mutually exclusive\n")); + smbadm_usage(B_FALSE); + } switch (option) { - case 'w': - if (mode != 0) { - (void) fprintf(stderr, - gettext("-u and -w must only appear " - "once and are mutually exclusive\n")); - smbadm_usage(B_FALSE); - } - - mode = SMB_SECMODE_WORKGRP; - domain = optarg; + case 'p': + mode = SMB_SECMODE_DOMAIN; + /* leave username = NULL */ break; case 'u': - if (mode != 0) { - (void) fprintf(stderr, - gettext("-u and -w must only appear " - "once and are mutually exclusive\n")); - smbadm_usage(B_FALSE); - } - mode = SMB_SECMODE_DOMAIN; username = optarg; + break; - if ((domain = argv[optind]) == NULL) { - /* - * The domain was not specified as a separate - * argument, check for the combination forms. - */ - (void) strlcpy(buf, username, sizeof (buf)); - smbadm_extract_domain(buf, &username, &domain); - } - - if ((username == NULL) || (*username == '\0')) { - (void) fprintf(stderr, - gettext("missing username\n")); - smbadm_usage(B_FALSE); - } + case 'w': + mode = SMB_SECMODE_WORKGRP; break; default: @@ -504,16 +490,28 @@ smbadm_join(int argc, char **argv) } } + if (optind < argc) + domain = argv[optind]; + + if (username != NULL && domain == NULL) { + /* + * The domain was not specified as a separate + * argument, check for the combination forms. + */ + (void) strlcpy(buf, username, sizeof (buf)); + smbadm_extract_domain(buf, &username, &domain); + } + if ((domain == NULL) || (*domain == '\0')) { (void) fprintf(stderr, gettext("missing %s name\n"), (mode == SMB_SECMODE_WORKGRP) ? "workgroup" : "domain"); smbadm_usage(B_FALSE); } - if (mode == SMB_SECMODE_WORKGRP) + if (mode == SMB_SECMODE_WORKGRP) { return (smbadm_join_workgroup(domain)); - else - return (smbadm_join_domain(domain, username)); + } + return (smbadm_join_domain(domain, username)); } /* @@ -582,37 +580,46 @@ smbadm_join_domain(const char *domain, const char *username) if (!smbadm_join_prompt(jdi.domain_name)) return (0); - if ((p = strchr(username, '+')) != NULL) { - ++p; - - len = (int)(p - username); - if (len > sizeof (jdi.domain_name)) - len = sizeof (jdi.domain_name); - - (void) strlcpy(jdi.domain_username, username, len); - (void) strlcpy(jdi.domain_passwd, p, - sizeof (jdi.domain_passwd)); - } else { - (void) strlcpy(jdi.domain_username, username, - sizeof (jdi.domain_username)); - } + /* + * Note: username is null for "unsecure join" + * (join using a pre-created computer account) + * No password either. + */ + if (username != NULL) { + if ((p = strchr(username, '+')) != NULL) { + ++p; - if (smb_name_validate_account(jdi.domain_username) != ERROR_SUCCESS) { - (void) fprintf(stderr, - gettext("username contains invalid characters\n")); - smbadm_usage(B_FALSE); - } + len = (int)(p - username); + if (len > sizeof (jdi.domain_name)) + len = sizeof (jdi.domain_name); - if (*jdi.domain_passwd == '\0') { - prompt = gettext("Enter domain password: "); + (void) strlcpy(jdi.domain_username, username, len); + (void) strlcpy(jdi.domain_passwd, p, + sizeof (jdi.domain_passwd)); + } else { + (void) strlcpy(jdi.domain_username, username, + sizeof (jdi.domain_username)); + } - if ((p = getpassphrase(prompt)) == NULL) { - (void) fprintf(stderr, gettext("missing password\n")); + if (smb_name_validate_account(jdi.domain_username) + != ERROR_SUCCESS) { + (void) fprintf(stderr, + gettext("username contains invalid characters\n")); smbadm_usage(B_FALSE); } - (void) strlcpy(jdi.domain_passwd, p, - sizeof (jdi.domain_passwd)); + if (*jdi.domain_passwd == '\0') { + prompt = gettext("Enter domain password: "); + + if ((p = getpassphrase(prompt)) == NULL) { + (void) fprintf(stderr, gettext( + "missing password\n")); + smbadm_usage(B_FALSE); + } + + (void) strlcpy(jdi.domain_passwd, p, + sizeof (jdi.domain_passwd)); + } } (void) printf(gettext("Joining %s ... this may take a minute ...\n"), @@ -635,6 +642,19 @@ smbadm_join_domain(const char *domain, const char *username) bzero(&jdi, sizeof (jdi)); return (1); + case NT_STATUS_BAD_NETWORK_PATH: + (void) fprintf(stderr, + gettext("failed to resolve domain controller name\n")); + bzero(&jdi, sizeof (jdi)); + return (1); + + case NT_STATUS_NETWORK_ACCESS_DENIED: + case NT_STATUS_BAD_NETWORK_NAME: + (void) fprintf(stderr, + gettext("failed connecting to domain controller\n")); + bzero(&jdi, sizeof (jdi)); + return (1); + default: (void) fprintf(stderr, gettext("failed to join %s: %s\n"), jdi.domain_name, xlate_nt_status(status)); diff --git a/usr/src/cmd/smbsrv/smbd/smbd_join.c b/usr/src/cmd/smbsrv/smbd/smbd_join.c index 54fcaccfbb..74d5fac9be 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_join.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c @@ -21,6 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include <syslog.h> @@ -48,8 +49,7 @@ static cond_t smbd_dc_cv; static void *smbd_dc_monitor(void *); static void smbd_dc_update(void); -static boolean_t smbd_set_netlogon_cred(void); -static int smbd_get_kpasswd_srv(char *, size_t); +/* Todo: static boolean_t smbd_set_netlogon_cred(void); */ static uint32_t smbd_join_workgroup(smb_joininfo_t *); static uint32_t smbd_join_domain(smb_joininfo_t *); @@ -164,8 +164,8 @@ smbd_dc_update(void) { char domain[MAXHOSTNAMELEN]; smb_domainex_t info; - smb_domain_t *primary; - + smb_domain_t *di; + DWORD status; if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0) { (void) smb_getdomainname(domain, MAXHOSTNAMELEN); @@ -175,26 +175,24 @@ smbd_dc_update(void) if (!smb_locate_dc(domain, "", &info)) { smb_log(smbd.s_loghd, LOG_NOTICE, "smbd_dc_update: %s: locate failed", domain); - } else { - primary = &info.d_primary; + return; + } - smb_config_setdomaininfo(primary->di_nbname, - primary->di_fqname, - primary->di_sid, - primary->di_u.di_dns.ddi_forest, - primary->di_u.di_dns.ddi_guid); + di = &info.d_primary; + smb_log(smbd.s_loghd, LOG_NOTICE, + "smbd_dc_update: %s: located %s", domain, info.d_dc); - smb_log(smbd.s_loghd, LOG_NOTICE, - "smbd_dc_update: %s: located %s", domain, info.d_dc); - } + status = mlsvc_netlogon(info.d_dc, di->di_nbname); + if (status != NT_STATUS_SUCCESS) { + syslog(LOG_NOTICE, + "failed to establish NETLOGON credential chain"); - if (smbd_set_netlogon_cred()) { /* * Restart required because the domain changed * or the credential chain setup failed. */ smb_log(smbd.s_loghd, LOG_NOTICE, - "smbd_dc_update: %s: smb/server restart required"); + "smbd_dc_update: smb/server restart required"); if (smb_smf_restart_service() != 0) smb_log(smbd.s_loghd, LOG_ERR, @@ -225,148 +223,6 @@ smbd_join(smb_joininfo_t *info) return (status); } -/* - * smbd_set_netlogon_cred - * - * If the system is joined to an AD domain via kclient, SMB daemon will need - * to establish the NETLOGON credential chain. - * - * Since the kclient has updated the machine password stored in SMF - * repository, the cached ipc_info must be updated accordingly by calling - * smb_ipc_commit. - * - * Due to potential replication delays in a multiple DC environment, the - * NETLOGON rpc request must be sent to the DC, to which the KPASSWD request - * is sent. If the DC discovered by the SMB daemon is different than the - * kpasswd server, the current connection with the DC will be torn down - * and a DC discovery process will be triggered to locate the kpasswd - * server. - * - * If joining a new domain, the domain_name property must be set after a - * successful credential chain setup. - */ -static boolean_t -smbd_set_netlogon_cred(void) -{ - char kpasswd_srv[MAXHOSTNAMELEN]; - char kpasswd_domain[MAXHOSTNAMELEN]; - char sam_acct[SMB_SAMACCT_MAXLEN]; - char ipc_usr[SMB_USERNAME_MAXLEN]; - char *dom; - boolean_t new_domain = B_FALSE; - smb_domainex_t dxi; - smb_domain_t *di; - - if (smb_match_netlogon_seqnum()) - return (B_FALSE); - - (void) smb_config_getstr(SMB_CI_KPASSWD_SRV, kpasswd_srv, - sizeof (kpasswd_srv)); - - if (*kpasswd_srv == '\0') - return (B_FALSE); - - /* - * If the domain join initiated by smbadm join CLI is in - * progress, don't do anything. - */ - (void) smb_getsamaccount(sam_acct, sizeof (sam_acct)); - smb_ipc_get_user(ipc_usr, SMB_USERNAME_MAXLEN); - if (smb_strcasecmp(ipc_usr, sam_acct, 0)) - return (B_FALSE); - - di = &dxi.d_primary; - if (!smb_domain_getinfo(&dxi)) - (void) smb_getfqdomainname(di->di_fqname, MAXHOSTNAMELEN); - - (void) smb_config_getstr(SMB_CI_KPASSWD_DOMAIN, kpasswd_domain, - sizeof (kpasswd_domain)); - - if (*kpasswd_domain != '\0' && - smb_strcasecmp(kpasswd_domain, di->di_fqname, 0)) { - dom = kpasswd_domain; - new_domain = B_TRUE; - } else { - dom = di->di_fqname; - } - - /* - * DC discovery will be triggered if the domain info is not - * currently cached or the SMB daemon has previously discovered a DC - * that is different than the kpasswd server. - */ - if (new_domain || smb_strcasecmp(dxi.d_dc, kpasswd_srv, 0) != 0) { - if (*dxi.d_dc != '\0') - mlsvc_disconnect(dxi.d_dc); - - if (!smb_locate_dc(dom, kpasswd_srv, &dxi)) { - if (!smb_locate_dc(di->di_fqname, "", &dxi)) { - smb_ipc_commit(); - return (B_FALSE); - } - } - } - - smb_ipc_commit(); - if (mlsvc_netlogon(dxi.d_dc, di->di_nbname)) { - syslog(LOG_NOTICE, - "failed to establish NETLOGON credential chain"); - return (B_TRUE); - } else { - if (new_domain) { - smb_config_setdomaininfo(di->di_nbname, di->di_fqname, - di->di_sid, - di->di_u.di_dns.ddi_forest, - di->di_u.di_dns.ddi_guid); - (void) smb_config_setstr(SMB_CI_KPASSWD_DOMAIN, ""); - } - } - - return (new_domain); -} - -/* - * Retrieve the kpasswd server from krb5.conf. - * - * Initialization of the locate dc thread. - * Returns 0 on success, an error number if thread creation fails. - */ -static int -smbd_get_kpasswd_srv(char *srv, size_t len) -{ - FILE *fp; - static char buf[512]; - char *p; - - *srv = '\0'; - p = getenv("KRB5_CONFIG"); - if (p == NULL || *p == '\0') - p = "/etc/krb5/krb5.conf"; - - if ((fp = fopen(p, "r")) == NULL) - return (-1); - - while (fgets(buf, sizeof (buf), fp)) { - - /* Weed out any comment text */ - (void) trim_whitespace(buf); - if (*buf == '#') - continue; - - if ((p = strstr(buf, "kpasswd_server")) != NULL) { - if ((p = strchr(p, '=')) != NULL) { - (void) trim_whitespace(++p); - (void) strlcpy(srv, p, len); - } - break; - } - } - - - (void) fclose(fp); - return ((*srv == '\0') ? -1 : 0); -} - static uint32_t smbd_join_workgroup(smb_joininfo_t *info) { @@ -387,11 +243,10 @@ smbd_join_workgroup(smb_joininfo_t *info) static uint32_t smbd_join_domain(smb_joininfo_t *info) { - uint32_t status; - unsigned char passwd_hash[SMBAUTH_HASH_SZ]; - char dc[MAXHOSTNAMELEN]; + static unsigned char zero_hash[SMBAUTH_HASH_SZ]; smb_domainex_t dxi; smb_domain_t *di; + uint32_t status; /* * Ensure that any previous membership of this domain has @@ -399,43 +254,50 @@ smbd_join_domain(smb_joininfo_t *info) * will ensure that we don't attempt a NETLOGON_SAMLOGON * when attempting to find the PDC. */ - (void) smb_config_setbool(SMB_CI_DOMAIN_MEMB, B_FALSE); - if (smb_auth_ntlm_hash(info->domain_passwd, passwd_hash) - != SMBAUTH_SUCCESS) { - syslog(LOG_ERR, "smbd: could not compute ntlm hash for '%s'", - info->domain_username); - return (NT_STATUS_INTERNAL_ERROR); - } + /* Clear DNS local (ADS) lookup cache too. */ + smb_ads_refresh(); - smb_ipc_set(info->domain_username, passwd_hash); + /* + * Use a NULL session while searching for a DC, and + * while getting information about the domain. + */ + smb_ipc_set(MLSVC_ANON_USER, zero_hash); + + if (!smb_locate_dc(info->domain_name, "", &dxi)) { + syslog(LOG_ERR, "smbd: failed locating " + "domain controller for %s", + info->domain_name); + status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + goto errout; + } - (void) smbd_get_kpasswd_srv(dc, sizeof (dc)); /* info->domain_name could either be NetBIOS domain name or FQDN */ - if (smb_locate_dc(info->domain_name, dc, &dxi)) { - status = mlsvc_join(&dxi, info->domain_username, - info->domain_passwd); - - if (status == NT_STATUS_SUCCESS) { - di = &dxi.d_primary; - smbd_set_secmode(SMB_SECMODE_DOMAIN); - smb_config_setdomaininfo(di->di_nbname, di->di_fqname, - di->di_sid, - di->di_u.di_dns.ddi_forest, - di->di_u.di_dns.ddi_guid); - smb_ipc_commit(); - return (status); - } - - smb_ipc_rollback(); + status = mlsvc_join(&dxi, info->domain_username, info->domain_passwd); + if (status != NT_STATUS_SUCCESS) { syslog(LOG_ERR, "smbd: failed joining %s (%s)", info->domain_name, xlate_nt_status(status)); - return (status); + goto errout; } + /* + * Success! + * + * Strange, mlsvc_join does some of the work to + * save the config, then the rest happens here. + * Todo: Do the config update all in one place. + */ + di = &dxi.d_primary; + smbd_set_secmode(SMB_SECMODE_DOMAIN); + smb_config_setdomaininfo(di->di_nbname, di->di_fqname, + di->di_sid, + di->di_u.di_dns.ddi_forest, + di->di_u.di_dns.ddi_guid); + smb_ipc_commit(); + return (status); + +errout: smb_ipc_rollback(); - syslog(LOG_ERR, "smbd: failed locating domain controller for %s", - info->domain_name); - return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND); + return (status); } diff --git a/usr/src/cmd/zfs/zfs_main.c b/usr/src/cmd/zfs/zfs_main.c index 34ddad2c38..109a2cf109 100644 --- a/usr/src/cmd/zfs/zfs_main.c +++ b/usr/src/cmd/zfs/zfs_main.c @@ -63,6 +63,7 @@ #include <libuutil.h> #include <aclutils.h> #include <directory.h> +#include <idmap.h> #include "zfs_iter.h" #include "zfs_util.h" @@ -2372,9 +2373,8 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space) /* SMB */ char sid[ZFS_MAXNAMELEN + 32]; uid_t id; - uint64_t classes; int err; - directory_error_t e; + int flag = IDMAP_REQ_FLG_USE_CACHE; smbentity = B_TRUE; @@ -2391,10 +2391,13 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space) if (err == 0) { rid = id; if (!cb->cb_sid2posix) { - e = directory_name_from_sid(NULL, sid, &name, - &classes); - if (e != NULL) - directory_error_free(e); + if (type == USTYPE_SMB_USR) { + (void) idmap_getwinnamebyuid(rid, flag, + &name, NULL); + } else { + (void) idmap_getwinnamebygid(rid, flag, + &name, NULL); + } if (name == NULL) name = sid; } diff --git a/usr/src/lib/libidmap/common/idmap.h b/usr/src/lib/libidmap/common/idmap.h index 3a3af0d32c..01dce38944 100644 --- a/usr/src/lib/libidmap/common/idmap.h +++ b/usr/src/lib/libidmap/common/idmap.h @@ -113,6 +113,9 @@ extern idmap_stat idmap_getwinnamebyuid(uid_t, int, char **, char **); /* Given GID, get Windows name */ extern idmap_stat idmap_getwinnamebygid(gid_t, int, char **, char **); +/* Given PID, get Windows name */ +extern idmap_stat idmap_getwinnamebypid(uid_t, int, int, char **, char **); + /* Given Windows name, get UID */ extern idmap_stat idmap_getuidbywinname(const char *, const char *, int, uid_t *); diff --git a/usr/src/lib/libidmap/common/idmap_api.c b/usr/src/lib/libidmap/common/idmap_api.c index 36aba7b5f2..315c01a73c 100644 --- a/usr/src/lib/libidmap/common/idmap_api.c +++ b/usr/src/lib/libidmap/common/idmap_api.c @@ -2173,7 +2173,7 @@ idmap_getgidbywinname(const char *name, const char *domain, int flag, /* * Get winname given pid */ -static idmap_retcode +idmap_stat idmap_getwinnamebypid(uid_t pid, int is_user, int flag, char **name, char **domain) { diff --git a/usr/src/lib/libidmap/common/mapfile-vers b/usr/src/lib/libidmap/common/mapfile-vers index fba4b644ef..4a6968ce49 100644 --- a/usr/src/lib/libidmap/common/mapfile-vers +++ b/usr/src/lib/libidmap/common/mapfile-vers @@ -83,6 +83,7 @@ SYMBOL_VERSION SUNWprivate { idmap_getgidbywinname; idmap_getuidbywinname; idmap_getwinnamebygid; + idmap_getwinnamebypid; idmap_getwinnamebyuid; idmap_how_clear; idmap_info_free; diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index 27c3cca8e8..05a2fdc9be 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -2557,7 +2557,7 @@ userquota_propname_decode(const char *propname, boolean_t zoned, boolean_t isuser; domain[0] = '\0'; - + *ridp = 0; /* Figure out the property type ({user|group}{quota|space}) */ for (type = 0; type < ZFS_NUM_USERQUOTA_PROPS; type++) { if (strncmp(propname, zfs_userquota_prop_prefixes[type], @@ -2578,35 +2578,61 @@ userquota_propname_decode(const char *propname, boolean_t zoned, * It's a SID name (eg "user@domain") that needs to be * turned into S-1-domainID-RID. */ - directory_error_t e; + int flag = 0; + idmap_stat stat, map_stat; + uid_t pid; + idmap_rid_t rid; + idmap_get_handle_t *gh = NULL; + + stat = idmap_get_create(&gh); + if (stat != IDMAP_SUCCESS) { + idmap_get_destroy(gh); + return (ENOMEM); + } if (zoned && getzoneid() == GLOBAL_ZONEID) return (ENOENT); if (isuser) { - e = directory_sid_from_user_name(NULL, - cp, &numericsid); + stat = idmap_getuidbywinname(cp, NULL, flag, &pid); + if (stat < 0) + return (ENOENT); + stat = idmap_get_sidbyuid(gh, pid, flag, &numericsid, + &rid, &map_stat); } else { - e = directory_sid_from_group_name(NULL, - cp, &numericsid); + stat = idmap_getgidbywinname(cp, NULL, flag, &pid); + if (stat < 0) + return (ENOENT); + stat = idmap_get_sidbygid(gh, pid, flag, &numericsid, + &rid, &map_stat); + } + if (stat < 0) { + idmap_get_destroy(gh); + return (ENOENT); } - if (e != NULL) { - directory_error_free(e); + stat = idmap_get_mappings(gh); + idmap_get_destroy(gh); + + if (stat < 0) { return (ENOENT); } if (numericsid == NULL) return (ENOENT); cp = numericsid; + *ridp = rid; /* will be further decoded below */ } if (strncmp(cp, "S-1-", 4) == 0) { /* It's a numeric SID (eg "S-1-234-567-89") */ (void) strlcpy(domain, cp, domainlen); - cp = strrchr(domain, '-'); - *cp = '\0'; - cp++; - errno = 0; - *ridp = strtoull(cp, &end, 10); + if (*ridp == 0) { + cp = strrchr(domain, '-'); + *cp = '\0'; + cp++; + *ridp = strtoull(cp, &end, 10); + } else { + end = ""; + } if (numericsid) { free(numericsid); numericsid = NULL; diff --git a/usr/src/lib/pysolaris/common/misc.c b/usr/src/lib/pysolaris/common/misc.c index 923cab445f..da7bb0075f 100644 --- a/usr/src/lib/pysolaris/common/misc.c +++ b/usr/src/lib/pysolaris/common/misc.c @@ -26,6 +26,7 @@ #include <Python.h> #include <zone.h> #include <libintl.h> +#include <idmap.h> #include <directory.h> #ifdef __lint @@ -62,36 +63,32 @@ py_sid_to_id(PyObject *self, PyObject *args) static PyObject * py_sid_to_name(PyObject *self, PyObject *args) { - int isuser; + int isuser, err, flag = IDMAP_REQ_FLG_USE_CACHE; char *name, *sid; - directory_error_t e; - uint64_t classes; + idmap_stat stat; + uid_t pid; PyObject *ret; if (!PyArg_ParseTuple(args, "si", &sid, &isuser)) return (NULL); - e = directory_name_from_sid(NULL, sid, &name, &classes); - if (e != NULL) { - directory_error_free(e); + + err = sid_to_id(sid, isuser, &pid); + if (err) { PyErr_SetString(PyExc_KeyError, sid); return (NULL); } - if (name == NULL) { + if (isuser) + stat = idmap_getwinnamebyuid(pid, flag, &name, NULL); + else + stat = idmap_getwinnamebygid(pid, flag, &name, NULL); + if (stat < 0) { PyErr_SetString(PyExc_KeyError, sid); return (NULL); } - if (isuser) { - if (!(classes & DIRECTORY_CLASS_USER)) { - free(name); - PyErr_SetString(PyExc_KeyError, sid); - return (NULL); - } - } else { - if (!(classes & DIRECTORY_CLASS_GROUP)) { - free(name); - PyErr_SetString(PyExc_KeyError, sid); - return (NULL); - } + + if (name == NULL) { + PyErr_SetString(PyExc_KeyError, sid); + return (NULL); } ret = PyString_FromString(name); 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; diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com index dbf479e106..bc371d4807 100644 --- a/usr/src/lib/smbsrv/libsmb/Makefile.com +++ b/usr/src/lib/smbsrv/libsmb/Makefile.com @@ -20,6 +20,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012 Nexenta Systems, Inc. All rights reserved. # LIBRARY= libsmb.a @@ -76,8 +77,9 @@ INCS += -I$(SRC)/common/smbsrv LINTCHECKFLAGS += -erroff=E_INCONS_ARG_DECL2 LDLIBS += $(MACH_LDLIBS) -LDLIBS += -lscf -lmd -luuid -lnsl -lpkcs11 -lsec -lsocket -lresolv -LDLIBS += -lidmap -lreparse -lnvpair -lcmdutils -lavl -lc +LDLIBS += -lscf -lmd -luuid -lpkcs11 -lcryptoutil +LDLIBS += -lsec -lidmap -lnsl -lsocket -lresolv +LDLIBS += -lreparse -lnvpair -lcmdutils -lavl -lc CPPFLAGS += $(INCS) -D_REENTRANT CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-char-subscripts diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h index 8a11384b61..31a5aeee2f 100644 --- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h @@ -21,7 +21,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. */ #ifndef _LIBSMB_H @@ -189,6 +189,7 @@ extern int smb_config_setstr(smb_cfg_id_t, char *); extern int smb_config_setnum(smb_cfg_id_t, int64_t); extern int smb_config_setbool(smb_cfg_id_t, boolean_t); +extern boolean_t smb_config_get_ads_enable(void); extern uint8_t smb_config_get_fg_flag(void); extern char *smb_config_get_localsid(void); extern int smb_config_secmode_fromstr(char *); @@ -478,6 +479,8 @@ extern int smb_auth_hmac_md5(unsigned char *, int, unsigned char *, int, extern int smb_auth_DES(unsigned char *, int, unsigned char *, int, unsigned char *, int); +extern int smb_auth_RC4(unsigned char *, int, unsigned char *, int, + unsigned char *, int); extern int smb_auth_md4(unsigned char *, unsigned char *, int); extern int smb_auth_lm_hash(const char *, unsigned char *); @@ -497,6 +500,8 @@ boolean_t smb_auth_validate_lm(unsigned char *, uint32_t, smb_passwd_t *, boolean_t smb_auth_validate_nt(unsigned char *, uint32_t, smb_passwd_t *, unsigned char *, int, char *, char *, uchar_t *); +int smb_gen_random_passwd(char *passwd, size_t bufsz); + /* * SMB authenticated IPC */ diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers index 63f2543780..4d2fc95e9b 100644 --- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers @@ -74,6 +74,7 @@ SYMBOL_VERSION SUNWprivate { smb_acl_sort; smb_acl_to_zfs; smb_auth_DES; + smb_auth_RC4; smb_auth_gen_session_key; smb_auth_hmac_md5; smb_auth_ntlm_hash; @@ -97,6 +98,7 @@ SYMBOL_VERSION SUNWprivate { smb_common_decode; smb_common_encode; smb_config_get; + smb_config_get_ads_enable; smb_config_get_execinfo; smb_config_get_fg_flag; smb_config_get_localsid; @@ -175,6 +177,7 @@ SYMBOL_VERSION SUNWprivate { smb_fsacl_free; smb_fssd_init; smb_fssd_term; + smb_gen_random_passwd; smb_get_dcinfo; smb_get_nameservers; smb_get_txid; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c index b53d109ed7..9f4100e805 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c @@ -21,15 +21,14 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #include <strings.h> #include <stdlib.h> #include <smbsrv/string.h> #include <smbsrv/libsmb.h> - -extern void randomize(char *data, unsigned len); -static uint64_t unix_micro_to_nt_time(struct timeval *unix_time); +#include <assert.h> /* * smb_auth_qnd_unicode @@ -145,15 +144,15 @@ int smb_auth_ntlm_hash(const char *password, unsigned char *hash) { smb_wchar_t *unicode_password; - int length; + int length, unicode_len; int rc; if (password == NULL || hash == NULL) return (SMBAUTH_FAILURE); length = strlen(password); - unicode_password = (smb_wchar_t *) - malloc((length + 1) * sizeof (smb_wchar_t)); + unicode_len = (length + 1) * sizeof (smb_wchar_t); + unicode_password = malloc(unicode_len); if (unicode_password == NULL) return (SMBAUTH_FAILURE); @@ -161,7 +160,9 @@ smb_auth_ntlm_hash(const char *password, unsigned char *hash) length = smb_auth_qnd_unicode(unicode_password, password, length); rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length); + (void) memset(unicode_password, 0, unicode_len); free(unicode_password); + return (rc); } @@ -187,91 +188,6 @@ smb_auth_ntlm_response(unsigned char *hash, } /* - * smb_auth_gen_data_blob - * - * Fill the NTLMv2 data blob structure with information as described in - * "Implementing CIFS, The Common Internet File System". (pg. 282) - */ -static void -smb_auth_gen_data_blob(smb_auth_data_blob_t *blob, char *ntdomain) -{ - struct timeval now; - - (void) memset(blob->ndb_signature, 1, 2); - (void) memset(&blob->ndb_signature[2], 0, 2); - (void) memset(blob->ndb_reserved, 0, sizeof (blob->ndb_reserved)); - - (void) gettimeofday(&now, 0); - blob->ndb_timestamp = unix_micro_to_nt_time(&now); - randomize((char *)blob->ndb_clnt_challenge, - SMBAUTH_V2_CLNT_CHALLENGE_SZ); - (void) memset(blob->ndb_unknown, 0, sizeof (blob->ndb_unknown)); - blob->ndb_names[0].nne_len = smb_auth_qnd_unicode( - blob->ndb_names[0].nne_name, ntdomain, strlen(ntdomain)); - blob->ndb_names[0].nne_type = SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS; - blob->ndb_names[1].nne_len = 0; - blob->ndb_names[1].nne_type = SMBAUTH_NAME_TYPE_LIST_END; - *blob->ndb_names[1].nne_name = 0; - (void) memset(blob->ndb_unknown2, 0, sizeof (blob->ndb_unknown2)); -} - -/* - * smb_auth_memcpy - * - * It increments the pointer to the destination buffer for the easy of - * concatenation. - */ -static void -smb_auth_memcpy(unsigned char **dstbuf, - unsigned char *srcbuf, - int srcbuf_len) -{ - (void) memcpy(*dstbuf, srcbuf, srcbuf_len); - *dstbuf += srcbuf_len; -} - -/* - * smb_auth_blob_to_string - * - * Prepare the data blob string which will be used in NTLMv2 response - * generation. - * - * Assumption: Caller must allocate big enough buffer to prevent buffer - * overrun. - * - * Returns the len of the data blob string. - */ -static int -smb_auth_blob_to_string(smb_auth_data_blob_t *blob, unsigned char *data_blob) -{ - unsigned char *bufp = data_blob; - - smb_auth_memcpy(&bufp, blob->ndb_signature, - sizeof (blob->ndb_signature)); - smb_auth_memcpy(&bufp, blob->ndb_reserved, - sizeof (blob->ndb_reserved)); - smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_timestamp, - sizeof (blob->ndb_timestamp)); - smb_auth_memcpy(&bufp, blob->ndb_clnt_challenge, - SMBAUTH_V2_CLNT_CHALLENGE_SZ); - smb_auth_memcpy(&bufp, blob->ndb_unknown, sizeof (blob->ndb_unknown)); - smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_type, - sizeof (blob->ndb_names[0].nne_type)); - smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_len, - sizeof (blob->ndb_names[0].nne_len)); - smb_auth_memcpy(&bufp, (unsigned char *)blob->ndb_names[0].nne_name, - blob->ndb_names[0].nne_len); - smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_type, - sizeof (blob->ndb_names[1].nne_type)); - smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_len, - sizeof (blob->ndb_names[1].nne_len)); - smb_auth_memcpy(&bufp, blob->ndb_unknown2, sizeof (blob->ndb_unknown2)); - - /*LINTED E_PTRDIFF_OVERFLOW*/ - return (bufp - data_blob); -} - -/* * smb_auth_ntlmv2_hash * * The NTLM v2 hash will be created from the given NTLM hash, username, @@ -360,102 +276,6 @@ smb_auth_v2_response( } /* - * smb_auth_set_info - * - * Fill the smb_auth_info instance with either NTLM or NTLMv2 related - * authentication information based on the LMCompatibilityLevel. - * - * If the LMCompatibilityLevel equals 2, the SMB Redirector will perform - * NTLM challenge/response authentication which requires the NTLM hash and - * NTLM response. - * - * If the LMCompatibilityLevel is 3 or above, the SMB Redirector will - * perfrom NTLMv2 challenge/response authenticatoin which requires the - * NTLM hash, NTLMv2 hash, NTLMv2 response and LMv2 response. - * - * Returns -1 on error. Otherwise, returns 0 upon success. - */ -int -smb_auth_set_info(char *username, - char *password, - unsigned char *ntlm_hash, - char *domain, - unsigned char *srv_challenge_key, - int srv_challenge_len, - int lmcomp_lvl, - smb_auth_info_t *auth) -{ - unsigned short blob_len; - unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN]; - int rc; - char *uppercase_dom; - - auth->lmcompatibility_lvl = lmcomp_lvl; - if (lmcomp_lvl == 2) { - auth->ci_len = 0; - *auth->ci = 0; - if (!ntlm_hash) { - if (smb_auth_ntlm_hash(password, auth->hash) != - SMBAUTH_SUCCESS) - return (-1); - } else { - (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ); - } - - auth->cs_len = smb_auth_ntlm_response(auth->hash, - srv_challenge_key, srv_challenge_len, auth->cs); - } else { - if (!ntlm_hash) { - if (smb_auth_ntlm_hash(password, auth->hash) != - SMBAUTH_SUCCESS) - return (-1); - } else { - (void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ); - } - - if (!domain) - return (-1); - - if ((uppercase_dom = strdup(domain)) == NULL) - return (-1); - - (void) smb_strupr(uppercase_dom); - - if (smb_auth_ntlmv2_hash(auth->hash, username, - uppercase_dom, auth->hash_v2) != SMBAUTH_SUCCESS) { - free(uppercase_dom); - return (-1); - } - - /* generate data blob */ - smb_auth_gen_data_blob(&auth->data_blob, uppercase_dom); - free(uppercase_dom); - blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf); - - /* generate NTLMv2 response */ - rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key, - srv_challenge_len, blob_buf, blob_len, auth->cs); - - if (rc < 0) - return (-1); - - auth->cs_len = rc; - - /* generate LMv2 response */ - rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key, - srv_challenge_len, auth->data_blob.ndb_clnt_challenge, - SMBAUTH_V2_CLNT_CHALLENGE_SZ, auth->ci); - - if (rc < 0) - return (-1); - - auth->ci_len = rc; - } - - return (0); -} - -/* * smb_auth_gen_session_key * * Generate the NTLM user session key if LMCompatibilityLevel is 2 or @@ -485,20 +305,6 @@ smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key) return (rc); } -/* 100's of ns between 1/1/1970 and 1/1/1601 */ -#define NT_TIME_BIAS (134774LL * 24LL * 60LL * 60LL * 10000000LL) - -static uint64_t -unix_micro_to_nt_time(struct timeval *unix_time) -{ - uint64_t nt_time; - - nt_time = unix_time->tv_sec; - nt_time *= 10000000; /* seconds to 100ns */ - nt_time += unix_time->tv_usec * 10; - return (nt_time + NT_TIME_BIAS); -} - static boolean_t smb_lm_password_ok( unsigned char *challenge, @@ -754,3 +560,42 @@ smb_auth_validate_nt( return (ok); } + +/* + * smb_gen_random_passwd(buf, len) + * Generate a random password of length len-1, and store it in buf, + * null terminated. This is used as a machine account password, + * which we set when we join a domain. + * + * [MS-DISO] A machine password is an ASCII string of randomly chosen + * characters. Each character's ASCII code is between 32 and 122 inclusive. + * That's space through 'z'. + */ + +int +smb_gen_random_passwd(char *buf, size_t len) +{ + const uchar_t start = ' '; + const uchar_t modulus = 'z' - ' ' + 1; + uchar_t t; + int i; + + /* Last byte is the null. */ + len--; + + /* Temporarily put random data in the caller's buffer. */ + randomize(buf, len); + + /* Convert the random data to printable characters. */ + for (i = 0; i < len; i++) { + /* need unsigned math */ + t = (uchar_t)buf[i]; + t = (t % modulus) + start; + assert(' ' <= t && t <= 'z'); + buf[i] = (char)t; + } + + buf[len] = '\0'; + + return (0); +} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c index 6270ca1af2..b59c582ca7 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c @@ -739,6 +739,32 @@ smb_config_get_fg_flag() } /* + * smb_config_get_ads_enable + * + * Returns value of the "config/use_ads" parameter + * from the IDMAP SMF configuration repository. + * + */ +boolean_t +smb_config_get_ads_enable(void) +{ + smb_scfhandle_t *handle = NULL; + uint8_t vbool; + int rc = 0; + + handle = smb_smf_scf_init(IDMAP_FMRI_PREFIX); + if (handle == NULL) + return (B_FALSE); + + rc = smb_smf_create_service_pgroup(handle, IDMAP_PG_NAME); + if (rc == SMBD_SMF_OK) + rc = smb_smf_get_boolean_property(handle, "use_ads", &vbool); + smb_smf_scf_fini(handle); + + return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_FALSE); +} + +/* * smb_config_get_localsid * * Returns value of the "config/machine_sid" parameter diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c b/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c index c6a95b7b43..7a1fb84709 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_crypt.c @@ -22,10 +22,9 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/md4.h> #include <sys/types.h> #include <string.h> @@ -37,6 +36,29 @@ static void smb_initlmkey(unsigned char *keyin, unsigned char *keyout); /* + * randomize + * + * Randomize the contents of the specified buffer. + */ +void +randomize(char *data, unsigned len) +{ + char *p = data; + + if (pkcs11_get_random(data, len) == 0) + return; + + /* + * Implement a "fall back", because current callers + * don't expect an error from this. In practice, + * we never use this fall back. + */ + while (len--) { + *p++ = (random() >> 24); + } +} + +/* * smb_auth_md4 * * Compute an MD4 digest. @@ -122,13 +144,21 @@ smb_auth_DES(unsigned char *Result, int ResultLen, int K, D; int k, d; - /* Calculate proper number of iterations */ + /* + * Calculate proper number of iterations. + * Known call cases include: + * ResultLen=16, KeyLen=14, DataLen=8 + * ResultLen=24, KeyLen=21, DataLen=8 + * ResultLen=16, KeyLen=14, DataLen=16 + */ K = KeyLen / 7; D = DataLen / 8; - - if (ResultLen < (K * 8 * D)) { - return (SMBAUTH_FAILURE); - } + if ((KeyLen % 7) || (DataLen % 8)) + return (EINVAL); + if (K == 0 || D == 0) + return (EINVAL); + if (ResultLen < (K * 8)) + return (EINVAL); /* * Use SUNW convenience function to initialize the cryptoki @@ -143,7 +173,10 @@ smb_auth_DES(unsigned char *Result, int ResultLen, return (SMBAUTH_FAILURE); } - for (k = 0; k < K; k++) { + for (d = k = 0; k < K; k++, d++) { + /* Cycle the input again, as necessary. */ + if (d == D) + d = 0; smb_initlmkey(&Key[k * 7], des_key); rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism, des_key, 8, &hKey); @@ -157,18 +190,18 @@ smb_auth_DES(unsigned char *Result, int ResultLen, error = 1; goto exit_encrypt; } - ciphertext_len = DataLen; - for (d = 0; d < D; d++) { - /* Read in the data and encrypt this portion */ - rv = C_EncryptUpdate(hSession, - (CK_BYTE_PTR)Data + (d * 8), 8, - &Result[(k * (8 * D)) + (d * 8)], - &ciphertext_len); - if (rv != CKR_OK) { - error = 1; - goto exit_encrypt; - } + ciphertext_len = 8; + + /* Read in the data and encrypt this portion */ + rv = C_EncryptUpdate(hSession, + (CK_BYTE_PTR)Data + (d * 8), 8, + (CK_BYTE_PTR)Result + (k * 8), + &ciphertext_len); + if (rv != CKR_OK) { + error = 1; + goto exit_encrypt; } + (void) C_DestroyObject(hSession, hKey); } goto exit_session; @@ -204,3 +237,56 @@ smb_initlmkey(unsigned char *keyin, unsigned char *keyout) for (i = 0; i < 8; i++) keyout[i] = (keyout[i] << 1) & 0xfe; } + +/* + * CKM_RC4 + */ +int +smb_auth_RC4(uchar_t *Result, int ResultLen, + uchar_t *Key, int KeyLen, + uchar_t *Data, int DataLen) +{ + CK_RV rv; + CK_MECHANISM mechanism; + CK_OBJECT_HANDLE hKey; + CK_SESSION_HANDLE hSession; + CK_ULONG ciphertext_len; + int error = SMBAUTH_FAILURE; + + /* + * Use SUNW convenience function to initialize the cryptoki + * library, and open a session with a slot that supports + * the mechanism we plan on using. + */ + mechanism.mechanism = CKM_RC4; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); + if (rv != CKR_OK) { + return (SMBAUTH_FAILURE); + } + + rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism, + Key, KeyLen, &hKey); + if (rv != CKR_OK) + goto exit_session; + + /* Initialize the encryption operation in the session */ + rv = C_EncryptInit(hSession, &mechanism, hKey); + if (rv != CKR_OK) + goto exit_encrypt; + + ciphertext_len = ResultLen; + rv = C_EncryptUpdate(hSession, + (CK_BYTE_PTR)Data, DataLen, + (CK_BYTE_PTR)Result, &ciphertext_len); + if (rv == CKR_OK) + error = 0; + +exit_encrypt: + (void) C_DestroyObject(hSession, hKey); +exit_session: + (void) C_CloseSession(hSession); + + return (error); +} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c index 3bd80e4425..91bf0a7b00 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.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 <ctype.h> @@ -328,29 +328,6 @@ trim_whitespace(char *buf) } /* - * randomize - * - * Randomize the contents of the specified buffer. - */ -void -randomize(char *data, unsigned len) -{ - unsigned dwlen = len / 4; - unsigned remlen = len % 4; - unsigned tmp; - unsigned i; /*LINTED E_BAD_PTR_CAST_ALIGN*/ - unsigned *p = (unsigned *)data; - - for (i = 0; i < dwlen; ++i) - *p++ = random(); - - if (remlen) { - tmp = random(); - (void) memcpy(p, &tmp, remlen); - } -} - -/* * This is the hash mechanism used to encrypt passwords for commands like * SamrSetUserInformation. It uses a 256 byte s-box. */ diff --git a/usr/src/lib/smbsrv/libsmbns/Makefile.com b/usr/src/lib/smbsrv/libsmbns/Makefile.com index 840d6392c6..d148e11d65 100644 --- a/usr/src/lib/smbsrv/libsmbns/Makefile.com +++ b/usr/src/lib/smbsrv/libsmbns/Makefile.com @@ -48,8 +48,7 @@ SRCS= $(OBJS_COMMON:%.o=$(SRCDIR)/%.c) \ $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c) LDLIBS += $(MACH_LDLIBS) -LDLIBS += -lsmb -lgss -lcmdutils -lldap -lresolv -lnsl -lsocket -LDLIBS += -lc -lcryptoutil +LDLIBS += -lsmb -lgss -lcmdutils -lldap -lresolv -lnsl -lsocket -lc CPPFLAGS += -D_REENTRANT CERRWARN += -_gcc=-Wno-unused-function CERRWARN += -_gcc=-Wno-uninitialized diff --git a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h index ba54279da4..95d16b104e 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h +++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #ifndef _LIBSMBNS_H @@ -89,7 +90,7 @@ extern int smb_ads_lookup_share(smb_ads_handle_t *, const char *, const char *, char *); extern int smb_ads_add_share(smb_ads_handle_t *, const char *, const char *, const char *); -extern smb_adjoin_status_t smb_ads_join(char *, char *, char *, char *, size_t); +extern smb_adjoin_status_t smb_ads_join(char *, char *, char *, char *); extern void smb_ads_join_errmsg(smb_adjoin_status_t); extern boolean_t smb_ads_lookup_msdcs(char *, char *, char *, uint32_t); extern smb_ads_host_info_t *smb_ads_find_host(char *, char *); diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c index 5626d270ab..bcdfb8dbbf 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #include <sys/param.h> @@ -62,13 +63,6 @@ #define SMB_ADS_SHARE_NUM_ATTR 3 #define SMB_ADS_SITE_MAX MAXHOSTNAMELEN -/* - * [MS-DISO] A machine password is an ASCII string of randomly chosen - * characters. Each character's ASCII code is between 32 and 122 inclusive. - */ -#define SMB_ADS_PWD_CHAR_NUM 91 -#define SMB_ADS_PWD_CHAR_START 32 - #define SMB_ADS_MSDCS_SRV_DC_RR "_ldap._tcp.dc._msdcs" #define SMB_ADS_MSDCS_SRV_SITE_RR "_ldap._tcp.%s._sites.dc._msdcs" @@ -209,7 +203,6 @@ static smb_ads_qstat_t smb_ads_lookup_computer_n_attr(smb_ads_handle_t *, smb_ads_avpair_t *, int, char *); static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *); static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *); -static int smb_ads_gen_machine_passwd(char *, size_t); static void smb_ads_free_cached_host(void); static int smb_ads_alloc_attr(LDAPMod **, int); static void smb_ads_free_attr(LDAPMod **); @@ -2145,39 +2138,6 @@ smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn) return (kvno); } -static int -smb_ads_gen_machine_passwd(char *machine_passwd, size_t bufsz) -{ - int i; - size_t pwdlen; - uint8_t *random_bytes; - - errno = 0; - if (machine_passwd == NULL || bufsz == 0) { - errno = EINVAL; - return (-1); - } - - pwdlen = bufsz - 1; - random_bytes = calloc(1, pwdlen); - if (random_bytes == NULL) - return (-1); - - if (pkcs11_get_random(random_bytes, pwdlen) != 0) { - free(random_bytes); - return (-1); - } - - for (i = 0; i < pwdlen; i++) - machine_passwd[i] = (random_bytes[i] % SMB_ADS_PWD_CHAR_NUM) + - SMB_ADS_PWD_CHAR_START; - - machine_passwd[pwdlen] = 0; - bzero(random_bytes, pwdlen); - free(random_bytes); - return (0); -} - /* * smb_ads_join * @@ -2204,8 +2164,7 @@ smb_ads_gen_machine_passwd(char *machine_passwd, size_t bufsz) * principal after the domain join operation. */ smb_adjoin_status_t -smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd, - size_t len) +smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd) { smb_ads_handle_t *ah = NULL; krb5_context ctx = NULL; @@ -2228,13 +2187,6 @@ smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd, return (SMB_ADJOIN_ERR_GET_HANDLE); } - if (smb_ads_gen_machine_passwd(machine_passwd, len) != 0) { - syslog(LOG_NOTICE, "machine password generation: %m"); - smb_ads_close(ah); - smb_ccache_remove(SMB_CCACHE_PATH); - return (SMB_ADJOIN_ERR_GEN_PWD); - } - if ((dclevel = smb_ads_get_dc_level(ah)) == -1) { smb_ads_close(ah); smb_ccache_remove(SMB_CCACHE_PATH); @@ -2294,6 +2246,7 @@ smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd, cnt = spns.s_cnt; smb_krb5_free_pn_set(&spns); + /* New machine_passwd was filled in by our caller. */ if (smb_krb5_setpwd(ctx, ah->domain, machine_passwd) != 0) { rc = SMB_ADJOIN_ERR_KSETPWD; goto adjoin_cleanup; @@ -2360,16 +2313,6 @@ adjoin_cleanup: if (rename(tmpfile, SMBNS_KRB5_KEYTAB) != 0) { (void) unlink(tmpfile); rc = SMB_ADJOIN_ERR_COMMIT_KEYTAB; - } else { - /* Set IDMAP config */ - if (smb_config_set_idmap_domain(ah->domain) != 0) { - rc = SMB_ADJOIN_ERR_IDMAP_SET_DOMAIN; - } else { - - /* Refresh IDMAP service */ - if (smb_config_refresh_idmap() != 0) - rc = SMB_ADJOIN_ERR_IDMAP_REFRESH; - } } } else { (void) unlink(tmpfile); diff --git a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl index 561928440f..de6c19049b 100644 --- a/usr/src/uts/common/smbsrv/ndl/netlogon.ndl +++ b/usr/src/uts/common/smbsrv/ndl/netlogon.ndl @@ -21,6 +21,7 @@ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #ifndef _MLSVC_NETR_NDL_ @@ -57,6 +58,17 @@ #define NETR_OPNUM_DatabaseRedo 0x11 #define NETR_OPNUM_LogonControl2Ex 0x12 #define NETR_OPNUM_TrustDomainList 0x13 +#define NETR_OPNUM_DsrGetDcName 0x14 +#define NETR_OPNUM_LogonGetCapabilities 0x15 +#define NETR_OPNUM_LogonSetServiceBits 0x16 +#define NETR_OPNUM_LogonGetTrustRid 0x17 +#define NETR_OPNUM_LogonComputeServerDigest 0x18 +#define NETR_OPNUM_LogonComputeClientDigest 0x19 +#define NETR_OPNUM_ServerAuthenticate3 0x1A +#define NETR_OPNUM_DsrGetDcNameEx 0x1B +#define NETR_OPNUM_DsrGetSiteName 0x1C +#define NETR_OPNUM_LogonGetDomainInfo 0x1D +#define NETR_OPNUM_ServerPasswordSet2 0x1E struct netr_sid { @@ -134,17 +146,25 @@ struct OLD_LARGE_INTEGER { }; typedef struct OLD_LARGE_INTEGER netr_int64_t; +struct CYPHER_BLOCK { + BYTE data[8]; +}; struct OWF_PASSWORD { BYTE data[16]; }; typedef struct OWF_PASSWORD netr_owf_password_t; - -struct CYPHER_BLOCK { - BYTE data[8]; +/* + * NL_TRUST_PASSWORD + * See also: samr_user_password + */ +#define NETR_TRUST_PWLEN 256 +struct netr_trust_password { + WORD Buffer[NETR_TRUST_PWLEN]; + DWORD Length; }; - +typedef struct netr_trust_password netr_trust_password_t; struct USER_SESSION_KEY { struct CYPHER_BLOCK data[2]; @@ -198,10 +218,21 @@ OPERATION(NETR_OPNUM_ServerPasswordSet) struct netr_PasswordSet { IN LPTSTR servername; IN REFERENCE LPTSTR account_name; - IN WORD account_type; + IN WORD sec_chan_type; + IN REFERENCE LPTSTR hostname; + INOUT struct netr_authenticator auth; + IN netr_owf_password_t owf_password; + OUT DWORD status; +}; + +OPERATION(NETR_OPNUM_ServerPasswordSet2) +struct netr_PasswordSet2 { + IN LPTSTR servername; + IN REFERENCE LPTSTR account_name; + IN WORD sec_chan_type; IN REFERENCE LPTSTR hostname; INOUT struct netr_authenticator auth; - IN netr_owf_password_t uas_new_password; + IN netr_trust_password_t trust_password; OUT DWORD status; }; @@ -398,6 +429,8 @@ union netr_interface { struct netr_SamLogoff SamLogoff; CASE(NETR_OPNUM_ServerPasswordSet) struct netr_PasswordSet PasswordSet; + CASE(NETR_OPNUM_ServerPasswordSet2) + struct netr_PasswordSet2 PasswordSet2; }; typedef union netr_interface netr_interface_t; EXTERNTYPEINFO(netr_interface) diff --git a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl index 5fe7a0f203..2e4a932a5b 100644 --- a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl +++ b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl @@ -18,8 +18,10 @@ * * CDDL HEADER END */ + /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ #ifndef _MLSVC_SAM_NDL_ @@ -89,10 +91,10 @@ #define SAMR_OPNUM_AddMultipleAliasMembers 0x34 #define SAMR_OPNUM_RemoveMultipleAliasMembers 0x35 #define SAMR_OPNUM_ChangeUserOemPassword 0x36 -#define SAMR_OPNUM_ChangeUserPasswd 0x37 /* UnicodePasswd */ +#define SAMR_OPNUM_ChangePasswordUser2 0x37 /* UnicodePasswd */ #define SAMR_OPNUM_GetDomainPwInfo 0x38 #define SAMR_OPNUM_Connect2 0x39 /* SamrConnect2 */ -#define SAMR_OPNUM_SetUserInfo 0x3a +#define SAMR_OPNUM_SetUserInfo 0x3a /* SetInfoUser2 */ #define SAMR_OPNUM_SetBootKeyInformation 0x3b #define SAMR_OPNUM_GetBootKeyInformation 0x3c #define SAMR_OPNUM_Connect3 0x3d /* NotUsedOnWire */ @@ -111,15 +113,6 @@ /* - * UNION_INFO_ENT is intended to simplify adding new entries to a union. - * If the entry structures are named using the form samr_QueryUserInfoX, - * where X is the sitch_value, you can just add a single line. Note - * that you must also update the fixup function in mlsvc_sam.c. - */ -#define UNION_INFO_ENT(N,NAME) CASE(N) struct NAME##N info##N - - -/* * Sam account flags used when creating an account. These flags seem * to be very similar to the USER_INFO_X flags (UF_XXX) in lmaccess.h * but the values are different. @@ -181,6 +174,7 @@ #define SAMR_USER_ALL_PRIVATEDATA 0x04000000 #define SAMR_USER_ALL_PASSWORDEXPIRED 0x08000000 #define SAMR_USER_ALL_SECURITYDESCRIPTOR 0x10000000 +#define SAMR_USER_ALL_OWF_PASSWORD 0x20000000 #define SAMR_USER_ALL_UNDEFINED_MASK 0xC0000000 /* @@ -204,6 +198,7 @@ /* * Definition for a SID. The ndl compiler does not allow a typedef of * a structure containing variable size members. + * Note: cast compatible with smb_sid_t, and code depends on that. */ struct samr_sid { BYTE Revision; @@ -235,6 +230,7 @@ struct samr_sd { typedef struct samr_sd samr_sd_t; /* + * See RPC_STRING in the MS IDL. * Definition for a string. The length and allosize should be set to * twice the string length (i.e. strlen(str) * 2). The runtime code * will perform the appropriate string to a wide-char conversions, @@ -355,9 +351,33 @@ struct samr_logon_hours_all { BYTE *hours; }; -struct samr_oem_password { - BYTE password[512]; - DWORD length; +/* + * SAMPR_USER_PASSWORD (in the MS Net API) or + * struct samr_user_password (internal use) is + * the "clear" form of struct samr_encr_passwd + * (SAMPR_ENCRYPTED_USER_PASSWORD in MS Net). + * It's not used by ndrgen, but is declared here + * to help clarify the relationship between these, + * and for the benefit of our client-side code. + */ +#ifndef NDRGEN +#define SAMR_USER_PWLEN 256 +struct samr_user_password { + smb_wchar_t Buffer[SAMR_USER_PWLEN]; + DWORD Length; +}; +#endif /* NDRGEN */ + +/* SAMPR_ENCRYPTED_USER_PASSWORD */ +#define SAMR_ENCR_PWLEN 516 /* sizeof samr_user_password */ +struct samr_encr_passwd { + BYTE data[SAMR_ENCR_PWLEN]; +}; + +/* ENCRYPTED_NT_OWF_PASSWORD */ +#define SAMR_PWHASH_LEN 16 +struct samr_encr_hash { + BYTE data[SAMR_PWHASH_LEN]; }; /* @@ -437,10 +457,16 @@ OPERATION(SAMR_OPNUM_Connect5) struct samr_Connect5 { IN LPTSTR servername; IN DWORD access_mask; - INOUT DWORD unknown2_00000001; - INOUT DWORD unknown3_00000001; - INOUT DWORD unknown4_00000003; - INOUT DWORD unknown5_00000000; + /* + * This should be a union, but instead this is + * done this way because unions are hard to + * express in this RPC implementation. + */ + INOUT DWORD unknown2_00000001; /* V1 */ + INOUT DWORD unknown3_00000001; /* V1 */ + /* SAMPR_REVISION_INFO_V1 */ + INOUT DWORD unknown4_00000003; /* Revision */ + INOUT DWORD unknown5_00000000; /* SupportedFeatures */ OUT samr_handle_t handle; OUT DWORD status; }; @@ -895,7 +921,7 @@ struct samr_QueryUserInfo9 { struct samr_QueryUserInfo16 { - DWORD unknown; + DWORD UserAccountControl; }; /* @@ -937,6 +963,7 @@ struct samr_QueryUserInfo21 { BYTE PrivateDataSensitive; }; +/* See also: fixup_samr_QueryUserInfo() */ union QueryUserInfo_result_u { UNION_INFO_ENT(1,samr_QueryUserInfo); UNION_INFO_ENT(6,samr_QueryUserInfo); @@ -1204,27 +1231,20 @@ struct samr_CreateUser { /* *********************************************************************** - * ChangeUserPasswd + * ChangePasswordUser2 - See: + * SamrUnicodeChangePasswordUser2 [MS-SAMR 3.1.5.10.3] *********************************************************************** */ -struct samr_newpasswd { - BYTE data[516]; -}; - - -struct samr_oldpasswd { - BYTE data[16]; -}; - -OPERATION(SAMR_OPNUM_ChangeUserPasswd) -struct samr_ChangeUserPasswd { - IN LPTSTR servername; - IN LPTSTR username; - IN struct samr_newpasswd *nt_newpasswd; - IN struct samr_oldpasswd *nt_oldpasswd; - IN struct samr_newpasswd *lm_newpasswd; - IN struct samr_oldpasswd *lm_oldpasswd; +OPERATION(SAMR_OPNUM_ChangePasswordUser2) +struct samr_ChangePasswordUser2 { + IN samr_string_t *servername; + IN REF samr_string_t *username; + IN struct samr_encr_passwd *nt_newpw; + IN struct samr_encr_hash *nt_oldpw; + IN BYTE lm_present; + IN struct samr_encr_passwd *lm_newpw; + IN struct samr_encr_hash *lm_oldpw; OUT DWORD status; }; @@ -1245,172 +1265,112 @@ struct samr_GetDomainPwInfo { /* *********************************************************************** * SetUserInfo - * - * +++ 20 byte user handle and the union switch_value +++ - * 00 00 00 00 77 F2 DD D5 66 48 D4 11 AD 5F D1 CD - * 18 43 7A DF 17 00 17 00 - * - * +++ 14 dwords (56 bytes) of zeros +++ - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 00 00 00 00 - * - * +++ 9 sets of something - 72 bytes +++ - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * 00 00 02 00 D0 04 8A 77 - * - * +++ 9 DWORD zeros +++ - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 - * - * +++ miscellaneous +++ - * 01 02 00 00 - * 80 00 00 00 - * FA 27 F8 09 - * A8 00 00 00 70 F1 14 00 - * 00 00 00 00 00 00 00 00 00 00 00 00 - * - * +++ encrypted password buffer - 512 bytes +++ - * 76 68 E8 AA 23 4F 62 C4 81 4E 30 B8 92 29 66 B9 - * 12 FF 3A 84 82 3A 55 0F C7 18 EA 56 86 50 D7 C5 - * 43 BA 9C F8 32 D4 E0 15 74 A1 6F E1 59 C2 F2 95 - * 53 A9 F2 68 9F 7F 29 B9 88 4C 65 A5 C1 DC 0B 44 - * B8 3C ED 74 D1 6A F7 09 66 97 94 6B 2C 3A A5 88 - * 39 34 C6 FE 24 59 30 2D CF 6D 7F D5 EC B1 9A 84 - * E6 57 96 29 40 32 FB 62 9D 93 E2 BE D8 A3 74 88 - * 8B 85 BC A0 76 D6 C9 DB 8C AF 81 BD 8A F0 08 8D - * 23 B0 52 FD 69 DE EF A1 36 E5 30 19 BD DA 67 A3 - * 81 BD 3F D0 2A A2 8F 60 62 B0 8D 34 9E A4 4F 20 - * 4E 79 93 82 58 A8 E5 6F 7A DC 12 13 33 E6 74 02 - * 4C 32 F9 FC 1A E1 C5 0D E2 CC 36 8D FC 72 87 DD - * 6C 44 E3 6F 4B FD 46 10 08 89 E5 64 B8 27 14 83 - * E7 08 DE CF 69 C7 E1 40 63 DF CB 67 95 73 03 1B - * CA 99 E1 1B 53 2A 89 6B 30 39 CD 5C DF A0 8A 1C - * 4E 50 74 7C 6D 3D E7 EA E9 B2 97 DD 38 7B DA EC - * 1A AD DA CE C4 58 9B 29 F3 6D 30 70 4E 63 6D 84 - * DB DC 5B CD 9A 4E 57 9C E4 65 5D 4F 76 E3 C7 52 - * 8B 3B 20 0A 3B 4C 4B B1 2E 5B 4D AB BA 2F 45 6A - * CA 17 AD 9F C0 B2 07 FB 56 7F E4 3F 9F D4 C6 8C - * A1 05 BF 53 42 1E 67 F4 57 54 E3 2C 38 CF E1 94 - * 75 69 F7 4E 5C 74 CC B3 FD EF 73 3F D5 28 22 EC - * 9B 40 E1 1D 65 44 7C BB 69 88 57 10 05 3A C5 48 - * 8E 4F 77 DB 1A 5C 49 9C D5 06 00 AC 79 BC 7E 89 - * B0 01 66 70 88 A2 E5 DF 96 DC 75 98 10 12 45 02 - * 33 35 6C DF 74 8B 14 2F 26 C6 FD 7A B4 D0 A6 7D - * DE 2B 13 44 EF 34 46 4D 9D 3E C3 75 BC 11 B4 41 - * 27 58 25 1E AF AA F0 BB DA 27 7A 1E AE 81 1A 78 - * 44 19 DE FC C4 7C 4E 32 44 F7 57 2A 41 A2 85 DC - * C0 AD 5D 6B 58 FD 2E 75 25 B9 F2 B6 19 82 E5 0E - * B6 69 0D C1 27 A9 B6 40 A6 50 49 E5 CB 17 98 65 - * 88 18 CA E4 1D 2E 20 F7 DE 8E 7D F2 9D A5 6B CD - * - * D6 79 45 71 - * - * +++ table of 9 things +++ - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * 01 00 00 00 00 00 00 00 00 00 00 00 - * - * +++ miscellaneous +++ - * EC 04 00 00 00 00 00 00 15 00 00 00 - * FF FF FF FF FF FF FF FF FF FF FF FF - * FF FF FF FF FF FF FF FF FF - * + * [MS-SAMR] SamrSetInformationUser2 *********************************************************************** */ -#define SAMR_SET_USER_INFO_23 23 -#define SAMR_SET_USER_DATA_SZ 516 +/* USER_CONTROL_INFORMATION */ +struct samr_SetUserInfo16 { + DWORD UserAccountControl; +}; + + +/* + * samr_SetUserInfo21, a.k.a + * SAMR_USER_ALL_INFORMATION + * + * We now know this is the same as samr_QueryUserInfo21 + * Could merge, except for the samr_vcbuf_t mess. + */ + +#define SAMR_SET_USER_INFO_21 21 + +struct samr_SetUserInfo21 { + samr_quad_t LastLogon; + samr_quad_t LastLogoff; + samr_quad_t PasswordLastSet; + samr_quad_t AccountExpires; + samr_quad_t PasswordCanChange; + samr_quad_t PasswordMustChange; + + samr_vcbuf_t UserName; + samr_vcbuf_t FullName; + samr_vcbuf_t HomeDirectory; + samr_vcbuf_t HomeDirectoryDrive; + samr_vcbuf_t ScriptPath; + samr_vcbuf_t ProfilePath; + samr_vcbuf_t AdminComment; + samr_vcbuf_t WorkStations; + samr_vcbuf_t UserComment; + samr_vcbuf_t Parameters; + + struct samr_short_blob LmOwfPassword; + struct samr_short_blob NtOwfPassword; + samr_vcbuf_t PrivateData; + samr_sd_t SecurityDescriptor; + + DWORD UserId; /* RID */ + DWORD PrimaryGroupId; + DWORD UserAccountControl; + DWORD WhichFields; -struct samr_SetUserInfo23 { - samr_quad_t logon_time; /* 00 00 00 00 00 00 00 00 */ - samr_quad_t logoff_time; /* 00 00 00 00 00 00 00 00 */ - samr_quad_t kickoff_time; /* 00 00 00 00 00 00 00 00 */ - samr_quad_t passwd_last_set_time; /* 00 00 00 00 00 00 00 00 */ - samr_quad_t passwd_can_change_time; /* 00 00 00 00 00 00 00 00 */ - samr_quad_t passwd_must_change_time; /* 00 00 00 00 00 00 00 00 */ - - samr_vcbuf_t user_name; /* 00 00 00 00 00 00 00 00 */ - samr_vcbuf_t full_name; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t home_dir; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t home_drive; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t logon_script; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t profile_path; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t acct_desc; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t workstations; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t unknown1; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t unknown2; /* 00 00 02 00 D0 04 8A 77 */ - samr_vcbuf_t lm_password; /* 00 00 00 00 00 00 00 00 */ - samr_vcbuf_t nt_password; /* 00 00 00 00 00 00 00 00 */ - samr_vcbuf_t unknown3; /* 00 00 00 00 00 00 00 00 */ - - struct samr_sd sd; /* 00 00 00 00 00 00 00 00 */ - DWORD user_rid; /* 00 00 00 00 */ - DWORD group_rid; /* 01 02 00 00 */ - DWORD acct_info; /* 80 00 00 00 */ - DWORD flags; /* FA 27 F8 09 */ - struct samr_logon_info logon_info; /* A8 00 00 00 70 F1 14 00->0xFF */ /* - * The following 12 bytes are encoded in Ethereal as: - * - * WORD bad_pwd_count; - * WORD logon_count; - * - * WORD country; (default 0) - * WORD codepage; - * - * BYTE nt_pwd_set; - * BYTE lm_pwd_set; - * BYTE expired_flag; - * BYTE unknown_char; + * This should be samr_logon_hours_all, but apparently + * ndrgen doesn't get that quite right, so instead, the + * client-side code patches this up. */ - DWORD unknown4_zero; /* 00 00 00 00 */ - DWORD unknown5_zero; /* 00 00 00 00 */ - DWORD unknown6_zero; /* 00 00 00 00 */ - BYTE password[SAMR_SET_USER_DATA_SZ]; + struct samr_logon_info LogonHours; + + WORD BadPasswordCount; + WORD LogonCount; + WORD CountryCode; + WORD CodePage; + BYTE LmPasswordPresent; + BYTE NtPasswordPresent; + BYTE PasswordExpired; + BYTE PrivateDataSensitive; +}; + +/* + * SAMPR_USER_INTERNAL4_INFORMATION + * UserInternal4Information (23) + */ +#define SAMR_SET_USER_INFO_23 23 +struct samr_SetUserInfo23 { + struct samr_SetUserInfo21 info21; + struct samr_encr_passwd encr_pw; +}; + +/* + * SAMPR_USER_INTERNAL5_INFORMATION + * UserInternal5Information (24) + */ +#define SAMR_SET_USER_INFO_24 24 +struct samr_SetUserInfo24 { + struct samr_encr_passwd encr_pw; + BYTE password_expired; }; union samr_SetUserInfo_u { + UNION_INFO_ENT(16,samr_SetUserInfo); + UNION_INFO_ENT(21,samr_SetUserInfo); UNION_INFO_ENT(23,samr_SetUserInfo); - DEFAULT char *nullptr; + UNION_INFO_ENT(24,samr_SetUserInfo); + DEFAULT DWORD nothing; }; - struct samr_SetUserInfo_s { - WORD index; + WORD info_level; WORD switch_value; SWITCH(switch_value) union samr_SetUserInfo_u ru; }; - -/* - IN DWORD unknown_04EC; - IN DWORD unknown_zero; - IN DWORD logon_bitmap_size; - IN BYTE logon_bitmap[SAMR_SET_USER_HOURS_SZ]; -*/ OPERATION(SAMR_OPNUM_SetUserInfo) struct samr_SetUserInfo { IN samr_handle_t user_handle; IN struct samr_SetUserInfo_s info; - IN struct samr_logon_hours logon_hours; OUT DWORD status; }; @@ -1458,8 +1418,8 @@ union samr_interface { struct samr_GetUserPwInfo GetUserPwInfo; CASE(SAMR_OPNUM_CreateUser) struct samr_CreateUser CreateUser; - CASE(SAMR_OPNUM_ChangeUserPasswd) - struct samr_ChangeUserPasswd ChangeUserPasswd; + CASE(SAMR_OPNUM_ChangePasswordUser2) + struct samr_ChangePasswordUser2 ChangePasswordUser2; CASE(SAMR_OPNUM_GetDomainPwInfo) struct samr_GetDomainPwInfo GetDomainPwInfo; CASE(SAMR_OPNUM_Connect2) |