"Fossies" - the Fresh Open Source Software archive 
Member "sysmask-1.08/smkdlib.c" of archive sysmask-1.08.tgz:
/* Copyright (C) 2005 XIAO, Gang of Universite de Nice - Sophia Antipolis
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* library functions for smkd. */
char logbuf[LOGBUFLEN];
char *logptr;
char passwdcache[PASSWDLEN];
time_t passwdtime;
struct { /* uid must be the second item after name */
char *name;
uid_t uid, gid;
char *uids, *gids, *sh, *home;
} users[ACCOUNTLIM];
int usercnt;
void writelog(void)
{
int fd, l;
int attr;
if(denyid) attr=0644; else attr=0600;
l=logptr-logbuf; if(l==0) return;
if(l<0) {
logptr=logbuf; logbuf[0]=0; return;
}
fd=open(logfile,O_WRONLY|O_CREAT|O_APPEND,attr);
if(fd<0) return;
write(fd,logbuf,l); logptr=logbuf; logbuf[0]=0;
l=lseek(fd,0,SEEK_END);
close(fd);
if(denyid) chown(logfile, 0, denyid);
if(l>=LOGLEN) rename(logfile,oldlog);
}
void tostderr(void)
{
int l;
l=logptr-logbuf; if(l==0) return;
if(l<0) {
logptr=logbuf; logbuf[0]=0; return;
}
write(2,logbuf,l); logptr=logbuf; logbuf[0]=0;
}
void print(char *str)
{
int l;
for(l=0;l<LOGLEN_MAX && str[l];l++);
while(logptr-logbuf+l >= LOGBUFLEN) {
int ll;
ll=LOGBUFLEN-(logptr-logbuf);
memmove(logptr,str,ll); str+=ll; l-=ll;
writelog();
}
if(l>0) {
memmove(logptr,str,l); logptr+=l;
}
}
void printu(unsigned long u)
{
char *p, buf[32];
if(u==0) {print("0 "); return;}
buf[31]=0; buf[30]=' ';
for(p=buf+29; p>=buf && u; u/=10) {
*p--=(u%10)+'0';
}
p++; print(p);
}
char hexstr[]="0123456789ABCDEF";
void printhex(unsigned long u)
{
char *p, buf[32];
if(u==0) {print("0 "); return;}
buf[31]=0; buf[30]=' '; p=buf+29;
for(p=buf+29;p>=buf && u; u>>=4) {
*p--=hexstr[u&0xF];
}
p++; print(p);
}
void int2str(unsigned long u, char *obuf, size_t buflen)
{
char *p, buf[32];
int l;
obuf[0]=0;
if(buflen<16) return;
if(u==0) {obuf[0]='0'; obuf[1]=0; return;}
buf[31]=0;
for(p=buf+30; p>=buf && u; p--, u/=10) {
*p=(u%10)+'0';
}
p++; l=strlen(p);
if(l<buflen) memmove(obuf,p,l+1);
}
void printtime(time_t t)
{
char buf[64];
char *p;
int2str(t/(24*3600),buf,sizeof(buf));
p=buf+strlen(buf); if(p-buf>20) return;
*p++=':';
*p++=((t/3600)%24)/10+'0';
*p++=((t/3600)%24)%10+'0';
*p++=':';
*p++=((t/60)%60)/10+'0';
*p++=((t/60)%60)%10+'0';
*p++=':';
*p++=(t%60)/10+'0';
*p++=(t%60)%10+'0';
*p=0;
print(buf);
}
void printtoken(int t)
{
if(t<=0 || t>=0x20000 || !(t&0xFFFF)) print("- ");
else {
if(!tokenn[t]) {
if(!(t&0xFFFF0000)) print("s"); else print("u");
printu(t&0xFFFF);
}
else {print(tokenn[t]); print(" ");}
}
}
void logprefix(char *type)
{
int t;
printtime(now); print(" ");
for(t=0;t<usercnt && request.uid!=users[t].uid; t++);
if(t>=usercnt) printu(request.uid);
else {print(users[t].name); print(" ");}
printtoken(request.token&0xFFFF);
printtoken((request.token>>16)|0x10000);
printu(request.pid); print(type);
}
void logreq(char *reqtype)
{
if(!(request.sm2&SM2_LOG)) return;
ans.ind |= SMKD_ANS_LOGGED;
logprefix(reqtype);
print(request.fname); print("\n");
}
/* for internal benchmarking: get microseconds */
int getusec(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec;
}
void call_log(int call)
{
call&=0xFFFF;
if(call<0 || call>=NR_sysmasks) return;
logprefix("syscall ");
printu(call);
if(call>=0 && call<NR_sysmasks && syscall_names[call].name)
print(syscall_names[call].name);
print("\n");
}
void _readfile(char *fname,char *buf,long bufsize)
{
struct stat st;
int f;
long l,l2;
buf[0]=0;
if(stat(fname,&st)) return;
if(st.st_mode&(S_IWGRP|S_IWOTH)) {
print(fname); print(": file is world-writable.\n");
return;
}
l=st.st_size;
if(l<0 || l>=bufsize) {
print(fname); print(": file too long.\n");
return;
}
f=open(fname,O_RDONLY,0); if(f<0) {
print(fname); print(": cannot open.\n");
return;
}
l2=read(f,buf,l); if(l2!=l) {
print(fname); print(": read() error.\n");
close(f); buf[0]=0; return;
}
buf[l]=0; close(f);
_tolinux(buf);
}
void readfile(char *fname,char *buf,long bufsize)
{
char *p;
_readfile(fname,buf,bufsize);
/* gather escaped multiple lines */
for(p=strchr(buf,'\\'); p; p=strchr(++p,'\\')) {
if(p[1]=='\n') p[0]=p[1]=' ';
}
}
void getpasswd(void)
{
int i;
struct stat st;
char *p1, *p2, *cut[16];
if(stat(passwdfile,&st)) { /* passwd file not found */
usercnt=0; return;
}
if(usercnt && (st.st_mtime<=passwdtime || st.st_mtime==now)) return; /* not modified */
new_passwd=1;
passwdtime=st.st_mtime;
readfile(passwdfile,passwdcache,sizeof(passwdcache));
usercnt=0;
for(p1=find_word_start(passwdcache);
*p1 && usercnt<ACCOUNTLIM;
p1=find_word_start(p2)) {
p2=find_line_end(p1); if(*p2) *p2++=0;
for(i=0; i<10 && p1; i++) {
cut[i]=p1; p1=strchr(p1,':');
if(p1) *p1++=0;
}
if(i<6 || !cut[0][0] || !cut[5][0] || !cut[6][0] ||
!myisdigit(cut[2][0]) || !myisdigit(cut[3][0])) continue;
strip_trailing_spaces(cut[0]);
i=search_list(users,usercnt,sizeof(users[0]),cut[0]);
if(i>=0) continue; /* double definition of user name */
i=~i;
memmove(users+i+1, users+i, (usercnt-i)*sizeof(users[0]));
users[i].name=cut[0];
users[i].uids=cut[2];
users[i].gids=cut[3];
users[i].uid=str2int(cut[2]);
users[i].gid=str2int(cut[3]);
users[i].home=cut[5];
users[i].sh=cut[6];
usercnt++;
}
}
enum{passwd_user, passwd_id, passwd_sh, passwd_home};
/* get passwd definitions */
char *passwd(int reqtype)
{
static uid_t uid=-1;
static int passwditem=-1;
if(request.uid!=uid) {
int i;
for(i=0;i<usercnt && users[i].uid!=request.uid;i++);
if(i>=usercnt) return "";
passwditem=i; uid=request.uid;
}
switch(reqtype) {
case passwd_user: return users[passwditem].name;
case passwd_id: return users[passwditem].uids;
case passwd_sh: return users[passwditem].sh;
case passwd_home: return users[passwditem].home;
default: return "";
}
}
/* substitute variable names by their environment strings
* The buffer pointed to by p must have enough space
* (defined by SMK_PATH_MAX). */
char *substit(char *p)
{
char *pp, *p2, *ev;
char *oldlast, *oldnext, *oldend, *newend;
char oldbuf[SMK_PATH_MAX+1];
int ln;
if((p2=strchr(p,'%'))==NULL) return p;
ln=strlen(p); if(ln>=SMK_PATH_MAX) goto too_long;
memmove(oldbuf,p,ln); oldbuf[ln]=0; oldend=oldbuf+ln;
newend=p; oldlast=oldnext=oldbuf;
for(pp=oldbuf+(p2-p); pp!=NULL; pp=strchr(pp,'%')) {
if(*(pp+1)=='%') { /* escaped % sign */
pp++; if(newend-p+(pp-oldlast)>=SMK_PATH_MAX) goto too_long;
memmove(newend,oldlast,pp-oldlast); newend+=pp-oldlast;
pp++; oldlast=pp; continue;
}
switch(*(pp+1)) {
case 0: {
*pp=0; oldend--; goto end;
}
case 'h': { /* user home */
ev=passwd(passwd_home); oldnext=pp+2; break;
}
case 'i': { /* user uid */
ev=passwd(passwd_id); oldnext=pp+2; break;
}
case 's': { /* user shell */
ev=passwd(passwd_sh); oldnext=pp+2; break;
}
case 'u': { /* user name */
ev=passwd(passwd_user); oldnext=pp+2; break;
break;
}
default: {
ev="%"; oldnext=pp+1; break;
}
}
ln=strlen(ev);
if(pp>oldlast) {
if(newend-p+(pp-oldlast)>=SMK_PATH_MAX) goto too_long;
memmove(newend,oldlast,pp-oldlast); newend+=pp-oldlast;
}
if(ln>0) {
if((newend-p)+ln>=SMK_PATH_MAX) goto too_long;
memmove(newend,ev,ln); newend+=ln;
}
pp=oldlast=oldnext;
continue;
}
end:
if(oldlast<oldend) {
if(newend-p+(oldend-oldlast)>=SMK_PATH_MAX) goto too_long;
memmove(newend,oldlast,oldend-oldlast); newend+=oldend-oldlast;
}
*newend=0;
return p;
too_long: *p=0; return NULL;
}
int _str2id(char *p, int type)
{
int i;
p=find_word_start(p); *find_word_end(p)=0;
if(!*p) return -1;
if(p[0]=='0' && p[1]==0) return 0;
i=str2int(p); if(i>0) return i;
i=search_list(users,usercnt,sizeof(users[0]),p);
if(i<0) return -1;
if(type==0) return users[i].uid;
else return users[i].gid;
}
#define str2uid(x) _str2id(x,0)
#define str2gid(x) _str2id(x,1)
int strhash(char *p)
{
int h;
for(h=0;*p;p++) if(*p>='a' && *p<='z') h |= 1 << (*p - 'a');
return h;
}
/* some name uniformization */
/* type=1 if no name check */
/* Returns -1 if backup number overflow */
int process_pathname(int type)
{
char c, *p, *pp, *start, *newstart;
int l, newpath, thisnamelen;
int *hash;
reqnamecnt=0; start=reqname[0]; pp=start; newpath=0;
namet=namelen=depth=backupcnt=0; thisnamelen=0;
hash=reqhash; *hash=0;
/* algorithm modeled after the kernel */
for(p=request.fname; *p;) {
*pp++ = *p;
if((c=*p++) != '/') {
thisnamelen++;
if(!myisalnum(c) && strchr("-_+.",c)==NULL) {
if(type) continue;
namet|=NAME_UNUSUAL;
if(c>0 && c<=' ') {
if(myisspace(c)) {
namet|=NAME_SPACE;
if(c=='\n' || c=='\r' || c=='\f' || c=='\v')
namet|=NAME_NEWLINE;
}
else namet|=NAME_CTRL;
}
else if(!(namet&NAME_SPECIAL) && strchr("()[]{}*?\\<>|'`\"&$",c)!=0)
namet|=NAME_SPECIAL;
}
else {
if(c>='a' && c<='z') *hash |= 1<<(c-'a');
if(thisnamelen==1 && (c=='-' || c=='+')) namet|=NAME_UNUSUAL;
}
continue;
}
if(thisnamelen>namelen) namelen=thisnamelen;
depth++; thisnamelen=0;
dotrep: while(*p == '/') p++;
if(*p == '.') {
if(p[1] == '/') {p++; goto dotrep;}
if(p[1] == 0) break;
if(p[1] == '.') {
if(p[2]!='/' && p[2]!=0) {
newpath=0; continue;
}
depth++; backupcnt++;
p+=2; if(*p) p++;
l=pp-start; if(l<=1) goto dotrep;
pp--; l--; *pp=0;
if(!newpath) {
if(reqnamecnt>=BACKUP_MAX-1) return ENAMETOOLONG;
reqnamelen[reqnamecnt++]=l;
hash[1]=hash[0]; hash++;
newstart=reqname[reqnamecnt];
memmove(newstart,start,l);
start=newstart; pp=start+l;
newpath=1;
}
do pp--; while(pp>start && *pp!='/');
pp++; goto dotrep;
}
}
newpath=0;
}
if(thisnamelen>namelen) namelen=thisnamelen;
if(pp>start+1 && pp[-1]=='/') pp--;
*pp=0; reqnamelen[reqnamecnt]=pp-start; reqnamecnt++;
if(*p) p++; pathlen=p-request.fname;
if(backupcnt) namet |= NAME_BACKUP;
if(request.reqtype&SMKD_REQ_ISCHROOT) namet |= NAME_CHROOT;
else namet |= NAME_REALROOT;
return 0;
}
void str2mask(char *str, struct sysmask_maskset *mk,unsigned short int ex[])
{
char *p1, *p2;
char buf[STRLEN_MAX];
unsigned short int *exptr, exx[SMK_EXCEPTS];
struct sysmask_maskset mkx, *mkptr;
int l, need;
if(*str=='@') {
p1=str+1; p2=p1+sizeof(struct sysmask_maskset);
mkptr=(struct sysmask_maskset *) p1;
mk->m1|=mkptr->m1; mk->m2|=mkptr->m2; mk->cap|=mkptr->cap;
join_excepts(ex,(unsigned short int *) p2);
return;
}
l=strlen(str); if(l>=sizeof(buf)) l=sizeof(buf)-1;
memmove(buf,str,l+1);
need=sizeof(struct sysmask_maskset) + sizeof(exx) + 1;
if(l>=need) {
memset(exx,0,sizeof(exx)); memset(&mkx,0,sizeof(mkx));
mkptr=&mkx; exptr=exx;
}
else {
mkptr=mk; exptr=ex;
}
for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
p2=find_word_end(p1); if(*p2) *p2++=0;
onemask(p1,mkptr,exptr);
}
if(l >= need) { /* compile */
join_excepts(ex,exx);
mk->m1|=mkx.m1; mk->m2|=mkx.m2; mk->cap|=mkx.cap;
str[0]='@'; p1=str+1; p2=p1+sizeof(struct sysmask_maskset);
memmove(p1,&mkx,sizeof(struct sysmask_maskset));
memmove(p2,exx,sizeof(exx));
}
}
int def2mask(struct sysmask_struct *sm)
{
int i,n;
int retval=0;
struct sysmask_maskset mt;
if(defs_mask) {
str2mask(defs_mask,&sm->active,sm->except);
retval=SMKD_ANS_ADDMASK;
}
if(defs_trigger1) {
i=gettrigger(defs_trigger1);
if(i && defs_tmask1) {
memset(&mt,0,sizeof(mt));
str2mask(defs_tmask1,&mt,sm->except);
if(mt.m1|mt.m2|mt.cap) {
n=1; if(defs_tcount1) n=str2int(defs_tcount1);
if(n<=0 || n>=30000) n=1;
if(sm->trigger!=0 && sm->trigger!=i) {
sm->active.m1|=sm->triggered.m1;
sm->active.m2|=sm->triggered.m2;
sm->active.cap|=sm->triggered.cap;
}
memmove(&sm->triggered,&mt,sizeof(mt));
sm->trigger=i;
sm->tcnt=n;
retval=SMKD_ANS_ADDMASK;
}
}
}
if(defs_agelim) {
i=str2int(defs_agelim); if(i>0) {
if(sm->token==0 || sm->token>i) sm->token=i;
}
}
return retval;
}
void _def2lim(char *def, unsigned long *val)
{
int i;
if(!def) return;
i=str2int(def); if(i<=0) return;
if(*val == 0 || *val > i) *val = i;
}
void def2lim(unsigned long rlim[])
{
_def2lim(defs_sizelim, rlim+SMK_RLIM_SIZE);
_def2lim(defs_fsizelim, rlim+SMK_RLIM_FSIZE);
_def2lim(defs_forklim, rlim+SMK_RLIM_FORK);
_def2lim(defs_forkdepth, rlim+SMK_RLIM_FORKDEPTH);
_def2lim(defs_forkfreq, rlim+SMK_RLIM_FORKFREQ);
_def2lim(defs_proclim, rlim+SMK_RLIM_NPROC);
}
/* translate a string to a number list */
int rlist(unsigned long list[], char p[],
void *table, int tablecnt, size_t itemsize)
{
unsigned long l1[LISTLIM];
unsigned long r1[LISTLIM], r2[LISTLIM];
int lcnt,rcnt;
int ttt;
unsigned long t1, t2, tt;
int i,n;
char *p1, *p2, *p3;
lcnt=rcnt=0;
for(p1=find_word_start(p);
*p1 && rcnt<LISTLIM && lcnt<LISTLIM;
p1=find_word_start(p2)) {
p2=find_word_end(p1); if(*p2) *p2++=0;
if(myisdigit(*p1)) t1=str2int(p1);
else {
int *ip;
char *vp;
ttt=search_list(table,tablecnt,itemsize,p1);
if(ttt<0) continue;
vp=table+ttt*itemsize+sizeof(char *);
ip=(int *) vp;
t1=*ip; goto one;
}
p3=strchr(p1,'-'); if(p3!=NULL) {
*p3++=0;
t1=str2int(p1); t2=str2int(p3);
if(t1==t2) goto one;
if(t1>t2) {tt=t1; t1=t2; t2=tt;}
r1[rcnt]=t1; r2[rcnt]=t2; rcnt++;
continue;
}
one:
for(i=0;i<lcnt && l1[i]!=t1;i++);
if(i<lcnt) continue;
l1[lcnt++]=t1;
}
n=0;
for(i=0;i<rcnt && n<LISTLIM;i++) {
list[n++]=(r1[i]&0xFFFF) | ((r2[i]&0xFFFF)<<16);
}
for(i=0;i<lcnt-1 && n<LISTLIM;i+=2) {
t1=l1[i]; t2=l1[i+1];
if(t1<t2) {tt=t1; t1=t2; t2=tt;}
list[n++]=(t1&0xFFFF) | ((t2&0xFFFF)<<16);
}
if(i<lcnt && n<LISTLIM) list[n++]=(l1[i]&0xFFFF) | ((l1[i]&0xFFFF)<<16);
return n;
}
/* returns 1 if match */
/* if n=0: always no match */
int rcheck(unsigned long list[], int check, int n)
{
int i;
unsigned int l1, l2;
for(i=0;i<n;i++) {
l1=list[i]&0xFFFF; l2=list[i]>>16;
if(l1<l2) {
if(check>=l1 && check<=l2) return 1;
}
else if(check==l1 || check==l2) return 1;
}
return 0;
}
/* returns 1 if match */
/* if n=0: always no match */
int tcheck(unsigned long list[], int check, int n)
{
int i;
for(i=0;i<n;i++) if(check == list[i]) return 1;
return 0;
}
void rc(void)
{
char buf[CONFLEN];
char *p1, *p2, *p3;
readfile(rcfile,buf,sizeof(buf));
for(p1=find_word_start(buf); *p1; p1=find_word_start(p2)) {
p2=find_line_end(p1); if(*p2) *p2++=0;
if(!myisalpha(*p1)) continue;
p3=strchr(p1,'='); if(p3==NULL) continue;
*p3++=0; p3=find_word_start(p3); strip_trailing_spaces(p3);
*find_word_end(p1)=0;
if(strcmp(p1,"follow_dotdot")==0) {
if(strcmp(p3,"yes")==0) follow_dotdot=1;
continue;
}
if(strcmp(p1,"denyid")==0) {
denyid=str2int(p3); continue;
}
}
printtime(now); print(" root smkd-startup denyid=");
printu(denyid); print("follow_dotdot="); printu(follow_dotdot);
print("\n");
}