#include "includes.h"
static fstring this_user;
static fstring this_salt;
static fstring this_crypted;
#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)
{
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);
DEBUG(0,
("DCE context expires: %s", asctime(localtime(&expire_time))));
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 KRB5_AUTH
#include <krb5.h>
static BOOL krb5_auth(char *user, char *password)
{
krb5_data tgtname = {
0,
KRB5_TGS_NAME_SIZE,
KRB5_TGS_NAME
};
krb5_context kcontext;
krb5_principal kprinc;
krb5_principal server;
krb5_creds kcreds;
int options = 0;
krb5_address **addrs = (krb5_address **) 0;
krb5_preauthtype *preauth = NULL;
krb5_keytab keytab = NULL;
krb5_timestamp now;
krb5_ccache ccache = NULL;
int retval;
char *name;
if (retval = krb5_init_context(&kcontext))
{
return (False);
}
if (retval = krb5_timeofday(kcontext, &now))
{
return (False);
}
if (retval = krb5_cc_default(kcontext, &ccache))
{
return (False);
}
if (retval = krb5_parse_name(kcontext, user, &kprinc))
{
return (False);
}
ZERO_STRUCT(kcreds);
kcreds.client = kprinc;
if ((retval = krb5_build_principal_ext(kcontext, &server,
krb5_princ_realm(kcontext,
kprinc)->
length,
krb5_princ_realm(kcontext,
kprinc)->data,
tgtname.length, tgtname.data,
krb5_princ_realm(kcontext,
kprinc)->
length,
krb5_princ_realm(kcontext,
kprinc)->data,
0)))
{
return (False);
}
kcreds.server = server;
retval = krb5_get_in_tkt_with_password(kcontext,
options,
addrs,
NULL,
preauth,
password, 0, &kcreds, 0);
if (retval)
{
return (False);
}
return (True);
}
#endif
#ifdef KRB4_AUTH
#include <krb.h>
static BOOL krb4_auth(char *user, char *password)
{
char realm[REALM_SZ];
char tkfile[MAXPATHLEN];
if (krb_get_lrealm(realm, 1) != KSUCCESS)
{
(void)safe_strcpy(realm, KRB_REALM, sizeof(realm) - 1);
}
(void)slprintf(tkfile, sizeof(tkfile) - 1, "/tmp/samba_tkt_%d",
(int)sys_getpid());
krb_set_tkt_string(tkfile);
if (krb_verify_user(user, "", realm, password, 0, "rmcd") == KSUCCESS)
{
unlink(tkfile);
return 1;
}
unlink(tkfile);
return 0;
}
#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 BOOL string_combinations2(char *s, int offset, BOOL (*fn) (char *),
int N)
{
int len = strlen(s);
int i;
#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(c))
continue;
s[i] = toupper(c);
if (string_combinations2(s, i + 1, fn, N - 1))
return (True);
s[i] = c;
}
return (False);
}
static BOOL string_combinations(char *s, BOOL (*fn) (char *), int N)
{
int n;
for (n = 1; n <= N; n++)
if (string_combinations2(s, 0, fn, n))
return (True);
return (False);
}
static BOOL password_check(char *password)
{
#ifdef WITH_PAM
return (NT_STATUS_IS_OK(smb_pam_passcheck(this_user, password)));
#endif
#ifdef WITH_AFS
if (afs_auth(this_user, password))
return (True);
#endif
#ifdef WITH_DFS
if (dfs_auth(this_user, password))
return (True);
#endif
#ifdef KRB5_AUTH
if (krb5_auth(this_user, password))
return (True);
#endif
#ifdef KRB4_AUTH
if (krb4_auth(this_user, password))
return (True);
#endif
#ifdef OSF1_ENH_SEC
{
BOOL 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);
}
return ret;
}
#endif
#ifdef ULTRIX_AUTH
return (strcmp((char *)crypt16(password, this_salt), this_crypted) == 0);
#endif
#ifdef LINUX_BIGCRYPT
return (linux_bigcrypt(password, this_salt, this_crypted));
#endif
#if defined(HAVE_BIGCRYPT) && defined(HAVE_CRYPT) && defined(USE_BOTH_CRYPT_CALLS)
if (strcmp(bigcrypt(password, this_salt), this_crypted) == 0)
return True;
else
return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
#else
#ifdef HAVE_BIGCRYPT
return (strcmp(bigcrypt(password, this_salt), this_crypted) == 0);
#endif
#ifndef HAVE_CRYPT
DEBUG(1, ("Warning - no crypt available\n"));
return (False);
#else
return (strcmp((char *)crypt(password, this_salt), this_crypted) == 0);
#endif
#endif
}
BOOL pass_check(char *user, char *password, int pwlen, struct passwd *pwd,
BOOL (*fn) (char *, char *))
{
pstring pass2;
int level = lp_passwordlevel();
struct passwd *pass = NULL;
if (password)
password[pwlen] = 0;
#if DEBUG_PASSWORD
DEBUG(100, ("checking user=[%s] pass=[%s]\n", user, password));
#endif
if (!password)
return (False);
if (((!*password) || (!pwlen)) && !lp_null_passwords())
return (False);
if (pwd && !user) {
pass = (struct passwd *)pwd;
user = pass->pw_name;
} else {
pass = Get_Pwnam(user, True);
}
#ifdef 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 (False);
}
#ifdef HAVE_GETSPNAM
{
struct spwd *spass;
spass = getspnam(pass->pw_name);
if (spass && spass->sp_pwdp)
pstrcpy(pass->pw_passwd, 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)
pstrcpy(pass->pw_passwd, pr_pw->ufld.fd_encrypt);
}
#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(pass->pw_name, mypasswd->ufld.fd_name);
fstrcpy(pass->pw_passwd, 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(pass->pw_passwd, ap->a_password);
endauthent();
}
}
#endif
fstrcpy(this_user, pass->pw_name);
fstrcpy(this_salt, pass->pw_passwd);
#if defined(HAVE_TRUNCATED_SALT)
this_salt[2] = 0;
#endif
fstrcpy(this_crypted, pass->pw_passwd);
if (!*this_crypted) {
if (!lp_null_passwords()) {
DEBUG(2, ("Disallowing %s with null password\n",
this_user));
return (False);
}
if (!*password) {
DEBUG(3,
("Allowing access to %s with null password\n",
this_user));
return (True);
}
}
#endif
if (password_check(password)) {
if (fn)
fn(user, password);
return (True);
}
if (strhasupper(password) && strhaslower(password)) {
return (False);
}
StrnCpy(pass2, password, sizeof(pass2) - 1);
if (strhasupper(password)) {
strlower(password);
if (password_check(password)) {
if (fn)
fn(user, password);
return (True);
}
}
if (level < 1) {
fstrcpy(password, pass2);
return (False);
}
strlower(password);
if (string_combinations(password, password_check, level)) {
if (fn)
fn(user, password);
return (True);
}
fstrcpy(password, pass2);
return (False);
}