diff options
Diffstat (limited to 'usr/src/lib')
27 files changed, 951 insertions, 1062 deletions
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 1172abc647..f2dd13f1af 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -2577,7 +2577,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], @@ -2598,35 +2598,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); |
