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