X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/d03f42626b290c7c9839e1ecb27dfb069e76a396..2fff96d8cea95213d66e7ba65e36cae6adcf403a:/openssh/openbsd-compat/port-aix.c diff --git a/openssh/openbsd-compat/port-aix.c b/openssh/openbsd-compat/port-aix.c index 4c96a31..2895f0d 100644 --- a/openssh/openbsd-compat/port-aix.c +++ b/openssh/openbsd-compat/port-aix.c @@ -24,11 +24,25 @@ * */ #include "includes.h" +#include "auth.h" +#include "ssh.h" +#include "log.h" +#include "servconf.h" +#include "canohost.h" +#include "xmalloc.h" +#include "buffer.h" #ifdef _AIX #include -#include <../xmalloc.h> +#include "port-aix.h" + +extern ServerOptions options; +extern Buffer loginmsg; + +# ifdef HAVE_SETAUTHDB +static char old_registry[REGISTRY_SIZE] = ""; +# endif /* * AIX has a "usrinfo" area where logname and other stuff is stored - @@ -41,16 +55,186 @@ void aix_usrinfo(struct passwd *pw) { u_int i; + size_t len; char *cp; - cp = xmalloc(16 + 2 * strlen(pw->pw_name)); - i = sprintf(cp, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, 0, - pw->pw_name, 0); + len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); + cp = xmalloc(len); + + i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', + pw->pw_name, '\0'); if (usrinfo(SETUINFO, cp, i) == -1) fatal("Couldn't set usrinfo: %s", strerror(errno)); debug3("AIX/UsrInfo: set len %d", i); + xfree(cp); } -#endif /* _AIX */ +# ifdef WITH_AIXAUTHENTICATE +/* + * Remove embedded newlines in string (if any). + * Used before logging messages returned by AIX authentication functions + * so the message is logged on one line. + */ +void +aix_remove_embedded_newlines(char *p) +{ + if (p == NULL) + return; + + for (; *p; p++) { + if (*p == '\n') + *p = ' '; + } + /* Remove trailing whitespace */ + if (*--p == ' ') + *p = '\0'; +} + +/* + * Do authentication via AIX's authenticate routine. We loop until the + * reenter parameter is 0, but normally authenticate is called only once. + * + * Note: this function returns 1 on success, whereas AIX's authenticate() + * returns 0. + */ +int +sys_auth_passwd(Authctxt *ctxt, const char *password) +{ + char *authmsg = NULL, *host, *msg, *name = ctxt->pw->pw_name; + int authsuccess = 0, expired, reenter, result; + + do { + result = authenticate((char *)name, (char *)password, &reenter, + &authmsg); + aix_remove_embedded_newlines(authmsg); + debug3("AIX/authenticate result %d, msg %.100s", result, + authmsg); + } while (reenter); + + if (result == 0) { + authsuccess = 1; + + host = (char *)get_canonical_hostname(options.use_dns); + + /* + * Record successful login. We don't have a pty yet, so just + * label the line as "ssh" + */ + aix_setauthdb(name); + if (loginsuccess((char *)name, (char *)host, "ssh", &msg) == 0) { + if (msg != NULL) { + debug("%s: msg %s", __func__, msg); + buffer_append(&loginmsg, msg, strlen(msg)); + xfree(msg); + } + } + + /* + * Check if the user's password is expired. + */ + expired = passwdexpired(name, &msg); + if (msg && *msg) { + buffer_append(&loginmsg, msg, strlen(msg)); + aix_remove_embedded_newlines(msg); + } + debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); + + switch (expired) { + case 0: /* password not expired */ + break; + case 1: /* expired, password change required */ + ctxt->force_pwchange = 1; + disable_forwarding(); + break; + default: /* user can't change(2) or other error (-1) */ + logit("Password can't be changed for user %s: %.100s", + name, msg); + if (msg) + xfree(msg); + authsuccess = 0; + } + + aix_restoreauthdb(); + } + + if (authmsg != NULL) + xfree(authmsg); + return authsuccess; +} + +# ifdef CUSTOM_FAILED_LOGIN +/* + * record_failed_login: generic "login failed" interface function + */ +void +record_failed_login(const char *user, const char *ttyname) +{ + char *hostname = (char *)get_canonical_hostname(options.use_dns); + + if (geteuid() != 0) + return; + + aix_setauthdb(user); +# ifdef AIX_LOGINFAILED_4ARG + loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH); +# else + loginfailed((char *)user, hostname, (char *)ttyname); +# endif + aix_restoreauthdb(); +} +# endif /* CUSTOM_FAILED_LOGIN */ + +/* + * If we have setauthdb, retrieve the password registry for the user's + * account then feed it to setauthdb. This will mean that subsequent AIX auth + * functions will only use the specified loadable module. If we don't have + * setauthdb this is a no-op. + */ +void +aix_setauthdb(const char *user) +{ +# ifdef HAVE_SETAUTHDB + char *registry; + + if (setuserdb(S_READ) == -1) { + debug3("%s: Could not open userdb to read", __func__); + return; + } + + if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { + if (setauthdb(registry, old_registry) == 0) + debug3("AIX/setauthdb set registry '%s'", registry); + else + debug3("AIX/setauthdb set registry '%s' failed: %s", + registry, strerror(errno)); + } else + debug3("%s: Could not read S_REGISTRY for user: %s", __func__, + strerror(errno)); + enduserdb(); +# endif /* HAVE_SETAUTHDB */ +} + +/* + * Restore the user's registry settings from old_registry. + * Note that if the first aix_setauthdb fails, setauthdb("") is still safe + * (it restores the system default behaviour). If we don't have setauthdb, + * this is a no-op. + */ +void +aix_restoreauthdb(void) +{ +# ifdef HAVE_SETAUTHDB + if (setauthdb(old_registry, NULL) == 0) + debug3("%s: restoring old registry '%s'", __func__, + old_registry); + else + debug3("%s: failed to restore old registry %s", __func__, + old_registry); +# endif /* HAVE_SETAUTHDB */ +} + +# endif /* WITH_AIXAUTHENTICATE */ + +#endif /* _AIX */