// // СЕРВЕР Olimp 1.01 // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sql.h" #include "version.h" #include "logger.h" #define SERV_PORT 777 #define SERV_EXE "in.olimpd" #define CfgName "olimpd.cfg" #define MAXFILES 20 /******************** флаги для run_process () ********************/ #define F_DUPSOCK 1 #define F_CLOSEALL 2 /******************** глобальные переменные ********************/ uid_t serv_uid=500; gid_t serv_gid=500; char buf[2 * 1024]; // буфер, используется для всяких непотребных целей int sock, nsock; // служебные сокеты int numproc = 0; // текущее количество работающих процессов char LogRecord[1024]; //фильтр IP #define ALLOW_IP_MAX 50 #define ALLOW_IP_LENGTH 20 #define DENY_IP_MAX 50 #define DENY_IP_LENGTH 20 int order_ad=1; int allow_ip_cnt=0; char allow_ip[ALLOW_IP_MAX][ALLOW_IP_LENGTH+1]; int deny_ip_cnt=0; char deny_ip[DENY_IP_MAX][DENY_IP_LENGTH+1]; int ip_allowed(char *ip); int ip_denied(char *ip); int CheckIP(char *ip); #define PROC_DESCR_MAX 100 struct _procdescr{ pid_t pid; char IP[20]; }; typedef struct _procdescr procdescr; procdescr ProcDescrs[PROC_DESCR_MAX]; //config для olimpd int maxproc=20; int maxproc4ip=2; int servtimelimit=300; char workdir[256]; char rundir[256]; char cfgdir[256]; /******************** прототипы функций ********************/ void init(); void run_process(char *name, int flags, char *ip); void onSigChld(int i); void onSigHup(int i); void onSigAlrm(int i); void ShowLimits(); void reply(int nsock, int code, char *msg); //---------------------- Надежный вариант функции signal void (*rel_signal(int signo, void (*hndlr)(int)))(int) { struct sigaction act,oact; act.sa_handler=hndlr; sigemptyset(&act.sa_mask); act.sa_flags=0; act.sa_flags |= SA_RESTART; if (sigaction(signo,&act,&oact)<0) return(SIG_ERR); return (oact.sa_handler); } //---------------------- long => "число.число.число.число" void long2IP(long l, char *IP){ unsigned char *c=&l; sprintf(IP,"%d.%d.%d.%d",c[0],c[1],c[2],c[3]); } //-----------------------Проверка процессов на одинаковый IP int CheckProc4IP(char *ip){ int i,cnt; for(i=0,cnt=0; i0) && (!strcmp(ip,ProcDescrs[i].IP))) cnt++; } if(cnt>=maxproc4ip) return 1; else return 0; } //----------------Получение базового, рабочего, и каталога конфига void GetDirs(char *base, char *workdir, char *cfgdir){ int i; workdir[0]=0; strcpy(workdir,base); //удалить имя программы for(i=strlen(workdir)-1; i>=0 && workdir[i]!='/'; i--); if(i>=0) workdir[i]=0; else workdir[0]=0; strcat(workdir,"/"); if(!strcmp(workdir,"./") || !strcmp(workdir,"/")) workdir[0]=0; sprintf(cfgdir,"%s../etc/",workdir); if(!workdir[0]) strcpy(workdir,"./"); } //----------------------Посылка ответа в виде "Код - расшифровка" void reply(int nsock, int code, char *msg){ char buf[256]; sprintf(buf,"%d - %s\n",code,msg); write(nsock,buf,strlen(buf)); } //----------------------Главное main (int argc, char **argv){ int addrlen, child, i, errcode; struct sockaddr_in tmp1; char IP[30]; char fname[256]; //Получить каталоги из командной строки GetDirs(argv[0],rundir,cfgdir); //Начать серверный лог strcpy (argv[0], "olimp: kernel"); open_log(DEFAULT_LOG); chown(DEFAULT_LOG,serv_uid,serv_gid); //temporary strcpy(workdir,"/tmp/olimp"); init(); //ДО БЕСКОНЕЧНОСТИ listen (sock, 5); while(1){ //сокет для ответов клиентам создаётся close (nsock); addrlen=sizeof(tmp1); //!busy! Обработка состояния Server is busy while(numproc >= maxproc); nsock = accept (sock, (struct sockaddr *) &tmp1, &addrlen); //если ошибка создания сокета - заново if (nsock < 0){ //if (errno != EINTR) perror("Не могу взять соединение"); continue; } long2IP(tmp1.sin_addr.s_addr,IP); /* Обрабатывается выше - не открывается сокет //проверить на загруженность (MaxProc) if(numproc>=maxproc){ write_log(IP,"too many connections (MaxProc limit)"); reply(nsock,552,"server is busy"); continue; } */ //проверить на соединения с одного IP if(CheckProc4IP(IP)){ write_log(IP,"too many connections from this IP"); reply(nsock,551,"too many connections from your IP"); continue; } //проверить на допустимость if(CheckIP(IP)){ //передать инфо сервису setenv("IP",IP,1); sprintf(fname,"%s%s",rundir,SERV_EXE); run_process(fname,F_DUPSOCK,IP); } else{ //ошибку в лог write_log(IP,"bad IP-address"); reply(nsock,550,"your IP-address restricted"); } } close (sock); } //--------------Проверка IP на допустимость int CheckIP(char *ip){ if(order_ad){ if(!ip_allowed(ip)) return 0; //не разрешен if(ip_denied(ip)) return 0; return 1; } else{ if(!ip_denied(ip)) return 1; //не запрещён if(ip_allowed(ip)) return 1; return 0; } } //-----------------------Имя юзера => UID uid_t user2uid(char *user){ struct passwd *pwd; if(pwd=getpwnam(user)) return pwd->pw_uid; else return 0; } //-----------------------Имя группы => GID gid_t group2gid(char *group){ struct group *grp; if(grp=getgrnam(group)) return grp->gr_gid; else return 0; } //-----------------------По шаблону проверяются переданные IP //с теми, которые разрешены в конфиге int ip_allowed(char *ip){ int i; int res=0; int j0,j1; for(i=0; iPROC_DESCR_MAX) maxproc=PROC_DESCR_MAX; } //Мах процессов с одного IP if(!strcmp(kwd,"MaxProc4IP")){ next=strtok(NULL,delim); if(next) maxproc4ip=atoi(next); } //Тайм-аут сервака if(!strcmp(kwd,"ServTimeout")){ next=strtok(NULL,delim); if(next) servtimelimit=atoi(next); } } fclose(f); // ShowLimits(); //Вернуть номер ошибочной строки if(!res) errline[0]=0; return res; } //--------------------Показ конфига void ShowLimits(){ int i; char buf[1024]; //разрешённые sprintf(LogRecord,"allowed: "); for(i=0; i 0){ //записать в таблицу for(i=0; i-1){ //зафиксировать смерть ребенка numproc--; //потереть в таблице for(i=0; i/dev/null 1>2 &",Cmd,Prm); system(str); sprintf(str,"Выполняется команда %d параметр %d",Cmd,Prm); write_log("Scheduler",str); SQL_Query(db,"delete from Schedule where Time='%s' and Command=%d and Param=%d",Time,Cmd,Prm); } else { if (dlt>30000) { alarm(30000); write_log("Scheduler","Запланирован контрольный сигнал"); } else { alarm(delta); sprintf(str,"Запланировано задание в %d-%02d-%02d %02d:%02d Command=%d Param=%d", time1.tm_mday,time1.tm_mon+1,time1.tm_year+1900,time1.tm_hour,time1.tm_min,Cmd,Prm); write_log("Scheduler",str); }; }; } else { write_log("Scheduler","Нет запланированных заданий"); row=0; }; } while ((dlt<=0)&&(row!=0)); SQL_Close(db); // сигнал получен и принят rel_signal(SIGALRM,onSigAlrm); };