Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright (C) 2006 The Free Software Foundation, Inc.
      3  *
      4  * Portions Copyright (C) 2006, Baris Sahin <sbaris at users.sourceforge.net>
      5  *                                          <http://cvsacl.sourceforge.net>
      6  *
      7  *
      8  * You may distribute under the terms of the GNU General Public License as
      9  * specified in the README file that comes with the CVS source distribution.
     10  *
     11  *
     12  *
     13  * CVS ACCESS CONTROL LIST EXTENSION
     14  *
     15  * It provides advanced access control definitions per modules,
     16  * directories, and files on branch/tag for remote cvs repository
     17  * connections.Execution of all CVS subcommands can be controlled
     18  * with eight different permissions.
     19  *
     20  * Permission Types:
     21  * - no permission      (n) (1)
     22  * - all permissions    (a) (2)
     23  * - write permission   (w) (3)
     24  * - tag permission     (t) (4)
     25  * - read permission    (r) (5)
     26  * - add permission     (c) (6)
     27  * - remove permission  (d) (7)
     28  * - permission	change  (p) (8)
     29  *
     30  */
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: acl.c,v 1.6 2016/05/17 14:00:09 christos Exp $");
     33 
     34 #include "cvs.h"
     35 #include "getline.h"
     36 #include <pwd.h>
     37 #include <grp.h>
     38 
     39 static int acl_fileproc (void *callerdat, struct file_info *finfo);
     40 
     41 static Dtype acl_dirproc (void *callerdat, const char *dir, const char *repos,
     42 			  const char *update_dir, List *entries);
     43 
     44 static int acllist_fileproc (void *callerdat, struct file_info *finfo);
     45 static Dtype acllist_dirproc (void *callerdat, const char *dir,
     46 			      const char *repos, const char *update_dir,
     47 			      List *entries);
     48 
     49 static void acllist_print (char *line, const char *obj);
     50 
     51 static int racl_proc (int argc, char **argv, char *xwhere,
     52 		      char *mwhere, char *mfile, int shorten,
     53 		      int local_specified, char *mname, char *msg);
     54 
     55 static FILE *open_accessfile (char *xmode, const char *repos, char **fname);
     56 static FILE *open_groupfile (char *xmode);
     57 
     58 static char *get_perms (const char *xperms);
     59 static char *make_perms (char *xperms, char *xfounduserpart, char **xerrmsg);
     60 
     61 static char *findusername (const char *string1, const char *string2);
     62 static char *findgroupname (const char *string1, const char *string2);
     63 static int valid_tag (const char *part_tag, const char *tag);
     64 static int valid_perm (const char *part_perms, int perm);
     65 static int write_perms (const char *user, const char *perms,
     66 			const char *founduserpart, int foundline,
     67 			char *otheruserparts, const char *part_type,
     68 			const char *part_object, const char *part_tag, int pos,
     69 			const char *arepos);
     70 
     71 static char *cache_repository;
     72 static int cache_retval;
     73 static int founddeniedfile;
     74 static int cache_perm;
     75 
     76 static int is_racl;
     77 static int debug = 0;
     78 
     79 int use_cvs_acl = 0;
     80 char *cvs_acl_default_permissions;
     81 int use_cvs_groups = 0;
     82 int use_system_groups = 0;
     83 int use_separate_acl_file_for_each_dir = 0;
     84 char *cvs_acl_file_location = NULL;
     85 char *cvs_groups_file_location = NULL;
     86 char *cvs_server_run_as = NULL;
     87 int stop_at_first_permission_denied = 0;
     88 
     89 char *tag = NULL;
     90 
     91 char *muser;
     92 char *mperms;
     93 static int defaultperms;
     94 
     95 static char *default_perms_object;
     96 char *default_part_perms_accessfile;
     97 int aclconfig_default_used;
     98 
     99 int acldir = 0;
    100 int aclfile = 0;
    101 int listacl = 0;
    102 
    103 int userfound = 0;
    104 int groupfound = 0;
    105 
    106 /* directory depth ... */
    107 char *dirs[255];
    108 
    109 static const char *const acl_usage[] =
    110         {
    111                 "Usage: %s %s [user||group:permissions] [-Rl] [-r tag] [directories...] [files...]\n",
    112                 "\t-R\tProcess directories recursively.\n",
    113                 "\t-r rev\tExisting revision/tag.\n",
    114                 "\t-l\tList defined ACLs.\n",
    115                 "(Specify the --help global option for a list of other help options)\n",
    116                 NULL
    117         };
    118 
    119 static const char *const racl_usage[] =
    120 {
    121     "Usage: %s %s [user||group:permissions] [-Rl] [-r tag] [directories...]"
    122     " [files...]\n",
    123     "\t-R\tProcess directories recursively.\n",
    124     "\t-r rev\tExisting revision/tag.\n",
    125     "\t-l\tList defined ACLs.\n",
    126     "(Specify the --help global option for a list of other help options)\n",
    127     NULL
    128 };
    129 
    130 
    131 int
    132 access_allowed (const char *file, const char *repos, const char *tag,
    133 		int perm, char **mline, int *mpos, int usecache)
    134 {
    135     int retval = 0;
    136     int foundline = 0;
    137     FILE *accessfp;
    138 
    139     int flag = 1;
    140 
    141     char *iline;
    142     char *tempv;
    143     char *tempc;
    144     size_t tempsize;
    145 
    146     int intcount;
    147     int accessfilecount;
    148     int signlevel = -1;
    149     int dadmin = 0;
    150 
    151     const char *repository;
    152     char *filefullname = NULL;
    153     userfound = 0;
    154     groupfound = 0;
    155 
    156     if (defaultperms)
    157     {
    158 	repository = xstrdup ("ALL");
    159     }
    160     else {
    161 	if (strlen(repository = Short_Repository (repos)) == 0)
    162 	{
    163 	    repository = xstrdup (".");
    164 	}
    165     }
    166 
    167     /* cache */
    168     if (usecache && cache_repository != NULL &&
    169 	strcmp (cache_repository, repository) == 0 && !founddeniedfile
    170 	&& perm == cache_perm)
    171 	return (cache_retval);
    172     else
    173     {
    174 	free (cache_repository);
    175 	cache_repository = xstrdup (repository);
    176 	cache_perm = perm;
    177     }
    178 
    179     iline = xstrdup(repository);
    180 
    181     tempv = strtok(iline, "/\t");
    182     tempc = xstrdup(tempv);
    183     tempsize = ( tempc != NULL ) ? strlen(tempc) : 0;
    184 
    185     intcount = 0;
    186     /* store paths from object to cvsroot */
    187     dirs[intcount] = xstrdup(tempc);
    188     while ((tempv = strtok(NULL, "/\t")) != NULL)
    189     {
    190 	intcount++;
    191 
    192 	xrealloc_and_strcat(&tempc, &tempsize, "/");
    193 	xrealloc_and_strcat(&tempc, &tempsize, tempv);
    194 
    195 	dirs[intcount] = xstrdup(tempc);
    196     }
    197 
    198     /* free not needed variables here */
    199     free (tempv);
    200     free (tempc);
    201     free (iline);
    202 
    203     /* accessfilecount will used
    204      * if UseSeparateACLFile keyword is set to yes*/
    205     accessfilecount = intcount;
    206 
    207     /* if file is not null add it to dirs array */
    208     if (file != NULL)
    209     {
    210 	filefullname = Xasprintf("%s/%s", repository, file);
    211 	intcount++;
    212 	dirs[intcount] = xstrdup(filefullname);
    213     }
    214 
    215     for (; accessfilecount >= 0 && flag; accessfilecount--)
    216     {
    217 	if (!use_separate_acl_file_for_each_dir) {
    218 	    flag = 0;
    219 	    accessfp = open_accessfile ("r", repository, NULL);
    220 	}
    221 	else
    222 	{
    223 	    flag = 1;
    224 	    accessfp = open_accessfile ("r", dirs[accessfilecount], NULL);
    225 	}
    226 
    227 	if (accessfp != NULL)
    228 	{
    229 	    char *line = NULL;
    230 	    size_t line_allocated = 0;
    231 
    232 	    char *xline;
    233 	    char *part_type = NULL;
    234 	    char *part_object = NULL;
    235 	    char *part_tag = NULL;
    236 	    char *part_perms = NULL;
    237 
    238 	    int x;
    239 
    240 	    while (getline (&line, &line_allocated, accessfp) >= 0)
    241 	    {
    242 
    243 		if (line[0] == '#' || line[0] == '\0' || line[0] == '\n')
    244 			continue;
    245 
    246 		xline = xstrdup (line);
    247 		part_type = strtok (line, ":\t");
    248 		part_object = strtok (NULL, ":\t");
    249 		part_tag = strtok (NULL, ":\t");
    250 		part_perms = strtok (NULL, ":\t");
    251 
    252 		if (part_type == NULL || part_object == NULL ||
    253 		    part_tag == NULL || part_perms == NULL)
    254 		{
    255 		    free (line);
    256 		    error(1, 0, "access file is corrupted or has invalid"
    257 				" format");
    258 		}
    259 
    260 		if (debug) fprintf (stderr, "type %s object %s tag %s perms"
    261 				    "%s\n", part_type, part_object, part_tag,
    262 				    part_perms);
    263 		for (x = intcount; x >= signlevel && x != -1; x--)
    264 		{
    265 		    if (debug) fprintf (stderr, "dirs[%d] = %s, part_object="
    266 					"%s\n", x, dirs[x], part_object);
    267 		    if (strcmp (dirs[x], part_object) == 0)
    268 		    {
    269 			if (debug) fprintf(stderr, "tag %s \n", tag);
    270 			if (valid_tag (part_tag, tag))
    271 			{
    272 			    foundline  = 1;
    273 			    if (debug) fprintf(stderr, "foundline\n");
    274 
    275 			    if (listacl || ((acldir || aclfile) &&
    276 					    x == intcount) &&
    277 				strcmp(part_tag, tag) == 0)
    278 			    {
    279 				*mline = xstrdup (xline);
    280 				*mpos = ftell (accessfp);
    281 			    }
    282 
    283 			    if (debug) fprintf(stderr, "perm %d\n", perm);
    284 			    if (valid_perm (part_perms, perm))
    285 			    {
    286 				if (debug) fprintf(stderr, "signlevel=%d "
    287 				    " x=%d, aclconfig_default_used=%d\n",
    288 				    signlevel, x, aclconfig_default_used);
    289 				if (signlevel == x)
    290 				{
    291 				    if (strcmp(part_tag, "ALL") != 0 &&
    292 					!aclconfig_default_used) {
    293 					retval = 1;
    294 					if (debug) fprintf(stderr,
    295 					    "%s, %d: %d\n", __FILE__, __LINE__,
    296 					    retval);
    297 				    }
    298 				}
    299 				else if (!aclconfig_default_used)
    300 				{
    301 				    signlevel = x;
    302 				    retval = 1;
    303 				    if (debug) fprintf(stderr,
    304 					"%s, %d: %d\n", __FILE__, __LINE__,
    305 					retval);
    306 				}
    307 				else {
    308 				    /* nothing... */
    309 				}
    310 			    }
    311 			    else
    312 			    {
    313 				if (signlevel == x)
    314 				{
    315 				    if (strcmp(part_tag, "ALL") != 0 &&
    316 					!aclconfig_default_used) {
    317 					retval = 0;
    318 					if (debug) fprintf(stderr,
    319 					    "%s, %d: %d\n", __FILE__, __LINE__,
    320 					    retval);
    321 				    }
    322 				}
    323 				else if (!aclconfig_default_used)
    324 				{
    325 				    signlevel = x;
    326 				    retval = 0;
    327 				    if (debug) fprintf(stderr,
    328 					"%s, %d: %d\n", __FILE__, __LINE__,
    329 					retval);
    330 
    331 				    if (strncmp (part_type, "f", 1) == 0)
    332 					founddeniedfile = 1;
    333 				}
    334 				else {
    335 				}
    336 			    }
    337 			}
    338 		    }
    339 		}
    340 
    341 		if (debug) fprintf (stderr, "xline tag = %s %d %d\n", xline,
    342 				    groupfound, userfound);
    343 		if (strncmp (xline, "d:ALL:", 6) == 0 &&
    344 		    ((!groupfound && !userfound) || listacl))
    345 		{
    346 		    if (debug) fprintf (stderr, "ALL tag = %s\n", tag);
    347 		    /* a default found */
    348 		    if (valid_tag (part_tag, tag) > 0)
    349 		    {
    350 			foundline = 1;
    351 
    352 			default_part_perms_accessfile = xstrdup (part_perms);
    353 
    354 			if (debug) fprintf (stderr, "valid perm = %d\n", perm);
    355 			if (valid_perm (part_perms, perm))
    356 			{
    357 			    retval = 1;
    358 			    if (debug) fprintf(stderr,
    359 				"%s, %d: %d\n", __FILE__, __LINE__,
    360 				retval);
    361 			    if (perm == 8)
    362 				dadmin = 1;
    363 			}
    364 			else {
    365 			    retval = 0;
    366 			    if (debug) fprintf(stderr,
    367 				"%s, %d: %d\n", __FILE__, __LINE__,
    368 				retval);
    369 			}
    370 		    }
    371 		}
    372 
    373 	    }
    374 
    375 	    if (fclose (accessfp) == EOF)
    376 		error (1, errno, "cannot close 'access' file");
    377 	}
    378     }
    379 
    380     if (!foundline)
    381     {
    382 	if (debug) fprintf(stderr, "not found line\n");
    383 	/* DEFAULT */
    384 	if (valid_perm (NULL, perm)) {
    385 	    retval = 1;
    386 	    if (debug) fprintf(stderr,
    387 		"%s, %d: %d\n", __FILE__, __LINE__,
    388 		retval);
    389 	} else {
    390 	    retval = 0;
    391 	    if (debug) fprintf(stderr,
    392 		"%s, %d: %d\n", __FILE__, __LINE__,
    393 		retval);
    394 	}
    395     }
    396 
    397     /* acl admin rigths 'p' */
    398     if (dadmin)
    399     {
    400 	retval = dadmin;
    401     }
    402 
    403     cache_retval = retval;
    404 
    405     free (filefullname);
    406     /* free directories array */
    407     while (intcount >= 0)
    408     {
    409 	free (dirs[intcount]);
    410 	intcount--;
    411     }
    412 
    413     return retval;
    414 }
    415 
    416 /* Returns 1 if tag is valid, 0 if not */
    417 static int
    418 valid_tag (const char *part_tag, const char *tag)
    419 {
    420     int retval;
    421 
    422     if (tag == NULL)
    423 	tag = "HEAD";
    424 
    425     if (strcmp (tag, part_tag) == 0 || strcmp (part_tag, "ALL") == 0)
    426 	retval = 1;
    427     else
    428 	retval = 0;
    429 
    430     return retval;
    431 }
    432 
    433 /* Returns 1 if successful, 0 if not. */
    434 static int
    435 valid_perm (const char *part_perms, int perm)
    436 {
    437     char *perms;
    438     int retval = 0;
    439 
    440     perms = get_perms (part_perms);
    441 
    442     /* Allow, if nothing found. */
    443     if (perms[0] == '\0')
    444 	return (1);
    445 
    446     /* no access allowed, exit */
    447     if (strstr (perms, "n"))
    448 	retval = 0;
    449 
    450     if (strstr (perms, "p"))
    451 	/* admin rights */
    452 	retval = 1;
    453     else if (strstr (perms, "a") && perm != 8)
    454 	/* all access allowed, exit */
    455 	retval = 1;
    456     else
    457 	switch (perm)
    458 	{
    459 	case 3:/* write permission */
    460 	    if (strstr (perms, "w"))
    461 		retval = 1;
    462 	    break;
    463 	case 4:/* tag permission */
    464 	    if (strstr (perms, "t"))
    465 		retval = 1;
    466 	    break;
    467 	case 5:/* read permission */
    468 	    if (strstr (perms, "w") || strstr (perms, "t") ||
    469 		strstr (perms, "c") || strstr (perms, "d") ||
    470 		strstr (perms, "r"))
    471 		retval = 1;
    472 	    break;
    473 	case 6:/* create permission */
    474 	    if (strstr (perms, "c"))
    475 		retval = 1;
    476 	    break;
    477 	case 7:/* delete permission */
    478 	    if (strstr (perms, "d"))
    479 		retval = 1;
    480 	    break;
    481 	case 8:/* permission change */
    482 	    if (strstr (perms, "p"))
    483 		retval = 1;
    484 	    break;
    485 	default:/* never reached */
    486 	    retval = 0;
    487 	    break;
    488 	}
    489 
    490     free (perms);
    491 
    492     return (retval);
    493 }
    494 
    495 /* returns permissions found */
    496 char *
    497 get_perms (const char *part_perms)
    498 {
    499     char *username;
    500     char *xperms;
    501     size_t xperms_len = 1;
    502 
    503     FILE *groupfp;
    504 
    505     char *founduser = NULL;
    506     char *foundall = NULL;
    507     int default_checked = 0;
    508 
    509     if (debug) fprintf (stderr, "get_perms %s...", part_perms);
    510     aclconfig_default_used = 0;
    511 
    512     xperms = xmalloc (xperms_len);
    513     xperms[0] = '\0';
    514 
    515     /* use CVS_Username if set */
    516     if (CVS_Username == NULL)
    517 	username = getcaller ();
    518     else
    519 	username = CVS_Username;
    520 
    521     /* no defined acl, no default acl in access file,
    522      * or no access file at all */
    523     if (part_perms == NULL) {
    524 	if (cvs_acl_default_permissions)
    525 	{
    526 	    aclconfig_default_used = 1;
    527 	    if (debug) fprintf (stderr, "default %s\n",
    528 			        cvs_acl_default_permissions);
    529 	    return xstrdup(cvs_acl_default_permissions);
    530 	}
    531 	else {
    532 	    if (debug) fprintf (stderr, "early %s\n", xperms);
    533 	    return xperms;
    534 	}
    535     }
    536 
    537 check_default:
    538     founduser = findusername (part_perms, username);
    539     foundall = strstr (part_perms, "ALL!");
    540 
    541     if (debug) fprintf (stderr, "founduser=%s foundALL=%s\n",
    542 		        founduser, foundall);
    543     if (founduser)
    544     {
    545 	char *usr;
    546 	char *per;
    547 
    548 	usr = strtok (founduser, "!\t");
    549 	per = strtok (NULL, ",\t");
    550 
    551 	free(xperms);
    552 	xperms = xstrdup (per);
    553 	xperms_len = strlen (xperms);
    554 
    555 	userfound = 1;
    556 	free (founduser);
    557     }
    558     else
    559     {
    560 	if (debug) fprintf (stderr, "usesystemgroups=%d\n", use_system_groups);
    561 	if (use_system_groups) {
    562 	    struct group *griter;
    563 	    struct passwd *pwd;
    564 	    gid_t gid = (pwd = getpwnam(username)) != NULL ? pwd->pw_gid : -1;
    565 	    setgrent ();
    566 	    while (griter = getgrent ())
    567 	    {
    568 		char *userchk;
    569 		if (gid == griter->gr_gid) {
    570 		    userchk = username;
    571 		} else  {
    572 		    char **users = griter->gr_mem;
    573 		    int index = 0;
    574 		    userchk = users [index++];
    575 		    while(userchk != NULL) {
    576 			if(strcmp (userchk, username) == 0)
    577 			    break;
    578 			userchk = users[index++];
    579 		    }
    580 		}
    581 		if (userchk != NULL) {
    582 		    char *grp;
    583 		    if ((grp = findusername (part_perms, griter->gr_name)))
    584 		    {
    585 			char *gperm = strtok (grp, "!\t");
    586 			if (debug) fprintf (stderr, "usercheck=%s, grp=%s\n",
    587 					    userchk, grp);
    588 			gperm = strtok (NULL, ",\t");
    589 			xrealloc_and_strcat (&xperms, &xperms_len, gperm);
    590 
    591 			groupfound = 1;
    592 			free (grp);
    593 		    }
    594 		}
    595 	    }
    596 	    endgrent ();
    597 	}
    598 	else if (use_cvs_groups) {
    599 	    groupfp = open_groupfile ("r");
    600 	    if (groupfp != NULL)
    601 	    {
    602 		char *line = NULL;
    603 		char *grp;
    604 		char *gperm;
    605 		int read;
    606 
    607 		size_t line_allocated = 0;
    608 
    609 		while ((read = getline (&line, &line_allocated, groupfp)) >= 0)
    610 		{
    611 		    char *user;
    612 		    if (line[0] == '#' || line[0] == '\0' || line[0] == '\n')
    613 			continue;
    614 
    615 		    if (line[read - 1] == '\n')
    616 			line[--read] = '\0';
    617 
    618 		    if ((grp = findgroupname (line, username)) &&
    619 			(user = findusername (part_perms, grp)))
    620 
    621 		    {
    622 			gperm = strtok (user, "!\t");
    623 			gperm = strtok (NULL, ",\t");
    624 			xrealloc_and_strcat (&xperms, &xperms_len, gperm);
    625 			groupfound = 1;
    626 			free (grp);
    627 			free (user);
    628 		    }
    629 		}
    630 
    631 		free (line);
    632 
    633 		if (fclose (groupfp) == EOF)
    634 		    error (1, errno, "cannot close 'group' file");
    635 	    }
    636 	}
    637     }
    638 
    639     if (foundall)
    640     {
    641 	char *usr;
    642 	char *per;
    643 
    644 	usr = strtok (strstr (part_perms, "ALL!"), "!\t");
    645 	per = strtok (NULL, ",\t");
    646 
    647 	if (!default_checked)
    648 	    default_perms_object = xstrdup (per);
    649 
    650 	if (xperms[0] == '\0')
    651 	{
    652 	    xperms = xstrdup (per);
    653 	    xperms_len = strlen (xperms);
    654 	}
    655 
    656 	/* You don't free pointers from strtok()! */
    657 	//free(usr);
    658 	//free(per);
    659     }
    660 
    661     if (xperms[0] == '\0' && !default_checked && default_part_perms_accessfile)
    662     {
    663 	part_perms = xstrdup (default_part_perms_accessfile);
    664 	default_checked = 1;
    665 
    666 	goto check_default;
    667     }
    668 
    669     if (xperms[0] != '\0' && strcmp (xperms, "x") == 0)
    670     {
    671 	if (default_perms_object)
    672 	    xperms = xstrdup (default_perms_object);
    673 	else if (default_part_perms_accessfile)
    674 	{
    675 	    part_perms = default_part_perms_accessfile;
    676 	    default_checked = 1;
    677 	    goto check_default;
    678 	}
    679 	else if (cvs_acl_default_permissions)
    680 	{
    681 	    aclconfig_default_used = 1;
    682 	    xperms = xstrdup (cvs_acl_default_permissions);
    683 	}
    684     }
    685 
    686     if (xperms[0] == '\0' && cvs_acl_default_permissions)
    687     {
    688 	aclconfig_default_used = 1;
    689 	xperms = xstrdup (cvs_acl_default_permissions);
    690     }
    691 
    692     if (debug) fprintf (stderr, "late %s\n", xperms);
    693     return xperms;
    694 }
    695 
    696 
    697 int
    698 cvsacl (int argc, char **argv)
    699 {
    700     char *chdirrepository;
    701     int c;
    702     int err = 0;
    703     int usetag = 0;
    704     int recursive = 0;
    705 
    706     int which;
    707     char *where;
    708 
    709     is_racl = (strcmp (cvs_cmd_name, "racl") == 0);
    710 
    711     if (argc == -1)
    712 	usage (is_racl ? racl_usage : acl_usage);
    713 
    714     /* parse the args */
    715     optind = 0;
    716 
    717     while ((c = getopt (argc, argv, "dRr:l")) != -1)
    718     {
    719 	switch (c)
    720 	{
    721 	case 'd':
    722 	    debug++;
    723 	    break;
    724 	case 'R':
    725 	    recursive = 1;
    726 	    break;
    727 	case 'r': // baris
    728 	    tag = xstrdup (optarg);
    729 	    break;
    730 	case 'l':
    731 	    listacl = 1;
    732 	    break;
    733 	case '?':
    734 	default:
    735 	    usage (is_racl ? racl_usage : acl_usage);
    736 	    break;
    737 	}
    738     }
    739 
    740     argc -= optind;
    741     argv += optind;
    742 
    743     if (argc < (is_racl ? 1 : 1))
    744 	usage (is_racl ? racl_usage : acl_usage);
    745     if (listacl) {
    746 	if (strstr (argv[0], ":"))
    747 	    usage (is_racl ? racl_usage : acl_usage);
    748     } else {
    749 	if (!strstr (argv[0], ":"))
    750 	    usage (is_racl ? racl_usage : acl_usage);
    751     }
    752 
    753 
    754 #ifdef CLIENT_SUPPORT
    755 
    756     if (current_parsed_root->isremote)
    757     {
    758 	start_server ();
    759 	ign_setup ();
    760 
    761 	if(recursive)
    762 	    send_arg ("-R");
    763 
    764 	if (listacl)
    765 	    send_arg ("-l");
    766 
    767 	if(tag)
    768 	{
    769 	    option_with_arg ("-r", tag);
    770 	}
    771 
    772 	send_arg ("--");
    773 
    774 	if (!listacl)
    775 	{
    776 	    send_arg (argv[0]);
    777 
    778 	    argc--;
    779 	    argv++;
    780 	}
    781 
    782 	if (is_racl)
    783 	{
    784 	    int i;
    785 	    for (i = 0; i < argc; ++i)
    786 		send_arg (argv[i]);
    787 
    788 	    send_to_server ("racl\012",0);
    789 	}
    790 	else
    791 	{
    792 	    send_files (argc, argv, recursive, 0, SEND_NO_CONTENTS);
    793 	    send_file_names (argc, argv, SEND_EXPAND_WILD);
    794 	    send_to_server ("acl\012", 0);
    795 	}
    796 
    797 	return get_responses_and_close ();
    798     }
    799 #endif
    800 
    801 #ifdef SERVER_SUPPORT
    802 
    803     if (!listacl)
    804     {
    805 	muser = strtok (argv[0], ":\t");
    806 	mperms = strtok (NULL, ":\t");
    807 
    808 	/* if set to 'default' */
    809 	if ((strlen (mperms) == 7) && (strncmp (mperms, "default", 7) == 0))
    810 	    mperms = xstrdup ("x");
    811 
    812 	/* Check that the given permissions are valid. */
    813 	if (!given_perms_valid (mperms))
    814 	    error (1,0,"Invalid permissions: `%s'", mperms);
    815 
    816 	argc--;
    817 	argv++;
    818     }
    819 
    820 
    821     if (!tag)
    822 	tag = xstrdup ("HEAD");
    823 
    824     if (!strcasecmp (argv[0], "ALL"))
    825     {
    826 	argv[0] = xstrdup (".");
    827 	defaultperms = 1;
    828 	if (!use_separate_acl_file_for_each_dir)
    829 	{
    830 	    recursive = 0;
    831 	}
    832 
    833     }
    834 
    835     if (is_racl)
    836     {
    837 	DBM *db;
    838 	int i;
    839 	db = open_module ();
    840 	for (i = 0; i < argc; i++)
    841 	{
    842 	    err += do_module (db, argv[i], MISC, "ACL ing: ",
    843 			      racl_proc, NULL, 0, !recursive, 0,
    844 			      0, NULL);
    845 	}
    846 	close_module (db);
    847     }
    848     else
    849     {
    850 	err = racl_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, !recursive,
    851 			 NULL, NULL);
    852     }
    853 
    854     return err;
    855 
    856 #endif
    857 }
    858 
    859 static int
    860 racl_proc (int argc, char **argv, char *xwhere, char *mwhere,
    861 	   char *mfile, int shorten, int local, char *mname, char *msg)
    862 {
    863     char *myargv[2];
    864     int err = 0;
    865     int which;
    866     char *repository;
    867     char *where;
    868     char *obj;
    869     size_t objlen = 0;
    870 
    871     if (!use_cvs_acl)
    872     {
    873 	error(1, 0, "CVSACL extension is not enabled, set `UseCVSACL=yes'"
    874 	      " in aclconfig file");
    875     }
    876 
    877     if (is_racl)
    878     {
    879 	char *v;
    880 	repository = Xasprintf ("%s/%s", current_parsed_root->directory,
    881 				argv[0]);
    882 	where = xstrdup (argv[0]);
    883 
    884 	/* if mfile isn't null, we need to set up to do only part of the
    885 	 * module */
    886 	if (mfile != NULL)
    887 	{
    888 	    char *cp;
    889 	    char *path;
    890 
    891 	    /* if the portion of the module is a path, put the dir part on
    892 	     * repos */
    893 	    if ((cp = strrchr (mfile, '/')) != NULL)
    894 	    {
    895 		*cp = '\0';
    896 		v = Xasprintf ("%s/%s", repository, mfile);
    897 		free (repository);
    898 		repository = v;
    899 		v = Xasprintf ("%s/%s", where, mfile);
    900 		free(where);
    901 		where = v;
    902 		mfile = cp + 1;
    903 	    }
    904 
    905 	    /* take care of the rest */
    906 	    path = Xasprintf ("%s/%s", repository, mfile);
    907 	    if (isdir (path))
    908 	    {
    909 		/* directory means repository gets the dir tacked on */
    910 		free(repository);
    911 		repository = path;
    912 		v = Xasprintf ("%s/%s", where, mfile);
    913 		free(where);
    914 		where = v;
    915 	    }
    916 	    else
    917 	    {
    918 		free (path);
    919 		myargv[0] = argv[0];
    920 		myargv[1] = mfile;
    921 		argc = 2;
    922 		argv = myargv;
    923 	    }
    924 	}
    925 
    926 	/* cd to the starting repository */
    927 	if ( CVS_CHDIR (repository) < 0)
    928 	{
    929 	    error (0, errno, "cannot chdir to %s", repository);
    930 	    free (repository);
    931 	    free (where);
    932 	    return 1;
    933 	}
    934 
    935 	/* End section which is identical to patch_proc.  */
    936 
    937 	which = W_REPOS | W_ATTIC;
    938 
    939 	if (argc > 1)
    940 	{
    941 		obj = Xasprintf ("%s/%s", repository, argv[1]);
    942 	}
    943 	else
    944 	{
    945 		obj = xstrdup(repository);
    946 	}
    947     }
    948     else
    949     {
    950 	where = NULL;
    951 	repository = NULL;
    952 	which = W_LOCAL | W_REPOS | W_ATTIC;
    953 
    954 	obj = xstrdup (argv[1]);
    955     }
    956 
    957     if (isdir (obj))
    958 	acldir = 1;
    959     else if (isfile (obj))
    960 	aclfile = 1;
    961     else
    962 	error(1, 0, "no such file or directory");
    963 
    964     free (obj);
    965 
    966     if (listacl)
    967 	err = start_recursion (acllist_fileproc, NULL, acllist_dirproc, NULL,
    968 			       NULL, argc - 1, argv + 1, local, which, 0, 0,
    969 			       where, 1, repository);
    970     else
    971 	err = start_recursion (acl_fileproc, NULL, acl_dirproc, NULL, NULL,
    972 			       argc - 1, argv + 1, local, which, 0, 0,
    973 			       where, 1, repository);
    974 
    975     if (repository != NULL)
    976 	free (repository);
    977     if (where != NULL)
    978 	free (where);
    979 
    980     return err;
    981 }
    982 
    983 
    984 static int
    985 acl_fileproc (void *callerdat, struct file_info *finfo)
    986 {
    987     char *filefullname;
    988     char *founduserpart = NULL;
    989     char *otheruserparts = NULL;
    990     size_t otherslen = 0;
    991 
    992     const char *frepository;
    993     int foundline = 0;
    994 
    995     char *line = NULL;
    996     size_t line_allocated = 0;
    997     int linelen;
    998 
    999     char *wperms;
   1000     char *errmsg;
   1001 
   1002     int pos;
   1003 
   1004     if (!aclfile)
   1005 	return 0;
   1006 
   1007     frepository = Short_Repository (finfo->repository);
   1008 
   1009     filefullname = Xasprintf("%s/%s", frepository, finfo->file);
   1010 
   1011 
   1012     if (!access_allowed (finfo->file, finfo->repository, tag, 8, &line, &pos,
   1013 			 0))
   1014 	error (1, 0, "You do not have acl admin rights on '%s'", frepository);
   1015 
   1016     if (line != NULL)
   1017     {
   1018 	char *part_type = NULL;
   1019 	char *part_object = NULL;
   1020 	char *part_tag = NULL;
   1021 	char *part_perms = NULL;
   1022 	char *userpart;
   1023 
   1024 	part_type = strtok (line, ":\t");
   1025 	part_object = strtok (NULL, ":\t");
   1026 	part_tag = strtok (NULL, ":\t");
   1027 	part_perms = strtok (NULL, ":\t");
   1028 
   1029 	foundline = 1;
   1030 	userpart = strtok (part_perms, ",\t");
   1031 
   1032 	do
   1033 	{
   1034 	    if (strncmp (userpart, muser, strlen (muser)) == 0)
   1035 		founduserpart = xstrdup (userpart);
   1036 	    else
   1037 	    {
   1038 		if (otheruserparts != NULL)
   1039 		{
   1040 		    xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
   1041 		    xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
   1042 		}
   1043 		else
   1044 		{
   1045 		    otheruserparts = xstrdup (userpart);
   1046 		    otherslen = strlen (otheruserparts);
   1047 		}
   1048 	    }
   1049 	} while ((userpart = strtok (NULL, ",\t")) != NULL);
   1050 
   1051 	free (userpart);
   1052     }
   1053 
   1054     wperms = make_perms (mperms, founduserpart, &errmsg);
   1055     if (wperms == NULL)
   1056     {
   1057 	if (errmsg)
   1058 	    error (0, 0, "`%s' %s", filefullname, errmsg);
   1059     }
   1060     else
   1061     {
   1062 	cvs_output ("X ", 0);
   1063 	cvs_output (filefullname, 0);
   1064 	cvs_output ("\n", 0);
   1065 
   1066 	write_perms (muser, wperms, founduserpart, foundline,
   1067 		     otheruserparts, "f", filefullname, tag, pos,
   1068 		     Short_Repository(finfo->repository));
   1069     }
   1070 
   1071     free (line);
   1072     free (founduserpart);
   1073     free (otheruserparts);
   1074     free (wperms);
   1075     free (filefullname);
   1076 
   1077     return 0;
   1078 }
   1079 
   1080 static Dtype
   1081 acl_dirproc (void *callerdat, const char *dir, const char *repos,
   1082 	     const char *update_dir, List *entries)
   1083 {
   1084     const char *drepository;
   1085     char *founduserpart = NULL;
   1086     char *otheruserparts = NULL;
   1087     size_t otherslen = 0;
   1088     int foundline = 0;
   1089 
   1090     char *line = NULL;
   1091     size_t line_allocated = 0;
   1092     int linelen;
   1093 
   1094     int pos;
   1095 
   1096     char *wperms;
   1097     char *errmsg;
   1098 
   1099     if (!acldir)
   1100 	return 0;
   1101 
   1102     if (repos[0] == '\0')
   1103 	repos = Name_Repository (dir, NULL);
   1104 
   1105     if (!access_allowed (NULL, repos, tag, 8, &line, &pos, 0))
   1106 	error (1, 0, "You do not have admin rights on '%s'",
   1107 	       Short_Repository (repos));
   1108 
   1109     drepository = Short_Repository (repos);
   1110 
   1111     if (line != NULL)
   1112     {
   1113 	char *part_type = NULL;
   1114 	char *part_object = NULL;
   1115 	char *part_tag = NULL;
   1116 	char *part_perms = NULL;
   1117 	char *userpart;
   1118 
   1119 	part_type = strtok (line, ":\t");
   1120 	part_object = strtok (NULL, ":\t");
   1121 	part_tag = strtok (NULL, ":\t");
   1122 	part_perms = strtok (NULL, ":\t");
   1123 
   1124 	foundline = 1;
   1125 	userpart = strtok (part_perms, ",\t");
   1126 
   1127 	do
   1128 	{
   1129 	    if (strncmp (userpart, muser, strlen (muser)) == 0)
   1130 		founduserpart = xstrdup (userpart);
   1131 	    else
   1132 	    {
   1133 		if (otheruserparts != NULL)
   1134 		{
   1135 		    xrealloc_and_strcat (&otheruserparts, &otherslen, ",");
   1136 		    xrealloc_and_strcat (&otheruserparts, &otherslen, userpart);
   1137 		}
   1138 		else
   1139 		{
   1140 		    otheruserparts = xstrdup (userpart);
   1141 		    otherslen = strlen (otheruserparts);
   1142 		}
   1143 	    }
   1144 	} while ((userpart = strtok (NULL, ",\t")) != NULL);
   1145     }
   1146 
   1147     wperms = make_perms (mperms, founduserpart, &errmsg);
   1148     if (wperms == NULL)
   1149     {
   1150 	if (errmsg)
   1151 	    error (0, 0, "`%s' %s", drepository, errmsg);
   1152     }
   1153     else
   1154     {
   1155 	if (defaultperms)
   1156 	{
   1157 	    cvs_output ("X ", 0);
   1158 	    cvs_output ("ALL", 0);
   1159 	    cvs_output ("\n", 0);
   1160 	    write_perms (muser, wperms, founduserpart, foundline,
   1161 			 otheruserparts, "d", "ALL", tag, pos, drepository);
   1162 
   1163 	}
   1164 	else
   1165 	{
   1166 	    cvs_output ("X ", 0);
   1167 	    cvs_output (drepository, 0);
   1168 	    cvs_output ("\n", 0);
   1169 	    write_perms (muser, wperms, founduserpart, foundline,
   1170 			 otheruserparts, "d", drepository, tag, pos,
   1171 			 drepository);
   1172 	}
   1173     }
   1174 
   1175     free (line);
   1176     free (founduserpart);
   1177     free (otheruserparts);
   1178     free (wperms);
   1179 
   1180     return 0;
   1181 }
   1182 
   1183 /* Open CVSROOT/access or defined CVSACLFileLocation file
   1184  * Open access file In each directory if UseSeparateACLFileForEachDir=yes
   1185  * returns file pointer to access file or NULL if access file not found */
   1186 FILE *
   1187 open_accessfile (char *fmode, const char *adir, char **fname)
   1188 {
   1189     char *accessfile = NULL;
   1190     FILE *accessfp;
   1191 
   1192     if (!use_separate_acl_file_for_each_dir)
   1193     {
   1194 	if (cvs_acl_file_location == NULL)
   1195 	{
   1196 	    accessfile = Xasprintf("%s/%s/%s", current_parsed_root->directory,
   1197 				   CVSROOTADM, CVSROOTADM_ACCESS);
   1198 	}
   1199 	else
   1200 	{
   1201 	    accessfile = xstrdup(cvs_acl_file_location);
   1202 	}
   1203     }
   1204     else
   1205     {
   1206 	size_t accessfilelen = 0;
   1207 	xrealloc_and_strcat (&accessfile, &accessfilelen,
   1208 			     current_parsed_root->directory);
   1209 	xrealloc_and_strcat (&accessfile, &accessfilelen, "/");
   1210 	xrealloc_and_strcat (&accessfile, &accessfilelen, adir);
   1211 	xrealloc_and_strcat (&accessfile, &accessfilelen, "/access");
   1212     }
   1213 
   1214     accessfp = CVS_FOPEN (accessfile, fmode);
   1215 
   1216     if (fname != NULL)
   1217 	*fname = xstrdup (accessfile);
   1218 
   1219     free (accessfile);
   1220 
   1221     return accessfp;
   1222 }
   1223 
   1224 /* Open /etc/group file if UseSystemGroups=yes in config file
   1225  * Open CVSROOT/group file if UseCVSGroups=yes in config file
   1226  * Open group file if specified in CVSGroupsFileLocation
   1227  * returns group file pointer if UseSystemGroups=yes
   1228  * returns NULL if UseSystemGroups=no or group file not found */
   1229 FILE *
   1230 open_groupfile (char *fmode)
   1231 {
   1232     char *groupfile;
   1233     FILE *groupfp;
   1234 
   1235     if (use_cvs_groups)
   1236     {
   1237 	if (cvs_groups_file_location != NULL)
   1238 	{
   1239 	    groupfile = xstrdup (cvs_groups_file_location);
   1240 	}
   1241 	else
   1242 	{
   1243 	    groupfile = Xasprintf("%s/%s/%s", current_parsed_root->directory,
   1244 				  CVSROOTADM, CVSROOTADM_GROUP);
   1245 	}
   1246     }
   1247     else
   1248     {
   1249 	    return NULL;
   1250     }
   1251 
   1252     groupfp = CVS_FOPEN (groupfile, "r");
   1253 
   1254     if (groupfp == NULL)
   1255 	error (0, 0, "cannot open file: %s", groupfile);
   1256 
   1257     free (groupfile);
   1258 
   1259     return groupfp;
   1260 }
   1261 
   1262 
   1263 /* Check whether given permissions are valid or not
   1264  * Returns 1 if permissions are valid
   1265  * Returns 0 if permissions are NOT valid */
   1266 int
   1267 given_perms_valid (const char *cperms)
   1268 {
   1269     int cperms_len;
   1270     int retval;
   1271     int index, i;
   1272 
   1273     if (cperms[0] == '+' || cperms[0] == '-')
   1274 	index = 1;
   1275     else
   1276 	index = 0;
   1277 
   1278     cperms_len = strlen (cperms);
   1279 
   1280     switch (cperms[index])
   1281     {
   1282     case 'x':
   1283 	if ((cperms_len - index) == 1 && cperms_len == 1)
   1284 	    retval = 1;
   1285 	else
   1286 	    retval = 0;
   1287 	break;
   1288     case 'n':
   1289 	if ((cperms_len - index) == 1 && cperms_len == 1)
   1290 	    retval = 1;
   1291 	else
   1292 	    retval = 0;
   1293 	break;
   1294     case 'p':
   1295 	if ((cperms_len - index) == 1)
   1296 	    retval = 1;
   1297 	else
   1298 	    retval = 0;
   1299 	break;
   1300     case 'a':
   1301 	if ((cperms_len - index) == 1)
   1302 	    retval = 1;
   1303 	else
   1304 	    retval = 0;
   1305 	break;
   1306     case 'r':
   1307 	if ((cperms_len - index) == 1)
   1308 	    retval = 1;
   1309 	else
   1310 	    retval = 0;
   1311 	break;
   1312     case 'w':
   1313 	if ((cperms_len - index) == 1)
   1314 		retval = 1;
   1315 	else
   1316 	    for (i = index + 1; i < cperms_len; i++)
   1317 		if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'd')
   1318 		    retval = 1;
   1319 		else
   1320 		    retval = 0;
   1321 	break;
   1322     case 't':
   1323 	if ((cperms_len - index) == 1)
   1324 	    retval = 1;
   1325 	else
   1326 	    for (i = index + 1; i < cperms_len; i++)
   1327 		if (cperms[i] == 'w' || cperms[i] == 'c' || cperms[i] == 'd')
   1328 		    retval = 1;
   1329 		else
   1330 		    retval = 0;
   1331 	break;
   1332     case 'c':
   1333 	if ((cperms_len - index) == 1)
   1334 	    retval = 1;
   1335 	else
   1336 	    for (i = index + 1; i < cperms_len; i++)
   1337 		if (cperms[i] == 't' || cperms[i] == 'w' || cperms[i] == 'd')
   1338 		    retval = 1;
   1339 		else
   1340 		    retval = 0;
   1341 	break;
   1342     case 'd':
   1343 	if ((cperms_len - index) == 1)
   1344 	    retval = 1;
   1345 	else
   1346 	    for (i = index + 1; i < cperms_len; i++)
   1347 		if (cperms[i] == 't' || cperms[i] == 'c' || cperms[i] == 'w')
   1348 		    retval = 1;
   1349 		else
   1350 		    retval = 0;
   1351 	break;
   1352     default:
   1353 	retval = 0;
   1354 	break;
   1355     }
   1356 
   1357     return retval;
   1358 }
   1359 
   1360 /* prepare permsissions string to be written to access file
   1361  * returns permissions or NULL if */
   1362 char *
   1363 make_perms (char *perms, char *founduserpart, char **xerrmsg)
   1364 {
   1365     char *fperms = NULL;
   1366     size_t perms_len;
   1367     size_t fperms_len;
   1368 
   1369     int i, j;
   1370     int err = 0;
   1371     char *errmsg = NULL;
   1372 
   1373     char *retperms;
   1374     size_t retperms_len;
   1375 
   1376     perms_len = strlen (perms);
   1377     if (perms[0] == '+' || perms[0] == '-')
   1378     {
   1379 	retperms = xmalloc (retperms_len);
   1380 	retperms[0] = '\0';
   1381 	retperms_len = 1;
   1382 
   1383 	if (founduserpart)
   1384 	{
   1385 	    char *tempfperms;
   1386 	    size_t tempfperms_len;
   1387 
   1388 	    char *temp;
   1389 	    int per = 0;
   1390 	    temp = strtok (founduserpart, "!\t");
   1391 	    fperms = strtok (NULL, "!\t");
   1392 	    fperms_len = strlen (fperms);
   1393 
   1394 	    if (strncmp (fperms, "x", 1) == 0)
   1395 	    {
   1396 		err = 1;
   1397 		if (perms[0] == '+')
   1398 		    *xerrmsg = xstrdup ("cannot add default permission 'x'");
   1399 		else
   1400 		    *xerrmsg = xstrdup ("cannot remove default permission 'x'");
   1401 	    }
   1402 
   1403 	    /* go through perms */
   1404 	    for (i = 1; i < perms_len && !err; i++)
   1405 	    {
   1406 		switch (perms[i])
   1407 		{
   1408 		case 'n':
   1409 		    err = 1;
   1410 		    break;
   1411 		case 'p':
   1412 		    if (perms[0] == '+')
   1413 			fperms = xstrdup ("p");
   1414 		    else if (perms[0] == '-')
   1415 		    {
   1416 			fperms_len = 1;
   1417 			fperms = xmalloc (fperms_len);
   1418 			fperms[0] = '\0';
   1419 		    }
   1420 		    break;
   1421 		case 'a':
   1422 		    for (j = 0; j < fperms_len; j++)
   1423 		    {
   1424 			if (fperms[j] == 'p')
   1425 			{
   1426 			    err = 1;
   1427 			    *xerrmsg = xstrdup ("user have admin rights,"
   1428 						" cannot use +/- permissions");
   1429 			}
   1430 			else if (fperms[j] == 'a' && perms[0] == '+')
   1431 			{
   1432 			    err = 1;
   1433 			    *xerrmsg = xstrdup ("user already has all ('a')"
   1434 						" permission");
   1435 			}
   1436 			else if (fperms[j] != 'a' && perms[0] == '-')
   1437 			{
   1438 			    err = 1;
   1439 			    *xerrmsg = xstrdup ("user does not have all "
   1440 						"('a') permission");
   1441 			}
   1442 		    }
   1443 		    if (perms[0] == '+')
   1444 		    {
   1445 			fperms = xstrdup ("a");
   1446 			fperms_len = strlen (fperms);
   1447 		    }
   1448 		    else if (perms[0] == '-')
   1449 		    {
   1450 			fperms_len = 1;
   1451 			fperms = xmalloc (fperms_len);
   1452 			fperms[0] = '\0';
   1453 		    }
   1454 		    break;
   1455 		case 'r':
   1456 		    for (i = 0; i < fperms_len; i++)
   1457 		    {
   1458 			if (fperms[i] == 'n' && perms[0] == '+')
   1459 			{
   1460 			    fperms = xstrdup ("r");
   1461 			    fperms_len = strlen (fperms);
   1462 			}
   1463 			else if (fperms[i] == 'r' && perms[0] == '-')
   1464 			{
   1465 			    fperms_len = 1;
   1466 			    fperms = xmalloc (fperms_len);
   1467 			    fperms[0] = '\0';
   1468 			}
   1469 			else if (perms[0] == '-')
   1470 			{
   1471 			    err = 1;
   1472 			    *xerrmsg = xstrdup ("user has other permissions,"
   1473 						" cannot remove read ('r')"
   1474 						" permission");
   1475 			}
   1476 			else
   1477 			{
   1478 			    err = 1;
   1479 			    *xerrmsg = xstrdup ("user has other permissions,"
   1480 						" cannot remove read ('r')"
   1481 						" permission");
   1482 			}
   1483 		    }
   1484 		    break;
   1485 		case 'w':
   1486 		    {
   1487 			tempfperms_len = 1;
   1488 
   1489 			tempfperms = xmalloc (tempfperms_len);
   1490 			tempfperms[0] = '\0';
   1491 
   1492 			for (j = 0; j < fperms_len; j++)
   1493 			{
   1494 			    if (fperms[j] == 't' || fperms[j] == 'c' ||
   1495 				fperms[j] == 'd')
   1496 			    {
   1497 				char *temp;
   1498 				temp = xmalloc (2);
   1499 				temp[0] = fperms[j];
   1500 				temp[1] = '\0';
   1501 
   1502 				xrealloc_and_strcat (&tempfperms,
   1503 						     &tempfperms_len, temp);
   1504 				free (temp);
   1505 			    }
   1506 			    else if (fperms[j] == 'a' || fperms[j] == 'p')
   1507 			    {
   1508 				err = 1;
   1509 				*xerrmsg = xstrdup ("user has higher"
   1510 						    " permissions, cannot use"
   1511 						    " +/- write permissions");
   1512 			    }
   1513 			    else if (fperms[j] == 'n' || fperms[j] == 'r')
   1514 			    {
   1515 				if (perms[0] == '-')
   1516 				{
   1517 				    err = 1;
   1518 				    *xerrmsg = xstrdup ("user does not have"
   1519 							" write ('w')"
   1520 							" permission");
   1521 				}
   1522 			    }
   1523 			    else if (fperms[j] == 'w')
   1524 			    {
   1525 				per = 1;
   1526 				if (perms[0] == '+') {
   1527 				    err = 1;
   1528 				    *xerrmsg = xstrdup ("user already have"
   1529 							" write ('w')"
   1530 							"permission");
   1531 				}
   1532 			    }
   1533 			}
   1534 
   1535 			fperms = tempfperms;
   1536 			fperms_len = strlen (fperms);
   1537 
   1538 			if (!per && !err && (perms[0] == '-')) {
   1539 			    err = 1;
   1540 			    *xerrmsg = xstrdup ("user does not have write"
   1541 						" ('w') permission");
   1542 			}
   1543 
   1544 			if (perms[0] == '+')
   1545 			{
   1546 			    xrealloc_and_strcat (&fperms, &fperms_len, "w");
   1547 			}
   1548 		    }
   1549 		    break;
   1550 		case 't':
   1551 		    {
   1552 			tempfperms_len = 1;
   1553 
   1554 			tempfperms = xmalloc (tempfperms_len);
   1555 			tempfperms[0] = '\0';
   1556 
   1557 			for (j = 0; j < fperms_len; j++)
   1558 			{
   1559 			    if (fperms[j] == 'w' || fperms[j] == 'c' ||
   1560 				fperms[j] == 'd')
   1561 			    {
   1562 				char *temp;
   1563 				temp = xmalloc (2);
   1564 				temp[0] = fperms[j];
   1565 				temp[1] = '\0';
   1566 
   1567 				xrealloc_and_strcat (&tempfperms,
   1568 						     &tempfperms_len, temp);
   1569 				free (temp);
   1570 			    }
   1571 			    else if (fperms[j] == 'a' || fperms[j] == 'p')
   1572 			    {
   1573 				err = 1;
   1574 				*xerrmsg = xstrdup ("user has higher"
   1575 						    " permissions, cannot use"
   1576 						    " +/- tag permissions");
   1577 			    }
   1578 			    else if (fperms[j] == 'n' || fperms[i] == 'r')
   1579 			    {
   1580 				if (perms[0] == '-')
   1581 				    *xerrmsg = xstrdup ("user does not have tag"
   1582 							" ('t') permission");
   1583 			    }
   1584 			    else if (fperms[j] == 't')
   1585 			    {
   1586 				per = 1;
   1587 				if (perms[0] == '+')
   1588 				{
   1589 				    err = 1;
   1590 				    *xerrmsg = xstrdup ("user already have tag"
   1591 							" ('t') permission");
   1592 				}
   1593 			    }
   1594 			}
   1595 
   1596 			fperms = tempfperms;
   1597 			fperms_len = strlen (fperms);
   1598 
   1599 			if (!per && !err && (perms[0] == '-'))
   1600 			{
   1601 			    err = 1;
   1602 			    *xerrmsg = xstrdup ("user does not have tag ('t')"
   1603 						" permission");
   1604 			}
   1605 
   1606 			if (perms[0] == '+')
   1607 			{
   1608 			    xrealloc_and_strcat (&fperms, &fperms_len, "t");
   1609 			}
   1610 		    }
   1611 		    break;
   1612 		case 'c':
   1613 		    {
   1614 			tempfperms_len = 1;
   1615 
   1616 			tempfperms = xmalloc (tempfperms_len);
   1617 			tempfperms[0] = '\0';
   1618 
   1619 			for (j = 0; j < fperms_len; j++)
   1620 			{
   1621 			    if (fperms[j] == 'w' || fperms[j] == 't' ||
   1622 				fperms[j] == 'd')
   1623 			    {
   1624 				char *temp;
   1625 				temp = xmalloc (2);
   1626 				temp[0] = fperms[j];
   1627 				temp[1] = '\0';
   1628 
   1629 				xrealloc_and_strcat (&tempfperms,
   1630 						     &tempfperms_len, temp);
   1631 				free (temp);
   1632 			    }
   1633 			    else if (fperms[j] == 'a' || fperms[j] == 'p')
   1634 			    {
   1635 				err = 1;
   1636 				*xerrmsg = xstrdup ("user has higher"
   1637 						    " permissions, cannot use"
   1638 						    " +/- create permissions");
   1639 			    }
   1640 			    else if (fperms[j] == 'n' || fperms[i] == 'r')
   1641 			    {
   1642 				if (perms[0] == '-')
   1643 				    err = 1;
   1644 				*xerrmsg = xstrdup ("user does not have create"
   1645 						    " ('c') permission");
   1646 			    }
   1647 			    else if (fperms[j] == 'c')
   1648 			    {
   1649 				per = 1;
   1650 				if (perms[0] == '+') {
   1651 				    err = 1;
   1652 				    *xerrmsg = xstrdup ("user already have"
   1653 							" create ('c')"
   1654 							" permission");
   1655 				}
   1656 			    }
   1657 			}
   1658 
   1659 			fperms = tempfperms;
   1660 			fperms_len = strlen (fperms);
   1661 
   1662 			if (!per && !err && (perms[0] == '-')) {
   1663 			    err = 1;
   1664 			    *xerrmsg = xstrdup ("user does not have create"
   1665 						" ('c') permission");
   1666 			}
   1667 
   1668 			if (perms[0] == '+')
   1669 			{
   1670 			    xrealloc_and_strcat (&fperms, &fperms_len, "c");
   1671 			}
   1672 		    }
   1673 		    break;
   1674 		case 'd':
   1675 		    {
   1676 			tempfperms_len = 1;
   1677 
   1678 			tempfperms = xmalloc (tempfperms_len);
   1679 			tempfperms[0] = '\0';
   1680 
   1681 			for (j = 0; j < fperms_len; j++)
   1682 			{
   1683 			    if (fperms[j] == 'w' || fperms[j] == 'c' ||
   1684 				fperms[j] == 't')
   1685 			    {
   1686 				char *temp;
   1687 				temp = xmalloc (2);
   1688 				temp[0] = fperms[j];
   1689 				temp[1] = '\0';
   1690 
   1691 				xrealloc_and_strcat (&tempfperms,
   1692 						     &tempfperms_len, temp);
   1693 				free (temp);
   1694 			    }
   1695 			    else if (fperms[j] == 'a' || fperms[j] == 'p')
   1696 			    {
   1697 				err = 1;
   1698 				*xerrmsg = xstrdup ("user has higher"
   1699 						    " permissions, cannot use"
   1700 						    " +/- delete permissions");
   1701 			    }
   1702 			    else if (fperms[j] == 'n' || fperms[i] == 'r')
   1703 			    {
   1704 				if (perms[0] == '-')
   1705 				    err = 1;
   1706 				*xerrmsg = xstrdup ("user does not have delete"
   1707 						    " ('d') permission");
   1708 			    }
   1709 			    else if (fperms[j] == 'd')
   1710 			    {
   1711 				per = 1;
   1712 				if (perms[0] == '+') {
   1713 				    err = 1;
   1714 				    *xerrmsg = xstrdup ("user already have"
   1715 							" delete ('d')"
   1716 							" permission");
   1717 				}
   1718 			    }
   1719 			}
   1720 
   1721 			fperms = tempfperms;
   1722 			fperms_len = strlen (fperms);
   1723 
   1724 			if (!per && !err && (perms[0] == '-')) {
   1725 				err = 1;
   1726 				*xerrmsg = xstrdup ("user does not have delete"
   1727 						    " ('d') permission");
   1728 			}
   1729 
   1730 			if (perms[0] == '+')
   1731 			{
   1732 				xrealloc_and_strcat (&fperms, &fperms_len, "d");
   1733 			}
   1734 		    }
   1735 		    break;
   1736 		default:
   1737 		    err  = 1;
   1738 		    *xerrmsg = xstrdup ("error in 'access' file format");
   1739 		    break;
   1740 		}
   1741 
   1742 		if (fperms[0] == '\0')
   1743 		    retperms = xstrdup ("none");
   1744 		else
   1745 		    retperms = xstrdup (fperms);
   1746 	    }
   1747 	}
   1748 	else
   1749 	{
   1750 	    err = 1;
   1751 	    *xerrmsg = xstrdup("user is not given any permissions to remove/add");
   1752 	}
   1753     }
   1754     else
   1755     {
   1756 	retperms = xstrdup (perms);
   1757     }
   1758     if (fperms)
   1759 	free (fperms);
   1760     if (err && retperms)
   1761 	free (retperms);
   1762 
   1763     return (err ? NULL : retperms);
   1764 }
   1765 
   1766 /* prepare and write resulting permissions to access file */
   1767 static int
   1768 write_perms (const char *user, const char *perms, const char *founduserpart,
   1769 	     int foundline, char *otheruserparts,
   1770 	     const char *part_type, const char *part_object,
   1771 	     const char *part_tag, int pos, const char *arepos)
   1772 {
   1773     char *accessfile;
   1774     char *tmpaccessout;
   1775     FILE *accessfpin;
   1776     FILE *accessfpout;
   1777 
   1778     char *newline = NULL;
   1779     size_t newlinelen = 1;
   1780     char *object;
   1781 
   1782     char *line = NULL;
   1783     size_t line_allocated = 0;
   1784 
   1785     newline = xmalloc (newlinelen);
   1786     newline[0] = '\0';
   1787 
   1788     if (!strcasecmp (part_tag, "ALL"))
   1789 	part_tag = "ALL";
   1790 
   1791     /* strip any trailing slash if found */
   1792     object = xstrdup (part_object);
   1793     if (object[strlen (object) - 1] == '/')
   1794 	object[strlen (object) - 1] = '\0';
   1795 
   1796     /* first parts, part type, object, and tag */
   1797     xrealloc_and_strcat (&newline, &newlinelen, part_type);
   1798     xrealloc_and_strcat (&newline, &newlinelen, ":");
   1799     xrealloc_and_strcat (&newline, &newlinelen, object);
   1800     xrealloc_and_strcat (&newline, &newlinelen, ":");
   1801     xrealloc_and_strcat (&newline, &newlinelen, part_tag);
   1802     xrealloc_and_strcat (&newline, &newlinelen, ":");
   1803 
   1804     if (strncmp (perms, "none", 4) != 0)
   1805     {
   1806 	xrealloc_and_strcat (&newline, &newlinelen, user);
   1807 	xrealloc_and_strcat (&newline, &newlinelen, "!");
   1808 	xrealloc_and_strcat (&newline, &newlinelen, perms);
   1809 	if (otheruserparts != NULL)
   1810 	    xrealloc_and_strcat (&newline, &newlinelen, ",");
   1811     }
   1812 
   1813     if (otheruserparts != NULL)
   1814     {
   1815 	if (otheruserparts[strlen (otheruserparts) - 1] == '\n')
   1816 	    otheruserparts[strlen (otheruserparts) - 1] = '\0';
   1817 
   1818 	xrealloc_and_strcat (&newline, &newlinelen, otheruserparts);
   1819     }
   1820 
   1821     xrealloc_and_strcat (&newline, &newlinelen, ":");
   1822 
   1823     if (foundline)
   1824     {
   1825 	accessfpout = cvs_temp_file (&tmpaccessout);
   1826 	if (accessfpout == NULL)
   1827 	    error (1, errno, "cannot open temporary file: %s", tmpaccessout);
   1828 
   1829 	accessfpin = open_accessfile ("r", arepos, &accessfile);
   1830 	if (accessfpout == NULL)
   1831 	    error (1, errno, "cannot open access file: %s", accessfile);
   1832 
   1833 	while (getline (&line, &line_allocated, accessfpin) >= 0)
   1834 	{
   1835 	    if (pos != ftell (accessfpin))
   1836 	    {
   1837 		if (fprintf (accessfpout, "%s", line) < 0)
   1838 		    error (1, errno, "writing temporary file: %s", tmpaccessout);
   1839 	    }
   1840 	    else
   1841 	    {
   1842 		if (fprintf (accessfpout, "%s\n", newline) < 0)
   1843 		    error (1, errno, "writing temporary file: %s", tmpaccessout);
   1844 	    }
   1845 
   1846 	}
   1847 	if (fclose (accessfpin) == EOF)
   1848 		error (1, errno, "cannot close access file: %s", accessfile);
   1849 
   1850 	if (fclose (accessfpout) == EOF)
   1851 	    error (1, errno, "cannot close temporary file: %s", tmpaccessout);
   1852 
   1853 	if (CVS_UNLINK (accessfile) < 0)
   1854 	    error (0, errno, "cannot remove %s", accessfile);
   1855 
   1856 	copy_file (tmpaccessout, accessfile);
   1857 
   1858 	if (CVS_UNLINK (tmpaccessout) < 0)
   1859 	    error (0, errno, "cannot remove temporary file: %s", tmpaccessout);
   1860     }
   1861     else
   1862     {
   1863 	accessfpout = open_accessfile ("r+", arepos, &accessfile);
   1864 
   1865 	if (accessfpout == NULL)
   1866 	{
   1867 	    if (existence_error (errno))
   1868 	    {
   1869 		accessfpout = open_accessfile ("w+", arepos, &accessfile);
   1870 	    }
   1871 	    if (accessfpout == NULL)
   1872 		error (1, errno, "cannot open access file: %s", accessfile);
   1873 	}
   1874 	else {
   1875 	    if (fseek (accessfpout, 0, 2) != 0)
   1876 		error (1, errno, "cannot fseek access file: %s", accessfile);
   1877 	}
   1878 
   1879 	if (fprintf (accessfpout, "%s\n", newline) < 0)
   1880 	    error (1, errno, "writing access file: %s", accessfile);
   1881 
   1882 	if (fclose (accessfpout) == EOF)
   1883 	    error (1, errno, "cannot close access file: %s", accessfile);
   1884     }
   1885 
   1886     free (line);
   1887     free (newline);
   1888 
   1889     chmod (accessfile, 0644);
   1890 
   1891     return 0;
   1892 }
   1893 
   1894 static int
   1895 acllist_fileproc (void *callerdat, struct file_info *finfo)
   1896 {
   1897     char *filefullname;
   1898     const char *frepository;
   1899     char *line = NULL;
   1900     int pos;
   1901 
   1902     if (!aclfile)
   1903 	return 0;
   1904 
   1905     frepository = Short_Repository (finfo->repository);
   1906 
   1907     filefullname = Xasprintf("%s/%s", frepository, finfo->file);
   1908 
   1909     /* check that user, which run acl/racl command, has admin permisson,
   1910      * and also return the line with permissions from access file.  */
   1911     if (!access_allowed (finfo->file, finfo->repository, tag, 5, &line, &pos,
   1912 			 0))
   1913 	error (1, 0, "You do not have admin rights on '%s'", frepository);
   1914 
   1915     acllist_print (line, filefullname);
   1916 
   1917     free (filefullname);
   1918 
   1919     return 0;
   1920 }
   1921 
   1922 static Dtype
   1923 acllist_dirproc (void *callerdat, const char *dir, const char *repos,
   1924 		 const char *update_dir, List *entries)
   1925 {
   1926     char *line = NULL;
   1927     const char *drepository;
   1928     int pos;
   1929 
   1930     if (repos[0] == '\0')
   1931 	repos = Name_Repository (dir, NULL);
   1932 
   1933     if (!acldir)
   1934 	return 0;
   1935 
   1936     drepository = Short_Repository (repos);
   1937 
   1938     /* check that user, which run acl/racl command, has admin permisson,
   1939      * and also return the line with permissions from access file.  */
   1940     if (!access_allowed (NULL, repos, tag, 5, &line, &pos, 0))
   1941 	error (1, 0, "You do not have admin rights on '%s'", drepository);
   1942 
   1943     acllist_print (line, drepository);
   1944 
   1945     return 0;
   1946 }
   1947 
   1948 /* Prints permissions to screen with -l option */
   1949 void
   1950 acllist_print (char *line, const char *obj)
   1951 {
   1952     char *temp;
   1953     int c = 0;
   1954     int def = 0;
   1955 
   1956     char *printedusers[255];
   1957     printedusers[0] = NULL;
   1958 
   1959     if (line != NULL)
   1960     {
   1961 	temp = strtok (line, ":\t");
   1962 
   1963 	if (acldir)
   1964 	    cvs_output ("d ", 0);
   1965 	else if (aclfile)
   1966 	    cvs_output ("f ", 0);
   1967 
   1968 	temp = strtok (NULL, ":\t");
   1969 
   1970 	cvs_output(obj, 0);
   1971 	cvs_output (" | ", 0);
   1972 
   1973 	temp = strtok (NULL, ":\t");
   1974 	cvs_output (temp, 0);
   1975 	cvs_output (" | ", 0);
   1976 
   1977 	while ((temp = strtok (NULL, "!\t")) != NULL)
   1978 	{
   1979 	    if (strncmp (temp, ":", 1) == 0)
   1980 		break;
   1981 
   1982 	    if (strcmp (temp, "ALL") == 0)
   1983 	    {
   1984 		temp = strtok (NULL, ",\t");
   1985 		continue;
   1986 	    }
   1987 
   1988 	    cvs_output (temp, 0);
   1989 	    cvs_output (":", 0);
   1990 
   1991 	    while (printedusers[c] != NULL)
   1992 		c++;
   1993 
   1994 	    printedusers[c] = xstrdup (temp);
   1995 	    c++;
   1996 	    printedusers[c] = NULL;
   1997 
   1998 	    temp = strtok (NULL, ",\t");
   1999 
   2000 	    if (temp != NULL && temp[strlen (temp) - 2] == ':')
   2001 		temp[strlen (temp) - 2] = '\0';
   2002 
   2003 	    cvs_output (temp, 0);
   2004 	    cvs_output (" ", 0);
   2005 	}
   2006 
   2007 	if (default_perms_object)
   2008 	{
   2009 	    cvs_output ("| defaults ", 0);
   2010 	    cvs_output ("ALL:", 0);
   2011 	    cvs_output (default_perms_object, 0);
   2012 	    def = 1;
   2013 	}
   2014 	if (default_part_perms_accessfile)
   2015 	{
   2016 	    size_t i;
   2017 	    i = strlen (default_part_perms_accessfile);
   2018 	    xrealloc_and_strcat (&default_part_perms_accessfile, &i, ",");
   2019 
   2020 	    free (line);
   2021 	    line = xstrdup (default_part_perms_accessfile);
   2022 
   2023 	    if (!def)
   2024 		cvs_output ("| defaults ", 0);
   2025 	    else
   2026 		cvs_output (" ", 0);
   2027 
   2028 	    temp = strtok (line, "!\t");
   2029 	    cvs_output (temp, 0);
   2030 	    cvs_output (":", 0);
   2031 
   2032 	    temp = strtok (NULL, ",\t");
   2033 
   2034 	    cvs_output (temp, 0);
   2035 	    cvs_output (" ", 0);
   2036 
   2037 	    while ((temp = strtok (NULL, "!\t")) != NULL)
   2038 	    {
   2039 		int printed = 0;
   2040 		int c2 = 0;
   2041 		while (printedusers[c2] != NULL && printed == 0)
   2042 		{
   2043 		    if (strcmp (printedusers[c2], temp) == 0)
   2044 		    {
   2045 			printed = 1;
   2046 			break;
   2047 		    }
   2048 		    c2++;
   2049 		}
   2050 
   2051 		if (printed == 0)
   2052 		{
   2053 		    cvs_output (temp, 0);
   2054 		    cvs_output (":", 0);
   2055 		}
   2056 
   2057 		temp = strtok (NULL, ",\t");
   2058 
   2059 		if (temp[strlen (temp) - 2] == ':')
   2060 		    temp[strlen (temp) - 2] = '\0';
   2061 
   2062 		if (printed == 0)
   2063 		{
   2064 		    cvs_output (temp, 0);
   2065 		    cvs_output (" ", 0);
   2066 		}
   2067 	    }
   2068 	    def = 1;
   2069 	}
   2070 	else if (cvs_acl_default_permissions)
   2071 	{
   2072 	    cvs_output ("| defaults ", 0);
   2073 	    cvs_output ("ALL: ", 0);
   2074 	    cvs_output (cvs_acl_default_permissions, 0);
   2075 	}
   2076     }
   2077     else
   2078     {
   2079 	if (acldir)
   2080 	    cvs_output ("d ", 0);
   2081 	else if (aclfile)
   2082 	    cvs_output ("f ", 0);
   2083 	cvs_output (obj, 0);
   2084 	cvs_output (" | ", 0);
   2085 	cvs_output (tag, 0);
   2086 	cvs_output (" | ", 0);
   2087 
   2088 	if (default_perms_object)
   2089 	{
   2090 	    cvs_output ("| defaults ", 0);
   2091 	    cvs_output ("ALL:", 0);
   2092 	    cvs_output (default_perms_object, 0);
   2093 	    def = 1;
   2094 	}
   2095 	if (default_part_perms_accessfile)
   2096 	{
   2097 	    free (line);
   2098 	    line = xstrdup (default_part_perms_accessfile);
   2099 
   2100 	    if (!def)
   2101 		cvs_output ("| defaults ", 0);
   2102 	    else
   2103 		cvs_output (" ", 0);
   2104 
   2105 	    temp = strtok (line, "!\t");
   2106 	    cvs_output (temp, 0);
   2107 	    cvs_output (":", 0);
   2108 
   2109 	    temp = strtok (NULL, ",\t");
   2110 
   2111 	    if (temp[strlen (temp) - 2] == ':')
   2112 		temp[strlen (temp) - 2] = '\0';
   2113 
   2114 	    cvs_output (temp, 0);
   2115 	    cvs_output (" ", 0);
   2116 
   2117 	    while ((temp = strtok (NULL, "!\t")) != NULL)
   2118 	    {
   2119 		cvs_output (temp, 0);
   2120 		cvs_output (":", 0);
   2121 
   2122 		if ((temp = strtok (NULL, ",\t")) != NULL)
   2123 		{
   2124 		    if (temp[strlen (temp) - 2] == ':')
   2125 			temp[strlen (temp) - 2] = '\0';
   2126 
   2127 		    cvs_output (temp, 0);
   2128 		    cvs_output (" ", 0);
   2129 		}
   2130 	    }
   2131 	    cvs_output ("\n", 0);
   2132 	}
   2133 	else if (cvs_acl_default_permissions)
   2134 	{
   2135 	    cvs_output ("| defaults ", 0);
   2136 	    cvs_output ("ALL: ", 0);
   2137 	    cvs_output (cvs_acl_default_permissions, 0);
   2138 	}
   2139 	else
   2140 	    cvs_output ("default:p (no perms)", 0);
   2141     }
   2142     cvs_output ("\n", 0);
   2143 
   2144     while (c >= 0)  {
   2145 	free (printedusers[c]);
   2146 	c--;
   2147     }
   2148 
   2149     free (line);
   2150 }
   2151 
   2152 /* find username
   2153  * returns username with its permissions if user found
   2154  * returns NULL if user not found */
   2155 char *findusername (const char *string1, const char *string2)
   2156 {
   2157     char *tmp1, *tmp2;
   2158 
   2159     if (string1 != NULL && string2 != NULL)
   2160     {
   2161 	tmp1 = xstrdup (string1);
   2162 	tmp2 = strtok (tmp1, ",\t");
   2163 
   2164 	do
   2165 	{
   2166 	    if (strncmp (tmp2, string2, strlen (string2)) == 0 &&
   2167 				     tmp2[strlen (string2)] == '!')
   2168 	    {
   2169 		tmp2 = xstrdup (tmp2);
   2170 		free (tmp1);
   2171 		return tmp2;
   2172 	    }
   2173 	    tmp2 = strtok (NULL, ",\t");
   2174 	}
   2175 	while (tmp2 != NULL);
   2176 
   2177 	free (tmp1);
   2178 
   2179 	return NULL;
   2180     }
   2181     else
   2182 	return NULL;
   2183 }
   2184 
   2185 /* find user name in group file
   2186  * returns group name if user found
   2187  * returns NULL if user not found */
   2188 char *findgroupname (const char *string1, const char *string2)
   2189 {
   2190     char *tmp1, *tmp2;
   2191     char *grpname;
   2192 
   2193     if (string1 != NULL && string2 != NULL)
   2194     {
   2195 	tmp1 = xstrdup (string1);
   2196 	grpname = strtok (tmp1, ":\t");
   2197 
   2198 	while (tmp2 = strtok(NULL, ",\t"))
   2199 	{
   2200 	    if (strcmp (tmp2, string2) == 0)
   2201 	    {
   2202 		grpname = xstrdup (grpname);
   2203 		free (tmp1);
   2204 		return grpname;
   2205 	    }
   2206 	}
   2207 
   2208 	free (tmp1);
   2209 
   2210 	return NULL;
   2211     }
   2212     else
   2213 	return NULL;
   2214 }
   2215