diff options
Diffstat (limited to 'openbsd-compat/port-aix.c')
-rw-r--r-- | openbsd-compat/port-aix.c | 121 |
1 files changed, 102 insertions, 19 deletions
diff --git a/openbsd-compat/port-aix.c b/openbsd-compat/port-aix.c index 78f4faea3..fa6a4ff7b 100644 --- a/openbsd-compat/port-aix.c +++ b/openbsd-compat/port-aix.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Copyright (c) 2001 Gert Doering. All rights reserved. | 3 | * Copyright (c) 2001 Gert Doering. All rights reserved. |
4 | * Copyright (c) 2003,2004 Darren Tucker. All rights reserved. | ||
4 | * | 5 | * |
5 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | 7 | * modification, are permitted provided that the following conditions |
@@ -27,19 +28,15 @@ | |||
27 | #include "auth.h" | 28 | #include "auth.h" |
28 | #include "ssh.h" | 29 | #include "ssh.h" |
29 | #include "log.h" | 30 | #include "log.h" |
30 | #include "servconf.h" | ||
31 | #include "canohost.h" | ||
32 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
33 | #include "buffer.h" | 32 | #include "buffer.h" |
34 | 33 | ||
35 | #ifdef _AIX | 34 | #ifdef _AIX |
36 | 35 | ||
37 | #include <uinfo.h> | 36 | #include <uinfo.h> |
37 | #include <sys/socket.h> | ||
38 | #include "port-aix.h" | 38 | #include "port-aix.h" |
39 | 39 | ||
40 | extern ServerOptions options; | ||
41 | extern Buffer loginmsg; | ||
42 | |||
43 | # ifdef HAVE_SETAUTHDB | 40 | # ifdef HAVE_SETAUTHDB |
44 | static char old_registry[REGISTRY_SIZE] = ""; | 41 | static char old_registry[REGISTRY_SIZE] = ""; |
45 | # endif | 42 | # endif |
@@ -51,6 +48,8 @@ static char old_registry[REGISTRY_SIZE] = ""; | |||
51 | * NOTE: TTY= should be set, but since no one uses it and it's hard to | 48 | * NOTE: TTY= should be set, but since no one uses it and it's hard to |
52 | * acquire due to privsep code. We will just drop support. | 49 | * acquire due to privsep code. We will just drop support. |
53 | */ | 50 | */ |
51 | |||
52 | |||
54 | void | 53 | void |
55 | aix_usrinfo(struct passwd *pw) | 54 | aix_usrinfo(struct passwd *pw) |
56 | { | 55 | { |
@@ -92,6 +91,59 @@ aix_remove_embedded_newlines(char *p) | |||
92 | } | 91 | } |
93 | 92 | ||
94 | /* | 93 | /* |
94 | * Test specifically for the case where SYSTEM == NONE and AUTH1 contains | ||
95 | * anything other than NONE or SYSTEM, which indicates that the admin has | ||
96 | * configured the account for purely AUTH1-type authentication. | ||
97 | * | ||
98 | * Since authenticate() doesn't check AUTH1, and sshd can't sanely support | ||
99 | * AUTH1 itself, in such a case authenticate() will allow access without | ||
100 | * authentation, which is almost certainly not what the admin intends. | ||
101 | * | ||
102 | * (The native tools, eg login, will process the AUTH1 list in addition to | ||
103 | * the SYSTEM list by using ckuserID(), however ckuserID() and AUTH1 methods | ||
104 | * have been deprecated since AIX 4.2.x and would be very difficult for sshd | ||
105 | * to support. | ||
106 | * | ||
107 | * Returns 0 if an unsupportable combination is found, 1 otherwise. | ||
108 | */ | ||
109 | static int | ||
110 | aix_valid_authentications(const char *user) | ||
111 | { | ||
112 | char *auth1, *sys, *p; | ||
113 | int valid = 1; | ||
114 | |||
115 | if (getuserattr((char *)user, S_AUTHSYSTEM, &sys, SEC_CHAR) != 0) { | ||
116 | logit("Can't retrieve attribute SYSTEM for %s: %.100s", | ||
117 | user, strerror(errno)); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | debug3("AIX SYSTEM attribute %s", sys); | ||
122 | if (strcmp(sys, "NONE") != 0) | ||
123 | return 1; /* not "NONE", so is OK */ | ||
124 | |||
125 | if (getuserattr((char *)user, S_AUTH1, &auth1, SEC_LIST) != 0) { | ||
126 | logit("Can't retrieve attribute auth1 for %s: %.100s", | ||
127 | user, strerror(errno)); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | p = auth1; | ||
132 | /* A SEC_LIST is concatenated strings, ending with two NULs. */ | ||
133 | while (p[0] != '\0' && p[1] != '\0') { | ||
134 | debug3("AIX auth1 attribute list member %s", p); | ||
135 | if (strcmp(p, "NONE") != 0 && strcmp(p, "SYSTEM")) { | ||
136 | logit("Account %s has unsupported auth1 value '%s'", | ||
137 | user, p); | ||
138 | valid = 0; | ||
139 | } | ||
140 | p += strlen(p) + 1; | ||
141 | } | ||
142 | |||
143 | return (valid); | ||
144 | } | ||
145 | |||
146 | /* | ||
95 | * Do authentication via AIX's authenticate routine. We loop until the | 147 | * Do authentication via AIX's authenticate routine. We loop until the |
96 | * reenter parameter is 0, but normally authenticate is called only once. | 148 | * reenter parameter is 0, but normally authenticate is called only once. |
97 | * | 149 | * |
@@ -99,7 +151,7 @@ aix_remove_embedded_newlines(char *p) | |||
99 | * returns 0. | 151 | * returns 0. |
100 | */ | 152 | */ |
101 | int | 153 | int |
102 | sys_auth_passwd(Authctxt *ctxt, const char *password) | 154 | sys_auth_passwd(Authctxt *ctxt, const char *password, Buffer *loginmsg) |
103 | { | 155 | { |
104 | char *authmsg = NULL, *msg, *name = ctxt->pw->pw_name; | 156 | char *authmsg = NULL, *msg, *name = ctxt->pw->pw_name; |
105 | int authsuccess = 0, expired, reenter, result; | 157 | int authsuccess = 0, expired, reenter, result; |
@@ -112,6 +164,9 @@ sys_auth_passwd(Authctxt *ctxt, const char *password) | |||
112 | authmsg); | 164 | authmsg); |
113 | } while (reenter); | 165 | } while (reenter); |
114 | 166 | ||
167 | if (!aix_valid_authentications(name)) | ||
168 | result = -1; | ||
169 | |||
115 | if (result == 0) { | 170 | if (result == 0) { |
116 | authsuccess = 1; | 171 | authsuccess = 1; |
117 | 172 | ||
@@ -126,7 +181,7 @@ sys_auth_passwd(Authctxt *ctxt, const char *password) | |||
126 | */ | 181 | */ |
127 | expired = passwdexpired(name, &msg); | 182 | expired = passwdexpired(name, &msg); |
128 | if (msg && *msg) { | 183 | if (msg && *msg) { |
129 | buffer_append(&loginmsg, msg, strlen(msg)); | 184 | buffer_append(loginmsg, msg, strlen(msg)); |
130 | aix_remove_embedded_newlines(msg); | 185 | aix_remove_embedded_newlines(msg); |
131 | } | 186 | } |
132 | debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); | 187 | debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg); |
@@ -136,7 +191,6 @@ sys_auth_passwd(Authctxt *ctxt, const char *password) | |||
136 | break; | 191 | break; |
137 | case 1: /* expired, password change required */ | 192 | case 1: /* expired, password change required */ |
138 | ctxt->force_pwchange = 1; | 193 | ctxt->force_pwchange = 1; |
139 | disable_forwarding(); | ||
140 | break; | 194 | break; |
141 | default: /* user can't change(2) or other error (-1) */ | 195 | default: /* user can't change(2) or other error (-1) */ |
142 | logit("Password can't be changed for user %s: %.100s", | 196 | logit("Password can't be changed for user %s: %.100s", |
@@ -160,7 +214,7 @@ sys_auth_passwd(Authctxt *ctxt, const char *password) | |||
160 | * Returns 1 if login is allowed, 0 if not allowed. | 214 | * Returns 1 if login is allowed, 0 if not allowed. |
161 | */ | 215 | */ |
162 | int | 216 | int |
163 | sys_auth_allowed_user(struct passwd *pw) | 217 | sys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg) |
164 | { | 218 | { |
165 | char *msg = NULL; | 219 | char *msg = NULL; |
166 | int result, permitted = 0; | 220 | int result, permitted = 0; |
@@ -187,7 +241,7 @@ sys_auth_allowed_user(struct passwd *pw) | |||
187 | if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) | 241 | if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0) |
188 | permitted = 1; | 242 | permitted = 1; |
189 | else if (msg != NULL) | 243 | else if (msg != NULL) |
190 | buffer_append(&loginmsg, msg, strlen(msg)); | 244 | buffer_append(loginmsg, msg, strlen(msg)); |
191 | if (msg == NULL) | 245 | if (msg == NULL) |
192 | msg = xstrdup("(none)"); | 246 | msg = xstrdup("(none)"); |
193 | aix_remove_embedded_newlines(msg); | 247 | aix_remove_embedded_newlines(msg); |
@@ -200,17 +254,18 @@ sys_auth_allowed_user(struct passwd *pw) | |||
200 | } | 254 | } |
201 | 255 | ||
202 | int | 256 | int |
203 | sys_auth_record_login(const char *user, const char *host, const char *ttynm) | 257 | sys_auth_record_login(const char *user, const char *host, const char *ttynm, |
258 | Buffer *loginmsg) | ||
204 | { | 259 | { |
205 | char *msg; | 260 | char *msg; |
206 | int success = 0; | 261 | int success = 0; |
207 | 262 | ||
208 | aix_setauthdb(user); | 263 | aix_setauthdb(user); |
209 | if (loginsuccess((char *)user, host, ttynm, &msg) == 0) { | 264 | if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) { |
210 | success = 1; | 265 | success = 1; |
211 | if (msg != NULL) { | 266 | if (msg != NULL) { |
212 | debug("AIX/loginsuccess: msg %s", __func__, msg); | 267 | debug("AIX/loginsuccess: msg %s", msg); |
213 | buffer_append(&loginmsg, msg, strlen(msg)); | 268 | buffer_append(loginmsg, msg, strlen(msg)); |
214 | xfree(msg); | 269 | xfree(msg); |
215 | } | 270 | } |
216 | } | 271 | } |
@@ -223,18 +278,17 @@ sys_auth_record_login(const char *user, const char *host, const char *ttynm) | |||
223 | * record_failed_login: generic "login failed" interface function | 278 | * record_failed_login: generic "login failed" interface function |
224 | */ | 279 | */ |
225 | void | 280 | void |
226 | record_failed_login(const char *user, const char *ttyname) | 281 | record_failed_login(const char *user, const char *hostname, const char *ttyname) |
227 | { | 282 | { |
228 | char *hostname = (char *)get_canonical_hostname(options.use_dns); | ||
229 | |||
230 | if (geteuid() != 0) | 283 | if (geteuid() != 0) |
231 | return; | 284 | return; |
232 | 285 | ||
233 | aix_setauthdb(user); | 286 | aix_setauthdb(user); |
234 | # ifdef AIX_LOGINFAILED_4ARG | 287 | # ifdef AIX_LOGINFAILED_4ARG |
235 | loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH); | 288 | loginfailed((char *)user, (char *)hostname, (char *)ttyname, |
289 | AUDIT_FAIL_AUTH); | ||
236 | # else | 290 | # else |
237 | loginfailed((char *)user, hostname, (char *)ttyname); | 291 | loginfailed((char *)user, (char *)hostname, (char *)ttyname); |
238 | # endif | 292 | # endif |
239 | aix_restoreauthdb(); | 293 | aix_restoreauthdb(); |
240 | } | 294 | } |
@@ -291,4 +345,33 @@ aix_restoreauthdb(void) | |||
291 | 345 | ||
292 | # endif /* WITH_AIXAUTHENTICATE */ | 346 | # endif /* WITH_AIXAUTHENTICATE */ |
293 | 347 | ||
348 | # if defined(AIX_GETNAMEINFO_HACK) && !defined(BROKEN_ADDRINFO) | ||
349 | # undef getnameinfo | ||
350 | /* | ||
351 | * For some reason, AIX's getnameinfo will refuse to resolve the all-zeros | ||
352 | * IPv6 address into its textual representation ("::"), so we wrap it | ||
353 | * with a function that will. | ||
354 | */ | ||
355 | int | ||
356 | sshaix_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, | ||
357 | size_t hostlen, char *serv, size_t servlen, int flags) | ||
358 | { | ||
359 | struct sockaddr_in6 *sa6; | ||
360 | u_int32_t *a6; | ||
361 | |||
362 | if (flags & (NI_NUMERICHOST|NI_NUMERICSERV) && | ||
363 | sa->sa_family == AF_INET6) { | ||
364 | sa6 = (struct sockaddr_in6 *)sa; | ||
365 | a6 = sa6->sin6_addr.u6_addr.u6_addr32; | ||
366 | |||
367 | if (a6[0] == 0 && a6[1] == 0 && a6[2] == 0 && a6[3] == 0) { | ||
368 | strlcpy(host, "::", hostlen); | ||
369 | snprintf(serv, servlen, "%d", sa6->sin6_port); | ||
370 | return 0; | ||
371 | } | ||
372 | } | ||
373 | return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); | ||
374 | } | ||
375 | # endif /* AIX_GETNAMEINFO_HACK */ | ||
376 | |||
294 | #endif /* _AIX */ | 377 | #endif /* _AIX */ |