1 /* $Id: perm.c 7426 2005-12-11 20:37:27Z eagle $
3 ** How to figure out where a user comes from, and what that user can do once
9 #include "portable/wait.h"
14 #include "inn/innconf.h"
18 /* Needed on AIX 4.1 to get fd_set and friends. */
19 #ifdef HAVE_SYS_SELECT_H
20 # include <sys/select.h>
24 typedef struct _CONFCHAIN {
26 struct _CONFCHAIN *parent;
29 typedef struct _METHOD {
32 int type; /* type of auth (perl, python or external) */
33 char *users; /* only used for auth_methods, not for res_methods. */
38 typedef struct _AUTHGROUP {
46 METHOD **auth_methods;
51 int access_type; /* type of access (perl or python) */
53 int dynamic_type; /* type of dynamic authorization (python only) */
56 typedef struct _GROUP {
63 /* function declarations */
64 static void PERMreadfile(char *filename);
65 static void authdecl_parse(AUTHGROUP*, CONFFILE*, CONFTOKEN*);
66 static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok);
67 static void method_parse(METHOD*, CONFFILE*, CONFTOKEN*, int);
69 static void add_authgroup(AUTHGROUP*);
70 static void add_accessgroup(ACCESSGROUP*);
71 static void strip_accessgroups(void);
73 static METHOD *copy_method(METHOD*);
74 static void free_method(METHOD*);
75 static AUTHGROUP *copy_authgroup(AUTHGROUP*);
76 static void free_authgroup(AUTHGROUP*);
77 static ACCESSGROUP *copy_accessgroup(ACCESSGROUP*);
78 static void free_accessgroup(ACCESSGROUP*);
80 static void CompressList(char*);
81 static bool MatchHost(char*, char*, char*);
82 static int MatchUser(char*, char*);
83 static char *ResolveUser(AUTHGROUP*);
84 static char *AuthenticateUser(AUTHGROUP*, char*, char*, char*);
86 static void GrowArray(void***, void*);
87 static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *acccess_vec);
89 /* global variables */
90 static AUTHGROUP **auth_realms;
91 static AUTHGROUP *success_auth;
92 static ACCESSGROUP **access_realms;
94 static char *ConfigBit;
95 static int ConfigBitsize;
97 extern bool PerlLoaded;
105 #define PERMauthprog 7
107 #define PERMresprog 9
108 #define PERMdefuser 10
109 #define PERMdefdomain 11
111 #define PERMnewsgroups 13
114 #define PERMaccessrp 16
115 #define PERMheader 17
116 #define PERMalsolog 18
117 #define PERMprogram 19
118 #define PERMinclude 20
120 #define PERMlocaltime 22
121 #define PERMstrippath 23
122 #define PERMnnrpdperlfilter 24
123 #define PERMnnrpdpythonfilter 25
124 #define PERMfromhost 26
125 #define PERMpathhost 27
126 #define PERMorganization 28
127 #define PERMmoderatormailer 29
128 #define PERMdomain 30
129 #define PERMcomplaints 31
130 #define PERMspoolfirst 32
131 #define PERMcheckincludedtext 33
132 #define PERMclienttimeout 34
133 #define PERMlocalmaxartsize 35
134 #define PERMreadertrack 36
135 #define PERMstrippostcc 37
136 #define PERMaddnntppostinghost 38
137 #define PERMaddnntppostingdate 39
138 #define PERMnnrpdposthost 40
139 #define PERMnnrpdpostport 41
140 #define PERMnnrpdoverstats 42
141 #define PERMbackoff_auth 43
142 #define PERMbackoff_db 44
143 #define PERMbackoff_k 45
144 #define PERMbackoff_postfast 46
145 #define PERMbackoff_postslow 47
146 #define PERMbackoff_trigger 48
147 #define PERMnnrpdcheckart 49
148 #define PERMnnrpdauthsender 50
149 #define PERMvirtualhost 51
150 #define PERMnewsmaster 52
151 #define PERMlocaladdress 53
152 #define PERMrejectwith 54
153 #define PERMmaxbytespersecond 55
154 #define PERMperl_auth 56
155 #define PERMpython_auth 57
156 #define PERMperl_access 58
157 #define PERMpython_access 59
158 #define PERMpython_dynamic 60
160 #define PERMrequire_ssl 61
166 #define TEST_CONFIG(a, b) \
170 byte = (a - offset) / 8; \
171 b = ((ConfigBit[byte] & (1 << offset)) != 0) ? true : false; \
173 #define SET_CONFIG(a) \
177 byte = (a - offset) / 8; \
178 ConfigBit[byte] |= (1 << offset); \
180 #define CLEAR_CONFIG(a) \
184 byte = (a - offset) / 8; \
185 ConfigBit[byte] &= ~(1 << offset); \
188 static CONFTOKEN PERMtoks[] = {
191 { PERMgroup, "group" },
192 { PERMauth, "auth" },
193 { PERMaccess, "access" },
194 { PERMhost, "hosts:" },
195 { PERMauthprog, "auth:" },
196 { PERMresolv, "res" },
197 { PERMresprog, "res:" },
198 { PERMdefuser, "default:" },
199 { PERMdefdomain, "default-domain:" },
200 { PERMusers, "users:" },
201 { PERMnewsgroups, "newsgroups:" },
202 { PERMread, "read:" },
203 { PERMpost, "post:" },
204 { PERMaccessrp, "access:" },
205 { PERMheader, "header:" },
206 { PERMalsolog, "log:" },
207 { PERMprogram, "program:" },
208 { PERMinclude, "include" },
210 { PERMlocaltime, "localtime:" },
211 { PERMstrippath, "strippath:" },
212 { PERMnnrpdperlfilter, "perlfilter:" },
213 { PERMnnrpdpythonfilter, "pythonfilter:" },
214 { PERMfromhost, "fromhost:" },
215 { PERMpathhost, "pathhost:" },
216 { PERMorganization, "organization:" },
217 { PERMmoderatormailer, "moderatormailer:" },
218 { PERMdomain, "domain:" },
219 { PERMcomplaints, "complaints:" },
220 { PERMspoolfirst, "spoolfirst:" },
221 { PERMcheckincludedtext, "checkincludedtext:" },
222 { PERMclienttimeout, "clienttimeout:" },
223 { PERMlocalmaxartsize, "localmaxartsize:" },
224 { PERMreadertrack, "readertrack:" },
225 { PERMstrippostcc, "strippostcc:" },
226 { PERMaddnntppostinghost, "addnntppostinghost:" },
227 { PERMaddnntppostingdate, "addnntppostingdate:" },
228 { PERMnnrpdposthost, "nnrpdposthost:" },
229 { PERMnnrpdpostport, "nnrpdpostport:" },
230 { PERMnnrpdoverstats, "nnrpdoverstats:" },
231 { PERMbackoff_auth, "backoff_auth:" },
232 { PERMbackoff_db, "backoff_db:" },
233 { PERMbackoff_k, "backoff_k:" },
234 { PERMbackoff_postfast, "backoff_postfast:" },
235 { PERMbackoff_postslow, "backoff_postslow:" },
236 { PERMbackoff_trigger, "backoff_trigger:" },
237 { PERMnnrpdcheckart, "nnrpdcheckart:" },
238 { PERMnnrpdauthsender, "nnrpdauthsender:" },
239 { PERMvirtualhost, "virtualhost:" },
240 { PERMnewsmaster, "newsmaster:" },
241 { PERMlocaladdress, "localaddress:" },
242 { PERMrejectwith, "reject_with:" },
243 { PERMmaxbytespersecond, "max_rate:" },
244 { PERMperl_auth, "perl_auth:" },
245 { PERMpython_auth, "python_auth:" },
246 { PERMperl_access, "perl_access:" },
247 { PERMpython_access, "python_access:" },
248 { PERMpython_dynamic, "python_dynamic:" },
250 { PERMrequire_ssl, "require_ssl:" },
255 /* function definitions */
256 static void GrowArray(void ***array, void *el)
261 *array = xmalloc(2 * sizeof(void *));
264 for (i = 0; (*array)[i]; i++)
266 *array = xrealloc(*array, (i + 2) * sizeof(void *));
272 static METHOD *copy_method(METHOD *orig)
277 ret = xmalloc(sizeof(METHOD));
278 memset(ConfigBit, '\0', ConfigBitsize);
280 ret->name = xstrdup(orig->name);
281 ret->program = xstrdup(orig->program);
283 ret->users = xstrdup(orig->users);
287 ret->extra_headers = 0;
288 if (orig->extra_headers) {
289 for (i = 0; orig->extra_headers[i]; i++)
290 GrowArray((void***) &ret->extra_headers,
291 (void*) xstrdup(orig->extra_headers[i]));
295 if (orig->extra_logs) {
296 for (i = 0; orig->extra_logs[i]; i++)
297 GrowArray((void***) &ret->extra_logs,
298 (void*) xstrdup(orig->extra_logs[i]));
301 ret->type = orig->type;
306 static void free_method(METHOD *del)
310 if (del->extra_headers) {
311 for (j = 0; del->extra_headers[j]; j++)
312 free(del->extra_headers[j]);
313 free(del->extra_headers);
315 if (del->extra_logs) {
316 for (j = 0; del->extra_logs[j]; j++)
317 free(del->extra_logs[j]);
318 free(del->extra_logs);
328 static AUTHGROUP *copy_authgroup(AUTHGROUP *orig)
335 ret = xmalloc(sizeof(AUTHGROUP));
336 memset(ConfigBit, '\0', ConfigBitsize);
339 ret->name = xstrdup(orig->name);
344 ret->key = xstrdup(orig->key);
349 ret->hosts = xstrdup(orig->hosts);
354 ret->require_ssl = orig->require_ssl;
357 ret->res_methods = 0;
358 if (orig->res_methods) {
359 for (i = 0; orig->res_methods[i]; i++)
360 GrowArray((void***) &ret->res_methods,
361 (void*) copy_method(orig->res_methods[i]));;
364 ret->auth_methods = 0;
365 if (orig->auth_methods) {
366 for (i = 0; orig->auth_methods[i]; i++)
367 GrowArray((void***) &ret->auth_methods,
368 (void*) copy_method(orig->auth_methods[i]));
371 if (orig->default_user)
372 ret->default_user = xstrdup(orig->default_user);
374 ret->default_user = 0;
376 if (orig->default_domain)
377 ret->default_domain = xstrdup(orig->default_domain);
379 ret->default_domain = 0;
381 if (orig->localaddress)
382 ret->localaddress = xstrdup(orig->localaddress);
384 ret->localaddress = 0;
386 if (orig->access_script)
387 ret->access_script = xstrdup(orig->access_script);
389 ret->access_script = 0;
391 if (orig->access_type)
392 ret->access_type = orig->access_type;
394 ret->access_type = 0;
396 if (orig->dynamic_script)
397 ret->dynamic_script = xstrdup(orig->dynamic_script);
399 ret->dynamic_script = 0;
401 if (orig->dynamic_type)
402 ret->dynamic_type = orig->dynamic_type;
404 ret->dynamic_type = 0;
409 static ACCESSGROUP *copy_accessgroup(ACCESSGROUP *orig)
415 ret = xmalloc(sizeof(ACCESSGROUP));
416 memset(ConfigBit, '\0', ConfigBitsize);
417 /* copy all anyway, and update for local strings */
421 ret->name = xstrdup(orig->name);
423 ret->key = xstrdup(orig->key);
425 ret->read = xstrdup(orig->read);
427 ret->post = xstrdup(orig->post);
429 ret->users = xstrdup(orig->users);
430 if (orig->rejectwith)
431 ret->rejectwith = xstrdup(orig->rejectwith);
433 ret->fromhost = xstrdup(orig->fromhost);
435 ret->pathhost = xstrdup(orig->pathhost);
436 if (orig->organization)
437 ret->organization = xstrdup(orig->organization);
438 if (orig->moderatormailer)
439 ret->moderatormailer = xstrdup(orig->moderatormailer);
441 ret->domain = xstrdup(orig->domain);
442 if (orig->complaints)
443 ret->complaints = xstrdup(orig->complaints);
444 if (orig->nnrpdposthost)
445 ret->nnrpdposthost = xstrdup(orig->nnrpdposthost);
446 if (orig->backoff_db)
447 ret->backoff_db = xstrdup(orig->backoff_db);
448 if (orig->newsmaster)
449 ret->newsmaster = xstrdup(orig->newsmaster);
453 static void SetDefaultAuth(AUTHGROUP *curauth UNUSED)
456 curauth->require_ssl = false;
460 void SetDefaultAccess(ACCESSGROUP *curaccess)
462 curaccess->allownewnews = innconf->allownewnews;;
463 curaccess->allowihave = false;
464 curaccess->locpost = false;
465 curaccess->allowapproved = false;
466 curaccess->localtime = false;
467 curaccess->strippath = false;
468 curaccess->nnrpdperlfilter = true;
469 curaccess->nnrpdpythonfilter = true;
470 curaccess->fromhost = NULL;
471 if (innconf->fromhost)
472 curaccess->fromhost = xstrdup(innconf->fromhost);
473 curaccess->pathhost = NULL;
474 if (innconf->pathhost)
475 curaccess->pathhost = xstrdup(innconf->pathhost);
476 curaccess->organization = NULL;
477 if (innconf->organization)
478 curaccess->organization = xstrdup(innconf->organization);
479 curaccess->moderatormailer = NULL;
480 if (innconf->moderatormailer)
481 curaccess->moderatormailer = xstrdup(innconf->moderatormailer);
482 curaccess->domain = NULL;
484 curaccess->domain = xstrdup(innconf->domain);
485 curaccess->complaints = NULL;
486 if (innconf->complaints)
487 curaccess->complaints = xstrdup(innconf->complaints);
488 curaccess->spoolfirst = innconf->spoolfirst;
489 curaccess->checkincludedtext = innconf->checkincludedtext;
490 curaccess->clienttimeout = innconf->clienttimeout;
491 curaccess->localmaxartsize = innconf->localmaxartsize;
492 curaccess->readertrack = innconf->readertrack;
493 curaccess->strippostcc = innconf->strippostcc;
494 curaccess->addnntppostinghost = innconf->addnntppostinghost;
495 curaccess->addnntppostingdate = innconf->addnntppostingdate;
496 curaccess->nnrpdposthost = innconf->nnrpdposthost;
497 curaccess->nnrpdpostport = innconf->nnrpdpostport;
498 curaccess->nnrpdoverstats = innconf->nnrpdoverstats;
499 curaccess->backoff_auth = innconf->backoffauth;
500 curaccess->backoff_db = NULL;
501 if (innconf->backoffdb && *innconf->backoffdb != '\0')
502 curaccess->backoff_db = xstrdup(innconf->backoffdb);
503 curaccess->backoff_k = innconf->backoffk;
504 curaccess->backoff_postfast = innconf->backoffpostfast;
505 curaccess->backoff_postslow = innconf->backoffpostslow;
506 curaccess->backoff_trigger = innconf->backofftrigger;
507 curaccess->nnrpdcheckart = innconf->nnrpdcheckart;
508 curaccess->nnrpdauthsender = innconf->nnrpdauthsender;
509 curaccess->virtualhost = false;
510 curaccess->newsmaster = NULL;
511 curaccess->maxbytespersecond = 0;
514 static void free_authgroup(AUTHGROUP *del)
524 if (del->res_methods) {
525 for (i = 0; del->res_methods[i]; i++)
526 free_method(del->res_methods[i]);
527 free(del->res_methods);
529 if (del->auth_methods) {
530 for (i = 0; del->auth_methods[i]; i++)
531 free_method(del->auth_methods[i]);
532 free(del->auth_methods);
534 if (del->default_user)
535 free(del->default_user);
536 if (del->default_domain)
537 free(del->default_domain);
538 if (del->localaddress)
539 free(del->localaddress);
540 if (del->access_script)
541 free(del->access_script);
542 if (del->dynamic_script)
543 free(del->dynamic_script);
547 static void free_accessgroup(ACCESSGROUP *del)
560 free(del->rejectwith);
565 if (del->organization)
566 free(del->organization);
567 if (del->moderatormailer)
568 free(del->moderatormailer);
572 free(del->complaints);
573 if (del->nnrpdposthost)
574 free(del->nnrpdposthost);
576 free(del->backoff_db);
578 free(del->newsmaster);
582 static void ReportError(CONFFILE *f, const char *err)
584 syslog(L_ERROR, "%s syntax error in %s(%d), %s", ClientHost,
585 f->filename, f->lineno, err);
586 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
587 ExitWithStats(1, true);
590 static void method_parse(METHOD *method, CONFFILE *f, CONFTOKEN *tok, int auth)
595 tok = CONFgettoken(0, f);
598 ReportError(f, "Expected value.");
603 GrowArray((void***) &method->extra_headers, (void*) xstrdup(tok->name));
606 GrowArray((void***) &method->extra_logs, (void*) xstrdup(tok->name));
611 ReportError(f, "Unexpected users: directive in file.");
612 } else if (method->users) {
613 ReportError(f, "Multiple users: directive in file.");
616 method->users = xstrdup(tok->name);
619 if (method->program) {
620 ReportError(f, "Multiple program: directives in auth/res decl.");
623 method->program = xstrdup(tok->name);
628 static void authdecl_parse(AUTHGROUP *curauth, CONFFILE *f, CONFTOKEN *tok)
633 char buff[SMBUF], *oldname, *p;
638 tok = CONFgettoken(PERMtoks, f);
641 ReportError(f, "Expected value.");
643 TEST_CONFIG(oldtype, bit);
645 snprintf(buff, sizeof(buff), "Duplicated '%s' field in authgroup.",
647 ReportError(f, buff);
650 if (strcasecmp(tok->name, "on") == 0
651 || strcasecmp(tok->name, "true") == 0
652 || strcasecmp(tok->name, "yes") == 0)
654 else if (strcasecmp(tok->name, "off") == 0
655 || strcasecmp(tok->name, "false") == 0
656 || strcasecmp(tok->name, "no") == 0)
663 curauth->key = xstrdup(tok->name);
667 case PERMrequire_ssl:
668 if (boolval != -1) curauth->require_ssl = boolval;
669 SET_CONFIG(PERMrequire_ssl);
673 curauth->hosts = xstrdup(tok->name);
674 CompressList(curauth->hosts);
675 SET_CONFIG(PERMhost);
677 /* nnrpd.c downcases the names of connecting hosts. We should
678 therefore also downcase the wildmat patterns to make sure there
679 aren't any surprises. DNS is case-insensitive. */
680 for (p = curauth->hosts; *p; p++)
681 if (CTYPE(isupper, (unsigned char) *p))
682 *p = tolower((unsigned char) *p);
686 curauth->default_domain = xstrdup(tok->name);
687 SET_CONFIG(PERMdefdomain);
690 curauth->default_user = xstrdup(tok->name);
691 SET_CONFIG(PERMdefuser);
695 m = xcalloc(1, sizeof(METHOD));
696 memset(ConfigBit, '\0', ConfigBitsize);
697 GrowArray((void***) &curauth->res_methods, (void*) m);
699 if (oldtype == PERMresprog)
700 m->program = xstrdup(tok->name);
702 m->name = xstrdup(tok->name);
703 tok = CONFgettoken(PERMtoks, f);
704 if (tok == NULL || tok->type != PERMlbrace) {
705 ReportError(f, "Expected '{' after 'res'");
708 tok = CONFgettoken(PERMtoks, f);
710 while (tok != NULL && tok->type != PERMrbrace) {
711 method_parse(m, f, tok, 0);
712 tok = CONFgettoken(PERMtoks, f);
716 ReportError(f, "Unexpected EOF.");
722 case PERMpython_auth:
724 m = xcalloc(1, sizeof(METHOD));
725 memset(ConfigBit, '\0', ConfigBitsize);
726 GrowArray((void***) &curauth->auth_methods, (void*) m);
727 if (oldtype == PERMauthprog) {
728 m->type = PERMauthprog;
729 m->program = xstrdup(tok->name);
730 } else if (oldtype == PERMperl_auth) {
732 m->type = PERMperl_auth;
733 m->program = xstrdup(tok->name);
735 ReportError(f, "perl_auth can not be used in readers.conf: inn not compiled with perl support enabled.");
737 } else if (oldtype == PERMpython_auth) {
739 m->type = PERMpython_auth;
740 m->program = xstrdup(tok->name);
742 ReportError(f, "python_auth can not be used in readers.conf: inn not compiled with python support enabled.");
745 m->name = xstrdup(tok->name);
746 tok = CONFgettoken(PERMtoks, f);
748 if (tok == NULL || tok->type != PERMlbrace) {
749 ReportError(f, "Expected '{' after 'auth'");
752 tok = CONFgettoken(PERMtoks, f);
754 while (tok != NULL && tok->type != PERMrbrace) {
755 method_parse(m, f, tok, 1);
756 tok = CONFgettoken(PERMtoks, f);
760 ReportError(f, "Unexpected EOF.");
764 case PERMperl_access:
766 curauth->access_script = xstrdup(tok->name);
767 curauth->access_type = PERMperl_access;
769 ReportError(f, "perl_access can not be used in readers.conf: inn not compiled with perl support enabled.");
772 case PERMpython_access:
774 curauth->access_script = xstrdup(tok->name);
775 curauth->access_type = PERMpython_access;
777 ReportError(f, "python_access can not be used in readers.conf: inn not compiled with python support enabled.");
780 case PERMpython_dynamic:
782 curauth->dynamic_script = xstrdup(tok->name);
783 curauth->dynamic_type = PERMpython_dynamic;
785 ReportError(f, "python_dynamic can not be used in readers.conf: inn not compiled with python support enabled.");
788 case PERMlocaladdress:
789 curauth->localaddress = xstrdup(tok->name);
790 CompressList(curauth->localaddress);
791 SET_CONFIG(PERMlocaladdress);
794 snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
795 ReportError(f, buff);
800 static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok)
802 int oldtype, boolval;
804 char buff[SMBUF], *oldname;
809 tok = CONFgettoken(0, f);
812 ReportError(f, "Expected value.");
814 TEST_CONFIG(oldtype, bit);
816 snprintf(buff, sizeof(buff), "Duplicated '%s' field in accessgroup.",
818 ReportError(f, buff);
820 if (strcasecmp(tok->name, "on") == 0
821 || strcasecmp(tok->name, "true") == 0
822 || strcasecmp(tok->name, "yes") == 0)
824 else if (strcasecmp(tok->name, "off") == 0
825 || strcasecmp(tok->name, "false") == 0
826 || strcasecmp(tok->name, "no") == 0)
833 curaccess->key = xstrdup(tok->name);
837 curaccess->users = xstrdup(tok->name);
838 CompressList(curaccess->users);
842 curaccess->rejectwith = xstrdup(tok->name);
846 TEST_CONFIG(PERMread, bit);
848 /* syntax error.. can't set read: or post: _and_ use
850 ReportError(f, "read: newsgroups already set.");
852 TEST_CONFIG(PERMpost, bit);
854 /* syntax error.. can't set read: or post: _and_ use
856 ReportError(f, "post: newsgroups already set.");
859 curaccess->read = xstrdup(tok->name);
860 CompressList(curaccess->read);
861 curaccess->post = xstrdup(tok->name);
862 CompressList(curaccess->post);
864 SET_CONFIG(PERMread);
865 SET_CONFIG(PERMpost);
868 curaccess->read = xstrdup(tok->name);
869 CompressList(curaccess->read);
873 curaccess->post = xstrdup(tok->name);
874 CompressList(curaccess->post);
878 TEST_CONFIG(PERMread, bit);
879 if (bit && strchr(tok->name, 'R') == NULL) {
880 free(curaccess->read);
882 CLEAR_CONFIG(PERMread);
884 TEST_CONFIG(PERMpost, bit);
885 if (bit && strchr(tok->name, 'P') == NULL) {
886 free(curaccess->post);
888 CLEAR_CONFIG(PERMpost);
890 curaccess->allowapproved = (strchr(tok->name, 'A') != NULL);
891 curaccess->allownewnews = (strchr(tok->name, 'N') != NULL);
892 curaccess->allowihave = (strchr(tok->name, 'I') != NULL);
893 curaccess->locpost = (strchr(tok->name, 'L') != NULL);
897 if (boolval != -1) curaccess->localtime = boolval;
901 if (boolval != -1) curaccess->strippath = boolval;
904 case PERMnnrpdperlfilter:
905 if (boolval != -1) curaccess->nnrpdperlfilter = boolval;
908 case PERMnnrpdpythonfilter:
909 if (boolval != -1) curaccess->nnrpdpythonfilter = boolval;
913 if (curaccess->fromhost)
914 free(curaccess->fromhost);
915 curaccess->fromhost = xstrdup(tok->name);
919 if (curaccess->pathhost)
920 free(curaccess->pathhost);
921 curaccess->pathhost = xstrdup(tok->name);
924 case PERMorganization:
925 if (curaccess->organization)
926 free(curaccess->organization);
927 curaccess->organization = xstrdup(tok->name);
930 case PERMmoderatormailer:
931 if (curaccess->moderatormailer)
932 free(curaccess->moderatormailer);
933 curaccess->moderatormailer = xstrdup(tok->name);
937 if (curaccess->domain)
938 free(curaccess->domain);
939 curaccess->domain = xstrdup(tok->name);
943 if (curaccess->complaints)
944 free(curaccess->complaints);
945 curaccess->complaints = xstrdup(tok->name);
949 if (boolval != -1) curaccess->spoolfirst = boolval;
952 case PERMcheckincludedtext:
953 if (boolval != -1) curaccess->checkincludedtext = boolval;
956 case PERMclienttimeout:
957 curaccess->clienttimeout = atoi(tok->name);
960 case PERMlocalmaxartsize:
961 curaccess->localmaxartsize = atol(tok->name);
964 case PERMreadertrack:
965 if (boolval != -1) curaccess->readertrack = boolval;
968 case PERMstrippostcc:
969 if (boolval != -1) curaccess->strippostcc = boolval;
972 case PERMaddnntppostinghost:
973 if (boolval != -1) curaccess->addnntppostinghost = boolval;
976 case PERMaddnntppostingdate:
977 if (boolval != -1) curaccess->addnntppostingdate = boolval;
980 case PERMnnrpdposthost:
981 if (curaccess->nnrpdposthost)
982 free(curaccess->nnrpdposthost);
983 curaccess->nnrpdposthost = xstrdup(tok->name);
986 case PERMnnrpdpostport:
987 curaccess->nnrpdpostport = atoi(tok->name);
990 case PERMnnrpdoverstats:
991 if (boolval != -1) curaccess->nnrpdoverstats = boolval;
994 case PERMbackoff_auth:
995 if (boolval != -1) curaccess->backoff_auth = boolval;
999 if (curaccess->backoff_db)
1000 free(curaccess->backoff_db);
1001 curaccess->backoff_db = xstrdup(tok->name);
1002 SET_CONFIG(oldtype);
1005 curaccess->backoff_k = atol(tok->name);
1006 SET_CONFIG(oldtype);
1008 case PERMbackoff_postfast:
1009 curaccess->backoff_postfast = atol(tok->name);
1010 SET_CONFIG(oldtype);
1012 case PERMbackoff_postslow:
1013 curaccess->backoff_postslow = atol(tok->name);
1014 SET_CONFIG(oldtype);
1016 case PERMbackoff_trigger:
1017 curaccess->backoff_trigger = atol(tok->name);
1018 SET_CONFIG(oldtype);
1020 case PERMnnrpdcheckart:
1021 if (boolval != -1) curaccess->nnrpdcheckart = boolval;
1022 SET_CONFIG(oldtype);
1024 case PERMnnrpdauthsender:
1025 if (boolval != -1) curaccess->nnrpdauthsender = boolval;
1026 SET_CONFIG(oldtype);
1028 case PERMvirtualhost:
1029 if (boolval != -1) curaccess->virtualhost = boolval;
1030 SET_CONFIG(oldtype);
1032 case PERMnewsmaster:
1033 if (curaccess->newsmaster)
1034 free(curaccess->newsmaster);
1035 curaccess->newsmaster = xstrdup(tok->name);
1036 SET_CONFIG(oldtype);
1038 case PERMmaxbytespersecond:
1039 curaccess->maxbytespersecond = atol(tok->name);
1040 SET_CONFIG(oldtype);
1043 snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
1044 ReportError(f, buff);
1049 static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *access_vec) {
1050 CONFTOKEN *tok = NULL;
1055 file = xcalloc(1, sizeof(CONFFILE));
1056 file->array = access_vec->strings;
1057 file->array_len = access_vec->count;
1059 memset(ConfigBit, '\0', ConfigBitsize);
1061 SetDefaultAccess(acc);
1062 str = xstrdup(name);
1065 for (i = 0; i <= access_vec->count; i++) {
1066 tok = CONFgettoken(PERMtoks, file);
1069 accessdecl_parse(acc, file, tok);
1076 static void PERMreadfile(char *filename)
1078 CONFCHAIN *cf = NULL,
1080 CONFTOKEN *tok = NULL;
1082 GROUP *curgroup = NULL,
1084 ACCESSGROUP *curaccess = NULL;
1085 AUTHGROUP *curauth = NULL;
1091 if(filename != NULL) {
1092 syslog(L_TRACE, "Reading access from %s",
1093 filename == NULL ? "(NULL)" : filename);
1096 cf = xmalloc(sizeof(CONFCHAIN));
1097 if ((cf->f = CONFfopen(filename)) == NULL) {
1098 syslog(L_ERROR, "%s cannot open %s: %m", ClientHost, filename);
1099 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
1100 ExitWithStats(1, true);
1104 /* are we editing an AUTH or ACCESS group? */
1107 newgroup = curgroup = 0;
1109 tok = CONFgettoken(PERMtoks, cf->f);
1111 while (tok != NULL) {
1113 /* top-level parser */
1115 switch (tok->type) {
1116 /* include a child file */
1119 tok = CONFgettoken(0, cf->f);
1122 ReportError(cf->f, "Expected filename after 'include'.");
1125 hold = xmalloc(sizeof(CONFCHAIN));
1128 /* unless the filename's path is fully qualified, open it
1129 * relative to /news/etc */
1131 path = concatpath(innconf->pathetc, tok->name);
1132 hold->f = CONFfopen(path);
1135 if (hold->f == NULL) {
1136 ReportError(cf->f, "Couldn't open 'include' filename.");
1143 /* nested group declaration. */
1145 tok = CONFgettoken(PERMtoks, cf->f);
1148 ReportError(cf->f, "Unexpected EOF at group name");
1151 newgroup = xmalloc(sizeof(GROUP));
1152 newgroup->above = curgroup;
1153 newgroup->name = xstrdup(tok->name);
1154 memset(ConfigBit, '\0', ConfigBitsize);
1156 tok = CONFgettoken(PERMtoks, cf->f);
1158 if (tok == NULL || tok->type != PERMlbrace) {
1159 ReportError(cf->f, "Expected '{' after group name");
1162 /* nested group declaration */
1164 newgroup->auth = copy_authgroup(curgroup->auth);
1165 newgroup->access = copy_accessgroup(curgroup->access);
1168 newgroup->access = 0;
1171 curgroup = newgroup;
1174 /* beginning of an auth or access group decl */
1177 oldtype = tok->type;
1179 if ((tok = CONFgettoken(PERMtoks, cf->f)) == NULL) {
1180 ReportError(cf->f, "Expected identifier.");
1183 str = xstrdup(tok->name);
1185 tok = CONFgettoken(PERMtoks, cf->f);
1187 if (tok == NULL || tok->type != PERMlbrace) {
1188 ReportError(cf->f, "Expected '{'");
1193 if (curgroup && curgroup->auth)
1194 curauth = copy_authgroup(curgroup->auth);
1196 curauth = xcalloc(1, sizeof(AUTHGROUP));
1197 memset(ConfigBit, '\0', ConfigBitsize);
1198 SetDefaultAuth(curauth);
1201 curauth->name = str;
1206 if (curgroup && curgroup->access)
1207 curaccess = copy_accessgroup(curgroup->access);
1209 curaccess = xcalloc(1, sizeof(ACCESSGROUP));
1210 memset(ConfigBit, '\0', ConfigBitsize);
1211 SetDefaultAccess(curaccess);
1213 curaccess->name = str;
1220 /* end of a group declaration */
1223 if (curgroup == NULL) {
1224 ReportError(cf->f, "Unmatched '}'");
1227 newgroup = curgroup;
1228 curgroup = curgroup->above;
1230 free_authgroup(newgroup->auth);
1231 if (newgroup->access)
1232 free_accessgroup(newgroup->access);
1233 free(newgroup->name);
1237 /* stuff that belongs in an authgroup */
1240 case PERMrequire_ssl:
1246 if (curgroup == NULL) {
1247 curgroup = xcalloc(1, sizeof(GROUP));
1248 memset(ConfigBit, '\0', ConfigBitsize);
1250 if (curgroup->auth == NULL) {
1251 curgroup->auth = xcalloc(1, sizeof(AUTHGROUP));
1252 memset(ConfigBit, '\0', ConfigBitsize);
1253 SetDefaultAuth(curgroup->auth);
1256 authdecl_parse(curgroup->auth, cf->f, tok);
1259 /* stuff that belongs in an accessgroup */
1261 case PERMrejectwith:
1262 case PERMnewsgroups:
1268 case PERMnnrpdperlfilter:
1269 case PERMnnrpdpythonfilter:
1272 case PERMorganization:
1273 case PERMmoderatormailer:
1275 case PERMcomplaints:
1276 case PERMspoolfirst:
1277 case PERMcheckincludedtext:
1278 case PERMclienttimeout:
1279 case PERMlocalmaxartsize:
1280 case PERMreadertrack:
1281 case PERMstrippostcc:
1282 case PERMaddnntppostinghost:
1283 case PERMaddnntppostingdate:
1284 case PERMnnrpdposthost:
1285 case PERMnnrpdpostport:
1286 case PERMnnrpdoverstats:
1287 case PERMbackoff_auth:
1288 case PERMbackoff_db:
1290 case PERMbackoff_postfast:
1291 case PERMbackoff_postslow:
1292 case PERMbackoff_trigger:
1293 case PERMnnrpdcheckart:
1294 case PERMnnrpdauthsender:
1295 case PERMvirtualhost:
1296 case PERMnewsmaster:
1298 curgroup = xcalloc(1, sizeof(GROUP));
1299 memset(ConfigBit, '\0', ConfigBitsize);
1301 if (!curgroup->access) {
1302 curgroup->access = xcalloc(1, sizeof(ACCESSGROUP));
1303 memset(ConfigBit, '\0', ConfigBitsize);
1304 SetDefaultAccess(curgroup->access);
1306 accessdecl_parse(curgroup->access, cf->f, tok);
1309 snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
1310 ReportError(cf->f, buff);
1313 } else if (inwhat == 1) {
1314 /* authgroup parser */
1315 if (tok->type == PERMrbrace) {
1320 && ((curauth->require_ssl == false) || (ClientSSL == true))
1322 && MatchHost(curauth->hosts, ClientHost, ClientIpString)) {
1323 if (!MatchHost(curauth->localaddress, ServerHost, ServerIpString)) {
1324 syslog(L_TRACE, "Auth strategy '%s' does not match localhost. Removing.",
1325 curauth->name == NULL ? "(NULL)" : curauth->name);
1326 free_authgroup(curauth);
1328 add_authgroup(curauth);
1330 syslog(L_TRACE, "Auth strategy '%s' does not match client. Removing.",
1331 curauth->name == NULL ? "(NULL)" : curauth->name);
1332 free_authgroup(curauth);
1338 authdecl_parse(curauth, cf->f, tok);
1339 } else if (inwhat == 2) {
1340 /* accessgroup parser */
1341 if (tok->type == PERMrbrace) {
1344 if (curaccess->name)
1345 add_accessgroup(curaccess);
1347 free_accessgroup(curaccess);
1352 accessdecl_parse(curaccess, cf->f, tok);
1354 /* should never happen */
1355 syslog(L_TRACE, "SHOULD NEVER HAPPEN!");
1358 /* go back up the 'include' chain. */
1359 tok = CONFgettoken(PERMtoks, cf->f);
1361 while (tok == NULL && cf) {
1364 CONFfclose(hold->f);
1367 tok = CONFgettoken(PERMtoks, cf->f);
1375 void PERMgetaccess(char *nnrpaccess)
1379 int canauthenticate;
1382 access_realms = NULL;
1383 success_auth = NULL;
1385 PERMcanread = PERMcanpost = false;
1386 PERMreadlist = PERMpostlist = false;
1387 PERMaccessconf = NULL;
1389 if (ConfigBit == NULL) {
1390 if (PERMMAX % 8 == 0)
1391 ConfigBitsize = PERMMAX/8;
1393 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1394 ConfigBit = xcalloc(ConfigBitsize, 1);
1396 PERMreadfile(nnrpaccess);
1398 strip_accessgroups();
1400 if (auth_realms == NULL) {
1401 /* no one can talk, empty file */
1402 syslog(L_NOTICE, "%s no_permission", ClientHost);
1403 Printf("%d You have no permission to talk. Goodbye.\r\n",
1405 ExitWithStats(1, true);
1408 /* auth_realms are all expected to match the user. */
1409 canauthenticate = 0;
1410 for (i = 0; auth_realms[i]; i++)
1411 if (auth_realms[i]->auth_methods)
1412 canauthenticate = 1;
1414 while (!uname && i--) {
1415 if ((uname = ResolveUser(auth_realms[i])) != NULL)
1416 PERMauthorized = true;
1417 if (!uname && auth_realms[i]->default_user)
1418 uname = auth_realms[i]->default_user;
1421 strlcpy(PERMuser, uname, sizeof(PERMuser));
1422 uname = strchr(PERMuser, '@');
1423 if (!uname && auth_realms[i]->default_domain) {
1424 /* append the default domain to the username */
1425 strlcat(PERMuser, "@", sizeof(PERMuser));
1426 strlcat(PERMuser, auth_realms[i]->default_domain,
1429 PERMneedauth = false;
1430 success_auth = auth_realms[i];
1431 syslog(L_TRACE, "%s res %s", ClientHost, PERMuser);
1432 } else if (!canauthenticate) {
1433 /* couldn't resolve the user. */
1434 syslog(L_NOTICE, "%s no_user", ClientHost);
1435 Printf("%d Could not get your access name. Goodbye.\r\n",
1437 ExitWithStats(1, true);
1439 PERMneedauth = true;
1441 /* check maximum allowed permissions for any host that matches (for
1442 * the greeting string) */
1443 for (i = 0; access_realms[i]; i++) {
1445 PERMcanread = (access_realms[i]->read != NULL);
1447 PERMcanpost = (access_realms[i]->post != NULL);
1450 /* no applicable access groups. Zeroing all these makes INN
1451 * return permission denied to client. */
1452 PERMcanread = PERMcanpost = PERMneedauth = false;
1456 void PERMlogin(char *uname, char *pass, char *errorstr)
1461 if (ConfigBit == NULL) {
1462 if (PERMMAX % 8 == 0)
1463 ConfigBitsize = PERMMAX/8;
1465 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1466 ConfigBit = xcalloc(ConfigBitsize, 1);
1468 /* The check in CMDauthinfo uses the value of PERMneedauth to know if
1469 * authentication succeeded or not. By default, authentication doesn't
1471 PERMneedauth = true;
1473 if(auth_realms != NULL) {
1474 for (i = 0; auth_realms[i]; i++) {
1481 while (runame == NULL && i--)
1482 runame = AuthenticateUser(auth_realms[i], uname, pass, errorstr);
1484 strlcpy(PERMuser, runame, sizeof(PERMuser));
1485 uname = strchr(PERMuser, '@');
1486 if (!uname && auth_realms[i]->default_domain) {
1487 /* append the default domain to the username */
1488 strlcat(PERMuser, "@", sizeof(PERMuser));
1489 strlcat(PERMuser, auth_realms[i]->default_domain,
1492 PERMneedauth = false;
1493 PERMauthorized = true;
1494 success_auth = auth_realms[i];
1498 static int MatchUser(char *pat, char *user)
1506 if (!user || !*user)
1510 NGgetlist(&list, cp);
1513 ret = PERMmatch(list, userlist);
1520 void PERMgetpermissions()
1525 static ACCESSGROUP *noaccessconf;
1527 char *cpp, *script_path;
1529 struct vector *access_vec;
1531 if (ConfigBit == NULL) {
1532 if (PERMMAX % 8 == 0)
1533 ConfigBitsize = PERMMAX/8;
1535 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1536 ConfigBit = xcalloc(ConfigBitsize, 1);
1538 if (!success_auth) {
1539 /* if we haven't successfully authenticated, we can't do anything. */
1540 syslog(L_TRACE, "%s no_success_auth", ClientHost);
1542 noaccessconf = xmalloc(sizeof(ACCESSGROUP));
1543 PERMaccessconf = noaccessconf;
1544 SetDefaultAccess(PERMaccessconf);
1547 } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMperl_access)) {
1549 cpp = xstrdup(success_auth->access_script);
1552 script_path = concat(args[0], (char *) 0);
1553 if ((script_path != NULL) && (strlen(script_path) > 0)) {
1557 PERLsetup(NULL, script_path, "access");
1560 uname = xstrdup(PERMuser);
1562 access_vec = vector_new();
1564 perlAccess(uname, access_vec);
1567 access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
1569 PERMvectortoaccess(access_realms[0], "perl-dynamic", access_vec);
1571 vector_free(access_vec);
1573 syslog(L_ERROR, "No script specified in perl_access method.\n");
1574 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
1575 ExitWithStats(1, true);
1579 #endif /* DO_PERL */
1581 } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMpython_access)) {
1583 cpp = xstrdup(success_auth->access_script);
1586 script_path = concat(args[0], (char *) 0);
1587 if ((script_path != NULL) && (strlen(script_path) > 0)) {
1588 uname = xstrdup(PERMuser);
1589 access_vec = vector_new();
1591 PY_access(script_path, access_vec, uname);
1596 access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
1597 memset(access_realms[0], 0, sizeof(ACCESSGROUP));
1599 PERMvectortoaccess(access_realms[0], "python-dynamic", access_vec);
1601 vector_free(access_vec);
1603 syslog(L_ERROR, "No script specified in python_access method.\n");
1604 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
1605 ExitWithStats(1, true);
1608 #endif /* DO_PYTHON */
1610 for (i = 0; access_realms[i]; i++)
1615 if ((!success_auth->key && !access_realms[i]->key) ||
1616 (access_realms[i]->key && success_auth->key &&
1617 strcmp(access_realms[i]->key, success_auth->key) == 0)) {
1618 if (!access_realms[i]->users)
1620 else if (!*PERMuser)
1622 cp = xstrdup(access_realms[i]->users);
1624 NGgetlist(&list, cp);
1625 if (PERMmatch(list, user)) {
1626 syslog(L_TRACE, "%s match_user %s %s", ClientHost,
1627 PERMuser, access_realms[i]->users);
1633 syslog(L_TRACE, "%s no_match_user %s %s", ClientHost,
1634 PERMuser, access_realms[i]->users);
1642 /* found the right access group */
1643 if (access_realms[i]->rejectwith) {
1644 syslog(L_ERROR, "%s rejected by rule (%s)",
1645 ClientHost, access_realms[i]->rejectwith);
1646 Reply("%d Permission denied: %s\r\n",
1647 NNTP_ACCESS_VAL, access_realms[i]->rejectwith);
1648 ExitWithStats(1, true);
1650 if (access_realms[i]->read) {
1651 cp = xstrdup(access_realms[i]->read);
1652 PERMspecified = NGgetlist(&PERMreadlist, cp);
1656 syslog(L_TRACE, "%s no_read %s", ClientHost, access_realms[i]->name);
1657 PERMcanread = false;
1659 if (access_realms[i]->post) {
1660 cp = xstrdup(access_realms[i]->post);
1661 NGgetlist(&PERMpostlist, cp);
1665 syslog(L_TRACE, "%s no_post %s", ClientHost, access_realms[i]->name);
1666 PERMcanpost = false;
1668 PERMaccessconf = access_realms[i];
1669 MaxBytesPerSecond = PERMaccessconf->maxbytespersecond;
1670 if (PERMaccessconf->virtualhost) {
1671 if (PERMaccessconf->domain == NULL) {
1672 syslog(L_ERROR, "%s virtualhost needs domain parameter(%s)",
1673 ClientHost, PERMaccessconf->name);
1674 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
1675 ExitWithStats(1, true);
1679 if (strcmp(innconf->pathhost, PERMaccessconf->pathhost) == 0) {
1680 /* use domain, if pathhost in access relm matches one in
1681 inn.conf to differentiate virtual host */
1682 if (innconf->domain != NULL && strcmp(innconf->domain, PERMaccessconf->domain) == 0) {
1683 syslog(L_ERROR, "%s domain parameter(%s) in readers.conf must be different from the one in inn.conf",
1684 ClientHost, PERMaccessconf->name);
1685 Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
1686 ExitWithStats(1, true);
1688 VirtualPath = concat(PERMaccessconf->domain, "!", (char *) 0);
1690 VirtualPath = concat(PERMaccessconf->pathhost, "!",
1693 VirtualPathlen = strlen(VirtualPath);
1698 noaccessconf = xmalloc(sizeof(ACCESSGROUP));
1699 PERMaccessconf = noaccessconf;
1700 SetDefaultAccess(PERMaccessconf);
1701 syslog(L_TRACE, "%s no_access_realm", ClientHost);
1703 /* check if dynamic access control is enabled, if so init it */
1705 if ((success_auth->dynamic_type == PERMpython_dynamic) && success_auth->dynamic_script) {
1706 PY_dynamic_init(success_auth->dynamic_script);
1708 #endif /* DO_PYTHON */
1711 /* strip blanks out of a string */
1712 static void CompressList(char *list)
1715 bool inword = false;
1717 for (cpto = list; *list; ) {
1718 if (strchr("\n \t,", *list) != NULL) {
1732 static bool MatchHost(char *hostlist, char *host, char *ip)
1741 /* If no hostlist are specified, by default they match. */
1743 if (hostlist == NULL) {
1748 cp = xstrdup(hostlist);
1750 NGgetlist(&list, cp);
1752 /* default is no access */
1753 for (iter = 0; list[iter]; iter++) {
1757 while (iter-- > 0) {
1761 ret = uwildmat(host, pat);
1763 ret = uwildmat(ip, pat);
1764 if (!ret && (p = strchr(pat, '/')) != (char *)NULL) {
1765 unsigned int bits, c;
1766 struct in_addr ia, net, tmp;
1768 struct in6_addr ia6, net6;
1769 unsigned char bits8;
1774 if (inet_aton(ip, &ia) && inet_aton(pat, &net)) {
1775 if (strchr(p+1, '.') == (char *)NULL) {
1776 /* string following / is a masklength */
1778 for (bits = c = 0; c < mask && c < 32; c++)
1779 bits |= (1 << (31 - c));
1781 } else { /* or it may be a dotted quad bitmask */
1782 if (inet_aton(p+1, &tmp))
1784 else /* otherwise skip it */
1787 if ((ia.s_addr & mask) == (net.s_addr & mask))
1791 else if (inet_pton(AF_INET6, ip, &ia6) &&
1792 inet_pton(AF_INET6, pat, &net6)) {
1795 /* do a prefix match byte by byte */
1796 for (c = 0; c*8 < mask && c < sizeof(ia6); c++) {
1797 if ( (c+1)*8 <= mask &&
1798 ia6.s6_addr[c] != net6.s6_addr[c] ) {
1801 } else if ( (c+1)*8 > mask ) {
1804 for (bits8 = b = 0; b < (mask % 8); b++)
1805 bits8 |= (1 << (7 - b));
1806 if ((ia6.s6_addr[c] & bits8) !=
1807 (net6.s6_addr[c] & bits8) ) {
1820 if (ret && list[iter][0] == '!')
1828 static void add_authgroup(AUTHGROUP *group)
1832 if (auth_realms == NULL) {
1834 auth_realms = xmalloc(2 * sizeof(AUTHGROUP *));
1836 for (i = 0; auth_realms[i]; i++)
1838 auth_realms = xrealloc(auth_realms, (i + 2) * sizeof(AUTHGROUP *));
1840 auth_realms[i] = group;
1841 auth_realms[i+1] = 0;
1844 static void add_accessgroup(ACCESSGROUP *group)
1848 if (access_realms == NULL) {
1850 access_realms = xmalloc(2 * sizeof(ACCESSGROUP *));
1852 for (i = 0; access_realms[i]; i++)
1854 access_realms = xrealloc(access_realms, (i + 2) * sizeof(ACCESSGROUP *));
1856 access_realms[i] = group;
1857 access_realms[i+1] = 0;
1860 /* clean out access groups that don't apply to any of our auth groups. */
1862 static void strip_accessgroups(void)
1866 /* flag the access group as used or not */
1868 if(access_realms != NULL) {
1869 for (j = 0; access_realms[j] != NULL; j++) {
1870 access_realms[j]->used = 0;
1873 syslog(L_TRACE, "No access realms to check!");
1876 /* If there are auth realms to check... */
1878 if(auth_realms != NULL) {
1879 /* ... Then for each auth realm... */
1881 for (i = 0; auth_realms[i] != NULL; i++) {
1883 /* ... for each access realm... */
1885 for (j = 0; access_realms[j] != NULL; j++) {
1887 /* If the access realm isn't already in use... */
1889 if (! access_realms[j]->used) {
1890 /* Check to see if both the access_realm key and
1891 auth_realm key are NULL... */
1893 if (!access_realms[j]->key && !auth_realms[i]->key) {
1894 /* If so, mark the realm in use and continue on... */
1896 access_realms[j]->used = 1;
1898 /* If not, check to see if both the access_realm and
1899 auth_realm are NOT _both_ NULL, and see if they are
1902 if (access_realms[j]->key && auth_realms[i]->key &&
1903 strcmp(access_realms[j]->key, auth_realms[i]->key) == 0) {
1905 /* And if so, mark the realm in use. */
1907 access_realms[j]->used = 1;
1914 syslog(L_TRACE, "No auth realms to check!");
1917 /* strip out unused access groups */
1920 while (access_realms[i] != NULL) {
1921 if (access_realms[i]->used)
1922 access_realms[j++] = access_realms[i];
1924 syslog(L_TRACE, "%s removing irrelevant access group %s",
1925 ClientHost, access_realms[i]->name);
1928 access_realms[j] = 0;
1931 typedef struct _EXECSTUFF {
1933 int rdfd, errfd, wrfd;
1936 static EXECSTUFF *ExecProg(char *arg0, char **args)
1939 int rdfd[2], errfd[2], wrfd[2];
1943 #if !defined(S_IXUSR) && defined(_S_IXUSR)
1944 #define S_IXUSR _S_IXUSR
1945 #endif /* !defined(S_IXUSR) && defined(_S_IXUSR) */
1947 #if !defined(S_IXUSR) && defined(S_IEXEC)
1948 #define S_IXUSR S_IEXEC
1949 #endif /* !defined(S_IXUSR) && defined(S_IEXEC) */
1951 if (stat(arg0, &stb) || !(stb.st_mode&S_IXUSR))
1957 switch (pid = fork()) {
1974 /* if we got here, there was an error */
1975 syslog(L_ERROR, "%s perm could not exec %s: %m", ClientHost, arg0);
1981 ret = xmalloc(sizeof(EXECSTUFF));
1983 ret->rdfd = rdfd[0];
1984 ret->errfd = errfd[0];
1985 ret->wrfd = wrfd[1];
1989 static void GetConnInfo(METHOD *method, char *buf)
1995 sprintf(buf, "ClientHost: %s\r\n", ClientHost);
1996 if (*ClientIpString)
1997 sprintf(buf+strlen(buf), "ClientIP: %s\r\n", ClientIpString);
1999 sprintf(buf+strlen(buf), "ClientPort: %d\r\n", ClientPort);
2000 if (*ServerIpString)
2001 sprintf(buf+strlen(buf), "LocalIP: %s\r\n", ServerIpString);
2003 sprintf(buf+strlen(buf), "LocalPort: %d\r\n", ServerPort);
2004 /* handle this here, since we only get here when we're about to exec
2006 if (method->extra_headers) {
2007 for (i = 0; method->extra_headers[i]; i++)
2008 sprintf(buf+strlen(buf), "%s\r\n", method->extra_headers[i]);
2012 static char ubuf[SMBUF];
2014 typedef void (*LineFunc)(char*);
2016 /* messages from a program's stdout */
2017 static void HandleProgLine(char *ln)
2019 if (strncasecmp(ln, "User:", strlen("User:")) == 0)
2020 strlcpy(ubuf, ln + strlen("User:"), sizeof(ubuf));
2023 /* messages from a programs stderr */
2024 static void HandleErrorLine(char *ln)
2026 syslog(L_NOTICE, "%s auth_err %s", ClientHost, ln);
2030 HandleProgInput(int fd, char *buf, int buflen, LineFunc f)
2037 curpos = strlen(buf);
2038 if (curpos >= buflen-1) {
2039 /* data overflow (on one line!) */
2042 got = read(fd, buf+curpos, buflen-curpos-1);
2045 buf[curpos+got] = '\0';
2047 /* break what we got up into lines */
2049 while ((nl = strchr(nl, '\n')) != NULL) {
2050 if (nl != buf && *(nl-1) == '\r')
2057 /* delete all the lines we've read from the buffer. */
2058 /* 'start' points to the end of the last unterminated string */
2074 static void GetProgInput(EXECSTUFF *prog)
2080 struct timeval tmout;
2083 char rdbuf[BIG_BUFFER], errbuf[BIG_BUFFER];
2087 FD_SET(prog->rdfd, &rfds);
2088 FD_SET(prog->errfd, &rfds);
2090 maxfd = prog->rdfd > prog->errfd ? prog->rdfd : prog->errfd;
2093 rdbuf[0] = errbuf[0] = '\0';
2094 start = TMRnow_double();
2095 while ((got = select(maxfd+1, &tfds, 0, 0, &tmout)) >= 0) {
2096 end = TMRnow_double();
2097 IDLEtime += end - start;
2102 if (FD_ISSET(prog->rdfd, &tfds)) {
2103 okay = HandleProgInput(prog->rdfd, rdbuf, sizeof(rdbuf), HandleProgLine);
2106 FD_CLR(prog->rdfd, &tfds);
2107 kill(prog->pid, SIGTERM);
2110 if (FD_ISSET(prog->errfd, &tfds)) {
2111 okay = HandleProgInput(prog->errfd, errbuf, sizeof(errbuf), HandleErrorLine);
2114 FD_CLR(prog->errfd, &tfds);
2115 kill(prog->pid, SIGTERM);
2121 end = TMRnow_double();
2122 IDLEtime += end - start;
2123 /* wait for it if he's toast. */
2125 tmp = waitpid(prog->pid, &status, 0);
2126 } while ((tmp >= 0 || (tmp < 0 && errno == EINTR)) &&
2127 !WIFEXITED(status) && !WIFSIGNALED(status));
2128 if (WIFSIGNALED(status)) {
2130 syslog(L_NOTICE, "%s bad_hook program caught signal %d", ClientHost,
2132 } else if (WIFEXITED(status)) {
2133 if (WEXITSTATUS(status) != 0) {
2135 syslog(L_TRACE, "%s bad_hook program exited with status %d",
2136 ClientHost, WEXITSTATUS(status));
2139 syslog(L_ERROR, "%s bad_hook waitpid failed: %m", ClientHost);
2144 /* execute a series of resolvers to get the remote username */
2145 static char *ResolveUser(AUTHGROUP *auth)
2155 char buf[BIG_BUFFER];
2157 if (!auth->res_methods)
2160 tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR);
2161 resdir = concatpath(tmp, _PATH_AUTHDIR_NOPASS);
2165 for (i = 0; auth->res_methods[i]; i++) {
2166 /* build the command line */
2167 syslog(L_TRACE, "%s res starting resolver %s", ClientHost, auth->res_methods[i]->program);
2168 if (auth->res_methods[i]->extra_logs) {
2169 for (j = 0; auth->res_methods[i]->extra_logs[j]; j++)
2170 syslog(L_NOTICE, "%s res also-log: %s", ClientHost,
2171 auth->res_methods[i]->extra_logs[j]);
2173 cp = xstrdup(auth->res_methods[i]->program);
2177 if (args[0][0] != '/')
2178 arg0 = concat(resdir, "/", arg0, (char *) 0);
2179 /* exec the resolver */
2180 foo = ExecProg(arg0, args);
2182 GetConnInfo(auth->res_methods[i], buf);
2183 strlcat(buf, ".\r\n", sizeof(buf));
2184 xwrite(foo->wrfd, buf, strlen(buf));
2188 done = (ubuf[0] != '\0');
2190 syslog(L_TRACE, "%s res resolver successful, user %s", ClientHost, ubuf);
2192 syslog(L_TRACE, "%s res resolver failed", ClientHost);
2195 syslog(L_ERROR, "%s res couldnt start resolver: %m", ClientHost);
2197 if (args[0][0] != '/') {
2203 /* this resolver succeeded */
2212 /* execute a series of authenticators to get the remote username */
2213 static char *AuthenticateUser(AUTHGROUP *auth, char *username, char *password, char *errorstr)
2222 char newUser[BIG_BUFFER];
2226 char buf[BIG_BUFFER];
2228 if (!auth->auth_methods)
2231 tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR);
2232 resdir = concatpath(tmp, _PATH_AUTHDIR_PASSWD);
2237 for (i = 0; auth->auth_methods[i]; i++) {
2238 if (auth->auth_methods[i]->type == PERMperl_auth) {
2240 cp = xstrdup(auth->auth_methods[i]->program);
2243 script_path = concat(args[0], (char *) 0);
2244 if ((script_path != NULL) && (strlen(script_path) > 0)) {
2248 PERLsetup(NULL, script_path, "authenticate");
2252 code = perlAuthenticate(username, password, errorstr, newUser);
2253 if (code == NNTP_AUTH_OK_VAL) {
2254 /* Set the value of ubuf to the right username */
2255 if (newUser[0] != '\0') {
2256 strlcpy(ubuf, newUser, sizeof(ubuf));
2258 strlcpy(ubuf, username, sizeof(ubuf));
2261 syslog(L_NOTICE, "%s user %s", ClientHost, ubuf);
2263 fprintf(locallog, "%s user %s\n", ClientHost, ubuf);
2268 syslog(L_NOTICE, "%s bad_auth", ClientHost);
2271 syslog(L_ERROR, "No script specified in auth method.\n");
2273 #endif /* DO_PERL */
2274 } else if (auth->auth_methods[i]->type == PERMpython_auth) {
2276 cp = xstrdup(auth->auth_methods[i]->program);
2279 script_path = concat(args[0], (char *) 0);
2280 if ((script_path != NULL) && (strlen(script_path) > 0)) {
2281 code = PY_authenticate(script_path, username, password, errorstr, newUser);
2284 syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
2286 if (code == NNTP_AUTH_OK_VAL) {
2287 /* Set the value of ubuf to the right username */
2288 if (newUser[0] != '\0') {
2289 strlcpy(ubuf, newUser, sizeof(ubuf));
2291 strlcpy(ubuf, username, sizeof(ubuf));
2294 syslog(L_NOTICE, "%s user %s", ClientHost, ubuf);
2296 fprintf(locallog, "%s user %s\n", ClientHost, ubuf);
2301 syslog(L_NOTICE, "%s bad_auth", ClientHost);
2305 syslog(L_ERROR, "No script specified in auth method.\n");
2307 #endif /* DO_PYTHON */
2309 if (auth->auth_methods[i]->users &&
2310 !MatchUser(auth->auth_methods[i]->users, username))
2313 /* build the command line */
2314 syslog(L_TRACE, "%s auth starting authenticator %s", ClientHost, auth->auth_methods[i]->program);
2315 if (auth->auth_methods[i]->extra_logs) {
2316 for (j = 0; auth->auth_methods[i]->extra_logs[j]; j++)
2317 syslog(L_NOTICE, "%s auth also-log: %s", ClientHost,
2318 auth->auth_methods[i]->extra_logs[j]);
2320 cp = xstrdup(auth->auth_methods[i]->program);
2324 if (args[0][0] != '/')
2325 arg0 = concat(resdir, "/", arg0, (char *) 0);
2326 /* exec the authenticator */
2327 foo = ExecProg(arg0, args);
2329 GetConnInfo(auth->auth_methods[i], buf);
2330 snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3,
2331 "ClientAuthname: %s\r\n", username);
2332 snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3,
2333 "ClientPassword: %s\r\n", password);
2334 strlcat(buf, ".\r\n", sizeof(buf));
2335 xwrite(foo->wrfd, buf, strlen(buf));
2339 done = (ubuf[0] != '\0');
2341 syslog(L_TRACE, "%s auth authenticator successful, user %s", ClientHost, ubuf);
2343 syslog(L_TRACE, "%s auth authenticator failed", ClientHost);
2346 syslog(L_ERROR, "%s auth couldnt start authenticator: %m", ClientHost);
2348 if (args[0][0] != '/') {
2354 /* this authenticator succeeded */