diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2008-04-04 16:02:17 +0200 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2008-04-04 16:02:17 +0200 |
commit | 30ccc36b8d61f2d09c3f0adeec4db0ab540619b8 (patch) | |
tree | 740fd5c06ebffb4991ede45182447d317603d115 | |
parent | adc09857420c4a9306148e8d15ff5faf633ba7a5 (diff) | |
parent | c26387a473fd26ac51c74c001b520d7fd7d353ec (diff) | |
download | samba-30ccc36b8d61f2d09c3f0adeec4db0ab540619b8.tar.gz samba-30ccc36b8d61f2d09c3f0adeec4db0ab540619b8.tar.bz2 samba-30ccc36b8d61f2d09c3f0adeec4db0ab540619b8.zip |
Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into openchange
Conflicts:
source/headermap.txt
(This used to be commit 1b084e85c1f5963d924f7764ae751f8cd8e57364)
29 files changed, 943 insertions, 287 deletions
diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 1e8f803f43..f58df497f5 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -97,6 +97,11 @@ continued to evolve, but you may particularly notice these areas: better integration with Windows administrative tools, especially Active Directory Users and Computers. + ID mapping: Samba4 now handles ID mapping via winbind. The mappings + are stored in a central ldb that could be shared across multiple + machines using LDAP. Internal callers access this interface via a new + wbclient library. + These are just some of the highlights of the work done in the past few months. More details can be found in our GIT history. diff --git a/source4/headermap.txt b/source4/headermap.txt index 7984149837..fbfc56e127 100644 --- a/source4/headermap.txt +++ b/source4/headermap.txt @@ -66,6 +66,8 @@ param/share.h: share.h lib/util/util_tdb.h: util_tdb.h lib/util/util_ldb.h: util_ldb.h lib/util/wrap_xattr.h: wrap_xattr.h +lib/events/events.h: events/events.h +lib/events/events_internal.h: events/events_internal.h libcli/ldap/ldap_ndr.h: ldap_ndr.h lib/events/events.h: events.h lib/events/events_internal.h: events_internal.h diff --git a/source4/lib/messaging/irpc.h b/source4/lib/messaging/irpc.h index d596c6721e..f44c0af3ec 100644 --- a/source4/lib/messaging/irpc.h +++ b/source4/lib/messaging/irpc.h @@ -19,6 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef IRPC_H +#define IRPC_H + #include "librpc/gen_ndr/irpc.h" /* @@ -123,4 +126,5 @@ struct server_id *irpc_servers_byname(struct messaging_context *msg_ctx, TALLOC_ void irpc_remove_name(struct messaging_context *msg_ctx, const char *name); NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status); +#endif diff --git a/source4/lib/util/util.c b/source4/lib/util/util.c index 7b6bfeeb7b..b5bb75358e 100644 --- a/source4/lib/util/util.c +++ b/source4/lib/util/util.c @@ -582,3 +582,18 @@ _PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count) return realloc(ptr, el_size * count); } +_PUBLIC_ void *talloc_check_name_abort(const void *ptr, const char *name) +{ + void *result; + + result = talloc_check_name(ptr, name); + if (result != NULL) + return result; + + DEBUG(0, ("Talloc type mismatch, expected %s, got %s\n", + name, talloc_get_name(ptr))); + smb_panic("talloc type mismatch"); + /* Keep the compiler happy */ + return NULL; +} + diff --git a/source4/lib/util/util.h b/source4/lib/util/util.h index 60c8437634..3bf6b98d2f 100644 --- a/source4/lib/util/util.h +++ b/source4/lib/util/util.h @@ -803,4 +803,11 @@ bool pm_process( const char *fileName, bool (*pfunc)(const char *, const char *, void *), void *userdata); +/** + * Add-on to talloc_get_type + */ +_PUBLIC_ void *talloc_check_name_abort(const void *ptr, const char *name); +#define talloc_get_type_abort(ptr, type) \ + (type *)talloc_check_name_abort(ptr, #type) + #endif /* _SAMBA_UTIL_H_ */ diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index b85fbe7066..0c00fa2740 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -1,6 +1,7 @@ mkinclude auth/config.mk mkinclude ldap/config.mk mkinclude security/config.mk +mkinclude wbclient/config.mk [SUBSYSTEM::LIBSAMBA-ERRORS] OBJ_FILES = util/doserr.o \ diff --git a/source4/libcli/wbclient/config.mk b/source4/libcli/wbclient/config.mk new file mode 100644 index 0000000000..32f2f5aeed --- /dev/null +++ b/source4/libcli/wbclient/config.mk @@ -0,0 +1,6 @@ +[SUBSYSTEM::LIBWBCLIENT] +OBJ_FILES = wbclient.o +PUBLIC_DEPENDENCIES = LIBSAMBA-ERRORS LIBEVENTS +PRIVATE_DEPENDENCIES = NDR_WINBIND MESSAGING + +PUBLIC_HEADERS += libcli/wbclient/wbclient.h diff --git a/source4/libcli/wbclient/wbclient.c b/source4/libcli/wbclient/wbclient.c new file mode 100644 index 0000000000..1b2d314824 --- /dev/null +++ b/source4/libcli/wbclient/wbclient.c @@ -0,0 +1,210 @@ +/* + Unix SMB/CIFS implementation. + + Winbind client library. + + Copyright (C) 2008 Kai Blin <kai@samba.org> + + 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/wbclient/wbclient.h" + +/** + * Get the server_id of the winbind task. + * + * \param[in] msg_ctx message context to use + * \param[in] mem_ctx talloc context to use + * \param[out] ids array of server_id structs containing the winbind id + * \return NT_STATUS_OK on success, NT_STATUS_INTERNAL_ERROR on failure + */ +static NTSTATUS get_server_id(struct messaging_context *msg_ctx, + TALLOC_CTX *mem_ctx, struct server_id **ids) +{ + *ids = irpc_servers_byname(msg_ctx, mem_ctx, "winbind_server"); + if (*ids == NULL || (*ids)[0].id == 0) { + DEBUG(0, ("Geting the winbind server ID failed.\n")); + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +/** + * Initialize the wbclient context, talloc_free() when done. + * + * \param mem_ctx talloc context to allocate memory from + * \param msg_ctx message context to use + * \param + */ +struct wbc_context *wbc_init(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + struct event_context *event_ctx) +{ + struct wbc_context *ctx; + NTSTATUS status; + + ctx = talloc(mem_ctx, struct wbc_context); + if (ctx == NULL) return NULL; + + status = get_server_id(msg_ctx, mem_ctx, &ctx->ids); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ctx); + return NULL; + } + + ctx->msg_ctx = msg_ctx; + ctx->event_ctx = event_ctx; + + return ctx; +} + +struct wbc_idmap_state { + struct composite_context *ctx; + struct winbind_get_idmap *req; + struct irpc_request *irpc_req; + struct id_mapping *ids; +}; + +static void sids_to_xids_recv_ids(struct irpc_request *req); + +struct composite_context *wbc_sids_to_xids_send(struct wbc_context *wbc_ctx, + TALLOC_CTX *mem_ctx, + uint32_t count, + struct id_mapping *ids) +{ + struct composite_context *ctx; + struct wbc_idmap_state *state; + + DEBUG(5, ("wbc_sids_to_xids called\n")); + + ctx = composite_create(mem_ctx, wbc_ctx->event_ctx); + if (ctx == NULL) return NULL; + + state = talloc(ctx, struct wbc_idmap_state); + if (composite_nomem(state, ctx)) return ctx; + ctx->private_data = state; + + state->req = talloc(state, struct winbind_get_idmap); + if (composite_nomem(state->req, ctx)) return ctx; + + state->req->in.count = count; + state->req->in.level = WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS; + state->req->in.ids = ids; + state->ctx = ctx; + + state->irpc_req = IRPC_CALL_SEND(wbc_ctx->msg_ctx, wbc_ctx->ids[0], + winbind, WINBIND_GET_IDMAP, state->req, + state); + if (composite_nomem(state->irpc_req, ctx)) return ctx; + + composite_continue_irpc(ctx, state->irpc_req, sids_to_xids_recv_ids, + state); + return ctx; +} + +static void sids_to_xids_recv_ids(struct irpc_request *req) +{ + struct wbc_idmap_state *state = talloc_get_type_abort( + req->async.private, + struct wbc_idmap_state); + + state->ctx->status = irpc_call_recv(state->irpc_req); + if (!composite_is_ok(state->ctx)) return; + + state->ids = state->req->out.ids; + composite_done(state->ctx); +} + +NTSTATUS wbc_sids_to_xids_recv(struct composite_context *ctx, + struct id_mapping **ids) +{ + NTSTATUS status = composite_wait(ctx); + DEBUG(5, ("wbc_sids_to_xids_recv called\n")); + if (NT_STATUS_IS_OK(status)) { + struct wbc_idmap_state *state = talloc_get_type_abort( + ctx->private_data, + struct wbc_idmap_state); + *ids = state->ids; + } + + return status; +} + +static void xids_to_sids_recv_ids(struct irpc_request *req); + +struct composite_context *wbc_xids_to_sids_send(struct wbc_context *wbc_ctx, + TALLOC_CTX *mem_ctx, + uint32_t count, + struct id_mapping *ids) +{ + struct composite_context *ctx; + struct wbc_idmap_state *state; + + DEBUG(5, ("wbc_xids_to_sids called\n")); + + ctx = composite_create(mem_ctx, wbc_ctx->event_ctx); + if (ctx == NULL) return NULL; + + state = talloc(ctx, struct wbc_idmap_state); + if (composite_nomem(state, ctx)) return ctx; + ctx->private_data = state; + + state->req = talloc(state, struct winbind_get_idmap); + if (composite_nomem(state->req, ctx)) return ctx; + + state->req->in.count = count; + state->req->in.level = WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS; + state->req->in.ids = ids; + state->ctx = ctx; + + state->irpc_req = IRPC_CALL_SEND(wbc_ctx->msg_ctx, wbc_ctx->ids[0], + winbind, WINBIND_GET_IDMAP, state->req, + state); + if (composite_nomem(state->irpc_req, ctx)) return ctx; + + composite_continue_irpc(ctx, state->irpc_req, xids_to_sids_recv_ids, + state); + + return ctx; +} + +static void xids_to_sids_recv_ids(struct irpc_request *req) +{ + struct wbc_idmap_state *state = talloc_get_type_abort( + req->async.private, + struct wbc_idmap_state); + + state->ctx->status = irpc_call_recv(state->irpc_req); + if (!composite_is_ok(state->ctx)) return; + + state->ids = state->req->out.ids; + composite_done(state->ctx); +} + +NTSTATUS wbc_xids_to_sids_recv(struct composite_context *ctx, + struct id_mapping **ids) +{ + NTSTATUS status = composite_wait(ctx); + DEBUG(5, ("wbc_xids_to_sids_recv called\n")); + if (NT_STATUS_IS_OK(status)) { + struct wbc_idmap_state *state = talloc_get_type_abort( + ctx->private_data, + struct wbc_idmap_state); + *ids = state->ids; + } + + return status; +} + diff --git a/source4/libcli/wbclient/wbclient.h b/source4/libcli/wbclient/wbclient.h new file mode 100644 index 0000000000..099abaa511 --- /dev/null +++ b/source4/libcli/wbclient/wbclient.h @@ -0,0 +1,50 @@ +/* + Unix SMB/CIFS implementation. + + Winbind client library. + + Copyright (C) 2008 Kai Blin <kai@samba.org> + + 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 "lib/messaging/irpc.h" +#include "libcli/composite/composite.h" +#include "librpc/gen_ndr/ndr_winbind.h" + +struct wbc_context { + struct messaging_context *msg_ctx; + struct event_context *event_ctx; + struct server_id *ids; +}; + +struct wbc_context *wbc_init(TALLOC_CTX *mem_ctx, + struct messaging_context *msg_ctx, + struct event_context *event_ctx); + +struct composite_context *wbc_sids_to_xids_send(struct wbc_context *wbc_ctx, + TALLOC_CTX *mem_ctx, + uint32_t count, + struct id_mapping *ids); + +NTSTATUS wbc_sids_to_xids_recv(struct composite_context *ctx, + struct id_mapping **ids); + +struct composite_context *wbc_xids_to_sids_send(struct wbc_context *wbc_ctx, + TALLOC_CTX *mem_ctx, + uint32_t count, + struct id_mapping *ids); + +NTSTATUS wbc_xids_to_sids_recv(struct composite_context *ctx, + struct id_mapping **ids); + diff --git a/source4/librpc/idl/lsa.idl b/source4/librpc/idl/lsa.idl index 6d15822ea6..e36e79f5c4 100644 --- a/source4/librpc/idl/lsa.idl +++ b/source4/librpc/idl/lsa.idl @@ -338,7 +338,7 @@ import "misc.idl", "security.idl"; /******************/ /* Function: 0x0e */ - typedef enum { + typedef [public] enum { SID_NAME_USE_NONE = 0,/* NOTUSED */ SID_NAME_USER = 1, /* user */ SID_NAME_DOM_GRP = 2, /* domain group */ diff --git a/source4/librpc/idl/winbind.idl b/source4/librpc/idl/winbind.idl index 29649c0ea7..5cefb38f75 100644 --- a/source4/librpc/idl/winbind.idl +++ b/source4/librpc/idl/winbind.idl @@ -3,8 +3,8 @@ */ #include "idl_types.h" - -import "netlogon.idl"; + +import "netlogon.idl", "lsa.idl", "security.idl"; [ uuid("245f3e6b-3c5d-6e21-3a2d-2a3d645b7221"), @@ -16,6 +16,24 @@ interface winbind typedef [switch_type(uint16)] union netr_LogonLevel netr_LogonLevel; typedef [switch_type(uint16)] union netr_Validation netr_Validation; + typedef enum { + ID_TYPE_NOT_SPECIFIED, + ID_TYPE_UID, + ID_TYPE_GID, + ID_TYPE_BOTH + } id_type; + + typedef struct { + uint32 id; + id_type type; + } unixid; + + typedef struct { + unixid *unixid; + dom_sid *sid; + NTSTATUS status; + } id_mapping; + /* a call to get runtime informations */ void winbind_information(/* TODO */); @@ -35,4 +53,16 @@ interface winbind [out] [switch_is(validation_level)] netr_Validation validation, [out] uint8 authoritative ); + + typedef [v1_enum] enum { + WINBIND_IDMAP_LEVEL_SIDS_TO_XIDS = 1, + WINBIND_IDMAP_LEVEL_XIDS_TO_SIDS = 2 + } winbind_get_idmap_level; + + NTSTATUS winbind_get_idmap( + [in] winbind_get_idmap_level level, + [in] uint32 count, + [in,out] [size_is(count)] id_mapping ids[] + ); + } diff --git a/source4/ntvfs/posix/pvfs_acl.c b/source4/ntvfs/posix/pvfs_acl.c index 5070f6852d..2393a2e7a3 100644 --- a/source4/ntvfs/posix/pvfs_acl.c +++ b/source4/ntvfs/posix/pvfs_acl.c @@ -126,6 +126,8 @@ static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs, NTSTATUS status; struct security_ace ace; mode_t mode; + struct id_mapping *ids; + struct composite_context *ctx; *psd = security_descriptor_initialise(req); if (*psd == NULL) { @@ -133,15 +135,33 @@ static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs, } sd = *psd; - status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + ids = talloc_array(sd, struct id_mapping, 2); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids[0].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); + + ids[0].unixid->id = name->st.st_uid; + ids[0].unixid->type = ID_TYPE_UID; + ids[0].sid = NULL; + ids[1].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); + + ids[1].unixid->id = name->st.st_gid; + ids[1].unixid->type = ID_TYPE_GID; + ids[1].sid = NULL; + + ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_xids_to_sids_recv(ctx, &ids); + NT_STATUS_NOT_OK_RETURN(status); + + sd->owner_sid = talloc_steal(sd, ids[0].sid); + sd->group_sid = talloc_steal(sd, ids[1].sid); + + talloc_free(ids); sd->type |= SEC_DESC_DACL_PRESENT; mode = name->st.st_mode; @@ -248,6 +268,8 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, gid_t old_gid = -1; uid_t new_uid = -1; gid_t new_gid = -1; + struct id_mapping *ids; + struct composite_context *ctx; if (pvfs->acl_ops != NULL) { status = pvfs->acl_ops->acl_load(pvfs, name, fd, req, &sd); @@ -259,6 +281,12 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, return status; } + ids = talloc(req, struct id_mapping); + NT_STATUS_HAVE_NO_MEMORY(ids); + ids->unixid = NULL; + ids->sid = NULL; + ids->status = NT_STATUS_NONE_MAPPED; + new_sd = info->set_secdesc.in.sd; orig_sd = *sd; @@ -271,8 +299,16 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, return NT_STATUS_ACCESS_DENIED; } if (!dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) { - status = sidmap_sid_to_unixuid(pvfs->sidmap, new_sd->owner_sid, &new_uid); + ids->sid = new_sd->owner_sid; + ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); + + if (ids->unixid->type == ID_TYPE_BOTH || + ids->unixid->type == ID_TYPE_UID) { + new_uid = ids->unixid->id; + } } sd->owner_sid = new_sd->owner_sid; } @@ -281,8 +317,17 @@ NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs, return NT_STATUS_ACCESS_DENIED; } if (!dom_sid_equal(sd->group_sid, new_sd->group_sid)) { - status = sidmap_sid_to_unixgid(pvfs->sidmap, new_sd->group_sid, &new_gid); + ids->sid = new_sd->group_sid; + ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); + + if (ids->unixid->type == ID_TYPE_BOTH || + ids->unixid->type == ID_TYPE_GID) { + new_gid = ids->unixid->id; + } + } sd->group_sid = new_sd->group_sid; } @@ -664,6 +709,8 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, struct pvfs_filename *parent; struct security_descriptor *parent_sd, *sd; bool container; + struct id_mapping *ids; + struct composite_context *ctx; /* form the parents path */ status = pvfs_resolve_parent(pvfs, req, name, &parent); @@ -705,14 +752,31 @@ NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs, return NT_STATUS_NO_MEMORY; } - status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + ids = talloc_array(sd, struct id_mapping, 2); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids[0].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); + ids[0].unixid->id = name->st.st_uid; + ids[0].unixid->type = ID_TYPE_UID; + ids[0].sid = NULL; + ids[0].status = NT_STATUS_NONE_MAPPED; + + ids[1].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); + ids[1].unixid->id = name->st.st_gid; + ids[1].unixid->type = ID_TYPE_GID; + ids[1].sid = NULL; + ids[1].status = NT_STATUS_NONE_MAPPED; + + ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, ids, 2, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_xids_to_sids_recv(ctx, &ids); + NT_STATUS_NOT_OK_RETURN(status); + + sd->owner_sid = talloc_steal(sd, ids[0].sid); + sd->group_sid = talloc_steal(sd, ids[1].sid); sd->type |= SEC_DESC_DACL_PRESENT; diff --git a/source4/ntvfs/posix/pvfs_acl_nfs4.c b/source4/ntvfs/posix/pvfs_acl_nfs4.c index 2abb1482a4..fa855555b2 100644 --- a/source4/ntvfs/posix/pvfs_acl_nfs4.c +++ b/source4/ntvfs/posix/pvfs_acl_nfs4.c @@ -38,7 +38,9 @@ static NTSTATUS pvfs_acl_load_nfs4(struct pvfs_state *pvfs, struct pvfs_filename NTSTATUS status; struct nfs4acl *acl; struct security_descriptor *sd; - int i; + int i, num_ids; + struct id_mapping *ids; + struct composite_context *ctx; acl = talloc_zero(mem_ctx, struct nfs4acl); NT_STATUS_HAVE_NO_MEMORY(acl); @@ -57,25 +59,57 @@ static NTSTATUS pvfs_acl_load_nfs4(struct pvfs_state *pvfs, struct pvfs_filename sd = *psd; sd->type |= acl->a_flags; - status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid); - NT_STATUS_NOT_OK_RETURN(status); - status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid); + + /* the number of ids to map is the acl count plus uid and gid */ + num_ids = acl->a_count +2; + ids = talloc_array(sd, struct id_mapping, num_ids); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids[0].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[0].unixid); + ids[0].unixid->id = name->st.st_uid; + ids[0].unixid->type = ID_TYPE_UID; + ids[0].sid = NULL; + ids[0].status = NT_STATUS_NONE_MAPPED; + + ids[1].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[1].unixid); + ids[1].unixid->id = name->st.st_gid; + ids[1].unixid->type = ID_TYPE_GID; + ids[1].sid = NULL; + ids[1].status = NT_STATUS_NONE_MAPPED; + + for (i=0;i<acl->a_count;i++) { + struct nfs4ace *a = &acl->ace[i]; + ids[i+2].unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids[i+2].unixid); + ids[i+2].unixid->id = a->e_id; + if (a->e_flags & ACE4_IDENTIFIER_GROUP) { + ids[i+2].unixid->type = ID_TYPE_GID; + } else { + ids[i+2].unixid->type = ID_TYPE_UID; + } + ids[i+2].sid = NULL; + ids[i+2].status = NT_STATUS_NONE_MAPPED; + } + + /* Allocate memory for the sids from the security descriptor to be on + * the safe side. */ + ctx = wbc_xids_to_sids_send(pvfs->wbc_ctx, sd, num_ids, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + status = wbc_xids_to_sids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); + sd->owner_sid = talloc_steal(sd, ids[0].sid); + sd->group_sid = talloc_steal(sd, ids[1].sid); + for (i=0;i<acl->a_count;i++) { struct nfs4ace *a = &acl->ace[i]; struct security_ace ace; - struct dom_sid *sid; ace.type = a->e_type; ace.flags = a->e_flags; ace.access_mask = a->e_mask; - if (a->e_flags & ACE4_IDENTIFIER_GROUP) { - status = sidmap_gid_to_sid(pvfs->sidmap, sd, a->e_id, &sid); - } else { - status = sidmap_uid_to_sid(pvfs->sidmap, sd, a->e_id, &sid); - } - NT_STATUS_NOT_OK_RETURN(status); - ace.trustee = *sid; + ace.trustee = *ids[i+2].sid; security_descriptor_dacl_add(sd, &ace); } @@ -93,6 +127,8 @@ static NTSTATUS pvfs_acl_save_nfs4(struct pvfs_state *pvfs, struct pvfs_filename struct nfs4acl acl; int i; TALLOC_CTX *tmp_ctx; + struct id_mapping *ids; + struct composite_context *ctx; tmp_ctx = talloc_new(pvfs); NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); @@ -110,30 +146,44 @@ static NTSTATUS pvfs_acl_save_nfs4(struct pvfs_state *pvfs, struct pvfs_filename return NT_STATUS_NO_MEMORY; } + ids = talloc_array(tmp_ctx, struct id_mapping, acl.a_count); + if (ids == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + + for (i=0;i<acl.a_count;i++) { + struct security_ace *ace = &sd->dacl->aces[i]; + ids[i].unixid = NULL; + ids[i].sid = dom_sid_dup(ids, &ace->trustee); + if (ids[i].sid == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + ids[i].status = NT_STATUS_NONE_MAPPED; + } + + ctx = wbc_sids_to_xids_send(pvfs->wbc_ctx,ids, acl.a_count, ids); + if (ctx == NULL) { + talloc_free(tmp_ctx); + return NT_STATUS_NO_MEMORY; + } + status = wbc_sids_to_xids_recv(ctx, &ids); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + for (i=0;i<acl.a_count;i++) { struct nfs4ace *a = &acl.ace[i]; struct security_ace *ace = &sd->dacl->aces[i]; a->e_type = ace->type; a->e_flags = ace->flags; a->e_mask = ace->access_mask; - if (sidmap_sid_is_group(pvfs->sidmap, &ace->trustee)) { - gid_t gid; + if (ids[i].unixid->type != ID_TYPE_UID) { a->e_flags |= ACE4_IDENTIFIER_GROUP; - status = sidmap_sid_to_unixgid(pvfs->sidmap, &ace->trustee, &gid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return status; - } - a->e_id = gid; - } else { - uid_t uid; - status = sidmap_sid_to_unixuid(pvfs->sidmap, &ace->trustee, &uid); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return status; - } - a->e_id = uid; } + a->e_id = ids[i].unixid->id; a->e_who = ""; } diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index ca874d1db1..ebc2d88e70 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -222,8 +222,10 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, event_context_find(pvfs), pvfs->ntvfs->ctx->config); - pvfs->sidmap = sidmap_open(pvfs, pvfs->ntvfs->ctx->lp_ctx); - if (pvfs->sidmap == NULL) { + pvfs->wbc_ctx = wbc_init(pvfs, + pvfs->ntvfs->ctx->msg_ctx, + pvfs->ntvfs->ctx->event_ctx); + if (pvfs->wbc_ctx == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 4d22a91714..441424142f 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -26,6 +26,7 @@ #include "system/filesys.h" #include "ntvfs/ntvfs.h" #include "ntvfs/common/ntvfs_common.h" +#include "libcli/wbclient/wbclient.h" #include "dsdb/samdb/samdb.h" struct pvfs_wait; @@ -46,7 +47,7 @@ struct pvfs_state { struct brl_context *brl_context; struct odb_context *odb_context; struct notify_context *notify_context; - struct sidmap_context *sidmap; + struct wbc_context *wbc_ctx; /* a list of pending async requests. Needed to support ntcancel */ diff --git a/source4/ntvfs/unixuid/vfs_unixuid.c b/source4/ntvfs/unixuid/vfs_unixuid.c index 63889c6677..66c2cfaf4c 100644 --- a/source4/ntvfs/unixuid/vfs_unixuid.c +++ b/source4/ntvfs/unixuid/vfs_unixuid.c @@ -25,11 +25,11 @@ #include "system/passwd.h" #include "auth/auth.h" #include "ntvfs/ntvfs.h" -#include "dsdb/samdb/samdb.h" +#include "libcli/wbclient/wbclient.h" #include "param/param.h" struct unixuid_private { - struct sidmap_context *sidmap; + struct wbc_context *wbc_ctx; struct unix_sec_ctx *last_sec_ctx; struct security_token *last_token; }; @@ -100,9 +100,11 @@ static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs, struct security_token *token, struct unix_sec_ctx **sec) { - struct unixuid_private *private = ntvfs->private_data; + struct unixuid_private *priv = ntvfs->private_data; int i; NTSTATUS status; + struct id_mapping *ids; + struct composite_context *ctx; *sec = talloc(req, struct unix_sec_ctx); /* we can't do unix security without a user and group */ @@ -110,29 +112,53 @@ static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs, return NT_STATUS_ACCESS_DENIED; } - status = sidmap_sid_to_unixuid(private->sidmap, - token->user_sid, &(*sec)->uid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + ids = talloc_array(req, struct id_mapping, token->num_sids); + NT_STATUS_HAVE_NO_MEMORY(ids); - status = sidmap_sid_to_unixgid(private->sidmap, - token->group_sid, &(*sec)->gid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } + ids[0].unixid = NULL; + ids[0].sid = token->user_sid; + ids[0].status = NT_STATUS_NONE_MAPPED; + + ids[1].unixid = NULL; + ids[1].sid = token->group_sid; + ids[1].status = NT_STATUS_NONE_MAPPED; (*sec)->ngroups = token->num_sids - 2; (*sec)->groups = talloc_array(*sec, gid_t, (*sec)->ngroups); - if ((*sec)->groups == NULL) { - return NT_STATUS_NO_MEMORY; + NT_STATUS_HAVE_NO_MEMORY((*sec)->groups); + + for (i=0;i<(*sec)->ngroups;i++) { + ids[i+2].unixid = NULL; + ids[i+2].sid = token->sids[i+2]; + ids[i+2].status = NT_STATUS_NONE_MAPPED; + } + + ctx = wbc_sids_to_xids_send(priv->wbc_ctx, ids, token->num_sids, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_sids_to_xids_recv(ctx, &ids); + NT_STATUS_NOT_OK_RETURN(status); + + if (ids[0].unixid->type == ID_TYPE_BOTH || + ids[0].unixid->type == ID_TYPE_UID) { + (*sec)->uid = ids[0].unixid->id; + } else { + return NT_STATUS_INVALID_SID; + } + + if (ids[1].unixid->type == ID_TYPE_BOTH || + ids[1].unixid->type == ID_TYPE_GID) { + (*sec)->gid = ids[1].unixid->id; + } else { + return NT_STATUS_INVALID_SID; } for (i=0;i<(*sec)->ngroups;i++) { - status = sidmap_sid_to_unixgid(private->sidmap, - token->sids[i+2], &(*sec)->groups[i]); - if (!NT_STATUS_IS_OK(status)) { - return status; + if (ids[i+2].unixid->type == ID_TYPE_BOTH || + ids[i+2].unixid->type == ID_TYPE_GID) { + (*sec)->groups[i] = ids[i+2].unixid->id; + } else { + return NT_STATUS_INVALID_SID; } } @@ -216,9 +242,11 @@ static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs, return NT_STATUS_NO_MEMORY; } - private->sidmap = sidmap_open(private, ntvfs->ctx->lp_ctx); - if (private->sidmap == NULL) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + private->wbc_ctx = wbc_init(private, ntvfs->ctx->msg_ctx, + ntvfs->ctx->event_ctx); + if (private->wbc_ctx == NULL) { + talloc_free(private); + return NT_STATUS_INTERNAL_ERROR; } ntvfs->private_data = private; diff --git a/source4/pidl/config.m4 b/source4/pidl/config.m4 new file mode 100644 index 0000000000..8b8bc5acf0 --- /dev/null +++ b/source4/pidl/config.m4 @@ -0,0 +1,9 @@ +# Check whether ExtUtils::ExtMaker is available + +if perl -e "use ExtUtils::MakeMaker" 2>/dev/null; then + HAVE_PERL_EXTUTILS_MAKEMAKER=1 +else + HAVE_PERL_EXTUTILS_MAKEMAKER=0 +fi + +AC_SUBST(HAVE_PERL_EXTUTILS_MAKEMAKER) diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk index 1d1c51cc6e..d6d77dd0d9 100644 --- a/source4/rpc_server/config.mk +++ b/source4/rpc_server/config.mk @@ -82,7 +82,8 @@ PRIVATE_DEPENDENCIES = \ DCERPC_COMMON \ SAMDB \ NDR_UNIXINFO \ - NSS_WRAPPER + NSS_WRAPPER \ + LIBWBCLIENT # End MODULE dcerpc_unixinfo ################################################ diff --git a/source4/rpc_server/lsa/lsa.h b/source4/rpc_server/lsa/lsa.h index db148d3dcb..b7c41486a2 100644 --- a/source4/rpc_server/lsa/lsa.h +++ b/source4/rpc_server/lsa/lsa.h @@ -40,7 +40,6 @@ struct lsa_policy_state { struct dcesrv_handle *handle; struct ldb_context *sam_ldb; - struct sidmap_context *sidmap; uint32_t access_mask; struct ldb_dn *domain_dn; struct ldb_dn *forest_dn; diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c index 57599b96a2..4dcd606435 100644 --- a/source4/rpc_server/lsa/lsa_init.c +++ b/source4/rpc_server/lsa/lsa_init.c @@ -57,11 +57,6 @@ NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_ partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx); - state->sidmap = sidmap_open(state, dce_call->conn->dce_ctx->lp_ctx); - if (state->sidmap == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; - } - /* work out the domain_dn - useful for so many calls its worth fetching here */ state->domain_dn = samdb_base_dn(state->sam_ldb); diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index e01efa8233..c6b9e3bd40 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -360,7 +360,7 @@ static NTSTATUS dcesrv_lsa_lookup_name(struct loadparm_context *lp_ctx, return NT_STATUS_OK; } - /* need to add a call into sidmap to check for a allocated sid */ + /* need to check for an allocated sid */ return NT_STATUS_INVALID_SID; } @@ -466,8 +466,7 @@ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX return NT_STATUS_OK; } - /* need to re-add a call into sidmap to check for a allocated sid */ - /* status = sidmap_allocated_sid_lookup(state->sidmap, mem_ctx, sid, name, rtype); */ + /* need to re-add a check for an allocated sid */ return NT_STATUS_NOT_FOUND; } diff --git a/source4/rpc_server/unixinfo/dcesrv_unixinfo.c b/source4/rpc_server/unixinfo/dcesrv_unixinfo.c index 2c08d501d1..e6313b771c 100644 --- a/source4/rpc_server/unixinfo/dcesrv_unixinfo.c +++ b/source4/rpc_server/unixinfo/dcesrv_unixinfo.c @@ -23,53 +23,100 @@ #include "rpc_server/dcerpc_server.h" #include "rpc_server/common/common.h" #include "librpc/gen_ndr/ndr_unixinfo.h" +#include "libcli/wbclient/wbclient.h" #include "lib/events/events.h" -#include "dsdb/samdb/samdb.h" #include "system/passwd.h" #include "param/param.h" +static NTSTATUS dcerpc_unixinfo_bind(struct dcesrv_call_state *dce_call, + const struct dcesrv_interface *iface) +{ + struct wbc_context *wbc_ctx; + + wbc_ctx = wbc_init(dce_call->context, dce_call->msg_ctx, + dce_call->event_ctx); + NT_STATUS_HAVE_NO_MEMORY(wbc_ctx); + + dce_call->context->private = wbc_ctx; + + return NT_STATUS_OK; +} + +#define DCESRV_INTERFACE_UNIXINFO_BIND dcerpc_unixinfo_bind + static NTSTATUS dcesrv_unixinfo_SidToUid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct unixinfo_SidToUid *r) { NTSTATUS status; - struct sidmap_context *sidmap; - uid_t uid; + struct wbc_context *wbc_ctx = talloc_get_type_abort( + dce_call->context->private, + struct wbc_context); + struct id_mapping *ids; + struct composite_context *ctx; - sidmap = sidmap_open(mem_ctx, dce_call->conn->dce_ctx->lp_ctx); - if (sidmap == NULL) { - DEBUG(10, ("sidmap_open failed\n")); - return NT_STATUS_NO_MEMORY; - } + DEBUG(5, ("dcesrv_unixinfo_SidToUid called\n")); + + ids = talloc(mem_ctx, struct id_mapping); + NT_STATUS_HAVE_NO_MEMORY(ids); - status = sidmap_sid_to_unixuid(sidmap, &r->in.sid, &uid); + ids->sid = &r->in.sid; + ids->status = NT_STATUS_NONE_MAPPED; + ids->unixid = NULL; + ctx = wbc_sids_to_xids_send(wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); - *r->out.uid = uid; - return NT_STATUS_OK; + if (ids->unixid->type == ID_TYPE_BOTH || + ids->unixid->type == ID_TYPE_UID) { + *r->out.uid = ids->unixid->id; + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_SID; + } } static NTSTATUS dcesrv_unixinfo_UidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct unixinfo_UidToSid *r) { - struct sidmap_context *sidmap; - uid_t uid; - - sidmap = sidmap_open(mem_ctx, dce_call->conn->dce_ctx->lp_ctx); - if (sidmap == NULL) { - DEBUG(10, ("sidmap_open failed\n")); - return NT_STATUS_NO_MEMORY; - } + struct wbc_context *wbc_ctx = talloc_get_type_abort( + dce_call->context->private, + struct wbc_context); + struct id_mapping *ids; + struct composite_context *ctx; + uint32_t uid; + NTSTATUS status; - uid = r->in.uid; /* This cuts uid to (probably) 32 bit */ + DEBUG(5, ("dcesrv_unixinfo_UidToSid called\n")); + uid = r->in.uid; /* This cuts uid to 32 bit */ if ((uint64_t)uid != r->in.uid) { DEBUG(10, ("uid out of range\n")); return NT_STATUS_INVALID_PARAMETER; } - return sidmap_uid_to_sid(sidmap, mem_ctx, uid, &r->out.sid); + ids = talloc(mem_ctx, struct id_mapping); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids->sid = NULL; + ids->status = NT_STATUS_NONE_MAPPED; + ids->unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids->unixid); + + ids->unixid->id = uid; + ids->unixid->type = ID_TYPE_UID; + + ctx = wbc_xids_to_sids_send(wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_xids_to_sids_recv(ctx, &ids); + NT_STATUS_NOT_OK_RETURN(status); + + r->out.sid = ids->sid; + return NT_STATUS_OK; } static NTSTATUS dcesrv_unixinfo_SidToGid(struct dcesrv_call_state *dce_call, @@ -77,43 +124,74 @@ static NTSTATUS dcesrv_unixinfo_SidToGid(struct dcesrv_call_state *dce_call, struct unixinfo_SidToGid *r) { NTSTATUS status; - struct sidmap_context *sidmap; - gid_t gid; + struct wbc_context *wbc_ctx = talloc_get_type_abort( + dce_call->context->private, + struct wbc_context); + struct id_mapping *ids; + struct composite_context *ctx; - sidmap = sidmap_open(mem_ctx, dce_call->conn->dce_ctx->lp_ctx); - if (sidmap == NULL) { - DEBUG(10, ("sidmap_open failed\n")); - return NT_STATUS_NO_MEMORY; - } + DEBUG(5, ("dcesrv_unixinfo_SidToGid called\n")); - status = sidmap_sid_to_unixgid(sidmap, &r->in.sid, &gid); + ids = talloc(mem_ctx, struct id_mapping); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids->sid = &r->in.sid; + ids->status = NT_STATUS_NONE_MAPPED; + ids->unixid = NULL; + ctx = wbc_sids_to_xids_send(wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_sids_to_xids_recv(ctx, &ids); NT_STATUS_NOT_OK_RETURN(status); - *r->out.gid = gid; - return NT_STATUS_OK; + if (ids->unixid->type == ID_TYPE_BOTH || + ids->unixid->type == ID_TYPE_GID) { + *r->out.gid = ids->unixid->id; + return NT_STATUS_OK; + } else { + return NT_STATUS_INVALID_SID; + } } static NTSTATUS dcesrv_unixinfo_GidToSid(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct unixinfo_GidToSid *r) { - struct sidmap_context *sidmap; - gid_t gid; - - sidmap = sidmap_open(mem_ctx, dce_call->conn->dce_ctx->lp_ctx); - if (sidmap == NULL) { - DEBUG(10, ("sidmap_open failed\n")); - return NT_STATUS_NO_MEMORY; - } + struct wbc_context *wbc_ctx = talloc_get_type_abort( + dce_call->context->private, + struct wbc_context); + struct id_mapping *ids; + struct composite_context *ctx; + uint32_t gid; + NTSTATUS status; - gid = r->in.gid; /* This cuts gid to (probably) 32 bit */ + DEBUG(5, ("dcesrv_unixinfo_GidToSid called\n")); + gid = r->in.gid; /* This cuts gid to 32 bit */ if ((uint64_t)gid != r->in.gid) { DEBUG(10, ("gid out of range\n")); return NT_STATUS_INVALID_PARAMETER; } - return sidmap_gid_to_sid(sidmap, mem_ctx, gid, &r->out.sid); + ids = talloc(mem_ctx, struct id_mapping); + NT_STATUS_HAVE_NO_MEMORY(ids); + + ids->sid = NULL; + ids->status = NT_STATUS_NONE_MAPPED; + ids->unixid = talloc(ids, struct unixid); + NT_STATUS_HAVE_NO_MEMORY(ids->unixid); + + ids->unixid->id = gid; + ids->unixid->type = ID_TYPE_GID; + + ctx = wbc_xids_to_sids_send(wbc_ctx, ids, 1, ids); + NT_STATUS_HAVE_NO_MEMORY(ctx); + + status = wbc_xids_to_sids_recv(ctx, &ids); + NT_STATUS_NOT_OK_RETURN(status); + + r->out.sid = ids->sid; + return NT_STATUS_OK; } static NTSTATUS dcesrv_unixinfo_GetPWUid(struct dcesrv_call_state *dce_call, diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py new file mode 100644 index 0000000000..355565968a --- /dev/null +++ b/source4/scripting/python/samba/idmap.py @@ -0,0 +1,73 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) 2008 Kai Blin <kai@samba.org> +# +# +# 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/>. +# + +"""Convenience functions for using the idmap database.""" + +import samba +import ldb + +class IDmapDB(samba.Ldb): + """The IDmap database.""" + + # Mappings for ID_TYPE_UID, ID_TYPE_GID and ID_TYPE_BOTH + TYPE_UID = 1 + TYPE_GID = 2 + TYPE_BOTH = 3 + + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open the IDmap Database. + + :param url: URL of the database. + """ + super(IDmapDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) + if url: + self.connect(url) + + + def setup_name_mapping(self, sid, type, unixid): + """Setup a mapping between a sam name and a unix name. + + :param sid: SID of the NT-side of the mapping. + :param unixname: Unix name to map to. + """ + type_string = "" + if type == self.TYPE_UID: + type_string = "ID_TYPE_UID" + elif type == self.TYPE_GID: + type_string = "ID_TYPE_GID" + elif type == self.TYPE_BOTH: + type_string = "ID_TYPE_BOTH" + else: + return + + mod = """ +dn: CN=%s +xidNumber: %s +objectSid: %s +objectClass: sidMap +type: %s +cn: %s + +""" % (sid, unixid, sid, type_string, sid) + self.add(self.parse_ldif(mod).next()[1]) + + diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index dfeb61e52b..6917aa1a54 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -35,6 +35,7 @@ import samba from auth import system_session from samba import Ldb, substitute_var, valid_netbios_name, check_all_substituted from samba.samdb import SamDB +from samba.idmap import IDmapDB import security import urllib from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ @@ -397,45 +398,30 @@ def load_or_make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrol return lp -def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, - wheel, backup): +def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid, + users_gid, wheel_gid): """setup reasonable name mappings for sam names to unix names. - - :param ldb: SamDB object. + + :param samdb: SamDB object. + :param idmap: IDmap db object. :param sid: The domain sid. :param domaindn: The domain DN. - :param root: Name of the UNIX root user. - :param nobody: Name of the UNIX nobody user. - :param nogroup: Name of the unix nobody group. - :param users: Name of the unix users group. - :param wheel: Name of the wheel group (users that can become root). - :param backup: Name of the backup group.""" + :param root_uid: uid of the UNIX root user. + :param nobody_uid: uid of the UNIX nobody user. + :param users_gid: gid of the UNIX users group. + :param wheel_gid: gid of the UNIX wheel group.""" # add some foreign sids if they are not present already - ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous") - ldb.add_foreign(domaindn, "S-1-1-0", "World") - ldb.add_foreign(domaindn, "S-1-5-2", "Network") - ldb.add_foreign(domaindn, "S-1-5-18", "System") - ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") - - # some well known sids - ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody) - ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-18", root) - ldb.setup_name_mapping(domaindn, "S-1-5-11", users) - ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel) - ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users) - ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup) - ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup) - - # and some well known domain rids - ldb.setup_name_mapping(domaindn, sid + "-500", root) - ldb.setup_name_mapping(domaindn, sid + "-518", wheel) - ldb.setup_name_mapping(domaindn, sid + "-519", wheel) - ldb.setup_name_mapping(domaindn, sid + "-512", wheel) - ldb.setup_name_mapping(domaindn, sid + "-513", users) - ldb.setup_name_mapping(domaindn, sid + "-520", wheel) + samdb.add_foreign(domaindn, "S-1-5-7", "Anonymous") + samdb.add_foreign(domaindn, "S-1-1-0", "World") + samdb.add_foreign(domaindn, "S-1-5-2", "Network") + samdb.add_foreign(domaindn, "S-1-5-18", "System") + samdb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") + + idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid) + idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid) + idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid) + idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid) def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info, credentials, names, @@ -663,8 +649,8 @@ def setup_idmapdb(path, setup_path, session_info, credentials, lp): if os.path.exists(path): os.unlink(path) - idmap_ldb = Ldb(path, session_info=session_info, credentials=credentials, - lp=lp) + idmap_ldb = IDmapDB(path, session_info=session_info, + credentials=credentials, lp=lp) idmap_ldb.erase() idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif")) @@ -924,18 +910,21 @@ def provision(setup_dir, message, session_info, if dnspass is None: dnspass = misc.random_password(12) if root is None: - root = findnss(pwd.getpwnam, ["root"])[0] + root_uid = findnss(pwd.getpwnam, ["root"])[2] + else: + root_uid = findnss(pwd.getpwnam, [root])[2] if nobody is None: - nobody = findnss(pwd.getpwnam, ["nobody"])[0] - if nogroup is None: - nogroup = findnss(grp.getgrnam, ["nogroup", "nobody"])[0] + nobody_uid = findnss(pwd.getpwnam, ["nobody"])[2] + else: + nobody_uid = findnss(pwd.getpwnam, [nobody])[2] if users is None: - users = findnss(grp.getgrnam, ["users", "guest", "other", "unknown", - "usr"])[0] + users_gid = findnss(grp.getgrnam, ["users"])[2] + else: + users_gid = findnss(grp.getgrnam, [users])[2] if wheel is None: - wheel = findnss(grp.getgrnam, ["wheel", "root", "staff", "adm"])[0] - if backup is None: - backup = findnss(grp.getgrnam, ["backup", "wheel", "root", "staff"])[0] + wheel_gid = findnss(grp.getgrnam, ["wheel", "adm"])[2] + else: + wheel_gid = findnss(grp.getgrnam, [wheel])[2] if aci is None: aci = "# no aci for local ldb" @@ -994,8 +983,8 @@ def provision(setup_dir, message, session_info, credentials=credentials, lp=lp) message("Setting up idmap db") - setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, - credentials=credentials, lp=lp) + idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info, + credentials=credentials, lp=lp) samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info, credentials=credentials, lp=lp, names=names, @@ -1026,11 +1015,11 @@ def provision(setup_dir, message, session_info, machinepass=machinepass, dnsdomain=names.dnsdomain) if samdb_fill == FILL_FULL: - setup_name_mappings(samdb, str(domainsid), names.domaindn, root=root, - nobody=nobody, nogroup=nogroup, wheel=wheel, - users=users, backup=backup) - - message("Compleating sam.ldb setup by marking as synchronized") + setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn, + root_uid=root_uid, nobody_uid=nobody_uid, + users_gid=users_gid, wheel_gid=wheel_gid) + + message("Setting up sam.ldb rootDSE marking as synchronized") setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) # Only make a zone file on the first DC, it should be replicated with DNS replication diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index de0fd4ba04..bc3eef7879 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -53,25 +53,6 @@ description: %s for msg in self.parse_ldif(add): self.add(msg[1]) - def setup_name_mapping(self, domaindn, sid, unixname): - """Setup a mapping between a sam name and a unix name. - - :param domaindn: DN of the domain. - :param sid: SID of the NT-side of the mapping. - :param unixname: Unix name to map to. - """ - res = self.search(domaindn, ldb.SCOPE_SUBTREE, - "objectSid=%s" % sid, ["dn"]) - assert len(res) == 1, "Failed to find record for objectSid %s" % sid - - mod = """ -dn: %s -changetype: modify -replace: unixName -unixName: %s -""" % (res[0].dn, unixname) - self.modify(self.parse_ldif(mod).next()[1]) - def enable_account(self, user_dn): """Enable an account. diff --git a/source4/winbind/idmap.c b/source4/winbind/idmap.c index de8a43ec02..92ac41f1d2 100644 --- a/source4/winbind/idmap.c +++ b/source4/winbind/idmap.c @@ -210,13 +210,26 @@ NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, NTSTATUS status = NT_STATUS_NONE_MAPPED; struct ldb_context *ldb = idmap_ctx->ldb_ctx; struct ldb_result *res = NULL; - uint32_t low, high; 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, "(&(objectClass=sidMap)(xidNumber=%u))", - unixid->id); + 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; @@ -235,40 +248,9 @@ NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } - DEBUG(6, ("xid not found in idmap db, trying to allocate SID.\n")); - - /* Now redo the search to make sure noone added a mapping for that SID - * while we weren't looking.*/ - ret = ldb_search_exp_fmt(ldb, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, - NULL, "(&(objectClass=sidMap)(xidNumber=%u))", - 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 > 0) { - DEBUG(1, ("sidMap modified while trying to add a mapping.\n")); - status = NT_STATUS_RETRY; - goto failed; - } - - ret = idmap_get_bounds(idmap_ctx, &low, &high); - if (ret != LDB_SUCCESS) { - DEBUG(1, ("Failed to get id bounds from db: %u\n", ret)); - status = NT_STATUS_NONE_MAPPED; - goto failed; - } - - if (unixid->id >= low && unixid->id <= high) { - /* An existing xid would have been mapped before */ - status = NT_STATUS_NONE_MAPPED; - goto failed; - } + DEBUG(6, ("xid not found in idmap db, create S-1-22- SID.\n")); - /* For local users, we just create a rid = uid +1, so root doesn't end - * up with a 0 rid */ + /* 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 { @@ -279,7 +261,7 @@ NTSTATUS idmap_xid_to_sid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, goto failed; } - new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id + 1); + new_sid = dom_sid_add_rid(mem_ctx, unix_sid, unixid->id); if (new_sid == NULL) { status = NT_STATUS_NO_MEMORY; goto failed; @@ -326,42 +308,27 @@ NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, bool hwm_entry_exists; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - 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) { - 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 (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 = new_xid; - (*unixid)->type = ID_TYPE_BOTH; + (*unixid)->id = rid; + (*unixid)->type = ID_TYPE_UID; talloc_free(tmp_ctx); return NT_STATUS_OK; } - DEBUG(6, ("No existing mapping found, attempting to create one.\n")); - - if (dom_sid_in_domain(idmap_ctx->unix_users_sid, sid)) { + if (dom_sid_in_domain(idmap_ctx->unix_groups_sid, sid)) { uint32_t rid; - DEBUG(6, ("This is a local unix uid, just calculate that.\n")); + 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; @@ -370,30 +337,60 @@ NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, status = NT_STATUS_NO_MEMORY; goto failed; } - (*unixid)->id = rid - 1; - (*unixid)->type = ID_TYPE_UID; + (*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 (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; + 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 = rid - 1; - (*unixid)->type = ID_TYPE_GID; + + (*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) { @@ -585,6 +582,12 @@ NTSTATUS idmap_sid_to_xid(struct idmap_context *idmap_ctx, TALLOC_CTX *mem_ctx, 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; diff --git a/source4/winbind/idmap.h b/source4/winbind/idmap.h index 045d50c568..6eae92cc68 100644 --- a/source4/winbind/idmap.h +++ b/source4/winbind/idmap.h @@ -22,6 +22,8 @@ #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; @@ -29,24 +31,6 @@ struct idmap_context { struct dom_sid *unix_users_sid; }; -enum id_type { - ID_TYPE_NOT_SPECIFIED = 0, - ID_TYPE_UID, - ID_TYPE_GID, - ID_TYPE_BOTH -}; - -struct unixid { - uint32_t id; - enum id_type type; -}; - -struct id_mapping { - struct unixid *unixid; - struct dom_sid *sid; - NTSTATUS status; -}; - #include "winbind/idmap_proto.h" #endif diff --git a/source4/winbind/wb_irpc.c b/source4/winbind/wb_irpc.c index 5d7f7fd7a6..0535045adb 100644 --- a/source4/winbind/wb_irpc.c +++ b/source4/winbind/wb_irpc.c @@ -22,6 +22,7 @@ #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" @@ -71,6 +72,71 @@ static void wb_irpc_SamLogon_callback(struct composite_context *ctx) 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; @@ -81,5 +147,9 @@ NTSTATUS wbsrv_init_irpc(struct wbsrv_service *service) 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_xids2sids.c b/source4/winbind/wb_xids2sids.c index 843d292c07..1be394d276 100644 --- a/source4/winbind/wb_xids2sids.c +++ b/source4/winbind/wb_xids2sids.c @@ -41,7 +41,7 @@ struct composite_context *wb_xids2sids_send(TALLOC_CTX *mem_ctx, struct composite_context *result; struct xids2sids_state *state; - DEBUG(0, ("wb_xids2sids_send called\n")); + DEBUG(5, ("wb_xids2sids_send called\n")); result = composite_create(mem_ctx, service->task->event_ctx); if (!result) return NULL; @@ -68,7 +68,7 @@ NTSTATUS wb_xids2sids_recv(struct composite_context *ctx, { NTSTATUS status = composite_wait(ctx); - DEBUG(0, ("wb_xids2sids_recv called.\n")); + DEBUG(5, ("wb_xids2sids_recv called.\n")); if (NT_STATUS_IS_OK(status)) { struct xids2sids_state *state = |