port-aix.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /*
  2. *
  3. * Copyright (c) 2001 Gert Doering. All rights reserved.
  4. * Copyright (c) 2003,2004,2005,2006 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. #ifdef _AIX
  29. #include "xmalloc.h"
  30. #include "sshbuf.h"
  31. #include "ssherr.h"
  32. #include "sshkey.h"
  33. #include "hostfile.h"
  34. #include "auth.h"
  35. #include "ssh.h"
  36. #include "ssh_api.h"
  37. #include "log.h"
  38. #include <errno.h>
  39. #if defined(HAVE_NETDB_H)
  40. # include <netdb.h>
  41. #endif
  42. #include <uinfo.h>
  43. #include <stdarg.h>
  44. #include <string.h>
  45. #include <unistd.h>
  46. #include <sys/socket.h>
  47. #ifdef WITH_AIXAUTHENTICATE
  48. # include <login.h>
  49. # include <userpw.h>
  50. # if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG)
  51. # include <sys/audit.h>
  52. # endif
  53. # include <usersec.h>
  54. #endif
  55. #include "port-aix.h"
  56. static char *lastlogin_msg = NULL;
  57. # ifdef HAVE_SETAUTHDB
  58. static char old_registry[REGISTRY_SIZE] = "";
  59. # endif
  60. /*
  61. * AIX has a "usrinfo" area where logname and other stuff is stored -
  62. * a few applications actually use this and die if it's not set
  63. *
  64. * NOTE: TTY= should be set, but since no one uses it and it's hard to
  65. * acquire due to privsep code. We will just drop support.
  66. */
  67. void
  68. aix_usrinfo(struct passwd *pw)
  69. {
  70. u_int i;
  71. size_t len;
  72. char *cp;
  73. len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
  74. cp = xmalloc(len);
  75. i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0',
  76. pw->pw_name, '\0');
  77. if (usrinfo(SETUINFO, cp, i) == -1)
  78. fatal("Couldn't set usrinfo: %s", strerror(errno));
  79. debug3("AIX/UsrInfo: set len %d", i);
  80. free(cp);
  81. }
  82. # ifdef WITH_AIXAUTHENTICATE
  83. /*
  84. * Remove embedded newlines in string (if any).
  85. * Used before logging messages returned by AIX authentication functions
  86. * so the message is logged on one line.
  87. */
  88. void
  89. aix_remove_embedded_newlines(char *p)
  90. {
  91. if (p == NULL)
  92. return;
  93. for (; *p; p++) {
  94. if (*p == '\n')
  95. *p = ' ';
  96. }
  97. /* Remove trailing whitespace */
  98. if (*--p == ' ')
  99. *p = '\0';
  100. }
  101. /*
  102. * Test specifically for the case where SYSTEM == NONE and AUTH1 contains
  103. * anything other than NONE or SYSTEM, which indicates that the admin has
  104. * configured the account for purely AUTH1-type authentication.
  105. *
  106. * Since authenticate() doesn't check AUTH1, and sshd can't sanely support
  107. * AUTH1 itself, in such a case authenticate() will allow access without
  108. * authentation, which is almost certainly not what the admin intends.
  109. *
  110. * (The native tools, eg login, will process the AUTH1 list in addition to
  111. * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods
  112. * have been deprecated since AIX 4.2.x and would be very difficult for sshd
  113. * to support.
  114. *
  115. * Returns 0 if an unsupportable combination is found, 1 otherwise.
  116. */
  117. static int
  118. aix_valid_authentications(const char *user)
  119. {
  120. char *auth1, *sys, *p;
  121. int valid = 1;
  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. debug3("AIX SYSTEM attribute %s", sys);
  128. if (strcmp(sys, "NONE") != 0)
  129. return 1; /* not "NONE", so is OK */
  130. if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) {
  131. logit("Can't retrieve attribute auth1 for %s: %.100s",
  132. user, strerror(errno));
  133. return 0;
  134. }
  135. p = auth1;
  136. /* A SEC_LIST is concatenated strings, ending with two NULs. */
  137. while (p[0] != '\0' && p[1] != '\0') {
  138. debug3("AIX auth1 attribute list member %s", p);
  139. if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) {
  140. logit("Account %s has unsupported auth1 value '%s'",
  141. user, p);
  142. valid = 0;
  143. }
  144. p += strlen(p) + 1;
  145. }
  146. return (valid);
  147. }
  148. /*
  149. * Do authentication via AIX's authenticate routine. We loop until the
  150. * reenter parameter is 0, but normally authenticate is called only once.
  151. *
  152. * Note: this function returns 1 on success, whereas AIX's authenticate()
  153. * returns 0.
  154. */
  155. int
  156. sys_auth_passwd(struct ssh *ssh, const char *password)
  157. {
  158. Authctxt *ctxt = ssh->authctxt;
  159. char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name;
  160. int r, authsuccess = 0, expired, reenter, result;
  161. do {
  162. result = authenticate((char *)name, (char *)password, &reenter,
  163. &authmsg);
  164. aix_remove_embedded_newlines(authmsg);
  165. debug3("AIX/authenticate result %d, authmsg %.100s", result,
  166. authmsg);
  167. } while (reenter);
  168. if (!aix_valid_authentications(name))
  169. result = -1;
  170. if (result == 0) {
  171. authsuccess = 1;
  172. /*
  173. * Record successful login. We don't have a pty yet, so just
  174. * label the line as "ssh"
  175. */
  176. aix_setauthdb(name);
  177. /*
  178. * Check if the user's password is expired.
  179. */
  180. expired = passwdexpired(name, &msg);
  181. if (msg && *msg) {
  182. if ((r = sshbuf_put(ctxt->loginmsg,
  183. msg, strlen(msg))) != 0)
  184. fatal("%s: buffer error: %s",
  185. __func__, ssh_err(r));
  186. aix_remove_embedded_newlines(msg);
  187. }
  188. debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
  189. switch (expired) {
  190. case 0: /* password not expired */
  191. break;
  192. case 1: /* expired, password change required */
  193. ctxt->force_pwchange = 1;
  194. break;
  195. default: /* user can't change(2) or other error (-1) */
  196. logit("Password can't be changed for user %s: %.100s",
  197. name, msg);
  198. free(msg);
  199. authsuccess = 0;
  200. }
  201. aix_restoreauthdb();
  202. }
  203. free(authmsg);
  204. return authsuccess;
  205. }
  206. /*
  207. * Check if specified account is permitted to log in.
  208. * Returns 1 if login is allowed, 0 if not allowed.
  209. */
  210. int
  211. sys_auth_allowed_user(struct passwd *pw, struct sshbuf *loginmsg)
  212. {
  213. char *msg = NULL;
  214. int r, result, permitted = 0;
  215. struct stat st;
  216. /*
  217. * Don't perform checks for root account (PermitRootLogin controls
  218. * logins via ssh) or if running as non-root user (since
  219. * loginrestrictions will always fail due to insufficient privilege).
  220. */
  221. if (pw->pw_uid == 0 || geteuid() != 0) {
  222. debug3("%s: not checking", __func__);
  223. return 1;
  224. }
  225. result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg);
  226. if (result == 0)
  227. permitted = 1;
  228. /*
  229. * If restricted because /etc/nologin exists, the login will be denied
  230. * in session.c after the nologin message is sent, so allow for now
  231. * and do not append the returned message.
  232. */
  233. if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0)
  234. permitted = 1;
  235. else if (msg != NULL) {
  236. if ((r = sshbuf_put(loginmsg, msg, strlen(msg))) != 0)
  237. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  238. }
  239. if (msg == NULL)
  240. msg = xstrdup("(none)");
  241. aix_remove_embedded_newlines(msg);
  242. debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg);
  243. if (!permitted)
  244. logit("Login restricted for %s: %.100s", pw->pw_name, msg);
  245. free(msg);
  246. return permitted;
  247. }
  248. int
  249. sys_auth_record_login(const char *user, const char *host, const char *ttynm,
  250. struct sshbuf *loginmsg)
  251. {
  252. char *msg = NULL;
  253. int success = 0;
  254. aix_setauthdb(user);
  255. if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) {
  256. success = 1;
  257. if (msg != NULL) {
  258. debug("AIX/loginsuccess: msg %s", msg);
  259. if (lastlogin_msg == NULL)
  260. lastlogin_msg = msg;
  261. }
  262. }
  263. aix_restoreauthdb();
  264. return (success);
  265. }
  266. char *
  267. sys_auth_get_lastlogin_msg(const char *user, uid_t uid)
  268. {
  269. char *msg = lastlogin_msg;
  270. lastlogin_msg = NULL;
  271. return msg;
  272. }
  273. # ifdef CUSTOM_FAILED_LOGIN
  274. /*
  275. * record_failed_login: generic "login failed" interface function
  276. */
  277. void
  278. record_failed_login(struct ssh *ssh, const char *user, const char *hostname,
  279. const char *ttyname)
  280. {
  281. if (geteuid() != 0)
  282. return;
  283. aix_setauthdb(user);
  284. # ifdef AIX_LOGINFAILED_4ARG
  285. loginfailed((char *)user, (char *)hostname, (char *)ttyname,
  286. AUDIT_FAIL_AUTH);
  287. # else
  288. loginfailed((char *)user, (char *)hostname, (char *)ttyname);
  289. # endif
  290. aix_restoreauthdb();
  291. }
  292. # endif /* CUSTOM_FAILED_LOGIN */
  293. /*
  294. * If we have setauthdb, retrieve the password registry for the user's
  295. * account then feed it to setauthdb. This will mean that subsequent AIX auth
  296. * functions will only use the specified loadable module. If we don't have
  297. * setauthdb this is a no-op.
  298. */
  299. void
  300. aix_setauthdb(const char *user)
  301. {
  302. # ifdef HAVE_SETAUTHDB
  303. char *registry;
  304. if (setuserdb(S_READ) == -1) {
  305. debug3("%s: Could not open userdb to read", __func__);
  306. return;
  307. }
  308. if (getuserattr((char *)user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
  309. if (setauthdb(registry, old_registry) == 0)
  310. debug3("AIX/setauthdb set registry '%s'", registry);
  311. else
  312. debug3("AIX/setauthdb set registry '%s' failed: %s",
  313. registry, strerror(errno));
  314. } else
  315. debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
  316. strerror(errno));
  317. enduserdb();
  318. # endif /* HAVE_SETAUTHDB */
  319. }
  320. /*
  321. * Restore the user's registry settings from old_registry.
  322. * Note that if the first aix_setauthdb fails, setauthdb("") is still safe
  323. * (it restores the system default behaviour). If we don't have setauthdb,
  324. * this is a no-op.
  325. */
  326. void
  327. aix_restoreauthdb(void)
  328. {
  329. # ifdef HAVE_SETAUTHDB
  330. if (setauthdb(old_registry, NULL) == 0)
  331. debug3("%s: restoring old registry '%s'", __func__,
  332. old_registry);
  333. else
  334. debug3("%s: failed to restore old registry %s", __func__,
  335. old_registry);
  336. # endif /* HAVE_SETAUTHDB */
  337. }
  338. # endif /* WITH_AIXAUTHENTICATE */
  339. # ifdef USE_AIX_KRB_NAME
  340. /*
  341. * aix_krb5_get_principal_name: returns the user's kerberos client principal
  342. * name if configured, otherwise NULL. Caller must free returned string.
  343. */
  344. char *
  345. aix_krb5_get_principal_name(const char *const_pw_name)
  346. {
  347. char *pw_name = (char *)const_pw_name;
  348. char *authname = NULL, *authdomain = NULL, *principal = NULL;
  349. setuserdb(S_READ);
  350. if (getuserattr(pw_name, S_AUTHDOMAIN, &authdomain, SEC_CHAR) != 0)
  351. debug("AIX getuserattr S_AUTHDOMAIN: %s", strerror(errno));
  352. if (getuserattr(pw_name, S_AUTHNAME, &authname, SEC_CHAR) != 0)
  353. debug("AIX getuserattr S_AUTHNAME: %s", strerror(errno));
  354. if (authdomain != NULL)
  355. xasprintf(&principal, "%s@%s", authname ? authname : pw_name,
  356. authdomain);
  357. else if (authname != NULL)
  358. principal = xstrdup(authname);
  359. enduserdb();
  360. return principal;
  361. }
  362. # endif /* USE_AIX_KRB_NAME */
  363. # if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO)
  364. # undef getnameinfo
  365. /*
  366. * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros
  367. * IPv6 address into its textual representation ("::"), so we wrap it
  368. * with a function that will.
  369. */
  370. int
  371. sshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
  372. size_t hostlen, char *serv, size_t servlen, int flags)
  373. {
  374. struct sockaddr_in6 *sa6;
  375. u_int32_t *a6;
  376. if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) &&
  377. sa->sa_family == AF_INET6) {
  378. sa6 = (struct sockaddr_in6 *)sa;
  379. a6 = sa6->sin6_addr.u6_addr.u6_addr32;
  380. if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) {
  381. strlcpy(host, "::", hostlen);
  382. snprintf(serv, servlen, "%d", sa6->sin6_port);
  383. return 0;
  384. }
  385. }
  386. return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
  387. }
  388. # endif /* AIX_GETNAMEINFO_HACK */
  389. # if defined(USE_GETGRSET)
  390. # include <stdlib.h>
  391. int
  392. getgrouplist(const char *user, gid_t pgid, gid_t *groups, int *grpcnt)
  393. {
  394. char *cp, *grplist, *grp;
  395. gid_t gid;
  396. int ret = 0, ngroups = 0, maxgroups;
  397. long l;
  398. maxgroups = *grpcnt;
  399. if ((cp = grplist = getgrset(user)) == NULL)
  400. return -1;
  401. /* handle zero-length case */
  402. if (maxgroups <= 0) {
  403. *grpcnt = 0;
  404. return -1;
  405. }
  406. /* copy primary group */
  407. groups[ngroups++] = pgid;
  408. /* copy each entry from getgrset into group list */
  409. while ((grp = strsep(&grplist, ",")) != NULL) {
  410. l = strtol(grp, NULL, 10);
  411. if (ngroups >= maxgroups || l == LONG_MIN || l == LONG_MAX) {
  412. ret = -1;
  413. goto out;
  414. }
  415. gid = (gid_t)l;
  416. if (gid == pgid)
  417. continue; /* we have already added primary gid */
  418. groups[ngroups++] = gid;
  419. }
  420. out:
  421. free(cp);
  422. *grpcnt = ngroups;
  423. return ret;
  424. }
  425. # endif /* USE_GETGRSET */
  426. #endif /* _AIX */