Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Jun 2001 14:00:12 -0700
From:      Nick Sayer <nsayer@talarian.com>
To:        freebsd-questions@freebsd.org
Subject:   cyrus imapd, sasl, pam, NT domains and unix passwords
Message-ID:  <3B310EDC.30405@talarian.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------070407040106050003000102
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

I just found all the bits and pieces to solve this bag of wasps on our 
mail server and thought I'd share.

1. There is now a security/pam_smb port. You will need to install this 
and make a pam_smb.conf file as directed.

2. In the cyrus-sasl port, you need to make a modification to pwcheck. 
The problem is that pwcheck is the only thing that will be able to deal 
with Unix passwords, since it runs as root, unlike imapd. Since you 
can't say 'sasl_pwcheck_method: pam,pwcheck' the only way to achieve the 
desired end is to PAMify pwcheck itself. imapd will use SASL, which will 
use pwcheck for plaintext methods, which will use PAM.

I have submitted the patch for PAMifying pwcheck to the cyrus-sasl port 
maintainer. Hopefully he can add it as an option for the port. I got it 
out of the cyrus imap users' mailing list archives. Take the attached 
file (pwcheck_pam.c) and drop it into 
ports/security/cyrus-sasl/work/*/pwcheck. Then edit the Makefile in the 
same directory to compile and link pwcheck with pwcheck_pam.c instead of 
any of the alternatives. Install the resulting pwcheck executable as normal.

3. Now you will want to put lines in /etc/pam.conf to activate the PAM 
code in pwcheck. The service you use is 'cyrus', which will match 
anything that uses pwcheck. Unfortunately, there's no way to offer 
different PAM lineups to different SASL users. Perhaps you could set up 
two pwchecks running on different local sockets and change the services, 
but pwcheck would have to have plumbing put in to allow you to change 
the service name (which is currently hard coded as 'cyrus').

So, for example, this is a useful lineup:

cyrus 
auth 
sufficient 
pam_unix.so 
try_first_pass
cyrus 
auth 
sufficient 
/usr/local/lib/pam_smb_auth.so 
nolocal

I do it this way just in case there is a difference between the way 
pam_smb_auth does unix authentication (which it does as a second-chance 
method) and the way pam_unix.so does it. nolocal to pam_smb_auth tells 
it not to attempt unix password authentication if the NT one fails. I 
tried to set 'use_first_pass' on pam_smb_auth, but this fails for some 
unknown reason. The way pwcheck_pam is wired, though, it doesn't really 
matter.


--------------070407040106050003000102
Content-Type: text/plain;
 name="pwcheck_pam.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="pwcheck_pam.c"

#include <security/pam_appl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *user, *pass;
} PAM_info;

/* PAM conversation function
 */
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;
  PAM_info *info = appdata_ptr;

  #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(info->user);
          /* PAM frees resp */
        break;
      case PAM_PROMPT_ECHO_OFF:
        reply[replies].resp_retcode = PAM_SUCCESS;
        reply[replies].resp = COPY_STRING(info->pass);
          /* PAM frees resp */
        break;
      case PAM_TEXT_INFO:
        /* fall through */
      case PAM_ERROR_MSG:
        /* ignore it, but pam still wants a NULL response... */
        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;
    }
  }
  *resp = reply;
  return PAM_SUCCESS;
}

/* Server log in
 * Accepts: user name string
 *          password string
 * Returns: "OK" if password validated, error message otherwise
 */ 
char *pwcheck(char *username, char *password)
{
  pam_handle_t *pamh;
  int pam_error;
  PAM_info info;
  struct pam_conv conv;

  /* PAM only handles authentication, not user information. */
  if ( !(username && password && strlen(username) && strlen(password)) )
      return "Incorrect username";

  /* validate password */

  info.pass = password;
  info.user = username;
  conv.conv = PAM_conv;
  conv.appdata_ptr = &info;
  fprintf(stderr, "checking %s\n", username);
  pam_error = pam_start("cyrus", username, &conv, &pamh);
  if (pam_error == PAM_SUCCESS) 
    pam_error = pam_authenticate(pamh, 0);
    
  if (pam_error == PAM_SUCCESS) 
    pam_error = pam_acct_mgmt(pamh, 0);

  if ( pam_error == PAM_SUCCESS) 
    fprintf(stderr, "\tauthenticated %s\n", username);
  else
    fprintf(stderr, "\tfailed to authenticate %s\n", username);
  
  if(pam_end(pamh, pam_error) != PAM_SUCCESS) {
    pamh = NULL;
    fprintf(stderr, "pwcheck: failed to release authenticator\n");
    exit(1);
  }
  return ( pam_error == PAM_SUCCESS ? "OK" : "Incorrect passwd" );
}




--------------070407040106050003000102--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3B310EDC.30405>