bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: pserver login fails on 9 char passwords


From: Brian Murphy
Subject: Re: pserver login fails on 9 char passwords
Date: Mon, 29 Mar 2004 17:22:40 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3

Mäkeläinen Juha wrote:

Have you tried using the PAM in the 1.12 versions?

/Brian

 No; we are trying to use a stable version and very straightforward solutions 
for out production group.

 I am not much aware of the possibilities of PAM, I have only glimsed 
http://www.cvshome.org/docs/manual/cvs-1.12.2/cvs_2.html . Is it something 
which can be easily installed in any server?


If you are interested here is a patch which adds PAM support for 1.11.x versions.

run

> patch -p1 < ../cvs-1.11.patch
patching file src/server.c
Hunk #1 succeeded at 5473 (offset 66 lines).
Hunk #2 succeeded at 5613 (offset 66 lines).

> LIBS=-lpam ./configure
....

> make

This does the same thing as the patch in 1.12 but hacks a little. There is no configure option to enable pam and no documentation. This is what I have been running for the
past year here where I work.

/Brian
diff -u -r cvs-1.11.6/src/server.c cvs-1.11.6.mine/src/server.c
--- cvs-1.11.6/src/server.c     Thu May  1 22:38:16 2003
+++ cvs-1.11.6.mine/src/server.c        Mon May 26 13:03:13 2003
@@ -5407,66 +5407,118 @@
     return retval;
 }
 
+#if 1
 
-/* Return a hosting username if password matches, else NULL. */
-static char *
-check_password (username, password, repository)
-    char *username, *password, *repository;
-{
-    int rc;
-    char *host_user = NULL;
-    char *found_passwd = NULL;
-    struct passwd *pw;
+#include <security/pam_appl.h>
 
-    /* First we see if this user has a password in the CVS-specific
-       password file.  If so, that's enough to authenticate with.  If
-       not, we'll check /etc/passwd. */
+#ifndef PAM_SERVICE_NAME
+#define PAM_SERVICE_NAME program_name
+#endif
 
-    rc = check_repository_password (username, password, repository,
-                                   &host_user);
+struct cvs_pam_userinfo {
+    char *username;
+    char *password;
+};
+
+static int
+cvs_pam_conv(num_msg, msg, resp, appdata_ptr)
+    int num_msg; 
+    const struct pam_message **msg;
+    struct pam_response **resp; 
+    void *appdata_ptr;
+{
+    int i;
+    struct pam_response *response;
+    struct cvs_pam_userinfo *ui = (struct cvs_pam_userinfo *)appdata_ptr;
 
-    if (rc == 2)
-       return NULL;
+    assert (ui && ui->username && ui->password && msg && resp);
 
-    if (rc == 1)
+    response = xmalloc(num_msg * sizeof(struct pam_response));
+    memset(response, 0, num_msg * sizeof(struct pam_response));
+
+    for (i = 0; i < num_msg; i++)
     {
-       /* host_user already set by reference, so just return. */
-       goto handle_return;
+       switch(msg[i]->msg_style) 
+       {
+           /* PAM wants a username */
+           case PAM_PROMPT_ECHO_ON:
+               response[i].resp = xstrdup(ui->username);
+               break;
+           /* PAM wants a password */
+           case PAM_PROMPT_ECHO_OFF:
+               response[i].resp = xstrdup(ui->password);
+               break;
+           case PAM_ERROR_MSG:
+           case PAM_TEXT_INFO:
+               printf("E %s\n",msg[i]->msg);
+               break;
+           /* PAM wants something we don't understand - bail out */
+           default:
+               goto cleanup;
+       }
     }
 
-    assert (rc == 0);
+    *resp = response;
+    return PAM_SUCCESS;
 
-    if (!system_auth)
+cleanup:
+    for (i = 0; i < num_msg; i++)
     {
-       /* Note that the message _does_ distinguish between the case in
-          which we check for a system password and the case in which
-          we do not.  It is a real pain to track down why it isn't
-          letting you in if it won't say why, and I am not convinced
-          that the potential information disclosure to an attacker
-          outweighs this.  */
-       printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
+       if (response[i].resp)
+       {
+           free(response[i].resp);
+           response[i].resp = 0;
+       }
+    }
+    free(response);
+    return PAM_CONV_ERR;
+}
+
+static int
+check_system_password (username, password)
+    char *username, *password;
+{
+    pam_handle_t *pamh = NULL;
+    int retval;
+    struct cvs_pam_userinfo ui = { username, password };
+    struct pam_conv conv = { cvs_pam_conv, (void *)&ui };
 
+    retval = pam_start(PAM_SERVICE_NAME, username, &conv, &pamh);
+
+    if (retval == PAM_SUCCESS)
+       retval = pam_authenticate(pamh, 0);
+
+    if (retval == PAM_SUCCESS)
+       retval = pam_acct_mgmt(pamh, 0);
+
+    if (pam_end(pamh,retval) != PAM_SUCCESS)
+    {
+       printf("E Fatal error, aborting.\n"
+       "pam failed to release authenticator\n");
        error_exit ();
     }
 
-    /* No cvs password found, so try /etc/passwd. */
-
+    return (retval == PAM_SUCCESS);       /* indicate success */
+}
+#else
+static int
+check_system_password (username, password)
+    char *username, *password;
+{
+    char *found_passwd = NULL;
+    struct passwd *pw;
 #ifdef HAVE_GETSPNAM
     {
        struct spwd *spw;
 
        spw = getspnam (username);
        if (spw != NULL)
-       {
            found_passwd = spw->sp_pwdp;
-       }
     }
 #endif
 
     if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
-    {
        found_passwd = pw->pw_passwd;
-    }
 
     if (found_passwd == NULL)
     {
@@ -5495,34 +5547,74 @@
     {
        /* user exists and has a password */
        if (strcmp (found_passwd, crypt (password, found_passwd)) == 0)
-       {
-           host_user = xstrdup (username);
-       }
+           return 1;
        else
        {
-           host_user = NULL;
 #ifdef LOG_AUTHPRIV
            syslog (LOG_AUTHPRIV | LOG_NOTICE,
                    "password mismatch for %s: %s vs. %s", username,
                    crypt(password, found_passwd), found_passwd);
 #endif
+           return 0;
        }
-       goto handle_return;
     }
 
-    if (password && *password)
-    {
-       /* user exists and has no system password, but we got
-          one as parameter */
-       host_user = xstrdup (username);
+#ifdef LOG_AUTHPRIV
+    syslog (LOG_AUTHPRIV | LOG_NOTICE,
+           "user %s authenticated because of blank system password",
+           username);
+#endif
+    return 1;
+}
+#endif
+
+/* Return a hosting username if password matches, else NULL. */
+static char *
+check_password (username, password, repository)
+    char *username, *password, *repository;
+{
+    int rc;
+    char *host_user = NULL;
+
+    /* First we see if this user has a password in the CVS-specific
+       password file.  If so, that's enough to authenticate with.  If
+       not, we'll check /etc/passwd. */
+
+    rc = check_repository_password (username, password, repository,
+                                   &host_user);
+
+    if (rc == 2)
+       return NULL;
+
+    if (rc == 1)
+       /* host_user already set by reference, so just return. */
        goto handle_return;
+
+    assert (rc == 0);
+
+    if (!system_auth)
+    {
+       /* Note that the message _does_ distinguish between the case in
+          which we check for a system password and the case in which
+          we do not.  It is a real pain to track down why it isn't
+          letting you in if it won't say why, and I am not convinced
+          that the potential information disclosure to an attacker
+          outweighs this.  */
+       printf ("error 0 no such user %s in CVSROOT/passwd\n", username);
+
+       error_exit ();
     }
 
-    /* user exists but has no password at all */
-    host_user = NULL;
+    /* No cvs password found, so try /etc/passwd. */
+    if ( check_system_password(username, password) )
+       host_user = xstrdup (username);
+    else
+       host_user = NULL;
+
 #ifdef LOG_AUTHPRIV
-    syslog (LOG_AUTHPRIV | LOG_NOTICE,
-           "login refused for %s: user has no password", username);
+    if (!host_user)
+       syslog (LOG_AUTHPRIV | LOG_NOTICE,
+               "login refused for %s: user has no password", username);
 #endif
 
 handle_return:

reply via email to

[Prev in Thread] Current Thread [Next in Thread]