[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
acl for cvs try II
From: |
Edward Peschko |
Subject: |
acl for cvs try II |
Date: |
Tue, 24 Jun 2003 17:00:58 -0700 |
User-agent: |
Mutt/1.3.22i |
ok,
here's acl for cvs - try II, to see if its getting through to the list.
The patch implements very simple acl at the code level, and works against
cvs-1.11.5/6.
Below is a bit of a writeup, followed by the patch. If people are interested in
having
this apply against 1.12.1, I'll work on it, otherwise it does what I need it to
do, so
I'm happy with it.
---
How it works:
You create a file 'CVSROOT/aclinfo' with a list of roles and their entries.
There are two special roles: 'default', which you get if as a user you are not
listed,
and 'all' which everybody gets.
Each entry is either a dir or a file. If the entry is prefixed by a '!' then
you *don't*
get the entry listed, and if its a directory, everything under the entry listed.
If it is a regular entry (ie: sans '!') you get everything underneath that
entry (or if
this entry is a file, just that file)
Entries that are underneath other entries supercede them. !dir + dir/a means
that you'll
get nothing in dir *except* dir/a (and anything underneath *it*)
Example:
esp:
!.
dir
!dir/dir2
dir2/file
<role>
all:
global_thingy
role:
common_dir
common_file1
default:
!.
If I'm logged in as esp, I:
don't get anything (!.),
except everything in directory 'dir' (dir),
except I don't get the contents of dir/dir2
I also get everything in <role> (commondir, common_file1), and
everything
in 'all' (global_thingy)
If I was logged in as another user, by default (the default: entry) I get
nothing ( default entry: !.)
except 'global_thingy' (in 'all' entry)
----
All of this is done at the software level: there is a function, do_recurse,
which pretty
much every cvs command uses. I added a 'acl_surgery' function which takes the
lists
of files, directories, or whatever, and does a lookup to enforce the above
rules. If
the file qualifies for user access, then it is allowed to go through. If the
file
*doesn't* qualify, it gets snipped out.
This insures that users won't even *see* the files that the aclinfo tells them
they
can't access - all the filtering is done at the server, And by extension, they
won't be
able to add, or commit entries that they are not allowed to, either (need to
work a
bit on the *notification* that they can't do this - but I wanted to make it
backwards
compatible with older versions of cvs)
That's about it - for my hashing, etc. I used the 'hash.c' api included inside
CVS, and
the 'x...' wrappers to do mallocing, etc. All the changes I did are prefixed
with 'acl_',
ex: acl_surgery, acl_check, etc..
Ed
--- patch follows against 1.11.5/6 --- patch with patch -p1 -d cvs_dir < patch,
one level
--- above your cvs source --
diff -rc cvs-1.11.5/src/Makefile.in cvs-1.11.5.new/src/Makefile.in
*** cvs-1.11.5/src/Makefile.in Thu Jan 16 13:36:43 2003
--- cvs-1.11.5.new/src/Makefile.in Sun Jun 8 16:46:30 2003
***************
*** 113,118 ****
--- 113,119 ----
# The cvs executable
cvs_SOURCES = \
+ acl.c \
add.c \
admin.c \
annotate.c \
***************
*** 209,215 ****
bin_PROGRAMS = cvs$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
! am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \
buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
--- 210,216 ----
bin_PROGRAMS = cvs$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
! am_cvs_OBJECTS = acl.$(OBJEXT) add.$(OBJEXT) admin.$(OBJEXT)
annotate.$(OBJEXT) \
buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
***************
*** 239,245 ****
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
! @address@hidden = ./$(DEPDIR)/add.Po ./$(DEPDIR)/admin.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/annotate.Po ./$(DEPDIR)/buffer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/checkin.Po ./$(DEPDIR)/checkout.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/classify.Po ./$(DEPDIR)/client.Po \
--- 240,246 ----
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
! @address@hidden = ./$(DEPDIR)/acl.Po ./$(DEPDIR)/add.Po ./$(DEPDIR)/admin.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/annotate.Po ./$(DEPDIR)/buffer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/checkin.Po ./$(DEPDIR)/checkout.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/classify.Po ./$(DEPDIR)/client.Po \
***************
*** 340,345 ****
--- 341,347 ----
distclean-compile:
-rm -f *.tab.c
+ @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff -rc cvs-1.11.5/src/acl.c cvs-1.11.5.new/src/acl.c
*** cvs-1.11.5/src/acl.c Sat Jun 21 22:27:17 2003
--- cvs-1.11.5.new/src/acl.c Mon Jun 23 12:07:27 2003
***************
*** 0 ****
--- 1,989 ----
+ /* 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, 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. */
+
+
+ #include "cvs.h"
+ #include "getline.h"
+ #include <stdio.h>
+
+ void _printit(List * a, char * b, int c);
+
+ /* Acl file format
+ * The acl file is located in CVSROOT/aclinfo
+ * It has the following format:
+ *
+ * user_or_role:
+ *
+ * directory
+ * file
+ * <user_or_role>
+ *
+ * One entry per line, and anything that is anchored to the beginning of the
line
+ * is considered a user, or a role.
+ *
+ * Roles are considered to be recursive, ie: a user can contain multiple
roles.
+ * whose entries are then added or replaced on the end of user. In the
conflict between
+ * not being able to see a file and being able to see it, pessimism wins.
+ *
+ * Usage:
+ *
+ * On startup the acl file is parsed, and a list is created for each user, of
entries
+ * they can or cannot access. This list is sorted, minus any preceeding '!'.
+ * In addition a hash is created for each entry, telling whether or not there
are
+ * sub-entries 'under' it. This is necessary for recursive
+ * operations (where one directory that is ignored may contain other
directories, which
+ * are wanted. )
+ *
+ */
+
+ typedef int (*INTPROC) PROTO (( const char *a, const char * b));
+ typedef size_t (*SIZEPROC) PROTO (( const char *a, const char * b));
+
+ static INTPROC _my_strcmp; /* case insensitive or not */
+ static SIZEPROC _my_strspn; /* case insensitive or not */
+ static int no_acl = 0;
+
+ int acl_quick_check_split ( char *dir, char *file, char *op )
+ {
+ char *fullpath;
+ char *repository;
+ char *entry;
+ int ret = 0;
+
+ if (no_acl) return;
+
+ fullpath = xmalloc( strlen(dir) + strlen(file) + 4 );
+ repository = current_parsed_root->directory;
+
+ sprintf(fullpath, "%s/%s", dir, file);
+
+ ret = acl_check(repository, fullpath, op, &entry);
+
+ free(fullpath);
+ free(entry);
+
+ return(ret);
+ }
+
+ int acl_quick_check_concat ( char *fullpath, char *op)
+ {
+ char *repository;
+ char *entry;
+ int ret = 0;
+
+ if (no_acl) return(1);
+ repository = current_parsed_root->directory;
+
+ ret = acl_check(repository, fullpath, op, &entry);
+
+ free(entry);
+ return(ret);
+ }
+
+ int acl_check( repository, file_or_dir, operation, entry )
+ char *repository;
+ char *file_or_dir;
+ char *operation;
+ char **entry;
+ {
+ char * user;
+ List * userlist;
+ int ret = 0;
+
+ if (no_acl) return(1);
+
+ user = acl_getuser();
+ List * acl_list = acl_getlist(repository);
+
+ if (!acl_list) return 1;
+
+ Node *usernode = findnode(acl_list, user);
+
+ if (usernode == NULL)
+ usernode = findnode(acl_list, "default");
+
+ userlist = (List *) usernode->data;
+
+ acl_find_closest_entry( userlist, file_or_dir, operation, entry );
+
+ if ((*entry)[0] == '!') ret = 0; else ret = 1;
+ free(user);
+ return(ret);
+ }
+
+ void acl_surgery(directory, filelist)
+ char * directory;
+ List * filelist;
+ {
+ int found = 0;
+ char *entry;
+ char * repository;
+ List * my_list;
+ Node * f, *g;
+ char * fullpath;
+
+ if (no_acl) return;
+ if (!directory) return; /* client.. how do you officially tell if you
are in
+ the client or
not anyways? */
+
+ repository = current_parsed_root->directory;
+ my_list = acl_getlist(repository);
+
+ if (!my_list) return;
+
+ Node * filenode = filelist->list; /* p represents each user. */
+ f = filenode->next;
+
+ while (f != filenode)
+ {
+ char * filename = f->key;
+ found = 1;
+ g = f->next;
+
+ fullpath = xmalloc( strlen(filename) + strlen(directory) + 4);
+ sprintf(fullpath, "%s/%s", directory, filename);
+
+ if (!acl_check( repository, fullpath, "nullop", &entry))
delnode(f);
+ free(fullpath);
+ f = g;
+ }
+ if (found == 1) free(entry);
+ }
+
+ char * acl_getuser()
+ {
+ char *ret;
+ char * user = getenv("CVS_USER");
+ if (user == NULL) ret = xstrdup("default");
+ else ret = xstrdup(user);
+
+ return(ret);
+ }
+
+ void acl_cleanup(repository)
+ char * repository;
+ {
+ List * my_list = acl_getlist(repository);
+ if (!my_list) return;
+ dellist(&my_list);
+ }
+
+ void acl_find_closest_entry ( userlist, file_or_dir, operation, entry )
+ List * userlist;
+ char * file_or_dir;
+ char * operation;
+ char **entry;
+ {
+ char *tmp = xstrdup(file_or_dir);
+ char *newfile = xstrdup(file_or_dir);
+
+ int found = 0;
+ Node *lookup;
+ Node *under;
+
+ *entry = xmalloc(strlen(tmp) + 2);
+ acl_clean(newfile);
+
+ while (*entry)
+ {
+ sprintf(*entry, "!%s", tmp);
+ lookup = findnode(userlist, *entry);
+
+ if (!lookup)
+ {
+ sprintf(*entry, "%s", tmp);
+ lookup = findnode(userlist, *entry);
+ if (!lookup)
+ {
+ acl_shorten(tmp);
+ }
+ else
+ {
+ free(tmp);
+ found = 1;
+ break;
+ }
+ }
+ else
+ {
+ free(tmp);
+ found = 1;
+ break;
+ }
+ }
+
+ acl_clean(*entry);
+ if (!found) free(tmp);
+
+ if (!lookup)
+ {
+ error(0,0, "error: could not find lookup for %s\n", newfile);
+ (*entry)[0] = '!';
+ }
+ else
+ {
+
+ if ((*entry)[0] != '!') { free(newfile); return; }
+
/* we found something which wasn't a
+
'!' and a direct match */
+
+ under = lookup->next;
+ while
+ (
+ under->type != HEADER &&
+ (under->data[0] == '!' || !(*_my_strcmp)(*entry+1,
under->data))
+ )
+ {
+ under = under->next;
+ }
+
+ while
+ (
+ under->type != HEADER &&
+ (
+ under->data[0] == '!' ||
+ ((*_my_strspn)(newfile, under->data) !=
strlen(newfile))
+ )
+ )
+ {
+ under = under->next;
+ }
+
+ if (under->type == HEADER)
+ {
+ free(newfile);
+ return; /* we found something that was a direct match
+ without an
underling */
+ }
+
+ /* fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d:\n",
under->data, *entry+1, (*_my_strspn)(*entry+1,under->data), strlen(*entry+1));
*/
+ if ((*_my_strspn)(*entry+1,under->data) == strlen(*entry+1))
+
/* we have an underling.. that is
+
not a ! therefore it takes
+
precedence */
+ {
+ free(newfile);
+ free(*entry);
+ *entry = xstrdup(under->data);
+ return;
+ }
+
+ free(newfile);
+ return;
+ }
+ }
+
+ void acl_shorten(char *tmp)
+ {
+ char *begin = tmp;
+
+ while (*tmp != '\0') tmp++;
+ if (tmp != begin) tmp--;
+
+ while (*tmp && *tmp != '/' && tmp != begin) tmp--;
+ *tmp = '\0';
+ }
+
+ List * acl_getlist(repository)
+ char *repository;
+ {
+
+ static List * acl_list = NULL;
+ char *acl_file;
+
+ if (no_acl) return((List *) NULL);
+
+ acl_file = xmalloc (strlen (repository) + sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_ACLINFO) + 10);
+
+
+ sprintf(acl_file, "%s/%s/%s", repository, CVSROOTADM,
CVSROOTADM_ACLINFO);
+
+ /* char *acl_file = "/tmp/testacl2"; */
+ /* xmalloc ( strlen (current_parsed_root->directory) +
sizeof (CVSROOTADM)
+ + sizeof (CVSROOTADM_ACLINFO) + 10); */
+
+ if (!acl_list)
+ acl_list = acl_add_file( acl_file, repository );
+
+ if (!acl_list) no_acl = 1;
+
+ free(acl_file);
+ return(acl_list);
+ }
+
+ List * acl_add_file( acl_file, repository )
+ char * acl_file;
+ char * repository;
+ {
+ List * top_list = getlist();
+ List * ret_list;
+ Node * node = NULL;
+ char * c_user_role = NULL;
+ char * line = NULL;
+ size_t line_allocated = 0;
+ List * add_list;
+ List * default_list;
+
+ FILE *fp = fopen(acl_file, "r");
+
+ if (!fp) return((List *) NULL);
+
+ default_list = acl_add_to_top(top_list, "default:");
+
+ acl_add_to_sublist(default_list, repository, "." );
+ default_list = acl_add_to_top(top_list, "all:");
+
+ /* special role which gets appended to
everybody */
+
+ if (!_my_strcmp)
+ _my_strcmp = (ign_case)? strcasecmp : strcmp;
+
+ if (!_my_strspn)
+ _my_strspn = (!ign_case)? acl_strnocasespn : acl_strcasespn;
+
+
+ if (!fp) return(top_list); /* empty in case we don't have a acllist,
which is OK */
+
+ while (getline (&line, &line_allocated, fp) >= 0)
+ {
+ switch (acl_line_type(line))
+ {
+ char *newline;
+ case CVS_BLANK :
+ break;
+
+ case CVS_USER_OR_ROLE_HEADER :
+
+ newline = strip_white_and_special(line);
+ add_list = acl_add_to_top(top_list, newline);
+ free(newline);
+ acl_add_to_sublist(add_list, repository, ".");
+
/* you can override this on a user basis */
+ acl_add_to_sublist(add_list, repository,
"<all>");
+
/* special default rule. */
+ break;
+
+ default:
+
+ newline = strip_white_and_special(line);
+ acl_add_to_sublist(add_list, repository,
newline);
+ free(newline);
+ break;
+ }
+ }
+
+
+ ret_list = acl_expand_roles(top_list);
+
+ if (ferror (fp))
+ error (0, errno, "cannot read %s", acl_file);
+ if (fclose (fp) < 0)
+ error (0, errno, "cannot close %s", acl_file);
+ free(line);
+ return(ret_list);
+ }
+
+ size_t acl_strspn(a, b)
+ const char * a;
+ const char * b;
+ {
+ size_t ret = 0;
+ while (*a && *b && *a == *b)
+ {
+ ret++; *a++; *b++;
+ }
+
+ return(ret);
+ }
+
+ size_t acl_strnocasespn(a, b)
+ const char * a;
+ const char * b;
+ {
+
+ size_t ret = acl_strspn(a, b);
+ /* fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d: :%d:\n",
+ b, a,
strlen(b), strlen(a), ret ) ; */
+ return(ret);
+
+ /*
+ if (strlen(a) > strlen(b))
+ {
+ fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d: :%d:\n", b, a,
strlen(b), strlen(a), strspn(b,a)) ;
+ return(acl_strspn(b, a));
+ }
+ else if (strlen(a) < strlen(b))
+ {
+ fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d: :%d:\n", a, b,
strlen(a), strlen(b), strspn(a,b));
+ return(acl_strspn(a,b));
+ }
+ else
+ {
+ if (strcmp(a,b) == 0)
+ {
+ fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d:
:%d:\n", a, b, strlen(a), strlen(b), strlen(a));
+ return(strlen(a));
+ }
+ else
+ {
+ fprintf(stderr, ":%s: :%s: STRSPN --> :%d: :%d:
:%d:\n", a, b, strlen(a), strlen(b), 0);
+ return(0);
+ }
+ }
+ */
+ }
+
+ size_t acl_strcasespn(a, b)
+ const char * a;
+ const char * b;
+
+ {
+ char *lowa, *lowb;
+ char *tmpa = xstrdup(a);
+ char *tmpb = xstrdup(b);
+
+ int ret = 0;
+
+ lowa = tmpa; lowb = tmpb;
+
+ while (*tmpa != '\0') { *tmpa = (char) tolower((int) *tmpa); tmpa++; }
+ while (*tmpb != '\0') { *tmpb = (char) tolower((int) *tmpb); tmpb++; }
+
+ ret = acl_strnocasespn(lowa, lowb);
+
+ free(lowa);
+ free(lowb);
+
+ return(ret);
+ }
+
+ enum acl_tag acl_line_type(line)
+ char *line;
+ {
+ char *mp;
+
+ if (!isspace((unsigned char) *line))
+ return(CVS_USER_OR_ROLE_HEADER);
+
+ else
+ for (mp = line; *mp != '\0'; ++mp)
+ if (!isspace((unsigned char) *mp))
+ return(CVS_DEFAULT);
+
+ return(CVS_BLANK);
+ }
+
+ List * acl_expand_roles(top)
+ List *top;
+ {
+ List * newtop = getlist();
+
+ Node *head, *p;
+
+ char *tagname;
+
+ head = top->list; /* p represents each user. */
+
+ for (p = head->next; p!= head; p = p->next)
+ {
+ List * taghash = getlist();
+
+ Node *subhead, *subp; /* subp represents each entry. */
+
+ subhead = ((List *) p->data)->list;
+
+ acl_hashkey_add(taghash, p); /* we add an entry to represent
the user
+ itself, to prevent
infinite recursion */
+
+ for ( subp = subhead->next; subp != subhead; subp = subp->next)
+ {
+ if (acl_istag(subp))
+ acl_append_tag(top, newtop, p, subp, taghash);
+ else
+ acl_append_entry(newtop, p, subp);
+ }
+ dellist(&taghash);
+ }
+
+ dellist(&top);
+ acl_sortbypath(newtop);
+ return(newtop);
+ }
+
+ void acl_sortbypath(newtop)
+ List * newtop;
+ {
+ Node *p;
+ Node *head = newtop->list;
+
+ for (p = head->next; p != head; p = p->next)
+ {
+ List * sublist = (List *) p->data;
+ sortlist(sublist, acl_depth_first);
+ }
+ }
+
+ int acl_depth_first (nodea , nodeb)
+ const Node * nodea;
+ const Node * nodeb;
+ {
+ char *compa, *compb;
+ int cmp = 0;
+
+ compa = nodea->data;
+ compb = nodeb->data;
+
+ if (*compa == '!') compa++;
+ if (*compb == '!') compb++;
+
+ if (!(*_my_strcmp)(compa, ".")) cmp = -1;
+ else if (!(*_my_strcmp)(compb, ".")) cmp = 1;
+ else cmp = (*_my_strcmp)(compa, compb);
+
+ if (!cmp && nodea->data[0] == '!') cmp = -1;
+ else if (!cmp && nodeb->data[0] == '!') cmp = 1;
+
+ return(cmp);
+ }
+
+
+ void acl_hashkey_add(hash, node)
+ List * hash;
+ Node * node;
+ {
+ Node *nodenew = getnode();
+
+ nodenew->key = acl_angletag(node->key);
+ nodenew->type = ENTRIES;
+ nodenew->data = "1";
+ nodenew->delproc = char_delproc;
+
+ if (addnode(hash, nodenew) == -1)
+ delnode(nodenew);
+ }
+
+ char * acl_angletag(name)
+ char * name;
+ {
+ char * newname = xmalloc( strlen(name) + 4 );
+
+ if (name[0] == '<')
+ sprintf(newname, name);
+ else
+ sprintf( newname, "<%s>", name);
+
+ return ( newname );
+ }
+
+ void acl_append_tag(top, newtop, parent, child, hash)
+ List *top;
+ List *newtop;
+ Node *parent;
+ Node *child;
+ List *hash;
+ {
+ Node *head, *p, *prior;
+
+ char * tagname;
+ char * name;
+ List * rolelist;
+ List * parentlist;
+
+ if (acl_taglookup(hash, child) != NULL) return;
+
+ acl_hashkey_add(hash, child); /* avoid infinite recursion */
+
+ name = acl_baretag(child->key);
+ head = findnode(top, name);
+
+ if (head == NULL)
+ {
+ error(0, 0, "warning: cannot find %s as a role!", name);
+ return;
+ }
+
+ rolelist = (List *) head->data;
+ head = rolelist->list;
+
+ parentlist = acl_getlistbykey(newtop, parent->key);
+
+ free(name);
+
+ for (p = head->next; p != head; p = p->next )
+ {
+ if (acl_istag(p))
+ acl_append_tag(top, newtop, parent, p, hash);
+ else
+ {
+ Node * dup = dupcharnode(p);
+ if (addnode(parentlist, dup) == -1)
+ delnode(dup);
+ }
+ }
+ }
+
+ Node * acl_taglookup(hash, node)
+ List * hash;
+ Node * node;
+ {
+ Node *prior;
+ prior = findnode(hash, node->key);
+
+ return(prior);
+ }
+
+
+ char * acl_baretag(name)
+ char *name;
+ {
+ int start = 0;
+ char *name2, *ret, *tmp;
+
+ ret = name2 = xmalloc(strlen(name));
+
+ for( tmp = name; *tmp != '\0'; tmp++ )
+ {
+ if (*tmp == '<' || *tmp == '>') continue;
+ *name2++ = *tmp;
+ }
+ *name2 = '\0';
+ return(ret);
+ }
+
+ List * acl_getlistbykey(newtop, name)
+ List * newtop;
+ char * name;
+ {
+ List * childlist;
+
+ Node *newhead = findnode(newtop, name);
+
+ if (newhead == NULL)
+ {
+ List *add_list = getlist();
+ newhead = getnode();
+
+ newhead->key = xstrdup(name);
+ newhead->type = LIST;
+ newhead->data = (char *) add_list;
+ newhead->delproc = list_delproc;
+
+ if (addnode(newtop, newhead) == -1)
+ delnode(newhead);
+
+ childlist = add_list;
+ return(childlist);
+ }
+ else
+ {
+ childlist = (List *) newhead->data;
+ return(childlist);
+ }
+ }
+
+ void _printit( newtop, name, num)
+ List * newtop;
+ char * name;
+ int num;
+ {
+ fprintf(stderr, "PRINTING %s -- %d \n-----\n", name, num);
+ printlist(newtop);
+ fprintf(stderr, "\n-----\n");
+ }
+
+ Node * dupcharnode(p)
+ Node *p;
+ {
+ Node *q = getnode();
+
+ q->type = p->type;
+ q->key = xstrdup(p->key);
+ q->data = q->key;
+ q->delproc = p->delproc;
+
+ /*
+ if (p->key != NULL)
+ q->key = xstrdup(p->key);
+
+ if (p->data != NULL)
+ {
+ q->data = xstrdup(p->data);
+ q->delproc = p->delproc;
+ }
+ */
+ return(q);
+ }
+
+ void acl_append_entry(newtop, parent, child)
+ List *newtop;
+ Node *parent;
+ Node *child;
+ {
+ char *name = parent->key;
+ Node * dup = dupcharnode(child);
+ List *childlist = acl_getlistbykey(newtop, name);
+
+ if ( acl_addnode(childlist, dup) == -1 )
+ delnode(dup);
+ }
+
+ int acl_addnode(list, add )
+ List * list;
+ Node * add;
+ {
+ char *key = add->key;
+
+ if (*key == '!')
+ {
+ Node *tmp = findnode(list, key+1);
+ if (tmp) delnode (tmp);
+ return(addnode(list, add));
+ }
+ else
+ return(addnode(list, add));
+ }
+
+
+ int acl_istag(subp)
+ Node *subp;
+ {
+ char *data = subp->data;
+
+ if (data[0] == '<' && data[strlen(data) - 1] == '>') return(1); else
return(0);
+ }
+
+ void acl_add_to_sublist(add_list, repository, ln)
+ List * add_list;
+ char * repository;
+ char * ln;
+ {
+ char *cur = xmalloc(strlen(ln) + strlen(repository) + 3);
+ Node * node = getnode();
+
+ acl_prepend_repository(cur, repository, ln);
+ acl_clean(cur);
+
+ node->key = cur;
+ node->type = FILES;
+ node->data = (char *) cur;
+ node->delproc = char_delproc;
+
+ if (addnode(add_list, node) == -1)
+ delnode(node);
+ }
+
+ void acl_clean(path)
+ char * path;
+ {
+ char *tmp = (char *)malloc(strlen(path));
+ char *start = tmp;
+ char *beg = path;
+ int state = 0;
+
+ while (*path)
+ {
+ if (*path == '.' && *(path+1) == '\0')
{ *tmp++ = '/'; path++; }
+ if (*path == '.' && path == beg && *(path+1) ==
'/') { path++; }
+ else if (*path == '.' && path == beg)
{ *tmp++ = *path++; }
+ else if (*path == '.' && *(path-1) == '/' && *(path+1) == '/')
{ path++; }
+ else if (*(path-1) == '/' && *path == '.' && !*(path+1))
{ path++; }
+ else if (*path == '/' && path == beg)
{ *tmp++ = *path++; }
+ else if (*path == '/' && !*(path+1))
{ path++; }
+ else if (*path == '/' && *(path+1) == '.' && !*(path+2))
{ path++; }
+ else if (*path == '/' && *(path+1) == '.' && *(path+2) == '/')
{ path++; }
+ else if (*path == '/' && tmp != start && *(tmp-1) == '/')
{ path++; }
+ else if (*path == '/' && *(path+1) == '/')
{ path++; }
+ else
{ *tmp++ = *path++; }
+ }
+ *tmp = '\0';
+
+ strcpy(beg, start);
+ free(start);
+ }
+
+ void acl_prepend_repository(cur, repository, ln)
+ char * cur;
+ char * repository;
+ char * ln;
+ {
+ char *tmp;
+
+ if (*ln == '.' && *(ln+1) == '\0')
+ strcpy(cur, repository);
+ else if (*ln == '!' && *(ln+1) == '\0')
+ {
+ sprintf(cur, "!%s", repository);
+ }
+ else if (*ln == '.' && *(ln+1) == '/' && *(ln+2) == '\0')
+ strcpy(cur, repository);
+ else if (*ln == '!' && *(ln+1) == '.' && *(ln+2) == '\0')
+ sprintf(cur, "!%s", repository);
+ else if (*ln == '<' && *(ln+1) != '\0')
+ strcpy(cur, ln);
+ else
+ {
+ if (*ln == '!') { *cur++ = '!'; *ln++; }
+
+ for (tmp = repository; *tmp != '\0'; ++tmp)
+ *cur++ = *tmp;
+
+ if (*ln == '.' && *(ln+1) == '/' ) ln++;
+ if (*ln != '/') { *cur++ = '/'; }
+
+ for (tmp = ln; *tmp != '\0'; ++tmp)
+ *cur++ = *tmp;
+
+ *cur = '\0';
+ }
+ }
+
+ List * acl_add_to_top(top, ln)
+ List * top;
+ char * ln;
+ {
+
+ Node * tmp;
+ List * add_list;
+
+
+ char * cur = xstrdup(ln);
+ cur[strlen(cur)-1] = '\0';
+
+ tmp = findnode(top, cur);
+
+ if (tmp == NULL)
+ {
+ Node *node = getnode();
+ add_list = getlist();
+
+ node->key = cur;
+ node->type = LIST;
+ node->data = (char *) add_list;
+ node->delproc = list_delproc;
+
+ if (addnode(top, node) == -1)
+ {
+ delnode(node);
+ }
+ }
+ else
+ {
+ free(cur);
+ add_list = (List *) tmp->data;
+ }
+
+ return(add_list);
+ }
+
+ void list_delproc(p)
+ Node *p;
+ {
+ List *listp = (List *) p->data;
+
+ /* char *cur = p->key;
+ free(cur);
+ */
+ dellist(&listp);
+ }
+
+ void char_delproc(p)
+ Node *p;
+ {
+ char *data = p->data;
+ char *key = p->key;
+
+ /* free(data); */
+ /* if (data != key) free(key); */
+
+ /* if (*data != '\0')
+ {
+ *data = '\0';
+ fprintf(stderr, "SUCCESSFULLY freed data!\n");
+ free(data);
+ }
+ else
+ {
+ fprintf(stderr, "WHOA..\n");
+ }
+ if (*key != '\0')
+ {
+ *key = '\0';
+ fprintf(stderr, "SUCCESSFULLY freed key!\n");
+ free(key);
+ }
+ else
+ {
+ fprintf(stderr, "ALREADY FREED\n");
+ }
+ */
+ }
+
+ char * strip_white_and_special(char * line)
+ {
+ int fnc = 0;
+ int len = strlen(line) + 1;
+
+ char *dst, *dp, *mp;
+ /* Strip whitespace from end of lines and end of string. */
+ dp = dst = (char *) xmalloc (len);
+
+ for (mp = line; *mp != '\0'; ++mp)
+ {
+ if (*mp == '\t' || *mp == ' ') continue;
+
+ if (*mp == '\n')
+ {
+ /* At end-of-line; backtrack to last non-space. */
+ while (dp > dst &&
+ (dp[-1] == ' ' || dp[-1] == '\t' ))
+ --dp;
+ }
+ *dp++ = *mp;
+ }
+
+ /* Backtrack to last non-space at end of string, and truncate. */
+ while (dp > dst && isspace ((unsigned char) dp[-1]))
+ --dp;
+ *dp = '\0';
+
+ /* After all that, if there was no non-space in the string,
+ substitute a non-empty message. */
+ if (*dst == '\0')
+ {
+ free (dst);
+ dst = xstrdup ("");
+ }
+
+ return(dst);
+ }
+
+
+ /*
+ * Acl section
+ *
+ * Acl works on an inclusion basis. The entry '.' says include everything,
which
+ * is the default (but which is cleared out when an entry is added). Adding
an entry
+ * says that it is accessible, adding an entry prefixed with a ! says it
is not. Entries
+ * are processed in bottom-up fashion, ie:
+ *
+ * directory1
+ * !directory1/directory2
+ * directory1/directory2/directory3
+ *
+ * says that all of directory1 is included, except for entries in
directory1/directory2
+ * which are not included, except for entries in
directory1/directory2/directory3 which
+ * are included. Wildcards are not supported currently, although they could
be with a
+ * performance penalty.
+ *
+ * In the case where there are two entries that are the same, ie: directory1
&&
+ * !directory1, this is equivalent to !directory1 (since both can't be true)
+ */
+
diff -rc cvs-1.11.5/src/add.c cvs-1.11.5.new/src/add.c
*** cvs-1.11.5/src/add.c Thu Oct 24 11:38:36 2002
--- cvs-1.11.5.new/src/add.c Wed Jun 11 22:00:01 2003
***************
*** 394,399 ****
--- 394,402 ----
}
#endif
+ /* ACL STUFF */
+ if (!acl_quick_check_split(finfo.repository, finfo.file, "add"))
continue;
+
/* We pass force_tag_match as 1. If the directory has a
sticky branch tag, and there is already an RCS file which
does not have that tag, then the head revision is
diff -rc cvs-1.11.5/src/cvs.h cvs-1.11.5.new/src/cvs.h
*** cvs-1.11.5/src/cvs.h Sat Dec 28 10:01:30 2002
--- cvs-1.11.5.new/src/cvs.h Sat Jun 21 21:16:48 2003
***************
*** 12,17 ****
--- 12,18 ----
*/
+ #define NOCACHE 1
#ifdef HAVE_CONFIG_H
# include <config.h> /* this is stuff found via autoconf */
#endif /* CONFIG_H */
***************
*** 176,181 ****
--- 177,183 ----
*/
#define CVSROOTADM "CVSROOT"
#define CVSROOTADM_MODULES "modules"
+ #define CVSROOTADM_ACLINFO "aclinfo"
#define CVSROOTADM_LOGINFO "loginfo"
#define CVSROOTADM_RCSINFO "rcsinfo"
#define CVSROOTADM_COMMITINFO "commitinfo"
***************
*** 289,294 ****
--- 291,301 ----
command line, the client, etc. */
#define MAXDATELEN 50
+ enum acl_tag
+ {
+ CVS_BLANK, CVS_USER_OR_ROLE_HEADER, CVS_DEFAULT
+ };
+
/* The type of an entnode. */
enum ent_type
{
***************
*** 470,475 ****
--- 477,537 ----
char *xstrdup PROTO((const char *str));
void strip_trailing_newlines PROTO((char *str));
int pathname_levels PROTO ((char *path));
+
+
+ /* acl stuff. */
+
+
+ void acl_clean PROTO (( char *acl ));
+ int acl_addnode PROTO (( List * list, Node * node));
+ char * acl_getuser PROTO (());
+ size_t acl_strcasespn PROTO (( const char *tmp, const char *tmp2 ));
+ size_t acl_strnocasespn PROTO (( const char *tmp, const char *tmp2 ));
+ void acl_shorten PROTO ((char *tmp));
+ int acl_depth_first PROTO ((const Node * nodea, const Node * nodeb));
+ void acl_sortbypath PROTO (( List * newtop));
+
+ List * acl_getlist PROTO (( char *repository));
+ void acl_find_closest_entry PROTO (( List * userlist, char * file_or_dir,
+
char *op, char **entry));
+
+ void acl_surgery PROTO (( char * repository, List * filelist ));
+ int acl_quick_check_split PROTO (( char * dir, char * file, char * op));
+ int acl_quick_check_concat PROTO (( char * fullpath, char * op));
+
+ int acl_check PROTO (( char * repository, char * file_or_dir,
+ char *
operation, char **entry ));
+ void acl_cleanup PROTO (( char * repository ));
+
+ List * acl_getlistbykey PROTO ((List * newtop, char * name));
+ void acl_hashkey_add PROTO (( List * hash, Node * node ));
+ void acl_append_entry PROTO ((List * newtop, Node * parent, Node * child));
+
+ void acl_setup PROTO(());
+ List * acl_add_file PROTO ((char * acl_file, char * repository));
+
+ void acl_prepend_repository PROTO (( char *cur, char *repository, char *ln ));
+ enum acl_tag acl_line_type PROTO (( char * line));
+ List * acl_expand_roles PROTO ((List * top));
+ void acl_add_to_sublist PROTO ((List *add_list, char *repostory, char *ln));
+
+ List * acl_add_to_top PROTO ((List *top, char * ln));
+ Node * dupcharnode( Node *q);
+
+ void list_delproc PROTO((Node *p));
+ void char_delproc PROTO((Node *p));
+ char * strip_white_and_special PROTO ((char *line));
+ int acl_istag PROTO((Node *data));
+ void acl_append_tag PROTO (( List * top, List * newtop, Node * parent,
+ Node * child,
List *hash ));
+
+ char * acl_baretag PROTO (( char * name ));
+ char * acl_angletag PROTO (( char * name ));
+ Node * acl_taglookup PROTO (( List * hash, Node * node));
+
+
+ /* end acl stuff */
+
typedef int (*CALLPROC) PROTO((char *repository, char *value));
int Parse_Info PROTO((char *infofile, char *repository, CALLPROC callproc,
int all));
diff -rc cvs-1.11.5/src/hash.c cvs-1.11.5.new/src/hash.c
*** cvs-1.11.5/src/hash.c Fri Jun 9 13:54:01 2000
--- cvs-1.11.5.new/src/hash.c Tue Jun 17 20:53:20 2003
***************
*** 163,170 ****
return;
/* take it out of the list */
! p->next->prev = p->prev;
! p->prev->next = p->next;
/* if it was hashed, remove it from there too */
if (p->hashnext != (Node *) NULL)
--- 163,173 ----
return;
/* take it out of the list */
! if (p->next)
! p->next->prev = p->prev;
!
! if (p->prev)
! p->prev->next = p->next;
/* if it was hashed, remove it from there too */
if (p->hashnext != (Node *) NULL)
***************
*** 484,494 ****
{
if (node == NULL)
{
! (void) printf("NULL node.\n");
return(0);
}
! (void) printf("Node at 0x%p: type = %s, key = 0x%p = \"%s\", data = 0x%p,
next = 0x%p, prev = 0x%p\n",
node, nodetypestring(node->type), node->key, node->key, node->data,
node->next, node->prev);
return(0);
--- 487,497 ----
{
if (node == NULL)
{
! (void) fprintf(stderr, "NULL node.\n");
return(0);
}
! (void) fprintf(stderr, "Node at 0x%p: type = %s, key = 0x%p = \"%s\",
data = 0x%p, next = 0x%p, prev = 0x%p\n",
node, nodetypestring(node->type), node->key, node->key, node->data,
node->next, node->prev);
return(0);
***************
*** 505,515 ****
{
if (list == NULL)
{
! (void) printf("NULL list.\n");
return;
}
! (void) printf("List at 0x%p: list = 0x%p, HASHSIZE = %d, next = 0x%p\n",
list, list->list, HASHSIZE, list->next);
(void) walklist(list, printnode, NULL);
--- 508,518 ----
{
if (list == NULL)
{
! (void) fprintf(stderr, "NULL list.\n");
return;
}
! (void) fprintf(stderr, "List at 0x%p: list = 0x%p, HASHSIZE = %d, next =
0x%p\n",
list, list->list, HASHSIZE, list->next);
(void) walklist(list, printnode, NULL);
diff -rc cvs-1.11.5/src/main.c cvs-1.11.5.new/src/main.c
*** cvs-1.11.5/src/main.c Thu Oct 24 11:38:37 2002
--- cvs-1.11.5.new/src/main.c Fri Jun 20 23:50:36 2003
***************
*** 433,439 ****
of), it's a good idea to call it. */
tzset ();
#endif
-
/*
* Just save the last component of the path for error messages
*/
--- 433,438 ----
diff -rc cvs-1.11.5/src/recurse.c cvs-1.11.5.new/src/recurse.c
*** cvs-1.11.5/src/recurse.c Sat Dec 28 10:01:30 2002
--- cvs-1.11.5.new/src/recurse.c Thu Jun 19 20:35:53 2003
***************
*** 125,130 ****
--- 125,131 ----
frame.dosrcs = dosrcs;
expand_wild (argc, argv, &argc, &argv);
+ /* add ACL ENTRY HERE!?!?!?!? */
if (update_preload == NULL)
update_dir = xstrdup ("");
***************
*** 624,630 ****
error (1, errno, "could not get working directory");
}
srepository = repository; /* remember what to free */
-
fileattr_startdir (repository);
/*
--- 625,630 ----
***************
*** 638,643 ****
--- 638,645 ----
if (dirlist != NULL && filelist == NULL)
dodoneproc = 0;
+
+
/*
* If filelist or dirlist is already set, we don't look again. Otherwise,
* find the files and directories
***************
*** 694,705 ****
--- 696,709 ----
/* we will process files, so pre-parse entries */
if (frame->which & W_LOCAL)
entries = Entries_Open (frame->aflag, NULL);
+ acl_surgery(srepository, entries);
}
}
/* process the files (if any) */
if (process_this_directory && filelist != NULL && frame->fileproc)
{
+ /* ADD ACL HERE current_parsed_root->directory, repository,
filelist */
struct file_info finfo_struct;
struct frame_and_file frfile;
***************
*** 732,737 ****
--- 736,744 ----
frfile.finfo = &finfo_struct;
frfile.frame = frame;
+ /* we get rid of entries as per acl */
+ acl_surgery(srepository, filelist);
+
/* process the files */
err += walklist (filelist, do_file_proc, &frfile);
***************
*** 759,765 ****
struct frame_and_entries frent;
frent.frame = frame;
! frent.entries = entries;
err += walklist (dirlist, do_dir_proc, (void *) &frent);
}
#if 0
--- 766,774 ----
struct frame_and_entries frent;
frent.frame = frame;
! frent.entries = entries;
!
! acl_surgery(srepository, dirlist);
err += walklist (dirlist, do_dir_proc, (void *) &frent);
}
#if 0
- acl for cvs try II,
Edward Peschko <=