This is acl.c in view mode; [Download] [Up]
/*
** acl.c -
**
**
** Copyright (c) 1993-95 David J. Hughes
** Copyright (c) 1995 Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
** ID = "$Id:"
**
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netdb.h>
#include <common/portability.h>
#include "msql_priv.h"
#define ALLOW 1
#define REJECT 2
typedef struct acc_s {
char name[50];
int access;
struct acc_s *next;
} acc_t;
typedef struct acl_s {
char db[NAME_LEN];
acc_t *host,
*read,
*write;
tlist_t *access,
*option;
struct acl_s *next;
} acl_t;
static acl_t *aclHead = NULL;
static int accessPerms;
extern char *packet;
#define ERR(msg) if (verbose) printf msg
#define DATABASE 1
#define READ 2
#define WRITE 3
#define HOST 4
#define ACCESS 5
#define OPTION 6
static int checkToken(tok)
char *tok;
{
if (strcmp(tok,"database") == 0)
return(DATABASE);
if (strcmp(tok,"read") == 0)
return(READ);
if (strcmp(tok,"write") == 0)
return(WRITE);
if (strcmp(tok,"host") == 0)
return(HOST);
if (strcmp(tok,"access") == 0)
return(ACCESS);
if (strcmp(tok,"option") == 0)
return(OPTION);
return(-1);
}
int msqlLoadAcl(verbose)
int verbose;
{
acl_t *new,
*aclTail;
tlist_t *tNew,
*tTail;
acc_t *accNew,
*accTail;
char buf[1024],
path[255],
*tok;
FILE *fp;
int newEntry,
lineNum;
/*
** Open the acl file
*/
(void)sprintf(path,"%s/msql.acl", msqlHomeDir);
fp = fopen(path,"r");
if (!fp)
{
if (verbose)
{
perror("Warning : Couldn't open ACL file");
}
sprintf(packet,"-1:Warning - Couldn't open ACL file\n");
return(-1);
}
/*
** Process the file
*/
fgets(buf,sizeof(buf),fp);
newEntry = 1;
lineNum = 1;
while(!feof(fp))
{
tok = (char *)strtok(buf," \t\n\r=,");
if (!tok)
{
/* Blank line ends a db entry */
newEntry = 1;
fgets(buf,sizeof(buf),fp);
lineNum++;
continue;
}
if (*tok == '#')
{
/* Comments are skipped */
fgets(buf,sizeof(buf),fp);
lineNum++;
continue;
}
switch(checkToken(tok))
{
case DATABASE:
if (!newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
newEntry = 0;
tok = (char *)strtok(NULL," \t\n\r");
if (!tok)
{
ERR(("Missing database name at line %d\n",
lineNum));
printf(packet,
"-1:Missing database name at line %d\n",
lineNum);
return(-1);
}
new = (acl_t *)malloc(sizeof(acl_t));
(void)bzero(new,sizeof(acl_t));
(void)strcpy(new->db,tok);
if (aclHead)
{
aclTail->next = new;
aclTail = new;
}
else
{
aclHead = aclTail = new;
}
break;
case READ:
if (newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
if (new->read)
{
accTail = new->read;
while(accTail->next)
accTail = accTail->next;
}
else
{
accTail = NULL;
}
tok = (char *)strtok(NULL," \t,\n\r");
while(tok)
{
accNew = (acc_t *)malloc(sizeof(acc_t));
(void)bzero(accNew,sizeof(acc_t));
if (*tok == '-')
{
strcpy(accNew->name,tok+1);
accNew->access = REJECT;
}
else
{
strcpy(accNew->name,tok);
accNew->access = ALLOW;
}
if (accTail)
{
accTail->next = accNew;
}
else
{
new->read = accNew;
}
accTail = accNew;
tok = (char *)strtok(NULL," \t,\n\r");
}
break;
case WRITE:
if (newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
if (new->write)
{
accTail = new->write;
while(accTail->next)
accTail = accTail->next;
}
else
{
accTail = NULL;
}
tok = (char *)strtok(NULL," \t,\n\r");
while(tok)
{
accNew = (acc_t *)malloc(sizeof(acc_t));
(void)bzero(accNew,sizeof(acc_t));
if (*tok == '-')
{
strcpy(accNew->name,tok+1);
accNew->access = REJECT;
}
else
{
strcpy(accNew->name,tok);
accNew->access = ALLOW;
}
if (accTail)
{
accTail->next = accNew;
}
else
{
new->write = accNew;
}
accTail = accNew;
tok = (char *)strtok(NULL," \t,\n\r");
}
break;
case HOST:
if (newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
if (new->host)
{
accTail = new->host;
while(accTail->next)
accTail = accTail->next;
}
else
{
accTail = NULL;
}
tok = (char *)strtok(NULL," \t,\n\r");
while(tok)
{
accNew = (acc_t *)malloc(sizeof(acc_t));
(void)bzero(accNew,sizeof(acc_t));
if (*tok == '-')
{
strcpy(accNew->name,tok+1);
accNew->access = REJECT;
}
else
{
strcpy(accNew->name,tok);
accNew->access = ALLOW;
}
if (accTail)
{
accTail->next = accNew;
}
else
{
new->host = accNew;
}
accTail = accNew;
tok = (char *)strtok(NULL," \t,\n\r");
}
break;
case ACCESS:
if (newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
if (new->access)
{
tTail = new->access;
while(tTail->next)
tTail = tTail->next;
}
else
{
tTail = NULL;
}
tok = (char *)strtok(NULL," \t,\n\r");
while(tok)
{
tNew = (tlist_t *)malloc(sizeof(tlist_t));
(void)bzero(tNew,sizeof(tlist_t));
strcpy(tNew->name,tok);
if (tTail)
{
tTail->next = tNew;
}
else
{
new->access = tNew;
}
tTail = tNew;
tok = (char *)strtok(NULL," \t,\n\r");
}
break;
case OPTION:
if (newEntry)
{
ERR(("Bad entry header location at line %d\n",
lineNum));
sprintf(packet,
"-1:Bad entry header location at line %d\n"
,lineNum);
return(-1);
}
if (new->option)
{
tTail = new->option;
while(tTail->next)
tTail = tTail->next;
}
else
{
tTail = NULL;
}
tok = (char *)strtok(NULL," \t,\n\r");
while(tok)
{
tNew = (tlist_t *)malloc(sizeof(tlist_t));
(void)bzero(tNew,sizeof(tlist_t));
strcpy(tNew->name,tok);
if (tTail)
{
tTail->next = tNew;
}
else
{
new->option = tNew;
}
tTail = tNew;
tok = (char *)strtok(NULL," \t,\n\r");
}
break;
default:
ERR(("Unknown ACL command \"%s\" at line %d\n",
tok,lineNum));
sprintf(packet,
"-1:Unknown ACL command \"%s\" at line %d\n",
tok,lineNum);
return(-1);
break;
}
fgets(buf,sizeof(buf),fp);
lineNum++;
}
}
dumpAcc(acc)
acc_t *acc;
{
while(acc)
{
printf("\t\t%s %s\n",(acc->access==ALLOW)?"Yes":"No ",
acc->name);
acc = acc->next;
}
}
static dumpAcl()
{
acl_t *curAcl;
tlist_t *curT;
acc_t *curAcc;
curAcl = aclHead;
while(curAcl)
{
printf("\nACL's for Database %s\n",curAcl->db);
printf("\tRead access :-\n");
dumpAcc(curAcl->read);
printf("\tWrite access :-\n");
dumpAcc(curAcl->write);
printf("\tHost access :-\n");
dumpAcc(curAcl->host);
curAcl = curAcl->next;
}
}
static int matchToken(pattern,tok)
char *pattern,
*tok;
{
register char *cp;
char *buf1,
*buf2,
*cp2;
int length1,
length2;
/*
** Put everything to lower case
*/
buf1 = (char *)strdup(pattern);
buf2 = (char *)strdup(tok);
cp = buf1;
while(*cp)
{
*cp = tolower(*cp);
cp++;
}
cp = buf2;
while(*cp)
{
*cp = tolower(*cp);
cp++;
}
/*
** Is this a wildcard?
*/
cp = pattern;
if (*cp == '*')
{
if (*(cp+1) == 0) /* match anything */
{
return(1);
}
length1 = strlen(cp)-1;
length2 = strlen(tok);
if (length1 > length2)
{
(void)free(buf1);
(void)free(buf2);
return(0);
}
cp2 = buf2 + length2 - length1;
if (strcmp(cp+1,cp2) == 0)
{
(void)free(buf1);
(void)free(buf2);
return(1);
}
else
{
(void)free(buf1);
(void)free(buf2);
return(0);
}
}
/*
** OK, does the actual text match
*/
if (strcmp(buf1,buf2) == 0)
{
(void)free(buf1);
(void)free(buf2);
return(1);
}
else
{
(void)free(buf1);
(void)free(buf2);
return(0);
}
}
static int matchTextList(list,tok)
tlist_t *list;
char *tok;
{
tlist_t *cur;
cur = list;
while(cur)
{
if (matchToken(cur->name, tok))
{
return(1);
}
cur = cur->next;
}
return(0);
}
static int matchAccessList(list,tok)
acc_t *list;
char *tok;
{
acc_t *cur;
cur = list;
while(cur)
{
if (matchToken(cur->name, tok))
{
if (cur->access == ALLOW)
{
return(1);
}
else
{
return(0);
}
}
cur = cur->next;
}
return(0);
}
int msqlCheckAccess(db,info)
char *db;
cinfo_t *info;
{
char *host,
*user;
struct sockaddr *local,
*remote;
acl_t *curAcl;
acc_t *curAcc;
int res,
perms;
host = info->host;
user = info->user;
local = (struct sockaddr *)&(info->local);
remote = (struct sockaddr *)&(info->remote);
/*
** Find an ACL entry that matches this DB
*/
curAcl = aclHead;
while(curAcl)
{
if(matchToken(curAcl->db,db))
{
break;
}
curAcl = curAcl->next;
}
if (!curAcl)
{
return(RW_ACCESS); /* default if no specific ACL */
}
/*
** Now check the connection details
*/
if (!host)
{
/* No host == local connection */
if (!matchTextList(curAcl->access,"local"))
{
return(NO_ACCESS);
}
}
else
{
if (!matchTextList(curAcl->access,"remote"))
{
return(NO_ACCESS);
}
if (!matchAccessList(curAcl->host,host))
{
return(NO_ACCESS);
}
}
/*
** Now check the access perms
*/
perms = 0;
if (matchAccessList(curAcl->read, user))
{
perms |= READ_ACCESS;
}
if (matchAccessList(curAcl->write, user))
{
perms |= WRITE_ACCESS;
}
if (perms == 0)
{
return(NO_ACCESS);
}
/*
** Now perform any options for this connection
*/
return(perms);
}
static freeAcc(head)
acc_t *head;
{
register acc_t *curAcc,
*prevAcc;
curAcc = head;
while(curAcc)
{
prevAcc = curAcc;
curAcc = curAcc->next;
(void)free(prevAcc);
}
}
static freeTlist(head)
tlist_t *head;
{
register tlist_t *curText,
*prevText;
curText = head;
while(curText)
{
prevText = curText;
curText = curText->next;
(void)free(prevText);
}
}
static freeAcls()
{
register acl_t *curAcl,
*prevAcl;
curAcl = aclHead;
while(curAcl)
{
freeAcc(curAcl->host);
freeAcc(curAcl->read);
freeAcc(curAcl->write);
freeTlist(curAcl->access);
freeTlist(curAcl->option);
prevAcl = curAcl;
curAcl = curAcl->next;
(void)free(prevAcl);
}
aclHead = NULL;
}
reloadAcls(sock)
int sock;
{
freeAcls();
msqlLoadAcl(0);
}
msqlSetPerms(perms)
int perms;
{
accessPerms = perms;
}
int msqlCheckPerms(access)
int access;
{
return( accessPerms & access);
}
int msqlCheckLocal(info)
cinfo_t *info;
{
char *host,
*user;
struct sockaddr *local,
*remote;
acl_t *curAcl;
acc_t *curAcc;
int res,
perms;
host = info->host;
user = info->user;
local = (struct sockaddr *)&(info->local);
remote = (struct sockaddr *)&(info->remote);
if ( (!info->host || strcmp(host,"localhost") == 0) &&
strcmp(info->user,ROOT) == 0)
{
return(1);
}
else
{
return(0);
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.