/* Copyright (C) 1999 Beau Kuiper
this is a quick hack for mudpasswd, servicable 1 nighter
this has had some more work on it now, it is safer to use and can't
destroy your password file
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 "../config.h"
#define FALSE 0
#define TRUE !FALSE
#define MAXSTRLEN 4096
#define ERRORMSGFATAL(x) { printf("mudpasswd: %s\n", x); exit(1); }
#define NOSIGNALINTR(x) (x)
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#define ROOTMSK 1
#define HOMEMSK 2
#define PASSMSK 4
extern void showversion(char *desc);
char *strsplit(char *in, char *cmd, char *data)
{
int pos = 0;
int pos2 = 0;
if (in[strlen(in) - 1] == 10)
in[strlen(in) - 1] = 0;
while((in[pos] <= 32) && (in[pos] != 0))
pos++;
if ((in[pos] == '#') || (in[pos] == 0))
return(NULL);
while((in[pos] != 32) && (in[pos] != 0))
{
cmd[pos2] = in[pos];
pos2++;
pos++;
}
if (in[pos] == 0)
return(NULL);
cmd[pos2] = 0;
while((in[pos] <= 32) && (in[pos] != 0))
pos++;
if (in[pos] == 0)
return(NULL);
pos2 = 0;
while((in[pos] != 32) && (in[pos] != 0) && (in[pos] != '\n'))
{
if ((in[pos] == '\\') && (in[pos+1] != 0))
pos++;
data[pos2] = in[pos];
pos2++;
pos++;
}
data[pos2] = 0;
return(data);
}
char getsaltchar(void)
{
char outchr;
outchr = random() & 63;
if (outchr < 26)
outchr += 'A';
else if (outchr < 52)
outchr += 'a' - 26;
else if (outchr < 62)
outchr += '0' - 52;
else if (outchr == 62)
outchr = '.';
else
outchr = '/';
return(outchr);
}
char *cryptedpass(char *clearpass)
{
char salt[5];
srandom((unsigned int)time(NULL));
salt[0] = getsaltchar();
salt[1] = getsaltchar();
salt[2] = 0;
return(crypt(clearpass, salt));
}
void usage(void)
{
printf("\nMuddleftpd Password File Editor.\n\n");
printf("Usage: mudpasswd [options]\n\n");
printf(" -p passfile The filename of the password file to use\n");
printf(" -a username Adds a new username\n");
printf(" -e username Edits the properties of a username\n");
printf(" -d username Deletes the username from the password file\n");
printf(" -P password Sets a new password\n");
printf(" -R directory Sets a new root directory for the user.\n");
printf(" -H directory Sets a new home directory for the user.\n");
printf(" -W Changes the password using user input.\n");
printf(" -h Displays this usage message.\n");
printf(" -V Displays version information.\n\n");
printf("You must specify -p and only one of -a -e or -d when running mudpasswd\n\n");
exit(0);
}
int searchuser(char *passfile, char *username)
{
FILE *passwdfile;
char instring[MAXSTRLEN], username2[MAXSTRLEN], data[MAXSTRLEN];
passwdfile = fopen(passfile, "r");
if (!passwdfile)
return(FALSE);
while (fgets(instring, MAXSTRLEN, passwdfile) != NULL)
{
if (strsplit(instring, username2, data) != NULL)
if (strcmp(username2, username) == 0)
{
fclose(passwdfile);
return(TRUE);
}
}
fclose(passwdfile);
return(FALSE);
}
void adduser(char *passfile, char *username, char *rootdir, char *homedir,
char *password)
{
FILE *passwdfile;
int pos;
if (searchuser(passfile, username))
ERRORMSGFATAL("Username already exists - Operation Failed!");
passwdfile = fopen(passfile, "a+");
if (passwdfile == NULL)
ERRORMSGFATAL("Cannot open password file!");
pos = ftell(passwdfile);
if (pos > 0)
{
char chkchr;
fseek(passwdfile, -1, SEEK_CUR);
chkchr = fgetc(passwdfile);
if (chkchr != '\n')
{
fseek(passwdfile, 1, SEEK_CUR);
fprintf(passwdfile, "\n");
}
}
if (!passwdfile)
ERRORMSGFATAL("Couldn't open password file for writing!");
fprintf(passwdfile, "%s %s:%s:%s\n", username, cryptedpass(password),
homedir, rootdir);
fclose(passwdfile);
}
void deleteuser(char *passfile, char *username)
{
FILE *passwdfilein, *passwdfileout;
char instring[MAXSTRLEN], username2[MAXSTRLEN], data[MAXSTRLEN];
char newpassfile[MAXSTRLEN];
if (!searchuser(passfile, username))
ERRORMSGFATAL("Username doesn't exists - Operation Failed!");
strncpy(newpassfile, passfile, 4096);
strncat(newpassfile, ".new", 4096 - strlen(newpassfile));
passwdfilein = fopen(passfile, "r");
if (!passwdfilein)
ERRORMSGFATAL("Could not open password file!");
passwdfileout = fopen(newpassfile, "w");
if (!passwdfileout)
ERRORMSGFATAL("Could not open replacement password file!");
while (fgets(instring, MAXSTRLEN, passwdfilein) != NULL)
{
int n = TRUE;
if (strsplit(instring, username2, data) != NULL)
if (strcmp(username2, username) == 0)
n = FALSE;
if (n)
fprintf(passwdfileout, "%s\n", instring);
}
fclose(passwdfilein);
fclose(passwdfileout);
if (rename(newpassfile, passfile) == -1)
{
unlink(newpassfile);
ERRORMSGFATAL("Could not replace password file!");
}
}
void edituserstr(char *userstr, int attrmask, char *password, char *rootdir,
char *homedir, char *username, char *data)
{
char passwordold[MAXSTRLEN], homedirold[MAXSTRLEN], rootdirold[MAXSTRLEN];
char *pos;
strcpy(passwordold, "");
strcpy(homedirold, "");
strcpy(rootdirold, "");
/* get old settings */
if ((pos = strchr(data, ':')) != NULL)
{
strncpy(passwordold, data, 4096);
pos = strchr(passwordold, ':');
*pos = 0;
pos++;
}
if (pos != NULL)
if ((strchr(pos, ':')) != NULL)
{
strncpy(homedirold, pos, 4096);
pos = strchr(homedirold, ':');
*pos = 0;
pos++;
}
if (pos != NULL)
strncpy(rootdirold, pos, 4096);
if (attrmask & ROOTMSK)
strncpy(rootdirold, rootdir, 4096);
if (attrmask & HOMEMSK)
strncpy(homedirold, homedir, 4096);
if (attrmask & PASSMSK)
strncpy(passwordold, cryptedpass(password), 4096);
snprintf(userstr, MAXSTRLEN, "%s %s:%s:%s", username, passwordold, homedirold,
rootdirold);
userstr[MAXSTRLEN-1] = 0;
}
void edituser(char *passfile, char *username, char *rootdir, char *homedir,
char *password, int attrmask)
{
FILE *passwdfilein, *passwdfileout;
char instring[MAXSTRLEN], username2[MAXSTRLEN], data[MAXSTRLEN];
char newpassfile[MAXSTRLEN];
if (!searchuser(passfile, username))
ERRORMSGFATAL("Username doesn't exists - Operation Failed!");
strncpy(newpassfile, passfile, 4096);
strncat(newpassfile, ".new", 4096 - strlen(newpassfile));
passwdfilein = fopen(passfile, "r");
if (!passwdfilein)
ERRORMSGFATAL("Could not open password file!");
passwdfileout = fopen(newpassfile, "w");
if (!passwdfileout)
ERRORMSGFATAL("Could not open replacement password file!");
while (fgets(instring, MAXSTRLEN, passwdfilein) != NULL)
{
int n = TRUE;
if (strsplit(instring, username2, data) != NULL)
if (strcmp(username2, username) == 0)
edituserstr(instring, attrmask, password,
rootdir, homedir, username, data);
if (n)
fprintf(passwdfileout, "%s\n", instring);
}
fclose(passwdfilein);
fclose(passwdfileout);
if (rename(newpassfile, passfile) == -1)
{
unlink(newpassfile);
ERRORMSGFATAL("Could not replace password file!");
}
}
int main(int argc, char **argv)
{
int ch;
char *passfile = NULL;
char *username = NULL;
char *password = NULL;
char *homedir = NULL;
char *rootdir = NULL;
int add_user = FALSE;
int delete_user = FALSE;
int edit_user = 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("mudpasswd must *NOT* be setuid root.\n");
while ((ch = getopt(argc, argv, "p:a:d:e:P:R:H:WhV")) != EOF)
{
switch(ch)
{
case 'V':
showversion("mudpasswd");
case 'p':
passfile = 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 'P':
password = optarg;
edit_mask |= PASSMSK;
break;
case 'R':
rootdir = optarg;
edit_mask |= ROOTMSK;
break;
case 'H':
homedir = optarg;
edit_mask |= HOMEMSK;
break;
case 'W':
edit_mask |= PASSMSK;
break;
case 'h':
usage();
break;
default:
usage();
}
}
if (!passfile)
usage();
if (add_user)
{
if (edit_user || delete_user)
usage();
if (!homedir)
{
homedir = (char *)malloc(MAXSTRLEN);
printf("Enter Home Directory For New User: ");
fgets(homedir, MAXSTRLEN, stdin);
homedir[strlen(homedir) - 1] = 0;
}
if (!rootdir)
{
rootdir = (char *)malloc(MAXSTRLEN);
printf("Enter Root Directory For New User: ");
fgets(rootdir, MAXSTRLEN, stdin);
rootdir[strlen(rootdir) - 1] = 0;
}
if (!password)
{
password = getpass("Enter Password For New User: ");
}
adduser(passfile, username, rootdir, homedir, password);
exit(0);
}
if (delete_user)
{
if (edit_user)
usage();
deleteuser(passfile, username);
exit(0);
}
if (edit_user)
{
if (!edit_mask)
usage();
if (!password && (edit_mask & PASSMSK))
{
password = getpass("Enter Password For New User: ");
}
edituser(passfile, username, rootdir, homedir, password, edit_mask);
exit(0);
}
usage();
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1