[Cvs-nserver-commits] CVS: cvs-nserver/src racl.c,1.1.2.5,1.1.2.6
Brought to you by:
tyranny
From: Alexey M. <mo...@us...> - 2002-06-13 13:44:42
|
Update of /cvsroot/cvs-nserver/cvs-nserver/src In directory usw-pr-cvs1:/tmp/cvs-serv18537/src Modified Files: Tag: NCLI-1-11-1 racl.c Log Message: Dir/Branch management (old semantics) implemented for racl subcommand Index: racl.c =================================================================== RCS file: /cvsroot/cvs-nserver/cvs-nserver/src/Attic/racl.c,v retrieving revision 1.1.2.5 retrieving revision 1.1.2.6 diff -u -d -r1.1.2.5 -r1.1.2.6 --- racl.c 25 May 2002 20:57:03 -0000 1.1.2.5 +++ racl.c 13 Jun 2002 13:44:33 -0000 1.1.2.6 @@ -9,7 +9,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - Copyright (c) Alexey Mahotkin <al...@hs...> 2001 + Copyright (c) Alexey Mahotkin <al...@hs...> 2001-2002 + Alexey Morozov <mo...@no...>, + Novosoft, Inc, 2002 "cvs racl" subcommand manages ACL directly to repository @@ -21,16 +23,21 @@ #include "acl.h" #include "acl-admins.h" +#include "default-file-acl.h" #include "module-acl.h" #include "repository.h" +#include "audit-log.h" +#include "recurse.h" +#ifdef HAVE_ERRNO_H #include <errno.h> +#endif #include <stdlib.h> static const char *const racl_usage[] = { - "Usage: cvs racl [-r BRANCH] [grant|revoke] USER PERMISSION modules...\n", + "Usage: cvs racl [-r BRANCH] [-t] [grant|revoke] USER PERMISSION modules...\n", "\tPERMISSION could be one of those:\n", "\t\ttag\t\tAllow creating tags\n", "\t\ttag:PREFIX\tAllow tags whose names start with PREFIX\n", @@ -39,27 +46,371 @@ NULL }; +static const char *branch = "trunk"; + + #ifdef SERVER_SUPPORT static void +tag_module_racl(int argc, char **argv, char *username, + char *prefix, int isgrant, int isbranch) +{ + struct REPOSITORY *repos; + + repos = get_repository(current_parsed_root->directory); + + while (*argv) { + char *module = *argv; + struct MODULE_ACL *mod_acl = get_module_acl(repos, module); + + if (isgrant) { + if (!grant_module_tagging(mod_acl, username, prefix)) + error(1, errno, "Error granting tag permission to %s for %s", + username, module); + } else { + if (!revoke_module_tagging(mod_acl, username, prefix)) + error(1, errno, "Error revoking tag permission to %s for %s", + username, module); + } + argv++; + argc--; + } + + if (!save_module_acl(repos)) + error(1, errno, "Error saving module ACLS: %s", strerror(errno)); + free_repository(repos); +} + +static dir_permission dir_perm = dir_perm_invalid; +static branch_permission branch_perm = branch_perm_invalid; +static int is_set_default_file_acl = 0; +static int error_counter = 0; + +static Dtype +access_dirproc (username, dir, repository, update_dir, entries) + void *username; + char *dir; + char *repository; + char *update_dir; + List *entries; +{ + DIR_ACL *dir_acl = NULL; + + if ((dir_acl = get_dir_acl(repository, branch))==NULL) { + error(0, errno, "Error getting Dir ACL for %s", repository); + error_counter++; + return R_PROCESS; + }; + + if (is_set_default_file_acl) { + /* BUG BUG BUG... We shouldn't check if resulting permission + * is exactly requested permission + */ + if ((set_default_file_acl(dir_acl, branch, (char*)username, branch_perm) != branch_perm)) { + error(0, 0, "Error setting default file permission '%s' for '%s' on directory %s", + branch_permissions_string(branch_perm), (char*)username, update_dir); + error_counter++; + goto out; + } + error(0, 0, "Setting default file permissions '%s' for '%s' on directory %s\n", + branch_permissions_string(branch_perm),(char*)username, update_dir); + } + else { + /* Just in case we was asked to change only file permissions */ + if (dir_perm == dir_perm_invalid) + goto out; + + /* BUG BUG BUG (the same as above. I should consult Alex */ + if (set_dir_ace(dir_acl, username, dir_perm) != dir_perm) { + error(0, 0, "Error setting '%s' permissions for '%s' on directory %s", + dir_permissions_string(dir_perm), (char*)username, update_dir); + error_counter++; + goto out; + } + error(0, 0, "Setting '%s' permissions for '%s' on directory %s\n", + dir_permissions_string(dir_perm), (char*)username, update_dir); + } + if (store_dir_acl(dir_acl) != 0) { + error(0, 0, "Error storing permissions on directory %s", update_dir); + goto out; + } + + /* log this operation */ + if (audit_log_active()) { + if (!start_audit_log_line("racl")) { + error(1, 0, "Out of memory"); + } + append_audit_log_line("grant"); + if (is_set_default_file_acl) { + append_audit_log_line("default-file"); + append_audit_log_line(branch_permissions_string(branch_perm)); + } else { + append_audit_log_line("dir"); + append_audit_log_line(dir_permissions_string(dir_perm)); + } + append_audit_log_line(update_dir); + append_audit_log_line((char*)username); + append_audit_log_line(branch); + log_audit_event(); + } + out: + destroy_dir_acl(dir_acl); + return R_PROCESS; +} + + +static int +access_fileproc (void *username, struct file_info *finfo) +{ + struct DIR_ACL *dir_acl = NULL; + struct BRANCH_ACL *branch_acl = NULL; + struct BRANCH_ACE *branch_ace = NULL; + int err = 0; + + dir_acl = get_dir_acl(finfo->repository, "trunk"); + if (dir_acl == NULL) { + error(0, errno, + "Error getting directory ACL for %s", finfo->update_dir); + return 1; + } + + branch_acl = get_branch_acl(dir_acl, branch); + if (branch_acl == NULL) { + error(0, errno, "Error getting branch ACL for %s", finfo->update_dir); + err = 1; + goto err; + } + + branch_ace = get_file_on_branch_ace(branch_acl, finfo->file); + if (branch_ace == NULL) { + error(0, errno, "Error getting file ACE for %s",finfo->fullname); + err = 1; + goto err; + } + + set_branch_ace(branch_ace, (char*)username, branch_perm); + + if (!store_branch_acls(dir_acl)) { + error(0, errno, "Error storing branch ACLs for %s",finfo->update_dir); + err = 1; + goto err; + } + + /* log this operation */ + if (audit_log_active()) { + if (!start_audit_log_line("racl")) { + error(1, 0, "Out of memory"); + /* It's senseless 'cause error called this way terminates cvs + * but in case we'll eventually make a proper lib... + */ + err = 1; + goto err; + } + append_audit_log_line("grant"); + append_audit_log_line("branch"); + append_audit_log_line(branch_permissions_string(branch_perm)); + append_audit_log_line(finfo->update_dir); + append_audit_log_line(finfo->file); + append_audit_log_line((char*)username); + append_audit_log_line(branch); + log_audit_event(); + } + + error(0, 0, "Setting '%s' permissions for '%s' on file %s\n", + branch_permissions_string(branch_perm), (char*)username, + finfo->fullname); + err: + destroy_dir_acl(dir_acl); + return err; +} + +static int +access_proc (argc, argv, xwhere, mwhere, mfile, shorten, local, mname, username) + int argc; + char **argv; + char *xwhere; + char *mwhere; + char *mfile; + int shorten; + int local; + char *mname; + char *username; +{ + char *myargv[2]; + int err = 0; + int which = W_REPOS | W_ATTIC; + +/* char *repository; */ +/* char *where; */ + + struct stringbuf *repository = NULL; + struct stringbuf *rptr = NULL; + + struct stringbuf *where; + struct stringbuf *wptr; + + FILEPROC fileproc; + DIRENTPROC dirproc; + + repository = new_stringbuf(current_parsed_root->directory); + rptr = catc_stringbuf(repository, '/'); + rptr = cat_stringbuf(rptr, argv[0]); + + where = new_stringbuf(argv[0]); + wptr = where; + + if (rptr == NULL || wptr == NULL) { + error(0, 0, "Not enough memory for repository stringbuf"); + err = 1; + goto err; + } + + + /* if mfile isn't null, we need to set up to do only part of the module */ + if (mfile != NULL) + { + + rptr = catc_stringbuf(rptr, '/'); + rptr = cat_stringbuf(rptr,mfile); + wptr = catc_stringbuf(wptr, '/'); + wptr = cat_stringbuf(wptr, mfile); + if (rptr == NULL || wptr == NULL) { + error(0, errno, "Not enough memory for repository stringbuf"); + err = 1; + goto err; + } + + if (!isdir(repository->buf)) { + /* Hmm... It's a file. we have to cut off its + * basename from repository... */ + size_t mflen; + char *sp = strrchr(mfile, '/'); + if (sp != NULL) + mfile = sp + 1; + mflen = strlen(mfile); + repository->buf[repository->len - mflen - 1] = '\0'; + repository->len -= (mflen + 1); + where->buf[where->len - mflen - 1] = '\0'; + where->len -= (mflen + 1); + + /* copied from patch.c w/o checking if this really way to + go :-) */ + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; + } + } + + /* cd to the starting repository */ + if ( CVS_CHDIR (repository->buf) < 0) { + error(0, errno, "Error changing working directory to %s", + repository->buf); + err = 1; + goto err; + } + + dirproc = (dir_perm != dir_perm_invalid || is_set_default_file_acl) ? + access_dirproc : NULL; + fileproc = (branch_perm != branch_perm_invalid && !is_set_default_file_acl) ? + access_fileproc : NULL; + + /* start the recursion processor */ + err = start_recursion (fileproc, (FILESDONEPROC) NULL, dirproc, + (DIRLEAVEPROC) NULL, (void*)username, + argc - 1, argv + 1, local, which, 0, 1, + where->buf, 1); + err: + free_stringbuf(where); where = NULL; + free_stringbuf(repository); repository = NULL; + return (err); +} + +static int +access_module_racl (int argc, char **argv, char *username, int local) +{ + DBM *db; + int err = 0; + int i; + db = open_module (); + for (i = 0; i < argc; i++) + err += do_module (db, argv[i], MISC, (char *) username, access_proc, + (char *) NULL, 0, local, 0, 0, (char*) NULL); + close_module (db); + return err + error_counter; +} + +static branch_permission +dir_branch_perm_translate(dir_permission dir_perm) { + if (dir_perm == dir_perm_invalid) + return branch_perm_invalid; + else if (dir_perm == dir_perm_none) + return branch_perm_none; + else if (dir_perm == dir_perm_all) + return branch_perm_all; + else { + branch_permission bp = branch_perm_none; + if (dir_perm & dir_perm_access) + bp |= branch_perm_checkout; + if (dir_perm & dir_perm_modify) + bp |= branch_perm_checkin; + return bp; + } +} +#endif /* SERVER_SUPPORT */ + + +#ifdef SERVER_SUPPORT +static int server_side_racl (int argc, char **argv) { - struct REPOSITORY *repos; char *subcommand; char *username; char *perm; char *prefix = ""; - int grant = 0; - + int grant = 0; + int istranslate = 0; + int local = 1; + int c; + if (!is_acl_admin(CVS_Username)) error(1, 0, "%s is not allowed to manage ACLs", CVS_Username); argv++; /* skip 'cvs server' */ - argv++; /* skip 'racl' */ - - repos = get_repository(current_parsed_root->directory); + /* argv++; */ /* Due to the bug of getopt(3) we don't need to + skip 'racl' */ + argc--; + + optind = 0; + while ((c = getopt(argc, argv, "tr:")) != -1) { + switch (c) { + case 'r': + branch = xstrdup(optarg); + break; + case 't': + istranslate = 1; + break; + default: + error(1, 0, "invalid option -%c\n", c); + usage(racl_usage); + break; + } + } + /* Hmm... Either I'm don't understand completely the [GNU] getopt(3) + logic or it's set to at least 1 even if no options were passed. + This check is made in case there're different getopts... + Thus we skip racl subcommand, see comments above... + */ + if (optind == 0) + optind ++; + argc -= optind; + argv += optind; + + /* It's not necessary to check argc at this point */ subcommand = *argv++; + argc--; + if (!subcommand) usage(racl_usage); @@ -71,39 +422,44 @@ usage(racl_usage); username = *argv++; - if (!username) + argc--; + if (!username || !username[0]) usage(racl_usage); perm = *argv++; + argc--; if (!perm) usage(racl_usage); if (strncmp(perm, "tag", strlen("tag")) == 0) { - prefix = perm + strlen("tag") + 1; + const size_t TAG_LEN = strlen("tag"); + if (perm[TAG_LEN] == ':') + prefix = perm + TAG_LEN + 1; /* PREFIX was specified */ + else if (perm[TAG_LEN] == '\0') + prefix = perm + TAG_LEN; /* No PREFIX specified */ + else + goto err; + tag_module_racl(argc,argv,username,prefix,grant,0); + return 0; + } else if (strncmp(perm, "branch", strlen("branch")) == 0) { + error(1, 0, "Branch permissions isn't implemented yet"); + return 1; + } else if ((dir_perm = parse_dir_permissions(perm)) != dir_perm_invalid) { + if (istranslate) + branch_perm = dir_branch_perm_translate(dir_perm); + return access_module_racl(argc,argv,username,local); } else { - error(1, 0, "Unknown permission: '%s'", perm); - } - - while (*argv) { - char *module = *argv; - struct MODULE_ACL *mod_acl = get_module_acl(repos, module); - - if (grant) { - if (!grant_module_tagging(mod_acl, username, prefix)) - error(1, errno, "Error granting tag permission to %s for %s", - username, module); - } else { - if (!revoke_module_tagging(mod_acl, username, prefix)) - error(1, errno, "Error revoking tag permission to %s for %s", - username, module); - } - argv++; + size_t deflen = strlen(DEFAULT_FILE_ACL_PREFIX); + if (strncmp(perm, DEFAULT_FILE_ACL_PREFIX, deflen)==0) { + is_set_default_file_acl = 1; + perm += deflen; + } + if ((branch_perm = parse_branch_permissions(perm)) != branch_perm_invalid) + return access_module_racl(argc,argv,username,local); } - - if (!save_module_acl(repos)) - error(1, errno, "Error saving module ACLS: %s", strerror(errno)); - - free_repository(repos); + err: + error(1, 0, "Unknown permission: '%s'", perm); + return 1; } #endif @@ -134,7 +490,7 @@ #ifdef SERVER_SUPPORT if (server_active) - server_side_racl(argc, argv); + return server_side_racl(argc, argv); #endif #ifdef CLIENT_SUPPORT @@ -144,3 +500,4 @@ return 0; } + |