]> andersk Git - gssapi-openssh.git/blob - openssh/openbsd-compat/port-aix.c
Import of OpenSSH 4.1p1
[gssapi-openssh.git] / openssh / openbsd-compat / port-aix.c
1 /*
2  *
3  * Copyright (c) 2001 Gert Doering.  All rights reserved.
4  * Copyright (c) 2003,2004 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 <uinfo.h>
37 #include <sys/socket.h>
38 #include "port-aix.h"
39
40 # ifdef HAVE_SETAUTHDB
41 static char old_registry[REGISTRY_SIZE] = "";
42 # endif
43
44 /*
45  * AIX has a "usrinfo" area where logname and other stuff is stored - 
46  * a few applications actually use this and die if it's not set
47  *
48  * NOTE: TTY= should be set, but since no one uses it and it's hard to
49  * acquire due to privsep code.  We will just drop support.
50  */
51
52
53 void
54 aix_usrinfo(struct passwd *pw)
55 {
56         u_int i;
57         size_t len;
58         char *cp;
59
60         len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
61         cp = xmalloc(len);
62
63         i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0', 
64             pw->pw_name, '\0');
65         if (usrinfo(SETUINFO, cp, i) == -1)
66                 fatal("Couldn't set usrinfo: %s", strerror(errno));
67         debug3("AIX/UsrInfo: set len %d", i);
68
69         xfree(cp);
70 }
71
72 # ifdef WITH_AIXAUTHENTICATE
73 /*
74  * Remove embedded newlines in string (if any).
75  * Used before logging messages returned by AIX authentication functions
76  * so the message is logged on one line.
77  */
78 void
79 aix_remove_embedded_newlines(char *p)
80 {
81         if (p == NULL)
82                 return;
83
84         for (; *p; p++) {
85                 if (*p == '\n')
86                         *p = ' ';
87         }
88         /* Remove trailing whitespace */
89         if (*--p == ' ')
90                 *p = '\0';
91 }
92
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 /*
147  * Do authentication via AIX's authenticate routine.  We loop until the
148  * reenter parameter is 0, but normally authenticate is called only once.
149  *
150  * Note: this function returns 1 on success, whereas AIX's authenticate()
151  * returns 0.
152  */
153 int
154 sys_auth_passwd(Authctxt *ctxt, const char *password)
155 {
156         char *authmsg = NULL, *msg, *name = ctxt->pw->pw_name;
157         int authsuccess = 0, expired, reenter, result;
158
159         do {
160                 result = authenticate((char *)name, (char *)password, &reenter,
161                     &authmsg);
162                 aix_remove_embedded_newlines(authmsg);  
163                 debug3("AIX/authenticate result %d, msg %.100s", result,
164                     authmsg);
165         } while (reenter);
166
167         if (!aix_valid_authentications(name))
168                 result = -1;
169
170         if (result == 0) {
171                 authsuccess = 1;
172
173                 /*
174                  * Record successful login.  We don't have a pty yet, so just
175                  * label the line as "ssh"
176                  */
177                 aix_setauthdb(name);
178
179                 /*
180                  * Check if the user's password is expired.
181                  */
182                 expired = passwdexpired(name, &msg);
183                 if (msg && *msg) {
184                         buffer_append(ctxt->loginmsg, msg, strlen(msg));
185                         aix_remove_embedded_newlines(msg);
186                 }
187                 debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
188
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                         if (msg)
199                                 xfree(msg);
200                         authsuccess = 0;
201                 }
202
203                 aix_restoreauthdb();
204         }
205
206         if (authmsg != NULL)
207                 xfree(authmsg);
208
209         return authsuccess;
210 }
211
212 /*
213  * Check if specified account is permitted to log in.
214  * Returns 1 if login is allowed, 0 if not allowed.
215  */
216 int
217 sys_auth_allowed_user(struct passwd *pw, Buffer *loginmsg)
218 {
219         char *msg = NULL;
220         int result, permitted = 0;
221         struct stat st;
222
223         /*
224          * Don't perform checks for root account (PermitRootLogin controls
225          * logins via * ssh) or if running as non-root user (since
226          * loginrestrictions will always fail due to insufficient privilege).
227          */
228         if (pw->pw_uid == 0 || geteuid() != 0) {
229                 debug3("%s: not checking", __func__);
230                 return 1;
231         }
232
233         result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg);
234         if (result == 0)
235                 permitted = 1;
236         /*
237          * If restricted because /etc/nologin exists, the login will be denied
238          * in session.c after the nologin message is sent, so allow for now
239          * and do not append the returned message.
240          */
241         if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0)
242                 permitted = 1;
243         else if (msg != NULL)
244                 buffer_append(loginmsg, msg, strlen(msg));
245         if (msg == NULL)
246                 msg = xstrdup("(none)");
247         aix_remove_embedded_newlines(msg);
248         debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg);
249
250         if (!permitted)
251                 logit("Login restricted for %s: %.100s", pw->pw_name, msg);
252         xfree(msg);
253         return permitted;
254 }
255
256 int
257 sys_auth_record_login(const char *user, const char *host, const char *ttynm,
258     Buffer *loginmsg)
259 {
260         char *msg;
261         int success = 0;
262
263         aix_setauthdb(user);
264         if (loginsuccess((char *)user, (char *)host, (char *)ttynm, &msg) == 0) {
265                 success = 1;
266                 if (msg != NULL) {
267                         debug("AIX/loginsuccess: msg %s", msg);
268                         buffer_append(loginmsg, msg, strlen(msg));
269                         xfree(msg);
270                 }
271         }
272         aix_restoreauthdb();
273         return (success);
274 }
275
276 #  ifdef CUSTOM_FAILED_LOGIN
277 /*
278  * record_failed_login: generic "login failed" interface function
279  */
280 void
281 record_failed_login(const char *user, const char *hostname, const char *ttyname)
282 {
283         if (geteuid() != 0)
284                 return;
285
286         aix_setauthdb(user);
287 #   ifdef AIX_LOGINFAILED_4ARG
288         loginfailed((char *)user, (char *)hostname, (char *)ttyname,
289             AUDIT_FAIL_AUTH);
290 #   else
291         loginfailed((char *)user, (char *)hostname, (char *)ttyname);
292 #   endif
293         aix_restoreauthdb();
294 }
295 #  endif /* CUSTOM_FAILED_LOGIN */
296
297 /*
298  * If we have setauthdb, retrieve the password registry for the user's
299  * account then feed it to setauthdb.  This will mean that subsequent AIX auth
300  * functions will only use the specified loadable module.  If we don't have
301  * setauthdb this is a no-op.
302  */
303 void
304 aix_setauthdb(const char *user)
305 {
306 #  ifdef HAVE_SETAUTHDB
307         char *registry;
308
309         if (setuserdb(S_READ) == -1) {
310                 debug3("%s: Could not open userdb to read", __func__);
311                 return;
312         }
313         
314         if (getuserattr((char *)user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
315                 if (setauthdb(registry, old_registry) == 0)
316                         debug3("AIX/setauthdb set registry '%s'", registry);
317                 else 
318                         debug3("AIX/setauthdb set registry '%s' failed: %s",
319                             registry, strerror(errno));
320         } else
321                 debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
322                     strerror(errno));
323         enduserdb();
324 #  endif /* HAVE_SETAUTHDB */
325 }
326
327 /*
328  * Restore the user's registry settings from old_registry.
329  * Note that if the first aix_setauthdb fails, setauthdb("") is still safe
330  * (it restores the system default behaviour).  If we don't have setauthdb,
331  * this is a no-op.
332  */
333 void
334 aix_restoreauthdb(void)
335 {
336 #  ifdef HAVE_SETAUTHDB
337         if (setauthdb(old_registry, NULL) == 0)
338                 debug3("%s: restoring old registry '%s'", __func__,
339                     old_registry);
340         else
341                 debug3("%s: failed to restore old registry %s", __func__,
342                     old_registry);
343 #  endif /* HAVE_SETAUTHDB */
344 }
345
346 # endif /* WITH_AIXAUTHENTICATE */
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
377 #endif /* _AIX */
This page took 0.6165 seconds and 5 git commands to generate.