diff --git a/include/auth.h b/include/auth.h index 9319d70..aff2dcb 100644 --- a/include/auth.h +++ b/include/auth.h @@ -1,6 +1,6 @@ /* * ProFTPD - FTP server daemon - * Copyright (c) 2004-2005 The ProFTPD Project team + * Copyright (c) 2004-2007 The ProFTPD Project team * * 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 @@ -86,6 +86,7 @@ int pr_auth_requires_pass(pool *, const char *); config_rec *pr_auth_get_anon_config(pool *p, char **, char **, char **); /* For internal use only. */ +int init_auth(void); int set_groups(pool *, gid_t, array_header *); #endif /* PR_MODULES_H */ diff --git a/modules/mod_core.c b/modules/mod_core.c index d4f0b7e..586e087 100644 --- a/modules/mod_core.c +++ b/modules/mod_core.c @@ -4356,6 +4356,8 @@ static int core_sess_init(void) { config_rec *c = NULL; unsigned int *debug_level = NULL; + init_auth(); + /* Check for a server-specific TimeoutIdle. */ c = find_config(main_server->conf, CONF_PARAM, "TimeoutIdle", FALSE); if (c != NULL) diff --git a/src/auth.c b/src/auth.c index 56a28c5..7537a3e 100644 --- a/src/auth.c +++ b/src/auth.c @@ -2,7 +2,7 @@ * ProFTPD - FTP server daemon * Copyright (c) 1997, 1998 Public Flood Software * Copyright (c) 1999, 2000 MacGyver aka Habeeb J. Dihu <macgyver@tos.net> - * Copyright (c) 2001-2005 The ProFTPD Project team + * Copyright (c) 2001-2007 The ProFTPD Project team * * 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 @@ -30,6 +30,10 @@ #include "conf.h" +static pool *auth_pool = NULL; +static pr_table_t *auth_tab = NULL; +static const char *trace_channel = "auth"; + /* The difference between this function, and pr_cmd_alloc(), is that this * allocates the cmd_rec directly from the given pool, whereas pr_cmd_alloc() * will allocate a subpool from the given pool, and allocate its cmd_rec @@ -63,7 +67,7 @@ static cmd_rec *make_cmd(pool *cp, int argc, ...) { return c; } -static modret_t *dispatch_auth(cmd_rec *cmd, char *match) { +static modret_t *dispatch_auth(cmd_rec *cmd, char *match, module **m) { authtable *authtab = NULL; modret_t *mr = NULL; @@ -71,6 +75,10 @@ static modret_t *dispatch_auth(cmd_rec *cmd, char *match) { &cmd->stash_index); while (authtab) { + if (m && *m && *m != authtab->m) { + goto next; + } + pr_log_debug(DEBUG6, "dispatching auth request \"%s\" to module mod_%s", match, authtab->m->name); @@ -80,9 +88,18 @@ static modret_t *dispatch_auth(cmd_rec *cmd, char *match) { break; if (MODRET_ISHANDLED(mr) || - MODRET_ISERROR(mr)) + MODRET_ISERROR(mr)) { + /* Return a pointer, if requested, to the module which answered the + * auth request. This is used, for example, by auth_getpwnam() for + * associating the answering auth module with the data looked up. + */ + if (m) + *m = authtab->m; + break; + } + next: authtab = pr_stash_get_symbol(PR_SYM_AUTH, match, authtab, &cmd->stash_index); } @@ -95,7 +112,7 @@ void pr_auth_setpwent(pool *p) { modret_t *mr = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "setpwent"); + mr = dispatch_auth(cmd, "setpwent", NULL); if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); @@ -110,13 +127,20 @@ void pr_auth_endpwent(pool *p) { modret_t *mr = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "endpwent"); + mr = dispatch_auth(cmd, "endpwent", NULL); if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); cmd->tmp_pool = NULL; } + if (auth_tab) { + pr_log_debug(DEBUG5, "emptying authcache"); + (void) pr_table_empty(auth_tab); + (void) pr_table_free(auth_tab); + auth_tab = NULL; + } + return; } @@ -125,7 +149,7 @@ void pr_auth_setgrent(pool *p) { modret_t *mr = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "setgrent"); + mr = dispatch_auth(cmd, "setgrent", NULL); if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); @@ -140,7 +164,7 @@ void pr_auth_endgrent(pool *p) { modret_t *mr = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "endgrent"); + mr = dispatch_auth(cmd, "endgrent", NULL); if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); @@ -156,7 +180,7 @@ struct passwd *pr_auth_getpwent(pool *p) { struct passwd *res = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "getpwent"); + mr = dispatch_auth(cmd, "getpwent", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) res = mr->data; @@ -190,7 +214,7 @@ struct group *pr_auth_getgrent(pool *p) { struct group *res = NULL; cmd = make_cmd(p, 0); - mr = dispatch_auth(cmd, "getgrent"); + mr = dispatch_auth(cmd, "getgrent", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) res = mr->data; @@ -217,11 +241,13 @@ struct passwd *pr_auth_getpwnam(pool *p, const char *name) { cmd_rec *cmd = NULL; modret_t *mr = NULL; struct passwd *res = NULL; + module *m = NULL; cmd = make_cmd(p, 1, name); - mr = dispatch_auth(cmd, "getpwnam"); + mr = dispatch_auth(cmd, "getpwnam", &m); - if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) + if (MODRET_ISHANDLED(mr) && + MODRET_HASDATA(mr)) res = mr->data; if (cmd->tmp_pool) { @@ -246,6 +272,46 @@ struct passwd *pr_auth_getpwnam(pool *p, const char *name) { return NULL; } + if (!auth_tab && auth_pool) { + auth_tab = pr_table_alloc(auth_pool, 0); + } + + if (m && auth_tab) { + int count = 0; + void *value = NULL; + + value = palloc(auth_pool, sizeof(module *)); + *((module **) value) = m; + + count = pr_table_exists(auth_tab, name); + if (count <= 0) { + if (pr_table_add(auth_tab, pstrdup(auth_pool, name), value, + sizeof(module *)) < 0) { + pr_log_debug(DEBUG3, + "error adding module 'mod_%s.c' for user '%s' to the authcache: %s", + m->name, name, strerror(errno)); + + } else { + pr_log_debug(DEBUG5, + "stashed module 'mod_%s.c' for user '%s' in the authcache", + m->name, name); + } + + } else { + if (pr_table_set(auth_tab, pstrdup(auth_pool, name), value, + sizeof(module *)) < 0) { + pr_log_debug(DEBUG3, + "error setting module 'mod_%s.c' for user '%s' in the authcache: %s", + m->name, name, strerror(errno)); + + } else { + pr_log_debug(DEBUG5, + "stashed module 'mod_%s.c' for user '%s' in the authcache", + m->name, name); + } + } + } + pr_log_debug(DEBUG10, "retrieved UID %lu for user '%s'", (unsigned long) res->pw_uid, name); return res; @@ -257,7 +323,7 @@ struct passwd *pr_auth_getpwuid(pool *p, uid_t uid) { struct passwd *res = NULL; cmd = make_cmd(p, 1, (void *) &uid); - mr = dispatch_auth(cmd, "getpwuid"); + mr = dispatch_auth(cmd, "getpwuid", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) res = mr->data; @@ -295,7 +361,7 @@ struct group *pr_auth_getgrnam(pool *p, const char *name) { struct group *res = NULL; cmd = make_cmd(p, 1, name); - mr = dispatch_auth(cmd, "getgrnam"); + mr = dispatch_auth(cmd, "getgrnam", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) res = mr->data; @@ -328,7 +394,7 @@ struct group *pr_auth_getgrgid(pool *p, gid_t gid) { struct group *res = NULL; cmd = make_cmd(p, 1, (void *) &gid); - mr = dispatch_auth(cmd, "getgrgid"); + mr = dispatch_auth(cmd, "getgrgid", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) res = mr->data; @@ -358,10 +424,25 @@ struct group *pr_auth_getgrgid(pool *p, gid_t gid) { int pr_auth_authenticate(pool *p, const char *name, const char *pw) { cmd_rec *cmd = NULL; modret_t *mr = NULL; + module *m = NULL; int res = PR_AUTH_NOPWD; cmd = make_cmd(p, 2, name, pw); - mr = dispatch_auth(cmd, "auth"); + + if (auth_tab) { + + /* Fetch the specific module to be used for authenticating this user. */ + void *v = pr_table_get(auth_tab, name, NULL); + if (v) { + m = *((module **) v); + + pr_log_debug(DEBUG4, + "using module 'mod_%s.c' from authcache to authenticate user '%s'", + m->name, name); + } + } + + mr = dispatch_auth(cmd, "auth", m ? &m : NULL); if (MODRET_ISHANDLED(mr)) res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK; @@ -380,10 +461,25 @@ int pr_auth_authenticate(pool *p, const char *name, const char *pw) { int pr_auth_check(pool *p, const char *cpw, const char *name, const char *pw) { cmd_rec *cmd = NULL; modret_t *mr = NULL; + module *m = NULL; int res = PR_AUTH_BADPWD; cmd = make_cmd(p, 3, cpw, name, pw); - mr = dispatch_auth(cmd, "check"); + + if (auth_tab) { + + /* Fetch the specific module to be used for authenticating this user. */ + void *v = pr_table_get(auth_tab, name, NULL); + if (v) { + m = *((module **) v); + + pr_log_debug(DEBUG4, + "using module 'mod_%s.c' from authcache to authenticate user '%s'", + m->name, name); + } + } + + mr = dispatch_auth(cmd, "check", m ? &m : NULL); if (MODRET_ISHANDLED(mr)) res = MODRET_HASDATA(mr) ? PR_AUTH_RFC2228_OK : PR_AUTH_OK; @@ -402,7 +498,7 @@ int pr_auth_requires_pass(pool *p, const char *name) { int res = TRUE; cmd = make_cmd(p, 1, name); - mr = dispatch_auth(cmd, "requires_pass"); + mr = dispatch_auth(cmd, "requires_pass", NULL); if (MODRET_ISHANDLED(mr)) res = FALSE; @@ -427,7 +523,7 @@ const char *pr_auth_uid2name(pool *p, uid_t uid) { memset(namebuf, '\0', sizeof(namebuf)); cmd = make_cmd(p, 1, (void *) &uid); - mr = dispatch_auth(cmd, "uid2name"); + mr = dispatch_auth(cmd, "uid2name", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) { res = mr->data; @@ -452,7 +548,7 @@ const char *pr_auth_gid2name(pool *p, gid_t gid) { memset(namebuf, '\0', sizeof(namebuf)); cmd = make_cmd(p, 1, (void *) &gid); - mr = dispatch_auth(cmd, "gid2name"); + mr = dispatch_auth(cmd, "gid2name", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) { res = mr->data; @@ -474,7 +570,7 @@ uid_t pr_auth_name2uid(pool *p, const char *name) { uid_t res = (uid_t) -1; cmd = make_cmd(p, 1, name); - mr = dispatch_auth(cmd, "name2uid"); + mr = dispatch_auth(cmd, "name2uid", NULL); if (MODRET_ISHANDLED(mr)) res = *((uid_t *) mr->data); @@ -495,7 +591,7 @@ gid_t pr_auth_name2gid(pool *p, const char *name) { gid_t res = (gid_t) -1; cmd = make_cmd(p, 1, name); - mr = dispatch_auth(cmd, "name2gid"); + mr = dispatch_auth(cmd, "name2gid", NULL); if (MODRET_ISHANDLED(mr)) res = *((gid_t *) mr->data); @@ -527,7 +623,7 @@ int pr_auth_getgroups(pool *p, const char *name, array_header **group_ids, cmd = make_cmd(p, 3, name, group_ids ? *group_ids : NULL, group_names ? *group_names : NULL); - mr = dispatch_auth(cmd, "getgroups"); + mr = dispatch_auth(cmd, "getgroups", NULL); if (MODRET_ISHANDLED(mr) && MODRET_HASDATA(mr)) { res = *((int *) mr->data); @@ -821,3 +917,10 @@ int set_groups(pool *p, gid_t primary_gid, array_header *suppl_gids) { return res; } +/* Internal use only. To be called in the session process. */ +int init_auth(void) { + auth_pool = make_sub_pool(permanent_pool); + pr_pool_tag(auth_pool, "Auth API"); + + return 0; +}