| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /*
- ** 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);
- }
|