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