X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=innduct.git;a=blobdiff_plain;f=nnrpd%2Fperm.c;fp=nnrpd%2Fperm.c;h=0000000000000000000000000000000000000000;hp=50a04ccabb6c9352043a5290ffbef0421da7d713;hb=b7a32e2d73e3ab1add8208d3e157f7269a31ef4d;hpb=ac902a8299ff4469b356836f431ead31c3377377 diff --git a/nnrpd/perm.c b/nnrpd/perm.c deleted file mode 100644 index 50a04cc..0000000 --- a/nnrpd/perm.c +++ /dev/null @@ -1,2362 +0,0 @@ -/* $Id: perm.c 7426 2005-12-11 20:37:27Z eagle $ -** -** How to figure out where a user comes from, and what that user can do once -** we know who sie is. -*/ - -#include "config.h" -#include "clibrary.h" -#include "portable/wait.h" -#include -#include - -#include "conffile.h" -#include "inn/innconf.h" -#include "innperl.h" -#include "nnrpd.h" - -/* Needed on AIX 4.1 to get fd_set and friends. */ -#ifdef HAVE_SYS_SELECT_H -# include -#endif - -/* data types */ -typedef struct _CONFCHAIN { - CONFFILE *f; - struct _CONFCHAIN *parent; -} CONFCHAIN; - -typedef struct _METHOD { - char *name; - char *program; - int type; /* type of auth (perl, python or external) */ - char *users; /* only used for auth_methods, not for res_methods. */ - char **extra_headers; - char **extra_logs; -} METHOD; - -typedef struct _AUTHGROUP { - char *name; - char *key; -#ifdef HAVE_SSL - int require_ssl; -#endif - char *hosts; - METHOD **res_methods; - METHOD **auth_methods; - char *default_user; - char *default_domain; - char *localaddress; - char *access_script; - int access_type; /* type of access (perl or python) */ - char *dynamic_script; - int dynamic_type; /* type of dynamic authorization (python only) */ -} AUTHGROUP; - -typedef struct _GROUP { - char *name; - struct _GROUP *above; - AUTHGROUP *auth; - ACCESSGROUP *access; -} GROUP; - -/* function declarations */ -static void PERMreadfile(char *filename); -static void authdecl_parse(AUTHGROUP*, CONFFILE*, CONFTOKEN*); -static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok); -static void method_parse(METHOD*, CONFFILE*, CONFTOKEN*, int); - -static void add_authgroup(AUTHGROUP*); -static void add_accessgroup(ACCESSGROUP*); -static void strip_accessgroups(void); - -static METHOD *copy_method(METHOD*); -static void free_method(METHOD*); -static AUTHGROUP *copy_authgroup(AUTHGROUP*); -static void free_authgroup(AUTHGROUP*); -static ACCESSGROUP *copy_accessgroup(ACCESSGROUP*); -static void free_accessgroup(ACCESSGROUP*); - -static void CompressList(char*); -static bool MatchHost(char*, char*, char*); -static int MatchUser(char*, char*); -static char *ResolveUser(AUTHGROUP*); -static char *AuthenticateUser(AUTHGROUP*, char*, char*, char*); - -static void GrowArray(void***, void*); -static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *acccess_vec); - -/* global variables */ -static AUTHGROUP **auth_realms; -static AUTHGROUP *success_auth; -static ACCESSGROUP **access_realms; - -static char *ConfigBit; -static int ConfigBitsize; - -extern bool PerlLoaded; - -#define PERMlbrace 1 -#define PERMrbrace 2 -#define PERMgroup 3 -#define PERMauth 4 -#define PERMaccess 5 -#define PERMhost 6 -#define PERMauthprog 7 -#define PERMresolv 8 -#define PERMresprog 9 -#define PERMdefuser 10 -#define PERMdefdomain 11 -#define PERMusers 12 -#define PERMnewsgroups 13 -#define PERMread 14 -#define PERMpost 15 -#define PERMaccessrp 16 -#define PERMheader 17 -#define PERMalsolog 18 -#define PERMprogram 19 -#define PERMinclude 20 -#define PERMkey 21 -#define PERMlocaltime 22 -#define PERMstrippath 23 -#define PERMnnrpdperlfilter 24 -#define PERMnnrpdpythonfilter 25 -#define PERMfromhost 26 -#define PERMpathhost 27 -#define PERMorganization 28 -#define PERMmoderatormailer 29 -#define PERMdomain 30 -#define PERMcomplaints 31 -#define PERMspoolfirst 32 -#define PERMcheckincludedtext 33 -#define PERMclienttimeout 34 -#define PERMlocalmaxartsize 35 -#define PERMreadertrack 36 -#define PERMstrippostcc 37 -#define PERMaddnntppostinghost 38 -#define PERMaddnntppostingdate 39 -#define PERMnnrpdposthost 40 -#define PERMnnrpdpostport 41 -#define PERMnnrpdoverstats 42 -#define PERMbackoff_auth 43 -#define PERMbackoff_db 44 -#define PERMbackoff_k 45 -#define PERMbackoff_postfast 46 -#define PERMbackoff_postslow 47 -#define PERMbackoff_trigger 48 -#define PERMnnrpdcheckart 49 -#define PERMnnrpdauthsender 50 -#define PERMvirtualhost 51 -#define PERMnewsmaster 52 -#define PERMlocaladdress 53 -#define PERMrejectwith 54 -#define PERMmaxbytespersecond 55 -#define PERMperl_auth 56 -#define PERMpython_auth 57 -#define PERMperl_access 58 -#define PERMpython_access 59 -#define PERMpython_dynamic 60 -#ifdef HAVE_SSL -#define PERMrequire_ssl 61 -#define PERMMAX 62 -#else -#define PERMMAX 61 -#endif - -#define TEST_CONFIG(a, b) \ - { \ - int byte, offset; \ - offset = a % 8; \ - byte = (a - offset) / 8; \ - b = ((ConfigBit[byte] & (1 << offset)) != 0) ? true : false; \ - } -#define SET_CONFIG(a) \ - { \ - int byte, offset; \ - offset = a % 8; \ - byte = (a - offset) / 8; \ - ConfigBit[byte] |= (1 << offset); \ - } -#define CLEAR_CONFIG(a) \ - { \ - int byte, offset; \ - offset = a % 8; \ - byte = (a - offset) / 8; \ - ConfigBit[byte] &= ~(1 << offset); \ - } - -static CONFTOKEN PERMtoks[] = { - { PERMlbrace, "{" }, - { PERMrbrace, "}" }, - { PERMgroup, "group" }, - { PERMauth, "auth" }, - { PERMaccess, "access" }, - { PERMhost, "hosts:" }, - { PERMauthprog, "auth:" }, - { PERMresolv, "res" }, - { PERMresprog, "res:" }, - { PERMdefuser, "default:" }, - { PERMdefdomain, "default-domain:" }, - { PERMusers, "users:" }, - { PERMnewsgroups, "newsgroups:" }, - { PERMread, "read:" }, - { PERMpost, "post:" }, - { PERMaccessrp, "access:" }, - { PERMheader, "header:" }, - { PERMalsolog, "log:" }, - { PERMprogram, "program:" }, - { PERMinclude, "include" }, - { PERMkey, "key:" }, - { PERMlocaltime, "localtime:" }, - { PERMstrippath, "strippath:" }, - { PERMnnrpdperlfilter, "perlfilter:" }, - { PERMnnrpdpythonfilter, "pythonfilter:" }, - { PERMfromhost, "fromhost:" }, - { PERMpathhost, "pathhost:" }, - { PERMorganization, "organization:" }, - { PERMmoderatormailer, "moderatormailer:" }, - { PERMdomain, "domain:" }, - { PERMcomplaints, "complaints:" }, - { PERMspoolfirst, "spoolfirst:" }, - { PERMcheckincludedtext, "checkincludedtext:" }, - { PERMclienttimeout, "clienttimeout:" }, - { PERMlocalmaxartsize, "localmaxartsize:" }, - { PERMreadertrack, "readertrack:" }, - { PERMstrippostcc, "strippostcc:" }, - { PERMaddnntppostinghost, "addnntppostinghost:" }, - { PERMaddnntppostingdate, "addnntppostingdate:" }, - { PERMnnrpdposthost, "nnrpdposthost:" }, - { PERMnnrpdpostport, "nnrpdpostport:" }, - { PERMnnrpdoverstats, "nnrpdoverstats:" }, - { PERMbackoff_auth, "backoff_auth:" }, - { PERMbackoff_db, "backoff_db:" }, - { PERMbackoff_k, "backoff_k:" }, - { PERMbackoff_postfast, "backoff_postfast:" }, - { PERMbackoff_postslow, "backoff_postslow:" }, - { PERMbackoff_trigger, "backoff_trigger:" }, - { PERMnnrpdcheckart, "nnrpdcheckart:" }, - { PERMnnrpdauthsender, "nnrpdauthsender:" }, - { PERMvirtualhost, "virtualhost:" }, - { PERMnewsmaster, "newsmaster:" }, - { PERMlocaladdress, "localaddress:" }, - { PERMrejectwith, "reject_with:" }, - { PERMmaxbytespersecond, "max_rate:" }, - { PERMperl_auth, "perl_auth:" }, - { PERMpython_auth, "python_auth:" }, - { PERMperl_access, "perl_access:" }, - { PERMpython_access, "python_access:" }, - { PERMpython_dynamic, "python_dynamic:" }, -#ifdef HAVE_SSL - { PERMrequire_ssl, "require_ssl:" }, -#endif - { 0, 0 } -}; - -/* function definitions */ -static void GrowArray(void ***array, void *el) -{ - int i; - - if (!*array) { - *array = xmalloc(2 * sizeof(void *)); - i = 0; - } else { - for (i = 0; (*array)[i]; i++) - ; - *array = xrealloc(*array, (i + 2) * sizeof(void *)); - } - (*array)[i++] = el; - (*array)[i] = 0; -} - -static METHOD *copy_method(METHOD *orig) -{ - METHOD *ret; - int i; - - ret = xmalloc(sizeof(METHOD)); - memset(ConfigBit, '\0', ConfigBitsize); - - ret->name = xstrdup(orig->name); - ret->program = xstrdup(orig->program); - if (orig->users) - ret->users = xstrdup(orig->users); - else - ret->users = 0; - - ret->extra_headers = 0; - if (orig->extra_headers) { - for (i = 0; orig->extra_headers[i]; i++) - GrowArray((void***) &ret->extra_headers, - (void*) xstrdup(orig->extra_headers[i])); - } - - ret->extra_logs = 0; - if (orig->extra_logs) { - for (i = 0; orig->extra_logs[i]; i++) - GrowArray((void***) &ret->extra_logs, - (void*) xstrdup(orig->extra_logs[i])); - } - - ret->type = orig->type; - - return(ret); -} - -static void free_method(METHOD *del) -{ - int j; - - if (del->extra_headers) { - for (j = 0; del->extra_headers[j]; j++) - free(del->extra_headers[j]); - free(del->extra_headers); - } - if (del->extra_logs) { - for (j = 0; del->extra_logs[j]; j++) - free(del->extra_logs[j]); - free(del->extra_logs); - } - if (del->program) - free(del->program); - if (del->users) - free(del->users); - free(del->name); - free(del); -} - -static AUTHGROUP *copy_authgroup(AUTHGROUP *orig) -{ - AUTHGROUP *ret; - int i; - - if (!orig) - return(0); - ret = xmalloc(sizeof(AUTHGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - - if (orig->name) - ret->name = xstrdup(orig->name); - else - ret->name = 0; - - if (orig->key) - ret->key = xstrdup(orig->key); - else - ret->key = 0; - - if (orig->hosts) - ret->hosts = xstrdup(orig->hosts); - else - ret->hosts = 0; - -#ifdef HAVE_SSL - ret->require_ssl = orig->require_ssl; -#endif - - ret->res_methods = 0; - if (orig->res_methods) { - for (i = 0; orig->res_methods[i]; i++) - GrowArray((void***) &ret->res_methods, - (void*) copy_method(orig->res_methods[i]));; - } - - ret->auth_methods = 0; - if (orig->auth_methods) { - for (i = 0; orig->auth_methods[i]; i++) - GrowArray((void***) &ret->auth_methods, - (void*) copy_method(orig->auth_methods[i])); - } - - if (orig->default_user) - ret->default_user = xstrdup(orig->default_user); - else - ret->default_user = 0; - - if (orig->default_domain) - ret->default_domain = xstrdup(orig->default_domain); - else - ret->default_domain = 0; - - if (orig->localaddress) - ret->localaddress = xstrdup(orig->localaddress); - else - ret->localaddress = 0; - - if (orig->access_script) - ret->access_script = xstrdup(orig->access_script); - else - ret->access_script = 0; - - if (orig->access_type) - ret->access_type = orig->access_type; - else - ret->access_type = 0; - - if (orig->dynamic_script) - ret->dynamic_script = xstrdup(orig->dynamic_script); - else - ret->dynamic_script = 0; - - if (orig->dynamic_type) - ret->dynamic_type = orig->dynamic_type; - else - ret->dynamic_type = 0; - - return(ret); -} - -static ACCESSGROUP *copy_accessgroup(ACCESSGROUP *orig) -{ - ACCESSGROUP *ret; - - if (!orig) - return(0); - ret = xmalloc(sizeof(ACCESSGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - /* copy all anyway, and update for local strings */ - *ret = *orig; - - if (orig->name) - ret->name = xstrdup(orig->name); - if (orig->key) - ret->key = xstrdup(orig->key); - if (orig->read) - ret->read = xstrdup(orig->read); - if (orig->post) - ret->post = xstrdup(orig->post); - if (orig->users) - ret->users = xstrdup(orig->users); - if (orig->rejectwith) - ret->rejectwith = xstrdup(orig->rejectwith); - if (orig->fromhost) - ret->fromhost = xstrdup(orig->fromhost); - if (orig->pathhost) - ret->pathhost = xstrdup(orig->pathhost); - if (orig->organization) - ret->organization = xstrdup(orig->organization); - if (orig->moderatormailer) - ret->moderatormailer = xstrdup(orig->moderatormailer); - if (orig->domain) - ret->domain = xstrdup(orig->domain); - if (orig->complaints) - ret->complaints = xstrdup(orig->complaints); - if (orig->nnrpdposthost) - ret->nnrpdposthost = xstrdup(orig->nnrpdposthost); - if (orig->backoff_db) - ret->backoff_db = xstrdup(orig->backoff_db); - if (orig->newsmaster) - ret->newsmaster = xstrdup(orig->newsmaster); - return(ret); -} - -static void SetDefaultAuth(AUTHGROUP *curauth UNUSED) -{ -#ifdef HAVE_SSL - curauth->require_ssl = false; -#endif -} - -void SetDefaultAccess(ACCESSGROUP *curaccess) -{ - curaccess->allownewnews = innconf->allownewnews;; - curaccess->allowihave = false; - curaccess->locpost = false; - curaccess->allowapproved = false; - curaccess->localtime = false; - curaccess->strippath = false; - curaccess->nnrpdperlfilter = true; - curaccess->nnrpdpythonfilter = true; - curaccess->fromhost = NULL; - if (innconf->fromhost) - curaccess->fromhost = xstrdup(innconf->fromhost); - curaccess->pathhost = NULL; - if (innconf->pathhost) - curaccess->pathhost = xstrdup(innconf->pathhost); - curaccess->organization = NULL; - if (innconf->organization) - curaccess->organization = xstrdup(innconf->organization); - curaccess->moderatormailer = NULL; - if (innconf->moderatormailer) - curaccess->moderatormailer = xstrdup(innconf->moderatormailer); - curaccess->domain = NULL; - if (innconf->domain) - curaccess->domain = xstrdup(innconf->domain); - curaccess->complaints = NULL; - if (innconf->complaints) - curaccess->complaints = xstrdup(innconf->complaints); - curaccess->spoolfirst = innconf->spoolfirst; - curaccess->checkincludedtext = innconf->checkincludedtext; - curaccess->clienttimeout = innconf->clienttimeout; - curaccess->localmaxartsize = innconf->localmaxartsize; - curaccess->readertrack = innconf->readertrack; - curaccess->strippostcc = innconf->strippostcc; - curaccess->addnntppostinghost = innconf->addnntppostinghost; - curaccess->addnntppostingdate = innconf->addnntppostingdate; - curaccess->nnrpdposthost = innconf->nnrpdposthost; - curaccess->nnrpdpostport = innconf->nnrpdpostport; - curaccess->nnrpdoverstats = innconf->nnrpdoverstats; - curaccess->backoff_auth = innconf->backoffauth; - curaccess->backoff_db = NULL; - if (innconf->backoffdb && *innconf->backoffdb != '\0') - curaccess->backoff_db = xstrdup(innconf->backoffdb); - curaccess->backoff_k = innconf->backoffk; - curaccess->backoff_postfast = innconf->backoffpostfast; - curaccess->backoff_postslow = innconf->backoffpostslow; - curaccess->backoff_trigger = innconf->backofftrigger; - curaccess->nnrpdcheckart = innconf->nnrpdcheckart; - curaccess->nnrpdauthsender = innconf->nnrpdauthsender; - curaccess->virtualhost = false; - curaccess->newsmaster = NULL; - curaccess->maxbytespersecond = 0; -} - -static void free_authgroup(AUTHGROUP *del) -{ - int i; - - if (del->name) - free(del->name); - if (del->key) - free(del->key); - if (del->hosts) - free(del->hosts); - if (del->res_methods) { - for (i = 0; del->res_methods[i]; i++) - free_method(del->res_methods[i]); - free(del->res_methods); - } - if (del->auth_methods) { - for (i = 0; del->auth_methods[i]; i++) - free_method(del->auth_methods[i]); - free(del->auth_methods); - } - if (del->default_user) - free(del->default_user); - if (del->default_domain) - free(del->default_domain); - if (del->localaddress) - free(del->localaddress); - if (del->access_script) - free(del->access_script); - if (del->dynamic_script) - free(del->dynamic_script); - free(del); -} - -static void free_accessgroup(ACCESSGROUP *del) -{ - if (del->name) - free(del->name); - if (del->key) - free(del->key); - if (del->read) - free(del->read); - if (del->post) - free(del->post); - if (del->users) - free(del->users); - if (del->rejectwith) - free(del->rejectwith); - if (del->fromhost) - free(del->fromhost); - if (del->pathhost) - free(del->pathhost); - if (del->organization) - free(del->organization); - if (del->moderatormailer) - free(del->moderatormailer); - if (del->domain) - free(del->domain); - if (del->complaints) - free(del->complaints); - if (del->nnrpdposthost) - free(del->nnrpdposthost); - if (del->backoff_db) - free(del->backoff_db); - if (del->newsmaster) - free(del->newsmaster); - free(del); -} - -static void ReportError(CONFFILE *f, const char *err) -{ - syslog(L_ERROR, "%s syntax error in %s(%d), %s", ClientHost, - f->filename, f->lineno, err); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); -} - -static void method_parse(METHOD *method, CONFFILE *f, CONFTOKEN *tok, int auth) -{ - int oldtype; - - oldtype = tok->type; - tok = CONFgettoken(0, f); - - if (tok == NULL) { - ReportError(f, "Expected value."); - } - - switch (oldtype) { - case PERMheader: - GrowArray((void***) &method->extra_headers, (void*) xstrdup(tok->name)); - break; - case PERMalsolog: - GrowArray((void***) &method->extra_logs, (void*) xstrdup(tok->name)); - break; - case PERMusers: - - if (!auth) { - ReportError(f, "Unexpected users: directive in file."); - } else if (method->users) { - ReportError(f, "Multiple users: directive in file."); - } - - method->users = xstrdup(tok->name); - break; - case PERMprogram: - if (method->program) { - ReportError(f, "Multiple program: directives in auth/res decl."); - } - - method->program = xstrdup(tok->name); - break; - } -} - -static void authdecl_parse(AUTHGROUP *curauth, CONFFILE *f, CONFTOKEN *tok) -{ - int oldtype,boolval; - METHOD *m; - bool bit; - char buff[SMBUF], *oldname, *p; - - oldtype = tok->type; - oldname = tok->name; - - tok = CONFgettoken(PERMtoks, f); - - if (tok == NULL) { - ReportError(f, "Expected value."); - } - TEST_CONFIG(oldtype, bit); - if (bit) { - snprintf(buff, sizeof(buff), "Duplicated '%s' field in authgroup.", - oldname); - ReportError(f, buff); - } - - if (strcasecmp(tok->name, "on") == 0 - || strcasecmp(tok->name, "true") == 0 - || strcasecmp(tok->name, "yes") == 0) - boolval = true; - else if (strcasecmp(tok->name, "off") == 0 - || strcasecmp(tok->name, "false") == 0 - || strcasecmp(tok->name, "no") == 0) - boolval = false; - else - boolval = -1; - - switch (oldtype) { - case PERMkey: - curauth->key = xstrdup(tok->name); - SET_CONFIG(PERMkey); - break; -#ifdef HAVE_SSL - case PERMrequire_ssl: - if (boolval != -1) curauth->require_ssl = boolval; - SET_CONFIG(PERMrequire_ssl); - break; -#endif - case PERMhost: - curauth->hosts = xstrdup(tok->name); - CompressList(curauth->hosts); - SET_CONFIG(PERMhost); - - /* nnrpd.c downcases the names of connecting hosts. We should - therefore also downcase the wildmat patterns to make sure there - aren't any surprises. DNS is case-insensitive. */ - for (p = curauth->hosts; *p; p++) - if (CTYPE(isupper, (unsigned char) *p)) - *p = tolower((unsigned char) *p); - - break; - case PERMdefdomain: - curauth->default_domain = xstrdup(tok->name); - SET_CONFIG(PERMdefdomain); - break; - case PERMdefuser: - curauth->default_user = xstrdup(tok->name); - SET_CONFIG(PERMdefuser); - break; - case PERMresolv: - case PERMresprog: - m = xcalloc(1, sizeof(METHOD)); - memset(ConfigBit, '\0', ConfigBitsize); - GrowArray((void***) &curauth->res_methods, (void*) m); - - if (oldtype == PERMresprog) - m->program = xstrdup(tok->name); - else { - m->name = xstrdup(tok->name); - tok = CONFgettoken(PERMtoks, f); - if (tok == NULL || tok->type != PERMlbrace) { - ReportError(f, "Expected '{' after 'res'"); - } - - tok = CONFgettoken(PERMtoks, f); - - while (tok != NULL && tok->type != PERMrbrace) { - method_parse(m, f, tok, 0); - tok = CONFgettoken(PERMtoks, f); - } - - if (tok == NULL) { - ReportError(f, "Unexpected EOF."); - } - } - break; - case PERMauth: - case PERMperl_auth: - case PERMpython_auth: - case PERMauthprog: - m = xcalloc(1, sizeof(METHOD)); - memset(ConfigBit, '\0', ConfigBitsize); - GrowArray((void***) &curauth->auth_methods, (void*) m); - if (oldtype == PERMauthprog) { - m->type = PERMauthprog; - m->program = xstrdup(tok->name); - } else if (oldtype == PERMperl_auth) { -#ifdef DO_PERL - m->type = PERMperl_auth; - m->program = xstrdup(tok->name); -#else - ReportError(f, "perl_auth can not be used in readers.conf: inn not compiled with perl support enabled."); -#endif - } else if (oldtype == PERMpython_auth) { -#ifdef DO_PYTHON - m->type = PERMpython_auth; - m->program = xstrdup(tok->name); -#else - ReportError(f, "python_auth can not be used in readers.conf: inn not compiled with python support enabled."); -#endif - } else { - m->name = xstrdup(tok->name); - tok = CONFgettoken(PERMtoks, f); - - if (tok == NULL || tok->type != PERMlbrace) { - ReportError(f, "Expected '{' after 'auth'"); - } - - tok = CONFgettoken(PERMtoks, f); - - while (tok != NULL && tok->type != PERMrbrace) { - method_parse(m, f, tok, 1); - tok = CONFgettoken(PERMtoks, f); - } - - if (tok == NULL) { - ReportError(f, "Unexpected EOF."); - } - } - break; - case PERMperl_access: -#ifdef DO_PERL - curauth->access_script = xstrdup(tok->name); - curauth->access_type = PERMperl_access; -#else - ReportError(f, "perl_access can not be used in readers.conf: inn not compiled with perl support enabled."); -#endif - break; - case PERMpython_access: -#ifdef DO_PYTHON - curauth->access_script = xstrdup(tok->name); - curauth->access_type = PERMpython_access; -#else - ReportError(f, "python_access can not be used in readers.conf: inn not compiled with python support enabled."); -#endif - break; - case PERMpython_dynamic: -#ifdef DO_PYTHON - curauth->dynamic_script = xstrdup(tok->name); - curauth->dynamic_type = PERMpython_dynamic; -#else - ReportError(f, "python_dynamic can not be used in readers.conf: inn not compiled with python support enabled."); -#endif - break; - case PERMlocaladdress: - curauth->localaddress = xstrdup(tok->name); - CompressList(curauth->localaddress); - SET_CONFIG(PERMlocaladdress); - break; - default: - snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name); - ReportError(f, buff); - break; - } -} - -static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok) -{ - int oldtype, boolval; - bool bit; - char buff[SMBUF], *oldname; - - oldtype = tok->type; - oldname = tok->name; - - tok = CONFgettoken(0, f); - - if (tok == NULL) { - ReportError(f, "Expected value."); - } - TEST_CONFIG(oldtype, bit); - if (bit) { - snprintf(buff, sizeof(buff), "Duplicated '%s' field in accessgroup.", - oldname); - ReportError(f, buff); - } - if (strcasecmp(tok->name, "on") == 0 - || strcasecmp(tok->name, "true") == 0 - || strcasecmp(tok->name, "yes") == 0) - boolval = true; - else if (strcasecmp(tok->name, "off") == 0 - || strcasecmp(tok->name, "false") == 0 - || strcasecmp(tok->name, "no") == 0) - boolval = false; - else - boolval = -1; - - switch (oldtype) { - case PERMkey: - curaccess->key = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMusers: - curaccess->users = xstrdup(tok->name); - CompressList(curaccess->users); - SET_CONFIG(oldtype); - break; - case PERMrejectwith: - curaccess->rejectwith = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMnewsgroups: - TEST_CONFIG(PERMread, bit); - if (bit) { - /* syntax error.. can't set read: or post: _and_ use - * newsgroups: */ - ReportError(f, "read: newsgroups already set."); - } - TEST_CONFIG(PERMpost, bit); - if (bit) { - /* syntax error.. can't set read: or post: _and_ use - * newsgroups: */ - ReportError(f, "post: newsgroups already set."); - } - - curaccess->read = xstrdup(tok->name); - CompressList(curaccess->read); - curaccess->post = xstrdup(tok->name); - CompressList(curaccess->post); - SET_CONFIG(oldtype); - SET_CONFIG(PERMread); - SET_CONFIG(PERMpost); - break; - case PERMread: - curaccess->read = xstrdup(tok->name); - CompressList(curaccess->read); - SET_CONFIG(oldtype); - break; - case PERMpost: - curaccess->post = xstrdup(tok->name); - CompressList(curaccess->post); - SET_CONFIG(oldtype); - break; - case PERMaccessrp: - TEST_CONFIG(PERMread, bit); - if (bit && strchr(tok->name, 'R') == NULL) { - free(curaccess->read); - curaccess->read = 0; - CLEAR_CONFIG(PERMread); - } - TEST_CONFIG(PERMpost, bit); - if (bit && strchr(tok->name, 'P') == NULL) { - free(curaccess->post); - curaccess->post = 0; - CLEAR_CONFIG(PERMpost); - } - curaccess->allowapproved = (strchr(tok->name, 'A') != NULL); - curaccess->allownewnews = (strchr(tok->name, 'N') != NULL); - curaccess->allowihave = (strchr(tok->name, 'I') != NULL); - curaccess->locpost = (strchr(tok->name, 'L') != NULL); - SET_CONFIG(oldtype); - break; - case PERMlocaltime: - if (boolval != -1) curaccess->localtime = boolval; - SET_CONFIG(oldtype); - break; - case PERMstrippath: - if (boolval != -1) curaccess->strippath = boolval; - SET_CONFIG(oldtype); - break; - case PERMnnrpdperlfilter: - if (boolval != -1) curaccess->nnrpdperlfilter = boolval; - SET_CONFIG(oldtype); - break; - case PERMnnrpdpythonfilter: - if (boolval != -1) curaccess->nnrpdpythonfilter = boolval; - SET_CONFIG(oldtype); - break; - case PERMfromhost: - if (curaccess->fromhost) - free(curaccess->fromhost); - curaccess->fromhost = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMpathhost: - if (curaccess->pathhost) - free(curaccess->pathhost); - curaccess->pathhost = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMorganization: - if (curaccess->organization) - free(curaccess->organization); - curaccess->organization = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMmoderatormailer: - if (curaccess->moderatormailer) - free(curaccess->moderatormailer); - curaccess->moderatormailer = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMdomain: - if (curaccess->domain) - free(curaccess->domain); - curaccess->domain = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMcomplaints: - if (curaccess->complaints) - free(curaccess->complaints); - curaccess->complaints = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMspoolfirst: - if (boolval != -1) curaccess->spoolfirst = boolval; - SET_CONFIG(oldtype); - break; - case PERMcheckincludedtext: - if (boolval != -1) curaccess->checkincludedtext = boolval; - SET_CONFIG(oldtype); - break; - case PERMclienttimeout: - curaccess->clienttimeout = atoi(tok->name); - SET_CONFIG(oldtype); - break; - case PERMlocalmaxartsize: - curaccess->localmaxartsize = atol(tok->name); - SET_CONFIG(oldtype); - break; - case PERMreadertrack: - if (boolval != -1) curaccess->readertrack = boolval; - SET_CONFIG(oldtype); - break; - case PERMstrippostcc: - if (boolval != -1) curaccess->strippostcc = boolval; - SET_CONFIG(oldtype); - break; - case PERMaddnntppostinghost: - if (boolval != -1) curaccess->addnntppostinghost = boolval; - SET_CONFIG(oldtype); - break; - case PERMaddnntppostingdate: - if (boolval != -1) curaccess->addnntppostingdate = boolval; - SET_CONFIG(oldtype); - break; - case PERMnnrpdposthost: - if (curaccess->nnrpdposthost) - free(curaccess->nnrpdposthost); - curaccess->nnrpdposthost = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMnnrpdpostport: - curaccess->nnrpdpostport = atoi(tok->name); - SET_CONFIG(oldtype); - break; - case PERMnnrpdoverstats: - if (boolval != -1) curaccess->nnrpdoverstats = boolval; - SET_CONFIG(oldtype); - break; - case PERMbackoff_auth: - if (boolval != -1) curaccess->backoff_auth = boolval; - SET_CONFIG(oldtype); - break; - case PERMbackoff_db: - if (curaccess->backoff_db) - free(curaccess->backoff_db); - curaccess->backoff_db = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMbackoff_k: - curaccess->backoff_k = atol(tok->name); - SET_CONFIG(oldtype); - break; - case PERMbackoff_postfast: - curaccess->backoff_postfast = atol(tok->name); - SET_CONFIG(oldtype); - break; - case PERMbackoff_postslow: - curaccess->backoff_postslow = atol(tok->name); - SET_CONFIG(oldtype); - break; - case PERMbackoff_trigger: - curaccess->backoff_trigger = atol(tok->name); - SET_CONFIG(oldtype); - break; - case PERMnnrpdcheckart: - if (boolval != -1) curaccess->nnrpdcheckart = boolval; - SET_CONFIG(oldtype); - break; - case PERMnnrpdauthsender: - if (boolval != -1) curaccess->nnrpdauthsender = boolval; - SET_CONFIG(oldtype); - break; - case PERMvirtualhost: - if (boolval != -1) curaccess->virtualhost = boolval; - SET_CONFIG(oldtype); - break; - case PERMnewsmaster: - if (curaccess->newsmaster) - free(curaccess->newsmaster); - curaccess->newsmaster = xstrdup(tok->name); - SET_CONFIG(oldtype); - break; - case PERMmaxbytespersecond: - curaccess->maxbytespersecond = atol(tok->name); - SET_CONFIG(oldtype); - break; - default: - snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name); - ReportError(f, buff); - break; - } -} - -static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *access_vec) { - CONFTOKEN *tok = NULL; - CONFFILE *file; - char *str; - unsigned int i; - - file = xcalloc(1, sizeof(CONFFILE)); - file->array = access_vec->strings; - file->array_len = access_vec->count; - - memset(ConfigBit, '\0', ConfigBitsize); - - SetDefaultAccess(acc); - str = xstrdup(name); - acc->name = str; - - for (i = 0; i <= access_vec->count; i++) { - tok = CONFgettoken(PERMtoks, file); - - if (tok != NULL) { - accessdecl_parse(acc, file, tok); - } - } - free(file); - return; -} - -static void PERMreadfile(char *filename) -{ - CONFCHAIN *cf = NULL, - *hold = NULL; - CONFTOKEN *tok = NULL; - int inwhat; - GROUP *curgroup = NULL, - *newgroup = NULL; - ACCESSGROUP *curaccess = NULL; - AUTHGROUP *curauth = NULL; - int oldtype; - char *str = NULL; - char *path = NULL; - char buff[SMBUF]; - - if(filename != NULL) { - syslog(L_TRACE, "Reading access from %s", - filename == NULL ? "(NULL)" : filename); - } - - cf = xmalloc(sizeof(CONFCHAIN)); - if ((cf->f = CONFfopen(filename)) == NULL) { - syslog(L_ERROR, "%s cannot open %s: %m", ClientHost, filename); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); - } - cf->parent = 0; - - /* are we editing an AUTH or ACCESS group? */ - - inwhat = 0; - newgroup = curgroup = 0; - - tok = CONFgettoken(PERMtoks, cf->f); - - while (tok != NULL) { - if (inwhat == 0) { - /* top-level parser */ - - switch (tok->type) { - /* include a child file */ - - case PERMinclude: - tok = CONFgettoken(0, cf->f); - - if (tok == NULL) { - ReportError(cf->f, "Expected filename after 'include'."); - } - - hold = xmalloc(sizeof(CONFCHAIN)); - hold->parent = cf; - - /* unless the filename's path is fully qualified, open it - * relative to /news/etc */ - - path = concatpath(innconf->pathetc, tok->name); - hold->f = CONFfopen(path); - free(path); - - if (hold->f == NULL) { - ReportError(cf->f, "Couldn't open 'include' filename."); - } - - cf = hold; - goto again; - break; - - /* nested group declaration. */ - case PERMgroup: - tok = CONFgettoken(PERMtoks, cf->f); - - if (tok == NULL) { - ReportError(cf->f, "Unexpected EOF at group name"); - } - - newgroup = xmalloc(sizeof(GROUP)); - newgroup->above = curgroup; - newgroup->name = xstrdup(tok->name); - memset(ConfigBit, '\0', ConfigBitsize); - - tok = CONFgettoken(PERMtoks, cf->f); - - if (tok == NULL || tok->type != PERMlbrace) { - ReportError(cf->f, "Expected '{' after group name"); - } - - /* nested group declaration */ - if (curgroup) { - newgroup->auth = copy_authgroup(curgroup->auth); - newgroup->access = copy_accessgroup(curgroup->access); - } else { - newgroup->auth = 0; - newgroup->access = 0; - } - - curgroup = newgroup; - break; - - /* beginning of an auth or access group decl */ - case PERMauth: - case PERMaccess: - oldtype = tok->type; - - if ((tok = CONFgettoken(PERMtoks, cf->f)) == NULL) { - ReportError(cf->f, "Expected identifier."); - } - - str = xstrdup(tok->name); - - tok = CONFgettoken(PERMtoks, cf->f); - - if (tok == NULL || tok->type != PERMlbrace) { - ReportError(cf->f, "Expected '{'"); - } - - switch (oldtype) { - case PERMauth: - if (curgroup && curgroup->auth) - curauth = copy_authgroup(curgroup->auth); - else { - curauth = xcalloc(1, sizeof(AUTHGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - SetDefaultAuth(curauth); - } - - curauth->name = str; - inwhat = 1; - break; - - case PERMaccess: - if (curgroup && curgroup->access) - curaccess = copy_accessgroup(curgroup->access); - else { - curaccess = xcalloc(1, sizeof(ACCESSGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - SetDefaultAccess(curaccess); - } - curaccess->name = str; - inwhat = 2; - break; - } - - break; - - /* end of a group declaration */ - - case PERMrbrace: - if (curgroup == NULL) { - ReportError(cf->f, "Unmatched '}'"); - } - - newgroup = curgroup; - curgroup = curgroup->above; - if (newgroup->auth) - free_authgroup(newgroup->auth); - if (newgroup->access) - free_accessgroup(newgroup->access); - free(newgroup->name); - free(newgroup); - break; - - /* stuff that belongs in an authgroup */ - case PERMhost: -#ifdef HAVE_SSL - case PERMrequire_ssl: -#endif - case PERMauthprog: - case PERMresprog: - case PERMdefuser: - case PERMdefdomain: - if (curgroup == NULL) { - curgroup = xcalloc(1, sizeof(GROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - } - if (curgroup->auth == NULL) { - curgroup->auth = xcalloc(1, sizeof(AUTHGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - SetDefaultAuth(curgroup->auth); - } - - authdecl_parse(curgroup->auth, cf->f, tok); - break; - - /* stuff that belongs in an accessgroup */ - case PERMusers: - case PERMrejectwith: - case PERMnewsgroups: - case PERMread: - case PERMpost: - case PERMaccessrp: - case PERMlocaltime: - case PERMstrippath: - case PERMnnrpdperlfilter: - case PERMnnrpdpythonfilter: - case PERMfromhost: - case PERMpathhost: - case PERMorganization: - case PERMmoderatormailer: - case PERMdomain: - case PERMcomplaints: - case PERMspoolfirst: - case PERMcheckincludedtext: - case PERMclienttimeout: - case PERMlocalmaxartsize: - case PERMreadertrack: - case PERMstrippostcc: - case PERMaddnntppostinghost: - case PERMaddnntppostingdate: - case PERMnnrpdposthost: - case PERMnnrpdpostport: - case PERMnnrpdoverstats: - case PERMbackoff_auth: - case PERMbackoff_db: - case PERMbackoff_k: - case PERMbackoff_postfast: - case PERMbackoff_postslow: - case PERMbackoff_trigger: - case PERMnnrpdcheckart: - case PERMnnrpdauthsender: - case PERMvirtualhost: - case PERMnewsmaster: - if (!curgroup) { - curgroup = xcalloc(1, sizeof(GROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - } - if (!curgroup->access) { - curgroup->access = xcalloc(1, sizeof(ACCESSGROUP)); - memset(ConfigBit, '\0', ConfigBitsize); - SetDefaultAccess(curgroup->access); - } - accessdecl_parse(curgroup->access, cf->f, tok); - break; - default: - snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name); - ReportError(cf->f, buff); - break; - } - } else if (inwhat == 1) { - /* authgroup parser */ - if (tok->type == PERMrbrace) { - inwhat = 0; - - if (curauth->name -#ifdef HAVE_SSL - && ((curauth->require_ssl == false) || (ClientSSL == true)) -#endif - && MatchHost(curauth->hosts, ClientHost, ClientIpString)) { - if (!MatchHost(curauth->localaddress, ServerHost, ServerIpString)) { - syslog(L_TRACE, "Auth strategy '%s' does not match localhost. Removing.", - curauth->name == NULL ? "(NULL)" : curauth->name); - free_authgroup(curauth); - } else - add_authgroup(curauth); - } else { - syslog(L_TRACE, "Auth strategy '%s' does not match client. Removing.", - curauth->name == NULL ? "(NULL)" : curauth->name); - free_authgroup(curauth); - } - curauth = NULL; - goto again; - } - - authdecl_parse(curauth, cf->f, tok); - } else if (inwhat == 2) { - /* accessgroup parser */ - if (tok->type == PERMrbrace) { - inwhat = 0; - - if (curaccess->name) - add_accessgroup(curaccess); - else - free_accessgroup(curaccess); - curaccess = NULL; - goto again; - } - - accessdecl_parse(curaccess, cf->f, tok); - } else { - /* should never happen */ - syslog(L_TRACE, "SHOULD NEVER HAPPEN!"); - } -again: - /* go back up the 'include' chain. */ - tok = CONFgettoken(PERMtoks, cf->f); - - while (tok == NULL && cf) { - hold = cf; - cf = hold->parent; - CONFfclose(hold->f); - free(hold); - if (cf) { - tok = CONFgettoken(PERMtoks, cf->f); - } - } - } - - return; -} - -void PERMgetaccess(char *nnrpaccess) -{ - int i; - char *uname; - int canauthenticate; - - auth_realms = NULL; - access_realms = NULL; - success_auth = NULL; - - PERMcanread = PERMcanpost = false; - PERMreadlist = PERMpostlist = false; - PERMaccessconf = NULL; - - if (ConfigBit == NULL) { - if (PERMMAX % 8 == 0) - ConfigBitsize = PERMMAX/8; - else - ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1; - ConfigBit = xcalloc(ConfigBitsize, 1); - } - PERMreadfile(nnrpaccess); - - strip_accessgroups(); - - if (auth_realms == NULL) { - /* no one can talk, empty file */ - syslog(L_NOTICE, "%s no_permission", ClientHost); - Printf("%d You have no permission to talk. Goodbye.\r\n", - NNTP_ACCESS_VAL); - ExitWithStats(1, true); - } - - /* auth_realms are all expected to match the user. */ - canauthenticate = 0; - for (i = 0; auth_realms[i]; i++) - if (auth_realms[i]->auth_methods) - canauthenticate = 1; - uname = 0; - while (!uname && i--) { - if ((uname = ResolveUser(auth_realms[i])) != NULL) - PERMauthorized = true; - if (!uname && auth_realms[i]->default_user) - uname = auth_realms[i]->default_user; - } - if (uname) { - strlcpy(PERMuser, uname, sizeof(PERMuser)); - uname = strchr(PERMuser, '@'); - if (!uname && auth_realms[i]->default_domain) { - /* append the default domain to the username */ - strlcat(PERMuser, "@", sizeof(PERMuser)); - strlcat(PERMuser, auth_realms[i]->default_domain, - sizeof(PERMuser)); - } - PERMneedauth = false; - success_auth = auth_realms[i]; - syslog(L_TRACE, "%s res %s", ClientHost, PERMuser); - } else if (!canauthenticate) { - /* couldn't resolve the user. */ - syslog(L_NOTICE, "%s no_user", ClientHost); - Printf("%d Could not get your access name. Goodbye.\r\n", - NNTP_ACCESS_VAL); - ExitWithStats(1, true); - } else { - PERMneedauth = true; - } - /* check maximum allowed permissions for any host that matches (for - * the greeting string) */ - for (i = 0; access_realms[i]; i++) { - if (!PERMcanread) - PERMcanread = (access_realms[i]->read != NULL); - if (!PERMcanpost) - PERMcanpost = (access_realms[i]->post != NULL); - } - if (!i) { - /* no applicable access groups. Zeroing all these makes INN - * return permission denied to client. */ - PERMcanread = PERMcanpost = PERMneedauth = false; - } -} - -void PERMlogin(char *uname, char *pass, char *errorstr) -{ - int i = 0; - char *runame; - - if (ConfigBit == NULL) { - if (PERMMAX % 8 == 0) - ConfigBitsize = PERMMAX/8; - else - ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1; - ConfigBit = xcalloc(ConfigBitsize, 1); - } - /* The check in CMDauthinfo uses the value of PERMneedauth to know if - * authentication succeeded or not. By default, authentication doesn't - * succeed. */ - PERMneedauth = true; - - if(auth_realms != NULL) { - for (i = 0; auth_realms[i]; i++) { - ; - } - } - - runame = NULL; - - while (runame == NULL && i--) - runame = AuthenticateUser(auth_realms[i], uname, pass, errorstr); - if (runame) { - strlcpy(PERMuser, runame, sizeof(PERMuser)); - uname = strchr(PERMuser, '@'); - if (!uname && auth_realms[i]->default_domain) { - /* append the default domain to the username */ - strlcat(PERMuser, "@", sizeof(PERMuser)); - strlcat(PERMuser, auth_realms[i]->default_domain, - sizeof(PERMuser)); - } - PERMneedauth = false; - PERMauthorized = true; - success_auth = auth_realms[i]; - } -} - -static int MatchUser(char *pat, char *user) -{ - char *cp, **list; - char *userlist[2]; - int ret; - - if (!pat) - return(1); - if (!user || !*user) - return(0); - cp = xstrdup(pat); - list = 0; - NGgetlist(&list, cp); - userlist[0] = user; - userlist[1] = 0; - ret = PERMmatch(list, userlist); - free(cp); - free(list[0]); - free(list); - return(ret); -} - -void PERMgetpermissions() -{ - int i; - char *cp, **list; - char *user[2]; - static ACCESSGROUP *noaccessconf; - char *uname; - char *cpp, *script_path; - char **args; - struct vector *access_vec; - - if (ConfigBit == NULL) { - if (PERMMAX % 8 == 0) - ConfigBitsize = PERMMAX/8; - else - ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1; - ConfigBit = xcalloc(ConfigBitsize, 1); - } - if (!success_auth) { - /* if we haven't successfully authenticated, we can't do anything. */ - syslog(L_TRACE, "%s no_success_auth", ClientHost); - if (!noaccessconf) - noaccessconf = xmalloc(sizeof(ACCESSGROUP)); - PERMaccessconf = noaccessconf; - SetDefaultAccess(PERMaccessconf); - return; -#ifdef DO_PERL - } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMperl_access)) { - i = 0; - cpp = xstrdup(success_auth->access_script); - args = 0; - Argify(cpp, &args); - script_path = concat(args[0], (char *) 0); - if ((script_path != NULL) && (strlen(script_path) > 0)) { - if(!PerlLoaded) { - loadPerl(); - } - PERLsetup(NULL, script_path, "access"); - free(script_path); - - uname = xstrdup(PERMuser); - - access_vec = vector_new(); - - perlAccess(uname, access_vec); - free(uname); - - access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP)); - - PERMvectortoaccess(access_realms[0], "perl-dynamic", access_vec); - - vector_free(access_vec); - } else { - syslog(L_ERROR, "No script specified in perl_access method.\n"); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); - } - free(cpp); - free(args); -#endif /* DO_PERL */ -#ifdef DO_PYTHON - } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMpython_access)) { - i = 0; - cpp = xstrdup(success_auth->access_script); - args = 0; - Argify(cpp, &args); - script_path = concat(args[0], (char *) 0); - if ((script_path != NULL) && (strlen(script_path) > 0)) { - uname = xstrdup(PERMuser); - access_vec = vector_new(); - - PY_access(script_path, access_vec, uname); - free(script_path); - free(uname); - free(args); - - access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP)); - memset(access_realms[0], 0, sizeof(ACCESSGROUP)); - - PERMvectortoaccess(access_realms[0], "python-dynamic", access_vec); - - vector_free(access_vec); - } else { - syslog(L_ERROR, "No script specified in python_access method.\n"); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); - } - free(cpp); -#endif /* DO_PYTHON */ - } else { - for (i = 0; access_realms[i]; i++) - ; - user[0] = PERMuser; - user[1] = 0; - while (i--) { - if ((!success_auth->key && !access_realms[i]->key) || - (access_realms[i]->key && success_auth->key && - strcmp(access_realms[i]->key, success_auth->key) == 0)) { - if (!access_realms[i]->users) - break; - else if (!*PERMuser) - continue; - cp = xstrdup(access_realms[i]->users); - list = 0; - NGgetlist(&list, cp); - if (PERMmatch(list, user)) { - syslog(L_TRACE, "%s match_user %s %s", ClientHost, - PERMuser, access_realms[i]->users); - free(cp); - free(list[0]); - free(list); - break; - } else - syslog(L_TRACE, "%s no_match_user %s %s", ClientHost, - PERMuser, access_realms[i]->users); - free(cp); - free(list[0]); - free(list); - } - } - } - if (i >= 0) { - /* found the right access group */ - if (access_realms[i]->rejectwith) { - syslog(L_ERROR, "%s rejected by rule (%s)", - ClientHost, access_realms[i]->rejectwith); - Reply("%d Permission denied: %s\r\n", - NNTP_ACCESS_VAL, access_realms[i]->rejectwith); - ExitWithStats(1, true); - } - if (access_realms[i]->read) { - cp = xstrdup(access_realms[i]->read); - PERMspecified = NGgetlist(&PERMreadlist, cp); - free(cp); - PERMcanread = true; - } else { - syslog(L_TRACE, "%s no_read %s", ClientHost, access_realms[i]->name); - PERMcanread = false; - } - if (access_realms[i]->post) { - cp = xstrdup(access_realms[i]->post); - NGgetlist(&PERMpostlist, cp); - free(cp); - PERMcanpost = true; - } else { - syslog(L_TRACE, "%s no_post %s", ClientHost, access_realms[i]->name); - PERMcanpost = false; - } - PERMaccessconf = access_realms[i]; - MaxBytesPerSecond = PERMaccessconf->maxbytespersecond; - if (PERMaccessconf->virtualhost) { - if (PERMaccessconf->domain == NULL) { - syslog(L_ERROR, "%s virtualhost needs domain parameter(%s)", - ClientHost, PERMaccessconf->name); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); - } - if (VirtualPath) - free(VirtualPath); - if (strcmp(innconf->pathhost, PERMaccessconf->pathhost) == 0) { - /* use domain, if pathhost in access relm matches one in - inn.conf to differentiate virtual host */ - if (innconf->domain != NULL && strcmp(innconf->domain, PERMaccessconf->domain) == 0) { - syslog(L_ERROR, "%s domain parameter(%s) in readers.conf must be different from the one in inn.conf", - ClientHost, PERMaccessconf->name); - Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL); - ExitWithStats(1, true); - } - VirtualPath = concat(PERMaccessconf->domain, "!", (char *) 0); - } else { - VirtualPath = concat(PERMaccessconf->pathhost, "!", - (char *) 0); - } - VirtualPathlen = strlen(VirtualPath); - } else - VirtualPathlen = 0; - } else { - if (!noaccessconf) - noaccessconf = xmalloc(sizeof(ACCESSGROUP)); - PERMaccessconf = noaccessconf; - SetDefaultAccess(PERMaccessconf); - syslog(L_TRACE, "%s no_access_realm", ClientHost); - } - /* check if dynamic access control is enabled, if so init it */ -#ifdef DO_PYTHON - if ((success_auth->dynamic_type == PERMpython_dynamic) && success_auth->dynamic_script) { - PY_dynamic_init(success_auth->dynamic_script); - } -#endif /* DO_PYTHON */ -} - -/* strip blanks out of a string */ -static void CompressList(char *list) -{ - char *cpto; - bool inword = false; - - for (cpto = list; *list; ) { - if (strchr("\n \t,", *list) != NULL) { - list++; - if(inword) { - *cpto++ = ','; - inword = false; - } - } else { - *cpto++ = *list++; - inword = true; - } - } - *cpto = '\0'; -} - -static bool MatchHost(char *hostlist, char *host, char *ip) -{ - char **list; - bool ret = false; - char *cp; - int iter; - char *pat, - *p; - - /* If no hostlist are specified, by default they match. */ - - if (hostlist == NULL) { - return(true); - } - - list = 0; - cp = xstrdup(hostlist); - - NGgetlist(&list, cp); - - /* default is no access */ - for (iter = 0; list[iter]; iter++) { - ; - } - - while (iter-- > 0) { - pat = list[iter]; - if (*pat == '!') - pat++; - ret = uwildmat(host, pat); - if (!ret && *ip) { - ret = uwildmat(ip, pat); - if (!ret && (p = strchr(pat, '/')) != (char *)NULL) { - unsigned int bits, c; - struct in_addr ia, net, tmp; -#ifdef HAVE_INET6 - struct in6_addr ia6, net6; - unsigned char bits8; -#endif - unsigned int mask; - - *p = '\0'; - if (inet_aton(ip, &ia) && inet_aton(pat, &net)) { - if (strchr(p+1, '.') == (char *)NULL) { - /* string following / is a masklength */ - mask = atoi(p+1); - for (bits = c = 0; c < mask && c < 32; c++) - bits |= (1 << (31 - c)); - mask = htonl(bits); - } else { /* or it may be a dotted quad bitmask */ - if (inet_aton(p+1, &tmp)) - mask = tmp.s_addr; - else /* otherwise skip it */ - continue; - } - if ((ia.s_addr & mask) == (net.s_addr & mask)) - ret = true; - } -#ifdef HAVE_INET6 - else if (inet_pton(AF_INET6, ip, &ia6) && - inet_pton(AF_INET6, pat, &net6)) { - mask = atoi(p+1); - ret = true; - /* do a prefix match byte by byte */ - for (c = 0; c*8 < mask && c < sizeof(ia6); c++) { - if ( (c+1)*8 <= mask && - ia6.s6_addr[c] != net6.s6_addr[c] ) { - ret = false; - break; - } else if ( (c+1)*8 > mask ) { - unsigned int b; - - for (bits8 = b = 0; b < (mask % 8); b++) - bits8 |= (1 << (7 - b)); - if ((ia6.s6_addr[c] & bits8) != - (net6.s6_addr[c] & bits8) ) { - ret = false; - break; - } - } - } - } -#endif - } - } - if (ret) - break; - } - if (ret && list[iter][0] == '!') - ret = false; - free(list[0]); - free(list); - free(cp); - return(ret); -} - -static void add_authgroup(AUTHGROUP *group) -{ - int i; - - if (auth_realms == NULL) { - i = 0; - auth_realms = xmalloc(2 * sizeof(AUTHGROUP *)); - } else { - for (i = 0; auth_realms[i]; i++) - ; - auth_realms = xrealloc(auth_realms, (i + 2) * sizeof(AUTHGROUP *)); - } - auth_realms[i] = group; - auth_realms[i+1] = 0; -} - -static void add_accessgroup(ACCESSGROUP *group) -{ - int i; - - if (access_realms == NULL) { - i = 0; - access_realms = xmalloc(2 * sizeof(ACCESSGROUP *)); - } else { - for (i = 0; access_realms[i]; i++) - ; - access_realms = xrealloc(access_realms, (i + 2) * sizeof(ACCESSGROUP *)); - } - access_realms[i] = group; - access_realms[i+1] = 0; -} - -/* clean out access groups that don't apply to any of our auth groups. */ - -static void strip_accessgroups(void) -{ - int i, j; - - /* flag the access group as used or not */ - - if(access_realms != NULL) { - for (j = 0; access_realms[j] != NULL; j++) { - access_realms[j]->used = 0; - } - } else { - syslog(L_TRACE, "No access realms to check!"); - } - - /* If there are auth realms to check... */ - - if(auth_realms != NULL) { - /* ... Then for each auth realm... */ - - for (i = 0; auth_realms[i] != NULL; i++) { - - /* ... for each access realm... */ - - for (j = 0; access_realms[j] != NULL; j++) { - - /* If the access realm isn't already in use... */ - - if (! access_realms[j]->used) { - /* Check to see if both the access_realm key and - auth_realm key are NULL... */ - - if (!access_realms[j]->key && !auth_realms[i]->key) { - /* If so, mark the realm in use and continue on... */ - - access_realms[j]->used = 1; - } else { - /* If not, check to see if both the access_realm and - auth_realm are NOT _both_ NULL, and see if they are - equal... */ - - if (access_realms[j]->key && auth_realms[i]->key && - strcmp(access_realms[j]->key, auth_realms[i]->key) == 0) { - - /* And if so, mark the realm in use. */ - - access_realms[j]->used = 1; - } - } - } - } - } - } else { - syslog(L_TRACE, "No auth realms to check!"); - } - - /* strip out unused access groups */ - i = j = 0; - - while (access_realms[i] != NULL) { - if (access_realms[i]->used) - access_realms[j++] = access_realms[i]; - else - syslog(L_TRACE, "%s removing irrelevant access group %s", - ClientHost, access_realms[i]->name); - i++; - } - access_realms[j] = 0; -} - -typedef struct _EXECSTUFF { - pid_t pid; - int rdfd, errfd, wrfd; -} EXECSTUFF; - -static EXECSTUFF *ExecProg(char *arg0, char **args) -{ - EXECSTUFF *ret; - int rdfd[2], errfd[2], wrfd[2]; - pid_t pid; - struct stat stb; - -#if !defined(S_IXUSR) && defined(_S_IXUSR) -#define S_IXUSR _S_IXUSR -#endif /* !defined(S_IXUSR) && defined(_S_IXUSR) */ - -#if !defined(S_IXUSR) && defined(S_IEXEC) -#define S_IXUSR S_IEXEC -#endif /* !defined(S_IXUSR) && defined(S_IEXEC) */ - - if (stat(arg0, &stb) || !(stb.st_mode&S_IXUSR)) - return(0); - - pipe(rdfd); - pipe(errfd); - pipe(wrfd); - switch (pid = fork()) { - case -1: - close(rdfd[0]); - close(rdfd[1]); - close(errfd[0]); - close(errfd[1]); - close(wrfd[0]); - close(wrfd[1]); - return(0); - case 0: - close(rdfd[0]); - dup2(rdfd[1], 1); - close(errfd[0]); - dup2(errfd[1], 2); - close(wrfd[1]); - dup2(wrfd[0], 0); - execv(arg0, args); - /* if we got here, there was an error */ - syslog(L_ERROR, "%s perm could not exec %s: %m", ClientHost, arg0); - exit(1); - } - close(rdfd[1]); - close(errfd[1]); - close(wrfd[0]); - ret = xmalloc(sizeof(EXECSTUFF)); - ret->pid = pid; - ret->rdfd = rdfd[0]; - ret->errfd = errfd[0]; - ret->wrfd = wrfd[1]; - return(ret); -} - -static void GetConnInfo(METHOD *method, char *buf) -{ - int i; - - buf[0] = '\0'; - if (*ClientHost) - sprintf(buf, "ClientHost: %s\r\n", ClientHost); - if (*ClientIpString) - sprintf(buf+strlen(buf), "ClientIP: %s\r\n", ClientIpString); - if (ClientPort) - sprintf(buf+strlen(buf), "ClientPort: %d\r\n", ClientPort); - if (*ServerIpString) - sprintf(buf+strlen(buf), "LocalIP: %s\r\n", ServerIpString); - if (ServerPort) - sprintf(buf+strlen(buf), "LocalPort: %d\r\n", ServerPort); - /* handle this here, since we only get here when we're about to exec - * something. */ - if (method->extra_headers) { - for (i = 0; method->extra_headers[i]; i++) - sprintf(buf+strlen(buf), "%s\r\n", method->extra_headers[i]); - } -} - -static char ubuf[SMBUF]; - -typedef void (*LineFunc)(char*); - -/* messages from a program's stdout */ -static void HandleProgLine(char *ln) -{ - if (strncasecmp(ln, "User:", strlen("User:")) == 0) - strlcpy(ubuf, ln + strlen("User:"), sizeof(ubuf)); -} - -/* messages from a programs stderr */ -static void HandleErrorLine(char *ln) -{ - syslog(L_NOTICE, "%s auth_err %s", ClientHost, ln); -} - -static bool -HandleProgInput(int fd, char *buf, int buflen, LineFunc f) -{ - char *nl; - char *start; - int curpos, got; - - /* read the data */ - curpos = strlen(buf); - if (curpos >= buflen-1) { - /* data overflow (on one line!) */ - return false; - } - got = read(fd, buf+curpos, buflen-curpos-1); - if (got <= 0) - return false; - buf[curpos+got] = '\0'; - - /* break what we got up into lines */ - start = nl = buf; - while ((nl = strchr(nl, '\n')) != NULL) { - if (nl != buf && *(nl-1) == '\r') - *(nl-1) = '\0'; - *nl++ = '\0'; - f(start); - start = nl; - } - - /* delete all the lines we've read from the buffer. */ - /* 'start' points to the end of the last unterminated string */ - nl = start; - start = buf; - if (nl == start) { - return true; - } - - while (*nl) { - *start++ = *nl++; - } - - *start = '\0'; - - return true; -} - -static void GetProgInput(EXECSTUFF *prog) -{ - fd_set rfds, tfds; - int maxfd; - int got; - bool okay; - struct timeval tmout; - pid_t tmp; - int status; - char rdbuf[BIG_BUFFER], errbuf[BIG_BUFFER]; - double start, end; - - FD_ZERO(&rfds); - FD_SET(prog->rdfd, &rfds); - FD_SET(prog->errfd, &rfds); - tfds = rfds; - maxfd = prog->rdfd > prog->errfd ? prog->rdfd : prog->errfd; - tmout.tv_sec = 5; - tmout.tv_usec = 0; - rdbuf[0] = errbuf[0] = '\0'; - start = TMRnow_double(); - while ((got = select(maxfd+1, &tfds, 0, 0, &tmout)) >= 0) { - end = TMRnow_double(); - IDLEtime += end - start; - start = end; - tmout.tv_sec = 5; - tmout.tv_usec = 0; - if (got > 0) { - if (FD_ISSET(prog->rdfd, &tfds)) { - okay = HandleProgInput(prog->rdfd, rdbuf, sizeof(rdbuf), HandleProgLine); - if (!okay) { - close(prog->rdfd); - FD_CLR(prog->rdfd, &tfds); - kill(prog->pid, SIGTERM); - } - } - if (FD_ISSET(prog->errfd, &tfds)) { - okay = HandleProgInput(prog->errfd, errbuf, sizeof(errbuf), HandleErrorLine); - if (!okay) { - close(prog->errfd); - FD_CLR(prog->errfd, &tfds); - kill(prog->pid, SIGTERM); - } - } - } - tfds = rfds; - } - end = TMRnow_double(); - IDLEtime += end - start; - /* wait for it if he's toast. */ - do { - tmp = waitpid(prog->pid, &status, 0); - } while ((tmp >= 0 || (tmp < 0 && errno == EINTR)) && - !WIFEXITED(status) && !WIFSIGNALED(status)); - if (WIFSIGNALED(status)) { - ubuf[0] = '\0'; - syslog(L_NOTICE, "%s bad_hook program caught signal %d", ClientHost, - WTERMSIG(status)); - } else if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != 0) { - ubuf[0] = '\0'; - syslog(L_TRACE, "%s bad_hook program exited with status %d", - ClientHost, WEXITSTATUS(status)); - } - } else { - syslog(L_ERROR, "%s bad_hook waitpid failed: %m", ClientHost); - ubuf[0] = '\0'; - } -} - -/* execute a series of resolvers to get the remote username */ -static char *ResolveUser(AUTHGROUP *auth) -{ - int i, j; - char *cp; - char **args; - char *arg0; - char *resdir; - char *tmp; - EXECSTUFF *foo; - int done = 0; - char buf[BIG_BUFFER]; - - if (!auth->res_methods) - return(0); - - tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR); - resdir = concatpath(tmp, _PATH_AUTHDIR_NOPASS); - free(tmp); - - ubuf[0] = '\0'; - for (i = 0; auth->res_methods[i]; i++) { - /* build the command line */ - syslog(L_TRACE, "%s res starting resolver %s", ClientHost, auth->res_methods[i]->program); - if (auth->res_methods[i]->extra_logs) { - for (j = 0; auth->res_methods[i]->extra_logs[j]; j++) - syslog(L_NOTICE, "%s res also-log: %s", ClientHost, - auth->res_methods[i]->extra_logs[j]); - } - cp = xstrdup(auth->res_methods[i]->program); - args = 0; - Argify(cp, &args); - arg0 = args[0]; - if (args[0][0] != '/') - arg0 = concat(resdir, "/", arg0, (char *) 0); - /* exec the resolver */ - foo = ExecProg(arg0, args); - if (foo) { - GetConnInfo(auth->res_methods[i], buf); - strlcat(buf, ".\r\n", sizeof(buf)); - xwrite(foo->wrfd, buf, strlen(buf)); - close(foo->wrfd); - - GetProgInput(foo); - done = (ubuf[0] != '\0'); - if (done) - syslog(L_TRACE, "%s res resolver successful, user %s", ClientHost, ubuf); - else - syslog(L_TRACE, "%s res resolver failed", ClientHost); - free(foo); - } else - syslog(L_ERROR, "%s res couldnt start resolver: %m", ClientHost); - /* clean up */ - if (args[0][0] != '/') { - free(arg0); - } - free(args); - free(cp); - if (done) - /* this resolver succeeded */ - break; - } - free(resdir); - if (ubuf[0]) - return(ubuf); - return(0); -} - -/* execute a series of authenticators to get the remote username */ -static char *AuthenticateUser(AUTHGROUP *auth, char *username, char *password, char *errorstr) -{ - int i, j; - char *cp; - char **args; - char *arg0; - char *resdir; - char *tmp; - char *script_path; - char newUser[BIG_BUFFER]; - EXECSTUFF *foo; - int done = 0; - int code; - char buf[BIG_BUFFER]; - - if (!auth->auth_methods) - return(0); - - tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR); - resdir = concatpath(tmp, _PATH_AUTHDIR_PASSWD); - free(tmp); - - ubuf[0] = '\0'; - newUser[0] = '\0'; - for (i = 0; auth->auth_methods[i]; i++) { - if (auth->auth_methods[i]->type == PERMperl_auth) { -#ifdef DO_PERL - cp = xstrdup(auth->auth_methods[i]->program); - args = 0; - Argify(cp, &args); - script_path = concat(args[0], (char *) 0); - if ((script_path != NULL) && (strlen(script_path) > 0)) { - if(!PerlLoaded) { - loadPerl(); - } - PERLsetup(NULL, script_path, "authenticate"); - free(script_path); - perlAuthInit(); - - code = perlAuthenticate(username, password, errorstr, newUser); - if (code == NNTP_AUTH_OK_VAL) { - /* Set the value of ubuf to the right username */ - if (newUser[0] != '\0') { - strlcpy(ubuf, newUser, sizeof(ubuf)); - } else { - strlcpy(ubuf, username, sizeof(ubuf)); - } - - syslog(L_NOTICE, "%s user %s", ClientHost, ubuf); - if (LLOGenable) { - fprintf(locallog, "%s user %s\n", ClientHost, ubuf); - fflush(locallog); - } - break; - } else { - syslog(L_NOTICE, "%s bad_auth", ClientHost); - } - } else { - syslog(L_ERROR, "No script specified in auth method.\n"); - } -#endif /* DO_PERL */ - } else if (auth->auth_methods[i]->type == PERMpython_auth) { -#ifdef DO_PYTHON - cp = xstrdup(auth->auth_methods[i]->program); - args = 0; - Argify(cp, &args); - script_path = concat(args[0], (char *) 0); - if ((script_path != NULL) && (strlen(script_path) > 0)) { - code = PY_authenticate(script_path, username, password, errorstr, newUser); - free(script_path); - if (code < 0) { - syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined."); - } else { - if (code == NNTP_AUTH_OK_VAL) { - /* Set the value of ubuf to the right username */ - if (newUser[0] != '\0') { - strlcpy(ubuf, newUser, sizeof(ubuf)); - } else { - strlcpy(ubuf, username, sizeof(ubuf)); - } - - syslog(L_NOTICE, "%s user %s", ClientHost, ubuf); - if (LLOGenable) { - fprintf(locallog, "%s user %s\n", ClientHost, ubuf); - fflush(locallog); - } - break; - } else { - syslog(L_NOTICE, "%s bad_auth", ClientHost); - } - } - } else { - syslog(L_ERROR, "No script specified in auth method.\n"); - } -#endif /* DO_PYTHON */ - } else { - if (auth->auth_methods[i]->users && - !MatchUser(auth->auth_methods[i]->users, username)) - continue; - - /* build the command line */ - syslog(L_TRACE, "%s auth starting authenticator %s", ClientHost, auth->auth_methods[i]->program); - if (auth->auth_methods[i]->extra_logs) { - for (j = 0; auth->auth_methods[i]->extra_logs[j]; j++) - syslog(L_NOTICE, "%s auth also-log: %s", ClientHost, - auth->auth_methods[i]->extra_logs[j]); - } - cp = xstrdup(auth->auth_methods[i]->program); - args = 0; - Argify(cp, &args); - arg0 = args[0]; - if (args[0][0] != '/') - arg0 = concat(resdir, "/", arg0, (char *) 0); - /* exec the authenticator */ - foo = ExecProg(arg0, args); - if (foo) { - GetConnInfo(auth->auth_methods[i], buf); - snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3, - "ClientAuthname: %s\r\n", username); - snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3, - "ClientPassword: %s\r\n", password); - strlcat(buf, ".\r\n", sizeof(buf)); - xwrite(foo->wrfd, buf, strlen(buf)); - close(foo->wrfd); - - GetProgInput(foo); - done = (ubuf[0] != '\0'); - if (done) - syslog(L_TRACE, "%s auth authenticator successful, user %s", ClientHost, ubuf); - else - syslog(L_TRACE, "%s auth authenticator failed", ClientHost); - free(foo); - } else - syslog(L_ERROR, "%s auth couldnt start authenticator: %m", ClientHost); - /* clean up */ - if (args[0][0] != '/') { - free(arg0); - } - free(args); - free(cp); - if (done) - /* this authenticator succeeded */ - break; - } - } - free(resdir); - if (ubuf[0]) - return(ubuf); - return(0); -}