port-aix.c revision 126274
159024Sobrien/* 278828Sobrien * 3218822Sdim * Copyright (c) 2001 Gert Doering. All rights reserved. 459024Sobrien * 559024Sobrien * Redistribution and use in source and binary forms, with or without 6218822Sdim * modification, are permitted provided that the following conditions 759024Sobrien * are met: 8218822Sdim * 1. Redistributions of source code must retain the above copyright 9218822Sdim * notice, this list of conditions and the following disclaimer. 10218822Sdim * 2. Redistributions in binary form must reproduce the above copyright 11218822Sdim * notice, this list of conditions and the following disclaimer in the 1259024Sobrien * documentation and/or other materials provided with the distribution. 13218822Sdim * 14218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15218822Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16218822Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1759024Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19218822Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20218822Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21218822Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2259024Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2359024Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2459024Sobrien * 2559024Sobrien */ 2659024Sobrien#include "includes.h" 2759024Sobrien#include "auth.h" 2860484Sobrien#include "ssh.h" 2959024Sobrien#include "log.h" 3059024Sobrien#include "servconf.h" 3159024Sobrien#include "canohost.h" 3259024Sobrien#include "xmalloc.h" 3359024Sobrien#include "buffer.h" 3459024Sobrien 3559024Sobrien#ifdef _AIX 3659024Sobrien 3759024Sobrien#include <uinfo.h> 3859024Sobrien#include "port-aix.h" 3977298Sobrien 4059024Sobrienextern ServerOptions options; 4159024Sobrienextern Buffer loginmsg; 4259024Sobrien 4359024Sobrien# ifdef HAVE_SETAUTHDB 4477298Sobrienstatic char old_registry[REGISTRY_SIZE] = ""; 45218822Sdim# endif 4659024Sobrien 4777298Sobrien/* 4859024Sobrien * AIX has a "usrinfo" area where logname and other stuff is stored - 4977298Sobrien * a few applications actually use this and die if it's not set 5059024Sobrien * 5159024Sobrien * NOTE: TTY= should be set, but since no one uses it and it's hard to 5259024Sobrien * acquire due to privsep code. We will just drop support. 5359024Sobrien */ 5459024Sobrienvoid 5559024Sobrienaix_usrinfo(struct passwd *pw) 5677298Sobrien{ 5777298Sobrien u_int i; 5859024Sobrien size_t len; 5959024Sobrien char *cp; 6077298Sobrien 6177298Sobrien len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); 6277298Sobrien cp = xmalloc(len); 63218822Sdim 6459024Sobrien i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 6559024Sobrien pw->pw_name, '\0'); 6659024Sobrien if (usrinfo(SETUINFO, cp, i) == -1) 67218822Sdim fatal("Couldn't set usrinfo: %s", strerror(errno)); 6859024Sobrien debug3("AIX/UsrInfo: set len %d", i); 6959024Sobrien 7059024Sobrien xfree(cp); 7159024Sobrien} 7259024Sobrien 73218822Sdim# ifdef WITH_AIXAUTHENTICATE 74218822Sdim/* 7559024Sobrien * Remove embedded newlines in string (if any). 7659024Sobrien * Used before logging messages returned by AIX authentication functions 7759024Sobrien * so the message is logged on one line. 7859024Sobrien */ 7959024Sobrienvoid 8059024Sobrienaix_remove_embedded_newlines(char *p) 8159024Sobrien{ 8259024Sobrien if (p == NULL) 8359024Sobrien return; 8477298Sobrien 8577298Sobrien for (; *p; p++) { 8659024Sobrien if (*p == '\n') 8759024Sobrien *p = ' '; 8859024Sobrien } 8959024Sobrien /* Remove trailing whitespace */ 9059024Sobrien if (*--p == ' ') 9159024Sobrien *p = '\0'; 92218822Sdim} 9359024Sobrien 9459024Sobrien/* 9559024Sobrien * Do authentication via AIX's authenticate routine. We loop until the 9659024Sobrien * reenter parameter is 0, but normally authenticate is called only once. 97218822Sdim * 98218822Sdim * Note: this function returns 1 on success, whereas AIX's authenticate() 9959024Sobrien * returns 0. 10059024Sobrien */ 10159024Sobrienint 10259024Sobriensys_auth_passwd(Authctxt *ctxt, const char *password) 10359024Sobrien{ 104218822Sdim char *authmsg = NULL, *host, *msg, *name = ctxt->pw->pw_name; 10559024Sobrien int authsuccess = 0, expired, reenter, result; 10659024Sobrien 107218822Sdim do { 10859024Sobrien result = authenticate((char *)name, (char *)password, &reenter, 10959024Sobrien &authmsg); 110218822Sdim aix_remove_embedded_newlines(authmsg); 11159024Sobrien debug3("AIX/authenticate result %d, msg %.100s", result, 112218822Sdim authmsg); 113218822Sdim } while (reenter); 114218822Sdim 115218822Sdim if (result == 0) { 116218822Sdim authsuccess = 1; 117218822Sdim 118218822Sdim host = (char *)get_canonical_hostname(options.use_dns); 119218822Sdim 120218822Sdim /* 121218822Sdim * Record successful login. We don't have a pty yet, so just 122218822Sdim * label the line as "ssh" 123218822Sdim */ 124218822Sdim aix_setauthdb(name); 125218822Sdim if (loginsuccess((char *)name, (char *)host, "ssh", &msg) == 0) { 126218822Sdim if (msg != NULL) { 127218822Sdim debug("%s: msg %s", __func__, msg); 12859024Sobrien buffer_append(&loginmsg, msg, strlen(msg)); 12959024Sobrien xfree(msg); 13059024Sobrien } 13159024Sobrien } 13259024Sobrien 13359024Sobrien /* 134218822Sdim * Check if the user's password is expired. 135218822Sdim */ 136218822Sdim expired = passwdexpired(name, &msg); 137218822Sdim if (msg && *msg) { 138218822Sdim buffer_append(&loginmsg, msg, strlen(msg)); 139218822Sdim aix_remove_embedded_newlines(msg); 140218822Sdim } 141218822Sdim debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); 142218822Sdim 143218822Sdim switch (expired) { 144218822Sdim case 0: /* password not expired */ 145218822Sdim break; 146218822Sdim case 1: /* expired, password change required */ 147218822Sdim ctxt->force_pwchange = 1; 148218822Sdim disable_forwarding(); 149218822Sdim break; 15059024Sobrien default: /* user can't change(2) or other error (-1) */ 15159024Sobrien logit("Password can't be changed for user %s: %.100s", 15259024Sobrien name, msg); 15359024Sobrien if (msg) 154218822Sdim xfree(msg); 155218822Sdim authsuccess = 0; 156218822Sdim } 157218822Sdim 15859024Sobrien aix_restoreauthdb(); 15959024Sobrien } 160218822Sdim 16159024Sobrien if (authmsg != NULL) 16259024Sobrien xfree(authmsg); 16359024Sobrien 164218822Sdim return authsuccess; 16559024Sobrien} 16659024Sobrien 16759024Sobrien# ifdef CUSTOM_FAILED_LOGIN 16859024Sobrien/* 16959024Sobrien * record_failed_login: generic "login failed" interface function 17059024Sobrien */ 17159024Sobrienvoid 17259024Sobrienrecord_failed_login(const char *user, const char *ttyname) 17359024Sobrien{ 17459024Sobrien char *hostname = (char *)get_canonical_hostname(options.use_dns); 17559024Sobrien 17659024Sobrien if (geteuid() != 0) 17759024Sobrien return; 17859024Sobrien 17959024Sobrien aix_setauthdb(user); 18059024Sobrien# ifdef AIX_LOGINFAILED_4ARG 18159024Sobrien loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH); 18259024Sobrien# else 18359024Sobrien loginfailed((char *)user, hostname, (char *)ttyname); 18459024Sobrien# endif 18559024Sobrien aix_restoreauthdb(); 18659024Sobrien} 18759024Sobrien# endif /* CUSTOM_FAILED_LOGIN */ 18859024Sobrien 18959024Sobrien/* 19059024Sobrien * If we have setauthdb, retrieve the password registry for the user's 19159024Sobrien * account then feed it to setauthdb. This will mean that subsequent AIX auth 19259024Sobrien * functions will only use the specified loadable module. If we don't have 19359024Sobrien * setauthdb this is a no-op. 19459024Sobrien */ 19559024Sobrienvoid 19659024Sobrienaix_setauthdb(const char *user) 19759024Sobrien{ 19859024Sobrien# ifdef HAVE_SETAUTHDB 19959024Sobrien char *registry; 20059024Sobrien 20159024Sobrien if (setuserdb(S_READ) == -1) { 20259024Sobrien debug3("%s: Could not open userdb to read", __func__); 20359024Sobrien return; 20459024Sobrien } 20559024Sobrien 20659024Sobrien if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { 20759024Sobrien if (setauthdb(registry, old_registry) == 0) 20859024Sobrien debug3("AIX/setauthdb set registry '%s'", registry); 20959024Sobrien else 21059024Sobrien debug3("AIX/setauthdb set registry '%s' failed: %s", 21159024Sobrien registry, strerror(errno)); 21259024Sobrien } else 21359024Sobrien debug3("%s: Could not read S_REGISTRY for user: %s", __func__, 21459024Sobrien strerror(errno)); 21559024Sobrien enduserdb(); 21659024Sobrien# endif /* HAVE_SETAUTHDB */ 21759024Sobrien} 21859024Sobrien 21959024Sobrien/* 22059024Sobrien * Restore the user's registry settings from old_registry. 22159024Sobrien * Note that if the first aix_setauthdb fails, setauthdb("") is still safe 22259024Sobrien * (it restores the system default behaviour). If we don't have setauthdb, 22359024Sobrien * this is a no-op. 22459024Sobrien */ 22559024Sobrienvoid 22659024Sobrienaix_restoreauthdb(void) 22759024Sobrien{ 22859024Sobrien# ifdef HAVE_SETAUTHDB 22959024Sobrien if (setauthdb(old_registry, NULL) == 0) 23059024Sobrien debug3("%s: restoring old registry '%s'", __func__, 23159024Sobrien old_registry); 23259024Sobrien else 23359024Sobrien debug3("%s: failed to restore old registry %s", __func__, 23459024Sobrien old_registry); 23559024Sobrien# endif /* HAVE_SETAUTHDB */ 23659024Sobrien} 23759024Sobrien 23859024Sobrien# endif /* WITH_AIXAUTHENTICATE */ 23959024Sobrien 24059024Sobrien#endif /* _AIX */ 24159024Sobrien