Add all our changes:

- our kerberos support
- nolock
- setuid support / setxid in child
- avoid dangerous commands and only allow admin group to execute them
- selectable CVS directory name
- symlinked repository fixes
- log admin commands in history
- default to ssh instead of rsh
- localid keyword
- null revision on re-added files
- umask fixes
- t flag in log
- don't recursively re-enter signal error handler
- xasprintf in selected places
- ipv6 support
This commit is contained in:
christos 2006-02-04 16:29:55 +00:00
parent 56ece2a214
commit 2cd25f5744
30 changed files with 528 additions and 274 deletions

View File

@ -28,12 +28,16 @@ static int admin_fileproc PROTO ((void *callerdat, struct file_info *finfo));
static const char *const admin_usage[] =
{
"Usage: %s %s [options] files...\n",
#ifndef CVS_ADMIN_LIMITED
"\t-a users Append (comma-separated) user names to access list.\n",
"\t-A file Append another file's access list.\n",
"\t-b[rev] Set default branch (highest branch on trunk if omitted).\n",
#endif
"\t-c string Set comment leader.\n",
#ifndef CVS_ADMIN_LIMITED
"\t-e[users] Remove (comma-separated) user names from access list\n",
"\t (all names if omitted).\n",
#endif
"\t-I Run interactively.\n",
"\t-k subst Set keyword substitution mode:\n",
"\t kv (Default) Substitute keyword and value.\n",
@ -42,10 +46,13 @@ static const char *const admin_usage[] =
"\t o Preserve original string.\n",
"\t b Like o, but mark file as binary.\n",
"\t v Substitute value only.\n",
#ifndef CVS_ADMIN_LIMITED
"\t-l[rev] Lock revision (latest revision on branch,\n",
"\t latest revision on trunk if omitted).\n",
"\t-L Set strict locking.\n",
#endif
"\t-m rev:msg Replace revision's log message.\n",
#ifndef CVS_ADMIN_LIMITED
"\t-n tag[:[rev]] Tag branch or revision. If :rev is omitted,\n",
"\t delete the tag; if rev is omitted, tag the latest\n",
"\t revision on the default branch.\n",
@ -58,14 +65,19 @@ static const char *const admin_usage[] =
"\t :rev rev and previous revisions on the same branch.\n",
"\t ::rev Before rev on the same branch.\n",
"\t rev Just rev.\n",
#endif
"\t-q Run quietly.\n",
#ifndef CVS_ADMIN_LIMITED
"\t-s state[:rev] Set revision state (latest revision on branch,\n",
"\t latest revision on trunk if omitted).\n",
#endif
"\t-t[file] Get descriptive text from file (stdin if omitted).\n",
"\t-t-string Set descriptive text.\n",
#ifndef CVS_ADMIN_LIMITED
"\t-u[rev] Unlock the revision (latest revision on branch,\n",
"\t latest revision on trunk if omitted).\n",
"\t-U Unset strict locking.\n",
#endif
"(Specify the --help global option for a list of other help options)\n",
NULL
};
@ -110,6 +122,11 @@ struct admin_data
int ac;
char **av;
int av_alloc;
/* This contains a printable version of the command line used
* for logging
*/
char *cmdline;
};
/* Add an argument. OPT is the option letter, e.g. 'a'. ARG is the
@ -144,20 +161,113 @@ arg_add (dat, opt, arg)
dat->av[dat->ac++] = newelt;
}
static size_t
wescape(dst, src)
char *dst;
const char *src;
{
const unsigned char *s = src;
char *d = dst;
for (; *s; s++) {
if (!isprint(*s) || isspace(*s) || *s == '|') {
*d++ = '\\';
*d++ = ((*s >> 6) & 3) + '0';
*d++ = ((*s >> 3) & 7) + '0';
*d++ = ((*s >> 0) & 7) + '0';
} else {
*d++ = *s;
}
}
*d = '\0';
return d - dst;
}
static char *
makecmdline(argc, argv)
int argc;
char **argv;
{
size_t clen = 1024, wlen = 1024, len, cpos = 0, i;
char *cmd = xmalloc(clen);
char *word = xmalloc(wlen);
for (i = 0; i < argc; i++) {
char *arg = (strncmp(argv[i], "cvs ", 4) == 0) ? argv[i] + 4 : argv[i];
len = strlen(arg);
if (len * 4 < wlen) {
wlen += len * 4;
word = xrealloc(word, wlen);
}
len = wescape(word, arg);
if (clen - cpos < len + 2) {
clen += len + 2;
cmd = xrealloc(cmd, clen);
}
memcpy(&cmd[cpos], word, len);
cpos += len;
cmd[cpos++] = ' ';
}
if (cpos != 0)
cmd[cpos - 1] = '\0';
else
cmd[cpos] = '\0';
free(word);
return cmd;
}
int
admin_group_member()
{
struct group *grp;
struct group *getgrnam();
int i;
if (CVS_admin_group == NULL)
return 1;
if ((grp = getgrnam(CVS_admin_group)) == NULL)
return 0;
{
#ifdef HAVE_GETGROUPS
gid_t *grps;
int n;
/* get number of auxiliary groups */
n = getgroups (0, NULL);
if (n < 0)
error (1, errno, "unable to get number of auxiliary groups");
grps = (gid_t *) xmalloc((n + 1) * sizeof *grps);
n = getgroups (n, grps);
if (n < 0)
error (1, errno, "unable to get list of auxiliary groups");
grps[n] = getgid();
for (i = 0; i <= n; i++)
if (grps[i] == grp->gr_gid) break;
free (grps);
if (i > n)
return 0;
#else
char *me = getcaller();
char **grnam;
for (grnam = grp->gr_mem; *grnam; grnam++)
if (strcmp (*grnam, me) == 0) break;
if (!*grnam && getgid() != grp->gr_gid)
return 0;
#endif
}
}
int
admin (argc, argv)
int argc;
char **argv;
{
int err;
#ifdef CVS_ADMIN_GROUP
struct group *grp;
struct group *getgrnam();
#endif
struct admin_data admin_data;
int c;
int i;
int only_k_option;
int only_limited_options = 1;
if (argc <= 1)
usage (admin_usage);
@ -165,17 +275,17 @@ admin (argc, argv)
wrap_setup ();
memset (&admin_data, 0, sizeof admin_data);
admin_data.cmdline = makecmdline (argc, argv);
/* TODO: get rid of `-' switch notation in admin_data. For
example, admin_data->branch should be not `-bfoo' but simply `foo'. */
optind = 0;
only_k_option = 1;
while ((c = getopt (argc, argv,
"+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
{
if (c != 'k' && c != 'q')
only_k_option = 0;
if (CVS_admin_options == NULL || strchr(CVS_admin_options, c) == NULL)
only_limited_options = 0;
switch (c)
{
@ -188,6 +298,7 @@ admin (argc, argv)
goto usage_error;
case 'b':
if (admin_data.branch != NULL)
{
error (0, 0, "duplicate 'b' option");
@ -380,49 +491,17 @@ admin (argc, argv)
argc -= optind;
argv += optind;
#ifdef CVS_ADMIN_GROUP
/* The use of `cvs admin -k' is unrestricted. However, any other
option is restricted if the group CVS_ADMIN_GROUP exists on the
server. */
/* This is only "secure" on the server, since the user could edit the
* RCS file on a local host, but some people like this kind of
* check anyhow. The alternative would be to check only when
* (server_active) rather than when not on the client.
*/
if (!current_parsed_root->isremote && !only_k_option &&
(grp = getgrnam(CVS_ADMIN_GROUP)) != NULL)
{
#ifdef HAVE_GETGROUPS
gid_t *grps;
int n;
/* get number of auxiliary groups */
n = getgroups (0, NULL);
if (n < 0)
error (1, errno, "unable to get number of auxiliary groups");
grps = (gid_t *) xmalloc((n + 1) * sizeof *grps);
n = getgroups (n, grps);
if (n < 0)
error (1, errno, "unable to get list of auxiliary groups");
grps[n] = getgid();
for (i = 0; i <= n; i++)
if (grps[i] == grp->gr_gid) break;
free (grps);
if (i > n)
error (1, 0, "usage is restricted to members of the group %s",
CVS_ADMIN_GROUP);
#else
char *me = getcaller();
char **grnam;
for (grnam = grp->gr_mem; *grnam; grnam++)
if (strcmp (*grnam, me) == 0) break;
if (!*grnam && getgid() != grp->gr_gid)
error (1, 0, "usage is restricted to members of the group %s",
CVS_ADMIN_GROUP);
#endif
}
#endif /* defined CVS_ADMIN_GROUP */
if (
/* This is only "secure" on the server, since the user could edit the
* RCS file on a local host, but some people like this kind of
* check anyhow. The alternative would be to check only when
* (server_active) rather than when not on the client.
*/
!current_parsed_root->isremote &&
!only_limited_options &&
!admin_group_member())
error (1, 0, "usage is restricted to members of the group %s",
CVS_admin_group);
for (i = 0; i < admin_data.ac; ++i)
{
@ -526,6 +605,8 @@ admin (argc, argv)
Lock_Cleanup ();
return_it:
if (admin_data.cmdline != NULL)
free (admin_data.cmdline);
if (admin_data.branch != NULL)
free (admin_data.branch);
if (admin_data.comment != NULL)
@ -570,6 +651,8 @@ admin_fileproc (callerdat, finfo)
goto exitfunc;
}
history_write ('X', finfo->update_dir, admin_data->cmdline, finfo->file,
finfo->repository);
rcs = vers->srcfile;
if (rcs == NULL)
{

View File

@ -194,7 +194,7 @@ checkout (argc, argv)
case 'p':
pipeout = 1;
run_module_prog = 0; /* don't run module prog when piping */
noexec = 1; /* so no locks will be created */
noexec = nolock = 1; /* so no locks will be created */
break;
case 'c':
cat = 1;

View File

@ -81,7 +81,7 @@ static Key_schedule sched;
/* This is needed for GSSAPI encryption. */
static gss_ctx_id_t gcontext;
static int connect_to_gserver PROTO((cvsroot_t *, int, struct hostent *));
static int connect_to_gserver PROTO((cvsroot_t *, int, const char *));
# endif /* HAVE_GSSAPI */
@ -145,7 +145,7 @@ static void handle_notified PROTO((char *, int));
static size_t try_read_from_server PROTO ((char *, size_t));
static void auth_server PROTO ((cvsroot_t *, struct buffer *, struct buffer *,
int, int, struct hostent *));
int, int));
/* We need to keep track of the list of directories we've sent to the
server. This list, along with the current CVSROOT, will help us
@ -1508,7 +1508,7 @@ handle_copy_file (args, len)
}
static void read_counted_file PROTO ((char *, char *));
static void read_counted_file PROTO ((const char *, const char *));
/* Read from the server the count for the length of a file, then read
the contents of that file and write them to FILENAME. FULLNAME is
@ -1517,8 +1517,8 @@ static void read_counted_file PROTO ((char *, char *));
use it. On error, gives a fatal error. */
static void
read_counted_file (filename, fullname)
char *filename;
char *fullname;
const char *filename;
const char *fullname;
{
char *size_string;
size_t size;
@ -3800,33 +3800,50 @@ connect_to_pserver (root, to_server_p, from_server_p, verify_only, do_gssapi)
{
int sock;
int port_number;
struct sockaddr_in client_sai;
struct hostent *hostinfo;
char no_passwd = 0; /* gets set if no password found */
struct addrinfo hints, *res, *res0 = NULL;
char pbuf[10];
int e;
struct buffer *to_server, *from_server;
sock = socket (AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO));
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
port_number = get_cvs_port_number (root);
hostinfo = init_sockaddr (&client_sai, root->hostname, port_number);
if (trace)
snprintf(pbuf, sizeof(pbuf), "%d", port_number);
e = getaddrinfo(root->hostname, pbuf, &hints, &res0);
if (e)
{
fprintf (stderr, " -> Connecting to %s(%s):%d\n",
root->hostname,
inet_ntoa (client_sai.sin_addr), port_number);
error (1, 0, "%s", gai_strerror(e));
}
sock = -1;
for (res = res0; res; res = res->ai_next) {
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock < 0)
continue;
if (trace)
{
fprintf (stderr, " -> Connecting to %s\n", root->hostname);
}
if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
close(sock);
sock = -1;
continue;
}
break;
}
freeaddrinfo(res0);
if (sock < 0)
{
error (1, 0, "connect to %s:%s failed: %s", root->hostname,
pbuf, SOCK_STRERROR (SOCK_ERRNO));
}
if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai))
< 0)
error (1, 0, "connect to %s(%s):%d failed: %s",
root->hostname,
inet_ntoa (client_sai.sin_addr),
port_number, SOCK_STRERROR (SOCK_ERRNO));
make_bufs_from_fds (sock, sock, 0, &to_server, &from_server, 1);
auth_server (root, to_server, from_server, verify_only, do_gssapi, hostinfo);
auth_server (root, to_server, from_server, verify_only, do_gssapi);
if (verify_only)
{
@ -3860,13 +3877,12 @@ connect_to_pserver (root, to_server_p, from_server_p, verify_only, do_gssapi)
static void
auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi)
cvsroot_t *root;
struct buffer *lto_server;
struct buffer *lfrom_server;
int verify_only;
int do_gssapi;
struct hostent *hostinfo;
{
char *username; /* the username we use to connect */
char no_passwd = 0; /* gets set if no password found */
@ -3896,7 +3912,7 @@ auth_server (root, lto_server, lfrom_server, verify_only, do_gssapi, hostinfo)
error (1, 0, "gserver currently only enabled for socket connections");
}
if (! connect_to_gserver (root, fd, hostinfo))
if (! connect_to_gserver (root, fd, root->hostname))
{
error (1, 0,
"authorization failed: server %s rejected access to %s",
@ -4137,7 +4153,8 @@ start_tcp_server (root, to_server, from_server)
/* We don't care about the checksum, and pass it as zero. */
status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd",
hname, realm, (unsigned long) 0, &msg_data,
hname, (char *)realm, (unsigned long) 0,
&msg_data,
&cred, sched, &laddr, &sin, "KCVSV1.0");
if (status != KSUCCESS)
error (1, 0, "kerberos authentication failed: %s",
@ -4197,10 +4214,10 @@ recv_bytes (sock, buf, need)
*/
#define BUFSIZE 1024
static int
connect_to_gserver (root, sock, hostinfo)
connect_to_gserver (root, sock, hostname)
cvsroot_t *root;
int sock;
struct hostent *hostinfo;
const char *hostname;
{
char *str;
char buf[BUFSIZE];
@ -4213,9 +4230,9 @@ connect_to_gserver (root, sock, hostinfo)
if (send (sock, str, strlen (str), 0) < 0)
error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO));
if (strlen (hostinfo->h_name) > BUFSIZE - 5)
if (strlen (hostname) > BUFSIZE - 5)
error (1, 0, "Internal error: hostname exceeds length of buffer");
sprintf (buf, "cvs@%s", hostinfo->h_name);
sprintf (buf, "cvs@%s", hostname);
tok_in.length = strlen (buf);
tok_in.value = buf;
gss_import_name (&stat_min, &tok_in, GSS_C_NT_HOSTBASED_SERVICE,
@ -4528,6 +4545,16 @@ start_server ()
error (1, 0,
"This server does not support the global -n option.");
}
if (nolock && !noexec)
{
if (have_global)
{
send_to_server ("Global_option -u\012", 0);
}
else
error (1, 0,
"This server does not support the global -u option.");
}
if (quiet)
{
if (have_global)
@ -4759,27 +4786,7 @@ start_rsh_server (root, to_server, from_server)
char *rsh_argv[10];
if (!cvs_rsh)
/* People sometimes suggest or assume that this should default
to "remsh" on systems like HPUX in which that is the
system-supplied name for the rsh program. However, that
causes various problems (keep in mind that systems such as
HPUX might have non-system-supplied versions of "rsh", like
a Kerberized one, which one might want to use). If we
based the name on what is found in the PATH of the person
who runs configure, that would make it harder to
consistently produce the same result in the face of
different people producing binary distributions. If we
based it on "remsh" always being the default for HPUX
(e.g. based on uname), that might be slightly better but
would require us to keep track of what the defaults are for
each system type, and probably would cope poorly if the
existence of remsh or rsh varies from OS version to OS
version. Therefore, it seems best to have the default
remain "rsh", and tell HPUX users to specify remsh, for
example in CVS_RSH or other such mechanisms to be devised,
if that is what they want (the manual already tells them
that). */
cvs_rsh = "rsh";
cvs_rsh = "ssh";
if (!cvs_server)
cvs_server = "cvs";
@ -4840,7 +4847,7 @@ start_rsh_server (root, to_server, from_server)
int child_pid;
if (!cvs_rsh)
cvs_rsh = "rsh";
cvs_rsh = "ssh";
if (!cvs_server)
cvs_server = "cvs";
@ -5332,8 +5339,7 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries)
* This case will happen when checking out a module defined as
* ``-a .''.
*/
cvsadm_name = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
sprintf (cvsadm_name, "%s/%s", dir, CVSADM);
xasprintf (&cvsadm_name, "%s/%s", dir, CVSADM);
dir_exists = isdir (cvsadm_name);
free (cvsadm_name);

View File

@ -1024,7 +1024,9 @@ warning: file `%s' seems to still contain conflict indicators",
xmalloc (sizeof (struct logfile_info)));
li->type = status;
li->tag = xstrdup (vers->tag);
li->rev_old = xstrdup (vers->vn_rcs);
/* If the file was re-added, we want the revision in the commitlog
to be NONE, not the previous dead revision. */
li->rev_old = status == T_ADDED ? NULL : xstrdup (vers->vn_rcs);
li->rev_new = NULL;
p->data = li;
(void) addnode (ulist, p);
@ -1176,7 +1178,8 @@ precommit_proc (repository, filter)
run_setup (filter);
run_arg (repository);
(void) walklist (saved_ulist, precommit_list_proc, NULL);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY);
return run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY|
(server_active ? 0 : RUN_UNSETXID));
}
@ -1787,9 +1790,8 @@ finaladd (finfo, rev, tag, options)
ret = Checkin ('A', finfo, rev, tag, options, saved_message);
if (ret == 0)
{
char *tmp = xmalloc (strlen (finfo->file) + sizeof (CVSADM)
+ sizeof (CVSEXT_LOG) + 10);
(void) sprintf (tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
char *tmp;
(void) xasprintf (&tmp, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
if (unlink_file (tmp) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", tmp);
@ -1970,9 +1972,8 @@ checkaddfile (file, repository, tag, options, rcsnode)
/* this is the first time we have ever seen this file; create
an RCS file. */
fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ sizeof (CVSEXT_LOG) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
(void) xasprintf (&fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG);
/* If the file does not exist, no big deal. In particular, the
server does not (yet at least) create CVSEXT_LOG files. */
if (isfile (fname))
@ -2090,9 +2091,7 @@ checkaddfile (file, repository, tag, options, rcsnode)
int retcode;
/* move the new file out of the way. */
fname = xmalloc (strlen (file) + sizeof (CVSADM)
+ sizeof (CVSPREFIX) + 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
(void) xasprintf (&fname, "%s/%s%s", CVSADM, CVSPREFIX, file);
rename_file (file, fname);
/* Create empty FILE. Can't use copy_file with a DEVNULL

View File

@ -130,38 +130,42 @@ extern int errno;
Here as #define's to make changing the names a simple task. */
#ifdef USE_VMS_FILENAMES
#define CVSADM "CVS"
#define CVSADM_ENT "CVS/Entries."
#define CVSADM_ENTBAK "CVS/Entries.Backup"
#define CVSADM_ENTLOG "CVS/Entries.Log"
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository."
#define CVSADM_ROOT "CVS/Root."
#define CVSADM_TAG "CVS/Tag."
#define CVSADM_NOTIFY "CVS/Notify."
#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
#define CVSADM_BASE "CVS/Base"
#define CVSADM_BASEREV "CVS/Baserev."
#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
#define CVSADM_TEMPLATE "CVS/Template."
#define CVSADM getCVSDir("")
#define CVSADM_ENT getCVSDir("/Entries.")
#define CVSADM_ENTBAK getCVSDir("/Entries.Backup")
#define CVSADM_ENTLOG getCVSDir("/Entries.Log")
#define CVSADM_ENTSTAT getCVSDir("/Entries.Static")
#define CVSADM_REP getCVSDir("/Repository.")
#define CVSADM_ROOT getCVSDir("/Root.")
#define CVSADM_CIPROG getCVSDir("/Checkin.prog")
#define CVSADM_UPROG getCVSDir("/Update.prog")
#define CVSADM_TAG getCVSDir("/Tag.")
#define CVSADM_NOTIFY getCVSDir("/Notify.")
#define CVSADM_NOTIFYTMP getCVSDir("/Notify.tmp")
#define CVSADM_BASE getCVSDir("/Base")
#define CVSADM_BASEREV getCVSDir("/Baserev.")
#define CVSADM_BASEREVTMP getCVSDir("/Baserev.tmp")
#define CVSADM_TEMPLATE getCVSDir("/Template.")
#else /* USE_VMS_FILENAMES */
#define CVSADM "CVS"
#define CVSADM_ENT "CVS/Entries"
#define CVSADM_ENTBAK "CVS/Entries.Backup"
#define CVSADM_ENTLOG "CVS/Entries.Log"
#define CVSADM_ENTSTAT "CVS/Entries.Static"
#define CVSADM_REP "CVS/Repository"
#define CVSADM_ROOT "CVS/Root"
#define CVSADM_TAG "CVS/Tag"
#define CVSADM_NOTIFY "CVS/Notify"
#define CVSADM_NOTIFYTMP "CVS/Notify.tmp"
#define CVSADM getCVSDir("")
#define CVSADM_ENT getCVSDir("/Entries")
#define CVSADM_ENTBAK getCVSDir("/Entries.Backup")
#define CVSADM_ENTLOG getCVSDir("/Entries.Log")
#define CVSADM_ENTSTAT getCVSDir("/Entries.Static")
#define CVSADM_REP getCVSDir("/Repository")
#define CVSADM_ROOT getCVSDir("/Root")
#define CVSADM_CIPROG getCVSDir("/Checkin.prog")
#define CVSADM_UPROG getCVSDir("/Update.prog")
#define CVSADM_TAG getCVSDir("/Tag")
#define CVSADM_NOTIFY getCVSDir("/Notify")
#define CVSADM_NOTIFYTMP getCVSDir("/Notify.tmp")
/* A directory in which we store base versions of files we currently are
editing with "cvs edit". */
#define CVSADM_BASE "CVS/Base"
#define CVSADM_BASEREV "CVS/Baserev"
#define CVSADM_BASEREVTMP "CVS/Baserev.tmp"
#define CVSADM_BASE getCVSDir("/Base")
#define CVSADM_BASEREV getCVSDir("/Baserev")
#define CVSADM_BASEREVTMP getCVSDir("/Baserev.tmp")
/* File which contains the template for use in log messages. */
#define CVSADM_TEMPLATE "CVS/Template"
#define CVSADM_TEMPLATE getCVSDir("/Template")
#endif /* USE_VMS_FILENAMES */
/* This is the special directory which we use to store various extra
@ -172,7 +176,7 @@ extern int errno;
See fileattr.h for details about file attributes, the only thing stored
in CVSREP currently. */
#define CVSREP "CVS"
#define CVSREP getCVSDir("")
/*
* Definitions for the CVSROOT Administrative directory and the files it
@ -382,8 +386,10 @@ extern int really_quiet, quiet;
extern int use_editor;
extern int cvswrite;
extern mode_t cvsumask;
extern char *RCS_citag;
extern char *CVS_admin_group;
extern char *CVS_admin_options;
extern int admin_group_member PROTO((void));
/* This global variable holds the global -d option. It is NULL if -d
was not used, which means that we must get the CVSroot information
@ -400,6 +406,7 @@ extern int safe_location PROTO ((char *));
extern int trace; /* Show all commands */
extern int noexec; /* Don't modify disk anywhere */
extern int nolock; /* Don't create locks */
extern int logoff; /* Don't write history entry */
extern int top_level_admin;
@ -453,6 +460,7 @@ List *Entries_Open PROTO ((int aflag, char *update_dir));
void Subdirs_Known PROTO((List *entries));
void Subdir_Register PROTO((List *, const char *, const char *));
void Subdir_Deregister PROTO((List *, const char *, const char *));
const char *getCVSDir PROTO((const char *));
char *Make_Date PROTO((char *rawdate));
char *date_from_time_t PROTO ((time_t));
@ -475,6 +483,8 @@ void *xrealloc PROTO((void *ptr, size_t bytes));
void expand_string PROTO ((char **, size_t *, size_t));
void xrealloc_and_strcat PROTO ((char **, size_t *, const char *));
char *xstrdup PROTO((const char *str));
int xasprintf PROTO((char ** __restrict, const char * __restrict, ...))
__attribute__((__format__(__printf__, 2, 3)));
int strip_trailing_newlines PROTO((char *str));
int pathname_levels PROTO ((const char *path));
@ -694,6 +704,7 @@ void sleep_past PROTO ((time_t desttime));
#define RUN_STDOUT_APPEND 0x0004 /* append to stdout, don't truncate */
#define RUN_STDERR_APPEND 0x0008 /* append to stderr, don't truncate */
#define RUN_SIGIGNORE 0x0010 /* ignore interrupts for command */
#define RUN_UNSETXID 0x0020 /* undo setxid in child */
#define RUN_TTY (char *)0 /* for the benefit of lint */
void run_add_arg_p PROTO ((int *, size_t *, char ***, const char *s));

View File

@ -672,11 +672,7 @@ diff_fileproc (callerdat, finfo)
if( tocvsPath != NULL )
{
/* Backup the current version of the file to CVS/,,filename */
fname = xmalloc (strlen (finfo->file)
+ sizeof CVSADM
+ sizeof CVSPREFIX
+ 10);
sprintf(fname,"%s/%s%s",CVSADM, CVSPREFIX, finfo->file);
xasprintf(&fname,"%s/%s%s",CVSADM, CVSPREFIX, finfo->file);
if (unlink_file_dir (fname) < 0)
if (! existence_error (errno))
error (1, errno, "cannot remove %s", fname);

View File

@ -341,10 +341,7 @@ edit_fileproc (callerdat, finfo)
trying to create the output file fails. But copy_file isn't
set up to facilitate that. */
mkdir_if_needed (CVSADM_BASE);
basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
strcpy (basefilename, CVSADM_BASE);
strcat (basefilename, "/");
strcat (basefilename, finfo->file);
xasprintf(&basefilename, "%s/%s", CVSADM_BASE, finfo->file);
copy_file (finfo->file, basefilename);
free (basefilename);
@ -473,10 +470,7 @@ unedit_fileproc (callerdat, finfo)
if (noexec)
return 0;
basefilename = xmalloc (10 + sizeof CVSADM_BASE + strlen (finfo->file));
strcpy (basefilename, CVSADM_BASE);
strcat (basefilename, "/");
strcat (basefilename, finfo->file);
xasprintf(&basefilename, "%s/%s", CVSADM_BASE, finfo->file);
if (!isfile (basefilename))
{
/* This file apparently was never cvs edit'd (e.g. we are uneditting

View File

@ -100,7 +100,7 @@ write_ent_proc (node, closure)
Entnode *entnode = node->data;
if (closure != NULL && entnode->type != ENT_FILE)
*(int *) closure = 1;
closure = (void *)1;
if (fputentent(entfile, entnode))
error (1, errno, "cannot write %s", entfilename);
@ -121,7 +121,7 @@ write_entries (list)
sawdir = 0;
/* open the new one and walk the list writing entries */
entfilename = CVSADM_ENTBAK;
entfilename = (char *)CVSADM_ENTBAK;
entfile = CVS_FOPEN (entfilename, "w+");
if (entfile == NULL)
{
@ -188,7 +188,7 @@ Scratch_Entry (list, fname)
{
if (!noexec)
{
entfilename = CVSADM_ENTLOG;
entfilename = (char *)CVSADM_ENTLOG;
entfile = open_file (entfilename, "a");
if (fprintf (entfile, "R ") < 0)
@ -251,7 +251,7 @@ Register (list, fname, vn, ts, options, tag, date, ts_conflict)
if (!noexec)
{
entfilename = CVSADM_ENTLOG;
entfilename = (char *)CVSADM_ENTLOG;
entfile = CVS_FOPEN (entfilename, "a");
if (entfile == NULL)
@ -659,13 +659,10 @@ WriteTag (dir, tag, date, nonbranch, update_dir, repository)
if (noexec)
return;
tmp = xmalloc ((dir ? strlen (dir) : 0)
+ sizeof (CVSADM_TAG)
+ 10);
if (dir == NULL)
(void) strcpy (tmp, CVSADM_TAG);
tmp = xstrdup(CVSADM_TAG);
else
(void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
(void) xasprintf (&tmp, "%s/%s", dir, CVSADM_TAG);
if (tag || date)
{
@ -816,7 +813,7 @@ Subdirs_Known (entries)
if (!noexec)
{
/* Create Entries.Log so that Entries_Close will do something. */
entfilename = CVSADM_ENTLOG;
entfilename = (char *)CVSADM_ENTLOG;
fp = CVS_FOPEN (entfilename, "a");
if (fp == NULL)
{
@ -856,14 +853,9 @@ subdir_record (cmd, parent, dir)
if (!noexec)
{
if (parent == NULL)
entfilename = CVSADM_ENTLOG;
entfilename = (char *)CVSADM_ENTLOG;
else
{
entfilename = xmalloc (strlen (parent)
+ sizeof CVSADM_ENTLOG
+ 10);
sprintf (entfilename, "%s/%s", parent, CVSADM_ENTLOG);
}
xasprintf (&entfilename, "%s/%s", parent, CVSADM_ENTLOG);
entfile = CVS_FOPEN (entfilename, "a");
if (entfile == NULL)
@ -1030,23 +1022,15 @@ base_walk (code, finfo, rev)
computation probably should be broken out into a separate function,
as recurse.c does it too and places like Entries_Open should be
doing it. */
baserev_fullname = xmalloc (sizeof (CVSADM_BASEREV)
+ strlen (finfo->update_dir)
+ 2);
baserev_fullname[0] = '\0';
baserevtmp_fullname = xmalloc (sizeof (CVSADM_BASEREVTMP)
+ strlen (finfo->update_dir)
+ 2);
baserevtmp_fullname[0] = '\0';
if (finfo->update_dir[0] != '\0')
{
strcat (baserev_fullname, finfo->update_dir);
strcat (baserev_fullname, "/");
strcat (baserevtmp_fullname, finfo->update_dir);
strcat (baserevtmp_fullname, "/");
xasprintf(&baserev_fullname, "%s/%s", finfo->update_dir, CVSADM_BASEREV);
xasprintf(&baserevtmp_fullname, "%s/%s",
finfo->update_dir, CVSADM_BASEREVTMP);
} else {
baserev_fullname = xstrdup(CVSADM_BASEREV);
baserevtmp_fullname = xstrdup(CVSADM_BASEREVTMP);
}
strcat (baserev_fullname, CVSADM_BASEREV);
strcat (baserevtmp_fullname, CVSADM_BASEREVTMP);
fp = CVS_FOPEN (CVSADM_BASEREV, "r");
if (fp == NULL)

View File

@ -203,6 +203,37 @@ iswritable (file)
return isaccessible(file, W_OK);
}
#ifdef SETXID_SUPPORT
int
ingroup(gid_t gid)
{
gid_t *gidp;
int i, ngroups;
if (gid == getegid())
return 1;
ngroups = getgroups(0, NULL);
if (ngroups == -1)
return 0;
if ((gidp = malloc(sizeof(gid_t) * ngroups)) == NULL)
return 0;
if (getgroups(ngroups, gidp) == -1) {
free(gidp);
return 0;
}
for (i = 0; i < ngroups; i++)
if (gid == gidp[i])
break;
free(gidp);
return i != ngroups;
}
#endif
/*
* Returns non-zero if the argument file is accessable according to
* mode. If compiled with SETXID_SUPPORT also works if cvs has setxid
@ -254,7 +285,7 @@ isaccessible (file, mode)
omask |= S_IXOTH;
}
mask = sb.st_uid == uid ? umask : sb.st_gid == getegid() ? gmask : omask;
mask = sb.st_uid == uid ? umask : ingroup(sb.st_gid) ? gmask : omask;
if ((sb.st_mode & mask) == mask)
return 1;
errno = EACCES;

View File

@ -366,7 +366,7 @@ find_dirs (dir, list, checkadm, entries)
expand_string (&tmp,
&tmp_size,
strlen (dir) + strlen (dp->d_name) + 10);
sprintf (tmp, "%s/%s", dir, dp->d_name);
snprintf (tmp, tmp_size, "%s/%s", dir, dp->d_name);
if (!isdir (tmp))
goto do_it_again;
@ -397,8 +397,8 @@ find_dirs (dir, list, checkadm, entries)
expand_string (&tmp,
&tmp_size,
(strlen (dir) + strlen (dp->d_name)
+ sizeof (CVSADM) + 10));
(void) sprintf (tmp, "%s/%s/%s", dir, dp->d_name, CVSADM);
+ strlen (CVSADM) + 10));
(void) snprintf (tmp, tmp_size, "%s/%s/%s", dir, dp->d_name, CVSADM);
if (!isdir (tmp))
goto do_it_again;
}

View File

@ -36,6 +36,7 @@
* M "Commit" cmd - "Modified" file.
* A "Commit" cmd - "Added" file.
* R "Commit" cmd - "Removed" file.
* X "Admin" cmd.
*
* date is a fixed length 8-char hex representation of a Unix time_t.
* [Starting here, variable fields are delimited by '|' chars.]
@ -760,7 +761,7 @@ history_write (type, update_dir, revs, name, repository)
if (trace)
fprintf (stderr, "%s-> fopen(%s,a)\n",
CLIENT_SERVER_STR, fname);
if (noexec)
if (nolock)
goto out;
if (!history_lock (current_parsed_root->directory))

View File

@ -12,4 +12,4 @@
* with other portions of CVS.
*/
#define ALL_HISTORY_REC_TYPES "TOEFWUPCGMAR"
#define ALL_HISTORY_REC_TYPES "TOEFWUPCGMARX"

View File

@ -33,8 +33,9 @@ static int ign_size; /* This many slots available (plus
static int ign_hold = -1; /* Index where first "temporary" item
* is held */
extern const char *cvsDir;
const char *ign_default = ". .. core RCSLOG tags TAGS RCS SCCS .make.state\
.nse_depinfo #* .#* cvslog.* ,* CVS CVS.adm .del-* *.a *.olb *.o *.obj\
.nse_depinfo #* .#* cvslog.* ,* CVS.adm .del-* *.a *.olb *.o *.obj\
*.so *.Z *~ *.old *.elc *.ln *.bak *.BAK *.orig *.rej *.exe _$* *$";
#define IGN_GROW 16 /* grow the list by 16 elements at a
@ -64,6 +65,9 @@ ign_setup ()
tmp = xstrdup (ign_default);
ign_add (tmp, 0);
free (tmp);
tmp = xstrdup(cvsDir);
ign_add (tmp, 0);
free (tmp);
/* The client handles another way, by (after it does its own ignore file
processing, and only if !ign_inhibit_server), letting the server
@ -428,8 +432,7 @@ ignore_files (ilist, entries, update_dir, proc)
this directory if there is a CVS subdirectory.
This will normally be the case, but the user may
have messed up the working directory somehow. */
p = xmalloc (strlen (file) + sizeof CVSADM + 10);
sprintf (p, "%s/%s", file, CVSADM);
xasprintf (&p, "%s/%s", file, CVSADM);
dir = isdir (p);
free (p);
if (dir)
@ -462,8 +465,7 @@ ignore_files (ilist, entries, update_dir, proc)
{
char *temp;
temp = xmalloc (strlen (file) + sizeof (CVSADM) + 10);
(void) sprintf (temp, "%s/%s", file, CVSADM);
(void) xasprintf (&temp, "%s/%s", file, CVSADM);
if (isdir (temp))
{
free (temp);

View File

@ -113,6 +113,7 @@ static void clear_lock PROTO ((struct lock *lock));
static void set_lockers_name PROTO((struct stat *statp));
static int set_writelock_proc PROTO((Node * p, void *closure));
static int unlock_proc PROTO((Node * p, void *closure));
static int find_root PROTO((const char *repository, char *rootdir));
static int write_lock PROTO ((struct lock *lock));
static void lock_simple_remove PROTO ((struct lock *lock));
static void lock_wait PROTO((char *repository));
@ -187,14 +188,19 @@ lock_name (repository, name)
{
struct stat sb;
mode_t new_mode = 0;
int len;
/* The interesting part of the repository is the part relative
to CVSROOT. */
assert (current_parsed_root != NULL);
assert (current_parsed_root->directory != NULL);
assert (strncmp (repository, current_parsed_root->directory,
strlen (current_parsed_root->directory)) == 0);
short_repos = repository + strlen (current_parsed_root->directory) + 1;
/*
* Unfortunately, string comparisons are not enough because we
* might have symlinks present
*/
len = find_root(repository, current_parsed_root->directory);
assert(len != -1);
short_repos = repository + len + 1;
if (strcmp (repository, current_parsed_root->directory) == 0)
short_repos = ".";
@ -297,6 +303,45 @@ lock_name (repository, name)
return retval;
}
/*
* Find the root directory in the repository directory
*/
static int
find_root(repository, rootdir)
const char *repository;
char *rootdir;
{
struct stat strep, stroot;
char *p = NULL, *q = NULL;
size_t len;
if (stat(rootdir, &stroot) == -1)
return -1;
len = strlen(repository);
do {
if (p != NULL) {
len = p - repository;
*p = '\0';
}
if (q != NULL)
*q = '/';
if (stat(repository, &strep) == -1) {
if (p != NULL)
*p = '/';
return -1;
}
if (strep.st_dev == stroot.st_dev && strep.st_ino == stroot.st_ino) {
if (p != NULL)
*p = '/';
if (q != NULL)
*q = '/';
return len;
}
q = p;
} while ((p = strrchr(repository, '/')) != NULL);
return -1;
}
/*
* Clean up all outstanding locks
*/
@ -416,6 +461,9 @@ Reader_Lock (xrepository)
FILE *fp;
char *tmp;
if (nolock)
return (0);
if (trace)
(void) fprintf (stderr, "%s-> Reader_Lock(%s)\n", CLIENT_SERVER_STR,
xrepository);
@ -494,6 +542,8 @@ Writer_Lock (list)
{
char *wait_repos;
if (nolock)
return (0);
if (noexec)
return 0;

View File

@ -227,6 +227,8 @@ do_editor (dir, messagep, repository, changes)
(*messagep)[strlen (*messagep) - 1] != '\n')
(void) fprintf (fp, "\n");
}
else
(void) fprintf (fp, "\n");
if (repository != NULL)
/* tack templates on if necessary */
@ -298,7 +300,7 @@ do_editor (dir, messagep, repository, changes)
run_setup (editinfo_editor ? editinfo_editor : Editor);
run_arg (fname);
if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
RUN_NORMAL | RUN_SIGIGNORE)) != 0)
RUN_NORMAL | RUN_SIGIGNORE | RUN_UNSETXID)) != 0)
error (editinfo_editor ? 1 : 0, retcode == -1 ? errno : 0,
editinfo_editor ? "Logfile verification failed" :
"warning: editor session failed");
@ -679,6 +681,15 @@ title_proc (p, closure)
strlen (str_list) + strlen (p->key) + 5);
(void) strcat (str_list, p->key);
break;
case 't':
str_list =
xrealloc (str_list,
(strlen (str_list)
+ (li->tag ? strlen (li->tag) : 0)
+ 10)
);
(void) strcat (str_list, (li->tag ? li->tag : ""));
break;
case 'V':
str_list =
xrealloc (str_list,

View File

@ -46,6 +46,7 @@ int really_quiet = 0;
int quiet = 0;
int trace = 0;
int noexec = 0;
int nolock = 0;
int logoff = 0;
/* Set if we should be writing CVSADM directories at top level. At
@ -54,6 +55,10 @@ int logoff = 0;
int top_level_admin = 0;
mode_t cvsumask = UMASK_DFLT;
char *RCS_citag = NULL;
char *CVS_admin_group = NULL;
char *CVS_admin_options = NULL;
const char *cvsDir = "CVS";
char *CurDir;
@ -243,11 +248,13 @@ static const char *const opt_usage[] =
" -r Make checked-out files read-only.\n",
" -w Make checked-out files read-write (default).\n",
" -n Do not execute anything that will change the disk.\n",
" -u Don't create locks (implies -l).\n",
" -t Show trace of program execution -- try with -n.\n",
" -v CVS version and copyright.\n",
" -T tmpdir Use 'tmpdir' for temporary files.\n",
" -e editor Use 'editor' for editing log information.\n",
" -d CVS_root Overrides $CVSROOT as the root of the CVS tree.\n",
" -D dir use DIR as the bookkeeping directory instead of CVS.\n"
" -f Do not use the ~/.cvsrc file.\n",
#ifdef CLIENT_SUPPORT
" -z # Use compression level '#' for net traffic.\n",
@ -339,6 +346,10 @@ main_cleanup (sig)
#ifndef DONT_USE_SIGNALS
const char *name;
char temp[10];
static int reenter = 0;
if (reenter++)
_exit(1);
switch (sig)
{
@ -401,7 +412,7 @@ main (argc, argv)
int help = 0; /* Has the user asked for help? This
lets us support the `cvs -H cmd'
convention to give help for cmd. */
static const char short_options[] = "+Qqrwtnvb:T:e:d:Hfz:s:xa";
static const char short_options[] = "+Qqrwtnulvb:T:e:d:D:Hfz:s:xa";
static struct option long_options[] =
{
{"help", 0, NULL, 'H'},
@ -525,6 +536,9 @@ main (argc, argv)
break;
case 'n':
noexec = 1;
case 'u': /* Fall through */
nolock = 1;
case 'l': /* Fall through */
logoff = 1;
break;
case 'v':
@ -613,6 +627,11 @@ distribution kit for a complete list of contributors and copyrights.\n",
We will issue an error later if stream
authentication is not supported. */
break;
case 'D':
cvsDir = xstrdup(optarg);
if (strchr(cvsDir, '/') != NULL)
error(1, 0, "cvsDir is not allowed to have slashes");
break;
case '?':
default:
usage (usg);
@ -887,7 +906,7 @@ distribution kit for a complete list of contributors and copyrights.\n",
/*
* Check to see if the repository exists.
*/
if (!current_parsed_root->isremote)
if (!current_parsed_root->isremote && !nolock)
{
char *path;
int save_errno;
@ -1121,6 +1140,26 @@ tm_to_internet (dest, source)
source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec);
}
const char *
getCVSDir(const char *suffix)
{
static const char *buf[20][2];
size_t i, len;
for (i = 0; i < 20; i++)
{
if (buf[i][0] == NULL)
break;
if (strcmp(buf[i][0], suffix) == 0)
return buf[i][1];
}
if (i == 20)
error(1, 0, "Out of static buffer space");
buf[i][0] = suffix;
buf[i][1] = xmalloc(len = strlen(cvsDir) + strlen(suffix) + 1);
snprintf((char *)buf[i][1], len, "%s%s", cvsDir, suffix);
return buf[i][1];
}
void
usage (cpp)
register const char *const *cpp;

View File

@ -313,6 +313,9 @@ static const char *const config_contents[] = {
"# repositories. Set it to `never' (the previous CVS behavior) to prevent\n",
"# verifymsg scripts from changing the log message.\n",
"#RereadLogAfterVerify=always\n",
"\n",
"# Set this to the name of a local tag to use in addition to Id\n",
"#tag=OurTag\n",
NULL
};
@ -871,6 +874,10 @@ init (argc, argv)
umask (cvsumask);
if (!admin_group_member())
error (1, 0, "usage is restricted to members of the group %s",
CVS_admin_group);
if (argc == -1 || argc > 1)
usage (init_usage);

View File

@ -747,7 +747,8 @@ module `%s' is a request for a file in a module which is not a directory",
cvs_output ("'\n", 0);
cvs_flushout ();
}
err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY,
RUN_NORMAL | RUN_UNSETXID);
free (expanded_path);
}
if (real_prog) free (real_prog);

View File

@ -357,6 +357,15 @@ parse_config (cvsroot)
goto error_return;
}
}
else if (strcmp (line, "tag") == 0) {
RCS_citag = xstrdup(p);
}
else if (strcmp (line, "AdminGroup") == 0) {
CVS_admin_group = xstrdup(p);
}
else if (strcmp (line, "AdminOptions") == 0) {
CVS_admin_options = xstrdup(p);
}
else if (strcmp (line, "PreservePermissions") == 0)
{
if (strcmp (p, "no") == 0)

View File

@ -803,6 +803,11 @@ patch_dirproc (callerdat, dir, repos, update_dir, entries)
static RETSIGTYPE
patch_cleanup ()
{
static int reenter = 0;
if (reenter++)
_exit(1);
/* Note that the checks for existence_error are because we are
called from a signal handler, without SIG_begincrsect, so
we don't know whether the files got created. */

View File

@ -3534,7 +3534,7 @@ struct rcs_keyword
size_t len;
};
#define KEYWORD_INIT(s) (s), sizeof (s) - 1
static const struct rcs_keyword keywords[] =
static struct rcs_keyword keywords[] =
{
{ KEYWORD_INIT ("Author") },
{ KEYWORD_INIT ("Date") },
@ -3547,6 +3547,7 @@ static const struct rcs_keyword keywords[] =
{ KEYWORD_INIT ("Revision") },
{ KEYWORD_INIT ("Source") },
{ KEYWORD_INIT ("State") },
{ NULL, 0 },
{ NULL, 0 }
};
enum keyword
@ -3561,7 +3562,8 @@ enum keyword
KEYWORD_RCSFILE,
KEYWORD_REVISION,
KEYWORD_SOURCE,
KEYWORD_STATE
KEYWORD_STATE,
KEYWORD_LOCALID
};
/* Convert an RCS date string into a readable string. This is like
@ -3698,6 +3700,11 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
return;
}
if (RCS_citag != NULL) {
keywords[KEYWORD_LOCALID].string = RCS_citag;
keywords[KEYWORD_LOCALID].len = strlen(RCS_citag);
}
/* If we are using -kkvl, dig out the locker information if any. */
locker = NULL;
if (expand == KFLAG_KVL)
@ -3789,6 +3796,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen)
case KEYWORD_HEADER:
case KEYWORD_ID:
case KEYWORD_LOCALID:
{
const char *path;
int free_path;
@ -4462,7 +4470,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat)
if (info != NULL)
{
/* If the size of `devtype' changes, fix the sscanf call also */
char devtype[16];
char devtype[16+1];
if (sscanf (info->data, "%15s %lu",
devtype, &devnum_long) < 2)
@ -8464,6 +8472,10 @@ count_delta_actions (np, ignore)
RETSIGTYPE
rcs_cleanup ()
{
static int reenter = 0;
if (reenter++)
_exit(1);
/* Note that the checks for existence_error are because we are
called from a signal handler, so we don't know whether the
files got created. */

View File

@ -551,7 +551,7 @@ do_recursion (frame)
if (frame->flags == R_SKIP_ALL)
return (0);
locktype = noexec ? CVS_LOCK_NONE : frame->locktype;
locktype = nolock ? CVS_LOCK_NONE : frame->locktype;
/* The fact that locks are not active here is what makes us fail to have
the
@ -1009,8 +1009,8 @@ but CVS uses %s for its own purposes; skipping %s directory",
char *cvsadmdir;
cvsadmdir = xmalloc (strlen (dir)
+ sizeof (CVSADM_REP)
+ sizeof (CVSADM_ENT)
+ strlen (CVSADM_REP)
+ strlen (CVSADM_ENT)
+ 80);
strcpy (cvsadmdir, dir);

View File

@ -204,11 +204,7 @@ remove_fileproc (callerdat, finfo)
* remove the ,t file for it and scratch it from the
* entries file. */
Scratch_Entry (finfo->entries, finfo->file);
fname = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSEXT_LOG)
+ 10);
(void) sprintf (fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
(void) xasprintf (&fname, "%s/%s%s", CVSADM, finfo->file, CVSEXT_LOG);
if (unlink_file (fname) < 0
&& !existence_error (errno))
error (0, errno, "cannot remove %s", CVSEXT_LOG);

View File

@ -42,10 +42,7 @@ Name_Repository (dir, update_dir)
xupdate_dir = ".";
if (dir != NULL)
{
tmp = xmalloc (strlen (dir) + sizeof (CVSADM_REP) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_REP);
}
(void) xasprintf (&tmp, "%s/%s", dir, CVSADM_REP);
else
tmp = xstrdup (CVSADM_REP);
@ -61,10 +58,7 @@ Name_Repository (dir, update_dir)
char *cvsadm;
if (dir != NULL)
{
cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
}
(void) xasprintf (&cvsadm, "%s/%s", dir, CVSADM);
else
cvsadm = xstrdup (CVSADM);

View File

@ -50,10 +50,8 @@ Name_Root (dir, update_dir)
if (dir != NULL)
{
cvsadm = xmalloc (strlen (dir) + sizeof (CVSADM) + 10);
(void) sprintf (cvsadm, "%s/%s", dir, CVSADM);
tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
(void) xasprintf (&cvsadm, "%s/%s", dir, CVSADM);
(void) xasprintf (&tmp, "%s/%s", dir, CVSADM_ROOT);
}
else
{
@ -155,10 +153,7 @@ Create_Root (dir, rootdir)
if (rootdir != NULL)
{
if (dir != NULL)
{
tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ROOT) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ROOT);
}
(void) xasprintf (&tmp, "%s/%s", dir, CVSADM_ROOT);
else
tmp = xstrdup (CVSADM_ROOT);

View File

@ -208,6 +208,13 @@ run_exec (stin, stout, sterr, flags)
#endif
if (pid == 0)
{
#ifdef SETXID_SUPPORT
if (flags & RUN_UNSETXID) {
(void) setgid (getgid ());
(void) setuid (getuid ());
}
#endif
if (shin != 0)
{
(void) dup2 (shin, 0);

View File

@ -782,6 +782,7 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
nothing. But for rsh, we need to do it now. */
parse_config (current_parsed_root->directory);
if (!nolock) {
path = xmalloc (strlen (current_parsed_root->directory)
+ sizeof (CVSROOTADM)
+ 2);
@ -799,6 +800,7 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"",
pending_error = save_errno;
}
free (path);
}
#ifdef HAVE_PUTENV
env = xmalloc (strlen (CVSROOT_ENV) + strlen (current_parsed_root->directory) + 2);
@ -2285,6 +2287,9 @@ serve_global_option (arg)
noexec = 1;
logoff = 1;
break;
case 'u':
nolock = 1;
break;
case 'q':
quiet = 1;
break;
@ -4796,6 +4801,8 @@ struct request requests[] =
REQ_LINE("Max-dotdot", serve_max_dotdot, 0),
REQ_LINE("Static-directory", serve_static_directory, 0),
REQ_LINE("Sticky", serve_sticky, 0),
REQ_LINE("Checkin-prog", serve_noop, 0),
REQ_LINE("Update-prog", serve_noop, 0),
REQ_LINE("Entry", serve_entry, RQ_ESSENTIAL),
REQ_LINE("Kopt", serve_kopt, 0),
REQ_LINE("Checkin-time", serve_checkin_time, 0),
@ -5306,6 +5313,7 @@ switch_to_user (cvs_username, username)
const char *username;
{
struct passwd *pw;
int rc;
pw = getpwnam (username);
if (pw == NULL)
@ -5384,7 +5392,14 @@ error 0 %s: no such system user\n", username);
}
}
if (setuid (pw->pw_uid) < 0)
#ifdef SETXID_SUPPORT
/* Honor the setuid bit iff set. */
if (getuid() != geteuid())
rc = setuid (geteuid ());
else
#endif
rc = setuid (pw->pw_uid);
if (rc < 0)
{
/* Note that this means that if run as a non-root user,
CVSROOT/passwd must contain the user we are running as
@ -5953,19 +5968,20 @@ kserver_authenticate_connection ()
{
int status;
char instance[INST_SZ];
struct sockaddr_in peer;
struct sockaddr_in laddr;
int len;
struct sockaddr_storage peer;
struct sockaddr_storage laddr;
int plen, llen;
KTEXT_ST ticket;
AUTH_DAT auth;
char version[KRB_SENDAUTH_VLEN];
char user[ANAME_SZ];
strcpy (instance, "*");
len = sizeof peer;
if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &len) < 0
plen = sizeof peer;
llen = sizeof laddr;
if (getpeername (STDIN_FILENO, (struct sockaddr *) &peer, &plen) < 0
|| getsockname (STDIN_FILENO, (struct sockaddr *) &laddr,
&len) < 0)
&llen) < 0)
{
printf ("E Fatal error, aborting.\n\
error %s getpeername or getsockname failed\n", strerror (errno));
@ -5990,7 +6006,8 @@ error %s getpeername or getsockname failed\n", strerror (errno));
#endif
status = krb_recvauth (KOPT_DO_MUTUAL, STDIN_FILENO, &ticket, "rcmd",
instance, &peer, &laddr, &auth, "", sched,
instance, (struct sockaddr_in *)&peer,
(struct sockaddr_in *)&laddr, &auth, "", sched,
version);
if (status != KSUCCESS)
{
@ -6342,7 +6359,7 @@ krb_encrypt_input (fnclosure, input, output, size)
struct krb_encrypt_data *kd = (struct krb_encrypt_data *) fnclosure;
int tcount;
des_cbc_encrypt ((C_Block *) input, (C_Block *) output,
des_cbc_encrypt ((char *) input, (char *) output,
size, kd->sched, &kd->block, 0);
/* SIZE is the size of the buffer, which is set by the encryption
@ -6389,7 +6406,7 @@ krb_encrypt_output (fnclosure, input, output, size, translated)
fail over a long network connection. We trust krb_recvauth to
guard against a replay attack. */
des_cbc_encrypt ((C_Block *) input, (C_Block *) output, aligned,
des_cbc_encrypt ((char *) input, (char *) output, aligned,
kd->sched, &kd->block, 1);
*translated = aligned;

View File

@ -16,6 +16,7 @@
#include <assert.h>
#include "cvs.h"
#include "getline.h"
#include <stdarg.h>
#ifdef HAVE_NANOSLEEP
# include "xtime.h"
@ -81,6 +82,21 @@ xrealloc (ptr, bytes)
return (cp);
}
int
xasprintf(char **buf, const char *fmt, ...)
{
int len;
va_list ap;
va_start(ap, fmt);
len = vasprintf(buf, fmt, ap);
va_end(ap);
if (len == -1)
error(1, 0, "out of memory: xasprintf(..., \"%s\", ...) failed", fmt);
return len;
}
/* Two constants which tune expand_string. Having MIN_INCR as large
as 1024 might waste a bit of memory, but it shouldn't be too bad
(CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often),

View File

@ -1411,8 +1411,6 @@ Numeric tag %s contains characters other than digits and '.'", name);
add_to_val_tags (name);
}
/*
* Check whether a join tag is valid. This is just like
* tag_check_valid, but we must stop before the colon if there is one.

View File

@ -977,8 +977,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries)
{
char *tmp;
tmp = xmalloc (strlen (dir) + sizeof (CVSADM_ENTSTAT) + 10);
(void) sprintf (tmp, "%s/%s", dir, CVSADM_ENTSTAT);
(void) xasprintf (&tmp, "%s/%s", dir, CVSADM_ENTSTAT);
if (unlink_file (tmp) < 0 && ! existence_error (errno))
error (1, errno, "cannot remove file %s", tmp);
#ifdef SERVER_SUPPORT
@ -1234,11 +1233,7 @@ checkout_file (finfo, vers_ts, adding, merging, update_server)
we are the server. */
if (!pipeout && !server_active)
{
backup = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSPREFIX)
+ 10);
(void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
(void) xasprintf (&backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
if (isfile (finfo->file))
rename_file (finfo->file, backup);
else
@ -1341,11 +1336,18 @@ VERS: ", 0);
xchmod (finfo->file, 1);
else
{
mode_t oumask, writeaccess;
/* We know that we are the server here, so
although xchmod checks umask, we don't bother. */
mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
/* Not bothering with the umask makes the files
mode 0777 on old clients, though. -chb */
oumask = umask(0);
(void) umask(oumask);
writeaccess = (((mode & S_IRUSR) ? S_IWUSR : 0)
| ((mode & S_IRGRP) ? S_IWGRP : 0)
| ((mode & S_IROTH) ? S_IWOTH : 0));
mode |= (~oumask) & writeaccess;
}
}
@ -1605,11 +1607,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
return 0;
}
backup = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSPREFIX)
+ 10);
(void) sprintf (backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
(void) xasprintf (&backup, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
if (isfile (finfo->file))
rename_file (finfo->file, backup);
else
@ -1619,16 +1617,8 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum)
error (0, errno, "cannot remove %s", backup);
}
file1 = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSPREFIX)
+ 10);
(void) sprintf (file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
file2 = xmalloc (strlen (finfo->file)
+ sizeof (CVSADM)
+ sizeof (CVSPREFIX)
+ 10);
(void) sprintf (file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
(void) xasprintf (&file1, "%s/%s%s-1", CVSADM, CVSPREFIX, finfo->file);
(void) xasprintf (&file2, "%s/%s%s-2", CVSADM, CVSPREFIX, finfo->file);
fail = 0;