#include "dm.h"
#include "dm_error.h"
#include <pwd.h>
#if defined(USE_PAM)
# include <security/pam_appl.h>
# include <stdlib.h>
#elif defined(USESHADOW)
# include <shadow.h>
# include <errno.h>
#elif defined(USE_BSDAUTH)
# include <login_cap.h>
# include <varargs.h>
# include <bsd_auth.h>
#elif defined(USESECUREWARE)
# include <sys/types.h>
# include <prot.h>
#endif
# include "greet.h"
#ifdef QNX4
extern char *crypt(const char *, const char *);
#endif
static char *envvars[] = {
"TZ",
#if defined(sony) && !defined(SYSTYPE_SYSV) && !defined(_SYSTYPE_SYSV)
"bootdev",
"boothowto",
"cputype",
"ioptype",
"machine",
"model",
"CONSDEVTYPE",
"SYS_LANGUAGE",
"SYS_CODE",
#endif
#if (defined(SVR4) || defined(SYSV)) && defined(i386) && !defined(sun)
"XLOCAL",
#endif
NULL
};
#ifdef KERBEROS
#include <sys/param.h>
#include <kerberosIV/krb.h>
#if defined(OpenBSD) && (OpenBSD <= 200012)
#include <kerberosIV/kafs.h>
#endif
static char krbtkfile[MAXPATHLEN];
#endif
static char **
userEnv (struct display *d, int useSystemPath, char *user, char *home, char *shell)
{
char **env;
char **envvar;
char *str;
env = defaultEnv ();
env = setEnv (env, "DISPLAY", d->name);
env = setEnv (env, "HOME", home);
env = setEnv (env, "LOGNAME", user);
env = setEnv (env, "USER", user);
env = setEnv (env, "PATH", useSystemPath ? d->systemPath : d->userPath);
env = setEnv (env, "SHELL", shell);
#ifdef KERBEROS
if (krbtkfile[0] != '\0')
env = setEnv (env, "KRBTKFILE", krbtkfile);
#endif
for (envvar = envvars; *envvar; envvar++)
{
str = getenv(*envvar);
if (str)
env = setEnv (env, *envvar, str);
}
return env;
}
#ifdef USE_BSDAUTH
_X_INTERNAL
int
Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
{
struct passwd *p;
login_cap_t *lc;
auth_session_t *as;
char *style, *shell, *home, *s, **argv;
char path[MAXPATHLEN];
int authok;
if ((style = strchr(greet->name, ':')) != NULL)
*style++ = '\0';
Debug ("Verify %s, style %s ...\n", greet->name,
style ? style : "default");
p = getpwnam (greet->name);
endpwent();
if (!p || strlen (greet->name) == 0) {
Debug("getpwnam() failed.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
if ((lc = login_getclass(p->pw_class)) == NULL) {
Debug("login_getclass() failed.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
if ((style = login_getstyle(lc, style, "xdm")) == NULL) {
Debug("login_getstyle() failed.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
if ((as = auth_open()) == NULL) {
Debug("auth_open() failed.\n");
login_close(lc);
bzero(greet->password, strlen(greet->password));
return 0;
}
if (auth_setoption(as, "login", "yes") == -1) {
Debug("auth_setoption() failed.\n");
login_close(lc);
bzero(greet->password, strlen(greet->password));
return 0;
}
auth_setstate(as, 0);
auth_setdata(as, "", 1);
auth_setdata(as, greet->password, strlen(greet->password) + 1);
snprintf(path, sizeof(path), _PATH_AUTHPROG "%s", style);
auth_call(as, path, style, "-s", "response", greet->name,
lc->lc_class, (void *)NULL);
authok = auth_getstate(as);
if ((authok & AUTH_ALLOW) == 0) {
Debug("password verify failed\n");
bzero(greet->password, strlen(greet->password));
auth_close(as);
login_close(lc);
return 0;
}
if (!auth_approval(as, lc, greet->name, "auth-xdm")) {
Debug("login not approved\n");
bzero(greet->password, strlen(greet->password));
auth_close(as);
login_close(lc);
return 0;
}
auth_close(as);
login_close(lc);
if (!greet->allow_null_passwd && strlen(greet->password) == 0) {
Debug("empty password not allowed\n");
return 0;
}
if (p->pw_uid == 0 && !greet->allow_root_login) {
Debug("root logins not allowed\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
for (;;) {
s = getusershell();
if (s == NULL) {
Debug("shell not in /etc/shells\n");
bzero(greet->password, strlen(greet->password));
endusershell();
return 0;
}
if (strcmp(s, p->pw_shell) == 0) {
endusershell();
break;
}
}
#elif defined(USESECUREWARE)
struct smp_user_info *userp = 0;
_X_INTERNAL
int
Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
{
int ret, pwtries = 0, nis, delay;
char *reason = 0;
struct passwd *p;
char *shell, *home, **argv;
Debug ("Verify %s ...\n", greet->name);
p = getpwnam (greet->name);
endpwent();
if (!p || strlen (greet->name) == 0) {
LogError ("getpwnam() failed.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
ret = smp_check_user (SMP_LOGIN, greet->name, 0, 0, &userp, &pwtries,
&reason, &nis, &delay);
if (ret != SMP_RETIRED && userp->retired)
ret = userp->result = SMP_RETIRED;
Debug ("smp_check_user returns %d\n", ret);
switch (ret) {
case SMP_FAIL:
Debug ("Out of memory in smp_check_user\n");
goto smp_fail;
case SMP_EXTFAIL:
Debug ("SMP_EXTFAIL: %s", reason);
goto smp_fail;
case SMP_NOTAUTH:
Debug ("Not authorized\n");
goto smp_fail;
case SMP_TERMLOCK:
Debug ("Terminal is locked!\n");
goto smp_fail;
case SMP_ACCTLOCK:
Debug ("Account is locked\n");
goto smp_fail;
case SMP_RETIRED:
Debug ("Account is retired\n");
goto smp_fail;
case SMP_OVERRIDE:
Debug ("On override device ... proceeding\n");
break;
case SMP_NULLPW:
Debug ("NULL password entry\n");
if (!greet->allow_null_passwd) {
goto smp_fail;
}
break;
case SMP_BADUSER:
Debug ("User not found in protected password database\n");
goto smp_fail;
case SMP_PWREQ:
Debug ("Password change required\n");
goto smp_fail;
case SMP_HASPW:
break;
default:
Debug ("Unhandled smp_check_user return %d\n", ret);
smp_fail:
sleep(delay);
smp_audit_fail (userp, 0);
bzero(greet->password, strlen(greet->password));
return 0;
break;
}
if (ret != SMP_NULLPW) {
ret = smp_check_pw (greet->password, userp, &reason);
switch (ret) {
case SMP_CANCHANGE:
case SMP_CANTCHANGE:
case SMP_OVERRIDE:
break;
default:
goto smp_fail;
}
}
#else
_X_INTERNAL
int
Verify (struct display *d, struct greet_info *greet, struct verify_info *verify)
{
struct passwd *p;
#ifndef USE_PAM
#ifdef USESHADOW
struct spwd *sp;
#endif
char *user_pass = NULL;
#endif
#ifdef __OpenBSD__
char *s;
struct timeval tp;
#endif
char *shell, *home;
char **argv;
Debug ("Verify %s ...\n", greet->name);
p = getpwnam (greet->name);
endpwent();
if (!p || strlen (greet->name) == 0) {
Debug ("getpwnam() failed.\n");
if (greet->password != NULL)
bzero(greet->password, strlen(greet->password));
return 0;
}
#if defined(sun) && defined(SVR4)
# define SOLARIS_LOGIN_DEFAULTS "/etc/default/login"
if (p->pw_uid == 0) {
char *console = NULL, *tmp = NULL;
FILE *fs;
if ((fs= fopen(SOLARIS_LOGIN_DEFAULTS, "r")) != NULL)
{
char str[120];
while (!feof(fs))
{
fgets(str, 120, fs);
if(str[0] == '#' || strlen(str) < 8)
continue;
if((tmp = strstr(str, "CONSOLE=")) != NULL)
console = strdup((tmp+8));
}
fclose(fs);
if ( console != NULL &&
(strncmp(console, "/dev/console", 12) == 0) &&
(strncmp(d->name,":0",2) != 0) )
{
Debug("Not on system console\n");
if (greet->password != NULL)
bzero(greet->password, strlen(greet->password));
free(console);
return 0;
}
free(console);
}
else
{
Debug("Could not open %s\n", SOLARIS_LOGIN_DEFAULTS);
}
}
#endif
#ifndef USE_PAM
#ifdef linux
if (!strcmp(p->pw_passwd, "!") || !strcmp(p->pw_passwd, "*")) {
Debug ("The account is locked, no login allowed.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
#endif
user_pass = p->pw_passwd;
#ifdef KERBEROS
if(strcmp(greet->name, "root") != 0){
char name[ANAME_SZ];
char realm[REALM_SZ];
char *q;
int ret;
if(krb_get_lrealm(realm, 1)){
Debug ("Can't get Kerberos realm.\n");
} else {
sprintf(krbtkfile, "%s.%s", TKT_ROOT, d->name);
krb_set_tkt_string(krbtkfile);
unlink(krbtkfile);
ret = krb_verify_user(greet->name, "", realm,
greet->password, 1, "rcmd");
if(ret == KSUCCESS){
chown(krbtkfile, p->pw_uid, p->pw_gid);
Debug("kerberos verify succeeded\n");
if (k_hasafs()) {
if (k_setpag() == -1)
LogError ("setpag() failed for %s\n",
greet->name);
if((ret = k_afsklog(NULL, NULL)) != KSUCCESS)
LogError("Warning %s\n",
krb_get_err_text(ret));
}
goto done;
} else if(ret != KDC_PR_UNKNOWN && ret != SKDC_CANT){
Debug("kerberos verify failure %d\n", ret);
krbtkfile[0] = '\0';
}
}
}
#endif
#ifdef USESHADOW
errno = 0;
sp = getspnam(greet->name);
if (sp == NULL) {
Debug ("getspnam() failed, errno=%d. Are you root?\n", errno);
} else {
user_pass = sp->sp_pwdp;
}
#ifndef QNX4
endspent();
#endif
#endif
#if defined(ultrix) || defined(__ultrix__)
if (authenticate_user(p, greet->password, NULL) < 0)
#else
if (strcmp (crypt (greet->password, user_pass), user_pass))
#endif
{
if(!greet->allow_null_passwd || strlen(p->pw_passwd) > 0) {
Debug ("password verify failed\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
}
#ifdef KERBEROS
done:
#endif
#ifdef __OpenBSD__
if ((p->pw_uid == 0) && !greet->allow_root_login) {
Debug("root logins not allowed\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
for (;;) {
s = getusershell();
if (s == NULL) {
Debug("shell not in /etc/shells\n");
bzero(greet->password, strlen(greet->password));
endusershell();
return 0;
}
if (strcmp(s, p->pw_shell) == 0) {
endusershell();
break;
}
}
if (p->pw_change || p->pw_expire)
(void)gettimeofday(&tp, (struct timezone *)NULL);
if (p->pw_change) {
if (tp.tv_sec >= p->pw_change) {
Debug("Password has expired.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
}
if (p->pw_expire) {
if (tp.tv_sec >= p->pw_expire) {
Debug("account has expired.\n");
bzero(greet->password, strlen(greet->password));
return 0;
}
}
#endif
bzero(user_pass, strlen(user_pass));
#endif
#endif
Debug ("verify succeeded\n");
verify->uid = p->pw_uid;
verify->gid = p->pw_gid;
home = p->pw_dir;
shell = p->pw_shell;
argv = NULL;
if (d->session)
argv = parseArgs (argv, d->session);
if (greet->string)
argv = parseArgs (argv, greet->string);
if (!argv)
argv = parseArgs (argv, "xsession");
verify->argv = argv;
verify->userEnviron = userEnv (d, p->pw_uid == 0,
greet->name, home, shell);
Debug ("user environment:\n");
printEnv (verify->userEnviron);
verify->systemEnviron = systemEnv (d, greet->name, home);
Debug ("system environment:\n");
printEnv (verify->systemEnviron);
Debug ("end of environments\n");
return 1;
}