1 /* 2 * 3 * Copyright (c) 2001 Gert Doering. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 #include "includes.h" 27 #include "auth.h" 28 #include "ssh.h" 29 #include "log.h" 30 #include "servconf.h" 31 #include "canohost.h" 32 #include "xmalloc.h" 33 #include "buffer.h" 34 35 #ifdef _AIX 36 37 #include <uinfo.h> 38 #include "port-aix.h" 39 40 extern ServerOptions options; 41 extern Buffer loginmsg; 42 43 # ifdef HAVE_SETAUTHDB 44 static char old_registry[REGISTRY_SIZE] = ""; 45 # endif 46 47 /* 48 * AIX has a "usrinfo" area where logname and other stuff is stored - 49 * a few applications actually use this and die if it's not set 50 * 51 * NOTE: TTY= should be set, but since no one uses it and it's hard to 52 * acquire due to privsep code. We will just drop support. 53 */ 54 void 55 aix_usrinfo(struct passwd *pw) 56 { 57 u_int i; 58 size_t len; 59 char *cp; 60 61 len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); 62 cp = xmalloc(len); 63 64 i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 65 pw->pw_name, '\0'); 66 if (usrinfo(SETUINFO, cp, i) == -1) 67 fatal("Couldn't set usrinfo: %s", strerror(errno)); 68 debug3("AIX/UsrInfo: set len %d", i); 69 70 xfree(cp); 71 } 72 73 # ifdef WITH_AIXAUTHENTICATE 74 /* 75 * Remove embedded newlines in string (if any). 76 * Used before logging messages returned by AIX authentication functions 77 * so the message is logged on one line. 78 */ 79 void 80 aix_remove_embedded_newlines(char *p) 81 { 82 if (p == NULL) 83 return; 84 85 for (; *p; p++) { 86 if (*p == '\n') 87 *p = ' '; 88 } 89 /* Remove trailing whitespace */ 90 if (*--p == ' ') 91 *p = '\0'; 92 } 93 94 /* 95 * Do authentication via AIX's authenticate routine. We loop until the 96 * reenter parameter is 0, but normally authenticate is called only once. 97 * 98 * Note: this function returns 1 on success, whereas AIX's authenticate() 99 * returns 0. 100 */ 101 int 102 sys_auth_passwd(Authctxt *ctxt, const char *password) 103 { 104 char *authmsg = NULL, *host, *msg, *name = ctxt->pw->pw_name; 105 int authsuccess = 0, expired, reenter, result; 106 107 do { 108 result = authenticate((char *)name, (char *)password, &reenter, 109 &authmsg); 110 aix_remove_embedded_newlines(authmsg); 111 debug3("AIX/authenticate result %d, msg %.100s", result, 112 authmsg); 113 } while (reenter); 114 115 if (result == 0) { 116 authsuccess = 1; 117 118 host = (char *)get_canonical_hostname(options.use_dns); 119 120 /* 121 * Record successful login. We don't have a pty yet, so just 122 * label the line as "ssh" 123 */ 124 aix_setauthdb(name); 125 if (loginsuccess((char *)name, (char *)host, "ssh", &msg) == 0) { 126 if (msg != NULL) { 127 debug("%s: msg %s", __func__, msg); 128 buffer_append(&loginmsg, msg, strlen(msg)); 129 xfree(msg); 130 } 131 } 132 133 /* 134 * Check if the user's password is expired. 135 */ 136 expired = passwdexpired(name, &msg); 137 if (msg && *msg) { 138 buffer_append(&loginmsg, msg, strlen(msg)); 139 aix_remove_embedded_newlines(msg); 140 } 141 debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); 142 143 switch (expired) { 144 case 0: /* password not expired */ 145 break; 146 case 1: /* expired, password change required */ 147 ctxt->force_pwchange = 1; 148 disable_forwarding(); 149 break; 150 default: /* user can't change(2) or other error (-1) */ 151 logit("Password can't be changed for user %s: %.100s", 152 name, msg); 153 if (msg) 154 xfree(msg); 155 authsuccess = 0; 156 } 157 158 aix_restoreauthdb(); 159 } 160 161 if (authmsg != NULL) 162 xfree(authmsg); 163 164 return authsuccess; 165 } 166 167 # ifdef CUSTOM_FAILED_LOGIN 168 /* 169 * record_failed_login: generic "login failed" interface function 170 */ 171 void 172 record_failed_login(const char *user, const char *ttyname) 173 { 174 char *hostname = (char *)get_canonical_hostname(options.use_dns); 175 176 if (geteuid() != 0) 177 return; 178 179 aix_setauthdb(user); 180 # ifdef AIX_LOGINFAILED_4ARG 181 loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH); 182 # else 183 loginfailed((char *)user, hostname, (char *)ttyname); 184 # endif 185 aix_restoreauthdb(); 186 } 187 # endif /* CUSTOM_FAILED_LOGIN */ 188 189 /* 190 * If we have setauthdb, retrieve the password registry for the user's 191 * account then feed it to setauthdb. This will mean that subsequent AIX auth 192 * functions will only use the specified loadable module. If we don't have 193 * setauthdb this is a no-op. 194 */ 195 void 196 aix_setauthdb(const char *user) 197 { 198 # ifdef HAVE_SETAUTHDB 199 char *registry; 200 201 if (setuserdb(S_READ) == -1) { 202 debug3("%s: Could not open userdb to read", __func__); 203 return; 204 } 205 206 if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { 207 if (setauthdb(registry, old_registry) == 0) 208 debug3("AIX/setauthdb set registry '%s'", registry); 209 else 210 debug3("AIX/setauthdb set registry '%s' failed: %s", 211 registry, strerror(errno)); 212 } else 213 debug3("%s: Could not read S_REGISTRY for user: %s", __func__, 214 strerror(errno)); 215 enduserdb(); 216 # endif /* HAVE_SETAUTHDB */ 217 } 218 219 /* 220 * Restore the user's registry settings from old_registry. 221 * Note that if the first aix_setauthdb fails, setauthdb("") is still safe 222 * (it restores the system default behaviour). If we don't have setauthdb, 223 * this is a no-op. 224 */ 225 void 226 aix_restoreauthdb(void) 227 { 228 # ifdef HAVE_SETAUTHDB 229 if (setauthdb(old_registry, NULL) == 0) 230 debug3("%s: restoring old registry '%s'", __func__, 231 old_registry); 232 else 233 debug3("%s: failed to restore old registry %s", __func__, 234 old_registry); 235 # endif /* HAVE_SETAUTHDB */ 236 } 237 238 # endif /* WITH_AIXAUTHENTICATE */ 239 240 #endif /* _AIX */ 241