/*
 * Distributed under the terms of the GNU General Public License v2
 * $Header: $
 */

 /********************************************************************
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA. 
 ********************************************************************/

/*
 * Remove world writeable bit from any attempted chmod access.
 * gcc -o libwperms.so libwperms.c -shared -fPIC -ldl
 * export LD_PRELOAD=$PWD/libwperms.so
 * touch out.x ; chmod 666 out.x ; ls -l out.x
 * Sun Nov 13 13:51:54 EST 2005
 */

#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>		/* for EXIT_FAULURE */
#include <unistd.h>		/* for _exit() */
#include <sys/types.h>
#include <sys/stat.h>

#ifndef RTLD_NEXT
#define RTLD_NEXT      ((void *) -1l)
#endif

typedef int (*chmod_t) (char *path, mode_t mode);
typedef int (*fchmod_t) (int fildes, mode_t mode);

static void *get_libc_func(const char *funcname)
{
   void *func;
   char *error;

   func = dlsym(RTLD_NEXT, funcname);
   if ((error = dlerror()) != NULL) {
      fprintf(stderr, "can't locate dlsym `%s' error: %s", funcname,
	      error);
      _exit(EXIT_FAILURE);
   }
   return func;
}

static mode_t wperms(mode_t mode)
{
   mode_t newmode = mode;
   newmode &= ~S_IWOTH;
   return newmode;
}

int chmod(const char *path, mode_t mode)
{
   chmod_t real_chmod;

   real_chmod = (chmod_t) get_libc_func("chmod");
   return real_chmod((char *) path, wperms(mode));
}

int fchmod(int fildes, mode_t mode)
{
   fchmod_t real_fchmod = (fchmod_t) get_libc_func("fchmod");
   return real_fchmod(fildes, wperms(mode));
}
