servxcheck.c

来自「minix操作系统最新版本(3.1.1)的源代码」· C语言 代码 · 共 303 行

C
303
字号
/*	servxcheck() - Service access check.		Author: Kees J. Bot *								8 Jan 1997 */#define nil 0#define ioctl _ioctl#define open _open#define write _write#define close _close#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <fcntl.h>#include <unistd.h>#include <time.h>#include <sys/ioctl.h>#include <net/hton.h>#include <net/gen/in.h>#include <net/gen/tcp.h>#include <net/gen/tcp_io.h>#include <net/gen/inet.h>#include <net/gen/socket.h>#include <net/gen/netdb.h>/* Default service access file. */static const char *path_servacces = _PATH_SERVACCES;#define WLEN	256static int getword(FILE *fp, char *word)/* Read a word from the file open by 'fp', skip whitespace and comments. * Colon and semicolon are returned as a one character "word".  Returns * word[0] or EOF. */{    int c;    char *pw;    int wc;    wc= 0;    for (;;) {	if ((c= getc(fp)) == EOF) return EOF;	if (c == '#') { wc= 1; continue; }	if (c == '\n') { wc= 0; continue; }	if (wc) continue;	if (c <= ' ') continue;	break;    }    pw= word;    if (c == ':' || c == ';') {	    *pw++ = c;    } else {	do {	    if (pw < word + WLEN-1) *pw++ = c;	    c= getc(fp);	} while (c != EOF && c > ' ' && c != ':' && c != ';');	if (c != EOF) ungetc(c, fp);    }    *pw= 0;    return word[0];}static int netspec(char *word, ipaddr_t *addr, ipaddr_t *mask)/* Try to interpret 'word' as an network spec, e.g. 172.16.102.64/27. */{    char *slash;    int r;    static char S32[]= "/32";    if (*word == 0) return 0;    if ((slash= strchr(word, '/')) == NULL) slash= S32;    *slash= 0;    r= inet_aton(word, addr);    *slash++= '/';    if (!r) return 0;    r= 0;    while ((*slash - '0') < 10u) {	r= 10*r + (*slash++ - '0');	if (r > 32) return 0;    }    if (*slash != 0 || slash[-1] == '/') return 0;    *mask= htonl(r == 0 ? 0L : (0xFFFFFFFFUL >> (32 - r)) << (32 - r));    return 1;}static int match(const char *word, const char *pattern)/* Match word onto a pattern.  Pattern may contain the * wildcard. */{    unsigned cw, cp;#define lc(c, d) ((((c)= (d)) - 'A') <= ('Z' - 'A') ? (c)+= ('a' - 'A') : 0)    for (;;) {	lc(cw, *word);	lc(cp, *pattern);	if (cp == '*') {	    do pattern++; while (*pattern == '*');	    lc(cp, *pattern);	    if (cp == 0) return 1;	    while (cw != 0) {		if (cw == cp && match(word+1, pattern+1)) return 1;		word++;		lc(cw, *word);	    }	    return 0;	} else	if (cw == 0 || cp == 0) {	    return cw == cp;	} else	if (cw == cp) {	    word++;	    pattern++;	} else {	    return 0;	}    }#undef lc}static int get_name(ipaddr_t addr, char *name)/* Do a reverse lookup on the remote IP address followed by a forward lookup * to check if the host has that address.  Return true if this is so, return * either the true name or the ascii IP address in name[]. */{    struct hostent *he;    int i;    he= gethostbyaddr((char *) &addr, sizeof(addr), AF_INET);    if (he != NULL) {	strcpy(name, he->h_name);	he= gethostbyname(name);	if (he != NULL && he->h_addrtype == AF_INET) {	    for (i= 0; he->h_addr_list[i] != NULL; i++) {		if (memcmp(he->h_addr_list[i], &addr, sizeof(addr)) == 0) {		    strcpy(name, he->h_name);		    return 1;		}	    }	}    }    strcpy(name, inet_ntoa(addr));    return 0;}/* "state" and "log" flags, made to be bitwise comparable. */#define DEFFAIL		 0x01#define FAIL		(0x02 | DEFFAIL)#define PASS		 0x04int servxcheck(ipaddr_t peer, const char *service,		void (*logf)(int pass, const char *name)){    FILE *fp;    char word[WLEN];    char name[WLEN];    int c;    int got_name, slist, seen, explicit, state, log;    ipaddr_t addr, mask;    /* Localhost? */    if ((peer & HTONL(0xFF000000)) == HTONL(0x7F000000)) return 1;    if ((fp= fopen(path_servacces, "r")) == nil) {	/* Succeed on error, fail if simply nonexistent. */	return (errno != ENOENT);    }    slist= 1;		/* Services list (before the colon.) */    seen= 0;		/* Given service not yet seen. */    explicit= 0;	/* Service mentioned explicitly. */    got_name= -1;	/* No reverse lookup done yet. */    log= FAIL;		/* By default log failures only. */    state= DEFFAIL;	/* Access denied until we know better. */    while ((c= getword(fp, word)) != EOF) {	if (c == ':') {	    slist= 0;		/* Switch to access list. */	} else	if (c == ';') {	    slist= 1;		/* Back to list of services. */	    seen= 0;	} else	if (slist) {	    /* Traverse services list. */	    if (match(service, word)) {		/* Service has been spotted! */		if (match(word, service)) {		    /* Service mentioned without wildcards. */		    seen= explicit= 1;		} else {		    /* Matched by a wildcard. */		    if (!explicit) seen= 1;		}	    }	} else {	    /* Traverse access list. */	    if (c == 'l' && strcmp(word, "log") == 0) {		if (seen) {		    /* Log failures and successes. */		    log= FAIL|PASS;		}		continue;	    }	    if (c != '-' && c != '+') {		if (logf == nil) {		    fprintf(stderr, "%s: strange check word '%s'\n",			path_servacces, word);		}		continue;	    }	    if (seen) {		if (state == DEFFAIL) {		    /* First check determines the default. */		    state= c == '+' ? FAIL : PASS;		}		if ((state == PASS) == (c == '+')) {		    /* This check won't change state. */		} else		if (word[1] == 0) {		    /* Lone + or - allows all or none. */		    state= c == '-' ? FAIL : PASS;		} else		if (netspec(word+1, &addr, &mask)) {		    /* Remote host is on the specified network? */		    if (((peer ^ addr) & mask) == 0) {			state= c == '-' ? FAIL : PASS;		    }		} else {		    /* Name check. */		    if (got_name == -1) {			got_name= get_name(peer, name);		    }		    /* Remote host name matches the word? */		    if (!got_name) {			state= FAIL;		    } else		    if (match(name, word+1)) {			state= c == '-' ? FAIL : PASS;		    }		}	    }	}    }    fclose(fp);    if ((log & state) != 0) {	/* Log the result of the check. */	if (got_name == -1) (void) get_name(peer, name);	if (logf != nil) {	    (*logf)(state == PASS, name);	} else {	    int lfd;	    char line[128+WLEN];	    time_t t;	    struct tm *tm;	    char month[][4]= {		"Jan", "Feb", "Mar", "Apr", "May", "Jun",		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",	    };	    if ((lfd= open("/usr/adm/log", O_WRONLY|O_APPEND)) != -1) {		time(&t);		tm= localtime(&t);		sprintf(line, "%s %02d %02d:%02d:%02d service '%s' %s to %s\n",		    month[tm->tm_mon],		    tm->tm_mday,		    tm->tm_hour, tm->tm_min, tm->tm_sec,		    service,		    state == PASS ? "granted" : "denied",		    name);		(void) write(lfd, line, strlen(line));		close(lfd);	    }	}    }    return state == PASS;}char *servxfile(const char *file)/* Specify a file to use for the access checks other than the default.  Return * the old path. */{    const char *oldpath= path_servacces;    path_servacces= file;    return (char *) oldpath;	/* (avoid const poisoning) */}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?