/**
*** XPG - Graphical User Interface for Postgres
*** Copyright (C) 1993  Ranen Goren (ranen@cs.huji.ac.il).

*** 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.
**/


#include <stdio.h>
#include <grp.h>
#include <string.h>
#include "xpg.h"


void initPermissions();
int  checkPermissions();
char *skipSpaces();


extern APP_RESOURCE_STRUCT appResources;

int numGroups;
char **groups;
char *username;




/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
void initPermissions()
{
    int *groupSet;
    struct group *grpData;
    int i;

    username = strdup(cuserid(NULL));
    numGroups = getgroups(0, NULL);
    groupSet = (int *)  XtMalloc(numGroups * sizeof(int));
    groups =   (char **)XtMalloc(numGroups * sizeof(char *));
    getgroups(numGroups, groupSet);
    for (i=0;  i < numGroups;  i++)
    {
	setgrent();
	grpData = getgrgid(groupSet[i]);
	groups[i] = strdup(grpData->gr_name);
	groups[i][0] = toupper(groups[i][0]);  /* capitalize 1st letter */
    }
    endgrent();
    XtFree(groupSet);

#ifdef XPG_DEBUG
    printf("user:\t%s\n", username);
    printf("groups:\n");
    for (i=0; i<numGroups; i++)
	printf("\t%s\n", groups[i]);	
#endif
    
    
}





/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/* fills the perms structure with the permissions of the user to
   access the class. This routine does no short-cuts in parsing
   PERMISSIONS_FILE. For class opened, the whole file is parsed,
   in order to prevent unpleasant parsing errors when accessing
   further classes. */

int checkPermissions(rel, className, perms)
  relInfo *rel;
  char *className;     /* class or portal name */
  permStruct *perms;
{
    FILE *file;
    char line[1000];
    int  lineNum = 0;
    char *p1, *p2, *p3;
    int i;
    Boolean isAdd;
    Boolean matched, dbMatched, classMatched, userMatched;

    /* set default permissions to allow anything to any class */
    perms->append = perms->read = perms->write = perms->rules = True;
    if ((file = fopen(PERMISSIONS_FILE, "r")) == NULL)
	XtError("Cannot open permissions file!");
    while ((fgets(line, 1000, file)) != NULL)
    {
	lineNum++;
	dbMatched = classMatched = True;   /* default */
	if (line[i=strlen(line)-1] == '\n')
	    line[i] = '\0';       /* chop the \n */
	p1 = line;
	p1 = skipSpaces(p1);
	/* skip comments and empty lines */
	if (*p1=='!' || *p1=='#' || *p1=='\0')
	    continue;
	/* the <database> part */
	for (p2=p1; *p2!='.' && *p2!='\0'; p2++)
	    ;
	if (*p2=='\0')
	{
	    fprintf(stderr, "line %d: '.' expected\n", lineNum);
	    XtError("Error parsing permissions file. xpg exits");
	}
	if (p2==p1)
	{
	    fprintf(stderr, "line %d: no database specified\n", lineNum);
	    XtError("Error parsing permissions file. xpg exits");
	}
	*p2 = '\0';
	if (strcmp(p1, "*") && strcmp(p1, appResources.database))
	    dbMatched = False;
	p1 = p2+1;
	/* the <class> part */
	for (p3=p1; *p3!=':' && *p3!='\0'; p3++)
	    ;
	for (p2=p3-1; *p2==' ' || *p2=='\t'; p2--)  /* remove trailing spcs */
	    ;
	p2++;
	if (*p2=='\0')
	{
	    fprintf(stderr, "line %d: ':' expected\n", lineNum);
	    XtError("Error parsing permissions file. xpg exits");
	}
	if (p2==p1)
	{
	    fprintf(stderr, "line %d: no class specified\n", lineNum);
	    XtError("Error parsing permissions file. xpg exits");
	}
	*p2 = '\0';
	if (strcmp(p1, "*") && strcmp(p1, className))
	    classMatched = False;
	p1 = p3+1;
	p2 = p1-1;
	while (1)
	{
	    p1 = p2+1;
	    /* find the next space */
	    /*while (*p1!=' ' && *p1!='\0' && *(p1-1)!=':')
		p1++;*/
	    p1 = skipSpaces(p1);
	    if (*p1=='\0')   /* end of line */
		break;
	    /* find the last '+' or '-' in the field. This handles
	       users/groups with '+' or '-' in their names correctly */
	    for (p3=p1; *p3!=' ' && *p3!='\t' && *p3!='\0'; p3++)
		;
	    for (p2=p3; p2!=p1 && *p2!='+' && *p2!='-'; p2--)
		;
	    if (*p2=='\0')
	    {
		fprintf(stderr, "line %d: '+' or '-' expected\n", lineNum);
		XtError("Error parsing permissions file. xpg exits");
	    }
	    if (p2==p1)
	    {
		fprintf(stderr, "line %d: no user/Group specified\n", lineNum);
		XtError("Error parsing permissions file. xpg exits");
	    }
	    isAdd = (*p2 == '+');
	    *p2 = '\0';
	    userMatched = True;   /* default */
	    if (!isupper(*p1) && strcmp(p1, "*"))  /* name is user name */
		if (strcmp(p1, username))
		    userMatched = False;
	    if (isupper(*p1))                       /* name is group name */
	    {
		for (i=0; i<numGroups; i++)
		    if (!strcmp(p1, groups[i]))
			break;
		if (i>=numGroups)      /* no group matched */
		    userMatched = False;
	    }
	    p1 = p2+1;
	    /* permission flags */
	    for (p2=p1;  *p2!=' ' && *p2!='\0';  p2++)
		;
	    if (p1==p2)   /* no flags */
	    {
		fprintf(stderr, "line %d: flags expected after %c\n", lineNum,
			(isAdd ? '+' : '-'));
		XtError("Error parsing permissions file. xpg exits");
	    }
	    *p2 = '\0';
	    matched = dbMatched && classMatched && userMatched;
	    if (!strcmp(p1, "*"))
	    {
		if (matched)
		{
		    perms->append = isAdd;
		    perms->read   = isAdd;
		    perms->write  = isAdd;
		    perms->rules  = isAdd;
		}
		p1 = p2;
	    }
	    for (; p1<p2; p1++)
		switch (*p1)
		{
		  case 'a':
		    if (matched)
			perms->append = isAdd;
		    break;
		  case 'r':
		    if (matched)
			perms->read = isAdd;
		    break;
		  case 'w':
		    if (matched)
		    {
			perms->write  = isAdd;
			perms->append = isAdd;
		    }
		    break;
		  case 'R':
		    if (matched)
			perms->rules = isAdd;
		    XtWarning("permissions: 'R' (RULES) not implemented");
		    break;
		  default:
		    fprintf(stderr, "line %d: illegal flag %c\n", lineNum,*p1);
		    XtError("Error parsing permissions file. xpg exits");
		}
	}
    }
#ifdef AUTO_OWNER_PERMISSIONS
    if (!strcmp(appResources.database, username))
    {
	perms->append = True;
	perms->read   = True;
	perms->write  = True;
	perms->rules  = True;
    }
#endif
#ifdef XPG_DEBUG
    printf("append: %d\nread:   %d\nwrite:  %d\nrules:  %d\n",
	   perms->append, perms->read, perms->write, perms->rules);
#endif
}
