r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / auth / auth_unix.c
index 7565d12eee148d0dcddf83f6d47cd8c24dbfdf11..dd000e94459690ffc2d0a41b8e5a18a6427b24ca 100644 (file)
@@ -7,7 +7,7 @@
    
    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
+   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,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "auth/auth.h"
-#include "system/passwd.h"
+#include "system/passwd.h" /* needed by some systems for struct passwd */
+#include "lib/socket/socket.h" 
+#include "auth/pam_errors.h"
+#include "param/param.h"
 
 /* TODO: look at how to best fill in parms retrieveing a struct passwd info
  * except in case USER_INFO_DONT_CHECK_UNIX_ACCOUNT is set
  */
 static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
                                          const struct auth_usersupplied_info *user_info,
+                                         struct passwd *pwd,
                                          struct auth_serversupplied_info **_server_info)
 {
        struct auth_serversupplied_info *server_info;
+       NTSTATUS status;
 
-       server_info = talloc(mem_ctx, struct auth_serversupplied_info);
-       NT_STATUS_HAVE_NO_MEMORY(server_info);
-
-       server_info->authenticated = True;
-
-       server_info->account_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, user_info->account_name));
-       NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
-
-       server_info->domain_name = talloc_strdup(server_info, talloc_strdup(mem_ctx, "unix"));
-       NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
-
+       /* This is a real, real hack */
+       if (pwd->pw_uid == 0) {
+               status = auth_system_server_info(mem_ctx, &server_info);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
 
-       /* is this correct? */
-       server_info->account_sid = NULL;
-       server_info->primary_group_sid = NULL;
-       server_info->n_domain_groups = 0;
-       server_info->domain_groups = NULL;
+               server_info->account_name = talloc_steal(server_info, pwd->pw_name);
+               NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
+               
+               server_info->domain_name = talloc_strdup(server_info, "unix");
+               NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
+       } else {
+               server_info = talloc(mem_ctx, struct auth_serversupplied_info);
+               NT_STATUS_HAVE_NO_MEMORY(server_info);
+               
+               server_info->authenticated = True;
+               
+               server_info->account_name = talloc_steal(server_info, pwd->pw_name);
+               NT_STATUS_HAVE_NO_MEMORY(server_info->account_name);
+               
+               server_info->domain_name = talloc_strdup(server_info, "unix");
+               NT_STATUS_HAVE_NO_MEMORY(server_info->domain_name);
+
+               /* This isn't in any way correct.. */
+               server_info->account_sid = NULL;
+               server_info->primary_group_sid = NULL;
+               server_info->n_domain_groups = 0;
+               server_info->domain_groups = NULL;
+       }
        server_info->user_session_key = data_blob(NULL,0);
        server_info->lm_session_key = data_blob(NULL,0);
 
-       server_info->full_name = talloc_strdup(server_info, "");
+       server_info->full_name = talloc_steal(server_info, pwd->pw_gecos);
        NT_STATUS_HAVE_NO_MEMORY(server_info->full_name);
        server_info->logon_script = talloc_strdup(server_info, "");
        NT_STATUS_HAVE_NO_MEMORY(server_info->logon_script);
@@ -79,6 +96,44 @@ static NTSTATUS authunix_make_server_info(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, const char *username, struct passwd **pws)
+{
+        struct passwd *ret;
+       struct passwd *from;
+
+       *pws = NULL;
+
+       ret = talloc(ctx, struct passwd);
+       NT_STATUS_HAVE_NO_MEMORY(ret);
+
+       from = getpwnam(username);
+       if (!from) {
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+        ret->pw_name = talloc_strdup(ctx, from->pw_name);
+       NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
+
+        ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
+       NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
+
+        ret->pw_uid = from->pw_uid;
+        ret->pw_gid = from->pw_gid;
+        ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
+       NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
+
+        ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
+       NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
+
+        ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
+       NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
+
+       *pws = ret;
+
+       return NT_STATUS_OK;
+}
+
+
 #ifdef HAVE_SECURITY_PAM_APPL_H
 #include <security/pam_appl.h>
 
@@ -142,6 +197,7 @@ static int smb_pam_conv(int num_msg, const struct pam_message **msg,
                                (*reply)[num].resp_retcode = PAM_SUCCESS;
                                (*reply)[num].resp = NULL;
                                DEBUG(4,("PAM Info message in conversation function: %s\n", (msg[num]->msg)));
+                               break;
 
                        case PAM_ERROR_MSG:
                                (*reply)[num].resp_retcode = PAM_SUCCESS;
@@ -150,6 +206,10 @@ static int smb_pam_conv(int num_msg, const struct pam_message **msg,
                                break;
 
                        default:
+                               while (num > 0) {
+                                       SAFE_FREE((*reply)[num-1].resp);
+                                       num--;
+                               }
                                SAFE_FREE(*reply);
                                *reply = NULL;
                                DEBUG(1,("Error: PAM subsystme sent an UNKNOWN message type to the conversation function!\n"));
@@ -166,7 +226,6 @@ static int smb_pam_conv(int num_msg, const struct pam_message **msg,
 
 static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, const char *remote_host, struct pam_conv *pconv)
 {
-       NTSTATUS nt_status;
        int pam_error;
 
        if (account_name == NULL || remote_host == NULL) {
@@ -186,6 +245,8 @@ static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, con
        DEBUG(4,("smb_pam_start: PAM: setting rhost to: %s\n", remote_host));
        pam_error = pam_set_item(*pamh, PAM_RHOST, remote_host);
        if (pam_error != PAM_SUCCESS) {
+               NTSTATUS nt_status;
+
                DEBUG(4,("smb_pam_start: setting rhost failed with error: %s\n",
                         pam_strerror(*pamh, pam_error)));
                nt_status = pam_to_nt_status(pam_error);
@@ -204,6 +265,8 @@ static NTSTATUS smb_pam_start(pam_handle_t **pamh, const char *account_name, con
        DEBUG(4,("smb_pam_start: PAM: setting tty\n"));
        pam_error = pam_set_item(*pamh, PAM_TTY, "samba");
        if (pam_error != PAM_SUCCESS) {
+               NTSTATUS nt_status;
+
                DEBUG(4,("smb_pam_start: setting tty failed with error: %s\n",
                         pam_strerror(*pamh, pam_error)));
                nt_status = pam_to_nt_status(pam_error);
@@ -259,7 +322,7 @@ static NTSTATUS smb_pam_auth(pam_handle_t *pamh, const char *user)
        pam_error = pam_authenticate(pamh, PAM_SILENT | lp_null_passwords() ? 0 : PAM_DISALLOW_NULL_AUTHTOK);
        switch( pam_error ){
                case PAM_AUTH_ERR:
-                       DEBUG(2, ("smb_pam_auth: PAM: Athentication Error for user %s\n", user));
+                       DEBUG(2, ("smb_pam_auth: PAM: Authentication Error for user %s\n", user));
                        break;
                case PAM_CRED_INSUFFICIENT:
                        DEBUG(2, ("smb_pam_auth: PAM: Insufficient Credentials for user %s\n", user));
@@ -364,7 +427,7 @@ static NTSTATUS smb_pam_setcred(pam_handle_t *pamh, const char * user)
        return pam_to_nt_status(pam_error);
 }
 
-static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
+static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info, struct passwd **pws)
 {
        struct smb_pam_user_info *info;
        struct pam_conv *pamconv;
@@ -376,8 +439,8 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
                return NT_STATUS_NO_MEMORY;
        }
 
-       info->account_name = user_info->account_name;
-       info->plaintext_password = (char *)(user_info->plaintext_password.data);
+       info->account_name = user_info->mapped.account_name;
+       info->plaintext_password = user_info->password.plaintext;
 
        pamconv = talloc(ctx, struct pam_conv);
        if (pamconv == NULL) {
@@ -392,13 +455,12 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
         * if true set up a crack name routine.
         */
 
-       nt_status = smb_pam_start(&pamh, user_info->account_name, user_info->remote_host, pamconv);
+       nt_status = smb_pam_start(&pamh, user_info->mapped.account_name, user_info->remote_host ? user_info->remote_host->addr : NULL, pamconv);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               smb_pam_end(pamh);
                return nt_status;
        }
 
-       nt_status = smb_pam_auth(pamh, user_info->account_name);
+       nt_status = smb_pam_auth(pamh, user_info->mapped.account_name);
        if (!NT_STATUS_IS_OK(nt_status)) {
                smb_pam_end(pamh);
                return nt_status;
@@ -406,13 +468,13 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
 
        if ( ! (user_info->flags & USER_INFO_DONT_CHECK_UNIX_ACCOUNT)) {
 
-               nt_status = smb_pam_account(pamh, user_info->account_name);
+               nt_status = smb_pam_account(pamh, user_info->mapped.account_name);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        smb_pam_end(pamh);
                        return nt_status;
                }
 
-               nt_status = smb_pam_setcred(pamh, user_info->account_name);
+               nt_status = smb_pam_setcred(pamh, user_info->mapped.account_name);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        smb_pam_end(pamh);
                        return nt_status;
@@ -420,48 +482,16 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
        }
 
        smb_pam_end(pamh);
-       return NT_STATUS_OK;    
-}
-
-#else
 
-static NTSTATUS talloc_getpwnam(TALLOC_CTX *ctx, char *username, struct passwd **pws)
-{
-        struct passwd *ret;
-       struct passwd *from;
-
-       *pws = NULL;
-
-       ret = talloc(ctx, struct passwd);
-       NT_STATUS_HAVE_NO_MEMORY(ret);
-
-       from = getpwnam(username);
-       if (!from) {
-               return NT_STATUS_NO_SUCH_USER;
+       nt_status = talloc_getpwnam(ctx, user_info->mapped.account_name, pws);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
        }
 
-        ret->pw_name = talloc_strdup(ctx, from->pw_name);
-       NT_STATUS_HAVE_NO_MEMORY(ret->pw_name);
-
-        ret->pw_passwd = talloc_strdup(ctx, from->pw_passwd);
-       NT_STATUS_HAVE_NO_MEMORY(ret->pw_passwd);
-
-        ret->pw_uid = from->pw_uid;
-        ret->pw_gid = from->pw_gid;
-        ret->pw_gecos = talloc_strdup(ctx, from->pw_gecos);
-       NT_STATUS_HAVE_NO_MEMORY(ret->pw_gecos);
-
-        ret->pw_dir = talloc_strdup(ctx, from->pw_dir);
-       NT_STATUS_HAVE_NO_MEMORY(ret->pw_dir);
-
-        ret->pw_shell = talloc_strdup(ctx, from->pw_shell);
-       NT_STATUS_HAVE_NO_MEMORY(ret->pw_shell);
-
-       *pws = ret;
-
-       return NT_STATUS_OK;
+       return NT_STATUS_OK;    
 }
 
+#else
 
 /****************************************************************************
 core of password checking routine
@@ -560,31 +590,7 @@ static NTSTATUS password_check(const char *username, const char *password,
 #endif /* HAVE_BIGCRYPT && HAVE_CRYPT && USE_BOTH_CRYPT_CALLS */
 }
 
-/**
- Does a string have any lowercase chars in it?
-**/
-static BOOL strhaslower(const char *s)
-{
-       while (*s) {
-               if (islower(*s)) return True;
-               s++;
-       }
-       return False;
-}
-
-/**
- Does a string have any uppercase chars in it?
-**/
-static BOOL strhasupper(const char *s)
-{
-       while (*s) {
-               if (isupper(*s)) return True;
-               s++;
-       }
-       return False;
-}
-
-static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info)
+static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersupplied_info *user_info, struct passwd **ret_passwd)
 {
        char *username;
        char *password;
@@ -595,8 +601,10 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
        NTSTATUS nt_status;
        int level = lp_passwordlevel();
 
-       username = talloc_strdup(ctx, user_info->account_name);
-       password = talloc_strdup(ctx, user_info->plaintext_password.data);
+       *ret_passwd = NULL;
+
+       username = talloc_strdup(ctx, user_info->mapped.account_name);
+       password = talloc_strdup(ctx, user_info->password.plaintext);
 
        nt_status = talloc_getpwnam(ctx, username, &pws);
        if (!NT_STATUS_IS_OK(nt_status)) {
@@ -700,13 +708,15 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
                }
                if (password == NULL) {
                        DEBUG(3, ("Allowing access to %s with null password\n", username));
+                       *ret_passwd = pws;
                        return NT_STATUS_OK;
                }
        }
 
        /* try it as it came to us */
        nt_status = password_check(username, password, crypted, salt);
-        if NT_STATUS_IS_OK(nt_status) {
+        if (NT_STATUS_IS_OK(nt_status)) {
+               *ret_passwd = pws;
                return nt_status;
        }
        else if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) {
@@ -735,6 +745,7 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
                strlower(pwcopy);
                nt_status = password_check(username, pwcopy, crypted, salt);
                if NT_STATUS_IS_OK(nt_status) {
+                       *ret_passwd = pws;
                        return nt_status;
                }
        }
@@ -749,6 +760,7 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
 
 #if 0
         if (NT_STATUS_IS_OK(nt_status = string_combinations(pwcopy, password_check, level))) {
+               *ret_passwd = pws;
                return nt_status;
        }
 #endif   
@@ -761,15 +773,27 @@ static NTSTATUS check_unix_password(TALLOC_CTX *ctx, const struct auth_usersuppl
  *
  **/
 
+static NTSTATUS authunix_want_check(struct auth_method_context *ctx,
+                                   TALLOC_CTX *mem_ctx,
+                                   const struct auth_usersupplied_info *user_info)
+{
+       if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
+               return NT_STATUS_NOT_IMPLEMENTED;
+       }
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
                                        TALLOC_CTX *mem_ctx,
                                        const struct auth_usersupplied_info *user_info,
-                                       struct  auth_serversupplied_info **server_info)
+                                       struct auth_serversupplied_info **server_info)
 {
        TALLOC_CTX *check_ctx;
        NTSTATUS nt_status;
+       struct passwd *pwd;
 
-       if (! user_info->account_name && ! *user_info->account_name) {
+       if (user_info->password_state != AUTH_PASSWORD_PLAIN) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -778,14 +802,14 @@ static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       nt_status = check_unix_password(check_ctx, user_info);
-       if ( ! NT_STATUS_IS_OK(nt_status)) {
+       nt_status = check_unix_password(check_ctx, user_info, &pwd);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(check_ctx);
                return nt_status;
        }
 
-       nt_status = authunix_make_server_info(mem_ctx, user_info, server_info);
-       if ( ! NT_STATUS_IS_OK(nt_status)) {
+       nt_status = authunix_make_server_info(mem_ctx, user_info, pwd, server_info);
+       if (!NT_STATUS_IS_OK(nt_status)) {
                talloc_free(check_ctx);
                return nt_status;
        }
@@ -797,7 +821,8 @@ static NTSTATUS authunix_check_password(struct auth_method_context *ctx,
 static const struct auth_operations unix_ops = {
        .name           = "unix",
        .get_challenge  = auth_get_challenge_not_implemented,
-       .check_password = authunix_check_password
+       .want_check     = authunix_want_check,
+       .check_password = authunix_check_password
 };
 
 NTSTATUS auth_unix_init(void)