/*****************************************************************************

  POPular -- A POP3 server and proxy for large mail systems

  $Id: libpdm_cdb.c,v 1.1 2001/04/08 18:50:10 sqrt Exp $

  http://www.remote.org/jochen/mail/popular/

******************************************************************************

  Copyright (C) 1999-2001  Jochen Topf <jochen@remote.org>

  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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA

*****************************************************************************/

#include <popular.h>
#include <cdb.h>


static struct pdm_mvar *mv;

struct pdm_ctx_cdb {
  char dirname[MAXBUF];
};


/*****************************************************************************
 
  pdm_init()
 
  Currently the filename is only saved in the init function and the file
  will be opened every time an authentication is done. This might change
  in a future version.
 
*****************************************************************************/
char *
pdm_init(int argc, char *argv[], struct pdm_mvar *mvar, void **pdmctx)
{
  struct pdm_ctx_cdb *ctx;
  mv = mvar;

  PDM_DEBUG3("pdm_init", "start with argc=%d id='%s' name='%s'", argc, argv[0], argv[1]);
  
  if (argc != 3) {
    PDM_DEBUG0("pdm_init", "argc != 1");
    return("not enough or too many arguments");
  }

  ctx = malloc(sizeof(struct pdm_ctx_cdb));
  if (! ctx) {
    PDM_DEBUG0("pdm_init", "out of memory");
    return("out of memory");
  }
  strlcpy(ctx->dirname, argv[2], sizeof(ctx->dirname));

  *pdmctx = ctx;
  PDM_DEBUG1("pdm_init", "module initialized (dirname='%s')", ctx->dirname);
  return NULL;
}


/*****************************************************************************
 
  pdm_close()

*****************************************************************************/
int
pdm_close(void *pdmctx)
{
  free(pdmctx);
  return 0;
}


/*****************************************************************************
 
  pdm_check()

*****************************************************************************/
pdm_result_t
pdm_check(void *pdmctx, const struct pdm_request *pdmr, struct pdm_data *pdmd)
{
  struct pdm_ctx_cdb *ctx = pdmctx;
  int fd;
  struct cdb c;
  int result;
  char *pw, *ho, *li;
  char namebuf[80];
  char resbuf[1024];
  int dberrno;
  int len;

  PDM_DEBUG1("pdm_check", "started ns='%s'", pdmr->namespace);

  /* translate user name to lowercase */
  {
    char *p;
    for (p=pdmr->user; *p; p++) *p = tolower(*p);
  }

  /* Name of cdb file */
  snprintf(namebuf, sizeof(namebuf), "%s/%s.cdb", ctx->dirname, pdmr->namespace);

  /* Open cdb file */
  fd = open(namebuf, O_RDONLY);
  if (fd < 0) {
    PDM_DEBUG3("pdm_check", "open_error errno=%d errstr='%s' file='%s'", dberrno, strerror(dberrno), namebuf);
    return pdmError;
  }
  cdb_init(&c, fd);

  PDM_DEBUG1("pdm_check", "cdb file '%s' opened", namebuf);

  /* Get data from cdb */ 
  result = cdb_find(&c, pdmr->user, strlen(pdmr->user));
  switch (result) {
    case 0:
      PDM_DEBUG0("pdm_check", "user not found");
      cdb_free(&c);
      close(fd);
      return pdmUnknown;
    case -1:
      PDM_DEBUG2("pdm_check", "cdb_error errno=%d errstr='%s'", errno, strerror(errno));
      cdb_free(&c);
      close(fd);
      return pdmError;
  }

  if (cdb_datalen(&c) > sizeof(resbuf)) {
    PDM_DEBUG0("pdm_check", "data size too large");
    cdb_free(&c);
    close(fd);
    return pdmError;
  }

  result = cdb_read(&c, resbuf, cdb_datalen(&c), cdb_datapos(&c));
  if (result == -1) {
    PDM_DEBUG0("pdm_check", "cdb_read error");
    cdb_free(&c);
    close(fd);
    return pdmError;
  }

  resbuf[cdb_datalen(&c)] = 0;

  cdb_free(&c);
  close(fd);

  pw = strtok(resbuf, ":");     /* password */
  ho = strtok(NULL, ":");       /* server number */
  li = strtok(NULL, ":");       /* mailbox file */
  if (!ho || !li) {
    PDM_DEBUG0("pdm_check", "format error");
    return pdmError;
  }

  len = strlcpy(pdmd->backend, ho, MAXLEN_ID);
  if (len >= MAXLEN_ID) {
    PDM_DEBUG0("pdm_check", "backend id too long");
    return pdmError;
  }

  len = strlcpy(pdmd->user, li, MAXLEN_USERNAME);
  if (len >= MAXLEN_USERNAME) {
    PDM_DEBUG0("pdm_check", "user name too long");
    return pdmError;
  }

  PDM_DEBUG2("pdm_check", "got user/mailbox='%s' backend='%s'", pdmd->user, pdmd->backend);

  /* Check password */
  if (!strcmp(pw, crypt(pdmr->pass, pw))) {
    PDM_DEBUG0("pdm_check", "password match, returning");
    len = strlcpy(pdmd->pass, pdmr->pass, MAXLEN_PASSWORD);
    if (len >= MAXLEN_PASSWORD) return pdmError;
    return pdmAccept;
  }

  PDM_DEBUG0("pdm_check", "password mismatch, returning");
  pdmd->reason = pdmFailPassword;
  return pdmFail;
}


/** THE END *****************************************************************/


syntax highlighted by Code2HTML, v. 0.9.1