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;
}

Attachment: 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

Reply via email to