Added mblogin program

This commit is contained in:
Michiel Broek 2002-01-02 22:17:58 +00:00
parent 8af5b1c2d1
commit 182f8c6b56
44 changed files with 5686 additions and 224 deletions

View File

@ -42,6 +42,7 @@
#undef REGEX
#undef REGEXEC
#undef SHADOW_PASSWORD
#undef HAVE_SHADOWGRP
#undef SO_OOBINLINE
/* mbuseradd */
@ -51,15 +52,77 @@
#undef AUTH_METHODS
#undef CKDEFS
#undef DOUBLESIZE
/* Defined if you have libcrack. */
#undef HAVE_LIBCRACK
/* Defined if you have the ts&szs cracklib. */
#undef HAVE_LIBCRACK_HIST
/* Defined if it includes *Pw functions. */
#undef HAVE_LIBCRACK_PW
/* Defined if it includes *Pw functions. */
#undef HAVE_LIBCRACK_PW
/* Defined if you have libcrypt. */
#undef HAVE_LIBCRYPT
#undef KEEP_NIS_AT_END
/* Define to support the MD5-based password hashing algorithm. */
#undef MD5_CRYPT
#undef PAM
/* Define to support OPIE one-time password logins. */
#undef OPIE
#undef SW_CRYPT
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* That's it */
/* Path for faillog file. */
#undef FAILLOG_FILE
/* Define to libshadow_getpass to use our own version of getpass(). */
#undef getpass
/* Define if your locale.h file contains LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
/* Path for lastlog file. */
#undef LASTLOG_FILE
/* Define to support /etc/login.access login access control. */
#undef LOGIN_ACCESS
/* Path for wtmp file. */
#undef _WTMP_FILE
/* Define if you have the updwtmp function. */
#undef HAVE_UPDWTMP
/* Define if you have the updwtmpx function. */
#undef HAVE_UPDWTMPX
/* Define if mblogin should support the -r flag for rlogind. */
#undef RLOGIN
/* Define if you have the getusershell function. */
#undef HAVE_GETUSERSHELL
/* Define if you have the getutent function. */
#undef HAVE_GETUTENT
/* Define if you have the <lastlog.h> header file. */
#undef HAVE_LASTLOG_H
/* Define if you have ut_host in struct utmp. */
#undef UT_HOST
/* Path for utmp file. */
#undef _UTMP_FILE
/* Define if you have the `a64l' function. */
#undef HAVE_A64L
@ -142,6 +205,12 @@
/* Define if you have the `putpwent' function. */
#undef HAVE_PUTPWENT
/* Define if you have the putspent function. */
#undef HAVE_PUTSPENT
/* Define if you have the putgrent function. */
#undef HAVE_PUTGRENT
/* Define if you have the `regcmp' function. */
#undef HAVE_REGCMP
@ -215,6 +284,9 @@
/* Define if you have the <syslog.h> header file. */
#undef HAVE_SYSLOG_H
/* Define to use syslog(). */
#undef USE_SYSLOG
/* Define if you have the <sys/dir.h> header file, and it defines `DIR'. */
#undef HAVE_SYS_DIR_H
@ -274,6 +346,12 @@
/* Define if you have the `vprintf' function. */
#undef HAVE_VPRINTF
/* Define if you have the memcpy function. */
#undef HAVE_MEMCPY
/* Define if you have the memset function. */
#undef HAVE_MEMSET
/* Name of package */
#undef PACKAGE
@ -295,8 +373,7 @@
/* Define if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/* Define if `lex' declares `yytext' as a `char *' by default, not a `char[]'.
*/
/* Define if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */
#undef YYTEXT_POINTER
/* Define to empty if `const' does not conform to ANSI C. */

574
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -119,6 +119,7 @@ AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h malloc.h sys/file.h sys/ioctl.h sys/time.h termios.h syslog.h sys/vfs.h unistd.h netinet/in.h regex.h)
AC_CHECK_HEADERS(sys/resource.h usersec.h utime.h ulimit.h gshadow.h shadow.h)
AC_CHECK_HEADERS(limits.h utmp.h utmpx.h sgtty.h lastlog.h rpc/key_prot.h)
AC_STRUCT_TIMEZONE
dnl Checks for typedefs, structures, and compiler characteristics.
@ -144,6 +145,7 @@ AC_FUNC_UTIME_NULL
AC_FUNC_VFORK
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname)
AC_CHECK_FUNCS(getgroups getspnam getusershell getutent initgroups setgroups updwtmp updwtmpx)
dnl Check for external programs
AC_PATH_PROG(COMPRESS,compress,no-compress-found-during-configure)
@ -165,6 +167,30 @@ AC_SUBST(LOG_COMPRESS)
AC_SUBST(LOG_COMPRESSEXT)
dnl
AC_MSG_CHECKING(location of utmp)
for utmpdir in /var/run /var/adm /usr/adm /etc NONE; do
if test "$utmpdir" = "NONE"; then
AC_MSG_WARN(utmp file not found)
elif test -f $utmpdir/utmp; then
AC_DEFINE_UNQUOTED(_UTMP_FILE, "$utmpdir/utmp")
AC_MSG_RESULT($utmpdir)
break
fi
done
AC_MSG_CHECKING(location of faillog/lastlog/wtmp)
for logdir in /var/log /var/adm /usr/adm /etc; do
if test -d $logdir; then
AC_DEFINE_UNQUOTED(_WTMP_FILE, "$logdir/wtmp")
AC_DEFINE_UNQUOTED(LASTLOG_FILE, "$logdir/lastlog")
AC_DEFINE_UNQUOTED(FAILLOG_FILE, "$logdir/faillog")
AC_MSG_RESULT($logdir)
break
fi
done
AC_OUTPUT(
Makefile.global
mbfido/paths.h

View File

@ -12,7 +12,10 @@ SRCS = bank.c commonio.c filesub.c language.c mbtoberep.c \
exitinfo.c mball.c mbsebbs.c menu.c nextuser.c pop3.c lastcallers.c \
safe.c timeout.c chat.c file.c getdef.c mbchat.c mbstat.c misc.c \
offline.c putpwent.c salt.c user.c mbnewusr.c input.c whoson.c \
door.c dispfile.c userlist.c timestats.c logentry.c pw_util.c
door.c dispfile.c userlist.c timestats.c logentry.c pw_util.c \
mblogin.c env.c snprintf.c chowntty.c ttytype.c shell.c basename.c \
failure.c pwdcheck.c pwauth.c loginprompt.c utmp.c limits.c \
setupenv.c sub.c ulimit.c log.c tz.c setugid.c
HDRS = bank.h commonio.h filesub.h language.h mbsebbs.h misc.h offline.h \
putpwent.h salt.h timeout.h bbslist.h email.h fsedit.h lineedit.h \
mbstat.h msgutil.h oneline.h sgetpwent.h user.h bye.h morefile.h \
@ -20,7 +23,10 @@ HDRS = bank.h commonio.h filesub.h language.h mbsebbs.h misc.h offline.h \
xmalloc.h change.h exitinfo.h mball.h mbuseradd.h newuser.h \
pinfo.h rad64.h chat.h file.h getdef.h mbpasswd.h menu.h \
nextuser.h pop3.h safe.h timecheck.h mbnewusr.h input.h whoson.h \
door.h dispfile.h userlist.h timestats.h logentry.h lastcallers.h pw_util.h
door.h dispfile.h userlist.h timestats.h logentry.h lastcallers.h pw_util.h \
mblogin.h env.h snprintf.h chowntty.h ttytype.h shell.h basename.h \
failure.h pwdcheck.h pwauth.h loginprompt.h utmp.h limits.h \
setupenv.h sub.h ulimit.h log.h tz.h setugid.h
MBSEBBS_OBJS = bank.o bbslist.o chat.o file.o funcs.o mail.o menu.o \
misc.o pinfo.o nextuser.o oneline.o page.o fsedit.o \
bye.o change.o mbsebbs.o safe.o timeout.o user.o timecheck.o \
@ -49,8 +55,11 @@ MBUSER_LIBS = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/
MBUSERADD_OBJS = mbuseradd.o
MBPASSWD_OBJS = mbpasswd.o commonio.o pwio.o shadowio.o sgetpwent.o \
xmalloc.o myname.o rad64.o salt.o getdef.o encrypt.o putpwent.o pw_util.o
MBLOGIN_OBJS = getdef.o env.o snprintf.o chowntty.o ttytype.o shell.o basename.o failure.o \
pwdcheck.o pwauth.o encrypt.o loginprompt.o utmp.o limits.o setupenv.o sub.o \
xmalloc.o ulimit.o log.o tz.o setugid.o mblogin.o
OTHER = Makefile
TARGET = mbsebbs mbnewusr mball mblang mbchat mbstat mbtoberep mbuser mbuseradd mbpasswd
TARGET = mbsebbs mbnewusr mball mblang mbchat mbstat mbtoberep mbuser mbuseradd mbpasswd mblogin
#############################################################################################################
@ -102,6 +111,10 @@ mbpasswd: ${MBPASSWD_OBJS}
${CC} -o mbpasswd ${MBPASSWD_OBJS} ${LIBS}
strip mbpasswd
mblogin: ${MBLOGIN_OBJS}
${CC} -o mblogin ${MBLOGIN_OBJS} ${LIBS}
strip mblogin
install: all
@if [ "`id -un`" != "root" ] ; then \
echo; echo " Must be root to install!"; echo; exit 3; \
@ -116,6 +129,7 @@ install: all
${INSTALL} -c -s -o `id -un` -g `id -gn` -m 6711 mbuser ${BINDIR}
${INSTALL} -c -s -o `id -un` -g `id -gn` -m 6711 mbuseradd ${BINDIR}
${INSTALL} -c -s -o `id -un` -g `id -gn` -m 6711 mbpasswd ${BINDIR}
${INSTALL} -c -s -o `id -un` -g `id -gn` -m 0755 mblogin ${BINDIR}
@rm -f ${BINDIR}/mbfbgen
filelist: Makefile
@ -206,4 +220,23 @@ userlist.o: ../lib/libs.h ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib
timestats.o: ../lib/libs.h ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h timestats.h funcs.h language.h input.h exitinfo.h
logentry.o: ../lib/libs.h ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h ../lib/clcomm.h logentry.h
pw_util.o: pw_util.h
mblogin.o: ../config.h mblogin.h getdef.h env.h chowntty.h ttytype.h basename.h shell.h failure.h pwdcheck.h pwauth.h loginprompt.h utmp.h limits.h setupenv.h sub.h ulimit.h log.h tz.h setugid.h
env.o: ../config.h mblogin.h xmalloc.h
snprintf.o: snprintf.h
chowntty.o: ../config.h mblogin.h getdef.h chowntty.h
ttytype.o: ../config.h mblogin.h getdef.h env.h ttytype.h
shell.o: ../config.h mblogin.h basename.h shell.h
basename.o: ../config.h mblogin.h basename.h
failure.o: ../config.h mblogin.h getdef.h failure.h
pwdcheck.o: ../config.h mblogin.h pwauth.h pwdcheck.h
pwauth.o: ../config.h mblogin.h pwauth.h getdef.h encrypt.h
loginprompt.o: ../config.h mblogin.h getdef.h xmalloc.h env.h loginprompt.h
utmp.o: ../config.h mblogin.h utmp.h
limits.o: ../config.h mblogin.h getdef.h utmp.h ulimit.h
setupenv.o: ../config.h mblogin.h getdef.h xmalloc.h env.h setupenv.h
sub.o: ../config.h mblogin.h sub.h
ulimit.o: ../config.h ulimit.h
log.o: ../config.h mblogin.h log.h
tz.o: ../config.h mblogin.h getdef.h tz.h
setugid.o: ../config.h mblogin.h getdef.h setugid.h
# End of generated dependencies

17
mbsebbs/basename.c Normal file
View File

@ -0,0 +1,17 @@
/*
* basename.c - not worth copyrighting :-). Some versions of Linux libc
* already have basename(), other versions don't. To avoid confusion,
* we will not use the function from libc and use a different name here.
* --marekm
*/
#include "../config.h"
#include "mblogin.h"
#include "basename.h"
char *Basename(char *str)
{
char *cp = strrchr(str, '/');
return cp ? cp+1 : str;
}

9
mbsebbs/basename.h Normal file
View File

@ -0,0 +1,9 @@
/* $Id$ */
#ifndef _BASENAME_H
#define _BASENAME_H
char *Basename(char *);
#endif

123
mbsebbs/chowntty.c Normal file
View File

@ -0,0 +1,123 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include <stdio.h>
#include <grp.h>
#include "mblogin.h"
#include <pwd.h>
#include "getdef.h"
#include "chowntty.h"
/*
* is_my_tty -- determine if "tty" is the same as TTY stdin is using
*/
int is_my_tty(const char *tty)
{
struct stat by_name, by_fd;
if (stat (tty, &by_name) || fstat (0, &by_fd))
return 0;
if (by_name.st_rdev != by_fd.st_rdev)
return 0;
else
return 1;
}
/*
* chown_tty() sets the login tty to be owned by the new user ID
* with TTYPERM modes
*/
void chown_tty(const char *tty, const struct passwd *info)
{
char buf[200], full_tty[200];
char *group; /* TTY group name or number */
struct group *grent;
gid_t gid;
/*
* See if login.defs has some value configured for the port group
* ID. Otherwise, use the user's primary group ID.
*/
if (! (group = getdef_str ("TTYGROUP")))
gid = info->pw_gid;
else if (group[0] >= '0' && group[0] <= '9')
gid = atoi (group);
else if ((grent = getgrnam (group)))
gid = grent->gr_gid;
else
gid = info->pw_gid;
/*
* Change the permissions on the TTY to be owned by the user with
* the group as determined above.
*/
if (*tty != '/') {
snprintf(full_tty, sizeof full_tty, "/dev/%s", tty);
tty = full_tty;
}
if (! is_my_tty (tty)) {
syslog(LOG_WARNING, "unable to determine TTY name, got %s\n", tty);
closelog();
exit (1);
}
if (chown(tty, info->pw_uid, gid) || chmod(tty, getdef_num("TTYPERM", 0600))) {
snprintf(buf, sizeof buf, "Unable to change tty %s", tty);
syslog(LOG_WARNING, "unable to change tty `%s' for user `%s'\n", tty, info->pw_name);
closelog();
perror (buf);
exit(1);
}
#ifdef __linux__
/*
* Please don't add code to chown /dev/vcs* to the user logging in -
* it's a potential security hole. I wouldn't like the previous user
* to hold the file descriptor open and watch my screen. We don't
* have the *BSD revoke() system call yet, and vhangup() only works
* for tty devices (which vcs* is not). --marekm
*/
#endif
}

11
mbsebbs/chowntty.h Normal file
View File

@ -0,0 +1,11 @@
/* $Id$ */
#ifndef _CHOWNTTY_H
#define _CHOWNTTY_H
int is_my_tty(const char *);
void chown_tty(const char *, const struct passwd *);
#endif

View File

@ -1,10 +1,9 @@
/*****************************************************************************
*
* File ..................: mbuseradd/encrypt.c
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Last modification date : 09-Aug-2001
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
@ -146,6 +145,10 @@ char *pw_encrypt(const char *clear, const char *salt)
#ifdef DOUBLESIZE
if (strlen (clear) > 8) {
cp = crypt (clear + 8, salt);
if (!cp) {
perror("crypt");
exit(1);
}
strcat (cipher, cp + 2);
}
#endif /* DOUBLESIZE */

253
mbsebbs/env.c Normal file
View File

@ -0,0 +1,253 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mblogin.h"
#include "xmalloc.h"
/*
* NEWENVP_STEP must be a power of two. This is the number
* of (char *) pointers to allocate at a time, to avoid using
* realloc() too often.
*/
#define NEWENVP_STEP 16
size_t newenvc = 0;
char **newenvp = NULL;
extern char **environ;
static const char *forbid[] = {
"_RLD_=",
"BASH_ENV=", /* GNU creeping featurism strikes again... */
"ENV=",
"HOME=",
"IFS=",
"KRB_CONF=",
"LD_", /* anything with the LD_ prefix */
"LIBPATH=",
"MAIL=",
"NLSPATH=",
"PATH=",
"SHELL=",
"SHLIB_PATH=",
(char *) 0
};
/* these are allowed, but with no slashes inside
(to work around security problems in GNU gettext) */
static const char *noslash[] = {
"LANG=",
"LANGUAGE=",
"LC_", /* anything with the LC_ prefix */
(char *) 0
};
/*
* initenv() must be called once before using addenv().
*/
void initenv(void)
{
newenvp = (char **)xmalloc(NEWENVP_STEP * sizeof(char *));
*newenvp = NULL;
}
void addenv(const char *string, const char *value)
{
char *cp, *newstring;
size_t i;
size_t n;
if (value) {
newstring = xmalloc(strlen(string) + strlen(value) + 2);
sprintf(newstring, "%s=%s", string, value);
} else {
newstring = xstrdup(string);
}
/*
* Search for a '=' character within the string and if none is found
* just ignore the whole string.
*/
cp = strchr(newstring, '=');
if (!cp) {
free(newstring);
return;
}
n = (size_t)(cp - newstring);
for (i = 0; i < newenvc; i++) {
if (strncmp(newstring, newenvp[i], n) == 0 &&
(newenvp[i][n] == '=' || newenvp[i][n] == '\0'))
break;
}
if (i < newenvc) {
free(newenvp[i]);
newenvp[i] = newstring;
return;
}
newenvp[newenvc++] = newstring;
/*
* Check whether newenvc is a multiple of NEWENVP_STEP.
* If so we have to resize the vector.
* the expression (newenvc & (NEWENVP_STEP - 1)) == 0
* is equal to (newenvc % NEWENVP_STEP) == 0
* as long as NEWENVP_STEP is a power of 2.
*/
if ((newenvc & (NEWENVP_STEP - 1)) == 0) {
char **__newenvp;
size_t newsize;
/*
* If the resize operation succeds we can
* happily go on, else print a message.
*/
newsize = (newenvc + NEWENVP_STEP) * sizeof(char *);
__newenvp = (char **)realloc(newenvp, newsize);
if (__newenvp) {
/*
* If this is our current environment, update
* environ so that it doesn't point to some
* free memory area (realloc() could move it).
*/
if (environ == newenvp)
environ = __newenvp;
newenvp = __newenvp;
} else {
fprintf(stderr, "Environment overflow\n");
free(newenvp[--newenvc]);
}
}
/*
* The last entry of newenvp must be NULL
*/
newenvp[newenvc] = NULL;
}
/*
* set_env - copy command line arguments into the environment
*/
void set_env(int argc, char * const *argv)
{
int noname = 1;
char variable[1024];
char *cp;
for ( ; argc > 0; argc--, argv++) {
if (strlen(*argv) >= sizeof variable)
continue; /* ignore long entries */
if (! (cp = strchr (*argv, '='))) {
snprintf(variable, sizeof variable, "L%d", noname++);
addenv(variable, *argv);
} else {
const char **p;
for (p = forbid; *p; p++)
if (strncmp(*argv, *p, strlen(*p)) == 0)
break;
if (*p) {
strncpy(variable, *argv, cp - *argv);
variable[cp - *argv] = '\0';
printf("You may not change $%s\n", variable);
continue;
}
addenv(*argv, NULL);
}
}
}
/*
* sanitize_env - remove some nasty environment variables
* If you fall into a total paranoia, you should call this
* function for any root-setuid program or anything the user
* might change the environment with. 99% useless as almost
* all modern Unixes will handle setuid executables properly,
* but... I feel better with that silly precaution. -j.
*/
void sanitize_env(void)
{
char **envp = environ;
const char **bad;
char **cur;
char **move;
for (cur = envp; *cur; cur++) {
for (bad = forbid; *bad; bad++) {
if (strncmp(*cur, *bad, strlen(*bad)) == 0) {
for (move = cur; *move; move++)
*move = *(move + 1);
cur--;
break;
}
}
}
for (cur = envp; *cur; cur++) {
for (bad = noslash; *bad; bad++) {
if (strncmp(*cur, *bad, strlen(*bad)) != 0)
continue;
if (!strchr(*cur, '/'))
continue; /* OK */
for (move = cur; *move; move++)
*move = *(move + 1);
cur--;
break;
}
}
}

12
mbsebbs/env.h Normal file
View File

@ -0,0 +1,12 @@
/* $Id$ */
#ifndef _ENV_H
#define _ENV_H
void initenv(void);
void addenv(const char *, const char *);
void set_env(int, char * const *);
void sanitize_env(void);
#endif

273
mbsebbs/failure.c Normal file
View File

@ -0,0 +1,273 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <fcntl.h>
#include <stdio.h>
#include "mblogin.h"
#include "getdef.h"
#include <utmp.h>
#include "failure.h"
#define YEAR (365L*DAY)
/*
* failure - make failure entry
*
* failure() creates a new (struct faillog) entry or updates an
* existing one with the current failed login information.
*/
void failure(uid_t uid, const char *tty, struct faillog *fl)
{
int fd;
/*
* Don't do anything if failure logging isn't set up.
*/
if ((fd = open(FAILLOG_FILE, O_RDWR)) < 0)
return;
/*
* The file is indexed by uid value meaning that shared UID's
* share failure log records. That's OK since they really
* share just about everything else ...
*/
lseek(fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
if (read(fd, (char *) fl, sizeof *fl) != sizeof *fl)
memzero(fl, sizeof *fl);
/*
* Update the record. We increment the failure count to log the
* latest failure. The only concern here is overflow, and we'll
* check for that. The line name and time of day are both
* updated as well.
*/
if (fl->fail_cnt + 1 > 0)
fl->fail_cnt++;
strncpy(fl->fail_line, tty, sizeof fl->fail_line);
time(&fl->fail_time);
/*
* Seek back to the correct position in the file and write the
* record out. Ideally we should lock the file in case the same
* account is being logged simultaneously. But the risk doesn't
* seem that great.
*/
lseek(fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
write(fd, (char *) fl, sizeof *fl);
close(fd);
}
static int too_many_failures(const struct faillog *fl)
{
time_t now;
if (fl->fail_max == 0 || fl->fail_cnt < fl->fail_max)
return 0;
if (fl->fail_locktime == 0)
return 1; /* locked until reset manually */
time(&now);
if (fl->fail_time + fl->fail_locktime > now)
return 0; /* enough time since last failure */
return 1;
}
/*
* failcheck - check for failures > allowable
*
* failcheck() is called AFTER the password has been validated. If the
* account has been "attacked" with too many login failures, failcheck()
* returns FALSE to indicate that the login should be denied even though
* the password is valid.
*/
int failcheck(uid_t uid, struct faillog *fl, int failed)
{
int fd;
struct faillog fail;
/*
* Suppress the check if the log file isn't there.
*/
if ((fd = open(FAILLOG_FILE, O_RDWR)) < 0)
return 1;
/*
* Get the record from the file and determine if the user has
* exceeded the failure limit. If "max" is zero, any number
* of failures are permitted. Only when "max" is non-zero and
* "cnt" is greater than or equal to "max" is the account
* considered to be locked.
*
* If read fails, there is no record for this user yet (the
* file is initially zero length and extended by writes), so
* no need to reset the count.
*/
lseek (fd, (off_t) (sizeof *fl) * uid, SEEK_SET);
if (read(fd, (char *) fl, sizeof *fl) != sizeof *fl) {
close(fd);
return 1;
}
if (too_many_failures(fl)) {
close(fd);
return 0;
}
/*
* The record is updated if this is not a failure. The count will
* be reset to zero, but the rest of the information will be left
* in the record in case someone wants to see where the failed
* login originated.
*/
if (!failed) {
fail = *fl;
fail.fail_cnt = 0;
lseek (fd, (off_t) sizeof fail * uid, SEEK_SET);
write (fd, (char *) &fail, sizeof fail);
}
close (fd);
return 1;
}
/*
* failprint - print line of failure information
*
* failprint takes a (struct faillog) entry and formats it into a
* message which is displayed at login time.
*/
void failprint(const struct faillog *fail)
{
struct tm *tp;
#if HAVE_STRFTIME
char lasttimeb[256];
char *lasttime = lasttimeb;
const char *fmt;
#else
char *lasttime;
#endif
time_t NOW;
if (fail->fail_cnt == 0)
return;
tp = localtime (&(fail->fail_time));
time(&NOW);
#if HAVE_STRFTIME
/*
* Only print as much date and time info as it needed to
* know when the failure was.
*/
if (NOW - fail->fail_time >= YEAR)
fmt = "%Y";
else if (NOW - fail->fail_time >= DAY)
fmt = "%A %T";
else
fmt = "%T";
strftime(lasttimeb, sizeof lasttimeb, fmt, tp);
#else
/*
* Do the same thing, but don't use strftime since it
* probably doesn't exist on this system
*/
lasttime = asctime (tp);
lasttime[24] = '\0';
if (NOW - fail->fail_time < YEAR)
lasttime[19] = '\0';
if (NOW - fail->fail_time < DAY)
lasttime = lasttime + 11;
if (*lasttime == ' ')
lasttime++;
#endif
printf ("%d %s since last login. Last was %s on %s.\n",
fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
lasttime, fail->fail_line);
}
/*
* failtmp - update the cummulative failure log
*
* failtmp updates the (struct utmp) formatted failure log which
* maintains a record of all login failures.
*/
void failtmp(const struct utmp *failent)
{
char *ftmp;
int fd;
/*
* Get the name of the failure file. If no file has been defined
* in login.defs, don't do this.
*/
if (!(ftmp = getdef_str("FTMP_FILE")))
return;
/*
* Open the file for append. It must already exist for this
* feature to be used.
*/
if ((fd = open(ftmp, O_WRONLY|O_APPEND)) == -1)
return;
/*
* Output the new failure record and close the log file.
*/
write(fd, (const char *) failent, sizeof *failent);
close(fd);
}

42
mbsebbs/failure.h Normal file
View File

@ -0,0 +1,42 @@
/* $Id$ */
#ifndef _FAILURE_H_
#define _FAILURE_H_
#include <utmp.h>
/*
* failure - make failure entry
*
* failure() creates a new (struct faillog) entry or updates an
* existing one with the current failed login information.
*/
extern void failure(uid_t, const char *, struct faillog *);
/*
* failcheck - check for failures > allowable
*
* failcheck() is called AFTER the password has been validated. If the
* account has been "attacked" with too many login failures, failcheck()
* returns FALSE to indicate that the login should be denied even though
* the password is valid.
*/
extern int failcheck(uid_t, struct faillog *, int);
/*
* failprint - print line of failure information
*
* failprint takes a (struct faillog) entry and formats it into a
* message which is displayed at login time.
*/
extern void failprint(const struct faillog *);
/*
* failtmp - update the cummulative failure log
*
* failtmp updates the (struct utmp) formatted failure log which
* maintains a record of all login failures.
*/
extern void failtmp(const struct utmp *);
#endif

420
mbsebbs/limits.c Normal file
View File

@ -0,0 +1,420 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
/*
* Separated from setup.c. --marekm
* Resource limits thanks to Cristian Gafton.
*/
#include "../config.h"
#include "mblogin.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <syslog.h>
#include <utmp.h>
#include <pwd.h>
#include <grp.h>
#include "getdef.h"
#include "utmp.h"
#include "ulimit.h"
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#define LIMITS
#endif
#ifdef LIMITS
#ifndef LIMITS_FILE
#define LIMITS_FILE "/etc/limits"
#endif
#define LOGIN_ERROR_RLIMIT 1
#define LOGIN_ERROR_LOGIN 2
/* Set a limit on a resource */
/*
* rlimit - RLIMIT_XXXX
* value - string value to be read
* multiplier - value*multiplier is the actual limit
*/
int setrlimit_value(unsigned int rlimit, const char *value, unsigned int multiplier)
{
struct rlimit rlim;
long limit;
char **endptr = (char **) &value;
const char *value_orig = value;
limit = strtol(value, endptr, 10);
if (limit == 0 && value_orig == *endptr) /* no chars read */
return 0;
limit *= multiplier;
rlim.rlim_cur = limit;
rlim.rlim_max = limit;
if (setrlimit(rlimit, &rlim))
return LOGIN_ERROR_RLIMIT;
return 0;
}
int set_prio(const char *value)
{
int prio;
char **endptr = (char **) &value;
prio = strtol(value, endptr, 10);
if ((prio == 0) && (value == *endptr))
return 0;
if (setpriority(PRIO_PROCESS, 0, prio))
return LOGIN_ERROR_RLIMIT;
return 0;
}
int set_umask(const char *value)
{
mode_t mask;
char **endptr = (char **) &value;
mask = strtol(value, endptr, 8) & 0777;
if ((mask == 0) && (value == *endptr))
return 0;
umask(mask);
return 0;
}
/* Counts the number of user logins and check against the limit */
int check_logins(const char *name, const char *maxlogins)
{
struct utmp *ut;
unsigned int limit, count;
char **endptr = (char **) &maxlogins;
const char *ml_orig = maxlogins;
limit = strtol(maxlogins, endptr, 10);
if (limit == 0 && ml_orig == *endptr) /* no chars read */
return 0;
if (limit == 0) /* maximum 0 logins ? */ {
syslog(LOG_WARNING, "No logins allowed for `%s'\n", name);
return LOGIN_ERROR_LOGIN;
}
setutent();
count = 0;
while ((ut = getutent())) {
#ifdef USER_PROCESS
if (ut->ut_type != USER_PROCESS)
continue;
#endif
if (ut->ut_user[0] == '\0')
continue;
if (strncmp(name, ut->ut_user, sizeof(ut->ut_user)) != 0)
continue;
if (++count > limit)
break;
}
endutent();
/*
* This is called after setutmp(), so the number of logins counted
* includes the user who is currently trying to log in.
*/
if (count > limit) {
syslog(LOG_WARNING, "Too many logins (max %d) for %s\n", limit, name);
return LOGIN_ERROR_LOGIN;
}
return 0;
}
/* Function setup_user_limits - checks/set limits for the curent login
* Original idea from Joel Katz's lshell. Ported to shadow-login
* by Cristian Gafton - gafton@sorosis.ro
*
* We are passed a string of the form ('BASH' constants for ulimit)
* [Aa][Cc][Dd][Ff][Mm][Nn][Rr][Ss][Tt][Uu][Ll][Pp]
* (eg. 'C2F256D2048N5' or 'C2 F256 D2048 N5')
* where:
* [Aa]: a = RLIMIT_AS max address space (KB)
* [Cc]: c = RLIMIT_CORE max core file size (KB)
* [Dd]: d = RLIMIT_DATA max data size (KB)
* [Ff]: f = RLIMIT_FSIZE max file size (KB)
* [Mm]: m = RLIMIT_MEMLOCK max locked-in-memory address space (KB)
* [Nn]: n = RLIMIT_NOFILE max number of open files
* [Rr]: r = RLIMIT_RSS max resident set size (KB)
* [Ss]: s = RLIMIT_STACK max stack size (KB)
* [Tt]: t = RLIMIT_CPU max CPU time (MIN)
* [Uu]: u = RLIMIT_NPROC max number of processes
* [Kk]: k = file creation masK (umask)
* [Ll]: l = max number of logins for this user
* [Pp]: p = process priority -20..20 (negative = high, positive = low)
*
* Return value:
* 0 = okay, of course
* LOGIN_ERROR_RLIMIT = error setting some RLIMIT
* LOGIN_ERROR_LOGIN = error - too many logins for this user
*
* buf - the limits string
* name - the username
*/
int do_user_limits(const char *buf, const char *name)
{
const char *pp;
int retval = 0;
pp = buf;
while (*pp != '\0') switch(*pp++) {
#ifdef RLIMIT_AS
case 'a':
case 'A':
/* RLIMIT_AS - max address space (KB) */
retval |= setrlimit_value(RLIMIT_AS, pp, 1024);
#endif
#ifdef RLIMIT_CPU
case 't':
case 'T':
/* RLIMIT_CPU - max CPU time (MIN) */
retval |= setrlimit_value(RLIMIT_CPU, pp, 60);
break;
#endif
#ifdef RLIMIT_DATA
case 'd':
case 'D':
/* RLIMIT_DATA - max data size (KB) */
retval |= setrlimit_value(RLIMIT_DATA, pp, 1024);
break;
#endif
#ifdef RLIMIT_FSIZE
case 'f':
case 'F':
/* RLIMIT_FSIZE - Maximum filesize (KB) */
retval |= setrlimit_value(RLIMIT_FSIZE, pp, 1024);
break;
#endif
#ifdef RLIMIT_NPROC
case 'u':
case 'U':
/* RLIMIT_NPROC - max number of processes */
retval |= setrlimit_value(RLIMIT_NPROC, pp, 1);
break;
#endif
#ifdef RLIMIT_CORE
case 'c':
case 'C':
/* RLIMIT_CORE - max core file size (KB) */
retval |= setrlimit_value(RLIMIT_CORE, pp, 1024);
break;
#endif
#ifdef RLIMIT_MEMLOCK
case 'm':
case 'M':
/* RLIMIT_MEMLOCK - max locked-in-memory address space (KB) */
retval |= setrlimit_value(RLIMIT_MEMLOCK, pp, 1024);
break;
#endif
#ifdef RLIMIT_NOFILE
case 'n':
case 'N':
/* RLIMIT_NOFILE - max number of open files */
retval |= setrlimit_value(RLIMIT_NOFILE, pp, 1);
break;
#endif
#ifdef RLIMIT_RSS
case 'r':
case 'R':
/* RLIMIT_RSS - max resident set size (KB) */
retval |= setrlimit_value(RLIMIT_RSS, pp, 1024);
break;
#endif
#ifdef RLIMIT_STACK
case 's':
case 'S':
/* RLIMIT_STACK - max stack size (KB) */
retval |= setrlimit_value(RLIMIT_STACK, pp, 1024);
break;
#endif
case 'k':
case 'K':
retval |= set_umask(pp);
break;
case 'l':
case 'L':
/* LIMIT the number of concurent logins */
retval |= check_logins(name, pp);
break;
case 'p':
case 'P':
retval |= set_prio(pp);
break;
}
return retval;
}
int setup_user_limits(const char *uname)
{
/* TODO: allow and use @group syntax --cristiang */
FILE *fil;
char buf[1024];
char name[1024];
char limits[1024];
char deflimits[1024];
char tempbuf[1024];
/* init things */
memzero(buf, sizeof(buf));
memzero(name, sizeof(name));
memzero(limits, sizeof(limits));
memzero(deflimits, sizeof(deflimits));
memzero(tempbuf, sizeof(tempbuf));
/* start the checks */
fil = fopen(LIMITS_FILE, "r");
if (fil == NULL) {
#if 0 /* no limits file is ok, not everyone is a BOFH :-). --marekm */
SYSLOG((LOG_WARN, NO_LIMITS, uname, LIMITS_FILE));
#endif
return 0;
}
/* The limits file have the following format:
* - '#' (comment) chars only as first chars on a line;
* - username must start on first column
* A better (smarter) checking should be done --cristiang */
while (fgets(buf, 1024, fil) != NULL) {
if (buf[0]=='#' || buf[0]=='\n')
continue;
memzero(tempbuf, sizeof(tempbuf));
/* a valid line should have a username, then spaces,
* then limits
* we allow the format:
* username L2 D2048 R4096
* where spaces={' ',\t}. Also, we reject invalid limits.
* Imposing a limit should be done with care, so a wrong
* entry means no care anyway :-). A '-' as a limits
* strings means no limits --cristiang */
if (sscanf(buf, "%s%[ACDFMNRSTULPacdfmnrstulp0-9 \t-]",
name, tempbuf) == 2) {
if (strcmp(name, uname) == 0) {
strcpy(limits, tempbuf);
break;
} else if (strcmp(name, "*") == 0) {
strcpy(deflimits, tempbuf);
}
}
}
fclose(fil);
if (limits[0] == '\0') {
/* no user specific limits */
if (deflimits[0] == '\0') /* no default limits */
return 0;
strcpy(limits, deflimits); /* use the default limits */
}
return do_user_limits(limits, uname);
}
#endif /* LIMITS */
void setup_usergroups(const struct passwd *info)
{
const struct group *grp;
mode_t oldmask;
/*
* if not root, and uid == gid, and username is the same as primary
* group name, set umask group bits to be the same as owner bits
* (examples: 022 -> 002, 077 -> 007).
*/
if (info->pw_uid != 0 && info->pw_uid == info->pw_gid) {
grp = getgrgid(info->pw_gid);
if (grp && (strcmp(info->pw_name, grp->gr_name) == 0)) {
oldmask = umask(0777);
umask((oldmask & ~070) | ((oldmask >> 3) & 070));
}
}
}
/*
* set the process nice, ulimit, and umask from the password file entry
*/
void setup_limits(const struct passwd *info)
{
char *cp;
int i;
long l;
if (getdef_bool("USERGROUPS_ENAB"))
setup_usergroups(info);
/*
* See if the GECOS field contains values for NICE, UMASK or ULIMIT.
* If this feature is enabled in /etc/login.defs, we make those
* values the defaults for this login session.
*/
if (getdef_bool("QUOTAS_ENAB")) {
#ifdef LIMITS
if (info->pw_uid != 0)
if (setup_user_limits(info->pw_name) & LOGIN_ERROR_LOGIN) {
fprintf(stderr, _("Too many logins.\n"));
sleep(2);
exit(1);
}
#endif
for (cp = info->pw_gecos ; cp != NULL ; cp = strchr (cp, ',')) {
if (*cp == ',')
cp++;
if (strncmp (cp, "pri=", 4) == 0) {
i = atoi (cp + 4);
if (i >= -20 && i <= 20)
(void) nice (i);
continue;
}
if (strncmp (cp, "ulimit=", 7) == 0) {
l = strtol (cp + 7, (char **) 0, 10);
set_filesize_limit(l);
continue;
}
if (strncmp (cp, "umask=", 6) == 0) {
i = strtol (cp + 6, (char **) 0, 8) & 0777;
(void) umask (i);
continue;
}
}
}
}

16
mbsebbs/limits.h Normal file
View File

@ -0,0 +1,16 @@
/* $Id$ */
#ifndef _LIMITS_H_
#define _LIMITS_H_
int setrlimit_value(unsigned int, const char *, unsigned int);
int set_prio(const char *);
int set_umask(const char *);
int check_logins(const char *, const char *);
int do_user_limits(const char *, const char *);
int setup_user_limits(const char *);
void setup_usergroups(const struct passwd *);
void setup_limits(const struct passwd *);
#endif

101
mbsebbs/log.c Normal file
View File

@ -0,0 +1,101 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <fcntl.h>
#include <time.h>
#include "mblogin.h"
#if HAVE_LASTLOG_H
#include <lastlog.h>
#else
// #include "lastlog_.h"
#endif
#include "log.h"
/*
* dolastlog - create lastlog entry
*
* A "last login" entry is created for the user being logged in. The
* UID is extracted from the global (struct passwd) entry and the
* TTY information is gotten from the (struct utmp).
*/
void dolastlog(struct lastlog *ll, const struct passwd *pw, const char *line, const char *host)
{
int fd;
off_t offset;
struct lastlog newlog;
/*
* If the file does not exist, don't create it.
*/
if ((fd = open(LASTLOG_FILE, O_RDWR)) == -1)
return;
/*
* The file is indexed by UID number. Seek to the record
* for this UID. Negative UID's will create problems, but ...
*/
offset = (unsigned long) pw->pw_uid * sizeof newlog;
if (lseek(fd, offset, SEEK_SET) != offset) {
close(fd);
return;
}
/*
* Read the old entry so we can tell the user when they last
* logged in. Then construct the new entry and write it out
* the way we read the old one in.
*/
if (read(fd, (char *) &newlog, sizeof newlog) != sizeof newlog)
memzero(&newlog, sizeof newlog);
if (ll)
*ll = newlog;
time(&newlog.ll_time);
strncpy(newlog.ll_line, line, sizeof newlog.ll_line);
#if HAVE_LL_HOST
strncpy(newlog.ll_host, host, sizeof newlog.ll_host);
#endif
if (lseek(fd, offset, SEEK_SET) == offset)
write(fd, (char *) &newlog, sizeof newlog);
close(fd);
}

8
mbsebbs/log.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _LOG_LOG_H
#define _LOG_LOG_H
void dolastlog(struct lastlog *, const struct passwd *, const char *, const char *);
#endif

168
mbsebbs/loginprompt.c Normal file
View File

@ -0,0 +1,168 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include "mblogin.h"
#include "getdef.h"
#include "xmalloc.h"
#include "env.h"
#include "loginprompt.h"
void login_exit(int sig)
{
exit(1);
}
/*
* login_prompt - prompt the user for their login name
*
* login_prompt() displays the standard login prompt. If ISSUE_FILE
* is set in login.defs, this file is displayed before the prompt.
*/
void login_prompt(const char *prompt, char *name, int namesize)
{
char buf[1024];
#define MAX_ENV 32
char *envp[MAX_ENV];
int envc;
char *cp;
int i;
FILE *fp;
RETSIGTYPE (*sigquit)(int);
#ifdef SIGTSTP
RETSIGTYPE (*sigtstp)(int);
#endif
/*
* There is a small chance that a QUIT character will be part of
* some random noise during a prompt. Deal with this by exiting
* instead of core dumping. If SIGTSTP is defined, do the same
* thing for that signal.
*/
sigquit = signal(SIGQUIT, login_exit);
#ifdef SIGTSTP
sigtstp = signal(SIGTSTP, login_exit);
#endif
/*
* See if the user has configured the issue file to
* be displayed and display it before the prompt.
*/
if (prompt) {
cp = getdef_str("ISSUE_FILE");
if (cp && (fp = fopen(cp, "r"))) {
while ((i = getc(fp)) != EOF)
putc(i, stdout);
fclose(fp);
}
gethostname(buf, sizeof buf);
printf(prompt, buf);
fflush(stdout);
}
/*
* Read the user's response. The trailing newline will be
* removed.
*/
memzero(buf, sizeof buf);
if (fgets(buf, sizeof buf, stdin) != buf)
exit(1);
cp = strchr(buf, '\n');
if (!cp)
exit(1);
*cp = '\0'; /* remove \n [ must be there ] */
/*
* Skip leading whitespace. This makes " username" work right.
* Then copy the rest (up to the end or the first "non-graphic"
* character into the username.
*/
for (cp = buf;*cp == ' ' || *cp == '\t';cp++)
;
// for (i = 0; i < namesize - 1 && isgraph(*cp); name[i++] = *cp++);
/*
* Allow double names for Fidonet login style.
*/
for (i = 0; i < namesize - 1 && isprint(*cp); name[i++] = *cp++);
while (isgraph(*cp))
cp++;
if (*cp)
cp++;
name[i] = '\0';
/*
* This is a disaster, at best. The user may have entered extra
* environmental variables at the prompt. There are several ways
* to do this, and I just take the easy way out.
*/
if (*cp != '\0') { /* process new variables */
char *nvar;
int count = 1;
for (envc = 0; envc < MAX_ENV; envc++) {
nvar = strtok(envc ? (char *)0 : cp, " \t,");
if (!nvar)
break;
if (strchr(nvar, '=')) {
envp[envc] = nvar;
} else {
envp[envc] = xmalloc(strlen(nvar) + 32);
sprintf(envp[envc], "L%d=%s", count++, nvar);
}
}
set_env(envc, envp);
}
/*
* Set the SIGQUIT handler back to its original value
*/
signal(SIGQUIT, sigquit);
#ifdef SIGTSTP
signal(SIGTSTP, sigtstp);
#endif
}

9
mbsebbs/loginprompt.h Normal file
View File

@ -0,0 +1,9 @@
/* $Id$ */
#ifndef _LOGINPROMPT_H
#define _LOGINPROMPT_H
void login_exit(int);
void login_prompt(const char *, char *, int);
#endif

890
mbsebbs/mblogin.c Normal file
View File

@ -0,0 +1,890 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: Login program for MBSE BBS.
* Shadow Suite (c) ......: Julianne Frances Haugh
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include "mblogin.h"
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#if defined(SHADOW_PASSWORD)
#include <shadow.h>
#endif
#if HAVE_UTMPX_H
#include <utmpx.h>
#else
#include <utmp.h>
#endif
#include <signal.h>
#include <unistd.h>
#include <lastlog.h>
#include "getdef.h"
#ifdef SVR4_SI86_EUA
#include <sys/proc.h>
#include <sys/sysi86.h>
#endif
#ifdef UT_ADDR
#include <netdb.h>
#endif
#include "env.h"
#include "chowntty.h"
#include "ttytype.h"
#include "basename.h"
#include "shell.h"
#include "failure.h"
#include "pwdcheck.h"
#include "pwauth.h"
#include "loginprompt.h"
#include "utmp.h"
#include "limits.h"
#include "setupenv.h"
#include "sub.h"
#include "ulimit.h"
#include "log.h"
#include "tz.h"
#include "setugid.h"
/*
* Needed for MkLinux DR1/2/2.1 - J.
*/
#ifndef LASTLOG_FILE
#define LASTLOG_FILE "/var/log/lastlog"
#endif
const char *hostname = "";
struct passwd pwent, *pw;
#if HAVE_UTMPX_H
struct utmpx utxent, failent;
struct utmp utent;
#else
struct utmp utent, failent;
#endif
struct lastlog lastlog;
static int preauth_flag = 0;
/*
* Global variables.
*/
static int hflg = 0;
static int pflg = 0;
static char *Prog;
static int amroot;
static int timeout;
/*
* External identifiers.
*/
extern char **newenvp;
extern size_t newenvc;
extern int optind;
extern char *optarg;
extern char **environ;
#ifndef ALARM
#define ALARM 60
#endif
#ifndef RETRIES
#define RETRIES 3
#endif
static struct faillog faillog;
#define NO_SHADOW "no shadow password for `%s'%s\n"
#define BAD_PASSWD "invalid password for `%s'%s\n"
#define BAD_DIALUP "invalid dialup password for `%s' on `%s'\n"
#define BAD_ROOT_LOGIN "ILLEGAL ROOT LOGIN%s\n"
#define BAD_GROUP "user `%s' not in group bbs\n"
#define ROOT_LOGIN "ROOT LOGIN%s\n"
#define FAILURE_CNT "exceeded failure limit for `%s'%s\n"
#define REG_LOGIN "`%s' logged in%s\n"
#define LOGIN_REFUSED "LOGIN `%s' REFUSED%s\n"
#define REENABLED2 \
"login `%s' re-enabled after temporary lockout (%d failures).\n"
#define MANY_FAILS "REPEATED login failures%s\n"
/* local function prototypes */
static void usage(void);
static void setup_tty(void);
static void check_flags(int, char * const *);
static void check_nologin(void);
static void init_env(void);
static RETSIGTYPE alarm_handler(int);
int main(int, char **);
/*
* usage - print login command usage and exit
*
* login [ name ]
* login -r hostname (for rlogind)
* login -h hostname (for telnetd, etc.)
* login -f name (for pre-authenticated login: datakit, xterm, etc.)
*/
static void
usage(void)
{
fprintf(stderr, _("usage: %s [-p] [name]\n"), Prog);
if (!amroot)
exit(1);
fprintf(stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
#ifdef RLOGIN
fprintf(stderr, _(" %s [-p] -r host\n"), Prog);
#endif
exit(1);
}
static void setup_tty(void)
{
TERMIO termio;
GTTY(0, &termio); /* get terminal characteristics */
/*
* Add your favorite terminal modes here ...
*/
termio.c_lflag |= ISIG|ICANON|ECHO|ECHOE;
termio.c_iflag |= ICRNL;
#if defined(ECHOKE) && defined(ECHOCTL)
termio.c_lflag |= ECHOKE|ECHOCTL;
#endif
#if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
termio.c_lflag &= ~(ECHOPRT|NOFLSH|TOSTOP);
#endif
#ifdef ONLCR
termio.c_oflag |= ONLCR;
#endif
#ifdef SUN4
/*
* Terminal setup for SunOS 4.1 courtesy of Steve Allen
* at UCO/Lick.
*/
termio.c_cc[VEOF] = '\04';
termio.c_cflag &= ~CSIZE;
termio.c_cflag |= (PARENB|CS7);
termio.c_lflag |= (ISIG|ICANON|ECHO|IEXTEN);
termio.c_iflag |= (BRKINT|IGNPAR|ISTRIP|IMAXBEL|ICRNL|IXON);
termio.c_iflag &= ~IXANY;
termio.c_oflag |= (XTABS|OPOST|ONLCR);
#endif
/* leave these values unchanged if not specified in login.defs */
termio.c_cc[VERASE] = getdef_num("ERASECHAR", termio.c_cc[VERASE]);
termio.c_cc[VKILL] = getdef_num("KILLCHAR", termio.c_cc[VKILL]);
/*
* ttymon invocation prefers this, but these settings won't come into
* effect after the first username login
*/
STTY(0, &termio);
}
static void check_flags(int argc, char * const *argv)
{
int arg;
/*
* Check the flags for proper form. Every argument starting with
* "-" must be exactly two characters long. This closes all the
* clever rlogin, telnet, and getty holes.
*/
for (arg = 1; arg < argc; arg++) {
// printf("%d <%s>\n", arg, argv[arg]);
if (argv[arg][0] == '-' && strlen(argv[arg]) > 2)
usage();
}
}
static void check_nologin(void)
{
char *fname;
/*
* Check to see if system is turned off for non-root users.
* This would be useful to prevent users from logging in
* during system maintenance. We make sure the message comes
* out for root so she knows to remove the file if she's
* forgotten about it ...
*/
fname = getdef_str("NOLOGINS_FILE");
if (fname != NULL && access(fname, F_OK) == 0) {
FILE *nlfp;
int c;
/*
* Cat the file if it can be opened, otherwise just
* print a default message
*/
if ((nlfp = fopen (fname, "r"))) {
while ((c = getc (nlfp)) != EOF) {
if (c == '\n')
putchar ('\r');
putchar (c);
}
fflush (stdout);
fclose (nlfp);
} else
printf("\nSystem closed for routine maintenance\n");
/*
* Non-root users must exit. Root gets the message, but
* gets to login.
*/
if (pwent.pw_uid != 0) {
closelog();
exit(0);
}
printf("\n[Disconnect bypassed -- root login allowed.]\n");
}
}
static void init_env(void)
{
char *cp, *tmp;
if ((tmp = getenv("LANG"))) {
addenv("LANG", tmp);
}
/*
* Add the timezone environmental variable so that time functions
* work correctly.
*/
if ((tmp = getenv("TZ"))) {
addenv("TZ", tmp);
} else if ((cp = getdef_str("ENV_TZ")))
addenv(*cp == '/' ? tz(cp) : cp, NULL);
/*
* Add the clock frequency so that profiling commands work
* correctly.
*/
if ((tmp = getenv("HZ"))) {
addenv("HZ", tmp);
} else if ((cp = getdef_str("ENV_HZ")))
addenv(cp, NULL);
}
static RETSIGTYPE alarm_handler(int sig)
{
fprintf(stderr, "\nLogin timed out after %d seconds.\n", timeout);
exit(0);
}
/*
* login - create a new login session for a user
*
* login is typically called by getty as the second step of a
* new user session. getty is responsible for setting the line
* characteristics to a reasonable set of values and getting
* the name of the user to be logged in. login may also be
* called to create a new user session on a pty for a variety
* of reasons, such as X servers or network logins.
*/
int main(int argc, char **argv)
{
char username[37];
char tty[BUFSIZ];
char userfile[PATH_MAX];
FILE *ufp;
struct userhdr usrconfighdr;
struct userrec usrconfig;
int reason = PW_LOGIN;
int delay;
int retries;
int failed;
int flag;
int subroot = 0;
int is_console = 0;
int FoundName;
const char *cp;
char *tmp;
char fromhost[512];
struct passwd *pwd;
char **envp = environ;
static char temp_pw[2];
static char temp_shell[] = "/bin/sh";
#ifdef SHADOW_PASSWORD
struct spwd *spwd=NULL;
#endif
#if defined(DES_RPC) || defined(KERBEROS)
/* from pwauth.c */
extern char *clear_pass;
extern int wipe_clear_pass;
/*
* We may need the password later, don't want pw_auth() to wipe it
* (we do it ourselves when it is no longer needed). --marekm
*/
wipe_clear_pass = 0;
#endif
printf("\nMBSE BBS v%s\n", VERSION);
printf("%s\n\n", COPYRIGHT);
/*
* Some quick initialization.
*/
sanitize_env();
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
initenv();
username[0] = '\0';
amroot = (getuid() == 0);
Prog = Basename(argv[0]);
check_flags(argc, argv);
while ((flag = getopt(argc, argv, "d:h:p")) != EOF) {
switch (flag) {
case 'p':
pflg++;
break;
case 'h':
hflg++;
hostname = optarg;
reason = PW_TELNET;
break;
case 'd':
/* "-d device" ignored for compatibility */
break;
default:
usage();
}
}
/*
* Allow authentication bypass only if real UID is zero.
*/
if (hflg && !amroot) {
fprintf(stderr, _("%s: permission denied\n"), Prog);
exit(1);
}
if (!isatty(0) || !isatty(1) || !isatty(2))
exit(1); /* must be a terminal */
/*
* Be picky if run by normal users (possible if installed setuid
* root), but not if run by root. This way it still allows logins
* even if your getty is broken, or if something corrupts utmp,
* but users must "exec login" which will use the existing utmp
* entry (will not overwrite remote hostname). --marekm
*/
checkutmp(!amroot);
STRFCPY(tty, utent.ut_line);
if (hflg) {
#ifdef UT_ADDR
struct hostent *he;
/*
* Fill in the ut_addr field (remote login IP address).
* XXX - login from util-linux does it, but this is not
* the right place to do it. The program that starts
* login (telnetd, rlogind) knows the IP address, so it
* should create the utmp entry and fill in ut_addr.
* gethostbyname() is not 100% reliable (the remote host
* may be unknown, etc.). --marekm
*/
if ((he = gethostbyname(hostname))) {
utent.ut_addr = *((int32_t *)(he->h_addr_list[0]));
#endif
#ifdef UT_HOST
strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
#endif
#if HAVE_UTMPX_H
strncpy(utxent.ut_host, hostname, sizeof(utxent.ut_host));
#endif
/*
* Add remote hostname to the environment. I think
* (not sure) I saw it once on Irix. --marekm
*/
addenv("REMOTEHOST", hostname);
}
#ifdef __linux__
/* workaround for init/getty leaving junk in ut_host at least in some
version of RedHat. --marekm */
else if (amroot)
memzero(utent.ut_host, sizeof utent.ut_host);
#endif
openlog("mblogin", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
setup_tty();
umask(getdef_num("UMASK", 077));
{
/*
* Use the ULIMIT in the login.defs file, and if
* there isn't one, use the default value. The
* user may have one for themselves, but otherwise,
* just take what you get.
*/
long limit = getdef_long("ULIMIT", -1L);
if (limit != -1)
set_filesize_limit(limit);
}
if (pflg)
while (*envp) /* add inherited environment, */
addenv(*envp++, NULL); /* some variables change later */
/* preserve TERM from getty */
if (!pflg && (tmp = getenv("TERM")))
addenv("TERM", tmp);
/* preserver CONNECT messages from mgetty */
if ((tmp = getenv("CONNECT")))
addenv("CONNECT", tmp);
if ((tmp = getenv("CALLER_ID")))
addenv("CALLER_ID", tmp);
/* get the mbse environment */
pw = getpwnam("mbse");
addenv("MBSE_ROOT", pw->pw_dir);
sprintf(userfile, "%s/etc/users.data", pw->pw_dir);
init_env();
if (optind < argc) { /* get the user name */
// if (rflg || fflg)
// usage();
#ifdef SVR4
/*
* The "-h" option can't be used with a command-line username,
* because telnetd invokes us as: login -h host TERM=...
*/
if (! hflg)
#endif
{
STRFCPY(username, argv[optind]);
strzero(argv[optind]);
++optind;
}
}
printf("[%s]\n", username);
#ifdef SVR4
/*
* check whether ttymon has done the prompt for us already
*/
{
char *ttymon_prompt;
if ((ttymon_prompt = getenv("TTYPROMPT")) != NULL && (*ttymon_prompt != 0)) {
/* read name, without prompt */
login_prompt((char *)0, username, sizeof username);
}
}
#endif /* SVR4 */
if (optind < argc) /* now set command line variables */
set_env(argc - optind, &argv[optind]);
if (hflg)
cp = hostname;
else
#ifdef UT_HOST
if (utent.ut_host[0])
cp = utent.ut_host;
else
#endif
#if HAVE_UTMPX_H
if (utxent.ut_host[0])
cp = utxent.ut_host;
else
#endif
cp = "";
if (*cp)
snprintf(fromhost, sizeof fromhost, _(" on `%s' from `%s'"), tty, cp);
else
snprintf(fromhost, sizeof fromhost, _(" on `%s'"), tty);
top:
/* only allow ALARM sec. for login */
signal(SIGALRM, alarm_handler);
timeout = getdef_num("LOGIN_TIMEOUT", ALARM);
if (timeout > 0)
alarm(timeout);
environ = newenvp; /* make new environment active */
delay = getdef_num("FAIL_DELAY", 1);
retries = getdef_num("LOGIN_RETRIES", RETRIES);
while (1) { /* repeatedly get login/password pairs */
failed = 0; /* haven't failed authentication yet */
if (! username[0]) { /* need to get a login id */
if (subroot) {
closelog ();
exit (1);
}
preauth_flag = 0;
#ifndef LOGIN_PROMPT
#ifdef __linux__ /* hostname login: - like in util-linux login */
login_prompt(_("\n%s login: "), username, sizeof username);
#else
login_prompt(_("login: "), username, sizeof username);
#endif
#else
login_prompt(LOGIN_PROMPT, username, sizeof username);
#endif
continue;
}
/*
* Here we try usernames on unix names and Fidonet style
* names that are stored in the bbs userdatabase.
*/
FoundName = 0;
if ((ufp = fopen(userfile, "r"))) {
fread(&usrconfighdr, sizeof(usrconfighdr), 1, ufp);
while (fread(&usrconfig, usrconfighdr.recsize, 1, ufp) == 1) {
if ((strcasecmp(usrconfig.sUserName, username) == 0) ||
(strcasecmp(usrconfig.sHandle, username) == 0) ||
(strcmp(usrconfig.Name, username) == 0)) {
FoundName = 1;
STRFCPY(username, usrconfig.Name);
break;
}
}
fclose(ufp);
}
if (! (pwd = getpwnam(username))) {
pwent.pw_name = username;
strcpy(temp_pw, "!");
pwent.pw_passwd = temp_pw;
pwent.pw_shell = temp_shell;
preauth_flag = 0;
failed = 1;
} else {
pwent = *pwd;
}
#ifdef SHADOW_PASSWORD
spwd = NULL;
if (pwd && strcmp(pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0) {
spwd = getspnam(username);
if (spwd)
pwent.pw_passwd = spwd->sp_pwdp;
else
syslog(LOG_WARNING, NO_SHADOW, username, fromhost);
}
#endif /* SHADOWPWD */
/*
* If the encrypted password begins with a "!", the account
* is locked and the user cannot login, even if they have
* been "pre-authenticated."
*/
if (pwent.pw_passwd[0] == '!' || pwent.pw_passwd[0] == '*')
failed = 1;
/*
* The -r and -f flags provide a name which has already
* been authenticated by some server.
*/
if (preauth_flag)
goto auth_ok;
if (pw_auth(pwent.pw_passwd, username, reason, (char *) 0) == 0)
goto auth_ok;
/*
* Don't log unknown usernames - I mistyped the password for
* username at least once... Should probably use LOG_AUTHPRIV
* for those who really want to log them. --marekm
*/
syslog(LOG_WARNING, BAD_PASSWD, (pwd || getdef_bool("LOG_UNKFAIL_ENAB")) ? username : "UNKNOWN", fromhost);
failed = 1;
auth_ok:
/*
* This is the point where all authenticated users
* wind up. If you reach this far, your password has
* been authenticated and so on.
*/
#if defined(RADIUS) && !(defined(DES_RPC) || defined(KERBEROS))
if (clear_pass) {
strzero(clear_pass);
clear_pass = NULL;
}
#endif
if (! failed && pwent.pw_name && pwent.pw_uid == 0 && ! is_console) {
syslog(LOG_CRIT, BAD_ROOT_LOGIN, fromhost);
failed = 1;
}
#ifdef LOGIN_ACCESS
if (!failed && !login_access(username, *hostname ? hostname : tty)) {
syslog(LOG_WARNING, LOGIN_REFUSED, username, fromhost);
failed = 1;
}
#endif
if (pwd && getdef_bool("FAILLOG_ENAB") && ! failcheck (pwent.pw_uid, &faillog, failed)) {
syslog(LOG_CRIT, FAILURE_CNT, username, fromhost);
failed = 1;
}
if (! failed)
break;
/* don't log non-existent users */
if (pwd && getdef_bool("FAILLOG_ENAB"))
failure (pwent.pw_uid, tty, &faillog);
if (getdef_str("FTMP_FILE") != NULL) {
const char *failent_user;
#if HAVE_UTMPX_H
failent = utxent;
gettimeofday(&(failent.ut_tv), NULL);
#else
failent = utent;
time(&failent.ut_time);
#endif
if (pwd) {
failent_user = pwent.pw_name;
} else {
if (getdef_bool("LOG_UNKFAIL_ENAB"))
failent_user = username;
else
failent_user = "UNKNOWN";
}
strncpy(failent.ut_user, failent_user, sizeof(failent.ut_user));
#ifdef USER_PROCESS
failent.ut_type = USER_PROCESS;
#endif
failtmp(&failent);
}
memzero(username, sizeof username);
if (--retries <= 0)
syslog(LOG_CRIT, MANY_FAILS, fromhost);
#if 1
/*
* If this was a passwordless account and we get here,
* login was denied (securetty, faillog, etc.). There
* was no password prompt, so do it now (will always
* fail - the bad guys won't see that the passwordless
* account exists at all). --marekm
*/
if (pwent.pw_passwd[0] == '\0')
pw_auth("!", username, reason, (char *) 0);
#endif
/*
* Wait a while (a la SVR4 /usr/bin/login) before attempting
* to login the user again. If the earlier alarm occurs
* before the sleep() below completes, login will exit.
*/
if (delay > 0)
sleep(delay);
puts(_("Login incorrect"));
} /* while (1) */
(void) alarm (0); /* turn off alarm clock */
#if 1
/*
* porttime checks moved here, after the user has been
* authenticated. now prints a message, as suggested
* by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
*/
// if (getdef_bool("PORTTIME_CHECKS_ENAB") &&
// !isttytime(pwent.pw_name, tty, time ((time_t *) 0))) {
// SYSLOG((LOG_WARN, BAD_TIME, username, fromhost));
// closelog();
// bad_time_notify();
// exit(1);
// }
#endif
check_nologin();
if (getenv("IFS")) /* don't export user IFS ... */
addenv("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
setutmp(username, tty, hostname); /* make entry in utmp & wtmp files */
if (pwent.pw_shell[0] == '*') { /* subsystem root */
subsystem (&pwent); /* figure out what to execute */
subroot++; /* say i was here again */
endpwent (); /* close all of the file which were */
endgrent (); /* open in the original rooted file */
#ifdef SHADOW_PASSWORD
endspent (); /* system. they will be re-opened */
#endif
#ifdef SHADOWGRP
endsgent (); /* in the new rooted file system */
#endif
goto top; /* go do all this all over again */
}
if (getdef_bool("LASTLOG_ENAB")) /* give last login and log this one */
dolastlog(&lastlog, &pwent, utent.ut_line, hostname);
#ifdef SVR4_SI86_EUA
sysi86(SI86LIMUSER, EUA_ADD_USER); /* how do we test for fail? */
#endif
#ifdef AGING
/*
* Have to do this while we still have root privileges, otherwise
* we don't have access to /etc/shadow. expire() closes password
* files, and changes to the user in the child before executing
* the passwd program. --marekm
*/
#ifdef SHADOW_PASSWORD
if (spwd) { /* check for age of password */
if (expire (&pwent, spwd)) {
pwd = getpwnam(username);
spwd = getspnam(username);
if (pwd)
pwent = *pwd;
}
}
#else
#ifdef ATT_AGE
if (pwent.pw_age && pwent.pw_age[0]) {
if (expire (&pwent)) {
pwd = getpwnam(username);
if (pwd)
pwent = *pwd;
}
}
#endif /* ATT_AGE */
#endif /* SHADOWPWD */
#endif /* AGING */
setup_limits(&pwent); /* nice, ulimit etc. */
chown_tty(tty, &pwent);
if (setup_uid_gid(&pwent, is_console))
exit(1);
#ifdef KERBEROS
if (clear_pass)
login_kerberos(username, clear_pass);
#endif
#ifdef DES_RPC
if (clear_pass)
login_desrpc(clear_pass);
#endif
#if defined(DES_RPC) || defined(KERBEROS)
if (clear_pass)
strzero(clear_pass);
#endif
setup_env(&pwent); /* set env vars, cd to the home dir */
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
addenv("HUSHLOGIN=TRUE", NULL);
if (getdef_str("TTYTYPE_FILE") != NULL && getenv("TERM") == NULL)
ttytype (tty);
signal(SIGQUIT, SIG_DFL); /* default quit signal */
signal(SIGTERM, SIG_DFL); /* default terminate signal */
signal(SIGALRM, SIG_DFL); /* default alarm signal */
signal(SIGHUP, SIG_DFL); /* added this. --marekm */
signal(SIGINT, SIG_DFL); /* default interrupt signal */
endpwent(); /* stop access to password file */
endgrent(); /* stop access to group file */
#ifdef SHADOW_PASSWORD
endspent(); /* stop access to shadow passwd file */
#endif
#ifdef SHADOWGRP
endsgent(); /* stop access to shadow group file */
#endif
if (pwent.pw_uid == 0)
syslog(LOG_NOTICE, ROOT_LOGIN, fromhost);
else
syslog(LOG_INFO, REG_LOGIN, username, fromhost);
closelog();
if ((tmp = getdef_str("FAKE_SHELL")) != NULL) {
shell(tmp, pwent.pw_shell); /* fake shell */
}
shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
/*NOTREACHED*/
return 0;
}

365
mbsebbs/mblogin.h Normal file
View File

@ -0,0 +1,365 @@
/* $Id$ */
#ifndef _MBLOGIN_H
#define _MBLOGIN_H
#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
/* Take care of NLS matters. */
#if HAVE_LOCALE_H
# include <locale.h>
#endif
#if !HAVE_SETLOCALE
# define setlocale(Category, Locale) /* empty */
#endif
#define gettext_noop(String) (String)
/* #define gettext_def(String) "#define String" */
#if ENABLE_NLS
# include <libintl.h>
# define _(Text) gettext (Text)
#else
# undef bindtextdomain
# define bindtextdomain(Domain, Directory) /* empty */
# undef textdomain
# define textdomain(Domain) /* empty */
# define _(Text) Text
#endif
#ifndef P_
# ifdef PROTOTYPES
# define P_(x) x
# else
# define P_(x) ()
# endif
#endif
#if STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else /* not STDC_HEADERS */
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr(), *strtok();
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy((s), (d), (n))
# endif
#endif /* not STDC_HEADERS */
#include <sys/stat.h>
#include <sys/types.h>
#if HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#if HAVE_UNISTD_H
# include <unistd.h>
#endif
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else /* not TIME_WITH_SYS_TIME */
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif /* not TIME_WITH_SYS_TIME */
#ifdef HAVE_MEMSET
# define memzero(ptr, size) memset((void *)(ptr), 0, (size))
#else
# define memzero(ptr, size) bzero((char *)(ptr), (size))
#endif
#define strzero(s) memzero(s, strlen(s)) /* warning: evaluates twice */
#ifdef HAVE_DIRENT_H /* DIR_SYSV */
# include <dirent.h>
# define DIRECT dirent
#else
# ifdef HAVE_SYS_NDIR_H /* DIR_XENIX */
# include <sys/ndir.h>
# endif
# ifdef HAVE_SYS_DIR_H /* DIR_??? */
# include <sys/dir.h>
# endif
# ifdef HAVE_NDIR_H /* DIR_BSD */
# include <ndir.h>
# endif
# define DIRECT direct
#endif
#ifdef SHADOWPWD
/*
* Possible cases:
* - /usr/include/shadow.h exists and includes the shadow group stuff.
* - /usr/include/shadow.h exists, but we use our own gshadow.h.
* - /usr/include/shadow.h doesn't exist, use our own shadow.h and gshadow.h.
*/
#if HAVE_SHADOW_H
#include <shadow.h>
#if defined(SHADOWGRP) && !defined(GSHADOW)
#include "gshadow_.h"
#endif
#else /* not HAVE_SHADOW_H */
#include "shadow_.h"
#ifdef SHADOWGRP
#include "gshadow_.h"
#endif
#endif /* not HAVE_SHADOW_H */
#endif /* SHADOWPWD */
#include <limits.h>
#ifndef NGROUPS_MAX
#ifdef NGROUPS
#define NGROUPS_MAX NGROUPS
#else
#define NGROUPS_MAX 64
#endif
#endif
#ifndef F_OK
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
#endif
#if HAVE_TERMIOS_H
# include <termios.h>
# define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
# define GTTY(fd, termio) tcgetattr(fd, termio)
# define TERMIO struct termios
# define USE_TERMIOS
#else /* assumed HAVE_TERMIO_H */
# include <sys/ioctl.h>
# include <termio.h>
# define STTY(fd, termio) ioctl(fd, TCSETA, termio)
# define GTTY(fd, termio) ioctl(fd, TCGETA, termio)
# define TEMRIO struct termio
# define USE_TERMIO
#endif
/*
* Password aging constants
*
* DAY - seconds / day
* WEEK - seconds / week
* SCALE - seconds / aging unit
*/
/* Solaris defines this in shadow.h */
#ifndef DAY
#define DAY (24L*3600L)
#endif
#define WEEK (7*DAY)
#ifdef ITI_AGING
#define SCALE 1
#else
#define SCALE DAY
#endif
/* Copy string pointed by B to array A with size checking. It was originally
* in lmain.c but is _very_ useful elsewhere. Some setuid root programs with
* very sloppy coding used to assume that BUFSIZ will always be enough... */
/* danger - side effects */
#define STRFCPY(A,B) \
(strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0')
/* get rid of a few ugly repeated #ifdefs in pwent.c and grent.c */
/* XXX - this is ugly too, configure should test it and not check for
any hardcoded system names, if possible. --marekm */
#if defined(SVR4) || defined(AIX) || defined(__linux__)
#define SETXXENT_TYPE void
#define SETXXENT_RET(x) return
#define SETXXENT_TEST(x) x; if (0) /* compiler should optimize this away */
#else
#define SETXXENT_TYPE int
#define SETXXENT_RET(x) return(x)
#define SETXXENT_TEST(x) if (x)
#endif
#ifndef PASSWD_FILE
#define PASSWD_FILE "/etc/passwd"
#endif
#ifndef GROUP_FILE
#define GROUP_FILE "/etc/group"
#endif
#ifdef SHADOWPWD
#ifndef SHADOW_FILE
#define SHADOW_FILE "/etc/shadow"
#endif
#endif
#ifdef SHADOWGRP
#ifndef SGROUP_FILE
#define SGROUP_FILE "/etc/gshadow"
#endif
#endif
#define PASSWD_PAG_FILE PASSWD_FILE ".pag"
#define GROUP_PAG_FILE GROUP_FILE ".pag"
#define SHADOW_PAG_FILE SHADOW_FILE ".pag"
#define SGROUP_PAG_FILE SGROUP_FILE ".pag"
#ifndef NULL
#define NULL ((void *) 0)
#endif
#ifdef sun /* hacks for compiling on SunOS */
# ifndef SOLARIS
extern int fputs();
extern char *strdup();
extern char *strerror();
# endif
#endif
#ifndef HAVE_SNPRINTF
#include "snprintf.h"
#endif
/*
* string to use for the pw_passwd field in /etc/passwd when using
* shadow passwords - most systems use "x" but there are a few
* exceptions, so it can be changed here if necessary. --marekm
*/
#ifndef SHADOW_PASSWD_STRING
#define SHADOW_PASSWD_STRING "x"
#endif
#ifdef PAM_STRERROR_NEEDS_TWO_ARGS /* Linux-PAM 0.59+ */
#define PAM_STRERROR(pamh, err) pam_strerror(pamh, err)
#else
#define PAM_STRERROR(pamh, err) pam_strerror(err)
#endif
/*
* login failure logging file format
*
* The login failure file is maintained by login(1) and faillog(8)
* Each record in the file represents a separate UID and the file
* is indexed in that fashion.
*/
struct faillog {
short fail_cnt; /* failures since last success */
short fail_max; /* failures before turning account off */
char fail_line[12]; /* last failure occured here */
time_t fail_time; /* last failure occured then */
/*
* If nonzero, the account will be re-enabled if there are no
* failures for fail_locktime seconds since last failure.
*/
long fail_locktime;
};
#define Max_passlen 14 /* Define maximum passwd length */
/*
* Security structure
*/
typedef struct _security {
unsigned int level; /* Security level */
unsigned long flags; /* Access flags */
unsigned long notflags; /* No Access flags */
} securityrec;
/*
* Users Control Structures (users.data)
*/
struct userhdr {
long hdrsize; /* Size of header */
long recsize; /* Size of records */
};
struct userrec {
char sUserName[36]; /* User First and Last Name */
char Name[9]; /* Unix name */
unsigned long xPassword; /* Users Password (CRC) */
char sVoicePhone[20]; /* Voice Number */
char sDataPhone[20]; /* Data/Business Number */
char sLocation[28]; /* Users Location */
char address[3][41]; /* Users address */
char sDateOfBirth[12]; /* Date of Birth */
time_t tFirstLoginDate; /* Date of First Login */
time_t tLastLoginDate; /* Date of Last Login */
securityrec Security; /* User Security Level */
char sComment[81]; /* User Comment */
char sExpiryDate[12]; /* User Expiry Date */
securityrec ExpirySec; /* Expiry Security Level */
char sSex[8]; /* Users Sex */
unsigned Hidden : 1; /* Hide User from Lists */
unsigned HotKeys : 1; /* Hot-Keys ON/OFF */
unsigned GraphMode : 1; /* ANSI Mode ON/OFF */
unsigned Deleted : 1; /* Deleted Status */
unsigned NeverDelete : 1; /* Never Delete User */
unsigned Chat : 1; /* Has IEMSI Chatmode */
unsigned LockedOut : 1; /* User is locked out */
unsigned DoNotDisturb : 1; /* DoNot disturb */
unsigned Cls : 1; /* CLS on/off */
unsigned More : 1; /* More prompt */
unsigned FsMsged : 1; /* Fullscreen editor */
unsigned MailScan : 1; /* New Mail scan */
unsigned Guest : 1; /* Is guest account */
unsigned OL_ExtInfo : 1; /* OLR extended msg info */
int iTotalCalls; /* Total number of calls */
int iTimeLeft; /* Time left today */
int iConnectTime; /* Connect time this call */
int iTimeUsed; /* Time used today */
int iScreenLen; /* User Screen Length */
time_t tLastPwdChange; /* Date last password chg */
unsigned xHangUps;
long Credit; /* Users credit */
int Paged; /* Times paged today */
int xOfflineFmt;
int LastPktNum; /* Todays Last packet number*/
char Archiver[6]; /* Archiver to use */
int iLastFileArea; /* Number of last file area */
int iLastFileGroup; /* Number of last file group*/
char sProtocol[21]; /* Users default protocol */
unsigned long Downloads; /* Total number of d/l's */
unsigned long Uploads; /* Total number of uploads */
unsigned long UploadK; /* Upload KiloBytes */
unsigned long DownloadK; /* Download KiloBytes */
long DownloadKToday; /* KB Downloaded today */
long UploadKToday; /* KB Uploaded today */
int iTransferTime; /* Last file transfer time */
int iLastMsgArea; /* Number of last msg area */
int iLastMsgGroup; /* Number of last msg group */
int iPosted; /* Number of msgs posted */
int iLanguage; /* Current Language */
char sHandle[36]; /* Users Handle */
int iStatus; /* WhosDoingWhat status */
int DownloadsToday; /* Downloads today */
int CrtDef; /* IEMSI Terminal emulation */
int Protocol; /* IEMSI protocol */
unsigned IEMSI : 1; /* Is this a IEMSI session */
unsigned ieMNU : 1; /* Can do ASCII download */
unsigned ieTAB : 1; /* Can handle TAB character */
unsigned ieASCII8 : 1; /* Can handle 8-bit IBM-PC */
unsigned ieNEWS : 1; /* Show bulletins */
unsigned ieFILE : 1; /* Check for new files */
unsigned Email : 1; /* Has private email box */
unsigned FSemacs : 1; /* FSedit uses emacs keys */
char Password[Max_passlen+1];/* Plain password */
};
#endif

View File

@ -5,7 +5,7 @@
* Shadow Suite (c) ......: Julianne Frances Haugh
*
*****************************************************************************
* Copyright (C) 1997-2001
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
@ -83,6 +83,7 @@ static int do_update_pwd = 0;
#ifdef SHADOW_PASSWORD
static int is_shadow_pwd;
static void check_password(const struct passwd *, const struct spwd *);
#else /* !SHADOW_PASSWORD */
static void check_password(const struct passwd *);
@ -124,7 +125,7 @@ static void fail_exit(int status)
if (is_shadow_grp)
sgr_unlock();
#endif
#ifdef SHADOWPWD
#ifdef SHADOW_PASSWORD
if (is_shadow_pwd)
spw_unlock();
#endif
@ -319,7 +320,7 @@ int isexpired(const struct passwd *pw)
* is considered to be infinite.
*/
#ifdef SHADOWPWD
#ifdef SHADOW_PASSWORD
if (sp->sp_lstchg == -1 ||
sp->sp_max == -1 || sp->sp_max >= (10000L*DAY/SCALE))
return 0;
@ -335,7 +336,7 @@ int isexpired(const struct passwd *pw)
* the password has expired.
*/
#ifdef SHADOWPWD
#ifdef SHADOW_PASSWORD
if (now >= sp->sp_lstchg + sp->sp_max)
return 1;
#endif
@ -778,8 +779,8 @@ int main(int argc, char *argv[])
* this program runs under account mbse.
*/
force = 1;
if (strcmp(pw->pw_name, (char *)"mbse")) {
fprintf(stderr, "mbpasswd: only user \"mbse\" may do this.\n");
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");
exit(E_NOPERM);
}
} else if (strncmp(argv[1], "-n", 2) == 0) {
@ -824,6 +825,8 @@ int main(int argc, char *argv[])
#ifdef SHADOW_PASSWORD
is_shadow_pwd = spw_file_present();
sp = getspnam(name);
if (!sp)
sp = pwd_to_spwd(pw);

575
mbsebbs/pwauth.c Normal file
View File

@ -0,0 +1,575 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2002
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include "mblogin.h"
#include "pwauth.h"
#include "getdef.h"
#include "encrypt.h"
#ifdef SKEY
#include <skey.h>
#endif
#ifdef OPIE
#include <opie.h>
#endif
#ifdef __linux__ /* standard password prompt by default */
static const char *PROMPT = gettext_noop("Password: ");
#else
static const char *PROMPT = gettext_noop("%s's Password: ");
#endif
#ifdef AUTH_METHODS
/*
* Look-up table for bound-in methods. Put the name that the
* method is known by in the password field as "name" and a
* pointer to the function
*/
struct method {
char *name;
int (*func) P_((const char *, int, const char *));
};
#ifdef PAD_AUTH
int pad_auth();
#endif
static struct method methods[] = {
#ifdef PAD_AUTH
{ "pad", pad_auth },
#endif
{ "", 0 }
};
#endif /* AUTH_METHODS */
int wipe_clear_pass = 1;
char *clear_pass = NULL;
/*
* _old_auth - perform getpass/crypt authentication
*
* _old_auth gets the user's cleartext password and encrypts it
* using the salt in the encrypted password. The results are
* compared.
*/
static int _old_auth(const char *cipher, const char *user, int reason, const char *input)
{
char prompt[1024];
char *clear = NULL;
const char *cp;
int retval;
#ifdef SKEY
int use_skey = 0;
char challenge_info[40];
struct skey skey;
#endif
#ifdef OPIE
int use_opie = 0;
char o_challenge_info[OPIE_CHALLENGE_MAX + 1];
struct opie opie;
/*
* This implementation is based almost entirely on the SKEY code
* above. Thus the opie struct is called skey, etc. I am unaware
* if the system works at the same time, but I cannot imagine why
* anyone would want to do this....
* -- A.R.
* Mod: 5/14/98 A.R.
* Made the OPIE code separate from the S/Key code. Now
* (conceivably) both can be compiled in and function apart from
* one another (assuming a sysadmin really wants to maintain OPIE
* and an S/Key databases....).
*
* Also cleaned up the code a bit. Will be adding second-prompt
* support (the traditional Echo-on S/Key/OPIE-only prompts to let
* the users see the one-time passwords they are typing/pasting
* in....
* -- A.R.
*/
#endif
/*
* There are programs for adding and deleting authentication data.
*/
if (reason == PW_ADD || reason == PW_DELETE)
return 0;
/*
* There are even programs for changing the user name ...
*/
if (reason == PW_CHANGE && input != (char *) 0)
return 0;
/*
* WARNING:
*
* When we change a password and we are root, we don't prompt.
* This is so root can change any password without having to
* know it. This is a policy decision that might have to be
* revisited.
*/
if (reason == PW_CHANGE && getuid () == 0)
return 0;
/*
* WARNING:
*
* When we are logging in a user with no ciphertext password,
* we don't prompt for the password or anything. In reality
* the user could just hit <ENTER>, so it doesn't really
* matter.
*/
if (cipher == (char *) 0 || *cipher == '\0')
return 0;
#ifdef SKEY
/*
* If the user has an S/KEY entry show them the pertinent info
* and then we can try validating the created cyphertext and the SKEY.
* If there is no SKEY information we default to not using SKEY.
*/
if (skeychallenge (&skey, user, challenge_info) == 0)
use_skey = 1;
#endif
#ifdef OPIE
/*
* Ditto above, for OPIE passwords.
* -- AR
*/
o_challenge_info[0] = '\0';
if (opiechallenge(&opie, user, o_challenge_info) == 0)
use_opie = 1;
if (use_opie == 0)
opieverify(&opie, (char *)NULL);
/*
* This call to opieverify is necessary within OPIE's interface:
* Every call to opiechallenge(), which checks to see if the user
* has an OPIE password, and if so get the challenge, must be
* accompanied by exactly one call to opieverify, which clears
* any outstanding locks, and otherwise cleans up.
* -- AR
*/
#endif
/*
* Prompt for the password as required. FTPD and REXECD both
* get the cleartext password for us.
*/
if (reason != PW_FTP && reason != PW_REXEC && !input) {
if (! (cp = getdef_str ("LOGIN_STRING")))
cp = PROMPT;
#ifdef SKEY
if (use_skey)
printf ("[%s]\n", challenge_info);
#endif
#ifdef OPIE
if (use_opie)
printf("[ %s ]\n", o_challenge_info);
#endif
snprintf(prompt, sizeof prompt, cp, user);
clear = getpass(prompt);
if (!clear) {
static char c[1];
c[0] = '\0';
clear = c;
}
input = clear;
}
/*
* Convert the cleartext password into a ciphertext string.
* If the two match, the return value will be zero, which is
* SUCCESS. Otherwise we see if SKEY is being used and check
* the results there as well.
*/
retval = strcmp(pw_encrypt(input, cipher), cipher);
#ifdef OPIE
/*
* This is required because using OPIE, opieverify() MUST be called
* opiechallenge() above even if OPIE isn't being used in this case,
* so locks get released, etc.
* -- AR
*/
if ((retval == 0) && use_opie)
opieverify(&opie, (char *)NULL);
#endif
#if (defined(SKEY) || defined(OPIE))
/*
* If (1) The password fails to match, and
* (2) The password is empty and
* (3) We are using OPIE or S/Key, then
* ...Re-prompt, with echo on.
* -- AR 8/22/1999
*/
if (retval && !input[0] &&
(0
#ifdef SKEY
|| use_skey
#endif
#ifdef OPIE
|| use_opie
#endif
)) {
strncat(prompt, _("(Echo on) "),
(sizeof(prompt) - strlen(prompt)));
clear = getpass_with_echo(prompt);
if (!clear) {
static char c[1];
c[0] = '\0';
clear = c;
}
input = clear;
}
#endif
#ifdef SKEY
if (retval && use_skey) {
int passcheck = -1;
#if 0 /* some skey libs don't have skey_passcheck. --marekm */
passcheck = skey_passcheck(user, input);
#else
if (skeyverify(&skey, input) == 0)
passcheck = skey.n;
#endif /* if 0 */
if (passcheck > 0)
retval = 0;
}
#endif
#ifdef OPIE
if (retval && use_opie) {
if (opieverify(&opie, input) == 0)
retval = 0;
}
#endif /* OPIE */
/*
* Things like RADIUS authentication may need the password -
* if the external variable wipe_clear_pass is zero, we will
* not wipe it (the caller should wipe clear_pass when it is
* no longer needed). --marekm
*/
clear_pass = clear;
if (wipe_clear_pass && clear && *clear)
strzero(clear);
return retval;
}
#ifdef AUTH_METHODS
/*
* _pw_auth - perform alternate password authentication
*
* pw_auth executes the alternate password authentication method
* described in the user's password entry. _pw_auth does the real
* work, pw_auth splits the authentication string into individual
* command names.
*/
static int _pw_auth(const char *command, const char *user, int reason, const char *input)
{
RETSIGTYPE (*sigint)();
RETSIGTYPE (*sigquit)();
#ifdef SIGTSTP
RETSIGTYPE (*sigtstp)();
#endif
int pid;
int status;
int i;
char * const argv[5];
int argc = 0;
int pipes[2];
char *empty_env = NULL;
int use_pipe;
/*
* Start with a quick sanity check. ALL command names must
* be fully-qualified path names.
*/
if (command[0] != '/')
return -1;
/*
* Set the keyboard signals to be ignored. When the user kills
* the child we don't want the parent dying as well.
*/
sigint = signal (SIGINT, SIG_IGN);
sigquit = signal (SIGQUIT, SIG_IGN);
#ifdef SIGTSTP
sigtstp = signal (SIGTSTP, SIG_IGN);
#endif
/*
* FTP and REXEC reasons don't give the program direct access
* to the user. This means that the program can only get input
* from this function. So we set up a pipe for that purpose.
*/
use_pipe = (reason == PW_FTP || reason == PW_REXEC);
if (use_pipe)
if (pipe (pipes))
return -1;
/*
* The program will be forked off with the parent process waiting
* on the child to tell it how successful it was.
*/
switch (pid = fork ()) {
/*
* The fork() failed completely. Clean up as needed and
* return to the caller.
*/
case -1:
if (use_pipe) {
close (pipes[0]);
close (pipes[1]);
}
return -1;
case 0:
/*
* Let the child catch the SIGINT and SIGQUIT
* signals. The parent, however, will continue
* to ignore them.
*/
signal (SIGINT, SIG_DFL);
signal (SIGQUIT, SIG_DFL);
/*
* Set up the command line. The first argument is
* the name of the command being executed. The
* second is the command line option for the reason,
* and the third is the user name.
*/
argv[argc++] = command;
switch (reason) {
case PW_SU: argv[argc++] = "-s"; break;
case PW_LOGIN: argv[argc++] = "-l"; break;
case PW_ADD: argv[argc++] = "-a"; break;
case PW_CHANGE: argv[argc++] = "-c"; break;
case PW_DELETE: argv[argc++] = "-d"; break;
case PW_TELNET: argv[argc++] = "-t"; break;
case PW_RLOGIN: argv[argc++] = "-r"; break;
case PW_FTP: argv[argc++] = "-f"; break;
case PW_REXEC: argv[argc++] = "-x"; break;
}
if (reason == PW_CHANGE && input)
argv[argc++] = input;
argv[argc++] = user;
argv[argc] = (char *) 0;
/*
* The FTP and REXEC reasons use a pipe to communicate
* with the parent. The other standard I/O descriptors
* are closed and re-opened as /dev/null.
*/
if (use_pipe) {
close (0);
close (1);
close (2);
if (dup (pipes[0]) != 0)
exit (1);
close (pipes[0]);
close (pipes[1]);
if (open ("/dev/null", O_WRONLY) != 1)
exit (1);
if (open ("/dev/null", O_WRONLY) != 2)
exit (1);
}
/*
* Now we execute the command directly.
* Do it with empty environment for safety. --marekm
*/
execve(command, argv, &empty_env);
_exit((errno == ENOENT) ? 127 : 126);
/*NOTREACHED*/
default:
/*
* FTP and REXEC cause a single line of text to be
* sent to the child over a pipe that was set up
* earlier.
*/
if (use_pipe) {
close (pipes[0]);
if (input)
write (pipes[1], input, strlen (input));
write (pipes[1], "\n", 1);
close (pipes[1]);
}
/*
* Wait on the child to die. When it does you will
* get the exit status and use that to determine if
* the authentication program was successful.
*/
while ((i = wait (&status)) != pid && i != -1)
;
/*
* Re-set the signals to their earlier values.
*/
signal (SIGINT, sigint);
signal (SIGQUIT, sigquit);
#ifdef SIGTSTP
signal (SIGTSTP, sigtstp);
#endif
/*
* Make sure we found the right process!
*/
if (i == -1)
return -1;
if (status == 0)
return 0;
else
return -1;
}
/*NOTREACHED*/
}
/*
* _builtin_auth - lookup routine in table and execute
*/
static int _builtin_auth(const char *command, const char *user, int reason, const char *input)
{
int i;
/*
* Scan the table, looking for a match. If we fall off
* the end, it must mean that this method isn't supported,
* so we fail the authentication.
*/
for (i = 0;methods[i].name[0];i++) {
if (! strcmp (command, methods[i].name))
break;
}
if (methods[i].name[0] == '\0')
return -1;
/*
* Call the pointed to function with the other three
* arguments.
*/
return (methods[i].func) (user, reason, input);
}
#endif /* AUTH_METHODS */
/*
* This function does the real work. It splits the list of program names
* up into individual programs and executes them one at a time.
*/
int pw_auth(const char *command, const char *user, int reason, const char *input)
{
#ifdef AUTH_METHODS
char buf[256];
char *cmd, *end;
int rc;
/*
* Quick little sanity check ...
*/
if (strlen (command) >= sizeof buf)
return -1;
strcpy(buf, command); /* safe (because of the above check) --marekm */
/*
* Find each command and make sure it is NUL-terminated. Then
* invoke _pw_auth to actually run the program. The first
* failing program ends the whole mess.
*/
for (cmd = buf;cmd;cmd = end) {
if ((end = strchr (cmd, ';')))
*end++ = '\0';
if (cmd[0] != '@')
rc = _old_auth (cmd, user, reason, input);
else if (cmd[1] == '/')
rc = _pw_auth (cmd + 1, user, reason, input);
else
rc = _builtin_auth (cmd + 1, user, reason, input);
if (rc)
return -1;
}
return 0;
#else
return _old_auth(command, user, reason, input);
#endif
}

31
mbsebbs/pwauth.h Normal file
View File

@ -0,0 +1,31 @@
/* $Id$ */
#ifndef _PWAUTH_H
#define _PWAUTH_H
int pw_auth(const char *program,const char *user,int flag,const char *input);
/*
* Local access
*/
#define PW_SU 1
#define PW_LOGIN 2
/*
* Administrative functions
*/
#define PW_ADD 101
#define PW_CHANGE 102
#define PW_DELETE 103
/*
* Network access
*/
#define PW_TELNET 201
#define PW_RLOGIN 202
#define PW_FTP 203
#define PW_REXEC 204
#endif

98
mbsebbs/pwdcheck.c Normal file
View File

@ -0,0 +1,98 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include "mblogin.h"
#include <pwd.h>
#include <syslog.h>
#include "pwauth.h"
#include "pwdcheck.h"
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif
#ifdef USE_PAM
// #include "pam_defs.h"
#endif
#define WRONGPWD2 "incorrect password for `%s'"
void passwd_check(const char *user, const char *passwd, const char *progname)
{
#ifdef USE_PAM
pam_handle_t *pamh = NULL;
int retcode;
struct pam_conv conv = { misc_conv, NULL };
if (pam_start(progname, user, &conv, &pamh)) {
bailout:
SYSLOG((LOG_WARN, WRONGPWD2, user));
sleep(1);
fprintf(stderr, "Incorrect password for %s.\n", user);
exit(1);
}
if (pam_authenticate(pamh, 0))
goto bailout;
retcode = pam_acct_mgmt(pamh, 0);
if (retcode == PAM_NEW_AUTHTOK_REQD) {
retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
} else if (retcode)
goto bailout;
if (pam_setcred(pamh, 0))
goto bailout;
/* no need to establish a session; this isn't a session-oriented
* activity... */
#else /* !USE_PAM */
#ifdef SHADOW_PASSWORD
struct spwd *sp;
if ((sp = getspnam(user)))
passwd = sp->sp_pwdp;
endspent();
#endif
if (pw_auth(passwd, user, PW_LOGIN, (char *) 0) != 0) {
syslog(LOG_WARNING, WRONGPWD2, user);
sleep(1);
fprintf(stderr, "Incorrect password for %s.\n", user);
exit(1);
}
#endif /* !USE_PAM */
}

8
mbsebbs/pwdcheck.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _PWDCHECK_H
#define _PWDCHECK_H
void passwd_check(const char *, const char *, const char *);
#endif

127
mbsebbs/setugid.c Normal file
View File

@ -0,0 +1,127 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
/*
* Separated from setup.c. --marekm
*/
#include "../config.h"
#include <stdio.h>
#include <grp.h>
#include <syslog.h>
#include "mblogin.h"
#include <pwd.h>
#include "getdef.h"
#include "setugid.h"
/*
* setup_uid_gid() split in two functions for PAM support -
* pam_setcred() needs to be called after initgroups(), but
* before setuid().
*/
int setup_groups(const struct passwd *info)
{
/*
* Set the real group ID to the primary group ID in the password
* file.
*/
if (setgid (info->pw_gid) == -1) {
perror("setgid");
syslog(LOG_ERR, "bad group ID `%d' for user `%s': %m\n", info->pw_gid, info->pw_name);
closelog();
return -1;
}
#ifdef HAVE_INITGROUPS
/*
* For systems which support multiple concurrent groups, go get
* the group set from the /etc/group file.
*/
if (initgroups(info->pw_name, info->pw_gid) == -1) {
perror("initgroups");
syslog(LOG_ERR, "initgroups failed for user `%s': %m\n", info->pw_name);
closelog();
return -1;
}
#endif
return 0;
}
int change_uid(const struct passwd *info)
{
/*
* Set the real UID to the UID value in the password file.
*/
#ifndef BSD
if (setuid(info->pw_uid))
#else
if (setreuid(info->pw_uid, info->pw_uid))
#endif
{
perror("setuid");
syslog(LOG_ERR, "bad user ID `%d' for user `%s': %m\n", (int) info->pw_uid, info->pw_name);
closelog();
return -1;
}
return 0;
}
/*
* setup_uid_gid() performs the following steps -
*
* set the group ID to the value from the password file entry
* set the supplementary group IDs
* optionally call specified function which may add more groups
* set the user ID to the value from the password file entry
*
* Returns 0 on success, or -1 on failure.
*/
int setup_uid_gid(const struct passwd *info, int is_console)
{
if (setup_groups(info) < 0)
return -1;
#ifdef HAVE_INITGROUPS
if (is_console) {
char *cp = getdef_str("CONSOLE_GROUPS");
if (cp && add_groups(cp))
perror("Warning: add_groups");
}
#endif /* HAVE_INITGROUPS */
if (change_uid(info) < 0)
return -1;
return 0;
}

10
mbsebbs/setugid.h Normal file
View File

@ -0,0 +1,10 @@
/* $Id$ */
#ifndef _SETUGID_H
#define _SETUGID_H
int setup_groups(const struct passwd *);
int change_uid(const struct passwd *);
int setup_uid_gid(const struct passwd *, int);
#endif

275
mbsebbs/setupenv.c Normal file
View File

@ -0,0 +1,275 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
/*
* Separated from setup.c. --marekm
*/
#include "../config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <ctype.h>
#include <syslog.h>
#include "mblogin.h"
#include <pwd.h>
#include "getdef.h"
#include "xmalloc.h"
#include "env.h"
#include "setupenv.h"
void addenv_path(const char *varname, const char *dirname, const char *filename)
{
char *buf;
buf = xmalloc(strlen(dirname) + strlen(filename) + 2);
sprintf(buf, "%s/%s", dirname, filename);
addenv(varname, buf);
free(buf);
}
void read_env_file(const char *filename)
{
FILE *fp;
char buf[1024];
char *cp, *name, *val;
fp = fopen(filename, "r");
if (!fp)
return;
while (fgets(buf, sizeof buf, fp) == buf) {
cp = strrchr(buf, '\n');
if (!cp)
break;
*cp = '\0';
cp = buf;
/* ignore whitespace and comments */
while (*cp && isspace(*cp))
cp++;
if (*cp == '\0' || *cp == '#')
continue;
/*
* ignore lines which don't follow the name=value format
* (for example, the "export NAME" shell commands)
*/
name = cp;
while (*cp && !isspace(*cp) && *cp != '=')
cp++;
if (*cp != '=')
continue;
/* NUL-terminate the name */
*cp++ = '\0';
val = cp;
#if 0 /* XXX untested, and needs rewrite with fewer goto's :-) */
/*
(state, char_type) -> (state, action)
state: unquoted, single_quoted, double_quoted, escaped, double_quoted_escaped
char_type: normal, white, backslash, single, double
action: remove_curr, remove_curr_skip_next, remove_prev, finish XXX
*/
no_quote:
if (*cp == '\\') {
/* remove the backslash */
remove_char(cp);
/* skip over the next character */
if (*cp)
cp++;
goto no_quote;
} else if (*cp == '\'') {
/* remove the quote */
remove_char(cp);
/* now within single quotes */
goto s_quote;
} else if (*cp == '"') {
/* remove the quote */
remove_char(cp);
/* now within double quotes */
goto d_quote;
} else if (*cp == '\0') {
/* end of string */
goto finished;
} else if (isspace(*cp)) {
/* unescaped whitespace - end of string */
*cp = '\0';
goto finished;
} else {
cp++;
goto no_quote;
}
s_quote:
if (*cp == '\'') {
/* remove the quote */
remove_char(cp);
/* unquoted again */
goto no_quote;
} else if (*cp == '\0') {
/* end of string */
goto finished;
} else {
/* preserve everything within single quotes */
cp++;
goto s_quote;
}
d_quote:
if (*cp == '\"') {
/* remove the quote */
remove_char(cp);
/* unquoted again */
goto no_quote;
} else if (*cp == '\\') {
cp++;
/* if backslash followed by double quote, remove backslash
else skip over the backslash and following char */
if (*cp == '"')
remove_char(cp - 1);
else if (*cp)
cp++;
goto d_quote;
} eise if (*cp == '\0') {
/* end of string */
goto finished;
} else {
/* preserve everything within double quotes */
goto d_quote;
}
finished:
#endif /* 0 */
/*
* XXX - should handle quotes, backslash escapes, etc.
* like the shell does.
*/
addenv(name, val);
}
fclose(fp);
}
/*
* change to the user's home directory
* set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental
* variables.
*/
void setup_env(struct passwd *info)
{
char *cp, *envf;
/*
* Change the current working directory to be the home directory
* of the user. It is a fatal error for this process to be unable
* to change to that directory. There is no "default" home
* directory.
*
* We no longer do it as root - should work better on NFS-mounted
* home directories. Some systems default to HOME=/, so we make
* this a configurable option. --marekm
*/
if (chdir(info->pw_dir) == -1) {
static char temp_pw_dir[] = "/";
if (!getdef_bool("DEFAULT_HOME") || chdir("/") == -1) {
fprintf(stderr, _("Unable to cd to \"%s\"\n"), info->pw_dir);
syslog(LOG_WARNING, "unable to cd to `%s' for user `%s'\n", info->pw_dir, info->pw_name);
closelog();
exit (1);
}
puts(_("No directory, logging in with HOME=/"));
info->pw_dir = temp_pw_dir;
}
/*
* Create the HOME environmental variable and export it.
*/
addenv("HOME", info->pw_dir);
/*
* Create the SHELL environmental variable and export it.
*/
if (info->pw_shell == (char *) 0 || ! *info->pw_shell) {
static char temp_pw_shell[] = "/bin/sh";
info->pw_shell = temp_pw_shell;
}
addenv("SHELL", info->pw_shell);
/*
* Create the PATH environmental variable and export it.
*/
cp = getdef_str( info->pw_uid == 0 ? "ENV_SUPATH" : "ENV_PATH" );
addenv(cp ? cp : "PATH=/bin:/usr/bin", NULL);
/*
* Export the user name. For BSD derived systems, it's "USER", for
* all others it's "LOGNAME". We set both of them.
*/
addenv("USER", info->pw_name);
addenv("LOGNAME", info->pw_name);
/*
* MAILDIR environment variable for Qmail
*/
if ((cp=getdef_str("QMAIL_DIR")))
addenv_path("MAILDIR", info->pw_dir, cp);
/*
* Create the MAIL environmental variable and export it. login.defs
* knows the prefix.
*/
if ((cp=getdef_str("MAIL_DIR")))
addenv_path("MAIL", cp, info->pw_name);
else if ((cp=getdef_str("MAIL_FILE")))
addenv_path("MAIL", info->pw_dir, cp);
else {
#if defined(MAIL_SPOOL_FILE)
addenv_path("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
#elif defined(MAIL_SPOOL_DIR)
addenv_path("MAIL", MAIL_SPOOL_DIR, info->pw_name);
#endif
}
/*
* Read environment from optional config file. --marekm
*/
if ((envf = getdef_str("ENVIRON_FILE")))
read_env_file(envf);
}

10
mbsebbs/setupenv.h Normal file
View File

@ -0,0 +1,10 @@
/* $Id$ */
#ifndef _SETUPENV_H
#define _SETUPENV_H
void addenv_path(const char *, const char *, const char *);
void read_env_file(const char *);
void setup_env(struct passwd *);
#endif

128
mbsebbs/shell.c Normal file
View File

@ -0,0 +1,128 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include <errno.h>
#include "mblogin.h"
#include "basename.h"
#include "shell.h"
extern char **newenvp;
extern size_t newenvc;
/*
* shell - execute the named program
*
* shell begins by trying to figure out what argv[0] is going to
* be for the named process. The user may pass in that argument,
* or it will be the last pathname component of the file with a
* '-' prepended. The first attempt is to just execute the named
* file. If the errno comes back "ENOEXEC", the file is assumed
* at first glance to be a shell script. The first two characters
* must be "#!", in which case "/bin/sh" is executed to process
* the file. If all that fails, give up in disgust ...
*/
void shell(const char *file, const char *arg)
{
char arg0[1024];
int err;
if (file == (char *) 0)
exit (1);
/*
* The argv[0]'th entry is usually the path name, but
* for various reasons the invoker may want to override
* that. So, we determine the 0'th entry only if they
* don't want to tell us what it is themselves.
*/
if (arg == (char *) 0) {
snprintf(arg0, sizeof arg0, "-%s", Basename((char *) file));
arg = arg0;
}
#ifdef DEBUG
printf (_("Executing shell %s\n"), file);
#endif
/*
* First we try the direct approach. The system should be
* able to figure out what we are up to without too much
* grief.
*/
execle (file, arg, (char *) 0, newenvp);
err = errno;
/* Linux handles #! in the kernel, and bash doesn't make
sense of "#!" so it wouldn't work anyway... --marekm */
#ifndef __linux__
/*
* It is perfectly OK to have a shell script for a login
* shell, and this code attempts to support that. It
* relies on the standard shell being able to make sense
* of the "#!" magic number.
*/
if (err == ENOEXEC) {
FILE *fp;
if ((fp = fopen (file, "r"))) {
if (getc (fp) == '#' && getc (fp) == '!') {
fclose (fp);
execle ("/bin/sh", "sh",
file, (char *) 0, newenvp);
err = errno;
} else {
fclose (fp);
}
}
}
#endif
/*
* Obviously something is really wrong - I can't figure out
* how to execute this stupid shell, so I might as well give
* up in disgust ...
*/
snprintf(arg0, sizeof arg0, "Cannot execute %s", file);
errno = err;
perror(arg0);
exit(1);
}

8
mbsebbs/shell.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _SHELL_H
#define _SHELL_H
void shell(const char *, const char *);
#endif

292
mbsebbs/snprintf.c Normal file
View File

@ -0,0 +1,292 @@
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
**************************************************************/
/* $XFree86: xc/lib/misc/snprintf.c,v 3.0 1996/08/26 06:19:23 dawes Exp $ */
#include <ctype.h>
#include "snprintf.h"
static void dopr(char *, char *, va_list);
static char *end;
/* varargs declarations: */
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
/*XX ** NO VARARGS ** XX*/
# endif
#endif
#ifdef HAVE_STDARGS
int snprintf (char *str, size_t count, const char *fmt, ...);
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
#else
int snprintf ();
int vsnprintf ();
#endif
int vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
str[0] = 0;
end = str+count-1;
dopr( str, fmt, args );
if( count>0 ){
end[0] = 0;
}
return(strlen(str));
}
/* VARARGS3 */
#ifdef HAVE_STDARGS
int
snprintf (char *str,size_t count,const char *fmt,...)
#else
int
snprintf (va_alist) va_dcl
#endif
{
#ifndef HAVE_STDARGS
char *str;
size_t count;
char *fmt;
#endif
VA_LOCAL_DECL
VA_START (fmt);
VA_SHIFT (str, char *);
VA_SHIFT (count, size_t );
VA_SHIFT (fmt, char *);
(void) vsnprintf ( str, count, fmt, ap);
VA_END;
return( strlen( str ) );
}
/*
* dopr(): poor man's version of doprintf
*/
static void fmtstr(char *value, int ljust, int len, int zpad);
static void fmtnum(long value, int base, int dosign, int ljust, int len, int zpad);
static void dostr(char *);
static char *output;
static void dopr_outch(int c);
static void dopr(char *buffer, char *format, va_list args)
{
int ch;
long value;
int longflag = 0;
char *strvalue;
int ljust;
int len;
int zpad;
output = buffer;
while( (ch = *format++) ){
switch( ch ){
case '%':
ljust = len = zpad = 0;
nextch:
ch = *format++;
switch( ch ){
case 0:
dostr((char *)"**end of format**");
return;
case '-': ljust = 1; goto nextch;
case '0': /* set zero padding if len not set */
if(len==0) zpad = '0';
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
len = len*10 + ch - '0';
goto nextch;
case 'l': longflag = 1; goto nextch;
case 'u': case 'U':
/*fmtnum(value,base,dosign,ljust,len,zpad) */
if( longflag ){
value = va_arg( args, long );
} else {
value = va_arg( args, int );
}
fmtnum( value, 10,0, ljust, len, zpad ); break;
case 'o': case 'O':
/*fmtnum(value,base,dosign,ljust,len,zpad) */
if( longflag ){
value = va_arg( args, long );
} else {
value = va_arg( args, int );
}
fmtnum( value, 8,0, ljust, len, zpad ); break;
case 'd': case 'D':
if( longflag ){
value = va_arg( args, long );
} else {
value = va_arg( args, int );
}
fmtnum( value, 10,1, ljust, len, zpad ); break;
case 'x':
if( longflag ){
value = va_arg( args, long );
} else {
value = va_arg( args, int );
}
fmtnum( value, 16,0, ljust, len, zpad ); break;
case 'X':
if( longflag ){
value = va_arg( args, long );
} else {
value = va_arg( args, int );
}
fmtnum( value,-16,0, ljust, len, zpad ); break;
case 's':
strvalue = va_arg( args, char *);
fmtstr( strvalue,ljust,len,zpad ); break;
case 'c':
ch = va_arg( args, int );
dopr_outch( ch ); break;
case '%': dopr_outch( ch ); continue;
default:
dostr((char *)"???????");
}
longflag = 0;
break;
default:
dopr_outch( ch );
break;
}
}
*output = 0;
}
static void fmtstr(char *value, int ljust, int len, int zpad)
{
int padlen, lstrlen; /* amount to pad */
if( value == 0 ){
value = (char *)"<NULL>";
}
for( lstrlen = 0; value[lstrlen]; ++ lstrlen ); /* strlen */
padlen = len - lstrlen;
if( padlen < 0 ) padlen = 0;
if( ljust ) padlen = -padlen;
while( padlen > 0 ) {
dopr_outch( ' ' );
--padlen;
}
dostr( value );
while( padlen < 0 ) {
dopr_outch( ' ' );
++padlen;
}
}
static void fmtnum(long value, int base, int dosign, int ljust, int len, int zpad)
{
int signvalue = 0;
unsigned long uvalue;
char convert[20];
int place = 0;
int padlen = 0; /* amount to pad */
int caps = 0;
/* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
value, base, dosign, ljust, len, zpad )); */
uvalue = value;
if( dosign ){
if( value < 0 ) {
signvalue = '-';
uvalue = -value;
}
}
if( base < 0 ){
caps = 1;
base = -base;
}
do{
convert[place++] =
(caps? "0123456789ABCDEF":"0123456789abcdef")
[uvalue % (unsigned)base ];
uvalue = (uvalue / (unsigned)base );
}while(uvalue);
convert[place] = 0;
padlen = len - place;
if( padlen < 0 ) padlen = 0;
if( ljust ) padlen = -padlen;
/* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
convert,place,signvalue,padlen)); */
if( zpad && padlen > 0 ){
if( signvalue ){
dopr_outch( signvalue );
--padlen;
signvalue = 0;
}
while( padlen > 0 ){
dopr_outch( zpad );
--padlen;
}
}
while( padlen > 0 ) {
dopr_outch( ' ' );
--padlen;
}
if( signvalue ) dopr_outch( signvalue );
while( place > 0 ) dopr_outch( convert[--place] );
while( padlen < 0 ){
dopr_outch( ' ' );
++padlen;
}
}
static void dostr(char *str)
{
while(*str) dopr_outch(*str++);
}
static void dopr_outch(int c)
{
if( iscntrl(c) && c != '\n' && c != '\t' ){
c = '@' + (c & 0x1F);
if( end == 0 || output < end ){
*output++ = '^';
}
}
if( end == 0 || output < end ){
*output++ = c;
}
}

51
mbsebbs/snprintf.h Normal file
View File

@ -0,0 +1,51 @@
/* $XFree86: xc/lib/misc/snprintf.h,v 3.1 1996/08/26 14:42:33 dawes Exp $ */
#ifndef SNPRINTF_H
#define SNPRINTF_H
#ifdef HAS_SNPRINTF
#ifdef LIBXT
#define _XtSnprintf snprintf
#define _XtVsnprintf vsnprintf
#endif
#ifdef LIBX11
#define _XSnprintf snprintf
#define _XVsnprintf vsnprintf
#endif
#else /* !HAS_SNPRINTF */
#ifdef LIBXT
#define snprintf _XtSnprintf
#define vsnprintf _XtVsnprintf
#endif
#ifdef LIBX11
#define snprintf _XSnprintf
#define vsnprintf _XVsnprintf
#endif
#if 1 /* the system might have no X11 headers. -MM */
#include <X11/Xos.h>
#include <X11/Xlib.h>
#else /* but we still need this... */
#include <sys/types.h>
/* adjust the following defines if necessary (pre-ANSI) */
#define NeedFunctionPrototypes 1
#define NeedVarargsPrototypes 1
#endif
#if NeedVarargsPrototypes
#define HAVE_STDARG_H
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
extern int snprintf (char *str, size_t count, const char *fmt, ...);
extern int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
#else
extern int snprintf ();
extern int vsnprintf ();
#endif
#endif /* HAS_SNPRINTF */
#endif /* SNPRINTF_H */

80
mbsebbs/sub.c Normal file
View File

@ -0,0 +1,80 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include <sys/types.h>
#include <syslog.h>
#include "mblogin.h"
#include <pwd.h>
#include "sub.h"
#define BAD_SUBROOT2 "invalid root `%s' for user `%s'\n"
#define NO_SUBROOT2 "no subsystem root `%s' for user `%s'\n"
/*
* subsystem - change to subsystem root
*
* A subsystem login is indicated by the presense of a "*" as
* the first character of the login shell. The given home
* directory will be used as the root of a new filesystem which
* the user is actually logged into.
*/
void subsystem(const struct passwd *pw)
{
/*
* The new root directory must begin with a "/" character.
*/
if (pw->pw_dir[0] != '/') {
printf("Invalid root directory \"%s\"\n", pw->pw_dir);
syslog(LOG_WARNING, BAD_SUBROOT2, pw->pw_dir, pw->pw_name);
closelog();
exit (1);
}
/*
* The directory must be accessible and the current process
* must be able to change into it.
*/
if (chdir (pw->pw_dir) || chroot (pw->pw_dir)) {
printf("Can't change root directory to \"%s\"\n", pw->pw_dir);
syslog(LOG_WARNING, NO_SUBROOT2, pw->pw_dir, pw->pw_name);
closelog();
exit (1);
}
}

8
mbsebbs/sub.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _SUB_H
#define _SUB_H
void subsystem(const struct passwd *);
#endif

90
mbsebbs/ttytype.c Normal file
View File

@ -0,0 +1,90 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include "mblogin.h"
#include "getdef.h"
#include "env.h"
#include "ttytype.h"
// extern char *getenv();
/*
* ttytype - set ttytype from port to terminal type mapping database
*/
void ttytype(const char *line)
{
FILE *fp;
char buf[BUFSIZ];
char *typefile;
char *cp;
char type[BUFSIZ];
char port[BUFSIZ];
if (getenv ("TERM"))
return;
if ((typefile=getdef_str("TTYTYPE_FILE")) == NULL )
return;
if (access(typefile, F_OK))
return;
if (! (fp = fopen (typefile, "r"))) {
perror (typefile);
return;
}
while (fgets(buf, sizeof buf, fp)) {
if (buf[0] == '#')
continue;
if ((cp = strchr (buf, '\n')))
*cp = '\0';
#if defined(SUN) || defined(BSD) || defined(SUN4)
if ((sscanf (buf, "%s \"%*[^\"]\" %s", port, type) == 2 ||
sscanf (buf, "%s %*s %s", port, type) == 2) &&
strcmp (line, port) == 0)
break;
#else /* USG */
if (sscanf (buf, "%s %s", type, port) == 2 &&
strcmp (line, port) == 0)
break;
#endif
}
if (! feof (fp) && ! ferror (fp))
addenv("TERM", type);
fclose (fp);
}

8
mbsebbs/ttytype.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _TTYTYPE_H
#define _TTYTYPE_H
void ttytype(const char *);
#endif

67
mbsebbs/tz.c Normal file
View File

@ -0,0 +1,67 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include <stdio.h>
#include <string.h>
#include "mblogin.h"
#include "getdef.h"
#include "tz.h"
/*
* tz - return local timezone name
*
* tz() determines the name of the local timezone by reading the
* contents of the file named by ``fname''.
*/
char *tz(const char *fname)
{
FILE *fp = 0;
static char tzbuf[BUFSIZ];
const char *def_tz;
if ((fp = fopen(fname,"r")) == NULL ||
fgets (tzbuf, sizeof (tzbuf), fp) == NULL) {
if (! (def_tz = getdef_str ("ENV_TZ")) || def_tz[0] == '/')
def_tz = "TZ=CST6CDT";
strcpy (tzbuf, def_tz);
} else
tzbuf[strlen(tzbuf) - 1] = '\0';
if (fp)
(void) fclose(fp);
return tzbuf;
}

8
mbsebbs/tz.h Normal file
View File

@ -0,0 +1,8 @@
/* $Id$ */
#ifndef _TZTZ_H
#define _TZTZ_H
char *tz(const char *);
#endif

66
mbsebbs/ulimit.c Normal file
View File

@ -0,0 +1,66 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyright ....: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#if HAVE_ULIMIT_H
#include <ulimit.h>
#ifndef UL_SETFSIZE
#ifdef UL_SFILLIM
#define UL_SETFSIZE UL_SFILLIM
#else
#define UL_SETFSIZE 2
#endif
#endif
#elif HAVE_SYS_RESOURCE_H
#include <sys/time.h> /* for struct timeval on sunos4 */
/* XXX - is the above ok or should it be <time.h> on ultrix? */
#include <sys/resource.h>
#endif
#include "ulimit.h"
void set_filesize_limit(int blocks)
{
#if HAVE_ULIMIT_H
ulimit(UL_SETFSIZE, blocks);
#elif defined(RLIMIT_FSIZE)
struct rlimit rlimit_fsize;
rlimit_fsize.rlim_cur = rlimit_fsize.rlim_max = 512L * blocks;
setrlimit(RLIMIT_FSIZE, &rlimit_fsize);
#endif
}

9
mbsebbs/ulimit.h Normal file
View File

@ -0,0 +1,9 @@
/* $Id$ */
#ifndef _ULIMIT_H_H
#define _ULIMIT_H_H
void set_filesize_limit(int);
#endif

477
mbsebbs/utmp.c Normal file
View File

@ -0,0 +1,477 @@
/*****************************************************************************
*
* $Id$
* Purpose ...............: MBSE BBS Shadow Password Suite
* Original Source .......: Shadow Password Suite
* Original Copyrioght ...: Julianne Frances Haugh and others.
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include "mblogin.h"
#include <utmp.h>
#if HAVE_UTMPX_H
#include <utmpx.h>
#endif
#include <fcntl.h>
#include <stdio.h>
#include "utmp.h"
#if HAVE_UTMPX_H
extern struct utmpx utxent;
#endif
extern struct utmp utent;
// extern struct utmp *getutent();
// extern struct utmp *getutline();
// extern void setutent();
// extern void endutent();
// extern time_t time();
// extern char *ttyname();
// extern long lseek();
#define NO_UTENT \
"No utmp entry. You must exec \"login\" from the lowest level \"sh\""
#define NO_TTY \
"Unable to determine your tty name."
/*
* checkutmp - see if utmp file is correct for this process
*
* System V is very picky about the contents of the utmp file
* and requires that a slot for the current process exist.
* The utmp file is scanned for an entry with the same process
* ID. If no entry exists the process exits with a message.
*
* The "picky" flag is for network and other logins that may
* use special flags. It allows the pid checks to be overridden.
* This means that getty should never invoke login with any
* command line flags.
*/
#if defined(__linux__) /* XXX */
void
checkutmp(int picky)
{
char *line;
struct utmp *ut;
pid_t pid = getpid();
setutent();
/* First, try to find a valid utmp entry for this process. */
while ((ut = getutent()))
if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
(ut->ut_type==LOGIN_PROCESS || ut->ut_type==USER_PROCESS))
break;
/* If there is one, just use it, otherwise create a new one. */
if (ut) {
utent = *ut;
} else {
if (picky) {
puts(NO_UTENT);
exit(1);
}
line = ttyname(0);
if (!line) {
puts(NO_TTY);
exit(1);
}
if (strncmp(line, "/dev/", 5) == 0)
line += 5;
memset((void *) &utent, 0, sizeof utent);
utent.ut_type = LOGIN_PROCESS;
utent.ut_pid = pid;
strncpy(utent.ut_line, line, sizeof utent.ut_line);
/* XXX - assumes /dev/tty?? */
strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
strcpy(utent.ut_user, "LOGIN");
time(&utent.ut_time);
}
}
#elif defined(LOGIN_PROCESS)
void
checkutmp(int picky)
{
char *line;
struct utmp *ut;
#if HAVE_UTMPX_H
struct utmpx *utx;
#endif
pid_t pid = getpid();
#if HAVE_UTMPX_H
setutxent();
#endif
setutent();
if (picky) {
#if HAVE_UTMPX_H
while ((utx = getutxent()))
if (utx->ut_pid == pid)
break;
if (utx)
utxent = *utx;
#endif
while ((ut = getutent()))
if (ut->ut_pid == pid)
break;
if (ut)
utent = *ut;
#if HAVE_UTMPX_H
endutxent();
#endif
endutent();
if (!ut) {
puts(NO_UTENT);
exit(1);
}
#ifndef UNIXPC
/*
* If there is no ut_line value in this record, fill
* it in by getting the TTY name and stuffing it in
* the structure. The UNIX/PC is broken in this regard
* and needs help ...
*/
if (utent.ut_line[0] == '\0')
#endif /* !UNIXPC */
{
if (!(line = ttyname(0))) {
puts(NO_TTY);
exit(1);
}
if (strncmp(line, "/dev/", 5) == 0)
line += 5;
strncpy(utent.ut_line, line, sizeof utent.ut_line);
#if HAVE_UTMPX_H
strncpy(utxent.ut_line, line, sizeof utxent.ut_line);
#endif
}
} else {
if (!(line = ttyname(0))) {
puts(NO_TTY);
exit(1);
}
if (strncmp(line, "/dev/", 5) == 0)
line += 5;
strncpy (utent.ut_line, line, sizeof utent.ut_line);
if ((ut = getutline(&utent)))
strncpy(utent.ut_id, ut->ut_id, sizeof ut->ut_id);
strcpy(utent.ut_user, "LOGIN");
utent.ut_pid = getpid();
utent.ut_type = LOGIN_PROCESS;
time(&utent.ut_time);
#if HAVE_UTMPX_H
strncpy(utxent.ut_line, line, sizeof utxent.ut_line);
if ((utx = getutxline(&utxent)))
strncpy(utxent.ut_id, utx->ut_id, sizeof utxent.ut_id);
strcpy(utxent.ut_user, "LOGIN");
utxent.ut_pid = utent.ut_pid;
utxent.ut_type = utent.ut_type;
gettimeofday((struct timeval *) &utxent.ut_tv, NULL);
utent.ut_time = utxent.ut_tv.tv_sec;
#endif
}
}
#else /* !USG */
void
checkutmp(int picky)
{
char *line;
/*
* Hand-craft a new utmp entry.
*/
memzero(&utent, sizeof utent);
if (! (line = ttyname (0))) {
puts (NO_TTY);
exit (1);
}
if (strncmp (line, "/dev/", 5) == 0)
line += 5;
(void) strncpy (utent.ut_line, line, sizeof utent.ut_line);
(void) time (&utent.ut_time);
}
#endif /* !USG */
/*
* Some systems already have updwtmp() and possibly updwtmpx(). Others
* don't, so we re-implement these functions if necessary. --marekm
*/
#ifndef HAVE_UPDWTMP
void updwtmp(const char *filename, const struct utmp *ut)
{
int fd;
fd = open(filename, O_APPEND | O_WRONLY, 0);
if (fd >= 0) {
write(fd, (const char *) ut, sizeof(*ut));
close(fd);
}
}
#endif /* ! HAVE_UPDWTMP */
#ifdef HAVE_UTMPX_H
#ifndef HAVE_UPDWTMPX
static void
updwtmpx(const char *filename, const struct utmpx *utx)
{
int fd;
fd = open(filename, O_APPEND | O_WRONLY, 0);
if (fd >= 0) {
write(fd, (const char *) utx, sizeof(*utx));
close(fd);
}
}
#endif /* ! HAVE_UPDWTMPX */
#endif /* ! HAVE_UTMPX_H */
/*
* setutmp - put a USER_PROCESS entry in the utmp file
*
* setutmp changes the type of the current utmp entry to
* USER_PROCESS. the wtmp file will be updated as well.
*/
#if defined(__linux__) /* XXX */
void
setutmp(const char *name, const char *line, const char *host)
{
utent.ut_type = USER_PROCESS;
strncpy(utent.ut_user, name, sizeof utent.ut_user);
time(&utent.ut_time);
/* other fields already filled in by checkutmp above */
setutent();
pututline(&utent);
endutent();
updwtmp(_WTMP_FILE, &utent);
}
#elif HAVE_UTMPX_H
void
setutmp(const char *name, const char *line, const char *host)
{
struct utmp *utmp, utline;
struct utmpx *utmpx, utxline;
pid_t pid = getpid ();
int found_utmpx = 0, found_utmp = 0;
/*
* The canonical device name doesn't include "/dev/"; skip it
* if it is already there.
*/
if (strncmp (line, "/dev/", 5) == 0)
line += 5;
/*
* Update utmpx. We create an empty entry in case there is
* no matching entry in the utmpx file.
*/
setutxent ();
setutent ();
while (utmpx = getutxent ()) {
if (utmpx->ut_pid == pid) {
found_utmpx = 1;
break;
}
}
while (utmp = getutent ()) {
if (utmp->ut_pid == pid) {
found_utmp = 1;
break;
}
}
/*
* If the entry matching `pid' cannot be found, create a new
* entry with the device name in it.
*/
if (! found_utmpx) {
memset ((void *) &utxline, 0, sizeof utxline);
strncpy (utxline.ut_line, line, sizeof utxline.ut_line);
utxline.ut_pid = getpid ();
} else {
utxline = *utmpx;
if (strncmp (utxline.ut_line, "/dev/", 5) == 0) {
memmove (utxline.ut_line, utxline.ut_line + 5,
sizeof utxline.ut_line - 5);
utxline.ut_line[sizeof utxline.ut_line - 5] = '\0';
}
}
if (! found_utmp) {
memset ((void *) &utline, 0, sizeof utline);
strncpy (utline.ut_line, utxline.ut_line,
sizeof utline.ut_line);
utline.ut_pid = utxline.ut_pid;
} else {
utline = *utmp;
if (strncmp (utline.ut_line, "/dev/", 5) == 0) {
memmove (utline.ut_line, utline.ut_line + 5,
sizeof utline.ut_line - 5);
utline.ut_line[sizeof utline.ut_line - 5] = '\0';
}
}
/*
* Fill in the fields in the utmpx entry and write it out. Do
* the utmp entry at the same time to make sure things don't
* get messed up.
*/
strncpy (utxline.ut_user, name, sizeof utxline.ut_user);
strncpy (utline.ut_user, name, sizeof utline.ut_user);
utline.ut_type = utxline.ut_type = USER_PROCESS;
gettimeofday(&utxline.ut_tv, NULL);
utline.ut_time = utxline.ut_tv.tv_sec;
strncpy(utxline.ut_host, host ? host : "", sizeof utxline.ut_host);
pututxline (&utxline);
pututline (&utline);
updwtmpx(_WTMP_FILE "x", &utxline);
updwtmp(_WTMP_FILE, &utline);
utxent = utxline;
utent = utline;
}
#else /* !SVR4 */
void
setutmp(const char *name, const char *line)
{
struct utmp utmp;
int fd;
int found = 0;
if ((fd = open(_UTMP_FILE, O_RDWR)) < 0)
return;
#if !defined(SUN) && !defined(BSD) && !defined(SUN4) /* XXX */
while (!found && read(fd, (char *)&utmp, sizeof utmp) == sizeof utmp) {
if (! strncmp (line, utmp.ut_line, (int) sizeof utmp.ut_line))
found++;
}
#endif
if (! found) {
/*
* This is a brand-new entry. Clear it out and fill it in
* later.
*/
memzero(&utmp, sizeof utmp);
strncpy(utmp.ut_line, line, (int) sizeof utmp.ut_line);
}
/*
* Fill in the parts of the UTMP entry. BSD has just the name,
* while System V has the name, PID and a type.
*/
strncpy(utmp.ut_user, name, sizeof utent.ut_user);
#ifdef USER_PROCESS
utmp.ut_type = USER_PROCESS;
utmp.ut_pid = getpid ();
#endif
/*
* Put in the current time (common to everyone)
*/
(void) time (&utmp.ut_time);
#ifdef UT_HOST
/*
* Update the host name field for systems with networking support
*/
(void) strncpy (utmp.ut_host, utent.ut_host, (int) sizeof utmp.ut_host);
#endif
/*
* Locate the correct position in the UTMP file for this
* entry.
*/
#ifdef HAVE_TTYSLOT
(void) lseek (fd, (off_t) (sizeof utmp) * ttyslot (), SEEK_SET);
#else
if (found) /* Back up a splot */
lseek (fd, (off_t) - sizeof utmp, SEEK_CUR);
else /* Otherwise, go to the end of the file */
lseek (fd, (off_t) 0, SEEK_END);
#endif
/*
* Scribble out the new entry and close the file. We're done
* with UTMP, next we do WTMP (which is real easy, put it on
* the end of the file.
*/
(void) write (fd, (char *) &utmp, sizeof utmp);
(void) close (fd);
updwtmp(_WTMP_FILE, &utmp);
utent = utmp;
}
#endif /* SVR4 */

21
mbsebbs/utmp.h Normal file
View File

@ -0,0 +1,21 @@
/* $Id$ */
#ifndef _UTMP_HH
#define _UTMP_HH
void checkutmp(int);
#ifndef HAVE_UPDWTMP
void updwtmp(const char *, const struct utmp *);
#endif /* ! HAVE_UPDWTMP */
#ifdef HAVE_UTMPX_H
#ifndef HAVE_UPDWTMPX
static void updwtmpx(const char *, const struct utmpx *);
#endif /* ! HAVE_UPDWTMPX */
#endif /* ! HAVE_UTMPX_H */
void setutmp(const char *, const char *, const char *);
#endif