diff --git a/config.h.in b/config.h.in index 7520ec92..3c40fdef 100644 --- a/config.h.in +++ b/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 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 header file. */ #undef HAVE_SYSLOG_H +/* Define to use syslog(). */ +#undef USE_SYSLOG + /* Define if you have the 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 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. */ diff --git a/configure b/configure index 93a20625..3b3a3781 100755 --- a/configure +++ b/configure @@ -3269,13 +3269,61 @@ EOF fi done -echo "$as_me:3272: checking whether struct tm is in sys/time.h or time.h" >&5 +for ac_header in limits.h utmp.h utmpx.h sgtty.h lastlog.h rpc/key_prot.h +do +ac_ac_Header=`echo "ac_cv_header_$ac_header" | $ac_tr_sh` +echo "$as_me:3275: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$ac_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 3281 "configure" +#include "confdefs.h" +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:3285: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + egrep -v '^ *\+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:3291: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + eval "$ac_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 + cat conftest.$ac_ext >&5 + eval "$ac_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_ext +fi +echo "$as_me:3310: result: `eval echo '${'$ac_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$ac_ac_Header'}'`" >&6 +if test `eval echo '${'$ac_ac_Header'}'` = yes; then + cat >>confdefs.h <&5 echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6 if test "${ac_cv_struct_tm+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3278 "configure" +#line 3326 "configure" #include "confdefs.h" #include #include @@ -3289,16 +3337,16 @@ struct tm *tp; tp->tm_sec; } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3292: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3340: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3295: \$? = $ac_status" >&5 + echo "$as_me:3343: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3298: \"$ac_try\"") >&5 + { (eval echo "$as_me:3346: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3301: \$? = $ac_status" >&5 + echo "$as_me:3349: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_struct_tm=time.h else @@ -3308,7 +3356,7 @@ ac_cv_struct_tm=sys/time.h fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3311: result: $ac_cv_struct_tm" >&5 +echo "$as_me:3359: result: $ac_cv_struct_tm" >&5 echo "${ECHO_T}$ac_cv_struct_tm" >&6 if test $ac_cv_struct_tm = sys/time.h; then @@ -3318,13 +3366,13 @@ EOF fi -echo "$as_me:3321: checking for struct tm.tm_zone" >&5 +echo "$as_me:3369: checking for struct tm.tm_zone" >&5 echo $ECHO_N "checking for struct tm.tm_zone... $ECHO_C" >&6 if test "${ac_cv_member_struct_tm_tm_zone+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3327 "configure" +#line 3375 "configure" #include "confdefs.h" #include #include <$ac_cv_struct_tm> @@ -3339,16 +3387,16 @@ foo.tm_zone; } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3342: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3390: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3345: \$? = $ac_status" >&5 + echo "$as_me:3393: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3348: \"$ac_try\"") >&5 + { (eval echo "$as_me:3396: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3351: \$? = $ac_status" >&5 + echo "$as_me:3399: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_member_struct_tm_tm_zone=yes else @@ -3358,7 +3406,7 @@ ac_cv_member_struct_tm_tm_zone=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3361: result: $ac_cv_member_struct_tm_tm_zone" >&5 +echo "$as_me:3409: result: $ac_cv_member_struct_tm_tm_zone" >&5 echo "${ECHO_T}$ac_cv_member_struct_tm_tm_zone" >&6 if test $ac_cv_member_struct_tm_tm_zone = yes; then @@ -3375,13 +3423,13 @@ cat >>confdefs.h <<\EOF EOF else - echo "$as_me:3378: checking for tzname" >&5 + echo "$as_me:3426: checking for tzname" >&5 echo $ECHO_N "checking for tzname... $ECHO_C" >&6 if test "${ac_cv_var_tzname+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3384 "configure" +#line 3432 "configure" #include "confdefs.h" #include #ifndef tzname /* For SGI. */ @@ -3397,16 +3445,16 @@ atoi(*tzname); } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:3400: \"$ac_link\"") >&5 +if { (eval echo "$as_me:3448: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:3403: \$? = $ac_status" >&5 + echo "$as_me:3451: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:3406: \"$ac_try\"") >&5 + { (eval echo "$as_me:3454: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3409: \$? = $ac_status" >&5 + echo "$as_me:3457: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_var_tzname=yes else @@ -3416,7 +3464,7 @@ ac_cv_var_tzname=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:3419: result: $ac_cv_var_tzname" >&5 +echo "$as_me:3467: result: $ac_cv_var_tzname" >&5 echo "${ECHO_T}$ac_cv_var_tzname" >&6 if test $ac_cv_var_tzname = yes; then @@ -3427,7 +3475,7 @@ EOF fi fi -echo "$as_me:3430: checking for $CC option to accept ANSI C" >&5 +echo "$as_me:3478: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -3435,7 +3483,7 @@ else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF -#line 3438 "configure" +#line 3486 "configure" #include "confdefs.h" #include #include @@ -3484,16 +3532,16 @@ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIO do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext -if { (eval echo "$as_me:3487: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3535: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3490: \$? = $ac_status" >&5 + echo "$as_me:3538: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3493: \"$ac_try\"") >&5 + { (eval echo "$as_me:3541: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3496: \$? = $ac_status" >&5 + echo "$as_me:3544: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break @@ -3510,21 +3558,21 @@ fi case "x$ac_cv_prog_cc_stdc" in x|xno) - echo "$as_me:3513: result: none needed" >&5 + echo "$as_me:3561: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) - echo "$as_me:3516: result: $ac_cv_prog_cc_stdc" >&5 + echo "$as_me:3564: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac -echo "$as_me:3521: checking for an ANSI C-conforming const" >&5 +echo "$as_me:3569: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 if test "${ac_cv_c_const+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3527 "configure" +#line 3575 "configure" #include "confdefs.h" int @@ -3582,16 +3630,16 @@ main () } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3585: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3633: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3588: \$? = $ac_status" >&5 + echo "$as_me:3636: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3591: \"$ac_try\"") >&5 + { (eval echo "$as_me:3639: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3594: \$? = $ac_status" >&5 + echo "$as_me:3642: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_const=yes else @@ -3601,7 +3649,7 @@ ac_cv_c_const=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3604: result: $ac_cv_c_const" >&5 +echo "$as_me:3652: result: $ac_cv_c_const" >&5 echo "${ECHO_T}$ac_cv_c_const" >&6 if test $ac_cv_c_const = no; then @@ -3611,13 +3659,13 @@ EOF fi -echo "$as_me:3614: checking for uid_t in sys/types.h" >&5 +echo "$as_me:3662: checking for uid_t in sys/types.h" >&5 echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6 if test "${ac_cv_type_uid_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3620 "configure" +#line 3668 "configure" #include "confdefs.h" #include @@ -3631,7 +3679,7 @@ fi rm -f conftest* fi -echo "$as_me:3634: result: $ac_cv_type_uid_t" >&5 +echo "$as_me:3682: result: $ac_cv_type_uid_t" >&5 echo "${ECHO_T}$ac_cv_type_uid_t" >&6 if test $ac_cv_type_uid_t = no; then @@ -3648,23 +3696,23 @@ fi for ac_header in stdlib.h string.h memory.h strings.h inttypes.h unistd.h do ac_ac_Header=`echo "ac_cv_header_$ac_header" | $ac_tr_sh` -echo "$as_me:3651: checking for $ac_header" >&5 +echo "$as_me:3699: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$ac_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3657 "configure" +#line 3705 "configure" #include "confdefs.h" #include <$ac_header> _ACEOF -if { (eval echo "$as_me:3661: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:3709: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:3667: \$? = $ac_status" >&5 + echo "$as_me:3715: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -3683,7 +3731,7 @@ else fi rm -f conftest.err conftest.$ac_ext fi -echo "$as_me:3686: result: `eval echo '${'$ac_ac_Header'}'`" >&5 +echo "$as_me:3734: result: `eval echo '${'$ac_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_Header'}'`" >&6 if test `eval echo '${'$ac_ac_Header'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:3744: checking for off_t" >&5 echo $ECHO_N "checking for off_t... $ECHO_C" >&6 if test "${ac_cv_type_off_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3702 "configure" +#line 3750 "configure" #include "confdefs.h" $ac_includes_default int @@ -3714,16 +3762,16 @@ if (sizeof (off_t)) } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3717: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3765: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3720: \$? = $ac_status" >&5 + echo "$as_me:3768: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3723: \"$ac_try\"") >&5 + { (eval echo "$as_me:3771: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3726: \$? = $ac_status" >&5 + echo "$as_me:3774: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_off_t=yes else @@ -3733,7 +3781,7 @@ ac_cv_type_off_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3736: result: $ac_cv_type_off_t" >&5 +echo "$as_me:3784: result: $ac_cv_type_off_t" >&5 echo "${ECHO_T}$ac_cv_type_off_t" >&6 if test $ac_cv_type_off_t = yes; then : @@ -3745,13 +3793,13 @@ EOF fi -echo "$as_me:3748: checking for pid_t" >&5 +echo "$as_me:3796: checking for pid_t" >&5 echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 if test "${ac_cv_type_pid_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3754 "configure" +#line 3802 "configure" #include "confdefs.h" $ac_includes_default int @@ -3766,16 +3814,16 @@ if (sizeof (pid_t)) } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3769: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3817: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3772: \$? = $ac_status" >&5 + echo "$as_me:3820: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3775: \"$ac_try\"") >&5 + { (eval echo "$as_me:3823: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3778: \$? = $ac_status" >&5 + echo "$as_me:3826: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_pid_t=yes else @@ -3785,7 +3833,7 @@ ac_cv_type_pid_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3788: result: $ac_cv_type_pid_t" >&5 +echo "$as_me:3836: result: $ac_cv_type_pid_t" >&5 echo "${ECHO_T}$ac_cv_type_pid_t" >&6 if test $ac_cv_type_pid_t = yes; then : @@ -3797,13 +3845,13 @@ EOF fi -echo "$as_me:3800: checking for mode_t" >&5 +echo "$as_me:3848: checking for mode_t" >&5 echo $ECHO_N "checking for mode_t... $ECHO_C" >&6 if test "${ac_cv_type_mode_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3806 "configure" +#line 3854 "configure" #include "confdefs.h" $ac_includes_default int @@ -3818,16 +3866,16 @@ if (sizeof (mode_t)) } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3821: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3869: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3824: \$? = $ac_status" >&5 + echo "$as_me:3872: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3827: \"$ac_try\"") >&5 + { (eval echo "$as_me:3875: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3830: \$? = $ac_status" >&5 + echo "$as_me:3878: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_mode_t=yes else @@ -3837,7 +3885,7 @@ ac_cv_type_mode_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3840: result: $ac_cv_type_mode_t" >&5 +echo "$as_me:3888: result: $ac_cv_type_mode_t" >&5 echo "${ECHO_T}$ac_cv_type_mode_t" >&6 if test $ac_cv_type_mode_t = yes; then : @@ -3849,13 +3897,13 @@ EOF fi -echo "$as_me:3852: checking for size_t" >&5 +echo "$as_me:3900: checking for size_t" >&5 echo $ECHO_N "checking for size_t... $ECHO_C" >&6 if test "${ac_cv_type_size_t+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3858 "configure" +#line 3906 "configure" #include "confdefs.h" $ac_includes_default int @@ -3870,16 +3918,16 @@ if (sizeof (size_t)) } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3873: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3921: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3876: \$? = $ac_status" >&5 + echo "$as_me:3924: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3879: \"$ac_try\"") >&5 + { (eval echo "$as_me:3927: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3882: \$? = $ac_status" >&5 + echo "$as_me:3930: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_size_t=yes else @@ -3889,7 +3937,7 @@ ac_cv_type_size_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3892: result: $ac_cv_type_size_t" >&5 +echo "$as_me:3940: result: $ac_cv_type_size_t" >&5 echo "${ECHO_T}$ac_cv_type_size_t" >&6 if test $ac_cv_type_size_t = yes; then : @@ -3901,13 +3949,13 @@ EOF fi -echo "$as_me:3904: checking for struct stat.st_blksize" >&5 +echo "$as_me:3952: checking for struct stat.st_blksize" >&5 echo $ECHO_N "checking for struct stat.st_blksize... $ECHO_C" >&6 if test "${ac_cv_member_struct_stat_st_blksize+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3910 "configure" +#line 3958 "configure" #include "confdefs.h" $ac_includes_default int @@ -3920,16 +3968,16 @@ foo.st_blksize; } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:3923: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:3971: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:3926: \$? = $ac_status" >&5 + echo "$as_me:3974: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:3929: \"$ac_try\"") >&5 + { (eval echo "$as_me:3977: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:3932: \$? = $ac_status" >&5 + echo "$as_me:3980: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_member_struct_stat_st_blksize=yes else @@ -3939,7 +3987,7 @@ ac_cv_member_struct_stat_st_blksize=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:3942: result: $ac_cv_member_struct_stat_st_blksize" >&5 +echo "$as_me:3990: result: $ac_cv_member_struct_stat_st_blksize" >&5 echo "${ECHO_T}$ac_cv_member_struct_stat_st_blksize" >&6 if test $ac_cv_member_struct_stat_st_blksize = yes; then @@ -3953,13 +4001,13 @@ EOF fi -echo "$as_me:3956: checking whether stat file-mode macros are broken" >&5 +echo "$as_me:4004: checking whether stat file-mode macros are broken" >&5 echo $ECHO_N "checking whether stat file-mode macros are broken... $ECHO_C" >&6 if test "${ac_cv_header_stat_broken+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 3962 "configure" +#line 4010 "configure" #include "confdefs.h" #include #include @@ -3998,7 +4046,7 @@ fi rm -f conftest* fi -echo "$as_me:4001: result: $ac_cv_header_stat_broken" >&5 +echo "$as_me:4049: result: $ac_cv_header_stat_broken" >&5 echo "${ECHO_T}$ac_cv_header_stat_broken" >&6 if test $ac_cv_header_stat_broken = yes; then @@ -4008,13 +4056,13 @@ EOF fi -echo "$as_me:4011: checking whether struct tm is in sys/time.h or time.h" >&5 +echo "$as_me:4059: checking whether struct tm is in sys/time.h or time.h" >&5 echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6 if test "${ac_cv_struct_tm+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4017 "configure" +#line 4065 "configure" #include "confdefs.h" #include #include @@ -4028,16 +4076,16 @@ struct tm *tp; tp->tm_sec; } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:4031: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:4079: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:4034: \$? = $ac_status" >&5 + echo "$as_me:4082: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:4037: \"$ac_try\"") >&5 + { (eval echo "$as_me:4085: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4040: \$? = $ac_status" >&5 + echo "$as_me:4088: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_struct_tm=time.h else @@ -4047,7 +4095,7 @@ ac_cv_struct_tm=sys/time.h fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:4050: result: $ac_cv_struct_tm" >&5 +echo "$as_me:4098: result: $ac_cv_struct_tm" >&5 echo "${ECHO_T}$ac_cv_struct_tm" >&6 if test $ac_cv_struct_tm = sys/time.h; then @@ -4060,13 +4108,13 @@ fi for ac_func in c64i a64l fchmod fchown fdatasync fsync lckpwdf strcasestr mkstemp putpwent do ac_ac_var=`echo "ac_cv_func_$ac_func" | $ac_tr_sh` -echo "$as_me:4063: checking for $ac_func" >&5 +echo "$as_me:4111: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$ac_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4069 "configure" +#line 4117 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. */ @@ -4097,16 +4145,16 @@ f = $ac_func; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4100: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4148: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4103: \$? = $ac_status" >&5 + echo "$as_me:4151: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4106: \"$ac_try\"") >&5 + { (eval echo "$as_me:4154: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4109: \$? = $ac_status" >&5 + echo "$as_me:4157: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$ac_ac_var=yes" else @@ -4116,7 +4164,7 @@ eval "$ac_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:4119: result: `eval echo '${'$ac_ac_var'}'`" >&5 +echo "$as_me:4167: result: `eval echo '${'$ac_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_var'}'`" >&6 if test `eval echo '${'$ac_ac_var'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:4177: checking for working GNU-style fnmatch" >&5 echo $ECHO_N "checking for working GNU-style fnmatch... $ECHO_C" >&6 if test "${ac_cv_func_fnmatch_works+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -4139,7 +4187,7 @@ if test "$cross_compiling" = yes; then ac_cv_func_fnmatch_works=no else cat >conftest.$ac_ext <<_ACEOF -#line 4142 "configure" +#line 4190 "configure" #include "confdefs.h" #include int @@ -4155,15 +4203,15 @@ exit (fnmatch ("a*", "abc", 0) != 0 } _ACEOF rm -f conftest$ac_exeext -if { (eval echo "$as_me:4158: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4206: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4161: \$? = $ac_status" >&5 + echo "$as_me:4209: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:4163: \"$ac_try\"") >&5 + { (eval echo "$as_me:4211: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4166: \$? = $ac_status" >&5 + echo "$as_me:4214: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_fnmatch_works=yes else @@ -4175,7 +4223,7 @@ fi rm -f core core.* *.core conftest$ac_exeext conftest.$ac_ext fi fi -echo "$as_me:4178: result: $ac_cv_func_fnmatch_works" >&5 +echo "$as_me:4226: result: $ac_cv_func_fnmatch_works" >&5 echo "${ECHO_T}$ac_cv_func_fnmatch_works" >&6 if test $ac_cv_func_fnmatch_works = yes; then @@ -4186,14 +4234,14 @@ EOF fi if test $ac_cv_c_compiler_gnu = yes; then - echo "$as_me:4189: checking whether $CC needs -traditional" >&5 + echo "$as_me:4237: checking whether $CC needs -traditional" >&5 echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6 if test "${ac_cv_prog_gcc_traditional+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_pattern="Autoconf.*'x'" cat >conftest.$ac_ext <<_ACEOF -#line 4196 "configure" +#line 4244 "configure" #include "confdefs.h" #include Autoconf TIOCGETP @@ -4208,7 +4256,7 @@ rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat >conftest.$ac_ext <<_ACEOF -#line 4211 "configure" +#line 4259 "configure" #include "confdefs.h" #include Autoconf TCGETA @@ -4221,14 +4269,14 @@ rm -f conftest* fi fi -echo "$as_me:4224: result: $ac_cv_prog_gcc_traditional" >&5 +echo "$as_me:4272: result: $ac_cv_prog_gcc_traditional" >&5 echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6 if test $ac_cv_prog_gcc_traditional = yes; then CC="$CC -traditional" fi fi -echo "$as_me:4231: checking for working memcmp" >&5 +echo "$as_me:4279: checking for working memcmp" >&5 echo $ECHO_N "checking for working memcmp... $ECHO_C" >&6 if test "${ac_cv_func_memcmp_working+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -4237,7 +4285,7 @@ else ac_cv_func_memcmp_working=no else cat >conftest.$ac_ext <<_ACEOF -#line 4240 "configure" +#line 4288 "configure" #include "confdefs.h" int @@ -4273,15 +4321,15 @@ main () } _ACEOF rm -f conftest$ac_exeext -if { (eval echo "$as_me:4276: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4324: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4279: \$? = $ac_status" >&5 + echo "$as_me:4327: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:4281: \"$ac_try\"") >&5 + { (eval echo "$as_me:4329: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4284: \$? = $ac_status" >&5 + echo "$as_me:4332: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_memcmp_working=yes else @@ -4293,22 +4341,22 @@ fi rm -f core core.* *.core conftest$ac_exeext conftest.$ac_ext fi fi -echo "$as_me:4296: result: $ac_cv_func_memcmp_working" >&5 +echo "$as_me:4344: result: $ac_cv_func_memcmp_working" >&5 echo "${ECHO_T}$ac_cv_func_memcmp_working" >&6 test $ac_cv_func_memcmp_working = no && LIBOBJS="$LIBOBJS memcmp.$ac_objext" -echo "$as_me:4300: checking whether setpgrp takes no argument" >&5 +echo "$as_me:4348: checking whether setpgrp takes no argument" >&5 echo $ECHO_N "checking whether setpgrp takes no argument... $ECHO_C" >&6 if test "${ac_cv_func_setpgrp_void+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then - { { echo "$as_me:4306: error: cannot check setpgrp if cross compiling" >&5 + { { echo "$as_me:4354: error: cannot check setpgrp if cross compiling" >&5 echo "$as_me: error: cannot check setpgrp if cross compiling" >&2;} { (exit 1); exit 1; }; } else cat >conftest.$ac_ext <<_ACEOF -#line 4311 "configure" +#line 4359 "configure" #include "confdefs.h" #if HAVE_UNISTD_H # include @@ -4325,15 +4373,15 @@ main () } _ACEOF rm -f conftest$ac_exeext -if { (eval echo "$as_me:4328: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4376: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4331: \$? = $ac_status" >&5 + echo "$as_me:4379: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:4333: \"$ac_try\"") >&5 + { (eval echo "$as_me:4381: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4336: \$? = $ac_status" >&5 + echo "$as_me:4384: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_setpgrp_void=no else @@ -4345,7 +4393,7 @@ fi rm -f core core.* *.core conftest$ac_exeext conftest.$ac_ext fi fi -echo "$as_me:4348: result: $ac_cv_func_setpgrp_void" >&5 +echo "$as_me:4396: result: $ac_cv_func_setpgrp_void" >&5 echo "${ECHO_T}$ac_cv_func_setpgrp_void" >&6 if test $ac_cv_func_setpgrp_void = yes; then @@ -4355,13 +4403,13 @@ EOF fi -echo "$as_me:4358: checking return type of signal handlers" >&5 +echo "$as_me:4406: checking return type of signal handlers" >&5 echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 if test "${ac_cv_type_signal+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4364 "configure" +#line 4412 "configure" #include "confdefs.h" #include #include @@ -4383,16 +4431,16 @@ int i; } _ACEOF rm -f conftest.$ac_objext -if { (eval echo "$as_me:4386: \"$ac_compile\"") >&5 +if { (eval echo "$as_me:4434: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? - echo "$as_me:4389: \$? = $ac_status" >&5 + echo "$as_me:4437: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:4392: \"$ac_try\"") >&5 + { (eval echo "$as_me:4440: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4395: \$? = $ac_status" >&5 + echo "$as_me:4443: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_signal=void else @@ -4402,7 +4450,7 @@ ac_cv_type_signal=int fi rm -f conftest.$ac_objext conftest.$ac_ext fi -echo "$as_me:4405: result: $ac_cv_type_signal" >&5 +echo "$as_me:4453: result: $ac_cv_type_signal" >&5 echo "${ECHO_T}$ac_cv_type_signal" >&6 cat >>confdefs.h <&5 +echo "$as_me:4463: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$ac_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4421 "configure" +#line 4469 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. */ @@ -4449,16 +4497,16 @@ f = $ac_func; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4452: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4500: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4455: \$? = $ac_status" >&5 + echo "$as_me:4503: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4458: \"$ac_try\"") >&5 + { (eval echo "$as_me:4506: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4461: \$? = $ac_status" >&5 + echo "$as_me:4509: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$ac_ac_var=yes" else @@ -4468,7 +4516,7 @@ eval "$ac_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:4471: result: `eval echo '${'$ac_ac_var'}'`" >&5 +echo "$as_me:4519: result: `eval echo '${'$ac_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_var'}'`" >&6 if test `eval echo '${'$ac_ac_var'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:4528: checking for strftime in -lintl" >&5 echo $ECHO_N "checking for strftime in -lintl... $ECHO_C" >&6 if test "${ac_cv_lib_intl_strftime+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -4485,7 +4533,7 @@ else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat >conftest.$ac_ext <<_ACEOF -#line 4488 "configure" +#line 4536 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ @@ -4504,16 +4552,16 @@ strftime (); } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4507: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4555: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4510: \$? = $ac_status" >&5 + echo "$as_me:4558: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4513: \"$ac_try\"") >&5 + { (eval echo "$as_me:4561: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4516: \$? = $ac_status" >&5 + echo "$as_me:4564: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_intl_strftime=yes else @@ -4524,7 +4572,7 @@ fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:4527: result: $ac_cv_lib_intl_strftime" >&5 +echo "$as_me:4575: result: $ac_cv_lib_intl_strftime" >&5 echo "${ECHO_T}$ac_cv_lib_intl_strftime" >&6 if test $ac_cv_lib_intl_strftime = yes; then cat >>confdefs.h <<\EOF @@ -4537,7 +4585,7 @@ fi fi done -echo "$as_me:4540: checking whether utime accepts a null argument" >&5 +echo "$as_me:4588: checking whether utime accepts a null argument" >&5 echo $ECHO_N "checking whether utime accepts a null argument... $ECHO_C" >&6 if test "${ac_cv_func_utime_null+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -4548,7 +4596,7 @@ if test "$cross_compiling" = yes; then ac_cv_func_utime_null=no else cat >conftest.$ac_ext <<_ACEOF -#line 4551 "configure" +#line 4599 "configure" #include "confdefs.h" #include #include @@ -4564,15 +4612,15 @@ main () } _ACEOF rm -f conftest$ac_exeext -if { (eval echo "$as_me:4567: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4615: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4570: \$? = $ac_status" >&5 + echo "$as_me:4618: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:4572: \"$ac_try\"") >&5 + { (eval echo "$as_me:4620: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4575: \$? = $ac_status" >&5 + echo "$as_me:4623: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_utime_null=yes else @@ -4585,7 +4633,7 @@ rm -f core core.* *.core conftest$ac_exeext conftest.$ac_ext fi rm -f core core.* *.core fi -echo "$as_me:4588: result: $ac_cv_func_utime_null" >&5 +echo "$as_me:4636: result: $ac_cv_func_utime_null" >&5 echo "${ECHO_T}$ac_cv_func_utime_null" >&6 if test $ac_cv_func_utime_null = yes; then @@ -4599,23 +4647,23 @@ rm -f conftest.data for ac_header in unistd.h vfork.h do ac_ac_Header=`echo "ac_cv_header_$ac_header" | $ac_tr_sh` -echo "$as_me:4602: checking for $ac_header" >&5 +echo "$as_me:4650: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$ac_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4608 "configure" +#line 4656 "configure" #include "confdefs.h" #include <$ac_header> _ACEOF -if { (eval echo "$as_me:4612: \"$ac_cpp conftest.$ac_ext\"") >&5 +if { (eval echo "$as_me:4660: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? egrep -v '^ *\+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 - echo "$as_me:4618: \$? = $ac_status" >&5 + echo "$as_me:4666: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag @@ -4634,7 +4682,7 @@ else fi rm -f conftest.err conftest.$ac_ext fi -echo "$as_me:4637: result: `eval echo '${'$ac_ac_Header'}'`" >&5 +echo "$as_me:4685: result: `eval echo '${'$ac_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_Header'}'`" >&6 if test `eval echo '${'$ac_ac_Header'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:4695: checking for working vfork" >&5 echo $ECHO_N "checking for working vfork... $ECHO_C" >&6 if test "${ac_cv_func_vfork_works+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then - echo "$as_me:4653: checking for vfork" >&5 + echo "$as_me:4701: checking for vfork" >&5 echo $ECHO_N "checking for vfork... $ECHO_C" >&6 if test "${ac_cv_func_vfork+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4659 "configure" +#line 4707 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char vfork (); below. */ @@ -4687,16 +4735,16 @@ f = vfork; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4690: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4738: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4693: \$? = $ac_status" >&5 + echo "$as_me:4741: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4696: \"$ac_try\"") >&5 + { (eval echo "$as_me:4744: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4699: \$? = $ac_status" >&5 + echo "$as_me:4747: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_vfork=yes else @@ -4706,13 +4754,13 @@ ac_cv_func_vfork=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:4709: result: $ac_cv_func_vfork" >&5 +echo "$as_me:4757: result: $ac_cv_func_vfork" >&5 echo "${ECHO_T}$ac_cv_func_vfork" >&6 ac_cv_func_vfork_works=$ac_cv_func_vfork else cat >conftest.$ac_ext <<_ACEOF -#line 4715 "configure" +#line 4763 "configure" #include "confdefs.h" /* Thanks to Paul Eggert for this test. */ #include @@ -4809,15 +4857,15 @@ main () } _ACEOF rm -f conftest$ac_exeext -if { (eval echo "$as_me:4812: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4860: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4815: \$? = $ac_status" >&5 + echo "$as_me:4863: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (eval echo "$as_me:4817: \"$ac_try\"") >&5 + { (eval echo "$as_me:4865: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4820: \$? = $ac_status" >&5 + echo "$as_me:4868: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_vfork_works=yes else @@ -4829,7 +4877,7 @@ fi rm -f core core.* *.core conftest$ac_exeext conftest.$ac_ext fi fi -echo "$as_me:4832: result: $ac_cv_func_vfork_works" >&5 +echo "$as_me:4880: result: $ac_cv_func_vfork_works" >&5 echo "${ECHO_T}$ac_cv_func_vfork_works" >&6 if test "x$ac_cv_func_vfork_works" = xno; then @@ -4842,13 +4890,13 @@ fi for ac_func in vprintf do ac_ac_var=`echo "ac_cv_func_$ac_func" | $ac_tr_sh` -echo "$as_me:4845: checking for $ac_func" >&5 +echo "$as_me:4893: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$ac_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4851 "configure" +#line 4899 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. */ @@ -4879,16 +4927,16 @@ f = $ac_func; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4882: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4930: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4885: \$? = $ac_status" >&5 + echo "$as_me:4933: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4888: \"$ac_try\"") >&5 + { (eval echo "$as_me:4936: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4891: \$? = $ac_status" >&5 + echo "$as_me:4939: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$ac_ac_var=yes" else @@ -4898,20 +4946,20 @@ eval "$ac_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:4901: result: `eval echo '${'$ac_ac_var'}'`" >&5 +echo "$as_me:4949: result: `eval echo '${'$ac_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_var'}'`" >&6 if test `eval echo '${'$ac_ac_var'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:4956: checking for _doprnt" >&5 echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 if test "${ac_cv_func__doprnt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4914 "configure" +#line 4962 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char _doprnt (); below. */ @@ -4942,16 +4990,16 @@ f = _doprnt; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:4945: \"$ac_link\"") >&5 +if { (eval echo "$as_me:4993: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:4948: \$? = $ac_status" >&5 + echo "$as_me:4996: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:4951: \"$ac_try\"") >&5 + { (eval echo "$as_me:4999: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:4954: \$? = $ac_status" >&5 + echo "$as_me:5002: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func__doprnt=yes else @@ -4961,7 +5009,7 @@ ac_cv_func__doprnt=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:4964: result: $ac_cv_func__doprnt" >&5 +echo "$as_me:5012: result: $ac_cv_func__doprnt" >&5 echo "${ECHO_T}$ac_cv_func__doprnt" >&6 if test $ac_cv_func__doprnt = yes; then @@ -4977,13 +5025,13 @@ done for ac_func in getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname do ac_ac_var=`echo "ac_cv_func_$ac_func" | $ac_tr_sh` -echo "$as_me:4980: checking for $ac_func" >&5 +echo "$as_me:5028: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$ac_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF -#line 4986 "configure" +#line 5034 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. */ @@ -5014,16 +5062,16 @@ f = $ac_func; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext -if { (eval echo "$as_me:5017: \"$ac_link\"") >&5 +if { (eval echo "$as_me:5065: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? - echo "$as_me:5020: \$? = $ac_status" >&5 + echo "$as_me:5068: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' - { (eval echo "$as_me:5023: \"$ac_try\"") >&5 + { (eval echo "$as_me:5071: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? - echo "$as_me:5026: \$? = $ac_status" >&5 + echo "$as_me:5074: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$ac_ac_var=yes" else @@ -5033,7 +5081,76 @@ eval "$ac_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext fi -echo "$as_me:5036: result: `eval echo '${'$ac_ac_var'}'`" >&5 +echo "$as_me:5084: result: `eval echo '${'$ac_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$ac_ac_var'}'`" >&6 +if test `eval echo '${'$ac_ac_var'}'` = yes; then + cat >>confdefs.h <&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$ac_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line 5103 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:5134: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:5137: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:5140: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:5143: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$ac_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$ac_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:5153: result: `eval echo '${'$ac_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$ac_ac_var'}'`" >&6 if test `eval echo '${'$ac_ac_var'}'` = yes; then cat >>confdefs.h <&5 +echo "$as_me:5165: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_COMPRESS+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -5062,7 +5179,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_COMPRESS="$ac_dir/$ac_word" - echo "$as_me:5065: found $ac_dir/$ac_word" >&5 + echo "$as_me:5182: found $ac_dir/$ac_word" >&5 break fi done @@ -5074,10 +5191,10 @@ fi COMPRESS=$ac_cv_path_COMPRESS if test -n "$COMPRESS"; then - echo "$as_me:5077: result: $COMPRESS" >&5 + echo "$as_me:5194: result: $COMPRESS" >&5 echo "${ECHO_T}$COMPRESS" >&6 else - echo "$as_me:5080: result: no" >&5 + echo "$as_me:5197: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -5085,7 +5202,7 @@ for ac_prog in gzip do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -echo "$as_me:5088: checking for $ac_word" >&5 +echo "$as_me:5205: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_GZIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -5102,7 +5219,7 @@ for ac_dir in $ac_dummy; do test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_GZIP="$ac_dir/$ac_word" - echo "$as_me:5105: found $ac_dir/$ac_word" >&5 + echo "$as_me:5222: found $ac_dir/$ac_word" >&5 break fi done @@ -5113,10 +5230,10 @@ fi GZIP=$ac_cv_path_GZIP if test -n "$GZIP"; then - echo "$as_me:5116: result: $GZIP" >&5 + echo "$as_me:5233: result: $GZIP" >&5 echo "${ECHO_T}$GZIP" >&6 else - echo "$as_me:5119: result: no" >&5 + echo "$as_me:5236: result: no" >&5 echo "${ECHO_T}no" >&6 fi @@ -5143,6 +5260,45 @@ compress) LOG_COMPRESSEXT=".unknown" ;; esac +echo "$as_me:5263: checking location of utmp" >&5 +echo $ECHO_N "checking location of utmp... $ECHO_C" >&6 +for utmpdir in /var/run /var/adm /usr/adm /etc NONE; do + if test "$utmpdir" = "NONE"; then + { echo "$as_me:5267: WARNING: utmp file not found" >&5 +echo "$as_me: WARNING: utmp file not found" >&2;} + elif test -f $utmpdir/utmp; then + cat >>confdefs.h <&5 +echo "${ECHO_T}$utmpdir" >&6 + break + fi +done + +echo "$as_me:5280: checking location of faillog/lastlog/wtmp" >&5 +echo $ECHO_N "checking location of faillog/lastlog/wtmp... $ECHO_C" >&6 +for logdir in /var/log /var/adm /usr/adm /etc; do + if test -d $logdir; then + cat >>confdefs.h <>confdefs.h <>confdefs.h <&5 +echo "${ECHO_T}$logdir" >&6 + break + fi +done + ac_config_files="$ac_config_files Makefile.global mbfido/paths.h INSTALL FILE_ID.DIZ" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -5223,7 +5379,7 @@ DEFS=-DHAVE_CONFIG_H : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ echo "$as_me:5226: creating $CONFIG_STATUS" >&5 +{ echo "$as_me:5382: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL @@ -5398,7 +5554,7 @@ cat >>$CONFIG_STATUS <<\EOF echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header - { { echo "$as_me:5401: error: ambiguous option: $1 + { { echo "$as_me:5557: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} @@ -5425,12 +5581,12 @@ Try \`$0 --help' for more information." >&2;} 'config.h' ) CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; # This is an error. - -*) { { echo "$as_me:5428: error: unrecognized option: $1 + -*) { { echo "$as_me:5584: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; - *) { { echo "$as_me:5433: error: invalid argument: $1" >&5 + *) { { echo "$as_me:5589: error: invalid argument: $1" >&5 echo "$as_me: error: invalid argument: $1" >&2;} { (exit 1); exit 1; }; };; esac @@ -5669,7 +5825,7 @@ done; } esac if test x"$ac_file" != x-; then - { echo "$as_me:5672: creating $ac_file" >&5 + { echo "$as_me:5828: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi @@ -5687,7 +5843,7 @@ echo "$as_me: creating $ac_file" >&6;} -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:5690: error: cannot find input file: $f" >&5 + test -f "$f" || { { echo "$as_me:5846: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; @@ -5700,7 +5856,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;} echo $srcdir/$f else # /dev/null tree - { { echo "$as_me:5703: error: cannot find input file: $f" >&5 + { { echo "$as_me:5859: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; @@ -5760,7 +5916,7 @@ for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue * ) ac_file_in=$ac_file.in ;; esac - test x"$ac_file" != x- && { echo "$as_me:5763: creating $ac_file" >&5 + test x"$ac_file" != x- && { echo "$as_me:5919: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the @@ -5771,7 +5927,7 @@ echo "$as_me: creating $ac_file" >&6;} -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) - test -f "$f" || { { echo "$as_me:5774: error: cannot find input file: $f" >&5 + test -f "$f" || { { echo "$as_me:5930: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; @@ -5784,7 +5940,7 @@ echo "$as_me: error: cannot find input file: $f" >&2;} echo $srcdir/$f else # /dev/null tree - { { echo "$as_me:5787: error: cannot find input file: $f" >&5 + { { echo "$as_me:5943: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; @@ -5901,7 +6057,7 @@ cat >>$CONFIG_STATUS <<\EOF rm -f $tmp/in if test x"$ac_file" != x-; then if cmp -s $ac_file $tmp/config.h 2>/dev/null; then - { echo "$as_me:5904: $ac_file is unchanged" >&5 + { echo "$as_me:6060: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ diff --git a/configure.in b/configure.in index ed20f361..7c1e8aeb 100644 --- a/configure.in +++ b/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 diff --git a/mbsebbs/Makefile b/mbsebbs/Makefile index b4e1bcb3..c3897828 100644 --- a/mbsebbs/Makefile +++ b/mbsebbs/Makefile @@ -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 diff --git a/mbsebbs/basename.c b/mbsebbs/basename.c new file mode 100644 index 00000000..5beeeae3 --- /dev/null +++ b/mbsebbs/basename.c @@ -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; +} diff --git a/mbsebbs/basename.h b/mbsebbs/basename.h new file mode 100644 index 00000000..b6423d90 --- /dev/null +++ b/mbsebbs/basename.h @@ -0,0 +1,9 @@ +/* $Id$ */ + +#ifndef _BASENAME_H +#define _BASENAME_H + + +char *Basename(char *); + +#endif diff --git a/mbsebbs/chowntty.c b/mbsebbs/chowntty.c new file mode 100644 index 00000000..1c05031e --- /dev/null +++ b/mbsebbs/chowntty.c @@ -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 +#include +#include +#include +#include + +#include "mblogin.h" +#include +#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 +} diff --git a/mbsebbs/chowntty.h b/mbsebbs/chowntty.h new file mode 100644 index 00000000..ab92ac31 --- /dev/null +++ b/mbsebbs/chowntty.h @@ -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 diff --git a/mbsebbs/encrypt.c b/mbsebbs/encrypt.c index 670e2c6d..d3dcbb26 100644 --- a/mbsebbs/encrypt.c +++ b/mbsebbs/encrypt.c @@ -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 */ diff --git a/mbsebbs/env.c b/mbsebbs/env.c new file mode 100644 index 00000000..cf91a5cc --- /dev/null +++ b/mbsebbs/env.c @@ -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 +#include +#include +#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; + } + } +} + diff --git a/mbsebbs/env.h b/mbsebbs/env.h new file mode 100644 index 00000000..a5f968a8 --- /dev/null +++ b/mbsebbs/env.h @@ -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 + diff --git a/mbsebbs/failure.c b/mbsebbs/failure.c new file mode 100644 index 00000000..e00221b0 --- /dev/null +++ b/mbsebbs/failure.c @@ -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 +#include +#include "mblogin.h" +#include "getdef.h" +#include +#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); +} + + diff --git a/mbsebbs/failure.h b/mbsebbs/failure.h new file mode 100644 index 00000000..8e687fff --- /dev/null +++ b/mbsebbs/failure.h @@ -0,0 +1,42 @@ +/* $Id$ */ + +#ifndef _FAILURE_H_ +#define _FAILURE_H_ + +#include +/* + * 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 + diff --git a/mbsebbs/limits.c b/mbsebbs/limits.c new file mode 100644 index 00000000..1d6c4fdf --- /dev/null +++ b/mbsebbs/limits.c @@ -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 +#include +#include +#include +#include +#include +#include +#include "getdef.h" +#include "utmp.h" +#include "ulimit.h" + +#ifdef HAVE_SYS_RESOURCE_H +#include +#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; + } + } + } +} + + diff --git a/mbsebbs/limits.h b/mbsebbs/limits.h new file mode 100644 index 00000000..6600640a --- /dev/null +++ b/mbsebbs/limits.h @@ -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 diff --git a/mbsebbs/log.c b/mbsebbs/log.c new file mode 100644 index 00000000..4dbb499f --- /dev/null +++ b/mbsebbs/log.c @@ -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 +#include +#include +#include +#include +#include "mblogin.h" +#if HAVE_LASTLOG_H +#include +#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); +} + diff --git a/mbsebbs/log.h b/mbsebbs/log.h new file mode 100644 index 00000000..30ea86b6 --- /dev/null +++ b/mbsebbs/log.h @@ -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 diff --git a/mbsebbs/loginprompt.c b/mbsebbs/loginprompt.c new file mode 100644 index 00000000..3fa095b6 --- /dev/null +++ b/mbsebbs/loginprompt.c @@ -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 +#include +#include +#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 +} diff --git a/mbsebbs/loginprompt.h b/mbsebbs/loginprompt.h new file mode 100644 index 00000000..8a9a2a47 --- /dev/null +++ b/mbsebbs/loginprompt.h @@ -0,0 +1,9 @@ +/* $Id$ */ + +#ifndef _LOGINPROMPT_H +#define _LOGINPROMPT_H + +void login_exit(int); +void login_prompt(const char *, char *, int); + +#endif diff --git a/mbsebbs/mblogin.c b/mbsebbs/mblogin.c new file mode 100644 index 00000000..df843fd7 --- /dev/null +++ b/mbsebbs/mblogin.c @@ -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 +#include +#include +#include +#include +#include +#if defined(SHADOW_PASSWORD) +#include +#endif +#if HAVE_UTMPX_H +#include +#else +#include +#endif +#include +#include +#include +#include "getdef.h" + +#ifdef SVR4_SI86_EUA +#include +#include +#endif + +#ifdef UT_ADDR +#include +#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 . --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; +} + + diff --git a/mbsebbs/mblogin.h b/mbsebbs/mblogin.h new file mode 100644 index 00000000..74d2ebbc --- /dev/null +++ b/mbsebbs/mblogin.h @@ -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 +#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 +# 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 +# include +#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 +#include +#if HAVE_SYS_WAIT_H +# include +#endif + +#if HAVE_UNISTD_H +# include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include +# else +# include +# 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 +# define DIRECT dirent +#else +# ifdef HAVE_SYS_NDIR_H /* DIR_XENIX */ +# include +# endif +# ifdef HAVE_SYS_DIR_H /* DIR_??? */ +# include +# endif +# ifdef HAVE_NDIR_H /* DIR_BSD */ +# include +# 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 +#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 + +#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 +# 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 +# include +# 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 diff --git a/mbsebbs/mbpasswd.c b/mbsebbs/mbpasswd.c index 2224f099..93b9d21e 100644 --- a/mbsebbs/mbpasswd.c +++ b/mbsebbs/mbpasswd.c @@ -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); diff --git a/mbsebbs/pwauth.c b/mbsebbs/pwauth.c new file mode 100644 index 00000000..1e578009 --- /dev/null +++ b/mbsebbs/pwauth.c @@ -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 +#include +#include +#include +#include +#include "mblogin.h" +#include "pwauth.h" +#include "getdef.h" +#include "encrypt.h" + +#ifdef SKEY +#include +#endif + +#ifdef OPIE +#include +#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 , 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 +} + + diff --git a/mbsebbs/pwauth.h b/mbsebbs/pwauth.h new file mode 100644 index 00000000..232cf76b --- /dev/null +++ b/mbsebbs/pwauth.h @@ -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 + diff --git a/mbsebbs/pwdcheck.c b/mbsebbs/pwdcheck.c new file mode 100644 index 00000000..4aaeada4 --- /dev/null +++ b/mbsebbs/pwdcheck.c @@ -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 +#include "mblogin.h" +#include +#include +#include "pwauth.h" +#include "pwdcheck.h" + + +#ifdef HAVE_SHADOW_H +#include +#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 */ +} + diff --git a/mbsebbs/pwdcheck.h b/mbsebbs/pwdcheck.h new file mode 100644 index 00000000..e83ad561 --- /dev/null +++ b/mbsebbs/pwdcheck.h @@ -0,0 +1,8 @@ +/* $Id$ */ + +#ifndef _PWDCHECK_H +#define _PWDCHECK_H + +void passwd_check(const char *, const char *, const char *); + +#endif diff --git a/mbsebbs/setugid.c b/mbsebbs/setugid.c new file mode 100644 index 00000000..9fec9c0e --- /dev/null +++ b/mbsebbs/setugid.c @@ -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 +#include +#include +#include "mblogin.h" +#include +#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; +} diff --git a/mbsebbs/setugid.h b/mbsebbs/setugid.h new file mode 100644 index 00000000..77a4864b --- /dev/null +++ b/mbsebbs/setugid.h @@ -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 diff --git a/mbsebbs/setupenv.c b/mbsebbs/setupenv.c new file mode 100644 index 00000000..55c09c73 --- /dev/null +++ b/mbsebbs/setupenv.c @@ -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 +#include +#include +#include +#include +#include "mblogin.h" +#include +#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); +} diff --git a/mbsebbs/setupenv.h b/mbsebbs/setupenv.h new file mode 100644 index 00000000..b4214c54 --- /dev/null +++ b/mbsebbs/setupenv.h @@ -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 diff --git a/mbsebbs/shell.c b/mbsebbs/shell.c new file mode 100644 index 00000000..b6a66fb6 --- /dev/null +++ b/mbsebbs/shell.c @@ -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 +#include +#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); +} + + diff --git a/mbsebbs/shell.h b/mbsebbs/shell.h new file mode 100644 index 00000000..ffa2ed22 --- /dev/null +++ b/mbsebbs/shell.h @@ -0,0 +1,8 @@ +/* $Id$ */ + +#ifndef _SHELL_H +#define _SHELL_H + +void shell(const char *, const char *); + +#endif diff --git a/mbsebbs/snprintf.c b/mbsebbs/snprintf.c new file mode 100644 index 00000000..240cf3f0 --- /dev/null +++ b/mbsebbs/snprintf.c @@ -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 +#include "snprintf.h" + +static void dopr(char *, char *, va_list); +static char *end; + +/* varargs declarations: */ + +#if defined(HAVE_STDARG_H) +# include +# 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 +# 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 *)""; + } + 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; + } +} + + diff --git a/mbsebbs/snprintf.h b/mbsebbs/snprintf.h new file mode 100644 index 00000000..e900e31e --- /dev/null +++ b/mbsebbs/snprintf.h @@ -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 +#include +#else /* but we still need this... */ +#include +/* 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 +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 */ diff --git a/mbsebbs/sub.c b/mbsebbs/sub.c new file mode 100644 index 00000000..346dd6de --- /dev/null +++ b/mbsebbs/sub.c @@ -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 +#include +#include +#include "mblogin.h" +#include +#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); + } +} + + diff --git a/mbsebbs/sub.h b/mbsebbs/sub.h new file mode 100644 index 00000000..19cdd7bc --- /dev/null +++ b/mbsebbs/sub.h @@ -0,0 +1,8 @@ +/* $Id$ */ + +#ifndef _SUB_H +#define _SUB_H + +void subsystem(const struct passwd *); + +#endif diff --git a/mbsebbs/ttytype.c b/mbsebbs/ttytype.c new file mode 100644 index 00000000..6e28a897 --- /dev/null +++ b/mbsebbs/ttytype.c @@ -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 +#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); +} + + diff --git a/mbsebbs/ttytype.h b/mbsebbs/ttytype.h new file mode 100644 index 00000000..27f89d58 --- /dev/null +++ b/mbsebbs/ttytype.h @@ -0,0 +1,8 @@ +/* $Id$ */ + +#ifndef _TTYTYPE_H +#define _TTYTYPE_H + +void ttytype(const char *); + +#endif diff --git a/mbsebbs/tz.c b/mbsebbs/tz.c new file mode 100644 index 00000000..0d897f4b --- /dev/null +++ b/mbsebbs/tz.c @@ -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 +#include +#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; +} diff --git a/mbsebbs/tz.h b/mbsebbs/tz.h new file mode 100644 index 00000000..aba72654 --- /dev/null +++ b/mbsebbs/tz.h @@ -0,0 +1,8 @@ +/* $Id$ */ + +#ifndef _TZTZ_H +#define _TZTZ_H + +char *tz(const char *); + +#endif diff --git a/mbsebbs/ulimit.c b/mbsebbs/ulimit.c new file mode 100644 index 00000000..e96c31a9 --- /dev/null +++ b/mbsebbs/ulimit.c @@ -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 + +#ifndef UL_SETFSIZE +#ifdef UL_SFILLIM +#define UL_SETFSIZE UL_SFILLIM +#else +#define UL_SETFSIZE 2 +#endif +#endif + +#elif HAVE_SYS_RESOURCE_H +#include /* for struct timeval on sunos4 */ +/* XXX - is the above ok or should it be on ultrix? */ +#include +#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 +} + + diff --git a/mbsebbs/ulimit.h b/mbsebbs/ulimit.h new file mode 100644 index 00000000..b7a10334 --- /dev/null +++ b/mbsebbs/ulimit.h @@ -0,0 +1,9 @@ +/* $Id$ */ + +#ifndef _ULIMIT_H_H +#define _ULIMIT_H_H + + +void set_filesize_limit(int); + +#endif diff --git a/mbsebbs/utmp.c b/mbsebbs/utmp.c new file mode 100644 index 00000000..e7e05c5d --- /dev/null +++ b/mbsebbs/utmp.c @@ -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 + +#if HAVE_UTMPX_H +#include +#endif + +#include +#include +#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 */ diff --git a/mbsebbs/utmp.h b/mbsebbs/utmp.h new file mode 100644 index 00000000..bf75471b --- /dev/null +++ b/mbsebbs/utmp.h @@ -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