#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
static fstring this_user;
#if !defined(WITH_PAM)
static fstring this_salt;
static fstring this_crypted;
#endif
#ifdef WITH_AFS
#include <afs/stds.h>
#include <afs/kautils.h>
static BOOL afs_auth(char *user, char *password)
{
long password_expires = 0;
char *reason;
setpag();
if (ka_UserAuthenticateGeneral
(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user, (char *)0,
(char *)0,
password, 0,
&password_expires,
0,
&reason) == 0)
{
return (True);
}
DEBUG(1,
("AFS authentication for \"%s\" failed (%s)\n", user, reason));
return (False);
}
#endif
#ifdef WITH_DFS
#include <dce/dce_error.h>
#include <dce/sec_login.h>
sec_login_handle_t my_dce_sec_context;
int dcelogin_atmost_once = 0;
static BOOL dfs_auth(char *user, char *password)
{
struct tm *t;
error_status_t err;
int err2;
int prterr;
signed32 expire_time, current_time;
boolean32 password_reset;
struct passwd *pw;
sec_passwd_rec_t passwd_rec;
sec_login_auth_src_t auth_src = sec_login_auth_src_network;
unsigned char dce_errstr[dce_c_error_string_len];
gid_t egid;
if (dcelogin_atmost_once)
return (False);
#ifdef HAVE_CRYPT
if (strcmp((char *)crypt(password, this_salt), this_crypted))
{
return (False);
}
#endif
sec_login_get_current_context(&my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
return (False);
}
sec_login_certify_identity(my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr));
return (False);
}
sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
return (False);
}
time(¤t_time);
if (expire_time < (current_time + 60))
{
struct passwd *pw;
sec_passwd_rec_t *key;
sec_login_get_pwent(my_dce_sec_context,
(sec_login_passwd_t *) & pw, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
return (False);
}
sec_login_refresh_identity(my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't refresh identity. %s\n",
dce_errstr));
return (False);
}
sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL,
(unsigned char *)pw->pw_name,
sec_c_key_version_none,
(void **)&key, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get key for %s. %s\n",
pw->pw_name, dce_errstr));
return (False);
}
sec_login_valid_and_cert_ident(my_dce_sec_context, key,
&password_reset, &auth_src,
&err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0,
("DCE can't validate and certify identity for %s. %s\n",
pw->pw_name, dce_errstr));
}
sec_key_mgmt_free_key(key, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't free key.\n", dce_errstr));
}
}
if (sec_login_setup_identity((unsigned char *)user,
sec_login_no_flags,
&my_dce_sec_context, &err) == 0)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
user, dce_errstr));
return (False);
}
sec_login_get_pwent(my_dce_sec_context,
(sec_login_passwd_t *) & pw, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
return (False);
}
sec_login_purge_context(&my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr));
return (False);
}
egid = getegid();
set_effective_gid(pw->pw_gid);
set_effective_uid(pw->pw_uid);
if (sec_login_setup_identity((unsigned char *)user,
sec_login_no_flags,
&my_dce_sec_context, &err) == 0)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE Setup Identity for %s failed: %s\n",
user, dce_errstr));
goto err;
}
sec_login_get_pwent(my_dce_sec_context,
(sec_login_passwd_t *) & pw, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
goto err;
}
passwd_rec.version_number = sec_passwd_c_version_none;
passwd_rec.pepper = NULL;
passwd_rec.key.key_type = sec_passwd_plain;
passwd_rec.key.tagged_union.plain = (idl_char *) password;
sec_login_validate_identity(my_dce_sec_context,
&passwd_rec, &password_reset,
&auth_src, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0,
("DCE Identity Validation failed for principal %s: %s\n",
user, dce_errstr));
goto err;
}
sec_login_certify_identity(my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr));
goto err;
}
if (auth_src != sec_login_auth_src_network)
{
DEBUG(0, ("DCE context has no network credentials.\n"));
}
sec_login_set_context(my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0,
("DCE login failed for principal %s, cant set context: %s\n",
user, dce_errstr));
sec_login_purge_context(&my_dce_sec_context, &err);
goto err;
}
sec_login_get_pwent(my_dce_sec_context,
(sec_login_passwd_t *) & pw, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr));
goto err;
}
DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n",
user, sys_getpid()));
DEBUG(3, ("DCE principal: %s\n"
" uid: %d\n"
" gid: %d\n",
pw->pw_name, pw->pw_uid, pw->pw_gid));
DEBUG(3, (" info: %s\n"
" dir: %s\n"
" shell: %s\n",
pw->pw_gecos, pw->pw_dir, pw->pw_shell));
sec_login_get_expiration(my_dce_sec_context, &expire_time, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr));
goto err;
}
set_effective_uid(0);
set_effective_gid(0);
t = localtime(&expire_time);
if (t) {
const char *asct = asctime(t);
if (asct) {
DEBUG(0,("DCE context expires: %s", asct));
}
}
dcelogin_atmost_once = 1;
return (True);
err:
set_effective_uid(0);
set_effective_gid(egid);
return (False);
}
void dfs_unlogin(void)
{
error_status_t err;
int err2;
unsigned char dce_errstr[dce_c_error_string_len];
sec_login_purge_context(&my_dce_sec_context, &err);
if (err != error_status_ok)
{
dce_error_inq_text(err, dce_errstr, &err2);
DEBUG(0,
("DCE purge login context failed for server instance %d: %s\n",
sys_getpid(), dce_errstr));
}
}
#endif
#ifdef LINUX_BIGCRYPT
static int linux_bigcrypt(char *password, char *salt1, char *crypted)
{
#define LINUX_PASSWORD_SEG_CHARS 8
char salt[3];
int i;
StrnCpy(salt, salt1, 2);
crypted += 2;
for (i = strlen(password); i > 0; i -= LINUX_PASSWORD_SEG_CHARS) {
char *p = crypt(password, salt) + 2;
if (strncmp(p, crypted, LINUX_PASSWORD_SEG_CHARS) != 0)
return (0);
password += LINUX_PASSWORD_SEG_CHARS;
crypted += strlen(p);
}
return (1);
}
#endif
#ifdef OSF1_ENH_SEC
static char *osf1_bigcrypt(char *password, char *salt1)
{
static char result[AUTH_MAX_PASSWD_LENGTH] = "";
char *p1;
char *p2 = password;
char salt[3];
int i;
int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
if (strlen(password) % AUTH_CLEARTEXT_SEG_CHARS)
parts++;
StrnCpy(salt, salt1, 2);
StrnCpy(result, salt1, 2);
result[2] = '\0';
for (i = 0; i < parts; i++) {
p1 = crypt(p2, salt);
strncat(result, p1 + 2,
AUTH_MAX_PASSWD_LENGTH - strlen(p1 + 2) - 1);
StrnCpy(salt, &result[2 + i * AUTH_CIPHERTEXT_SEG_CHARS], 2);
p2 += AUTH_CLEARTEXT_SEG_CHARS;
}
return (result);
}
#endif
static NTSTATUS string_combinations2(char *s, int offset, NTSTATUS (*fn) (const char *),
int N)
{
int len = strlen(s);
int i;
NTSTATUS nt_status;
#ifdef PASSWORD_LENGTH
len = MIN(len, PASSWORD_LENGTH);
#endif
if (N <= 0 || offset >= len)
return (fn(s));
for (i = offset; i < (len - (N - 1)); i++) {
char c = s[i];
if (!islower_ascii(c))
continue;
s[i] = toupper_ascii(c);
if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, i + 1, fn, N - 1),NT_STATUS_WRONG_PASSWORD)) {
return (nt_status);
}
s[i] = c;
}
return (NT_STATUS_WRONG_PASSWORD);
}
static NTSTATUS string_combinations(char *s, NTSTATUS (*fn) (const char *), int N)
{
int n;
NTSTATUS nt_status;
for (n = 1; n <= N; n++)
if (!NT_STATUS_EQUAL(nt_status = string_combinations2(s, 0, fn, n), NT_STATUS_WRONG_PASSWORD))
return nt_status;
return NT_STATUS_WRONG_PASSWORD;
}
static NTSTATUS password_check(const char *password)
{
#ifdef WITH_PAM
return smb_pam_passcheck(this_user, password);
#else
BOOL ret;
#ifdef WITH_AFS
if (afs_auth(this_user, password))
return NT_STATUS_OK;
#endif
#ifdef WITH_DFS
if (dfs_auth(this_user, password))
return NT_STATUS_OK;
#endif
#ifdef OSF1_ENH_SEC
ret = (strcmp(osf1_bigcrypt(password, this_salt),
this_crypted) == 0);
if (!ret) {
DEBUG(2,
("OSF1_ENH_SEC failed. Trying normal crypt.\n"));
ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
}
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#endif
#ifdef ULTRIX_AUTH
ret = (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#endif
#ifdef LINUX_BIGCRYPT
ret = (linux_bigcrypt(password, this_salt, this_crypted));
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#endif
#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
return NT_STATUS_OK;
else
ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#else
#ifdef HAVE_BIGCRYPT
ret = (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#endif
#ifndef HAVE_CRYPT
DEBUG(1, ("Warning - no crypt available\n"));
return NT_STATUS_LOGON_FAILURE;
#else
ret = (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
if (ret) {
return NT_STATUS_OK;
} else {
return NT_STATUS_WRONG_PASSWORD;
}
#endif
#endif
#endif
}
NTSTATUS pass_check(const struct passwd *pass, const char *user, const char *password,
int pwlen, BOOL (*fn) (const char *, const char *), BOOL run_cracker)
{
pstring pass2;
int level = lp_passwordlevel();
NTSTATUS nt_status;
#ifdef DEBUG_PASSWORD
DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
#endif
if (!password)
return NT_STATUS_LOGON_FAILURE;
if (((!*password) || (!pwlen)) && !lp_null_passwords())
return NT_STATUS_LOGON_FAILURE;
#if defined(WITH_PAM)
fstrcpy(this_user, user);
DEBUG(4, ("pass_check: Checking (PAM) password for user %s (l=%d)\n", user, pwlen));
#else
DEBUG(4, ("pass_check: Checking password for user %s (l=%d)\n", user, pwlen));
if (!pass) {
DEBUG(3, ("Couldn't find user %s\n", user));
return NT_STATUS_NO_SUCH_USER;
}
fstrcpy(this_crypted, pass->pw_passwd);
fstrcpy(this_salt, pass->pw_passwd);
#ifdef HAVE_GETSPNAM
{
struct spwd *spass;
spass = getspnam(pass->pw_name);
if (spass && spass->sp_pwdp) {
fstrcpy(this_crypted, spass->sp_pwdp);
fstrcpy(this_salt, spass->sp_pwdp);
}
}
#elif defined(IA_UINFO)
{
uinfo_t uinfo;
if (ia_openinfo(pass->pw_name, &uinfo) != -1)
ia_get_logpwd(uinfo, &(pass->pw_passwd));
}
#endif
#ifdef HAVE_GETPRPWNAM
{
struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
if (pr_pw && pr_pw->ufld.fd_encrypt)
fstrcpy(this_crypted, pr_pw->ufld.fd_encrypt);
}
#endif
#ifdef HAVE_GETPWANAM
{
struct passwd_adjunct *pwret;
pwret = getpwanam(s);
if (pwret && pwret->pwa_passwd)
fstrcpy(this_crypted, pwret->pwa_passwd);
}
#endif
#ifdef OSF1_ENH_SEC
{
struct pr_passwd *mypasswd;
DEBUG(5, ("Checking password for user %s in OSF1_ENH_SEC\n",
user));
mypasswd = getprpwnam(user);
if (mypasswd) {
fstrcpy(this_user, mypasswd->ufld.fd_name);
fstrcpy(this_crypted, mypasswd->ufld.fd_encrypt);
} else {
DEBUG(5,
("OSF1_ENH_SEC: No entry for user %s in protected database !\n",
user));
}
}
#endif
#ifdef ULTRIX_AUTH
{
AUTHORIZATION *ap = getauthuid(pass->pw_uid);
if (ap) {
fstrcpy(this_crypted, ap->a_password);
endauthent();
}
}
#endif
#if defined(HAVE_TRUNCATED_SALT)
this_salt[2] = 0;
#endif
if (!*this_crypted) {
if (!lp_null_passwords()) {
DEBUG(2, ("Disallowing %s with null password\n",
this_user));
return NT_STATUS_LOGON_FAILURE;
}
if (!*password) {
DEBUG(3,
("Allowing access to %s with null password\n",
this_user));
return NT_STATUS_OK;
}
}
#endif
nt_status = password_check(password);
if NT_STATUS_IS_OK(nt_status) {
if (fn) {
fn(user, password);
}
return (nt_status);
} else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
return (nt_status);
}
if (!run_cracker) {
return (nt_status);
}
if (strhasupper(password) && strhaslower(password)) {
return nt_status;
}
pstrcpy(pass2, password);
if (strhasupper(pass2)) {
strlower_m(pass2);
if NT_STATUS_IS_OK(nt_status = password_check(pass2)) {
if (fn)
fn(user, pass2);
return (nt_status);
}
}
if (level < 1) {
return NT_STATUS_WRONG_PASSWORD;
}
strlower_m(pass2);
if (NT_STATUS_IS_OK(nt_status = string_combinations(pass2, password_check, level))) {
if (fn)
fn(user, pass2);
return nt_status;
}
return NT_STATUS_WRONG_PASSWORD;
}