/* * Copyright (C) 2006 The Free Software Foundation, Inc. * * Portions Copyright (C) 2006, Baris Sahin * * * * 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) * */ #include __RCSID("$NetBSD: acl.c,v 1.6 2016/05/17 14:00:09 christos Exp $"); #include "cvs.h" #include "getline.h" #include #include 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); static FILE *open_accessfile (char *xmode, const char *repos, char **fname); static FILE *open_groupfile (char *xmode); static char *get_perms (const char *xperms); static char *make_perms (char *xperms, char *xfounduserpart, char **xerrmsg); static char *findusername (const char *string1, const char *string2); static char *findgroupname (const char *string1, const char *string2); static int valid_tag (const char *part_tag, const char *tag); static int valid_perm (const char *part_perms, int perm); static int write_perms (const char *user, const char *perms, const char *founduserpart, int foundline, char *otheruserparts, const char *part_type, const char *part_object, const char *part_tag, int pos, const char *arepos); static char *cache_repository; static int cache_retval; static int founddeniedfile; static int cache_perm; static int is_racl; static int debug = 0; int use_cvs_acl = 0; char *cvs_acl_default_permissions; int use_cvs_groups = 0; int use_system_groups = 0; int use_separate_acl_file_for_each_dir = 0; char *cvs_acl_file_location = NULL; char *cvs_groups_file_location = NULL; char *cvs_server_run_as = NULL; int stop_at_first_permission_denied = 0; char *tag = NULL; char *muser; char *mperms; static int defaultperms; static char *default_perms_object; char *default_part_perms_accessfile; 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, const char *tag, int perm, char **mline, int *mpos, int usecache) { int retval = 0; int foundline = 0; FILE *accessfp; int flag = 1; char *iline; char *tempv; char *tempc; size_t tempsize; int intcount; int accessfilecount; int signlevel = -1; int dadmin = 0; const char *repository; char *filefullname = NULL; userfound = 0; groupfound = 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 { free (cache_repository); cache_repository = xstrdup (repository); cache_perm = perm; } iline = xstrdup(repository); tempv = strtok(iline, "/\t"); tempc = xstrdup(tempv); tempsize = ( tempc != NULL ) ? strlen(tempc) : 0; intcount = 0; /* store paths from object to cvsroot */ dirs[intcount] = xstrdup(tempc); 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); free (tempc); free (iline); /* 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 = Xasprintf("%s/%s", repository, file); intcount++; dirs[intcount] = xstrdup(filefullname); } for (; accessfilecount >= 0 && flag; accessfilecount--) { if (!use_separate_acl_file_for_each_dir) { flag = 0; accessfp = open_accessfile ("r", repository, NULL); } else { flag = 1; 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) { free (line); error(1, 0, "access file is corrupted or has invalid" " format"); } if (debug) fprintf (stderr, "type %s object %s tag %s perms" "%s\n", part_type, part_object, part_tag, part_perms); for (x = intcount; x >= signlevel && x != -1; x--) { if (debug) fprintf (stderr, "dirs[%d] = %s, part_object=" "%s\n", x, dirs[x], part_object); if (strcmp (dirs[x], part_object) == 0) { if (debug) fprintf(stderr, "tag %s \n", tag); if (valid_tag (part_tag, tag)) { foundline = 1; if (debug) fprintf(stderr, "foundline\n"); if (listacl || ((acldir || aclfile) && x == intcount) && strcmp(part_tag, tag) == 0) { *mline = xstrdup (xline); *mpos = ftell (accessfp); } if (debug) fprintf(stderr, "perm %d\n", perm); if (valid_perm (part_perms, perm)) { if (debug) fprintf(stderr, "signlevel=%d " " x=%d, aclconfig_default_used=%d\n", signlevel, x, aclconfig_default_used); if (signlevel == x) { if (strcmp(part_tag, "ALL") != 0 && !aclconfig_default_used) { retval = 1; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } } else if (!aclconfig_default_used) { signlevel = x; retval = 1; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } else { /* nothing... */ } } else { if (signlevel == x) { if (strcmp(part_tag, "ALL") != 0 && !aclconfig_default_used) { retval = 0; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } } else if (!aclconfig_default_used) { signlevel = x; retval = 0; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); if (strncmp (part_type, "f", 1) == 0) founddeniedfile = 1; } else { } } } } } if (debug) fprintf (stderr, "xline tag = %s %d %d\n", xline, groupfound, userfound); if (strncmp (xline, "d:ALL:", 6) == 0 && ((!groupfound && !userfound) || listacl)) { if (debug) fprintf (stderr, "ALL tag = %s\n", tag); /* a default found */ if (valid_tag (part_tag, tag) > 0) { foundline = 1; default_part_perms_accessfile = xstrdup (part_perms); if (debug) fprintf (stderr, "valid perm = %d\n", perm); if (valid_perm (part_perms, perm)) { retval = 1; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); if (perm == 8) dadmin = 1; } else { retval = 0; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } } } } if (fclose (accessfp) == EOF) error (1, errno, "cannot close 'access' file"); } } if (!foundline) { if (debug) fprintf(stderr, "not found line\n"); /* DEFAULT */ if (valid_perm (NULL, perm)) { retval = 1; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } else { retval = 0; if (debug) fprintf(stderr, "%s, %d: %d\n", __FILE__, __LINE__, retval); } } /* acl admin rigths 'p' */ if (dadmin) { retval = dadmin; } cache_retval = retval; free (filefullname); /* free directories array */ while (intcount >= 0) { free (dirs[intcount]); intcount--; } return retval; } /* Returns 1 if tag is valid, 0 if not */ static int valid_tag (const char *part_tag, const char *tag) { int retval; if (tag == NULL) tag = "HEAD"; if (strcmp (tag, part_tag) == 0 || strcmp (part_tag, "ALL") == 0) retval = 1; else retval = 0; return retval; } /* Returns 1 if successful, 0 if not. */ static int valid_perm (const char *part_perms, int perm) { char *perms; 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; } free (perms); return (retval); } /* returns permissions found */ char * get_perms (const char *part_perms) { char *username; char *xperms; size_t xperms_len = 1; FILE *groupfp; char *founduser = NULL; char *foundall = NULL; int default_checked = 0; if (debug) fprintf (stderr, "get_perms %s...", part_perms); 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 (cvs_acl_default_permissions) { aclconfig_default_used = 1; if (debug) fprintf (stderr, "default %s\n", cvs_acl_default_permissions); return xstrdup(cvs_acl_default_permissions); } else { if (debug) fprintf (stderr, "early %s\n", xperms); return xperms; } } check_default: founduser = findusername (part_perms, username); foundall = strstr (part_perms, "ALL!"); if (debug) fprintf (stderr, "founduser=%s foundALL=%s\n", founduser, foundall); if (founduser) { char *usr; char *per; usr = strtok (founduser, "!\t"); per = strtok (NULL, ",\t"); free(xperms); xperms = xstrdup (per); xperms_len = strlen (xperms); userfound = 1; free (founduser); } else { if (debug) fprintf (stderr, "usesystemgroups=%d\n", use_system_groups); if (use_system_groups) { struct group *griter; struct passwd *pwd; gid_t gid = (pwd = getpwnam(username)) != NULL ? pwd->pw_gid : -1; setgrent (); while (griter = getgrent ()) { char *userchk; if (gid == griter->gr_gid) { userchk = username; } else { char **users = griter->gr_mem; int index = 0; 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"); if (debug) fprintf (stderr, "usercheck=%s, grp=%s\n", userchk, grp); gperm = strtok (NULL, ",\t"); xrealloc_and_strcat (&xperms, &xperms_len, gperm); groupfound = 1; free (grp); } } } endgrent (); } else if (use_cvs_groups) { 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) { char *user; if (line[0] == '#' || line[0] == '\0' || line[0] == '\n') continue; if (line[read - 1] == '\n') line[--read] = '\0'; if ((grp = findgroupname (line, username)) && (user = findusername (part_perms, grp))) { gperm = strtok (user, "!\t"); gperm = strtok (NULL, ",\t"); xrealloc_and_strcat (&xperms, &xperms_len, gperm); groupfound = 1; free (grp); free (user); } } free (line); 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') { xperms = xstrdup (per); xperms_len = strlen (xperms); } /* You don't free pointers from strtok()! */ //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) 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 (cvs_acl_default_permissions) { aclconfig_default_used = 1; xperms = xstrdup (cvs_acl_default_permissions); } } if (xperms[0] == '\0' && cvs_acl_default_permissions) { aclconfig_default_used = 1; xperms = xstrdup (cvs_acl_default_permissions); } if (debug) fprintf (stderr, "late %s\n", xperms); 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, "dRr:l")) != -1) { switch (c) { case 'd': debug++; break; 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 (argc < (is_racl ? 1 : 1)) usage (is_racl ? racl_usage : acl_usage); if (listacl) { if (strstr (argv[0], ":")) usage (is_racl ? racl_usage : acl_usage); } else { if (!strstr (argv[0], ":")) 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 (!use_separate_acl_file_for_each_dir) { 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; char *where; char *obj; size_t objlen = 0; if (!use_cvs_acl) { error(1, 0, "CVSACL extension is not enabled, set `UseCVSACL=yes'" " in aclconfig file"); } if (is_racl) { char *v; repository = Xasprintf ("%s/%s", current_parsed_root->directory, argv[0]); where = xstrdup (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'; v = Xasprintf ("%s/%s", repository, mfile); free (repository); repository = v; v = Xasprintf ("%s/%s", where, mfile); free(where); where = v; mfile = cp + 1; } /* take care of the rest */ path = Xasprintf ("%s/%s", repository, mfile); if (isdir (path)) { /* directory means repository gets the dir tacked on */ free(repository); repository = path; v = Xasprintf ("%s/%s", where, mfile); free(where); where = v; } else { free (path); myargv[0] = argv[0]; myargv[1] = mfile; argc = 2; argv = myargv; } } /* cd to the starting repository */ if ( CVS_CHDIR (repository) < 0) { error (0, errno, "cannot chdir to %s", repository); free (repository); free (where); return 1; } /* End section which is identical to patch_proc. */ which = W_REPOS | W_ATTIC; if (argc > 1) { obj = Xasprintf ("%s/%s", repository, argv[1]); } else { obj = xstrdup(repository); } } else { where = NULL; repository = 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"); free (obj); if (listacl) err = start_recursion (acllist_fileproc, NULL, acllist_dirproc, NULL, NULL, argc - 1, argv + 1, local, which, 0, 0, where, 1, repository); else err = start_recursion (acl_fileproc, NULL, acl_dirproc, NULL, NULL, argc - 1, argv + 1, local, which, 0, 0, where, 1, repository); if (repository != NULL) free (repository); if (where != NULL) free (where); 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 = Xasprintf("%s/%s", frepository, 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); } 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)); } free (line); free (founduserpart); free (otheruserparts); free (wperms); free (filefullname); 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); } } free (line); free (founduserpart); free (otheruserparts); free (wperms); 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 (!use_separate_acl_file_for_each_dir) { if (cvs_acl_file_location == NULL) { accessfile = Xasprintf("%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSROOTADM_ACCESS); } else { accessfile = xstrdup(cvs_acl_file_location); } } 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 (fname != NULL) *fname = xstrdup (accessfile); free (accessfile); 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; FILE *groupfp; if (use_cvs_groups) { if (cvs_groups_file_location != NULL) { groupfile = xstrdup (cvs_groups_file_location); } else { groupfile = Xasprintf("%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSROOTADM_GROUP); } } else { return NULL; } groupfp = CVS_FOPEN (groupfile, "r"); if (groupfp == NULL) error (0, 0, "cannot open file: %s", groupfile); free (groupfile); 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; size_t retperms_len; perms_len = strlen (perms); if (perms[0] == '+' || perms[0] == '-') { retperms = xmalloc (retperms_len); retperms[0] = '\0'; retperms_len = 1; 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); free (temp); } 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 = tempfperms; fperms_len = strlen (fperms); 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); free (temp); } 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 = tempfperms; fperms_len = strlen (fperms); 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); free (temp); } 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 = tempfperms; fperms_len = strlen (fperms); 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); free (temp); } 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 = tempfperms; fperms_len = strlen (fperms); 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); } if (fperms) free (fperms); if (err && retperms) free (retperms); return (err ? NULL : retperms); } /* prepare and write resulting permissions to access file */ static int write_perms (const char *user, const char *perms, const char *founduserpart, int foundline, char *otheruserparts, const char *part_type, const char *part_object, const char *part_tag, int pos, const char *arepos) { char *accessfile; char *tmpaccessout; FILE *accessfpin; FILE *accessfpout; char *newline = NULL; size_t newlinelen = 1; char *object; char *line = NULL; size_t line_allocated = 0; newline = xmalloc (newlinelen); newline[0] = '\0'; if (!strcasecmp (part_tag, "ALL")) part_tag = "ALL"; /* strip any trailing slash if found */ object = xstrdup (part_object); if (object[strlen (object) - 1] == '/') object[strlen (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, 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); if (accessfpout == NULL) error (1, errno, "cannot open temporary file: %s", tmpaccessout); accessfpin = open_accessfile ("r", arepos, &accessfile); if (accessfpout == NULL) error (1, errno, "cannot open access file: %s", accessfile); while (getline (&line, &line_allocated, accessfpin) >= 0) { if (pos != ftell (accessfpin)) { if (fprintf (accessfpout, "%s", 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); } if (accessfpout == NULL) error (1, errno, "cannot open access file: %s", 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); } free (line); free (newline); chmod (accessfile, 0644); return 0; } static int acllist_fileproc (void *callerdat, struct file_info *finfo) { char *filefullname; const char *frepository; char *line = NULL; int pos; if (!aclfile) return 0; frepository = Short_Repository (finfo->repository); filefullname = Xasprintf("%s/%s", frepository, 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); free (filefullname); 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; 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 (temp, 0); cvs_output (":", 0); while (printedusers[c] != NULL) c++; printedusers[c] = xstrdup (temp); c++; printedusers[c] = NULL; temp = strtok (NULL, ",\t"); if (temp != NULL && temp[strlen (temp) - 2] == ':') temp[strlen (temp) - 2] = '\0'; cvs_output (temp, 0); cvs_output (" ", 0); } if (default_perms_object) { cvs_output ("| defaults ", 0); cvs_output ("ALL:", 0); cvs_output (default_perms_object, 0); def = 1; } if (default_part_perms_accessfile) { size_t i; i = strlen (default_part_perms_accessfile); xrealloc_and_strcat (&default_part_perms_accessfile, &i, ","); free (line); line = xstrdup (default_part_perms_accessfile); if (!def) cvs_output ("| defaults ", 0); else cvs_output (" ", 0); temp = strtok (line, "!\t"); cvs_output (temp, 0); cvs_output (":", 0); temp = strtok (NULL, ",\t"); cvs_output (temp, 0); cvs_output (" ", 0); while ((temp = strtok (NULL, "!\t")) != NULL) { int printed = 0; int c2 = 0; while (printedusers[c2] != NULL && printed == 0) { if (strcmp (printedusers[c2], temp) == 0) { printed = 1; break; } c2++; } if (printed == 0) { cvs_output (temp, 0); cvs_output (":", 0); } temp = strtok (NULL, ",\t"); if (temp[strlen (temp) - 2] == ':') temp[strlen (temp) - 2] = '\0'; if (printed == 0) { cvs_output (temp, 0); cvs_output (" ", 0); } } def = 1; } else if (cvs_acl_default_permissions) { cvs_output ("| defaults ", 0); cvs_output ("ALL: ", 0); cvs_output (cvs_acl_default_permissions, 0); } } else { if (acldir) cvs_output ("d ", 0); else if (aclfile) cvs_output ("f ", 0); cvs_output (obj, 0); cvs_output (" | ", 0); cvs_output (tag, 0); cvs_output (" | ", 0); if (default_perms_object) { cvs_output ("| defaults ", 0); cvs_output ("ALL:", 0); cvs_output (default_perms_object, 0); def = 1; } if (default_part_perms_accessfile) { free (line); line = xstrdup (default_part_perms_accessfile); if (!def) cvs_output ("| defaults ", 0); else cvs_output (" ", 0); temp = strtok (line, "!\t"); cvs_output (temp, 0); cvs_output (":", 0); temp = strtok (NULL, ",\t"); if (temp[strlen (temp) - 2] == ':') temp[strlen (temp) - 2] = '\0'; cvs_output (temp, 0); cvs_output (" ", 0); while ((temp = strtok (NULL, "!\t")) != NULL) { cvs_output (temp, 0); cvs_output (":", 0); if ((temp = strtok (NULL, ",\t")) != NULL) { if (temp[strlen (temp) - 2] == ':') temp[strlen (temp) - 2] = '\0'; cvs_output (temp, 0); cvs_output (" ", 0); } } cvs_output ("\n", 0); } else if (cvs_acl_default_permissions) { cvs_output ("| defaults ", 0); cvs_output ("ALL: ", 0); cvs_output (cvs_acl_default_permissions, 0); } else cvs_output ("default:p (no perms)", 0); } cvs_output ("\n", 0); while (c >= 0) { free (printedusers[c]); c--; } free (line); } /* find username * returns username with its permissions if user found * returns NULL if user not found */ char *findusername (const char *string1, const char *string2) { char *tmp1, *tmp2; if (string1 != NULL && string2 != NULL) { tmp1 = xstrdup (string1); tmp2 = strtok (tmp1, ",\t"); do { if (strncmp (tmp2, string2, strlen (string2)) == 0 && tmp2[strlen (string2)] == '!') { tmp2 = xstrdup (tmp2); free (tmp1); return tmp2; } tmp2 = strtok (NULL, ",\t"); } while (tmp2 != NULL); free (tmp1); return NULL; } else return NULL; } /* find user name in group file * returns group name if user found * returns NULL if user not found */ char *findgroupname (const char *string1, const char *string2) { char *tmp1, *tmp2; char *grpname; if (string1 != NULL && string2 != NULL) { tmp1 = xstrdup (string1); grpname = strtok (tmp1, ":\t"); while (tmp2 = strtok(NULL, ",\t")) { if (strcmp (tmp2, string2) == 0) { grpname = xstrdup (grpname); free (tmp1); return grpname; } } free (tmp1); return NULL; } else return NULL; }