s3:pam_smbpass: don't call openlog() or closelog() from pam_smbpass
[ira/wip.git] / source3 / pam_smbpass / pam_smb_passwd.c
index 338d873d257506425f98894ae85926edb80e7e6c..9504e4d53c17240762d810c96767166a5d584019 100644 (file)
@@ -1,18 +1,21 @@
-/* Unix NT password database implementation, version 0.7.5.
- *
- * 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.
+/*
+   Unix SMB/CIFS implementation.
+   Use PAM to update user passwords in the local SAM
+   Copyright (C) Steve Langasek                1998-2003
+   
+   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 3 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, see <http://www.gnu.org/licenses/>.
+
 */
 
 /* indicate the following groups are defined */
 
 #include "includes.h"
 
-#ifndef LINUX
+/* This is only used in the Sun implementation.  FIXME: we really
+   want a define here that distinguishes between the Solaris PAM
+   and others (including FreeBSD). */
 
-/* This is only used in the Sun implementation. */
+#ifndef LINUX
+#if defined(HAVE_SECURITY_PAM_APPL_H)
 #include <security/pam_appl.h>
+#elif defined(HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#endif
+#endif
 
-#endif  /* LINUX */
-
+#if defined(HAVE_SECURITY_PAM_MODULES_H)
 #include <security/pam_modules.h>
+#elif defined(HAVE_PAM_PAM_MODULES_H)
+#include <pam/pam_modules.h>
+#endif
 
 #include "general.h" 
 
 
 int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user,  const char *pass_new )
 {
- char          c;
- int           retval, i;
- pstring       err_str;
- pstring       msg_str;
-
-    err_str[0] = '\0';
-    msg_str[0] = '\0';
-
-    retval = local_password_change( user, 0, pass_new, err_str, sizeof(err_str),
-                                   msg_str, sizeof(msg_str) );
-
-    if (!retval) {
-        if (*err_str) {
-            err_str[PSTRING_LEN-1] = '\0';
-            make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
-        }
-
-        /* FIXME: what value is appropriate here? */
-        retval = PAM_AUTHTOK_ERR;
-    } else {
-        if (*msg_str) {
-            msg_str[PSTRING_LEN-1] = '\0';
-            make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
-        }
-        retval = PAM_SUCCESS;
-    }
-
-    return retval;      
+       int retval;
+       char *err_str = NULL;
+       char *msg_str = NULL;
+
+       retval = NT_STATUS_IS_OK(local_password_change(user, LOCAL_SET_PASSWORD, pass_new,
+                                       &err_str,
+                                       &msg_str));
+
+       if (!retval) {
+               if (err_str) {
+                       make_remark(pamh, ctrl, PAM_ERROR_MSG, err_str );
+               }
+
+               /* FIXME: what value is appropriate here? */
+               retval = PAM_AUTHTOK_ERR;
+       } else {
+               if (msg_str) {
+                       make_remark(pamh, ctrl, PAM_TEXT_INFO, msg_str );
+               }
+               retval = PAM_SUCCESS;
+       }
 
+       SAFE_FREE(err_str);
+       SAFE_FREE(msg_str);
+       return retval;      
 }
 
 
@@ -90,19 +98,17 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
     unsigned int ctrl;
     int retval;
 
-    extern BOOL in_client;
-
-    SAM_ACCOUNT *sampass = NULL;
+    struct samu *sampass = NULL;
+    void (*oldsig_handler)(int);
     const char *user;
-    const char *pass_old, *pass_new;
+    char *pass_old;
+    char *pass_new;
 
     /* Samba initialization. */
-    setup_logging( "pam_smbpass", False );
-    charset_initialise();
-    codepage_initialise(lp_client_code_page());
-    in_client = True;
+    load_case_tables();
+    lp_set_in_client(True);
 
-    ctrl = set_ctrl(flags, argc, argv);
+    ctrl = set_ctrl(pamh, flags, argc, argv);
 
     /*
      * First get the name of a user.  No need to do anything if we can't
@@ -112,27 +118,43 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
     retval = pam_get_user( pamh, &user, "Username: " );
     if (retval != PAM_SUCCESS) {
         if (on( SMB_DEBUG, ctrl )) {
-            _log_err( LOG_DEBUG, "password: could not identify user" );
+            _log_err(pamh, LOG_DEBUG, "password: could not identify user");
         }
         return retval;
     }
     if (on( SMB_DEBUG, ctrl )) {
-        _log_err( LOG_DEBUG, "username [%s] obtained", user );
+        _log_err(pamh, LOG_DEBUG, "username [%s] obtained", user);
     }
 
-    if (!initialize_password_db(True)) {
-        _log_err( LOG_ALERT, "Cannot access samba password database" );
+    if (geteuid() != 0) {
+       _log_err(pamh, LOG_DEBUG, "Cannot access samba password database, not running as root.");
+       return PAM_AUTHINFO_UNAVAIL;
+    }
+
+    /* Getting into places that might use LDAP -- protect the app
+       from a SIGPIPE it's not expecting */
+    oldsig_handler = CatchSignal(SIGPIPE, SIGNAL_CAST SIG_IGN);
+
+    if (!initialize_password_db(False, NULL)) {
+      _log_err(pamh, LOG_ALERT, "Cannot access samba password database" );
+        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
         return PAM_AUTHINFO_UNAVAIL;
     }
 
     /* obtain user record */
-    pdb_init_sam(&sampass);
-    pdb_getsampwnam(sampass,user);
+    if ( !(sampass = samu_new( NULL )) ) {
+        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
+        return nt_status_to_pam(NT_STATUS_NO_MEMORY);
+    }
 
-    if (sampass == NULL) {
-        _log_err( LOG_ALERT, "Failed to find entry for user %s.", user );
+    if (!pdb_getsampwnam(sampass,user)) {
+        _log_err(pamh, LOG_ALERT, "Failed to find entry for user %s.", user);
+        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
         return PAM_USER_UNKNOWN;
     }
+    if (on( SMB_DEBUG, ctrl )) {
+        _log_err(pamh, LOG_DEBUG, "Located account for %s", user);
+    }
 
     if (flags & PAM_PRELIM_CHECK) {
         /*
@@ -144,7 +166,8 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 
         if (_smb_blankpasswd( ctrl, sampass )) {
 
-            pdb_free_sam(&sampass);
+            TALLOC_FREE(sampass);
+            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
             return PAM_SUCCESS;
         }
 
@@ -154,10 +177,11 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 
             /* tell user what is happening */
 #define greeting "Changing password for "
-            Announce = (char *) malloc(sizeof(greeting)+strlen(user));
+            Announce = SMB_MALLOC_ARRAY(char, sizeof(greeting)+strlen(user));
             if (Announce == NULL) {
-                _log_err(LOG_CRIT, "password: out of memory");
-                pdb_free_sam(&sampass);
+                _log_err(pamh, LOG_CRIT, "password: out of memory");
+                TALLOC_FREE(sampass);
+                CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
                 return PAM_BUF_ERR;
             }
             strncpy( Announce, greeting, sizeof(greeting) );
@@ -170,9 +194,10 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
             SAFE_FREE( Announce );
 
             if (retval != PAM_SUCCESS) {
-                _log_err( LOG_NOTICE
-                          , "password - (old) token not obtained" );
-                pdb_free_sam(&sampass);
+                _log_err(pamh, LOG_NOTICE,
+                         "password - (old) token not obtained");
+                TALLOC_FREE(sampass);
+                CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
                 return retval;
             }
 
@@ -186,20 +211,12 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
         }
 
         pass_old = NULL;
-        pdb_free_sam(&sampass);
+        TALLOC_FREE(sampass);
+        CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
         return retval;
 
     } else if (flags & PAM_UPDATE_AUTHTOK) {
 
-#if 0
-        /* We used to return when this flag was set, but that breaks
-           password synchronization when /other/ tokens are expired.  For
-           now, we change the password whenever we're asked. SRL */
-        if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
-            pdb_free_sam(&sampass);
-            return PAM_SUCCESS;
-        }
-#endif
         /*
          * obtain the proposed password
          */
@@ -211,11 +228,11 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
          */
 
         if (off( SMB_NOT_SET_PASS, ctrl )) {
-            retval = pam_get_item( pamh, PAM_OLDAUTHTOK,
-                                   (const void **)&pass_old );
+            retval = _pam_get_item( pamh, PAM_OLDAUTHTOK,
+                                   &pass_old );
         } else {
-            retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK,
-                                   (const void **)&pass_old );
+            retval = _pam_get_data( pamh, _SMB_OLD_AUTHTOK,
+                                   &pass_old );
             if (retval == PAM_NO_MODULE_DATA) {
                pass_old = NULL;
                 retval = PAM_SUCCESS;
@@ -223,8 +240,9 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
         }
 
         if (retval != PAM_SUCCESS) {
-            _log_err( LOG_NOTICE, "password: user not authenticated" );
-            pdb_free_sam(&sampass);
+            _log_err(pamh, LOG_NOTICE, "password: user not authenticated");
+            TALLOC_FREE(sampass);
+            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
             return retval;
         }
 
@@ -247,11 +265,12 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 
         if (retval != PAM_SUCCESS) {
             if (on( SMB_DEBUG, ctrl )) {
-                _log_err( LOG_ALERT
-                          , "password: new password not obtained" );
+                _log_err(pamh, LOG_ALERT,
+                         "password: new password not obtained");
             }
             pass_old = NULL;                               /* tidy up */
-            pdb_free_sam(&sampass);
+            TALLOC_FREE(sampass);
+            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
             return retval;
         }
 
@@ -268,9 +287,10 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
         retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);
 
         if (retval != PAM_SUCCESS) {
-            _log_err(LOG_NOTICE, "new password not acceptable");
+            _log_err(pamh, LOG_NOTICE, "new password not acceptable");
             pass_new = pass_old = NULL;               /* tidy up */
-            pdb_free_sam(&sampass);
+            TALLOC_FREE(sampass);
+            CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
             return retval;
         }
 
@@ -283,34 +303,43 @@ int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 
         retval = smb_update_db(pamh, ctrl, user, pass_new);
         if (retval == PAM_SUCCESS) {
+           uid_t uid;
+           
             /* password updated */
-            _log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)"
-                      , user, pdb_get_uid(sampass), uidtoname( getuid() )
-                      , getuid() );
-        } else {
-            _log_err( LOG_ERR, "password change failed for user %s"
-                      , user );
-        }
+               if (!sid_to_uid(pdb_get_user_sid(sampass), &uid)) {
+                       _log_err(pamh, LOG_NOTICE,
+                                "Unable to get uid for user %s",
+                               pdb_get_username(sampass));
+                       _log_err(pamh, LOG_NOTICE, "password for (%s) changed by (%s/%d)",
+                               user, uidtoname(getuid()), getuid());
+               } else {
+                       _log_err(pamh, LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)",
+                               user, uid, uidtoname(getuid()), getuid());
+               }
+       } else {
+               _log_err(pamh, LOG_ERR, "password change failed for user %s", user);
+       }
 
         pass_old = pass_new = NULL;
        if (sampass) {
-               pdb_free_sam(&sampass);
+               TALLOC_FREE(sampass);
                sampass = NULL;
        }
 
     } else {            /* something has broken with the library */
 
-        _log_err( LOG_ALERT, "password received unknown request" );
+        _log_err(pamh, LOG_ALERT, "password received unknown request");
         retval = PAM_ABORT;
 
     }
     
     if (sampass) {
-       pdb_free_sam(&sampass);
+       TALLOC_FREE(sampass);
        sampass = NULL;
     }
 
-    pdb_free_sam(&sampass);
+    TALLOC_FREE(sampass);
+    CatchSignal(SIGPIPE, SIGNAL_CAST oldsig_handler);
     return retval;
 }