Added more security checks to mbpasswd

This commit is contained in:
Michiel Broek 2005-08-27 12:06:48 +00:00
parent efccc2e9fa
commit b79e9b07bc
9 changed files with 259 additions and 222 deletions

View File

@ -40,13 +40,22 @@ v0.71.5 18-Aug-2005
mbsebbs: mbsebbs:
Code cleanup. Code cleanup.
Changed syntax for calling mbpasswd.
mbnewusr:
Changed syntax for calling mbpasswd.
mbsetup: mbsetup:
Added node setup switch to override node Hold or Down status. Added node setup switch to override node Hold or Down status.
Changed syntax for calling mbpasswd.
script: script:
Added mbfile check to monthly maintenance script. Added mbfile check to monthly maintenance script.
mbpasswd:
Added security checks to see if this program is legally called.
Changed commandline syntax.
v0.71.4 12-Aug-2005 - 18-Aug-2005 v0.71.4 12-Aug-2005 - 18-Aug-2005

View File

@ -14,14 +14,9 @@
</HEAD> </HEAD>
<BODY> <BODY>
<BLOCKQUOTE> <BLOCKQUOTE>
<div align="right"><h5>Last update 21-Jan-2002</h5></div> <div align="right"><h5>Last update 27-Aug-2005</h5></div>
<div align="center"><H1>mbpasswd - The password wrapper.</H1></div> <div align="center"><H1>mbpasswd - The password wrapper.</H1></div>
<H3>Synopsis.</h3>
<P>
<code><strong>mbpasswd</strong> [-opt] [username] [password]</code>
<P>&nbsp;<P>
<H3>Description.</h3> <H3>Description.</h3>
<P> <P>
<strong>mbpasswd</strong> is the wrapper for the <strong>passwd</strong> program <strong>mbpasswd</strong> is the wrapper for the <strong>passwd</strong> program
@ -33,9 +28,8 @@ bbs when an existing user changes his password. If you as sysop use
<strong>mbsetup</strong> to change a users password it will be used too. <strong>mbsetup</strong> to change a users password it will be used too.
His password under Unix is then always the same as his password in the bbs program. His password under Unix is then always the same as his password in the bbs program.
This is necessary for the user to be able to get his email using the pop3 protocol.<P> This is necessary for the user to be able to get his email using the pop3 protocol.<P>
You never need to run <strong>mbpasswd</strong> by hand, in fact it is protected so that only You never need to run <strong>mbpasswd</strong> by hand, in fact it is protected so that
members of group <b>bbs</b> are allowed to use it. User <b>mbse</b> can use this it can only be started by the bbs or mbsetup.
program and if you do, the password for a user are not in sync anymore.
<P>&nbsp;<P> <P>&nbsp;<P>
<H3>Environment.</H3> <H3>Environment.</H3>
@ -48,15 +42,8 @@ program and if you do, the password for a user are not in sync anymore.
<H3>Commands.</H3> <H3>Commands.</H3>
<P> <P>
<code><strong>mbpasswd</strong> [-opt] [username] [password]</code> for example:<br> Not mentioned here because <b>mbpasswd</b> is only called by other programs,
<pre> running manually is not supported.
mbpasswd -f michiel secret
</pre>
Valid options are <strong>-f</strong> (forced), this will also change locked passwords,
this has only effect if your system uses shadow passwords. This is used for new
users or from the <b>mbsetup</b> program to reset users passwords.<br>
If you use <strong>-n</strong> as option, locked passwords cannot be changed.
This mode is used when a user changes his password from the bbs.
<P> <P>

View File

@ -194,14 +194,13 @@ void Chg_Password()
} }
} }
Syslog('+', "%s/bin/mbpasswd -n %s ******", getenv("MBSE_ROOT"), exitinfo.Name); Syslog('+', "%s/bin/mbpasswd %s ******", getenv("MBSE_ROOT"), exitinfo.Name);
sprintf(temp1, "%s/bin/mbpasswd", getenv("MBSE_ROOT")); sprintf(temp1, "%s/bin/mbpasswd", getenv("MBSE_ROOT"));
memset(args, 0, sizeof(args)); memset(args, 0, sizeof(args));
args[0] = temp1; args[0] = temp1;
args[1] = (char *)"-n"; args[1] = exitinfo.Name;
args[2] = exitinfo.Name; args[2] = temp2;
args[3] = temp2; args[3] = NULL;
args[4] = NULL;
if (execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") != 0) { if (execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") != 0) {
WriteError("Failed to set new Unix password"); WriteError("Failed to set new Unix password");

View File

@ -723,10 +723,9 @@ char *NameCreate(char *Name, char *Comment, char *Password)
sprintf(progname, "%s/bin/mbpasswd", getenv("MBSE_ROOT")); sprintf(progname, "%s/bin/mbpasswd", getenv("MBSE_ROOT"));
memset(args, 0, sizeof(args)); memset(args, 0, sizeof(args));
args[0] = progname; args[0] = progname;
args[1] = (char *)"-f"; args[1] = Name;
args[2] = Name; args[2] = Password;
args[3] = Password; args[3] = NULL;
args[4] = NULL;
if ((err = execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"))) { if ((err = execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"))) {
WriteError("Failed to set unix password"); WriteError("Failed to set unix password");

View File

@ -378,14 +378,13 @@ int EditUsrRec2(void)
memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); memset(&usrconfig.Password, 0, sizeof(usrconfig.Password));
strcpy(usrconfig.Password, temp); strcpy(usrconfig.Password, temp);
usrconfig.tLastPwdChange = time(NULL); usrconfig.tLastPwdChange = time(NULL);
Syslog('+', "%s/bin/mbpasswd -f %s ******", getenv("MBSE_ROOT"), usrconfig.Name); Syslog('+', "%s/bin/mbpasswd %s ******", getenv("MBSE_ROOT"), usrconfig.Name);
sprintf(temp, "%s/bin/mbpasswd", getenv("MBSE_ROOT")); sprintf(temp, "%s/bin/mbpasswd", getenv("MBSE_ROOT"));
memset(args, 0, sizeof(args)); memset(args, 0, sizeof(args));
args[0] = temp; args[0] = temp;
args[1] = (char *)"-f"; args[1] = usrconfig.Name;
args[2] = usrconfig.Name; args[2] = usrconfig.Password;
args[3] = usrconfig.Password; args[3] = NULL;
args[4] = NULL;
if (execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")!= 0) { if (execute(args, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")!= 0) {
WriteError("$Failed to set new Unix password"); WriteError("$Failed to set new Unix password");

View File

@ -809,6 +809,18 @@ static void update_shadow(void)
/*
* Internal version of basename to make this better portable.
*/
char *Basename(char *str)
{
char *cp = strrchr(str, '/');
return cp ? cp+1 : str;
}
/* /*
* Function will set a new password in the users password file. * Function will set a new password in the users password file.
* Note that this function must run setuid root! * Note that this function must run setuid root!
@ -816,235 +828,249 @@ static void update_shadow(void)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
const struct passwd *pw; const struct passwd *pw;
const struct group *gr; const struct group *gr;
#ifdef SHADOW_PASSWORD #ifdef SHADOW_PASSWORD
const struct spwd *sp; const struct spwd *sp;
#endif #endif
#else #else
static struct passwd *pw; static struct passwd *pw;
static struct group *gr; static struct group *gr;
int pfd, tfd; int pfd, tfd;
#endif #endif
char *cp; char *cp;
#ifdef _VPOPMAIL_PATH #ifdef _VPOPMAIL_PATH
char temp[PATH_MAX]; char *args[16];
char *args[16];
#endif #endif
char temp[PATH_MAX];
pid_t ppid;
char *parent;
FILE *fp;
/*
* Init $MBSE_ROOT/etc/login.defs file before the *pw gets overwritten.
*/
def_load();
/*
* Get my username
*/
pw = get_my_pwent();
if (!pw) {
fprintf(stderr, "mbpasswd: Cannot determine your user name.\n");
exit(1);
}
myname = xstrdup(pw->pw_name);
/*
* Get my groupname, this must be "bbs", other users may not
* use this program, not even root.
*/
gr = getgrgid(pw->pw_gid);
if (!gr) {
fprintf(stderr, "mbpasswd: Cannot determine group name.\n");
free(myname);
exit(E_NOPERM);
}
if (strcmp(gr->gr_name, (char *)"bbs")) {
fprintf(stderr, "mbpasswd: You are not a member of group \"bbs\".\n");
free(myname);
exit(E_NOPERM);
}
/*
* We don't log into MBSE BBS logfiles but to the system logfiles,
* because we are modifying system files not belonging to MBSE BBS.
*/
openlog("mbpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
/*
* Find out the name of our parent.
*/
ppid = getppid();
sprintf(temp, "/proc/%d/cmdline", ppid);
if ((fp = fopen(temp, "r")) == NULL) {
fprintf(stderr, "mbpasswd: can't read %s\n", temp);
syslog(LOG_ERR, "mbpasswd: can't read %s", temp);
free(myname);
exit(E_FAILURE);
}
fgets(temp, PATH_MAX-1, fp);
fclose(fp);
parent = xstrcpy(Basename(temp));
if (strcmp((char *)"mbsetup", parent) && strcmp((char *)"-mbsebbs", parent) && strcmp((char *)"-mbnewusr", parent)) {
fprintf(stderr, "mbpasswd: illegal parent\n");
syslog(LOG_ERR, "mbpasswd: illegal parent \"%s\"", parent);
free(myname);
exit(E_FAILURE);
}
if (argc != 3) {
fprintf(stderr, "\nmbpasswd commandline:\n\n");
fprintf(stderr, "mbpasswd [username] [newpassword]\n");
free(myname);
exit(E_FAILURE);
}
if ((strcmp((char *)"-mbnewusr", parent) == 0) || (strcmp((char *)"mbsetup", parent) == 0)) {
/* /*
* Init $MBSE_ROOT/etc/login.defs file before the *pw gets overwritten. * This is a new user setting his password, or the sysop resetting
* the password using mbsetup. This program runs under account mbse.
*/ */
def_load(); force = 1;
if (strcmp(pw->pw_name, (char *)"mbse") && strcmp(pw->pw_name, (char *)"bbs")) {
fprintf(stderr, "mbpasswd: only users `mbse' and `bbs' may do this.\n");
free(myname);
exit(E_NOPERM);
}
} else if (strcmp((char *)"-mbsebbs", parent) == 0) {
/* /*
* Get my username * Normal password change by user, check caller is the user.
* Calling program is only mbsebbs.
*/ */
pw = get_my_pwent(); force = 0;
if (!pw) { if (strcmp(pw->pw_name, argv[1])) {
fprintf(stderr, "mbpasswd: Cannot determine your user name.\n"); fprintf(stderr, "mbpasswd: only owner may do this.\n");
exit(1); free(myname);
exit(E_NOPERM);
} }
myname = xstrdup(pw->pw_name); } else {
syslog(LOG_ERR, "mbpasswd: illegal called");
free(myname);
exit(E_NOPERM);
}
/* /*
* Get my groupname, this must be "bbs", other users may not * Check commandline arguments
* use this program, not even root. */
*/ if (strlen(argv[1]) > 32) {
gr = getgrgid(pw->pw_gid); fprintf(stderr, "mbpasswd: Username too long\n");
if (!gr) { free(myname);
fprintf(stderr, "mbpasswd: Cannot determine group name.\n"); exit(E_FAILURE);
free(myname); }
exit(E_NOPERM); if (strlen(argv[2]) > 32) {
} fprintf(stderr, "mbpasswd: Password too long\n");
if (strcmp(gr->gr_name, (char *)"bbs")) { free(myname);
fprintf(stderr, "mbpasswd: You are not a member of group \"bbs\".\n"); exit(E_FAILURE);
free(myname); }
exit(E_NOPERM);
}
// NOOT dit programma moet kontroleren of het is aangeroepen door mbsebbs. name = strdup(argv[1]);
// ook kontroleren of de originele uid en gid correct zijn. if ((pw = getpwnam(name)) == NULL) {
// Gewone stervelingen mogen dit niet kunnen starten. syslog(LOG_ERR, "mbpasswd: Unknown user %s", name);
// Dit programma is een groot security gat. fprintf(stderr, "mbpasswd: Unknown user %s\n", name);
free(myname);
// On Linux: use getppid to get the parent pid. exit(E_FAILURE);
// cat /proc/<pid>/cmdline gives name of parent. }
// check parent name: mbsebbs | mbnewusr | mbsetup
if (argc != 4) {
fprintf(stderr, "\nmbpasswd commandline:\n\n");
fprintf(stderr, "mbpasswd [-opt] [username] [newpassword]\n");
fprintf(stderr, "options are: -n normal password change\n");
fprintf(stderr, " -f forced password change\n");
free(myname);
exit(E_FAILURE);
}
if (strncmp(argv[1], "-f", 2) == 0) {
/*
* This is a new user setting his password,
* this program runs under account mbse.
*/
force = 1;
if (strcmp(pw->pw_name, (char *)"mbse") && strcmp(pw->pw_name, (char *)"bbs")) {
fprintf(stderr, "mbpasswd: only users `mbse' and `bbs' may do this.\n");
free(myname);
exit(E_NOPERM);
}
} else if (strncmp(argv[1], "-n", 2) == 0) {
/*
* Normal password change by user, check
* caller is the user.
*/
force = 0;
if (strcmp(pw->pw_name, argv[2])) {
fprintf(stderr, "mbpasswd: only owner may do this.\n");
free(myname);
exit(E_NOPERM);
}
} else {
fprintf(stderr, "mbpasswd: wrong option switch.\n");
free(myname);
exit(E_FAILURE);
}
/*
* Check stringlengths
*/
if (strlen(argv[2]) > 16) {
fprintf(stderr, "mbpasswd: Username too long\n");
free(myname);
exit(E_FAILURE);
}
if (strlen(argv[3]) > 16) {
fprintf(stderr, "mbpasswd: Password too long\n");
free(myname);
exit(E_FAILURE);
}
/*
* We don't log into MBSE BBS logfiles but to the system logfiles,
* because we are modifying system files not belonging to MBSE BBS.
*/
openlog("mbpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
name = strdup(argv[2]);
if ((pw = getpwnam(name)) == NULL) {
syslog(LOG_ERR, "mbpasswd: Unknown user %s", name);
fprintf(stderr, "mbpasswd: Unknown user %s\n", name);
free(myname);
exit(E_FAILURE);
}
#ifdef SHADOW_PASSWORD #ifdef SHADOW_PASSWORD
is_shadow_pwd = spw_file_present(); is_shadow_pwd = spw_file_present();
sp = getspnam(name); sp = getspnam(name);
if (!sp) if (!sp)
sp = pwd_to_spwd(pw); sp = pwd_to_spwd(pw);
cp = sp->sp_pwdp; cp = sp->sp_pwdp;
#else #else
cp = pw->pw_passwd; cp = pw->pw_passwd;
#endif #endif
/* /*
* See if the user is permitted to change the password. * See if the user is permitted to change the password.
* Otherwise, go ahead and set a new password. * Otherwise, go ahead and set a new password.
*/ */
#ifdef SHADOW_PASSWORD #ifdef SHADOW_PASSWORD
check_password(pw, sp); check_password(pw, sp);
#else #else
check_password(pw); check_password(pw);
#endif #endif
if (new_password(pw, argv[3])) { if (new_password(pw, argv[2])) {
fprintf(stderr, "The password for %s is unchanged.\n", name); fprintf(stderr, "The password for %s is unchanged.\n", name);
syslog(LOG_ERR, "The password for %s is unchanged", name); syslog(LOG_ERR, "The password for %s is unchanged", name);
closelog(); closelog();
free(myname); free(myname);
exit(E_FAILURE); exit(E_FAILURE);
} }
do_update_pwd = 1; do_update_pwd = 1;
do_update_age = 1; do_update_age = 1;
/* /*
* Before going any further, raise the ulimit to prevent * Before going any further, raise the ulimit to prevent
* colliding into a lowered ulimit, and set the real UID * colliding into a lowered ulimit, and set the real UID
* to root to protect against unexpected signals. Any * to root to protect against unexpected signals. Any
* keyboard signals are set to be ignored. * keyboard signals are set to be ignored.
*/ */
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
pwd_init(); pwd_init();
#else #else
pw_init(); pw_init();
#endif #endif
if (setuid(0)) { if (setuid(0)) {
fprintf(stderr, "Cannot change ID to root.\n"); fprintf(stderr, "Cannot change ID to root.\n");
syslog(LOG_ERR, "can't setuid(0)"); syslog(LOG_ERR, "can't setuid(0)");
closelog(); closelog();
free(myname); free(myname);
exit(E_FAILURE); exit(E_FAILURE);
} }
#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
#ifdef HAVE_USERSEC_H #ifdef HAVE_USERSEC_H
update_userpw(pw->pw_passwd); update_userpw(pw->pw_passwd);
#else /* !HAVE_USERSEC_H */ #else /* !HAVE_USERSEC_H */
#ifdef SHADOW_PASSWORD #ifdef SHADOW_PASSWORD
if (spw_file_present()) if (spw_file_present())
update_shadow(); update_shadow();
else else
#endif #endif
update_noshadow(0); update_noshadow(0);
#endif /* !HAVE_USERSEC_H */ #endif /* !HAVE_USERSEC_H */
#else /* __FreeBSD__ && __NetBSD__ && __OpenBSD__ */ #else /* __FreeBSD__ && __NetBSD__ && __OpenBSD__ */
/* /*
* FreeBSD password change, borrowed from the original FreeBSD sources * FreeBSD password change, borrowed from the original FreeBSD sources
*/ */
/* /*
* Get the new password. Reset passwd change time to zero by * Get the new password. Reset passwd change time to zero by
* default. * default.
*/ */
pw->pw_change = 0; pw->pw_change = 0;
pw->pw_passwd = crypt_passwd; pw->pw_passwd = crypt_passwd;
pfd = pw_lock(); pfd = pw_lock();
tfd = pw_tmp(); tfd = pw_tmp();
pw_copy(pfd, tfd, pw); pw_copy(pfd, tfd, pw);
if (!pw_mkdb(pw->pw_name)) if (!pw_mkdb(pw->pw_name))
pw_error((char *)NULL, 0, 1); pw_error((char *)NULL, 0, 1);
#endif /* __FreeBSD__ && __NetBSD__ && __OpenBSD__ */ #endif /* __FreeBSD__ && __NetBSD__ && __OpenBSD__ */
#ifdef _VPOPMAIL_PATH #ifdef _VPOPMAIL_PATH
fflush(stdout); fflush(stdout);
fflush(stdin); fflush(stdin);
memset(args, 0, sizeof(args)); memset(args, 0, sizeof(args));
sprintf(temp, "%s/vpasswd", (char *)_VPOPMAIL_PATH); sprintf(temp, "%s/vpasswd", (char *)_VPOPMAIL_PATH);
args[0] = temp; args[0] = temp;
args[1] = argv[2]; args[1] = argv[1];
args[2] = argv[3]; args[2] = argv[2];
args[3] = NULL; args[3] = NULL;
if (execute(args, (char *)"/dev/tty", (char *)"/dev/tty", (char *)"/dev/tty") != 0) { if (execute(args, (char *)"/dev/tty", (char *)"/dev/tty", (char *)"/dev/tty") != 0) {
perror("mbpasswd: Failed to change vpopmail password\n"); perror("mbpasswd: Failed to change vpopmail password\n");
syslog(LOG_ERR, "Failed to change vpopmail password"); syslog(LOG_ERR, "Failed to change vpopmail password");
} }
#endif #endif
syslog(LOG_NOTICE, "password for `%s' changed by user `%s'", name, myname); syslog(LOG_NOTICE, "password for `%s' changed by user `%s'", name, myname);
closelog(); closelog();
free(myname); free(myname);
exit(E_SUCCESS); exit(E_SUCCESS);
} }

View File

@ -1,5 +1,7 @@
#ifndef _MBUSERADD_H #ifndef _MBPASSWD_H
#define _MBUSERADD_H #define _MBPASSWD_H
/* $Id$ */
/* danger - side effects */ /* danger - side effects */
@ -39,6 +41,7 @@ static void update_noshadow(int);
struct spwd *pwd_to_spwd(const struct passwd *); struct spwd *pwd_to_spwd(const struct passwd *);
static void update_shadow(void); static void update_shadow(void);
#endif #endif
char *Basename(char *);
#endif #endif

View File

@ -1,13 +1,12 @@
/***************************************************************************** /*****************************************************************************
* *
* File ..................: mbuseradd/xmalloc.c * $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite * Purpose ...............: MBSE BBS Shadow Password Suite
* Last modification date : 25-Jul-2000
* Original Source .......: Shadow Password Suite * Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others. * Original Copyrioght ...: Julianne Frances Haugh and others.
* *
***************************************************************************** *****************************************************************************
* Copyright (C) 1997-2000 * Copyright (C) 1997-2005
* *
* Michiel Broek FIDO: 2:280/2802 * Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10 * Beekmansbos 10
@ -52,20 +51,33 @@
char *xmalloc(size_t size) char *xmalloc(size_t size)
{ {
char *ptr; char *ptr;
ptr = malloc(size); ptr = malloc(size);
if (!ptr && size) { if (!ptr && size) {
fprintf(stderr, "malloc(%d) failed\n", (int) size); fprintf(stderr, "malloc(%d) failed\n", (int) size);
exit(13); exit(13);
} }
return ptr; return ptr;
} }
char *xstrdup(const char *str) char *xstrdup(const char *str)
{ {
return strcpy(xmalloc(strlen(str) + 1), str); return strcpy(xmalloc(strlen(str) + 1), str);
}
char *xstrcpy(char *src)
{
char *tmp;
if (src == NULL)
return(NULL);
tmp = xmalloc(strlen(src)+1);
strcpy(tmp, src);
return tmp;
} }

View File

@ -1,8 +1,11 @@
#ifndef _XMALLOC_H #ifndef _XMALLOC_H
#define _XMALLOC_H #define _XMALLOC_H
/* $Id$ */
char *xmalloc(size_t); char *xmalloc(size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
char *xstrcpy(char *);
#endif #endif