xref: /netbsd/external/gpl2/xcvs/dist/src/acl.c (revision 3cd63638)
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
access_allowed(const char * file,const char * repos,const char * tag,int perm,char ** mline,int * mpos,int usecache)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
valid_tag(const char * part_tag,const char * tag)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
valid_perm(const char * part_perms,int perm)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 *
get_perms(const char * part_perms)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
cvsacl(int argc,char ** argv)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
racl_proc(int argc,char ** argv,char * xwhere,char * mwhere,char * mfile,int shorten,int local,char * mname,char * msg)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
acl_fileproc(void * callerdat,struct file_info * finfo)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
acl_dirproc(void * callerdat,const char * dir,const char * repos,const char * update_dir,List * entries)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 *
open_accessfile(char * fmode,const char * adir,char ** fname)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 *
open_groupfile(char * fmode)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
given_perms_valid(const char * cperms)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 *
make_perms(char * perms,char * founduserpart,char ** xerrmsg)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
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)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
acllist_fileproc(void * callerdat,struct file_info * finfo)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
acllist_dirproc(void * callerdat,const char * dir,const char * repos,const char * update_dir,List * entries)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
acllist_print(char * line,const char * obj)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 */
findusername(const char * string1,const char * string2)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 */
findgroupname(const char * string1,const char * string2)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