diff options
author | Roman Rakus <rrakus@redhat.com> | 2013-06-26 16:39:57 +0200 |
---|---|---|
committer | Roman Rakus <rrakus@redhat.com> | 2013-07-01 11:32:25 +0200 |
commit | 17155ddc8f2d7168a8f6f6fa24439342758d3125 (patch) | |
tree | b917be9030dd0d64be5d701b20d4d410da3350ce /src/account/indication_common.c | |
parent | 9382852767bcd560fa14e9cdbbbc8764fdf4dd91 (diff) | |
download | openlmi-providers-17155ddc8f2d7168a8f6f6fa24439342758d3125.tar.gz openlmi-providers-17155ddc8f2d7168a8f6f6fa24439342758d3125.tar.xz openlmi-providers-17155ddc8f2d7168a8f6f6fa24439342758d3125.zip |
Account: Indications for creation and deletion
Signed-off-by: Roman Rakus <rrakus@redhat.com>
Diffstat (limited to 'src/account/indication_common.c')
-rw-r--r-- | src/account/indication_common.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/account/indication_common.c b/src/account/indication_common.c new file mode 100644 index 0000000..7c61ba0 --- /dev/null +++ b/src/account/indication_common.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Roman Rakus <rrakus@redhat.com> + */ + +/* + * Common functions for indications used in Account provider + */ + +#include <cmpimacs.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/inotify.h> +#include <limits.h> + +#include "indication_common.h" + + +#include "LMI_Account.h" +#include "LMI_Group.h" +#include "LMI_Identity.h" +static const char* allowed_classes[] = { + LMI_Account_ClassName, + LMI_Group_ClassName, + LMI_Identity_ClassName, + NULL }; + +#define EVENT_SIZE (sizeof(struct inotify_event)) +#define BUF_LEN (10 * EVENT_SIZE + NAME_MAX + 1) +#define PASSWD_FILE "/etc/passwd" +#define GROUP_FILE "/etc/group" + + +bool filter_checker(const CMPISelectExp *filter) +{ + /* + * Support only simple conditions and only on allowed_classes + * and type of `sourceinstance ISA allowed_class' + */ + CMPIStatus st; + CMPISelectCond *sec = CMGetDoc(filter, &st); + if (!sec) return false; + CMPICount count = CMGetSubCondCountAndType(sec, NULL, &st); + if (count != 1) return false; + CMPISubCond *sub = CMGetSubCondAt(sec, 0, &st); + if (!sub) return false; + count = CMGetPredicateCount(sub, &st); + if (count != 1) return false; + CMPIPredicate *pred = CMGetPredicateAt(sub, 0, &st); + if (!pred) return false; + CMPIType type; + CMPIPredOp op; + CMPIString *lhs = NULL; + CMPIString *rhs = NULL; + st = CMGetPredicateData(pred, &type, &op, &lhs, &rhs); + if (st.rc != CMPI_RC_OK || op != CMPI_PredOp_Isa) return false; + const char *rhs_str = CMGetCharsPtr(rhs, &st); + if (!rhs_str) return false; + unsigned i = 0; + while (allowed_classes[i]) { + if (strcasecmp(rhs_str, allowed_classes[i++]) == 0) return true; + } + return false; +} + +/* + * Returns last modification time for specified file name + */ +static struct timespec get_last_mod(const char* file) +{ + struct stat buf = {0}; + stat (file, &buf); + return buf.st_mtim; +} + +/* + * Compares 2 timespecs + * return value is same like in strcmp + */ +static int timecmp(struct timespec a, struct timespec b) +{ + if (a.tv_sec == b.tv_sec) { + if (a.tv_nsec == b.tv_nsec) { + return 0; + } else { + return (a.tv_nsec > b.tv_nsec ? 1 : -1); + } + } else { + return (a.tv_sec > b.tv_sec ? 1 : -1); + } +} + +#define ADD_WATCH(fd, wd, file)\ + (wd) = inotify_add_watch((fd), (file), IN_CLOSE_WRITE | IN_MODIFY |\ + IN_DELETE | IN_DELETE_SELF);\ + if ((wd) < 0) {\ + close((fd));\ + return false;\ + }\ + +bool watcher(void *data) +{ + struct timespec last_pwd = get_last_mod(PASSWD_FILE); + struct timespec last_grp = get_last_mod(GROUP_FILE); + int fd = inotify_init(); + + if (fd < 0) { + return false; + } + char buffer[BUF_LEN]; + + int wd_pwd, wd_grp; + ADD_WATCH(fd, wd_pwd, PASSWD_FILE); + ADD_WATCH(fd, wd_grp, GROUP_FILE); + if (wd_pwd < 0 || wd_grp < 0) { + close(fd); + return false; + } + + do { + int len = 0, i = 0; + if ((len = read(fd, buffer, BUF_LEN)) < 0) { + close(fd); + return false; + } + while (i < len) { + struct inotify_event *event = (struct inotify_event *) &buffer[i]; + switch (event->mask) { + case IN_MODIFY: + case IN_CLOSE_WRITE: + case IN_DELETE: + case IN_DELETE_SELF: + if (event->wd == wd_grp) { + if (timecmp(last_grp, get_last_mod(GROUP_FILE)) == -1) { + goto out; + } + } else { + if (timecmp(last_pwd, get_last_mod(PASSWD_FILE)) == -1) { + goto out; + } + } + break; + case IN_IGNORED: + if (event->wd == wd_grp) { + ADD_WATCH(fd, wd_grp, GROUP_FILE); + if (timecmp(last_grp, get_last_mod(GROUP_FILE)) == -1) { + goto out; + } + } else { + ADD_WATCH(fd, wd_pwd, PASSWD_FILE); + if (timecmp(last_pwd, get_last_mod(PASSWD_FILE)) == -1) { + goto out; + } + } + break; + i += EVENT_SIZE + event->len; + } + } + } while (1); + +out: + inotify_rm_watch(fd, wd_pwd); + inotify_rm_watch(fd, wd_grp); + close(fd); + return true; +} |