From 1018345c45fd104399285a30659cf6c29be77539 Mon Sep 17 00:00:00 2001 From: Gregor Beck Date: Thu, 3 Feb 2011 16:30:29 +0100 Subject: [PATCH] s3: smbcontrol to notify smbd about idmap changes --- source3/Makefile.in | 2 +- source3/include/proto.h | 4 + source3/librpc/idl/messaging.idl | 4 + source3/smbd/msg_idmap.c | 205 +++++++++++++++++++++++++++++++ source3/smbd/server.c | 2 + source3/utils/smbcontrol.c | 49 ++++++++ 6 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 source3/smbd/msg_idmap.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 0d6a631265c..f52e92207bb 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -867,7 +867,7 @@ AUTH_OBJ = auth/auth.o @AUTH_STATIC@ auth/auth_util.o auth/token_util.o \ MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_hash2.o -SMBD_OBJ_MAIN = smbd/server.o smbd/server_exit.o +SMBD_OBJ_MAIN = smbd/server.o smbd/server_exit.o smbd/msg_idmap.o BUILDOPT_OBJ = smbd/build_options.o diff --git a/source3/include/proto.h b/source3/include/proto.h index 050e4d64b1d..0fddbb1d841 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -5546,6 +5546,10 @@ struct AvahiPoll *tevent_avahi_poll(TALLOC_CTX *mem_ctx, void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev, uint16_t port); +/* The following definitions come from smbd/msg_idmap.c */ + +void msg_idmap_register_msgs(struct messaging_context *ctx); + /* Misc protos */ struct fncall_context *fncall_context_init(TALLOC_CTX *mem_ctx, diff --git a/source3/librpc/idl/messaging.idl b/source3/librpc/idl/messaging.idl index 0ac7220995b..419e995ed7e 100644 --- a/source3/librpc/idl/messaging.idl +++ b/source3/librpc/idl/messaging.idl @@ -34,6 +34,10 @@ interface messaging MSG_REQ_DMALLOC_LOG_CHANGED = 0x000C, MSG_SHUTDOWN = 0x000D, + MSG_IDMAP_FLUSH = 0x000E, + MSG_IDMAP_DELETE = 0x000F, + MSG_IDMAP_KILL = 0x0010, + /* nmbd messages */ MSG_FORCE_ELECTION = 0x0101, MSG_WINS_NEW_ENTRY = 0x0102, diff --git a/source3/smbd/msg_idmap.c b/source3/smbd/msg_idmap.c new file mode 100644 index 00000000000..8cef268af72 --- /dev/null +++ b/source3/smbd/msg_idmap.c @@ -0,0 +1,205 @@ +/* + * Samba Unix/Linux SMB client library + * + * Copyright (C) Gregor Beck 2011 + * + * 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 . + */ + +/** + * @brief Notify smbd about idmap changes + * @file msg_idmap.c + * @author Gregor Beck + * @date Feb 2011 + * + */ + +#include "includes.h" +#include "memcache.h" +#include "globals.h" +#include "../libcli/security/dom_sid.h" +#include "../librpc/gen_ndr/messaging.h" +#include "../librpc/gen_ndr/ndr_security.h" +#include "idmap_cache.h" + +struct id { + union { + uid_t uid; + gid_t gid; + struct dom_sid sid; + }; + enum {UID, GID, SID} type; +}; + +static bool parse_id(const char* str, struct id* id) +{ + struct dom_sid sid; + unsigned long ul; + char c, trash; + + if (sscanf(str, "%cID %lu%c", &c, &ul, &trash) == 2) { + switch(c) { + case 'G': + id->gid = ul; + id->type = GID; + return true; + case 'U': + id->uid = ul; + id->type = UID; + return true; + default: + break; + } + } else if (string_to_sid(&sid, str)) { + id->sid = sid; + id->type = SID; + return true; + } + return false; +} + +static bool uid_in_use(const struct user_struct* user, uid_t uid) +{ + while (user) { + if (user->server_info && (user->server_info->utok.uid == uid)) { + return true; + } + user = user->next; + } + return false; +} + +static bool gid_in_use(const struct user_struct* user, gid_t gid) +{ + while (user) { + if (user->server_info != NULL) { + int i; + struct unix_user_token utok = user->server_info->utok; + if (utok.gid == gid) { + return true; + } + for(i=0; inext; + } + return false; +} + +static bool sid_in_use(const struct user_struct* user, const struct dom_sid* psid) +{ + uid_t uid; + gid_t gid; + if (sid_to_gid(psid, &gid)) { + return gid_in_use(user, gid); + } else if (sid_to_uid(psid, &uid)) { + return uid_in_use(user, uid); + } + return false; +} + + +static bool id_in_use(const struct user_struct* user, const struct id* id) +{ + switch(id->type) { + case UID: + return uid_in_use(user, id->uid); + case GID: + return gid_in_use(user, id->gid); + case SID: + return sid_in_use(user, &id->sid); + default: + break; + } + return false; +} + +static void delete_from_cache(const struct id* id) +{ + switch(id->type) { + case UID: + delete_uid_cache(id->uid); + idmap_cache_del_uid(id->uid); + break; + case GID: + delete_gid_cache(id->gid); + idmap_cache_del_gid(id->gid); + break; + case SID: + delete_sid_cache(&id->sid); + idmap_cache_del_sid(&id->sid); + break; + default: + break; + } +} + + +static void message_idmap_flush(struct messaging_context *msg_ctx, + void* private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB* data) +{ + const char* msg = data ? (const char*)data->data : NULL; + + DEBUG(0, ("Foo: idmap flush cache message(0x%.2x): %s\n", msg_type, msg ? msg : "")); + + if ((msg == NULL) || (msg[0] == '\0')) { + flush_gid_cache(); + flush_uid_cache(); + } else if (strncmp(msg, "GID", 3)) { + flush_gid_cache(); + } else if (strncmp(msg, "UID", 3)) { + flush_uid_cache(); + } else { + DEBUG(0, ("Invalid argument: %s\n", msg)); + } +} + + +static void message_idmap_delete(struct messaging_context *msg_ctx, + void* private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB* data) +{ + const char* msg = (data && data->data) ? (const char*)data->data : ""; + bool do_kill = (msg_type == MSG_IDMAP_KILL); + struct user_struct* validated_users = smbd_server_conn->smb1.sessions.validated_users; + struct id id; + + DEBUG(0, ("Foo: idmap delete message(0x%.2x): %s\n", msg_type, msg)); + + if (!parse_id(msg, &id)) { + DEBUG(0, ("Invalid ?ID: %s\n", msg)); + return; + } + + if( do_kill && id_in_use(validated_users, &id) ) { + exit_server_cleanly(msg); + } else { + delete_from_cache(&id); + } +} + +void msg_idmap_register_msgs(struct messaging_context *ctx) +{ + messaging_register(ctx, NULL, MSG_IDMAP_FLUSH, message_idmap_flush); + messaging_register(ctx, NULL, MSG_IDMAP_DELETE, message_idmap_delete); + messaging_register(ctx, NULL, MSG_IDMAP_KILL, message_idmap_delete); +} diff --git a/source3/smbd/server.c b/source3/smbd/server.c index f4436bfad7a..61464f2ac57 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -758,6 +758,8 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent, messaging_register(msg_ctx, NULL, MSG_PRINTER_PCAP, smb_pcap_updated); brl_register_msgs(msg_ctx); + msg_idmap_register_msgs(msg_ctx); + #ifdef CLUSTER_SUPPORT if (lp_clustering()) { ctdbd_register_reconfigure(messaging_ctdbd_connection()); diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c index f4daf830885..d6b647f7a9e 100644 --- a/source3/utils/smbcontrol.c +++ b/source3/utils/smbcontrol.c @@ -166,6 +166,54 @@ static bool do_debug(struct messaging_context *msg_ctx, strlen(argv[1]) + 1); } + +static bool do_idmap(struct messaging_context *msg_ctx, + const struct server_id pid, + const int argc, const char **argv) +{ + static const char* usage = "Usage: " + "smbcontrol idmap [arg]\n" + "\tcmd:\tflush [gid|uid]\n" + "\t\tdelete \"UID \"|\"GID \"|\n" + "\t\tkill \"UID \"|\"GID \"|\n"; + const char* arg = NULL; + int arglen = 0; + int msg_type; + + switch (argc) { + case 2: + break; + case 3: + arg = argv[2]; + arglen = strlen(arg) + 1; + break; + default: + fprintf(stderr, "%s", usage); + return false; + } + + if (strcmp(argv[1], "flush") == 0) { + msg_type = MSG_IDMAP_FLUSH; + } + else if (strcmp(argv[1], "delete") == 0) { + msg_type = MSG_IDMAP_DELETE; + } + else if (strcmp(argv[1], "kill") == 0) { + msg_type = MSG_IDMAP_KILL; + } + else if (strcmp(argv[1], "help") == 0) { + fprintf(stdout, "%s", usage); + return true; + } + else { + fprintf(stderr, "%s", usage); + return false; + } + + return send_message(msg_ctx, pid, msg_type, arg, arglen); +} + + #if defined(HAVE_LIBUNWIND_PTRACE) && defined(HAVE_LINUX_PTRACE) /* Return the name of a process given it's PID. This will only work on Linux, @@ -1200,6 +1248,7 @@ static const struct { const char *help; /* Short help text */ } msg_types[] = { { "debug", do_debug, "Set debuglevel" }, + { "idmap", do_idmap, "Manipulate idmap cache" }, { "force-election", do_election, "Force a browse election" }, { "ping", do_ping, "Elicit a response" }, -- 2.34.1