//Copyright 2009 Calculate Pack, http://www.calculate-linux.ru
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
// 
//      http://www.apache.org/licenses/LICENSE-2.0
// 
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// для пароля
#include <sys/types.h>
#include <pwd.h>

// для strcpy strlen
#include <string.h>

//Статистика файла
#include <sys/stat.h>
#include <fcntl.h>

//Время
#include <time.h>

//Cоздание строки
#include <stdarg.h>

// Директория хранения логов
char *DIR_LOG = "/var/log/calculate";
// Лог ошибок
char *FILE_LOG = "/var/log/calculate/replication-error.log";

// Запись лога
int write_log(char *message){
  struct tm *ptr_time;
  time_t lt;
  int fd;
  lt = time(NULL);
  ptr_time = localtime (&lt);
  fd = open(FILE_LOG,O_WRONLY|O_CREAT|O_APPEND, 0600);
  if (fd == -1)
  {
    printf("No open or create file %s\n",FILE_LOG);
    return 1;
  };
  char *str_time;
  char *asc_time;
  char *buff;
  asc_time = asctime(ptr_time);
  str_time = (char*) malloc(strlen(asc_time));
  memset(str_time,0,sizeof(str_time));
  strncat(str_time,asc_time,strlen(asc_time)-1);
  buff = (char*) malloc (strlen(str_time)+strlen(message)+3);
  sprintf (buff, "%s %s", str_time, message);
  write(fd,buff,strlen(buff));
  free(buff);
  free(str_time);
  close(fd);
  return 0;
};

// Выводит на экран и записывает сообщение в log
int print_and_log(const char *fmt, ...)
{
  const char *fmt_pr = fmt;
  const char *fmt_b = fmt;
  char *message;
  int n;
  va_list ap, ap_copy;
  va_start(ap, fmt);
  va_copy(ap_copy, ap);
  char *test;
  int len_str_args = 0;
  int len_args = 0;
  int size_str = strlen(fmt);
  while(*fmt_b != '\0' )
  {
    if ( *fmt_pr=='%' && *fmt_b == 's') 
      {
        test = va_arg(ap_copy,  char *);
        len_str_args += strlen(test);
        len_args++;
      };
      fmt_pr = fmt_b;
      *fmt_b++;
  };
  size_str = size_str + len_str_args -(2*len_args)+1;
  va_end(ap_copy);
  int err_malloc = 0;
  if ((message = malloc(size_str)) == NULL)
    {
      va_end(ap);
      err_malloc = 1;
    };
  if (err_malloc==0)
    {
      n = vsprintf(message, fmt, ap);
      va_end(ap);
      if (n <= -1)
        {
          printf ("Error create message in function print_and_log()");
          exit(EXIT_FAILURE);
        };
    }else 
    {
       printf ("Error allocate memory in function print_and_log()");
       exit(EXIT_FAILURE);
    };
  printf(message);
  write_log(message);
  free(message);
  return 0;
};

int main(int argc, char** argv){
  if (argc==1)
    {
      uid_t uid, gid;
      int rez1,rez2;
      int fd_dir;

      fd_dir = open(DIR_LOG,O_RDONLY);
      if (fd_dir == -1)
        {
        if (mkdir(DIR_LOG, S_IRWXU)!=0)
            {
              printf ("Can not create directory %s\n",DIR_LOG);
              exit(EXIT_FAILURE);
            };
        }else
        {
          close(fd_dir);
        };
      // получаем id и группу пользователя
      uid = getuid();
      gid = getgid();
      struct passwd *pwd = getpwuid (uid);
      if (pwd == NULL)
        {
          exit(EXIT_FAILURE);
        };
      // Получение имени пользователя
      char *login;
      login = (char*) malloc (strlen(pwd->pw_name)+1);
      if (login == NULL)
          {
            printf ("Unable to allocate memory for the program\n");
            exit(EXIT_FAILURE);
          };
      strcpy (login,pwd->pw_name);
      //Устанавливаем права пользователя на этот процесс
      rez1 = setgid(0);
      rez2 = setuid(0);
      if (rez1==-1||rez2==-1)
        {
          free(login);
          print_and_log("File %s is not suid or its owner is not root\n", argv[0]);
          exit(EXIT_FAILURE);
        };
  struct stat bufS;
  int res;
  int fd;
  //   Выполняемая программа
  char *str_prog = "/usr/bin/repldap";
  fd = open(str_prog, O_RDONLY);
  res = fstat(fd,&bufS);
  if (res==0)
    {
      close(fd);
    }else
    {
      print_and_log("No exists file %s\n",str_prog);
      exit(EXIT_FAILURE);
    };
  //  Проверка на доступ на запись в выполнимую программу
  int file_mode_err;
  file_mode_err = S_IWGRP|S_IWOTH;
  if (bufS.st_mode & file_mode_err)
    {
      print_and_log("Invalid file access mode, file %s\n",str_prog);
      exit(EXIT_FAILURE);
    };
  //  Проверка на флаг выполнения выполнимой программы
  int file_mode_success;
  file_mode_success = S_IXUSR;
  if (!(bufS.st_mode & file_mode_success))
    {
      print_and_log("Invalid file access mode, file %s\n",str_prog);
      exit(EXIT_FAILURE);
    };
  //  Проверка на владельца файла, должен быть root
  if (!(bufS.st_uid == 0 && bufS.st_gid == 0))
    {
      print_and_log("Owner or group of file %s are not root\n",str_prog);
      exit(EXIT_FAILURE);
    };
    char str_exec[255];
    memset(str_exec,0,sizeof(str_exec));
    sprintf (str_exec, "%s -s -l %s",str_prog,login);
    free(login);
    int ret;
    ret = system(str_exec);
    if (ret!=0)
      {
        print_and_log("The program '%s' is executed with an error\n",str_exec);
        exit(EXIT_FAILURE);
      };
      exit(EXIT_SUCCESS);
    }
  else
    {
      print_and_log("Program do not require command line parameters\n");
      exit(EXIT_FAILURE);
    };
}
