port-aix.c revision 126274
159024Sobrien/*
278828Sobrien *
3218822Sdim * Copyright (c) 2001 Gert Doering.  All rights reserved.
459024Sobrien *
559024Sobrien * Redistribution and use in source and binary forms, with or without
6218822Sdim * modification, are permitted provided that the following conditions
759024Sobrien * are met:
8218822Sdim * 1. Redistributions of source code must retain the above copyright
9218822Sdim *    notice, this list of conditions and the following disclaimer.
10218822Sdim * 2. Redistributions in binary form must reproduce the above copyright
11218822Sdim *    notice, this list of conditions and the following disclaimer in the
1259024Sobrien *    documentation and/or other materials provided with the distribution.
13218822Sdim *
14218822Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15218822Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16218822Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1759024Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18218822Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19218822Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20218822Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21218822Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2259024Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2359024Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2459024Sobrien *
2559024Sobrien */
2659024Sobrien#include "includes.h"
2759024Sobrien#include "auth.h"
2860484Sobrien#include "ssh.h"
2959024Sobrien#include "log.h"
3059024Sobrien#include "servconf.h"
3159024Sobrien#include "canohost.h"
3259024Sobrien#include "xmalloc.h"
3359024Sobrien#include "buffer.h"
3459024Sobrien
3559024Sobrien#ifdef _AIX
3659024Sobrien
3759024Sobrien#include <uinfo.h>
3859024Sobrien#include "port-aix.h"
3977298Sobrien
4059024Sobrienextern ServerOptions options;
4159024Sobrienextern Buffer loginmsg;
4259024Sobrien
4359024Sobrien# ifdef HAVE_SETAUTHDB
4477298Sobrienstatic char old_registry[REGISTRY_SIZE] = "";
45218822Sdim# endif
4659024Sobrien
4777298Sobrien/*
4859024Sobrien * AIX has a "usrinfo" area where logname and other stuff is stored -
4977298Sobrien * a few applications actually use this and die if it's not set
5059024Sobrien *
5159024Sobrien * NOTE: TTY= should be set, but since no one uses it and it's hard to
5259024Sobrien * acquire due to privsep code.  We will just drop support.
5359024Sobrien */
5459024Sobrienvoid
5559024Sobrienaix_usrinfo(struct passwd *pw)
5677298Sobrien{
5777298Sobrien	u_int i;
5859024Sobrien	size_t len;
5959024Sobrien	char *cp;
6077298Sobrien
6177298Sobrien	len = sizeof("LOGNAME= NAME= ") + (2 * strlen(pw->pw_name));
6277298Sobrien	cp = xmalloc(len);
63218822Sdim
6459024Sobrien	i = snprintf(cp, len, "LOGNAME=%s%cNAME=%s%c", pw->pw_name, '\0',
6559024Sobrien	    pw->pw_name, '\0');
6659024Sobrien	if (usrinfo(SETUINFO, cp, i) == -1)
67218822Sdim		fatal("Couldn't set usrinfo: %s", strerror(errno));
6859024Sobrien	debug3("AIX/UsrInfo: set len %d", i);
6959024Sobrien
7059024Sobrien	xfree(cp);
7159024Sobrien}
7259024Sobrien
73218822Sdim# ifdef WITH_AIXAUTHENTICATE
74218822Sdim/*
7559024Sobrien * Remove embedded newlines in string (if any).
7659024Sobrien * Used before logging messages returned by AIX authentication functions
7759024Sobrien * so the message is logged on one line.
7859024Sobrien */
7959024Sobrienvoid
8059024Sobrienaix_remove_embedded_newlines(char *p)
8159024Sobrien{
8259024Sobrien	if (p == NULL)
8359024Sobrien		return;
8477298Sobrien
8577298Sobrien	for (; *p; p++) {
8659024Sobrien		if (*p == '\n')
8759024Sobrien			*p = ' ';
8859024Sobrien	}
8959024Sobrien	/* Remove trailing whitespace */
9059024Sobrien	if (*--p == ' ')
9159024Sobrien		*p = '\0';
92218822Sdim}
9359024Sobrien
9459024Sobrien/*
9559024Sobrien * Do authentication via AIX's authenticate routine.  We loop until the
9659024Sobrien * reenter parameter is 0, but normally authenticate is called only once.
97218822Sdim *
98218822Sdim * Note: this function returns 1 on success, whereas AIX's authenticate()
9959024Sobrien * returns 0.
10059024Sobrien */
10159024Sobrienint
10259024Sobriensys_auth_passwd(Authctxt *ctxt, const char *password)
10359024Sobrien{
104218822Sdim	char *authmsg = NULL, *host, *msg, *name = ctxt->pw->pw_name;
10559024Sobrien	int authsuccess = 0, expired, reenter, result;
10659024Sobrien
107218822Sdim	do {
10859024Sobrien		result = authenticate((char *)name, (char *)password, &reenter,
10959024Sobrien		    &authmsg);
110218822Sdim		aix_remove_embedded_newlines(authmsg);
11159024Sobrien		debug3("AIX/authenticate result %d, msg %.100s", result,
112218822Sdim		    authmsg);
113218822Sdim	} while (reenter);
114218822Sdim
115218822Sdim	if (result == 0) {
116218822Sdim		authsuccess = 1;
117218822Sdim
118218822Sdim		host = (char *)get_canonical_hostname(options.use_dns);
119218822Sdim
120218822Sdim	       	/*
121218822Sdim		 * Record successful login.  We don't have a pty yet, so just
122218822Sdim		 * label the line as "ssh"
123218822Sdim		 */
124218822Sdim		aix_setauthdb(name);
125218822Sdim	       	if (loginsuccess((char *)name, (char *)host, "ssh", &msg) == 0) {
126218822Sdim			if (msg != NULL) {
127218822Sdim				debug("%s: msg %s", __func__, msg);
12859024Sobrien				buffer_append(&loginmsg, msg, strlen(msg));
12959024Sobrien				xfree(msg);
13059024Sobrien			}
13159024Sobrien		}
13259024Sobrien
13359024Sobrien		/*
134218822Sdim		 * Check if the user's password is expired.
135218822Sdim		 */
136218822Sdim                expired = passwdexpired(name, &msg);
137218822Sdim                if (msg && *msg) {
138218822Sdim                        buffer_append(&loginmsg, msg, strlen(msg));
139218822Sdim                        aix_remove_embedded_newlines(msg);
140218822Sdim                }
141218822Sdim                debug3("AIX/passwdexpired returned %d msg %.100s", expired, msg);
142218822Sdim
143218822Sdim		switch (expired) {
144218822Sdim		case 0: /* password not expired */
145218822Sdim			break;
146218822Sdim		case 1: /* expired, password change required */
147218822Sdim			ctxt->force_pwchange = 1;
148218822Sdim			disable_forwarding();
149218822Sdim			break;
15059024Sobrien		default: /* user can't change(2) or other error (-1) */
15159024Sobrien			logit("Password can't be changed for user %s: %.100s",
15259024Sobrien			    name, msg);
15359024Sobrien			if (msg)
154218822Sdim				xfree(msg);
155218822Sdim			authsuccess = 0;
156218822Sdim		}
157218822Sdim
15859024Sobrien		aix_restoreauthdb();
15959024Sobrien	}
160218822Sdim
16159024Sobrien	if (authmsg != NULL)
16259024Sobrien		xfree(authmsg);
16359024Sobrien
164218822Sdim	return authsuccess;
16559024Sobrien}
16659024Sobrien
16759024Sobrien#  ifdef CUSTOM_FAILED_LOGIN
16859024Sobrien/*
16959024Sobrien * record_failed_login: generic "login failed" interface function
17059024Sobrien */
17159024Sobrienvoid
17259024Sobrienrecord_failed_login(const char *user, const char *ttyname)
17359024Sobrien{
17459024Sobrien	char *hostname = (char *)get_canonical_hostname(options.use_dns);
17559024Sobrien
17659024Sobrien	if (geteuid() != 0)
17759024Sobrien		return;
17859024Sobrien
17959024Sobrien	aix_setauthdb(user);
18059024Sobrien#   ifdef AIX_LOGINFAILED_4ARG
18159024Sobrien	loginfailed((char *)user, hostname, (char *)ttyname, AUDIT_FAIL_AUTH);
18259024Sobrien#   else
18359024Sobrien	loginfailed((char *)user, hostname, (char *)ttyname);
18459024Sobrien#   endif
18559024Sobrien	aix_restoreauthdb();
18659024Sobrien}
18759024Sobrien#  endif /* CUSTOM_FAILED_LOGIN */
18859024Sobrien
18959024Sobrien/*
19059024Sobrien * If we have setauthdb, retrieve the password registry for the user's
19159024Sobrien * account then feed it to setauthdb.  This will mean that subsequent AIX auth
19259024Sobrien * functions will only use the specified loadable module.  If we don't have
19359024Sobrien * setauthdb this is a no-op.
19459024Sobrien */
19559024Sobrienvoid
19659024Sobrienaix_setauthdb(const char *user)
19759024Sobrien{
19859024Sobrien#  ifdef HAVE_SETAUTHDB
19959024Sobrien	char *registry;
20059024Sobrien
20159024Sobrien	if (setuserdb(S_READ) == -1) {
20259024Sobrien		debug3("%s: Could not open userdb to read", __func__);
20359024Sobrien		return;
20459024Sobrien	}
20559024Sobrien
20659024Sobrien	if (getuserattr((char *)user, S_REGISTRY, &registry, SEC_CHAR) == 0) {
20759024Sobrien		if (setauthdb(registry, old_registry) == 0)
20859024Sobrien			debug3("AIX/setauthdb set registry '%s'", registry);
20959024Sobrien		else
21059024Sobrien			debug3("AIX/setauthdb set registry '%s' failed: %s",
21159024Sobrien			    registry, strerror(errno));
21259024Sobrien	} else
21359024Sobrien		debug3("%s: Could not read S_REGISTRY for user: %s", __func__,
21459024Sobrien		    strerror(errno));
21559024Sobrien	enduserdb();
21659024Sobrien#  endif /* HAVE_SETAUTHDB */
21759024Sobrien}
21859024Sobrien
21959024Sobrien/*
22059024Sobrien * Restore the user's registry settings from old_registry.
22159024Sobrien * Note that if the first aix_setauthdb fails, setauthdb("") is still safe
22259024Sobrien * (it restores the system default behaviour).  If we don't have setauthdb,
22359024Sobrien * this is a no-op.
22459024Sobrien */
22559024Sobrienvoid
22659024Sobrienaix_restoreauthdb(void)
22759024Sobrien{
22859024Sobrien#  ifdef HAVE_SETAUTHDB
22959024Sobrien	if (setauthdb(old_registry, NULL) == 0)
23059024Sobrien		debug3("%s: restoring old registry '%s'", __func__,
23159024Sobrien		    old_registry);
23259024Sobrien	else
23359024Sobrien		debug3("%s: failed to restore old registry %s", __func__,
23459024Sobrien		    old_registry);
23559024Sobrien#  endif /* HAVE_SETAUTHDB */
23659024Sobrien}
23759024Sobrien
23859024Sobrien# endif /* WITH_AIXAUTHENTICATE */
23959024Sobrien
24059024Sobrien#endif /* _AIX */
24159024Sobrien