#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include "access.h"

/*****************************************************
 * Function; fileAccess()
 *
 * Check if we have the required permissions for
 * the given file.
 *
 * Input:
 *   char *file  the name of the file to check
 *   int   mode  the permissions as R_OK|W_OK|X_OK
 *               or a part from there
 *
 * Return:
 *  -1 if we have not sufficient permission for the file
 *  0  if we have the permission
 *
 * Remark:
 *  We test also against euid and egid. The programm shall
 *  have its right set accordindly if we use this
 *
 *****************************************************/
 
int fileAccess(char *file, int mode)
{
   struct stat     status;
   int             euid = geteuid();
   int             egid = getegid();
   int             uid = getuid();
   int             gid = getgid();
   int             mask;
   struct passwd  *pwd;
   struct group   *grp;
   char          **gr_mem;

   if ( stat(file, &status) != 0 )
   {
      return -1;
   }

   if ( uid == 0 )
   {
      return 0;
   }

   if ( uid == status.st_uid || euid == status.st_uid)
   {
      mask = ((mode & R_OK) ? S_IRUSR : 0) | ((mode & W_OK) ? S_IWUSR : 0);
      if ( (status.st_mode & mask) == mask)
      {
         return 0;
      }
   }

   /* egid is only set the rights for the group are rwx!
    * chmod 2770 program_file this is not very nice.
    */

   mask = ((mode & R_OK) ? S_IRGRP : 0) | ((mode & W_OK) ? S_IWGRP : 0);
   if ( gid == status.st_gid || egid == status.st_gid )
   {
      if ( (status.st_mode & mask) == mask)
      {
         return 0;
      }
   }

   /* check for group membership if the group mask is OK */
   if ( (status.st_mode & mask) == mask)
   {
      if ( (pwd = getpwuid(uid)) != NULL)
      {
         if ( (grp = getgrgid(status.st_gid) ) != NULL )
         {
            gr_mem = grp->gr_mem;
            while ( *gr_mem )
            {
               if ( strcmp(pwd->pw_name, *gr_mem) == 0 )
               {
                  return 0;
               }
               gr_mem++;
            }
         }
      }
   }
   return -1;
}
