瀏覽代碼

new package: openpkg-audit 0.9.0 (OpenPKG Administration Auditing)

Ralf S. Engelschall 21 年之前
父節點
當前提交
ecef943185
共有 3 個文件被更改,包括 528 次插入0 次删除
  1. 279 0
      openpkg-audit/audit-rpm.c
  2. 162 0
      openpkg-audit/audit.sh
  3. 87 0
      openpkg-audit/openpkg-audit.spec

+ 279 - 0
openpkg-audit/audit-rpm.c

@@ -0,0 +1,279 @@
+/*
+**  rpm.c -- OpenPKG RPM Auditing Wrapper
+**  Copyright (c) 2004 The OpenPKG Project <http://www.openpkg.org/>
+**  Copyright (c) 2004 Ralf S. Engelschall <rse@engelschall.com>
+**  Copyright (c) 2004 Cable & Wireless <http://www.cw.com/>
+**
+**  Permission to use, copy, modify, and distribute this software for
+**  any purpose with or without fee is hereby granted, provided that
+**  the above copyright notice and this permission notice appear in all
+**  copies.
+**
+**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+**  SUCH DAMAGE.
+*/
+
+/*  This is a small OpenPKG RPM command wrapper which provides minimal
+    auditing/logging possibilities to an OpenPKG instance by writing
+    a <prefix>/RPM/DB/Audit logfile containing the RPM commands which
+    actually led to a RPM database change. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+/* utility function for fatal program termination under error condition */
+void die(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    fprintf(stderr, "openpkg-audit: rpm: ERROR: ");
+    vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
+    va_end(ap);
+    exit(1);
+}
+
+/* the auditing logfile */
+#ifndef LOGFILE
+#define LOGFILE "/var/openpkg-audit/openpkg-audit.log"
+#endif
+
+/* the RPM database directory and owner/permission */
+#define RPMDB_DIR   "RPM/DB"
+
+/* list of RPM database files to check */
+static char *RPMDB_files[] = {
+    "Basenames",
+    "Conflictname",
+    "Depends",
+    "Dirnames",
+    "Filemd5s",
+    "Group",
+    "Installtid",
+    "Name",
+    "Packages",
+    "Providename",
+    "Provideversion",
+    "Pubkeys",
+    "Requirename",
+    "Requireversion",
+    "Sha1header",
+    "Sigmd5",
+    "Triggername"
+};
+
+/* utility function for making a concatenated string out of multiple arguments */
+static char *mkstr(const char *pad, const char *s1, ...)
+{
+    va_list ap;
+    va_list apbak;
+    int n;
+    const char *cp;
+    char *str;
+
+    va_start(ap, s1);
+    va_copy(apbak, ap);
+    n = 0;
+    for (cp = s1; cp != NULL; cp = (const char *)va_arg(ap, const char *))
+        n += strlen(cp);
+    n++;
+    va_copy(ap, apbak);
+    if ((str = (char *)malloc(n)) == NULL)
+        die("failed to allocate %d bytes of memory", n);
+    str[0] = '\0';
+    for (cp = s1; cp != NULL; cp = (const char *)va_arg(ap, const char *)) {
+        if (pad != NULL && str[0] != '\0')
+            strcat(str, pad);
+        strcat(str, cp);
+    }
+    va_end(ap);
+    return str;
+}
+
+/* utility function for making a concatenated string out of an array */
+static char *mkstra(const char *pad, char **sa)
+{
+    int n, i;
+    char *str;
+
+    n = 0;
+    for (i = 0; sa[i] != NULL; i++)
+        n += strlen(sa[i]);
+    n++;
+    if ((str = (char *)malloc(n)) == NULL)
+        die("failed to allocate %d bytes of memory", n);
+    str[0] = '\0';
+    for (i = 0; sa[i] != NULL; i++) {
+        if (pad != NULL && str[0] != '\0')
+            strcat(str, pad);
+        strcat(str, sa[i]);
+    }
+    return str;
+}
+
+/* utility function for determining the maximum mtime of the RPM database */
+static time_t rpmdb_mtime(const char *cpPrefix)
+{
+    time_t mtime = 0;
+    int i;
+    char *cp;
+    struct stat sb;
+
+    for (i = 0; i < sizeof(RPMDB_files)/sizeof(RPMDB_files[0]); i++) {
+        cp = mkstr(NULL, cpPrefix, "/", RPMDB_DIR, "/", RPMDB_files[i], NULL);
+        if (stat(cp, &sb) == 0) {
+            if (mtime < sb.st_mtime)
+                mtime = sb.st_mtime;
+        }
+        free(cp);
+    }
+    return mtime;
+}
+
+/* main procedure */
+int main(int argc, char *argv[])
+{
+    char *cpPrefix;
+    char *cpToolsCmdProg;
+    char *cpToolsCmdName;
+    int i, j;
+    char **argv2;
+    FILE *fp;
+    char *cpLogfile;
+    struct tm *tm;
+    time_t t;
+    struct passwd *pw;
+    char *cpCmd;
+    time_t mtime_before;
+    time_t mtime_after;
+    char *cp;
+    pid_t pid;
+    int status;
+    int rv;
+    int fd;
+    struct stat sb;
+
+    /* determine OpenPKG run-time information
+       (provided by <prefix>/bin/openpkg execution wrapper) */
+    if ((cpPrefix = getenv("OPENPKG_PREFIX")) == NULL)
+        die("$OPENPKG_PREFIX not set");
+    if ((cpToolsCmdProg = getenv("OPENPKG_TOOLS_CMDPROG")) == NULL)
+        die("$OPENPKG_TOOLS_CMDPROG not set");
+    if ((cpToolsCmdName = getenv("OPENPKG_TOOLS_CMDNAME")) == NULL)
+        die("$OPENPKG_TOOLS_CMDNAME not set");
+
+    /* determine argument vector for real OpenPKG RPM command
+       argv:  <prefix>/lib/openpkg-audit/rpm <arg1> <arg2> ...
+       argv2: <prefix>/bin/openpkg       rpm <arg1> <arg2> ... */
+    if ((argv2 = (char **)malloc((2+argc+1) * sizeof(char *))) == NULL)
+        die("cannot malloc");
+    j = 0;
+    argv2[j++] = cpToolsCmdProg;
+    argv2[j++] = cpToolsCmdName;
+    i = 1;
+    while (i < argc)
+        argv2[j++] = argv[i++];
+    argv2[j++] = NULL;
+
+    /* determine whether access to the RPM database is possible
+       and it not, short-circuit processing */
+    cp = mkstr(NULL, cpPrefix, "/", RPMDB_DIR, "/", RPMDB_files[0], NULL);
+    if (access(cp, R_OK|W_OK) != 0) {
+        /* pass-through execution to real OpenPKG RPM command */
+        execvp(argv2[0], argv2);
+        /* NEVER REACHED */
+        abort();
+    }
+    free(cp);
+
+    /* determine maximum modification time (before operation) */
+    mtime_before = rpmdb_mtime(cpPrefix);
+
+    /* execute real OpenPKG RPM command */
+    if ((pid = fork()) == 0) {
+        /* pass-through execution to real OpenPKG RPM command */
+        execvp(argv2[0], argv2);
+        /* NEVER REACHED */
+        abort();
+    }
+
+    /* wait for child to terminate */
+    if (waitpid(pid, &status, 0) < 0)
+        die("failed to wait for child process with PID %d\n", pid);
+
+    /* determine return code */
+    rv = (WIFEXITED(status) ? WEXITSTATUS(status) : -1);
+
+    /* determine maximum modification time (after operation) */
+    mtime_after = rpmdb_mtime(cpPrefix);
+
+    /* if an operation was performed which has not changed the RPM
+       database we short-circuit processing and exit without logging */
+    if (mtime_after == mtime_before)
+        exit(rv);
+
+    /* determine time */
+    t = time(NULL);
+    if ((tm = localtime(&t)) == NULL)
+        die("cannot determine local time");
+
+    /* determine user */
+    if ((pw = getpwuid(getuid())) == NULL)
+        die("cannot determine user information");
+
+    /* determine command */
+    cpCmd = mkstra(" ", &argv2[1]);
+
+    /* optionally give up any root privileges to make sure
+       the file is written with the OpenPKG RPM database user/group */
+    cp = mkstr(NULL, cpPrefix, "/", RPMDB_DIR, "/", RPMDB_files[0], NULL);
+    if (stat(cp, &sb) < 0)
+        die("unable to stat the RPM database file %s", cp);
+    free(cp);
+    setgid(sb.st_gid); setegid(sb.st_gid);
+    setuid(sb.st_uid); seteuid(sb.st_uid);
+
+    /* write entry to logfile */
+    cpLogfile = mkstr(NULL, cpPrefix, "/", LOGFILE, NULL);
+    if ((fd = open(cpLogfile, O_CREAT|O_RDWR|O_APPEND, sb.st_mode)) == -1)
+        die("cannot open logfile \"%s\"", cpLogfile);
+    free(cpLogfile);
+    if ((fp = fdopen(fd, "a")) == NULL)
+        die("cannot open filedescriptor");
+    fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d user=%s, command=\"%s\", return=%d\n",
+        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+        tm->tm_hour, tm->tm_min, tm->tm_sec,
+        pw->pw_name,
+        cpCmd, rv);
+    fclose(fp);
+    close(fd);
+
+    /* cleanup */
+    free(argv2);
+    free(cpCmd);
+
+    exit(0);
+}
+

+ 162 - 0
openpkg-audit/audit.sh

@@ -0,0 +1,162 @@
+#!@l_prefix@/lib/openpkg/bash
+##
+##  audit -- OpenPKG Tool Chain "audit" command
+##  Copyright (c) 2004 The OpenPKG Project <http://www.openpkg.org/>
+##  Copyright (c) 2004 Ralf S. Engelschall <rse@engelschall.com>
+##  Copyright (c) 2004 Cable & Wireless <http://www.cw.com/>
+##
+##  Permission to use, copy, modify, and distribute this software for
+##  any purpose with or without fee is hereby granted, provided that
+##  the above copyright notice and this permission notice appear in all
+##  copies.
+##
+##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+##  SUCH DAMAGE.
+##
+
+#   configuration
+logfile="@l_prefix@/var/openpkg-audit/openpkg-audit.log"
+
+#   command line parsing
+opt_m=""
+opt_r=no
+opt_h=no
+opt_l=no
+opt_n=0
+opt_f=no
+OPTIND=1
+while getopts m:rln:fh opt; do
+    case ${opt} in
+        m ) opt_m=$OPTARG ;;
+        r ) opt_r=yes ;;
+        l ) opt_l=yes ;;
+        n ) opt_n=$OPTARG ;;
+        f ) opt_f=yes ;;
+        h ) opt_h=yes ;;
+        * ) echo "openpkg:audit:ERROR: invalid option \"${opt}\"" 1>&2; exit 1 ;;
+    esac
+done
+shift $(($OPTIND - 1))
+
+#   dispatch into commands
+if [ ".${opt_h}" = .yes ]; then
+    #   show usage message
+    echo "Usage: openpkg audit [-m <message>] [-r] [-l] [-n <lines>] [-f] [-h]" 1>&2
+elif [ ".${opt_l}" = .yes ]; then
+    #   show logfile
+    if [ ".${opt_f}" = .yes ]; then
+        tail -f ${logfile}
+    elif [ ".${opt_n}" != .0 ]; then
+        tail -n ${opt_n} ${logfile}
+    else
+        cat ${logfile}
+    fi
+elif [ ".${opt_m}" != . ]; then
+    #   add manual administrator entry to logfile
+    if [ ! -w $logfile ]; then
+        echo "openpkg:audit:ERROR: unsufficient privileges to write to \"$logfile\"" 1>&2
+        exit 1
+    fi
+
+    #   determine date and user
+    date=`date '+%Y-%m-%d %H:%M:%S'`
+    user=`@l_prefix@/lib/openpkg/shtool echo -e '%u'`
+
+    #   create logfile entry
+    if [ ".${opt_r}" = .yes ]; then
+        echo "$date user=$user, $opt_m" >>$logfile
+    else
+        echo "$date user=$user, message=\"$opt_m\"" >>$logfile
+    fi
+fi
+exit 0
+
+##
+##  MANUAL PAGE
+##
+
+=pod
+
+=head1 NAME
+
+B<openpkg audit> - OpenPKG Auditing Facility
+
+=head1 SYNOPSIS
+
+B<openpkg audit> [B<-m> I<message>] [B<-r>]
+
+B<openpkg audit> [B<-l>] [B<-n> I<lines>] [B<-f>]
+
+B<openpkg audit> [B<-h>]
+
+=head1 DESCRIPTION
+
+The B<openpkg audit> command is the frontend to the OpenPKG auditing
+logfile which is currently written by the B<openpkg rpm>
+command in case the RPM database was changed.
+
+=head1 OPTIONS
+
+The following command line options exist:
+
+=over 4
+
+=item B<-m> I<message>
+
+Adds I<message> to the auditing logfile as a C<message="..."> entry.
+
+=item B<-r>
+
+In conjunction with B<-m>, adds I<message> to the auditing logfile as a
+raw message.
+
+=item B<-l>
+
+Shows the auditing logfile.
+
+=item B<-n> I<lines>
+
+In conjunction with B<-l>, shows only the last I<lines> number of lines.
+
+=item B<-f>
+
+In conjunction with B<-l>, follows the logfile.
+
+=item B<-h>
+
+Shows a command usage.
+
+=back
+
+=head1 FILES
+
+The following paths are used by B<openpkg audit>:
+
+=over 4
+
+=item F<@l_prefix@/bin/openpkg>
+
+=item F<@l_prefix@/var/openpkg-audit/openpkg-audit.log>
+
+=back
+
+=head1 SEE ALSO
+
+C<openpkg man rpm>.
+
+=head1 AUTHOR
+
+Ralf S. Engelschall E<lt>rse@openpkg.orgE<gt>
+
+=cut
+

+ 87 - 0
openpkg-audit/openpkg-audit.spec

@@ -0,0 +1,87 @@
+##
+##  openpkg-audit.spec -- OpenPKG RPM Specification
+##  Copyright (c) 2000-2004 The OpenPKG Project <http://www.openpkg.org/>
+##  Copyright (c) 2000-2004 Ralf S. Engelschall <rse@engelschall.com>
+##  Copyright (c) 2000-2004 Cable & Wireless <http://www.cw.com/>
+##
+##  Permission to use, copy, modify, and distribute this software for
+##  any purpose with or without fee is hereby granted, provided that
+##  the above copyright notice and this permission notice appear in all
+##  copies.
+##
+##  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+##  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+##  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+##  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+##  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+##  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+##  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+##  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+##  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+##  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+##  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+##  SUCH DAMAGE.
+##
+
+#   package information
+Name:         openpkg-audit
+Summary:      OpenPKG Administration Auditing
+URL:          http://www.openpkg.org/
+Vendor:       The OpenPKG Project
+Packager:     The OpenPKG Project
+Distribution: OpenPKG
+Class:        EVAL
+Group:        Bootstrap
+License:      MIT-style
+Version:      0.9.0
+Release:      20040701
+
+#   list of sources
+Source0:      audit.sh
+Source1:      audit-rpm.c
+
+#   build information
+Prefix:       %{l_prefix}
+BuildRoot:    %{l_buildroot}
+BuildPreReq:  OpenPKG, openpkg >= 20040701
+PreReq:       OpenPKG, openpkg >= 20040701
+AutoReq:      no
+AutoReqProv:  no
+
+%description
+    This is the OpenPKG administration auditing package. It provides
+    a wrapper for the "openpkg rpm" command which logs all commands
+    the administrator performs on the OpenPKG instance plus a "openpkg
+    audit" command as a frontend to the log entries.
+
+%track
+    prog openpkg-audit = {
+        disabled
+        version   = %{version}
+        url       = ftp://ftp.openpkg.org/
+        regex     = .*
+    }
+
+%prep
+    %setup -q -T -c
+
+%build
+    %{l_cc} %{l_cflags -O} %{l_cppflags} %{l_ldflags} \
+        -o rpm %{SOURCE audit-rpm.c}
+
+%install
+    rm -rf $RPM_BUILD_ROOT
+    %{l_shtool} mkdir -f -p -m 755 \
+        $RPM_BUILD_ROOT%{l_prefix}/libexec/openpkg-audit \
+        $RPM_BUILD_ROOT%{l_prefix}/var/openpkg-audit
+    %{l_shtool} install -c -m 755 %{l_value -s -a} \
+        %{SOURCE audit.sh} $RPM_BUILD_ROOT%{l_prefix}/libexec/openpkg-audit/
+    %{l_shtool} install -c -s -m 755 \
+        rpm $RPM_BUILD_ROOT%{l_prefix}/libexec/openpkg-audit/
+    %{l_rpmtool} files -v -ofiles -r$RPM_BUILD_ROOT %{l_files_std}
+
+%files -f files
+
+%clean
+    rm -rf $RPM_BUILD_ROOT
+