"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");
}