summaryrefslogtreecommitdiff
path: root/source4/winbind
diff options
context:
space:
mode:
Diffstat (limited to 'source4/winbind')
-rw-r--r--source4/winbind/config.mk74
-rw-r--r--source4/winbind/idmap.c718
-rw-r--r--source4/winbind/idmap.h39
-rw-r--r--source4/winbind/wb_async_helpers.c442
-rw-r--r--source4/winbind/wb_async_helpers.h34
-rw-r--r--source4/winbind/wb_cmd_getdcname.c124
-rw-r--r--source4/winbind/wb_cmd_getpwent.c128
-rw-r--r--source4/winbind/wb_cmd_getpwnam.c196
-rw-r--r--source4/winbind/wb_cmd_getpwuid.c205
-rw-r--r--source4/winbind/wb_cmd_list_trustdom.c196
-rw-r--r--source4/winbind/wb_cmd_list_users.c198
-rw-r--r--source4/winbind/wb_cmd_lookupname.c121
-rw-r--r--source4/winbind/wb_cmd_lookupsid.c119
-rw-r--r--source4/winbind/wb_cmd_setpwent.c142
-rw-r--r--source4/winbind/wb_cmd_userdomgroups.c147
-rw-r--r--source4/winbind/wb_cmd_usersids.c193
-rw-r--r--source4/winbind/wb_connect_lsa.c135
-rw-r--r--source4/winbind/wb_connect_sam.c164
-rw-r--r--source4/winbind/wb_dom_info.c126
-rw-r--r--source4/winbind/wb_dom_info_trusted.c239
-rw-r--r--source4/winbind/wb_gid2sid.c108
-rw-r--r--source4/winbind/wb_init_domain.c428
-rw-r--r--source4/winbind/wb_irpc.c155
-rw-r--r--source4/winbind/wb_name2domain.c121
-rw-r--r--source4/winbind/wb_pam_auth.c271
-rw-r--r--source4/winbind/wb_sam_logon.c166
-rw-r--r--source4/winbind/wb_samba3_cmd.c1114
-rw-r--r--source4/winbind/wb_samba3_protocol.c300
-rw-r--r--source4/winbind/wb_server.c227
-rw-r--r--source4/winbind/wb_server.h169
-rw-r--r--source4/winbind/wb_sid2domain.c212
-rw-r--r--source4/winbind/wb_sid2gid.c109
-rw-r--r--source4/winbind/wb_sid2uid.c109
-rw-r--r--source4/winbind/wb_sids2xids.c80
-rw-r--r--source4/winbind/wb_uid2sid.c110
-rw-r--r--source4/winbind/wb_utils.c49
-rw-r--r--source4/winbind/wb_xids2sids.c80
37 files changed, 7548 insertions, 0 deletions
diff --git a/source4/winbind/config.mk b/source4/winbind/config.mk
new file mode 100644
index 0000000000..b5eb2c23f0
--- /dev/null
+++ b/source4/winbind/config.mk
@@ -0,0 +1,74 @@
+# server subsystem
+
+#######################
+# Start SUBSYSTEM WINBIND
+[MODULE::WINBIND]
+INIT_FUNCTION = server_service_winbind_init
+SUBSYSTEM = smbd
+PRIVATE_DEPENDENCIES = \
+ WB_HELPER \
+ IDMAP \
+ NDR_WINBIND \
+ process_model \
+ RPC_NDR_LSA \
+ dcerpc_samr \
+ PAM_ERRORS \
+ LIBCLI_LDAP
+# End SUBSYSTEM WINBIND
+#######################
+
+WINBIND_OBJ_FILES = $(addprefix $(winbindsrcdir)/, \
+ wb_server.o \
+ wb_irpc.o \
+ wb_samba3_protocol.o \
+ wb_samba3_cmd.o \
+ wb_init_domain.o \
+ wb_dom_info.o \
+ wb_dom_info_trusted.o \
+ wb_sid2domain.o \
+ wb_name2domain.o \
+ wb_sids2xids.o \
+ wb_xids2sids.o \
+ wb_gid2sid.o \
+ wb_sid2uid.o \
+ wb_sid2gid.o \
+ wb_uid2sid.o \
+ wb_connect_lsa.o \
+ wb_connect_sam.o \
+ wb_cmd_lookupname.o \
+ wb_cmd_lookupsid.o \
+ wb_cmd_getdcname.o \
+ wb_cmd_getpwnam.o \
+ wb_cmd_getpwuid.o \
+ wb_cmd_userdomgroups.o \
+ wb_cmd_usersids.o \
+ wb_cmd_list_trustdom.o \
+ wb_cmd_list_users.o \
+ wb_cmd_setpwent.o \
+ wb_cmd_getpwent.o \
+ wb_pam_auth.o \
+ wb_sam_logon.o)
+
+$(eval $(call proto_header_template,$(winbindsrcdir)/wb_proto.h,$(WINBIND_OBJ_FILES:.o=.c)))
+
+################################################
+# Start SUBYSTEM WB_HELPER
+[SUBSYSTEM::WB_HELPER]
+PUBLIC_DEPENDENCIES = RPC_NDR_LSA dcerpc_samr
+# End SUBSYSTEM WB_HELPER
+################################################
+
+WB_HELPER_OBJ_FILES = $(addprefix $(winbindsrcdir)/, wb_async_helpers.o wb_utils.o)
+
+$(eval $(call proto_header_template,$(winbindsrcdir)/wb_helper.h,$(WB_HELPER_OBJ_FILES:.o=.c)))
+
+################################################
+# Start SUBYSTEM IDMAP
+[SUBSYSTEM::IDMAP]
+PUBLIC_DEPENDENCIES = SAMDB_COMMON
+# End SUBSYSTEM IDMAP
+################################################
+
+IDMAP_OBJ_FILES = $(winbindsrcdir)/idmap.o
+
+$(eval $(call proto_header_template,$(winbindsrcdir)/idmap_proto.h,$(IDMAP_OBJ_FILES:.o=.c)))
diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c
new file mode 100644
index 0000000000..333a86445a
--- /dev/null
+++ b/source4/winbind/idmap.c
@@ -0,0 +1,718 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Map SIDs to unixids and back
+
+ Copyright (C) Kai Blin 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 "includes.h"
+#include "auth/auth.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "librpc/gen_ndr/samr.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "lib/ldb_wrap.h"
+#include "param/param.h"
+#include "winbind/idmap.h"
+#include "libcli/security/proto.h"
+#include "libcli/ldap/ldap_ndr.h"
+
+/**
+ * Get uid/gid bounds from idmap database
+ *
+ * \param idmap_ctx idmap context to use
+ * \param low lower uid/gid bound is stored here
+ * \param high upper uid/gid bound is stored here
+ * \return 0 on success, nonzero on failure
+ */
+static int idmap_get_bounds(struct idmap_context *idmap_ctx, uint32_t *low,
+ uint32_t *high)
+{
+ int ret = -1;
+ struct ldb_context *ldb = idmap_ctx->ldb_ctx;
+ struct ldb_dn *dn;
+ struct ldb_result *res = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(idmap_ctx);
+ uint32_t lower_bound = (uint32_t) -1;
+ uint32_t upper_bound = (uint32_t) -1;
+
+ dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
+ if (dn == NULL) goto failed;
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+ if (ret != LDB_SUCCESS) goto failed;
+
+ talloc_steal(tmp_ctx, res);
+
+ if (res->count != 1) {
+ ret = -1;
+ goto failed;
+ }
+
+ lower_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "lowerBound", -1);
+ if (lower_bound != (uint32_t) -1) {
+ ret = LDB_SUCCESS;
+ } else {
+ ret = -1;
+ goto failed;
+ }
+
+ upper_bound = ldb_msg_find_attr_as_uint(res->msgs[0], "upperBound", -1);
+ if (upper_bound != (uint32_t) -1) {
+ ret = LDB_SUCCESS;
+ } else {
+ ret = -1;
+ }
+
+failed:
+ talloc_free(tmp_ctx);
+ *low = lower_bound;
+ *high = upper_bound;
+ return ret;
+}
+
+/**
+ * Add a dom_sid structure to a ldb_message
+ * \param idmap_ctx idmap context to use
+ * \param mem_ctx talloc context to use
+ * \param ldb_message ldb message to add dom_sid to
+ * \param attr_name name of the attribute to store the dom_sid in
+ * \param sid dom_sid to store
+ * \return 0 on success, an ldb error code on failure.
+ */
+static int idmap_msg_add_dom_sid(struct idmap_context *idmap_ctx,
+ TALLOC_CTX *mem_ctx, struct ldb_message *msg,
+ const char *attr_name, const struct dom_sid *sid)
+{
+ struct ldb_val val;
+ enum ndr_err_code ndr_err;
+
+ ndr_err = ndr_push_struct_blob(&val, mem_ctx,
+ lp_iconv_convenience(idmap_ctx->lp_ctx),
+ sid,
+ (ndr_push_flags_fn_t)ndr_push_dom_sid);
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return -1;
+ }
+
+ return ldb_msg_add_value(msg, attr_name, &val, NULL);
+}
+
+/**
+ * Get a dom_sid structure from a ldb message.
+ *
+ * \param mem_ctx talloc context to allocate dom_sid memory in
+ * \param msg ldb_message to get dom_sid from
+ * \param attr_name key that has the dom_sid as data
+ * \return dom_sid structure on success, NULL on failure
+ */
+static struct dom_sid *idmap_msg_get_dom_sid(TALLOC_CTX *mem_ctx,
+ struct ldb_message *msg, const char *attr_name)
+{
+ struct dom_sid *sid;
+ const struct ldb_val *val;
+ enum ndr_err_code ndr_err;
+
+ val = ldb_msg_find_ldb_val(msg, attr_name);
+ if (val == NULL) {
+ return NULL;
+ }
+
+ sid = talloc(mem_ctx, struct dom_sid);
+ if (sid == NULL) {
+ return NULL;
+ }
+
+ ndr_err = ndr_pull_struct_blob(val, sid, NULL, sid,
+ (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(sid);
+ return NULL;
+ }
+
+ return sid;
+}
+
+/**
+ * Initialize idmap context
+ *
+ * talloc_free to close.
+ *
+ * \param mem_ctx talloc context to use.
+ * \return allocated idmap_context on success, NULL on error
+ */
+struct idmap_context *idmap_init(TALLOC_CTX *mem_ctx,
+ struct event_context *ev_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ struct idmap_context *idmap_ctx;
+
+ idmap_ctx = talloc(mem_ctx, struct idmap_context);
+ if (idmap_ctx == NULL) {
+ return NULL;
+ }
+
+ idmap_ctx->lp_ctx = lp_ctx;
+
+ idmap_ctx->ldb_ctx = ldb_wrap_connect(mem_ctx, ev_ctx, lp_ctx,
+ lp_idmap_url(lp_ctx),
+ system_session(mem_ctx, lp_ctx),
+ NULL, 0, NULL);
+ if (idmap_ctx->ldb_ctx == NULL) {
+ return NULL;
+ }
+
+ idmap_ctx->unix_groups_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-2");
+ if (idmap_ctx->unix_groups_sid == NULL) {
+ return NULL;
+ }
+
+ idmap_ctx->unix_users_sid = dom_sid_parse_talloc(mem_ctx, "S-1-22-1");
+ if (idmap_ctx->unix_users_sid == NULL) {
+ return NULL;
+ }
+
+ return idmap_ctx;
+}
+
+/**
+ * Convert an unixid to the corresponding SID
+ *
+ * \param idmap_ctx idmap context to use
+ * \param mem_ctx talloc context the memory for the struct dom_sid is allocated
+ * from.
+ * \param unixid pointer to a unixid struct to convert
+ * \param sid pointer that will take the struct dom_sid pointer if the mapping
+ * succeeds.
+ * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping not
+ * possible or some other NTSTATUS that is more descriptive on failure.
+ */
+
+NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
+ const struct unixid *unixid, struct dom_sid **sid)
+{
+ int ret;
+ NTSTATUS status = NT_STATUS_NONE_MAPPED;
+ struct ldb_context *ldb = idmap_ctx->ldb_ctx;
+ struct ldb_result *res = NULL;
+ struct dom_sid *unix_sid, *new_sid;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+ const char *id_type;
+
+ switch (unixid->type) {
+ case ID_TYPE_UID:
+ id_type = "ID_TYPE_UID";
+ break;
+ case ID_TYPE_GID:
+ id_type = "ID_TYPE_GID";
+ break;
+ default:
+ DEBUG(1, ("unixid->type must be type gid or uid\n"));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
+ NULL, "(&(|(type=ID_TYPE_BOTH)(type=%s))"
+ "(xidNumber=%u))", id_type, unixid->id);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ if (res->count == 1) {
+ *sid = idmap_msg_get_dom_sid(mem_ctx, res->msgs[0],
+ "objectSid");
+ if (*sid == NULL) {
+ DEBUG(1, ("Failed to get sid from db: %u\n", ret));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n"));
+
+ /* For local users/groups , we just create a rid = uid/gid */
+ if (unixid->type == ID_TYPE_UID) {
+ unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-1");
+ } else {
+ unix_sid = dom_sid_parse_talloc(tmp_ctx, "S-1-22-2");
+ }
+ if (unix_sid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id);
+ if (new_sid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ *sid = new_sid;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+
+/**
+ * Map a SID to an unixid struct.
+ *
+ * If no mapping exists, a new mapping will be created.
+ *
+ * \todo Check if SIDs can be resolved if lp_idmap_trusted_only() == true
+ * \todo Fix backwards compatibility for Samba3
+ *
+ * \param idmap_ctx idmap context to use
+ * \param mem_ctx talloc context to use
+ * \param sid SID to map to an unixid struct
+ * \param unixid pointer to a unixid struct pointer
+ * \return NT_STATUS_OK on success, NT_STATUS_INVALID_SID if the sid is not from
+ * a trusted domain and idmap trusted only = true, NT_STATUS_NONE_MAPPED if the
+ * mapping failed.
+ */
+NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid, struct unixid **unixid)
+{
+ int ret;
+ NTSTATUS status = NT_STATUS_NONE_MAPPED;
+ struct ldb_context *ldb = idmap_ctx->ldb_ctx;
+ struct ldb_dn *dn;
+ struct ldb_message *hwm_msg, *map_msg;
+ struct ldb_result *res = NULL;
+ int trans;
+ uint32_t low, high, hwm, new_xid;
+ char *sid_string, *unixid_string, *hwm_string;
+ bool hwm_entry_exists;
+ TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+
+ if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) {
+ uint32_t rid;
+ DEBUG(6, ("This is a local unix uid, just calculate that.\n"));
+ status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) goto failed;
+
+ *unixid = talloc(mem_ctx, struct unixid);
+ if (*unixid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+ (*unixid)->id = rid;
+ (*unixid)->type = ID_TYPE_UID;
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) {
+ uint32_t rid;
+ DEBUG(6, ("This is a local unix gid, just calculate that.\n"));
+ status = dom_sid_split_rid(tmp_ctx, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) goto failed;
+
+ *unixid = talloc(mem_ctx, struct unixid);
+ if (*unixid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+ (*unixid)->id = rid;
+ (*unixid)->type = ID_TYPE_GID;
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
+ NULL, "(&(objectClass=sidMap)(objectSid=%s))",
+ ldap_encode_ndr_dom_sid(tmp_ctx, sid));
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ if (res->count == 1) {
+ const char *type = ldb_msg_find_attr_as_string(res->msgs[0],
+ "type", NULL);
+ new_xid = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber",
+ -1);
+ if (new_xid == (uint32_t) -1) {
+ DEBUG(1, ("Invalid xid mapping.\n"));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ if (type == NULL) {
+ DEBUG(1, ("Invalid type for mapping entry.\n"));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ *unixid = talloc(mem_ctx, struct unixid);
+ if (*unixid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ (*unixid)->id = new_xid;
+
+ if (strcmp(type, "ID_TYPE_BOTH") == 0) {
+ (*unixid)->type = ID_TYPE_BOTH;
+ } else if (strcmp(type, "ID_TYPE_UID") == 0) {
+ (*unixid)->type = ID_TYPE_UID;
+ } else {
+ (*unixid)->type = ID_TYPE_GID;
+ }
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+ }
+
+ DEBUG(6, ("No existing mapping found, attempting to create one.\n"));
+
+ trans = ldb_transaction_start(ldb);
+ if (trans != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ /* Redo the search to make sure noone changed the mapping while we
+ * weren't looking */
+ ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
+ NULL, "(&(objectClass=sidMap)(objectSid=%s))",
+ ldap_encode_ndr_dom_sid(tmp_ctx, sid));
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ if (res->count > 0) {
+ DEBUG(1, ("Database changed while trying to add a sidmap.\n"));
+ status = NT_STATUS_RETRY;
+ goto failed;
+ }
+
+ /*FIXME: if lp_idmap_trusted_only() == true, check if SID can be
+ * resolved here. */
+
+ ret = idmap_get_bounds(idmap_ctx, &low, &high);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ dn = ldb_dn_new(tmp_ctx, ldb, "CN=CONFIG");
+ if (dn == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Search failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ talloc_steal(tmp_ctx, res);
+
+ if (res->count != 1) {
+ DEBUG(1, ("No CN=CONFIG record, idmap database is broken.\n"));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ hwm = ldb_msg_find_attr_as_uint(res->msgs[0], "xidNumber", -1);
+ if (hwm == (uint32_t)-1) {
+ hwm = low;
+ hwm_entry_exists = false;
+ } else {
+ hwm_entry_exists = true;
+ }
+
+ if (hwm > high) {
+ DEBUG(1, ("Out of xids to allocate.\n"));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ hwm_msg = ldb_msg_new(tmp_ctx);
+ if (hwm_msg == NULL) {
+ DEBUG(1, ("Out of memory when creating ldb_message\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ hwm_msg->dn = dn;
+
+ new_xid = hwm;
+ hwm++;
+
+ hwm_string = talloc_asprintf(tmp_ctx, "%u", hwm);
+ if (hwm_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ sid_string = dom_sid_string(tmp_ctx, sid);
+ if (sid_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ unixid_string = talloc_asprintf(tmp_ctx, "%u", new_xid);
+ if (unixid_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ if (hwm_entry_exists) {
+ struct ldb_message_element *els;
+ struct ldb_val *vals;
+
+ /* We're modifying the entry, not just adding a new one. */
+ els = talloc_array(tmp_ctx, struct ldb_message_element, 2);
+ if (els == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ vals = talloc_array(tmp_ctx, struct ldb_val, 2);
+ if (els == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ hwm_msg->num_elements = 2;
+ hwm_msg->elements = els;
+
+ els[0].num_values = 1;
+ els[0].values = &vals[0];
+ els[0].flags = LDB_FLAG_MOD_DELETE;
+ els[0].name = talloc_strdup(tmp_ctx, "xidNumber");
+ if (els[0].name == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ els[1].num_values = 1;
+ els[1].values = &vals[1];
+ els[1].flags = LDB_FLAG_MOD_ADD;
+ els[1].name = els[0].name;
+
+ vals[0].data = (uint8_t *)unixid_string;
+ vals[0].length = strlen(unixid_string);
+ vals[1].data = (uint8_t *)hwm_string;
+ vals[1].length = strlen(hwm_string);
+ } else {
+ ret = ldb_msg_add_empty(hwm_msg, "xidNumber", LDB_FLAG_MOD_ADD,
+ NULL);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_msg_add_string(hwm_msg, "xidNumber", hwm_string);
+ if (ret != LDB_SUCCESS)
+ {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+ }
+
+ ret = ldb_modify(ldb, hwm_msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Updating the xid high water mark failed: %s\n",
+ ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ map_msg = ldb_msg_new(tmp_ctx);
+ if (map_msg == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ map_msg->dn = ldb_dn_new_fmt(tmp_ctx, ldb, "CN=%s", sid_string);
+ if (map_msg->dn == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ ret = ldb_msg_add_string(map_msg, "xidNumber", unixid_string);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = idmap_msg_add_dom_sid(idmap_ctx, tmp_ctx, map_msg, "objectSid",
+ sid);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_msg_add_string(map_msg, "objectClass", "sidMap");
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_msg_add_string(map_msg, "type", "ID_TYPE_BOTH");
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_msg_add_string(map_msg, "cn", sid_string);
+ if (ret != LDB_SUCCESS) {
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ ret = ldb_add(ldb, map_msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(1, ("Adding a sidmap failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ trans = ldb_transaction_commit(ldb);
+ if (trans != LDB_SUCCESS) {
+ DEBUG(1, ("Transaction failed: %s\n", ldb_errstring(ldb)));
+ status = NT_STATUS_NONE_MAPPED;
+ goto failed;
+ }
+
+ *unixid = talloc(mem_ctx, struct unixid);
+ if (*unixid == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
+ }
+
+ (*unixid)->id = new_xid;
+ (*unixid)->type = ID_TYPE_BOTH;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+
+failed:
+ if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
+ talloc_free(tmp_ctx);
+ return status;
+}
+
+/**
+ * Convert an array of unixids to the corresponding array of SIDs
+ *
+ * \param idmap_ctx idmap context to use
+ * \param mem_ctx talloc context the memory for the dom_sids is allocated
+ * from.
+ * \param count length of id_mapping array.
+ * \param id array of id_mappings.
+ * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
+ * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
+ * did not.
+ */
+
+NTSTATUS idmap_xids_to_sids(struct idmap_context *idmap_ctx,
+ TALLOC_CTX *mem_ctx, int count,
+ struct id_mapping *id)
+{
+ int i;
+ int error_count = 0;
+
+ for (i = 0; i < count; ++i) {
+ id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
+ id[i].unixid, &id[i].sid);
+ if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) {
+ id[i].status = idmap_xid_to_sid(idmap_ctx, mem_ctx,
+ id[i].unixid,
+ &id[i].sid);
+ }
+ if (!NT_STATUS_IS_OK(id[i].status)) {
+ DEBUG(1, ("idmapping xid_to_sid failed for id[%d]\n", i));
+ error_count++;
+ }
+ }
+
+ if (error_count == count) {
+ /* Mapping did not work at all. */
+ return NT_STATUS_NONE_MAPPED;
+ } else if (error_count > 0) {
+ /* Some mappings worked, some did not. */
+ return STATUS_SOME_UNMAPPED;
+ } else {
+ return NT_STATUS_OK;
+ }
+}
+
+/**
+ * Convert an array of SIDs to the corresponding array of unixids
+ *
+ * \param idmap_ctx idmap context to use
+ * \param mem_ctx talloc context the memory for the unixids is allocated
+ * from.
+ * \param count length of id_mapping array.
+ * \param id array of id_mappings.
+ * \return NT_STATUS_OK on success, NT_STATUS_NONE_MAPPED if mapping is not
+ * possible at all, NT_STATUS_SOME_UNMAPPED if some mappings worked and some
+ * did not.
+ */
+
+NTSTATUS idmap_sids_to_xids(struct idmap_context *idmap_ctx,
+ TALLOC_CTX *mem_ctx, int count,
+ struct id_mapping *id)
+{
+ int i;
+ int error_count = 0;
+
+ for (i = 0; i < count; ++i) {
+ id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
+ id[i].sid, &id[i].unixid);
+ if (NT_STATUS_EQUAL(id[i].status, NT_STATUS_RETRY)) {
+ id[i].status = idmap_sid_to_xid(idmap_ctx, mem_ctx,
+ id[i].sid,
+ &id[i].unixid);
+ }
+ if (!NT_STATUS_IS_OK(id[i].status)) {
+ DEBUG(1, ("idmapping sid_to_xid failed for id[%d]\n", i));
+ error_count++;
+ }
+ }
+
+ if (error_count == count) {
+ /* Mapping did not work at all. */
+ return NT_STATUS_NONE_MAPPED;
+ } else if (error_count > 0) {
+ /* Some mappings worked, some did not. */
+ return STATUS_SOME_UNMAPPED;
+ } else {
+ return NT_STATUS_OK;
+ }
+}
+
diff --git a/source4/winbind/idmap.h b/source4/winbind/idmap.h
new file mode 100644
index 0000000000..13dbe0b921
--- /dev/null
+++ b/source4/winbind/idmap.h
@@ -0,0 +1,39 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Map SIDs to uids/gids and back
+
+ Copyright (C) Kai Blin 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/>.
+*/
+
+#ifndef _IDMAP_H_
+#define _IDMAP_H_
+
+#include "librpc/gen_ndr/winbind.h"
+
+struct idmap_context {
+ struct loadparm_context *lp_ctx;
+ struct ldb_context *ldb_ctx;
+ struct dom_sid *unix_groups_sid;
+ struct dom_sid *unix_users_sid;
+};
+
+struct event_context;
+
+#include "winbind/idmap_proto.h"
+
+#endif
+
diff --git a/source4/winbind/wb_async_helpers.c b/source4/winbind/wb_async_helpers.c
new file mode 100644
index 0000000000..25d52a16b5
--- /dev/null
+++ b/source4/winbind/wb_async_helpers.c
@@ -0,0 +1,442 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+/*
+ a composite API for finding a DC and its name
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_async_helpers.h"
+
+#include "lib/messaging/irpc.h"
+#include "librpc/gen_ndr/irpc.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/security/security.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+
+#include "winbind/wb_helper.h"
+
+struct lsa_lookupsids_state {
+ struct composite_context *ctx;
+ int num_sids;
+ struct lsa_LookupSids r;
+ struct lsa_SidArray sids;
+ struct lsa_TransNameArray names;
+ uint32_t count;
+ struct wb_sid_object **result;
+};
+
+static void lsa_lookupsids_recv_names(struct rpc_request *req);
+
+struct composite_context *wb_lsa_lookupsids_send(TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe *lsa_pipe,
+ struct policy_handle *handle,
+ int num_sids,
+ const struct dom_sid **sids)
+{
+ struct composite_context *result;
+ struct rpc_request *req;
+ struct lsa_lookupsids_state *state;
+ int i;
+
+ result = composite_create(mem_ctx, lsa_pipe->conn->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct lsa_lookupsids_state);
+ if (state == NULL) goto failed;
+ result->private_data = state;
+ state->ctx = result;
+
+ state->sids.num_sids = num_sids;
+ state->sids.sids = talloc_array(state, struct lsa_SidPtr, num_sids);
+ if (state->sids.sids == NULL) goto failed;
+
+ for (i=0; i<num_sids; i++) {
+ state->sids.sids[i].sid = dom_sid_dup(state->sids.sids,
+ sids[i]);
+ if (state->sids.sids[i].sid == NULL) goto failed;
+ }
+
+ state->count = 0;
+ state->num_sids = num_sids;
+ state->names.count = 0;
+ state->names.names = NULL;
+
+ state->r.in.handle = handle;
+ state->r.in.sids = &state->sids;
+ state->r.in.names = &state->names;
+ state->r.in.level = 1;
+ state->r.in.count = &state->count;
+ state->r.out.names = &state->names;
+ state->r.out.count = &state->count;
+
+ req = dcerpc_lsa_LookupSids_send(lsa_pipe, state, &state->r);
+ if (req == NULL) goto failed;
+
+ req->async.callback = lsa_lookupsids_recv_names;
+ req->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void lsa_lookupsids_recv_names(struct rpc_request *req)
+{
+ struct lsa_lookupsids_state *state =
+ talloc_get_type(req->async.private_data,
+ struct lsa_lookupsids_state);
+ int i;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->r.out.result;
+ if (!NT_STATUS_IS_OK(state->ctx->status) &&
+ !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
+ composite_error(state->ctx, state->ctx->status);
+ return;
+ }
+
+ state->result = talloc_array(state, struct wb_sid_object *,
+ state->num_sids);
+ if (composite_nomem(state->result, state->ctx)) return;
+
+ for (i=0; i<state->num_sids; i++) {
+ struct lsa_TranslatedName *name =
+ &state->r.out.names->names[i];
+ struct lsa_DomainInfo *dom;
+
+ state->result[i] = talloc_zero(state->result,
+ struct wb_sid_object);
+ if (composite_nomem(state->result[i], state->ctx)) return;
+
+ state->result[i]->type = name->sid_type;
+ if (state->result[i]->type == SID_NAME_UNKNOWN) {
+ continue;
+ }
+
+ if (name->sid_index >= state->r.out.domains->count) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ dom = &state->r.out.domains->domains[name->sid_index];
+ state->result[i]->domain = talloc_reference(state->result[i],
+ dom->name.string);
+ if ((name->sid_type == SID_NAME_DOMAIN) ||
+ (name->name.string == NULL)) {
+ state->result[i]->name =
+ talloc_strdup(state->result[i], "");
+ } else {
+ state->result[i]->name =
+ talloc_steal(state->result[i],
+ name->name.string);
+ }
+
+ if (composite_nomem(state->result[i]->name, state->ctx)) {
+ return;
+ }
+ }
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_lsa_lookupsids_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct wb_sid_object ***names)
+{
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct lsa_lookupsids_state *state =
+ talloc_get_type(c->private_data,
+ struct lsa_lookupsids_state);
+ *names = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(c);
+ return status;
+}
+
+
+struct lsa_lookupnames_state {
+ struct composite_context *ctx;
+ uint32_t num_names;
+ struct lsa_LookupNames r;
+ struct lsa_TransSidArray sids;
+ uint32_t count;
+ struct wb_sid_object **result;
+};
+
+static void lsa_lookupnames_recv_sids(struct rpc_request *req);
+
+struct composite_context *wb_lsa_lookupnames_send(TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe *lsa_pipe,
+ struct policy_handle *handle,
+ int num_names,
+ const char **names)
+{
+ struct composite_context *result;
+ struct rpc_request *req;
+ struct lsa_lookupnames_state *state;
+
+ struct lsa_String *lsa_names;
+ int i;
+
+ result = composite_create(mem_ctx, lsa_pipe->conn->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct lsa_lookupnames_state);
+ if (state == NULL) goto failed;
+ result->private_data = state;
+ state->ctx = result;
+
+ state->sids.count = 0;
+ state->sids.sids = NULL;
+ state->num_names = num_names;
+ state->count = 0;
+
+ lsa_names = talloc_array(state, struct lsa_String, num_names);
+ if (lsa_names == NULL) goto failed;
+
+ for (i=0; i<num_names; i++) {
+ lsa_names[i].string = names[i];
+ }
+
+ state->r.in.handle = handle;
+ state->r.in.num_names = num_names;
+ state->r.in.names = lsa_names;
+ state->r.in.sids = &state->sids;
+ state->r.in.level = 1;
+ state->r.in.count = &state->count;
+ state->r.out.count = &state->count;
+ state->r.out.sids = &state->sids;
+
+ req = dcerpc_lsa_LookupNames_send(lsa_pipe, state, &state->r);
+ if (req == NULL) goto failed;
+
+ req->async.callback = lsa_lookupnames_recv_sids;
+ req->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void lsa_lookupnames_recv_sids(struct rpc_request *req)
+{
+ struct lsa_lookupnames_state *state =
+ talloc_get_type(req->async.private_data,
+ struct lsa_lookupnames_state);
+ int i;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->r.out.result;
+ if (!NT_STATUS_IS_OK(state->ctx->status) &&
+ !NT_STATUS_EQUAL(state->ctx->status, STATUS_SOME_UNMAPPED)) {
+ composite_error(state->ctx, state->ctx->status);
+ return;
+ }
+
+ state->result = talloc_array(state, struct wb_sid_object *,
+ state->num_names);
+ if (composite_nomem(state->result, state->ctx)) return;
+
+ for (i=0; i<state->num_names; i++) {
+ struct lsa_TranslatedSid *sid = &state->r.out.sids->sids[i];
+ struct lsa_DomainInfo *dom;
+
+ state->result[i] = talloc_zero(state->result,
+ struct wb_sid_object);
+ if (composite_nomem(state->result[i], state->ctx)) return;
+
+ state->result[i]->type = sid->sid_type;
+ if (state->result[i]->type == SID_NAME_UNKNOWN) {
+ continue;
+ }
+
+ if (sid->sid_index >= state->r.out.domains->count) {
+ composite_error(state->ctx,
+ NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+
+ dom = &state->r.out.domains->domains[sid->sid_index];
+
+ state->result[i]->sid = dom_sid_add_rid(state->result[i],
+ dom->sid, sid->rid);
+ }
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_lsa_lookupnames_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct wb_sid_object ***sids)
+{
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct lsa_lookupnames_state *state =
+ talloc_get_type(c->private_data,
+ struct lsa_lookupnames_state);
+ *sids = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(c);
+ return status;
+}
+struct samr_getuserdomgroups_state {
+ struct composite_context *ctx;
+ struct dcerpc_pipe *samr_pipe;
+
+ int num_rids;
+ uint32_t *rids;
+
+ struct policy_handle *user_handle;
+ struct samr_OpenUser o;
+ struct samr_GetGroupsForUser g;
+ struct samr_Close c;
+};
+
+static void samr_usergroups_recv_open(struct rpc_request *req);
+static void samr_usergroups_recv_groups(struct rpc_request *req);
+static void samr_usergroups_recv_close(struct rpc_request *req);
+
+struct composite_context *wb_samr_userdomgroups_send(TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe *samr_pipe,
+ struct policy_handle *domain_handle,
+ uint32_t rid)
+{
+ struct composite_context *result;
+ struct rpc_request *req;
+ struct samr_getuserdomgroups_state *state;
+
+ result = composite_create(mem_ctx, samr_pipe->conn->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct samr_getuserdomgroups_state);
+ if (state == NULL) goto failed;
+ result->private_data = state;
+ state->ctx = result;
+
+ state->samr_pipe = samr_pipe;
+
+ state->user_handle = talloc(state, struct policy_handle);
+ if (state->user_handle == NULL) goto failed;
+
+ state->o.in.domain_handle = domain_handle;
+ state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->o.in.rid = rid;
+ state->o.out.user_handle = state->user_handle;
+
+ req = dcerpc_samr_OpenUser_send(state->samr_pipe, state, &state->o);
+ if (req == NULL) goto failed;
+
+ req->async.callback = samr_usergroups_recv_open;
+ req->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void samr_usergroups_recv_open(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private_data,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->o.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->g.in.user_handle = state->user_handle;
+
+ req = dcerpc_samr_GetGroupsForUser_send(state->samr_pipe, state,
+ &state->g);
+ composite_continue_rpc(state->ctx, req, samr_usergroups_recv_groups,
+ state);
+}
+
+static void samr_usergroups_recv_groups(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private_data,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->g.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->c.in.handle = state->user_handle;
+ state->c.out.handle = state->user_handle;
+
+ req = dcerpc_samr_Close_send(state->samr_pipe, state, &state->c);
+ composite_continue_rpc(state->ctx, req, samr_usergroups_recv_close,
+ state);
+}
+
+static void samr_usergroups_recv_close(struct rpc_request *req)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(req->async.private_data,
+ struct samr_getuserdomgroups_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->c.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_samr_userdomgroups_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ int *num_rids, uint32_t **rids)
+{
+ struct samr_getuserdomgroups_state *state =
+ talloc_get_type(ctx->private_data,
+ struct samr_getuserdomgroups_state);
+
+ int i;
+ NTSTATUS status = composite_wait(ctx);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ *num_rids = state->g.out.rids->count;
+ *rids = talloc_array(mem_ctx, uint32_t, *num_rids);
+ if (*rids == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<*num_rids; i++) {
+ (*rids)[i] = state->g.out.rids->rids[i].rid;
+ }
+
+ done:
+ talloc_free(ctx);
+ return status;
+}
diff --git a/source4/winbind/wb_async_helpers.h b/source4/winbind/wb_async_helpers.h
new file mode 100644
index 0000000000..0dc2d4ff10
--- /dev/null
+++ b/source4/winbind/wb_async_helpers.h
@@ -0,0 +1,34 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ SMB composite request interfaces
+
+ Copyright (C) Volker Lendecke 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 __WB_ASYNC_HELPERS_H__
+#define __WB_ASYNC_HELPERS_H__
+
+#include "librpc/gen_ndr/lsa.h"
+
+struct wb_sid_object {
+ enum lsa_SidType type;
+ struct dom_sid *sid;
+ const char *domain;
+ const char *name;
+};
+
+#endif /* __WB_ASYNC_HELPERS_H__ */
diff --git a/source4/winbind/wb_cmd_getdcname.c b/source4/winbind/wb_cmd_getdcname.c
new file mode 100644
index 0000000000..46d7f0d82f
--- /dev/null
+++ b/source4/winbind/wb_cmd_getdcname.c
@@ -0,0 +1,124 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo --getdcname
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+
+struct cmd_getdcname_state {
+ struct composite_context *ctx;
+ const char *domain_name;
+
+ struct netr_GetAnyDCName g;
+};
+
+static void getdcname_recv_domain(struct composite_context *ctx);
+static void getdcname_recv_dcname(struct rpc_request *req);
+
+struct composite_context *wb_cmd_getdcname_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *domain_name)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_getdcname_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_getdcname_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->domain_name = talloc_strdup(state, domain_name);
+ if (state->domain_name == NULL) goto failed;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = getdcname_recv_domain;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void getdcname_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_getdcname_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getdcname_state);
+ struct wbsrv_domain *domain;
+ struct rpc_request *req;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->g.in.logon_server = talloc_asprintf(
+ state, "\\\\%s",
+ dcerpc_server_name(domain->netlogon_pipe));
+ state->g.in.domainname = state->domain_name;
+
+ req = dcerpc_netr_GetAnyDCName_send(domain->netlogon_pipe, state,
+ &state->g);
+ if (composite_nomem(req, state->ctx)) return;
+
+ composite_continue_rpc(state->ctx, req, getdcname_recv_dcname, state);
+}
+
+static void getdcname_recv_dcname(struct rpc_request *req)
+{
+ struct cmd_getdcname_state *state =
+ talloc_get_type(req->async.private_data,
+ struct cmd_getdcname_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = werror_to_ntstatus(state->g.out.result);
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_getdcname_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ const char **dcname)
+{
+ struct cmd_getdcname_state *state =
+ talloc_get_type(c->private_data, struct cmd_getdcname_state);
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ const char *p = state->g.out.dcname;
+ if (*p == '\\') p += 1;
+ if (*p == '\\') p += 1;
+ *dcname = talloc_strdup(mem_ctx, p);
+ if (*dcname == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ }
+ }
+ talloc_free(state);
+ return status;
+}
diff --git a/source4/winbind/wb_cmd_getpwent.c b/source4/winbind/wb_cmd_getpwent.c
new file mode 100644
index 0000000000..980a8a4d92
--- /dev/null
+++ b/source4/winbind/wb_cmd_getpwent.c
@@ -0,0 +1,128 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for getpwent
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libnet/libnet_proto.h"
+
+struct cmd_getpwent_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+
+ struct wbsrv_pwent *pwent;
+ uint32_t max_users;
+
+ uint32_t num_users;
+ struct winbindd_pw *result;
+};
+
+static void cmd_getpwent_recv_pwnam(struct composite_context *ctx);
+#if 0 /*FIXME: implement this*/
+static void cmd_getpwent_recv_user_list(struct composite_context *ctx);
+#endif
+
+struct composite_context *wb_cmd_getpwent_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, struct wbsrv_pwent *pwent,
+ uint32_t max_users)
+{
+ struct composite_context *ctx, *result;
+ struct cmd_getpwent_state *state;
+
+ DEBUG(5, ("wb_cmd_getpwent_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(mem_ctx, struct cmd_getpwent_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->pwent = pwent;
+ state->max_users = max_users;
+ state->num_users = 0;
+
+ /* If there are users left in the libnet_UserList and we're below the
+ * maximum number of users to get per winbind getpwent call, use
+ * getpwnam to get the winbindd_pw struct */
+ if (pwent->page_index < pwent->user_list->out.count) {
+ int idx = pwent->page_index;
+ char *username = talloc_strdup(state,
+ pwent->user_list->out.users[idx].username);
+
+ pwent->page_index++;
+ ctx = wb_cmd_getpwnam_send(state, service, username);
+ if (composite_nomem(ctx, state->ctx)) return result;
+
+ composite_continue(state->ctx, ctx, cmd_getpwent_recv_pwnam,
+ state);
+ } else {
+ /* If there is no valid user left, call libnet_UserList to get a new
+ * list of users. */
+ composite_error(state->ctx, NT_STATUS_NO_MORE_ENTRIES);
+ }
+ return result;
+}
+
+static void cmd_getpwent_recv_pwnam(struct composite_context *ctx)
+{
+ struct cmd_getpwent_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getpwent_state);
+ struct winbindd_pw *pw;
+
+ DEBUG(5, ("cmd_getpwent_recv_pwnam called\n"));
+
+ state->ctx->status = wb_cmd_getpwnam_recv(ctx, state, &pw);
+ if (!composite_is_ok(state->ctx)) return;
+
+ /*FIXME: Cheat for now and only get one user per call */
+ state->result = pw;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_getpwent_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx, struct winbindd_pw **pw,
+ uint32_t *num_users)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_getpwent_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_getpwent_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_getpwent_state);
+ *pw = talloc_steal(mem_ctx, state->result);
+ /*FIXME: Cheat and only get oner user */
+ *num_users = 1;
+ }
+
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_cmd_getpwnam.c b/source4/winbind/wb_cmd_getpwnam.c
new file mode 100644
index 0000000000..7d821537f0
--- /dev/null
+++ b/source4/winbind/wb_cmd_getpwnam.c
@@ -0,0 +1,196 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -i
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "param/param.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libnet/libnet_proto.h"
+#include "libcli/security/proto.h"
+
+struct cmd_getpwnam_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ char *name;
+ char *workgroup_name;
+ struct dom_sid *group_sid;
+
+ struct winbindd_pw *result;
+};
+
+static void cmd_getpwnam_recv_domain(struct composite_context *ctx);
+static void cmd_getpwnam_recv_user_info(struct composite_context *ctx);
+static void cmd_getpwnam_recv_uid(struct composite_context *ctx);
+static void cmd_getpwnam_recv_gid(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_getpwnam_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *name)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_getpwnam_state *state;
+
+ DEBUG(5, ("wb_cmd_getpwnam_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct cmd_getpwnam_state);
+ if (composite_nomem(state, result)) return result;
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->name = talloc_strdup(state, name);
+ if(composite_nomem(state->name, result)) return result;
+
+ ctx = wb_name2domain_send(state, service, name);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, cmd_getpwnam_recv_domain, state);
+ return result;
+}
+
+static void cmd_getpwnam_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_getpwnam_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_getpwnam_state);
+ struct wbsrv_domain *domain;
+ struct libnet_UserInfo *user_info;
+ char *user_dom, *user_name;
+ bool ok;
+
+ state->ctx->status = wb_name2domain_recv(ctx, &domain);
+ if(!composite_is_ok(state->ctx)) return;
+
+ user_info = talloc(state, struct libnet_UserInfo);
+ if (composite_nomem(user_info, state->ctx)) return;
+
+ ok= wb_samba3_split_username(state, state->service->task->lp_ctx, state->name, &user_dom, &user_name);
+ if(!ok){
+ composite_error(state->ctx, NT_STATUS_OBJECT_NAME_INVALID);
+ return;
+ }
+
+ user_info->in.level = USER_INFO_BY_NAME;
+ user_info->in.data.user_name = user_name;
+ user_info->in.domain_name = domain->libnet_ctx->samr.name;
+ state->workgroup_name = talloc_strdup(state,
+ domain->libnet_ctx->samr.name);
+ if(composite_nomem(state->workgroup_name, state->ctx)) return;
+
+ ctx = libnet_UserInfo_send(domain->libnet_ctx, state, user_info, NULL);
+
+ composite_continue(state->ctx, ctx, cmd_getpwnam_recv_user_info, state);
+}
+
+static void cmd_getpwnam_recv_user_info(struct composite_context *ctx)
+{
+ struct cmd_getpwnam_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_getpwnam_state);
+ struct libnet_UserInfo *user_info;
+ struct winbindd_pw *pw;
+
+ DEBUG(5, ("cmd_getpwnam_recv_user_info called\n"));
+
+ user_info = talloc(state, struct libnet_UserInfo);
+ if(composite_nomem(user_info, state->ctx)) return;
+
+ pw = talloc(state, struct winbindd_pw);
+ if(composite_nomem(pw, state->ctx)) return;
+
+ state->ctx->status = libnet_UserInfo_recv(ctx, state, user_info);
+ if(!composite_is_ok(state->ctx)) return;
+
+ WBSRV_SAMBA3_SET_STRING(pw->pw_name, user_info->out.account_name);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_passwd, "*");
+ WBSRV_SAMBA3_SET_STRING(pw->pw_gecos, user_info->out.full_name);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_dir,
+ lp_template_homedir(state->service->task->lp_ctx));
+ all_string_sub(pw->pw_dir, "%WORKGROUP%", state->workgroup_name,
+ sizeof(fstring) - 1);
+ all_string_sub(pw->pw_dir, "%ACCOUNTNAME%", user_info->out.account_name,
+ sizeof(fstring) - 1);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_shell,
+ lp_template_shell(state->service->task->lp_ctx));
+
+ state->group_sid = dom_sid_dup(state, user_info->out.primary_group_sid);
+ if(composite_nomem(state->group_sid, state->ctx)) return;
+
+ state->result = pw;
+
+ ctx = wb_sid2uid_send(state, state->service, user_info->out.user_sid);
+ composite_continue(state->ctx, ctx, cmd_getpwnam_recv_uid, state);
+}
+
+static void cmd_getpwnam_recv_uid(struct composite_context *ctx)
+{
+ struct cmd_getpwnam_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_getpwnam_state);
+ uid_t uid;
+
+ DEBUG(5, ("cmd_getpwnam_recv_uid called\n"));
+
+ state->ctx->status = wb_sid2uid_recv(ctx, &uid);
+ if(!composite_is_ok(state->ctx)) return;
+
+ state->result->pw_uid = uid;
+
+ ctx = wb_sid2gid_send(state, state->service, state->group_sid);
+ composite_continue(state->ctx, ctx, cmd_getpwnam_recv_gid, state);
+}
+
+static void cmd_getpwnam_recv_gid(struct composite_context *ctx)
+{
+ struct cmd_getpwnam_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_getpwnam_state);
+ gid_t gid;
+
+ DEBUG(5, ("cmd_getpwnam_recv_gid called\n"));
+
+ state->ctx->status = wb_sid2gid_recv(ctx, &gid);
+ if(!composite_is_ok(state->ctx)) return;
+
+ state->result->pw_gid = gid;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_getpwnam_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx, struct winbindd_pw **pw)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_getpwnam_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_getpwnam_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_getpwnam_state);
+ *pw = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(ctx);
+ return status;
+
+}
+
diff --git a/source4/winbind/wb_cmd_getpwuid.c b/source4/winbind/wb_cmd_getpwuid.c
new file mode 100644
index 0000000000..15cc592cf6
--- /dev/null
+++ b/source4/winbind/wb_cmd_getpwuid.c
@@ -0,0 +1,205 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Backend for getpwuid
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libnet/libnet_proto.h"
+#include "param/param.h"
+#include "libcli/security/proto.h"
+#include "auth/credentials/credentials.h"
+
+struct cmd_getpwuid_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ uid_t uid;
+ struct dom_sid *sid;
+ char *workgroup;
+ struct wbsrv_domain *domain;
+
+ struct winbindd_pw *result;
+};
+
+static void cmd_getpwuid_recv_sid(struct composite_context *ctx);
+static void cmd_getpwuid_recv_domain(struct composite_context *ctx);
+static void cmd_getpwuid_recv_user_info(struct composite_context *ctx);
+static void cmd_getpwuid_recv_gid(struct composite_context *ctx);
+
+/* Get the SID using the uid */
+
+struct composite_context *wb_cmd_getpwuid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ uid_t uid)
+{
+ struct composite_context *ctx, *result;
+ struct cmd_getpwuid_state *state;
+
+ DEBUG(5, ("wb_cmd_getpwnam_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct cmd_getpwuid_state);
+ if (composite_nomem(state, result)) return result;
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->uid = uid;
+
+ ctx = wb_uid2sid_send(state, service, uid);
+ if (composite_nomem(ctx, state->ctx)) return result;
+
+ composite_continue(result, ctx, cmd_getpwuid_recv_sid, state);
+ return result;
+}
+
+
+/* Receive the sid and get the domain structure with it */
+
+static void cmd_getpwuid_recv_sid(struct composite_context *ctx)
+{
+ struct cmd_getpwuid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getpwuid_state);
+
+ DEBUG(5, ("cmd_getpwuid_recv_sid called %p\n", ctx->private_data));
+
+ state->ctx->status = wb_uid2sid_recv(ctx, state, &state->sid);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_sid2domain_send(state, state->service, state->sid);
+
+ composite_continue(state->ctx, ctx, cmd_getpwuid_recv_domain, state);
+}
+
+/* Receive the domain struct and call libnet to get the user info struct */
+
+static void cmd_getpwuid_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_getpwuid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getpwuid_state);
+ struct libnet_UserInfo *user_info;
+
+ DEBUG(5, ("cmd_getpwuid_recv_domain called\n"));
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &state->domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ user_info = talloc(state, struct libnet_UserInfo);
+ if (composite_nomem(user_info, state->ctx)) return;
+
+ user_info->in.level = USER_INFO_BY_SID;
+ user_info->in.data.user_sid = state->sid;
+ user_info->in.domain_name = state->domain->libnet_ctx->samr.name;
+
+ /* We need the workgroup later, so copy it */
+ state->workgroup = talloc_strdup(state,
+ state->domain->libnet_ctx->samr.name);
+ if (composite_nomem(state->workgroup, state->ctx)) return;
+
+ ctx = libnet_UserInfo_send(state->domain->libnet_ctx, state, user_info,
+ NULL);
+
+ composite_continue(state->ctx, ctx, cmd_getpwuid_recv_user_info, state);
+}
+
+/* Receive the user info struct and get the gid for the user */
+
+static void cmd_getpwuid_recv_user_info(struct composite_context *ctx)
+{
+ struct cmd_getpwuid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getpwuid_state);
+ struct libnet_UserInfo *user_info;
+ struct winbindd_pw *pw;
+
+ DEBUG(5, ("cmd_getpwuid_recv_user_info called\n"));
+
+ pw = talloc(state, struct winbindd_pw);
+ if (composite_nomem(pw, state->ctx)) return;
+
+ user_info = talloc(state, struct libnet_UserInfo);
+ if(composite_nomem(user_info, state->ctx)) return;
+
+ state->ctx->status = libnet_UserInfo_recv(ctx, state, user_info);
+ if (!composite_is_ok(state->ctx)) return;
+
+ WBSRV_SAMBA3_SET_STRING(pw->pw_name, user_info->out.account_name);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_passwd, "*");
+ WBSRV_SAMBA3_SET_STRING(pw->pw_gecos, user_info->out.full_name);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_dir,
+ lp_template_homedir(state->service->task->lp_ctx));
+ all_string_sub(pw->pw_dir, "%WORKGROUP%", state->workgroup,
+ sizeof(fstring) - 1);
+ all_string_sub(pw->pw_dir, "%ACCOUNTNAME%", user_info->out.account_name,
+ sizeof(fstring) - 1);
+ WBSRV_SAMBA3_SET_STRING(pw->pw_shell,
+ lp_template_shell(state->service->task->lp_ctx));
+
+ pw->pw_uid = state->uid;
+
+ state->result = pw;
+
+ ctx = wb_sid2gid_send(state, state->service,
+ user_info->out.primary_group_sid);
+
+ composite_continue(state->ctx, ctx, cmd_getpwuid_recv_gid, state);
+}
+
+static void cmd_getpwuid_recv_gid(struct composite_context *ctx)
+{
+ struct cmd_getpwuid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_getpwuid_state);
+ gid_t gid;
+
+ DEBUG(5, ("cmd_getpwuid_recv_gid called\n"));
+
+ state->ctx->status = wb_sid2gid_recv(ctx, &gid);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->result->pw_gid = gid;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_getpwuid_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx, struct winbindd_pw **pw)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_getpwnam_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_getpwuid_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_getpwuid_state);
+ *pw = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(ctx);
+ return status;
+
+}
+
diff --git a/source4/winbind/wb_cmd_list_trustdom.c b/source4/winbind/wb_cmd_list_trustdom.c
new file mode 100644
index 0000000000..fe98ce2f6a
--- /dev/null
+++ b/source4/winbind/wb_cmd_list_trustdom.c
@@ -0,0 +1,196 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -m
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+
+/* List trusted domains. To avoid the trouble with having to wait for other
+ * conflicting requests waiting for the lsa pipe we're opening our own lsa
+ * pipe here. */
+
+struct cmd_list_trustdom_state {
+ struct composite_context *ctx;
+ struct dcerpc_pipe *lsa_pipe;
+ struct policy_handle *lsa_policy;
+ int num_domains;
+ struct wb_dom_info **domains;
+
+ uint32_t resume_handle;
+ struct lsa_DomainList domainlist;
+ struct lsa_EnumTrustDom r;
+};
+
+static void cmd_list_trustdoms_recv_domain(struct composite_context *ctx);
+static void cmd_list_trustdoms_recv_lsa(struct composite_context *ctx);
+static void cmd_list_trustdoms_recv_doms(struct rpc_request *req);
+
+struct composite_context *wb_cmd_list_trustdoms_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_list_trustdom_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_list_trustdom_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (ctx == NULL) goto failed;
+ ctx->async.fn = cmd_list_trustdoms_recv_domain;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void cmd_list_trustdoms_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_list_trustdom_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_list_trustdom_state);
+ struct wbsrv_domain *domain;
+ struct smbcli_tree *tree;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ tree = dcerpc_smb_tree(domain->libnet_ctx->lsa.pipe->conn);
+ if (composite_nomem(tree, state->ctx)) return;
+
+ ctx = wb_init_lsa_send(state, domain);
+ composite_continue(state->ctx, ctx, cmd_list_trustdoms_recv_lsa,
+ state);
+}
+
+static void cmd_list_trustdoms_recv_lsa(struct composite_context *ctx)
+{
+ struct cmd_list_trustdom_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_list_trustdom_state);
+ struct rpc_request *req;
+
+ state->ctx->status = wb_init_lsa_recv(ctx, state,
+ &state->lsa_pipe,
+ &state->lsa_policy);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->num_domains = 0;
+ state->domains = NULL;
+
+ state->domainlist.count = 0;
+ state->domainlist.domains = NULL;
+
+ state->resume_handle = 0;
+ state->r.in.handle = state->lsa_policy;
+ state->r.in.resume_handle = &state->resume_handle;
+ state->r.in.max_size = 1000;
+ state->r.out.resume_handle = &state->resume_handle;
+ state->r.out.domains = &state->domainlist;
+
+ req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->r);
+ composite_continue_rpc(state->ctx, req, cmd_list_trustdoms_recv_doms,
+ state);
+}
+
+static void cmd_list_trustdoms_recv_doms(struct rpc_request *req)
+{
+ struct cmd_list_trustdom_state *state =
+ talloc_get_type(req->async.private_data,
+ struct cmd_list_trustdom_state);
+ int i, old_num_domains;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->r.out.result;
+
+ if (!NT_STATUS_IS_OK(state->ctx->status) &&
+ !NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_NO_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(state->ctx->status, STATUS_MORE_ENTRIES)) {
+ composite_error(state->ctx, state->ctx->status);
+ return;
+ }
+
+ old_num_domains = state->num_domains;
+
+ state->num_domains += state->r.out.domains->count;
+ state->domains = talloc_realloc(state, state->domains,
+ struct wb_dom_info *,
+ state->num_domains);
+ if (state->num_domains &&
+ composite_nomem(state->domains, state->ctx)) return;
+
+ for (i=0; i<state->r.out.domains->count; i++) {
+ int j = i+old_num_domains;
+ state->domains[j] = talloc(state->domains,
+ struct wb_dom_info);
+ if (composite_nomem(state->domains[i], state->ctx)) return;
+ state->domains[j]->name = talloc_steal(
+ state->domains[j],
+ state->r.out.domains->domains[i].name.string);
+ state->domains[j]->sid = talloc_steal(
+ state->domains[j],
+ state->r.out.domains->domains[i].sid);
+ }
+
+ if (NT_STATUS_IS_OK(state->ctx->status) || NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_NO_MORE_ENTRIES)) {
+ state->ctx->status = NT_STATUS_OK;
+ composite_done(state->ctx);
+ return;
+ }
+
+ state->domainlist.count = 0;
+ state->domainlist.domains = NULL;
+ state->r.in.handle = state->lsa_policy;
+ state->r.in.resume_handle = &state->resume_handle;
+ state->r.in.max_size = 1000;
+ state->r.out.resume_handle = &state->resume_handle;
+ state->r.out.domains = &state->domainlist;
+
+ req = dcerpc_lsa_EnumTrustDom_send(state->lsa_pipe, state, &state->r);
+ composite_continue_rpc(state->ctx, req, cmd_list_trustdoms_recv_doms,
+ state);
+}
+
+NTSTATUS wb_cmd_list_trustdoms_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ int *num_domains,
+ struct wb_dom_info ***domains)
+{
+ NTSTATUS status = composite_wait(ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_list_trustdom_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_list_trustdom_state);
+ *num_domains = state->num_domains;
+ *domains = talloc_steal(mem_ctx, state->domains);
+ }
+ talloc_free(ctx);
+ return status;
+}
diff --git a/source4/winbind/wb_cmd_list_users.c b/source4/winbind/wb_cmd_list_users.c
new file mode 100644
index 0000000000..f67f133488
--- /dev/null
+++ b/source4/winbind/wb_cmd_list_users.c
@@ -0,0 +1,198 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -u
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libnet/libnet_proto.h"
+
+struct cmd_list_users_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+
+ struct wbsrv_domain *domain;
+ char *domain_name;
+ uint resume_index;
+ char *result;
+};
+
+static void cmd_list_users_recv_domain(struct composite_context *ctx);
+static void cmd_list_users_recv_user_list(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_list_users_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, const char *domain_name)
+{
+ struct composite_context *ctx, *result;
+ struct cmd_list_users_state *state;
+
+ DEBUG(5, ("wb_cmd_list_users_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct cmd_list_users_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->resume_index = 0;
+ state->result = talloc_strdup(state, "");
+ if (composite_nomem(state->result, state->ctx)) return result;
+
+ /*FIXME: We should look up the domain in the winbind request if it is
+ * set, not just take the primary domain. However, I want to get the
+ * libnet logic to work first. */
+
+ if (domain_name && *domain_name != '\0') {
+ state->domain_name = talloc_strdup(state, domain_name);
+ if (composite_nomem(state->domain_name, state->ctx))
+ return result;
+ } else {
+ state->domain_name = NULL;
+ }
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (composite_nomem(ctx, state->ctx)) return result;
+
+ composite_continue(state->ctx, ctx, cmd_list_users_recv_domain, state);
+ return result;
+}
+
+static void cmd_list_users_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_list_users_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_list_users_state);
+ struct wbsrv_domain *domain;
+ struct libnet_UserList *user_list;
+
+ DEBUG(5, ("cmd_list_users_recv_domain called\n"));
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->domain = domain;
+
+ /* If this is non-null, we've looked up the domain given in the winbind
+ * request, otherwise we'll just use the default name.*/
+ if (state->domain_name == NULL) {
+ state->domain_name = talloc_strdup(state,
+ domain->libnet_ctx->samr.name);
+ if (composite_nomem(state->domain_name, state->ctx)) return;
+ }
+
+ user_list = talloc(state, struct libnet_UserList);
+ if (composite_nomem(user_list, state->ctx)) return;
+
+ user_list->in.domain_name = state->domain_name;
+
+ /* Rafal suggested that 128 is a good number here. I don't like magic
+ * numbers too much, but for now it'll have to do.
+ */
+ user_list->in.page_size = 128;
+ user_list->in.resume_index = state->resume_index;
+
+ ctx = libnet_UserList_send(domain->libnet_ctx, state, user_list, NULL);
+
+ composite_continue(state->ctx, ctx, cmd_list_users_recv_user_list,
+ state);
+}
+
+static void cmd_list_users_recv_user_list(struct composite_context *ctx)
+{
+ struct cmd_list_users_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_list_users_state);
+ struct libnet_UserList *user_list;
+ NTSTATUS status;
+ int i;
+
+ DEBUG(5, ("cmd_list_users_recv_user_list called\n"));
+
+ user_list = talloc(state, struct libnet_UserList);
+ if (composite_nomem(user_list, state->ctx)) return;
+
+ status = libnet_UserList_recv(ctx, state, user_list);
+
+ /* If NTSTATUS is neither OK nor MORE_ENTRIES, something broke */
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ composite_error(state->ctx, status);
+ return;
+ }
+
+ for (i = 0; i < user_list->out.count; ++i) {
+ DEBUG(5, ("Appending user '%s'\n", user_list->out.users[i].username));
+ state->result = talloc_asprintf_append_buffer(state->result, "%s,",
+ user_list->out.users[i].username);
+ }
+
+ /* If the status is OK, we're finished, there's no more users.
+ * So we'll trim off the trailing ',' and are done.*/
+ if (NT_STATUS_IS_OK(status)) {
+ int str_len = strlen(state->result);
+ DEBUG(5, ("list_UserList_recv returned NT_STATUS_OK\n"));
+ state->result[str_len - 1] = '\0';
+ composite_done(state->ctx);
+ return;
+ }
+
+ DEBUG(5, ("list_UserList_recv returned NT_STATUS_MORE_ENTRIES\n"));
+
+ /* Otherwise there's more users to get, so call out to libnet and
+ * continue on this function here. */
+
+ user_list->in.domain_name = state->domain_name;
+ /* See comment above about the page size. 128 seems like a good default.
+ */
+ user_list->in.page_size = 128;
+ user_list->in.resume_index = user_list->out.resume_index;
+
+ ctx = libnet_UserList_send(state->domain->libnet_ctx, state, user_list,
+ NULL);
+
+ composite_continue(state->ctx, ctx, cmd_list_users_recv_user_list,
+ state);
+}
+
+NTSTATUS wb_cmd_list_users_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx, uint32_t *extra_data_len,
+ char **extra_data)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_list_users_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_list_users_state *state = talloc_get_type(
+ ctx->private_data, struct cmd_list_users_state);
+
+ *extra_data_len = strlen(state->result);
+ *extra_data = talloc_steal(mem_ctx, state->result);
+ }
+
+ talloc_free(ctx);
+ return status;
+}
+
+
diff --git a/source4/winbind/wb_cmd_lookupname.c b/source4/winbind/wb_cmd_lookupname.c
new file mode 100644
index 0000000000..9839e2cd80
--- /dev/null
+++ b/source4/winbind/wb_cmd_lookupname.c
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -n
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+
+struct cmd_lookupname_state {
+ struct composite_context *ctx;
+ const char *name;
+ struct wb_sid_object *result;
+};
+
+static void lookupname_recv_domain(struct composite_context *ctx);
+static void lookupname_recv_sids(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_lookupname_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *dom_name,
+ const char *name)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_lookupname_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_lookupname_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->name = talloc_asprintf(state, "%s\\%s", dom_name, name);
+ if (state->name == NULL) goto failed;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = lookupname_recv_domain;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void lookupname_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_lookupname_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_lookupname_state);
+ struct wbsrv_domain *domain;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_lsa_lookupnames_send(state, domain->libnet_ctx->lsa.pipe,
+ &domain->libnet_ctx->lsa.handle, 1, &state->name);
+ composite_continue(state->ctx, ctx, lookupname_recv_sids, state);
+}
+
+static void lookupname_recv_sids(struct composite_context *ctx)
+{
+ struct cmd_lookupname_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_lookupname_state);
+ struct wb_sid_object **sids;
+
+ state->ctx->status = wb_lsa_lookupnames_recv(ctx, state, &sids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->result = sids[0];
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_lookupname_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct wb_sid_object **sid)
+{
+ struct cmd_lookupname_state *state =
+ talloc_get_type(c->private_data, struct cmd_lookupname_state);
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ *sid = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(state);
+ return status;
+}
+
+NTSTATUS wb_cmd_lookupname(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *dom_name,
+ const char *name,
+ struct wb_sid_object **sid)
+{
+ struct composite_context *c =
+ wb_cmd_lookupname_send(mem_ctx, service, dom_name, name);
+ return wb_cmd_lookupname_recv(c, mem_ctx, sid);
+}
diff --git a/source4/winbind/wb_cmd_lookupsid.c b/source4/winbind/wb_cmd_lookupsid.c
new file mode 100644
index 0000000000..2d72ae2072
--- /dev/null
+++ b/source4/winbind/wb_cmd_lookupsid.c
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -s
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libcli/security/security.h"
+
+struct cmd_lookupsid_state {
+ struct composite_context *ctx;
+ const struct dom_sid *sid;
+ struct wb_sid_object *result;
+};
+
+static void lookupsid_recv_domain(struct composite_context *ctx);
+static void lookupsid_recv_names(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_lookupsid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_lookupsid_state *state;
+
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_lookupsid_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->sid = dom_sid_dup(state, sid);
+ if (state->sid == NULL) goto failed;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = lookupsid_recv_domain;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void lookupsid_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_lookupsid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_lookupsid_state);
+ struct wbsrv_domain *domain;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_lsa_lookupsids_send(state, domain->libnet_ctx->lsa.pipe,
+ &domain->libnet_ctx->lsa.handle, 1, &state->sid);
+ composite_continue(state->ctx, ctx, lookupsid_recv_names, state);
+}
+
+static void lookupsid_recv_names(struct composite_context *ctx)
+{
+ struct cmd_lookupsid_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_lookupsid_state);
+ struct wb_sid_object **names;
+
+ state->ctx->status = wb_lsa_lookupsids_recv(ctx, state, &names);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->result = names[0];
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_lookupsid_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct wb_sid_object **sid)
+{
+ struct cmd_lookupsid_state *state =
+ talloc_get_type(c->private_data, struct cmd_lookupsid_state);
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ *sid = talloc_steal(mem_ctx, state->result);
+ }
+ talloc_free(state);
+ return status;
+}
+
+NTSTATUS wb_cmd_lookupsid(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
+ const struct dom_sid *sid,
+ struct wb_sid_object **name)
+{
+ struct composite_context *c =
+ wb_cmd_lookupsid_send(mem_ctx, service, sid);
+ return wb_cmd_lookupsid_recv(c, mem_ctx, name);
+}
diff --git a/source4/winbind/wb_cmd_setpwent.c b/source4/winbind/wb_cmd_setpwent.c
new file mode 100644
index 0000000000..50ab2fdff6
--- /dev/null
+++ b/source4/winbind/wb_cmd_setpwent.c
@@ -0,0 +1,142 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for setpwent
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "libnet/libnet_proto.h"
+
+struct cmd_setpwent_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct libnet_context *libnet_ctx;
+
+ struct wbsrv_pwent *result;
+};
+
+static void cmd_setpwent_recv_domain(struct composite_context *ctx);
+static void cmd_setpwent_recv_user_list(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_setpwent_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service)
+{
+ struct composite_context *ctx, *result;
+ struct cmd_setpwent_state *state;
+
+ DEBUG(5, ("wb_cmd_setpwent_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(mem_ctx, struct cmd_setpwent_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ state->result = talloc(state, struct wbsrv_pwent);
+ if (composite_nomem(state->result, state->ctx)) return result;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (composite_nomem(ctx, state->ctx)) return result;
+
+ composite_continue(state->ctx, ctx, cmd_setpwent_recv_domain, state);
+ return result;
+}
+
+static void cmd_setpwent_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_setpwent_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_setpwent_state);
+ struct wbsrv_domain *domain;
+ struct libnet_UserList *user_list;
+
+ DEBUG(5, ("cmd_setpwent_recv_domain called\n"));
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->libnet_ctx = domain->libnet_ctx;
+
+ user_list = talloc(state->result, struct libnet_UserList);
+ if (composite_nomem(user_list, state->ctx)) return;
+
+ user_list->in.domain_name = talloc_strdup(state,
+ domain->libnet_ctx->samr.name);
+ if (composite_nomem(user_list->in.domain_name, state->ctx)) return;
+
+ /* Page size recommended by Rafal */
+ user_list->in.page_size = 128;
+
+ /* Always get the start of the list */
+ user_list->in.resume_index = 0;
+
+ ctx = libnet_UserList_send(domain->libnet_ctx, state->result, user_list,
+ NULL);
+
+ composite_continue(state->ctx, ctx, cmd_setpwent_recv_user_list, state);
+}
+
+static void cmd_setpwent_recv_user_list(struct composite_context *ctx)
+{
+ struct cmd_setpwent_state *state = talloc_get_type(
+ ctx->async.private_data, struct cmd_setpwent_state);
+ struct libnet_UserList *user_list;
+
+ DEBUG(5, ("cmd_setpwent_recv_user_list called\n"));
+
+ user_list = talloc(state->result, struct libnet_UserList);
+ if (composite_nomem(user_list, state->ctx)) return;
+
+ state->ctx->status = libnet_UserList_recv(ctx, state->result,
+ user_list);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->result->user_list = user_list;
+ state->result->page_index = 0;
+ state->result->libnet_ctx = state->libnet_ctx;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_setpwent_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx, struct wbsrv_pwent **pwent)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_cmd_setpwent_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_setpwent_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_setpwent_state);
+
+ *pwent = talloc_steal(mem_ctx, state->result);
+ }
+
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_cmd_userdomgroups.c b/source4/winbind/wb_cmd_userdomgroups.c
new file mode 100644
index 0000000000..649fe489cc
--- /dev/null
+++ b/source4/winbind/wb_cmd_userdomgroups.c
@@ -0,0 +1,147 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo --user-domgroups
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "libcli/security/security.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+
+struct cmd_userdomgroups_state {
+ struct composite_context *ctx;
+ struct dom_sid *dom_sid;
+ uint32_t user_rid;
+ int num_rids;
+ uint32_t *rids;
+};
+
+static void userdomgroups_recv_domain(struct composite_context *ctx);
+static void userdomgroups_recv_rids(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_userdomgroups_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_userdomgroups_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_userdomgroups_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->dom_sid = dom_sid_dup(state, sid);
+ if (state->dom_sid == NULL) goto failed;
+ state->dom_sid->num_auths -= 1;
+
+ state->user_rid = sid->sub_auths[sid->num_auths-1];
+
+ ctx = wb_sid2domain_send(state, service, sid);
+
+ composite_continue(state->ctx, ctx, userdomgroups_recv_domain, state);
+
+ if (ctx) {
+ return result;
+ }
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void userdomgroups_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_userdomgroups_state);
+ struct wbsrv_domain *domain;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_samr_userdomgroups_send(state, domain->libnet_ctx->samr.pipe,
+ &domain->libnet_ctx->samr.handle,
+ state->user_rid);
+ composite_continue(state->ctx, ctx, userdomgroups_recv_rids, state);
+
+}
+
+static void userdomgroups_recv_rids(struct composite_context *ctx)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_userdomgroups_state);
+
+ state->ctx->status = wb_samr_userdomgroups_recv(ctx, state,
+ &state->num_rids,
+ &state->rids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_userdomgroups_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ int *num_sids, struct dom_sid ***sids)
+{
+ struct cmd_userdomgroups_state *state =
+ talloc_get_type(c->private_data,
+ struct cmd_userdomgroups_state);
+ int i;
+ NTSTATUS status;
+
+ status = composite_wait(c);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ *num_sids = state->num_rids;
+ *sids = talloc_array(mem_ctx, struct dom_sid *, state->num_rids);
+ if (*sids == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<state->num_rids; i++) {
+ (*sids)[i] = dom_sid_add_rid((*sids), state->dom_sid,
+ state->rids[i]);
+ if ((*sids)[i] == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+done:
+ talloc_free(c);
+ return status;
+}
+
+NTSTATUS wb_cmd_userdomgroups(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const struct dom_sid *sid,
+ int *num_sids, struct dom_sid ***sids)
+{
+ struct composite_context *c =
+ wb_cmd_userdomgroups_send(mem_ctx, service, sid);
+ return wb_cmd_userdomgroups_recv(c, mem_ctx, num_sids, sids);
+}
diff --git a/source4/winbind/wb_cmd_usersids.c b/source4/winbind/wb_cmd_usersids.c
new file mode 100644
index 0000000000..b414cf6313
--- /dev/null
+++ b/source4/winbind/wb_cmd_usersids.c
@@ -0,0 +1,193 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo --user-sids
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "libcli/security/security.h"
+
+/* Calculate the token in two steps: Go the user's originating domain, ask for
+ * the user's domain groups. Then with the resulting list of sids go to our
+ * own domain to expand the aliases aka domain local groups. */
+
+struct cmd_usersids_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct dom_sid *user_sid;
+ int num_domgroups;
+ struct dom_sid **domgroups;
+
+ struct lsa_SidArray lsa_sids;
+ struct samr_Ids rids;
+ struct samr_GetAliasMembership r;
+
+ int num_sids;
+ struct dom_sid **sids;
+};
+
+static void usersids_recv_domgroups(struct composite_context *ctx);
+static void usersids_recv_domain(struct composite_context *ctx);
+static void usersids_recv_aliases(struct rpc_request *req);
+
+struct composite_context *wb_cmd_usersids_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct cmd_usersids_state *state;
+
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct cmd_usersids_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->service = service;
+ state->user_sid = dom_sid_dup(state, sid);
+ if (state->user_sid == NULL) goto failed;
+
+ ctx = wb_cmd_userdomgroups_send(state, service, sid);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = usersids_recv_domgroups;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void usersids_recv_domgroups(struct composite_context *ctx)
+{
+ struct cmd_usersids_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_usersids_state);
+
+ state->ctx->status = wb_cmd_userdomgroups_recv(ctx, state,
+ &state->num_domgroups,
+ &state->domgroups);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_sid2domain_send(state, state->service,
+ state->service->primary_sid);
+ composite_continue(state->ctx, ctx, usersids_recv_domain, state);
+}
+
+static void usersids_recv_domain(struct composite_context *ctx)
+{
+ struct cmd_usersids_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct cmd_usersids_state);
+ struct rpc_request *req;
+ struct wbsrv_domain *domain;
+ int i;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->lsa_sids.num_sids = state->num_domgroups+1;
+ state->lsa_sids.sids = talloc_array(state, struct lsa_SidPtr,
+ state->lsa_sids.num_sids);
+ if (composite_nomem(state->lsa_sids.sids, state->ctx)) return;
+
+ state->lsa_sids.sids[0].sid = state->user_sid;
+ for (i=0; i<state->num_domgroups; i++) {
+ state->lsa_sids.sids[i+1].sid = state->domgroups[i];
+ }
+
+ state->rids.count = 0;
+ state->rids.ids = NULL;
+
+ state->r.in.domain_handle = &domain->libnet_ctx->samr.handle;
+ state->r.in.sids = &state->lsa_sids;
+ state->r.out.rids = &state->rids;
+
+ req = dcerpc_samr_GetAliasMembership_send(domain->libnet_ctx->samr.pipe, state,
+ &state->r);
+ composite_continue_rpc(state->ctx, req, usersids_recv_aliases, state);
+}
+
+static void usersids_recv_aliases(struct rpc_request *req)
+{
+ struct cmd_usersids_state *state =
+ talloc_get_type(req->async.private_data,
+ struct cmd_usersids_state);
+ int i;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->r.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->num_sids = 1 + state->num_domgroups + state->r.out.rids->count;
+ state->sids = talloc_array(state, struct dom_sid *, state->num_sids);
+ if (composite_nomem(state->sids, state->ctx)) return;
+
+ state->sids[0] = talloc_steal(state->sids, state->user_sid);
+
+ for (i=0; i<state->num_domgroups; i++) {
+ state->sids[1+i] =
+ talloc_steal(state->sids, state->domgroups[i]);
+ }
+
+ for (i=0; i<state->r.out.rids->count; i++) {
+ state->sids[1+state->num_domgroups+i] = dom_sid_add_rid(
+ state->sids, state->service->primary_sid,
+ state->r.out.rids->ids[i]);
+
+ if (composite_nomem(state->sids[1+state->num_domgroups+i],
+ state->ctx)) return;
+ }
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_cmd_usersids_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ int *num_sids, struct dom_sid ***sids)
+{
+ NTSTATUS status = composite_wait(ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ struct cmd_usersids_state *state =
+ talloc_get_type(ctx->private_data,
+ struct cmd_usersids_state);
+ *num_sids = state->num_sids;
+ *sids = talloc_steal(mem_ctx, state->sids);
+ }
+ talloc_free(ctx);
+ return status;
+}
+
+NTSTATUS wb_cmd_usersids(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
+ const struct dom_sid *sid,
+ int *num_sids, struct dom_sid ***sids)
+{
+ struct composite_context *c =
+ wb_cmd_usersids_send(mem_ctx, service, sid);
+ return wb_cmd_usersids_recv(c, mem_ctx, num_sids, sids);
+}
+
diff --git a/source4/winbind/wb_connect_lsa.c b/source4/winbind/wb_connect_lsa.c
new file mode 100644
index 0000000000..a728f8abe4
--- /dev/null
+++ b/source4/winbind/wb_connect_lsa.c
@@ -0,0 +1,135 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Connect to the LSA pipe, given an smbcli_tree and possibly some
+ credentials. Try ntlmssp, schannel and anon in that order.
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+
+#include "libcli/raw/libcliraw.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "winbind/wb_server.h"
+
+/* Helper to initialize LSA with a specific auth methods. Verify by opening
+ * the LSA policy. */
+
+struct init_lsa_state {
+ struct composite_context *ctx;
+ struct dcerpc_pipe *lsa_pipe;
+
+ uint8_t auth_type;
+ struct cli_credentials *creds;
+
+ struct lsa_ObjectAttribute objectattr;
+ struct lsa_OpenPolicy2 openpolicy;
+ struct policy_handle *handle;
+};
+
+static void init_lsa_recv_pipe(struct composite_context *ctx);
+static void init_lsa_recv_openpol(struct rpc_request *req);
+
+struct composite_context *wb_init_lsa_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_domain *domain)
+{
+ struct composite_context *result, *ctx;
+ struct init_lsa_state *state;
+
+ result = composite_create(mem_ctx, domain->netlogon_pipe->conn->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct init_lsa_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ /* this will make the secondary connection on the same IPC$ share,
+ secured with SPNEGO or NTLMSSP */
+ ctx = dcerpc_secondary_auth_connection_send(domain->netlogon_pipe,
+ domain->lsa_binding,
+ &ndr_table_lsarpc,
+ domain->libnet_ctx->cred,
+ domain->libnet_ctx->lp_ctx);
+ composite_continue(state->ctx, ctx, init_lsa_recv_pipe, state);
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void init_lsa_recv_pipe(struct composite_context *ctx)
+{
+ struct rpc_request *req;
+ struct init_lsa_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct init_lsa_state);
+
+ state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state,
+ &state->lsa_pipe);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->handle = talloc(state, struct policy_handle);
+ if (composite_nomem(state->handle, state->ctx)) return;
+
+ state->openpolicy.in.system_name =
+ talloc_asprintf(state, "\\\\%s",
+ dcerpc_server_name(state->lsa_pipe));
+ ZERO_STRUCT(state->objectattr);
+ state->openpolicy.in.attr = &state->objectattr;
+ state->openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->openpolicy.out.handle = state->handle;
+
+ req = dcerpc_lsa_OpenPolicy2_send(state->lsa_pipe, state,
+ &state->openpolicy);
+ composite_continue_rpc(state->ctx, req, init_lsa_recv_openpol, state);
+}
+
+static void init_lsa_recv_openpol(struct rpc_request *req)
+{
+ struct init_lsa_state *state =
+ talloc_get_type(req->async.private_data,
+ struct init_lsa_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->openpolicy.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_init_lsa_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe **lsa_pipe,
+ struct policy_handle **lsa_policy)
+{
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct init_lsa_state *state =
+ talloc_get_type(c->private_data,
+ struct init_lsa_state);
+ *lsa_pipe = talloc_steal(mem_ctx, state->lsa_pipe);
+ *lsa_policy = talloc_steal(mem_ctx, state->handle);
+ }
+ talloc_free(c);
+ return status;
+}
+
diff --git a/source4/winbind/wb_connect_sam.c b/source4/winbind/wb_connect_sam.c
new file mode 100644
index 0000000000..efd715b164
--- /dev/null
+++ b/source4/winbind/wb_connect_sam.c
@@ -0,0 +1,164 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Connect to the SAMR pipe, and return connection and domain handles.
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+
+#include "libcli/raw/libcliraw.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "winbind/wb_server.h"
+
+
+/* Helper to initialize SAMR with a specific auth methods. Verify by opening
+ * the SAM handle */
+
+struct connect_samr_state {
+ struct composite_context *ctx;
+ struct dom_sid *sid;
+
+ struct dcerpc_pipe *samr_pipe;
+ struct policy_handle *connect_handle;
+ struct policy_handle *domain_handle;
+
+ struct samr_Connect2 c;
+ struct samr_OpenDomain o;
+};
+
+static void connect_samr_recv_pipe(struct composite_context *ctx);
+static void connect_samr_recv_conn(struct rpc_request *req);
+static void connect_samr_recv_open(struct rpc_request *req);
+
+struct composite_context *wb_connect_samr_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_domain *domain)
+{
+ struct composite_context *result, *ctx;
+ struct connect_samr_state *state;
+
+ result = composite_create(mem_ctx, domain->netlogon_pipe->conn->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct connect_samr_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->sid = dom_sid_dup(state, domain->info->sid);
+ if (state->sid == NULL) goto failed;
+
+ /* this will make the secondary connection on the same IPC$ share,
+ secured with SPNEGO, NTLMSSP or SCHANNEL */
+ ctx = dcerpc_secondary_auth_connection_send(domain->netlogon_pipe,
+ domain->samr_binding,
+ &ndr_table_samr,
+ domain->libnet_ctx->cred,
+ domain->libnet_ctx->lp_ctx);
+ composite_continue(state->ctx, ctx, connect_samr_recv_pipe, state);
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void connect_samr_recv_pipe(struct composite_context *ctx)
+{
+ struct rpc_request *req;
+ struct connect_samr_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct connect_samr_state);
+
+ state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state,
+ &state->samr_pipe);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->connect_handle = talloc(state, struct policy_handle);
+ if (composite_nomem(state->connect_handle, state->ctx)) return;
+
+ state->c.in.system_name =
+ talloc_asprintf(state, "\\\\%s",
+ dcerpc_server_name(state->samr_pipe));
+ state->c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->c.out.connect_handle = state->connect_handle;
+
+ req = dcerpc_samr_Connect2_send(state->samr_pipe, state, &state->c);
+ composite_continue_rpc(state->ctx, req, connect_samr_recv_conn, state);
+ return;
+}
+
+static void connect_samr_recv_conn(struct rpc_request *req)
+{
+ struct connect_samr_state *state =
+ talloc_get_type(req->async.private_data,
+ struct connect_samr_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->c.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->domain_handle = talloc(state, struct policy_handle);
+ if (composite_nomem(state->domain_handle, state->ctx)) return;
+
+ state->o.in.connect_handle = state->connect_handle;
+ state->o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->o.in.sid = state->sid;
+ state->o.out.domain_handle = state->domain_handle;
+
+ req = dcerpc_samr_OpenDomain_send(state->samr_pipe, state, &state->o);
+ composite_continue_rpc(state->ctx, req,
+ connect_samr_recv_open, state);
+}
+
+static void connect_samr_recv_open(struct rpc_request *req)
+{
+ struct connect_samr_state *state =
+ talloc_get_type(req->async.private_data,
+ struct connect_samr_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->o.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_connect_samr_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct dcerpc_pipe **samr_pipe,
+ struct policy_handle *connect_handle,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct connect_samr_state *state =
+ talloc_get_type(c->private_data,
+ struct connect_samr_state);
+ *samr_pipe = talloc_steal(mem_ctx, state->samr_pipe);
+ *connect_handle = *state->connect_handle;
+ *domain_handle = *state->domain_handle;
+ }
+ talloc_free(c);
+ return status;
+}
+
diff --git a/source4/winbind/wb_dom_info.c b/source4/winbind/wb_dom_info.c
new file mode 100644
index 0000000000..4fcbf3a6e5
--- /dev/null
+++ b/source4/winbind/wb_dom_info.c
@@ -0,0 +1,126 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Get a struct wb_dom_info for a domain using DNS, netbios, possibly cldap
+ etc.
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/security/security.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_irpc.h"
+#include "librpc/gen_ndr/samr.h"
+#include "lib/messaging/irpc.h"
+#include "libcli/finddcs.h"
+#include "param/param.h"
+
+struct get_dom_info_state {
+ struct composite_context *ctx;
+ struct wb_dom_info *info;
+};
+
+static void get_dom_info_recv_addrs(struct composite_context *ctx);
+
+struct composite_context *wb_get_dom_info_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *domain_name,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct get_dom_info_state *state;
+ struct dom_sid *dom_sid;
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct get_dom_info_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->info = talloc_zero(state, struct wb_dom_info);
+ if (state->info == NULL) goto failed;
+
+ state->info->name = talloc_strdup(state->info, domain_name);
+ if (state->info->name == NULL) goto failed;
+
+ state->info->sid = dom_sid_dup(state->info, sid);
+ if (state->info->sid == NULL) goto failed;
+
+ dom_sid = dom_sid_dup(mem_ctx, sid);
+ if (dom_sid == NULL) goto failed;
+
+ ctx = finddcs_send(mem_ctx, lp_netbios_name(service->task->lp_ctx),
+ lp_nbt_port(service->task->lp_ctx),
+ domain_name, NBT_NAME_LOGON,
+ dom_sid,
+ lp_iconv_convenience(service->task->lp_ctx),
+ lp_resolve_context(service->task->lp_ctx),
+ service->task->event_ctx,
+ service->task->msg_ctx);
+ if (ctx == NULL) goto failed;
+
+ composite_continue(state->ctx, ctx, get_dom_info_recv_addrs, state);
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void get_dom_info_recv_addrs(struct composite_context *ctx)
+{
+ struct get_dom_info_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct get_dom_info_state);
+
+ state->ctx->status = finddcs_recv(ctx, state->info,
+ &state->info->num_dcs,
+ &state->info->dcs);
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_get_dom_info_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct wb_dom_info **result)
+{
+ NTSTATUS status = composite_wait(ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ struct get_dom_info_state *state =
+ talloc_get_type(ctx->private_data,
+ struct get_dom_info_state);
+ *result = talloc_steal(mem_ctx, state->info);
+ }
+ talloc_free(ctx);
+ return status;
+}
+
+NTSTATUS wb_get_dom_info(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *domain_name,
+ const struct dom_sid *sid,
+ struct wb_dom_info **result)
+{
+ struct composite_context *ctx =
+ wb_get_dom_info_send(mem_ctx, service, domain_name, sid);
+ return wb_get_dom_info_recv(ctx, mem_ctx, result);
+}
diff --git a/source4/winbind/wb_dom_info_trusted.c b/source4/winbind/wb_dom_info_trusted.c
new file mode 100644
index 0000000000..46d3bf37f6
--- /dev/null
+++ b/source4/winbind/wb_dom_info_trusted.c
@@ -0,0 +1,239 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Get a struct wb_dom_info for a trusted domain, relying on "our" DC.
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "libcli/resolve/resolve.h"
+#include "libcli/security/security.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "libcli/libcli.h"
+#include "param/param.h"
+
+struct trusted_dom_info_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct wbsrv_domain *my_domain;
+
+ struct netr_DsRGetDCName d;
+ struct netr_GetAnyDCName g;
+
+ struct wb_dom_info *info;
+};
+
+static void trusted_dom_info_recv_domain(struct composite_context *ctx);
+static void trusted_dom_info_recv_dsr(struct rpc_request *req);
+static void trusted_dom_info_recv_dcname(struct rpc_request *req);
+static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx);
+
+struct composite_context *wb_trusted_dom_info_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *domain_name,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct trusted_dom_info_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct trusted_dom_info_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->info = talloc_zero(state, struct wb_dom_info);
+ if (state->info == NULL) goto failed;
+
+ state->service = service;
+
+ state->info->sid = dom_sid_dup(state->info, sid);
+ if (state->info->sid == NULL) goto failed;
+
+ state->info->name = talloc_strdup(state->info, domain_name);
+ if (state->info->name == NULL) goto failed;
+
+ ctx = wb_sid2domain_send(state, service, service->primary_sid);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = trusted_dom_info_recv_domain;
+ ctx->async.private_data = state;
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void trusted_dom_info_recv_domain(struct composite_context *ctx)
+{
+ struct trusted_dom_info_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct trusted_dom_info_state);
+ struct rpc_request *req;
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &state->my_domain);
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->d.in.server_unc =
+ talloc_asprintf(state, "\\\\%s",
+ dcerpc_server_name(state->my_domain->netlogon_pipe));
+ if (composite_nomem(state->d.in.server_unc,
+ state->ctx)) return;
+
+ state->d.in.domain_name = state->info->name;
+ state->d.in.domain_guid = NULL;
+ state->d.in.site_guid = NULL;
+ state->d.in.flags = DS_RETURN_DNS_NAME;
+
+ req = dcerpc_netr_DsRGetDCName_send(state->my_domain->netlogon_pipe,
+ state, &state->d);
+ composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dsr,
+ state);
+}
+
+/*
+ * dcerpc_netr_DsRGetDCName has replied
+ */
+
+static void trusted_dom_info_recv_dsr(struct rpc_request *req)
+{
+ struct trusted_dom_info_state *state =
+ talloc_get_type(req->async.private_data,
+ struct trusted_dom_info_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ DEBUG(9, ("dcerpc_ndr_request_recv returned %s\n",
+ nt_errstr(state->ctx->status)));
+ goto fallback;
+ }
+
+ state->ctx->status =
+ werror_to_ntstatus(state->d.out.result);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ DEBUG(9, ("dsrgetdcname returned %s\n",
+ nt_errstr(state->ctx->status)));
+ goto fallback;
+ }
+
+ /* Hey, that was easy! */
+ state->info->num_dcs = 1;
+ state->info->dcs = talloc(state->info, struct nbt_dc_name);
+ state->info->dcs[0].name = talloc_steal(state->info,
+ state->d.out.info->dc_unc);
+ if (*state->info->dcs[0].name == '\\') state->info->dcs[0].name++;
+ if (*state->info->dcs[0].name == '\\') state->info->dcs[0].name++;
+
+ state->info->dcs[0].address = talloc_steal(state->info,
+ state->d.out.info->dc_address);
+ if (*state->info->dcs[0].address == '\\') state->info->dcs[0].address++;
+ if (*state->info->dcs[0].address == '\\') state->info->dcs[0].address++;
+
+ state->info->dns_name = talloc_steal(state->info,
+ state->d.out.info->domain_name);
+
+ composite_done(state->ctx);
+ return;
+
+ fallback:
+
+ state->g.in.logon_server = talloc_asprintf(
+ state, "\\\\%s",
+ dcerpc_server_name(state->my_domain->netlogon_pipe));
+ state->g.in.domainname = state->info->name;
+
+ req = dcerpc_netr_GetAnyDCName_send(state->my_domain->netlogon_pipe,
+ state, &state->g);
+ if (composite_nomem(req, state->ctx)) return;
+
+ composite_continue_rpc(state->ctx, req, trusted_dom_info_recv_dcname,
+ state);
+}
+
+static void trusted_dom_info_recv_dcname(struct rpc_request *req)
+{
+ struct trusted_dom_info_state *state =
+ talloc_get_type(req->async.private_data,
+ struct trusted_dom_info_state);
+ struct composite_context *ctx;
+ struct nbt_name name;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = werror_to_ntstatus(state->g.out.result);
+ if (!composite_is_ok(state->ctx)) return;
+
+ /* Hey, that was easy! */
+ state->info->num_dcs = 1;
+ state->info->dcs = talloc(state->info, struct nbt_dc_name);
+ state->info->dcs[0].name = talloc_steal(state->info,
+ state->g.out.dcname);
+ if (*state->info->dcs[0].name == '\\') state->info->dcs[0].name++;
+ if (*state->info->dcs[0].name == '\\') state->info->dcs[0].name++;
+
+ make_nbt_name(&name, state->info->dcs[0].name, 0x20);
+ ctx = resolve_name_send(lp_resolve_context(state->service->task->lp_ctx),
+ &name, state->service->task->event_ctx);
+
+ composite_continue(state->ctx, ctx, trusted_dom_info_recv_dcaddr,
+ state);
+}
+
+static void trusted_dom_info_recv_dcaddr(struct composite_context *ctx)
+{
+ struct trusted_dom_info_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct trusted_dom_info_state);
+
+ state->ctx->status = resolve_name_recv(ctx, state->info,
+ &state->info->dcs[0].address);
+ if (!composite_is_ok(state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_trusted_dom_info_recv(struct composite_context *ctx,
+ TALLOC_CTX *mem_ctx,
+ struct wb_dom_info **result)
+{
+ NTSTATUS status = composite_wait(ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ struct trusted_dom_info_state *state =
+ talloc_get_type(ctx->private_data,
+ struct trusted_dom_info_state);
+ *result = talloc_steal(mem_ctx, state->info);
+ }
+ talloc_free(ctx);
+ return status;
+}
+
+NTSTATUS wb_trusted_dom_info(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const char *domain_name,
+ const struct dom_sid *sid,
+ struct wb_dom_info **result)
+{
+ struct composite_context *ctx =
+ wb_trusted_dom_info_send(mem_ctx, service, domain_name, sid);
+ return wb_trusted_dom_info_recv(ctx, mem_ctx, result);
+}
diff --git a/source4/winbind/wb_gid2sid.c b/source4/winbind/wb_gid2sid.c
new file mode 100644
index 0000000000..834d869845
--- /dev/null
+++ b/source4/winbind/wb_gid2sid.c
@@ -0,0 +1,108 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -G
+
+ Copyright (C) 2007-2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct gid2sid_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct dom_sid *sid;
+};
+
+static void gid2sid_recv_sid(struct composite_context *ctx);
+
+struct composite_context *wb_gid2sid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, gid_t gid)
+{
+ struct composite_context *result, *ctx;
+ struct gid2sid_state *state;
+ struct unixid *unixid;
+ struct id_mapping *ids;
+
+ DEBUG(5, ("wb_gid2sid_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct gid2sid_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ unixid = talloc(result, struct unixid);
+ if (composite_nomem(unixid, result)) return result;
+ unixid->id = gid;
+ unixid->type = ID_TYPE_GID;
+
+ ids = talloc(result, struct id_mapping);
+ if (composite_nomem(ids, result)) return result;
+ ids->unixid = unixid;
+ ids->sid = NULL;
+
+ ctx = wb_xids2sids_send(result, service, 1, ids);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, gid2sid_recv_sid, state);
+ return result;
+}
+
+static void gid2sid_recv_sid(struct composite_context *ctx)
+{
+ struct gid2sid_state *state = talloc_get_type(ctx->async.private_data,
+ struct gid2sid_state);
+ struct id_mapping *ids = NULL;
+ state->ctx->status = wb_xids2sids_recv(ctx, &ids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ if (!NT_STATUS_IS_OK(ids->status)) {
+ composite_error(state->ctx, ids->status);
+ return;
+ }
+
+ state->sid = ids->sid;
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_gid2sid_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx,
+ struct dom_sid **sid)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_gid2sid_recv called.\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct gid2sid_state *state =
+ talloc_get_type(ctx->private_data,
+ struct gid2sid_state);
+ *sid = talloc_steal(mem_ctx, state->sid);
+ }
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_init_domain.c b/source4/winbind/wb_init_domain.c
new file mode 100644
index 0000000000..c6dee825a9
--- /dev/null
+++ b/source4/winbind/wb_init_domain.c
@@ -0,0 +1,428 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ A composite API for initializing a domain
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_helper.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "libcli/libcli.h"
+
+#include "libcli/auth/credentials.h"
+#include "libcli/security/security.h"
+
+#include "libcli/ldap/ldap_client.h"
+
+#include "auth/credentials/credentials.h"
+#include "param/param.h"
+
+/*
+ * Initialize a domain:
+ *
+ * - With schannel credentials, try to open the SMB connection and
+ * NETLOGON pipe with the machine creds. This works against W2k3SP1
+ * with an NTLMSSP session setup. Fall back to anonymous (for the CIFS level).
+ *
+ * - If we have schannel creds, do the auth2 and open the schannel'ed netlogon
+ * pipe.
+ *
+ * - Open LSA. If we have machine creds, try to open with SPNEGO or NTLMSSP. Fall back
+ * to schannel.
+ *
+ * - With queryinfopolicy, verify that we're talking to the right domain
+ *
+ * A bit complex, but with all the combinations I think it's the best we can
+ * get. NT4, W2k3 and W2k all have different combinations, but in the end we
+ * have a signed&sealed lsa connection on all of them.
+ *
+ * Not sure if it is overkill, but it seems to work.
+ */
+
+struct init_domain_state {
+ struct composite_context *ctx;
+ struct wbsrv_domain *domain;
+ struct wbsrv_service *service;
+
+ struct lsa_ObjectAttribute objectattr;
+ struct lsa_OpenPolicy2 lsa_openpolicy;
+ struct lsa_QueryInfoPolicy queryinfo;
+};
+
+static void init_domain_recv_netlogonpipe(struct composite_context *ctx);
+static void init_domain_recv_lsa_pipe(struct composite_context *ctx);
+static void init_domain_recv_lsa_policy(struct rpc_request *req);
+static void init_domain_recv_queryinfo(struct rpc_request *req);
+static void init_domain_recv_samr(struct composite_context *ctx);
+
+static struct dcerpc_binding *init_domain_binding(struct init_domain_state *state,
+ const struct ndr_interface_table *table)
+{
+ struct dcerpc_binding *binding;
+ NTSTATUS status;
+
+ /* Make a binding string */
+ {
+ char *s = talloc_asprintf(state, "ncacn_np:%s", state->domain->dc_name);
+ if (s == NULL) return NULL;
+ status = dcerpc_parse_binding(state, s, &binding);
+ talloc_free(s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ }
+
+ /* Alter binding to contain hostname, but also address (so we don't look it up twice) */
+ binding->target_hostname = state->domain->dc_name;
+ binding->host = state->domain->dc_address;
+
+ /* This shouldn't make a network call, as the mappings for named pipes are well known */
+ status = dcerpc_epm_map_binding(binding, binding, table, state->service->task->event_ctx,
+ state->service->task->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+
+ return binding;
+}
+
+struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ struct wb_dom_info *dom_info)
+{
+ struct composite_context *result, *ctx;
+ struct init_domain_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc_zero(result, struct init_domain_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->service = service;
+
+ state->domain = talloc(state, struct wbsrv_domain);
+ if (state->domain == NULL) goto failed;
+
+ state->domain->info = talloc_reference(state->domain, dom_info);
+ if (state->domain->info == NULL) goto failed;
+
+ /* Caller should check, but to be safe: */
+ if (dom_info->num_dcs < 1) {
+ goto failed;
+ }
+
+ /* For now, we just pick the first. The next step will be to
+ * walk the entire list. Also need to fix finddcs() to return
+ * the entire list */
+ state->domain->dc_name = dom_info->dcs[0].name;
+ state->domain->dc_address = dom_info->dcs[0].address;
+
+ state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx,
+ service->task->lp_ctx);
+
+ /* Create a credentials structure */
+ state->domain->libnet_ctx->cred = cli_credentials_init(state->domain);
+ if (state->domain->libnet_ctx->cred == NULL) goto failed;
+
+ cli_credentials_set_conf(state->domain->libnet_ctx->cred, service->task->lp_ctx);
+
+ /* Connect the machine account to the credentials */
+ state->ctx->status =
+ cli_credentials_set_machine_account(state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
+
+ state->domain->netlogon_binding = init_domain_binding(state, &ndr_table_netlogon);
+
+ state->domain->netlogon_pipe = NULL;
+
+ if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) &&
+ ((lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) ||
+ (lp_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) &&
+ (dom_sid_equal(state->domain->info->sid,
+ state->service->primary_sid))) {
+ state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL;
+
+ /* For debugging, it can be a real pain if all the traffic is encrypted */
+ if (lp_winbind_sealed_pipes(service->task->lp_ctx)) {
+ state->domain->netlogon_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
+ } else {
+ state->domain->netlogon_binding->flags |= (DCERPC_SIGN);
+ }
+ }
+
+ /* No encryption on anonymous pipes */
+
+ ctx = dcerpc_pipe_connect_b_send(state, state->domain->netlogon_binding,
+ &ndr_table_netlogon,
+ state->domain->libnet_ctx->cred,
+ service->task->event_ctx,
+ service->task->lp_ctx);
+
+ if (composite_nomem(ctx, state->ctx)) {
+ goto failed;
+ }
+
+ composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
+ state);
+ return result;
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+/* Having make a netlogon connection (possibly secured with schannel),
+ * make an LSA connection to the same DC, on the same IPC$ share */
+static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
+{
+ struct init_domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct init_domain_state);
+
+ state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain,
+ &state->domain->netlogon_pipe);
+
+ if (!composite_is_ok(state->ctx)) {
+ return;
+ }
+ talloc_steal(state->domain->netlogon_pipe, state->domain->netlogon_binding);
+
+ state->domain->lsa_binding = init_domain_binding(state, &ndr_table_lsarpc);
+
+ /* For debugging, it can be a real pain if all the traffic is encrypted */
+ if (lp_winbind_sealed_pipes(state->service->task->lp_ctx)) {
+ state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
+ } else {
+ state->domain->lsa_binding->flags |= (DCERPC_SIGN);
+ }
+
+ state->domain->libnet_ctx->lsa.pipe = NULL;
+
+ /* this will make the secondary connection on the same IPC$ share,
+ secured with SPNEGO or NTLMSSP */
+ ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
+ state->domain->lsa_binding,
+ &ndr_table_lsarpc,
+ state->domain->libnet_ctx->cred,
+ state->domain->libnet_ctx->lp_ctx
+ );
+ composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
+}
+
+static bool retry_with_schannel(struct init_domain_state *state,
+ struct dcerpc_binding *binding,
+ const struct ndr_interface_table *table,
+ void (*continuation)(struct composite_context *))
+{
+ struct composite_context *ctx;
+ state->ctx->status = NT_STATUS_OK;
+ if (state->domain->netlogon_binding->flags & DCERPC_SCHANNEL
+ && !(binding->flags & DCERPC_SCHANNEL)) {
+ /* Opening a policy handle failed, perhaps it was
+ * because we don't get a 'wrong password' error on
+ * NTLMSSP binds */
+
+ /* Try again with schannel */
+ binding->flags |= DCERPC_SCHANNEL;
+
+ /* Try again, likewise on the same IPC$ share,
+ secured with SCHANNEL */
+ ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
+ binding,
+ table,
+ state->domain->libnet_ctx->cred,
+ state->domain->libnet_ctx->lp_ctx);
+ composite_continue(state->ctx, ctx, continuation, state);
+ return true;
+ } else {
+ return false;
+ }
+}
+/* We should now have either an authenticated LSA pipe, or an error.
+ * On success, open a policy handle
+ */
+static void init_domain_recv_lsa_pipe(struct composite_context *ctx)
+{
+ struct rpc_request *req;
+ struct init_domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct init_domain_state);
+
+ state->ctx->status = dcerpc_secondary_auth_connection_recv(ctx, state->domain,
+ &state->domain->libnet_ctx->lsa.pipe);
+ if (NT_STATUS_EQUAL(state->ctx->status, NT_STATUS_LOGON_FAILURE)) {
+ if (retry_with_schannel(state, state->domain->lsa_binding,
+ &ndr_table_lsarpc,
+ init_domain_recv_lsa_pipe)) {
+ return;
+ }
+ }
+ if (!composite_is_ok(state->ctx)) return;
+
+ talloc_steal(state->domain->libnet_ctx, state->domain->libnet_ctx->lsa.pipe);
+ talloc_steal(state->domain->libnet_ctx->lsa.pipe, state->domain->lsa_binding);
+ state->domain->libnet_ctx->lsa.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->domain->libnet_ctx->lsa.name = state->domain->info->name;
+
+ ZERO_STRUCT(state->domain->libnet_ctx->lsa.handle);
+ state->lsa_openpolicy.in.system_name =
+ talloc_asprintf(state, "\\\\%s",
+ dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe));
+ ZERO_STRUCT(state->objectattr);
+ state->lsa_openpolicy.in.attr = &state->objectattr;
+ state->lsa_openpolicy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->lsa_openpolicy.out.handle = &state->domain->libnet_ctx->lsa.handle;
+
+ req = dcerpc_lsa_OpenPolicy2_send(state->domain->libnet_ctx->lsa.pipe, state,
+ &state->lsa_openpolicy);
+
+ composite_continue_rpc(state->ctx, req, init_domain_recv_lsa_policy, state);
+}
+
+/* Receive a policy handle (or not, and retry the authentication) and
+ * obtain some basic information about the domain */
+
+static void init_domain_recv_lsa_policy(struct rpc_request *req)
+{
+ struct init_domain_state *state =
+ talloc_get_type(req->async.private_data,
+ struct init_domain_state);
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if ((!NT_STATUS_IS_OK(state->ctx->status)
+ || !NT_STATUS_IS_OK(state->lsa_openpolicy.out.result))) {
+ if (retry_with_schannel(state, state->domain->lsa_binding,
+ &ndr_table_lsarpc,
+ init_domain_recv_lsa_pipe)) {
+ return;
+ }
+ }
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->lsa_openpolicy.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ state->queryinfo.in.handle = &state->domain->libnet_ctx->lsa.handle;
+ state->queryinfo.in.level = LSA_POLICY_INFO_ACCOUNT_DOMAIN;
+
+ req = dcerpc_lsa_QueryInfoPolicy_send(state->domain->libnet_ctx->lsa.pipe, state,
+ &state->queryinfo);
+ composite_continue_rpc(state->ctx, req,
+ init_domain_recv_queryinfo, state);
+}
+
+static void init_domain_recv_queryinfo(struct rpc_request *req)
+{
+ struct init_domain_state *state =
+ talloc_get_type(req->async.private_data, struct init_domain_state);
+ struct lsa_DomainInfo *dominfo;
+ struct composite_context *ctx;
+
+ state->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(state->ctx)) return;
+ state->ctx->status = state->queryinfo.out.result;
+ if (!composite_is_ok(state->ctx)) return;
+
+ dominfo = &state->queryinfo.out.info->account_domain;
+
+ if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
+ DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
+ state->domain->info->name,
+ dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
+ dominfo->name.string));
+ composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
+ return;
+ }
+
+ if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
+ DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
+ dom_sid_string(state, state->domain->info->sid),
+ dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
+ dom_sid_string(state, dominfo->sid)));
+ composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
+ return;
+ }
+
+ state->domain->samr_binding = init_domain_binding(state, &ndr_table_samr);
+
+ /* We want to use the same flags as the LSA pipe did (so, if
+ * it needed schannel, then we need that here too) */
+ state->domain->samr_binding->flags = state->domain->lsa_binding->flags;
+
+ state->domain->libnet_ctx->samr.pipe = NULL;
+
+ ctx = wb_connect_samr_send(state, state->domain);
+ composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
+}
+
+/* Recv the SAMR details (SamrConnect and SamrOpenDomain handle) and
+ * open an LDAP connection */
+static void init_domain_recv_samr(struct composite_context *ctx)
+{
+ const char *ldap_url;
+ struct init_domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct init_domain_state);
+
+ state->ctx->status = wb_connect_samr_recv(
+ ctx, state->domain,
+ &state->domain->libnet_ctx->samr.pipe,
+ &state->domain->libnet_ctx->samr.handle,
+ &state->domain->libnet_ctx->samr.handle);
+ if (!composite_is_ok(state->ctx)) return;
+
+ talloc_steal(state->domain->libnet_ctx->samr.pipe, state->domain->samr_binding);
+ state->domain->libnet_ctx->samr.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ state->domain->libnet_ctx->samr.name = state->domain->info->name;
+ state->domain->libnet_ctx->samr.sid = state->domain->info->sid;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_init_domain_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct wbsrv_domain **result)
+{
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ struct init_domain_state *state =
+ talloc_get_type(c->private_data,
+ struct init_domain_state);
+ *result = talloc_steal(mem_ctx, state->domain);
+ }
+ talloc_free(c);
+ return status;
+}
+
+NTSTATUS wb_init_domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
+ struct wb_dom_info *dom_info,
+ struct wbsrv_domain **result)
+{
+ struct composite_context *c =
+ wb_init_domain_send(mem_ctx, service, dom_info);
+ return wb_init_domain_recv(c, mem_ctx, result);
+}
diff --git a/source4/winbind/wb_irpc.c b/source4/winbind/wb_irpc.c
new file mode 100644
index 0000000000..0535045adb
--- /dev/null
+++ b/source4/winbind/wb_irpc.c
@@ -0,0 +1,155 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main winbindd irpc handlers
+
+ Copyright (C) Stefan Metzmacher 2006
+
+ 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 "includes.h"
+#include "winbind/wb_server.h"
+#include "lib/messaging/irpc.h"
+#include "libcli/composite/composite.h"
+#include "libcli/security/proto.h"
+#include "librpc/gen_ndr/ndr_winbind.h"
+#include "smbd/service_task.h"
+
+struct wb_irpc_SamLogon_state {
+ struct irpc_message *msg;
+ struct winbind_SamLogon *req;
+};
+
+static void wb_irpc_SamLogon_callback(struct composite_context *ctx);
+
+static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
+ struct winbind_SamLogon *req)
+{
+ struct wbsrv_service *service = talloc_get_type(msg->private,
+ struct wbsrv_service);
+ struct wb_irpc_SamLogon_state *s;
+ struct composite_context *ctx;
+
+ DEBUG(5, ("wb_irpc_SamLogon called\n"));
+
+ s = talloc(msg, struct wb_irpc_SamLogon_state);
+ NT_STATUS_HAVE_NO_MEMORY(s);
+
+ s->msg = msg;
+ s->req = req;
+
+ ctx = wb_sam_logon_send(msg, service, req);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = wb_irpc_SamLogon_callback;
+ ctx->async.private_data = s;
+
+ msg->defer_reply = true;
+ return NT_STATUS_OK;
+}
+
+static void wb_irpc_SamLogon_callback(struct composite_context *ctx)
+{
+ struct wb_irpc_SamLogon_state *s = talloc_get_type(ctx->async.private_data,
+ struct wb_irpc_SamLogon_state);
+ NTSTATUS status;
+
+ DEBUG(5, ("wb_irpc_SamLogon_callback called\n"));
+
+ status = wb_sam_logon_recv(ctx, s, s->req);
+
+ irpc_send_reply(s->msg, status);
+}
+
+struct wb_irpc_get_idmap_state {
+ struct irpc_message *msg;
+ struct winbind_get_idmap *req;
+ int level;
+};
+
+static void wb_irpc_get_idmap_callback(struct composite_context *ctx);
+
+static NTSTATUS wb_irpc_get_idmap(struct irpc_message *msg,
+ struct winbind_get_idmap *req)
+{
+ struct wbsrv_service *service = talloc_get_type(msg->private,
+ struct wbsrv_service);
+ struct wb_irpc_get_idmap_state *s;
+ struct composite_context *ctx;
+
+ DEBUG(5, ("wb_irpc_get_idmap called\n"));
+
+ s = talloc(msg, struct wb_irpc_get_idmap_state);
+ NT_STATUS_HAVE_NO_MEMORY(s);
+
+ s->msg = msg;
+ s->req = req;
+ s->level = req->in.level;
+
+ switch(s->level) {
+ case WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS:
+ ctx = wb_sids2xids_send(msg, service, req->in.count,
+ req->in.ids);
+ break;
+ case WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS:
+ ctx = wb_xids2sids_send(msg, service, req->in.count,
+ req->in.ids);
+ break;
+ }
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ composite_continue(ctx, ctx, wb_irpc_get_idmap_callback, s);
+ msg->defer_reply = true;
+
+ return NT_STATUS_OK;
+}
+
+static void wb_irpc_get_idmap_callback(struct composite_context *ctx)
+{
+ struct wb_irpc_get_idmap_state *s;
+ NTSTATUS status;
+
+ DEBUG(5, ("wb_irpc_get_idmap_callback called\n"));
+
+ s = talloc_get_type(ctx->async.private_data,
+ struct wb_irpc_get_idmap_state);
+
+ switch(s->level) {
+ case WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS:
+ status = wb_sids2xids_recv(ctx, &s->req->out.ids);
+ break;
+ case WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS:
+ status = wb_xids2sids_recv(ctx, &s->req->out.ids);
+ break;
+ }
+
+ irpc_send_reply(s->msg, status);
+}
+
+NTSTATUS wbsrv_init_irpc(struct wbsrv_service *service)
+{
+ NTSTATUS status;
+
+ irpc_add_name(service->task->msg_ctx, "winbind_server");
+
+ status = IRPC_REGISTER(service->task->msg_ctx, winbind, WINBIND_SAMLOGON,
+ wb_irpc_SamLogon, service);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = IRPC_REGISTER(service->task->msg_ctx, winbind, WINBIND_GET_IDMAP,
+ wb_irpc_get_idmap, service);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/winbind/wb_name2domain.c b/source4/winbind/wb_name2domain.c
new file mode 100644
index 0000000000..e19703b1e5
--- /dev/null
+++ b/source4/winbind/wb_name2domain.c
@@ -0,0 +1,121 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Find and init a domain struct for a name
+
+ Copyright (C) Kai Blin 2007
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "param/param.h"
+
+struct name2domain_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+
+ struct wbsrv_domain *domain;
+};
+
+static void name2domain_recv_sid(struct composite_context *ctx);
+static void name2domain_recv_domain(struct composite_context *ctx);
+
+struct composite_context *wb_name2domain_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, const char* name)
+{
+ struct composite_context *result, *ctx;
+ struct name2domain_state *state;
+ char *user_dom, *user_name;
+ bool ok;
+
+ DEBUG(5, ("wb_name2domain_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct name2domain_state);
+ if (composite_nomem(state, result)) return result;
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ ok = wb_samba3_split_username(state, service->task->lp_ctx, name, &user_dom, &user_name);
+ if(!ok) {
+ composite_error(state->ctx, NT_STATUS_OBJECT_NAME_INVALID);
+ return result;
+ }
+
+ ctx = wb_cmd_lookupname_send(state, service, user_dom, user_name);
+ if (composite_nomem(ctx, state->ctx)) return result;
+
+ composite_continue(result, ctx, name2domain_recv_sid, state);
+ return result;
+}
+
+static void name2domain_recv_sid(struct composite_context *ctx)
+{
+ struct name2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct name2domain_state);
+ struct wb_sid_object *sid;
+
+ DEBUG(5, ("name2domain_recv_sid called\n"));
+
+ state->ctx->status = wb_cmd_lookupname_recv(ctx, state, &sid);
+ if(!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_sid2domain_send(state, state->service, sid->sid);
+
+ composite_continue(state->ctx, ctx, name2domain_recv_domain, state);
+}
+
+static void name2domain_recv_domain(struct composite_context *ctx)
+{
+ struct name2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct name2domain_state);
+ struct wbsrv_domain *domain;
+
+ DEBUG(5, ("name2domain_recv_domain called\n"));
+
+ state->ctx->status = wb_sid2domain_recv(ctx, &domain);
+ if(!composite_is_ok(state->ctx)) return;
+
+ state->domain = domain;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_name2domain_recv(struct composite_context *ctx,
+ struct wbsrv_domain **result)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_name2domain_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct name2domain_state *state =
+ talloc_get_type(ctx->private_data,
+ struct name2domain_state);
+ *result = state->domain;
+ }
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_pam_auth.c b/source4/winbind/wb_pam_auth.c
new file mode 100644
index 0000000000..ee54bcd58f
--- /dev/null
+++ b/source4/winbind/wb_pam_auth.c
@@ -0,0 +1,271 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Authenticate a user
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/winbind.h"
+#include "param/param.h"
+
+/* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */
+struct pam_auth_crap_state {
+ struct composite_context *ctx;
+ struct event_context *event_ctx;
+ struct loadparm_context *lp_ctx;
+
+ struct winbind_SamLogon *req;
+ char *unix_username;
+
+ struct netr_NetworkInfo ninfo;
+ struct netr_LogonSamLogon r;
+
+ const char *user_name;
+ const char *domain_name;
+
+ struct netr_UserSessionKey user_session_key;
+ struct netr_LMSessionKey lm_key;
+ DATA_BLOB info3;
+};
+
+/*
+ * NTLM authentication.
+*/
+
+static void pam_auth_crap_recv_logon(struct composite_context *ctx);
+
+struct composite_context *wb_cmd_pam_auth_crap_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ uint32_t logon_parameters,
+ const char *domain,
+ const char *user,
+ const char *workstation,
+ DATA_BLOB chal,
+ DATA_BLOB nt_resp,
+ DATA_BLOB lm_resp)
+{
+ struct composite_context *result, *ctx;
+ struct pam_auth_crap_state *state;
+ struct netr_NetworkInfo *ninfo;
+ DATA_BLOB tmp_nt_resp, tmp_lm_resp;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct pam_auth_crap_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ state->lp_ctx = service->task->lp_ctx;
+ result->private_data = state;
+
+ state->req = talloc(state, struct winbind_SamLogon);
+
+ state->req->in.logon_level = 2;
+ state->req->in.validation_level = 3;
+ ninfo = state->req->in.logon.network = talloc(state, struct netr_NetworkInfo);
+ if (ninfo == NULL) goto failed;
+
+ ninfo->identity_info.account_name.string = talloc_strdup(state, user);
+ ninfo->identity_info.domain_name.string = talloc_strdup(state, domain);
+ ninfo->identity_info.parameter_control = logon_parameters;
+ ninfo->identity_info.logon_id_low = 0;
+ ninfo->identity_info.logon_id_high = 0;
+ ninfo->identity_info.workstation.string = talloc_strdup(state, workstation);
+
+ SMB_ASSERT(chal.length == sizeof(ninfo->challenge));
+ memcpy(ninfo->challenge, chal.data,
+ sizeof(ninfo->challenge));
+
+ tmp_nt_resp = data_blob_talloc(ninfo, nt_resp.data, nt_resp.length);
+ if ((nt_resp.data != NULL) &&
+ (tmp_nt_resp.data == NULL)) goto failed;
+
+ tmp_lm_resp = data_blob_talloc(ninfo, lm_resp.data, lm_resp.length);
+ if ((lm_resp.data != NULL) &&
+ (tmp_lm_resp.data == NULL)) goto failed;
+
+ ninfo->nt.length = tmp_nt_resp.length;
+ ninfo->nt.data = tmp_nt_resp.data;
+ ninfo->lm.length = tmp_lm_resp.length;
+ ninfo->lm.data = tmp_lm_resp.data;
+
+ state->unix_username = NULL;
+
+ ctx = wb_sam_logon_send(mem_ctx, service, state->req);
+ if (ctx == NULL) goto failed;
+
+ composite_continue(result, ctx, pam_auth_crap_recv_logon, state);
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+/*
+ NTLM Authentication
+
+ Send of a SamLogon request to authenticate a user.
+*/
+static void pam_auth_crap_recv_logon(struct composite_context *ctx)
+{
+ DATA_BLOB tmp_blob;
+ enum ndr_err_code ndr_err;
+ struct netr_SamBaseInfo *base;
+ struct pam_auth_crap_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct pam_auth_crap_state);
+
+ state->ctx->status = wb_sam_logon_recv(ctx, state, state->req);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ndr_err = ndr_push_struct_blob(
+ &tmp_blob, state, lp_iconv_convenience(state->lp_ctx),
+ state->req->out.validation.sam3,
+ (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ state->ctx->status = ndr_map_error2ntstatus(ndr_err);
+ if (!composite_is_ok(state->ctx)) return;
+ }
+
+ /* The Samba3 protocol is a bit broken (due to non-IDL
+ * heritage, so for compatability we must add a non-zero 4
+ * bytes to the info3 */
+ state->info3 = data_blob_talloc(state, NULL, tmp_blob.length+4);
+ if (composite_nomem(state->info3.data, state->ctx)) return;
+
+ SIVAL(state->info3.data, 0, 1);
+ memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length);
+
+ base = &state->req->out.validation.sam3->base;
+
+ state->user_session_key = base->key;
+ state->lm_key = base->LMSessKey;
+
+ /* Give the caller the most accurate username possible.
+ * Assists where case sensitive comparisons may be done by our
+ * ntlm_auth callers */
+ if (base->account_name.string) {
+ state->user_name = base->account_name.string;
+ talloc_steal(state, base->account_name.string);
+ }
+ if (base->domain.string) {
+ state->domain_name = base->domain.string;
+ talloc_steal(state, base->domain.string);
+ }
+
+ state->unix_username = talloc_asprintf(state, "%s%s%s",
+ state->domain_name,
+ lp_winbind_separator(state->lp_ctx),
+ state->user_name);
+ if (composite_nomem(state->unix_username, state->ctx)) return;
+
+ composite_done(state->ctx);
+}
+
+/* Having received a NTLM authentication reply, parse out the useful
+ * reply data for the caller */
+NTSTATUS wb_cmd_pam_auth_crap_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *info3,
+ struct netr_UserSessionKey *user_session_key,
+ struct netr_LMSessionKey *lm_key,
+ char **unix_username)
+{
+ struct pam_auth_crap_state *state =
+ talloc_get_type(c->private_data, struct pam_auth_crap_state);
+ NTSTATUS status = composite_wait(c);
+ if (NT_STATUS_IS_OK(status)) {
+ info3->length = state->info3.length;
+ info3->data = talloc_steal(mem_ctx, state->info3.data);
+ *user_session_key = state->user_session_key;
+ *lm_key = state->lm_key;
+ *unix_username = talloc_steal(mem_ctx, state->unix_username);
+ }
+ talloc_free(state);
+ return status;
+}
+
+/* Handle plaintext authentication, by encrypting the password and
+ * then sending via the NTLM calls */
+
+struct composite_context *wb_cmd_pam_auth_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ struct cli_credentials *credentials)
+{
+ const char *workstation;
+ NTSTATUS status;
+ const char *user, *domain;
+ DATA_BLOB chal, nt_resp, lm_resp, names_blob;
+ int flags = CLI_CRED_NTLM_AUTH;
+ if (lp_client_lanman_auth(service->task->lp_ctx)) {
+ flags |= CLI_CRED_LANMAN_AUTH;
+ }
+
+ if (lp_client_ntlmv2_auth(service->task->lp_ctx)) {
+ flags |= CLI_CRED_NTLMv2_AUTH;
+ }
+
+ DEBUG(5, ("wbsrv_samba3_pam_auth called\n"));
+
+ chal = data_blob_talloc(mem_ctx, NULL, 8);
+ if (!chal.data) {
+ return NULL;
+ }
+ generate_random_buffer(chal.data, chal.length);
+ cli_credentials_get_ntlm_username_domain(credentials, mem_ctx,
+ &user, &domain);
+ /* for best compatability with multiple vitual netbios names
+ * on the host, this should be generated from the
+ * cli_credentials associated with the machine account */
+ workstation = cli_credentials_get_workstation(credentials);
+
+ names_blob = NTLMv2_generate_names_blob(
+ mem_ctx,
+ lp_iconv_convenience(service->task->lp_ctx),
+ cli_credentials_get_workstation(credentials),
+ cli_credentials_get_domain(credentials));
+
+ status = cli_credentials_get_ntlm_response(
+ credentials, mem_ctx, &flags, chal, names_blob,
+ &lm_resp, &nt_resp, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ return wb_cmd_pam_auth_crap_send(mem_ctx, service,
+ MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT|MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT /* logon parameters */,
+ domain, user, workstation,
+ chal, nt_resp, lm_resp);
+}
+
+NTSTATUS wb_cmd_pam_auth_recv(struct composite_context *c)
+{
+ struct pam_auth_crap_state *state =
+ talloc_get_type(c->private_data, struct pam_auth_crap_state);
+ NTSTATUS status = composite_wait(c);
+ talloc_free(state);
+ return status;
+}
diff --git a/source4/winbind/wb_sam_logon.c b/source4/winbind/wb_sam_logon.c
new file mode 100644
index 0000000000..c9203c8bec
--- /dev/null
+++ b/source4/winbind/wb_sam_logon.c
@@ -0,0 +1,166 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Do a netr_LogonSamLogon to a remote DC
+
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Stefan Metzmacher 2006
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "auth/credentials/credentials.h"
+#include "libcli/auth/libcli_auth.h"
+#include "librpc/gen_ndr/ndr_netlogon.h"
+#include "librpc/gen_ndr/ndr_netlogon_c.h"
+#include "librpc/gen_ndr/winbind.h"
+
+struct wb_sam_logon_state {
+ struct composite_context *ctx;
+
+ struct winbind_SamLogon *req;
+
+ struct creds_CredentialState *creds_state;
+ struct netr_Authenticator auth1, auth2;
+
+ TALLOC_CTX *r_mem_ctx;
+ struct netr_LogonSamLogon r;
+};
+
+static void wb_sam_logon_recv_domain(struct composite_context *ctx);
+static void wb_sam_logon_recv_samlogon(struct rpc_request *req);
+
+/*
+ Find the connection to the DC (or find an existing connection)
+*/
+struct composite_context *wb_sam_logon_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ struct winbind_SamLogon *req)
+{
+ struct composite_context *c, *creq;
+ struct wb_sam_logon_state *s;
+
+ c = composite_create(mem_ctx, service->task->event_ctx);
+ if (!c) return NULL;
+
+ s = talloc_zero(c, struct wb_sam_logon_state);
+ if (composite_nomem(s, c)) return c;
+ s->ctx = c;
+ s->req = req;
+
+ c->private_data = s;
+
+ creq = wb_sid2domain_send(s, service, service->primary_sid);
+ composite_continue(c, creq, wb_sam_logon_recv_domain, s);
+ return c;
+}
+
+/*
+ Having finished making the connection to the DC
+ Send of a SamLogon request to authenticate a user.
+*/
+static void wb_sam_logon_recv_domain(struct composite_context *creq)
+{
+ struct wb_sam_logon_state *s = talloc_get_type(creq->async.private_data,
+ struct wb_sam_logon_state);
+ struct rpc_request *req;
+ struct wbsrv_domain *domain;
+
+ s->ctx->status = wb_sid2domain_recv(creq, &domain);
+ if (!composite_is_ok(s->ctx)) return;
+
+ s->creds_state = cli_credentials_get_netlogon_creds(domain->libnet_ctx->cred);
+ creds_client_authenticator(s->creds_state, &s->auth1);
+
+ s->r.in.server_name = talloc_asprintf(s, "\\\\%s",
+ dcerpc_server_name(domain->netlogon_pipe));
+ if (composite_nomem(s->r.in.server_name, s->ctx)) return;
+
+ s->r.in.computer_name = cli_credentials_get_workstation(domain->libnet_ctx->cred);
+ s->r.in.credential = &s->auth1;
+ s->r.in.return_authenticator = &s->auth2;
+ s->r.in.logon_level = s->req->in.logon_level;
+ s->r.in.logon = s->req->in.logon;
+ s->r.in.validation_level = s->req->in.validation_level;
+ s->r.out.return_authenticator = NULL;
+
+ /*
+ * use a new talloc context for the LogonSamLogon call
+ * because then we can just to a talloc_steal on this context
+ * in the final _recv() function to give the caller all the content of
+ * the s->r.out.validation
+ */
+ s->r_mem_ctx = talloc_new(s);
+ if (composite_nomem(s->r_mem_ctx, s->ctx)) return;
+
+ req = dcerpc_netr_LogonSamLogon_send(domain->netlogon_pipe, s->r_mem_ctx, &s->r);
+ composite_continue_rpc(s->ctx, req, wb_sam_logon_recv_samlogon, s);
+}
+
+/*
+ NTLM Authentication
+
+ Check the SamLogon reply and decrypt the session keys
+*/
+static void wb_sam_logon_recv_samlogon(struct rpc_request *req)
+{
+ struct wb_sam_logon_state *s = talloc_get_type(req->async.private_data,
+ struct wb_sam_logon_state);
+
+ s->ctx->status = dcerpc_ndr_request_recv(req);
+ if (!composite_is_ok(s->ctx)) return;
+
+ s->ctx->status = s->r.out.result;
+ if (!composite_is_ok(s->ctx)) return;
+
+ if ((s->r.out.return_authenticator == NULL) ||
+ (!creds_client_check(s->creds_state,
+ &s->r.out.return_authenticator->cred))) {
+ DEBUG(0, ("Credentials check failed!\n"));
+ composite_error(s->ctx, NT_STATUS_ACCESS_DENIED);
+ return;
+ }
+
+ /* Decrypt the session keys before we reform the info3, so the
+ * person on the other end of winbindd pipe doesn't have to.
+ * They won't have the encryption key anyway */
+ creds_decrypt_samlogon(s->creds_state,
+ s->r.in.validation_level,
+ &s->r.out.validation);
+
+ composite_done(s->ctx);
+}
+
+NTSTATUS wb_sam_logon_recv(struct composite_context *c,
+ TALLOC_CTX *mem_ctx,
+ struct winbind_SamLogon *req)
+{
+ struct wb_sam_logon_state *s = talloc_get_type(c->private_data,
+ struct wb_sam_logon_state);
+ NTSTATUS status = composite_wait(c);
+
+ if (NT_STATUS_IS_OK(status)) {
+ talloc_steal(mem_ctx, s->r_mem_ctx);
+ req->out.validation = s->r.out.validation;
+ req->out.authoritative = 1;
+ }
+
+ talloc_free(s);
+ return status;
+}
diff --git a/source4/winbind/wb_samba3_cmd.c b/source4/winbind/wb_samba3_cmd.c
new file mode 100644
index 0000000000..c2ba55ff18
--- /dev/null
+++ b/source4/winbind/wb_samba3_cmd.c
@@ -0,0 +1,1114 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main winbindd samba3 server routines
+
+ Copyright (C) Stefan Metzmacher 2005
+ Copyright (C) Volker Lendecke 2005
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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/>.
+*/
+
+#include "includes.h"
+#include "winbind/wb_server.h"
+#include "winbind/wb_async_helpers.h"
+#include "param/param.h"
+#include "winbind/wb_helper.h"
+#include "libcli/composite/composite.h"
+#include "version.h"
+#include "librpc/gen_ndr/netlogon.h"
+#include "libcli/security/security.h"
+#include "auth/ntlm/pam_errors.h"
+#include "auth/credentials/credentials.h"
+#include "smbd/service_task.h"
+
+/*
+ Send off the reply to an async Samba3 query, handling filling in the PAM, NTSTATUS and string errors.
+*/
+
+static void wbsrv_samba3_async_auth_epilogue(NTSTATUS status,
+ struct wbsrv_samba3_call *s3call)
+{
+ struct winbindd_response *resp = &s3call->response;
+ if (!NT_STATUS_IS_OK(status)) {
+ resp->result = WINBINDD_ERROR;
+ } else {
+ resp->result = WINBINDD_OK;
+ }
+
+ WBSRV_SAMBA3_SET_STRING(resp->data.auth.nt_status_string,
+ nt_errstr(status));
+ WBSRV_SAMBA3_SET_STRING(resp->data.auth.error_string,
+ get_friendly_nt_error_msg(status));
+
+ resp->data.auth.pam_error = nt_status_to_pam(status);
+ resp->data.auth.nt_status = NT_STATUS_V(status);
+
+ wbsrv_samba3_send_reply(s3call);
+}
+
+/*
+ Send of a generic reply to a Samba3 query
+*/
+
+static void wbsrv_samba3_async_epilogue(NTSTATUS status,
+ struct wbsrv_samba3_call *s3call)
+{
+ struct winbindd_response *resp = &s3call->response;
+ if (NT_STATUS_IS_OK(status)) {
+ resp->result = WINBINDD_OK;
+ } else {
+ resp->result = WINBINDD_ERROR;
+ }
+
+ wbsrv_samba3_send_reply(s3call);
+}
+
+/*
+ Boilerplate commands, simple queries without network traffic
+*/
+
+NTSTATUS wbsrv_samba3_interface_version(struct wbsrv_samba3_call *s3call)
+{
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.data.interface_version = WINBIND_INTERFACE_VERSION;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_info(struct wbsrv_samba3_call *s3call)
+{
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.data.info.winbind_separator = *lp_winbind_separator(s3call->wbconn->lp_ctx);
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.info.samba_version,
+ SAMBA_VERSION_STRING);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_domain_name(struct wbsrv_samba3_call *s3call)
+{
+ s3call->response.result = WINBINDD_OK;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.domain_name,
+ lp_workgroup(s3call->wbconn->lp_ctx));
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_netbios_name(struct wbsrv_samba3_call *s3call)
+{
+ s3call->response.result = WINBINDD_OK;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.netbios_name,
+ lp_netbios_name(s3call->wbconn->lp_ctx));
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_priv_pipe_dir(struct wbsrv_samba3_call *s3call)
+{
+ char *path = s3call->wbconn->listen_socket->service->priv_socket_path;
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.extra_data.data = path;
+
+ s3call->response.length += strlen(path) + 1;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_ping(struct wbsrv_samba3_call *s3call)
+{
+ s3call->response.result = WINBINDD_OK;
+ return NT_STATUS_OK;
+}
+
+/* Plaintext authentication
+
+ This interface is used by ntlm_auth in it's 'basic' authentication
+ mode, as well as by pam_winbind to authenticate users where we are
+ given a plaintext password.
+*/
+
+static void check_machacc_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_check_machacc(struct wbsrv_samba3_call *s3call)
+{
+ NTSTATUS status;
+ struct cli_credentials *creds;
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ /* Create a credentials structure */
+ creds = cli_credentials_init(s3call);
+ if (creds == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ cli_credentials_set_conf(creds, service->task->lp_ctx);
+
+ /* Connect the machine account to the credentials */
+ status = cli_credentials_set_machine_account(creds, service->task->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(creds);
+ return status;
+ }
+
+ ctx = wb_cmd_pam_auth_send(s3call, service, creds);
+
+ if (!ctx) {
+ talloc_free(creds);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx->async.fn = check_machacc_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void check_machacc_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+
+ status = wb_cmd_pam_auth_recv(ctx);
+
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ done:
+ wbsrv_samba3_async_auth_epilogue(status, s3call);
+}
+
+/*
+ Find the name of a suitable domain controller, by query on the
+ netlogon pipe to the DC.
+*/
+
+static void getdcname_recv_dc(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getdcname(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_getdcname called\n"));
+
+ ctx = wb_cmd_getdcname_send(s3call, service,
+ s3call->request.domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = getdcname_recv_dc;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void getdcname_recv_dc(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ const char *dcname;
+ NTSTATUS status;
+
+ status = wb_cmd_getdcname_recv(ctx, s3call, &dcname);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ s3call->response.result = WINBINDD_OK;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.dc_name, dcname);
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/*
+ Lookup a user's domain groups
+*/
+
+static void userdomgroups_recv_groups(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_userdomgroups(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_userdomgroups called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ if (sid == NULL) {
+ DEBUG(5, ("Could not parse sid %s\n",
+ s3call->request.data.sid));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx = wb_cmd_userdomgroups_send(
+ s3call, s3call->wbconn->listen_socket->service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = userdomgroups_recv_groups;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void userdomgroups_recv_groups(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ int i, num_sids;
+ struct dom_sid **sids;
+ char *sids_string;
+ NTSTATUS status;
+
+ status = wb_cmd_userdomgroups_recv(ctx, s3call, &num_sids, &sids);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ sids_string = talloc_strdup(s3call, "");
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ sids_string = talloc_asprintf_append_buffer(
+ sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
+ }
+
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.extra_data.data = sids_string;
+ s3call->response.length += strlen(sids_string)+1;
+ s3call->response.data.num_entries = num_sids;
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/*
+ Lookup the list of SIDs for a user
+*/
+static void usersids_recv_sids(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_usersids(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_usersids called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ if (sid == NULL) {
+ DEBUG(5, ("Could not parse sid %s\n",
+ s3call->request.data.sid));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx = wb_cmd_usersids_send(
+ s3call, s3call->wbconn->listen_socket->service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = usersids_recv_sids;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void usersids_recv_sids(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ int i, num_sids;
+ struct dom_sid **sids;
+ char *sids_string;
+ NTSTATUS status;
+
+ status = wb_cmd_usersids_recv(ctx, s3call, &num_sids, &sids);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ sids_string = talloc_strdup(s3call, "");
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_sids; i++) {
+ sids_string = talloc_asprintf_append_buffer(
+ sids_string, "%s\n", dom_sid_string(s3call, sids[i]));
+ if (sids_string == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+ }
+
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.extra_data.data = sids_string;
+ s3call->response.length += strlen(sids_string);
+ s3call->response.data.num_entries = num_sids;
+
+ /* Hmmmm. Nasty protocol -- who invented the zeros between the
+ * SIDs? Hmmm. Could have been me -- vl */
+
+ while (*sids_string != '\0') {
+ if ((*sids_string) == '\n') {
+ *sids_string = '\0';
+ }
+ sids_string += 1;
+ }
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/*
+ Lookup a DOMAIN\\user style name, and return a SID
+*/
+
+static void lookupname_recv_sid(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_lookupname(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_lookupname called\n"));
+
+ ctx = wb_cmd_lookupname_send(s3call, service,
+ s3call->request.data.name.dom_name,
+ s3call->request.data.name.name);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ /* setup the callbacks */
+ ctx->async.fn = lookupname_recv_sid;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void lookupname_recv_sid(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ struct wb_sid_object *sid;
+ NTSTATUS status;
+
+ status = wb_cmd_lookupname_recv(ctx, s3call, &sid);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.data.sid.type = sid->type;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid,
+ dom_sid_string(s3call, sid->sid));
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/*
+ Lookup a SID, and return a DOMAIN\\user style name
+*/
+
+static void lookupsid_recv_name(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_lookupsid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_lookupsid called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ if (sid == NULL) {
+ DEBUG(5, ("Could not parse sid %s\n",
+ s3call->request.data.sid));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ ctx = wb_cmd_lookupsid_send(s3call, service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ /* setup the callbacks */
+ ctx->async.fn = lookupsid_recv_name;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void lookupsid_recv_name(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ struct wb_sid_object *sid;
+ NTSTATUS status;
+
+ status = wb_cmd_lookupsid_recv(ctx, s3call, &sid);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ s3call->response.result = WINBINDD_OK;
+ s3call->response.data.name.type = sid->type;
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.dom_name,
+ sid->domain);
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.name.name, sid->name);
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/*
+ Challenge-response authentication. This interface is used by
+ ntlm_auth and the smbd auth subsystem to pass NTLM authentication
+ requests along a common pipe to the domain controller.
+
+ The return value (in the async reply) may include the 'info3'
+ (effectivly most things you would want to know about the user), or
+ the NT and LM session keys seperated.
+*/
+
+static void pam_auth_crap_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_pam_auth_crap(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+ DATA_BLOB chal, nt_resp, lm_resp;
+
+ DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
+
+ chal.data = s3call->request.data.auth_crap.chal;
+ chal.length = sizeof(s3call->request.data.auth_crap.chal);
+ nt_resp.data = (uint8_t *)s3call->request.data.auth_crap.nt_resp;
+ nt_resp.length = s3call->request.data.auth_crap.nt_resp_len;
+ lm_resp.data = (uint8_t *)s3call->request.data.auth_crap.lm_resp;
+ lm_resp.length = s3call->request.data.auth_crap.lm_resp_len;
+
+ ctx = wb_cmd_pam_auth_crap_send(
+ s3call, service,
+ s3call->request.data.auth_crap.logon_parameters,
+ s3call->request.data.auth_crap.domain,
+ s3call->request.data.auth_crap.user,
+ s3call->request.data.auth_crap.workstation,
+ chal, nt_resp, lm_resp);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = pam_auth_crap_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void pam_auth_crap_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ DATA_BLOB info3;
+ struct netr_UserSessionKey user_session_key;
+ struct netr_LMSessionKey lm_key;
+ char *unix_username;
+
+ status = wb_cmd_pam_auth_crap_recv(ctx, s3call, &info3,
+ &user_session_key, &lm_key, &unix_username);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ if (s3call->request.flags & WBFLAG_PAM_USER_SESSION_KEY) {
+ memcpy(s3call->response.data.auth.user_session_key,
+ &user_session_key.key,
+ sizeof(s3call->response.data.auth.user_session_key));
+ }
+
+ if (s3call->request.flags & WBFLAG_PAM_INFO3_NDR) {
+ s3call->response.extra_data.data = info3.data;
+ s3call->response.length += info3.length;
+ }
+
+ if (s3call->request.flags & WBFLAG_PAM_LMKEY) {
+ memcpy(s3call->response.data.auth.first_8_lm_hash,
+ lm_key.key,
+ sizeof(s3call->response.data.auth.first_8_lm_hash));
+ }
+
+ if (s3call->request.flags & WBFLAG_PAM_UNIX_NAME) {
+ s3call->response.extra_data.data = unix_username;
+ s3call->response.length += strlen(unix_username)+1;
+ }
+
+ done:
+ wbsrv_samba3_async_auth_epilogue(status, s3call);
+}
+
+/* Plaintext authentication
+
+ This interface is used by ntlm_auth in it's 'basic' authentication
+ mode, as well as by pam_winbind to authenticate users where we are
+ given a plaintext password.
+*/
+
+static void pam_auth_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_pam_auth(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+ struct cli_credentials *credentials;
+ char *user, *domain;
+
+ if (!wb_samba3_split_username(s3call, s3call->wbconn->lp_ctx,
+ s3call->request.data.auth.user,
+ &domain, &user)) {
+ return NT_STATUS_NO_SUCH_USER;
+ }
+
+ credentials = cli_credentials_init(s3call);
+ if (!credentials) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ cli_credentials_set_conf(credentials, service->task->lp_ctx);
+ cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
+ cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
+
+ cli_credentials_set_password(credentials, s3call->request.data.auth.pass, CRED_SPECIFIED);
+
+ ctx = wb_cmd_pam_auth_send(s3call, service, credentials);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = pam_auth_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void pam_auth_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+
+ status = wb_cmd_pam_auth_recv(ctx);
+
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ done:
+ wbsrv_samba3_async_auth_epilogue(status, s3call);
+}
+
+/*
+ List trusted domains
+*/
+
+static void list_trustdom_recv_doms(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_list_trustdom(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_list_trustdom called\n"));
+
+ ctx = wb_cmd_list_trustdoms_send(s3call, service);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = list_trustdom_recv_doms;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void list_trustdom_recv_doms(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ int i, num_domains;
+ struct wb_dom_info **domains;
+ NTSTATUS status;
+ char *result;
+
+ status = wb_cmd_list_trustdoms_recv(ctx, s3call, &num_domains,
+ &domains);
+ if (!NT_STATUS_IS_OK(status)) goto done;
+
+ result = talloc_strdup(s3call, "");
+ if (result == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ for (i=0; i<num_domains; i++) {
+ result = talloc_asprintf_append_buffer(
+ result, "%s\\%s\\%s",
+ domains[i]->name, domains[i]->name,
+ dom_sid_string(s3call, domains[i]->sid));
+ }
+
+ if (result == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ s3call->response.result = WINBINDD_OK;
+ if (num_domains > 0) {
+ s3call->response.extra_data.data = result;
+ s3call->response.length += strlen(result)+1;
+ }
+
+ done:
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+
+/* List users */
+
+static void list_users_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_list_users(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_list_users called\n"));
+
+ ctx = wb_cmd_list_users_send(s3call, service,
+ s3call->request.domain_name);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = list_users_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void list_users_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ uint32_t extra_data_len;
+ char *extra_data;
+ NTSTATUS status;
+
+ DEBUG(5, ("list_users_recv called\n"));
+
+ status = wb_cmd_list_users_recv(ctx, s3call, &extra_data_len,
+ &extra_data);
+
+ if (NT_STATUS_IS_OK(status)) {
+ s3call->response.extra_data.data = extra_data;
+ s3call->response.length += extra_data_len;
+ if (extra_data) {
+ s3call->response.length += 1;
+ }
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+/* NSS calls */
+
+static void getpwnam_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwnam(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_getpwnam called\n"));
+
+ ctx = wb_cmd_getpwnam_send(s3call, service,
+ s3call->request.data.username);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = getpwnam_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void getpwnam_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct winbindd_pw *pw;
+
+ DEBUG(5, ("getpwnam_recv called\n"));
+
+ status = wb_cmd_getpwnam_recv(ctx, s3call, &pw);
+ if(NT_STATUS_IS_OK(status))
+ s3call->response.data.pw = *pw;
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void getpwuid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwuid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_getpwuid called\n"));
+
+ ctx = wb_cmd_getpwuid_send(s3call, service,
+ s3call->request.data.uid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = getpwuid_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void getpwuid_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct winbindd_pw *pw;
+
+ DEBUG(5, ("getpwuid_recv called\n"));
+
+ status = wb_cmd_getpwuid_recv(ctx, s3call, &pw);
+ if (NT_STATUS_IS_OK(status))
+ s3call->response.data.pw = *pw;
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void setpwent_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_setpwent(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_setpwent called\n"));
+
+ ctx = wb_cmd_setpwent_send(s3call, service);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = setpwent_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void setpwent_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct wbsrv_pwent *pwent;
+
+ DEBUG(5, ("setpwent_recv called\n"));
+
+ status = wb_cmd_setpwent_recv(ctx, s3call->wbconn, &pwent);
+ if (NT_STATUS_IS_OK(status)) {
+ s3call->wbconn->protocol_private_data = pwent;
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void getpwent_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_getpwent(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service = s3call->wbconn->listen_socket->service;
+ struct wbsrv_pwent *pwent;
+
+ DEBUG(5, ("wbsrv_samba3_getpwent called\n"));
+
+ NT_STATUS_HAVE_NO_MEMORY(s3call->wbconn->protocol_private_data);
+
+ pwent = talloc_get_type(s3call->wbconn->protocol_private_data,
+ struct wbsrv_pwent);
+ NT_STATUS_HAVE_NO_MEMORY(pwent);
+
+ ctx = wb_cmd_getpwent_send(s3call, service, pwent,
+ s3call->request.data.num_entries);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = getpwent_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+}
+
+static void getpwent_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct winbindd_pw *pw;
+ uint32_t num_users;
+
+ DEBUG(5, ("getpwent_recv called\n"));
+
+ status = wb_cmd_getpwent_recv(ctx, s3call, &pw, &num_users);
+ if (NT_STATUS_IS_OK(status)) {
+ uint32_t extra_len = sizeof(struct winbindd_pw) * num_users;
+
+ s3call->response.data.num_entries = num_users;
+ s3call->response.extra_data.data = pw;
+ s3call->response.length += extra_len;
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+NTSTATUS wbsrv_samba3_endpwent(struct wbsrv_samba3_call *s3call)
+{
+ struct wbsrv_pwent *pwent =
+ talloc_get_type(s3call->wbconn->protocol_private_data,
+ struct wbsrv_pwent);
+ DEBUG(5, ("wbsrv_samba3_endpwent called\n"));
+
+ talloc_free(pwent);
+
+ s3call->wbconn->protocol_private_data = NULL;
+ s3call->response.result = WINBINDD_OK;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrnam(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_getgrnam called\n"));
+ s3call->response.result = WINBINDD_ERROR;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrgid(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_getgrgid called\n"));
+ s3call->response.result = WINBINDD_ERROR;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgroups(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_getgroups called\n"));
+ s3call->response.result = WINBINDD_ERROR;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_setgrent(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_setgrent called\n"));
+ s3call->response.result = WINBINDD_OK;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_getgrent(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_getgrent called\n"));
+ s3call->response.result = WINBINDD_ERROR;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_endgrent(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(5, ("wbsrv_samba3_endgrent called\n"));
+ s3call->response.result = WINBINDD_OK;
+ return NT_STATUS_OK;
+}
+
+static void sid2uid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_sid2uid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_sid2uid called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ NT_STATUS_HAVE_NO_MEMORY(sid);
+
+ ctx = wb_sid2uid_send(s3call, service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = sid2uid_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+
+}
+
+static void sid2uid_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+
+ DEBUG(5, ("sid2uid_recv called\n"));
+
+ status = wb_sid2uid_recv(ctx, &s3call->response.data.uid);
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void sid2gid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_sid2gid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+ struct dom_sid *sid;
+
+ DEBUG(5, ("wbsrv_samba3_sid2gid called\n"));
+
+ sid = dom_sid_parse_talloc(s3call, s3call->request.data.sid);
+ NT_STATUS_HAVE_NO_MEMORY(sid);
+
+ ctx = wb_sid2gid_send(s3call, service, sid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = sid2gid_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+
+}
+
+static void sid2gid_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+
+ DEBUG(5, ("sid2gid_recv called\n"));
+
+ status = wb_sid2gid_recv(ctx, &s3call->response.data.gid);
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void uid2sid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_uid2sid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_uid2sid called\n"));
+
+ ctx = wb_uid2sid_send(s3call, service, s3call->request.data.uid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = uid2sid_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+
+}
+
+static void uid2sid_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct dom_sid *sid;
+ char *sid_str;
+
+ DEBUG(5, ("uid2sid_recv called\n"));
+
+ status = wb_uid2sid_recv(ctx, s3call, &sid);
+ if(NT_STATUS_IS_OK(status)) {
+ sid_str = dom_sid_string(s3call, sid);
+
+ /* If the conversion failed, bail out with a failure. */
+ if (sid_str == NULL)
+ wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
+
+ /* But we assume this worked, so we'll set the string. Work
+ * done. */
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
+ s3call->response.data.sid.type = SID_NAME_USER;
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
+static void gid2sid_recv(struct composite_context *ctx);
+
+NTSTATUS wbsrv_samba3_gid2sid(struct wbsrv_samba3_call *s3call)
+{
+ struct composite_context *ctx;
+ struct wbsrv_service *service =
+ s3call->wbconn->listen_socket->service;
+
+ DEBUG(5, ("wbsrv_samba3_gid2sid called\n"));
+
+ ctx = wb_gid2sid_send(s3call, service, s3call->request.data.gid);
+ NT_STATUS_HAVE_NO_MEMORY(ctx);
+
+ ctx->async.fn = gid2sid_recv;
+ ctx->async.private_data = s3call;
+ s3call->flags |= WBSRV_CALL_FLAGS_REPLY_ASYNC;
+ return NT_STATUS_OK;
+
+}
+
+static void gid2sid_recv(struct composite_context *ctx)
+{
+ struct wbsrv_samba3_call *s3call =
+ talloc_get_type(ctx->async.private_data,
+ struct wbsrv_samba3_call);
+ NTSTATUS status;
+ struct dom_sid *sid;
+ char *sid_str;
+
+ DEBUG(5, ("gid2sid_recv called\n"));
+
+ status = wb_gid2sid_recv(ctx, s3call, &sid);
+ if(NT_STATUS_IS_OK(status)) {
+ sid_str = dom_sid_string(s3call, sid);
+
+ if (sid_str == NULL)
+ wbsrv_samba3_async_epilogue(NT_STATUS_NO_MEMORY,s3call);
+
+ WBSRV_SAMBA3_SET_STRING(s3call->response.data.sid.sid, sid_str);
+ s3call->response.data.sid.type = SID_NAME_DOMAIN;
+ }
+
+ wbsrv_samba3_async_epilogue(status, s3call);
+}
+
diff --git a/source4/winbind/wb_samba3_protocol.c b/source4/winbind/wb_samba3_protocol.c
new file mode 100644
index 0000000000..3b97dff276
--- /dev/null
+++ b/source4/winbind/wb_samba3_protocol.c
@@ -0,0 +1,300 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main winbindd samba3 server routines
+
+ Copyright (C) Stefan Metzmacher 2005
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_stream.h"
+#include "lib/stream/packet.h"
+
+/*
+ work out if a packet is complete for protocols that use a 32 bit host byte
+ order length
+*/
+NTSTATUS wbsrv_samba3_packet_full_request(void *private, DATA_BLOB blob, size_t *size)
+{
+ uint32_t *len;
+ if (blob.length < 4) {
+ return STATUS_MORE_ENTRIES;
+ }
+ len = (uint32_t *)blob.data;
+ *size = (*len);
+ if (*size > blob.length) {
+ return STATUS_MORE_ENTRIES;
+ }
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS wbsrv_samba3_pull_request(DATA_BLOB blob, struct wbsrv_connection *wbconn,
+ struct wbsrv_samba3_call **_call)
+{
+ struct wbsrv_samba3_call *call;
+
+ if (blob.length != sizeof(call->request)) {
+ DEBUG(0,("wbsrv_samba3_pull_request: invalid blob length %lu should be %lu\n"
+ " make sure you use the correct winbind client tools!\n",
+ (long)blob.length, (long)sizeof(call->request)));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ call = talloc_zero(wbconn, struct wbsrv_samba3_call);
+ NT_STATUS_HAVE_NO_MEMORY(call);
+
+ /* the packet layout is the same as the in memory layout of the request, so just copy it */
+ memcpy(&call->request, blob.data, sizeof(call->request));
+
+ call->wbconn = wbconn;
+ call->event_ctx = call->wbconn->conn->event.ctx;
+
+ *_call = call;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS wbsrv_samba3_handle_call(struct wbsrv_samba3_call *s3call)
+{
+ DEBUG(10, ("Got winbind samba3 request %d\n", s3call->request.cmd));
+
+ s3call->response.length = sizeof(s3call->response);
+
+ switch(s3call->request.cmd) {
+ case WINBINDD_INTERFACE_VERSION:
+ return wbsrv_samba3_interface_version(s3call);
+
+ case WINBINDD_CHECK_MACHACC:
+ return wbsrv_samba3_check_machacc(s3call);
+
+ case WINBINDD_PING:
+ return wbsrv_samba3_ping(s3call);
+
+ case WINBINDD_INFO:
+ return wbsrv_samba3_info(s3call);
+
+ case WINBINDD_DOMAIN_NAME:
+ return wbsrv_samba3_domain_name(s3call);
+
+ case WINBINDD_NETBIOS_NAME:
+ return wbsrv_samba3_netbios_name(s3call);
+
+ case WINBINDD_PRIV_PIPE_DIR:
+ return wbsrv_samba3_priv_pipe_dir(s3call);
+
+ case WINBINDD_LOOKUPNAME:
+ return wbsrv_samba3_lookupname(s3call);
+
+ case WINBINDD_LOOKUPSID:
+ return wbsrv_samba3_lookupsid(s3call);
+
+ case WINBINDD_PAM_AUTH:
+ return wbsrv_samba3_pam_auth(s3call);
+
+ case WINBINDD_PAM_AUTH_CRAP:
+ return wbsrv_samba3_pam_auth_crap(s3call);
+
+ case WINBINDD_GETDCNAME:
+ return wbsrv_samba3_getdcname(s3call);
+
+ case WINBINDD_GETUSERDOMGROUPS:
+ return wbsrv_samba3_userdomgroups(s3call);
+
+ case WINBINDD_GETUSERSIDS:
+ return wbsrv_samba3_usersids(s3call);
+
+ case WINBINDD_LIST_TRUSTDOM:
+ return wbsrv_samba3_list_trustdom(s3call);
+
+ case WINBINDD_LIST_USERS:
+ return wbsrv_samba3_list_users(s3call);
+
+ case WINBINDD_GETPWNAM:
+ return wbsrv_samba3_getpwnam(s3call);
+
+ case WINBINDD_GETPWUID:
+ return wbsrv_samba3_getpwuid(s3call);
+
+ case WINBINDD_SETPWENT:
+ return wbsrv_samba3_setpwent(s3call);
+
+ case WINBINDD_GETPWENT:
+ return wbsrv_samba3_getpwent(s3call);
+
+ case WINBINDD_ENDPWENT:
+ return wbsrv_samba3_endpwent(s3call);
+
+ case WINBINDD_GETGRNAM:
+ return wbsrv_samba3_getgrnam(s3call);
+
+ case WINBINDD_GETGRGID:
+ return wbsrv_samba3_getgrgid(s3call);
+
+ case WINBINDD_GETGROUPS:
+ return wbsrv_samba3_getgroups(s3call);
+
+ case WINBINDD_SETGRENT:
+ return wbsrv_samba3_setgrent(s3call);
+
+ case WINBINDD_GETGRENT:
+ return wbsrv_samba3_getgrent(s3call);
+
+ case WINBINDD_ENDGRENT:
+ return wbsrv_samba3_endgrent(s3call);
+
+ case WINBINDD_SID_TO_UID:
+ case WINBINDD_DUAL_SID2UID:
+ return wbsrv_samba3_sid2uid(s3call);
+
+ case WINBINDD_SID_TO_GID:
+ case WINBINDD_DUAL_SID2GID:
+ return wbsrv_samba3_sid2gid(s3call);
+
+ case WINBINDD_UID_TO_SID:
+ case WINBINDD_DUAL_UID2SID:
+ return wbsrv_samba3_uid2sid(s3call);
+
+ case WINBINDD_GID_TO_SID:
+ case WINBINDD_DUAL_GID2SID:
+ return wbsrv_samba3_gid2sid(s3call);
+
+ /* Unimplemented commands */
+
+ case WINBINDD_PAM_CHAUTHTOK:
+ case WINBINDD_PAM_LOGOFF:
+ case WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP:
+ case WINBINDD_LIST_GROUPS:
+ case WINBINDD_LOOKUPRIDS:
+ case WINBINDD_SIDS_TO_XIDS:
+ case WINBINDD_ALLOCATE_UID:
+ case WINBINDD_ALLOCATE_GID:
+ case WINBINDD_SET_MAPPING:
+ case WINBINDD_SET_HWM:
+ case WINBINDD_DUMP_MAPS:
+ case WINBINDD_DOMAIN_INFO:
+ case WINBINDD_SHOW_SEQUENCE:
+ case WINBINDD_WINS_BYIP:
+ case WINBINDD_WINS_BYNAME:
+ case WINBINDD_GETGRLST:
+ case WINBINDD_INIT_CONNECTION:
+ case WINBINDD_DUAL_SIDS2XIDS:
+ case WINBINDD_DUAL_SET_MAPPING:
+ case WINBINDD_DUAL_SET_HWM:
+ case WINBINDD_DUAL_DUMP_MAPS:
+ case WINBINDD_DUAL_UID2NAME:
+ case WINBINDD_DUAL_NAME2UID:
+ case WINBINDD_DUAL_GID2NAME:
+ case WINBINDD_DUAL_NAME2GID:
+ case WINBINDD_DUAL_USERINFO:
+ case WINBINDD_DUAL_GETSIDALIASES:
+ case WINBINDD_CCACHE_NTLMAUTH:
+ case WINBINDD_NUM_CMDS:
+ DEBUG(10, ("Unimplemented winbind samba3 request %d\n",
+ s3call->request.cmd));
+ break;
+ }
+
+ s3call->response.result = WINBINDD_ERROR;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS wbsrv_samba3_push_reply(struct wbsrv_samba3_call *call, TALLOC_CTX *mem_ctx, DATA_BLOB *_blob)
+{
+ DATA_BLOB blob;
+ uint8_t *extra_data;
+ size_t extra_data_len = 0;
+
+ extra_data = (uint8_t *)call->response.extra_data.data;
+ if (extra_data != NULL) {
+ extra_data_len = call->response.length -
+ sizeof(call->response);
+ }
+
+ blob = data_blob_talloc(mem_ctx, NULL, call->response.length);
+ NT_STATUS_HAVE_NO_MEMORY(blob.data);
+
+ /* don't push real pointer values into sockets */
+ if (extra_data) {
+ call->response.extra_data.data = (void *)0xFFFFFFFF;
+ }
+ memcpy(blob.data, &call->response, sizeof(call->response));
+ /* set back the pointer */
+ call->response.extra_data.data = extra_data;
+
+ if (extra_data) {
+ memcpy(blob.data + sizeof(call->response), extra_data, extra_data_len);
+ }
+
+ *_blob = blob;
+ return NT_STATUS_OK;
+}
+
+/*
+ * queue a wbsrv_call reply on a wbsrv_connection
+ * NOTE: that this implies talloc_free(call),
+ * use talloc_reference(call) if you need it after
+ * calling wbsrv_queue_reply
+ */
+NTSTATUS wbsrv_samba3_send_reply(struct wbsrv_samba3_call *call)
+{
+ struct wbsrv_connection *wbconn = call->wbconn;
+ DATA_BLOB rep;
+ NTSTATUS status;
+
+ status = wbsrv_samba3_push_reply(call, call, &rep);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ status = packet_send(call->wbconn->packet, rep);
+
+ talloc_free(call);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ wbsrv_terminate_connection(wbconn,
+ "failed to packet_send winbindd reply");
+ return status;
+ }
+ /* the call isn't needed any more */
+ return status;
+}
+
+NTSTATUS wbsrv_samba3_process(void *private, DATA_BLOB blob)
+{
+ NTSTATUS status;
+ struct wbsrv_connection *wbconn = talloc_get_type(private,
+ struct wbsrv_connection);
+ struct wbsrv_samba3_call *call;
+ status = wbsrv_samba3_pull_request(blob, wbconn, &call);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = wbsrv_samba3_handle_call(call);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(call);
+ return status;
+ }
+
+ if (call->flags & WBSRV_CALL_FLAGS_REPLY_ASYNC) {
+ return NT_STATUS_OK;
+ }
+
+ status = wbsrv_samba3_send_reply(call);
+ return status;
+}
+
diff --git a/source4/winbind/wb_server.c b/source4/winbind/wb_server.c
new file mode 100644
index 0000000000..d56a82ea18
--- /dev/null
+++ b/source4/winbind/wb_server.c
@@ -0,0 +1,227 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main winbindd server routines
+
+ Copyright (C) Stefan Metzmacher 2005
+ 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/>.
+*/
+
+#include "includes.h"
+#include "lib/socket/socket.h"
+#include "lib/util/dlinklist.h"
+#include "lib/events/events.h"
+#include "smbd/service_task.h"
+#include "smbd/process_model.h"
+#include "smbd/service_stream.h"
+#include "nsswitch/winbind_nss_config.h"
+#include "winbind/wb_server.h"
+#include "lib/stream/packet.h"
+#include "smbd/service.h"
+#include "param/secrets.h"
+#include "param/param.h"
+
+void wbsrv_terminate_connection(struct wbsrv_connection *wbconn, const char *reason)
+{
+ stream_terminate_connection(wbconn->conn, reason);
+}
+
+/*
+ called on a tcp recv error
+*/
+static void wbsrv_recv_error(void *private, NTSTATUS status)
+{
+ struct wbsrv_connection *wbconn = talloc_get_type(private, struct wbsrv_connection);
+ wbsrv_terminate_connection(wbconn, nt_errstr(status));
+}
+
+static void wbsrv_accept(struct stream_connection *conn)
+{
+ struct wbsrv_listen_socket *listen_socket = talloc_get_type(conn->private,
+ struct wbsrv_listen_socket);
+ struct wbsrv_connection *wbconn;
+
+ wbconn = talloc_zero(conn, struct wbsrv_connection);
+ if (!wbconn) {
+ stream_terminate_connection(conn, "wbsrv_accept: out of memory");
+ return;
+ }
+ wbconn->conn = conn;
+ wbconn->listen_socket = listen_socket;
+ wbconn->lp_ctx = listen_socket->service->task->lp_ctx;
+ conn->private = wbconn;
+
+ wbconn->packet = packet_init(wbconn);
+ if (wbconn->packet == NULL) {
+ wbsrv_terminate_connection(wbconn, "wbsrv_accept: out of memory");
+ return;
+ }
+ packet_set_private(wbconn->packet, wbconn);
+ packet_set_socket(wbconn->packet, conn->socket);
+ packet_set_callback(wbconn->packet, wbsrv_samba3_process);
+ packet_set_full_request(wbconn->packet, wbsrv_samba3_packet_full_request);
+ packet_set_error_handler(wbconn->packet, wbsrv_recv_error);
+ packet_set_event_context(wbconn->packet, conn->event.ctx);
+ packet_set_fde(wbconn->packet, conn->event.fde);
+ packet_set_serialise(wbconn->packet);
+}
+
+/*
+ receive some data on a winbind connection
+*/
+static void wbsrv_recv(struct stream_connection *conn, uint16_t flags)
+{
+ struct wbsrv_connection *wbconn = talloc_get_type(conn->private,
+ struct wbsrv_connection);
+ packet_recv(wbconn->packet);
+
+}
+
+/*
+ called when we can write to a connection
+*/
+static void wbsrv_send(struct stream_connection *conn, uint16_t flags)
+{
+ struct wbsrv_connection *wbconn = talloc_get_type(conn->private,
+ struct wbsrv_connection);
+ packet_queue_run(wbconn->packet);
+}
+
+static const struct stream_server_ops wbsrv_ops = {
+ .name = "winbind samba3 protocol",
+ .accept_connection = wbsrv_accept,
+ .recv_handler = wbsrv_recv,
+ .send_handler = wbsrv_send
+};
+
+/*
+ startup the winbind task
+*/
+static void winbind_task_init(struct task_server *task)
+{
+ uint16_t port = 1;
+ const struct model_ops *model_ops;
+ NTSTATUS status;
+ struct wbsrv_service *service;
+ struct wbsrv_listen_socket *listen_socket;
+
+ task_server_set_title(task, "task[winbind]");
+
+ /* within the winbind task we want to be a single process, so
+ ask for the single process model ops and pass these to the
+ stream_setup_socket() call. */
+ model_ops = process_model_byname("single");
+ if (!model_ops) {
+ task_server_terminate(task,
+ "Can't find 'single' process model_ops");
+ return;
+ }
+
+ /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
+ if (!directory_create_or_exist(lp_winbindd_socket_directory(task->lp_ctx), geteuid(), 0755)) {
+ task_server_terminate(task,
+ "Cannot create winbindd pipe directory");
+ return;
+ }
+
+ /* Make sure the directory for the Samba3 socket exists, and is of the correct permissions */
+ if (!directory_create_or_exist(lp_winbindd_privileged_socket_directory(task->lp_ctx), geteuid(), 0750)) {
+ task_server_terminate(task,
+ "Cannot create winbindd privileged pipe directory");
+ return;
+ }
+
+ service = talloc_zero(task, struct wbsrv_service);
+ if (!service) goto nomem;
+ service->task = task;
+
+ service->primary_sid = secrets_get_domain_sid(service,
+ task->event_ctx,
+ task->lp_ctx,
+ lp_workgroup(task->lp_ctx));
+ if (service->primary_sid == NULL) {
+ task_server_terminate(
+ task, nt_errstr(NT_STATUS_CANT_ACCESS_DOMAIN_INFO));
+ return;
+ }
+
+ service->idmap_ctx = idmap_init(service, task->event_ctx, task->lp_ctx);
+ if (service->idmap_ctx == NULL) {
+ task_server_terminate(task, "Failed to load idmap database");
+ return;
+ }
+
+ /* setup the unprivileged samba3 socket */
+ listen_socket = talloc(service, struct wbsrv_listen_socket);
+ if (!listen_socket) goto nomem;
+ listen_socket->socket_path = talloc_asprintf(listen_socket, "%s/%s",
+ lp_winbindd_socket_directory(task->lp_ctx),
+ WINBINDD_SAMBA3_SOCKET);
+ if (!listen_socket->socket_path) goto nomem;
+ listen_socket->service = service;
+ listen_socket->privileged = false;
+ status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
+ &wbsrv_ops, "unix",
+ listen_socket->socket_path, &port,
+ lp_socket_options(task->lp_ctx),
+ listen_socket);
+ if (!NT_STATUS_IS_OK(status)) goto listen_failed;
+
+ /* setup the privileged samba3 socket */
+ listen_socket = talloc(service, struct wbsrv_listen_socket);
+ if (!listen_socket) goto nomem;
+ listen_socket->socket_path
+ = service->priv_socket_path
+ = talloc_asprintf(listen_socket, "%s/%s",
+ lp_winbindd_privileged_socket_directory(task->lp_ctx),
+ WINBINDD_SAMBA3_SOCKET);
+ if (!listen_socket->socket_path) goto nomem;
+ if (!listen_socket->socket_path) goto nomem;
+ listen_socket->service = service;
+ listen_socket->privileged = true;
+ status = stream_setup_socket(task->event_ctx, task->lp_ctx, model_ops,
+ &wbsrv_ops, "unix",
+ listen_socket->socket_path, &port,
+ lp_socket_options(task->lp_ctx),
+ listen_socket);
+ if (!NT_STATUS_IS_OK(status)) goto listen_failed;
+
+ status = wbsrv_init_irpc(service);
+ if (!NT_STATUS_IS_OK(status)) goto irpc_failed;
+
+ return;
+
+listen_failed:
+ DEBUG(0,("stream_setup_socket(path=%s) failed - %s\n",
+ listen_socket->socket_path, nt_errstr(status)));
+ task_server_terminate(task, nt_errstr(status));
+ return;
+irpc_failed:
+ DEBUG(0,("wbsrv_init_irpc() failed - %s\n",
+ nt_errstr(status)));
+ task_server_terminate(task, nt_errstr(status));
+ return;
+nomem:
+ task_server_terminate(task, nt_errstr(NT_STATUS_NO_MEMORY));
+ return;
+}
+
+/*
+ register ourselves as a available server
+*/
+NTSTATUS server_service_winbind_init(void)
+{
+ return register_server_service("winbind", winbind_task_init);
+}
diff --git a/source4/winbind/wb_server.h b/source4/winbind/wb_server.h
new file mode 100644
index 0000000000..97d7d8151e
--- /dev/null
+++ b/source4/winbind/wb_server.h
@@ -0,0 +1,169 @@
+/*
+ Unix SMB/CIFS implementation.
+ Main winbindd server routines
+
+ Copyright (C) Stefan Metzmacher 2005
+ 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/>.
+*/
+
+#include "nsswitch/winbind_nss_config.h"
+#include "nsswitch/winbind_struct_protocol.h"
+#include "winbind/idmap.h"
+#include "libnet/libnet.h"
+
+#define WINBINDD_SAMBA3_SOCKET "pipe"
+/* the privileged socket is in smbd_tmp_dir() */
+#define WINBINDD_SAMBA3_PRIVILEGED_SOCKET "winbind_pipe"
+
+/* this struct stores global data for the winbind task */
+struct wbsrv_service {
+ struct task_server *task;
+
+ const struct dom_sid *primary_sid;
+ struct wbsrv_domain *domains;
+ struct idmap_context *idmap_ctx;
+
+ const char *priv_socket_path;
+};
+
+struct wbsrv_samconn {
+ struct wbsrv_domain *domain;
+ void *private_data;
+
+ struct composite_context (*seqnum_send)(struct wbsrv_samconn *);
+ NTSTATUS (*seqnum_recv)(struct composite_context *, uint64_t *);
+};
+
+struct wb_dom_info {
+ const char *name;
+ const char *dns_name;
+ const struct dom_sid *sid;
+
+ int num_dcs;
+ struct nbt_dc_name *dcs;
+};
+
+struct wbsrv_domain {
+ struct wbsrv_domain *next, *prev;
+
+ struct wb_dom_info *info;
+
+ /* Details for the server we are currently talking to */
+ const char *dc_address;
+ const char *dc_name;
+
+ struct libnet_context *libnet_ctx;
+
+ struct dcerpc_binding *lsa_binding;
+
+ struct dcerpc_binding *samr_binding;
+
+ struct dcerpc_pipe *netlogon_pipe;
+ struct dcerpc_binding *netlogon_binding;
+};
+
+/*
+ state of a listen socket and it's protocol information
+*/
+struct wbsrv_listen_socket {
+ const char *socket_path;
+ struct wbsrv_service *service;
+ bool privileged;
+};
+
+/*
+ state of an open winbind connection
+*/
+struct wbsrv_connection {
+ /* stream connection we belong to */
+ struct stream_connection *conn;
+
+ /* the listening socket we belong to, it holds protocol hooks */
+ struct wbsrv_listen_socket *listen_socket;
+
+ /* storage for protocol specific data */
+ void *protocol_private_data;
+
+ /* how many calls are pending */
+ uint32_t pending_calls;
+
+ struct packet_context *packet;
+
+ struct loadparm_context *lp_ctx;
+};
+
+#define WBSRV_SAMBA3_SET_STRING(dest, src) do { \
+ safe_strcpy(dest, src, sizeof(dest)-1);\
+} while(0)
+
+/*
+ state of a pwent query
+*/
+struct wbsrv_pwent {
+ /* Current UserList structure, contains 1+ user structs */
+ struct libnet_UserList *user_list;
+
+ /* Index of the next user struct in the current UserList struct */
+ uint32_t page_index;
+
+ /* The libnet_ctx to use for the libnet_UserList call */
+ struct libnet_context *libnet_ctx;
+};
+
+/*
+ state of one request
+
+ NOTE about async replies:
+ if the backend wants to reply later:
+
+ - it should set the WBSRV_CALL_FLAGS_REPLY_ASYNC flag, and may set a
+ talloc_destructor on the this structure or on the private_data (if it's a
+ talloc child of this structure), so that wbsrv_terminate_connection
+ called by another call clean up the whole connection correct.
+ - When the backend is ready to reply it should call wbsrv_send_reply(call),
+ wbsrv_send_reply implies talloc_free(call), so the backend should use
+ talloc_reference(call), if it needs it later.
+ - If wbsrv_send_reply doesn't return NT_STATUS_OK, the backend function
+ should call, wbsrv_terminate_connection(call->wbconn, nt_errstr(status));
+ return;
+
+*/
+struct wbsrv_samba3_call {
+#define WBSRV_CALL_FLAGS_REPLY_ASYNC 0x00000001
+ uint32_t flags;
+
+ /* the connection the call belongs to */
+ struct wbsrv_connection *wbconn;
+
+ /* the backend should use this event context */
+ struct event_context *event_ctx;
+
+ /* here the backend can store stuff like composite_context's ... */
+ void *private_data;
+
+ /* the request structure of the samba3 protocol */
+ struct winbindd_request request;
+
+ /* the response structure of the samba3 protocol*/
+ struct winbindd_response response;
+};
+
+struct netr_LMSessionKey;
+struct netr_UserSessionKey;
+struct winbind_SamLogon;
+
+#include "winbind/wb_async_helpers.h"
+#include "winbind/wb_proto.h"
diff --git a/source4/winbind/wb_sid2domain.c b/source4/winbind/wb_sid2domain.c
new file mode 100644
index 0000000000..fcf02cedcd
--- /dev/null
+++ b/source4/winbind/wb_sid2domain.c
@@ -0,0 +1,212 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Find and init a domain struct for a SID
+
+ Copyright (C) Volker Lendecke 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/>.
+*/
+
+#include "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_async_helpers.h"
+#include "libcli/security/security.h"
+#include "lib/util/dlinklist.h"
+#include "param/param.h"
+
+static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service,
+ const struct dom_sid *sid)
+{
+ struct wbsrv_domain *domain;
+
+ for (domain = service->domains; domain!=NULL; domain = domain->next) {
+ if (dom_sid_equal(domain->info->sid, sid)) {
+ break;
+ }
+ if (dom_sid_in_domain(domain->info->sid, sid)) {
+ break;
+ }
+ }
+ return domain;
+}
+
+struct sid2domain_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct dom_sid *sid;
+
+ struct wbsrv_domain *domain;
+};
+
+static void sid2domain_recv_dom_info(struct composite_context *ctx);
+static void sid2domain_recv_name(struct composite_context *ctx);
+static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx);
+static void sid2domain_recv_init(struct composite_context *ctx);
+
+struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct sid2domain_state *state;
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (result == NULL) goto failed;
+
+ state = talloc(result, struct sid2domain_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
+
+ state->service = service;
+ state->sid = dom_sid_dup(state, sid);
+ if (state->sid == NULL) goto failed;
+
+ state->domain = find_domain_from_sid(service, sid);
+ if (state->domain != NULL) {
+ result->status = NT_STATUS_OK;
+ composite_done(result);
+ return result;
+ }
+
+ if (dom_sid_equal(service->primary_sid, sid) ||
+ dom_sid_in_domain(service->primary_sid, sid)) {
+ ctx = wb_get_dom_info_send(state, service, lp_workgroup(service->task->lp_ctx),
+ service->primary_sid);
+ if (ctx == NULL) goto failed;
+ ctx->async.fn = sid2domain_recv_dom_info;
+ ctx->async.private_data = state;
+ return result;
+ }
+
+ ctx = wb_cmd_lookupsid_send(state, service, state->sid);
+ if (ctx == NULL) goto failed;
+ composite_continue(result, ctx, sid2domain_recv_name, state);
+
+ return result;
+
+ failed:
+ talloc_free(result);
+ return NULL;
+
+}
+
+static void sid2domain_recv_dom_info(struct composite_context *ctx)
+{
+ struct sid2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct sid2domain_state);
+ struct wb_dom_info *info;
+
+ state->ctx->status = wb_get_dom_info_recv(ctx, state, &info);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_init_domain_send(state, state->service, info);
+
+ composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
+}
+
+static void sid2domain_recv_name(struct composite_context *ctx)
+{
+ struct sid2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct sid2domain_state);
+ struct wb_sid_object *name;
+
+ state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name);
+ if (!composite_is_ok(state->ctx)) return;
+
+ if (name->type == SID_NAME_UNKNOWN) {
+ composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN);
+ return;
+ }
+
+ if (name->type != SID_NAME_DOMAIN) {
+ state->sid->num_auths -= 1;
+ }
+
+ ctx = wb_trusted_dom_info_send(state, state->service, name->domain,
+ state->sid);
+
+ composite_continue(state->ctx, ctx, sid2domain_recv_trusted_dom_info,
+ state);
+}
+
+static void sid2domain_recv_trusted_dom_info(struct composite_context *ctx)
+{
+ struct sid2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct sid2domain_state);
+ struct wb_dom_info *info;
+
+ state->ctx->status = wb_trusted_dom_info_recv(ctx, state, &info);
+ if (!composite_is_ok(state->ctx)) return;
+
+ ctx = wb_init_domain_send(state, state->service, info);
+
+ composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
+}
+
+static void sid2domain_recv_init(struct composite_context *ctx)
+{
+ struct sid2domain_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct sid2domain_state);
+ struct wbsrv_domain *existing;
+
+ state->ctx->status = wb_init_domain_recv(ctx, state,
+ &state->domain);
+ if (!composite_is_ok(state->ctx)) {
+ DEBUG(10, ("Could not init domain\n"));
+ return;
+ }
+
+ existing = find_domain_from_sid(state->service, state->sid);
+ if (existing != NULL) {
+ DEBUG(5, ("Initialized domain twice, dropping second one\n"));
+ talloc_free(state->domain);
+ state->domain = existing;
+ }
+
+ talloc_steal(state->service, state->domain);
+ DLIST_ADD(state->service->domains, state->domain);
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_sid2domain_recv(struct composite_context *ctx,
+ struct wbsrv_domain **result)
+{
+ NTSTATUS status = composite_wait(ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ struct sid2domain_state *state =
+ talloc_get_type(ctx->private_data,
+ struct sid2domain_state);
+ *result = state->domain;
+ }
+ talloc_free(ctx);
+ return status;
+}
+
+NTSTATUS wb_sid2domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
+ const struct dom_sid *sid,
+ struct wbsrv_domain **result)
+{
+ struct composite_context *c = wb_sid2domain_send(mem_ctx, service,
+ sid);
+ return wb_sid2domain_recv(c, result);
+}
diff --git a/source4/winbind/wb_sid2gid.c b/source4/winbind/wb_sid2gid.c
new file mode 100644
index 0000000000..d68956ce85
--- /dev/null
+++ b/source4/winbind/wb_sid2gid.c
@@ -0,0 +1,109 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Map a SID to a gid
+
+ Copyright (C) 2007-2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct sid2gid_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ gid_t gid;
+};
+
+static void sid2gid_recv_gid(struct composite_context *ctx);
+
+struct composite_context *wb_sid2gid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct sid2gid_state *state;
+ struct id_mapping *ids;
+
+ DEBUG(5, ("wb_sid2gid_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct sid2gid_state);
+ if(composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ ids = talloc(result, struct id_mapping);
+ if (composite_nomem(ids, result)) return result;
+
+ ids->sid = dom_sid_dup(result, sid);
+ if (composite_nomem(ids->sid, result)) return result;
+
+ ctx = wb_sids2xids_send(result, service, 1, ids);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, sid2gid_recv_gid, state);
+ return result;
+}
+
+static void sid2gid_recv_gid(struct composite_context *ctx)
+{
+ struct sid2gid_state *state = talloc_get_type(ctx->async.private_data,
+ struct sid2gid_state);
+
+ struct id_mapping *ids = NULL;
+
+ state->ctx->status = wb_sids2xids_recv(ctx, &ids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ if (!NT_STATUS_IS_OK(ids->status)) {
+ composite_error(state->ctx, ids->status);
+ return;
+ }
+
+ if (ids->unixid->type == ID_TYPE_BOTH ||
+ ids->unixid->type == ID_TYPE_GID) {
+ state->gid = ids->unixid->id;
+ composite_done(state->ctx);
+ } else {
+ composite_error(state->ctx, NT_STATUS_INVALID_SID);
+ }
+}
+
+NTSTATUS wb_sid2gid_recv(struct composite_context *ctx, gid_t *gid)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_sid2gid_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct sid2gid_state *state =
+ talloc_get_type(ctx->private_data,
+ struct sid2gid_state);
+ *gid = state->gid;
+ }
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_sid2uid.c b/source4/winbind/wb_sid2uid.c
new file mode 100644
index 0000000000..b65e41978c
--- /dev/null
+++ b/source4/winbind/wb_sid2uid.c
@@ -0,0 +1,109 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Map a SID to a uid
+
+ Copyright (C) 2007-2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct sid2uid_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ uid_t uid;
+};
+
+static void sid2uid_recv_uid(struct composite_context *ctx);
+
+struct composite_context *wb_sid2uid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, const struct dom_sid *sid)
+{
+ struct composite_context *result, *ctx;
+ struct sid2uid_state *state;
+ struct id_mapping *ids;
+
+ DEBUG(5, ("wb_sid2uid_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct sid2uid_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ ids = talloc(result, struct id_mapping);
+ if (composite_nomem(ids, result)) return result;
+
+ ids->sid = dom_sid_dup(result, sid);
+ if (composite_nomem(ids->sid, result)) return result;
+
+ ctx = wb_sids2xids_send(result, service, 1, ids);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, sid2uid_recv_uid, state);
+ return result;
+}
+
+static void sid2uid_recv_uid(struct composite_context *ctx)
+{
+ struct sid2uid_state *state = talloc_get_type(ctx->async.private_data,
+ struct sid2uid_state);
+
+ struct id_mapping *ids = NULL;
+
+ state->ctx->status = wb_sids2xids_recv(ctx, &ids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ if (!NT_STATUS_IS_OK(ids->status)) {
+ composite_error(state->ctx, ids->status);
+ return;
+ }
+
+ if (ids->unixid->type == ID_TYPE_BOTH ||
+ ids->unixid->type == ID_TYPE_UID) {
+ state->uid = ids->unixid->id;
+ composite_done(state->ctx);
+ } else {
+ composite_error(state->ctx, NT_STATUS_INVALID_SID);
+ }
+}
+
+NTSTATUS wb_sid2uid_recv(struct composite_context *ctx, uid_t *uid)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_sid2uid_recv called\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct sid2uid_state *state =
+ talloc_get_type(ctx->private_data,
+ struct sid2uid_state);
+ *uid = state->uid;
+ }
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_sids2xids.c b/source4/winbind/wb_sids2xids.c
new file mode 100644
index 0000000000..6b89caf465
--- /dev/null
+++ b/source4/winbind/wb_sids2xids.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Map SIDs to unixids.
+
+ Copyright (C) 2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct sids2xids_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct id_mapping *ids;
+ int count;
+};
+
+struct composite_context *wb_sids2xids_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ int count, struct id_mapping *ids)
+{
+ struct composite_context *result;
+ struct sids2xids_state *state;
+
+ DEBUG(5, ("wb_sids2xids_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct sids2xids_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->count = count;
+ state->ids = ids;
+
+ state->ctx->status = idmap_sids_to_xids(service->idmap_ctx, mem_ctx,
+ count, state->ids);
+ if (!composite_is_ok(state->ctx)) return result;
+
+ composite_done(state->ctx);
+ return result;
+}
+
+NTSTATUS wb_sids2xids_recv(struct composite_context *ctx,
+ struct id_mapping **ids)
+{
+ NTSTATUS status = composite_wait(ctx);
+ struct sids2xids_state *state = talloc_get_type(ctx->private_data,
+ struct sids2xids_state);
+
+ DEBUG(5, ("wb_sids2xids_recv called\n"));
+
+ *ids = state->ids;
+
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_uid2sid.c b/source4/winbind/wb_uid2sid.c
new file mode 100644
index 0000000000..fd43dd64b9
--- /dev/null
+++ b/source4/winbind/wb_uid2sid.c
@@ -0,0 +1,110 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Command backend for wbinfo -U
+
+ Copyright (C) 2007-2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct uid2sid_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct dom_sid *sid;
+};
+
+static void uid2sid_recv_sid(struct composite_context *ctx);
+
+struct composite_context *wb_uid2sid_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service, uid_t uid)
+{
+ struct composite_context *result, *ctx;
+ struct uid2sid_state *state;
+ struct unixid *unixid;
+ struct id_mapping *ids;
+
+ DEBUG(5, ("wb_uid2sid_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(result, struct uid2sid_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+
+ unixid = talloc(result, struct unixid);
+ if (composite_nomem(unixid, result)) return result;
+ unixid->id = uid;
+ unixid->type = ID_TYPE_UID;
+
+ ids = talloc(result, struct id_mapping);
+ if (composite_nomem(ids, result)) return result;
+ ids->unixid = unixid;
+ ids->sid = NULL;
+
+ ctx = wb_xids2sids_send(result, service, 1, ids);
+ if (composite_nomem(ctx, result)) return result;
+
+ composite_continue(result, ctx, uid2sid_recv_sid, state);
+ return result;
+}
+
+static void uid2sid_recv_sid(struct composite_context *ctx)
+{
+ struct uid2sid_state *state = talloc_get_type(ctx->async.private_data,
+ struct uid2sid_state);
+ struct id_mapping *ids = NULL;
+
+ state->ctx->status = wb_xids2sids_recv(ctx, &ids);
+ if (!composite_is_ok(state->ctx)) return;
+
+ if (!NT_STATUS_IS_OK(ids->status)) {
+ composite_error(state->ctx, ids->status);
+ return;
+ }
+
+ state->sid = ids->sid;
+
+ composite_done(state->ctx);
+}
+
+NTSTATUS wb_uid2sid_recv(struct composite_context *ctx, TALLOC_CTX *mem_ctx,
+ struct dom_sid **sid)
+{
+ NTSTATUS status = composite_wait(ctx);
+
+ DEBUG(5, ("wb_uid2sid_recv called.\n"));
+
+ if (NT_STATUS_IS_OK(status)) {
+ struct uid2sid_state *state =
+ talloc_get_type(ctx->private_data,
+ struct uid2sid_state);
+ *sid = talloc_steal(mem_ctx, state->sid);
+ }
+ talloc_free(ctx);
+ return status;
+}
+
diff --git a/source4/winbind/wb_utils.c b/source4/winbind/wb_utils.c
new file mode 100644
index 0000000000..43effc3028
--- /dev/null
+++ b/source4/winbind/wb_utils.c
@@ -0,0 +1,49 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Utility functions that are not related with async operations.
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 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/>.
+*/
+
+#include "includes.h"
+#include "param/param.h"
+
+
+/* Split a domain\\user string into it's parts, because the client supplies it
+ * as one string.
+ * TODO: We probably will need to handle other formats later. */
+
+bool wb_samba3_split_username(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
+ const char *domuser,
+ char **domain, char **user)
+{
+ char *p = strchr(domuser, *lp_winbind_separator(lp_ctx));
+
+ if (p == NULL) {
+ *domain = talloc_strdup(mem_ctx, lp_workgroup(lp_ctx));
+ } else {
+ *domain = talloc_strndup(mem_ctx, domuser,
+ PTR_DIFF(p, domuser));
+ domuser = p+1;
+ }
+
+ *user = talloc_strdup(mem_ctx, domuser);
+
+ return ((*domain != NULL) && (*user != NULL));
+}
+
+
diff --git a/source4/winbind/wb_xids2sids.c b/source4/winbind/wb_xids2sids.c
new file mode 100644
index 0000000000..a1cf2667ff
--- /dev/null
+++ b/source4/winbind/wb_xids2sids.c
@@ -0,0 +1,80 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Convet an unixid struct to a SID
+
+ Copyright (C) 2008 Kai Blin
+
+ 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 "includes.h"
+#include "libcli/composite/composite.h"
+#include "winbind/wb_server.h"
+#include "smbd/service_task.h"
+#include "winbind/wb_helper.h"
+#include "libcli/security/proto.h"
+#include "winbind/idmap.h"
+
+struct xids2sids_state {
+ struct composite_context *ctx;
+ struct wbsrv_service *service;
+ struct id_mapping *ids;
+ int count;
+};
+
+struct composite_context *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
+ struct wbsrv_service *service,
+ int count, struct id_mapping *ids)
+{
+ struct composite_context *result;
+ struct xids2sids_state *state;
+
+ DEBUG(5, ("wb_xids2sids_send called\n"));
+
+ result = composite_create(mem_ctx, service->task->event_ctx);
+ if (!result) return NULL;
+
+ state = talloc(mem_ctx, struct xids2sids_state);
+ if (composite_nomem(state, result)) return result;
+
+ state->ctx = result;
+ result->private_data = state;
+ state->service = service;
+ state->count = count;
+ state->ids = ids;
+
+ state->ctx->status = idmap_xids_to_sids(service->idmap_ctx, mem_ctx,
+ count, state->ids);
+ if (!composite_is_ok(state->ctx)) return result;
+
+ composite_done(state->ctx);
+ return result;
+}
+
+NTSTATUS wb_xids2sids_recv(struct composite_context *ctx,
+ struct id_mapping **ids)
+{
+ NTSTATUS status = composite_wait(ctx);
+ struct xids2sids_state *state = talloc_get_type(ctx->private_data,
+ struct xids2sids_state);
+
+ DEBUG(5, ("wb_xids2sids_recv called.\n"));
+
+ *ids = state->ids;
+
+ talloc_free(ctx);
+ return status;
+}
+