1 /* 2 * 3 * Copyright (c) 2001 Gert Doering. All rights reserved. 4 * Copyright (c) 2003,2004,2005 Darren Tucker. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 */ 27 #include "includes.h" 28 29 #include "xmalloc.h" 30 #include "buffer.h" 31 #include "key.h" 32 #include "hostfile.h" 33 #include "auth.h" 34 #include "ssh.h" 35 #include "log.h" 36 37 #ifdef _AIX 38 39 #include <errno.h> 40 #if defined(HAVE_NETDB_H) 41 # include <netdb.h> 42 #endif 43 #include <uinfo.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <sys/socket.h> 47 #include "port-aix.h" 48 49 # ifdef HAVE_SETAUTHDB 50 static char old_registry[REGISTRY_SIZE] = ""; 51 # endif 52 53 /* 54 * AIX has a "usrinfo" area where logname and other stuff is stored - 55 * a few applications actually use this and die if it's not set 56 * 57 * NOTE: TTY= should be set, but since no one uses it and it's hard to 58 * acquire due to privsep code. We will just drop support. 59 */ 60 void 61 aix_usrinfo(struct passwd *pw) 62 { 63 u_int i; 64 size_t len; 65 char *cp; 66 67 len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); 68 cp = xmalloc(len); 69 70 i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 71 pw->pw_name, '\0'); 72 if (usrinfo(SETUINFO, cp, i) == -1) 73 fatal("Couldn't set usrinfo: %s", strerror(errno)); 74 debug3("AIX/UsrInfo: set len %d", i); 75 76 xfree(cp); 77 } 78 79 # ifdef WITH_AIXAUTHENTICATE 80 /* 81 * Remove embedded newlines in string (if any). 82 * Used before logging messages returned by AIX authentication functions 83 * so the message is logged on one line. 84 */ 85 void 86 aix_remove_embedded_newlines(char *p) 87 { 88 if (p == NULL) 89 return; 90 91 for (; *p; p++) { 92 if (*p == '\n') 93 *p = ' '; 94 } 95 /* Remove trailing whitespace */ 96 if (*--p == ' ') 97 *p = '\0'; 98 } 99 100 /* 101 * Test specifically for the case where SYSTEM == NONE and AUTH1 contains 102 * anything other than NONE or SYSTEM, which indicates that the admin has 103 * configured the account for purely AUTH1-type authentication. 104 * 105 * Since authenticate() doesn't check AUTH1, and sshd can't sanely support 106 * AUTH1 itself, in such a case authenticate() will allow access without 107 * authentation, which is almost certainly not what the admin intends. 108 * 109 * (The native tools, eg login, will process the AUTH1 list in addition to 110 * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods 111 * have been deprecated since AIX 4.2.x and would be very difficult for sshd 112 * to support. 113 * 114 * Returns 0 if an unsupportable combination is found, 1 otherwise. 115 */ 116 static int 117 aix_valid_authentications(const char *user) 118 { 119 char *auth1, *sys, *p; 120 int valid = 1; 121 122 if (getuserattr((char *)user, S_AUTHSYSTEM, &sys, SEC_CHAR) != 0) { 123 logit("Can't retrieve attribute SYSTEM for %s: %.100s", 124 user, strerror(errno)); 125 return 0; 126 } 127 128 debug3("AIX SYSTEM attribute %s", sys); 129 if (strcmp(sys, "NONE") != 0) 130 return 1; /* not "NONE", so is OK */ 131 132 if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) { 133 logit("Can't retrieve attribute auth1 for %s: %.100s", 134 user, strerror(errno)); 135 return 0; 136 } 137 138 p = auth1; 139 /* A SEC_LIST is concatenated strings, ending with two NULs. */ 140 while (p[0] != '\0' && p[1] != '\0') { 141 debug3("AIX auth1 attribute list member %s", p); 142 if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) { 143 logit("Account %s has unsupported auth1 value '%s'", 144 user, p); 145 valid = 0; 146 } 147 p += strlen(p) + 1; 148 } 149 150 return (valid); 151 } 152 153 /* 154 * Do authentication via AIX's authenticate routine. We loop until the 155 * reenter parameter is 0, but normally authenticate is called only once. 156 * 157 * Note: this function returns 1 on success, whereas AIX's authenticate() 158 * returns 0. 159 */ 160 int 161 sys_auth_passwd(Authctxt *ctxt, const char *password) 162 { 163 char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name; 164 int authsuccess = 0, expired, reenter, result; 165 166 do { 167 result = authenticate((char *)name, (char *)password, &reenter, 168 &authmsg); 169 aix_remove_embedded_newlines(authmsg); 170 debug3("AIX/authenticate result %d, authmsg %.100s", result, 171 authmsg); 172 } while (reenter); 173 174 if (!aix_valid_authentications(name)) 175 result = -1; 176 177 if (result == 0) { 178 authsuccess = 1; 179 180 /* 181 * Record successful login. We don't have a pty yet, so just 182 * label the line as "ssh" 183 */ 184 aix_setauthdb(name); 185 186 /* 187 * Check if the user's password is expired. 188 */ 189 expired = passwdexpired(name, &msg); 190 if (msg && *msg) { 191 buffer_append(ctxt->loginmsg, msg, strlen(msg)); 192 aix_remove_embedded_newlines(msg); 193 } 194 debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); 195 196 switch (expired) { 197 case 0: /* password not expired */ 198 break; 199 case 1: /* expired, password change required */ 200 ctxt->force_pwchange = 1; 201 break; 202 default: /* user can't change(2) or other error (-1) */ 203 logit("Password can't be changed for user %s: %.100s", 204 name, msg); 205 if (msg) 206 xfree(msg); 207 authsuccess = 0; 208 } 209 210 aix_restoreauthdb(); 211 } 212 213 if (authmsg != NULL) 214 xfree(authmsg); 215 216 return authsuccess; 217 } 218 219 /* 220 * Check if specified account is permitted to log in. 221 * Returns 1 if login is allowed, 0 if not allowed. 222 */ 223 int 224 sys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg) 225 { 226 char *msg = NULL; 227 int result, permitted = 0; 228 struct stat st; 229 230 /* 231 * Don't perform checks for root account (PermitRootLogin controls 232 * logins via * ssh) or if running as non-root user (since 233 * loginrestrictions will always fail due to insufficient privilege). 234 */ 235 if (pw->pw_uid == 0 || geteuid() != 0) { 236 debug3("%s: not checking", __func__); 237 return 1; 238 } 239 240 result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg); 241 if (result == 0) 242 permitted = 1; 243 /* 244 * If restricted because /etc/nologin exists, the login will be denied 245 * in session.c after the nologin message is sent, so allow for now 246 * and do not append the returned message. 247 */ 248 if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) 249 permitted = 1; 250 else if (msg != NULL) 251 buffer_append(loginmsg, msg, strlen(msg)); 252 if (msg == NULL) 253 msg = xstrdup("(none)"); 254 aix_remove_embedded_newlines(msg); 255 debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg); 256 257 if (!permitted) 258 logit("Login restricted for %s: %.100s", pw->pw_name, msg); 259 xfree(msg); 260 return permitted; 261 } 262 263 int 264 sys_auth_record_login(const char *user, const char *host, const char *ttynm, 265 Buffer *loginmsg) 266 { 267 char *msg = NULL; 268 int success = 0; 269 270 aix_setauthdb(user); 271 if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) { 272 success = 1; 273 if (msg != NULL) { 274 debug("AIX/loginsuccess: msg %s", msg); 275 buffer_append(loginmsg, msg, strlen(msg)); 276 xfree(msg); 277 } 278 } 279 aix_restoreauthdb(); 280 return (success); 281 } 282 283 # ifdef CUSTOM_FAILED_LOGIN 284 /* 285 * record_failed_login: generic "login failed" interface function 286 */ 287 void 288 record_failed_login(const char *user, const char *hostname, const char *ttyname) 289 { 290 if (geteuid() != 0) 291 return; 292 293 aix_setauthdb(user); 294 # ifdef AIX_LOGINFAILED_4ARG 295 loginfailed((char *)user, (char *)hostname, (char *)ttyname, 296 AUDIT_FAIL_AUTH); 297 # else 298 loginfailed((char *)user, (char *)hostname, (char *)ttyname); 299 # endif 300 aix_restoreauthdb(); 301 } 302 # endif /* CUSTOM_FAILED_LOGIN */ 303 304 /* 305 * If we have setauthdb, retrieve the password registry for the user's 306 * account then feed it to setauthdb. This will mean that subsequent AIX auth 307 * functions will only use the specified loadable module. If we don't have 308 * setauthdb this is a no-op. 309 */ 310 void 311 aix_setauthdb(const char *user) 312 { 313 # ifdef HAVE_SETAUTHDB 314 char *registry; 315 316 if (setuserdb(S_READ) == -1) { 317 debug3("%s: Could not open userdb to read", __func__); 318 return; 319 } 320 321 if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { 322 if (setauthdb(registry, old_registry) == 0) 323 debug3("AIX/setauthdb set registry '%s'", registry); 324 else 325 debug3("AIX/setauthdb set registry '%s' failed: %s", 326 registry, strerror(errno)); 327 } else 328 debug3("%s: Could not read S_REGISTRY for user: %s", __func__, 329 strerror(errno)); 330 enduserdb(); 331 # endif /* HAVE_SETAUTHDB */ 332 } 333 334 /* 335 * Restore the user's registry settings from old_registry. 336 * Note that if the first aix_setauthdb fails, setauthdb("") is still safe 337 * (it restores the system default behaviour). If we don't have setauthdb, 338 * this is a no-op. 339 */ 340 void 341 aix_restoreauthdb(void) 342 { 343 # ifdef HAVE_SETAUTHDB 344 if (setauthdb(old_registry, NULL) == 0) 345 debug3("%s: restoring old registry '%s'", __func__, 346 old_registry); 347 else 348 debug3("%s: failed to restore old registry %s", __func__, 349 old_registry); 350 # endif /* HAVE_SETAUTHDB */ 351 } 352 353 # endif /* WITH_AIXAUTHENTICATE */ 354 355 # if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) 356 # undef getnameinfo 357 /* 358 * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros 359 * IPv6 address into its textual representation ("::"), so we wrap it 360 * with a function that will. 361 */ 362 int 363 sshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 364 size_t hostlen, char *serv, size_t servlen, int flags) 365 { 366 struct sockaddr_in6 *sa6; 367 u_int32_t *a6; 368 369 if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) && 370 sa->sa_family == AF_INET6) { 371 sa6 = (struct sockaddr_in6 *)sa; 372 a6 = sa6->sin6_addr.u6_addr.u6_addr32; 373 374 if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) { 375 strlcpy(host, "::", hostlen); 376 snprintf(serv, servlen, "%d", sa6->sin6_port); 377 return 0; 378 } 379 } 380 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 381 } 382 # endif /* AIX_GETNAMEINFO_HACK */ 383 384 #endif /* _AIX */ 385