/***************************************************************************** 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 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 #include 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 *****************************************************************/