[cvsacl-users] New Patch for stock CVS-ACL 1.12.13
Brought to you by:
sbaris
From: Arlindo da S. <arl...@na...> - 2010-05-24 17:40:10
|
diff -ruN cvs-1.12.13/ACL-DOC.txt cvs-1.12.13-cvsacl-2-patched/ACL-DOC.txt --- cvs-1.12.13/ACL-DOC.txt 1969-12-31 19:00:00.000000000 -0500 +++ cvs-1.12.13-cvsacl-2-patched/ACL-DOC.txt 2006-06-03 15:12:28.000000000 -0400 @@ -0,0 +1,266 @@ + +CVS Access Control List Extension + +Execution of all CVS commands can be controlled with eight +different permissions. + +Permission Types: + +- no access + Command line character: 'n' + If a user is given 'n' permission, it is not allowed for any + action on repository. +- read + Command line character: 'r' + 'r' permission gives only read access on repository. + With r permission users are allowed to run cvs commands: + annotate, checkout, diff, export, log, rannotate, rdiff, rlog, status. +- write + Command line character: 'w' + 'w permission allows only cvs commit/checkin action. + With w permission, users are not allowed to add/remove any file + to/from repository, other permissions should be defines for that. +- tag + Command line character: 't' + 't' permission allows cvs tag and rtag commands to run. + 't' permission includes 'r' permission, since without + reading you can not tag/untag a file. However 't' permission + does not include write permission, users can not commit + a file with only 't' permission. +- create + Command line character: 'c' + 'c' permission allows cvs add and import commands to run. + To add or import a file/directory to repository, users must have + 'c' permission. Again, 'c' permission does not include write permission, + thus users may only add or import files, but can not modify any + existing file. After issuing add command, file must be committed + to complete adding. This commit command is allowed because the user + is adding file and not modifying existing one. +- delete + Command line character: 'd' + 'd' permission allows cvs remove command to run. To remove a file/directory + from repository, 'd' permission have to be set. 'd' permission does not + include write permission, so users can not modify contents of an existing + file on repository. +- full access except admin rights + Command line character: 'a' + 'a' permission gives all access (above permissions) to repository, but it + can not modify permissions. Only acl admins may modify the acl definitions. +- acl admin + Command line character: 'p' + 'p' permission means that user is an acl admin, so it is allowed to + make anything on repository including permission change. + + +ACL Config Keywords: +The administrative file aclconfig contains miscellaneous settings which +affect the behaviour of ACL extension. Currently defined keywords are: + +UseCVSACL=value +Access Control is enabled if set to yes. acl/racl commands only run when +keyword is set to yes, and access control is enabled. +Default value: no. + +UseCVSACLDefaultPermissions=value +Value can be any combination of valid permission types (w,r,t,c,d,t,a,p). +if there is no defined ACL and default permissions in access file, or no +access file at all, this permissions are used. +Default value: p (admin rights). + +UseCVSGroups=value +CVS does not have a CVSROOT/passwd file. However it can be created manually +(format should be same as /etc/group). If value set to yes, CVS checks for +groups in file $CVSROOT/CVSROOT/group. +Default value: no. + +UseSystemGroups=value +Group memberships for users are checked in file /etc/group, if value is set +to yes. +Default value: no. + +CVSACLFileLocation=value +Originally access file is put under CVSROOT/CVSROOT, To use a different +location, set value to a valid path. +Default value: $CVSROOT/CVSROOT/access. + +CVSGroupsFileLocation=value +To use a different location for group file set value to a valid path to group +file. UseCVSGroups must be also enabled. +Default value: NULL. + +UseSeparateACLFileForEachDir=value +If value is set to yes, a separate ACL file (access) is created for each +directory in repository. If the repository is really big and has tousands of +files and directories, performance may drop due to a big access file. +Setting the value to yes, may increase performance. Normally, it is not needed. +Default value: no. + +DontPrintFileCantOpenWarnings=value +If UseSeparateACLFileForEachDir keyword is set to yes, cvs acl looks for access +file in each directory, and if there are many directories it will print a warning +message for each directory which does not have an access file. To disable this warning +messages set DontPrintFileCantOpenWarnings keyword to yes. +Default value: no. + +StopAtFirstPermissionDenied=value +If StopAtFirstPermissionDenied is set to yes operation will stop at first +permission denied message. e.g. when you send commit command for a directory, +if you dont have write permission for just one file under the directory, +by default you will have a warning and commit will continue on the other files. +If this keyword is set to 'yes', then commit operation will be stopped +when inaccassable file found. +Default value: no. + +CVSServerRunAsUser=value +Set CVSServerRunAsUser keyword to a valid system user. +When a user make a remote connection to CVS, after successfull authentication +cvs process switch to run as that user, or defined system user in +$CVSROOT/CVSROOT/passwd. Also unix file permissions should be set accordingly. +A better solution: +Add a user and group such as both cvsadm. +Set CVSServerRunAsUser keyword to cvsadm. +Change unix file system permissions for the repository, +make cvsadm user and group owner, and read, write, execute permissions and setgid. +(chown cvsadm -R /path/to/your/repository) +(chgrp cvsadm -R /path/to/your/repository) +(chmod 2770 -R /path/to/your/repository) +Add yourself to cvsadm group (since you are ACL administrator). +Therefore, only users making remote connections will have access to repository +if they have sufficient permissions defined through acl/racl commands. +Local users can not access to repository via a cvs client or directly. + +Command Line Usage Information: +acl command is used on checked out files or directories. racl command is +used on repository without a working copy. Usage information can be obtained +with standard cvs --help command. +Output of cvs --help acl and cvs --help racl: + +Usage: cvs racl [user||group:permissions] [-Rl] [-r tag] + -R Process directories recursively. + -r rev Existing revision/tag. + -l List defined ACLs. + +Usage: cvs acl [user||group:permissions] [-Rl] [-r tag] + -R Process directories recursively. + -r rev Existing revision/tag. + -l List defined ACLs. + +You may directly set permissions for a user or group or add/remove +permissions with + and - signs to/from existing permissions. +If you do not give the branch/tag information, default value of HEAD +(main branch) will be used. You have to give branch/tag name with -r option. +You may type ALL for branch/tag field. + +While checking for permissions, it goes thorough the list below. So the highest +significant permission is the first item in list. + +- permissions assigned to username for specific directory or file. +- permissions assigned to group name for specific directory or file. +- permissions as defaults for specific directory or file. +- permissions assigned to parent folders (inherits from the first parent + which permissions are assigned). +- permissions as repository defaults. +- default permissions in aclconfig file. + +Using ALL keyword +ALL keyword can be given as directory/file name or tag name or user/group name. As +usually it represents all directory/file, or tag, or user/group. e.g. Using ALL +for directory/file name means ALL directories and files in repository. Using ALL +for tag name means all tags including main branch. + +Examples + /cvs/ + | + | + +--projectA/ + | | + | +---CVSROOT/ + | | + | +---lib/ + | | | + | | +---gnulib/ + | | | + | | +---zlib/ + | | + | +---src/ + | | | + | | +---main.c + | | | + | | +---server.c + | | | + | | +---client.c + | | + | +---gui/ + | + +--projectB/ +We have above directory structure for a cvs repository, and no defined permissions. + +Setting main default permissions: + +$ cvs -d /cvs/projectA racl cvsadmin:p -r ALL ALL +$ cvs -d /cvs/projectA racl ALL:r -r ALL ALL +User cvsadmin will be an acl admin, and all other users will have only read +rights on all branches/tags in projectA repository. This is the default acl +definition and it overwrites default permissions in $CVSROOT/CVSROOT/aclconfig file. + +$ cvs -d /cvs/projectA racl ALL:r -r ALL ALL +$ cvs -d /cvs/projectA racl ALL:n -r ALL gui +After executing these two commands, all users will have read access on all +directories and files except gui directory. Everyone will be denied to access to gui +directory because no access(n) permission is set. + +Setting permissions directly on a file or directory: + +$ cvs -d /cvs/projectA racl userX:wcd lib +$ cvs -d /cvs/projectA racl group1:w lib +First command will set write, create, and delete permissions for userX on directory +lib with branch HEAD (since no branch/tag information given, branch defaults to HEAD). + +Second command will set only write permission for group1 on directory lib with branch HEAD. +Members of group1 will have only commit rights on lib directory, branch HEAD, they can +not add or remove any file, just modify existing files. +If userX is also a member of group1, userX will have write, create, and delete permissions +because it is specifically given these permissions. + +$ cvs -d /cvs/projectA racl userY:wcd -r develStream lib +$ cvs -d /cvs/projectA racl userY:r -r integStream lib +These commands will give 'wcd' permissions to userY on lib directory with tag develStream, +and 'r' permissions on lib directory with tag integStream. + +$ cvs -d /cvs/projectA racl userZ:wcd src +$ cvs -d /cvs/projectA racl userZ:r src/main.c +First command will give 'wcd' permissions to userZ on src directory, but only read +permission on file main.c in src directory. + +Using + and - signs to set permissions on a file or directory: + +$ cvs -d /cvs/projectA racl userZ:+t src +$ cvs -d /cvs/projectA racl userZ:-cd src +$ cvs -d /cvs/projectA racl userZ:-wt src +Before the first command, userZ has 'wcd' permissions on src directory, after issuing +command it will have 'wcdt' permissions. Tag permission will be added. UserZ has 'wcdt' +permissions, and we execute the second command to remove create and delete permissions. +So userZ has 'wt' permissions. In the last command we also remove 'wt' permissions, finally +userZ has no defined permissions left, and it will use the default permissions if set. + +Listing permissions on a file or directory: + +$ cvs -d /cvs/projectA racl -l src +$ cvs -d /cvs/projectA racl -l src +$ cvs -d /cvs/projectA racl -l src/main.c + +First command will list the permissions for src directory. +Example output: +d src HEAD | userX:wcd group1:r | defaults:r +userX and group1 has assigned permissions, all other users will have default +permissions, which is only read. + +Second command will list the permissions for files in src directory. +Example output: +f src/main.c HEAD | userX:wcd group1:r | defaults:r +f src/server.c HEAD | userX:wcd group1:r | defaults:r +f src/client.c HEAD | userX:wcd group1:r | defaults:r + +Third command will list the permissions for main.c file in src directory. +Example output: +f src/main.c HEAD | userX:wcd group1:r | defaults:r diff -ruN cvs-1.12.13/src/acl.c cvs-1.12.13-cvsacl-2-patched/src/acl.c --- cvs-1.12.13/src/acl.c 1969-12-31 19:00:00.000000000 -0500 +++ cvs-1.12.13-cvsacl-2-patched/src/acl.c 2010-02-03 13:00:54.000000000 -0500 @@ -0,0 +1,2133 @@ +/* + * Copyright (C) 2006 The Free Software Foundation, Inc. + * + * Portions Copyright (C) 2006, Baris Sahin <sbaris at users.sourceforge.net> + * <http://cvsacl.sourceforge.net> + * + * + * You may distribute under the terms of the GNU General Public License as + * specified in the README file that comes with the CVS source distribution. + * + * + * + * CVS ACCESS CONTROL LIST EXTENSION + * + * It provides advanced access control definitions per modules, + * directories, and files on branch/tag for remote cvs repository + * connections.Execution of all CVS subcommands can be controlled + * with eight different permissions. + * + * Permission Types: + * - no permission (n) (1) + * - all permissions (a) (2) + * - write permission (w) (3) + * - tag permission (t) (4) + * - read permission (r) (5) + * - add permission (c) (6) + * - remove permission (d) (7) + * - permission change (p) (8) + * + */ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* CVS headers. */ +#include "fileattr.h" +#include "cvs.h" +#include "hardlink.h" + +/* GNULIB headers. */ +#include "getline.h" +#include <grp.h> +#include <assert.h> + +static int acl_fileproc (void *callerdat, struct file_info *finfo); +static Dtype acl_dirproc (void *callerdat, const char *dir, const char *repos, + const char *update_dir, List *entries); + +static int acllist_fileproc (void *callerdat, struct file_info *finfo); +static Dtype acllist_dirproc (void *callerdat, const char *dir, const char *repos, + const char *update_dir, List *entries); + +static void acllist_print (char *line, const char *obj); + +static int racl_proc (int argc, char **argv, char *xwhere, + char *mwhere, char *mfile, int shorten, + int local_specified, char *mname, char *msg); + +FILE *open_accessfile (char *xmode, const char *repos, char **fname); +FILE *open_groupfile (char *xmode); + +char *get_perms (char *xperms); +char *make_perms (char *xperms, char *xfounduserpart, char **xerrmsg); + +char *findusername(const char *string1, const char *string2); +char *findgroupname(const char *string1, const char *string2); + +static char *cache_repository = NULL; +static int cache_retval; +static int founddeniedfile; +static int cache_perm; + +static int is_racl; + +char *tag = NULL; + +char *muser; +char *mperms; +static int defaultperms; + +static char *default_perms_object = NULL; +char *default_part_perms_accessfile = NULL; +int aclconfig_default_used; + +int acldir = 0; +int aclfile = 0; +int listacl = 0; + +int userfound = 0; +int groupfound = 0; + +/* directory depth ... */ +char *dirs[255]; + +static const char *const acl_usage[] = + { + "Usage: %s %s [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]\n", + "\t-R\tProcess directories recursively.\n", + "\t-r rev\tExisting revision/tag.\n", + "\t-l\tList defined ACLs.\n", + "(Specify the --help global option for a list of other help options)\n", + NULL + }; + +static const char *const racl_usage[] = + { + "Usage: %s %s [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]\n", + "\t-R\tProcess directories recursively.\n", + "\t-r rev\tExisting revision/tag.\n", + "\t-l\tList defined ACLs.\n", + "(Specify the --help global option for a list of other help options)\n", + NULL + }; + + +int +access_allowed (const char *file, const char *repos, char *tag, + int perm, char **mline, int *mpos, int usecache) +{ + int retval = 0; + int foundline = 0; + FILE *accessfp; + + bool flag = true; + + char *iline = NULL; + char *tempv = NULL; + char *tempc = NULL; + size_t tempsize; + + int intcount; + int accessfilecount; + int signlevel = -1; + int dadmin = 0; + + const char *repository; + char *filefullname = NULL; + + TRACE (TRACE_FUNCTION, "access_allowed (%s, %s, %s, %d, %s, %d, %d)", file, repos, tag, perm, mline, mpos, usecache); + + retval = 0; + + if (defaultperms) + { + repository = xstrdup ("ALL"); + } + else { + if (strlen(repository = Short_Repository (repos)) == 0) + { + repository = xstrdup ("."); + } + } + + /* cache */ + if (usecache + && cache_repository != NULL + && strcmp (cache_repository, repository) == 0 + && !founddeniedfile + && perm == cache_perm) + return (cache_retval); + else + { + if (cache_repository) free (cache_repository); // ams + cache_repository = xstrdup (repository); + cache_perm = perm; + } + + iline = xstrdup(repository); + + tempv = strtok(iline, "/\t"); + tempc = xstrdup(tempv); + tempsize = strlen(tempc); + + intcount = 0; + /* store paths from object to cvsroot */ + dirs[intcount] = xstrdup(tempc); + //- printf("%%%%%% [%d] dir token = <%s>\n",intcount,dirs[intcount]); + while ((tempv = strtok(NULL, "/\t")) != NULL) + { + intcount++; + + xrealloc_and_strcat(&tempc, &tempsize, "/"); + xrealloc_and_strcat(&tempc, &tempsize, tempv); + + dirs[intcount] = xstrdup(tempc); + + } + + /* free not needed variables here */ + // free (tempv); + // if (tempc) free (tempc); // ams: do not deallocate output of strtok() + // if (iline) free (iline); // ams: do not deallocate output of strtok() + + /* accessfilecount will used + * if UseSeparateACLFile keyword is set to yes*/ + accessfilecount = intcount; + + /* if file is not null add it to dirs array */ + if (file != NULL) + { + filefullname = xmalloc (strlen (repository) + + strlen (file) + 2); + + strcpy (filefullname, repository); + strcat (filefullname, "/"); + strcat (filefullname, file); + + intcount++; + dirs[intcount] = xstrdup(filefullname); + + } + + for (accessfilecount; accessfilecount >= 0 && flag; accessfilecount--) + { + if (!config->aclconfig->UseSeparateACLFileForEachDir) { + flag = false; + accessfp = open_accessfile ("r", repository, NULL); + } + else + { + flag = true; + accessfp = open_accessfile ("r", dirs[accessfilecount], NULL); + } + + if (accessfp != NULL) + { + char *line = NULL; + size_t line_allocated = 0; + + char *xline; + char *part_type = NULL; + char *part_object = NULL; + char *part_tag = NULL; + char *part_perms = NULL; + + int x; + + while (getline (&line, &line_allocated, accessfp) >= 0) + { + + if (line[0] == '#' || line[0] == '\0' || line[0] == '\n') + continue; + + xline = xstrdup (line); + part_type = strtok (line, ":\t"); + part_object = strtok (NULL, ":\t"); + part_tag = strtok (NULL, ":\t"); + part_perms = strtok (NULL, ":\t"); + + if (part_type == NULL || part_object == NULL || + part_tag == NULL || part_perms == NULL) + { + if (line) free (line); // ams + error(1, 0, "access file is corrupted or has invalid format"); + } + + for (x = intcount; x >= signlevel && x != -1; x--) + { + if (strcmp (dirs[x], part_object) == 0) + { + if (valid_tag (part_tag, tag)) + { + foundline = 1; + + if (listacl || ((acldir || aclfile) && x == intcount) && strcmp(part_tag, tag) == 0) + { + *mline = xstrdup (xline); + *mpos = ftell (accessfp); + } + + if (valid_perm (part_perms, perm)) + { + if (signlevel == x) + { + if (strcmp(part_tag, "ALL") != 0 && !aclconfig_default_used) + retval = 1; + } + else if (!aclconfig_default_used) + { + signlevel = x; + retval = 1; + } + else { + /* nothing... */ + } + } + else + { + if (signlevel == x) + { + if (strcmp(part_tag, "ALL") != 0 && !aclconfig_default_used) + retval = 0; + } + else if (!aclconfig_default_used) + { + signlevel = x; + retval = 0; + + if (strncmp (part_type, "f", 1) == 0) + founddeniedfile = 1; + } + else { + } + } + } + } + } + + if (strncmp (xline, "d:ALL:", 6) == 0 && ((!groupfound && !userfound) || listacl)) + { + /* a default found */ + if (valid_tag (part_tag, tag) > 0) + { + foundline = 1; + + default_part_perms_accessfile = xstrdup (part_perms); + if (valid_perm (part_perms, perm)) + { + + retval = 1; // ams: only if user is in this group + + if (perm == 8 || groupfound) + dadmin = 1; + //break; // ams: without jumping out of this loop admin permissions + // ams: are not honored. + } + else + retval = 0; + + } + + } + + } + + if (fclose (accessfp) == EOF) + error (1, errno, "cannot close 'access' file"); + } + } + + if (!foundline) + { + /* DEFAULT */ + if (valid_perm (NULL, perm)) + retval = 1; + else + retval = 0; + } + + /* acl admin rigths 'p' */ + if (dadmin) + { + retval = dadmin; + } + + cache_retval = retval; + + if (filefullname) free (filefullname); // ams + + /* free directories array */ + while (intcount >= 0) + { + if (dirs[intcount]) free (dirs[intcount]); // ams + intcount--; + } + + return retval; +} + +/* Returns 1 if tag is valid, 0 if not */ +int +valid_tag (char *part_tag, char *tag) +{ + int retval; + char *tag_; + + if (tag == NULL) + tag_ = xstrdup ("HEAD"); + else + tag_ = xstrdup(tag); + + if (strcmp (tag_, part_tag) == 0 || strcmp (part_tag, "ALL") == 0) + retval = 1; + else + retval = 0; + + free(tag_); + return retval; +} + +/* Returns 1 if successful, 0 if not. */ +int +valid_perm (char *part_perms, int perm) +{ + char *perms=NULL; + int retval = 0; + + perms = get_perms (part_perms); + + /* Allow, if nothing found. */ + if (perms[0] == '\0') + return (1); + + /* no access allowed, exit */ + if (strstr (perms, "n")) + retval = 0; + + if (strstr (perms, "p")) + /* admin rights */ + retval = 1; + else if (strstr (perms, "a") && perm != 8) + /* all access allowed, exit */ + retval = 1; + else + switch (perm) + { + case 3:/* write permission */ + if (strstr (perms, "w")) + retval = 1; + break; + case 4:/* tag permission */ + if (strstr (perms, "t")) + retval = 1; + break; + case 5:/* read permission */ + if (strstr (perms, "w") || strstr (perms, "t") || strstr (perms, "c") || + strstr (perms, "d") || strstr (perms, "r")) + retval = 1; + break; + case 6:/* create permission */ + if (strstr (perms, "c")) + retval = 1; + break; + case 7:/* delete permission */ + if (strstr (perms, "d")) + retval = 1; + break; + case 8:/* permission change */ + if (strstr (perms, "p")) + retval = 1; + break; + default:/* never reached */ + retval = 0; + break; + } + + if (perms) free (perms); // ams + + return (retval); +} + +/* returns permissions found */ +char * +get_perms (char *part_perms) +{ + char *username=NULL; + char *xperms=NULL; + // size_t xperms_len = 1; + size_t xperms_len = 2; // must leave space for null termination + + FILE *groupfp; + + char *founduser = NULL; + char *foundall = NULL; + int default_checked = 0; + + aclconfig_default_used = 0; + + xperms = xmalloc (xperms_len); + xperms[0] = '\0'; + + /* use CVS_Username if set */ + if (CVS_Username == NULL) + username = getcaller (); + else + username = CVS_Username; + + /* no defined acl, no default acl in access file, + * or no access file at all */ + if (part_perms == NULL) { + if (config->aclconfig->CVSACLDefaultPermissions) + { + aclconfig_default_used = 1; + //- return (config->aclconfig->CVSACLDefaultPermissions); + if (xperms) free(xperms); + xperms = xstrdup(config->aclconfig->CVSACLDefaultPermissions); + return xperms; + } + else + return xperms; + } + +check_default: + founduser = findusername (part_perms, username); + foundall = strstr (part_perms, "ALL!"); + + if (founduser) + { + char *usr; + char *per; + + usr = strtok (founduser, "!\t"); + per = strtok (NULL, ",\t"); + + if (xperms) free(xperms); + xperms = xstrdup (per); + xperms_len = strlen (xperms); + + userfound = 1; + } + else + { + if (config->aclconfig->UseSystemGroups) { + struct group *griter; + setgrent (); + while (griter = getgrent ()) { + char **users=griter->gr_mem; + int index = 0; + char *userchk = users [index++]; + while(userchk != NULL) { + if(strcmp (userchk, username) == 0) + break; + userchk = users[index++]; + } + if (userchk != NULL) { + char *grp; + if ((grp = findusername (part_perms, griter->gr_name))) { + char *gperm = strtok (grp, "!\t"); + gperm = strtok (NULL, ",\t"); + xrealloc_and_strcat (&xperms, &xperms_len, gperm); + + groupfound = 1; + } + } + } + endgrent (); + } + else if (config->aclconfig->UseCVSGroups) { + groupfp = open_groupfile ("r"); + if (groupfp != NULL) + { + char *line = NULL; + char *grp; + char *gperm; + int read; + + size_t line_allocated = 0; + + while ((read = getline (&line, &line_allocated, groupfp)) >= 0) + { + if (line[0] == '#' || line[0] == '\0' || line[0] == '\n') + continue; + + if (line[read - 1] == '\n') + line[--read] = '\0'; + + if (grp = findusername (part_perms, findgroupname (line, username))) + { + gperm = strtok (grp, "!\t"); + gperm = strtok (NULL, ",\t"); + xrealloc_and_strcat (&xperms, &xperms_len, gperm); + groupfound = 1; + } + } + + if (line) free (line); // ams + + if (fclose (groupfp) == EOF) + error (1, errno, "cannot close 'group' file"); + } + } + } + + if (foundall) + { + char *usr; + char *per; + + usr = strtok (strstr (part_perms, "ALL!"), "!\t"); + per = strtok (NULL, ",\t"); + + if (!default_checked) + default_perms_object = xstrdup (per); + + if (xperms[0] == '\0') + { + if (xperms) free(xperms); + xperms = xstrdup (per); + xperms_len = strlen (xperms); + } + + // ams: these come from strtok()/strstr() --- do not deallocate + // free(foundall); + // free(usr); + // free(per); + } + + if (xperms[0] == '\0' && !default_checked && default_part_perms_accessfile) + { + part_perms = xstrdup (default_part_perms_accessfile); + default_checked = 1; + + goto check_default; + } + + if (xperms[0] != '\0' && strcmp (xperms, "x") == 0) + { + if (default_perms_object) { + if (xperms) free(xperms); + xperms = xstrdup (default_perms_object); + } + else if (default_part_perms_accessfile) + { + part_perms = default_part_perms_accessfile; + default_checked = 1; + goto check_default; + } + else if (config->aclconfig->CVSACLDefaultPermissions) + { + aclconfig_default_used = 1; + if (xperms) free(xperms); + xperms = xstrdup (config->aclconfig->CVSACLDefaultPermissions); + } + } + + if (xperms[0] == '\0' && config->aclconfig->CVSACLDefaultPermissions) + { + aclconfig_default_used = 1; + if (xperms) free(xperms); + xperms = xstrdup (config->aclconfig->CVSACLDefaultPermissions); + } + + return xperms; +} + + +int +cvsacl (int argc, char **argv) +{ + char *chdirrepository; + int c; + int err = 0; + int usetag = 0; + int recursive = 0; + + int which; + char *where; + + is_racl = (strcmp (cvs_cmd_name, "racl") == 0); + + if (argc == -1) + usage (is_racl ? racl_usage : acl_usage); + + /* parse the args */ + optind = 0; + + while ((c = getopt (argc, argv, "Rr:l")) != -1) + { + switch (c) + { + case 'R': + recursive = 1; + break; + case 'r': // baris + tag = xstrdup (optarg); + break; + case 'l': + listacl = 1; + break; + case '?': + default: + usage (is_racl ? racl_usage : acl_usage); + break; + } + } + + argc -= optind; + argv += optind; + + if (listacl) + if ( argv[0] ) // ams: to prevent segfaults + { if (strstr (argv[0], ":")) + usage (is_racl ? racl_usage : acl_usage); } + if (!listacl) + if ( argv[0] ) // ams: to prevent segfaults + { if (!strstr (argv[0], ":")) + usage (is_racl ? racl_usage : acl_usage); } + + if (argc < (is_racl ? 1 : 1)) + usage (is_racl ? racl_usage : acl_usage); + +#ifdef CLIENT_SUPPORT + + if (current_parsed_root->isremote) + { + start_server (); + ign_setup (); + + if(recursive) + send_arg ("-R"); + + if (listacl) + send_arg ("-l"); + + if(tag) + { + option_with_arg ("-r", tag); + } + + send_arg ("--"); + + if (!listacl) + { + send_arg (argv[0]); + + argc--; + argv++; + } + + if (is_racl) + { + int i; + for (i = 0; i < argc; ++i) + send_arg (argv[i]); + + send_to_server ("racl\012",0); + } + else + { + send_files (argc, argv, recursive, 0, SEND_NO_CONTENTS); + send_file_names (argc, argv, SEND_EXPAND_WILD); + send_to_server ("acl\012", 0); + } + + return get_responses_and_close (); + } +#endif + +#ifdef SERVER_SUPPORT + + if (!listacl) + { + muser = strtok (argv[0], ":\t"); + mperms = strtok (NULL, ":\t"); + + /* if set to 'default' */ + if ((strlen (mperms) == 7) && (strncmp (mperms, "default", 7) == 0)) + mperms = xstrdup ("x"); + + /* Check that the given permissions are valid. */ + if (!given_perms_valid (mperms)) + error (1,0,"Invalid permissions: `%s'", mperms); + + argc--; + argv++; + } + + + if (!tag) + tag = xstrdup ("HEAD"); + + if (!strcasecmp (argv[0], "ALL")) + { + argv[0] = xstrdup ("."); + defaultperms = 1; + if (!config->aclconfig->UseSeparateACLFileForEachDir) + { + recursive = 0; + } + + } + + if (is_racl) + { + DBM *db; + int i; + db = open_module (); + for (i = 0; i < argc; i++) + { + err += do_module (db, argv[i], MISC, "ACL ing: ", + racl_proc, NULL, 0, !recursive, 0, + 0, NULL); + } + close_module (db); + } + else + { + err = racl_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, !recursive, NULL, + NULL); + } + + return err; + +#endif +} + +static int +racl_proc (int argc, char **argv, char *xwhere, char *mwhere, + char *mfile, int shorten, int local, char *mname, char *msg) +{ + char *myargv[2]; + int err = 0; + int which; + char *repository = NULL; + char *where; + char *obj; + size_t objlen = 0; + + if (!config->aclconfig->UseCVSACL)//baris + { + error(1, 0, "CVSACL extension is not enabled, set `UseCVSACL=yes' in aclconfig file"); + } + + if (is_racl) + { + repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) + + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); + + (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); + where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + + 1); + (void) strcpy (where, argv[0]); + + /* if mfile isn't null, we need to set up to do only part of the module */ + if (mfile != NULL) + { + char *cp; + char *path; + + /* if the portion of the module is a path, put the dir part on repos */ + if ((cp = strrchr (mfile, '/')) != NULL) + { + *cp = '\0'; + (void) strcat (repository, "/"); + (void) strcat (repository, mfile); + (void) strcat (where, "/"); + (void) strcat (where, mfile); + mfile = cp + 1; + } + + /* take care of the rest */ + path = xmalloc (strlen (repository) + strlen (mfile) + 5); + (void) sprintf (path, "%s/%s", repository, mfile); + if (isdir (path)) + { + /* directory means repository gets the dir tacked on */ + (void) strcpy (repository, path); + (void) strcat (where, "/"); + (void) strcat (where, mfile); + } + else + { + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; + } + if (path) free (path); // ams + } + + /* cd to the starting repository */ + if ( CVS_CHDIR (repository) < 0) + { + error (0, errno, "cannot chdir to %s", repository); + if (repository) free (repository); // ams + if (where) free (where); // ams + return 1; + } + + /* End section which is identical to patch_proc. */ + + which = W_REPOS | W_ATTIC; + + if (argc > 1) + { +/* xrealloc_and_strcat (&obj, &objlen, repository); + xrealloc_and_strcat (&obj, &objlen, "/"); + xrealloc_and_strcat (&obj, &objlen, argv[1]); + xrealloc_and_strcat (&obj, &objlen, ",v"); +*/ + obj = xmalloc (strlen (repository) + 1 + strlen (argv[1])); + (void) sprintf (obj, "%s/%s", repository, argv[1]); + } + else + { +/* xrealloc_and_strcat (&obj, &objlen, repository); + xrealloc_and_strcat (&obj, &objlen, ",v"); + obj = xmalloc (strlen (repository) + 2); + (void) sprintf (obj, "%s,v", repository); +*/ + obj = xstrdup(repository); + } + } + else + { + where = NULL; + which = W_LOCAL | W_REPOS | W_ATTIC; + + obj = xstrdup (argv[1]); + } + + if (isdir (obj)) + acldir = 1; + else if (isfile (obj)) + aclfile = 1; + else + error(1, 0, "no such file or directory"); + + if (obj) free (obj); // ams + + if (listacl) + err = start_recursion (acllist_fileproc, NULL, acllist_dirproc, NULL, NULL, + argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1, + repository); + else + err = start_recursion (acl_fileproc, NULL, acl_dirproc, NULL, NULL, + argc - 1, argv + 1, local, which, 0, 0, (char *) where, 1, + repository); + + if (repository != NULL) + free (repository); + + return err; +} + + +static int +acl_fileproc (void *callerdat, struct file_info *finfo) +{ + char *filefullname; + char *founduserpart = NULL; + char *otheruserparts = NULL; + size_t otherslen = 0; + + const char *frepository; + int foundline = 0; + + char *line = NULL; + size_t line_allocated = 0; + int linelen; + + char *wperms; + char *errmsg; + + int pos; + + if (!aclfile) + return 0; + + frepository = Short_Repository (finfo->repository); + + filefullname = xmalloc (strlen (frepository) + + strlen (finfo->file) + + 2); + strcpy (filefullname, frepository); + strcat (filefullname, "/"); + strcat (filefullname, finfo->file); + + + if (!access_allowed (finfo->file, finfo->repository, tag, 8, &line, &pos, 0)) + error (1,0,"You do not have acl admin rights on '%s'", frepository); + + if (line != NULL) + { + char *part_type = NULL; + char *part_object = NULL; + char *part_tag = NULL; + char *part_perms = NULL; + char *userpart; + + part_type = strtok (line, ":\t"); + part_object = strtok (NULL, ":\t"); + part_tag = strtok (NULL, ":\t"); + part_perms = strtok (NULL, ":\t"); + + foundline = 1; + userpart = strtok (part_perms, ",\t"); + + do + { + if (strncmp (userpart, muser, strlen (muser)) == 0) + founduserpart = xstrdup (userpart); + else + { + if (otheruserparts != NULL) + { + xrealloc_and_strcat (&otheruserparts, &otherslen, ","); + xrealloc_and_strcat (&otheruserparts, &otherslen, userpart); + } + else + { + otheruserparts = xstrdup (userpart); + otherslen = strlen (otheruserparts); + } + } + } while ((userpart = strtok (NULL, ",\t")) != NULL); + + // free (userpart); // ams: do not deallocated output of strtok() + } + + wperms = make_perms (mperms, founduserpart, &errmsg); + if (wperms == NULL) + { + if (errmsg) + error (0, 0, "`%s' %s", filefullname, errmsg); + } + else + { + cvs_output ("X ", 0); + cvs_output (filefullname, 0); + cvs_output ("\n", 0); + + write_perms (muser, wperms, founduserpart, foundline, + otheruserparts, "f", filefullname, tag, pos, Short_Repository(finfo->repository)); + } + + if (line) free (line); // ams + if (founduserpart) free (founduserpart); // ams + if (otheruserparts) free (otheruserparts); // ams + if (wperms) free (wperms); // ams + if (filefullname) free (filefullname); // ams + + return 0; +} + +static Dtype +acl_dirproc (void *callerdat, const char *dir, const char *repos, + const char *update_dir, List *entries) +{ + const char *drepository; + char *founduserpart = NULL; + char *otheruserparts = NULL; + size_t otherslen = 0; + int foundline = 0; + + char *line = NULL; + size_t line_allocated = 0; + int linelen; + + int pos; + + char *wperms; + char *errmsg; + + if (!acldir) + return 0; + + if (repos[0] == '\0') + repos = Name_Repository (dir, NULL); + + if (!access_allowed (NULL, repos, tag, 8, &line, &pos, 0)) + error (1,0,"You do not have admin rights on '%s'", Short_Repository (repos)); + + drepository = Short_Repository (repos); + + if (line != NULL) + { + char *part_type = NULL; + char *part_object = NULL; + char *part_tag = NULL; + char *part_perms = NULL; + char *userpart; + + part_type = strtok (line, ":\t"); + part_object = strtok (NULL, ":\t"); + part_tag = strtok (NULL, ":\t"); + part_perms = strtok (NULL, ":\t"); + + foundline = 1; + userpart = strtok (part_perms, ",\t"); + + do + { + if (strncmp (userpart, muser, strlen (muser)) == 0) + founduserpart = xstrdup (userpart); + else + { + if (otheruserparts != NULL) + { + xrealloc_and_strcat (&otheruserparts, &otherslen, ","); + xrealloc_and_strcat (&otheruserparts, &otherslen, userpart); + } + else + { + otheruserparts = xstrdup (userpart); + otherslen = strlen (otheruserparts); + } + } + } while ((userpart = strtok (NULL, ",\t")) != NULL); + } + + wperms = make_perms (mperms, founduserpart, &errmsg); + if (wperms == NULL) + { + if (errmsg) + error (0, 0, "`%s' %s", drepository, errmsg); + } + else + { + if (defaultperms) + { + cvs_output ("X ", 0); + cvs_output ("ALL", 0); + cvs_output ("\n", 0); + write_perms (muser, wperms, founduserpart, foundline, + otheruserparts, "d", "ALL", tag, pos, drepository); + + } + else + { + cvs_output ("X ", 0); + cvs_output (drepository, 0); + cvs_output ("\n", 0); + write_perms (muser, wperms, founduserpart, foundline, + otheruserparts, "d", drepository, tag, pos, drepository); + } + } + + if (line) free (line); // ams + if (founduserpart) free (founduserpart); // ams + if (otheruserparts) free (otheruserparts); // ams + if (wperms) free (wperms); // ams + + return 0; +} + +/* Open CVSROOT/access or defined CVSACLFileLocation file + * Open access file In each directory if UseSeparateACLFileForEachDir=yes + * returns file pointer to access file or NULL if access file not found */ +FILE * +open_accessfile (char *fmode, const char *adir, char **fname) +{ + char *accessfile = NULL; + FILE *accessfp; + + if (!config->aclconfig->UseSeparateACLFileForEachDir) + { + if (config->aclconfig->CVSACLFileLocation == NULL) + { + accessfile = xmalloc (strlen (current_parsed_root->directory) + + sizeof (CVSROOTADM) + + sizeof (CVSROOTADM_ACCESS) + + 3); + + strcpy (accessfile, current_parsed_root->directory); + strcat (accessfile, "/"); + strcat (accessfile, CVSROOTADM); + strcat (accessfile, "/"); + strcat (accessfile, CVSROOTADM_ACCESS); + } + else + { + accessfile = xstrdup(config->aclconfig->CVSACLFileLocation); + } + } + else + { + size_t accessfilelen = 0; + xrealloc_and_strcat (&accessfile, &accessfilelen, current_parsed_root->directory); + xrealloc_and_strcat (&accessfile, &accessfilelen, "/"); + xrealloc_and_strcat (&accessfile, &accessfilelen, adir); + xrealloc_and_strcat (&accessfile, &accessfilelen, "/access"); + } + + accessfp = CVS_FOPEN (accessfile, fmode); + + if (accessfp == NULL && !config->aclconfig->DontPrintFileCantOpenWarnings) + error (0, 0, "cannot open file: %s", accessfile); + + if (fname != NULL) + *fname = xstrdup (accessfile); + + if (accessfile) free (accessfile); // ams + + return accessfp; +} + +/* Open /etc/group file if UseSystemGroups=yes in config file + * Open CVSROOT/group file if UseCVSGroups=yes in config file + * Open group file if specified in CVSGroupsFileLocation + * returns group file pointer if UseSystemGroups=yes + * returns NULL if UseSystemGroups=no or group file not found */ +FILE * +open_groupfile (char *fmode) +{ + char *groupfile = NULL; + FILE *groupfp; + + if (config->aclconfig->UseCVSGroups) + { + if (config->aclconfig->CVSGroupsFileLocation != NULL) + { + groupfile = xmalloc (strlen (config->aclconfig->CVSGroupsFileLocation)); + strcpy (groupfile, config->aclconfig->CVSGroupsFileLocation); + } + else + { + groupfile = xmalloc (strlen (current_parsed_root->directory) + + sizeof (CVSROOTADM) + + sizeof (CVSROOTADM_GROUP) + + 3); + + strcpy (groupfile, current_parsed_root->directory); + strcat (groupfile, "/"); + strcat (groupfile, CVSROOTADM); + strcat (groupfile, "/"); + strcat (groupfile, CVSROOTADM_GROUP); + } + } + else + { + return NULL; + } + + groupfp = CVS_FOPEN (groupfile, "r"); + + if (groupfp == NULL) + error (0, 0, "cannot open file: %s", groupfile); + + if (groupfile) free (groupfile); // ams + + return groupfp; +} + + +/* Check whether given permissions are valid or not + * Returns 1 if permissions are valid + * Returns 0 if permissions are NOT valid */ +int +given_perms_valid (const char *cperms) +{ + int cperms_len; + int retval; + int index, i; + + if (cperms[0] == '+' || cperms[0] == '-') + index = 1; + else + index = 0; + + cperms_len = strlen (cperms); + + switch (cperms[index]) + { + case 'x': + if ((cperms_len - index) == 1 && cperms_len == 1) + retval = 1; + else + retval = 0; + break; + case 'n': + if ((cperms_len - index) == 1 && cperms_len == 1) + retval = 1; + else + retval = 0; + break; + case 'p': + if ((cperms_len - index) == 1) + retval = 1; + else + retval = 0; + break; + case 'a': + if ((cperms_len - index) == 1) + retval = 1; + else + retval = 0; + break; + case 'r': + if ((cperms_len - index) == 1) + retval = 1; + else + retval = 0; + break; + case 'w': + if ((cperms_len - index) == 1) + retval = 1; + else + for (i = index + 1; i < cperms_len; i++) + if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd') + retval = 1; + else + retval = 0; + break; + case 't': + if ((cperms_len - index) == 1) + retval = 1; + else + for (i = index + 1; i < cperms_len; i++) + if (cperms[i] == 'w' || cperms[i] == 'c' || cperms[i] == 'd') + retval = 1; + else + retval = 0; + break; + case 'c': + if ((cperms_len - index) == 1) + retval = 1; + else + for (i = index + 1; i < cperms_len; i++) + if (cperms[i] == 't' || cperms[i] == 'w' || cperms[i] == 'd') + retval = 1; + else + retval = 0; + break; + case 'd': + if ((cperms_len - index) == 1) + retval = 1; + else + for (i = index + 1; i < cperms_len; i++) + if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'w') + retval = 1; + else + retval = 0; + break; + default: + retval = 0; + break; + } + + return retval; +} + +/* prepare permsissions string to be written to access file + * returns permissions or NULL if */ +char * +make_perms (char *perms, char *founduserpart, char **xerrmsg) +{ + char *fperms = NULL; + size_t perms_len; + size_t fperms_len; + + int i, j; + int err = 0; + char *errmsg = NULL; + + char *retperms = NULL; + size_t retperms_len = 1; + + retperms = xmalloc (retperms_len); + retperms[0] = '\0'; + + perms_len = strlen (perms); + + if (perms[0] == '+' || perms[0] == '-') + { + if (founduserpart) + { + char *tempfperms; + size_t tempfperms_len; + + char *temp; + int per = 0; + temp = strtok (founduserpart, "!\t"); + fperms = strtok (NULL, "!\t"); + fperms_len = strlen (fperms); + + if (strncmp (fperms, "x", 1) == 0) + { + err = 1; + if (perms[0] == '+') + *xerrmsg = xstrdup ("cannot add default permission 'x'"); + else + *xerrmsg = xstrdup ("cannot remove default permission 'x'"); + } + + /* go through perms */ + for (i = 1; i < perms_len && !err; i++) + { + switch (perms[i]) + { + case 'n': + err = 1; + break; + case 'p': + if (perms[0] == '+') + fperms = xstrdup ("p"); + else if (perms[0] == '-') + { + fperms_len = 1; + fperms = xmalloc (fperms_len); + fperms[0] = '\0'; + } + break; + case 'a': + for (j = 0; j < fperms_len; j++) + { + if (fperms[j] == 'p') + { + err = 1; + *xerrmsg = xstrdup ("user have admin rights, cannot use +/- permissions"); + } + else if (fperms[j] == 'a' && perms[0] == '+') + { + err = 1; + *xerrmsg = xstrdup ("user already has all ('a') permission"); + } + else if (fperms[j] != 'a' && perms[0] == '-') + { + err = 1; + *xerrmsg = xstrdup ("user does not have all ('a') permission"); + } + } + if (perms[0] == '+') + { + fperms = xstrdup ("a"); + fperms_len = strlen (fperms); + } + else if (perms[0] == '-') + { + fperms_len = 1; + fperms = xmalloc (fperms_len); + fperms[0] = '\0'; + } + + break; + case 'r': + for (i = 0; i < fperms_len; i++) + { + if (fperms[i] == 'n' && perms[0] == '+') + { + fperms = xstrdup ("r"); + fperms_len = strlen (fperms); + } + else if (fperms[i] == 'r' && perms[0] == '-') + { + fperms_len = 1; + fperms = xmalloc (fperms_len); + fperms[0] = '\0'; + } + else if (perms[0] == '-') + { + err = 1; + *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission"); + } + else + { + err = 1; + *xerrmsg = xstrdup ("user has other permissions, cannot remove read ('r') permission"); + } + } + break; + case 'w': + { + tempfperms_len = 1; + + tempfperms = xmalloc (tempfperms_len); + tempfperms[0] = '\0'; + + for (j = 0; j < fperms_len; j++) + { + if (fperms[j] == 't' || fperms[j] == 'c' || fperms[j] == 'd') + { + char *temp; + temp = xmalloc (2); + temp[0] = fperms[j]; + temp[1] = '\0'; + + xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp); + if (temp) free (temp); // ams + } + else if (fperms[j] == 'a' || fperms[j] == 'p') + { + err = 1; + *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- write permissions"); + } + else if (fperms[j] == 'n' || fperms[j] == 'r') + { + if (perms[0] == '-') + { + err = 1; + *xerrmsg = xstrdup ("user does not have write ('w') permission"); + } + } + else if (fperms[j] == 'w') + { + per = 1; + if (perms[0] == '+') { + err = 1; + *xerrmsg = xstrdup ("user already have write ('w') permission"); + } + } + } + + fperms = xstrdup (tempfperms); + fperms_len = strlen (fperms); + if (tempfperms) free (tempfperms); // ams + + if (!per && !err && (perms[0] == '-')) { + err = 1; + *xerrmsg = xstrdup ("user does not have write ('w') permission"); + } + + if (perms[0] == '+') + { + xrealloc_and_strcat (&fperms, &fperms_len, "w"); + } + } + break; + case 't': + { + tempfperms_len = 1; + + tempfperms = xmalloc (tempfperms_len); + tempfperms[0] = '\0'; + + for (j = 0; j < fperms_len; j++) + { + if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 'd') + { + char *temp; + temp = xmalloc (2); + temp[0] = fperms[j]; + temp[1] = '\0'; + + xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp); + if (temp) free (temp); // ams + } + else if (fperms[j] == 'a' || fperms[j] == 'p') + { + err = 1; + *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- tag permissions"); + } + else if (fperms[j] == 'n' || fperms[i] == 'r') + { + if (perms[0] == '-') + *xerrmsg = xstrdup ("user does not have tag ('t') permission"); + } + else if (fperms[j] == 't') + { + per = 1; + if (perms[0] == '+') { + err = 1; + *xerrmsg = xstrdup ("user already have tag ('t') permission"); + } + } + } + + fperms = xstrdup (tempfperms); + fperms_len = strlen (fperms); + if (tempfperms) free (tempfperms); // ams + + if (!per && !err && (perms[0] == '-')) { + err = 1; + *xerrmsg = xstrdup ("user does not have tag ('t') permission"); + } + + if (perms[0] == '+') + { + xrealloc_and_strcat (&fperms, &fperms_len, "t"); + } + } + break; + case 'c': + { + tempfperms_len = 1; + + tempfperms = xmalloc (tempfperms_len); + tempfperms[0] = '\0'; + + for (j = 0; j < fperms_len; j++) + { + if (fperms[j] == 'w' || fperms[j] == 't' || fperms[j] == 'd') + { + char *temp; + temp = xmalloc (2); + temp[0] = fperms[j]; + temp[1] = '\0'; + + xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp); + if (temp) free (temp); // ams + } + else if (fperms[j] == 'a' || fperms[j] == 'p') + { + err = 1; + *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- create permissions"); + } + else if (fperms[j] == 'n' || fperms[i] == 'r') + { + if (perms[0] == '-') + err = 1; + *xerrmsg = xstrdup ("user does not have create ('c') permission"); + } + else if (fperms[j] == 'c') + { + per = 1; + if (perms[0] == '+') { + err = 1; + *xerrmsg = xstrdup ("user already have create ('c') permission"); + } + } + } + + fperms = xstrdup (tempfperms); + fperms_len = strlen (fperms); + if (tempfperms) free (tempfperms); // ams + + if (!per && !err && (perms[0] == '-')) { + err = 1; + *xerrmsg = xstrdup ("user does not have create ('c') permission"); + } + + if (perms[0] == '+') + { + xrealloc_and_strcat (&fperms, &fperms_len, "c"); + } + } + break; + case 'd': + { + tempfperms_len = 1; + + tempfperms = xmalloc (tempfperms_len); + tempfperms[0] = '\0'; + + for (j = 0; j < fperms_len; j++) + { + if (fperms[j] == 'w' || fperms[j] == 'c' || fperms[j] == 't') + { + char *temp; + temp = xmalloc (2); + temp[0] = fperms[j]; + temp[1] = '\0'; + + xrealloc_and_strcat (&tempfperms, &tempfperms_len, temp); + if (temp) free (temp); // ams + } + else if (fperms[j] == 'a' || fperms[j] == 'p') + { + err = 1; + *xerrmsg = xstrdup ("user has higher permissions, cannot use +/- delete permissions"); + } + else if (fperms[j] == 'n' || fperms[i] == 'r') + { + if (perms[0] == '-') + err = 1; + *xerrmsg = xstrdup ("user does not have delete ('d') permission"); + } + else if (fperms[j] == 'd') + { + per = 1; + if (perms[0] == '+') { + err = 1; + *xerrmsg = xstrdup ("user already have delete ('d') permission"); + } + } + } + + fperms = xstrdup (tempfperms); + fperms_len = strlen (fperms); + if (tempfperms) free (tempfperms); // ams + + if (!per && !err && (perms[0] == '-')) { + err = 1; + *xerrmsg = xstrdup ("user does not have delete ('d') permission"); + } + + if (perms[0] == '+') + { + xrealloc_and_strcat (&fperms, &fperms_len, "d"); + } + } + break; + default: + err = 1; + *xerrmsg = xstrdup ("error in 'access' file format"); + break; + } + + if (fperms[0] == '\0') + retperms = xstrdup ("none"); + else + retperms = xstrdup (fperms); + } + } + else + { + err = 1; + *xerrmsg = xstrdup("user is not given any permissions to remove/add"); + } + } + else + { + retperms = xstrdup (perms); + } + + return (err ? NULL : retperms); +} + +/* prepare and write resulting permissions to access file */ +int +write_perms (char *user, char *perms, char *founduserpart, char *foundline, + char *otheruserparts, char *part_type, char *part_object, char *part_tag, + int pos, char *arepos) +{ + char *accessfile = NULL; + char *tmpaccessout = NULL; + FILE *accessfpin; + FILE *accessfpout; + + char *newline = NULL; + size_t newlinelen = 1; + + char *line = NULL; + size_t line_allocated = 0; + + newline = xmalloc (newlinelen); + newline[0] = '\0'; + + if (!strcasecmp (part_tag, "ALL")) + part_tag = xstrdup ("ALL"); + + /* strip any trailing slash if found */ + if (part_object[strlen (part_object) - 1] == '/') + part_object[strlen (part_object) - 1] = '\0'; + + /* first parts, part type, object, and tag */ + xrealloc_and_strcat (&newline, &newlinelen, part_type); + xrealloc_and_strcat (&newline, &newlinelen, ":"); + xrealloc_and_strcat (&newline, &newlinelen, part_object); + xrealloc_and_strcat (&newline, &newlinelen, ":"); + xrealloc_and_strcat (&newline, &newlinelen, part_tag); + xrealloc_and_strcat (&newline, &newlinelen, ":"); + + if (strncmp (perms, "none", 4) != 0) + { + xrealloc_and_strcat (&newline, &newlinelen, user); + xrealloc_and_strcat (&newline, &newlinelen, "!"); + xrealloc_and_strcat (&newline, &newlinelen, perms); + if (otheruserparts != NULL) + xrealloc_and_strcat (&newline, &newlinelen, ","); + } + + if (otheruserparts != NULL) + { + if (otheruserparts[strlen (otheruserparts) - 1] == '\n') + otheruserparts[strlen (otheruserparts) - 1] = '\0'; + + xrealloc_and_strcat (&newline, &newlinelen, otheruserparts); + } + + xrealloc_and_strcat (&newline, &newlinelen, ":"); + + if (foundline) + { + accessfpout = cvs_temp_file (&tmpaccessout); + accessfpin = open_accessfile ("r", arepos, &accessfile); + + while (getline (&line, &line_allocated, accessfpin) >= 0) + { + if (pos != ftell (accessfpin)) + { + if (fprintf (accessfpout, line) < 0) + error (1, errno, "writing temporary file: %s", tmpaccessout); + } + else + { + if (fprintf (accessfpout, "%s\n", newline) < 0) + error (1, errno, "writing temporary file: %s", tmpaccessout); + } + + } + if (fclose (accessfpin) == EOF) + error (1, errno, "cannot close access file: %s", accessfile); + + if (fclose (accessfpout) == EOF) + error (1, errno, "cannot close temporary file: %s", tmpaccessout); + + if (CVS_UNLINK (accessfile) < 0) + error (0, errno, "cannot remove %s", accessfile); + + copy_file (tmpaccessout, accessfile); + + if (CVS_UNLINK (tmpaccessout) < 0) + error (0, errno, "cannot remove temporary file: %s", tmpaccessout); + } + else + { + accessfpout = open_accessfile ("r+", arepos, &accessfile); + + if (accessfpout == NULL) + { + if (existence_error (errno)) + { + accessfpout = open_accessfile ("w+", arepos, &accessfile); + } + } + else { + if (fseek (accessfpout, 0, 2) != 0) + error (1, errno, "cannot fseek access file: %s", accessfile); + } + + if (fprintf (accessfpout, "%s\n", newline) < 0) + error (1, errno, "writing access file: %s", accessfile); + + if (fclose (accessfpout) == EOF) + error (1, errno, "cannot close access file: %s", accessfile); + } + + if (line) free (line); // ams + if (newline) free (newline); // ams + + chmod (accessfile, 0644); + + return 0; +} + +static int +acllist_fileproc (void *callerdat, struct file_info *finfo) +{ + + char *filefullname = NULL; + const char *frepository; + char *line = NULL; + int pos; + + if (!aclfile) + return 0; + + frepository = Short_Repository (finfo->repository); + + filefullname = xmalloc (strlen (frepository) + + strlen (finfo->file) + + 2); + strcpy (filefullname, frepository); + strcat (filefullname, "/"); + strcat (filefullname, finfo->file); + + /* check that user, which run acl/racl command, has admin permisson, + * and also return the line with permissions from access file. */ + if (!access_allowed (finfo->file, finfo->repository, tag, 5, &line, &pos, 0)) + error (1,0,"You do not have admin rights on '%s'", frepository); + + acllist_print (line, filefullname); + + if (filefullname) free (filefullname); // ams + + return 0; +} + +static Dtype +acllist_dirproc (void *callerdat, const char *dir, const char *repos, + const char *update_dir, List *entries) +{ + char *line = NULL; + const char *drepository; + int pos; + + if (repos[0] == '\0') + repos = Name_Repository (dir, NULL); + + if (!acldir) + return 0; + + drepository = Short_Repository (repos); + + /* check that user, which run acl/racl command, has admin permisson, + * and also return the line with permissions from access file. */ + if (!access_allowed (NULL, repos, tag, 5, &line, &pos, 0)) + error (1, 0, "You do not have admin rights on '%s'", drepository); + + acllist_print (line, drepository); + + return 0; +} + +/* Prints permissions to screen with -l option */ +void +acllist_print (char *line, const char *obj) +{ + char *temp = NULL; + int c = 0; + int def = 0; + + char *printedusers[255]; + printedusers[0] = NULL; + + if (line != NULL) + { + temp = strtok (line, ":\t"); + + if (acldir) + cvs_output ("d ", 0); + else if (aclfile) + cvs_output ("f ", 0); + + temp = strtok (NULL, ":\t"); + + cvs_output(obj, 0); + cvs_output (" | ", 0); + + temp = strtok (NULL, ":\t"); + cvs_output (temp, 0); + cvs_output (" | ", 0); + + while ((temp = strtok (NULL, "!\t")) != NULL) + { + if (strncmp (temp, ":", 1) == 0) + break; + + if (strcmp (temp, "ALL") == 0) + { + temp = strtok (NULL, ",\t"); + continue; + } + + cvs_output ... [truncated message content] |