/*****************************************************************************
POPular -- A POP3 server and proxy for large mail systems
$Id: libpdm_bdb.c,v 1.2 2003/12/01 13:30:51 sqrt Exp $
http://www.remote.org/jochen/mail/popular/
******************************************************************************
Copyright (C) 1999-2003 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 <db.h>
#include <popular.h>
static struct pdm_mvar *mv;
struct pdm_ctx_bdb {
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_bdb *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_bdb));
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_args()
*****************************************************************************/
char *
pdm_args(void *pdmctx)
{
struct pdm_ctx_bdb *ctx = pdmctx;
return ctx->dirname;
}
/*****************************************************************************
pdm_reload()
We don't have to do anything in this module. Just return true.
*****************************************************************************/
int
pdm_reload(void *pdmctx)
{
return 1;
}
/*****************************************************************************
pdm_check()
*****************************************************************************/
pdm_result_t
pdm_check(void *pdmctx, const struct pdm_request *pdmr, struct pdm_data *pdmd)
{
struct pdm_ctx_bdb *ctx = pdmctx;
DBT key, data;
DB *db;
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 dbm file */
snprintf(namebuf, sizeof(namebuf), "%s/%s.db", ctx->dirname, pdmr->namespace);
/* Create database handle */
dberrno = db_create(&db, NULL, 0);
if (dberrno) {
PDM_DEBUG2("pdm_check", "db_create failed errno=%d errstr='%s'", dberrno, strerror(dberrno));
return pdmError;
}
/* Open dbm file */
PDM_DEBUG1("pdm_check", "opening db file '%s'", namebuf);
dberrno = db->open(db, NULL, namebuf, NULL, DB_HASH, DB_RDONLY, 0);
if (dberrno) {
PDM_DEBUG3("pdm_check", "dbopen_error errno=%d errstr='%s' file='%s'", dberrno, strerror(dberrno), namebuf);
return pdmError;
}
PDM_DEBUG1("pdm_check", "db file '%s' opened", namebuf);
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = pdmr->user;
key.size = strlen(pdmr->user);
/* Get data from Berkeley DB */
PDM_DEBUG0("pdm_check", "getting data from db");
result = (db->get)(db, NULL, &key, &data, 0);
if (result == DB_NOTFOUND) {
(void) db->close(db, 0);
PDM_DEBUG0("pdm_check", "user not found");
return pdmUnknown;
} else if (result != 0) {
PDM_DEBUG2("pdm_check", "dbget_error errno=%d errmsg='%s'", result, strerror(result));
(void) db->close(db, 0);
return pdmError;
}
PDM_DEBUG0("pdm_check", "got data from db");
memcpy(resbuf, data.data, data.size < sizeof(resbuf) ? data.size : sizeof(resbuf));
resbuf[data.size] = 0;
pw = strtok(resbuf, ":"); /* password */
ho = strtok(NULL, ":"); /* server number */
li = strtok(NULL, ":"); /* mailbox file */
if (!ho || !li) {
PDM_DEBUG0("pdm_check", "format error");
(void) db->close(db, 0);
return pdmError;
}
len = strlcpy(pdmd->backend, ho, MAXLEN_ID);
if (len >= MAXLEN_ID) return pdmError;
len = strlcpy(pdmd->user, li, MAXLEN_USERNAME);
if (len >= MAXLEN_USERNAME) 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))) {
(void) db->close(db, 0);
PDM_DEBUG0("pdm_check", "password match, returning");
len = strlcpy(pdmd->pass, pdmr->pass, MAXLEN_PASSWORD);
if (len >= MAXLEN_PASSWORD) return pdmError;
return pdmAccept;
}
(void) db->close(db, 0);
PDM_DEBUG0("pdm_check", "password mismatch, returning");
pdmd->reason = pdmFailPassword;
return pdmFail;
}
/** THE END *****************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1