Hi folks!
I've written a backend for authlib to sqlite3. It's not complete yet, though,
there are still sever{e,al} security checks missing, which I'll fix after-
wards.
Now: what exactly needs to be done to integrate it into the source? Sorry
for asking such a question, but I mainly develop in Python and have no clue
about the authlib source structure.Greetings, Fabiano
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sqlite3.h>
#include "auth.h"
#include "authstaticlist.h"
#if HAVE_CONFIG_H
#include "courier_auth_config.h"
#endif
#if HAVE_HMACLIB
#include "libhmac/hmac.h"
#include "cramlib.h"
#endif
typedef struct authinfo authinfo;
typedef int* (*callback)(authinfo*, void*);
typedef void (*enumcallback)
(const char*, uid_t, gid_t, const char*, const char*, void*);
static int auth_sqlite(
const char *service,
const char *authtype,
char *authdata,
callback *cb,
void *cbarg);
static int auth_sqlite_no_vrfy(
const char *user,
const char *service,
callback *cb,
void *cbarg);
static void auth_sqlite_exit(
void);
static int auth_sqlite_chgpwd(
const char *service,
const char *user,
const char *oldpwd,
const char *newpwd);
static void auth_sqlite_idle(
void);
static void auth_sqlite_enum(
enumcallback *cb,
void *cbarg);
static struct authstaticinfo authsqlite_info={
"authsqlite",
auth_sqlite,
auth_sqlite_no_vrfy,
auth_sqlite_exit,
auth_sqlite_chgpwd,
auth_sqlite_idle,
auth_sqlite_enum,
};
static sqlite3 *db;
char *errmsg=NULL;
int rc;
char
*dbfilename,
*emailfld, *uidfld, *gidfld, *homefld, *maildirfld, *passwdfld,
*clearpwfld, *optionsfld, *fullnamefld, *quotafld,
*table, *pop3table, *imaptable, *smtptable,
*userfmt, *pop3userfmt, *imapuserfmt, *smtpuserfmt,
*usersfmt, *pop3usersfmt, *imapusersfmt, *smtpusersfmt,
*updatefmt, *pop3updatefmt, *imapupdatefmt, *smtpupdatefmt;
void err(char *fmt, ...)
{
va_list args;
va_start(args,fmt);
vprintf(fmt, args);
va_end(args);
}
static char* concat(
char *first,
char *next,
...)
{
va_list args1, args2;
int retlen=0;
char *p,*ret,*retend;
retlen = strlen(first) + strlen(next);
va_start(args1, next);
va_copy(args2, args1);
while (p=va_arg(args1, char*)) retlen += strlen(p);
va_end(args1);
ret = (char*) malloc(sizeof(char)*retlen);
retend = ret;
while (p=va_arg(args2, char*)) {
strcpy(retend,p);
retend-=1;
}
va_end(args2);
return ret;
}
static struct {
char *svc;
char *userfmt;
char *usersfmt;
char *updatefmt;
int userlen;
int userslen;
int updatelen;
} svc_stmt[] = {
{"NONE",0},
{"pop3",0},
{"imap",0},
{"smtp",0},
};
extern struct authstaticinfo *courier_authsqlite_init(
void)
{
char *tmp;
#define VAR(x,def) (tmp=read_env(#x)) ? tmp : def
dbfilename = VAR(DBFILENAME,"/etc/courier/authsqlite.db");
emailfld = VAR(EMAIL,"email");
uidfld = VAR(UID,"uid");
gidfld = VAR(GID,"gid");
homefld = VAR(HOMEFLD,"home");
maildirfld = VAR(MAILDIR,"maildir");
passwdfld = VAR(PASSWD,"passwd");
clearpwfld = VAR(CLEARPW,"clearpw");
optionsfld = VAR(OPTIONS,"options");
fullnamefld = VAR(FULLNAME,"fullname");
quotafld = VAR(QUOTA,"quota");
table = VAR(TABLE,"users");
pop3table = VAR(POP3TABLE,table);
imaptable = VAR(IMAPTABLE,table);
smtptable = VAR(SMTPTABLE,table);
#undef VAR
userfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",table," where
",emailfld,"=%s", NULL);
pop3userfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",pop3table," where
",emailfld,"=%s", NULL);
imapuserfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",imaptable," where
",emailfld,"=%s", NULL);
smtpuserfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",smtptable," where
",emailfld,"=%s", NULL);
usersfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",table, NULL);
pop3usersfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",pop3table, NULL);
imapusersfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",imaptable, NULL);
smtpusersfmt = concat("select ",emailfld,", ",uidfld,", ",gidfld,",
",homefld,
", ",maildirfld,", ",passwdfld,", ",clearpwfld,",
",optionsfld,", ",
fullnamefld,", ",quotafld," from ",smtptable, NULL);
updatefmt = concat("update ",table, " set ", passwdfld,"=%s",
" where ",emailfld,"=%s", NULL);
pop3updatefmt = concat("update ",pop3table, " set ", passwdfld,"=%s",
" where ",emailfld,"=%s", NULL);
imapupdatefmt = concat("update ",imaptable, " set ", passwdfld,"=%s",
" where ",emailfld,"=%s", NULL);
smtpupdatefmt = concat("update ",smtptable, " set ", passwdfld,"=%s",
" where ",emailfld,"=%s", NULL);
svc_stmt[0].userfmt = userfmt;
svc_stmt[0].usersfmt = usersfmt;
svc_stmt[0].updatefmt = updatefmt;
svc_stmt[0].userlen = strlen(userfmt);
svc_stmt[0].userslen = strlen(usersfmt);
svc_stmt[0].updatelen = strlen(updatefmt);
svc_stmt[1].userfmt = pop3userfmt;
svc_stmt[1].usersfmt = pop3usersfmt;
svc_stmt[1].updatefmt = pop3updatefmt;
svc_stmt[1].userlen = strlen(pop3userfmt);
svc_stmt[1].userslen = strlen(pop3usersfmt);
svc_stmt[1].updatelen = strlen(pop3updatefmt);
svc_stmt[2].userfmt = imapuserfmt;
svc_stmt[2].usersfmt = imapusersfmt;
svc_stmt[2].updatefmt = imapupdatefmt;
svc_stmt[2].userlen = strlen(imapuserfmt);
svc_stmt[2].userslen = strlen(imapusersfmt);
svc_stmt[2].updatelen = strlen(imapupdatefmt);
svc_stmt[3].userfmt = smtpuserfmt;
svc_stmt[3].usersfmt = smtpusersfmt;
svc_stmt[3].updatefmt = smtpupdatefmt;
svc_stmt[3].userlen = strlen(smtpuserfmt);
svc_stmt[3].userslen = strlen(smtpusersfmt);
svc_stmt[3].updatelen = strlen(smtpupdatefmt);
/* open db connection */
if (sqlite3_open(dbfilename, &db)) {
sqlite3_close(db);
return NULL;
}
return &authsqlite_info;
}
static int get_user(
char *user,
char *service,
char ***res,
int *r,
int *c,
char **e)
{
int i;
char *sql;
if (!strcmp(service, svc_stmt[1].svc)) i=1;
else if (!strcmp(service,svc_stmt[2].svc)) i=2;
else if (!strcmp(service,svc_stmt[3].svc)) i=3;
else {
*e = "invalid service";
return 1;
}
sql = (char*) malloc(svc_stmt[i].userlen+strlen(user));
if (sprintf(&sql,svc_stmt[i].userfmt,user)==-1) {
*e = "sprintf failed!";
return 5;
}
if (sqlite3_get_table(db, sql, &res, &r, &c, NULL)!=SQLITE_OK) {
*e = "SQL statement failed";
sqlite3_free_table(&res);
return 2;
}
if (*r==0) {
*e = "user not found";
sqlite3_free_table(&res);
return 3;
}
if (*r>1) {
*e = "ambiguous user name";
sqlite3_free_table(&res);
return 4;
}
return 0;
}
static int get_users(
char *service,
char ***res,
int *r,
int *c,
char **e)
{
int i;
if (!strcmp(service, svc_stmt[1].svc)) i=1;
else if (!strcmp(service,svc_stmt[2].svc)) i=2;
else if (!strcmp(service,svc_stmt[3].svc)) i=3;
else {
*e = "invalid service";
return 1;
}
if (sqlite3_get_table(db, svc_stmt[i].usersfmt, &res, &r, &c, NULL)
!=SQLITE_OK) {
*e = "SQL statement failed";
sqlite3_free_table(&res);
return 2;
}
return 0;
}
static int get_user_errhnd(
char *svc,
char **res,
int errval,
char *mesg)
{
if (errval==1 || errval==3) {
err("error getting user: %s", mesg);
errno=EINVAL;
return -1;
} else if (errval==2 || errval==4) {
err("error getting user: %s", mesg);
errno=EPERM;
return 1;
}
}
static int get_users_errhnd(
char *svc,
char **res,
int errval,
char *mesg)
{
err("error getting users: %s", mesg);
return errval;
}
static int auth_sqlite_common(
const char *user,
const char *pass,
const char *service,
callback *cb,
void *cbarg)
{
char **res;
int r,c,ret;
char *e;
authinfo info = {0};
if (!(ret=get_user(user,service,&res,&r,&c,&e))) {
return get_user_errhnd(service,res,ret,e); }
info.sysusername = NULL;
info.address = res[1][0];
info.sysuserid = strtol(res[1][1], NULL, 0);
info.sysgroupid = strtol(res[1][2], NULL, 0);
info.homedir = res[1][3] ;
info.maildir = res[1][4];
info.passwd = res[1][5];
info.clearpasswd = res[1][6];
info.options = res[1][7];
info.fullname = res[1][8];
info.quota = res[1][9];
return (*cb)(&info, cbarg);
}
static int auth_sqlite(
const char *service,
const char *authtype,
char *authdata,
callback *cb,
void *cbarg)
{
if (strcmp(authtype, AUTHTYPE_LOGIN) == 0) {
const char *user, *pass;
if ((user=strtok(authdata, "\n")) == NULL ||
(pass=strtok(0, "\n")) == NULL) {
errno=EPERM;
return (-1);
}
return auth_sqlite_common(user, pass, service, cb, cbarg);
}
#if HAVE_HMACLIB
struct cram_callback_info cci;
if (auth_get_cram(authtype, authdata, &cci)) return (-1);
cci.callback_func = cb;
cci.callback_arg = cbarg;
return auth_sqlite_common(cci.user, NULL, service, cb, (void*)&cci);
#else
return -1;
#endif
}
static int auth_sqlite_no_vrfy(
const char *user,
const char *service,
callback *cb,
void *cbarg)
{
return auth_sqlite_common(user, NULL, service, cb, cbarg);
}
static void auth_sqlite_exit(
void)
{
sqlite3_close(db);
}
static int auth_sqlite_chgpwd(
const char *service,
const char *user,
const char *oldpw,
const char *newpw)
{
/* TODO */
char **res;
int r,c,ret,i;
char *e;
if (!(ret=get_user(user,service,&res,&r,&c,&e))) {
return get_user_errhnd(service,res,ret,e); }
if (res[1][5]) { // crypted pw
if (authcheckpassword(oldpw,res[1][5])) {
err("wrong password for user %s", user);
errno=EPERM;
return 1;
}
} else if (res[1][6]) { // clear pw
if (strcmp(oldpw,res[1][6])) {
err("wrong password for user %s", user);
errno=EPERM;
return 1;
}
} else {
err("clear pw and crypted pw unset");
errno=EPERM;
return 1;
}
char *newcryptpw = authcryptpasswd(newpw,res[1][5]);
char *sql;
if (!strcmp(service, svc_stmt[1].svc)) i=1;
else if (!strcmp(service,svc_stmt[2].svc)) i=2;
else if (!strcmp(service,svc_stmt[3].svc)) i=3;
else {
err("invalid service: %s",service);
errno=EPERM;
return 2;
}
sql = (char*) malloc(svc_stmt[i].updatelen+strlen(user));
if (sprintf(&sql,svc_stmt[i].updatefmt,user)==-1) {
err("sprintf failed!");
errno=EPERM;
return 3;
}
if (sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK) {
err("error updating passwd: %s", errmsg);
sqlite3_free(errmsg);
errno=EPERM;
return 1;
}
sqlite3_free_table(res);
/* passwd successfully changed */
return 0;
}
static void auth_sqlite_idle(
void)
{
return;
}
static void auth_sqlite_enum(
enumcallback *cb,
void *cbarg)
{
/* TODO */
char **res,*e,*svc=NULL;
int pop3used=0, imapused=0, smtpused=0, r,c,ret,i;
if (!strcmp(usersfmt,pop3usersfmt)) pop3used=1;
if (!strcmp(usersfmt,imapusersfmt)) imapused=1;
if (!strcmp(usersfmt,smtpusersfmt)) smtpused=1;
if (pop3used) {
if (!(ret=get_users("pop3",&res,&r,&c,&e))) {
get_users_errhnd("pop3",res,ret,e);
return;
}
for (i=1;i<=r;i++) {
(*cb)(res[i][0],
strtol(res[i][1], NULL, 0),
strtol(res[i][2], NULL, 0),
res[i][3], res[i][4], cbarg); }
sqlite3_free_table(res);
}
if (imapused) {
if (!(ret=get_users("imap",&res,&r,&c,&e))) {
get_users_errhnd("imap",res,ret,e);
return;
}
for (i=1;i<=r;i++) {
(*cb)(res[i][0],
strtol(res[i][1], NULL, 0),
strtol(res[i][2], NULL, 0),
res[i][3], res[i][4], cbarg); }
sqlite3_free_table(res);
}
if (smtpused) {
if (!(ret=get_users("smtp",&res,&r,&c,&e))) {
get_users_errhnd("smtp",res,ret,e);
return;
}
for (i=1;i<=r;i++) {
(*cb)(res[i][0],
strtol(res[i][1], NULL, 0),
strtol(res[i][2], NULL, 0),
res[i][3], res[i][4], cbarg); }
sqlite3_free_table(res);
}
if (!pop3used) svc="pop3";
else if (!imapused) svc="imap";
else if (!smtpused) svc="smtp";
if (!svc) {
if (!(ret=get_users(svc,&res,&r,&c,&e))) {
get_users_errhnd(svc,res,ret,e);
return;
}
for (i=1;i<=r;i++) {
(*cb)(res[i][0],
strtol(res[i][1], NULL, 0),
strtol(res[i][2], NULL, 0),
res[i][3], res[i][4], cbarg); }
sqlite3_free_table(res);
}
sqlite3_free_table(res);
(*cb)(NULL, 0, 0, NULL, NULL, cbarg);
return;
}
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________ courier-users mailing list [email protected] Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users
