split the system password checking routines out of smbd/password.c and
authorAndrew Tridgell <tridge@samba.org>
Mon, 10 Aug 1998 07:04:53 +0000 (07:04 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 10 Aug 1998 07:04:53 +0000 (07:04 +0000)
into passdb/pass_check.c. This means SWAT no longer needs to link to
smbd/password.c

source/Makefile.in
source/auth/pass_check.c [new file with mode: 0644]
source/include/proto.h
source/passdb/pass_check.c [new file with mode: 0644]
source/smbd/password.c
source/smbd/server.c
source/web/cgi.c

index 7a31b2b4425a4bf70e522daf347a281682a7c772..1f975d48c594f90ecfde8dca4e36c6613ac2e610 100644 (file)
@@ -116,15 +116,15 @@ RPC_CLIENT_OBJ = rpc_client/cli_login.o rpc_client/cli_netlogon.o \
 LOCKING_OBJ = locking/locking.o locking/locking_shm.o locking/locking_slow.o \
               locking/shmem.o locking/shmem_sysv.o
 
-PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o 
+PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \
+             passdb/pass_check.o
 
 SMBD_OBJ1 = smbd/server.o smbd/access.o smbd/chgpasswd.o smbd/connection.o \
             smbd/dfree.o smbd/dir.o smbd/password.o \
             smbd/groupname.o smbd/ipc.o smbd/ldap.o smbd/mangle.o \
             smbd/message.o smbd/nispass.o smbd/nttrans.o \
-            smbd/pipes.o smbd/predict.o \
-            smbd/print_svid.o smbd/printing.o smbd/quotas.o smbd/reply.o \
-            smbd/ssl.o smbd/trans2.o smbd/uid.o 
+            smbd/pipes.o smbd/predict.o smbd/print_svid.o smbd/printing.o \
+            smbd/quotas.o smbd/reply.o smbd/ssl.o smbd/trans2.o smbd/uid.o 
 
 SMBD_OBJ = $(SMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
            $(RPC_SERVER_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \
@@ -148,9 +148,7 @@ NMBD_OBJ = $(NMBD_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
            $(PASSDB_OBJ) $(LIB_OBJ)
 
 SWAT_OBJ = web/cgi.o web/diagnose.o web/startstop.o web/statuspage.o \
-           web/swat.o \
-           smbd/password.o \
-           $(LIBSMB_OBJ) $(LOCKING_OBJ) \
+           web/swat.o $(LIBSMB_OBJ) $(LOCKING_OBJ) \
            $(PARAM_OBJ) $(PASSDB_OBJ) $(RPC_CLIENT_OBJ) $(RPC_PARSE_OBJ) \
            $(UBIQX_OBJ) $(LIB_OBJ)
 
diff --git a/source/auth/pass_check.c b/source/auth/pass_check.c
new file mode 100644 (file)
index 0000000..b5aa832
--- /dev/null
@@ -0,0 +1,950 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Password checking
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this module is for checking a username/password against a system
+   password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/* these are kept here to keep the string_combinations function simple */
+static char this_user[100]="";
+static char this_salt[100]="";
+static char this_crypted[100]="";
+
+
+/****************************************************************************
+update the enhanced security database. Only relevant for OSF1 at the moment.
+****************************************************************************/
+static void update_protected_database(char *user, BOOL result)
+{
+#ifdef OSF1_ENH_SEC
+       struct pr_passwd *mypasswd;
+       time_t starttime;
+
+       mypasswd = getprpwnam (user);
+       starttime = time (NULL);
+
+       if (result)  {
+               mypasswd->ufld.fd_slogin = starttime;
+               mypasswd->ufld.fd_nlogins = 0;
+      
+               putprpwnam(user,mypasswd);
+       } else {
+               mypasswd->ufld.fd_ulogin = starttime;
+               mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
+               if (mypasswd->ufld.fd_max_tries != 0 && 
+                   mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries) {
+                       mypasswd->uflg.fg_lock = 0;
+                       DEBUG(3,("Account %s is disabled\n", user));
+               }
+               putprpwnam(user ,mypasswd);
+       }
+#endif
+}
+
+
+#ifdef HAVE_PAM
+/*******************************************************************
+check on PAM authentication
+********************************************************************/
+
+/* We first need some helper functions */
+#include <security/pam_appl.h>
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int PAM_conv (int num_msg,
+                     const struct pam_message **msg,
+                     struct pam_response **resp,
+                     void *appdata_ptr) {
+  int replies = 0;
+  struct pam_response *reply = NULL;
+
+  #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+  reply = malloc(sizeof(struct pam_response) * num_msg);
+  if (!reply) return PAM_CONV_ERR;
+
+  for (replies = 0; replies < num_msg; replies++) {
+    switch (msg[replies]->msg_style) {
+      case PAM_PROMPT_ECHO_ON:
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = COPY_STRING(PAM_username);
+          /* PAM frees resp */
+        break;
+      case PAM_PROMPT_ECHO_OFF:
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = COPY_STRING(PAM_password);
+          /* PAM frees resp */
+        break;
+      case PAM_TEXT_INFO:
+       /* fall through */
+      case PAM_ERROR_MSG:
+        /* ignore it... */
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = NULL;
+        break;
+      default:
+        /* Must be an error of some sort... */
+        free (reply);
+        return PAM_CONV_ERR;
+    }
+  }
+  if (reply) *resp = reply;
+  return PAM_SUCCESS;
+}
+static struct pam_conv PAM_conversation = {
+    &PAM_conv,
+    NULL
+};
+
+
+static BOOL pam_auth(char *this_user,char *password)
+{
+  pam_handle_t *pamh;
+  int pam_error;
+
+  /* Now use PAM to do authentication.  For now, we won't worry about
+   * session logging, only authentication.  Bail out if there are any
+   * errors.  Since this is a limited protocol, and an even more limited
+   * function within a server speaking this protocol, we can't be as
+   * verbose as would otherwise make sense.
+   * Query: should we be using PAM_SILENT to shut PAM up?
+   */
+  #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
+     pam_end(pamh, 0); return False; \
+   }
+  PAM_password = password;
+  PAM_username = this_user;
+  pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
+  PAM_BAIL;
+/* Setting PAM_SILENT stops generation of error messages to syslog
+ * to enable debugging on Red Hat Linux set:
+ * /etc/pam.d/samba:
+ *     auth required /lib/security/pam_pwdb.so nullok shadow audit
+ * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
+ */
+  pam_error = pam_authenticate(pamh, PAM_SILENT);
+  PAM_BAIL;
+  /* It is not clear to me that account management is the right thing
+   * to do, but it is not clear that it isn't, either.  This can be
+   * removed if no account management should be done.  Alternately,
+   * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+  pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
+  PAM_BAIL;
+  pam_end(pamh, PAM_SUCCESS);
+  /* If this point is reached, the user has been authenticated. */
+  return(True);
+}
+#endif
+
+
+#ifdef WITH_AFS
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static BOOL afs_auth(char *this_user,char *password)
+{
+       long password_expires = 0;
+       char *reason;
+    
+       /* For versions of AFS prior to 3.3, this routine has few arguments, */
+       /* but since I can't find the old documentation... :-)               */
+       setpag();
+       if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
+                                      this_user,
+                                      (char *) 0, /* instance */
+                                      (char *) 0, /* cell */
+                                      password,
+                                      0,          /* lifetime, default */
+                                      &password_expires, /*days 'til it expires */
+                                      0,          /* spare 2 */
+                                      &reason) == 0) {
+               return(True);
+       }
+       return(False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+  - Server credentials may expire
+  - Client credential cache files have wrong owner
+  - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static BOOL dfs_auth(char *this_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];
+
+       if (dcelogin_atmost_once) return(False);
+
+#ifdef HAVE_CRYPT
+       /*
+        * We only go for a DCE login context if the given password
+        * matches that stored in the local password file.. 
+        * Assumes local passwd file is kept in sync w/ DCE RGY!
+        */
+
+       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(&current_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 *)this_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",
+                        this_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);
+       }
+
+       /*
+        * NB. I'd like to change these to call something like become_user()
+        * instead but currently we don't have a connection
+        * context to become the correct user. This is already
+        * fairly platform specific code however, so I think
+        * this should be ok. I have added code to go
+        * back to being root on error though. JRA.
+        */
+       
+       if (setregid(-1, pw->pw_gid) != 0) {
+               DEBUG(0,("Can't set egid to %d (%s)\n", 
+                        pw->pw_gid, strerror(errno)));
+               return False;
+       }
+
+       if (setreuid(-1, pw->pw_uid) != 0) {
+               setgid(0);
+               DEBUG(0,("Can't set euid to %d (%s)\n", 
+                        pw->pw_uid, strerror(errno)));
+               return False;
+       }
+       if (sec_login_setup_identity((unsigned char *)this_user,
+                                    sec_login_no_flags,
+                                    &my_dce_sec_context,
+                                    &err) == 0) {
+               dce_error_inq_text(err, dce_errstr, &err2);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
+                        this_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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
+               
+               return(False);
+       }
+
+       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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
+                        this_user,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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
+               
+               return(False);
+       }
+
+       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",
+                        this_user,dce_errstr));
+               
+               sec_login_purge_context(&my_dce_sec_context, &err);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               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));
+
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               return(False);
+       }
+       
+       DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
+                this_user, 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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
+               
+               return(False);
+       }
+       
+       setuid(0);
+       setgid(0);
+       
+       DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
+       
+       dcelogin_atmost_once = 1;
+       return (True);
+}
+
+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",
+                        getpid(), dce_errstr));
+       }
+}
+#endif
+
+#ifdef KRB5_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb5_auth(char *this_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, this_user, &kprinc)) {
+               return(False);
+       }
+
+       memset((char *)&kcreds, 0, sizeof(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 /* KRB5_AUTH */
+
+#ifdef KRB4_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb4_auth(char *this_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", 
+                       getpid());
+  
+       krb_set_tkt_string(tkfile);
+       if (krb_verify_user(this_user, "", realm,
+                           password, 0,
+                           "rmcd") == KSUCCESS) {
+               unlink(tkfile);
+               return 1;
+       }
+       unlink(tkfile);
+       return 0;
+}
+#endif /* KRB4_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+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
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+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);
+
+       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
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+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);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+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);
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static BOOL password_check(char *password)
+{
+
+#ifdef HAVE_PAM
+       /* This falls through if the password check fails
+          - if HAVE_CRYPT is not defined this causes an error msg
+          saying Warning - no crypt available
+          - if HAVE_CRYPT is defined this is a potential security hole
+          as it may authenticate via the crypt call when PAM
+          settings say it should fail.
+          if (pam_auth(this_user,password)) return(True);
+          Hence we make a direct return to avoid a second chance!!!
+       */
+       return (pam_auth(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
+
+#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
+}
+
+
+
+/****************************************************************************
+check if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file 
+return True on correct match, False otherwise
+****************************************************************************/
+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;
+
+       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);
+       }
+
+
+       DEBUG(4,("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;
+
+               /* many shadow systems require you to be root to get
+                  the password, in most cases this should already be
+                  the case when this function is called, except
+                  perhaps for IPC password changing requests */
+
+               spass = getspnam(pass->pw_name);
+               if (spass && spass->sp_pwdp) {
+                       pass->pw_passwd = spass->sp_pwdp;
+               }
+       }
+#elif defined(IA_UINFO)
+       {
+               /* Need to get password with SVR4.2's ia_ functions
+                  instead of get{sp,pw}ent functions. Required by
+                  UnixWare 2.x, tested on version
+                  2.1. (tangent@cyberport.com) */
+               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)
+                       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,("No entry for user %s in protected database !\n",
+                                user));
+                       return(False);
+               }
+       }
+#endif
+
+#ifdef ULTRIX_AUTH
+       {
+               AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+               if (ap) {
+                       fstrcpy(pass->pw_passwd, ap->a_password);
+                       endauthent();
+               }
+       }
+#endif
+
+       /* extract relevant info */
+       fstrcpy(this_user,pass->pw_name);  
+       fstrcpy(this_salt,pass->pw_passwd);
+       /* crypt on some platforms (HPUX in particular)
+          won't work with more than 2 salt characters. */
+       this_salt[2] = 0;
+       
+       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);
+               }
+       }
+
+       /* try it as it came to us */
+       if (password_check(password)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       /* if the password was given to us with mixed case then we don't
+          need to proceed as we know it hasn't been case modified by the
+          client */
+       if (strhasupper(password) && strhaslower(password)) {
+               return(False);
+       }
+
+       /* make a copy of it */
+       StrnCpy(pass2,password,sizeof(pstring)-1);
+  
+       /* try all lowercase */
+       strlower(password);
+       if (password_check(password)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       /* give up? */
+       if (level < 1) {
+               update_protected_database(user,False);
+
+               /* restore it */
+               fstrcpy(password,pass2);
+               
+               return(False);
+       }
+
+       /* last chance - all combinations of up to level chars upper! */
+       strlower(password);
+
+       if (string_combinations(password,password_check,level)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       update_protected_database(user,False);
+  
+       /* restore it */
+       fstrcpy(password,pass2);
+  
+       return(False);
+}
index 558e17acabf5ed7136c7a4b3b458189df34b4578..d9a35aa33f461b54477c1b2486d413e3805f22d4 100644 (file)
@@ -185,6 +185,13 @@ time_t get_create_time(struct stat *st,BOOL fake_dirs);
 
 char *ufc_crypt(char *key,char *salt);
 
+/*The following definitions come from  lib/username.c  */
+
+char *get_home_dir(char *user);
+BOOL map_username(char *user);
+struct passwd *Get_Pwnam(char *user,BOOL allow_change);
+BOOL user_in_list(char *user,char *list);
+
 /*The following definitions come from  lib/util.c  */
 
 char *tmpdir(void);
@@ -1067,6 +1074,12 @@ BOOL pm_process( char *FileName,
 BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
 void pcap_printer_fn(void (*fn)(char *, char *));
 
+/*The following definitions come from  passdb/pass_check.c  */
+
+void dfs_unlogin(void);
+BOOL pass_check(char *user,char *password, int pwlen, struct passwd *pwd,
+               BOOL (*fn)(char *, char *));
+
 /*The following definitions come from  passdb/passdb.c  */
 
 BOOL initialize_password_db(void);
@@ -1134,13 +1147,6 @@ BOOL trust_password_delete( char *domain, char *name );
 BOOL get_trust_account_password( unsigned char *ret_pwd, time_t *pass_last_set_time);
 BOOL set_trust_account_password( unsigned char *md4_new_pwd);
 
-/*The following definitions come from  passdb/username.c  */
-
-char *get_home_dir(char *user);
-BOOL map_username(char *user);
-struct passwd *Get_Pwnam(char *user,BOOL allow_change);
-BOOL user_in_list(char *user,char *list);
-
 /*The following definitions come from  rpc_client/cli_login.c  */
 
 BOOL cli_nt_setup_creds(struct cli_state *cli, unsigned char mach_pwd[16]);
@@ -1947,9 +1953,7 @@ char *validated_username(uint16 vuid);
 int setup_groups(char *user, int uid, int gid, int *p_ngroups, GID_T **p_groups);
 uint16 register_vuid(int uid,int gid, char *unix_name, char *requested_name, BOOL guest);
 void add_session_user(char *user);
-BOOL update_smbpassword_file( char *user, fstring password);
-void dfs_unlogin(void);
-BOOL password_check(char *password);
+BOOL update_smbpassword_file(char *user, char *password);
 BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned char *c8);
 BOOL smb_password_ok(struct smb_passwd *smb_pass,
                      uchar lm_pass[24], uchar nt_pass[24]);
diff --git a/source/passdb/pass_check.c b/source/passdb/pass_check.c
new file mode 100644 (file)
index 0000000..b5aa832
--- /dev/null
@@ -0,0 +1,950 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Password checking
+   Copyright (C) Andrew Tridgell 1992-1998
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* this module is for checking a username/password against a system
+   password database. The SMB encrypted password support is elsewhere */
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/* these are kept here to keep the string_combinations function simple */
+static char this_user[100]="";
+static char this_salt[100]="";
+static char this_crypted[100]="";
+
+
+/****************************************************************************
+update the enhanced security database. Only relevant for OSF1 at the moment.
+****************************************************************************/
+static void update_protected_database(char *user, BOOL result)
+{
+#ifdef OSF1_ENH_SEC
+       struct pr_passwd *mypasswd;
+       time_t starttime;
+
+       mypasswd = getprpwnam (user);
+       starttime = time (NULL);
+
+       if (result)  {
+               mypasswd->ufld.fd_slogin = starttime;
+               mypasswd->ufld.fd_nlogins = 0;
+      
+               putprpwnam(user,mypasswd);
+       } else {
+               mypasswd->ufld.fd_ulogin = starttime;
+               mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
+               if (mypasswd->ufld.fd_max_tries != 0 && 
+                   mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries) {
+                       mypasswd->uflg.fg_lock = 0;
+                       DEBUG(3,("Account %s is disabled\n", user));
+               }
+               putprpwnam(user ,mypasswd);
+       }
+#endif
+}
+
+
+#ifdef HAVE_PAM
+/*******************************************************************
+check on PAM authentication
+********************************************************************/
+
+/* We first need some helper functions */
+#include <security/pam_appl.h>
+/* Static variables used to communicate between the conversation function
+ * and the server_login function
+ */
+static char *PAM_username;
+static char *PAM_password;
+
+/* PAM conversation function
+ * Here we assume (for now, at least) that echo on means login name, and
+ * echo off means password.
+ */
+static int PAM_conv (int num_msg,
+                     const struct pam_message **msg,
+                     struct pam_response **resp,
+                     void *appdata_ptr) {
+  int replies = 0;
+  struct pam_response *reply = NULL;
+
+  #define COPY_STRING(s) (s) ? strdup(s) : NULL
+
+  reply = malloc(sizeof(struct pam_response) * num_msg);
+  if (!reply) return PAM_CONV_ERR;
+
+  for (replies = 0; replies < num_msg; replies++) {
+    switch (msg[replies]->msg_style) {
+      case PAM_PROMPT_ECHO_ON:
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = COPY_STRING(PAM_username);
+          /* PAM frees resp */
+        break;
+      case PAM_PROMPT_ECHO_OFF:
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = COPY_STRING(PAM_password);
+          /* PAM frees resp */
+        break;
+      case PAM_TEXT_INFO:
+       /* fall through */
+      case PAM_ERROR_MSG:
+        /* ignore it... */
+        reply[replies].resp_retcode = PAM_SUCCESS;
+        reply[replies].resp = NULL;
+        break;
+      default:
+        /* Must be an error of some sort... */
+        free (reply);
+        return PAM_CONV_ERR;
+    }
+  }
+  if (reply) *resp = reply;
+  return PAM_SUCCESS;
+}
+static struct pam_conv PAM_conversation = {
+    &PAM_conv,
+    NULL
+};
+
+
+static BOOL pam_auth(char *this_user,char *password)
+{
+  pam_handle_t *pamh;
+  int pam_error;
+
+  /* Now use PAM to do authentication.  For now, we won't worry about
+   * session logging, only authentication.  Bail out if there are any
+   * errors.  Since this is a limited protocol, and an even more limited
+   * function within a server speaking this protocol, we can't be as
+   * verbose as would otherwise make sense.
+   * Query: should we be using PAM_SILENT to shut PAM up?
+   */
+  #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
+     pam_end(pamh, 0); return False; \
+   }
+  PAM_password = password;
+  PAM_username = this_user;
+  pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
+  PAM_BAIL;
+/* Setting PAM_SILENT stops generation of error messages to syslog
+ * to enable debugging on Red Hat Linux set:
+ * /etc/pam.d/samba:
+ *     auth required /lib/security/pam_pwdb.so nullok shadow audit
+ * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
+ */
+  pam_error = pam_authenticate(pamh, PAM_SILENT);
+  PAM_BAIL;
+  /* It is not clear to me that account management is the right thing
+   * to do, but it is not clear that it isn't, either.  This can be
+   * removed if no account management should be done.  Alternately,
+   * put a pam_allow.so entry in /etc/pam.conf for account handling. */
+  pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
+  PAM_BAIL;
+  pam_end(pamh, PAM_SUCCESS);
+  /* If this point is reached, the user has been authenticated. */
+  return(True);
+}
+#endif
+
+
+#ifdef WITH_AFS
+/*******************************************************************
+check on AFS authentication
+********************************************************************/
+static BOOL afs_auth(char *this_user,char *password)
+{
+       long password_expires = 0;
+       char *reason;
+    
+       /* For versions of AFS prior to 3.3, this routine has few arguments, */
+       /* but since I can't find the old documentation... :-)               */
+       setpag();
+       if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
+                                      this_user,
+                                      (char *) 0, /* instance */
+                                      (char *) 0, /* cell */
+                                      password,
+                                      0,          /* lifetime, default */
+                                      &password_expires, /*days 'til it expires */
+                                      0,          /* spare 2 */
+                                      &reason) == 0) {
+               return(True);
+       }
+       return(False);
+}
+#endif
+
+
+#ifdef WITH_DFS
+
+/*****************************************************************
+ This new version of the DFS_AUTH code was donated by Karsten Muuss
+ <muuss@or.uni-bonn.de>. It fixes the following problems with the
+ old code :
+
+  - Server credentials may expire
+  - Client credential cache files have wrong owner
+  - purge_context() function is called with invalid argument
+
+ This new code was modified to ensure that on exit the uid/gid is
+ still root, and the original directory is restored. JRA.
+******************************************************************/
+
+sec_login_handle_t my_dce_sec_context;
+int dcelogin_atmost_once = 0;
+
+/*******************************************************************
+check on a DCE/DFS authentication
+********************************************************************/
+static BOOL dfs_auth(char *this_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];
+
+       if (dcelogin_atmost_once) return(False);
+
+#ifdef HAVE_CRYPT
+       /*
+        * We only go for a DCE login context if the given password
+        * matches that stored in the local password file.. 
+        * Assumes local passwd file is kept in sync w/ DCE RGY!
+        */
+
+       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(&current_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 *)this_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",
+                        this_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);
+       }
+
+       /*
+        * NB. I'd like to change these to call something like become_user()
+        * instead but currently we don't have a connection
+        * context to become the correct user. This is already
+        * fairly platform specific code however, so I think
+        * this should be ok. I have added code to go
+        * back to being root on error though. JRA.
+        */
+       
+       if (setregid(-1, pw->pw_gid) != 0) {
+               DEBUG(0,("Can't set egid to %d (%s)\n", 
+                        pw->pw_gid, strerror(errno)));
+               return False;
+       }
+
+       if (setreuid(-1, pw->pw_uid) != 0) {
+               setgid(0);
+               DEBUG(0,("Can't set euid to %d (%s)\n", 
+                        pw->pw_uid, strerror(errno)));
+               return False;
+       }
+       if (sec_login_setup_identity((unsigned char *)this_user,
+                                    sec_login_no_flags,
+                                    &my_dce_sec_context,
+                                    &err) == 0) {
+               dce_error_inq_text(err, dce_errstr, &err2);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
+                        this_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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
+               
+               return(False);
+       }
+
+       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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
+                        this_user,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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
+               
+               return(False);
+       }
+
+       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",
+                        this_user,dce_errstr));
+               
+               sec_login_purge_context(&my_dce_sec_context, &err);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               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));
+
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               return(False);
+       }
+       
+       DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
+                this_user, 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);
+               /* Go back to root, JRA. */
+               setuid(0);
+               setgid(0);
+               DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
+               
+               return(False);
+       }
+       
+       setuid(0);
+       setgid(0);
+       
+       DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
+       
+       dcelogin_atmost_once = 1;
+       return (True);
+}
+
+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",
+                        getpid(), dce_errstr));
+       }
+}
+#endif
+
+#ifdef KRB5_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb5_auth(char *this_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, this_user, &kprinc)) {
+               return(False);
+       }
+
+       memset((char *)&kcreds, 0, sizeof(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 /* KRB5_AUTH */
+
+#ifdef KRB4_AUTH
+/*******************************************************************
+check on Kerberos authentication
+********************************************************************/
+static BOOL krb4_auth(char *this_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", 
+                       getpid());
+  
+       krb_set_tkt_string(tkfile);
+       if (krb_verify_user(this_user, "", realm,
+                           password, 0,
+                           "rmcd") == KSUCCESS) {
+               unlink(tkfile);
+               return 1;
+       }
+       unlink(tkfile);
+       return 0;
+}
+#endif /* KRB4_AUTH */
+
+#ifdef LINUX_BIGCRYPT
+/****************************************************************************
+an enhanced crypt for Linux to handle password longer than 8 characters
+****************************************************************************/
+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
+/****************************************************************************
+an enhanced crypt for OSF1
+****************************************************************************/
+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);
+
+       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
+
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+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);
+}
+
+/****************************************************************************
+apply a function to upper/lower case combinations
+of a string and return true if one of them returns true.
+try all combinations with up to N uppercase letters.
+offset is the first char to try and change (start with 0)
+it assumes the string starts lowercased
+****************************************************************************/
+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);
+}
+
+
+/****************************************************************************
+core of password checking routine
+****************************************************************************/
+static BOOL password_check(char *password)
+{
+
+#ifdef HAVE_PAM
+       /* This falls through if the password check fails
+          - if HAVE_CRYPT is not defined this causes an error msg
+          saying Warning - no crypt available
+          - if HAVE_CRYPT is defined this is a potential security hole
+          as it may authenticate via the crypt call when PAM
+          settings say it should fail.
+          if (pam_auth(this_user,password)) return(True);
+          Hence we make a direct return to avoid a second chance!!!
+       */
+       return (pam_auth(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
+
+#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
+}
+
+
+
+/****************************************************************************
+check if a username/password is OK
+the function pointer fn() points to a function to call when a successful
+match is found and is used to update the encrypted password file 
+return True on correct match, False otherwise
+****************************************************************************/
+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;
+
+       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);
+       }
+
+
+       DEBUG(4,("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;
+
+               /* many shadow systems require you to be root to get
+                  the password, in most cases this should already be
+                  the case when this function is called, except
+                  perhaps for IPC password changing requests */
+
+               spass = getspnam(pass->pw_name);
+               if (spass && spass->sp_pwdp) {
+                       pass->pw_passwd = spass->sp_pwdp;
+               }
+       }
+#elif defined(IA_UINFO)
+       {
+               /* Need to get password with SVR4.2's ia_ functions
+                  instead of get{sp,pw}ent functions. Required by
+                  UnixWare 2.x, tested on version
+                  2.1. (tangent@cyberport.com) */
+               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)
+                       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,("No entry for user %s in protected database !\n",
+                                user));
+                       return(False);
+               }
+       }
+#endif
+
+#ifdef ULTRIX_AUTH
+       {
+               AUTHORIZATION *ap = getauthuid(pass->pw_uid);
+               if (ap) {
+                       fstrcpy(pass->pw_passwd, ap->a_password);
+                       endauthent();
+               }
+       }
+#endif
+
+       /* extract relevant info */
+       fstrcpy(this_user,pass->pw_name);  
+       fstrcpy(this_salt,pass->pw_passwd);
+       /* crypt on some platforms (HPUX in particular)
+          won't work with more than 2 salt characters. */
+       this_salt[2] = 0;
+       
+       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);
+               }
+       }
+
+       /* try it as it came to us */
+       if (password_check(password)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       /* if the password was given to us with mixed case then we don't
+          need to proceed as we know it hasn't been case modified by the
+          client */
+       if (strhasupper(password) && strhaslower(password)) {
+               return(False);
+       }
+
+       /* make a copy of it */
+       StrnCpy(pass2,password,sizeof(pstring)-1);
+  
+       /* try all lowercase */
+       strlower(password);
+       if (password_check(password)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       /* give up? */
+       if (level < 1) {
+               update_protected_database(user,False);
+
+               /* restore it */
+               fstrcpy(password,pass2);
+               
+               return(False);
+       }
+
+       /* last chance - all combinations of up to level chars upper! */
+       strlower(password);
+
+       if (string_combinations(password,password_check,level)) {
+               update_protected_database(user,True);
+               if (fn) fn(user,password);
+               return(True);
+       }
+
+       update_protected_database(user,False);
+  
+       /* restore it */
+       fstrcpy(password,pass2);
+  
+       return(False);
+}
index 0f8e33940f5711c633281c4334e7116eb79b5633..055c53d009d9798b68d2669bb956a539a44cf707 100644 (file)
@@ -36,11 +36,6 @@ static pstring session_users="";
 extern pstring global_myname;
 extern fstring global_myworkgroup;
 
-/* these are kept here to keep the string_combinations function simple */
-static char this_user[100]="";
-static char this_salt[100]="";
-static char this_crypted[100]="";
-
 /* Data to do lanman1/2 password challenge. */
 static unsigned char saved_challenge[8];
 static BOOL challenge_sent=False;
@@ -305,779 +300,36 @@ void add_session_user(char *user)
 }
 
 
-#ifdef OSF1_ENH_SEC
-/****************************************************************************
-an enhanced crypt for OSF1
-****************************************************************************/
-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);
-
-  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
-
 /****************************************************************************
 update the encrypted smbpasswd file from the plaintext username and password
 *****************************************************************************/
-BOOL update_smbpassword_file( char *user, fstring password)
-{
-  struct smb_passwd *smbpw;
-  BOOL ret;
-
-  become_root(0);
-  smbpw = getsmbpwnam(user);
-  unbecome_root(0);
-
-  if(smbpw == NULL)
-  {
-    DEBUG(0,("update_smbpassword_file: getsmbpwnam returned NULL\n"));
-    return False;
-  }
-  /* Here, the flag is one, because we want to ignore the XXXXXXX'd out password */
-  ret = change_oem_password( smbpw, password, True);
-  if (ret == False)
-    DEBUG(3,("update_smbpasswd_file: change_oem_password returned False\n"));
-
-  return ret;
-}
-
-/****************************************************************************
-update the enhanced security database. Only relevant for OSF1 at the moment.
-****************************************************************************/
-static void update_protected_database( char *user, BOOL result)
-{
-#ifdef OSF1_ENH_SEC
-  struct pr_passwd *mypasswd;
-  time_t starttime;
-
-  mypasswd = getprpwnam (user);
-  starttime = time (NULL);
-
-  if (result)
-    {
-      mypasswd->ufld.fd_slogin = starttime;
-      mypasswd->ufld.fd_nlogins = 0;
-      
-      putprpwnam(user,mypasswd);
-      
-      DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
-    }
-  else
-    {
-      mypasswd->ufld.fd_ulogin = starttime;
-      mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
-      if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
-       {
-         mypasswd->uflg.fg_lock = 0;
-         DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
-       }
-      putprpwnam ( user , mypasswd );
-      DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
-    }
-#else
-  DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
-#endif
-}
-
-
-#ifdef HAVE_PAM
-/*******************************************************************
-check on PAM authentication
-********************************************************************/
-
-/* We first need some helper functions */
-#include <security/pam_appl.h>
-/* Static variables used to communicate between the conversation function
- * and the server_login function
- */
-static char *PAM_username;
-static char *PAM_password;
-
-/* PAM conversation function
- * Here we assume (for now, at least) that echo on means login name, and
- * echo off means password.
- */
-static int PAM_conv (int num_msg,
-                     const struct pam_message **msg,
-                     struct pam_response **resp,
-                     void *appdata_ptr) {
-  int replies = 0;
-  struct pam_response *reply = NULL;
-
-  #define COPY_STRING(s) (s) ? strdup(s) : NULL
-
-  reply = malloc(sizeof(struct pam_response) * num_msg);
-  if (!reply) return PAM_CONV_ERR;
-
-  for (replies = 0; replies < num_msg; replies++) {
-    switch (msg[replies]->msg_style) {
-      case PAM_PROMPT_ECHO_ON:
-        reply[replies].resp_retcode = PAM_SUCCESS;
-        reply[replies].resp = COPY_STRING(PAM_username);
-          /* PAM frees resp */
-        break;
-      case PAM_PROMPT_ECHO_OFF:
-        reply[replies].resp_retcode = PAM_SUCCESS;
-        reply[replies].resp = COPY_STRING(PAM_password);
-          /* PAM frees resp */
-        break;
-      case PAM_TEXT_INFO:
-       /* fall through */
-      case PAM_ERROR_MSG:
-        /* ignore it... */
-        reply[replies].resp_retcode = PAM_SUCCESS;
-        reply[replies].resp = NULL;
-        break;
-      default:
-        /* Must be an error of some sort... */
-        free (reply);
-        return PAM_CONV_ERR;
-    }
-  }
-  if (reply) *resp = reply;
-  return PAM_SUCCESS;
-}
-static struct pam_conv PAM_conversation = {
-    &PAM_conv,
-    NULL
-};
-
-
-static BOOL pam_auth(char *this_user,char *password)
+BOOL update_smbpassword_file(char *user, char *password)
 {
-  pam_handle_t *pamh;
-  int pam_error;
-
-  /* Now use PAM to do authentication.  For now, we won't worry about
-   * session logging, only authentication.  Bail out if there are any
-   * errors.  Since this is a limited protocol, and an even more limited
-   * function within a server speaking this protocol, we can't be as
-   * verbose as would otherwise make sense.
-   * Query: should we be using PAM_SILENT to shut PAM up?
-   */
-  #define PAM_BAIL if (pam_error != PAM_SUCCESS) { \
-     pam_end(pamh, 0); return False; \
-   }
-  PAM_password = password;
-  PAM_username = this_user;
-  pam_error = pam_start("samba", this_user, &PAM_conversation, &pamh);
-  PAM_BAIL;
-/* Setting PAM_SILENT stops generation of error messages to syslog
- * to enable debugging on Red Hat Linux set:
- * /etc/pam.d/samba:
- *     auth required /lib/security/pam_pwdb.so nullok shadow audit
- * _OR_ change PAM_SILENT to 0 to force detailed reporting (logging)
- */
-  pam_error = pam_authenticate(pamh, PAM_SILENT);
-  PAM_BAIL;
-  /* It is not clear to me that account management is the right thing
-   * to do, but it is not clear that it isn't, either.  This can be
-   * removed if no account management should be done.  Alternately,
-   * put a pam_allow.so entry in /etc/pam.conf for account handling. */
-  pam_error = pam_acct_mgmt(pamh, PAM_SILENT);
-  PAM_BAIL;
-  pam_end(pamh, PAM_SUCCESS);
-  /* If this point is reached, the user has been authenticated. */
-  return(True);
-}
-#endif
-
-
-#ifdef WITH_AFS
-/*******************************************************************
-check on AFS authentication
-********************************************************************/
-static BOOL afs_auth(char *this_user,char *password)
-{
-  long password_expires = 0;
-  char *reason;
-    
-  /* For versions of AFS prior to 3.3, this routine has few arguments, */
-  /* but since I can't find the old documentation... :-)               */
-  setpag();
-  if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG,
-                                this_user,
-                                (char *) 0, /* instance */
-                                (char *) 0, /* cell */
-                                password,
-                                0,          /* lifetime, default */
-                                &password_expires, /*days 'til it expires */
-                                0,          /* spare 2 */
-                                &reason) == 0)
-    return(True);
-  return(False);
-}
-#endif
-
-
-#ifdef WITH_DFS
-
-/*****************************************************************
- This new version of the DFS_AUTH code was donated by Karsten Muuss
- <muuss@or.uni-bonn.de>. It fixes the following problems with the
- old code :
-
-  - Server credentials may expire
-  - Client credential cache files have wrong owner
-  - purge_context() function is called with invalid argument
-
- This new code was modified to ensure that on exit the uid/gid is
- still root, and the original directory is restored. JRA.
-******************************************************************/
-
-sec_login_handle_t my_dce_sec_context;
-int dcelogin_atmost_once = 0;
-
-/*******************************************************************
-check on a DCE/DFS authentication
-********************************************************************/
-static BOOL dfs_auth(char *this_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];
-
-  if (dcelogin_atmost_once) return(False);
-
-#ifdef HAVE_CRYPT
-  /*
-   * We only go for a DCE login context if the given password
-   * matches that stored in the local password file.. 
-   * Assumes local passwd file is kept in sync w/ DCE RGY!
-   */
-
-  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(&current_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 *)this_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",
-               this_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);
-  }
-
-  /*
-   * NB. I'd like to change these to call something like become_user()
-   * instead but currently we don't have a connection
-   * context to become the correct user. This is already
-   * fairly platform specific code however, so I think
-   * this should be ok. I have added code to go
-   * back to being root on error though. JRA.
-   */
-
-  if (setregid(-1, pw->pw_gid) != 0) {
-    DEBUG(0,("Can't set egid to %d (%s)\n", pw->pw_gid, strerror(errno)));
-    return False;
-  }
-
-  if (setreuid(-1, pw->pw_uid) != 0) {
-    setgid(0);
-    DEBUG(0,("Can't set euid to %d (%s)\n", pw->pw_uid, strerror(errno)));
-    return False;
-  }
-  if (sec_login_setup_identity((unsigned char *)this_user,
-                               sec_login_no_flags,
-                               &my_dce_sec_context,
-                               &err) == 0)
-
-    {
-      dce_error_inq_text(err, dce_errstr, &err2);
-      /* Go back to root, JRA. */
-      setuid(0);
-      setgid(0);
-      DEBUG(0,("DCE Setup Identity for %s failed: %s\n",
-               this_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);
-    /* Go back to root, JRA. */
-    setuid(0);
-    setgid(0);
-    DEBUG(0,("DCE can't get pwent. %s\n", dce_errstr));
-
-    return(False);
-  }
-
-  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);
-    /* Go back to root, JRA. */
-    setuid(0);
-    setgid(0);
-    DEBUG(0,("DCE Identity Validation failed for principal %s: %s\n",
-             this_user,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);
-    /* Go back to root, JRA. */
-    setuid(0);
-    setgid(0);
-    DEBUG(0,("DCE certify identity failed: %s\n", dce_errstr));
-
-    return(False);
-  }
-
-  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",
-               this_user,dce_errstr));
-
-      sec_login_purge_context(&my_dce_sec_context, &err);
-      /* Go back to root, JRA. */
-      setuid(0);
-      setgid(0);
-      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));
-
-    /* Go back to root, JRA. */
-    setuid(0);
-    setgid(0);
-    return(False);
-  }
-
-  DEBUG(0,("DCE login succeeded for principal %s on pid %d\n",
-           this_user, 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);
-    /* Go back to root, JRA. */
-    setuid(0);
-    setgid(0);
-    DEBUG(0,("DCE can't get expiration. %s\n", dce_errstr));
-
-    return(False);
-  }
-
-  setuid(0);
-  setgid(0);
-
-  DEBUG(0,("DCE context expires: %s",asctime(localtime(&expire_time))));
-
-  dcelogin_atmost_once = 1;
-  return (True);
-}
-
-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",
-               getpid(), dce_errstr));
-    }
-}
-#endif
-
-#ifdef KRB5_AUTH
-/*******************************************************************
-check on Kerberos authentication
-********************************************************************/
-static BOOL krb5_auth(char *this_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);
-       }
+       struct smb_passwd *smbpw;
+       BOOL ret;
        
-       if ( retval = krb5_parse_name(kcontext, this_user, &kprinc) )
-       {
-               return(False);
-       }
-
-       memset((char *)&kcreds, 0, sizeof(kcreds));
-
-       kcreds.client = kprinc;
+       become_root(0);
+       smbpw = getsmbpwnam(user);
+       unbecome_root(0);
        
-       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);
+       if(smbpw == NULL) {
+               DEBUG(0,("getsmbpwnam returned NULL\n"));
+               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);
+       /* Here, the flag is one, because we want to ignore the
+           XXXXXXX'd out password */
+       ret = change_oem_password( smbpw, password, True);
+       if (ret == False) {
+               DEBUG(3,("change_oem_password returned False\n"));
        }
 
-       return(True);
-}
-#endif /* KRB5_AUTH */
-
-#ifdef KRB4_AUTH
-/*******************************************************************
-check on Kerberos authentication
-********************************************************************/
-static BOOL krb4_auth(char *this_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", getpid());
-  
-  krb_set_tkt_string(tkfile);
-  if (krb_verify_user(this_user, "", realm,
-                     password, 0,
-                     "rmcd") == KSUCCESS) {
-    unlink(tkfile);
-    return 1;
-  }
-  unlink(tkfile);
-  return 0;
-}
-#endif /* KRB4_AUTH */
-
-#ifdef LINUX_BIGCRYPT
-/****************************************************************************
-an enhanced crypt for Linux to handle password longer than 8 characters
-****************************************************************************/
-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);
+       return ret;
 }
-#endif
-
-
-/****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
-****************************************************************************/
-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);
-}
-
-/****************************************************************************
-apply a function to upper/lower case combinations
-of a string and return true if one of them returns true.
-try all combinations with up to N uppercase letters.
-offset is the first char to try and change (start with 0)
-it assumes the string starts lowercased
-****************************************************************************/
-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);
-}
-
-
-
-/****************************************************************************
-core of password checking routine
-****************************************************************************/
-BOOL password_check(char *password)
-{
-
-#ifdef HAVE_PAM
-/* This falls through if the password check fails
-       - if HAVE_CRYPT is not defined this causes an error msg
-               saying Warning - no crypt available
-       - if HAVE_CRYPT is defined this is a potential security hole
-               as it may authenticate via the crypt call when PAM
-               settings say it should fail.
-               if (pam_auth(this_user,password)) return(True);
-               Hence we make a direct return to avoid a second chance!!!
-*/
-  return (pam_auth(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,("password_check: 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
-
-#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
-}
 
 /****************************************************************************
 core of smb password checking routine.
@@ -1125,327 +377,175 @@ BOOL smb_password_check(char *password, unsigned char *part_passwd, unsigned cha
  Do a specific test for an smb password being correct, given a smb_password and
  the lanman and NT responses.
 ****************************************************************************/
-
 BOOL smb_password_ok(struct smb_passwd *smb_pass,
                      uchar lm_pass[24], uchar nt_pass[24])
 {
-  uchar challenge[8];
+       uchar challenge[8];
 
-  if (!lm_pass || !smb_pass) return(False);
+       if (!lm_pass || !smb_pass) return(False);
 
-  if(smb_pass->acct_ctrl & ACB_DISABLED)
-  {
-    DEBUG(3,("smb_password_ok: account for user %s was disabled.\n", smb_pass->smb_name));
-    return(False);
-  }
-
-  if (!last_challenge(challenge))
-  {
-    DEBUG(1,("smb_password_ok: no challenge done - password failed\n"));
-    return False;
-  }
+       if(smb_pass->acct_ctrl & ACB_DISABLED) {
+               DEBUG(3,("account for user %s was disabled.\n", 
+                        smb_pass->smb_name));
+               return(False);
+       }
 
-  DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n", smb_pass->smb_name));
+       if (!last_challenge(challenge)) {
+               DEBUG(1,("no challenge done - password failed\n"));
+               return False;
+       }
 
-  if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL))
-  {
-    /* We have the NT MD4 hash challenge available - see if we can
-       use it (ie. does it exist in the smbpasswd file).
-     */
-    DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
-    if (smb_password_check((char *)nt_pass, (uchar *)smb_pass->smb_nt_passwd, challenge))
-    {
-      DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
-      return(True);
-    }
-    DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
-  }
+       DEBUG(4,("Checking SMB password for user %s\n", 
+                smb_pass->smb_name));
+
+       if ((Protocol >= PROTOCOL_NT1) && (smb_pass->smb_nt_passwd != NULL)) {
+               /* We have the NT MD4 hash challenge available - see if we can
+                  use it (ie. does it exist in the smbpasswd file).
+               */
+               DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
+               if (smb_password_check((char *)nt_pass, 
+                                      (uchar *)smb_pass->smb_nt_passwd, 
+                                      challenge)) {
+                       DEBUG(4,("NT MD4 password check succeeded\n"));
+                       return(True);
+               }
+               DEBUG(4,("NT MD4 password check failed\n"));
+       }
 
-  /* Try against the lanman password. smb_pass->smb_passwd == NULL means
-     no password, allow access. */
+       /* Try against the lanman password. smb_pass->smb_passwd == NULL means
+          no password, allow access. */
 
-  DEBUG(4,("Checking LM MD4 password\n"));
+       DEBUG(4,("Checking LM MD4 password\n"));
 
-  if((smb_pass->smb_passwd == NULL) && (smb_pass->acct_ctrl & ACB_PWNOTREQ))
-  {
-    DEBUG(4,("smb_password_ok: no password required for user %s\n", smb_pass->smb_name));
-    return True;
-  }
+       if((smb_pass->smb_passwd == NULL) && 
+          (smb_pass->acct_ctrl & ACB_PWNOTREQ)) {
+               DEBUG(4,("no password required for user %s\n",
+                        smb_pass->smb_name));
+               return True;
+       }
 
-  if((smb_pass->smb_passwd != NULL) && smb_password_check((char *)lm_pass, (uchar *)smb_pass->smb_passwd, challenge))
-  {
-    DEBUG(4,("smb_password_ok: LM MD4 password check succeeded\n"));
-    return(True);
-  }
+       if((smb_pass->smb_passwd != NULL) && 
+          smb_password_check((char *)lm_pass, 
+                             (uchar *)smb_pass->smb_passwd, challenge)) {
+               DEBUG(4,("LM MD4 password check succeeded\n"));
+               return(True);
+       }
 
-  DEBUG(4,("smb_password_ok: LM MD4 password check failed\n"));
+       DEBUG(4,("LM MD4 password check failed\n"));
 
-  return False;
+       return False;
 }
 
+
 /****************************************************************************
-check if a username/password is OK
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
 ****************************************************************************/
-BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
+static BOOL pass_check_smb(char *user,char *password, struct passwd *pwd)
 {
-  pstring pass2;
-  int level = lp_passwordlevel();
-  struct passwd *pass;
-  uchar challenge[8];
-  struct smb_passwd *smb_pass;
-  BOOL update_encrypted = lp_update_encrypted();
-  BOOL challenge_done = False;
+       struct passwd *pass;
+       uchar challenge[8];
+       struct smb_passwd *smb_pass;
+       BOOL challenge_done;
 
-  if (password) password[pwlen] = 0;
-
-  if (pwlen == 24)
-    challenge_done = last_challenge(challenge);
-
-#if DEBUG_PASSWORD
-  if (challenge_done)
-    {
-      int i;      
-      DEBUG(100,("checking user=[%s] pass=[",user));
-      for( i = 0; i < 24; i++)
-       DEBUG(100,("%0x ", (unsigned char)password[i]));
-      DEBUG(100,("]\n"));
-    } else {
-           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);
-
-  DEBUG(4,("SMB Password - pwlen = %d, challenge_done = %d\n", pwlen, challenge_done));
+       if (!password) {
+               return(False);
+       }
 
-  if ((pwlen == 24) && challenge_done)
-    {
-      DEBUG(4,("Checking SMB password for user %s (l=24)\n",user));
+       challenge_done = last_challenge(challenge);
 
-      if (!pass) 
-       {
-         DEBUG(3,("Couldn't find user %s\n",user));
-         return(False);
+       if (!challenge_done) {
+               DEBUG(0,("Error: challenge not done for user=%s\n", user));
+               return False;
        }
 
-      smb_pass = getsmbpwnam(user);
+       if (pwd && !user) {
+               pass = (struct passwd *) pwd;
+               user = pass->pw_name;
+       } else {
+               pass = Get_Pwnam(user,True);
+       }
 
-      if (!smb_pass)
-       {
-         DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
-         return(False);
+       if (!pass) {
+               DEBUG(3,("Couldn't find user %s\n",user));
+               return(False);
        }
 
-      /* Quit if the account was disabled. */
-      if(smb_pass->acct_ctrl & ACB_DISABLED)
-        {
-          DEBUG(3,("password_ok: account for user %s was disabled.\n", user));
-          return(False);
-        }
+       smb_pass = getsmbpwnam(user);
 
-      /* Ensure the uid's match */
-      if (smb_pass->smb_userid != pass->pw_uid)
-       {
-         DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
-         return(False);
+       if (!smb_pass) {
+               DEBUG(3,("Couldn't find user %s in smb_passwd file.\n", user));
+               return(False);
        }
 
-      if(smb_password_ok( smb_pass, (unsigned char *)password,(uchar *)password))
-        {
-          update_protected_database(user,True);
-          return(True);
+       /* Quit if the account was disabled. */
+       if(smb_pass->acct_ctrl & ACB_DISABLED) {
+               DEBUG(3,("account for user %s was disabled.\n", user));
+               return(False);
         }
 
-      DEBUG(3,("Error smb_password_check failed\n"));
-    }
-
-  DEBUG(4,("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;
-
-    /* many shadow systems require you to be root to get the password,
-       in most cases this should already be the case when this
-       function is called, except perhaps for IPC password changing
-       requests */
-
-    spass = getspnam(pass->pw_name);
-    if (spass && spass->sp_pwdp)
-      pass->pw_passwd = spass->sp_pwdp;
-  }
-#elif defined(IA_UINFO)
-  {
-      /* Need to get password with SVR4.2's ia_ functions instead of
-         get{sp,pw}ent functions. Required by UnixWare 2.x, tested on 
-         version 2.1. (tangent@cyberport.com) */
-      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)
-      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,("No entry for user %s in protected database !\n",user));
-       return(False);
-      }
-  }
-#endif
-
-#ifdef ULTRIX_AUTH
-  {
-    AUTHORIZATION *ap = getauthuid( pass->pw_uid );
-    if (ap)
-      {
-       fstrcpy( pass->pw_passwd, ap->a_password );
-       endauthent();
-      }
-  }
-#endif
-
-  /* extract relevant info */
-  fstrcpy(this_user,pass->pw_name);  
-  fstrcpy(this_salt,pass->pw_passwd);
-  /* crypt on some platforms (HPUX in particular)
-     won't work with more than 2 salt characters. */
-  this_salt[2] = 0;
-
-  fstrcpy(this_crypted,pass->pw_passwd);
-  if (!*this_crypted) {
-    if (!lp_null_passwords()) {
-           DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
-           return(False);
-    }
-    if (!*password) {
-           DEBUG(3,("Allowing access to %s with null password\n",this_user));
-           return(True);
-    }
-  }
-
-  /* try it as it came to us */
-  if (password_check(password))
-    {
-      update_protected_database(user,True);
-      if (update_encrypted)
-        update_smbpassword_file(user,password);
-      return(True);
-    }
-
-  /* if the password was given to us with mixed case then we don't
-     need to proceed as we know it hasn't been case modified by the
-     client */
-  if (strhasupper(password) && strhaslower(password))
-    return(False);
-
-  /* make a copy of it */
-  StrnCpy(pass2,password,sizeof(pstring)-1);
-  
-  /* try all lowercase */
-  strlower(password);
-  if (password_check(password))
-    {
-      update_protected_database(user,True);
-      if (update_encrypted)
-        update_smbpassword_file(user,password);
-      return(True);
-    }
-
-  /* give up? */
-  if (level < 1)
-    {
-      update_protected_database(user,False);
-
-      /* restore it */
-      fstrcpy(password,pass2);
-
-      return(False);
-    }
-
-  /* last chance - all combinations of up to level chars upper! */
-  strlower(password);
-
-  if (string_combinations(password,password_check,level))
-    {
-      update_protected_database(user,True);
-      if (update_encrypted)
-        update_smbpassword_file(user,password);
-      return(True);
-    }
+       /* Ensure the uid's match */
+       if (smb_pass->smb_userid != pass->pw_uid)       {
+               DEBUG(3,("Error : UNIX and SMB uids in password files do not match !\n"));
+               return(False);
+       }
 
-  update_protected_database(user,False);
-  
-  /* restore it */
-  fstrcpy(password,pass2);
-  
-  return(False);
+       if (smb_password_ok(smb_pass, 
+                           (unsigned char *)password,
+                           (uchar *)password)) {
+               return(True);
+       }
+       
+       DEBUG(3,("Error smb_password_check failed\n"));
+       return False;
 }
 
-
+/****************************************************************************
+check if a username/password pair is OK either via the system password
+database or the encrypted SMB password database
+return True if the password is correct, False otherwise
+****************************************************************************/
+BOOL password_ok(char *user,char *password, int pwlen, struct passwd *pwd)
+{
+       if (pwlen == 24) {
+               /* if it is 24 bytes long then assume it is an encrypted
+                  password */
+               return pass_check_smb(user, password, pwd);
+       } 
+
+       return pass_check(user, password, pwlen, pwd, 
+                         lp_update_encrypted() ? 
+                         update_smbpassword_file : NULL);
+}
 
 /****************************************************************************
 check if a username is valid
 ****************************************************************************/
 BOOL user_ok(char *user,int snum)
 {
-  pstring valid, invalid;
-  BOOL ret;
-
-  StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
-  StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
+       pstring valid, invalid;
+       BOOL ret;
 
-  string_sub(valid,"%S",lp_servicename(snum));
-  string_sub(invalid,"%S",lp_servicename(snum));
+       StrnCpy(valid, lp_valid_users(snum), sizeof(pstring));
+       StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring));
 
-  ret = !user_in_list(user,invalid);
-
-  if (ret && valid && *valid)
-    ret = user_in_list(user,valid);
+       string_sub(valid,"%S",lp_servicename(snum));
+       string_sub(invalid,"%S",lp_servicename(snum));
+       
+       ret = !user_in_list(user,invalid);
+       
+       if (ret && valid && *valid) {
+               ret = user_in_list(user,valid);
+       }
 
-  if (ret && lp_onlyuser(snum)) {
-    char *user_list = lp_username(snum);
-    string_sub(user_list,"%S",lp_servicename(snum));
-    ret = user_in_list(user,user_list);
-  }
+       if (ret && lp_onlyuser(snum)) {
+               char *user_list = lp_username(snum);
+               string_sub(user_list,"%S",lp_servicename(snum));
+               ret = user_in_list(user,user_list);
+       }
 
-  return(ret);
+       return(ret);
 }
 
 
index 97c54cde047d9b0d16ce0bd780be4eaf66da6827..8f9349f3fc541826faf5262edee8209688106d57 100644 (file)
@@ -4426,8 +4426,9 @@ void exit_server(char *reason)
     if (Connections[i].open)
       close_cnum(i,(uint16)-1);
 #ifdef WITH_DFS
-  if (dcelogin_atmost_once)
+  if (dcelogin_atmost_once) {
     dfs_unlogin();
+  }
 #endif
   if (!reason) {   
     int oldlevel = DEBUGLEVEL;
index 5958b0a41954b763a3a89d8d3d580da37dda8362..1a9d34d0047dc4497857bca8ef3f2c29c609ec45 100644 (file)
@@ -483,7 +483,7 @@ static int cgi_handle_authorization(char *line)
        }
 
 
-       return password_ok(user, pass, strlen(pass), NULL);
+       return pass_check(user, pass, strlen(pass), NULL, NULL);
 }