diff --git a/config.h.in b/config.h.in index b929b41d7e..daf15d3216 100644 --- a/config.h.in +++ b/config.h.in @@ -402,9 +402,15 @@ /* Define if you have the llistxattr function. */ #undef HAVE_LLISTXATTR +/* Define if you have the loginfailed function. */ +#undef HAVE_LOGINFAILED + /* Define if you have the loginrestrictions function. */ #undef HAVE_LOGINRESTRICTIONS +/* Define if you have the loginsuccess function. */ +#undef HAVE_LOGINSUCCESS + /* Define if you have the lremovexattr function. */ #undef HAVE_LREMOVEXATTR @@ -753,6 +759,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_ACL_H +/* Define if you have the header file. */ +#undef HAVE_SYS_AUDIT_H + /* Define if you have the header file. */ #undef HAVE_SYS_DIR_H diff --git a/configure b/configure index 084bd8bb36..5b9a9c895a 100755 --- a/configure +++ b/configure @@ -21872,7 +21872,8 @@ fi -for ac_header in krb.h login.h prot.h usersec.h + +for ac_header in krb.h login.h prot.h usersec.h sys/audit.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -22381,6 +22382,132 @@ fi done +{ echo "$as_me:$LINENO: checking for AIX loginfailed" >&5 +echo $ECHO_N "checking for AIX loginfailed... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #ifdef HAVE_USERSEC_H + # include + #endif + +int +main () +{ + + (void) loginfailed(NULL, NULL, NULL, 0); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LOGINFAILED 1 +_ACEOF + + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ echo "$as_me:$LINENO: checking for AIX loginsuccess" >&5 +echo $ECHO_N "checking for AIX loginsuccess... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #ifdef HAVE_USERSEC_H + # include + #endif + +int +main () +{ + + (void) loginsuccess(NULL, NULL, NULL, NULL); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LOGINSUCCESS 1 +_ACEOF + + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test x"$install_user" = x; then if test "x$target_os" = "xcygwin"; then diff --git a/configure.in b/configure.in index 57d9bea4e3..322def4f6c 100644 --- a/configure.in +++ b/configure.in @@ -1334,7 +1334,7 @@ if test "$pr_cv_var__pw_stayopen" = "yes"; then AC_DEFINE(HAVE__PW_STAYOPEN, 1, [Define if you have __pw_stayopen variable.]) fi -AC_CHECK_HEADERS(krb.h login.h prot.h usersec.h) +AC_CHECK_HEADERS(krb.h login.h prot.h usersec.h sys/audit.h) dnl HP-UX's hpsecurity.h can multiply define MAXINT and confuse configure AC_CHECK_HEADERS(hpsecurity.h, [ @@ -1356,6 +1356,45 @@ AC_CHECK_HEADERS(hpsecurity.h, [ ]) ]) +dnl AIX's "lastlog" support is done via specific functions, rather than a +dnl struct (Bug#4285). +AC_MSG_CHECKING(for AIX loginfailed) +AC_TRY_COMPILE([ + #include + #ifdef HAVE_USERSEC_H + # include + #endif + ], + [ + (void) loginfailed(NULL, NULL, NULL, 0); + ], + [ + AC_DEFINE(HAVE_LOGINFAILED, 1, [Define if you have AIX loginfailed function]) + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + ] +) + +AC_MSG_CHECKING(for AIX loginsuccess) +AC_TRY_COMPILE([ + #include + #ifdef HAVE_USERSEC_H + # include + #endif + ], + [ + (void) loginsuccess(NULL, NULL, NULL, NULL); + ], + [ + AC_DEFINE(HAVE_LOGINSUCCESS, 1, [Define if you have AIX loginsuccess function] +) + AC_MSG_RESULT(yes) + ], [ + AC_MSG_RESULT(no) + ] +) + dnl Checks for installation user/group if test x"$install_user" = x; then diff --git a/modules/mod_auth.c b/modules/mod_auth.c index 94c6b49645..3bd628afc1 100644 --- a/modules/mod_auth.c +++ b/modules/mod_auth.c @@ -2,7 +2,7 @@ * ProFTPD - FTP server daemon * Copyright (c) 1997, 1998 Public Flood Software * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu - * Copyright (c) 2001-2016 The ProFTPD Project team + * Copyright (c) 2001-2017 The ProFTPD Project team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,14 @@ #include "conf.h" #include "privs.h" +#ifdef HAVE_USERSEC_H +# include +#endif + +#ifdef HAVE_SYS_AUDIT_H +# include +#endif + extern pid_t mpid; module auth_module; @@ -336,7 +344,34 @@ static int do_auth(pool *p, xaset_t *conf, const char *u, char *pw) { /* Command handlers */ +static void login_failed(pool *p, const char *user) { +#ifdef HAVE_LOGINFAILED + char *host, *sess_ttyname; + int res, xerrno; + + host = pr_netaddr_get_dnsstr(session.c->remote_addr); + sess_ttyname = pr_session_get_ttyname(p); + + PRIVS_ROOT + res = loginfailed((char *) user, host, sess_ttyname, AUDIT_FAIL); + xerrno = errno; + PRIVS_RELINQUISH + + if (res < 0) { + pr_trace_msg("auth", 3, "AIX loginfailed() error for user '%s', " + "host '%s', tty '%s', reason %d: %s", user, host, sess_ttyname, + AUDIT_FAIL, strerror(errno)); + } +#endif /* HAVE_LOGINFAILED */ +} + MODRET auth_err_pass(cmd_rec *cmd) { + const char *user; + + user = pr_table_get(session.notes, "mod_auth.orig-user", NULL); + if (user != NULL) { + login_failed(cmd->tmp_pool, user); + } /* Remove the stashed original USER name here in a LOG_CMD_ERR handler, so * that other modules, who may want to lookup the original USER parameter on @@ -371,6 +406,35 @@ MODRET auth_log_pass(cmd_rec *cmd) { return PR_DECLINED(cmd); } +static void login_succeeded(pool *p, const char *user) { +#ifdef HAVE_LOGINSUCCESS + char *host, *msg = NULL, *sess_ttyname; + int res, xerrno; + + host = pr_netaddr_get_dnsstr(session.c->remote_addr); + sess_ttyname = pr_session_get_ttyname(p); + + PRIVS_ROOT + res = loginsuccess((char *) user, host, sess_ttyname, &msg); + xerrno = errno; + PRIVS_RELINQUISH + + if (res == 0) { + if (msg != NULL) { + pr_trace_msg("auth", 14, "AIX loginsuccess() report: %s", msg); + } + + } else { + pr_trace_msg("auth", 3, "AIX loginsuccess() error for user '%s', " + "host '%s', tty '%s': %s", user, host, sess_ttyname, strerror(errno)); + } + + if (msg != NULL) { + free(msg); + } +#endif /* HAVE_LOGINSUCCESS */ +} + MODRET auth_post_pass(cmd_rec *cmd) { config_rec *c = NULL; const char *grantmsg = NULL, *user; @@ -596,6 +660,8 @@ MODRET auth_post_pass(cmd_rec *cmd) { pr_response_add(auth_pass_resp_code, "%s", grantmsg); } + login_succeeded(cmd->tmp_pool, user); + /* A RootRevoke value of 0 indicates 'false', 1 indicates 'true', and * 2 indicates 'NonCompliantActiveTransfer'. We will drop root privs for any * RootRevoke value greater than 0.