1106121Sdes/* 2106121Sdes * 3106121Sdes * Copyright (c) 2001 Gert Doering. All rights reserved. 4181111Sdes * Copyright (c) 2003,2004,2005,2006 Darren Tucker. All rights reserved. 5106121Sdes * 6106121Sdes * Redistribution and use in source and binary forms, with or without 7106121Sdes * modification, are permitted provided that the following conditions 8106121Sdes * are met: 9106121Sdes * 1. Redistributions of source code must retain the above copyright 10106121Sdes * notice, this list of conditions and the following disclaimer. 11106121Sdes * 2. Redistributions in binary form must reproduce the above copyright 12106121Sdes * notice, this list of conditions and the following disclaimer in the 13106121Sdes * documentation and/or other materials provided with the distribution. 14106121Sdes * 15106121Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16106121Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17106121Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18106121Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19106121Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20106121Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21106121Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22106121Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23106121Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24106121Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25106121Sdes * 26106121Sdes */ 2798937Sdes#include "includes.h" 28162852Sdes 29162852Sdes#include "xmalloc.h" 30162852Sdes#include "buffer.h" 31162852Sdes#include "key.h" 32162852Sdes#include "hostfile.h" 33126274Sdes#include "auth.h" 34124208Sdes#include "ssh.h" 35124208Sdes#include "log.h" 3698937Sdes 3798937Sdes#ifdef _AIX 3898937Sdes 39162852Sdes#include <errno.h> 40162852Sdes#if defined(HAVE_NETDB_H) 41162852Sdes# include <netdb.h> 42162852Sdes#endif 4398937Sdes#include <uinfo.h> 44162852Sdes#include <stdarg.h> 45162852Sdes#include <string.h> 46162852Sdes#include <unistd.h> 47146998Sdes#include <sys/socket.h> 48162852Sdes 49162852Sdes#ifdef WITH_AIXAUTHENTICATE 50162852Sdes# include <login.h> 51162852Sdes# include <userpw.h> 52162852Sdes# if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG) 53162852Sdes# include <sys/audit.h> 54162852Sdes# endif 55162852Sdes# include <usersec.h> 56162852Sdes#endif 57162852Sdes 58124208Sdes#include "port-aix.h" 5998937Sdes 60197679Sdesstatic char *lastlogin_msg = NULL; 61197679Sdes 62126274Sdes# ifdef HAVE_SETAUTHDB 63126274Sdesstatic char old_registry[REGISTRY_SIZE] = ""; 64126274Sdes# endif 65126274Sdes 6698937Sdes/* 67149749Sdes * AIX has a "usrinfo" area where logname and other stuff is stored - 68106121Sdes * a few applications actually use this and die if it's not set 69106121Sdes * 70106121Sdes * NOTE: TTY= should be set, but since no one uses it and it's hard to 71106121Sdes * acquire due to privsep code. We will just drop support. 7298937Sdes */ 7398937Sdesvoid 74106121Sdesaix_usrinfo(struct passwd *pw) 7598937Sdes{ 7698937Sdes u_int i; 77124208Sdes size_t len; 78106121Sdes char *cp; 7998937Sdes 80124208Sdes len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name)); 81124208Sdes cp = xmalloc(len); 82124208Sdes 83149749Sdes i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 84124208Sdes pw->pw_name, '\0'); 8598937Sdes if (usrinfo(SETUINFO, cp, i) == -1) 8698937Sdes fatal("Couldn't set usrinfo: %s", strerror(errno)); 8798937Sdes debug3("AIX/UsrInfo: set len %d", i); 88124208Sdes 89255767Sdes free(cp); 9098937Sdes} 9198937Sdes 92126274Sdes# ifdef WITH_AIXAUTHENTICATE 93124208Sdes/* 94124208Sdes * Remove embedded newlines in string (if any). 95124208Sdes * Used before logging messages returned by AIX authentication functions 96124208Sdes * so the message is logged on one line. 97124208Sdes */ 98124208Sdesvoid 99124208Sdesaix_remove_embedded_newlines(char *p) 100124208Sdes{ 101124208Sdes if (p == NULL) 102124208Sdes return; 103124208Sdes 104124208Sdes for (; *p; p++) { 105124208Sdes if (*p == '\n') 106124208Sdes *p = ' '; 107124208Sdes } 108124208Sdes /* Remove trailing whitespace */ 109124208Sdes if (*--p == ' ') 110124208Sdes *p = '\0'; 111124208Sdes} 112126274Sdes 113126274Sdes/* 114146998Sdes * Test specifically for the case where SYSTEM == NONE and AUTH1 contains 115146998Sdes * anything other than NONE or SYSTEM, which indicates that the admin has 116146998Sdes * configured the account for purely AUTH1-type authentication. 117146998Sdes * 118146998Sdes * Since authenticate() doesn't check AUTH1, and sshd can't sanely support 119146998Sdes * AUTH1 itself, in such a case authenticate() will allow access without 120146998Sdes * authentation, which is almost certainly not what the admin intends. 121146998Sdes * 122146998Sdes * (The native tools, eg login, will process the AUTH1 list in addition to 123146998Sdes * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods 124146998Sdes * have been deprecated since AIX 4.2.x and would be very difficult for sshd 125146998Sdes * to support. 126146998Sdes * 127146998Sdes * Returns 0 if an unsupportable combination is found, 1 otherwise. 128146998Sdes */ 129146998Sdesstatic int 130146998Sdesaix_valid_authentications(const char *user) 131146998Sdes{ 132146998Sdes char *auth1, *sys, *p; 133146998Sdes int valid = 1; 134146998Sdes 135146998Sdes if (getuserattr((char *)user, S_AUTHSYSTEM, &sys, SEC_CHAR) != 0) { 136146998Sdes logit("Can't retrieve attribute SYSTEM for %s: %.100s", 137146998Sdes user, strerror(errno)); 138146998Sdes return 0; 139146998Sdes } 140146998Sdes 141146998Sdes debug3("AIX SYSTEM attribute %s", sys); 142146998Sdes if (strcmp(sys, "NONE") != 0) 143146998Sdes return 1; /* not "NONE", so is OK */ 144146998Sdes 145146998Sdes if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) { 146146998Sdes logit("Can't retrieve attribute auth1 for %s: %.100s", 147146998Sdes user, strerror(errno)); 148146998Sdes return 0; 149146998Sdes } 150146998Sdes 151146998Sdes p = auth1; 152146998Sdes /* A SEC_LIST is concatenated strings, ending with two NULs. */ 153146998Sdes while (p[0] != '\0' && p[1] != '\0') { 154146998Sdes debug3("AIX auth1 attribute list member %s", p); 155146998Sdes if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) { 156146998Sdes logit("Account %s has unsupported auth1 value '%s'", 157146998Sdes user, p); 158146998Sdes valid = 0; 159146998Sdes } 160146998Sdes p += strlen(p) + 1; 161146998Sdes } 162146998Sdes 163146998Sdes return (valid); 164146998Sdes} 165146998Sdes 166146998Sdes/* 167126274Sdes * Do authentication via AIX's authenticate routine. We loop until the 168126274Sdes * reenter parameter is 0, but normally authenticate is called only once. 169126274Sdes * 170126274Sdes * Note: this function returns 1 on success, whereas AIX's authenticate() 171126274Sdes * returns 0. 172126274Sdes */ 173126274Sdesint 174147001Sdessys_auth_passwd(Authctxt *ctxt, const char *password) 175126274Sdes{ 176149749Sdes char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name; 177126274Sdes int authsuccess = 0, expired, reenter, result; 178126274Sdes 179126274Sdes do { 180126274Sdes result = authenticate((char *)name, (char *)password, &reenter, 181126274Sdes &authmsg); 182323134Sdes aix_remove_embedded_newlines(authmsg); 183149749Sdes debug3("AIX/authenticate result %d, authmsg %.100s", result, 184126274Sdes authmsg); 185126274Sdes } while (reenter); 186126274Sdes 187146998Sdes if (!aix_valid_authentications(name)) 188146998Sdes result = -1; 189146998Sdes 190126274Sdes if (result == 0) { 191126274Sdes authsuccess = 1; 192126274Sdes 193149749Sdes /* 194126274Sdes * Record successful login. We don't have a pty yet, so just 195126274Sdes * label the line as "ssh" 196126274Sdes */ 197126274Sdes aix_setauthdb(name); 198126274Sdes 199126274Sdes /* 200126274Sdes * Check if the user's password is expired. 201126274Sdes */ 202137015Sdes expired = passwdexpired(name, &msg); 203137015Sdes if (msg && *msg) { 204147001Sdes buffer_append(ctxt->loginmsg, msg, strlen(msg)); 205137015Sdes aix_remove_embedded_newlines(msg); 206137015Sdes } 207137015Sdes debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); 208126274Sdes 209126274Sdes switch (expired) { 210126274Sdes case 0: /* password not expired */ 211126274Sdes break; 212126274Sdes case 1: /* expired, password change required */ 213126274Sdes ctxt->force_pwchange = 1; 214126274Sdes break; 215126274Sdes default: /* user can't change(2) or other error (-1) */ 216126274Sdes logit("Password can't be changed for user %s: %.100s", 217126274Sdes name, msg); 218255767Sdes free(msg); 219126274Sdes authsuccess = 0; 220126274Sdes } 221126274Sdes 222126274Sdes aix_restoreauthdb(); 223126274Sdes } 224126274Sdes 225255767Sdes free(authmsg); 226126274Sdes 227126274Sdes return authsuccess; 228126274Sdes} 229137015Sdes 230137015Sdes/* 231137015Sdes * Check if specified account is permitted to log in. 232137015Sdes * Returns 1 if login is allowed, 0 if not allowed. 233137015Sdes */ 234137015Sdesint 235146998Sdessys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg) 236137015Sdes{ 237137015Sdes char *msg = NULL; 238137015Sdes int result, permitted = 0; 239137015Sdes struct stat st; 240137015Sdes 241137015Sdes /* 242137015Sdes * Don't perform checks for root account (PermitRootLogin controls 243181111Sdes * logins via ssh) or if running as non-root user (since 244137015Sdes * loginrestrictions will always fail due to insufficient privilege). 245137015Sdes */ 246137015Sdes if (pw->pw_uid == 0 || geteuid() != 0) { 247137015Sdes debug3("%s: not checking", __func__); 248137015Sdes return 1; 249137015Sdes } 250137015Sdes 251137015Sdes result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg); 252137015Sdes if (result == 0) 253137015Sdes permitted = 1; 254137015Sdes /* 255137015Sdes * If restricted because /etc/nologin exists, the login will be denied 256137015Sdes * in session.c after the nologin message is sent, so allow for now 257137015Sdes * and do not append the returned message. 258137015Sdes */ 259137015Sdes if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) 260137015Sdes permitted = 1; 261137015Sdes else if (msg != NULL) 262146998Sdes buffer_append(loginmsg, msg, strlen(msg)); 263137015Sdes if (msg == NULL) 264137015Sdes msg = xstrdup("(none)"); 265137015Sdes aix_remove_embedded_newlines(msg); 266137015Sdes debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg); 267137015Sdes 268137015Sdes if (!permitted) 269137015Sdes logit("Login restricted for %s: %.100s", pw->pw_name, msg); 270255767Sdes free(msg); 271137015Sdes return permitted; 272137015Sdes} 273137015Sdes 274137015Sdesint 275146998Sdessys_auth_record_login(const char *user, const char *host, const char *ttynm, 276146998Sdes Buffer *loginmsg) 277137015Sdes{ 278149749Sdes char *msg = NULL; 279137015Sdes int success = 0; 280137015Sdes 281137015Sdes aix_setauthdb(user); 282146998Sdes if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) { 283137015Sdes success = 1; 284197679Sdes if (msg != NULL) { 285146998Sdes debug("AIX/loginsuccess: msg %s", msg); 286197679Sdes if (lastlogin_msg == NULL) 287197679Sdes lastlogin_msg = msg; 288137015Sdes } 289137015Sdes } 290137015Sdes aix_restoreauthdb(); 291137015Sdes return (success); 292137015Sdes} 293137015Sdes 294197679Sdeschar * 295197679Sdessys_auth_get_lastlogin_msg(const char *user, uid_t uid) 296197679Sdes{ 297197679Sdes char *msg = lastlogin_msg; 298197679Sdes 299197679Sdes lastlogin_msg = NULL; 300197679Sdes return msg; 301197679Sdes} 302197679Sdes 303126274Sdes# ifdef CUSTOM_FAILED_LOGIN 304124208Sdes/* 305124208Sdes * record_failed_login: generic "login failed" interface function 306124208Sdes */ 307124208Sdesvoid 308146998Sdesrecord_failed_login(const char *user, const char *hostname, const char *ttyname) 309124208Sdes{ 310124208Sdes if (geteuid() != 0) 311124208Sdes return; 312124208Sdes 313124208Sdes aix_setauthdb(user); 314126274Sdes# ifdef AIX_LOGINFAILED_4ARG 315146998Sdes loginfailed((char *)user, (char *)hostname, (char *)ttyname, 316146998Sdes AUDIT_FAIL_AUTH); 317126274Sdes# else 318146998Sdes loginfailed((char *)user, (char *)hostname, (char *)ttyname); 319126274Sdes# endif 320126274Sdes aix_restoreauthdb(); 321124208Sdes} 322126274Sdes# endif /* CUSTOM_FAILED_LOGIN */ 323124208Sdes 324124208Sdes/* 325124208Sdes * If we have setauthdb, retrieve the password registry for the user's 326126274Sdes * account then feed it to setauthdb. This will mean that subsequent AIX auth 327126274Sdes * functions will only use the specified loadable module. If we don't have 328126274Sdes * setauthdb this is a no-op. 329124208Sdes */ 330124208Sdesvoid 331124208Sdesaix_setauthdb(const char *user) 332124208Sdes{ 333124208Sdes# ifdef HAVE_SETAUTHDB 334126274Sdes char *registry; 335124208Sdes 336124208Sdes if (setuserdb(S_READ) == -1) { 337124208Sdes debug3("%s: Could not open userdb to read", __func__); 338124208Sdes return; 339124208Sdes } 340323134Sdes 341124208Sdes if (getuserattr((char *)user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { 342126274Sdes if (setauthdb(registry, old_registry) == 0) 343126274Sdes debug3("AIX/setauthdb set registry '%s'", registry); 344323134Sdes else 345126274Sdes debug3("AIX/setauthdb set registry '%s' failed: %s", 346126274Sdes registry, strerror(errno)); 347124208Sdes } else 348124208Sdes debug3("%s: Could not read S_REGISTRY for user: %s", __func__, 349124208Sdes strerror(errno)); 350124208Sdes enduserdb(); 351126274Sdes# endif /* HAVE_SETAUTHDB */ 352124208Sdes} 353126274Sdes 354126274Sdes/* 355126274Sdes * Restore the user's registry settings from old_registry. 356126274Sdes * Note that if the first aix_setauthdb fails, setauthdb("") is still safe 357126274Sdes * (it restores the system default behaviour). If we don't have setauthdb, 358126274Sdes * this is a no-op. 359126274Sdes */ 360126274Sdesvoid 361126274Sdesaix_restoreauthdb(void) 362126274Sdes{ 363126274Sdes# ifdef HAVE_SETAUTHDB 364126274Sdes if (setauthdb(old_registry, NULL) == 0) 365126274Sdes debug3("%s: restoring old registry '%s'", __func__, 366126274Sdes old_registry); 367126274Sdes else 368126274Sdes debug3("%s: failed to restore old registry %s", __func__, 369126274Sdes old_registry); 370126274Sdes# endif /* HAVE_SETAUTHDB */ 371126274Sdes} 372126274Sdes 373126274Sdes# endif /* WITH_AIXAUTHENTICATE */ 374126274Sdes 375204917Sdes# ifdef USE_AIX_KRB_NAME 376204917Sdes/* 377204917Sdes * aix_krb5_get_principal_name: returns the user's kerberos client principal name if 378204917Sdes * configured, otherwise NULL. Caller must free returned string. 379204917Sdes */ 380204917Sdeschar * 381204917Sdesaix_krb5_get_principal_name(char *pw_name) 382204917Sdes{ 383204917Sdes char *authname = NULL, *authdomain = NULL, *principal = NULL; 384204917Sdes 385204917Sdes setuserdb(S_READ); 386204917Sdes if (getuserattr(pw_name, S_AUTHDOMAIN, &authdomain, SEC_CHAR) != 0) 387204917Sdes debug("AIX getuserattr S_AUTHDOMAIN: %s", strerror(errno)); 388204917Sdes if (getuserattr(pw_name, S_AUTHNAME, &authname, SEC_CHAR) != 0) 389204917Sdes debug("AIX getuserattr S_AUTHNAME: %s", strerror(errno)); 390204917Sdes 391204917Sdes if (authdomain != NULL) 392204917Sdes xasprintf(&principal, "%s@%s", authname ? authname : pw_name, authdomain); 393204917Sdes else if (authname != NULL) 394204917Sdes principal = xstrdup(authname); 395204917Sdes enduserdb(); 396204917Sdes return principal; 397204917Sdes} 398204917Sdes# endif /* USE_AIX_KRB_NAME */ 399204917Sdes 400146998Sdes# if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) 401146998Sdes# undef getnameinfo 402146998Sdes/* 403146998Sdes * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros 404146998Sdes * IPv6 address into its textual representation ("::"), so we wrap it 405146998Sdes * with a function that will. 406146998Sdes */ 407146998Sdesint 408146998Sdessshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 409146998Sdes size_t hostlen, char *serv, size_t servlen, int flags) 410146998Sdes{ 411146998Sdes struct sockaddr_in6 *sa6; 412146998Sdes u_int32_t *a6; 413146998Sdes 414146998Sdes if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) && 415146998Sdes sa->sa_family == AF_INET6) { 416146998Sdes sa6 = (struct sockaddr_in6 *)sa; 417146998Sdes a6 = sa6->sin6_addr.u6_addr.u6_addr32; 418146998Sdes 419146998Sdes if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) { 420146998Sdes strlcpy(host, "::", hostlen); 421146998Sdes snprintf(serv, servlen, "%d", sa6->sin6_port); 422146998Sdes return 0; 423146998Sdes } 424146998Sdes } 425146998Sdes return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); 426146998Sdes} 427146998Sdes# endif /* AIX_GETNAMEINFO_HACK */ 428146998Sdes 429181111Sdes# if defined(USE_GETGRSET) 430181111Sdes# include <stdlib.h> 431181111Sdesint 432181111Sdesgetgrouplist(const char *user, gid_t pgid, gid_t *groups, int *grpcnt) 433181111Sdes{ 434181111Sdes char *cp, *grplist, *grp; 435181111Sdes gid_t gid; 436181111Sdes int ret = 0, ngroups = 0, maxgroups; 437181111Sdes long l; 438181111Sdes 439181111Sdes maxgroups = *grpcnt; 440181111Sdes 441181111Sdes if ((cp = grplist = getgrset(user)) == NULL) 442181111Sdes return -1; 443181111Sdes 444181111Sdes /* handle zero-length case */ 445181111Sdes if (maxgroups <= 0) { 446181111Sdes *grpcnt = 0; 447181111Sdes return -1; 448181111Sdes } 449181111Sdes 450181111Sdes /* copy primary group */ 451181111Sdes groups[ngroups++] = pgid; 452181111Sdes 453181111Sdes /* copy each entry from getgrset into group list */ 454181111Sdes while ((grp = strsep(&grplist, ",")) != NULL) { 455181111Sdes l = strtol(grp, NULL, 10); 456181111Sdes if (ngroups >= maxgroups || l == LONG_MIN || l == LONG_MAX) { 457181111Sdes ret = -1; 458181111Sdes goto out; 459181111Sdes } 460181111Sdes gid = (gid_t)l; 461181111Sdes if (gid == pgid) 462181111Sdes continue; /* we have already added primary gid */ 463181111Sdes groups[ngroups++] = gid; 464181111Sdes } 465181111Sdesout: 466181111Sdes free(cp); 467181111Sdes *grpcnt = ngroups; 468181111Sdes return ret; 469181111Sdes} 470181111Sdes# endif /* USE_GETGRSET */ 471181111Sdes 47298937Sdes#endif /* _AIX */ 473