/* Copyright (C) 1999 Beau Kuiper
this is a quick hack for ratiotool, works ok but that is all
warning, this code is not buffer overflow safe. DONT RUN AS SETUID ROOT
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "ftpd.h"
#define BYTERATIOMSK 1
#define FILERATIOMSK 2
#define BYTECREDITMSK 4
#define FILECREDITMSK 8
#define RELATIVE TRUE
#define ABSOLUTE FALSE
int lockarea(int fd, int pos, int len, int locktype, int do_wait)
{
struct flock lock;
register int err;
int lockt;
lockt = (do_wait == TRUE ? F_SETLKW : F_SETLK);
lock.l_type = locktype;
lock.l_whence = SEEK_SET;
lock.l_start = pos;
lock.l_len = len;
NOSIGNALINTR(err = fcntl(fd, lockt, &lock));
if (err == -1)
{
if (errno != EAGAIN)
exit(0);
else
return(FALSE);
}
return(TRUE);
}
void lock_n_read(RATIOHANDLE *rh)
{
if (rh->ratiofilefd != 0)
{
lockarea(rh->ratiofilefd, rh->filepos, sizeof(RATIOFILEDATA), F_WRLCK, TRUE);
lseek(rh->ratiofilefd, rh->filepos, SEEK_SET);
read(rh->ratiofilefd, rh->rdat, sizeof(RATIOFILEDATA));
}
}
void write_n_unlock(RATIOHANDLE *rh)
{
if (rh->ratiofilefd != 0)
{
lseek(rh->ratiofilefd, rh->filepos, SEEK_SET);
write(rh->ratiofilefd, rh->rdat, sizeof(RATIOFILEDATA));
lockarea(rh->ratiofilefd, rh->filepos, sizeof(RATIOFILEDATA), F_UNLCK, TRUE);
}
}
int decoderatiostr(char *ratstr, int *pa, int *pb)
{
return(sscanf(ratstr, "%d:%d", pa, pb) == 2);
}
RATIOHANDLE *getuserrh(char *filename, char *username)
{
static RATIOHANDLE rh;
static RATIOFILEDATA filedata;
int pos = 0;
rh.rdat = &filedata;
rh.ratiofilefd = open(filename, O_RDWR);
if (rh.ratiofilefd == -1)
ERRORMSGFATAL("couldn't open ratio file!");
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_WRLCK, TRUE);
while(read(rh.ratiofilefd, &filedata, sizeof(RATIOFILEDATA)) ==
sizeof(RATIOFILEDATA))
{
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_UNLCK, TRUE);
if (strcmp(filedata.username, username) == 0)
{
rh.filepos = pos;
return(&rh);
}
pos += sizeof(RATIOFILEDATA);
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_WRLCK, TRUE);
}
close(rh.ratiofilefd);
return(NULL);
}
/* this just returns a pointer to the end of the file, and checks to make user
the user doesn't exist yet */
RATIOHANDLE *adduserrh(char *filename, char *username)
{
static RATIOHANDLE rh;
static RATIOFILEDATA filedata;
int pos = 0;
rh.rdat = &filedata;
rh.ratiofilefd = open(filename, O_RDWR | O_CREAT, 0600);
if (rh.ratiofilefd == -1)
ERRORMSGFATAL("couldn't open ratio file!");
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_WRLCK, TRUE);
while(read(rh.ratiofilefd, &filedata, sizeof(RATIOFILEDATA)) ==
sizeof(RATIOFILEDATA))
{
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_UNLCK, TRUE);
if (strcmp(filedata.username, username) == 0)
{
close(rh.ratiofilefd);
return(NULL);
}
pos += sizeof(RATIOFILEDATA);
lockarea(rh.ratiofilefd, pos, sizeof(RATIOFILEDATA), F_WRLCK, TRUE);
}
rh.filepos = pos;
return(&rh);
}
void usage(void)
{
printf("\nMuddleftpd Ratio File Editor.\n\n");
printf("Usage: ratiotool [options]\n\n");
printf(" -f ratiofile The filename of the ratio file to modify\n");
printf(" -a username Adds a new username\n");
printf(" -e username Edits the properties of a username\n");
printf(" -d username Scrubs the username from the ratio file\n");
printf(" -r fileratio Sets a new file ratio for the user.\n");
printf(" -R byteratio Sets a new byte ratio for the user.\n");
printf(" -c files Sets a new file credit for the user.\n");
printf(" -C bytes Sets a new byte credit for the user.\n");
printf(" -i username Gets information about user.\n");
printf(" -h Displays this usage message.\n");
printf(" -V Displays version information.\n\n");
printf("You must specify -f and only one of -a, -e, -d or -i when running ratiotool\n\n");
exit(0);
}
void showinfo(RATIOHANDLE *rh)
{
printf("Showing ratio information for user '%s'\n", rh->rdat->username);
printf("\nThis user has the following download credits:\n\n");
if (rh->rdat->flags & BYTECREDITS)
printf("%15lld bytes\n", rh->rdat->downloadcredits / rh->rdat->byteoutmult);
if (rh->rdat->flags & FILECREDITS)
printf("%15d files\n", rh->rdat->filecredits / rh->rdat->fileoutmult);
if (rh->rdat->flags == 0)
printf("This person does not use ratios and has no credits\n");
printf("\nThis user is subject to the following ratios:\n\n");
if (rh->rdat->flags & BYTECREDITS)
printf("Byte ratio: %d:%d (ie %d bytes uploaded = %d download bytes)\n",
rh->rdat->byteinmult, rh->rdat->byteoutmult,
rh->rdat->byteoutmult, rh->rdat->byteinmult);
if (rh->rdat->flags & FILECREDITS)
printf("File ratio: %d:%d (ie %d files uploaded = %d download files)\n",
rh->rdat->fileinmult, rh->rdat->fileoutmult,
rh->rdat->fileoutmult, rh->rdat->fileinmult);
if (rh->rdat->flags == 0)
printf("This person does not use ratios.\n");
printf("\n\n");
}
void adduser(char *rationame, char *username, char *byteratio, char *fileratio,
char *filecount, char *bytecount)
{
int flags = 0;
int upb, downb, upf, downf;
int initalf;
long long int initalb;
RATIOHANDLE *rh;
if (byteratio == NULL)
{
byteratio = (char *)malloc(4096);
printf("Enter a byte ratio for the user (down:up or 'none') : ");
fgets(byteratio, 4096, stdin);
byteratio[strlen(byteratio) - 1] = 0;
}
if (fileratio == NULL)
{
fileratio = (char *)malloc(4096);
printf("Enter a file ratio for the user (down:up or 'none') : ");
fgets(fileratio, 4096, stdin);
fileratio[strlen(fileratio) - 1] = 0;
}
if (strcasecmp(byteratio, "none") != 0)
flags |= BYTECREDITS;
if (strcasecmp(fileratio, "none") != 0)
flags |= FILECREDITS;
if (flags & BYTECREDITS)
{
if (bytecount == NULL)
{
bytecount = (char *)malloc(4096);
printf("Enter an inital byte credit for the user (bytes) : ");
fgets(bytecount, 4096, stdin);
bytecount[strlen(bytecount) - 1] = 0;
}
if (sscanf(byteratio, "%d:%d", &upb, &downb) != 2)
ERRORMSGFATAL("could not decode byte ratio");
if (sscanf(bytecount, "%lld", &initalb) != 1)
ERRORMSGFATAL("could not decode inital byte credits");
initalb *= downb;
}
if (flags & FILECREDITS)
{
if (filecount == NULL)
{
filecount = (char *)malloc(4096);
printf("Enter a inital file credit for the user : ");
fgets(filecount, 4096, stdin);
filecount[strlen(filecount) - 1] = 0;
}
if (sscanf(fileratio, "%d:%d", &upf, &downf) != 2)
ERRORMSGFATAL("could not decode file ratio");
printf("%d\n", sscanf(filecount, "%d", &initalf));
if (sscanf(filecount, "%d", &initalf) != 1)
ERRORMSGFATAL("could not decode inital file credits");
initalf *= downf;
}
rh = adduserrh(rationame, username);
if (rh == NULL)
ERRORMSGFATAL("user by that name already exists in the ratio file");
lock_n_read(rh);
memset(rh->rdat, 0, sizeof(RATIOFILEDATA));
strncpy(rh->rdat->username, username, MAXNAMELEN);
rh->rdat->flags = flags;
if (flags & FILECREDITS)
{
rh->rdat->filecredits = initalf;
rh->rdat->fileinmult = (short int)upf;
rh->rdat->fileoutmult = (short int)downf;
}
if (flags & BYTECREDITS)
{
rh->rdat->downloadcredits = initalb;
rh->rdat->byteinmult = (short int)upb;
rh->rdat->byteoutmult = (short int)downb;
}
write_n_unlock(rh);
close(rh->ratiofilefd);
printf("Adding user to ratio file successful!\n");
}
void edituser(char *rationame, char *username, char *byteratio, char *fileratio,
char *filecount, char *bytecount, int edit_mask)
{
int upb, downb, upf, downf;
int initalf;
int modf = 0;
int modb = 0;
long long int initalb;
RATIOHANDLE *rh;
#define BYTERATIOMSK 1
#define FILERATIOMSK 2
#define BYTECREDITMSK 4
#define FILECREDITMSK 8
/* decode arguments */
if (edit_mask & BYTERATIOMSK)
if (strcasecmp(byteratio, "none") != 0)
if (sscanf(byteratio, "%d:%d", &upb, &downb) != 2)
ERRORMSGFATAL("could not decode byte ratio");
if (edit_mask & BYTECREDITMSK)
{
if (bytecount[0] == 'r')
{
bytecount++;
modb = RELATIVE;
}
else
modb = ABSOLUTE;
if (sscanf(bytecount, "%lld", &initalb) != 1)
ERRORMSGFATAL("could not decode byte credits");
}
if (edit_mask & FILERATIOMSK)
if (strcasecmp(fileratio, "none") != 0)
if (sscanf(fileratio, "%d:%d", &upf, &downf) != 2)
ERRORMSGFATAL("could not decode file ratio");
if (edit_mask & FILECREDITMSK)
{
if (filecount[0] == 'r')
{
modf = RELATIVE;
filecount++;
}
else
modf = ABSOLUTE;
if (sscanf(filecount, "%d", &initalf) != 1)
ERRORMSGFATAL("could not decode file credits");
}
rh = getuserrh(rationame, username);
if (rh == NULL)
ERRORMSGFATAL("Username is not in ratio file.");
lock_n_read(rh);
if (edit_mask & BYTERATIOMSK)
{
if (strcasecmp(byteratio, "none") == 0)
rh->rdat->flags &= FILECREDITS;
else
{
/* this updates the ratio and the credits */
rh->rdat->flags |= BYTECREDITS;
rh->rdat->downloadcredits /= rh->rdat->byteoutmult;
rh->rdat->byteinmult = (short int)upb;
rh->rdat->byteoutmult = (short int)downb;
rh->rdat->downloadcredits *= rh->rdat->byteoutmult;
}
}
if (edit_mask & FILERATIOMSK)
{
if (strcasecmp(fileratio, "none") == 0)
rh->rdat->flags &= BYTECREDITS;
else
{
/* this updates the ratio and the credits */
rh->rdat->flags |= FILECREDITS;
rh->rdat->filecredits /= rh->rdat->fileoutmult;
rh->rdat->fileinmult = (short int)upf;
rh->rdat->fileoutmult = (short int)downf;
rh->rdat->filecredits *= rh->rdat->fileoutmult;
}
}
if (edit_mask & BYTECREDITMSK)
{
if (modb == ABSOLUTE)
rh->rdat->downloadcredits = initalb * rh->rdat->byteoutmult;
else
rh->rdat->downloadcredits += initalb * rh->rdat->byteoutmult;
}
if (edit_mask & FILECREDITMSK)
{
if (modf == ABSOLUTE)
rh->rdat->filecredits = initalf * rh->rdat->fileoutmult;
else
rh->rdat->filecredits += initalf * rh->rdat->fileoutmult;
}
write_n_unlock(rh);
close(rh->ratiofilefd);
printf("Editing user in ratio file successful!\n");
}
void deluser(char *ratiofile, char *username)
{
RATIOHANDLE *rh;
rh = getuserrh(ratiofile, username);
if (rh == NULL)
ERRORMSGFATAL("Username is not in ratio file!");
lock_n_read(rh);
rh->rdat->username[0] = 0;
write_n_unlock(rh);
close(rh->ratiofilefd);
printf("Deleting user from ratio file successful!\n");
}
int main(int argc, char **argv)
{
int ch;
char *ratiofile = NULL;
char *username = NULL;
char *byteratio = NULL;
char *fileratio = NULL;
char *bytecount = NULL;
char *filecount = NULL;
int add_user = FALSE;
int delete_user = FALSE;
int edit_user = FALSE;
int get_info = FALSE;
int edit_mask = FALSE;
extern char *optarg;
/* stolen from smbpasswd - checking for setuid root! */
/* Check the effective uid - make sure we are not setuid */
if ((geteuid() == (uid_t)0) && (getuid() != (uid_t)0))
ERRORMSGFATAL("ratiotool must *NOT* be setuid root.\n");
while ((ch = getopt(argc, argv, "f:a:d:e:r:R:c:C:i:hV")) != EOF)
{
switch(ch)
{
case 'V':
showversion("ratiotool");
case 'f':
ratiofile = optarg;
break;
case 'a':
add_user = TRUE;
username = optarg;
break;
case 'd':
delete_user = TRUE;
username = optarg;
break;
case 'e':
edit_user = TRUE;
username = optarg;
break;
case 'r':
fileratio = optarg;
edit_mask |= FILERATIOMSK;
break;
case 'R':
byteratio = optarg;
edit_mask |= BYTERATIOMSK;
break;
case 'c':
filecount = optarg;
edit_mask |= FILECREDITMSK;
break;
case 'C':
bytecount = optarg;
edit_mask |= BYTECREDITMSK;
break;
case 'i':
username = optarg;
get_info = TRUE;
break;
case 'h':
usage();
break;
default:
usage();
}
}
if (!ratiofile)
usage();
if (add_user)
{
if (edit_user || delete_user || get_info)
usage();
adduser(ratiofile, username, byteratio, fileratio,
filecount, bytecount);
exit(0);
}
if (delete_user)
{
if (edit_user || get_info)
usage();
deluser(ratiofile, username);
exit(0);
}
if (edit_user)
{
if (!edit_mask)
usage();
edituser(ratiofile, username, byteratio, fileratio,
filecount, bytecount, edit_mask);
exit(0);
}
if (get_info)
{
RATIOHANDLE *rh;
rh = getuserrh(ratiofile, username);
if (rh == NULL)
ERRORMSGFATAL("Username is not in ratio file!");
showinfo(rh);
close(rh->ratiofilefd);
exit(0);
}
usage();
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1