Added mblogin program
This commit is contained in:
parent
8af5b1c2d1
commit
182f8c6b56
83
config.h.in
83
config.h.in
@ -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. */
|
||||
|
26
configure.in
26
configure.in
@ -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
|
||||
|
@ -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
17
mbsebbs/basename.c
Normal 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
9
mbsebbs/basename.h
Normal file
@ -0,0 +1,9 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _BASENAME_H
|
||||
#define _BASENAME_H
|
||||
|
||||
|
||||
char *Basename(char *);
|
||||
|
||||
#endif
|
123
mbsebbs/chowntty.c
Normal file
123
mbsebbs/chowntty.c
Normal 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
11
mbsebbs/chowntty.h
Normal 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
|
@ -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
253
mbsebbs/env.c
Normal 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
12
mbsebbs/env.h
Normal 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
273
mbsebbs/failure.c
Normal 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
42
mbsebbs/failure.h
Normal 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
420
mbsebbs/limits.c
Normal 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
16
mbsebbs/limits.h
Normal 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
101
mbsebbs/log.c
Normal 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
8
mbsebbs/log.h
Normal 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
168
mbsebbs/loginprompt.c
Normal 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
9
mbsebbs/loginprompt.h
Normal 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
890
mbsebbs/mblogin.c
Normal 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
365
mbsebbs/mblogin.h
Normal 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
|
@ -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
575
mbsebbs/pwauth.c
Normal 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
31
mbsebbs/pwauth.h
Normal 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
98
mbsebbs/pwdcheck.c
Normal 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
8
mbsebbs/pwdcheck.h
Normal 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
127
mbsebbs/setugid.c
Normal 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
10
mbsebbs/setugid.h
Normal 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
275
mbsebbs/setupenv.c
Normal 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
10
mbsebbs/setupenv.h
Normal 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
128
mbsebbs/shell.c
Normal 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
8
mbsebbs/shell.h
Normal 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
292
mbsebbs/snprintf.c
Normal 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
51
mbsebbs/snprintf.h
Normal 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
80
mbsebbs/sub.c
Normal 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
8
mbsebbs/sub.h
Normal file
@ -0,0 +1,8 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _SUB_H
|
||||
#define _SUB_H
|
||||
|
||||
void subsystem(const struct passwd *);
|
||||
|
||||
#endif
|
90
mbsebbs/ttytype.c
Normal file
90
mbsebbs/ttytype.c
Normal 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
8
mbsebbs/ttytype.h
Normal file
@ -0,0 +1,8 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _TTYTYPE_H
|
||||
#define _TTYTYPE_H
|
||||
|
||||
void ttytype(const char *);
|
||||
|
||||
#endif
|
67
mbsebbs/tz.c
Normal file
67
mbsebbs/tz.c
Normal 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
8
mbsebbs/tz.h
Normal file
@ -0,0 +1,8 @@
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef _TZTZ_H
|
||||
#define _TZTZ_H
|
||||
|
||||
char *tz(const char *);
|
||||
|
||||
#endif
|
66
mbsebbs/ulimit.c
Normal file
66
mbsebbs/ulimit.c
Normal 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
9
mbsebbs/ulimit.h
Normal 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
477
mbsebbs/utmp.c
Normal 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
21
mbsebbs/utmp.h
Normal 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
|
Reference in New Issue
Block a user