diff options
Diffstat (limited to 'usr/src/lib')
39 files changed, 2147 insertions, 1462 deletions
diff --git a/usr/src/lib/libshare/common/libshare.c b/usr/src/lib/libshare/common/libshare.c index 6af47e38c6..d8989a70ce 100644 --- a/usr/src/lib/libshare/common/libshare.c +++ b/usr/src/lib/libshare/common/libshare.c @@ -727,11 +727,13 @@ sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) } else { char *index; index = get_node_attr((void *)parent, "id"); - if (index != NULL) + if (index != NULL) { len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", index); - else + sa_free_attr_string(index); + } else { len = 0; + } } if (proto != NULL) @@ -1387,7 +1389,6 @@ mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) if (value == NULL) continue; features = sa_proto_get_featureset(value); - sa_free_attr_string(value); if (!(features & flags)) { (void) strlcat(exclude_list, sep, sizeof (exclude_list)); @@ -1395,6 +1396,7 @@ mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) sizeof (exclude_list)); sep = ","; } + sa_free_attr_string(value); } if (exclude_list[0] != '\0') (void) xmlSetProp(share, (xmlChar *)"exclude", @@ -2043,7 +2045,7 @@ get_node_attr(void *nodehdl, char *tag) } /* - * get_node_attr(node, tag) + * set_node_attr(node, tag) * * Set the specified tag(attribute) to the specified value This is * used internally by a number of attribute oriented functions. It @@ -2897,6 +2899,8 @@ sa_create_security(sa_group_t group, char *sectype, char *proto) } } } + if (id != NULL) + sa_free_attr_string(id); if (groupname != NULL) sa_free_attr_string(groupname); return (security); @@ -3109,6 +3113,8 @@ sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, (void) sa_security_name(optionset, oname, sizeof (oname), id); ret = sa_start_transaction(scf_handle, oname); + if (id != NULL) + sa_free_attr_string(id); } if (ret == SA_OK) { switch (type) { diff --git a/usr/src/lib/libshare/common/libshare_zfs.c b/usr/src/lib/libshare/common/libshare_zfs.c index 7e461ba3b7..5adef70b4c 100644 --- a/usr/src/lib/libshare/common/libshare_zfs.c +++ b/usr/src/lib/libshare/common/libshare_zfs.c @@ -990,6 +990,7 @@ add_resources(sa_share_t share, char *opt) newopt = calloc(1, size); if (newopt != NULL) (void) snprintf(newopt, size, "%s,name=%s", opt, name); + sa_free_attr_string(name); free(opt); opt = newopt; propstr = sa_proto_legacy_format("smb", resource, 0); diff --git a/usr/src/lib/libshare/common/libsharecore.c b/usr/src/lib/libshare/common/libsharecore.c index 72d3420e1c..18e5f3c793 100644 --- a/usr/src/lib/libshare/common/libsharecore.c +++ b/usr/src/lib/libshare/common/libsharecore.c @@ -410,7 +410,7 @@ adddfsentry(xfs_sharelist_t *list, sa_share_t share, char *proto) if (item != NULL) { parent = sa_get_parent_group(share); groupname = sa_get_group_attr(parent, "name"); - if (strcmp(groupname, "default") == 0) { + if (groupname != NULL && strcmp(groupname, "default") == 0) { sa_free_attr_string(groupname); groupname = NULL; } @@ -691,11 +691,15 @@ sa_update_legacy(sa_share_t share, char *proto) * set or the type is not "transient". */ if (persist == NULL || strcmp(persist, "transient") != 0) { + path = sa_get_share_attr(share, "path"); + if (path == NULL) { + ret = SA_NO_MEMORY; + goto out; + } dfstab = open_dfstab(SA_LEGACY_DFSTAB); if (dfstab != NULL) { (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); sablocksigs(&old); - path = sa_get_share_attr(share, "path"); (void) lockf(fileno(dfstab), F_LOCK, 0); list = getdfstab(dfstab); rewind(dfstab); @@ -708,7 +712,6 @@ sa_update_legacy(sa_share_t share, char *proto) (void) fsync(fileno(dfstab)); saunblocksigs(&old); (void) fclose(dfstab); - sa_free_attr_string(path); if (list != NULL) dfs_free_list(list); } else { @@ -717,7 +720,9 @@ sa_update_legacy(sa_share_t share, char *proto) else ret = SA_CONFIG_ERR; } + sa_free_attr_string(path); } +out: if (persist != NULL) sa_free_attr_string(persist); return (ret); diff --git a/usr/src/lib/libshare/common/scfutil.c b/usr/src/lib/libshare/common/scfutil.c index f5fabad540..21395d0731 100644 --- a/usr/src/lib/libshare/common/scfutil.c +++ b/usr/src/lib/libshare/common/scfutil.c @@ -20,12 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* helper functions for using libscf with sharemgr */ #include <libscf.h> @@ -1585,7 +1583,7 @@ sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) valstr ? valstr : ""); else (void) snprintf(propstr, strsize, "%s:%s:%s", - idstr ? idstr : "", valstr ? valstr : "", + idstr, valstr ? valstr : "", description ? description : ""); if (scf_value_set_astring(value, propstr) != 0) { ret = SA_SYSTEM_ERR; @@ -1604,16 +1602,29 @@ sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share) free(propstr); } err: - if (valstr != NULL) + if (valstr != NULL) { sa_free_attr_string(valstr); - if (idstr != NULL) + valstr = NULL; + } + if (idstr != NULL) { sa_free_attr_string(idstr); - if (description != NULL) + idstr = NULL; + } + if (description != NULL) { sa_free_share_description(description); + description = NULL; + } } /* the entry is in the transaction */ entry = NULL; + if (valstr != NULL) + sa_free_attr_string(valstr); + if (idstr != NULL) + sa_free_attr_string(idstr); + if (description != NULL) + sa_free_share_description(description); + if (ret == SA_SYSTEM_ERR) { switch (scf_error()) { case SCF_ERROR_PERMISSION_DENIED: diff --git a/usr/src/lib/libshare/nfs/libshare_nfs.c b/usr/src/lib/libshare/nfs/libshare_nfs.c index b71df49804..8007ab2466 100644 --- a/usr/src/lib/libshare/nfs/libshare_nfs.c +++ b/usr/src/lib/libshare/nfs/libshare_nfs.c @@ -1014,7 +1014,8 @@ fill_export_from_optionset(struct exportdata *export, sa_optionset_t optionset) /* have a syntactic error */ (void) printf(dgettext(TEXT_DOMAIN, "NFS: unrecognized option %s=%s\n"), - name, value != NULL ? value : ""); + name != NULL ? name : "", + value != NULL ? value : ""); break; } if (name != NULL) @@ -1841,7 +1842,7 @@ nfs_enable_share(sa_share_t share) prop != NULL && i < num_secinfo; prop = sa_get_next_property(prop), i++) { char *sectype; - sectype = sa_get_property_attr(prop, "type"); + sectype = sa_get_property_attr(prop, "type"); /* * if sectype is NULL, we probably * have a memory problem and can't get @@ -3023,6 +3024,7 @@ nfs_minmax_check(int index, int value) OPT_CMP_GE) { ret = value >= val ? B_TRUE : B_FALSE; } + sa_free_attr_string(pval); } } } diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c index 2b72fe919a..b6c5417c19 100644 --- a/usr/src/lib/libshare/smb/libshare_smb.c +++ b/usr/src/lib/libshare/smb/libshare_smb.c @@ -563,7 +563,8 @@ smb_disable_resource(sa_resource_t resource) if (smb_isonline()) { res = smb_share_delete(rname); - if (res != NERR_Success) { + if (res != NERR_Success && + res != NERR_NetNameNotFound) { sa_free_attr_string(rname); return (SA_CONFIG_ERR); } @@ -1775,8 +1776,9 @@ smb_parse_optstring(sa_group_t group, char *options) "prefix", prefix); } } - name = fix_resource_name((sa_share_t)group, - value, prefix); + if (prefix != NULL) + name = fix_resource_name( + (sa_share_t)group, value, prefix); if (name != NULL) { resource = sa_add_resource( (sa_share_t)group, name, @@ -1981,6 +1983,8 @@ smb_rename_resource(sa_handle_t handle, sa_resource_t resource, char *newname) err = smb_share_rename(oldname, newname); + sa_free_attr_string(oldname); + /* improve error values somewhat */ switch (err) { case NERR_Success: diff --git a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h index f832e1d0cf..cc97e6046e 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h +++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h @@ -457,6 +457,7 @@ typedef struct ndr_client { ndr_binding_t *binding_list; ndr_binding_t binding_pool[NDR_N_BINDING_POOL]; + boolean_t nonull; boolean_t heap_preserved; ndr_heap_t *heap; ndr_stream_t *recv_nds; @@ -470,7 +471,6 @@ typedef struct ndr_handle { ndr_hdid_t nh_id; struct ndr_handle *nh_next; int nh_fid; - int nh_remote_os; const ndr_service_t *nh_svc; ndr_client_t *nh_clnt; void *nh_data; @@ -488,7 +488,7 @@ typedef struct ndr_buf { } ndr_buf_t; /* ndr_ops.c */ -void nds_initialize(ndr_stream_t *, unsigned, int, ndr_heap_t *); +int nds_initialize(ndr_stream_t *, unsigned, int, ndr_heap_t *); void nds_finalize(ndr_stream_t *, ndr_fraglist_t *); void nds_destruct(ndr_stream_t *); void nds_show_state(ndr_stream_t *); diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_marshal.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_marshal.c index abed01bf2f..2c0fc3e478 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_marshal.c +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_marshal.c @@ -138,8 +138,11 @@ ndr_buf_decode(ndr_buf_t *nbuf, unsigned opnum, const char *data, else pdu_size_hint = datalen; - nds_initialize(&nbuf->nb_nds, pdu_size_hint, NDR_MODE_BUF_DECODE, + rc = nds_initialize(&nbuf->nb_nds, pdu_size_hint, NDR_MODE_BUF_DECODE, nbuf->nb_heap); + if (NDR_DRC_IS_FAULT(rc)) + return (rc); + bcopy(data, nbuf->nb_nds.pdu_base_addr, datalen); rc = ndr_decode_hdr_common(&nbuf->nb_nds, &hdr); @@ -147,7 +150,7 @@ ndr_buf_decode(ndr_buf_t *nbuf, unsigned opnum, const char *data, return (rc); if (!NDR_IS_SINGLE_FRAG(hdr.pfc_flags)) - return (rc); + return (NDR_DRC_FAULT_DECODE_FAILED); rc = ndr_encode_decode_common(&nbuf->nb_nds, opnum, nbuf->nb_ti, result); diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c index 2d4573b613..25f43111db 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_ops.c @@ -121,7 +121,7 @@ nds_bswap(void *srcbuf, void *dstbuf, size_t len) * operations and the reference to the heap. An external heap is provided * to the stream, rather than each stream creating its own heap. */ -void +int nds_initialize(ndr_stream_t *nds, unsigned pdu_size_hint, int composite_op, ndr_heap_t *heap) { @@ -133,11 +133,16 @@ nds_initialize(ndr_stream_t *nds, unsigned pdu_size_hint, bzero(nds, sizeof (*nds)); if (pdu_size_hint > NDR_PDU_MAX_SIZE) - return; + return (0); size = (pdu_size_hint == 0) ? NDR_PDU_BLOCK_SIZE : pdu_size_hint; - nds->pdu_base_addr = malloc(size); - assert(nds->pdu_base_addr); + + if ((nds->pdu_base_addr = malloc(size)) == NULL) { + nds->error = NDR_ERR_MALLOC_FAILED; + nds->error_ref = __LINE__; + NDS_TATTLE_ERROR(nds, NULL, NULL); + return (NDR_DRC_FAULT_OUT_OF_MEMORY); + } nds->pdu_max_size = size; nds->pdu_size = 0; @@ -150,6 +155,7 @@ nds_initialize(ndr_stream_t *nds, unsigned pdu_size_hint, nds->dir = NDR_MODE_TO_DIR(composite_op); nds->outer_queue_tailp = &nds->outer_queue_head; + return (0); } void diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c index af76a0a08c..ebc66c0810 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_process.c @@ -1189,8 +1189,11 @@ ndr_outer_string(ndr_ref_t *outer_ref) * size_is is the number of characters in the * (multibyte) string, including the null. */ - size_is = (smb_wcequiv_strlen(valp) / - sizeof (smb_wchar_t)) + 1; + size_is = smb_wcequiv_strlen(valp) / + sizeof (smb_wchar_t); + + if (!(nds->flags & NDS_F_NONULL)) + ++size_is; if (size_is > NDR_STRING_MAX) { NDR_SET_ERROR(outer_ref, NDR_ERR_STRLEN); diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c index 0c2dde8be2..93070966f5 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c @@ -217,6 +217,7 @@ ndr_pipe_transact(ndr_pipe_t *np) ndr_stream_t *send_nds; char *data; int datalen; + int rc; data = np->np_buf; datalen = np->np_uio.uio_offset; @@ -235,7 +236,12 @@ ndr_pipe_transact(ndr_pipe_t *np) } recv_nds = &mxa->recv_nds; - nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap); + rc = nds_initialize(recv_nds, datalen, NDR_MODE_CALL_RECV, mxa->heap); + if (rc != 0) { + ndr_heap_destroy(mxa->heap); + free(mxa); + return (ENOMEM); + } /* * Copy the input data and reset the input stream. @@ -244,7 +250,13 @@ ndr_pipe_transact(ndr_pipe_t *np) ndr_pipe_rewind(np); send_nds = &mxa->send_nds; - nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); + rc = nds_initialize(send_nds, 0, NDR_MODE_RETURN_SEND, mxa->heap); + if (rc != 0) { + nds_destruct(&mxa->recv_nds); + ndr_heap_destroy(mxa->heap); + free(mxa); + return (ENOMEM); + } (void) ndr_svc_process(mxa); diff --git a/usr/src/lib/smbsrv/libmlsvc/Makefile.com b/usr/src/lib/smbsrv/libmlsvc/Makefile.com index c10cab0b67..af744ee14c 100644 --- a/usr/src/lib/smbsrv/libmlsvc/Makefile.com +++ b/usr/src/lib/smbsrv/libmlsvc/Makefile.com @@ -33,14 +33,12 @@ OBJS_COMMON = \ eventlog_svc.o \ eventlog_syslog.o \ lsalib.o \ - lsar_lookup.o \ - lsar_open.o \ + lsar_clnt.o \ + lsar_svc.o \ mlsvc_client.o \ mlsvc_domain.o \ mlsvc_init.o \ - mlsvc_lsa.o \ mlsvc_netr.o \ - mlsvc_sam.o \ mlsvc_util.o \ mlsvc_wkssvc.o \ msgsvc_svc.o \ @@ -48,8 +46,8 @@ OBJS_COMMON = \ netr_auth.o \ netr_logon.o \ samlib.o \ - samr_open.o \ - samr_lookup.o \ + samr_clnt.o \ + samr_svc.o \ smb_autohome.o \ smb_logon.o \ smb_share.o \ @@ -84,7 +82,7 @@ INCS += -I$(SRC)/common/smbsrv LDLIBS += $(MACH_LDLIBS) LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lresolv -lnsl -lpkcs11 -lscf \ - -lnvpair -luutil -lzfs -lc + -lnvpair -lsec -luutil -lzfs -lc CPPFLAGS += $(INCS) -D_REENTRANT diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h index 99f10fc368..a2daead00d 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h @@ -49,8 +49,8 @@ extern "C" { #endif -extern uint32_t mlsvc_lookup_name(char *, smb_sid_t **, uint16_t *); -extern uint32_t mlsvc_lookup_sid(smb_sid_t *, char **); +uint32_t lsa_lookup_name(char *, uint16_t, smb_account_t *); +uint32_t lsa_lookup_sid(smb_sid_t *, smb_account_t *); /* * SMB domain API to discover a domain controller and obtain domain @@ -73,13 +73,6 @@ extern DWORD mlsvc_join(smb_domainex_t *, char *, char *); */ #define MLSVC_DOMAIN_MAX 32 -/* - * Status code returned from enumeration RPCs to indicate - * that the server has no more data. Normally returned at - * severity level ERROR_SEVERITY_WARNING. - */ -#define MLSVC_NO_MORE_DATA 0x1A - #define MLSVC_ANON_USER "IPC$" char *mlsvc_ipc_name(int ipc_type, char *username); @@ -110,7 +103,7 @@ typedef struct smb_autohome { char *ah_container; /* ADS container distinguished name */ } smb_autohome_t; -extern void smb_autohome_add(const char *); +extern void smb_autohome_add(const smb_token_t *); extern void smb_autohome_remove(const char *); /* @@ -151,7 +144,6 @@ int srvsvc_net_server_getinfo(char *, char *, srvsvc_server_info_t *); typedef struct mlsvc_handle { ndr_hdid_t handle; ndr_client_t *clnt; - uint32_t remote_os; srvsvc_server_info_t svinfo; } mlsvc_handle_t; @@ -160,6 +152,8 @@ void ndr_rpc_fini(void); int ndr_rpc_bind(mlsvc_handle_t *, char *, char *, char *, const char *); void ndr_rpc_unbind(mlsvc_handle_t *); int ndr_rpc_call(mlsvc_handle_t *, int, void *); +void ndr_rpc_set_nonull(mlsvc_handle_t *); +const srvsvc_server_info_t *ndr_rpc_server_info(mlsvc_handle_t *); uint32_t ndr_rpc_server_os(mlsvc_handle_t *); int ndr_rpc_get_ssnkey(mlsvc_handle_t *, unsigned char *, size_t); void *ndr_rpc_malloc(mlsvc_handle_t *, size_t); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c index c091d63f9b..5545ab1d3a 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c @@ -239,9 +239,9 @@ lsa_enum_trusted_domains(char *server, char *domain, enum_context = 0; status = lsar_enum_trusted_domains(&domain_handle, &enum_context, info); - if (status == MLSVC_NO_MORE_DATA) { + if (status == NT_STATUS_NO_MORE_DATA) { /* - * MLSVC_NO_MORE_DATA indicates that we + * NT_STATUS_NO_MORE_DATA indicates that we * have all of the available information. */ status = NT_STATUS_SUCCESS; @@ -279,9 +279,9 @@ lsa_enum_trusted_domains_ex(char *server, char *domain, status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context, info); - if (status == MLSVC_NO_MORE_DATA) { + if (status == NT_STATUS_NO_MORE_DATA) { /* - * MLSVC_NO_MORE_DATA indicates that we + * NT_STATUS_NO_MORE_DATA indicates that we * have all of the available information. */ status = NT_STATUS_SUCCESS; @@ -357,14 +357,7 @@ lsa_lookup_name_domain(char *account_name, smb_account_t *info) &domain_handle) != 0) return (NT_STATUS_INVALID_PARAMETER); - status = lsar_lookup_names2(&domain_handle, account_name, info); - if (status == NT_STATUS_REVISION_MISMATCH) { - /* - * Not a Windows 2000 domain controller: - * use the NT compatible call. - */ - status = lsar_lookup_names(&domain_handle, account_name, info); - } + status = lsar_lookup_names(&domain_handle, account_name, info); (void) lsar_close(&domain_handle); return (status); @@ -547,17 +540,7 @@ lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo) &domain_handle) != 0) return (NT_STATUS_INVALID_PARAMETER); - status = lsar_lookup_sids2(&domain_handle, (struct mslsa_sid *)sid, - ainfo); - - if (status == NT_STATUS_REVISION_MISMATCH) { - /* - * Not a Windows 2000 domain controller: - * use the NT compatible call. - */ - status = lsar_lookup_sids(&domain_handle, - (struct mslsa_sid *)sid, ainfo); - } + status = lsar_lookup_sids(&domain_handle, sid, ainfo); (void) lsar_close(&domain_handle); return (status); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h index afbf685bc5..f6f3f11fcd 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h @@ -45,6 +45,8 @@ extern "C" { #endif +typedef struct mslsa_sid lsa_sid_t; + /* * lsalib.c */ @@ -70,11 +72,7 @@ int lsar_close(mlsvc_handle_t *); int lsar_query_security_desc(mlsvc_handle_t *); DWORD lsar_query_info_policy(mlsvc_handle_t *, WORD, smb_domain_t *); uint32_t lsar_lookup_names(mlsvc_handle_t *, char *, smb_account_t *); -uint32_t lsar_lookup_names2(mlsvc_handle_t *, char *, smb_account_t *); -uint32_t lsar_lookup_sids(mlsvc_handle_t *, struct mslsa_sid *, - smb_account_t *); -uint32_t lsar_lookup_sids2(mlsvc_handle_t *, struct mslsa_sid *, - smb_account_t *); +uint32_t lsar_lookup_sids(mlsvc_handle_t *, smb_sid_t *, smb_account_t *); int lsar_enum_accounts(mlsvc_handle_t *, DWORD *, struct mslsa_EnumAccountBuf *); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c index 1121d67d6f..e01ac58363 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_clnt.c @@ -24,22 +24,21 @@ */ /* - * Local Security Authority RPC (LSARPC) library interface functions for - * query, lookup and enumeration calls. + * Local Security Authority RPC (LSAR) client-side interface. */ - +#include <sys/errno.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> -#include <sys/errno.h> #include <smbsrv/libsmb.h> +#include <smbsrv/libmlsvc.h> +#include <smbsrv/smbinfo.h> #include <smbsrv/ntaccess.h> #include <smbsrv/ntstatus.h> #include <smbsrv/ntlocale.h> #include <smbsrv/string.h> -#include <smbsrv/libmlsvc.h> #include <lsalib.h> /* @@ -49,13 +48,30 @@ #define MLSVC_MAX_RESPONSE_LEN 1024 /* - * This structure is used when lookuping up names. We only lookup one + * This structure is used when looking up names. We only lookup one * name at a time but the structure will allow for more. */ -typedef struct lookup_name_table { - DWORD n_entry; - mslsa_string_t name[8]; -} lookup_name_table_t; +typedef struct lsa_names { + uint32_t n_entry; + mslsa_string_t name[8]; +} lsa_names_t; + +typedef DWORD (*lsar_nameop_t)(mlsvc_handle_t *, lsa_names_t *, + smb_account_t *); + +static uint32_t lsar_lookup_names1(mlsvc_handle_t *, lsa_names_t *, + smb_account_t *); +static uint32_t lsar_lookup_names2(mlsvc_handle_t *, lsa_names_t *, + smb_account_t *); +static uint32_t lsar_lookup_names3(mlsvc_handle_t *, lsa_names_t *, + smb_account_t *); +static uint32_t lsar_lookup_sids1(mlsvc_handle_t *, lsa_sid_t *, + smb_account_t *); +static uint32_t lsar_lookup_sids2(mlsvc_handle_t *, lsa_sid_t *, + smb_account_t *account); + +static char *lsar_get_username(const char *); +static void smb_account_trace(const smb_account_t *); static void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *, smb_trusted_domains_t *); @@ -63,6 +79,190 @@ static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *, smb_trusted_domains_t *); /* + * lsar_open + * + * This is a wrapper round lsar_open_policy2 to ensure that we connect + * using the appropriate domain information. + * + * If username argument is NULL, an anonymous connection will be established. + * Otherwise, an authenticated connection will be established. + * + * On success 0 is returned. Otherwise a -ve error code. + */ +int lsar_open(char *server, char *domain, char *username, + mlsvc_handle_t *domain_handle) +{ + if (server == NULL || domain == NULL) + return (-1); + + if (username == NULL) + username = MLSVC_ANON_USER; + + return (lsar_open_policy2(server, domain, username, domain_handle)); +} + +/* + * lsar_open_policy2 + * + * Obtain an LSA policy handle. A policy handle is required to access + * LSA resources on a remote server. The server name supplied here does + * not need the double backslash prefix; it is added here. Call this + * 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 +lsar_open_policy2(char *server, char *domain, char *username, + mlsvc_handle_t *lsa_handle) +{ + struct mslsa_OpenPolicy2 arg; + int opnum; + int len; + int rc; + + rc = ndr_rpc_bind(lsa_handle, server, domain, username, "LSARPC"); + if (rc != 0) + return (-1); + + opnum = LSARPC_OPNUM_OpenPolicy2; + bzero(&arg, sizeof (struct mslsa_OpenPolicy2)); + + len = strlen(server) + 4; + arg.servername = ndr_rpc_malloc(lsa_handle, len); + if (arg.servername == NULL) { + ndr_rpc_unbind(lsa_handle); + return (-1); + } + + (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; + } + + if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) { + ndr_rpc_unbind(lsa_handle); + return (-1); + } + + if (arg.status != 0) { + rc = -1; + } else { + (void) memcpy(&lsa_handle->handle, &arg.domain_handle, + sizeof (ndr_hdid_t)); + + if (ndr_is_null_handle(lsa_handle)) + rc = -1; + } + + ndr_rpc_release(lsa_handle); + + if (rc != 0) + ndr_rpc_unbind(lsa_handle); + return (rc); +} + +/* + * lsar_open_account + * + * Obtain an LSA account handle. The lsa_handle must be a valid handle + * obtained via lsar_open_policy2. The main thing to remember here is + * to set up the context in the lsa_account_handle. I'm not sure what + * the requirements are for desired access. Some values require admin + * access. + * + * Returns 0 on success. Otherwise non-zero to indicate a failure. + */ +int +lsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, + mlsvc_handle_t *lsa_account_handle) +{ + struct mslsa_OpenAccount arg; + int opnum; + int rc; + + if (ndr_is_null_handle(lsa_handle) || sid == NULL) + return (-1); + + opnum = LSARPC_OPNUM_OpenAccount; + bzero(&arg, sizeof (struct mslsa_OpenAccount)); + + (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); + arg.sid = sid; + arg.access_mask = STANDARD_RIGHTS_REQUIRED +#if 0 + | POLICY_VIEW_AUDIT_INFORMATION + | POLICY_GET_PRIVATE_INFORMATION + | POLICY_TRUST_ADMIN +#endif + | POLICY_VIEW_LOCAL_INFORMATION; + + if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) + return (-1); + + if (arg.status != 0) { + rc = -1; + } else { + ndr_inherit_handle(lsa_account_handle, lsa_handle); + + (void) memcpy(&lsa_account_handle->handle, + &arg.account_handle, sizeof (ndr_hdid_t)); + + if (ndr_is_null_handle(lsa_account_handle)) + rc = -1; + } + + ndr_rpc_release(lsa_handle); + return (rc); +} + +/* + * lsar_close + * + * Close the LSA connection associated with the handle. The lsa_handle + * must be a valid handle obtained via a call to lsar_open_policy2 or + * lsar_open_account. On success the handle will be zeroed out to + * ensure that it is not used again. If this is the top level handle + * (i.e. the one obtained via lsar_open_policy2) the pipe is closed. + * + * Returns 0 on success. Otherwise non-zero to indicate a failure. + */ +int +lsar_close(mlsvc_handle_t *lsa_handle) +{ + struct mslsa_CloseHandle arg; + int opnum; + + if (ndr_is_null_handle(lsa_handle)) + return (-1); + + opnum = LSARPC_OPNUM_CloseHandle; + bzero(&arg, sizeof (struct mslsa_CloseHandle)); + (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); + + (void) ndr_rpc_call(lsa_handle, opnum, &arg); + ndr_rpc_release(lsa_handle); + + if (ndr_is_bind_handle(lsa_handle)) + ndr_rpc_unbind(lsa_handle); + + bzero(lsa_handle, sizeof (mlsvc_handle_t)); + return (0); +} + +/* * lsar_query_security_desc * * Don't use this call yet. It is just a place holder for now. @@ -70,9 +270,9 @@ static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *, int lsar_query_security_desc(mlsvc_handle_t *lsa_handle) { - struct mslsa_QuerySecurityObject arg; - int rc; - int opnum; + struct mslsa_QuerySecurityObject arg; + int rc; + int opnum; opnum = LSARPC_OPNUM_QuerySecurityObject; @@ -84,7 +284,6 @@ lsar_query_security_desc(mlsvc_handle_t *lsa_handle) return (rc); } - /* * lsar_query_info_policy * @@ -105,14 +304,14 @@ DWORD lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass, smb_domain_t *info) { - struct mslsa_QueryInfoPolicy arg; - struct mslsa_PrimaryDomainInfo *pd_info; - struct mslsa_AccountDomainInfo *ad_info; - struct mslsa_DnsDomainInfo *dns_info; - char guid_str[UUID_PRINTABLE_STRING_LENGTH]; - char sidstr[SMB_SID_STRSZ]; - int opnum; - DWORD status; + struct mslsa_QueryInfoPolicy arg; + struct mslsa_PrimaryDomainInfo *pd_info; + struct mslsa_AccountDomainInfo *ad_info; + struct mslsa_DnsDomainInfo *dns_info; + char guid_str[UUID_PRINTABLE_STRING_LENGTH]; + char sidstr[SMB_SID_STRSZ]; + int opnum; + DWORD status; if (lsa_handle == NULL || info == NULL) return (NT_STATUS_INVALID_PARAMETER); @@ -181,53 +380,34 @@ lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass, } /* - * lsar_lookup_names - * - * Lookup a name and obtain the domain and user rid. The RPC call will - * actually support lookup of multiple names but we probably don't - * need to do that. On the final system the lookup level should be - * level 2 but for now we want to restrict it to level 1 so that we - * don't crash the PDC when we get things wrong. - * - * If the lookup fails, the status will typically be - * NT_STATUS_NONE_MAPPED. + * Lookup a name and obtain the sid/rid. + * This is a wrapper for the various lookup sid RPCs. */ uint32_t lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) { - struct mslsa_LookupNames arg; - struct mslsa_rid_entry *rid_entry; - struct mslsa_domain_entry *domain_entry; - lookup_name_table_t name_table; - uint32_t status = NT_STATUS_SUCCESS; - char *domname; - int opnum; - size_t length; - char *p; + static lsar_nameop_t ops[] = { + lsar_lookup_names3, + lsar_lookup_names2, + lsar_lookup_names1 + }; + + const srvsvc_server_info_t *svinfo; + lsa_names_t names; + char *p; + uint32_t length; + uint32_t status = NT_STATUS_INVALID_PARAMETER; + int n_op = (sizeof (ops) / sizeof (ops[0])); + int i; if (lsa_handle == NULL || name == NULL || info == NULL) return (NT_STATUS_INVALID_PARAMETER); bzero(info, sizeof (smb_account_t)); - opnum = LSARPC_OPNUM_LookupNames; - - bzero(&arg, sizeof (struct mslsa_LookupNames)); - (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); - - arg.name_table = (struct mslsa_lup_name_table *)&name_table; - name_table.n_entry = 1; - - /* - * Windows NT expects the name length to exclude the terminating - * wchar null but doesn't care whether the allosize includes or - * excludes the null char. Windows 2000 insists that both the - * length and the allosize include the wchar null. - * - * Note: NT returns an error if the mapped_count is non-zero - * when the RPC is called. - */ - if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) { + svinfo = ndr_rpc_server_info(lsa_handle); + if (svinfo->sv_os == NATIVE_OS_WIN2000 && + svinfo->sv_version_major == 5 && svinfo->sv_version_minor == 0) { /* * Windows 2000 doesn't like an LSA lookup for * DOMAIN\Administrator. @@ -239,16 +419,148 @@ lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) name = p; } - length = smb_wcequiv_strlen(name) + sizeof (smb_wchar_t); - arg.lookup_level = MSLSA_LOOKUP_LEVEL_1; + } + + length = smb_wcequiv_strlen(name); + names.name[0].length = length; + names.name[0].allosize = length; + names.name[0].str = (unsigned char *)name; + names.n_entry = 1; + + if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) { + for (i = 0; i < n_op; ++i) { + ndr_rpc_set_nonull(lsa_handle); + status = (*ops[i])(lsa_handle, &names, info); + + if (status != NT_STATUS_INVALID_PARAMETER) + break; + } } else { - length = smb_wcequiv_strlen(name); - arg.lookup_level = MSLSA_LOOKUP_LEVEL_1; + ndr_rpc_set_nonull(lsa_handle); + status = lsar_lookup_names1(lsa_handle, &names, info); } - name_table.name[0].length = length; - name_table.name[0].allosize = length; - name_table.name[0].str = (unsigned char *)name; + if (status == NT_STATUS_SUCCESS) { + info->a_name = lsar_get_username(name); + + if (!smb_account_validate(info)) { + smb_account_free(info); + status = NT_STATUS_NO_MEMORY; + } else { + smb_account_trace(info); + } + } + + return (status); +} + +/* + * The name may be in one of the following forms: + * + * domain\username + * domain/username + * username + * username@domain + * + * Return a strdup'd copy of the username. The caller is responsible + * for freeing the allocated memory. + */ +static char * +lsar_get_username(const char *name) +{ + char tmp[MAXNAMELEN]; + char *dp = NULL; + char *np = NULL; + + (void) strlcpy(tmp, name, MAXNAMELEN); + smb_name_parse(tmp, &np, &dp); + + if (dp != NULL && np != NULL) + return (strdup(np)); + else + return (strdup(name)); +} + +/* + * lsar_lookup_names1 + * + * Lookup a name and obtain the domain and user rid. + * + * Note: NT returns an error if the mapped_count is non-zero when the RPC + * is called. + * + * If the lookup fails, the status will typically be NT_STATUS_NONE_MAPPED. + */ +static uint32_t +lsar_lookup_names1(mlsvc_handle_t *lsa_handle, lsa_names_t *names, + smb_account_t *info) +{ + struct mslsa_LookupNames arg; + struct mslsa_rid_entry *rid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *domname; + int opnum = LSARPC_OPNUM_LookupNames; + + bzero(&arg, sizeof (struct mslsa_LookupNames)); + (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.name_table = (struct mslsa_lup_name_table *)names; + + if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + rid_entry = &arg.translated_sids.rids[0]; + if (rid_entry->domain_index != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + domain_entry = &arg.domain_table->entries[0]; + + info->a_type = rid_entry->sid_name_use; + info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + if ((domname = (char *)domain_entry->domain_name.str) != NULL) + info->a_domain = strdup(domname); + info->a_rid = rid_entry->rid; + info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid); + + ndr_rpc_release(lsa_handle); + return (status); +} + +/* + * lsar_lookup_names2 + */ +static uint32_t +lsar_lookup_names2(mlsvc_handle_t *lsa_handle, lsa_names_t *names, + smb_account_t *info) +{ + struct lsar_LookupNames2 arg; + struct lsar_rid_entry2 *rid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *domname; + int opnum = LSARPC_OPNUM_LookupNames2; + + bzero(&arg, sizeof (struct lsar_LookupNames2)); + (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t)); + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.client_revision = LSA_CLIENT_REVISION_AD; + arg.name_table = (struct mslsa_lup_name_table *)names; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { ndr_rpc_release(lsa_handle); @@ -275,56 +587,256 @@ lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) domain_entry = &arg.domain_table->entries[0]; info->a_type = rid_entry->sid_name_use; - info->a_name = strdup(name); info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); if ((domname = (char *)domain_entry->domain_name.str) != NULL) info->a_domain = strdup(domname); info->a_rid = rid_entry->rid; info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid); - if (!smb_account_validate(info)) { - smb_account_free(info); - status = NT_STATUS_NO_MEMORY; + ndr_rpc_release(lsa_handle); + return (status); +} + +/* + * lsar_lookup_names3 + */ +static uint32_t +lsar_lookup_names3(mlsvc_handle_t *lsa_handle, lsa_names_t *names, + smb_account_t *info) +{ + struct lsar_LookupNames3 arg; + lsar_translated_sid_ex2_t *sid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *domname; + int opnum = LSARPC_OPNUM_LookupNames3; + + bzero(&arg, sizeof (struct lsar_LookupNames3)); + (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t)); + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.client_revision = LSA_CLIENT_REVISION_AD; + arg.name_table = (struct mslsa_lup_name_table *)names; + + if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); } + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + sid_entry = &arg.translated_sids.sids[0]; + if (sid_entry->domain_index != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + domain_entry = &arg.domain_table->entries[0]; + + info->a_type = sid_entry->sid_name_use; + info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + if ((domname = (char *)domain_entry->domain_name.str) != NULL) + info->a_domain = strdup(domname); + info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid); + (void) smb_sid_getrid(info->a_sid, &info->a_rid); + ndr_rpc_release(lsa_handle); return (status); } /* - * lsar_lookup_sids + * lsar_lookup_names4 + * + * This function is only valid if the remote RPC server is a domain + * controller and requires the security extensions defined in MS-RPCE. * - * Lookup a sid and obtain the domain sid and user name. The RPC call - * will actually support lookup of multiple sids but we probably don't - * need to do that. On the final system the lookup level should be - * level 2 but for now we want to restrict it to level 1 so that we - * don't crash the PDC when we get things wrong. + * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here + * because we don't support the RPC_C_AUTHN_NETLOGON security provider. + * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE. + */ +static uint32_t /*LINTED E_STATIC_UNUSED*/ +lsar_lookup_names4(mlsvc_handle_t *lsa_handle, lsa_names_t *names, + smb_account_t *info) +{ + struct lsar_LookupNames4 arg; + lsar_translated_sid_ex2_t *sid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *domname; + int opnum = LSARPC_OPNUM_LookupNames4; + + bzero(&arg, sizeof (struct lsar_LookupNames4)); + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.client_revision = LSA_CLIENT_REVISION_AD; + arg.name_table = (struct mslsa_lup_name_table *)names; + + if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED || + arg.status == NT_STATUS_INVALID_SERVER_STATE) + return (NT_STATUS_INVALID_PARAMETER); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + sid_entry = &arg.translated_sids.sids[0]; + if (sid_entry->domain_index != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + domain_entry = &arg.domain_table->entries[0]; + + info->a_type = sid_entry->sid_name_use; + info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + if ((domname = (char *)domain_entry->domain_name.str) != NULL) + info->a_domain = strdup(domname); + info->a_sid = smb_sid_dup((smb_sid_t *)sid_entry->sid); + (void) smb_sid_getrid(info->a_sid, &info->a_rid); + + ndr_rpc_release(lsa_handle); + return (status); +} + +/* + * Lookup a sid and obtain the domain sid and account name. + * This is a wrapper for the various lookup sid RPCs. */ uint32_t -lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, +lsar_lookup_sids(mlsvc_handle_t *lsa_handle, smb_sid_t *sid, smb_account_t *account) { - struct mslsa_LookupSids arg; - struct mslsa_lup_sid_entry sid_entry; - struct mslsa_name_entry *name_entry; - struct mslsa_domain_entry *domain_entry; - uint32_t status = NT_STATUS_SUCCESS; - char *name; - int opnum; + char sidbuf[SMB_SID_STRSZ]; + uint32_t status; if (lsa_handle == NULL || sid == NULL || account == NULL) return (NT_STATUS_INVALID_PARAMETER); bzero(account, sizeof (smb_account_t)); - opnum = LSARPC_OPNUM_LookupSids; + bzero(sidbuf, SMB_SID_STRSZ); + smb_sid_tostr(sid, sidbuf); + smb_tracef("%s", sidbuf); + + if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) + status = lsar_lookup_sids2(lsa_handle, (lsa_sid_t *)sid, + account); + else + status = lsar_lookup_sids1(lsa_handle, (lsa_sid_t *)sid, + account); + + if (status == NT_STATUS_SUCCESS) { + if (!smb_account_validate(account)) { + smb_account_free(account); + status = NT_STATUS_NO_MEMORY; + } else { + smb_account_trace(account); + } + } + + return (status); +} + +/* + * lsar_lookup_sids1 + */ +static uint32_t +lsar_lookup_sids1(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid, + smb_account_t *account) +{ + struct mslsa_LookupSids arg; + struct mslsa_lup_sid_entry sid_entry; + struct mslsa_name_entry *name_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *name; + int opnum = LSARPC_OPNUM_LookupSids; bzero(&arg, sizeof (struct mslsa_LookupSids)); (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); - arg.lookup_level = MSLSA_LOOKUP_LEVEL_2; + arg.lookup_level = LSA_LOOKUP_WKSTA; + + sid_entry.psid = sid; + arg.lup_sid_table.n_entry = 1; + arg.lup_sid_table.entries = &sid_entry; + + if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + name_entry = &arg.name_table.entries[0]; + if (name_entry->domain_ix != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + name = (char *)name_entry->name.str; + account->a_name = (name) ? strdup(name) : strdup(""); + account->a_type = name_entry->sid_name_use; + account->a_sid = smb_sid_dup((smb_sid_t *)sid); + (void) smb_sid_getrid(account->a_sid, &account->a_rid); + + domain_entry = &arg.domain_table->entries[0]; + if ((name = (char *)domain_entry->domain_name.str) != NULL) + account->a_domain = strdup(name); + account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + + ndr_rpc_release(lsa_handle); + return (status); +} + +/* + * lsar_lookup_sids2 + */ +static uint32_t +lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid, + smb_account_t *account) +{ + struct lsar_lookup_sids2 arg; + struct lsar_name_entry2 *name_entry; + struct mslsa_lup_sid_entry sid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *name; + int opnum = LSARPC_OPNUM_LookupSids2; + + bzero(&arg, sizeof (struct lsar_lookup_sids2)); + (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t)); sid_entry.psid = sid; arg.lup_sid_table.n_entry = 1; arg.lup_sid_table.entries = &sid_entry; + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.client_revision = LSA_CLIENT_REVISION_AD; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { ndr_rpc_release(lsa_handle); @@ -352,17 +864,83 @@ lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, account->a_name = (name) ? strdup(name) : strdup(""); account->a_type = name_entry->sid_name_use; account->a_sid = smb_sid_dup((smb_sid_t *)sid); + (void) smb_sid_getrid(account->a_sid, &account->a_rid); domain_entry = &arg.domain_table->entries[0]; if ((name = (char *)domain_entry->domain_name.str) != NULL) account->a_domain = strdup(name); account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); - if (!smb_account_validate(account)) { - smb_account_free(account); - status = NT_STATUS_NO_MEMORY; + ndr_rpc_release(lsa_handle); + return (status); +} + +/* + * lsar_lookup_sids3 + * + * This function is only valid if the remote RPC server is a domain + * controller and requires the security extensions defined in MS-RPCE. + * + * Domain controllers will return RPC_NT_PROTSEQ_NOT_SUPPORTED here + * because we don't support the RPC_C_AUTHN_NETLOGON security provider. + * Non-domain controllers will return NT_STATUS_INVALID_SERVER_STATE. + */ +static uint32_t /*LINTED E_STATIC_UNUSED*/ +lsar_lookup_sids3(mlsvc_handle_t *lsa_handle, lsa_sid_t *sid, + smb_account_t *account) +{ + struct lsar_lookup_sids3 arg; + lsar_translated_name_ex_t *name_entry; + struct mslsa_lup_sid_entry sid_entry; + struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; + char *name; + int opnum = LSARPC_OPNUM_LookupSids3; + + bzero(&arg, sizeof (struct lsar_lookup_sids3)); + + sid_entry.psid = sid; + arg.lup_sid_table.n_entry = 1; + arg.lup_sid_table.entries = &sid_entry; + arg.lookup_level = LSA_LOOKUP_WKSTA; + arg.client_revision = LSA_CLIENT_REVISION_AD; + + if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + if (arg.status == RPC_NT_PROTSEQ_NOT_SUPPORTED || + arg.status == NT_STATUS_INVALID_SERVER_STATE) + return (NT_STATUS_INVALID_PARAMETER); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + name_entry = &arg.name_table.entries[0]; + if (name_entry->domain_ix != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); } + name = (char *)name_entry->name.str; + account->a_name = (name) ? strdup(name) : strdup(""); + account->a_type = name_entry->sid_name_use; + account->a_sid = smb_sid_dup((smb_sid_t *)sid); + (void) smb_sid_getrid(account->a_sid, &account->a_rid); + + domain_entry = &arg.domain_table->entries[0]; + if ((name = (char *)domain_entry->domain_name.str) != NULL) + account->a_domain = strdup(name); + account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + ndr_rpc_release(lsa_handle); return (status); } @@ -384,13 +962,13 @@ int lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context, struct mslsa_EnumAccountBuf *accounts) { - struct mslsa_EnumerateAccounts arg; - struct mslsa_AccountInfo *info; - int opnum; - int rc; - DWORD n_entries; - DWORD i; - int nbytes; + struct mslsa_EnumerateAccounts arg; + struct mslsa_AccountInfo *info; + int opnum; + int rc; + DWORD n_entries; + DWORD i; + int nbytes; if (lsa_handle == NULL || enum_context == NULL || accounts == NULL) return (-1); @@ -408,7 +986,8 @@ lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context, rc = ndr_rpc_call(lsa_handle, opnum, &arg); if (rc == 0) { if (arg.status != 0) { - if ((arg.status & 0x00FFFFFF) == MLSVC_NO_MORE_DATA) { + if ((arg.status & 0x00FFFFFF) == + NT_STATUS_NO_MORE_DATA) { *enum_context = arg.enum_context; } else { ndr_rpc_status(lsa_handle, opnum, arg.status); @@ -424,7 +1003,7 @@ lsar_enum_accounts(mlsvc_handle_t *lsa_handle, DWORD *enum_context, } for (i = 0; i < n_entries; ++i) - info[i].sid = (struct mslsa_sid *)smb_sid_dup( + info[i].sid = (lsa_sid_t *)smb_sid_dup( (smb_sid_t *)arg.enum_buf->info[i].sid); accounts->entries_read = n_entries; @@ -456,9 +1035,9 @@ DWORD lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context, smb_trusted_domains_t *list) { - struct mslsa_EnumTrustedDomain arg; - int opnum; - DWORD status; + struct mslsa_EnumTrustedDomain arg; + int opnum; + DWORD status; if (list == NULL) return (NT_STATUS_INVALID_PARAMETER); @@ -481,7 +1060,7 @@ lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context, * status 0x8000001A means NO_MORE_DATA, * which is not an error. */ - if (status != MLSVC_NO_MORE_DATA) + if (status != NT_STATUS_NO_MORE_DATA) ndr_rpc_status(lsa_handle, opnum, arg.status); } else if (arg.enum_buf->entries_read == 0) { *enum_context = arg.enum_context; @@ -500,9 +1079,9 @@ DWORD lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context, smb_trusted_domains_t *list) { - struct mslsa_EnumTrustedDomainEx arg; - int opnum; - DWORD status; + struct mslsa_EnumTrustedDomainEx arg; + int opnum; + DWORD status; if (list == NULL) return (NT_STATUS_INVALID_PARAMETER); @@ -525,7 +1104,7 @@ lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context, * status 0x8000001A means NO_MORE_DATA, * which is not an error. */ - if (status != MLSVC_NO_MORE_DATA) + if (status != NT_STATUS_NO_MORE_DATA) ndr_rpc_status(lsa_handle, opnum, arg.status); } else if (arg.enum_buf->entries_read == 0) { *enum_context = arg.enum_context; @@ -549,9 +1128,9 @@ lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context, int lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account) { - struct mslsa_EnumPrivsAccount arg; - int opnum; - int rc; + struct mslsa_EnumPrivsAccount arg; + int opnum; + int rc; opnum = LSARPC_OPNUM_EnumPrivsAccount; @@ -581,10 +1160,10 @@ int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name, struct ms_luid *luid) { - struct mslsa_LookupPrivValue arg; - int opnum; - int rc; - size_t length; + struct mslsa_LookupPrivValue arg; + int opnum; + int rc; + size_t length; if (lsa_handle == NULL || name == NULL || luid == NULL) return (-1); @@ -626,9 +1205,9 @@ int lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, struct ms_luid *luid, char *name, int namelen) { - struct mslsa_LookupPrivName arg; - int opnum; - int rc; + struct mslsa_LookupPrivName arg; + int opnum; + int rc; if (lsa_handle == NULL || luid == NULL || name == NULL) return (-1); @@ -669,10 +1248,10 @@ DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name, char *display_name, int display_len) { - struct mslsa_LookupPrivDisplayName arg; - int opnum; - size_t length; - DWORD status; + struct mslsa_LookupPrivDisplayName arg; + int opnum; + size_t length; + DWORD status; if (lsa_handle == NULL || name == NULL || display_name == NULL) return (NT_STATUS_INVALID_PARAMETER); @@ -706,179 +1285,12 @@ lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name, return (status); } -/* - * lsar_lookup_sids2 - */ -uint32_t -lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, - smb_account_t *account) -{ - struct lsar_lookup_sids2 arg; - struct lsar_name_entry2 *name_entry; - struct mslsa_lup_sid_entry sid_entry; - struct mslsa_domain_entry *domain_entry; - uint32_t status = NT_STATUS_SUCCESS; - char *name; - int opnum; - - if (lsa_handle == NULL || sid == NULL || account == NULL) - return (NT_STATUS_INVALID_PARAMETER); - - bzero(account, sizeof (smb_account_t)); - opnum = LSARPC_OPNUM_LookupSids2; - - if (ndr_rpc_server_os(lsa_handle) != NATIVE_OS_WIN2000) - return (NT_STATUS_REVISION_MISMATCH); - - bzero(&arg, sizeof (struct lsar_lookup_sids2)); - (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t)); - - sid_entry.psid = sid; - arg.lup_sid_table.n_entry = 1; - arg.lup_sid_table.entries = &sid_entry; - arg.lookup_level = MSLSA_LOOKUP_LEVEL_1; - arg.requested_count = arg.lup_sid_table.n_entry; - - if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_INVALID_PARAMETER); - } - - if (arg.status != NT_STATUS_SUCCESS) { - ndr_rpc_status(lsa_handle, opnum, arg.status); - ndr_rpc_release(lsa_handle); - return (NT_SC_VALUE(arg.status)); - } - - if (arg.mapped_count == 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_NONE_MAPPED); - } - - name_entry = &arg.name_table.entries[0]; - if (name_entry->domain_ix != 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_NONE_MAPPED); - } - - name = (char *)name_entry->name.str; - account->a_name = (name) ? strdup(name) : strdup(""); - account->a_type = name_entry->sid_name_use; - account->a_sid = smb_sid_dup((smb_sid_t *)sid); - - domain_entry = &arg.domain_table->entries[0]; - if ((name = (char *)domain_entry->domain_name.str) != NULL) - account->a_domain = strdup(name); - account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); - - if (!smb_account_validate(account)) { - smb_account_free(account); - status = NT_STATUS_NO_MEMORY; - } - - ndr_rpc_release(lsa_handle); - return (status); -} - - -/* - * lsar_lookup_names2 - * - * Windows NT expects the name length to exclude the terminating - * wchar null but Windows 2000 insists that both the length and - * the allosize include the wchar null. Windows NT doesn't care - * whether or not the allosize includes or excludes the null char. - * - * As a precaution, I set the lookup level to 1 on Windows 2000 - * until I can do some more testing. - * - * Note that NT returns an error if the mapped_count is non-zero - * when the RPC is called. - * - * It should be okay to lookup DOMAIN\Administrator in this function. - */ -uint32_t -lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) -{ - struct lsar_LookupNames2 arg; - struct lsar_rid_entry2 *rid_entry; - struct mslsa_domain_entry *domain_entry; - lookup_name_table_t name_table; - uint32_t status = NT_STATUS_SUCCESS; - char *domname; - size_t length; - int opnum; - - if (lsa_handle == NULL || name == NULL || info == NULL) - return (NT_STATUS_INVALID_PARAMETER); - - bzero(info, sizeof (smb_account_t)); - - opnum = LSARPC_OPNUM_LookupNames2; - - if (ndr_rpc_server_os(lsa_handle) != NATIVE_OS_WIN2000) - return (NT_STATUS_REVISION_MISMATCH); - - bzero(&arg, sizeof (struct lsar_LookupNames2)); - (void) memcpy(&arg.policy_handle, lsa_handle, sizeof (mslsa_handle_t)); - arg.unknown_sb2 = 0x00000002; - arg.lookup_level = MSLSA_LOOKUP_LEVEL_1; - - arg.name_table = (struct mslsa_lup_name_table *)&name_table; - name_table.n_entry = 1; - - length = smb_wcequiv_strlen(name) + sizeof (smb_wchar_t); - name_table.name[0].length = length; - name_table.name[0].allosize = length; - name_table.name[0].str = (unsigned char *)name; - - if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_INVALID_PARAMETER); - } - - if (arg.status != NT_STATUS_SUCCESS) { - ndr_rpc_status(lsa_handle, opnum, arg.status); - ndr_rpc_release(lsa_handle); - return (NT_SC_VALUE(arg.status)); - } - - if (arg.mapped_count == 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_NONE_MAPPED); - } - - rid_entry = &arg.translated_sids.rids[0]; - if (rid_entry->domain_index != 0) { - ndr_rpc_release(lsa_handle); - return (NT_STATUS_NONE_MAPPED); - } - - domain_entry = &arg.domain_table->entries[0]; - - info->a_type = rid_entry->sid_name_use; - info->a_name = strdup(name); - info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); - if ((domname = (char *)domain_entry->domain_name.str) != NULL) - info->a_domain = strdup(domname); - info->a_rid = rid_entry->rid; - info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid); - - if (!smb_account_validate(info)) { - smb_account_free(info); - status = NT_STATUS_NO_MEMORY; - } - - ndr_rpc_release(lsa_handle); - return (status); -} - static void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf, smb_trusted_domains_t *list) { - char sidstr[SMB_SID_STRSZ]; - int i; + char sidstr[SMB_SID_STRSZ]; + int i; if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0) return; @@ -908,8 +1320,8 @@ static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf, smb_trusted_domains_t *list) { - char sidstr[SMB_SID_STRSZ]; - int i; + char sidstr[SMB_SID_STRSZ]; + int i; if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0) return; @@ -929,3 +1341,15 @@ lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf, "", 0, 0, 0, &list->td_domains[i]); } } + +static void +smb_account_trace(const smb_account_t *info) +{ + char sidbuf[SMB_SID_STRSZ]; + + bzero(sidbuf, SMB_SID_STRSZ); + smb_sid_tostr(info->a_sid, sidbuf); + + smb_tracef("%s %s %s %lu %s", info->a_domain, info->a_name, + sidbuf, info->a_rid, smb_sid_type2str(info->a_type)); +} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c deleted file mode 100644 index aefb2723e8..0000000000 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_open.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Local Security Authority RPC (LSARPC) library interface functions for - * open and close calls. - */ - -#include <stdio.h> -#include <strings.h> - -#include <smbsrv/libsmb.h> -#include <smbsrv/libmlsvc.h> -#include <smbsrv/smbinfo.h> -#include <smbsrv/ntaccess.h> -#include <smbsrv/ntstatus.h> -#include <lsalib.h> - -/* - * lsar_open - * - * This is a wrapper round lsar_open_policy2 to ensure that we connect - * using the appropriate domain information. - * - * If username argument is NULL, an anonymous connection will be established. - * Otherwise, an authenticated connection will be established. - * - * On success 0 is returned. Otherwise a -ve error code. - */ -int lsar_open(char *server, char *domain, char *username, - mlsvc_handle_t *domain_handle) -{ - if (server == NULL || domain == NULL) - return (-1); - - if (username == NULL) - username = MLSVC_ANON_USER; - - return (lsar_open_policy2(server, domain, username, domain_handle)); -} - -/* - * lsar_open_policy2 - * - * Obtain an LSA policy handle. A policy handle is required to access - * LSA resources on a remote server. The server name supplied here does - * not need the double backslash prefix; it is added here. Call this - * 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 -lsar_open_policy2(char *server, char *domain, char *username, - mlsvc_handle_t *lsa_handle) -{ - struct mslsa_OpenPolicy2 arg; - int opnum; - int len; - int rc; - - rc = ndr_rpc_bind(lsa_handle, server, domain, username, "LSARPC"); - if (rc != 0) - return (-1); - - opnum = LSARPC_OPNUM_OpenPolicy2; - bzero(&arg, sizeof (struct mslsa_OpenPolicy2)); - - len = strlen(server) + 4; - arg.servername = ndr_rpc_malloc(lsa_handle, len); - if (arg.servername == NULL) { - ndr_rpc_unbind(lsa_handle); - return (-1); - } - - (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; - } - - if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) { - ndr_rpc_unbind(lsa_handle); - return (-1); - } - - if (arg.status != 0) { - rc = -1; - } else { - (void) memcpy(&lsa_handle->handle, &arg.domain_handle, - sizeof (ndr_hdid_t)); - - if (ndr_is_null_handle(lsa_handle)) - rc = -1; - } - - ndr_rpc_release(lsa_handle); - - if (rc != 0) - ndr_rpc_unbind(lsa_handle); - return (rc); -} - -/* - * lsar_open_account - * - * Obtain an LSA account handle. The lsa_handle must be a valid handle - * obtained via lsar_open_policy2. The main thing to remember here is - * to set up the context in the lsa_account_handle. I'm not sure what - * the requirements are for desired access. Some values require admin - * access. - * - * Returns 0 on success. Otherwise non-zero to indicate a failure. - */ -int -lsar_open_account(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, - mlsvc_handle_t *lsa_account_handle) -{ - struct mslsa_OpenAccount arg; - int opnum; - int rc; - - if (ndr_is_null_handle(lsa_handle) || sid == NULL) - return (-1); - - opnum = LSARPC_OPNUM_OpenAccount; - bzero(&arg, sizeof (struct mslsa_OpenAccount)); - - (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); - arg.sid = sid; - arg.access_mask = STANDARD_RIGHTS_REQUIRED -#if 0 - | POLICY_VIEW_AUDIT_INFORMATION - | POLICY_GET_PRIVATE_INFORMATION - | POLICY_TRUST_ADMIN -#endif - | POLICY_VIEW_LOCAL_INFORMATION; - - if ((rc = ndr_rpc_call(lsa_handle, opnum, &arg)) != 0) - return (-1); - - if (arg.status != 0) { - rc = -1; - } else { - ndr_inherit_handle(lsa_account_handle, lsa_handle); - - (void) memcpy(&lsa_account_handle->handle, - &arg.account_handle, sizeof (ndr_hdid_t)); - - if (ndr_is_null_handle(lsa_account_handle)) - rc = -1; - } - - ndr_rpc_release(lsa_handle); - return (rc); -} - -/* - * lsar_close - * - * Close the LSA connection associated with the handle. The lsa_handle - * must be a valid handle obtained via a call to lsar_open_policy2 or - * lsar_open_account. On success the handle will be zeroed out to - * ensure that it is not used again. If this is the top level handle - * (i.e. the one obtained via lsar_open_policy2) the pipe is closed. - * - * Returns 0 on success. Otherwise non-zero to indicate a failure. - */ -int -lsar_close(mlsvc_handle_t *lsa_handle) -{ - struct mslsa_CloseHandle arg; - int opnum; - - if (ndr_is_null_handle(lsa_handle)) - return (-1); - - opnum = LSARPC_OPNUM_CloseHandle; - bzero(&arg, sizeof (struct mslsa_CloseHandle)); - (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); - - (void) ndr_rpc_call(lsa_handle, opnum, &arg); - ndr_rpc_release(lsa_handle); - - if (ndr_is_bind_handle(lsa_handle)) - ndr_rpc_unbind(lsa_handle); - - bzero(lsa_handle, sizeof (mlsvc_handle_t)); - return (0); -} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c index 058811cb6e..7e9a3aa0e0 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c @@ -24,7 +24,7 @@ */ /* - * Local Security Authority RPC (LSARPC) server-side interface definition. + * Local Security Authority RPC (LSAR) server-side interface. */ #include <unistd.h> @@ -55,26 +55,29 @@ static int lsarpc_key_account; static int lsarpc_call_stub(ndr_xa_t *mxa); -static int lsarpc_s_CloseHandle(void *arg, ndr_xa_t *); -static int lsarpc_s_QuerySecurityObject(void *arg, ndr_xa_t *); -static int lsarpc_s_EnumAccounts(void *arg, ndr_xa_t *); -static int lsarpc_s_EnumTrustedDomain(void *arg, ndr_xa_t *); -static int lsarpc_s_EnumTrustedDomainsEx(void *arg, ndr_xa_t *); -static int lsarpc_s_OpenAccount(void *arg, ndr_xa_t *); -static int lsarpc_s_EnumPrivsAccount(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupPrivValue(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupPrivName(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupPrivDisplayName(void *arg, ndr_xa_t *); +static int lsarpc_s_CloseHandle(void *, ndr_xa_t *); +static int lsarpc_s_QuerySecurityObject(void *, ndr_xa_t *); +static int lsarpc_s_EnumAccounts(void *, ndr_xa_t *); +static int lsarpc_s_EnumTrustedDomain(void *, ndr_xa_t *); +static int lsarpc_s_EnumTrustedDomainsEx(void *, ndr_xa_t *); +static int lsarpc_s_OpenAccount(void *, ndr_xa_t *); +static int lsarpc_s_EnumPrivsAccount(void *, ndr_xa_t *); +static int lsarpc_s_LookupPrivValue(void *, ndr_xa_t *); +static int lsarpc_s_LookupPrivName(void *, ndr_xa_t *); +static int lsarpc_s_LookupPrivDisplayName(void *, ndr_xa_t *); static int lsarpc_s_CreateSecret(void *, ndr_xa_t *); static int lsarpc_s_OpenSecret(void *, ndr_xa_t *); -static int lsarpc_s_QueryInfoPolicy(void *arg, ndr_xa_t *); -static int lsarpc_s_OpenDomainHandle(void *arg, ndr_xa_t *); -static int lsarpc_s_OpenDomainHandle(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupSids(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupNames(void *arg, ndr_xa_t *); -static int lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupSids2(void *arg, ndr_xa_t *); -static int lsarpc_s_LookupNames2(void *arg, ndr_xa_t *); +static int lsarpc_s_QueryInfoPolicy(void *, ndr_xa_t *); +static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *); +static int lsarpc_s_OpenDomainHandle(void *, ndr_xa_t *); +static int lsarpc_s_LookupSids(void *, ndr_xa_t *); +static int lsarpc_s_LookupNames(void *, ndr_xa_t *); +static int lsarpc_s_GetConnectedUser(void *, ndr_xa_t *); +static int lsarpc_s_LookupSids2(void *, ndr_xa_t *); +static int lsarpc_s_LookupSids3(void *, ndr_xa_t *); +static int lsarpc_s_LookupNames2(void *, ndr_xa_t *); +static int lsarpc_s_LookupNames3(void *, ndr_xa_t *); +static int lsarpc_s_LookupNames4(void *, ndr_xa_t *); static DWORD lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *, ndr_xa_t *); @@ -103,7 +106,10 @@ static ndr_stub_table_t lsarpc_stub_table[] = { { lsarpc_s_LookupNames, LSARPC_OPNUM_LookupNames }, { lsarpc_s_GetConnectedUser, LSARPC_OPNUM_GetConnectedUser }, { lsarpc_s_LookupSids2, LSARPC_OPNUM_LookupSids2 }, + { lsarpc_s_LookupSids3, LSARPC_OPNUM_LookupSids3 }, { lsarpc_s_LookupNames2, LSARPC_OPNUM_LookupNames2 }, + { lsarpc_s_LookupNames3, LSARPC_OPNUM_LookupNames3 }, + { lsarpc_s_LookupNames4, LSARPC_OPNUM_LookupNames4 }, {0} }; @@ -214,7 +220,7 @@ lsarpc_s_QuerySecurityObject(void *arg, ndr_xa_t *mxa) * multiple enumeration calls to obtain the complete list of SIDs. * It should be set to 0 on the first call and passed unchanged on * subsequent calls until there are no more accounts - the server will - * return NT_SC_WARNING(MLSVC_NO_MORE_DATA). + * return NT_SC_WARNING(NT_STATUS_NO_MORE_DATA). * * For now just set the status to access-denied. Note that we still have * to provide a valid address for enum_buf because it's a reference and @@ -251,7 +257,7 @@ lsarpc_s_EnumAccounts(void *arg, ndr_xa_t *mxa) * support multiple enumeration calls to obtain the complete list. * It should be set to 0 on the first call and passed unchanged on * subsequent calls until there are no more accounts - the server will - * return NT_SC_WARNING(MLSVC_NO_MORE_DATA). + * return NT_SC_WARNING(NT_STATUS_NO_MORE_DATA). * * For now just set the status to access-denied. Note that we still have * to provide a valid address for enum_buf because it's a reference and @@ -286,7 +292,7 @@ lsarpc_s_EnumTrustedDomain(void *arg, ndr_xa_t *mxa) * support multiple enumeration calls to obtain the complete list. * It should be set to 0 on the first call and passed unchanged on * subsequent calls until there are no more accounts - the server will - * return NT_SC_WARNING(MLSVC_NO_MORE_DATA). + * return NT_SC_WARNING(NT_STATUS_NO_MORE_DATA). * * For now just set the status to access-denied. Note that we still have * to provide a valid address for enum_buf because it's a reference and @@ -506,13 +512,8 @@ lsarpc_s_OpenSecret(void *arg, ndr_xa_t *mxa) /* * lsarpc_s_GetConnectedUser * - * This is still guesswork. Netmon doesn't know about this - * call and I'm not really sure what it is intended to achieve. - * Another packet capture application, Ethereal, calls this RPC as - * GetConnectedUser. - * We will receive our own hostname in the request and it appears - * we should respond with an account name and the domain name of connected - * user from the client that makes this call. + * Return the account name and NetBIOS domain name for the user making + * the request. The hostname field should be ignored by the server. */ static int lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa) @@ -781,6 +782,10 @@ lsarpc_s_LookupNames(void *arg, ndr_xa_t *mxa) * table and make the name entry point at the appropriate domain table * entry. * + * + * This RPC should behave as if LookupOptions is LSA_LOOKUP_OPT_ALL and + * ClientRevision is LSA_CLIENT_REVISION_NT. + * * On success return 0. Otherwise return an RPC specific error code. */ static int @@ -925,6 +930,8 @@ lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa, * * Other than the use of lsar_lookup_sids2 and lsar_name_entry2, this * is identical to lsarpc_s_LookupSids. + * + * Ignore lookup_level, it is reserved and should be zero. */ static int lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa) @@ -1005,10 +1012,28 @@ lookup_sid_failed: } /* + * LookupSids3 is only valid on domain controllers. + * Other servers must return NT_STATUS_INVALID_SERVER_STATE. + */ +/*ARGSUSED*/ +static int +lsarpc_s_LookupSids3(void *arg, ndr_xa_t *mxa) +{ + struct lsar_lookup_sids3 *param = arg; + + bzero(param, sizeof (struct lsar_lookup_sids3)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE); + return (NDR_DRC_OK); +} + +/* * lsarpc_s_LookupNames2 * * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this * is identical to lsarpc_s_LookupNames. + * + * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not + * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER. */ static int lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) @@ -1025,6 +1050,13 @@ lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) if (param->name_table->n_entry != 1) return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED); + if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) && + param->lookup_level != LSA_LOOKUP_WKSTA) { + bzero(param, sizeof (struct lsar_LookupNames2)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER); + return (NDR_DRC_OK); + } + rids = NDR_NEW(mxa, struct lsar_rid_entry2); domain_table = NDR_NEW(mxa, struct mslsa_domain_table); domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry); @@ -1081,6 +1113,105 @@ lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) return (NDR_DRC_OK); } +/* + * Other than the use of lsar_LookupNames2 and lsar_rid_entry2, this + * is identical to lsarpc_s_LookupNames. + * + * If LookupOptions contains LSA_LOOKUP_OPT_LOCAL and LookupLevel is not + * LSA_LOOKUP_WKSTA, return STATUS_INVALID_PARAMETER. + */ +static int +lsarpc_s_LookupNames3(void *arg, ndr_xa_t *mxa) +{ + struct lsar_LookupNames3 *param = arg; + struct lsar_translated_sid_ex2 *sids; + struct mslsa_domain_table *domain_table; + struct mslsa_domain_entry *domain_entry; + smb_account_t account; + uint32_t status; + char *accname; + int rc = 0; + + if (param->name_table->n_entry != 1) + return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED); + + if ((param->lookup_options & LSA_LOOKUP_OPT_LOCAL) && + param->lookup_level != LSA_LOOKUP_WKSTA) { + bzero(param, sizeof (struct lsar_LookupNames3)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER); + return (NDR_DRC_OK); + } + + sids = NDR_NEW(mxa, struct lsar_translated_sid_ex2); + domain_table = NDR_NEW(mxa, struct mslsa_domain_table); + domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry); + + if (sids == NULL || domain_table == NULL || domain_entry == NULL) { + bzero(param, sizeof (struct lsar_LookupNames3)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); + } + + accname = (char *)param->name_table->names->str; + status = lsa_lookup_name(accname, SidTypeUnknown, &account); + if (status != NT_STATUS_SUCCESS) { + bzero(param, sizeof (struct lsar_LookupNames3)); + param->status = NT_SC_ERROR(status); + return (NDR_DRC_OK); + } + + /* + * Set up the SID table. + */ + bzero(sids, sizeof (struct lsar_translated_sid_ex2)); + sids[0].sid_name_use = account.a_type; + sids[0].sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_sid); + sids[0].domain_index = 0; + param->translated_sids.n_entry = 1; + param->translated_sids.sids = sids; + + /* + * Set up the domain table. + */ + domain_table->entries = domain_entry; + domain_table->n_entry = 1; + domain_table->max_n_entry = MLSVC_DOMAIN_MAX; + + rc = NDR_MSTRING(mxa, account.a_domain, + (ndr_mstring_t *)&domain_entry->domain_name); + + domain_entry->domain_sid = + (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid); + + if (rc == -1 || domain_entry->domain_sid == NULL) { + smb_account_free(&account); + bzero(param, sizeof (struct lsar_LookupNames3)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); + } + + param->domain_table = domain_table; + param->mapped_count = 1; + param->status = NT_STATUS_SUCCESS; + + smb_account_free(&account); + return (NDR_DRC_OK); +} + +/* + * LookupNames4 is only valid on domain controllers. + * Other servers must return NT_STATUS_INVALID_SERVER_STATE. + */ +/*ARGSUSED*/ +static int +lsarpc_s_LookupNames4(void *arg, ndr_xa_t *mxa) +{ + struct lsar_LookupNames4 *param = arg; + + bzero(param, sizeof (struct lsar_LookupNames4)); + param->status = NT_SC_ERROR(NT_STATUS_INVALID_SERVER_STATE); + return (NDR_DRC_OK); +} /* * There is a bug in the way that ndrgen and the marshalling code handles diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers index 59bd319ef3..1855b2ea66 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers @@ -41,19 +41,18 @@ SUNWprivate { global: dssetup_clear_domain_info; + lsa_lookup_name; + lsa_lookup_sid; mlsvc_disconnect; mlsvc_fini; mlsvc_init; mlsvc_join; - mlsvc_lookup_name; - mlsvc_lookup_sid; mlsvc_netlogon; smb_autohome_add; smb_autohome_remove; smb_locate_dc; smb_logon; smb_shr_add; - smb_shr_chkname; smb_shr_count; smb_shr_exec; smb_shr_get; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c index 9194ec7871..6ef7897fe1 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c @@ -38,6 +38,7 @@ #include <smbsrv/libsmbrdr.h> #include <smbsrv/libmlrpc.h> #include <smbsrv/libmlsvc.h> +#include <smbsrv/ndl/srvsvc.ndl> /* * Server info cache entry expiration in seconds. @@ -135,7 +136,6 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain, ndr_client_t *clnt; ndr_service_t *svc; srvsvc_server_info_t svinfo; - int remote_os; int fid; int rc; @@ -151,14 +151,17 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain, * 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 remote OS. + * None of the SRVSVC calls depend on the server info. */ - remote_os = NATIVE_OS_WIN2000; + bzero(&svinfo, sizeof (srvsvc_server_info_t)); + svinfo.sv_platform_id = SV_PLATFORM_ID_NT; + svinfo.sv_version_major = 5; + svinfo.sv_version_minor = 0; + svinfo.sv_type = SV_TYPE_DEFAULT; + svinfo.sv_os = NATIVE_OS_WIN2000; - if (strcasecmp(service, "SRVSVC") != 0) { - if (ndr_svinfo_lookup(server, domain, &svinfo) == 0) - remote_os = svinfo.sv_os; - } + if (strcasecmp(service, "SRVSVC") != 0) + (void) ndr_svinfo_lookup(server, domain, &svinfo); if ((clnt = malloc(sizeof (ndr_client_t))) == NULL) return (-1); @@ -185,7 +188,7 @@ ndr_rpc_bind(mlsvc_handle_t *handle, char *server, char *domain, bzero(&handle->handle, sizeof (ndr_hdid_t)); handle->clnt = clnt; - handle->remote_os = remote_os; + bcopy(&svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t)); if (ndr_rpc_get_heap(handle) == NULL) { free(clnt); @@ -248,6 +251,12 @@ ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) rc = ndr_clnt_call(clnt->binding, opnum, params); + /* + * Always clear the nonull flag to ensure + * it is not applied to subsequent calls. + */ + clnt->nonull = B_FALSE; + if (NDR_DRC_IS_FAULT(rc)) { ndr_rpc_release(handle); return (-1); @@ -257,12 +266,30 @@ ndr_rpc_call(mlsvc_handle_t *handle, int opnum, void *params) } /* - * Returns the Native-OS of the RPC server. + * Outgoing strings should not be null terminated. + */ +void +ndr_rpc_set_nonull(mlsvc_handle_t *handle) +{ + handle->clnt->nonull = B_TRUE; +} + +/* + * Return a reference to the server info. + */ +const srvsvc_server_info_t * +ndr_rpc_server_info(mlsvc_handle_t *handle) +{ + return (&handle->svinfo); +} + +/* + * Return the RPC server OS level. */ uint32_t ndr_rpc_server_os(mlsvc_handle_t *handle) { - return (handle->remote_os); + return (handle->svinfo.sv_os); } /* @@ -366,7 +393,7 @@ void ndr_inherit_handle(mlsvc_handle_t *child, mlsvc_handle_t *parent) { child->clnt = parent->clnt; - child->remote_os = parent->remote_os; + bcopy(&parent->svinfo, &child->svinfo, sizeof (srvsvc_server_info_t)); } void @@ -401,9 +428,10 @@ ndr_rpc_status(mlsvc_handle_t *handle, int opnum, DWORD status) static int ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa) { - ndr_stream_t *recv_nds = &mxa->recv_nds; - ndr_stream_t *send_nds = &mxa->send_nds; - ndr_heap_t *heap = clnt->heap; + ndr_stream_t *recv_nds = &mxa->recv_nds; + ndr_stream_t *send_nds = &mxa->send_nds; + ndr_heap_t *heap = clnt->heap; + int rc; if (heap == NULL) { if ((heap = ndr_heap_create()) == NULL) @@ -414,9 +442,23 @@ ndr_xa_init(ndr_client_t *clnt, ndr_xa_t *mxa) mxa->heap = heap; - nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap); - nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT, - NDR_MODE_RETURN_RECV, heap); + rc = nds_initialize(send_nds, 0, NDR_MODE_CALL_SEND, heap); + if (rc == 0) + rc = nds_initialize(recv_nds, NDR_PDU_SIZE_HINT_DEFAULT, + NDR_MODE_RETURN_RECV, heap); + + if (rc != 0) { + nds_destruct(&mxa->recv_nds); + nds_destruct(&mxa->send_nds); + ndr_heap_destroy(mxa->heap); + mxa->heap = NULL; + clnt->heap = NULL; + return (-1); + } + + if (clnt->nonull) + NDS_SETF(send_nds, NDS_F_NONULL); + return (0); } @@ -530,6 +572,9 @@ 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) @@ -549,6 +594,8 @@ ndr_svinfo_lookup(char *server, char *domain, srvsvc_server_info_t *svinfo) 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); } @@ -572,6 +619,8 @@ ndr_svinfo_lookup(char *server, char *domain, srvsvc_server_info_t *svinfo) (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; (void) mutex_unlock(&ndr_svlist.svl_mtx); return (0); } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c index ac4cda132f..80f26918a4 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c @@ -53,60 +53,6 @@ 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); -/* - * mlsvc_lookup_name - * - * This is just a wrapper for lsa_lookup_name. - * - * The memory for the sid is allocated using malloc so the caller should - * call free when it is no longer required. - */ -uint32_t -mlsvc_lookup_name(char *name, smb_sid_t **sid, uint16_t *sid_type) -{ - smb_account_t account; - uint32_t status; - - status = lsa_lookup_name(name, *sid_type, &account); - if (status == NT_STATUS_SUCCESS) { - *sid = account.a_sid; - account.a_sid = NULL; - *sid_type = account.a_type; - smb_account_free(&account); - } - - return (status); -} - -/* - * mlsvc_lookup_sid - * - * This is just a wrapper for lsa_lookup_sid. - * - * The allocated memory for the returned name must be freed by caller upon - * successful return. - */ -uint32_t -mlsvc_lookup_sid(smb_sid_t *sid, char **name) -{ - smb_account_t ainfo; - uint32_t status; - int namelen; - - if ((status = lsa_lookup_sid(sid, &ainfo)) == NT_STATUS_SUCCESS) { - namelen = strlen(ainfo.a_domain) + strlen(ainfo.a_name) + 2; - if ((*name = malloc(namelen)) != NULL) - (void) snprintf(*name, namelen, "%s\\%s", - ainfo.a_domain, ainfo.a_name); - else - status = NT_STATUS_NO_MEMORY; - - smb_account_free(&ainfo); - } - - return (status); -} - DWORD mlsvc_netlogon(char *server, char *domain) { diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c index 254102b85d..1c659bcc16 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c @@ -138,7 +138,7 @@ sam_create_account(char *server, char *domain_name, char *account_name, if (status == NT_STATUS_SUCCESS) { (void) samr_query_user_info(&user_handle, - SAMR_QUERY_USER_UNKNOWN16, &sui); + SAMR_QUERY_USER_CONTROL_INFO, &sui); (void) samr_get_user_pwinfo(&user_handle); (void) samr_set_user_info(&user_handle); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c index d29e7d3d64..3236ab5381 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c @@ -24,18 +24,21 @@ */ /* - * Security Access Manager RPC (SAMR) library interface functions for - * connect, open and close calls. The SAM is a hierarchical database. - * If you want to talk to the SAM you need a SAM handle, if you want - * to work with a domain, you need to use the SAM handle to obtain a - * domain handle. Then you can use the domain handle to obtain a user - * handle etc. Be careful about returning null handles to the - * application. Use of a null handle may crash the domain controller - * if you attempt to use it. + * Security Accounts Manager RPC (SAMR) client-side interface. + * + * The SAM is a hierarchical database: + * - If you want to talk to the SAM you need a SAM handle. + * - If you want to work with a domain, use the SAM handle. + * to obtain a domain handle. + * - Use domain handles to obtain user handles etc. + * + * Be careful about returning null handles to the application. Use of a + * null handle may crash the domain controller if you attempt to use it. */ #include <stdio.h> #include <strings.h> +#include <stdlib.h> #include <unistd.h> #include <netdb.h> #include <sys/param.h> @@ -46,6 +49,7 @@ #include <smbsrv/smbinfo.h> #include <smbsrv/ntstatus.h> #include <smbsrv/ntaccess.h> +#include <smbsrv/smb_sid.h> #include <samlib.h> /*LINTED E_STATIC_UNUSED*/ @@ -57,6 +61,12 @@ static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *); typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD, mlsvc_handle_t *); +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 * @@ -606,3 +616,479 @@ samr_create_user(mlsvc_handle_t *domain_handle, char *username, ndr_rpc_release(domain_handle); return (status); } + +/* + * samr_lookup_domain + * + * Lookup up the domain SID for the specified domain name. The handle + * should be one returned from samr_connect. The allocated memory for + * the returned SID must be freed by caller. + */ +smb_sid_t * +samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name) +{ + struct samr_LookupDomain arg; + smb_sid_t *domsid = NULL; + int opnum; + size_t length; + + if (ndr_is_null_handle(samr_handle) || domain_name == NULL) + return (NULL); + + opnum = SAMR_OPNUM_LookupDomain; + bzero(&arg, sizeof (struct samr_LookupDomain)); + + (void) memcpy(&arg.handle, &samr_handle->handle, + 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); + + arg.domain_name.length = length; + arg.domain_name.allosize = length; + arg.domain_name.str = (unsigned char *)domain_name; + + if (ndr_rpc_call(samr_handle, opnum, &arg) == 0) + domsid = smb_sid_dup((smb_sid_t *)arg.sid); + + ndr_rpc_release(samr_handle); + return (domsid); +} + +/* + * samr_enum_local_domains + * + * Get the list of local domains supported by a server. + * + * Returns NT status codes. + */ +DWORD +samr_enum_local_domains(mlsvc_handle_t *samr_handle) +{ + struct samr_EnumLocalDomain arg; + int opnum; + DWORD status; + + if (ndr_is_null_handle(samr_handle)) + return (NT_STATUS_INVALID_PARAMETER); + + opnum = SAMR_OPNUM_EnumLocalDomains; + bzero(&arg, sizeof (struct samr_EnumLocalDomain)); + + (void) memcpy(&arg.handle, &samr_handle->handle, + sizeof (samr_handle_t)); + arg.enum_context = 0; + arg.max_length = 0x00002000; /* Value used by NT */ + + if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { + status = NT_STATUS_INVALID_PARAMETER; + } else { + status = NT_SC_VALUE(arg.status); + + /* + * Handle none-mapped status quietly. + */ + if (status != NT_STATUS_NONE_MAPPED) + ndr_rpc_status(samr_handle, opnum, arg.status); + } + + ndr_rpc_release(samr_handle); + return (status); +} + +/* + * samr_lookup_domain_names + * + * Lookup up the given name in the domain specified by domain_handle. + * Upon a successful lookup the information is returned in the account + * arg and caller must free allocated memories by calling smb_account_free(). + * + * Returns NT status codes. + */ +uint32_t +samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, + smb_account_t *account) +{ + struct samr_LookupNames arg; + int opnum; + uint32_t status; + size_t length; + + if (ndr_is_null_handle(domain_handle) || + name == NULL || account == NULL) { + return (NT_STATUS_INVALID_PARAMETER); + } + + bzero(account, sizeof (smb_account_t)); + opnum = SAMR_OPNUM_LookupNames; + bzero(&arg, sizeof (struct samr_LookupNames)); + + (void) memcpy(&arg.handle, &domain_handle->handle, + sizeof (samr_handle_t)); + arg.n_entry = 1; + arg.max_n_entry = 1000; + arg.index = 0; + arg.total = 1; + + length = smb_wcequiv_strlen(name); + if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000) + length += sizeof (smb_wchar_t); + + arg.name.length = length; + arg.name.allosize = length; + arg.name.str = (unsigned char *)name; + + if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { + status = NT_STATUS_INVALID_PARAMETER; + } else if (arg.status != NT_STATUS_SUCCESS) { + status = NT_SC_VALUE(arg.status); + + /* + * Handle none-mapped status quietly. + */ + if (status != NT_STATUS_NONE_MAPPED) + ndr_rpc_status(domain_handle, opnum, arg.status); + } else { + account->a_type = arg.rid_types.rid_type[0]; + account->a_rid = arg.rids.rid[0]; + status = NT_STATUS_SUCCESS; + } + + ndr_rpc_release(domain_handle); + return (status); +} + +/* + * samr_query_user_info + * + * 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. + */ +int +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); + + opnum = SAMR_OPNUM_QueryUserInfo; + bzero(&arg, sizeof (struct samr_QueryUserInfo)); + + (void) memcpy(&arg.user_handle, &user_handle->handle, + 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 (arg.status != 0) + rc = -1; + else + rc = samr_setup_user_info(switch_value, &arg, user_info); + + ndr_rpc_release(user_handle); + return (rc); +} + +/* + * samr_setup_user_info + * + * Private function to set up the samr_user_info data. Dependent on + * the switch value this function may use strdup which will malloc + * memory. The caller is responsible for deallocating this memory. + * + * Returns 0 on success, otherwise returns -1. + */ +static int +samr_setup_user_info(WORD switch_value, + struct samr_QueryUserInfo *arg, union samr_user_info *user_info) +{ + struct samr_QueryUserInfo1 *info1; + struct samr_QueryUserInfo6 *info6; + + switch (switch_value) { + case 1: + info1 = &arg->ru.info1; + user_info->info1.username = strdup( + (char const *)info1->username.str); + user_info->info1.fullname = strdup( + (char const *)info1->fullname.str); + user_info->info1.description = strdup( + (char const *)info1->description.str); + user_info->info1.unknown = 0; + user_info->info1.group_rid = info1->group_rid; + return (0); + + case 6: + info6 = &arg->ru.info6; + user_info->info6.username = strdup( + (char const *)info6->username.str); + user_info->info6.fullname = strdup( + (char const *)info6->fullname.str); + return (0); + + case 7: + user_info->info7.username = strdup( + (char const *)arg->ru.info7.username.str); + return (0); + + case 8: + user_info->info8.fullname = strdup( + (char const *)arg->ru.info8.fullname.str); + return (0); + + case 9: + user_info->info9.group_rid = arg->ru.info9.group_rid; + return (0); + + case 16: + return (0); + + default: + break; + }; + + return (-1); +} + +/* + * samr_query_user_groups + * + * Query the groups for a specific user. The handle must be a valid + * user handle obtained via samr_open_user. The list of groups is + * returned in group_info. Note that group_info->groups is allocated + * using malloc. The caller is responsible for deallocating this + * memory when it is no longer required. If group_info->n_entry is 0 + * then no memory was allocated. + * + * Returns 0 on success, otherwise returns -1. + */ +int +samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups, + struct samr_UserGroups **groups) +{ + struct samr_QueryUserGroups arg; + int opnum; + int rc; + int nbytes; + + if (ndr_is_null_handle(user_handle)) + return (-1); + + opnum = SAMR_OPNUM_QueryUserGroups; + bzero(&arg, sizeof (struct samr_QueryUserGroups)); + + (void) memcpy(&arg.user_handle, &user_handle->handle, + sizeof (samr_handle_t)); + + rc = ndr_rpc_call(user_handle, opnum, &arg); + if (rc == 0) { + if (arg.info == 0) { + rc = -1; + } else { + nbytes = arg.info->n_entry * + sizeof (struct samr_UserGroups); + + if ((*groups = malloc(nbytes)) == NULL) { + *n_groups = 0; + rc = -1; + } else { + *n_groups = arg.info->n_entry; + bcopy(arg.info->groups, *groups, nbytes); + } + } + } + + ndr_rpc_release(user_handle); + return (rc); +} + +/* + * samr_get_user_pwinfo + * + * Get some user password info. I'm not sure what this is yet but it is + * part of the create user sequence. The handle must be a valid user + * handle. Since I don't know what this is returning, I haven't provided + * any return data yet. + * + * Returns 0 on success. Otherwise returns an NT status code. + */ +DWORD +samr_get_user_pwinfo(mlsvc_handle_t *user_handle) +{ + struct samr_GetUserPwInfo arg; + int opnum; + DWORD status; + + if (ndr_is_null_handle(user_handle)) + return (NT_STATUS_INVALID_PARAMETER); + + opnum = SAMR_OPNUM_GetUserPwInfo; + bzero(&arg, sizeof (struct samr_GetUserPwInfo)); + (void) memcpy(&arg.user_handle, &user_handle->handle, + sizeof (samr_handle_t)); + + if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { + status = NT_STATUS_INVALID_PARAMETER; + } else if (arg.status != 0) { + ndr_rpc_status(user_handle, opnum, arg.status); + status = NT_SC_VALUE(arg.status); + } else { + status = 0; + } + + ndr_rpc_release(user_handle); + return (status); +} + +/* + * samr_set_user_info + * + * Returns 0 on success. Otherwise returns an NT status code. + * NT status codes observed so far: + * NT_STATUS_WRONG_PASSWORD + */ +/*ARGSUSED*/ +DWORD +samr_set_user_info(mlsvc_handle_t *user_handle) +{ + unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ]; + struct samr_SetUserInfo arg; + int opnum; + DWORD status = 0; + + if (ndr_is_null_handle(user_handle)) + return (NT_STATUS_INVALID_PARAMETER); + + if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key))) + return (NT_STATUS_INVALID_PARAMETER); + + opnum = SAMR_OPNUM_SetUserInfo; + bzero(&arg, sizeof (struct samr_SetUserInfo)); + (void) memcpy(&arg.user_handle, &user_handle->handle, + sizeof (samr_handle_t)); + + 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) { + 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; +} + +/* + * 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. + */ +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) +{ + char hostname[NETBIOS_NAME_SZ]; + + randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ); + + /* + * The new password is going to be the NetBIOS name of the system + * in lower case. + */ + if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) + return (-1); + + (void) smb_strlwr(hostname); + + /* + * Generate the OEM password from the hostname and the user session + * key(nt_key). + */ + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + (void) sam_oem_password((oem_password_t *)oem_password, + (unsigned char *)hostname, nt_key); + return (0); +} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c deleted file mode 100644 index 477a5a1e62..0000000000 --- a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Security Access Manager RPC (SAMR) library interface functions for - * query and lookup calls. - */ - - -#include <stdio.h> -#include <strings.h> -#include <stdlib.h> -#include <unistd.h> - -#include <smbsrv/libsmb.h> -#include <smbsrv/libmlsvc.h> -#include <smbsrv/ntstatus.h> -#include <smbsrv/smb_sid.h> -#include <samlib.h> -#include <smbsrv/libmlrpc.h> - -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_lookup_domain - * - * Lookup up the domain SID for the specified domain name. The handle - * should be one returned from samr_connect. The allocated memory for - * the returned SID must be freed by caller. - */ -smb_sid_t * -samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name) -{ - struct samr_LookupDomain arg; - smb_sid_t *domsid = NULL; - int opnum; - size_t length; - - if (ndr_is_null_handle(samr_handle) || domain_name == NULL) - return (NULL); - - opnum = SAMR_OPNUM_LookupDomain; - bzero(&arg, sizeof (struct samr_LookupDomain)); - - (void) memcpy(&arg.handle, &samr_handle->handle, - 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); - - arg.domain_name.length = length; - arg.domain_name.allosize = length; - arg.domain_name.str = (unsigned char *)domain_name; - - if (ndr_rpc_call(samr_handle, opnum, &arg) == 0) - domsid = smb_sid_dup((smb_sid_t *)arg.sid); - - ndr_rpc_release(samr_handle); - return (domsid); -} - -/* - * samr_enum_local_domains - * - * Get the list of local domains supported by a server. - * - * Returns NT status codes. - */ -DWORD -samr_enum_local_domains(mlsvc_handle_t *samr_handle) -{ - struct samr_EnumLocalDomain arg; - int opnum; - DWORD status; - - if (ndr_is_null_handle(samr_handle)) - return (NT_STATUS_INVALID_PARAMETER); - - opnum = SAMR_OPNUM_EnumLocalDomains; - bzero(&arg, sizeof (struct samr_EnumLocalDomain)); - - (void) memcpy(&arg.handle, &samr_handle->handle, - sizeof (samr_handle_t)); - arg.enum_context = 0; - arg.max_length = 0x00002000; /* Value used by NT */ - - if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else { - status = NT_SC_VALUE(arg.status); - - /* - * Handle none-mapped status quietly. - */ - if (status != NT_STATUS_NONE_MAPPED) - ndr_rpc_status(samr_handle, opnum, arg.status); - } - - ndr_rpc_release(samr_handle); - return (status); -} - -/* - * samr_lookup_domain_names - * - * Lookup up the given name in the domain specified by domain_handle. - * Upon a successful lookup the information is returned in the account - * arg and caller must free allocated memories by calling smb_account_free(). - * - * Returns NT status codes. - */ -uint32_t -samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, - smb_account_t *account) -{ - struct samr_LookupNames arg; - int opnum; - uint32_t status; - size_t length; - - if (ndr_is_null_handle(domain_handle) || - name == NULL || account == NULL) { - return (NT_STATUS_INVALID_PARAMETER); - } - - bzero(account, sizeof (smb_account_t)); - opnum = SAMR_OPNUM_LookupNames; - bzero(&arg, sizeof (struct samr_LookupNames)); - - (void) memcpy(&arg.handle, &domain_handle->handle, - sizeof (samr_handle_t)); - arg.n_entry = 1; - arg.max_n_entry = 1000; - arg.index = 0; - arg.total = 1; - - length = smb_wcequiv_strlen(name); - if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000) - length += sizeof (smb_wchar_t); - - arg.name.length = length; - arg.name.allosize = length; - arg.name.str = (unsigned char *)name; - - if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.status != NT_STATUS_SUCCESS) { - status = NT_SC_VALUE(arg.status); - - /* - * Handle none-mapped status quietly. - */ - if (status != NT_STATUS_NONE_MAPPED) - ndr_rpc_status(domain_handle, opnum, arg.status); - } else { - account->a_type = arg.rid_types.rid_type[0]; - account->a_rid = arg.rids.rid[0]; - status = NT_STATUS_SUCCESS; - } - - ndr_rpc_release(domain_handle); - return (status); -} - -/* - * samr_query_user_info - * - * 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. - */ -int -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); - - opnum = SAMR_OPNUM_QueryUserInfo; - bzero(&arg, sizeof (struct samr_QueryUserInfo)); - - (void) memcpy(&arg.user_handle, &user_handle->handle, - 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 (arg.status != 0) - rc = -1; - else - rc = samr_setup_user_info(switch_value, &arg, user_info); - - ndr_rpc_release(user_handle); - return (rc); -} - -/* - * samr_setup_user_info - * - * Private function to set up the samr_user_info data. Dependent on - * the switch value this function may use strdup which will malloc - * memory. The caller is responsible for deallocating this memory. - * - * Returns 0 on success, otherwise returns -1. - */ -static int -samr_setup_user_info(WORD switch_value, - struct samr_QueryUserInfo *arg, union samr_user_info *user_info) -{ - struct samr_QueryUserInfo1 *info1; - struct samr_QueryUserInfo6 *info6; - - switch (switch_value) { - case 1: - info1 = &arg->ru.info1; - user_info->info1.username = strdup( - (char const *)info1->username.str); - user_info->info1.fullname = strdup( - (char const *)info1->fullname.str); - user_info->info1.description = strdup( - (char const *)info1->description.str); - user_info->info1.unknown = 0; - user_info->info1.group_rid = info1->group_rid; - return (0); - - case 6: - info6 = &arg->ru.info6; - user_info->info6.username = strdup( - (char const *)info6->username.str); - user_info->info6.fullname = strdup( - (char const *)info6->fullname.str); - return (0); - - case 7: - user_info->info7.username = strdup( - (char const *)arg->ru.info7.username.str); - return (0); - - case 8: - user_info->info8.fullname = strdup( - (char const *)arg->ru.info8.fullname.str); - return (0); - - case 9: - user_info->info9.group_rid = arg->ru.info9.group_rid; - return (0); - - case 16: - return (0); - - default: - break; - }; - - return (-1); -} - -/* - * samr_query_user_groups - * - * Query the groups for a specific user. The handle must be a valid - * user handle obtained via samr_open_user. The list of groups is - * returned in group_info. Note that group_info->groups is allocated - * using malloc. The caller is responsible for deallocating this - * memory when it is no longer required. If group_info->n_entry is 0 - * then no memory was allocated. - * - * Returns 0 on success, otherwise returns -1. - */ -int -samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups, - struct samr_UserGroups **groups) -{ - struct samr_QueryUserGroups arg; - int opnum; - int rc; - int nbytes; - - if (ndr_is_null_handle(user_handle)) - return (-1); - - opnum = SAMR_OPNUM_QueryUserGroups; - bzero(&arg, sizeof (struct samr_QueryUserGroups)); - - (void) memcpy(&arg.user_handle, &user_handle->handle, - sizeof (samr_handle_t)); - - rc = ndr_rpc_call(user_handle, opnum, &arg); - if (rc == 0) { - if (arg.info == 0) { - rc = -1; - } else { - nbytes = arg.info->n_entry * - sizeof (struct samr_UserGroups); - - if ((*groups = malloc(nbytes)) == NULL) { - *n_groups = 0; - rc = -1; - } else { - *n_groups = arg.info->n_entry; - bcopy(arg.info->groups, *groups, nbytes); - } - } - } - - ndr_rpc_release(user_handle); - return (rc); -} - -/* - * samr_get_user_pwinfo - * - * Get some user password info. I'm not sure what this is yet but it is - * part of the create user sequence. The handle must be a valid user - * handle. Since I don't know what this is returning, I haven't provided - * any return data yet. - * - * Returns 0 on success. Otherwise returns an NT status code. - */ -DWORD -samr_get_user_pwinfo(mlsvc_handle_t *user_handle) -{ - struct samr_GetUserPwInfo arg; - int opnum; - DWORD status; - - if (ndr_is_null_handle(user_handle)) - return (NT_STATUS_INVALID_PARAMETER); - - opnum = SAMR_OPNUM_GetUserPwInfo; - bzero(&arg, sizeof (struct samr_GetUserPwInfo)); - (void) memcpy(&arg.user_handle, &user_handle->handle, - sizeof (samr_handle_t)); - - if (ndr_rpc_call(user_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.status != 0) { - ndr_rpc_status(user_handle, opnum, arg.status); - status = NT_SC_VALUE(arg.status); - } else { - status = 0; - } - - ndr_rpc_release(user_handle); - return (status); -} - -/* - * samr_set_user_info - * - * Returns 0 on success. Otherwise returns an NT status code. - * NT status codes observed so far: - * NT_STATUS_WRONG_PASSWORD - */ -/*ARGSUSED*/ -DWORD -samr_set_user_info(mlsvc_handle_t *user_handle) -{ - unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ]; - struct samr_SetUserInfo arg; - int opnum; - DWORD status = 0; - - if (ndr_is_null_handle(user_handle)) - return (NT_STATUS_INVALID_PARAMETER); - - if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key))) - return (NT_STATUS_INVALID_PARAMETER); - - opnum = SAMR_OPNUM_SetUserInfo; - bzero(&arg, sizeof (struct samr_SetUserInfo)); - (void) memcpy(&arg.user_handle, &user_handle->handle, - sizeof (samr_handle_t)); - - 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) { - 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; -} - -/* - * 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. - */ -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) -{ - char hostname[NETBIOS_NAME_SZ]; - - randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ); - - /* - * The new password is going to be the NetBIOS name of the system - * in lower case. - */ - if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) - return (-1); - - (void) smb_strlwr(hostname); - - /* - * Generate the OEM password from the hostname and the user session - * key(nt_key). - */ - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - (void) sam_oem_password((oem_password_t *)oem_password, - (unsigned char *)hostname, nt_key); - return (0); -} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c index a56214954e..d8a477ef6e 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c @@ -24,7 +24,13 @@ */ /* - * Security Accounts Manager RPC (SAMR) interface definition. + * Security Accounts Manager RPC (SAMR) server-side interface. + * + * The SAM is a hierarchical database: + * - If you want to talk to the SAM you need a SAM handle. + * - If you want to work with a domain, use the SAM handle. + * to obtain a domain handle. + * - Use domain handles to obtain user handles etc. */ #include <strings.h> @@ -629,12 +635,7 @@ samr_s_OpenUser(void *arg, ndr_xa_t *mxa) param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); } else { bcopy(id, ¶m->user_handle, sizeof (samr_handle_t)); - /* - * Need QueryUserInfo(level 21). - */ - samr_hdfree(mxa, id); - bzero(¶m->user_handle, sizeof (samr_handle_t)); - param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + param->status = NT_STATUS_SUCCESS; } return (NDR_DRC_OK); @@ -660,8 +661,6 @@ samr_s_DeleteUser(void *arg, ndr_xa_t *mxa) /* * samr_s_QueryUserInfo * - * The caller should provide a valid user key. - * * Returns: * NT_STATUS_SUCCESS * NT_STATUS_ACCESS_DENIED @@ -671,10 +670,72 @@ samr_s_DeleteUser(void *arg, ndr_xa_t *mxa) static int samr_s_QueryUserInfo(void *arg, ndr_xa_t *mxa) { - struct samr_QueryUserInfo *param = arg; + static uint16_t owf_buf[8]; + static uint8_t hour_buf[SAMR_SET_USER_HOURS_SZ]; + struct samr_QueryUserInfo *param = arg; + struct samr_QueryUserInfo21 *all_info; + ndr_hdid_t *id; + ndr_handle_t *hd; + samr_keydata_t *data; + smb_domain_t di; + smb_account_t account; + smb_sid_t *sid; + uint32_t status; + + id = (ndr_hdid_t *)¶m->user_handle; + if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_USER)) == NULL) { + status = NT_STATUS_INVALID_HANDLE; + goto QueryUserInfoError; + } + + data = (samr_keydata_t *)hd->nh_data; + + if (param->switch_value != SAMR_QUERY_USER_ALL_INFO) { + status = NT_STATUS_ACCESS_DENIED; + goto QueryUserInfoError; + } + if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) { + status = NT_STATUS_ACCESS_DENIED; + goto QueryUserInfoError; + } + + if ((sid = smb_sid_splice(di.di_binsid, data->kd_rid)) == NULL) { + status = NT_STATUS_ACCESS_DENIED; + goto QueryUserInfoError; + } + + if (smb_sam_lookup_sid(sid, &account) != NT_STATUS_SUCCESS) { + status = NT_STATUS_ACCESS_DENIED; + goto QueryUserInfoError; + } + + all_info = ¶m->ru.info21; + bzero(all_info, sizeof (struct samr_QueryUserInfo21)); + + all_info->WhichFields = SAMR_USER_ALL_USERNAME | SAMR_USER_ALL_USERID; + + (void) NDR_MSTRING(mxa, account.a_name, + (ndr_mstring_t *)&all_info->UserName); + all_info->UserId = data->kd_rid; + + all_info->LmOwfPassword.length = 16; + all_info->LmOwfPassword.maxlen = 16; + all_info->LmOwfPassword.buf = owf_buf; + all_info->NtOwfPassword.length = 16; + all_info->NtOwfPassword.maxlen = 16; + all_info->NtOwfPassword.buf = owf_buf; + all_info->LogonHours.units_per_week = SAMR_HOURS_PER_WEEK; + all_info->LogonHours.hours = hour_buf; + + param->address = 1; + param->switch_index = SAMR_QUERY_USER_ALL_INFO; + param->status = NT_STATUS_SUCCESS; + return (NDR_DRC_OK); + +QueryUserInfoError: bzero(param, sizeof (struct samr_QueryUserInfo)); - param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + param->status = NT_SC_ERROR(status); return (NDR_DRC_OK); } @@ -1567,6 +1628,7 @@ fixup_samr_QueryUserInfo(struct samr_QueryUserInfo *val) CASE_INFO_ENT(samr_QueryUserInfo, 8); CASE_INFO_ENT(samr_QueryUserInfo, 9); CASE_INFO_ENT(samr_QueryUserInfo, 16); + CASE_INFO_ENT(samr_QueryUserInfo, 21); default: return; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c index 695bfb55b7..ba6f81c3fb 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c @@ -68,10 +68,11 @@ static void smb_autohome_parse_options(smb_share_t *); * autohome shares. */ void -smb_autohome_add(const char *username) +smb_autohome_add(const smb_token_t *token) { - smb_share_t si; - smb_autohome_t *ai; + smb_share_t si; + smb_autohome_t *ai; + char *username = token->tkn_account_name; assert(username); @@ -98,8 +99,11 @@ smb_autohome_add(const char *username) (void) strlcpy(si.shr_name, username, MAXNAMELEN); (void) strlcpy(si.shr_container, ai->ah_container, MAXPATHLEN); + (void) strlcpy(si.shr_cmnt, "Autohome", SMB_SHARE_CMNT_MAX); smb_autohome_parse_options(&si); si.shr_flags |= SMB_SHRF_TRANS | SMB_SHRF_AUTOHOME; + si.shr_uid = token->tkn_user.i_id; + si.shr_gid = token->tkn_primary_grp.i_id; (void) smb_shr_add(&si); } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c index 5b78165a68..d626a443f4 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c @@ -434,7 +434,8 @@ smb_logon(netr_client_t *clnt) status = smb_logon_anon(clnt, token); if (status == NT_STATUS_INVALID_LOGON_TYPE) { status = smb_logon_local(clnt, token); - if (status != NT_STATUS_SUCCESS) { + if ((status != NT_STATUS_SUCCESS) && + (smb_config_get_secmode() == SMB_SECMODE_DOMAIN)) { if ((status == NT_STATUS_INVALID_LOGON_TYPE) || (*clnt->e_domain == '\0')) status = smb_logon_domain(clnt, token); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c index d42622dfca..0c8f4b296b 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c @@ -384,7 +384,7 @@ smb_shr_add(smb_share_t *si) assert(si != NULL); - if (!smb_shr_chkname(si->shr_name)) + if (smb_name_validate_share(si->shr_name) != ERROR_SUCCESS) return (ERROR_INVALID_NAME); if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) @@ -450,7 +450,7 @@ smb_shr_remove(char *sharename) assert(sharename != NULL); - if (!smb_shr_chkname(sharename)) + if (smb_name_validate_share(sharename) != ERROR_SUCCESS) return (ERROR_INVALID_NAME); if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) @@ -507,7 +507,8 @@ smb_shr_rename(char *from_name, char *to_name) assert((from_name != NULL) && (to_name != NULL)); - if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name)) + if (smb_name_validate_share(from_name) != ERROR_SUCCESS || + smb_name_validate_share(to_name) != ERROR_SUCCESS) return (ERROR_INVALID_NAME); if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success) @@ -830,34 +831,6 @@ smb_shr_is_admin(char *sharename) } /* - * smb_shr_chkname - * - * Check for invalid characters in a share name. The list of invalid - * characters includes control characters and the following: - * - * " / \ [ ] : | < > + ; , ? * = - */ -boolean_t -smb_shr_chkname(char *sharename) -{ - char *invalid = "\"/\\[]:|<>+;,?*="; - char *cp; - - if (sharename == NULL) - return (B_FALSE); - - if (strpbrk(sharename, invalid)) - return (B_FALSE); - - for (cp = sharename; *cp != '\0'; cp++) { - if (iscntrl(*cp)) - return (B_FALSE); - } - - return (B_TRUE); -} - -/* * smb_shr_get_realpath * * Derive the real path for a share from the path provided by a client. diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c index a5a3aad694..4b92b5dc58 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c @@ -40,6 +40,7 @@ #define SRVSVC_ACE_OFFSET 8 #define SRVSVC_SID_OFFSET 8 +static uint32_t srvsvc_sd_get_autohome(const smb_share_t *, smb_sd_t *); static uint32_t srvsvc_sd_status_to_error(uint32_t); static uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); static uint32_t srvsvc_sd_set_absolute(uint8_t *, smb_sd_t *); @@ -151,13 +152,19 @@ srvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size) if (sdbuf == NULL && size == NULL) return (ERROR_INVALID_PARAMETER); - ret = srvsvc_shareacl_getpath(si, path); - if (ret != 0) - return (ERROR_PATH_NOT_FOUND); - bzero(&sd, sizeof (smb_sd_t)); - status = smb_sd_read(path, &sd, SMB_ALL_SECINFO); - status = srvsvc_sd_status_to_error(status); + + if (si->shr_flags & SMB_SHRF_AUTOHOME) { + status = srvsvc_sd_get_autohome(si, &sd); + } else { + ret = srvsvc_shareacl_getpath(si, path); + if (ret != 0) + return (ERROR_PATH_NOT_FOUND); + + status = smb_sd_read(path, &sd, SMB_ALL_SECINFO); + status = srvsvc_sd_status_to_error(status); + } + if (status != ERROR_SUCCESS) { smb_sd_term(&sd); return (status); @@ -175,6 +182,28 @@ srvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size) return (status); } +static uint32_t +srvsvc_sd_get_autohome(const smb_share_t *si, smb_sd_t *sd) +{ + smb_fssd_t fs_sd; + acl_t *acl; + uint32_t status; + + if (acl_fromtext("owner@:rwxpdDaARWcCos::allow", &acl) != 0) + return (ERROR_NOT_ENOUGH_MEMORY); + + smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); + fs_sd.sd_uid = si->shr_uid; + fs_sd.sd_gid = si->shr_gid; + fs_sd.sd_zdacl = acl; + fs_sd.sd_zsacl = NULL; + + status = smb_sd_fromfs(&fs_sd, sd); + status = srvsvc_sd_status_to_error(status); + smb_fssd_term(&fs_sd); + return (status); +} + /* * This method converts an ACE from absolute (pointer) to * self relative (flat buffer) format. diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c index 08eeca4462..d829d4335f 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c @@ -57,8 +57,6 @@ #include <smbsrv/smb_common_door.h> #include "mlsvc.h" -#define SV_TYPE_SENT_BY_ME (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_NT) - /* * Qualifier types for NetConnectEnum. */ @@ -1678,7 +1676,7 @@ netservergetinfo_no_memory: info101->sv101_platform_id = SV_PLATFORM_ID_NT; info101->sv101_version_major = 4; info101->sv101_version_minor = 0; - info101->sv101_type = SV_TYPE_SENT_BY_ME; + info101->sv101_type = SV_TYPE_DEFAULT; info101->sv101_name = (uint8_t *)NDR_STRDUP(mxa, hostname); info101->sv101_comment = (uint8_t *)NDR_STRDUP(mxa, sys_comment); @@ -1699,7 +1697,7 @@ netservergetinfo_no_memory: info102->sv102_platform_id = SV_PLATFORM_ID_NT; info102->sv102_version_major = 4; info102->sv102_version_minor = 0; - info102->sv102_type = SV_TYPE_SENT_BY_ME; + info102->sv102_type = SV_TYPE_DEFAULT; info102->sv102_name = (uint8_t *)NDR_STRDUP(mxa, hostname); info102->sv102_comment = (uint8_t *)NDR_STRDUP(mxa, sys_comment); @@ -1843,11 +1841,6 @@ srvsvc_s_NetRemoteTOD(void *arg, ndr_xa_t *mxa) * * Perform name validation. * - * The share name is considered invalid if it contains any of the - * following character (MSDN 236388). - * - * " / \ [ ] : | < > + ; , ? * = - * * Returns Win32 error codes. */ /*ARGSUSED*/ @@ -1856,6 +1849,7 @@ srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa) { struct mslm_NetNameValidate *param = arg; char *name; + int maxlen; int len; if ((name = (char *)param->pathname) == NULL) { @@ -1863,34 +1857,41 @@ srvsvc_s_NetNameValidate(void *arg, ndr_xa_t *mxa) return (NDR_DRC_OK); } - len = strlen(name); - - if ((param->flags == 0 && len > 81) || - (param->flags == 0x80000000 && len > 13)) { - param->status = ERROR_INVALID_NAME; - return (NDR_DRC_OK); - } - switch (param->type) { case NAMETYPE_SHARE: - if (smb_shr_chkname(name)) - param->status = ERROR_SUCCESS; - else + len = strlen(name); + maxlen = (param->flags & NAMEFLAG_LM2) ? + SMB_SHARE_OEMNAME_MAX : SMB_SHARE_NTNAME_MAX; + + if (len > maxlen) { param->status = ERROR_INVALID_NAME; + return (NDR_DRC_OK); + } + + param->status = smb_name_validate_share(name); break; case NAMETYPE_USER: - case NAMETYPE_PASSWORD: case NAMETYPE_GROUP: + param->status = smb_name_validate_account(name); + break; + + case NAMETYPE_DOMAIN: /* NetBIOS domain name */ + param->status = smb_name_validate_nbdomain(name); + break; + + case NAMETYPE_WORKGROUP: + param->status = smb_name_validate_workgroup(name); + break; + + case NAMETYPE_PASSWORD: case NAMETYPE_COMPUTER: case NAMETYPE_EVENT: - case NAMETYPE_DOMAIN: case NAMETYPE_SERVICE: case NAMETYPE_NET: case NAMETYPE_MESSAGE: case NAMETYPE_MESSAGEDEST: case NAMETYPE_SHAREPASSWORD: - case NAMETYPE_WORKGROUP: param->status = ERROR_NOT_SUPPORTED; break; diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h index 189bce0021..f9acbec34c 100644 --- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h @@ -47,6 +47,7 @@ extern "C" { #include <smbsrv/smb_idmap.h> #include <smbsrv/netbios.h> #include <smbsrv/smb_share.h> +#include <smbsrv/nterror.h> #include <smbsrv/ntstatus.h> #include <smbsrv/smb_door_svc.h> #include <smbsrv/alloc.h> @@ -697,8 +698,8 @@ int smb_lgrp_iteropen(smb_giter_t *); void smb_lgrp_iterclose(smb_giter_t *); int smb_lgrp_iterate(smb_giter_t *, smb_group_t *); -int smb_lookup_sid(smb_sid_t *, char *buf, int buflen); -int smb_lookup_name(char *, smb_gsid_t *); +int smb_lookup_sid(const char *, lsa_account_t *); +int smb_lookup_name(const char *, sid_type_t, lsa_account_t *); #define SMB_LGRP_SUCCESS 0 #define SMB_LGRP_INVALID_ARG 1 @@ -733,9 +734,7 @@ int smb_lookup_name(char *, smb_gsid_t *); #define SMB_LGRP_LOOKUP_FAILED 30 #define SMB_LGRP_NOT_SUPPORTED 31 -#define SMB_LGRP_NAME_CHAR_MAX 32 #define SMB_LGRP_COMMENT_MAX 256 -#define SMB_LGRP_NAME_MAX (SMB_LGRP_NAME_CHAR_MAX * MTS_MB_CHAR_MAX + 1) /* * values for smb_nic_t.smbflags @@ -847,6 +846,7 @@ boolean_t smb_account_validate(smb_account_t *); */ uint32_t smb_sd_read(char *path, smb_sd_t *, uint32_t); uint32_t smb_sd_write(char *path, smb_sd_t *, uint32_t); +uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *); /* Kernel Module Interface */ int smb_kmod_bind(void); @@ -867,6 +867,13 @@ void smb_kmod_enum_fini(smb_netsvc_t *); int smb_kmod_session_close(const char *, const char *); int smb_kmod_file_close(uint32_t); +void smb_name_parse(char *, char **, char **); +uint32_t smb_name_validate_share(const char *); +uint32_t smb_name_validate_account(const char *); +uint32_t smb_name_validate_domain(const char *); +uint32_t smb_name_validate_nbdomain(const char *); +uint32_t smb_name_validate_workgroup(const char *); + /* * Interposer library validation */ diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers index 4191970939..43e39c72da 100644 --- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers @@ -70,6 +70,7 @@ SUNWprivate { list_prev; list_remove; list_tail; + lsa_account_xdr; netr_client_mkabsolute; netr_client_xfree; oemtoucs; @@ -280,6 +281,12 @@ SUNWprivate { smb_msgbuf_term; smb_msgbuf_used; smb_msgbuf_word_align; + smb_name_parse; + smb_name_validate_account; + smb_name_validate_share; + smb_name_validate_domain; + smb_name_validate_nbdomain; + smb_name_validate_workgroup; smb_netconnectinfo_decode; smb_netconnectinfo_encode; smb_netfileinfo_decode; @@ -330,6 +337,7 @@ SUNWprivate { smb_sam_usr_groups; smb_sbequiv_strlen; smb_sd_get_secinfo; + smb_sd_fromfs; smb_sd_init; smb_sd_len; smb_sd_term; @@ -348,6 +356,7 @@ SUNWprivate { smb_sid_len; smb_sid_splice; smb_sid_split; + smb_sid_splitstr; smb_sid_tostr; smb_sid_type2str; smb_smf_maintenance_mode; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c index 417bc55896..e6fb3fe6ca 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c @@ -41,121 +41,110 @@ #include <smbsrv/smb_common_door.h> /* - * smb_lookup_sid + * Given a SID, make a door call to get the associated name. * - * Tries to get the account name associated with the given SID - * The mapping is requested to be performed by smbd via a door - * call. If no account name can be found the string format of - * the SID will be returned as the name. + * Returns 0 if the door call is successful, otherwise -1. * - * The passed namebuf should be big enough to hold the string - * format of a SID. + * If 0 is returned, the lookup result will be available in a_status. + * NT_STATUS_SUCCESS The SID was mapped to a name. + * NT_STATUS_NONE_MAPPED The SID could not be mapped to a name. */ int -smb_lookup_sid(smb_sid_t *sid, char *namebuf, int namebuflen) +smb_lookup_sid(const char *sid, lsa_account_t *acct) { - door_arg_t arg; - char *buf; - size_t len; - int opcode = SMB_DR_LOOKUP_SID; - char *name = NULL; - int fd; + door_arg_t arg; + char *buf; + size_t len; + int opcode = SMB_DR_LOOKUP_SID; + int fd; + int rc; - assert((namebuf != NULL) && (namebuflen != 0)); + assert((sid != NULL) && (acct != NULL)); - if (!smb_sid_isvalid(sid)) - return (NT_STATUS_INVALID_SID); + bzero(acct, sizeof (lsa_account_t)); + (void) strlcpy(acct->a_sid, sid, SMB_SID_STRSZ); - smb_sid_tostr(sid, namebuf); - - if ((fd = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) { - /* returning string SID */ - return (NT_STATUS_SUCCESS); - } + if ((fd = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) + return (-1); - if ((buf = smb_dr_encode_string(opcode, namebuf, &len)) == 0) { - /* returning string SID */ + buf = smb_dr_encode_common(opcode, acct, lsa_account_xdr, &len); + if (buf == NULL) { (void) close(fd); - return (NT_STATUS_SUCCESS); + return (-1); } smb_dr_clnt_setup(&arg, buf, len); - if (smb_dr_clnt_call(fd, &arg) == 0) { + if ((rc = smb_dr_clnt_call(fd, &arg)) == 0) { buf = arg.rbuf + SMB_DR_DATA_OFFSET; len = arg.rsize - SMB_DR_DATA_OFFSET; - name = smb_dr_decode_string(buf, len); + + rc = smb_dr_decode_common(buf, len, lsa_account_xdr, acct); } smb_dr_clnt_cleanup(&arg); (void) close(fd); - - if (name) { - if (*name != '\0') - (void) strlcpy(namebuf, name, namebuflen); - - xdr_free(xdr_string, (char *)&name); - } - - return (NT_STATUS_SUCCESS); + return (rc); } /* - * smb_lookup_name + * Given a name, make a door call to get the associated SID. * - * Tries to get the SID associated with the given account name - * The mapping is requested to be performed by smbd via a door - * call. If no SID can be found NT_STATUS_NONE_MAPPED is returned. + * Returns 0 if the door call is successful, otherwise -1. + * + * If 0 is returned, the lookup result will be available in a_status. + * NT_STATUS_SUCCESS The name was mapped to a SID. + * NT_STATUS_NONE_MAPPED The name could not be mapped to a SID. */ int -smb_lookup_name(char *name, smb_gsid_t *sid) +smb_lookup_name(const char *name, sid_type_t sidtype, lsa_account_t *acct) { - door_arg_t arg; - char *buf; - size_t len; - int opcode = SMB_DR_LOOKUP_NAME; - char *strsid = NULL; - char *p; - int fd; - - assert(name && sid); - - if (*name == '\0') - return (NT_STATUS_NONE_MAPPED); + char tmp[MAXNAMELEN]; + door_arg_t arg; + char *buf; + char *dp = NULL; + char *np = NULL; + size_t len; + int opcode = SMB_DR_LOOKUP_NAME; + int fd; + int rc; + + assert((name != NULL) && (acct != NULL)); + + (void) strlcpy(tmp, name, MAXNAMELEN); + smb_name_parse(tmp, &np, &dp); + + bzero(acct, sizeof (lsa_account_t)); + acct->a_sidtype = sidtype; + + if (dp != NULL && np != NULL) { + (void) strlcpy(acct->a_domain, dp, MAXNAMELEN); + (void) strlcpy(acct->a_name, np, MAXNAMELEN); + } else { + (void) strlcpy(acct->a_name, name, MAXNAMELEN); + } if ((fd = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0) - return (NT_STATUS_INTERNAL_ERROR); + return (-1); - if ((buf = smb_dr_encode_string(opcode, name, &len)) == 0) { + buf = smb_dr_encode_common(opcode, acct, lsa_account_xdr, &len); + if (buf == NULL) { (void) close(fd); - return (NT_STATUS_INTERNAL_ERROR); + return (-1); } smb_dr_clnt_setup(&arg, buf, len); - if (smb_dr_clnt_call(fd, &arg) == 0) { + if ((rc = smb_dr_clnt_call(fd, &arg)) == 0) { buf = arg.rbuf + SMB_DR_DATA_OFFSET; len = arg.rsize - SMB_DR_DATA_OFFSET; - strsid = smb_dr_decode_string(buf, len); + + rc = smb_dr_decode_common(buf, len, lsa_account_xdr, acct); } smb_dr_clnt_cleanup(&arg); (void) close(fd); - - if (strsid == NULL) - return (NT_STATUS_INTERNAL_ERROR); - - p = strchr(strsid, '-'); - if (p == NULL) { - xdr_free(xdr_string, (char *)&strsid); - return (NT_STATUS_NONE_MAPPED); - } - - *p++ = '\0'; - sid->gs_type = atoi(strsid); - sid->gs_sid = smb_sid_fromstr(p); - xdr_free(xdr_string, (char *)&strsid); - return (NT_STATUS_SUCCESS); + return (rc); } uint32_t diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c b/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c index bce2ad677b..b746060c99 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c @@ -266,3 +266,59 @@ smb_dr_decode_arg_get_token(char *buf, size_t len) xdr_free(xdr_smb_dr_bytes_t, (char *)&arg); return (clnt_info); } + +/* + * Encode an lsa_account_t into a buffer. + */ +int +lsa_account_encode(lsa_account_t *acct, uint8_t *buf, uint32_t buflen) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE); + + if (!lsa_account_xdr(&xdrs, acct)) + rc = -1; + + xdr_destroy(&xdrs); + return (rc); +} + +/* + * Decode an XDR buffer into an lsa_account_t. + */ +int +lsa_account_decode(lsa_account_t *acct, uint8_t *buf, uint32_t buflen) +{ + XDR xdrs; + int rc = 0; + + xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE); + + bzero(acct, sizeof (lsa_account_t)); + if (!lsa_account_xdr(&xdrs, acct)) + rc = -1; + + xdr_destroy(&xdrs); + return (rc); +} + +bool_t +lsa_account_xdr(XDR *xdrs, lsa_account_t *objp) +{ + if (!xdr_uint16_t(xdrs, &objp->a_sidtype)) + return (FALSE); + if (!xdr_uint32_t(xdrs, &objp->a_status)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->a_domain, MAXNAMELEN, + sizeof (char), (xdrproc_t)xdr_char)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->a_name, MAXNAMELEN, + sizeof (char), (xdrproc_t)xdr_char)) + return (FALSE); + if (!xdr_vector(xdrs, (char *)objp->a_sid, SMB_SID_STRSZ, + sizeof (char), (xdrproc_t)xdr_char)) + return (FALSE); + return (TRUE); +} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c index d8bc1d69fe..f5c82001bc 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c @@ -23,8 +23,6 @@ * Use is subject to license terms. */ -#pragma ident "@(#)smb_lgrp.c 1.5 08/07/29 SMI" - #include <stdlib.h> #include <strings.h> #include <unistd.h> @@ -178,7 +176,7 @@ static int smb_lgrp_decode_privset(smb_group_t *, char *, char *); static int smb_lgrp_decode_members(smb_group_t *, char *, char *, sqlite *); static void smb_lgrp_set_default_privs(smb_group_t *); -static boolean_t smb_lgrp_chkname(char *); +static boolean_t smb_lgrp_normalize_name(char *); static boolean_t smb_lgrp_chkmember(uint16_t); static int smb_lgrp_getsid(int, uint32_t *, uint16_t, sqlite *, smb_sid_t **); static int smb_lgrp_getgid(uint32_t rid, gid_t *gid); @@ -206,8 +204,7 @@ smb_lgrp_add(char *gname, char *cmnt) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX)) @@ -278,12 +275,10 @@ smb_lgrp_rename(char *gname, char *new_gname) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); - (void) trim_whitespace(new_gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (smb_strcasecmp(gname, new_gname, 0) == 0) @@ -317,8 +312,7 @@ smb_lgrp_delete(char *gname) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); /* Cannot remove a built-in group */ @@ -344,8 +338,7 @@ smb_lgrp_setcmnt(char *gname, char *cmnt) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (cmnt && (strlen(cmnt) > SMB_LGRP_COMMENT_MAX)) @@ -372,8 +365,7 @@ smb_lgrp_getcmnt(char *gname, char **cmnt) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (cmnt == NULL) @@ -405,8 +397,7 @@ smb_lgrp_setpriv(char *gname, uint8_t priv_lid, boolean_t enable) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID)) @@ -439,8 +430,7 @@ smb_lgrp_getpriv(char *gname, uint8_t priv_lid, boolean_t *enable) smb_group_t grp; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if ((priv_lid < SE_MIN_LUID) || (priv_lid > SE_MAX_LUID)) @@ -471,8 +461,7 @@ smb_lgrp_add_member(char *gname, smb_sid_t *msid, uint16_t sid_type) smb_gsid_t mid; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (!smb_sid_isvalid(msid)) @@ -503,8 +492,7 @@ smb_lgrp_del_member(char *gname, smb_sid_t *msid, uint16_t sid_type) smb_gsid_t mid; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); if (!smb_sid_isvalid(msid)) @@ -538,8 +526,7 @@ smb_lgrp_getbyname(char *gname, smb_group_t *grp) sqlite *db; int rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (SMB_LGRP_INVALID_NAME); db = smb_lgrp_db_open(SMB_LGRP_DB_ORD); @@ -2127,40 +2114,18 @@ smb_lgrp_decode(smb_group_t *grp, char **values, int infolvl, sqlite *db) } /* - * smb_lgrp_chkname - * - * User account names are limited to 20 characters and group names are - * limited to 256 characters. In addition, account names cannot be terminated - * by a period and they cannot include commas or any of the following printable - * characters: ", /, \, [, ], :, |, <, >, +, =, ;, ?, *. - * Names also cannot include characters in the range 1-31, which are - * nonprintable. + * smb_lgrp_normalize_name * - * Source: MSDN, description of NetLocalGroupAdd function. + * Trim whitespace, validate the group name and convert it to lowercase. */ static boolean_t -smb_lgrp_chkname(char *name) +smb_lgrp_normalize_name(char *name) { - static char *invalid_chars = - "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" - "\020\021\022\023\024\025\026\027\030\031" - "\"/\\[]:|<>+=;,*?"; - int len, i; - - if (name == NULL || *name == '\0') - return (B_FALSE); + (void) trim_whitespace(name); - len = strlen(name); - if (len > SMB_LGRP_NAME_MAX) + if (smb_name_validate_account(name) != ERROR_SUCCESS) return (B_FALSE); - if (name[len - 1] == '.') - return (B_FALSE); - - for (i = 0; i < len; i++) - if (strchr(invalid_chars, name[i])) - return (B_FALSE); - (void) smb_strlwr(name); return (B_TRUE); } @@ -2270,8 +2235,7 @@ smb_lgrp_exists(char *gname) sqlite *db; boolean_t rc; - (void) trim_whitespace(gname); - if (!smb_lgrp_chkname(gname)) + if (!smb_lgrp_normalize_name(gname)) return (B_FALSE); db = smb_lgrp_db_open(SMB_LGRP_DB_ORD); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c index 1dfa3fbf6f..d8a2d5333e 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c @@ -167,7 +167,17 @@ smb_pwd_init(boolean_t create_cache) { if (create_cache) { smb_lucache_create(); +#if 0 + /* + * This pre-loading of the cache results in idmapd requests. + * With the change to allow idmapd to call into libsmb to + * map names and SIDs, this creates a circular startup + * dependency. This call has been temporarily disabled to + * avoid this issue. It can be enabled when the name/SID + * lookup can be done directly on the LSA service. + */ smb_lucache_update(); +#endif } smb_pwd_hdl = smb_dlopen(); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_sd.c b/usr/src/lib/smbsrv/libsmb/common/smb_sd.c index 74f653e689..af9171ce1d 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_sd.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_sd.c @@ -55,7 +55,6 @@ static struct { static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int); static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int); -static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *); void smb_sd_init(smb_sd_t *sd, uint8_t revision) @@ -384,7 +383,7 @@ smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd) * Should call smb_sd_term() for the returned sd to free allocated * members. */ -static uint32_t +uint32_t smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd) { uint32_t status = NT_STATUS_SUCCESS; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c index f21d7e477a..41a96a940e 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c @@ -844,3 +844,246 @@ smb_getnameinfo(smb_inaddr_t *ip, char *hostname, int hostlen, int flags) return (getnameinfo((struct sockaddr *)sp, salen, hostname, hostlen, NULL, 0, flags)); } + +/* + * A share name is considered invalid if it contains control + * characters or any of the following characters (MSDN 236388). + * + * " / \ [ ] : | < > + ; , ? * = + */ +uint32_t +smb_name_validate_share(const char *sharename) +{ + const char *invalid = "\"/\\[]:|<>+;,?*="; + const char *p; + + if (sharename == NULL) + return (ERROR_INVALID_PARAMETER); + + if (strpbrk(sharename, invalid) != NULL) + return (ERROR_INVALID_NAME); + + for (p = sharename; *p != '\0'; p++) { + if (iscntrl(*p)) + return (ERROR_INVALID_NAME); + } + + return (ERROR_SUCCESS); +} + +/* + * User and group names are limited to 256 characters, cannot be terminated + * by '.' and must not contain control characters or any of the following + * characters. + * + * " / \ [ ] < > + ; , ? * = @ + */ +uint32_t +smb_name_validate_account(const char *name) +{ + const char *invalid = "\"/\\[]<>+;,?*=@"; + const char *p; + int len; + + if ((name == NULL) || (*name == '\0')) + return (ERROR_INVALID_PARAMETER); + + len = strlen(name); + if ((len > MAXNAMELEN) || (name[len - 1] == '.')) + return (ERROR_INVALID_NAME); + + if (strpbrk(name, invalid) != NULL) + return (ERROR_INVALID_NAME); + + for (p = name; *p != '\0'; p++) { + if (iscntrl(*p)) + return (ERROR_INVALID_NAME); + } + + return (ERROR_SUCCESS); +} + +/* + * Check a domain name for RFC 1035 and 1123 compliance. Domain names may + * contain alphanumeric characters, hyphens and dots. The first and last + * character of a label must be alphanumeric. Interior characters may be + * alphanumeric or hypens. + * + * Domain names should not contain underscores but we allow them because + * Windows names are often in non-compliance with this rule. + */ +uint32_t +smb_name_validate_domain(const char *domain) +{ + boolean_t new_label = B_TRUE; + const char *p; + char label_terminator; + + if (domain == NULL) + return (ERROR_INVALID_PARAMETER); + + if (*domain == '\0') + return (ERROR_INVALID_NAME); + + label_terminator = *domain; + + for (p = domain; *p != '\0'; ++p) { + if (new_label) { + if (!isalnum(*p)) + return (ERROR_INVALID_NAME); + new_label = B_FALSE; + label_terminator = *p; + continue; + } + + if (*p == '.') { + if (!isalnum(label_terminator)) + return (ERROR_INVALID_NAME); + new_label = B_TRUE; + label_terminator = *p; + continue; + } + + label_terminator = *p; + + if (isalnum(*p) || *p == '-' || *p == '_') + continue; + + return (ERROR_INVALID_NAME); + } + + if (!isalnum(label_terminator)) + return (ERROR_INVALID_NAME); + + return (ERROR_SUCCESS); +} + +/* + * A NetBIOS domain name can contain letters (a-zA-Z), numbers (0-9) and + * hyphens. + * + * It cannot: + * - be blank or longer than 15 chracters + * - contain all numbers + * - be the same as the computer name + */ +uint32_t +smb_name_validate_nbdomain(const char *name) +{ + char netbiosname[NETBIOS_NAME_SZ]; + const char *p; + int len; + + if (name == NULL) + return (ERROR_INVALID_PARAMETER); + + len = strlen(name); + if (len == 0 || len >= NETBIOS_NAME_SZ) + return (ERROR_INVALID_NAME); + + if (strspn(name, "0123456789") == len) + return (ERROR_INVALID_NAME); + + if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) { + if (smb_strcasecmp(name, netbiosname, 0) == 0) + return (ERROR_INVALID_NAME); + } + + for (p = name; *p != '\0'; ++p) { + if (isalnum(*p) || *p == '-' || *p == '_') + continue; + + return (ERROR_INVALID_NAME); + } + + return (ERROR_SUCCESS); +} + +/* + * A workgroup name can contain 1 to 15 characters but cannot be the same + * as the NetBIOS name. The name must begin with a letter or number. + * + * The name cannot consist entirely of spaces or dots, which is covered + * by the requirement that the name must begin with an alphanumeric + * character. + * + * The name must not contain control characters or any of the following + * characters. + * + * " / \ [ ] : | < > + = ; , ? + */ +uint32_t +smb_name_validate_workgroup(const char *workgroup) +{ + char netbiosname[NETBIOS_NAME_SZ]; + const char *invalid = "\"/\\[]:|<>+=;,?"; + const char *p; + + if (workgroup == NULL) + return (ERROR_INVALID_PARAMETER); + + if (*workgroup == '\0' || (!isalnum(*workgroup))) + return (ERROR_INVALID_NAME); + + if (strlen(workgroup) >= NETBIOS_NAME_SZ) + return (ERROR_INVALID_NAME); + + if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) { + if (smb_strcasecmp(workgroup, netbiosname, 0) == 0) + return (ERROR_INVALID_NAME); + } + + if (strpbrk(workgroup, invalid) != NULL) + return (ERROR_INVALID_NAME); + + for (p = workgroup; *p != '\0'; p++) { + if (iscntrl(*p)) + return (ERROR_INVALID_NAME); + } + + return (ERROR_SUCCESS); +} + +/* + * Parse a string to obtain the account and domain names as separate strings. + * + * Names containing a backslash ('\') are known as qualified or composite + * names. The string preceding the backslash should be the domain name + * and the string following the slash should be a name within that domain. + * + * Names that do not contain a backslash are known as isolated names. + * An isolated name may be a single label, such as john, or may be in + * user principal name (UPN) form, such as john@example.com. + * + * domain\name + * domain/name + * name + * name@domain + * + * If we encounter any of the forms above in arg, the @, / or \ separator + * is replaced by \0 and the name and domain pointers are set to point to + * the appropriate components in arg. Otherwise, name and domain pointers + * will be set to NULL. + */ +void +smb_name_parse(char *arg, char **account, char **domain) +{ + char *p; + + *account = NULL; + *domain = NULL; + + if ((p = strpbrk(arg, "/\\@")) != NULL) { + if (*p == '@') { + *p = '\0'; + ++p; + *domain = p; + *account = arg; + } else { + *p = '\0'; + ++p; + *account = p; + *domain = arg; + } + } +} diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c index 5ec6bb0915..a54cf7123d 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c @@ -202,6 +202,7 @@ static boolean_t smb_ads_is_sought_host(smb_ads_host_info_t *, char *); static boolean_t smb_ads_is_same_domain(char *, char *); static boolean_t smb_ads_is_pdc_configured(void); static smb_ads_host_info_t *smb_ads_dup_host_info(smb_ads_host_info_t *); +static char *smb_ads_get_sharedn(const char *, const char *, const char *); /* * smb_ads_init @@ -1275,6 +1276,46 @@ smb_ads_free_spnset(char **spn_set) } /* + * Returns share DN in an allocated buffer. The format of the DN is + * cn=<sharename>,<container RDNs>,<domain DN> + * + * If the domain DN is not included in the container parameter, + * then it will be appended to create the share DN. + * + * The caller must free the allocated buffer. + */ +static char * +smb_ads_get_sharedn(const char *sharename, const char *container, + const char *domain_dn) +{ + char *share_dn; + int rc, offset, container_len, domain_len; + boolean_t append_domain = B_TRUE; + + container_len = strlen(container); + domain_len = strlen(domain_dn); + + if (container_len >= domain_len) { + + /* offset to last domain_len characters */ + offset = container_len - domain_len; + + if (smb_strcasecmp(container + offset, + domain_dn, domain_len) == 0) + append_domain = B_FALSE; + } + + if (append_domain) + rc = asprintf(&share_dn, "cn=%s,%s,%s", sharename, + container, domain_dn); + else + rc = asprintf(&share_dn, "cn=%s,%s", sharename, + container); + + return ((rc == -1) ? NULL : share_dn); +} + +/* * smb_ads_add_share * Call by smb_ads_publish_share to create share object in ADS. * This routine specifies the attributes of an ADS LDAP share object. The first @@ -1299,19 +1340,13 @@ smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName, LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR]; int j = 0; char *share_dn; - int len, ret; + int ret; char *unc_names[] = {(char *)unc_name, NULL}; - len = 5 + strlen(adsShareName) + strlen(adsContainer) + - strlen(ah->domain_dn) + 1; - - share_dn = (char *)malloc(len); - if (share_dn == NULL) + if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer, + ah->domain_dn)) == NULL) return (-1); - (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName, - adsContainer, ah->domain_dn); - if (smb_ads_alloc_attr(attrs, SMB_ADS_SHARE_NUM_ATTR) != 0) { free(share_dn); return (-1); @@ -1355,17 +1390,12 @@ smb_ads_del_share(smb_ads_handle_t *ah, const char *adsShareName, const char *adsContainer) { char *share_dn; - int len, ret; - - len = 5 + strlen(adsShareName) + strlen(adsContainer) + - strlen(ah->domain_dn) + 1; + int ret; - share_dn = (char *)malloc(len); - if (share_dn == NULL) + if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer, + ah->domain_dn)) == NULL) return (-1); - (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName, - adsContainer, ah->domain_dn); if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) { smb_tracef("ldap_delete: %s", ldap_err2string(ret)); free(share_dn); @@ -1450,23 +1480,17 @@ smb_ads_lookup_share(smb_ads_handle_t *ah, const char *adsShareName, { char *attrs[4], filter[SMB_ADS_MAXBUFLEN]; char *share_dn; - int len, ret; + int ret; LDAPMessage *res; char tmpbuf[SMB_ADS_MAXBUFLEN]; if (adsShareName == NULL || adsContainer == NULL) return (-1); - len = 5 + strlen(adsShareName) + strlen(adsContainer) + - strlen(ah->domain_dn) + 1; - - share_dn = (char *)malloc(len); - if (share_dn == NULL) + if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer, + ah->domain_dn)) == NULL) return (-1); - (void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName, - adsContainer, ah->domain_dn); - res = NULL; attrs[0] = "cn"; attrs[1] = "objectClass"; |