/* * 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 */ /* * Common functions for indications used in Account provider */ #include #include #include #include #include #include #include #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) {\ goto bail;\ }\ 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); 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; bail: if (wd_pwd > 0) { inotify_rm_watch(fd, wd_pwd); } if (wd_grp > 0) { inotify_rm_watch(fd, wd_grp); } close(fd); return false; }