]> andersk Git - openssh.git/blame - openbsd-compat/port-aix.c
- deraadt@cvs.openbsd.org 2006/08/03 03:34:42
[openssh.git] / openbsd-compat / port-aix.c
CommitLineData
0ba40daa 1/*
34a88012 2 *
3 * Copyright (c) 2001 Gert Doering. All rights reserved.
c8ed2130 4 * Copyright (c) 2003,2004,2005 Darren Tucker. All rights reserved.
34a88012 5 *
0ba40daa 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 */
90e70cfc 27#include "includes.h"
31652869 28
29#include "xmalloc.h"
30#include "buffer.h"
31#include "key.h"
32#include "hostfile.h"
262b1744 33#include "auth.h"
73d9dad3 34#include "ssh.h"
35#include "log.h"
90e70cfc 36
37#ifdef _AIX
38
4f4b7d4d 39#include <errno.h>
c8dfff33 40#if defined(HAVE_NETDB_H)
41# include <netdb.h>
42#endif
90e70cfc 43#include <uinfo.h>
e204f3ee 44#include <string.h>
45#include <unistd.h>
5ccf88cb 46#include <sys/socket.h>
2aa3a16c 47#include "port-aix.h"
90e70cfc 48
d852ad8b 49# ifdef HAVE_SETAUTHDB
50static char old_registry[REGISTRY_SIZE] = "";
51# endif
52
90e70cfc 53/*
5700232d 54 * AIX has a "usrinfo" area where logname and other stuff is stored -
0ba40daa 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.
90e70cfc 59 */
60void
0ba40daa 61aix_usrinfo(struct passwd *pw)
90e70cfc 62{
90e70cfc 63 u_int i;
9901cb37 64 size_t len;
0ba40daa 65 char *cp;
90e70cfc 66
9901cb37 67 len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
68 cp = xmalloc(len);
69
5700232d 70 i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0',
1e72a7e3 71 pw->pw_name, '\0');
90e70cfc 72 if (usrinfo(SETUINFO, cp, i) == -1)
73 fatal("Couldn't set usrinfo: %s", strerror(errno));
74 debug3("AIX/UsrInfo: set len %d", i);
9901cb37 75
90e70cfc 76 xfree(cp);
77}
78
f0b467ef 79# ifdef WITH_AIXAUTHENTICATE
bc7dfc06 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 */
85void
86aix_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}
f0b467ef 99
1383f285 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 */
116static int
117aix_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
f0b467ef 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 */
160int
1b394137 161sys_auth_passwd(Authctxt *ctxt, const char *password)
f0b467ef 162{
c8ed2130 163 char *authmsg = NULL, *msg = NULL, *name = ctxt->pw->pw_name;
cadfc759 164 int authsuccess = 0, expired, reenter, result;
f0b467ef 165
166 do {
167 result = authenticate((char *)name, (char *)password, &reenter,
168 &authmsg);
169 aix_remove_embedded_newlines(authmsg);
ec7f28f2 170 debug3("AIX/authenticate result %d, authmsg %.100s", result,
f0b467ef 171 authmsg);
172 } while (reenter);
173
1383f285 174 if (!aix_valid_authentications(name))
175 result = -1;
176
f0b467ef 177 if (result == 0) {
178 authsuccess = 1;
179
5700232d 180 /*
cadfc759 181 * Record successful login. We don't have a pty yet, so just
182 * label the line as "ssh"
183 */
f0b467ef 184 aix_setauthdb(name);
cadfc759 185
186 /*
187 * Check if the user's password is expired.
188 */
6d05637a 189 expired = passwdexpired(name, &msg);
190 if (msg && *msg) {
1b394137 191 buffer_append(ctxt->loginmsg, msg, strlen(msg));
6d05637a 192 aix_remove_embedded_newlines(msg);
193 }
194 debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
cadfc759 195
196 switch (expired) {
197 case 0: /* password not expired */
198 break;
199 case 1: /* expired, password change required */
200 ctxt->force_pwchange = 1;
cadfc759 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
d852ad8b 210 aix_restoreauthdb();
f0b467ef 211 }
212
213 if (authmsg != NULL)
214 xfree(authmsg);
215
216 return authsuccess;
217}
bc5c2025 218
219/*
220 * Check if specified account is permitted to log in.
221 * Returns 1 if login is allowed, 0 if not allowed.
222 */
223int
5ccf88cb 224sys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg)
bc5c2025 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) {
13f72b91 236 debug3("%s: not checking", __func__);
bc5c2025 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)
5ccf88cb 251 buffer_append(loginmsg, msg, strlen(msg));
bc5c2025 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
f5ed3301 263int
5ccf88cb 264sys_auth_record_login(const char *user, const char *host, const char *ttynm,
265 Buffer *loginmsg)
f5ed3301 266{
c8ed2130 267 char *msg = NULL;
f5ed3301 268 int success = 0;
269
270 aix_setauthdb(user);
c2edf154 271 if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) {
f5ed3301 272 success = 1;
273 if (msg != NULL) {
c2edf154 274 debug("AIX/loginsuccess: msg %s", msg);
5ccf88cb 275 buffer_append(loginmsg, msg, strlen(msg));
f5ed3301 276 xfree(msg);
277 }
278 }
279 aix_restoreauthdb();
280 return (success);
281}
282
f0b467ef 283# ifdef CUSTOM_FAILED_LOGIN
73d9dad3 284/*
285 * record_failed_login: generic "login failed" interface function
286 */
287void
575e336f 288record_failed_login(const char *user, const char *hostname, const char *ttyname)
73d9dad3 289{
2aa3a16c 290 if (geteuid() != 0)
291 return;
292
293 aix_setauthdb(user);
f0b467ef 294# ifdef AIX_LOGINFAILED_4ARG
c2edf154 295 loginfailed((char *)user, (char *)hostname, (char *)ttyname,
296 AUDIT_FAIL_AUTH);
f0b467ef 297# else
c2edf154 298 loginfailed((char *)user, (char *)hostname, (char *)ttyname);
f0b467ef 299# endif
d852ad8b 300 aix_restoreauthdb();
73d9dad3 301}
f0b467ef 302# endif /* CUSTOM_FAILED_LOGIN */
2aa3a16c 303
304/*
305 * If we have setauthdb, retrieve the password registry for the user's
d852ad8b 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.
2aa3a16c 309 */
310void
311aix_setauthdb(const char *user)
312{
313# ifdef HAVE_SETAUTHDB
d852ad8b 314 char *registry;
2aa3a16c 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, &registry, SEC_CHAR) == 0) {
d852ad8b 322 if (setauthdb(registry, old_registry) == 0)
323 debug3("AIX/setauthdb set registry '%s'", registry);
2aa3a16c 324 else
d852ad8b 325 debug3("AIX/setauthdb set registry '%s' failed: %s",
326 registry, strerror(errno));
2aa3a16c 327 } else
328 debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
329 strerror(errno));
330 enduserdb();
f0b467ef 331# endif /* HAVE_SETAUTHDB */
2aa3a16c 332}
90e70cfc 333
d852ad8b 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 */
340void
341aix_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
f0b467ef 353# endif /* WITH_AIXAUTHENTICATE */
354
5ccf88cb 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 */
362int
363sshaix_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
f0b467ef 384#endif /* _AIX */
This page took 0.219442 seconds and 5 git commands to generate.