port-aix.c revision 181097
196925Sgrog/* 296925Sgrog * 396925Sgrog * Copyright (c) 2001 Gert Doering. All rights reserved. 496925Sgrog * Copyright (c) 2003,2004,2005 Darren Tucker. All rights reserved. 596925Sgrog * 696925Sgrog * Redistribution and use in source and binary forms, with or without 796925Sgrog * modification, are permitted provided that the following conditions 896925Sgrog * are met: 996925Sgrog * 1. Redistributions of source code must retain the above copyright 1096925Sgrog * notice, this list of conditions and the following disclaimer. 1196925Sgrog * 2. Redistributions in binary form must reproduce the above copyright 1296925Sgrog * notice, this list of conditions and the following disclaimer in the 1396925Sgrog * documentation and/or other materials provided with the distribution. 1496925Sgrog * 1596925Sgrog * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1696925Sgrog * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1796925Sgrog * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1896925Sgrog * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1996925Sgrog * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2096925Sgrog * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2196925Sgrog * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2296925Sgrog * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2396925Sgrog * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2496925Sgrog * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2596925Sgrog * 2696925Sgrog */ 2796925Sgrog#include "includes.h" 2896925Sgrog 2996925Sgrog#include "xmalloc.h" 3096925Sgrog#include "buffer.h" 3196925Sgrog#include "key.h" 3296925Sgrog#include "hostfile.h" 3396925Sgrog#include "auth.h" 3496925Sgrog#include "ssh.h" 3596925Sgrog#include "log.h" 3696925Sgrog 3796925Sgrog#ifdef _AIX 3896924Sgrog 3996924Sgrog#include <errno.h> 4096924Sgrog#if defined(HAVE_NETDB_H) 4196924Sgrog# include <netdb.h> 4296924Sgrog#endif 4396924Sgrog#include <uinfo.h> 4496924Sgrog#include <stdarg.h> 4596924Sgrog#include <string.h> 4696924Sgrog#include <unistd.h> 4796924Sgrog#include <sys/socket.h> 4896924Sgrog 4996924Sgrog#ifdef WITH_AIXAUTHENTICATE 5096924Sgrog# include <login.h> 5196924Sgrog# include <userpw.h> 5296924Sgrog# if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG) 5396924Sgrog# include <sys/audit.h> 5496924Sgrog# endif 5596924Sgrog# include <usersec.h> 5696924Sgrog#endif 5796924Sgrog 5896924Sgrog#include "port-aix.h" 5996924Sgrog 6096924Sgrog# ifdef HAVE_SETAUTHDB 6196924Sgrogstatic char old_registry[REGISTRY_SIZE] = ""; 6296924Sgrog# endif 6396924Sgrog 6496924Sgrog/* 6596924Sgrog * AIX has a "usrinfo" area where logname and other stuff is stored - 6696924Sgrog * a few applications actually use this and die if it's not set 6796924Sgrog * 6896924Sgrog * NOTE: TTY= should be set, but since no one uses it and it's hard to 6996924Sgrog * acquire due to privsep code. We will just drop support. 7096924Sgrog */ 7196924Sgrogvoid 7296924Sgrogaix_usrinfo(struct passwd *pw) 7396924Sgrog{ 7496924Sgrog u_int i; 7596924Sgrog size_t len; 7696924Sgrog char *cp; 7796924Sgrog 7896924Sgrog len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); 7996924Sgrog cp = xmalloc(len); 8096924Sgrog 8196924Sgrog i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 8296924Sgrog pw->pw_name, '\0'); 8396924Sgrog if (usrinfo(SETUINFO, cp, i) == -1) 8496924Sgrog fatal("Couldn't set usrinfo: %s", strerror(errno)); 8596924Sgrog debug3("AIX/UsrInfo: set len %d", i); 8696924Sgrog 8796924Sgrog xfree(cp); 8896924Sgrog} 8996924Sgrog 9096924Sgrog# ifdef WITH_AIXAUTHENTICATE 9196924Sgrog/* 9296924Sgrog * Remove embedded newlines in string (if any). 9396924Sgrog * Used before logging messages returned by AIX authentication functions 9496924Sgrog * so the message is logged on one line. 9596924Sgrog */ 9696924Sgrogvoid 9796924Sgrogaix_remove_embedded_newlines(char *p) 9896924Sgrog{ 9996924Sgrog if (p == NULL) 10096924Sgrog return; 10196924Sgrog 10296924Sgrog for (; *p; p++) { 10396924Sgrog if (*p == '\n') 10496924Sgrog *p = ' '; 10596924Sgrog } 10696924Sgrog /* Remove trailing whitespace */ 10796924Sgrog if (*--p == ' ') 10896924Sgrog *p = '\0'; 10996924Sgrog} 11096924Sgrog 11196924Sgrog/* 11296924Sgrog * Test specifically for the case where SYSTEM == NONE and AUTH1 contains 11396924Sgrog * anything other than NONE or SYSTEM, which indicates that the admin has 11496924Sgrog * configured the account for purely AUTH1-type authentication. 11596924Sgrog * 11696924Sgrog * Since authenticate() doesn't check AUTH1, and sshd can't sanely support 11796924Sgrog * AUTH1 itself, in such a case authenticate() will allow access without 11896924Sgrog * authentation, which is almost certainly not what the admin intends. 11996924Sgrog * 12096924Sgrog * (The native tools, eg login, will process the AUTH1 list in addition to 12196924Sgrog * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods 12296924Sgrog * have been deprecated since AIX 4.2.x and would be very difficult for sshd 12396924Sgrog * to support. 12496924Sgrog * 12596924Sgrog * Returns 0 if an unsupportable combination is found, 1 otherwise. 12696924Sgrog */ 12796924Sgrogstatic int 12896924Sgrogaix_valid_authentications(const char *user) 12996924Sgrog{ 13096924Sgrog char *auth1, *sys, *p; 13196924Sgrog int valid = 1; 13296924Sgrog 13396924Sgrog if (getuserattr((char *)user, S_AUTHSYSTEM, &sys, SEC_CHAR) != 0) { 13496924Sgrog logit("Can't retrieve attribute SYSTEM for %s: %.100s", 13596924Sgrog user, strerror(errno)); 13696924Sgrog return 0; 13796924Sgrog } 13896924Sgrog 13996924Sgrog debug3("AIX SYSTEM attribute %s", sys); 14096924Sgrog if (strcmp(sys, "NONE") != 0) 14196924Sgrog return 1; /* not "NONE", so is OK */ 14296924Sgrog 14396924Sgrog if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) { 14496924Sgrog logit("Can't retrieve attribute auth1 for %s: %.100s", 14596924Sgrog user, strerror(errno)); 14696924Sgrog return 0; 14796924Sgrog } 14896924Sgrog 14996924Sgrog p = auth1; 15096924Sgrog /* A SEC_LIST is concatenated strings, ending with two NULs. */ 15196924Sgrog while (p[0] != '\0' && p[1] != '\0') { 15296924Sgrog debug3("AIX auth1 attribute list member %s", p); 15396924Sgrog if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) { 15496924Sgrog logit("Account %s has unsupported auth1 value '%s'", 15596924Sgrog user, p); 15696924Sgrog valid = 0; 15796924Sgrog } 15896924Sgrog p += strlen(p) + 1; 15996924Sgrog } 16096924Sgrog 16196924Sgrog return (valid); 16296924Sgrog} 16396924Sgrog 16496924Sgrog/* 16596924Sgrog * Do authentication via AIX's authenticate routine. We loop until the 16696924Sgrog * reenter parameter is 0, but normally authenticate is called only once. 16796924Sgrog * 16896924Sgrog * Note: this function returns 1 on success, whereas AIX's authenticate() 16996924Sgrog * returns 0. 17096924Sgrog */ 17196924Sgrogint 17296924Sgrogsys_auth_passwd(Authctxt *ctxt, const char *password) 17396924Sgrog{ 17496924Sgrog char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name; 17596924Sgrog int authsuccess = 0, expired, reenter, result; 17696924Sgrog 17796924Sgrog do { 17896924Sgrog result = authenticate((char *)name, (char *)password, &reenter, 17996924Sgrog &authmsg); 18096924Sgrog aix_remove_embedded_newlines(authmsg); 18196924Sgrog debug3("AIX/authenticate result %d, authmsg %.100s", result, 18296924Sgrog authmsg); 18396924Sgrog } while (reenter); 18496924Sgrog 18596924Sgrog if (!aix_valid_authentications(name)) 18696924Sgrog result = -1; 18796924Sgrog 18896924Sgrog if (result == 0) { 18996924Sgrog authsuccess = 1; 19096924Sgrog 19196924Sgrog /* 19296924Sgrog * Record successful login. We don't have a pty yet, so just 19396924Sgrog * label the line as "ssh" 19496924Sgrog */ 19596924Sgrog aix_setauthdb(name); 19696924Sgrog 19796924Sgrog /* 19896924Sgrog * Check if the user's password is expired. 19996924Sgrog */ 20096924Sgrog expired = passwdexpired(name, &msg); 20196924Sgrog if (msg && *msg) { 20296924Sgrog buffer_append(ctxt->loginmsg, msg, strlen(msg)); 20396924Sgrog aix_remove_embedded_newlines(msg); 20496924Sgrog } 20596924Sgrog debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); 20696924Sgrog 20796924Sgrog switch (expired) { 20896924Sgrog case 0: /* password not expired */ 20996924Sgrog break; 21096924Sgrog case 1: /* expired, password change required */ 21196924Sgrog ctxt->force_pwchange = 1; 21296924Sgrog break; 21396924Sgrog default: /* user can't change(2) or other error (-1) */ 21496924Sgrog logit("Password can't be changed for user %s: %.100s", 21596924Sgrog name, msg); 21696924Sgrog if (msg) 21796924Sgrog xfree(msg); 21896924Sgrog authsuccess = 0; 21996924Sgrog } 22096924Sgrog 22196924Sgrog aix_restoreauthdb(); 22296924Sgrog } 22396924Sgrog 22496924Sgrog if (authmsg != NULL) 22596924Sgrog xfree(authmsg); 22696924Sgrog 22796924Sgrog return authsuccess; 22896924Sgrog} 22996924Sgrog 23096924Sgrog/* 23196924Sgrog * Check if specified account is permitted to log in. 23296924Sgrog * Returns 1 if login is allowed, 0 if not allowed. 23396924Sgrog */ 23496924Sgrogint 23596924Sgrogsys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg) 23696924Sgrog{ 23796924Sgrog char *msg = NULL; 23896924Sgrog int result, permitted = 0; 23996924Sgrog struct stat st; 24096924Sgrog 24196924Sgrog /* 24296924Sgrog * Don't perform checks for root account (PermitRootLogin controls 24396924Sgrog * logins via * ssh) or if running as non-root user (since 24496924Sgrog * loginrestrictions will always fail due to insufficient privilege). 24596924Sgrog */ 24696924Sgrog if (pw->pw_uid == 0 || geteuid() != 0) { 24796924Sgrog debug3("%s: not checking", __func__); 24896924Sgrog return 1; 24996924Sgrog } 25096924Sgrog 25196924Sgrog result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg); 25296924Sgrog if (result == 0) 25396924Sgrog permitted = 1; 25496924Sgrog /* 25596924Sgrog * If restricted because /etc/nologin exists, the login will be denied 25696924Sgrog * in session.c after the nologin message is sent, so allow for now 25796924Sgrog * and do not append the returned message. 25896924Sgrog */ 25996924Sgrog if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) 26096924Sgrog permitted = 1; 26196924Sgrog else if (msg != NULL) 26296924Sgrog buffer_append(loginmsg, msg, strlen(msg)); 26396924Sgrog if (msg == NULL) 26496924Sgrog msg = xstrdup("(none)"); 26596924Sgrog aix_remove_embedded_newlines(msg); 26696924Sgrog debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg); 26796924Sgrog 26896924Sgrog if (!permitted) 26996924Sgrog logit("Login restricted for %s: %.100s", pw->pw_name, msg); 27096924Sgrog xfree(msg); 27196924Sgrog return permitted; 27296924Sgrog} 27396924Sgrog 27496924Sgrogint 27596924Sgrogsys_auth_record_login(const char *user, const char *host, const char *ttynm, 27696924Sgrog Buffer *loginmsg) 27796924Sgrog{ 27896924Sgrog char *msg = NULL; 27996924Sgrog static int msg_done = 0; 28096924Sgrog int success = 0; 28196924Sgrog 28296924Sgrog aix_setauthdb(user); 28396924Sgrog if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) { 28496924Sgrog success = 1; 28596924Sgrog if (msg != NULL && loginmsg != NULL && !msg_done) { 28696924Sgrog debug("AIX/loginsuccess: msg %s", msg); 28796924Sgrog buffer_append(loginmsg, msg, strlen(msg)); 28896924Sgrog xfree(msg); 28996924Sgrog msg_done = 1; 29096924Sgrog } 29196924Sgrog } 29296924Sgrog aix_restoreauthdb(); 29396924Sgrog return (success); 29496924Sgrog} 29596924Sgrog 29696924Sgrog# ifdef CUSTOM_FAILED_LOGIN 29796924Sgrog/* 29896924Sgrog * record_failed_login: generic "login failed" interface function 29996924Sgrog */ 30096924Sgrogvoid 30196924Sgrogrecord_failed_login(const char *user, const char *hostname, const char *ttyname) 30296924Sgrog{ 30396924Sgrog if (geteuid() != 0) 30496924Sgrog return; 30596924Sgrog 30696924Sgrog aix_setauthdb(user); 30796924Sgrog# ifdef AIX_LOGINFAILED_4ARG 30896924Sgrog loginfailed((char *)user, (char *)hostname, (char *)ttyname, 30996924Sgrog AUDIT_FAIL_AUTH); 31096924Sgrog# else 31196924Sgrog loginfailed((char *)user, (char *)hostname, (char *)ttyname); 31296924Sgrog# endif 31396924Sgrog aix_restoreauthdb(); 31496924Sgrog} 31596924Sgrog# endif /* CUSTOM_FAILED_LOGIN */ 31696924Sgrog 31796924Sgrog/* 31896924Sgrog * If we have setauthdb, retrieve the password registry for the user's 31996924Sgrog * account then feed it to setauthdb. This will mean that subsequent AIX auth 32096924Sgrog * functions will only use the specified loadable module. If we don't have 32196924Sgrog * setauthdb this is a no-op. 32296924Sgrog */ 32396924Sgrogvoid 32496924Sgrogaix_setauthdb(const char *user) 32596924Sgrog{ 32696924Sgrog# ifdef HAVE_SETAUTHDB 32796924Sgrog char *registry; 32896924Sgrog 32996924Sgrog if (setuserdb(S_READ) == -1) { 33096924Sgrog debug3("%s: Could not open userdb to read", __func__); 33196924Sgrog return; 33296924Sgrog } 33396924Sgrog 33496924Sgrog if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { 33596924Sgrog if (setauthdb(registry, old_registry) == 0) 33696924Sgrog debug3("AIX/setauthdb set registry '%s'", registry); 33796924Sgrog else 33896924Sgrog debug3("AIX/setauthdb set registry '%s' failed: %s", 33996924Sgrog registry, strerror(errno)); 34096924Sgrog } else 34196924Sgrog debug3("%s: Could not read S_REGISTRY for user: %s", __func__, 34296924Sgrog strerror(errno)); 34396924Sgrog enduserdb(); 34496924Sgrog# endif /* HAVE_SETAUTHDB */ 34596924Sgrog} 34696924Sgrog 34796924Sgrog/* 34896924Sgrog * Restore the user's registry settings from old_registry. 34996924Sgrog * Note that if the first aix_setauthdb fails, setauthdb("") is still safe 35096924Sgrog * (it restores the system default behaviour). If we don't have setauthdb, 35196924Sgrog * this is a no-op. 35296924Sgrog */ 35396924Sgrogvoid 35496924Sgrogaix_restoreauthdb(void) 35596924Sgrog{ 35696924Sgrog# ifdef HAVE_SETAUTHDB 35796924Sgrog if (setauthdb(old_registry, NULL) == 0) 35896924Sgrog debug3("%s: restoring old registry '%s'", __func__, 35996924Sgrog old_registry); 36096924Sgrog else 36196924Sgrog debug3("%s: failed to restore old registry %s", __func__, 362 old_registry); 363# endif /* HAVE_SETAUTHDB */ 364} 365 366# endif /* WITH_AIXAUTHENTICATE */ 367 368# if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) 369# undef getnameinfo 370/* 371 * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros 372 * IPv6 address into its textual representation ("::"), so we wrap it 373 * with a function that will. 374 */ 375int 376sshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 377 size_t hostlen, char *serv, size_t servlen, int flags) 378{ 379 struct sockaddr_in6 *sa6; 380 u_int32_t *a6; 381 382 if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) && 383 sa->sa_family == AF_INET6) { 384 sa6 = (struct sockaddr_in6 *)sa; 385 a6 = sa6->sin6_addr.u6_addr.u6_addr32; 386 387 if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) { 388 strlcpy(host, "::", hostlen); 389 snprintf(serv, servlen, "%d", sa6->sin6_port); 390 return 0; 391 } 392 } 393 return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 394} 395# endif /* AIX_GETNAMEINFO_HACK */ 396 397#endif /* _AIX */ 398