Thu Mar 8 20:34:35 2012 UTC ()
- restrict tag command to non-destructive operations for non-admins.
  [deletion, moving is dissallowed]
- add history for tag commands
- cvs acl support


(christos)
diff -r1.2 -r1.3 src/external/gpl2/xcvs/dist/src/tag.c

cvs diff -r1.2 -r1.3 src/external/gpl2/xcvs/dist/src/tag.c (expand / switch to unified diff)

--- src/external/gpl2/xcvs/dist/src/tag.c 2009/04/10 11:20:30 1.2
+++ src/external/gpl2/xcvs/dist/src/tag.c 2012/03/08 20:34:35 1.3
@@ -8,26 +8,27 @@ @@ -8,26 +8,27 @@
8 * Portions Copyright (C) 1989-1992, Brian Berliner 8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *  9 *
10 * You may distribute under the terms of the GNU General Public License as 10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution. 11 * specified in the README file that comes with the CVS source distribution.
12 * 12 *
13 * Tag and Rtag 13 * Tag and Rtag
14 * 14 *
15 * Add or delete a symbolic name to an RCS file, or a collection of RCS files. 15 * Add or delete a symbolic name to an RCS file, or a collection of RCS files.
16 * Tag uses the checked out revision in the current directory, rtag uses 16 * Tag uses the checked out revision in the current directory, rtag uses
17 * the modules database, if necessary. 17 * the modules database, if necessary.
18 */ 18 */
19 19
20#include "cvs.h" 20#include "cvs.h"
 21#include <grp.h>
21#include "save-cwd.h" 22#include "save-cwd.h"
22 23
23static int rtag_proc (int argc, char **argv, char *xwhere, 24static int rtag_proc (int argc, char **argv, char *xwhere,
24 char *mwhere, char *mfile, int shorten, 25 char *mwhere, char *mfile, int shorten,
25 int local_specified, char *mname, char *msg); 26 int local_specified, char *mname, char *msg);
26static int check_fileproc (void *callerdat, struct file_info *finfo); 27static int check_fileproc (void *callerdat, struct file_info *finfo);
27static int check_filesdoneproc (void *callerdat, int err, 28static int check_filesdoneproc (void *callerdat, int err,
28 const char *repos, const char *update_dir, 29 const char *repos, const char *update_dir,
29 List *entries); 30 List *entries);
30static int pretag_proc (const char *_repository, const char *_filter, 31static int pretag_proc (const char *_repository, const char *_filter,
31 void *_closure); 32 void *_closure);
32static void masterlist_delproc (Node *_p); 33static void masterlist_delproc (Node *_p);
33static void tag_delproc (Node *_p); 34static void tag_delproc (Node *_p);
@@ -96,44 +97,49 @@ static const char *const tag_usage[] = @@ -96,44 +97,49 @@ static const char *const tag_usage[] =
96 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n", 97 "\t-B\tAllows -F and -d to disturb branch tags. Use with extreme care.\n",
97 "\t-c\tCheck that working files are unmodified.\n", 98 "\t-c\tCheck that working files are unmodified.\n",
98 "\t-d\tDelete the given tag.\n", 99 "\t-d\tDelete the given tag.\n",
99 "\t-F\tMove tag if it already exists.\n", 100 "\t-F\tMove tag if it already exists.\n",
100 "\t-f\tForce a head revision match if tag/date not found.\n", 101 "\t-f\tForce a head revision match if tag/date not found.\n",
101 "\t-l\tLocal directory only, not recursive.\n", 102 "\t-l\tLocal directory only, not recursive.\n",
102 "\t-R\tProcess directories recursively.\n", 103 "\t-R\tProcess directories recursively.\n",
103 "\t-r rev\tExisting revision/tag.\n", 104 "\t-r rev\tExisting revision/tag.\n",
104 "\t-D\tExisting date.\n", 105 "\t-D\tExisting date.\n",
105 "(Specify the --help global option for a list of other help options)\n", 106 "(Specify the --help global option for a list of other help options)\n",
106 NULL 107 NULL
107}; 108};
108 109
109 110char *UserTagOptions = "bcflRrD";
110 111
111int 112int
112cvstag (int argc, char **argv) 113cvstag (int argc, char **argv)
113{ 114{
 115 struct group *grp;
114 bool local = false; /* recursive by default */ 116 bool local = false; /* recursive by default */
115 int c; 117 int c;
116 int err = 0; 118 int err = 0;
117 bool run_module_prog = true; 119 bool run_module_prog = true;
 120 int only_allowed_options;
118 121
119 is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0); 122 is_rtag = (strcmp (cvs_cmd_name, "rtag") == 0);
120 123
121 if (argc == -1) 124 if (argc == -1)
122 usage (is_rtag ? rtag_usage : tag_usage); 125 usage (is_rtag ? rtag_usage : tag_usage);
123 126
124 getoptreset (); 127 getoptreset ();
 128 only_allowed_options = 1;
125 while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1) 129 while ((c = getopt (argc, argv, is_rtag ? rtag_opts : tag_opts)) != -1)
126 { 130 {
 131 if (!strchr(UserTagOptions, c))
 132 only_allowed_options = 0;
127 switch (c) 133 switch (c)
128 { 134 {
129 case 'a': 135 case 'a':
130 attic_too = true; 136 attic_too = true;
131 break; 137 break;
132 case 'b': 138 case 'b':
133 branch_mode = true; 139 branch_mode = true;
134 break; 140 break;
135 case 'B': 141 case 'B':
136 disturb_branch_tags = true; 142 disturb_branch_tags = true;
137 break; 143 break;
138 case 'c': 144 case 'c':
139 check_uptodate = true; 145 check_uptodate = true;
@@ -183,26 +189,62 @@ cvstag (int argc, char **argv) @@ -183,26 +189,62 @@ cvstag (int argc, char **argv)
183 189
184 if (argc < (is_rtag ? 2 : 1)) 190 if (argc < (is_rtag ? 2 : 1))
185 usage (is_rtag ? rtag_usage : tag_usage); 191 usage (is_rtag ? rtag_usage : tag_usage);
186 symtag = argv[0]; 192 symtag = argv[0];
187 argc--; 193 argc--;
188 argv++; 194 argv++;
189 195
190 if (date && delete_flag) 196 if (date && delete_flag)
191 error (1, 0, "-d makes no sense with a date specification."); 197 error (1, 0, "-d makes no sense with a date specification.");
192 if (delete_flag && branch_mode) 198 if (delete_flag && branch_mode)
193 error (0, 0, "warning: -b ignored with -d options"); 199 error (0, 0, "warning: -b ignored with -d options");
194 RCS_check_tag (symtag); 200 RCS_check_tag (symtag);
195 201
 202#ifdef CVS_ADMIN_GROUP
 203 if (!only_allowed_options &&
 204 (grp = getgrnam(CVS_ADMIN_GROUP)) != NULL)
 205 {
 206#ifdef HAVE_GETGROUPS
 207 gid_t *grps;
 208 int i, n;
 209
 210 /* get number of auxiliary groups */
 211 n = getgroups (0, NULL);
 212 if (n < 0)
 213 error (1, errno, "unable to get number of auxiliary groups");
 214 grps = (gid_t *) xmalloc((n + 1) * sizeof *grps);
 215 n = getgroups (n, grps);
 216 if (n < 0)
 217 error (1, errno, "unable to get list of auxiliary groups");
 218 grps[n] = getgid();
 219 for (i = 0; i <= n; i++)
 220 if (grps[i] == grp->gr_gid) break;
 221 free (grps);
 222 if (i > n)
 223 error (1, 0, "usage is restricted to members of the group %s",
 224 CVS_ADMIN_GROUP);
 225#else
 226 char *me = getcaller();
 227 char **grnam;
 228
 229 for (grnam = grp->gr_mem; *grnam; grnam++)
 230 if (strcmp (*grnam, me) == 0) break;
 231 if (!*grnam && getgid() != grp->gr_gid)
 232 error (1, 0, "usage is restricted to members of the group %s",
 233 CVS_ADMIN_GROUP);
 234#endif
 235 }
 236#endif /* defined CVS_ADMIN_GROUP */
 237
196#ifdef CLIENT_SUPPORT 238#ifdef CLIENT_SUPPORT
197 if (current_parsed_root->isremote) 239 if (current_parsed_root->isremote)
198 { 240 {
199 /* We're the client side. Fire up the remote server. */ 241 /* We're the client side. Fire up the remote server. */
200 start_server (); 242 start_server ();
201  243
202 ign_setup (); 244 ign_setup ();
203 245
204 if (attic_too) 246 if (attic_too)
205 send_arg ("-a"); 247 send_arg ("-a");
206 if (branch_mode) 248 if (branch_mode)
207 send_arg ("-b"); 249 send_arg ("-b");
208 if (disturb_branch_tags) 250 if (disturb_branch_tags)
@@ -261,26 +303,33 @@ cvstag (int argc, char **argv) @@ -261,26 +303,33 @@ cvstag (int argc, char **argv)
261 { 303 {
262 /* XXX last arg should be repository, but doesn't make sense here */ 304 /* XXX last arg should be repository, but doesn't make sense here */
263 history_write ('T', (delete_flag ? "D" : (numtag ? numtag : 305 history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
264 (date ? date : "A"))), symtag, argv[i], ""); 306 (date ? date : "A"))), symtag, argv[i], "");
265 err += do_module (db, argv[i], TAG, 307 err += do_module (db, argv[i], TAG,
266 delete_flag ? "Untagging" : "Tagging", 308 delete_flag ? "Untagging" : "Tagging",
267 rtag_proc, NULL, 0, local, run_module_prog, 309 rtag_proc, NULL, 0, local, run_module_prog,
268 0, symtag); 310 0, symtag);
269 } 311 }
270 close_module (db); 312 close_module (db);
271 } 313 }
272 else 314 else
273 { 315 {
 316 int i;
 317 for (i = 0; i < argc; i++)
 318 {
 319 /* XXX last arg should be repository, but doesn't make sense here */
 320 history_write ('T', (delete_flag ? "D" : (numtag ? numtag :
 321 (date ? date : "A"))), symtag, argv[i], "");
 322 }
274 err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL, 323 err = rtag_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
275 NULL); 324 NULL);
276 } 325 }
277 326
278 return err; 327 return err;
279} 328}
280 329
281 330
282 331
283struct pretag_proc_data { 332struct pretag_proc_data {
284 List *tlist; 333 List *tlist;
285 bool delete_flag; 334 bool delete_flag;
286 bool force_tag_move; 335 bool force_tag_move;
@@ -938,26 +987,45 @@ rtag_fileproc (void *callerdat, struct f @@ -938,26 +987,45 @@ rtag_fileproc (void *callerdat, struct f
938 /* find the parsed RCS data */ 987 /* find the parsed RCS data */
939 if ((rcsfile = finfo->rcs) == NULL) 988 if ((rcsfile = finfo->rcs) == NULL)
940 { 989 {
941 retval = 1; 990 retval = 1;
942 goto free_vars_and_return; 991 goto free_vars_and_return;
943 } 992 }
944 993
945 /* 994 /*
946 * For tagging an RCS file which is a symbolic link, you'd best be 995 * For tagging an RCS file which is a symbolic link, you'd best be
947 * running with RCS 5.6, since it knows how to handle symbolic links 996 * running with RCS 5.6, since it knows how to handle symbolic links
948 * correctly without breaking your link! 997 * correctly without breaking your link!
949 */ 998 */
950 999
 1000/* cvsacl patch */
 1001#ifdef SERVER_SUPPORT
 1002 if (use_cvs_acl /* && server_active */)
 1003 {
 1004 if (!access_allowed (finfo->file, finfo->repository, numtag, 4,
 1005 NULL, NULL, 1))
 1006 {
 1007 if (stop_at_first_permission_denied)
 1008 error (1, 0, "permission denied for %s",
 1009 Short_Repository (finfo->repository));
 1010 else
 1011 error (0, 0, "permission denied for %s/%s",
 1012 Short_Repository (finfo->repository), finfo->file);
 1013
 1014 return (0);
 1015 }
 1016 }
 1017#endif
 1018
951 if (delete_flag) 1019 if (delete_flag)
952 { 1020 {
953 retval = rtag_delete (rcsfile); 1021 retval = rtag_delete (rcsfile);
954 goto free_vars_and_return; 1022 goto free_vars_and_return;
955 } 1023 }
956 1024
957 /* 1025 /*
958 * If we get here, we are adding a tag. But, if -a was specified, we 1026 * If we get here, we are adding a tag. But, if -a was specified, we
959 * need to check to see if a -r or -D option was specified. If neither 1027 * need to check to see if a -r or -D option was specified. If neither
960 * was specified and the file is in the Attic, remove the tag. 1028 * was specified and the file is in the Attic, remove the tag.
961 */ 1029 */
962 if (attic_too && (!numtag && !date)) 1030 if (attic_too && (!numtag && !date))
963 { 1031 {
@@ -1157,26 +1225,41 @@ tag_fileproc (void *callerdat, struct fi @@ -1157,26 +1225,41 @@ tag_fileproc (void *callerdat, struct fi
1157 int retcode = 0; 1225 int retcode = 0;
1158 int retval = 0; 1226 int retval = 0;
1159 static bool valtagged = false; 1227 static bool valtagged = false;
1160 1228
1161 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); 1229 vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0);
1162 1230
1163 if (numtag || date) 1231 if (numtag || date)
1164 { 1232 {
1165 nversion = RCS_getversion (vers->srcfile, numtag, date, 1233 nversion = RCS_getversion (vers->srcfile, numtag, date,
1166 force_tag_match, NULL); 1234 force_tag_match, NULL);
1167 if (!nversion) 1235 if (!nversion)
1168 goto free_vars_and_return; 1236 goto free_vars_and_return;
1169 } 1237 }
 1238
 1239/* cvsacl patch */
 1240#ifdef SERVER_SUPPORT
 1241 if (use_cvs_acl /* && server_active */)
 1242 {
 1243 if (!access_allowed (finfo->file, finfo->repository, vers->tag, 4,
 1244 NULL, NULL, 1))
 1245 {
 1246 error (0, 0, "permission denied for %s/%s",
 1247 Short_Repository (finfo->repository), finfo->file);
 1248 return (0);
 1249 }
 1250 }
 1251#endif
 1252
1170 if (delete_flag) 1253 if (delete_flag)
1171 { 1254 {
1172 1255
1173 int isbranch; 1256 int isbranch;
1174 /* 1257 /*
1175 * If -d is specified, "force_tag_match" is set, so that this call to 1258 * If -d is specified, "force_tag_match" is set, so that this call to
1176 * RCS_getversion() will return a NULL version string if the symbolic 1259 * RCS_getversion() will return a NULL version string if the symbolic
1177 * tag does not exist in the RCS file. 1260 * tag does not exist in the RCS file.
1178 * 1261 *
1179 * This is done here because it's MUCH faster than just blindly calling 1262 * This is done here because it's MUCH faster than just blindly calling
1180 * "rcs" to remove the tag... trust me. 1263 * "rcs" to remove the tag... trust me.
1181 */ 1264 */
1182 1265