info-cvs
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]