port-aix.c revision 137015
1/*
2 *
3 * Copyright (c) 2001 Gert Doering.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26#include "includes.h"
27#include "auth.h"
28#include "ssh.h"
29#include "log.h"
30#include "servconf.h"
31#include "canohost.h"
32#include "xmalloc.h"
33#include "buffer.h"
34
35#ifdef _AIX
36
37#include <uinfo.h>
38#include "port-aix.h"
39
40extern ServerOptions options;
41extern Buffer loginmsg;
42
43# ifdef HAVE_SETAUTHDB
44static char old_registry[REGISTRY_SIZE] = "";
45# endif
46
47/*
48 * AIX has a "usrinfo" area where logname and other stuff is stored -
49 * a few applications actually use this and die if it's not set
50 *
51 * 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.
53 */
54void
55aix_usrinfo(struct passwd *pw)
56{
57	u_int i;
58	size_t len;
59	char *cp;
60
61	len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
62	cp = xmalloc(len);
63
64	i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0',
65	    pw->pw_name, '\0');
66	if (usrinfo(SETUINFO, cp, i) == -1)
67		fatal("Couldn't set usrinfo: %s", strerror(errno));
68	debug3("AIX/UsrInfo: set len %d", i);
69
70	xfree(cp);
71}
72
73# ifdef WITH_AIXAUTHENTICATE
74/*
75 * Remove embedded newlines in string (if any).
76 * Used before logging messages returned by AIX authentication functions
77 * so the message is logged on one line.
78 */
79void
80aix_remove_embedded_newlines(char *p)
81{
82	if (p == NULL)
83		return;
84
85	for (; *p; p++) {
86		if (*p == '\n')
87			*p = ' ';
88	}
89	/* Remove trailing whitespace */
90	if (*--p == ' ')
91		*p = '\0';
92}
93
94/*
95 * Do authentication via AIX's authenticate routine.  We loop until the
96 * reenter parameter is 0, but normally authenticate is called only once.
97 *
98 * Note: this function returns 1 on success, whereas AIX's authenticate()
99 * returns 0.
100 */
101int
102sys_auth_passwd(Authctxt *ctxt, const char *password)
103{
104	char *authmsg = NULL, *msg, *name = ctxt->pw->pw_name;
105	int authsuccess = 0, expired, reenter, result;
106
107	do {
108		result = authenticate((char *)name, (char *)password, &reenter,
109		    &authmsg);
110		aix_remove_embedded_newlines(authmsg);
111		debug3("AIX/authenticate result %d, msg %.100s", result,
112		    authmsg);
113	} while (reenter);
114
115	if (result == 0) {
116		authsuccess = 1;
117
118	       	/*
119		 * Record successful login.  We don't have a pty yet, so just
120		 * label the line as "ssh"
121		 */
122		aix_setauthdb(name);
123
124		/*
125		 * Check if the user's password is expired.
126		 */
127		expired = passwdexpired(name, &msg);
128		if (msg && *msg) {
129			buffer_append(&loginmsg, msg, strlen(msg));
130			aix_remove_embedded_newlines(msg);
131		}
132		debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
133
134		switch (expired) {
135		case 0: /* password not expired */
136			break;
137		case 1: /* expired, password change required */
138			ctxt->force_pwchange = 1;
139			disable_forwarding();
140			break;
141		default: /* user can't change(2) or other error (-1) */
142			logit("Password can't be changed for user %s: %.100s",
143			    name, msg);
144			if (msg)
145				xfree(msg);
146			authsuccess = 0;
147		}
148
149		aix_restoreauthdb();
150	}
151
152	if (authmsg != NULL)
153		xfree(authmsg);
154
155	return authsuccess;
156}
157
158/*
159 * Check if specified account is permitted to log in.
160 * Returns 1 if login is allowed, 0 if not allowed.
161 */
162int
163sys_auth_allowed_user(struct passwd *pw)
164{
165	char *msg = NULL;
166	int result, permitted = 0;
167	struct stat st;
168
169	/*
170	 * Don't perform checks for root account (PermitRootLogin controls
171	 * logins via * ssh) or if running as non-root user (since
172	 * loginrestrictions will always fail due to insufficient privilege).
173	 */
174	if (pw->pw_uid == 0 || geteuid() != 0) {
175		debug3("%s: not checking", __func__);
176		return 1;
177	}
178
179	result = loginrestrictions(pw->pw_name, S_RLOGIN, NULL, &msg);
180	if (result == 0)
181		permitted = 1;
182	/*
183	 * If restricted because /etc/nologin exists, the login will be denied
184	 * in session.c after the nologin message is sent, so allow for now
185	 * and do not append the returned message.
186	 */
187	if (result == -1 && errno == EPERM && stat(_PATH_NOLOGIN, &st) == 0)
188		permitted = 1;
189	else if (msg != NULL)
190		buffer_append(&loginmsg, msg, strlen(msg));
191	if (msg == NULL)
192		msg = xstrdup("(none)");
193	aix_remove_embedded_newlines(msg);
194	debug3("AIX/loginrestrictions returned %d msg %.100s", result, msg);
195
196	if (!permitted)
197		logit("Login restricted for %s: %.100s", pw->pw_name, msg);
198	xfree(msg);
199	return permitted;
200}
201
202int
203sys_auth_record_login(const char *user, const char *host, const char *ttynm)
204{
205	char *msg;
206	int success = 0;
207
208	aix_setauthdb(user);
209	if (loginsuccess((char *)user, host, ttynm, &msg) == 0) {
210		success = 1;
211		if (msg != NULL) {
212			debug("AIX/loginsuccess: msg %s", __func__, msg);
213			buffer_append(&loginmsg, msg, strlen(msg));
214			xfree(msg);
215		}
216	}
217	aix_restoreauthdb();
218	return (success);
219}
220
221#  ifdef CUSTOM_FAILED_LOGIN
222/*
223 * record_failed_login: generic "login failed" interface function
224 */
225void
226record_failed_login(const char *user, const char *ttyname)
227{
228	char *hostname = (char *)get_canonical_hostname(options.use_dns);
229
230	if (geteuid() != 0)
231		return;
232
233	aix_setauthdb(user);
234#   ifdef AIX_LOGINFAILED_4ARG
235	loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH);
236#   else
237	loginfailed((char *)user, hostname, (char *)ttyname);
238#   endif
239	aix_restoreauthdb();
240}
241#  endif /* CUSTOM_FAILED_LOGIN */
242
243/*
244 * If we have setauthdb, retrieve the password registry for the user's
245 * account then feed it to setauthdb.  This will mean that subsequent AIX auth
246 * functions will only use the specified loadable module.  If we don't have
247 * setauthdb this is a no-op.
248 */
249void
250aix_setauthdb(const char *user)
251{
252#  ifdef HAVE_SETAUTHDB
253	char *registry;
254
255	if (setuserdb(S_READ) == -1) {
256		debug3("%s: Could not open userdb to read", __func__);
257		return;
258	}
259
260	if (getuserattr((char *)user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
261		if (setauthdb(registry, old_registry) == 0)
262			debug3("AIX/setauthdb set registry '%s'", registry);
263		else
264			debug3("AIX/setauthdb set registry '%s' failed: %s",
265			    registry, strerror(errno));
266	} else
267		debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
268		    strerror(errno));
269	enduserdb();
270#  endif /* HAVE_SETAUTHDB */
271}
272
273/*
274 * Restore the user's registry settings from old_registry.
275 * Note that if the first aix_setauthdb fails, setauthdb("") is still safe
276 * (it restores the system default behaviour).  If we don't have setauthdb,
277 * this is a no-op.
278 */
279void
280aix_restoreauthdb(void)
281{
282#  ifdef HAVE_SETAUTHDB
283	if (setauthdb(old_registry, NULL) == 0)
284		debug3("%s: restoring old registry '%s'", __func__,
285		    old_registry);
286	else
287		debug3("%s: failed to restore old registry %s", __func__,
288		    old_registry);
289#  endif /* HAVE_SETAUTHDB */
290}
291
292# endif /* WITH_AIXAUTHENTICATE */
293
294#endif /* _AIX */
295