diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-09-23 11:15:46 -0700 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-09-23 11:15:46 -0700 |
commit | 66092ced5e1dc4d35923a3c90bcb3214a885b17d (patch) | |
tree | d40fd46e86244f1b45abda2a95c8fe84bfc88c3c /source3 | |
parent | 9cf29abee296ea2fcdf712687a6ce2cf9fd9d74c (diff) | |
parent | 353aaf26c5f71d9a94e799a1c1e37449211e7a87 (diff) | |
download | samba-66092ced5e1dc4d35923a3c90bcb3214a885b17d.tar.gz samba-66092ced5e1dc4d35923a3c90bcb3214a885b17d.tar.bz2 samba-66092ced5e1dc4d35923a3c90bcb3214a885b17d.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3')
54 files changed, 4176 insertions, 1178 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 2300e4a20c..94d8d50da8 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -376,7 +376,7 @@ LIBADS_SERVER_OBJ = libads/kerberos_verify.o libads/authdata.o \ SECRETS_OBJ = passdb/secrets.o passdb/machine_sid.o -LIBNBT_OBJ = libcli/nbt/nbtname.o \ +LIBNBT_OBJ = ../libcli/nbt/nbtname.o \ librpc/gen_ndr/ndr_nbt.o \ librpc/gen_ndr/ndr_svcctl.o @@ -946,13 +946,14 @@ SHARESEC_OBJ = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ $(LIBSAMBA_OBJ) \ $(POPT_LIB_OBJ) -TALLOCTORT_OBJ = @tallocdir@/testsuite.o $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ - $(LIBSAMBA_OBJ) +TALLOCTORT_OBJ = @tallocdir@/testsuite.o @tallocdir@/testsuite_main.o \ + $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSAMBA_OBJ) REPLACETORT_OBJ = @libreplacedir@/test/testsuite.o \ @libreplacedir@/test/getifaddrs.o \ @libreplacedir@/test/os2_delete.o \ @libreplacedir@/test/strptime.o \ + @libreplacedir@/test/main.o \ $(LIBREPLACE_OBJ) NDRDUMP_OBJ = librpc/tools/ndrdump.o \ @@ -984,6 +985,14 @@ IDMAP_HASH_OBJ = \ winbindd/idmap_hash/idmap_hash.o \ winbindd/idmap_hash/mapfile.o +IDMAP_ADEX_OBJ = \ + winbindd/idmap_adex/idmap_adex.o \ + winbindd/idmap_adex/cell_util.o \ + winbindd/idmap_adex/likewise_cell.o \ + winbindd/idmap_adex/provider_unified.o \ + winbindd/idmap_adex/gc_util.o \ + winbindd/idmap_adex/domain_util.o + WINBINDD_OBJ1 = \ winbindd/winbindd.o \ winbindd/winbindd_user.o \ @@ -2217,6 +2226,10 @@ bin/hash.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_HASH_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(IDMAP_HASH_OBJ) +bin/adex.@SHLIBEXT@: $(BINARY_PREREQS) $(IDMAP_ADEX_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(IDMAP_ADEX_OBJ) + bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o @echo "Building plugin $@" @$(SHLD_MODULE) winbindd/idmap_tdb2.o diff --git a/source3/client/mount.cifs.c b/source3/client/mount.cifs.c index 3b56e5f861..b7a76c6102 100644 --- a/source3/client/mount.cifs.c +++ b/source3/client/mount.cifs.c @@ -56,6 +56,10 @@ #endif /* _SAMBA_BUILD_ */ #endif /* MOUNT_CIFS_VENDOR_SUFFIX */ +#ifdef _SAMBA_BUILD_ +#include "include/config.h" +#endif + #ifndef MS_MOVE #define MS_MOVE 8192 #endif @@ -94,6 +98,8 @@ char * prefixpath = NULL; /* like strncpy but does not 0 fill the buffer and always null * terminates. bufsize is the size of the destination buffer */ + +#ifndef HAVE_STRLCPY static size_t strlcpy(char *d, const char *s, size_t bufsize) { size_t len = strlen(s); @@ -104,10 +110,13 @@ static size_t strlcpy(char *d, const char *s, size_t bufsize) d[len] = 0; return ret; } +#endif /* like strncat but does not 0 fill the buffer and always null * terminates. bufsize is the length of the buffer, which should * be one more than the maximum resulting string length */ + +#ifndef HAVE_STRLCAT static size_t strlcat(char *d, const char *s, size_t bufsize) { size_t len1 = strlen(d); @@ -126,6 +135,7 @@ static size_t strlcat(char *d, const char *s, size_t bufsize) } return ret; } +#endif /* BB finish BB diff --git a/source3/configure.in b/source3/configure.in index 640afc47fb..f23f6b55be 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -6058,6 +6058,7 @@ SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP) SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP) SMB_MODULE(idmap_ad, winbindd/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP) SMB_MODULE(idmap_hash, \$(IDMAP_HASH_OBJ), "bin/hash.$SHLIBEXT", IDMAP) +SMB_MODULE(idmap_adex, \$(IDMAP_ADEX_OBJ), "bin/adex.$SHLIBEXT", IDMAP) SMB_SUBSYSTEM(IDMAP, winbindd/idmap.o) SMB_MODULE(nss_info_template, winbindd/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO) @@ -6271,8 +6272,10 @@ fi SMBD_LIBS="$samba_dmapi_libs" AC_SUBST(SMBD_LIBS) +CFLAGS="${CFLAGS} \$(FLAGS)" + if test x$MERGED_BUILD != x1; then - CFLAGS="${CFLAGS} \$(FLAGS) -D_SAMBA_BUILD_=3" + CFLAGS="${CFLAGS} -D_SAMBA_BUILD_=3" fi AC_OUTPUT(Makefile diff --git a/source3/include/charset.h b/source3/include/charset.h index 4d04b5a1a6..1c2a5fb5f0 100644 --- a/source3/include/charset.h +++ b/source3/include/charset.h @@ -18,6 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +struct smb_iconv_convenience; + /* this defines the charset types used in samba */ typedef enum {CH_UTF16LE=0, CH_UTF16=0, CH_UNIX=1, CH_DISPLAY=2, CH_DOS=3, CH_UTF8=4, CH_UTF16BE=5} charset_t; diff --git a/source3/include/proto.h b/source3/include/proto.h index 2901911c70..a2772384c5 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -2204,23 +2204,6 @@ ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_princip ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads, char **returned_principal); -/* The following definitions come from libcli/nbt/nbtname.c */ - -_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s); -_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s); -_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s); -_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r); -_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r); -_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname); -_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name); -_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name); -_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx, - struct nbt_name *n, const char *name, int type); -_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name); -_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r); -_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r); -_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r); - /* The following definitions come from libgpo/gpext/gpext.c */ struct gp_extension *get_gp_extension_list(void); @@ -3960,16 +3943,14 @@ _PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, con _PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p); _PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p); _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p); -_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, - ndr_pull_flags_fn_t fn); +_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p, ndr_pull_flags_fn_t fn); _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, ndr_pull_flags_fn_t fn); _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn); _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_pull_flags_fn_t fn); -_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, - ndr_push_flags_fn_t fn); +_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const void *p, ndr_push_flags_fn_t fn); _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_push_flags_fn_t fn); _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push); @@ -7049,6 +7030,12 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli, DATA_BLOB lm_response, DATA_BLOB nt_response, struct netr_SamInfo3 **info3); +NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const unsigned char orig_trust_passwd_hash[16], + const char *new_trust_pwd_cleartext, + const unsigned char new_trust_passwd_hash[16], + uint32_t sec_channel_type); /* The following definitions come from rpc_client/cli_pipe.c */ @@ -7427,6 +7414,9 @@ void init_netr_PasswordInfo(struct netr_PasswordInfo *r, const char *workstation, struct samr_Password lmpassword, struct samr_Password ntpassword); +void init_netr_CryptPassword(const char *pwd, + unsigned char session_key[16], + struct netr_CryptPassword *pwd_buf); /* The following definitions come from rpc_client/init_samr.c */ diff --git a/source3/lib/messages_local.c b/source3/lib/messages_local.c index f436afc2ff..9f7f88f783 100644 --- a/source3/lib/messages_local.c +++ b/source3/lib/messages_local.c @@ -160,7 +160,7 @@ static NTSTATUS messaging_tdb_fetch(TDB_CONTEXT *msg_tdb, blob = data_blob_const(data.dptr, data.dsize); ndr_err = ndr_pull_struct_blob( - &blob, result, result, + &blob, result, NULL, result, (ndr_pull_flags_fn_t)ndr_pull_messaging_array); SAFE_FREE(data.dptr); @@ -203,7 +203,7 @@ static NTSTATUS messaging_tdb_store(TDB_CONTEXT *msg_tdb, } ndr_err = ndr_push_struct_blob( - &blob, mem_ctx, array, + &blob, mem_ctx, NULL, array, (ndr_push_flags_fn_t)ndr_push_messaging_array); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { diff --git a/source3/lib/netapi/examples/user/user_modalsset.c b/source3/lib/netapi/examples/user/user_modalsset.c index 57e1ef70ea..c6958a9012 100644 --- a/source3/lib/netapi/examples/user/user_modalsset.c +++ b/source3/lib/netapi/examples/user/user_modalsset.c @@ -95,6 +95,7 @@ int main(int argc, const char **argv) case 1: case 2: case 3: + break; case 1001: u1001.usrmod1001_min_passwd_len = 0; buffer = (uint8_t *)&u1001; diff --git a/source3/lib/netapi/tests/Makefile.in b/source3/lib/netapi/tests/Makefile.in index 0145753212..659f82c9d8 100644 --- a/source3/lib/netapi/tests/Makefile.in +++ b/source3/lib/netapi/tests/Makefile.in @@ -44,7 +44,7 @@ bin/.dummy: CMDLINE_OBJ = common.o NETAPIBUFFER_OBJ = netapibuffer.o -NETAPITEST_OBJ = netapitest.o netlocalgroup.o netuser.o netgroup.o netdisplay.o netshare.o $(CMDLINE_OBJ) +NETAPITEST_OBJ = netapitest.o netlocalgroup.o netuser.o netgroup.o netdisplay.o netshare.o netfile.o $(CMDLINE_OBJ) bin/netapitest@EXEEXT@: $(BINARY_PREREQS) $(NETAPITEST_OBJ) @echo Linking $@ diff --git a/source3/lib/netapi/tests/common.h b/source3/lib/netapi/tests/common.h index 5a320321ba..9320840909 100644 --- a/source3/lib/netapi/tests/common.h +++ b/source3/lib/netapi/tests/common.h @@ -41,6 +41,8 @@ NET_API_STATUS netapitest_display(struct libnetapi_ctx *ctx, const char *hostname); NET_API_STATUS netapitest_share(struct libnetapi_ctx *ctx, const char *hostname); +NET_API_STATUS netapitest_file(struct libnetapi_ctx *ctx, + const char *hostname); #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) diff --git a/source3/lib/netapi/tests/netapitest.c b/source3/lib/netapi/tests/netapitest.c index 87144020f5..4a38f721d8 100644 --- a/source3/lib/netapi/tests/netapitest.c +++ b/source3/lib/netapi/tests/netapitest.c @@ -84,6 +84,11 @@ int main(int argc, const char **argv) goto out; } + status = netapitest_file(ctx, hostname); + if (status) { + goto out; + } + out: if (status != 0) { printf("testsuite failed with: %s\n", diff --git a/source3/lib/netapi/tests/netfile.c b/source3/lib/netapi/tests/netfile.c new file mode 100644 index 0000000000..36ee8288ee --- /dev/null +++ b/source3/lib/netapi/tests/netfile.c @@ -0,0 +1,143 @@ +/* + * Unix SMB/CIFS implementation. + * NetFile testsuite + * Copyright (C) Guenther Deschner 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <netapi.h> + +#include "common.h" + +static NET_API_STATUS test_netfileenum(const char *hostname, + uint32_t level) +{ + NET_API_STATUS status; + uint32_t entries_read = 0; + uint32_t total_entries = 0; + uint32_t resume_handle = 0; + uint8_t *buffer = NULL; + int i; + + struct FILE_INFO_2 *i2; + struct FILE_INFO_3 *i3; + + printf("testing NetFileEnum level %d\n", level); + + do { + status = NetFileEnum(hostname, + NULL, + NULL, + level, + &buffer, + (uint32_t)-1, + &entries_read, + &total_entries, + &resume_handle); + if (status == 0 || status == ERROR_MORE_DATA) { + switch (level) { + case 2: + i2 = (struct FILE_INFO_2 *)buffer; + break; + case 3: + i3 = (struct FILE_INFO_3 *)buffer; + break; + default: + return -1; + } + + for (i=0; i<entries_read; i++) { + + switch (level) { + case 2: + case 3: + break; + default: + break; + } + + switch (level) { + case 2: + i2++; + break; + case 3: + i3++; + break; + } + } + NetApiBufferFree(buffer); + } + } while (status == ERROR_MORE_DATA); + + if (status) { + return status; + } + + return 0; +} + +NET_API_STATUS netapitest_file(struct libnetapi_ctx *ctx, + const char *hostname) +{ + NET_API_STATUS status = 0; + uint8_t *buffer = NULL; + uint32_t levels[] = { 2, 3 }; + uint32_t enum_levels[] = { 2, 3 }; + int i; + + printf("NetFile tests\n"); + + /* test enum */ + + for (i=0; i<ARRAY_SIZE(enum_levels); i++) { + + status = test_netfileenum(hostname, enum_levels[i]); + if (status) { + NETAPI_STATUS(ctx, status, "NetFileEnum"); + goto out; + } + } + + /* basic queries */ +#if 0 + for (i=0; i<ARRAY_SIZE(levels); i++) { + + printf("testing NetFileGetInfo level %d\n", levels[i]); + + status = NetFileGetInfo(hostname, fid, levels[i], &buffer); + if (status && status != 124) { + NETAPI_STATUS(ctx, status, "NetFileGetInfo"); + goto out; + } + } +#endif + + status = 0; + + printf("NetFile tests succeeded\n"); + out: + if (status != 0) { + printf("NetFile testsuite failed with: %s\n", + libnetapi_get_error_string(ctx, status)); + } + + return status; +} diff --git a/source3/lib/secdesc.c b/source3/lib/secdesc.c index 44ae23271e..4965200bc1 100644 --- a/source3/lib/secdesc.c +++ b/source3/lib/secdesc.c @@ -249,7 +249,7 @@ NTSTATUS marshall_sec_desc(TALLOC_CTX *mem_ctx, enum ndr_err_code ndr_err; ndr_err = ndr_push_struct_blob( - &blob, mem_ctx, secdesc, + &blob, mem_ctx, NULL, secdesc, (ndr_push_flags_fn_t)ndr_push_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -285,7 +285,7 @@ NTSTATUS unmarshall_sec_desc(TALLOC_CTX *mem_ctx, uint8 *data, size_t len, blob = data_blob_const(data, len); ndr_err = ndr_pull_struct_blob( - &blob, result, result, + &blob, result, NULL, result, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c index 0bde3e6984..40f051c851 100644 --- a/source3/libads/authdata.c +++ b/source3/libads/authdata.c @@ -108,7 +108,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, } ndr_err = ndr_pull_struct_blob(pac_data_blob, pac_data, - pac_data, + NULL, pac_data, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -124,7 +124,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, } ndr_err = ndr_pull_struct_blob(pac_data_blob, pac_data_raw, - pac_data_raw, + NULL, pac_data_raw, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -205,7 +205,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, /* We find the data blobs above, now we parse them to get at the exact portion we should zero */ ndr_err = ndr_pull_struct_blob(kdc_sig_blob, kdc_sig_wipe, - kdc_sig_wipe, + NULL, kdc_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -215,7 +215,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, } ndr_err = ndr_pull_struct_blob(srv_sig_blob, srv_sig_wipe, - srv_sig_wipe, + NULL, srv_sig_wipe, (ndr_pull_flags_fn_t)ndr_pull_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -230,7 +230,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, /* and reencode, back into the same place it came from */ ndr_err = ndr_push_struct_blob(kdc_sig_blob, pac_data_raw, - kdc_sig_wipe, + NULL, kdc_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -239,7 +239,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, return status; } ndr_err = ndr_push_struct_blob(srv_sig_blob, pac_data_raw, - srv_sig_wipe, + NULL, srv_sig_wipe, (ndr_push_flags_fn_t)ndr_push_PAC_SIGNATURE_DATA); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -250,7 +250,7 @@ static krb5_error_code check_pac_checksum(TALLOC_CTX *mem_ctx, /* push out the whole structure, but now with zero'ed signatures */ ndr_err = ndr_push_struct_blob(&modified_pac_blob, pac_data_raw, - pac_data_raw, + NULL, pac_data_raw, (ndr_push_flags_fn_t)ndr_push_PAC_DATA_RAW); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c index 11565065af..73b28b523a 100644 --- a/source3/libads/cldap.c +++ b/source3/libads/cldap.c @@ -294,7 +294,7 @@ bool pull_mailslot_cldap_reply(TALLOC_CTX *mem_ctx, uint32_t nt_version_query = ((*nt_version) & 0x0000001f); uint16_t command = 0; - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, &command, + ndr_err = ndr_pull_struct_blob(blob, mem_ctx, NULL, &command, (ndr_pull_flags_fn_t)ndr_pull_uint16); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return false; diff --git a/source3/libcli/nbt/libnbt.h b/source3/libcli/nbt/libnbt.h deleted file mode 100644 index d37a17c192..0000000000 --- a/source3/libcli/nbt/libnbt.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - a raw async NBT library - - Copyright (C) Andrew Tridgell 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef __LIBNBT_H__ -#define __LIBNBT_H__ - -#include "librpc/gen_ndr/nbt.h" -#include "librpc/ndr/libndr.h" - -/* - possible states for pending requests -*/ -enum nbt_request_state {NBT_REQUEST_SEND, - NBT_REQUEST_WAIT, - NBT_REQUEST_DONE, - NBT_REQUEST_TIMEOUT, - NBT_REQUEST_ERROR}; - -/* - a nbt name request -*/ -struct nbt_name_request { - struct nbt_name_request *next, *prev; - - enum nbt_request_state state; - - NTSTATUS status; - - /* the socket this was on */ - struct nbt_name_socket *nbtsock; - - /* where to send the request */ - struct socket_address *dest; - - /* timeout between retries */ - int timeout; - - /* how many retries to send on timeout */ - int num_retries; - - /* whether we have received a WACK */ - bool received_wack; - - /* the timeout event */ - struct timed_event *te; - - /* the name transaction id */ - uint16_t name_trn_id; - - /* is it a reply? */ - bool is_reply; - - /* the encoded request */ - DATA_BLOB encoded; - - /* shall we allow multiple replies? */ - bool allow_multiple_replies; - - unsigned int num_replies; - struct nbt_name_reply { - struct nbt_name_packet *packet; - struct socket_address *dest; - } *replies; - - /* information on what to do on completion */ - struct { - void (*fn)(struct nbt_name_request *); - void *_private; - } async; -}; - - - -/* - context structure for operations on name queries -*/ -struct nbt_name_socket { - struct socket_context *sock; - struct event_context *event_ctx; -/* - struct smb_iconv_convenience *iconv_convenience; -*/ - /* a queue of requests pending to be sent */ - struct nbt_name_request *send_queue; - - /* the fd event */ - struct fd_event *fde; - - /* mapping from name_trn_id to pending event */ - struct idr_context *idr; - - /* how many requests are waiting for a reply */ - uint16_t num_pending; - - /* what to do with incoming request packets */ - struct { - void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, - struct socket_address *); - void *_private; - } incoming; - - /* what to do with unexpected replies */ - struct { - void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, - struct socket_address *); - void *_private; - } unexpected; -}; - - -/* a simple name query */ -struct nbt_name_query { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - bool broadcast; - bool wins_lookup; - int timeout; /* in seconds */ - int retries; - } in; - struct { - const char *reply_from; - struct nbt_name name; - int16_t num_addrs; - const char **reply_addrs; - } out; -}; - -/* a simple name status query */ -struct nbt_name_status { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - int timeout; /* in seconds */ - int retries; - } in; - struct { - const char *reply_from; - struct nbt_name name; - struct nbt_rdata_status status; - } out; -}; - -/* a name registration request */ -struct nbt_name_register { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - const char *address; - uint16_t nb_flags; - bool register_demand; - bool broadcast; - bool multi_homed; - uint32_t ttl; - int timeout; /* in seconds */ - int retries; - } in; - struct { - const char *reply_from; - struct nbt_name name; - const char *reply_addr; - uint8_t rcode; - } out; -}; - -/* a send 3 times then demand name broadcast name registration */ -struct nbt_name_register_bcast { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - const char *address; - uint16_t nb_flags; - uint32_t ttl; - } in; -}; - - -/* wins name register with multiple wins servers to try and multiple - addresses to register */ -struct nbt_name_register_wins { - struct { - struct nbt_name name; - const char **wins_servers; - uint16_t wins_port; - const char **addresses; - uint16_t nb_flags; - uint32_t ttl; - } in; - struct { - const char *wins_server; - uint8_t rcode; - } out; -}; - - - -/* a name refresh request */ -struct nbt_name_refresh { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - const char *address; - uint16_t nb_flags; - bool broadcast; - uint32_t ttl; - int timeout; /* in seconds */ - int retries; - } in; - struct { - const char *reply_from; - struct nbt_name name; - const char *reply_addr; - uint8_t rcode; - } out; -}; - -/* wins name refresh with multiple wins servers to try and multiple - addresses to register */ -struct nbt_name_refresh_wins { - struct { - struct nbt_name name; - const char **wins_servers; - uint16_t wins_port; - const char **addresses; - uint16_t nb_flags; - uint32_t ttl; - } in; - struct { - const char *wins_server; - uint8_t rcode; - } out; -}; - - -/* a name release request */ -struct nbt_name_release { - struct { - struct nbt_name name; - const char *dest_addr; - uint16_t dest_port; - const char *address; - uint16_t nb_flags; - bool broadcast; - int timeout; /* in seconds */ - int retries; - } in; - struct { - const char *reply_from; - struct nbt_name name; - const char *reply_addr; - uint8_t rcode; - } out; -}; - -struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx, - struct event_context *event_ctx); - /*, - struct smb_iconv_convenience *iconv_convenience);*/ -struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nbtsock, - struct nbt_name_query *io); -NTSTATUS nbt_name_query_recv(struct nbt_name_request *req, - TALLOC_CTX *mem_ctx, struct nbt_name_query *io); -NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, struct nbt_name_query *io); -struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *nbtsock, - struct nbt_name_status *io); -NTSTATUS nbt_name_status_recv(struct nbt_name_request *req, - TALLOC_CTX *mem_ctx, struct nbt_name_status *io); -NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, struct nbt_name_status *io); - -NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname); -NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name); -NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name); -void nbt_choose_called_name(TALLOC_CTX *mem_ctx, struct nbt_name *n, const char *name, int type); -char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name); -NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, struct nbt_name_register *io); -NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io); -NTSTATUS nbt_name_release(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, struct nbt_name_release *io); -NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, - struct nbt_name_register_wins *io); -NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock, - TALLOC_CTX *mem_ctx, - struct nbt_name_refresh_wins *io); -NTSTATUS nbt_name_register_recv(struct nbt_name_request *req, - TALLOC_CTX *mem_ctx, struct nbt_name_register *io); -struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock, - struct nbt_name_register *io); -NTSTATUS nbt_name_release_recv(struct nbt_name_request *req, - TALLOC_CTX *mem_ctx, struct nbt_name_release *io); - -struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *nbtsock, - struct nbt_name_release *io); - -NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req, - TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io); - -NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock, - void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, - struct socket_address *), - void *_private); -NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock, - struct socket_address *dest, - struct nbt_name_packet *request); - - -NDR_SCALAR_PROTO(wrepl_nbt_name, const struct nbt_name *); -NDR_SCALAR_PROTO(nbt_string, const char *); -NDR_BUFFER_PROTO(nbt_name, struct nbt_name); -NTSTATUS nbt_rcode_to_ntstatus(uint8_t rcode); - -struct composite_context; -struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock, - struct nbt_name_register_bcast *io); -NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c); -struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock, - struct nbt_name_register_wins *io); -NTSTATUS nbt_name_refresh_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct nbt_name_refresh_wins *io); -struct composite_context *nbt_name_refresh_wins_send(struct nbt_name_socket *nbtsock, - struct nbt_name_refresh_wins *io); -NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx, - struct nbt_name_register_wins *io); - - -#endif /* __LIBNBT_H__ */ diff --git a/source3/libcli/nbt/nbtname.c b/source3/libcli/nbt/nbtname.c deleted file mode 100644 index fbb9550655..0000000000 --- a/source3/libcli/nbt/nbtname.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - manipulate nbt name structures - - Copyright (C) Andrew Tridgell 2005 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -/* - see rfc1002 for the detailed format of compressed names -*/ - -#include "includes.h" -#include "librpc/gen_ndr/ndr_nbt.h" -#include "librpc/gen_ndr/ndr_misc.h" - -/* don't allow an unlimited number of name components */ -#define MAX_COMPONENTS 10 - -/** - print a nbt string -*/ -_PUBLIC_ void ndr_print_nbt_string(struct ndr_print *ndr, const char *name, const char *s) -{ - ndr_print_string(ndr, name, s); -} - -/* - pull one component of a nbt_string -*/ -static enum ndr_err_code ndr_pull_component(struct ndr_pull *ndr, - uint8_t **component, - uint32_t *offset, - uint32_t *max_offset) -{ - uint8_t len; - uint_t loops = 0; - while (loops < 5) { - if (*offset >= ndr->data_size) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "BAD NBT NAME component"); - } - len = ndr->data[*offset]; - if (len == 0) { - *offset += 1; - *max_offset = MAX(*max_offset, *offset); - *component = NULL; - return NDR_ERR_SUCCESS; - } - if ((len & 0xC0) == 0xC0) { - /* its a label pointer */ - if (1 + *offset >= ndr->data_size) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "BAD NBT NAME component"); - } - *max_offset = MAX(*max_offset, *offset + 2); - *offset = ((len&0x3F)<<8) | ndr->data[1 + *offset]; - *max_offset = MAX(*max_offset, *offset); - loops++; - continue; - } - if ((len & 0xC0) != 0) { - /* its a reserved length field */ - return ndr_pull_error(ndr, NDR_ERR_STRING, - "BAD NBT NAME component"); - } - if (*offset + len + 2 > ndr->data_size) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "BAD NBT NAME component"); - } - *component = (uint8_t*)talloc_strndup(ndr, (const char *)&ndr->data[1 + *offset], len); - NDR_ERR_HAVE_NO_MEMORY(*component); - *offset += len + 1; - *max_offset = MAX(*max_offset, *offset); - return NDR_ERR_SUCCESS; - } - - /* too many pointers */ - return ndr_pull_error(ndr, NDR_ERR_STRING, "BAD NBT NAME component"); -} - -/** - pull a nbt_string from the wire -*/ -_PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_flags, const char **s) -{ - uint32_t offset = ndr->offset; - uint32_t max_offset = offset; - unsigned num_components; - char *name; - - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - name = NULL; - - /* break up name into a list of components */ - for (num_components=0;num_components<MAX_COMPONENTS;num_components++) { - uint8_t *component = NULL; - NDR_CHECK(ndr_pull_component(ndr, &component, &offset, &max_offset)); - if (component == NULL) break; - if (name) { - name = talloc_asprintf_append_buffer(name, ".%s", component); - NDR_ERR_HAVE_NO_MEMORY(name); - } else { - name = (char *)component; - } - } - if (num_components == MAX_COMPONENTS) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "BAD NBT NAME too many components"); - } - if (num_components == 0) { - name = talloc_strdup(ndr, ""); - NDR_ERR_HAVE_NO_MEMORY(name); - } - - (*s) = name; - ndr->offset = max_offset; - - return NDR_ERR_SUCCESS; -} - -/** - push a nbt string to the wire -*/ -_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s) -{ - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - while (s && *s) { - enum ndr_err_code ndr_err; - char *compname; - size_t complen; - uint32_t offset; - - /* see if we have pushed the remaing string allready, - * if so we use a label pointer to this string - */ - ndr_err = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, false); - if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - uint8_t b[2]; - - if (offset > 0x3FFF) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "offset for nbt string label pointer %u[%08X] > 0x00003FFF", - offset, offset); - } - - b[0] = 0xC0 | (offset>>8); - b[1] = (offset & 0xFF); - - return ndr_push_bytes(ndr, b, 2); - } - - complen = strcspn(s, "."); - - /* we need to make sure the length fits into 6 bytes */ - if (complen >= 0x3F) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "component length %u[%08X] > 0x00003F", - (unsigned)complen, (unsigned)complen); - } - - compname = talloc_asprintf(ndr, "%c%*.*s", - (unsigned char)complen, - (unsigned char)complen, - (unsigned char)complen, s); - NDR_ERR_HAVE_NO_MEMORY(compname); - - /* remember the current componemt + the rest of the string - * so it can be reused later - */ - NDR_CHECK(ndr_token_store(ndr, &ndr->nbt_string_list, s, ndr->offset)); - - /* push just this component into the blob */ - NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1)); - talloc_free(compname); - - s += complen; - if (*s == '.') s++; - } - - /* if we reach the end of the string and have pushed the last component - * without using a label pointer, we need to terminate the string - */ - return ndr_push_bytes(ndr, (const uint8_t *)"", 1); -} - - -/* - decompress a 'compressed' name component - */ -static bool decompress_name(char *name, enum nbt_name_type *type) -{ - int i; - for (i=0;name[2*i];i++) { - uint8_t c1 = name[2*i]; - uint8_t c2 = name[1+(2*i)]; - if (c1 < 'A' || c1 > 'P' || - c2 < 'A' || c2 > 'P') { - return false; - } - name[i] = ((c1-'A')<<4) | (c2-'A'); - } - name[i] = 0; - if (i == 16) { - *type = (enum nbt_name_type)(name[15]); - name[15] = 0; - i--; - } else { - *type = NBT_NAME_CLIENT; - } - - /* trim trailing spaces */ - for (;i>0 && name[i-1]==' ';i--) { - name[i-1] = 0; - } - - return true; -} - - -/* - compress a name component - */ -static uint8_t *compress_name(TALLOC_CTX *mem_ctx, - const uint8_t *name, enum nbt_name_type type) -{ - uint8_t *cname; - int i; - uint8_t pad_char; - - if (strlen((const char *)name) > 15) { - return NULL; - } - - cname = talloc_array(mem_ctx, uint8_t, 33); - if (cname == NULL) return NULL; - - for (i=0;name[i];i++) { - cname[2*i] = 'A' + (name[i]>>4); - cname[1+2*i] = 'A' + (name[i]&0xF); - } - if (strcmp((const char *)name, "*") == 0) { - pad_char = 0; - } else { - pad_char = ' '; - } - for (;i<15;i++) { - cname[2*i] = 'A' + (pad_char>>4); - cname[1+2*i] = 'A' + (pad_char&0xF); - } - - pad_char = type; - cname[2*i] = 'A' + (pad_char>>4); - cname[1+2*i] = 'A' + (pad_char&0xF); - - cname[32] = 0; - return cname; -} - - -/** - pull a nbt name from the wire -*/ -_PUBLIC_ enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r) -{ - uint8_t *scope; - char *cname; - const char *s; - bool ok; - - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - NDR_CHECK(ndr_pull_nbt_string(ndr, ndr_flags, &s)); - - scope = (uint8_t *)strchr(s, '.'); - if (scope) { - *scope = 0; - r->scope = talloc_strdup(ndr->current_mem_ctx, (const char *)&scope[1]); - NDR_ERR_HAVE_NO_MEMORY(r->scope); - } else { - r->scope = NULL; - } - - cname = discard_const_p(char, s); - - /* the first component is limited to 16 bytes in the DOS charset, - which is 32 in the 'compressed' form */ - if (strlen(cname) > 32) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "NBT NAME cname > 32"); - } - - /* decompress the first component */ - ok = decompress_name(cname, &r->type); - if (!ok) { - return ndr_pull_error(ndr, NDR_ERR_STRING, - "NBT NAME failed to decompress"); - } - - r->name = talloc_strdup(ndr->current_mem_ctx, cname); - NDR_ERR_HAVE_NO_MEMORY(r->name); - - talloc_free(cname); - - return NDR_ERR_SUCCESS; -} - -/** - push a nbt name to the wire -*/ -_PUBLIC_ enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r) -{ - uint8_t *cname, *fullname; - enum ndr_err_code ndr_err; - - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - if (strlen(r->name) > 15) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "nbt_name longer as 15 chars: %s", - r->name); - } - - cname = compress_name(ndr, (const uint8_t *)r->name, r->type); - NDR_ERR_HAVE_NO_MEMORY(cname); - - if (r->scope) { - fullname = (uint8_t *)talloc_asprintf(ndr, "%s.%s", cname, r->scope); - NDR_ERR_HAVE_NO_MEMORY(fullname); - talloc_free(cname); - } else { - fullname = cname; - } - - ndr_err = ndr_push_nbt_string(ndr, ndr_flags, (const char *)fullname); - - return ndr_err; -} - - -/** - copy a nbt name structure -*/ -_PUBLIC_ NTSTATUS nbt_name_dup(TALLOC_CTX *mem_ctx, struct nbt_name *name, struct nbt_name *newname) -{ - *newname = *name; - newname->name = talloc_strdup(mem_ctx, newname->name); - NT_STATUS_HAVE_NO_MEMORY(newname->name); - newname->scope = talloc_strdup(mem_ctx, newname->scope); - if (name->scope) { - NT_STATUS_HAVE_NO_MEMORY(newname->scope); - } - return NT_STATUS_OK; -} - -/** - push a nbt name into a blob -*/ -_PUBLIC_ NTSTATUS nbt_name_to_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct nbt_name *name) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(blob, mem_ctx, name, (ndr_push_flags_fn_t)ndr_push_nbt_name); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - return NT_STATUS_OK; -} - -/** - pull a nbt name from a blob -*/ -_PUBLIC_ NTSTATUS nbt_name_from_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, struct nbt_name *name) -{ - enum ndr_err_code ndr_err; - - ndr_err = ndr_pull_struct_blob(blob, mem_ctx, name, - (ndr_pull_flags_fn_t)ndr_pull_nbt_name); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ndr_map_error2ntstatus(ndr_err); - } - - return NT_STATUS_OK; -} - - -/** - choose a name to use when calling a server in a NBT session request. - we use heuristics to see if the name we have been given is a IP - address, or a too-long name. If it is then use *SMBSERVER, or a - truncated name -*/ -_PUBLIC_ void nbt_choose_called_name(TALLOC_CTX *mem_ctx, - struct nbt_name *n, const char *name, int type) -{ - n->scope = NULL; - n->type = type; - - if ((name == NULL) || is_ipaddress(name)) { - n->name = "*SMBSERVER"; - return; - } - if (strlen(name) > 15) { - const char *p = strchr(name, '.'); - char *s; - if (p - name > 15) { - n->name = "*SMBSERVER"; - return; - } - s = talloc_strndup(mem_ctx, name, PTR_DIFF(p, name)); - n->name = talloc_strdup_upper(mem_ctx, s); - return; - } - - n->name = talloc_strdup_upper(mem_ctx, name); -} - - -/* - escape a string into a form containing only a small set of characters, - the rest is hex encoded. This is similar to URL encoding -*/ -static const char *nbt_hex_encode(TALLOC_CTX *mem_ctx, const char *s) -{ - int i, len; - char *ret; - const char *valid_chars = "_-.$@ "; -#define NBT_CHAR_ALLOW(c) (isalnum((unsigned char)c) || strchr(valid_chars, c)) - - for (len=i=0;s[i];i++,len++) { - if (!NBT_CHAR_ALLOW(s[i])) { - len += 2; - } - } - - ret = talloc_array(mem_ctx, char, len+1); - if (ret == NULL) return NULL; - - for (len=i=0;s[i];i++) { - if (NBT_CHAR_ALLOW(s[i])) { - ret[len++] = s[i]; - } else { - snprintf(&ret[len], 4, "%%%02x", (unsigned char)s[i]); - len += 3; - } - } - ret[len] = 0; - - return ret; -} - - -/** - form a string for a NBT name -*/ -_PUBLIC_ char *nbt_name_string(TALLOC_CTX *mem_ctx, const struct nbt_name *name) -{ - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - char *ret; - if (name->scope) { - ret = talloc_asprintf(mem_ctx, "%s<%02x>-%s", - nbt_hex_encode(tmp_ctx, name->name), - name->type, - nbt_hex_encode(tmp_ctx, name->scope)); - } else { - ret = talloc_asprintf(mem_ctx, "%s<%02x>", - nbt_hex_encode(tmp_ctx, name->name), - name->type); - } - talloc_free(tmp_ctx); - return ret; -} - -/** - pull a nbt name, WINS Replication uses another on wire format for nbt name -*/ -_PUBLIC_ enum ndr_err_code ndr_pull_wrepl_nbt_name(struct ndr_pull *ndr, int ndr_flags, const struct nbt_name **_r) -{ - struct nbt_name *r; - uint8_t *namebuf; - uint32_t namebuf_len; - - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - NDR_CHECK(ndr_pull_align(ndr, 4)); - NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &namebuf_len)); - if (namebuf_len < 1 || namebuf_len > 255) { - return ndr_pull_error(ndr, NDR_ERR_ALLOC, "value out of range"); - } - NDR_PULL_ALLOC_N(ndr, namebuf, namebuf_len); - NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len)); - - NDR_PULL_ALLOC(ndr, r); - - /* oh wow, what a nasty bug in windows ... */ - if (namebuf[0] == 0x1b && namebuf_len >= 16) { - namebuf[0] = namebuf[15]; - namebuf[15] = 0x1b; - } - - if (namebuf_len < 17) { - r->type = 0x00; - - r->name = talloc_strndup(r, (char *)namebuf, namebuf_len); - if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); - - r->scope= NULL; - - talloc_free(namebuf); - *_r = r; - return NDR_ERR_SUCCESS; - } - - r->type = namebuf[15]; - - namebuf[15] = '\0'; - trim_string((char *)namebuf, NULL, " "); - r->name = talloc_strdup(r, (char *)namebuf); - if (!r->name) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); - - if (namebuf_len > 18) { - r->scope = talloc_strndup(r, (char *)(namebuf+17), namebuf_len-17); - if (!r->scope) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "out of memory"); - } else { - r->scope = NULL; - } - - talloc_free(namebuf); - *_r = r; - return NDR_ERR_SUCCESS; -} - -/** - push a nbt name, WINS Replication uses another on wire format for nbt name -*/ -_PUBLIC_ enum ndr_err_code ndr_push_wrepl_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r) -{ - uint8_t *namebuf; - uint32_t namebuf_len; - uint32_t _name_len; - uint32_t scope_len = 0; - - if (r == NULL) { - return ndr_push_error(ndr, NDR_ERR_INVALID_POINTER, - "wrepl_nbt_name NULL pointer"); - } - - if (!(ndr_flags & NDR_SCALARS)) { - return NDR_ERR_SUCCESS; - } - - _name_len = strlen(r->name); - if (_name_len > 15) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "wrepl_nbt_name longer as 15 chars: %s", - r->name); - } - - if (r->scope) { - scope_len = strlen(r->scope); - } - if (scope_len > 238) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "wrepl_nbt_name scope longer as 238 chars: %s", - r->scope); - } - - namebuf = (uint8_t *)talloc_asprintf(ndr, "%-15s%c%s", - r->name, 'X', - (r->scope?r->scope:"")); - if (!namebuf) return ndr_push_error(ndr, NDR_ERR_ALLOC, "out of memory"); - - namebuf_len = strlen((char *)namebuf) + 1; - - /* - * we need to set the type here, and use a place-holder in the talloc_asprintf() - * as the type can be 0x00, and then the namebuf_len = strlen(namebuf); would give wrong results - */ - namebuf[15] = r->type; - - /* oh wow, what a nasty bug in windows ... */ - if (r->type == 0x1b) { - namebuf[15] = namebuf[0]; - namebuf[0] = 0x1b; - } - - NDR_CHECK(ndr_push_align(ndr, 4)); - NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, namebuf_len)); - NDR_CHECK(ndr_push_array_uint8(ndr, NDR_SCALARS, namebuf, namebuf_len)); - - talloc_free(namebuf); - return NDR_ERR_SUCCESS; -} - -_PUBLIC_ void ndr_print_wrepl_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r) -{ - char *s = nbt_name_string(ndr, r); - ndr_print_string(ndr, name, s); - talloc_free(s); -} diff --git a/source3/libnet/libnet_dssync_keytab.c b/source3/libnet/libnet_dssync_keytab.c index 6ba2c3aa41..e762ecbe49 100644 --- a/source3/libnet/libnet_dssync_keytab.c +++ b/source3/libnet/libnet_dssync_keytab.c @@ -86,7 +86,7 @@ static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx, old_utdv = talloc(mem_ctx, struct replUpToDateVectorBlob); ndr_err = ndr_pull_struct_blob(&entry->password, old_utdv, - old_utdv, + NULL, old_utdv, (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { NTSTATUS status = ndr_map_error2ntstatus(ndr_err); @@ -124,7 +124,7 @@ static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx, NDR_PRINT_DEBUG(replUpToDateVectorBlob, new_utdv); } - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, new_utdv, + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, new_utdv, (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -236,7 +236,7 @@ static NTSTATUS parse_supplemental_credentials(TALLOC_CTX *mem_ctx, status = NT_STATUS_NO_MEMORY; goto done; } - ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, pkb, + ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, NULL, pkb, (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); diff --git a/source3/libnet/libnet_samsync.c b/source3/libnet/libnet_samsync.c index daf27ffb51..64dcf6de51 100644 --- a/source3/libnet/libnet_samsync.c +++ b/source3/libnet/libnet_samsync.c @@ -65,7 +65,7 @@ static NTSTATUS fix_user(TALLOC_CTX *mem_ctx, user->user_private_info.SensitiveData = data.data; user->user_private_info.DataLength = data.length; - ndr_err = ndr_pull_struct_blob(&data, mem_ctx, &keys, + ndr_err = ndr_pull_struct_blob(&data, mem_ctx, NULL, &keys, (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { dump_data(10, data.data, data.length); @@ -397,7 +397,7 @@ NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx, blob = data_blob_const(r->array, r->length); - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, str, + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, str, (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { diff --git a/source3/librpc/gen_ndr/libnetapi.h b/source3/librpc/gen_ndr/libnetapi.h index 98da9e12ea..ae7acbf572 100644 --- a/source3/librpc/gen_ndr/libnetapi.h +++ b/source3/librpc/gen_ndr/libnetapi.h @@ -413,7 +413,9 @@ struct USER_INFO_X { uint32_t usriX_code_page; const char * usriX_profile; const char * usriX_home_dir_drive; + uint32_t usriX_user_id; uint32_t usriX_primary_group_id; + uint32_t usriX_password_expired; }; struct GROUP_USERS_INFO_0 { diff --git a/source3/librpc/gen_ndr/nbt.h b/source3/librpc/gen_ndr/nbt.h index 62ad524a91..0943ee1a4d 100644 --- a/source3/librpc/gen_ndr/nbt.h +++ b/source3/librpc/gen_ndr/nbt.h @@ -221,7 +221,7 @@ union nbt_rdata { struct nbt_rdata_netbios netbios;/* [case(NBT_QTYPE_NETBIOS)] */ struct nbt_rdata_status status;/* [case(NBT_QTYPE_STATUS)] */ struct nbt_rdata_data data;/* [default] */ -}/* [nodiscriminant] */; +}/* [nodiscriminant,public] */; struct nbt_res_rec { struct nbt_name name; diff --git a/source3/librpc/gen_ndr/ndr_libnetapi.c b/source3/librpc/gen_ndr/ndr_libnetapi.c index a5266827b6..d7bf63e62f 100644 --- a/source3/librpc/gen_ndr/ndr_libnetapi.c +++ b/source3/librpc/gen_ndr/ndr_libnetapi.c @@ -1895,7 +1895,9 @@ _PUBLIC_ enum ndr_err_code ndr_push_USER_INFO_X(struct ndr_push *ndr, int ndr_fl NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_code_page)); NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_profile)); NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->usriX_home_dir_drive)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_user_id)); NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_primary_group_id)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->usriX_password_expired)); } if (ndr_flags & NDR_BUFFERS) { if (r->usriX_logon_hours) { @@ -1942,7 +1944,9 @@ _PUBLIC_ enum ndr_err_code ndr_pull_USER_INFO_X(struct ndr_pull *ndr, int ndr_fl NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_code_page)); NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_profile)); NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->usriX_home_dir_drive)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_user_id)); NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_primary_group_id)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->usriX_password_expired)); } if (ndr_flags & NDR_BUFFERS) { if (r->usriX_logon_hours) { @@ -1990,7 +1994,9 @@ _PUBLIC_ void ndr_print_USER_INFO_X(struct ndr_print *ndr, const char *name, con ndr_print_uint32(ndr, "usriX_code_page", r->usriX_code_page); ndr_print_string(ndr, "usriX_profile", r->usriX_profile); ndr_print_string(ndr, "usriX_home_dir_drive", r->usriX_home_dir_drive); + ndr_print_uint32(ndr, "usriX_user_id", r->usriX_user_id); ndr_print_uint32(ndr, "usriX_primary_group_id", r->usriX_primary_group_id); + ndr_print_uint32(ndr, "usriX_password_expired", r->usriX_password_expired); ndr->depth--; } diff --git a/source3/librpc/gen_ndr/ndr_nbt.c b/source3/librpc/gen_ndr/ndr_nbt.c index 75667183a8..01cccd6742 100644 --- a/source3/librpc/gen_ndr/ndr_nbt.c +++ b/source3/librpc/gen_ndr/ndr_nbt.c @@ -77,13 +77,13 @@ _PUBLIC_ void ndr_print_nbt_name(struct ndr_print *ndr, const char *name, const ndr->depth--; } -static enum ndr_err_code ndr_push_nbt_qclass(struct ndr_push *ndr, int ndr_flags, enum nbt_qclass r) +_PUBLIC_ enum ndr_err_code ndr_push_nbt_qclass(struct ndr_push *ndr, int ndr_flags, enum nbt_qclass r) { NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r)); return NDR_ERR_SUCCESS; } -static enum ndr_err_code ndr_pull_nbt_qclass(struct ndr_pull *ndr, int ndr_flags, enum nbt_qclass *r) +_PUBLIC_ enum ndr_err_code ndr_pull_nbt_qclass(struct ndr_pull *ndr, int ndr_flags, enum nbt_qclass *r) { uint16_t v; NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v)); @@ -101,13 +101,13 @@ _PUBLIC_ void ndr_print_nbt_qclass(struct ndr_print *ndr, const char *name, enum ndr_print_enum(ndr, name, "ENUM", val, r); } -static enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, int ndr_flags, enum nbt_qtype r) +_PUBLIC_ enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, int ndr_flags, enum nbt_qtype r) { NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, r)); return NDR_ERR_SUCCESS; } -static enum ndr_err_code ndr_pull_nbt_qtype(struct ndr_pull *ndr, int ndr_flags, enum nbt_qtype *r) +_PUBLIC_ enum ndr_err_code ndr_pull_nbt_qtype(struct ndr_pull *ndr, int ndr_flags, enum nbt_qtype *r) { uint16_t v; NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &v)); @@ -496,7 +496,7 @@ _PUBLIC_ void ndr_print_nbt_rdata_data(struct ndr_print *ndr, const char *name, ndr->depth--; } -static enum ndr_err_code ndr_push_nbt_rdata(struct ndr_push *ndr, int ndr_flags, const union nbt_rdata *r) +_PUBLIC_ enum ndr_err_code ndr_push_nbt_rdata(struct ndr_push *ndr, int ndr_flags, const union nbt_rdata *r) { if (ndr_flags & NDR_SCALARS) { int level = ndr_push_get_switch_value(ndr, r); @@ -532,7 +532,7 @@ static enum ndr_err_code ndr_push_nbt_rdata(struct ndr_push *ndr, int ndr_flags, return NDR_ERR_SUCCESS; } -static enum ndr_err_code ndr_pull_nbt_rdata(struct ndr_pull *ndr, int ndr_flags, union nbt_rdata *r) +_PUBLIC_ enum ndr_err_code ndr_pull_nbt_rdata(struct ndr_pull *ndr, int ndr_flags, union nbt_rdata *r) { int level; level = ndr_pull_get_switch_value(ndr, r); diff --git a/source3/librpc/gen_ndr/ndr_nbt.h b/source3/librpc/gen_ndr/ndr_nbt.h index 6e9702d5d5..f70d1ba8df 100644 --- a/source3/librpc/gen_ndr/ndr_nbt.h +++ b/source3/librpc/gen_ndr/ndr_nbt.h @@ -6,14 +6,18 @@ #ifndef _HEADER_NDR_nbt #define _HEADER_NDR_nbt -#include "libcli/nbt/libnbt.h" +#include "../libcli/nbt/libnbt.h" #define NDR_NBT_CALL_COUNT (0) void ndr_print_nbt_operation(struct ndr_print *ndr, const char *name, uint16_t r); void ndr_print_nbt_name_type(struct ndr_print *ndr, const char *name, enum nbt_name_type r); enum ndr_err_code ndr_push_nbt_name(struct ndr_push *ndr, int ndr_flags, const struct nbt_name *r); enum ndr_err_code ndr_pull_nbt_name(struct ndr_pull *ndr, int ndr_flags, struct nbt_name *r); void ndr_print_nbt_name(struct ndr_print *ndr, const char *name, const struct nbt_name *r); +enum ndr_err_code ndr_push_nbt_qclass(struct ndr_push *ndr, int ndr_flags, enum nbt_qclass r); +enum ndr_err_code ndr_pull_nbt_qclass(struct ndr_pull *ndr, int ndr_flags, enum nbt_qclass *r); void ndr_print_nbt_qclass(struct ndr_print *ndr, const char *name, enum nbt_qclass r); +enum ndr_err_code ndr_push_nbt_qtype(struct ndr_push *ndr, int ndr_flags, enum nbt_qtype r); +enum ndr_err_code ndr_pull_nbt_qtype(struct ndr_pull *ndr, int ndr_flags, enum nbt_qtype *r); void ndr_print_nbt_qtype(struct ndr_print *ndr, const char *name, enum nbt_qtype r); void ndr_print_nbt_name_question(struct ndr_print *ndr, const char *name, const struct nbt_name_question *r); void ndr_print_nb_flags(struct ndr_print *ndr, const char *name, uint16_t r); @@ -23,6 +27,8 @@ void ndr_print_nbt_statistics(struct ndr_print *ndr, const char *name, const str void ndr_print_nbt_status_name(struct ndr_print *ndr, const char *name, const struct nbt_status_name *r); void ndr_print_nbt_rdata_status(struct ndr_print *ndr, const char *name, const struct nbt_rdata_status *r); void ndr_print_nbt_rdata_data(struct ndr_print *ndr, const char *name, const struct nbt_rdata_data *r); +enum ndr_err_code ndr_push_nbt_rdata(struct ndr_push *ndr, int ndr_flags, const union nbt_rdata *r); +enum ndr_err_code ndr_pull_nbt_rdata(struct ndr_pull *ndr, int ndr_flags, union nbt_rdata *r); void ndr_print_nbt_rdata(struct ndr_print *ndr, const char *name, const union nbt_rdata *r); void ndr_print_nbt_res_rec(struct ndr_print *ndr, const char *name, const struct nbt_res_rec *r); enum ndr_err_code ndr_push_nbt_name_packet(struct ndr_push *ndr, int ndr_flags, const struct nbt_name_packet *r); diff --git a/source3/librpc/idl/libnetapi.idl b/source3/librpc/idl/libnetapi.idl index 039dcf4152..f2f4a16c12 100644 --- a/source3/librpc/idl/libnetapi.idl +++ b/source3/librpc/idl/libnetapi.idl @@ -517,7 +517,9 @@ interface libnetapi uint32 usriX_code_page; string usriX_profile; string usriX_home_dir_drive; + uint32 usriX_user_id; uint32 usriX_primary_group_id; + uint32 usriX_password_expired; } USER_INFO_X; [nopush,nopull] NET_API_STATUS NetUserAdd( diff --git a/source3/librpc/idl/nbt.idl b/source3/librpc/idl/nbt.idl index 654f53c52f..da1eb2ef3f 100644 --- a/source3/librpc/idl/nbt.idl +++ b/source3/librpc/idl/nbt.idl @@ -10,7 +10,7 @@ import "misc.idl", "security.idl", "svcctl.idl", "samr.idl"; [ -helper("libcli/nbt/libnbt.h") +helper("../libcli/nbt/libnbt.h") ] interface nbt { @@ -73,11 +73,11 @@ interface nbt nbt_name_type type; } nbt_name; - typedef [enum16bit] enum { + typedef [public,enum16bit] enum { NBT_QCLASS_IP = 0x01 } nbt_qclass; - typedef [enum16bit] enum { + typedef [public,enum16bit] enum { NBT_QTYPE_ADDRESS = 0x0001, NBT_QTYPE_NAMESERVICE = 0x0002, NBT_QTYPE_NULL = 0x000A, @@ -160,7 +160,7 @@ interface nbt uint8 data[length]; } nbt_rdata_data; - typedef [nodiscriminant] union { + typedef [nodiscriminant,public] union { [case(NBT_QTYPE_NETBIOS)] nbt_rdata_netbios netbios; [case(NBT_QTYPE_STATUS)] nbt_rdata_status status; [default] nbt_rdata_data data; diff --git a/source3/librpc/ndr/ndr.c b/source3/librpc/ndr/ndr.c index d94d12e146..624024c94d 100644 --- a/source3/librpc/ndr/ndr.c +++ b/source3/librpc/ndr/ndr.c @@ -803,8 +803,11 @@ _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void * /* pull a struct from a blob using NDR */ -_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, - ndr_pull_flags_fn_t fn) +_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + void *p, + ndr_pull_flags_fn_t fn) { struct ndr_pull *ndr; ndr = ndr_pull_init_blob(blob, mem_ctx); @@ -868,8 +871,11 @@ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC /* push a struct to a blob using NDR */ -_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, - ndr_push_flags_fn_t fn) +_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, + TALLOC_CTX *mem_ctx, + struct smb_iconv_convenience *iconv_convenience, + const void *p, + ndr_push_flags_fn_t fn) { struct ndr_push *ndr; ndr = ndr_push_init_ctx(mem_ctx); diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c index 8b35a69def..8ee3507a04 100644 --- a/source3/libsmb/clidgram.c +++ b/source3/libsmb/clidgram.c @@ -181,7 +181,7 @@ bool send_getdc_request(TALLOC_CTX *mem_ctx, NDR_PRINT_DEBUG(nbt_ntlogon_packet, &packet); } - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &packet, + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &packet, (ndr_push_flags_fn_t)ndr_push_nbt_ntlogon_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return false; diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 9d65fb4e94..8a5aedfde5 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -464,13 +464,11 @@ struct cli_state *cli_initialise(void) return NULL; } - cli = talloc(NULL, struct cli_state); + cli = TALLOC_ZERO_P(NULL, struct cli_state); if (!cli) { return NULL; } - ZERO_STRUCTP(cli); - cli->port = 0; cli->fd = -1; cli->cnum = -1; diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index 2a445cbd5a..e822635546 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -331,7 +331,7 @@ static NTSTATUS store_cldap_reply(TALLOC_CTX *mem_ctx, return status; } - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &logon29, + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &logon29, (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon_29); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return ndr_map_error2ntstatus(ndr_err); @@ -508,7 +508,7 @@ static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx, return NT_STATUS_NO_MEMORY; } - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, &r, (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon_29); data_blob_free(&blob); diff --git a/source3/libsmb/samlogon_cache.c b/source3/libsmb/samlogon_cache.c index 4abe5bb6de..af4986fa9d 100644 --- a/source3/libsmb/samlogon_cache.c +++ b/source3/libsmb/samlogon_cache.c @@ -141,7 +141,7 @@ bool netsamlogon_cache_store(const char *username, struct netr_SamInfo3 *info3) NDR_PRINT_DEBUG(netsamlogoncache_entry, &r); } - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, &r, + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &r, (ndr_push_flags_fn_t)ndr_push_netsamlogoncache_entry); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0,("netsamlogon_cache_store: failed to push entry to cache\n")); @@ -197,7 +197,7 @@ struct netr_SamInfo3 *netsamlogon_cache_get(TALLOC_CTX *mem_ctx, const DOM_SID * blob = data_blob_const(data.dptr, data.dsize); - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &r, + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, &r, (ndr_pull_flags_fn_t)ndr_pull_netsamlogoncache_entry); if (DEBUGLEVEL >= 10) { diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c index 08a49930b4..2f336f14e6 100644 --- a/source3/libsmb/trusts_util.c +++ b/source3/libsmb/trusts_util.c @@ -22,104 +22,6 @@ /********************************************************* Change the domain password on the PDC. - - Just changes the password betwen the two values specified. - - Caller must have the cli connected to the netlogon pipe - already. -**********************************************************/ - -static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, - const unsigned char orig_trust_passwd_hash[16], - const char *new_trust_pwd_cleartext, - const unsigned char new_trust_passwd_hash[16], - uint32 sec_channel_type) -{ - NTSTATUS result; - uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; - - result = rpccli_netlogon_setup_creds(cli, - cli->desthost, /* server name */ - lp_workgroup(), /* domain */ - global_myname(), /* client name */ - global_myname(), /* machine account name */ - orig_trust_passwd_hash, - sec_channel_type, - &neg_flags); - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n", - nt_errstr(result))); - return result; - } - - if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) { - - struct netr_Authenticator clnt_creds, srv_cred; - struct netr_CryptPassword new_password; - struct samr_CryptPassword password_buf; - - netlogon_creds_client_step(cli->dc, &clnt_creds); - - encode_pw_buffer(password_buf.data, new_trust_pwd_cleartext, STR_UNICODE); - - SamOEMhash(password_buf.data, cli->dc->sess_key, 516); - memcpy(new_password.data, password_buf.data, 512); - new_password.length = IVAL(password_buf.data, 512); - - result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx, - cli->dc->remote_machine, - cli->dc->mach_acct, - sec_channel_type, - global_myname(), - &clnt_creds, - &srv_cred, - &new_password); - - /* Always check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { - DEBUG(0,("rpccli_netr_ServerPasswordSet2: " - "credentials chain check failed\n")); - return NT_STATUS_ACCESS_DENIED; - } - - } else { - - struct netr_Authenticator clnt_creds, srv_cred; - struct samr_Password new_password; - - netlogon_creds_client_step(cli->dc, &clnt_creds); - - cred_hash3(new_password.hash, - new_trust_passwd_hash, - cli->dc->sess_key, 1); - - result = rpccli_netr_ServerPasswordSet(cli, mem_ctx, - cli->dc->remote_machine, - cli->dc->mach_acct, - sec_channel_type, - global_myname(), - &clnt_creds, - &srv_cred, - &new_password); - - /* Always check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { - DEBUG(0,("rpccli_netr_ServerPasswordSet: " - "credentials chain check failed\n")); - return NT_STATUS_ACCESS_DENIED; - } - } - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(0,("just_change_the_password: unable to change password (%s)!\n", - nt_errstr(result))); - } - return result; -} - -/********************************************************* - Change the domain password on the PDC. Store the password ourselves, but use the supplied password Caller must have already setup the connection to the NETLOGON pipe **********************************************************/ @@ -144,11 +46,11 @@ NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *m E_md4hash(new_trust_passwd, new_trust_passwd_hash); - nt_status = just_change_the_password(cli, mem_ctx, - orig_trust_passwd_hash, - new_trust_passwd, - new_trust_passwd_hash, - sec_channel_type); + nt_status = rpccli_netlogon_set_trust_password(cli, mem_ctx, + orig_trust_passwd_hash, + new_trust_passwd, + new_trust_passwd_hash, + sec_channel_type); if (NT_STATUS_IS_OK(nt_status)) { DEBUG(3,("%s : trust_pw_change_and_store_it: Changed password.\n", diff --git a/source3/modules/vfs_acl_xattr.c b/source3/modules/vfs_acl_xattr.c index fd59310755..a2f3477b76 100644 --- a/source3/modules/vfs_acl_xattr.c +++ b/source3/modules/vfs_acl_xattr.c @@ -38,7 +38,7 @@ static NTSTATUS parse_acl_blob(const DATA_BLOB *pblob, size_t sd_size; struct timespec ts; - ndr_err = ndr_pull_struct_blob(pblob, ctx, &xacl, + ndr_err = ndr_pull_struct_blob(pblob, ctx, NULL, &xacl, (ndr_pull_flags_fn_t)ndr_pull_xattr_NTACL); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -245,7 +245,7 @@ static NTSTATUS create_acl_blob(SEC_DESC *psd, DATA_BLOB *pblob) unix_timespec_to_nt_time(&xacl.info.sd_ts->last_changed, curr); ndr_err = ndr_push_struct_blob( - pblob, ctx, &xacl, + pblob, ctx, NULL, &xacl, (ndr_push_flags_fn_t)ndr_push_xattr_NTACL); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c index 7b5e510747..c707a1828f 100644 --- a/source3/modules/vfs_xattr_tdb.c +++ b/source3/modules/vfs_xattr_tdb.c @@ -48,7 +48,7 @@ static NTSTATUS xattr_tdb_pull_attrs(TALLOC_CTX *mem_ctx, blob = data_blob_const(data->dptr, data->dsize); ndr_err = ndr_pull_struct_blob( - &blob, result, result, + &blob, result, NULL, result, (ndr_pull_flags_fn_t)ndr_pull_tdb_xattrs); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { @@ -74,7 +74,7 @@ static NTSTATUS xattr_tdb_push_attrs(TALLOC_CTX *mem_ctx, enum ndr_err_code ndr_err; ndr_err = ndr_push_struct_blob( - &blob, mem_ctx, attribs, + &blob, mem_ctx, NULL, attribs, (ndr_push_flags_fn_t)ndr_push_tdb_xattrs); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index df87ed13d1..23618efd9f 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -538,3 +538,94 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli, return result; } + +/********************************************************* + Change the domain password on the PDC. + + Just changes the password betwen the two values specified. + + Caller must have the cli connected to the netlogon pipe + already. +**********************************************************/ + +NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const unsigned char orig_trust_passwd_hash[16], + const char *new_trust_pwd_cleartext, + const unsigned char new_trust_passwd_hash[16], + uint32_t sec_channel_type) +{ + NTSTATUS result; + uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + struct netr_Authenticator clnt_creds, srv_cred; + + result = rpccli_netlogon_setup_creds(cli, + cli->desthost, /* server name */ + lp_workgroup(), /* domain */ + global_myname(), /* client name */ + global_myname(), /* machine account name */ + orig_trust_passwd_hash, + sec_channel_type, + &neg_flags); + + if (!NT_STATUS_IS_OK(result)) { + DEBUG(3,("rpccli_netlogon_set_trust_password: unable to setup creds (%s)!\n", + nt_errstr(result))); + return result; + } + + netlogon_creds_client_step(cli->dc, &clnt_creds); + + if (neg_flags & NETLOGON_NEG_PASSWORD_SET2) { + + struct netr_CryptPassword new_password; + + init_netr_CryptPassword(new_trust_pwd_cleartext, + cli->dc->sess_key, + &new_password); + + result = rpccli_netr_ServerPasswordSet2(cli, mem_ctx, + cli->dc->remote_machine, + cli->dc->mach_acct, + sec_channel_type, + global_myname(), + &clnt_creds, + &srv_cred, + &new_password); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0,("rpccli_netr_ServerPasswordSet2 failed: %s\n", + nt_errstr(result))); + return result; + } + } else { + + struct samr_Password new_password; + + cred_hash3(new_password.hash, + new_trust_passwd_hash, + cli->dc->sess_key, 1); + + result = rpccli_netr_ServerPasswordSet(cli, mem_ctx, + cli->dc->remote_machine, + cli->dc->mach_acct, + sec_channel_type, + global_myname(), + &clnt_creds, + &srv_cred, + &new_password); + if (!NT_STATUS_IS_OK(result)) { + DEBUG(0,("rpccli_netr_ServerPasswordSet failed: %s\n", + nt_errstr(result))); + return result; + } + } + + /* Always check returned credentials. */ + if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { + DEBUG(0,("credentials chain check failed\n")); + return NT_STATUS_ACCESS_DENIED; + } + + return result; +} + diff --git a/source3/rpc_client/init_netlogon.c b/source3/rpc_client/init_netlogon.c index 61841953fc..e4c39e739e 100644 --- a/source3/rpc_client/init_netlogon.c +++ b/source3/rpc_client/init_netlogon.c @@ -391,3 +391,20 @@ void init_netr_PasswordInfo(struct netr_PasswordInfo *r, r->lmpassword = lmpassword; r->ntpassword = ntpassword; } + +/************************************************************************* + inits a netr_CryptPassword structure + *************************************************************************/ + +void init_netr_CryptPassword(const char *pwd, + unsigned char session_key[16], + struct netr_CryptPassword *pwd_buf) +{ + struct samr_CryptPassword password_buf; + + encode_pw_buffer(password_buf.data, pwd, STR_UNICODE); + + SamOEMhash(password_buf.data, session_key, 516); + memcpy(pwd_buf->data, password_buf.data, 512); + pwd_buf->length = IVAL(password_buf.data, 512); +} diff --git a/source3/samba4.m4 b/source3/samba4.m4 index c02d3d4b3b..728fd2d45d 100644 --- a/source3/samba4.m4 +++ b/source3/samba4.m4 @@ -95,7 +95,6 @@ m4_include(ntvfs/unixuid/config.m4) m4_include(auth/config.m4) m4_include(kdc/config.m4) m4_include(ntvfs/sysdep/config.m4) -m4_include(lib/appweb/config.m4) m4_include(nsswitch/config.m4) dnl Samba 4 files diff --git a/source3/samba4.mk b/source3/samba4.mk index 294eef8b8f..2646b12a0d 100644 --- a/source3/samba4.mk +++ b/source3/samba4.mk @@ -7,7 +7,7 @@ PARTLINK = $(PROG_LD) -r MDLD = $(SHLD) MDLD_FLAGS = $(LDSHFLAGS) -samba4srcdir = $(call abspath,$(srcdir)/../source4) +samba4srcdir = $(srcdir)/../source4 # Flags used for the samba 4 files # $(srcdir)/include is required for config.h @@ -83,7 +83,6 @@ libcmdlinesrcdir := $(samba4srcdir)/lib/cmdline poptsrcdir := $(samba4srcdir)/../lib/popt socketwrappersrcdir := $(samba4srcdir)/../lib/socket_wrapper nsswrappersrcdir := $(samba4srcdir)/../lib/nss_wrapper -appwebsrcdir := $(samba4srcdir)/lib/appweb libstreamsrcdir := $(samba4srcdir)/lib/stream libutilsrcdir := $(samba4srcdir)/lib/util libtdrsrcdir := $(samba4srcdir)/lib/tdr @@ -108,7 +107,6 @@ ntvfssrcdir := $(samba4srcdir)/ntvfs ntptrsrcdir := $(samba4srcdir)/ntptr clientsrcdir := $(samba4srcdir)/client libclisrcdir := $(samba4srcdir)/libcli -ejsscriptsrcdir := $(samba4srcdir)/scripting/ejs pyscriptsrcdir := $(samba4srcdir)/scripting/python kdcsrcdir := $(samba4srcdir)/kdc smbreadlinesrcdir := $(samba4srcdir)/lib/smbreadline @@ -116,6 +114,7 @@ ntp_signdsrcdir := $(samba4srcdir)/ntp_signd tdbsrcdir := $(samba4srcdir)/../lib/tdb ldbsrcdir := $(samba4srcdir)/lib/ldb tallocsrcdir := $(samba4srcdir)/../lib/talloc +comsrcdir := $(samba4srcdir)/lib/com override ASN1C = bin/asn1_compile4 override ET_COMPILER = bin/compile_et4 include samba4-data.mk diff --git a/source3/script/build_idl.sh b/source3/script/build_idl.sh index 8ff5dcd949..2027fd3937 100755 --- a/source3/script/build_idl.sh +++ b/source3/script/build_idl.sh @@ -19,7 +19,7 @@ for f in ${IDL_FILES}; do basename=`basename $f .idl` ndr="librpc/gen_ndr/ndr_$basename.c" - if [ -f $ndr ] && false; then + if [ -f $ndr ]; then if [ "x`find librpc/idl/$f -newer $ndr -print`" = "xlibrpc/idl/$f" ]; then list="$list librpc/idl/$f" fi diff --git a/source3/smbd/notify_internal.c b/source3/smbd/notify_internal.c index 84b8e1098e..06da717799 100644 --- a/source3/smbd/notify_internal.c +++ b/source3/smbd/notify_internal.c @@ -166,7 +166,7 @@ static NTSTATUS notify_load(struct notify_context *notify, struct db_record *rec status = NT_STATUS_OK; if (blob.length > 0) { enum ndr_err_code ndr_err; - ndr_err = ndr_pull_struct_blob(&blob, notify->array, notify->array, + ndr_err = ndr_pull_struct_blob(&blob, notify->array, NULL, notify->array, (ndr_pull_flags_fn_t)ndr_pull_notify_array); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); @@ -220,7 +220,7 @@ static NTSTATUS notify_save(struct notify_context *notify, struct db_record *rec tmp_ctx = talloc_new(notify); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); - ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, notify->array, + ndr_err = ndr_push_struct_blob(&blob, tmp_ctx, NULL, notify->array, (ndr_push_flags_fn_t)ndr_push_notify_array); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); @@ -258,7 +258,7 @@ static void notify_handler(struct messaging_context *msg_ctx, void *private_data return; } - ndr_err = ndr_pull_struct_blob(data, tmp_ctx, &ev, + ndr_err = ndr_pull_struct_blob(data, tmp_ctx, NULL, &ev, (ndr_pull_flags_fn_t)ndr_pull_notify_event); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); @@ -561,7 +561,7 @@ static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry * tmp_ctx = talloc_new(notify); - ndr_err = ndr_push_struct_blob(&data, tmp_ctx, &ev, + ndr_err = ndr_push_struct_blob(&data, tmp_ctx, NULL, &ev, (ndr_push_flags_fn_t)ndr_push_notify_event); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { talloc_free(tmp_ctx); diff --git a/source3/utils/net_rpc_registry.c b/source3/utils/net_rpc_registry.c index 124af00b57..005e3ca556 100644 --- a/source3/utils/net_rpc_registry.c +++ b/source3/utils/net_rpc_registry.c @@ -1186,7 +1186,7 @@ static NTSTATUS rpc_registry_getsd_internal(struct net_context *c, blob.data = sd->data; blob.length = sd->size; - ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &sec_desc, + ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, &sec_desc, (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { status = ndr_map_error2ntstatus(ndr_err); diff --git a/source3/winbindd/idmap_adex/cell_util.c b/source3/winbindd/idmap_adex/cell_util.c new file mode 100644 index 0000000000..f5c08a0454 --- /dev/null +++ b/source3/winbindd/idmap_adex/cell_util.c @@ -0,0 +1,292 @@ +/* + * idmap_adex: Support for AD Forests + * + * Copyright (C) Gerald (Jerry) Carter 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +/********************************************************************** +**********************************************************************/ + + char *find_attr_string(char **list, size_t num_lines, const char *substr) +{ + int i; + int cmplen = strlen(substr); + + for (i = 0; i < num_lines; i++) { + /* make sure to avoid substring matches like uid + and uidNumber */ + if ((StrnCaseCmp(list[i], substr, cmplen) == 0) && + (list[i][cmplen] == '=')) { + /* Don't return an empty string */ + if (list[i][cmplen + 1] != '\0') + return &(list[i][cmplen + 1]); + + return NULL; + } + } + + return NULL; +} + +/********************************************************************** +**********************************************************************/ + + bool is_object_class(char **list, size_t num_lines, const char *substr) +{ + int i; + + for (i = 0; i < num_lines; i++) { + if (strequal(list[i], substr)) { + return true; + } + } + + return false; +} + +/********************************************************************** + Find out about the cell (e.g. use2307Attrs, etc...) +**********************************************************************/ + + NTSTATUS cell_lookup_settings(struct likewise_cell * cell) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + + /* Parameter check */ + + if (!cell) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Only supporting Forest-wide, schema based searches */ + + cell_set_flags(cell, LWCELL_FLAG_USE_RFC2307_ATTRS); + cell_set_flags(cell, LWCELL_FLAG_SEARCH_FOREST); + + cell->provider = &ccp_unified; + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1,("LWI: Failed to obtain cell settings (%s)\n", + nt_errstr(nt_status))); + } + + return nt_status; +} + + +static NTSTATUS cell_lookup_forest(struct likewise_cell *c) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct gc_info *gc = NULL; + + if (!c) { + return NT_STATUS_INVALID_PARAMETER; + } + + if ((gc = TALLOC_ZERO_P(NULL, struct gc_info)) == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Query the rootDSE for the forest root naming conect first. + Check that the a GC server for the forest has not already + been added */ + + nt_status = gc_find_forest_root(gc, cell_dns_domain(c)); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + c->forest_name = talloc_strdup(c, gc->forest_name); + BAIL_ON_PTR_ERROR(c->forest_name, nt_status); + +done: + if (gc) { + talloc_free(gc); + } + + return nt_status; +} + +/********************************************************************** +**********************************************************************/ + + NTSTATUS cell_locate_membership(ADS_STRUCT * ads) +{ + ADS_STATUS status; + char *domain_dn = ads_build_dn(lp_realm()); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + struct likewise_cell *cell = NULL; + + /* In the Likewise plugin, I had to support the concept of cells + based on the machine's membership in an OU. However, now I'll + just assume our membership in the forest cell */ + + DEBUG(2, ("locate_cell_membership: Located membership " + "in cell \"%s\"\n", domain_dn)); + + if ((cell = cell_new()) == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + status = ads_domain_sid(ads, &sid); + if (!ADS_ERR_OK(status)) { + DEBUG(3,("locate_cell_membership: Failed to find " + "domain SID for %s\n", domain_dn)); + } + + /* save the SID and search base for our domain */ + + cell_set_dns_domain(cell, lp_realm()); + cell_set_connection(cell, ads); + cell_set_dn(cell, domain_dn); + cell_set_domain_sid(cell, &sid); + + /* Now save our forest root */ + + cell_lookup_forest(cell); + + /* Add the cell to the list */ + + if (!cell_list_add(cell)) { + nt_status = NT_STATUS_INSUFFICIENT_RESOURCES; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Done! */ + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(0,("LWI: Failed to locate cell membership (%s)\n", + nt_errstr(nt_status))); + } + + SAFE_FREE(domain_dn); + + return nt_status; +} + +/********************************************************************* + ********************************************************************/ + + int min_id_value(void) +{ + int id_val; + + id_val = lp_parm_int(-1, "lwidentity", "min_id_value", MIN_ID_VALUE); + + /* Still don't let it go below 50 */ + + return MAX(50, id_val); +} + +/******************************************************************** + *******************************************************************/ + + char *cell_dn_to_dns(const char *dn) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *domain = NULL; + char *dns_name = NULL; + const char *tmp_dn; + char *buffer = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!dn || !*dn) { + goto done; + } + + tmp_dn = talloc_strdup(frame, dn); + BAIL_ON_PTR_ERROR(tmp_dn, nt_status); + + while (next_token_talloc(frame, &tmp_dn, &buffer, ",")) { + + /* skip everything up the where DC=... begins */ + if (StrnCaseCmp(buffer, "DC=", 3) != 0) + continue; + + if (!domain) { + domain = talloc_strdup(frame, &buffer[3]); + } else { + domain = talloc_asprintf_append(domain, ".%s", + &buffer[3]); + } + BAIL_ON_PTR_ERROR(domain, nt_status); + } + + dns_name = SMB_STRDUP(domain); + BAIL_ON_PTR_ERROR(dns_name, nt_status); + + nt_status = NT_STATUS_OK; + +done: + PRINT_NTSTATUS_ERROR(nt_status, "cell_dn_to_dns", 1); + + talloc_destroy(frame); + + return dns_name; +} + +/********************************************************************* + ********************************************************************/ + + NTSTATUS get_sid_type(ADS_STRUCT *ads, + LDAPMessage *msg, + enum lsa_SidType *type) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + uint32_t atype; + + if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) { + nt_status = NT_STATUS_INVALID_USER_BUFFER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + switch (atype &0xF0000000) { + case ATYPE_SECURITY_GLOBAL_GROUP: + *type = SID_NAME_DOM_GRP; + break; + case ATYPE_SECURITY_LOCAL_GROUP: + *type = SID_NAME_ALIAS; + break; + case ATYPE_NORMAL_ACCOUNT: + case ATYPE_WORKSTATION_TRUST: + case ATYPE_INTERDOMAIN_TRUST: + *type = SID_NAME_USER; + break; + default: + *type = SID_NAME_USE_NONE; + nt_status = NT_STATUS_INVALID_ACCOUNT_NAME; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + return nt_status; +} diff --git a/source3/winbindd/idmap_adex/domain_util.c b/source3/winbindd/idmap_adex/domain_util.c new file mode 100644 index 0000000000..ab31ccef7a --- /dev/null +++ b/source3/winbindd/idmap_adex/domain_util.c @@ -0,0 +1,278 @@ +/* + * idmap_adex: Domain search interface + * + * Copyright (C) Gerald (Jerry) Carter 2007-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +struct dc_info { + struct dc_info *prev, *next; + char *dns_name; + struct likewise_cell *domain_cell; +}; + +static struct dc_info *_dc_server_list = NULL; + + +/********************************************************************** + *********************************************************************/ + +static struct dc_info *dc_list_head(void) +{ + return _dc_server_list; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS dc_add_domain(const char *domain) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct dc_info *dc = NULL; + + /* Check for duplicates */ + + dc = dc_list_head(); + while (dc) { + if (strequal (dc->dns_name, domain)) + break; + dc = dc->next; + } + + if (dc) { + DEBUG(10,("dc_add_domain: %s already in list\n", domain)); + return NT_STATUS_OK; + } + + dc = TALLOC_ZERO_P(NULL, struct dc_info); + BAIL_ON_PTR_ERROR(dc, nt_status); + + dc->dns_name = talloc_strdup(dc, domain); + BAIL_ON_PTR_ERROR(dc->dns_name, nt_status); + + DLIST_ADD_END(_dc_server_list, dc, struct dc_info*); + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_destroy(dc); + DEBUG(0,("LWI: Failed to add new DC connection for %s (%s)\n", + domain, nt_errstr(nt_status))); + } + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static void dc_server_list_destroy(void) +{ + struct dc_info *dc = dc_list_head(); + + while (dc) { + struct dc_info *p = dc->next; + + cell_destroy(dc->domain_cell); + talloc_destroy(dc); + + dc = p; + } + + return; +} + + +/********************************************************************** + *********************************************************************/ + + NTSTATUS domain_init_list(void) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct winbindd_tdc_domain *domains = NULL; + size_t num_domains = 0; + int i; + + if (_dc_server_list != NULL) { + dc_server_list_destroy(); + } + + /* Add our domain */ + + nt_status = dc_add_domain(lp_realm()); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if (!wcache_tdc_fetch_list(&domains, &num_domains)) { + nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Add all domains with an incoming trust path */ + + for (i=0; i<num_domains; i++) { + uint32_t flags = (NETR_TRUST_FLAG_INBOUND|NETR_TRUST_FLAG_IN_FOREST); + + /* We just require one of the flags to be set here */ + + if (domains[i].trust_flags & flags) { + nt_status = dc_add_domain(domains[i].dns_name); + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + } + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("LWI: Failed to initialize DC list (%s)\n", + nt_errstr(nt_status))); + } + + TALLOC_FREE(domains); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS dc_do_search(struct dc_info *dc, + const char *search_base, + int scope, + const char *expr, + const char **attrs, + LDAPMessage ** msg) +{ + ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + + status = cell_do_search(dc->domain_cell, search_base, + scope, expr, attrs, msg); + nt_status = ads_ntstatus(status); + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static struct dc_info *dc_find_domain(const char *dns_domain) +{ + struct dc_info *dc = dc_list_head(); + + if (!dc) + return NULL; + + while (dc) { + if (strequal(dc->dns_name, dns_domain)) { + return dc; + } + + dc = dc->next; + } + + return NULL; +} + +/********************************************************************** + *********************************************************************/ + + NTSTATUS dc_search_domains(struct likewise_cell **cell, + LDAPMessage **msg, + const char *dn, + const DOM_SID *sid) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX *frame = talloc_stackframe(); + char *dns_domain; + const char *attrs[] = { "*", NULL }; + struct dc_info *dc = NULL; + const char *base = NULL; + + if (!dn || !*dn) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + dns_domain = cell_dn_to_dns(dn); + BAIL_ON_PTR_ERROR(dns_domain, nt_status); + + if ((dc = dc_find_domain(dns_domain)) == NULL) { + nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Reparse the cell settings for the domain if necessary */ + + if (!dc->domain_cell) { + char *base_dn; + + base_dn = ads_build_dn(dc->dns_name); + BAIL_ON_PTR_ERROR(base_dn, nt_status); + + nt_status = cell_connect_dn(&dc->domain_cell, base_dn); + SAFE_FREE(base_dn); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = cell_lookup_settings(dc->domain_cell); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* By definition this is already part of a larger + forest-wide search scope */ + + cell_set_flags(dc->domain_cell, LWCELL_FLAG_SEARCH_FOREST); + } + + /* Check whether we are operating in non-schema or RFC2307 + mode */ + + if (cell_flags(dc->domain_cell) & LWCELL_FLAG_USE_RFC2307_ATTRS) { + nt_status = dc_do_search(dc, dn, LDAP_SCOPE_BASE, + "(objectclass=*)", attrs, msg); + } else { + const char *sid_str = NULL; + char *filter = NULL; + + sid_str = sid_string_talloc(frame, sid); + BAIL_ON_PTR_ERROR(sid_str, nt_status); + + filter = talloc_asprintf(frame, "(keywords=backLink=%s)", + sid_str); + BAIL_ON_PTR_ERROR(filter, nt_status); + + base = cell_search_base(dc->domain_cell); + BAIL_ON_PTR_ERROR(base, nt_status); + + nt_status = dc_do_search(dc, base, LDAP_SCOPE_SUBTREE, + filter, attrs, msg); + } + BAIL_ON_NTSTATUS_ERROR(nt_status); + + *cell = dc->domain_cell; + +done: + talloc_destroy(CONST_DISCARD(char*, base)); + talloc_destroy(frame); + + return nt_status; +} diff --git a/source3/winbindd/idmap_adex/gc_util.c b/source3/winbindd/idmap_adex/gc_util.c new file mode 100644 index 0000000000..87dd3c058d --- /dev/null +++ b/source3/winbindd/idmap_adex/gc_util.c @@ -0,0 +1,848 @@ +/* + * idmap_adex: Global Catalog search interface + * + * Copyright (C) Gerald (Jerry) Carter 2007-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +static struct gc_info *_gc_server_list = NULL; + + +/********************************************************************** + *********************************************************************/ + +static struct gc_info *gc_list_head(void) +{ + return _gc_server_list; +} + +/********************************************************************** + Checks if either of the domains is a subdomain of the other + *********************************************************************/ + +static bool is_subdomain(const char* a, const char *b) +{ + char *s; + TALLOC_CTX *frame = talloc_stackframe(); + char *x, *y; + bool ret = false; + + /* Trivial cases */ + + if (!a && !b) + return true; + + if (!a || !b) + return false; + + /* Normalize the case */ + + x = talloc_strdup(frame, a); + y = talloc_strdup(frame, b); + if (!x || !y) { + ret = false; + goto done; + } + + strupper_m(x); + strupper_m(y); + + /* Exact match */ + + if (strcmp(x, y) == 0) { + ret = true; + goto done; + } + + /* Check for trailing substrings */ + + s = strstr_m(x, y); + if (s && (strlen(s) == strlen(y))) { + ret = true; + goto done; + } + + s = strstr_m(y, x); + if (s && (strlen(s) == strlen(x))) { + ret = true; + goto done; + } + +done: + talloc_destroy(frame); + + return ret; +} + +/********************************************************************** + *********************************************************************/ + + NTSTATUS gc_find_forest_root(struct gc_info *gc, const char *domain) +{ + ADS_STRUCT *ads = NULL; + ADS_STATUS ads_status; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct nbt_cldap_netlogon_5 cldap_reply; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!gc || !domain) { + return NT_STATUS_INVALID_PARAMETER; + } + + ZERO_STRUCT(cldap_reply); + + ads = ads_init(domain, NULL, NULL); + BAIL_ON_PTR_ERROR(ads, nt_status); + + ads->auth.flags = ADS_AUTH_NO_BIND; + ads_status = ads_connect(ads); + if (!ADS_ERR_OK(ads_status)) { + DEBUG(4, ("find_forest_root: ads_connect(%s) failed! (%s)\n", + domain, ads_errstr(ads_status))); + } + nt_status = ads_ntstatus(ads_status); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if (!ads_cldap_netlogon_5(frame, + ads->config.ldap_server_name, + ads->config.realm, + &cldap_reply)) + { + DEBUG(4,("find_forest_root: Failed to get a CLDAP reply from %s!\n", + ads->server.ldap_server)); + nt_status = NT_STATUS_IO_TIMEOUT; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + gc->forest_name = talloc_strdup(gc, cldap_reply.forest); + BAIL_ON_PTR_ERROR(gc->forest_name, nt_status); + +done: + if (ads) { + ads_destroy(&ads); + } + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS gc_add_forest(const char *domain) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct gc_info *gc = NULL; + struct gc_info *find_gc = NULL; + char *dn; + ADS_STRUCT *ads = NULL; + struct likewise_cell *primary_cell = NULL; + + primary_cell = cell_list_head(); + if (!primary_cell) { + nt_status = NT_STATUS_INVALID_SERVER_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Check for duplicates based on domain name first as this + requires no connection */ + + find_gc = gc_list_head(); + while (find_gc) { + if (strequal (find_gc->forest_name, domain)) + break; + find_gc = find_gc->next; + } + + if (find_gc) { + DEBUG(10,("gc_add_forest: %s already in list\n", find_gc->forest_name)); + return NT_STATUS_OK; + } + + if ((gc = TALLOC_ZERO_P(NULL, struct gc_info)) == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Query the rootDSE for the forest root naming conect first. + Check that the a GC server for the forest has not already + been added */ + + nt_status = gc_find_forest_root(gc, domain); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + find_gc = gc_list_head(); + while (find_gc) { + if (strequal (find_gc->forest_name, gc->forest_name)) + break; + find_gc = find_gc->next; + } + + if (find_gc) { + DEBUG(10,("gc_add_forest: Forest %s already in list\n", + find_gc->forest_name)); + return NT_STATUS_OK; + } + + /* Not found, so add it here. Make sure we connect to + a DC in _this_ domain and not the forest root. */ + + dn = ads_build_dn(gc->forest_name); + BAIL_ON_PTR_ERROR(dn, nt_status); + + gc->search_base = talloc_strdup(gc, dn); + SAFE_FREE(dn); + BAIL_ON_PTR_ERROR(gc->search_base, nt_status); + +#if 0 + /* Can't use cell_connect_dn() here as there is no way to + specifiy the LWCELL_FLAG_GC_CELL flag setting for cell_connect() */ + + nt_status = cell_connect_dn(&gc->forest_cell, gc->search_base); + BAIL_ON_NTSTATUS_ERROR(nt_status); +#else + + gc->forest_cell = cell_new(); + BAIL_ON_PTR_ERROR(gc->forest_cell, nt_status); + + /* Set the DNS domain, dn, etc ... and add it to the list */ + + cell_set_dns_domain(gc->forest_cell, gc->forest_name); + cell_set_dn(gc->forest_cell, gc->search_base); + cell_set_flags(gc->forest_cell, LWCELL_FLAG_GC_CELL); +#endif + + /* It is possible to belong to a non-forest cell and a + non-provisioned forest (at our domain levele). In that + case, we should just inherit the flags from our primary + cell since the GC searches will match our own schema + model. */ + + if (strequal(primary_cell->forest_name, gc->forest_name) + || is_subdomain(primary_cell->dns_domain, gc->forest_name)) + { + cell_set_flags(gc->forest_cell, cell_flags(primary_cell)); + } else { + /* outside of our domain */ + + nt_status = cell_connect(gc->forest_cell); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = cell_lookup_settings(gc->forest_cell); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Drop the connection now that we have the settings */ + + ads = cell_connection(gc->forest_cell); + ads_destroy(&ads); + cell_set_connection(gc->forest_cell, NULL); + } + + DLIST_ADD_END(_gc_server_list, gc, struct gc_info*); + + DEBUG(10,("gc_add_forest: Added %s to Global Catalog list of servers\n", + gc->forest_name)); + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_destroy(gc); + DEBUG(3,("LWI: Failed to add new GC connection for %s (%s)\n", + domain, nt_errstr(nt_status))); + } + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static void gc_server_list_destroy(void) +{ + struct gc_info *gc = gc_list_head(); + + while (gc) { + struct gc_info *p = gc->next; + + cell_destroy(gc->forest_cell); + talloc_destroy(gc); + + gc = p; + } + + _gc_server_list = NULL; + + return; +} + +/********************************************************************** + Setup the initial list of forests and initial the forest cell + settings for each. FIXME!!! + *********************************************************************/ + + NTSTATUS gc_init_list(void) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct winbindd_tdc_domain *domains = NULL; + size_t num_domains = 0; + int i; + + if (_gc_server_list != NULL) { + gc_server_list_destroy(); + } + + if (!wcache_tdc_fetch_list(&domains, &num_domains)) { + nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Find our forest first. Have to try all domains here starting + with our own. gc_add_forest() filters duplicates */ + + nt_status = gc_add_forest(lp_realm()); + WARN_ON_NTSTATUS_ERROR(nt_status); + + for (i=0; i<num_domains; i++) { + uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST); + + /* I think we should be able to break out of loop once + we add a GC for our forest and not have to test every one. + In fact, this entire loop is probably irrelevant since + the GC location code should always find a GC given lp_realm(). + Will have to spend time testing before making the change. + --jerry */ + + if ((domains[i].trust_flags & flags) == flags) { + nt_status = gc_add_forest(domains[i].dns_name); + WARN_ON_NTSTATUS_ERROR(nt_status); + /* Don't BAIL here since not every domain may + have a GC server */ + } + } + + /* Now add trusted forests. gc_add_forest() will filter out + duplicates. Check everything with an incoming trust path + that is not in our own forest. */ + + for (i=0; i<num_domains; i++) { + uint32_t flags = domains[i].trust_flags; + uint32_t attribs = domains[i].trust_attribs; + + /* Skip non_AD domains */ + + if (strlen(domains[i].dns_name) == 0) { + continue; + } + + /* Only add a GC for a forest outside of our own. + Ignore QUARANTINED/EXTERNAL trusts */ + + if ((flags & NETR_TRUST_FLAG_INBOUND) + && !(flags & NETR_TRUST_FLAG_IN_FOREST) + && (attribs & NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) + { + nt_status = gc_add_forest(domains[i].dns_name); + WARN_ON_NTSTATUS_ERROR(nt_status); + } + } + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("LWI: Failed to initialized GC list (%s)\n", + nt_errstr(nt_status))); + } + + TALLOC_FREE(domains); + + return nt_status; +} + + +/********************************************************************** + *********************************************************************/ + + struct gc_info *gc_search_start(void) +{ + NTSTATUS nt_status = NT_STATUS_OK; + struct gc_info *gc = gc_list_head(); + + if (!gc) { + nt_status = gc_init_list(); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + gc = gc_list_head(); + } + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("LWI: Failed to initialize GC list (%s)\n", + nt_errstr(nt_status))); + } + + return gc; +} + +/********************************************************************** + Search Global Catalog. Always search our own forest. The flags set + controls whether or not we search cross forest. Assume that the + resulting set is always returned from one GC so that we don't have to + both combining the LDAPMessage * results + *********************************************************************/ + + NTSTATUS gc_search_forest(struct gc_info *gc, + LDAPMessage **msg, + const char *filter) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + const char *attrs[] = {"*", NULL}; + LDAPMessage *m = NULL; + + if (!gc || !msg || !filter) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* When you have multiple domain trees in a forest, the + GC will search all naming contexts when you send it + and empty ("") base search suffix. Tested against + Windows 2003. */ + + ads_status = cell_do_search(gc->forest_cell, "", + LDAP_SCOPE_SUBTREE, filter, attrs, &m); + nt_status = ads_ntstatus(ads_status); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + *msg = m; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(2,("LWI: Forest wide search %s failed (%s)\n", + filter, nt_errstr(nt_status))); + } + + return nt_status; +} + +/********************************************************************** + Search all forests via GC and return the results in an array of + ADS_STRUCT/LDAPMessage pairs. + *********************************************************************/ + + NTSTATUS gc_search_all_forests(const char *filter, + ADS_STRUCT ***ads_list, + LDAPMessage ***msg_list, + int *num_resp, uint32_t flags) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct gc_info *gc = NULL; + uint32_t test_flags = ADEX_GC_SEARCH_CHECK_UNIQUE; + + *ads_list = NULL; + *msg_list = NULL; + *num_resp = 0; + + if ((gc = gc_search_start()) == NULL) { + nt_status = NT_STATUS_INVALID_DOMAIN_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + while (gc) { + LDAPMessage *m = NULL; + + nt_status = gc_search_forest(gc, &m, filter); + if (!NT_STATUS_IS_OK(nt_status)) { + gc = gc->next; + continue; + } + + nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell), + m, ads_list, msg_list, + num_resp); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* If there can only be one match, then we are done */ + + if ((*num_resp > 0) && ((flags & test_flags) == test_flags)) { + break; + } + + gc = gc->next; + } + + if (*num_resp == 0) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + return nt_status; +} + +/********************************************************************** + Search all forests via GC and return the results in an array of + ADS_STRUCT/LDAPMessage pairs. + *********************************************************************/ + + NTSTATUS gc_search_all_forests_unique(const char *filter, + ADS_STRUCT **ads, + LDAPMessage **msg) +{ + ADS_STRUCT **ads_list = NULL; + LDAPMessage **msg_list = NULL; + int num_resp; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + + nt_status = gc_search_all_forests(filter, &ads_list, + &msg_list, &num_resp, + ADEX_GC_SEARCH_CHECK_UNIQUE); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = check_result_unique(ads_list[0], msg_list[0]); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + *ads = ads_list[0]; + *msg = msg_list[0]; + +done: + /* Be care that we don't free the msg result being returned */ + + if (!NT_STATUS_IS_OK(nt_status)) { + free_result_array(ads_list, msg_list, num_resp); + } else { + talloc_destroy(ads_list); + talloc_destroy(msg_list); + } + + return nt_status; +} + +/********************************************************************* + ********************************************************************/ + + NTSTATUS gc_name_to_sid(const char *domain, + const char *name, + DOM_SID *sid, + enum lsa_SidType *sid_type) +{ + TALLOC_CTX *frame = talloc_stackframe(); + char *p, *name_user; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *name_filter; + ADS_STRUCT *ads = NULL; + LDAPMessage *msg = NULL; + LDAPMessage *e = NULL; + char *dn = NULL; + char *dns_domain = NULL; + ADS_STRUCT **ads_list = NULL; + LDAPMessage **msg_list = NULL; + int num_resp = 0; + int i; + + /* Strip the "DOMAIN\" prefix if necessary and search for + a matching sAMAccountName in the forest */ + + if ((p = strchr_m( name, '\\' )) == NULL) + name_user = talloc_strdup( frame, name ); + else + name_user = talloc_strdup( frame, p+1 ); + BAIL_ON_PTR_ERROR(name_user, nt_status); + + name_filter = talloc_asprintf(frame, "(sAMAccountName=%s)", name_user); + BAIL_ON_PTR_ERROR(name_filter, nt_status); + + nt_status = gc_search_all_forests(name_filter, &ads_list, + &msg_list, &num_resp, 0); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Assume failure until we know otherwise*/ + + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + + /* Match the domain name from the DN */ + + for (i=0; i<num_resp; i++) { + ads = ads_list[i]; + msg = msg_list[i]; + + e = ads_first_entry(ads, msg); + while (e) { + struct winbindd_tdc_domain *domain_rec; + + dn = ads_get_dn(ads, e); + BAIL_ON_PTR_ERROR(dn, nt_status); + + dns_domain = cell_dn_to_dns(dn); + SAFE_FREE(dn); + BAIL_ON_PTR_ERROR(dns_domain, nt_status); + + domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); + SAFE_FREE(dns_domain); + + /* Ignore failures and continue the search */ + + if (!domain_rec) { + e = ads_next_entry(ads, e); + continue; + } + + /* Check for a match on the domain name */ + + if (strequal(domain, domain_rec->domain_name)) { + if (!ads_pull_sid(ads, e, "objectSid", sid)) { + nt_status = NT_STATUS_INVALID_SID; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + talloc_destroy(domain_rec); + + nt_status = get_sid_type(ads, msg, sid_type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* We're done! */ + nt_status = NT_STATUS_OK; + break; + } + + /* once more around thew merry-go-round */ + + talloc_destroy(domain_rec); + e = ads_next_entry(ads, e); + } + } + +done: + free_result_array(ads_list, msg_list, num_resp); + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + Pull an attribute string value + *******************************************************************/ + +static NTSTATUS get_object_account_name(ADS_STRUCT *ads, + LDAPMessage *msg, + char **name) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *sam_name = NULL; + struct winbindd_tdc_domain *domain_rec = NULL; + char *dns_domain = NULL; + char *dn = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + int len; + + /* Check parameters */ + + if (!ads || !msg || !name) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* get the name and domain */ + + dn = ads_get_dn(ads, msg); + BAIL_ON_PTR_ERROR(dn, nt_status); + + DEBUG(10,("get_object_account_name: dn = \"%s\"\n", dn)); + + dns_domain = cell_dn_to_dns(dn); + SAFE_FREE(dn); + BAIL_ON_PTR_ERROR(dns_domain, nt_status); + + domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); + SAFE_FREE(dns_domain); + + if (!domain_rec) { + nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + sam_name = ads_pull_string(ads, frame, msg, "sAMAccountName"); + BAIL_ON_PTR_ERROR(sam_name, nt_status); + + len = asprintf(name, "%s\\%s", domain_rec->domain_name, sam_name); + if (len == -1) { + *name = NULL; + BAIL_ON_PTR_ERROR((*name), nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(frame); + + return nt_status; +} + +/********************************************************************* + ********************************************************************/ + + NTSTATUS gc_sid_to_name(const DOM_SID *sid, + char **name, + enum lsa_SidType *sid_type) +{ + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *filter; + ADS_STRUCT *ads = NULL; + LDAPMessage *msg = NULL; + char *sid_string; + + *name = NULL; + + sid_string = sid_binstring(sid); + BAIL_ON_PTR_ERROR(sid_string, nt_status); + + filter = talloc_asprintf(frame, "(objectSid=%s)", sid_string); + SAFE_FREE(sid_string); + BAIL_ON_PTR_ERROR(filter, nt_status); + + nt_status = gc_search_all_forests_unique(filter, &ads, &msg); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_object_account_name(ads, msg, name); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_sid_type(ads, msg, sid_type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + ads_msgfree(ads, msg); + talloc_destroy(frame); + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + + NTSTATUS add_ads_result_to_array(ADS_STRUCT *ads, + LDAPMessage *msg, + ADS_STRUCT ***ads_list, + LDAPMessage ***msg_list, + int *size) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + ADS_STRUCT **ads_tmp = NULL; + LDAPMessage **msg_tmp = NULL; + int count = *size; + + if (!ads || !msg) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + +#if 0 + /* Don't add a response with no entries */ + + if (ads_count_replies(ads, msg) == 0) { + return NT_STATUS_OK; + } +#endif + + if (count == 0) { + ads_tmp = TALLOC_ARRAY(NULL, ADS_STRUCT*, 1); + BAIL_ON_PTR_ERROR(ads_tmp, nt_status); + + msg_tmp = TALLOC_ARRAY(NULL, LDAPMessage*, 1); + BAIL_ON_PTR_ERROR(msg_tmp, nt_status); + } else { + ads_tmp = TALLOC_REALLOC_ARRAY(*ads_list, *ads_list, ADS_STRUCT*, + count+1); + BAIL_ON_PTR_ERROR(ads_tmp, nt_status); + + msg_tmp = TALLOC_REALLOC_ARRAY(*msg_list, *msg_list, LDAPMessage*, + count+1); + BAIL_ON_PTR_ERROR(msg_tmp, nt_status); + } + + ads_tmp[count] = ads; + msg_tmp[count] = msg; + count++; + + *ads_list = ads_tmp; + *msg_list = msg_tmp; + *size = count; + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_destroy(ads_tmp); + talloc_destroy(msg_tmp); + } + + return nt_status; +} + +/********************************************************************** + Frees search results. Do not free the ads_list as these are + references back to the GC search structures. + *********************************************************************/ + + void free_result_array(ADS_STRUCT **ads_list, + LDAPMessage **msg_list, + int num_resp) +{ + int i; + + for (i=0; i<num_resp; i++) { + ads_msgfree(ads_list[i], msg_list[i]); + } + + talloc_destroy(ads_list); + talloc_destroy(msg_list); +} + +/********************************************************************** + Check that we have exactly one entry from the search + *********************************************************************/ + + NTSTATUS check_result_unique(ADS_STRUCT *ads, LDAPMessage *msg) +{ + NTSTATUS nt_status; + int count; + + count = ads_count_replies(ads, msg); + + if (count <= 0) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if (count > 1) { + nt_status = NT_STATUS_DUPLICATE_NAME; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + return nt_status; +} diff --git a/source3/winbindd/idmap_adex/idmap_adex.c b/source3/winbindd/idmap_adex/idmap_adex.c new file mode 100644 index 0000000000..23ab843e95 --- /dev/null +++ b/source3/winbindd/idmap_adex/idmap_adex.c @@ -0,0 +1,460 @@ +/* + * idmap_adex: Support for D Forests + * + * Copyright (C) Gerald (Jerry) Carter 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" + +NTSTATUS init_module(void); + +/* + * IdMap backend + */ + +/******************************************************************** + Basic init function responsible for determining our current mode + (standalone or using Centeris Cells). This must return success or + it will be dropped from the idmap backend list. + *******************************************************************/ + +static NTSTATUS _idmap_adex_init(struct idmap_domain *dom, + const char *params) +{ + ADS_STRUCT *ads = NULL; + ADS_STATUS status; + static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + DOM_SID domain_sid; + fstring dcname; + struct sockaddr_storage ip; + struct likewise_cell *lwcell; + + if (NT_STATUS_IS_OK(init_status)) + return NT_STATUS_OK; + + /* Silently fail if we are not a member server in security = ads */ + + if ((lp_server_role() != ROLE_DOMAIN_MEMBER) || + (lp_security() != SEC_ADS)) { + init_status = NT_STATUS_INVALID_SERVER_STATE; + BAIL_ON_NTSTATUS_ERROR(init_status); + } + + /* fetch our domain SID first */ + + if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { + init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + BAIL_ON_NTSTATUS_ERROR(init_status); + } + + /* reuse the same ticket cache as winbindd */ + + setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); + + /* Establish a connection to a DC */ + + if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) { + init_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(init_status); + } + + ads->auth.password = + secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + ads->auth.realm = SMB_STRDUP(lp_realm()); + + /* get the DC name here to setup the server affinity cache and + local krb5.conf */ + + get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip); + + status = ads_connect(ads); + if (!ADS_ERR_OK(status)) { + DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n", + ads_errstr(status))); + } + init_status = ads_ntstatus(status); + BAIL_ON_NTSTATUS_ERROR(init_status); + + + /* Find out cell membership */ + + init_status = cell_locate_membership(ads); + if (!NT_STATUS_IS_OK(init_status)) { + DEBUG(0,("LWI: Fail to locate cell membership (%s).", + nt_errstr(init_status))); + goto done; + } + + /* Fill in the cell information */ + + lwcell = cell_list_head(); + + init_status = cell_lookup_settings(lwcell); + BAIL_ON_NTSTATUS_ERROR(init_status); + + /* Miscellaneous setup. E.g. set up the list of GC + servers and domain list for our forest (does not actually + connect). */ + + init_status = gc_init_list(); + BAIL_ON_NTSTATUS_ERROR(init_status); + + init_status = domain_init_list(); + BAIL_ON_NTSTATUS_ERROR(init_status); + +done: + if (!NT_STATUS_IS_OK(init_status)) { + DEBUG(1,("Likewise initialization failed (%s)\n", + nt_errstr(init_status))); + } + + /* cleanup */ + + if (!NT_STATUS_IS_OK(init_status)) { + cell_list_destroy(); + + /* init_status stores the failure reason but we need to + return success or else idmap_init() will drop us from the + backend list */ + return NT_STATUS_OK; + } + + init_status = NT_STATUS_OK; + + return init_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_get_sid_from_id(struct + idmap_domain + *dom, struct + id_map + **ids) +{ + int i; + bool one_mapped = false; + bool all_mapped = true; + NTSTATUS nt_status; + struct likewise_cell *cell; + + nt_status = _idmap_adex_init(dom, NULL); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + if ((cell = cell_list_head()) == NULL) { + return NT_STATUS_INVALID_SERVER_STATE; + } + + /* have to work through these one by one */ + for (i = 0; ids[i]; i++) { + NTSTATUS status; + status = cell->provider->get_sid_from_id(ids[i]->sid, + ids[i]->xid.id, + ids[i]->xid.type); + /* Fail if we cannot find any DC */ + if (NT_STATUS_EQUAL + (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { + return status; + } + + if (!NT_STATUS_IS_OK(status)) { + ids[i]->status = ID_UNMAPPED; + all_mapped = false; + continue; + } + + ids[i]->status = ID_MAPPED; + one_mapped = true; + } + + return NT_STATUS_OK; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_get_id_from_sid(struct + idmap_domain + *dom, struct + id_map + **ids) +{ + int i; + bool one_mapped = false; + bool all_mapped = true; + NTSTATUS nt_status; + struct likewise_cell *cell; + + nt_status = _idmap_adex_init(dom, NULL); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + if ((cell = cell_list_head()) == NULL) { + return NT_STATUS_INVALID_SERVER_STATE; + } + + /* have to work through these one by one */ + for (i = 0; ids[i]; i++) { + NTSTATUS status; + status = cell->provider->get_id_from_sid(&ids[i]->xid.id, + &ids[i]->xid. + type, ids[i]->sid); + /* Fail if we cannot find any DC */ + if (NT_STATUS_EQUAL + (status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) { + return status; + } + + if (!NT_STATUS_IS_OK(status)) { + ids[i]->status = ID_UNMAPPED; + all_mapped = false; + continue; + } + + ids[i]->status = ID_MAPPED; + one_mapped = true; + } + + return NT_STATUS_OK; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_set_mapping(struct + idmap_domain + *dom, const struct + id_map *map) +{ + DEBUG(0, ("_idmap_adex_set_mapping: not implemented\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_remove_mapping(struct + idmap_domain + *dom, const + struct + id_map + *map) +{ + DEBUG(0, ("_idmap_adex_remove_mapping: not implemented\n")); + return NT_STATUS_NOT_IMPLEMENTED; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_dump(struct idmap_domain + *dom, struct id_map **maps, int *num_map) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _idmap_adex_close(struct idmap_domain + *dom) +{ + /* FIXME! need to do cleanup here */ + + return NT_STATUS_OK; +} + +/* + * IdMap NSS plugin + */ + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _nss_adex_init(struct nss_domain_entry + *e) +{ + return _idmap_adex_init(NULL, NULL); +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _nss_adex_get_info(struct + nss_domain_entry *e, + const DOM_SID * sid, + TALLOC_CTX * ctx, + ADS_STRUCT * ads, + LDAPMessage * msg, + char **homedir, + char **shell, char **gecos, gid_t * p_gid) +{ + NTSTATUS nt_status; + struct likewise_cell *cell; + + nt_status = _idmap_adex_init(NULL, NULL); + if (!NT_STATUS_IS_OK(nt_status)) + return nt_status; + + if ((cell = cell_list_head()) == NULL) { + return NT_STATUS_INVALID_SERVER_STATE; + } + + return cell->provider->get_nss_info(sid, ctx, homedir, + shell, gecos, p_gid); +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _nss_adex_map_to_alias(TALLOC_CTX * mem_ctx, const char + *domain, const char + *name, char **alias) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct likewise_cell *cell = NULL; + + nt_status = _idmap_adex_init(NULL, NULL); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if ((cell = cell_list_head()) == NULL) { + nt_status = NT_STATUS_INVALID_SERVER_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = cell->provider->map_to_alias(mem_ctx, domain, + name, alias); + + /* go ahead and allow the cache mgr to mark this in + negative cache */ + + if (!NT_STATUS_IS_OK(nt_status)) + nt_status = NT_STATUS_NONE_MAPPED; + +done: + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _nss_adex_map_from_alias(TALLOC_CTX * mem_ctx, const char + *domain, const char + *alias, char **name) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct likewise_cell *cell = NULL; + + nt_status = _idmap_adex_init(NULL, NULL); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if ((cell = cell_list_head()) == NULL) { + nt_status = NT_STATUS_INVALID_SERVER_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + + nt_status = cell->provider->map_from_alias(mem_ctx, domain, + alias, name); + + /* go ahead and allow the cache mgr to mark this in + negative cache */ + + if (!NT_STATUS_IS_OK(nt_status)) + nt_status = NT_STATUS_NONE_MAPPED; + +done: + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _nss_adex_close(void) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/********************************************************************** + *********************************************************************/ + +static struct idmap_methods adex_idmap_methods = { + + .init = _idmap_adex_init, + .unixids_to_sids = _idmap_adex_get_sid_from_id, + .sids_to_unixids = _idmap_adex_get_id_from_sid, + .set_mapping = _idmap_adex_set_mapping, + .remove_mapping = _idmap_adex_remove_mapping, + .dump_data = _idmap_adex_dump, + .close_fn = _idmap_adex_close +}; +static struct nss_info_methods adex_nss_methods = { + .init = _nss_adex_init, + .get_nss_info = _nss_adex_get_info, + .map_to_alias = _nss_adex_map_to_alias, + .map_from_alias = _nss_adex_map_from_alias, + .close_fn = _nss_adex_close +}; + +/********************************************************************** + Register with the idmap and idmap_nss subsystems. We have to protect + against the idmap and nss_info interfaces being in a half-registered + state. + **********************************************************************/ +NTSTATUS idmap_adex_init(void) +{ + static NTSTATUS idmap_status = NT_STATUS_UNSUCCESSFUL; + static NTSTATUS nss_status = NT_STATUS_UNSUCCESSFUL; + if (!NT_STATUS_IS_OK(idmap_status)) { + idmap_status = + smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, + "adex", &adex_idmap_methods); + if (!NT_STATUS_IS_OK(idmap_status)) { + DEBUG(0, + ("idmap_centeris_init: Failed to register the adex" + "idmap plugin.\n")); + return idmap_status; + } + } + + if (!NT_STATUS_IS_OK(nss_status)) { + nss_status = + smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "adex", &adex_nss_methods); + if (!NT_STATUS_IS_OK(nss_status)) { + DEBUG(0, + ("idmap_adex_init: Failed to register the adex" + "nss plugin.\n")); + return nss_status; + } + } + + return NT_STATUS_OK; +} + +NTSTATUS nss_info_adex_init(void) +{ + return idmap_adex_init(); +} diff --git a/source3/winbindd/idmap_adex/idmap_adex.h b/source3/winbindd/idmap_adex/idmap_adex.h new file mode 100644 index 0000000000..f91bba8d07 --- /dev/null +++ b/source3/winbindd/idmap_adex/idmap_adex.h @@ -0,0 +1,257 @@ +/* + * idmap_centeris: Support for Local IDs and Centeris Cell Structure + * + * Copyright (C) Gerald (Jerry) Carter 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _IDMAP_ADEX_H +#define _IDMAP_ADEX_H + +#include "winbindd/winbindd.h" + +#define ADEX_CELL_RDN "$LikewiseIdentityCell" + +#define ADEX_OC_USER "centerisLikewiseUser" +#define ADEX_OC_GROUP "centerisLikewiseGroup" + +#define AD_USER "User" +#define AD_GROUP "Group" + +#define ADEX_OC_POSIX_USER "posixAccount" +#define ADEX_OC_POSIX_GROUP "posixGroup" + +#define ADEX_ATTR_UIDNUM "uidNumber" +#define ADEX_ATTR_GIDNUM "gidNUmber" +#define ADEX_ATTR_HOMEDIR "unixHomeDirectory" +#define ADEX_ATTR_USERPW "unixUserPassword" +#define ADEX_ATTR_GROUPALIAS "groupAlias" /* Not part of RFC2307 */ +#define ADEX_ATTR_SHELL "loginShell" +#define ADEX_ATTR_GECOS "gecos" +#define ADEX_ATTR_UID "uid" +#define ADEX_ATTR_DISPLAYNAME "displayName" + +#define MIN_ID_VALUE 100 + +#define BAIL_ON_NTSTATUS_ERROR(x) \ + do { \ + if (!NT_STATUS_IS_OK(x)) { \ + DEBUG(10,("Failed! (%s)\n", nt_errstr(x))); \ + goto done; \ + } \ + } \ + while (0); \ + +#define WARN_ON_NTSTATUS_ERROR(x) \ + do { \ + if (!NT_STATUS_IS_OK(x)) { \ + DEBUG(10,("Failure ignored! (%s)\n", nt_errstr(x))); \ + } \ + } \ + while (0); \ + +#define BAIL_ON_ADS_ERROR(x) \ + do { \ + if (!ADS_ERR_OK(x)) { \ + goto done; \ + } \ + } \ + while (0); + +#define BAIL_ON_PTR_ERROR(p, x) \ + do { \ + if ((p) == NULL ) { \ + DEBUG(10,("NULL pointer!\n")); \ + x = NT_STATUS_NO_MEMORY; \ + goto done; \ + } \ + } while (0); + +#define PRINT_NTSTATUS_ERROR(x, hdr, level) \ + do { \ + if (!NT_STATUS_IS_OK(x)) { \ + DEBUG(level,("LWI ("hdr"): %s\n", nt_errstr(x))); \ + } \ + } while(0); +/* + * Cell Provider API + */ + +struct cell_provider_api { + NTSTATUS(*get_sid_from_id) (DOM_SID * sid, + uint32_t id, enum id_type type); + NTSTATUS(*get_id_from_sid) (uint32_t * id, + enum id_type * type, const DOM_SID * sid); + NTSTATUS(*get_nss_info) (const DOM_SID * sid, + TALLOC_CTX * ctx, + char **homedir, + char **shell, char **gecos, gid_t * p_gid); + NTSTATUS(*map_to_alias) (TALLOC_CTX * mem_ctx, + const char *domain, + const char *name, char **alias); + NTSTATUS(*map_from_alias) (TALLOC_CTX * mem_ctx, + const char *domain, + const char *alias, char **name); +}; + +/* registered providers */ + +extern struct cell_provider_api ccp_unified; +extern struct cell_provider_api ccp_local; + +#define LWCELL_FLAG_USE_RFC2307_ATTRS 0x00000001 +#define LWCELL_FLAG_SEARCH_FOREST 0x00000002 +#define LWCELL_FLAG_GC_CELL 0x00000004 +#define LWCELL_FLAG_LOCAL_MODE 0x00000008 + +struct likewise_cell { + struct likewise_cell *prev, *next; + ADS_STRUCT *conn; + struct likewise_cell *gc_search_cell; + DOM_SID domain_sid; + char *dns_domain; + char *forest_name; + char *dn; + struct GUID *links; /* only held by owning cell */ + size_t num_links; + uint32_t flags; + struct cell_provider_api *provider; +}; + +/* Search flags used for Global Catalog API */ + +#define ADEX_GC_SEARCH_CHECK_UNIQUE 0x00000001 + +struct gc_info { + struct gc_info *prev, *next; + char *forest_name; + char *search_base; + struct likewise_cell *forest_cell; +}; + +/* Available functions outside of idmap_lwidentity.c */ + +/* cell_util.c */ + +char *find_attr_string(char **list, size_t num_lines, const char *substr); +bool is_object_class(char **list, size_t num_lines, const char *substr); +int min_id_value(void); +char *cell_dn_to_dns(const char *dn); +NTSTATUS get_sid_type(ADS_STRUCT *ads, + LDAPMessage *msg, + enum lsa_SidType *type); + +NTSTATUS cell_locate_membership(ADS_STRUCT * ads); +NTSTATUS cell_lookup_settings(struct likewise_cell * cell); +NTSTATUS cell_follow_links(struct likewise_cell *cell); +NTSTATUS cell_set_local_provider(void); + +/* likewise_cell.c */ + +struct likewise_cell *cell_new(void); +struct likewise_cell *cell_list_head(void); + +bool cell_list_add(struct likewise_cell *cell); +bool cell_list_remove(struct likewise_cell * cell); + +void cell_list_destroy(); +void cell_destroy(struct likewise_cell *c); +void cell_set_forest_searches(struct likewise_cell *c, + bool search); +void cell_set_dns_domain(struct likewise_cell *c, + const char *dns_domain); +void cell_set_connection(struct likewise_cell *c, + ADS_STRUCT *ads); +void cell_set_dn(struct likewise_cell *c, + const char *dn); +void cell_set_domain_sid(struct likewise_cell *c, + DOM_SID *sid); +void cell_set_flags(struct likewise_cell *c, uint32_t flags); +void cell_clear_flags(struct likewise_cell *c, uint32_t flags); + +const char* cell_search_base(struct likewise_cell *c); +const char *cell_dns_domain(struct likewise_cell *c); +ADS_STRUCT *cell_connection(struct likewise_cell *c); +bool cell_search_forest(struct likewise_cell *c); +ADS_STATUS cell_do_search(struct likewise_cell *c, + const char *search_base, + int scope, + const char *expr, + const char **attrs, + LDAPMessage ** msg); +uint32_t cell_flags(struct likewise_cell *c); + +NTSTATUS cell_connect_dn(struct likewise_cell **c, + const char *dn); +NTSTATUS cell_connect(struct likewise_cell *c); + + +/* gc_util.c */ + +NTSTATUS gc_init_list(void); + +NTSTATUS gc_find_forest_root(struct gc_info *gc, + const char *domain); + +struct gc_info *gc_search_start(void); + +NTSTATUS gc_search_forest(struct gc_info *gc, + LDAPMessage **msg, + const char *filter); + +NTSTATUS gc_search_all_forests(const char *filter, + ADS_STRUCT ***ads_list, + LDAPMessage ***msg_list, + int *num_resp, uint32_t flags); + +NTSTATUS gc_search_all_forests_unique(const char *filter, + ADS_STRUCT **ads, + LDAPMessage **msg); + +NTSTATUS gc_name_to_sid(const char *domain, + const char *name, + DOM_SID *sid, + enum lsa_SidType *sid_type); + +NTSTATUS gc_sid_to_name(const DOM_SID *sid, + char **name, + enum lsa_SidType *sid_type); + +NTSTATUS add_ads_result_to_array(ADS_STRUCT *ads, + LDAPMessage *msg, + ADS_STRUCT ***ads_list, + LDAPMessage ***msg_list, + int *size); + +void free_result_array(ADS_STRUCT **ads_list, + LDAPMessage **msg_list, + int num_resp); + +NTSTATUS check_result_unique(ADS_STRUCT *ads, + LDAPMessage *msg); + + +/* domain_util.c */ + +NTSTATUS domain_init_list(void); + +NTSTATUS dc_search_domains(struct likewise_cell **cell, + LDAPMessage **msg, + const char *dn, + const DOM_SID *user_sid); + + +#endif /* _IDMAP_ADEX_H */ diff --git a/source3/winbindd/idmap_adex/likewise_cell.c b/source3/winbindd/idmap_adex/likewise_cell.c new file mode 100644 index 0000000000..77eeee406b --- /dev/null +++ b/source3/winbindd/idmap_adex/likewise_cell.c @@ -0,0 +1,425 @@ +/* + * idmap_adex: Support for AD Forests + * + * Copyright (C) Gerald (Jerry) Carter 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +static struct likewise_cell *_lw_cell_list = NULL; + +/********************************************************************** + Return the current HEAD of the list + *********************************************************************/ + + struct likewise_cell *cell_list_head(void) +{ + return _lw_cell_list; +} + + +/********************************************************************** + *********************************************************************/ + + void cell_destroy(struct likewise_cell *c) +{ + if (!c) + return; + + if (c->conn) + ads_destroy(&c->conn); + + talloc_destroy(c); +} + +/********************************************************************** + Free all cell entries and reset the list head to NULL + *********************************************************************/ + + void cell_list_destroy(void) +{ + struct likewise_cell *p = _lw_cell_list; + + while (p) { + struct likewise_cell *q = p->next; + + cell_destroy(p); + + p = q; + } + + _lw_cell_list = NULL; + + return; +} + +/********************************************************************** + Add a new cell structure to the list + *********************************************************************/ + + struct likewise_cell* cell_new(void) +{ + struct likewise_cell *c; + + /* Each cell struct is a TALLOC_CTX* */ + + c = TALLOC_ZERO_P(NULL, struct likewise_cell); + if (!c) { + DEBUG(0,("cell_new: memory allocation failure!\n")); + return NULL; + } + + return c; +} + +/********************************************************************** + Add a new cell structure to the list + *********************************************************************/ + + bool cell_list_add(struct likewise_cell * cell) +{ + if (!cell) { + return false; + } + + /* Always add to the end */ + + DLIST_ADD_END(_lw_cell_list, cell, struct likewise_cell *); + + return true; +} + +/********************************************************************** + Add a new cell structure to the list + *********************************************************************/ + + bool cell_list_remove(struct likewise_cell * cell) +{ + if (!cell) { + return false; + } + + /* Remove and drop the cell structure */ + + DLIST_REMOVE(_lw_cell_list, cell); + talloc_destroy(cell); + + return true; +} + +/********************************************************************** + Set the containing DNS domain for a cell + *********************************************************************/ + + void cell_set_dns_domain(struct likewise_cell *c, const char *dns_domain) +{ + c->dns_domain = talloc_strdup(c, dns_domain); +} + +/********************************************************************** + Set ADS connection for a cell + *********************************************************************/ + + void cell_set_connection(struct likewise_cell *c, ADS_STRUCT *ads) +{ + c->conn = ads; +} + +/********************************************************************** + *********************************************************************/ + + void cell_set_flags(struct likewise_cell *c, uint32_t flags) +{ + c->flags |= flags; +} + +/********************************************************************** + *********************************************************************/ + + void cell_clear_flags(struct likewise_cell *c, uint32_t flags) +{ + c->flags &= ~flags; +} + +/********************************************************************** + Set the Cell's DN + *********************************************************************/ + + void cell_set_dn(struct likewise_cell *c, const char *dn) +{ + if ( c->dn) { + talloc_free(c->dn); + c->dn = NULL; + } + + c->dn = talloc_strdup(c, dn); +} + +/********************************************************************** + *********************************************************************/ + + void cell_set_domain_sid(struct likewise_cell *c, DOM_SID *sid) +{ + sid_copy(&c->domain_sid, sid); +} + +/* + * Query Routines + */ + +/********************************************************************** + *********************************************************************/ + + const char* cell_search_base(struct likewise_cell *c) +{ + if (!c) + return NULL; + + return talloc_asprintf(c, "cn=%s,%s", ADEX_CELL_RDN, c->dn); +} + +/********************************************************************** + *********************************************************************/ + + bool cell_search_forest(struct likewise_cell *c) +{ + uint32_t test_flags = LWCELL_FLAG_SEARCH_FOREST; + + return ((c->flags & test_flags) == test_flags); +} + +/********************************************************************** + *********************************************************************/ + + uint32_t cell_flags(struct likewise_cell *c) +{ + if (!c) + return 0; + + return c->flags; +} + +/********************************************************************** + *********************************************************************/ + + const char *cell_dns_domain(struct likewise_cell *c) +{ + if (!c) + return NULL; + + return c->dns_domain; +} + +/********************************************************************** + *********************************************************************/ + + ADS_STRUCT *cell_connection(struct likewise_cell *c) +{ + if (!c) + return NULL; + + return c->conn; +} + +/* + * Connection functions + */ + +/******************************************************************** + *******************************************************************/ + + NTSTATUS cell_connect(struct likewise_cell *c) +{ + ADS_STRUCT *ads = NULL; + ADS_STATUS ads_status; + fstring dc_name; + struct sockaddr_storage dcip; + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + + /* have to at least have the AD domain name */ + + if (!c->dns_domain) { + nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* clear out any old information */ + + if (c->conn) { + ads_destroy(&c->conn); + c->conn = NULL; + } + + /* now setup the new connection */ + + ads = ads_init(c->dns_domain, NULL, NULL); + BAIL_ON_PTR_ERROR(ads, nt_status); + + ads->auth.password = + secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + ads->auth.realm = SMB_STRDUP(lp_realm()); + + /* Make the connection. We should already have an initial + TGT using the machine creds */ + + if (cell_flags(c) & LWCELL_FLAG_GC_CELL) { + ads_status = ads_connect_gc(ads); + } else { + /* Set up server affinity for normal cells and the client + site name cache */ + + if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) { + nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + ads_status = ads_connect(ads); + } + + + c->conn = ads; + + nt_status = ads_ntstatus(ads_status); + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + ads_destroy(&ads); + c->conn = NULL; + } + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + + NTSTATUS cell_connect_dn(struct likewise_cell **c, const char *dn) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct likewise_cell *new_cell = NULL; + char *dns_domain = NULL; + + if (*c || !dn) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if ((new_cell = cell_new()) == NULL) { + nt_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Set the DNS domain, dn, etc ... and add it to the list */ + + dns_domain = cell_dn_to_dns(dn); + cell_set_dns_domain(new_cell, dns_domain); + SAFE_FREE(dns_domain); + + cell_set_dn(new_cell, dn); + + nt_status = cell_connect(new_cell); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + *c = new_cell; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1,("LWI: Failled to connect to cell \"%s\" (%s)\n", + dn ? dn : "NULL", nt_errstr(nt_status))); + talloc_destroy(new_cell); + } + + return nt_status; +} + + +/******************************************************************** + *******************************************************************/ + +#define MAX_SEARCH_COUNT 2 + + ADS_STATUS cell_do_search(struct likewise_cell *c, + const char *search_base, + int scope, + const char *expr, + const char **attrs, + LDAPMessage ** msg) +{ + int search_count = 0; + ADS_STATUS status; + NTSTATUS nt_status; + + /* check for a NULL connection */ + + if (!c->conn) { + nt_status = cell_connect(c); + if (!NT_STATUS_IS_OK(nt_status)) { + status = ADS_ERROR_NT(nt_status); + return status; + } + } + + DEBUG(10, ("cell_do_search: Base = %s, Filter = %s, Scope = %d, GC = %s\n", + search_base, expr, scope, + c->conn->server.gc ? "yes" : "no")); + + /* we try multiple times in case the ADS_STRUCT is bad + and we need to reconnect */ + + while (search_count < MAX_SEARCH_COUNT) { + *msg = NULL; + status = ads_do_search(c->conn, search_base, + scope, expr, attrs, msg); + if (ADS_ERR_OK(status)) { + return status; + } + + + DEBUG(5, ("cell_do_search: search[%d] failed (%s)\n", + search_count, ads_errstr(status))); + + search_count++; + + /* Houston, we have a problem */ + + if (status.error_type == ENUM_ADS_ERROR_LDAP) { + switch (status.err.rc) { + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_TIMEOUT: + case -1: /* we get this error if we cannot contact + the LDAP server */ + nt_status = cell_connect(c); + if (!NT_STATUS_IS_OK(nt_status)) { + status = ADS_ERROR_NT(nt_status); + return status; + } + break; + default: + /* we're all done here */ + return status; + } + } + } + + DEBUG(5, ("cell_do_search: exceeded maximum search count!\n")); + + return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); +} diff --git a/source3/winbindd/idmap_adex/provider_unified.c b/source3/winbindd/idmap_adex/provider_unified.c new file mode 100644 index 0000000000..f18534797e --- /dev/null +++ b/source3/winbindd/idmap_adex/provider_unified.c @@ -0,0 +1,1180 @@ +/* + * idmap_adex + * + * Provider for RFC2307 and SFU AD Forests + * + * Copyright (C) Gerald (Jerry) Carter 2006-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "includes.h" +#include "idmap_adex.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +/* Information needed by the LDAP search filters */ + +enum filterType { SidFilter, IdFilter, AliasFilter }; + +struct lwcell_filter +{ + enum filterType ftype; + bool use2307; + union { + DOM_SID sid; + struct { + uint32_t id; + enum id_type type; + } id; + fstring alias; + } filter; +}; + +/******************************************************************** + *******************************************************************/ + +static char* build_id_filter(uint32_t id, + enum id_type type, + uint32_t search_flags) +{ + char *filter = NULL; + char *oc_filter, *attr_filter; + NTSTATUS nt_status; + TALLOC_CTX *frame = talloc_stackframe(); + bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS) + == LWCELL_FLAG_USE_RFC2307_ATTRS); + bool use_gc = ((search_flags & LWCELL_FLAG_SEARCH_FOREST) + == LWCELL_FLAG_SEARCH_FOREST); + const char *oc; + + /* Construct search filter for objectclass and attributes */ + + switch (type) { + case ID_TYPE_UID: + oc = ADEX_OC_USER; + if (use2307) { + oc = ADEX_OC_POSIX_USER; + if (use_gc) { + oc = AD_USER; + } + } + oc_filter = talloc_asprintf(frame, "objectclass=%s", oc); + attr_filter = talloc_asprintf(frame, "%s=%u", + ADEX_ATTR_UIDNUM, id); + break; + + case ID_TYPE_GID: + oc = ADEX_OC_GROUP; + if (use2307) { + oc = ADEX_OC_POSIX_GROUP; + if (use_gc) { + oc = AD_GROUP; + } + } + oc_filter = talloc_asprintf(frame, "objectclass=%s", oc); + attr_filter = talloc_asprintf(frame, "%s=%u", + ADEX_ATTR_GIDNUM, id); + break; + default: + return NULL; + } + + BAIL_ON_PTR_ERROR(oc_filter, nt_status); + BAIL_ON_PTR_ERROR(attr_filter, nt_status); + + /* Use "keywords=%s" for non-schema cells */ + + if (use2307) { + filter = talloc_asprintf(frame, "(&(%s)(%s))", + oc_filter, attr_filter); + } else { + filter = talloc_asprintf(frame, "(&(keywords=%s)(keywords=%s))", + oc_filter, attr_filter); + } + + talloc_destroy(oc_filter); + talloc_destroy(attr_filter); + +done: + /* Don't destroy the stackframe CTX since we are returning + memory from it */ + + return filter; +} + +/******************************************************************** + *******************************************************************/ + +static char* build_alias_filter(const char *alias, uint32_t search_flags) +{ + char *filter = NULL; + char *user_attr_filter, *group_attr_filter; + NTSTATUS nt_status; + TALLOC_CTX *frame = talloc_stackframe(); + bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS) + == LWCELL_FLAG_USE_RFC2307_ATTRS); + bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST) + == LWCELL_FLAG_SEARCH_FOREST); + + /* Construct search filter for objectclass and attributes */ + + user_attr_filter = talloc_asprintf(frame, "%s=%s", + ADEX_ATTR_UID, alias); + group_attr_filter = talloc_asprintf(frame, "%s=%s", + ADEX_ATTR_DISPLAYNAME, alias); + BAIL_ON_PTR_ERROR(user_attr_filter, nt_status); + BAIL_ON_PTR_ERROR(group_attr_filter, nt_status); + + /* Use "keywords=%s" for non-schema cells */ + + if (use2307) { + filter = talloc_asprintf(frame, + "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))", + user_attr_filter, + search_forest ? AD_USER : ADEX_OC_POSIX_USER, + group_attr_filter, + search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP); + } else { + filter = talloc_asprintf(frame, + "(|(keywords=%s)(keywords=%s))", + user_attr_filter, + group_attr_filter); + } + + talloc_destroy(user_attr_filter); + talloc_destroy(group_attr_filter); + +done: + /* Don't destroy the stackframe CTX since we are returning + memory from it */ + + return filter; +} + + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS search_cell(struct likewise_cell *c, + LDAPMessage **msg, + const struct lwcell_filter *fdata) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX* frame = talloc_stackframe(); + char *filter = NULL; + const char *base = NULL; + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + const char *attrs[] = { "*", NULL }; + int count; + char *sid_str; + + /* get the filter and other search parameters */ + + switch (fdata->ftype) { + case SidFilter: + sid_str = sid_string_talloc(frame, &fdata->filter.sid); + BAIL_ON_PTR_ERROR(sid_str, nt_status); + + filter = talloc_asprintf(frame, "(keywords=backLink=%s)", + sid_str); + break; + case IdFilter: + filter = build_id_filter(fdata->filter.id.id, + fdata->filter.id.type, + cell_flags(c)); + break; + case AliasFilter: + filter = build_alias_filter(fdata->filter.alias, + cell_flags(c)); + break; + default: + nt_status = NT_STATUS_INVALID_PARAMETER; + break; + } + BAIL_ON_PTR_ERROR(filter, nt_status); + + base = cell_search_base(c); + BAIL_ON_PTR_ERROR(base, nt_status); + + ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE, + filter, attrs, msg); + + nt_status = ads_ntstatus(ads_status); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Now check that we got only one reply */ + + count = ads_count_replies(c->conn, *msg); + if (count < 1) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if ( count > 1) { + nt_status = NT_STATUS_DUPLICATE_NAME; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + +done: + PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4); + + talloc_destroy(CONST_DISCARD(char*, base)); + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS search_domain(struct likewise_cell **cell, + LDAPMessage **msg, + const char *dn, + const DOM_SID *sid) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX* frame = talloc_stackframe(); + int count; + + nt_status = dc_search_domains(cell, msg, dn, sid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Now check that we got only one reply */ + + count = ads_count_replies(cell_connection(*cell), *msg); + if (count < 1) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if ( count > 1) { + nt_status = NT_STATUS_DUPLICATE_NAME; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + +done: + PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4); + talloc_destroy(frame); + + return nt_status; +} + + +/******************************************************************** + Check that a DN is within the forest scope. + *******************************************************************/ + +static bool check_forest_scope(const char *dn) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX *frame = talloc_stackframe(); + char *p = NULL; + char *q = NULL; + char *dns_domain = NULL; + struct winbindd_tdc_domain *domain; + + /* If the DN does *not* contain "$LikewiseIdentityCell", + assume this is a schema mode forest and it is in the + forest scope by definition. */ + + if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) { + nt_status = NT_STATUS_OK; + goto done; + } + + /* If this is a non-schema forest, then make sure that the DN + is in the form "...,cn=$LikewiseIdentityCell,DC=..." */ + + if ((q = strchr_m(p, ',')) == NULL) { + nt_status = NT_STATUS_OBJECT_NAME_INVALID; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + q++; + if (StrnCaseCmp(q, "dc=", 3) != 0) { + nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + + dns_domain = cell_dn_to_dns(q); + BAIL_ON_PTR_ERROR(dns_domain, nt_status); + + domain = wcache_tdc_fetch_domain(frame, dns_domain); + if (!domain) { + nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(frame); + SAFE_FREE(dns_domain); + + return NT_STATUS_IS_OK(nt_status); +} + + + +/******************************************************************** + Check that only one result was returned within the forest cell + scope. + *******************************************************************/ + +static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list, + LDAPMessage **msg_list, + int num_resp, + char **dn, + DOM_SID *user_sid) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + int i; + ADS_STRUCT *ads = NULL; + LDAPMessage *msg = NULL; + int count = 0; + char *entry_dn = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (!dn || !user_sid) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + *dn = NULL; + + if (!ads_list || !msg_list || (num_resp == 0)) { + nt_status = NT_STATUS_NO_SUCH_FILE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Loop over all msgs */ + + for (i=0; i<num_resp; i++) { + LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]); + + while (e) { + entry_dn = ads_get_dn(ads_list[i], e); + BAIL_ON_PTR_ERROR(entry_dn, nt_status); + + if (check_forest_scope(entry_dn)) { + count++; + + /* If we've already broken the condition, no + need to continue */ + + if (count > 1) { + nt_status = NT_STATUS_DUPLICATE_NAME; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + ads = ads_list[i]; + msg = e; + *dn = SMB_STRDUP(entry_dn); + BAIL_ON_PTR_ERROR((*dn), nt_status); + } + + e = ads_next_entry(ads_list[i], e); + SAFE_FREE(entry_dn); + } + } + + if (!ads || !msg) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* If we made is through the loop, then grab the user_sid and + run home to base */ + + /* + Try and get the SID from either objectSid or keywords. + We cannot use pull_sid() here since we want to try + both methods and not only one or the other (and we + have no full likewise_cell struct. + + Fail if both are unavailable + */ + + if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) { + char **keywords; + char *s; + size_t num_lines = 0; + + keywords = ads_pull_strings(ads, frame, msg, "keywords", + &num_lines); + BAIL_ON_PTR_ERROR(keywords, nt_status); + + s = find_attr_string(keywords, num_lines, "backLink"); + if (!s) { + nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if (!string_to_sid(user_sid, s)) { + nt_status = NT_STATUS_INVALID_SID; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + } + + nt_status = NT_STATUS_OK; + +done: + if (!NT_STATUS_IS_OK(nt_status)) { + SAFE_FREE(*dn); + } + + talloc_destroy(frame); + SAFE_FREE(entry_dn); + + return nt_status; +} + +/******************************************************************** + Search all forests. Each forest can have it's own forest-cell + settings so we have to generate the filter for each search. + We don't use gc_search_all_forests() since we may have a different + schema model in each forest and need to construct the search + filter for each GC search. + *******************************************************************/ + +static NTSTATUS search_forest(struct likewise_cell *forest_cell, + LDAPMessage **msg, + const struct lwcell_filter *fdata) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX *frame = talloc_stackframe(); + char *filter = NULL; + char *dn = NULL; + struct gc_info *gc = NULL; + ADS_STRUCT **ads_list = NULL; + LDAPMessage **msg_list = NULL; + int num_resp = 0; + LDAPMessage *m; + DOM_SID user_sid; + struct likewise_cell *domain_cell = NULL; + + if ((gc = gc_search_start()) == NULL) { + nt_status = NT_STATUS_INVALID_DOMAIN_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + while (gc) { + char *sid_binstr = NULL; + uint32_t flags = LWCELL_FLAG_SEARCH_FOREST; + + m = NULL; + + flags |= cell_flags(gc->forest_cell); + + switch (fdata->ftype) { + case SidFilter: + sid_binstr = sid_binstring(&fdata->filter.sid); + BAIL_ON_PTR_ERROR(sid_binstr, nt_status); + + filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr); + SAFE_FREE(sid_binstr); + break; + case IdFilter: + filter = build_id_filter(fdata->filter.id.id, + fdata->filter.id.type, flags); + break; + case AliasFilter: + filter = build_alias_filter(fdata->filter.alias, flags); + break; + } + + /* First find the sparse object in GC */ + nt_status = gc_search_forest(gc, &m, filter); + if (!NT_STATUS_IS_OK(nt_status)) { + gc = gc->next; + continue; + } + + nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell), + m, &ads_list, &msg_list, + &num_resp); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + gc = gc->next; + } + + /* Uniqueness check across forests */ + + nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp, + &dn, &user_sid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = search_domain(&domain_cell, &m, dn, &user_sid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Save the connection and results in the return parameters */ + + forest_cell->gc_search_cell = domain_cell; + *msg = m; + +done: + PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4); + + SAFE_FREE(dn); + + free_result_array(ads_list, msg_list, num_resp); + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS search_cell_list(struct likewise_cell **c, + LDAPMessage **m, + const struct lwcell_filter *fdata) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct likewise_cell *cell = NULL; + LDAPMessage *msg = NULL; + struct likewise_cell *result_cell = NULL; + + if ((cell = cell_list_head()) == NULL) { + nt_status = NT_STATUS_INVALID_SERVER_STATE; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + while (cell) { + /* Clear any previous GC search results */ + + cell->gc_search_cell = NULL; + + if (cell_search_forest(cell)) { + nt_status = search_forest(cell, &msg, fdata); + } else { + nt_status = search_cell(cell, &msg, fdata); + } + + /* Always point to the search result cell. + In forests this might be for another domain + which means the schema model may be different */ + + result_cell = cell->gc_search_cell ? + cell->gc_search_cell : cell; + + /* Check if we are done */ + + if (NT_STATUS_IS_OK(nt_status)) { + break; + } + + /* No luck. Free memory and hit the next cell. + Forest searches always set the gc_search_cell + so give preference to that connection if possible. */ + + ads_msgfree(cell_connection(result_cell), msg); + msg = NULL; + + cell = cell->next; + } + + /* This might be assigning NULL but that is ok as long as we + give back the proper error code */ + + *c = result_cell; + *m = msg; + +done: + PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3); + + return nt_status; +} + +/******************************************************************** + Pull the SID from an object which is always stored in the keywords + attribute as "backLink=S-1-5-21-..." + *******************************************************************/ + +static NTSTATUS pull_sid(struct likewise_cell *c, + LDAPMessage *msg, + DOM_SID *sid) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + TALLOC_CTX *frame = talloc_stackframe(); + ADS_STRUCT *ads = NULL; + + ads = cell_connection(c); + + /* + We have two ways of getting the sid: + (a) from the objectSID in case of a GC search, + (b) from backLink in the case of a cell search. + Pull the keywords attributes and grab the backLink. + */ + + if (!ads_pull_sid(ads, msg, "objectSid", sid)) { + char **keywords; + char *s; + size_t num_lines = 0; + + keywords = ads_pull_strings(ads, frame, msg, + "keywords", &num_lines); + BAIL_ON_PTR_ERROR(keywords, nt_status); + + s = find_attr_string(keywords, num_lines, "backLink"); + if (!s) { + nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + if (!string_to_sid(sid, s)) { + nt_status = NT_STATUS_INVALID_SID; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS get_object_type(struct likewise_cell *c, + LDAPMessage *msg, + enum id_type *type) +{ + TALLOC_CTX *ctx = talloc_stackframe(); + char **oc_list = NULL; + NTSTATUS nt_status = NT_STATUS_OK; + size_t list_size = 0; + char *s = NULL; + ADS_STRUCT *ads = NULL; + + ads = cell_connection(c); + + /* Deal with RFC 2307 support first */ + + if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { + oc_list = ads_pull_strings(ads, ctx, msg, + "objectClass", &list_size); + if (!oc_list) { + nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + /* Check for posix classes and AD classes */ + + if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER) + || is_object_class(oc_list, list_size, AD_USER)) { + *type = ID_TYPE_UID; + } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP) + || is_object_class(oc_list, list_size, AD_GROUP)) { + *type = ID_TYPE_GID; + } else { + *type = ID_TYPE_NOT_SPECIFIED; + nt_status = NT_STATUS_INVALID_PARAMETER; + } + } else { + /* Default to non-schema mode */ + + oc_list = ads_pull_strings(ads, ctx, msg, + "keywords", &list_size); + if (!oc_list) { + nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + s = find_attr_string(oc_list, list_size, "objectClass"); + if (!s) { + nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto done; + } + + if (strequal(s, ADEX_OC_USER)) { + *type = ID_TYPE_UID; + } else if (strequal(s, ADEX_OC_GROUP)) { + *type = ID_TYPE_GID; + } else { + *type = ID_TYPE_NOT_SPECIFIED; + nt_status = NT_STATUS_INVALID_PARAMETER; + } + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(ctx); + + return nt_status; +} + +/******************************************************************** + Pull an attribute uint32_t value + *******************************************************************/ + +static NTSTATUS get_object_uint32(struct likewise_cell *c, + LDAPMessage *msg, + const char *attrib, + uint32_t *x) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char **keywords = NULL; + size_t list_size = 0; + TALLOC_CTX *frame = talloc_stackframe(); + ADS_STRUCT *ads = NULL; + + ads = cell_connection(c); + + /* Deal with RFC2307 schema */ + + if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { + if (!ads_pull_uint32(ads, msg, attrib, x)) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + } else { + /* Non-schema mode */ + char *s = NULL; + uint32_t num; + + keywords = ads_pull_strings(ads, frame, msg, "keywords", + &list_size); + BAIL_ON_PTR_ERROR(keywords, nt_status); + + s = find_attr_string(keywords, list_size, attrib); + if (!s) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + num = strtoll(s, NULL, 10); + if (errno == ERANGE) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + *x = num; + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS get_object_id(struct likewise_cell *c, + LDAPMessage *msg, + enum id_type type, + uint32_t *id) +{ + NTSTATUS nt_status = NT_STATUS_OK; + const char *id_attr; + + /* Figure out which attribute we need to pull */ + + switch (type) { + case ID_TYPE_UID: + id_attr = ADEX_ATTR_UIDNUM; + break; + case ID_TYPE_GID: + id_attr = ADEX_ATTR_GIDNUM; + break; + default: + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + break; + } + + nt_status = get_object_uint32(c, msg, id_attr, id); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + return nt_status; +} + +/******************************************************************** + Pull the uid/gid and type from an object. This differs depending on + the cell flags. + *******************************************************************/ + +static NTSTATUS pull_id(struct likewise_cell *c, + LDAPMessage *msg, + uint32_t *id, + enum id_type *type) +{ + NTSTATUS nt_status; + + nt_status = get_object_type(c, msg, type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_object_id(c, msg, *type, id); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + return nt_status; +} + +/******************************************************************** + Pull an attribute string value + *******************************************************************/ + +static NTSTATUS get_object_string(struct likewise_cell *c, + LDAPMessage *msg, + TALLOC_CTX *ctx, + const char *attrib, + char **string) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char **keywords = NULL; + size_t list_size = 0; + TALLOC_CTX *frame = talloc_stackframe(); + ADS_STRUCT *ads = NULL; + + *string = NULL; + + ads = cell_connection(c); + + /* Deal with RFC2307 schema */ + + if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) { + *string = ads_pull_string(ads, ctx, msg, attrib); + } else { + /* Non-schema mode */ + + char *s = NULL; + + keywords = ads_pull_strings(ads, frame, msg, + "keywords", &list_size); + if (!keywords) { + nt_status = NT_STATUS_NO_MEMORY; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + s = find_attr_string(keywords, list_size, attrib); + if (s) { + *string = talloc_strdup(ctx, s); + } + } + + if (!*string) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = NT_STATUS_OK; + +done: + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + Pull the struct passwd fields for a user + *******************************************************************/ + +static NTSTATUS pull_nss_info(struct likewise_cell *c, + LDAPMessage *msg, + TALLOC_CTX *ctx, + char **homedir, + char **shell, + char **gecos, + gid_t *p_gid) +{ + NTSTATUS nt_status; + + nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, homedir); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, shell); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, gecos); + /* Gecos is often not set so ignore failures */ + + nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + return nt_status; +} + +/******************************************************************** + Pull the struct passwd fields for a user + *******************************************************************/ + +static NTSTATUS pull_alias(struct likewise_cell *c, + LDAPMessage *msg, + TALLOC_CTX *ctx, + char **alias) +{ + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + enum id_type type; + const char *attr = NULL; + + /* Figure out if this is a user or a group */ + + nt_status = get_object_type(c, msg, &type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + switch (type) { + case ID_TYPE_UID: + attr = ADEX_ATTR_UID; + break; + case ID_TYPE_GID: + /* What is the group attr for RFC2307 Forests? */ + attr = ADEX_ATTR_DISPLAYNAME; + break; + default: + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + break; + } + + nt_status = get_object_string(c, msg, ctx, attr, alias); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid, + uint32_t id, enum id_type type) +{ + struct likewise_cell *cell = NULL; + LDAPMessage *msg = NULL; + NTSTATUS nt_status; + struct lwcell_filter filter; + + filter.ftype = IdFilter; + filter.filter.id.id = id; + filter.filter.id.type = type; + + nt_status = search_cell_list(&cell, &msg, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = pull_sid(cell, msg, sid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + ads_msgfree(cell->conn, msg); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS _ccp_get_id_from_sid(uint32_t * id, + enum id_type *type, + const DOM_SID * sid) +{ + struct likewise_cell *cell = NULL; + LDAPMessage *msg = NULL; + NTSTATUS nt_status; + struct lwcell_filter filter; + + filter.ftype = SidFilter; + sid_copy(&filter.filter.sid, sid); + + nt_status = search_cell_list(&cell, &msg, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = pull_id(cell, msg, id, type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if (*id < min_id_value()) { + nt_status = NT_STATUS_INVALID_PARAMETER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + +done: + ads_msgfree(cell->conn, msg); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid, + TALLOC_CTX * ctx, + char **homedir, + char **shell, + char **gecos, gid_t * p_gid) +{ + struct likewise_cell *cell = NULL; + LDAPMessage *msg = NULL; + NTSTATUS nt_status; + struct lwcell_filter filter; + enum id_type type; + + filter.ftype = SidFilter; + sid_copy(&filter.filter.sid, sid); + + nt_status = search_cell_list(&cell, &msg, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = get_object_type(cell, msg, &type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if (type != ID_TYPE_UID) { + nt_status = NT_STATUS_NO_SUCH_USER; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos, + (uint32_t*) p_gid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + ads_msgfree(cell->conn, msg); + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx, + const char *domain, + const char *name, char **alias) +{ + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + struct likewise_cell *cell = NULL; + LDAPMessage *msg = NULL; + struct lwcell_filter filter; + enum lsa_SidType sid_type; + + /* Convert the name to a SID */ + + nt_status = gc_name_to_sid(domain, name, &sid, &sid_type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Find the user/group */ + + filter.ftype = SidFilter; + sid_copy(&filter.filter.sid, &sid); + + nt_status = search_cell_list(&cell, &msg, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Pull the alias and return */ + + nt_status = pull_alias(cell, msg, ctx, alias); + BAIL_ON_NTSTATUS_ERROR(nt_status); + +done: + PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3); + + talloc_destroy(frame); + ads_msgfree(cell_connection(cell), msg); + + return nt_status; +} + +/********************************************************************** + Map from an alias name to the canonical, qualified name. + Ensure that the alias is only pull from the closest in which + the user or gorup is enabled in + *********************************************************************/ + +static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx, + const char *domain, + const char *alias, char **name) +{ + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + DOM_SID sid; + struct likewise_cell *cell_alias = NULL; + LDAPMessage *msg_alias = NULL; + struct likewise_cell *cell_sid = NULL; + LDAPMessage *msg_sid = NULL; + struct lwcell_filter filter; + char *canonical_name = NULL; + enum lsa_SidType type; + + /* Find the user/group */ + + filter.ftype = AliasFilter; + fstrcpy(filter.filter.alias, alias); + + nt_status = search_cell_list(&cell_alias, &msg_alias, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + nt_status = pull_sid(cell_alias, msg_alias, &sid); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + /* Now search again for the SID according to the cell list. + Verify that the cell of both search results is the same + so that we only match an alias from the closest cell + in which a user/group has been instantied. */ + + filter.ftype = SidFilter; + sid_copy(&filter.filter.sid, &sid); + + nt_status = search_cell_list(&cell_sid, &msg_sid, &filter); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + if (cell_alias != cell_sid) { + nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + BAIL_ON_NTSTATUS_ERROR(nt_status); + } + + /* Finally do the GC sid/name conversion */ + + nt_status = gc_sid_to_name(&sid, &canonical_name, &type); + BAIL_ON_NTSTATUS_ERROR(nt_status); + + *name = talloc_strdup(mem_ctx, canonical_name); + BAIL_ON_PTR_ERROR((*name), nt_status); + + nt_status = NT_STATUS_OK; + +done: + PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3); + + ads_msgfree(cell_connection(cell_alias), msg_alias); + ads_msgfree(cell_connection(cell_sid), msg_sid); + + SAFE_FREE(canonical_name); + + talloc_destroy(frame); + + return nt_status; +} + +/******************************************************************** + *******************************************************************/ + +struct cell_provider_api ccp_unified = { + .get_sid_from_id = _ccp_get_sid_from_id, + .get_id_from_sid = _ccp_get_id_from_sid, + .get_nss_info = _ccp_nss_get_info, + .map_to_alias = _ccp_map_to_alias, + .map_from_alias = _ccp_map_from_alias +}; diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 894e7866b3..1febddf110 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -1023,10 +1023,11 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, DEBUG(10,("ads: lookup_groupmem: got sid %s from " "cache\n", sid_string_dbg(&sid))); sid_copy(&(*sid_mem)[*num_names], &sid); - (*names)[*num_names] = talloc_asprintf(*names, "%s%c%s", - domain_name, - *lp_winbind_separator(), - name ); + (*names)[*num_names] = fill_domain_username_talloc( + *names, + domain_name, + name, + true); (*name_types)[*num_names] = name_type; (*num_names)++; @@ -1071,11 +1072,12 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, { sid_copy(&(*sid_mem)[*num_names], &sid_mem_nocache[i]); - (*names)[*num_names] = talloc_asprintf( *names, - "%s%c%s", - domains_nocache[i], - *lp_winbind_separator(), - names_nocache[i] ); + (*names)[*num_names] = + fill_domain_username_talloc( + *names, + domains_nocache[i], + names_nocache[i], + true); (*name_types)[*num_names] = name_types_nocache[i]; (*num_names)++; } diff --git a/source3/winbindd/winbindd_async.c b/source3/winbindd/winbindd_async.c index 1481aed8e1..7500bcbe5b 100644 --- a/source3/winbindd/winbindd_async.c +++ b/source3/winbindd/winbindd_async.c @@ -366,7 +366,7 @@ static void lookupname_recv(TALLOC_CTX *mem_ctx, bool success, /******************************************************************** The lookup name call first contacts a DC in its own domain - and fallbacks to contact a DC in the forest in our domain doesn't + and fallbacks to contact a DC if the forest in our domain doesn't know the name. ********************************************************************/ diff --git a/source3/winbindd/winbindd_group.c b/source3/winbindd/winbindd_group.c index 088f946877..f2b6fbefb5 100644 --- a/source3/winbindd/winbindd_group.c +++ b/source3/winbindd/winbindd_group.c @@ -35,7 +35,11 @@ static void add_member(const char *domain, const char *user, { fstring name; - fill_domain_username(name, domain, user, True); + if (domain != NULL) { + fill_domain_username(name, domain, user, True); + } else { + fstrcpy(name, user); + } safe_strcat(name, ",", sizeof(name)-1); string_append(pp_members, name); *p_num_members += 1; @@ -136,7 +140,7 @@ static void add_expanded_sid(const DOM_SID *sid, continue; } - add_member(domain->name, names[i], pp_members, p_num_members); + add_member(NULL, names[i], pp_members, p_num_members); } done: diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index d9104ca600..9ff3899661 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -127,7 +127,7 @@ static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx, DATA_BLOB blob; enum ndr_err_code ndr_err; - ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3, + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, info3, (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0,("append_info3_as_ndr: failed to append\n")); diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 4774bc8106..3836c46e36 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -569,6 +569,10 @@ bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser, void parse_add_domuser(void *buf, char *domuser, int *len); bool canonicalize_username(fstring username_inout, fstring domain, fstring user); void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume); +char *fill_domain_username_talloc(TALLOC_CTX *ctx, + const char *domain, + const char *user, + bool can_assume); const char *get_winbind_pipe_dir(void) ; char *get_winbind_priv_pipe_dir(void) ; int open_winbindd_socket(void); diff --git a/source3/winbindd/winbindd_rpc.c b/source3/winbindd/winbindd_rpc.c index df80ad8029..9fbea8e45b 100644 --- a/source3/winbindd/winbindd_rpc.c +++ b/source3/winbindd/winbindd_rpc.c @@ -854,7 +854,10 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, } for (r=0; r<tmp_names.count; r++) { - (*names)[i+r] = CONST_DISCARD(char *, tmp_names.names[r].string); + (*names)[i+r] = fill_domain_username_talloc(mem_ctx, + domain->name, + tmp_names.names[r].string, + true); (*name_types)[i+r] = tmp_types.ids[r]; } diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index e7b6576317..5b5ca41a74 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -1160,7 +1160,7 @@ void parse_add_domuser(void *buf, char *domuser, int *len) } } - safe_strcpy(buf, user, *len); + safe_strcpy((char *)buf, user, *len); } /* Ensure an incoming username from NSS is fully qualified. Replace the @@ -1213,6 +1213,33 @@ void fill_domain_username(fstring name, const char *domain, const char *user, bo } } +/** + * talloc version of fill_domain_username() + * return NULL on talloc failure. + */ +char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx, + const char *domain, + const char *user, + bool can_assume) +{ + char *tmp_user, *name; + + tmp_user = talloc_strdup(mem_ctx, user); + strlower_m(tmp_user); + + if (can_assume && assume_domain(domain)) { + name = tmp_user; + } else { + name = talloc_asprintf(mem_ctx, "%s%c%s", + domain, + *lp_winbind_separator(), + tmp_user); + TALLOC_FREE(tmp_user); + } + + return name; +} + /* * Winbindd socket accessor functions */ |