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 */
382