1 /* $Id: perm.c 10117 2016-11-06 14:23:27Z iulius $
2 **
3 ** How to figure out where a user comes from, and what that user can do once
4 ** we know who sie is.
5 */
6
7 #include "config.h"
8 #include "clibrary.h"
9 #include <netdb.h>
10 #include <signal.h>
11 #include <sys/wait.h>
12
13 #include "conffile.h"
14 #include "inn/network.h"
15 #include "inn/innconf.h"
16 #include "innperl.h"
17 #include "nnrpd.h"
18 #include "tls.h"
19
20 /* Needed on AIX 4.1 to get fd_set and friends. */
21 #ifdef HAVE_SYS_SELECT_H
22 # include <sys/select.h>
23 #endif
24
25 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
26 extern bool encryption_layer_on;
27 #endif /* HAVE_OPENSSL || HAVE_SASL */
28
29 /* Data types. */
30 typedef struct _CONFCHAIN {
31 CONFFILE *f;
32 struct _CONFCHAIN *parent;
33 } CONFCHAIN;
34
35 typedef struct _METHOD {
36 char *name;
37 char *program;
38 int type; /* Type of auth (perl, python or external)/ */
39 char *users; /* Only used for auth_methods, not for res_methods. */
40 char **extra_logs;
41 } METHOD;
42
43 typedef struct _AUTHGROUP {
44 char *name;
45 char *key;
46 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
47 int require_ssl;
48 #endif
49 char *hosts;
50 METHOD **res_methods;
51 METHOD **auth_methods;
52 char *default_user;
53 char *default_domain;
54 char *localaddress;
55 char *access_script;
56 int access_type; /* Type of access (Perl or Python). */
57 char *dynamic_script;
58 int dynamic_type; /* Type of dynamic authorization (Python only). */
59 } AUTHGROUP;
60
61 typedef struct _GROUP {
62 char *name;
63 struct _GROUP *above;
64 AUTHGROUP *auth;
65 ACCESSGROUP *access;
66 } GROUP;
67
68 /* Function declarations. */
69 static void PERMreadfile(char *filename);
70 static void authdecl_parse(AUTHGROUP*, CONFFILE*, CONFTOKEN*);
71 static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok);
72 static void method_parse(METHOD*, CONFFILE*, CONFTOKEN*, int);
73
74 static void add_authgroup(AUTHGROUP*);
75 static void add_accessgroup(ACCESSGROUP*);
76 static void strip_accessgroups(void);
77
78 static METHOD *copy_method(METHOD*);
79 static void free_method(METHOD*);
80 static AUTHGROUP *copy_authgroup(AUTHGROUP*);
81 static void free_authgroup(AUTHGROUP*);
82 static ACCESSGROUP *copy_accessgroup(ACCESSGROUP*);
83 static void free_accessgroup(ACCESSGROUP*);
84
85 static void CompressList(char*);
86 static bool MatchHost(char*, char*, char*);
87 static int MatchUser(char*, char*);
88 static char *ResolveUser(AUTHGROUP*);
89 static char *AuthenticateUser(AUTHGROUP*, char*, char*, int*, char*);
90
91 static void GrowArray(void*, void*);
92 static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *acccess_vec) UNUSED;
93
94 /* Global variables. */
95 static AUTHGROUP **auth_realms;
96 static AUTHGROUP *success_auth;
97 static ACCESSGROUP **access_realms;
98
99 static char *ConfigBit;
100 static int ConfigBitsize;
101
102 extern bool PerlLoaded;
103
104 #define PERMlbrace 1
105 #define PERMrbrace 2
106 #define PERMgroup 3
107 #define PERMauth 4
108 #define PERMaccess 5
109 #define PERMhost 6
110 #define PERMauthprog 7
111 #define PERMresolv 8
112 #define PERMresprog 9
113 #define PERMdefuser 10
114 #define PERMdefdomain 11
115 #define PERMusers 12
116 #define PERMnewsgroups 13
117 #define PERMread 14
118 #define PERMpost 15
119 #define PERMaccessrp 16
120
121 #define PERMalsolog 18
122 #define PERMprogram 19
123 #define PERMinclude 20
124 #define PERMkey 21
125 #define PERMlocaltime 22
126 #define PERMstrippath 23
127 #define PERMnnrpdperlfilter 24
128 #define PERMnnrpdpythonfilter 25
129 #define PERMfromhost 26
130 #define PERMpathhost 27
131 #define PERMorganization 28
132 #define PERMmoderatormailer 29
133 #define PERMdomain 30
134 #define PERMcomplaints 31
135 #define PERMspoolfirst 32
136 #define PERMcheckincludedtext 33
137 #define PERMclienttimeout 34
138 #define PERMlocalmaxartsize 35
139 #define PERMreadertrack 36
140 #define PERMstrippostcc 37
141 #define PERMaddinjectiondate 38
142 #define PERMaddinjectionpostingaccount 39
143 #define PERMaddinjectionpostinghost 40
144 #define PERMnnrpdposthost 41
145 #define PERMnnrpdpostport 42
146 #define PERMnnrpdoverstats 43
147 #define PERMbackoff_auth 44
148 #define PERMbackoff_db 45
149 #define PERMbackoff_k 46
150 #define PERMbackoff_postfast 47
151 #define PERMbackoff_postslow 48
152 #define PERMbackoff_trigger 49
153 #define PERMnnrpdcheckart 50
154 #define PERMnnrpdauthsender 51
155 #define PERMvirtualhost 52
156 #define PERMnewsmaster 53
157 #define PERMlocaladdress 54
158 #define PERMrejectwith 55
159 #define PERMmaxbytespersecond 56
160 #define PERMperl_auth 57
161 #define PERMpython_auth 58
162 #define PERMperl_access 59
163 #define PERMpython_access 60
164 #define PERMpython_dynamic 61
165 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
166 #define PERMrequire_ssl 62
167 #define PERMMAX 63
168 #else
169 #define PERMMAX 62
170 #endif
171
172 #define TEST_CONFIG(a, b) \
173 { \
174 int byte, offset; \
175 offset = a % 8; \
176 byte = (a - offset) / 8; \
177 b = ((ConfigBit[byte] & (1 << offset)) != 0) ? true : false; \
178 }
179 #define SET_CONFIG(a) \
180 { \
181 int byte, offset; \
182 offset = a % 8; \
183 byte = (a - offset) / 8; \
184 ConfigBit[byte] |= (1 << offset); \
185 }
186 #define CLEAR_CONFIG(a) \
187 { \
188 int byte, offset; \
189 offset = a % 8; \
190 byte = (a - offset) / 8; \
191 ConfigBit[byte] &= ~(1 << offset); \
192 }
193
194 static CONFTOKEN PERMtoks[] = {
195 { PERMlbrace, (char *) "{" },
196 { PERMrbrace, (char *) "}" },
197 { PERMgroup, (char *) "group" },
198 { PERMauth, (char *) "auth" },
199 { PERMaccess, (char *) "access" },
200 { PERMhost, (char *) "hosts:" },
201 { PERMauthprog, (char *) "auth:" },
202 { PERMresolv, (char *) "res" },
203 { PERMresprog, (char *) "res:" },
204 { PERMdefuser, (char *) "default:" },
205 { PERMdefdomain, (char *) "default-domain:" },
206 { PERMusers, (char *) "users:" },
207 { PERMnewsgroups, (char *) "newsgroups:" },
208 { PERMread, (char *) "read:" },
209 { PERMpost, (char *) "post:" },
210 { PERMaccessrp, (char *) "access:" },
211 { PERMalsolog, (char *) "log:" },
212 { PERMprogram, (char *) "program:" },
213 { PERMinclude, (char *) "include" },
214 { PERMkey, (char *) "key:" },
215 { PERMlocaltime, (char *) "localtime:" },
216 { PERMstrippath, (char *) "strippath:" },
217 { PERMnnrpdperlfilter, (char *) "perlfilter:" },
218 { PERMnnrpdpythonfilter, (char *) "pythonfilter:" },
219 { PERMfromhost, (char *) "fromhost:" },
220 { PERMpathhost, (char *) "pathhost:" },
221 { PERMorganization, (char *) "organization:" },
222 { PERMmoderatormailer, (char *) "moderatormailer:" },
223 { PERMdomain, (char *) "domain:" },
224 { PERMcomplaints, (char *) "complaints:" },
225 { PERMspoolfirst, (char *) "spoolfirst:" },
226 { PERMcheckincludedtext, (char *) "checkincludedtext:" },
227 { PERMclienttimeout, (char *) "clienttimeout:" },
228 { PERMlocalmaxartsize, (char *) "localmaxartsize:" },
229 { PERMreadertrack, (char *) "readertrack:" },
230 { PERMstrippostcc, (char *) "strippostcc:" },
231 { PERMaddinjectiondate, (char *) "addinjectiondate:" },
232 { PERMaddinjectionpostingaccount, (char *) "addinjectionpostingaccount:" },
233 { PERMaddinjectionpostinghost, (char *) "addinjectionpostinghost:" },
234 { PERMnnrpdposthost, (char *) "nnrpdposthost:" },
235 { PERMnnrpdpostport, (char *) "nnrpdpostport:" },
236 { PERMnnrpdoverstats, (char *) "nnrpdoverstats:" },
237 { PERMbackoff_auth, (char *) "backoff_auth:" },
238 { PERMbackoff_db, (char *) "backoff_db:" },
239 { PERMbackoff_k, (char *) "backoff_k:" },
240 { PERMbackoff_postfast, (char *) "backoff_postfast:" },
241 { PERMbackoff_postslow, (char *) "backoff_postslow:" },
242 { PERMbackoff_trigger, (char *) "backoff_trigger:" },
243 { PERMnnrpdcheckart, (char *) "nnrpdcheckart:" },
244 { PERMnnrpdauthsender, (char *) "nnrpdauthsender:" },
245 { PERMvirtualhost, (char *) "virtualhost:" },
246 { PERMnewsmaster, (char *) "newsmaster:" },
247 { PERMlocaladdress, (char *) "localaddress:" },
248 { PERMrejectwith, (char *) "reject_with:" },
249 { PERMmaxbytespersecond, (char *) "max_rate:" },
250 { PERMperl_auth, (char *) "perl_auth:" },
251 { PERMpython_auth, (char *) "python_auth:" },
252 { PERMperl_access, (char *) "perl_access:" },
253 { PERMpython_access, (char *) "python_access:" },
254 { PERMpython_dynamic, (char *) "python_dynamic:" },
255 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
256 { PERMrequire_ssl, (char *) "require_ssl:" },
257 #endif
258 { 0, (char *) NULL }
259 };
260
261 /* Function definitions. */
262 static void
GrowArray(void * data,void * el)263 GrowArray(void *data, void *el)
264 {
265 int i;
266 void ***array = data;
267
268 if (*array == NULL) {
269 *array = xmalloc(2 * sizeof(void *));
270 i = 0;
271 } else {
272 for (i = 0; (*array)[i]; i++)
273 ;
274 *array = xrealloc(*array, (i + 2) * sizeof(void *));
275 }
276 (*array)[i++] = el;
277 (*array)[i] = 0;
278 }
279
280 static METHOD *
copy_method(METHOD * orig)281 copy_method(METHOD *orig)
282 {
283 METHOD *ret;
284 int i;
285
286 ret = xmalloc(sizeof(METHOD));
287 memset(ConfigBit, '\0', ConfigBitsize);
288
289 ret->name = xstrdup(orig->name);
290 if (orig->program != NULL) {
291 ret->program = xstrdup(orig->program);
292 } else {
293 ret->program = NULL;
294 }
295 if (orig->users)
296 ret->users = xstrdup(orig->users);
297 else
298 ret->users = 0;
299
300 ret->extra_logs = 0;
301 if (orig->extra_logs) {
302 for (i = 0; orig->extra_logs[i]; i++)
303 GrowArray(&ret->extra_logs, xstrdup(orig->extra_logs[i]));
304 }
305
306 ret->type = orig->type;
307
308 return(ret);
309 }
310
311 static void
free_method(METHOD * del)312 free_method(METHOD *del)
313 {
314 int j;
315
316 if (del->extra_logs) {
317 for (j = 0; del->extra_logs[j]; j++)
318 free(del->extra_logs[j]);
319 free(del->extra_logs);
320 }
321 if (del->program)
322 free(del->program);
323 if (del->users)
324 free(del->users);
325 free(del->name);
326 free(del);
327 }
328
329 static AUTHGROUP *
copy_authgroup(AUTHGROUP * orig)330 copy_authgroup(AUTHGROUP *orig)
331 {
332 AUTHGROUP *ret;
333 int i;
334
335 if (!orig)
336 return(0);
337 ret = xmalloc(sizeof(AUTHGROUP));
338 memset(ConfigBit, '\0', ConfigBitsize);
339
340 if (orig->name)
341 ret->name = xstrdup(orig->name);
342 else
343 ret->name = 0;
344
345 if (orig->key)
346 ret->key = xstrdup(orig->key);
347 else
348 ret->key = 0;
349
350 if (orig->hosts)
351 ret->hosts = xstrdup(orig->hosts);
352 else
353 ret->hosts = 0;
354
355 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
356 ret->require_ssl = orig->require_ssl;
357 #endif
358
359 ret->res_methods = 0;
360 if (orig->res_methods) {
361 for (i = 0; orig->res_methods[i]; i++)
362 GrowArray(&ret->res_methods, copy_method(orig->res_methods[i]));;
363 }
364
365 ret->auth_methods = 0;
366 if (orig->auth_methods) {
367 for (i = 0; orig->auth_methods[i]; i++)
368 GrowArray(&ret->auth_methods, copy_method(orig->auth_methods[i]));
369 }
370
371 if (orig->default_user)
372 ret->default_user = xstrdup(orig->default_user);
373 else
374 ret->default_user = 0;
375
376 if (orig->default_domain)
377 ret->default_domain = xstrdup(orig->default_domain);
378 else
379 ret->default_domain = 0;
380
381 if (orig->localaddress)
382 ret->localaddress = xstrdup(orig->localaddress);
383 else
384 ret->localaddress = 0;
385
386 if (orig->access_script)
387 ret->access_script = xstrdup(orig->access_script);
388 else
389 ret->access_script = 0;
390
391 if (orig->access_type)
392 ret->access_type = orig->access_type;
393 else
394 ret->access_type = 0;
395
396 if (orig->dynamic_script)
397 ret->dynamic_script = xstrdup(orig->dynamic_script);
398 else
399 ret->dynamic_script = 0;
400
401 if (orig->dynamic_type)
402 ret->dynamic_type = orig->dynamic_type;
403 else
404 ret->dynamic_type = 0;
405
406 return(ret);
407 }
408
409 static ACCESSGROUP *
copy_accessgroup(ACCESSGROUP * orig)410 copy_accessgroup(ACCESSGROUP *orig)
411 {
412 ACCESSGROUP *ret;
413
414 if (!orig)
415 return(0);
416 ret = xmalloc(sizeof(ACCESSGROUP));
417 memset(ConfigBit, '\0', ConfigBitsize);
418 /* Copy all anyway, and update for local strings. */
419 *ret = *orig;
420
421 if (orig->name)
422 ret->name = xstrdup(orig->name);
423 if (orig->key)
424 ret->key = xstrdup(orig->key);
425 if (orig->read)
426 ret->read = xstrdup(orig->read);
427 if (orig->post)
428 ret->post = xstrdup(orig->post);
429 if (orig->users)
430 ret->users = xstrdup(orig->users);
431 if (orig->rejectwith)
432 ret->rejectwith = xstrdup(orig->rejectwith);
433 if (orig->fromhost)
434 ret->fromhost = xstrdup(orig->fromhost);
435 if (orig->pathhost)
436 ret->pathhost = xstrdup(orig->pathhost);
437 if (orig->organization)
438 ret->organization = xstrdup(orig->organization);
439 if (orig->moderatormailer)
440 ret->moderatormailer = xstrdup(orig->moderatormailer);
441 if (orig->domain)
442 ret->domain = xstrdup(orig->domain);
443 if (orig->complaints)
444 ret->complaints = xstrdup(orig->complaints);
445 if (orig->nnrpdposthost)
446 ret->nnrpdposthost = xstrdup(orig->nnrpdposthost);
447 if (orig->backoff_db)
448 ret->backoff_db = xstrdup(orig->backoff_db);
449 if (orig->newsmaster)
450 ret->newsmaster = xstrdup(orig->newsmaster);
451 return(ret);
452 }
453
454 static void
SetDefaultAuth(AUTHGROUP * curauth UNUSED)455 SetDefaultAuth(AUTHGROUP *curauth UNUSED)
456 {
457 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
458 curauth->require_ssl = false;
459 #endif
460 }
461
462 void
SetDefaultAccess(ACCESSGROUP * curaccess)463 SetDefaultAccess(ACCESSGROUP *curaccess)
464 {
465 curaccess->allownewnews = innconf->allownewnews;;
466 curaccess->allowihave = false;
467 curaccess->locpost = false;
468 curaccess->allowapproved = false;
469 curaccess->localtime = false;
470 curaccess->strippath = false;
471 curaccess->nnrpdperlfilter = true;
472 curaccess->nnrpdpythonfilter = true;
473 curaccess->fromhost = NULL;
474 if (innconf->fromhost)
475 curaccess->fromhost = xstrdup(innconf->fromhost);
476 curaccess->pathhost = NULL;
477 if (innconf->pathhost)
478 curaccess->pathhost = xstrdup(innconf->pathhost);
479 curaccess->organization = NULL;
480 if (innconf->organization)
481 curaccess->organization = xstrdup(innconf->organization);
482 curaccess->moderatormailer = NULL;
483 if (innconf->moderatormailer)
484 curaccess->moderatormailer = xstrdup(innconf->moderatormailer);
485 curaccess->domain = NULL;
486 if (innconf->domain)
487 curaccess->domain = xstrdup(innconf->domain);
488 curaccess->complaints = NULL;
489 if (innconf->complaints)
490 curaccess->complaints = xstrdup(innconf->complaints);
491 curaccess->spoolfirst = innconf->spoolfirst;
492 curaccess->checkincludedtext = innconf->checkincludedtext;
493 curaccess->clienttimeout = innconf->clienttimeout;
494 curaccess->localmaxartsize = innconf->localmaxartsize;
495 curaccess->readertrack = innconf->readertrack;
496 curaccess->strippostcc = innconf->strippostcc;
497 curaccess->addinjectiondate = innconf->addinjectiondate;
498 curaccess->addinjectionpostingaccount = innconf->addinjectionpostingaccount;
499 curaccess->addinjectionpostinghost = innconf->addinjectionpostinghost;
500 curaccess->nnrpdposthost = innconf->nnrpdposthost;
501 curaccess->nnrpdpostport = innconf->nnrpdpostport;
502 curaccess->nnrpdoverstats = innconf->nnrpdoverstats;
503 curaccess->backoff_auth = innconf->backoffauth;
504 curaccess->backoff_db = NULL;
505 if (innconf->backoffdb && *innconf->backoffdb != '\0')
506 curaccess->backoff_db = xstrdup(innconf->backoffdb);
507 curaccess->backoff_k = innconf->backoffk;
508 curaccess->backoff_postfast = innconf->backoffpostfast;
509 curaccess->backoff_postslow = innconf->backoffpostslow;
510 curaccess->backoff_trigger = innconf->backofftrigger;
511 curaccess->nnrpdcheckart = innconf->nnrpdcheckart;
512 curaccess->nnrpdauthsender = innconf->nnrpdauthsender;
513 curaccess->virtualhost = false;
514 curaccess->newsmaster = NULL;
515 curaccess->maxbytespersecond = 0;
516 }
517
518 static void
free_authgroup(AUTHGROUP * del)519 free_authgroup(AUTHGROUP *del)
520 {
521 int i;
522
523 if (del->name)
524 free(del->name);
525 if (del->key)
526 free(del->key);
527 if (del->hosts)
528 free(del->hosts);
529 if (del->res_methods) {
530 for (i = 0; del->res_methods[i]; i++)
531 free_method(del->res_methods[i]);
532 free(del->res_methods);
533 }
534 if (del->auth_methods) {
535 for (i = 0; del->auth_methods[i]; i++)
536 free_method(del->auth_methods[i]);
537 free(del->auth_methods);
538 }
539 if (del->default_user)
540 free(del->default_user);
541 if (del->default_domain)
542 free(del->default_domain);
543 if (del->localaddress)
544 free(del->localaddress);
545 if (del->access_script)
546 free(del->access_script);
547 if (del->dynamic_script)
548 free(del->dynamic_script);
549 free(del);
550 }
551
552 static void
free_accessgroup(ACCESSGROUP * del)553 free_accessgroup(ACCESSGROUP *del)
554 {
555 if (del->name)
556 free(del->name);
557 if (del->key)
558 free(del->key);
559 if (del->read)
560 free(del->read);
561 if (del->post)
562 free(del->post);
563 if (del->users)
564 free(del->users);
565 if (del->rejectwith)
566 free(del->rejectwith);
567 if (del->fromhost)
568 free(del->fromhost);
569 if (del->pathhost)
570 free(del->pathhost);
571 if (del->organization)
572 free(del->organization);
573 if (del->moderatormailer)
574 free(del->moderatormailer);
575 if (del->domain)
576 free(del->domain);
577 if (del->complaints)
578 free(del->complaints);
579 if (del->nnrpdposthost)
580 free(del->nnrpdposthost);
581 if (del->backoff_db)
582 free(del->backoff_db);
583 if (del->newsmaster)
584 free(del->newsmaster);
585 free(del);
586 }
587
588 static void
ReportError(CONFFILE * f,const char * err)589 ReportError(CONFFILE *f, const char *err)
590 {
591 syslog(L_ERROR, "%s syntax error in %s(%d), %s", Client.host,
592 f->filename, f->lineno, err);
593 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
594 ExitWithStats(1, true);
595 }
596
597 static void
method_parse(METHOD * method,CONFFILE * f,CONFTOKEN * tok,int auth)598 method_parse(METHOD *method, CONFFILE *f, CONFTOKEN *tok, int auth)
599 {
600 int oldtype;
601
602 oldtype = tok->type;
603 tok = CONFgettoken(0, f);
604
605 if (tok == NULL) {
606 ReportError(f, "Expected value.");
607 }
608
609 switch (oldtype) {
610 case PERMalsolog:
611 GrowArray(&method->extra_logs, xstrdup(tok->name));
612 break;
613 case PERMusers:
614
615 if (!auth) {
616 ReportError(f, "Unexpected users: directive in file.");
617 } else if (method->users) {
618 ReportError(f, "Multiple users: directive in file.");
619 }
620
621 method->users = xstrdup(tok->name);
622 break;
623 case PERMprogram:
624 if (method->program) {
625 ReportError(f, "Multiple program: directives in auth/res declaration.");
626 }
627
628 method->program = xstrdup(tok->name);
629 break;
630 }
631 }
632
633 static void
authdecl_parse(AUTHGROUP * curauth,CONFFILE * f,CONFTOKEN * tok)634 authdecl_parse(AUTHGROUP *curauth, CONFFILE *f, CONFTOKEN *tok)
635 {
636 int oldtype;
637 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
638 int boolval;
639 #endif
640 METHOD *m;
641 bool bit;
642 char buff[SMBUF], *oldname, *p;
643
644 oldtype = tok->type;
645 oldname = tok->name;
646
647 tok = CONFgettoken(PERMtoks, f);
648
649 if (tok == NULL) {
650 ReportError(f, "Expected value.");
651 }
652 TEST_CONFIG(oldtype, bit);
653 if (bit) {
654 snprintf(buff, sizeof(buff), "Duplicated '%s' field in auth group.",
655 oldname);
656 ReportError(f, buff);
657 }
658
659 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
660 if (strcasecmp(tok->name, "on") == 0
661 || strcasecmp(tok->name, "true") == 0
662 || strcasecmp(tok->name, "yes") == 0)
663 boolval = true;
664 else if (strcasecmp(tok->name, "off") == 0
665 || strcasecmp(tok->name, "false") == 0
666 || strcasecmp(tok->name, "no") == 0)
667 boolval = false;
668 else
669 boolval = -1;
670 #endif
671
672 switch (oldtype) {
673 case PERMkey:
674 curauth->key = xstrdup(tok->name);
675 SET_CONFIG(PERMkey);
676 break;
677 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
678 case PERMrequire_ssl:
679 if (boolval != -1)
680 curauth->require_ssl = boolval;
681 SET_CONFIG(PERMrequire_ssl);
682 break;
683 #endif
684 case PERMhost:
685 curauth->hosts = xstrdup(tok->name);
686 CompressList(curauth->hosts);
687 SET_CONFIG(PERMhost);
688
689 /* nnrpd.c downcases the names of connecting hosts. We should
690 * therefore also downcase the wildmat patterns to make sure there
691 * aren't any surprises. DNS is case-insensitive. */
692 for (p = curauth->hosts; *p; p++)
693 if (isupper((unsigned char) *p))
694 *p = tolower((unsigned char) *p);
695
696 break;
697 case PERMdefdomain:
698 curauth->default_domain = xstrdup(tok->name);
699 SET_CONFIG(PERMdefdomain);
700 break;
701 case PERMdefuser:
702 curauth->default_user = xstrdup(tok->name);
703 SET_CONFIG(PERMdefuser);
704 break;
705 case PERMresolv:
706 case PERMresprog:
707 m = xcalloc(1, sizeof(METHOD));
708 memset(ConfigBit, '\0', ConfigBitsize);
709 GrowArray(&curauth->res_methods, m);
710
711 if (oldtype == PERMresprog)
712 m->program = xstrdup(tok->name);
713 else {
714 m->name = xstrdup(tok->name);
715 tok = CONFgettoken(PERMtoks, f);
716 if (tok == NULL || tok->type != PERMlbrace) {
717 ReportError(f, "Expected '{' after 'res'.");
718 }
719
720 tok = CONFgettoken(PERMtoks, f);
721
722 while (tok != NULL && tok->type != PERMrbrace) {
723 method_parse(m, f, tok, 0);
724 tok = CONFgettoken(PERMtoks, f);
725 }
726
727 if (m->program == NULL) {
728 ReportError(f, "Missing 'program:' key.");
729 }
730
731 if (tok == NULL) {
732 ReportError(f, "Unexpected EOF.");
733 }
734 }
735 break;
736 case PERMauth:
737 case PERMperl_auth:
738 case PERMpython_auth:
739 case PERMauthprog:
740 m = xcalloc(1, sizeof(METHOD));
741 memset(ConfigBit, '\0', ConfigBitsize);
742 GrowArray(&curauth->auth_methods, m);
743 if (oldtype == PERMauthprog) {
744 m->type = PERMauthprog;
745 m->program = xstrdup(tok->name);
746 } else if (oldtype == PERMperl_auth) {
747 #ifdef DO_PERL
748 m->type = PERMperl_auth;
749 m->program = xstrdup(tok->name);
750 #else
751 ReportError(f, "perl_auth can not be used in readers.conf: INN not compiled with Perl support enabled.");
752 #endif
753 } else if (oldtype == PERMpython_auth) {
754 #ifdef DO_PYTHON
755 m->type = PERMpython_auth;
756 m->program = xstrdup(tok->name);
757 #else
758 ReportError(f, "python_auth can not be used in readers.conf: INN not compiled with Python support enabled.");
759 #endif
760 } else {
761 m->name = xstrdup(tok->name);
762 tok = CONFgettoken(PERMtoks, f);
763
764 if (tok == NULL || tok->type != PERMlbrace) {
765 ReportError(f, "Expected '{' after 'auth'.");
766 }
767
768 tok = CONFgettoken(PERMtoks, f);
769
770 while (tok != NULL && tok->type != PERMrbrace) {
771 method_parse(m, f, tok, 1);
772 tok = CONFgettoken(PERMtoks, f);
773 }
774
775 if (tok == NULL) {
776 ReportError(f, "Unexpected EOF.");
777 }
778 }
779 break;
780 case PERMperl_access:
781 #ifdef DO_PERL
782 curauth->access_script = xstrdup(tok->name);
783 curauth->access_type = PERMperl_access;
784 #else
785 ReportError(f, "perl_access can not be used in readers.conf: INN not compiled with Perl support enabled.");
786 #endif
787 break;
788 case PERMpython_access:
789 #ifdef DO_PYTHON
790 curauth->access_script = xstrdup(tok->name);
791 curauth->access_type = PERMpython_access;
792 #else
793 ReportError(f, "python_access can not be used in readers.conf: INN not compiled with Python support enabled.");
794 #endif
795 break;
796 case PERMpython_dynamic:
797 #ifdef DO_PYTHON
798 curauth->dynamic_script = xstrdup(tok->name);
799 curauth->dynamic_type = PERMpython_dynamic;
800 #else
801 ReportError(f, "python_dynamic can not be used in readers.conf: INN not compiled with Python support enabled.");
802 #endif
803 break;
804 case PERMlocaladdress:
805 curauth->localaddress = xstrdup(tok->name);
806 CompressList(curauth->localaddress);
807 SET_CONFIG(PERMlocaladdress);
808 break;
809 default:
810 snprintf(buff, sizeof(buff), "Unexpected token '%s'.", tok->name);
811 ReportError(f, buff);
812 break;
813 }
814 }
815
816 static void
accessdecl_parse(ACCESSGROUP * curaccess,CONFFILE * f,CONFTOKEN * tok)817 accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok)
818 {
819 int oldtype, boolval;
820 bool bit;
821 char buff[SMBUF], *oldname;
822
823 oldtype = tok->type;
824 oldname = tok->name;
825
826 tok = CONFgettoken(0, f);
827
828 if (tok == NULL) {
829 ReportError(f, "Expected value.");
830 }
831 TEST_CONFIG(oldtype, bit);
832 if (bit) {
833 snprintf(buff, sizeof(buff), "Duplicated '%s' field in access group.",
834 oldname);
835 ReportError(f, buff);
836 }
837 if (strcasecmp(tok->name, "on") == 0
838 || strcasecmp(tok->name, "true") == 0
839 || strcasecmp(tok->name, "yes") == 0)
840 boolval = true;
841 else if (strcasecmp(tok->name, "off") == 0
842 || strcasecmp(tok->name, "false") == 0
843 || strcasecmp(tok->name, "no") == 0)
844 boolval = false;
845 else
846 boolval = -1;
847
848 switch (oldtype) {
849 case PERMkey:
850 curaccess->key = xstrdup(tok->name);
851 SET_CONFIG(oldtype);
852 break;
853 case PERMusers:
854 curaccess->users = xstrdup(tok->name);
855 CompressList(curaccess->users);
856 SET_CONFIG(oldtype);
857 break;
858 case PERMrejectwith:
859 curaccess->rejectwith = xstrdup(tok->name);
860 SET_CONFIG(oldtype);
861 break;
862 case PERMnewsgroups:
863 TEST_CONFIG(PERMread, bit);
864 if (bit) {
865 /* Syntax error... can't set read: or post: _and_ use
866 * newsgroups:. */
867 ReportError(f, "read: newsgroups already set.");
868 }
869 TEST_CONFIG(PERMpost, bit);
870 if (bit) {
871 /* Syntax error... can't set read: or post: _and_ use
872 * newsgroups:. */
873 ReportError(f, "post: newsgroups already set.");
874 }
875
876 curaccess->read = xstrdup(tok->name);
877 CompressList(curaccess->read);
878 curaccess->post = xstrdup(tok->name);
879 CompressList(curaccess->post);
880 SET_CONFIG(oldtype);
881 SET_CONFIG(PERMread);
882 SET_CONFIG(PERMpost);
883 break;
884 case PERMread:
885 curaccess->read = xstrdup(tok->name);
886 CompressList(curaccess->read);
887 SET_CONFIG(oldtype);
888 break;
889 case PERMpost:
890 curaccess->post = xstrdup(tok->name);
891 CompressList(curaccess->post);
892 SET_CONFIG(oldtype);
893 break;
894 case PERMaccessrp:
895 TEST_CONFIG(PERMread, bit);
896 if (bit && strchr(tok->name, 'R') == NULL) {
897 free(curaccess->read);
898 curaccess->read = 0;
899 CLEAR_CONFIG(PERMread);
900 }
901 TEST_CONFIG(PERMpost, bit);
902 if (bit && strchr(tok->name, 'P') == NULL) {
903 free(curaccess->post);
904 curaccess->post = 0;
905 CLEAR_CONFIG(PERMpost);
906 }
907 curaccess->allowapproved = (strchr(tok->name, 'A') != NULL);
908 curaccess->allownewnews = (strchr(tok->name, 'N') != NULL);
909 curaccess->allowihave = (strchr(tok->name, 'I') != NULL);
910 curaccess->locpost = (strchr(tok->name, 'L') != NULL);
911 SET_CONFIG(oldtype);
912 break;
913 case PERMlocaltime:
914 if (boolval != -1) curaccess->localtime = boolval;
915 SET_CONFIG(oldtype);
916 break;
917 case PERMstrippath:
918 if (boolval != -1) curaccess->strippath = boolval;
919 SET_CONFIG(oldtype);
920 break;
921 case PERMnnrpdperlfilter:
922 if (boolval != -1) curaccess->nnrpdperlfilter = boolval;
923 SET_CONFIG(oldtype);
924 break;
925 case PERMnnrpdpythonfilter:
926 if (boolval != -1) curaccess->nnrpdpythonfilter = boolval;
927 SET_CONFIG(oldtype);
928 break;
929 case PERMfromhost:
930 if (curaccess->fromhost)
931 free(curaccess->fromhost);
932 curaccess->fromhost = xstrdup(tok->name);
933 SET_CONFIG(oldtype);
934 break;
935 case PERMpathhost:
936 if (curaccess->pathhost)
937 free(curaccess->pathhost);
938 curaccess->pathhost = xstrdup(tok->name);
939 SET_CONFIG(oldtype);
940 break;
941 case PERMorganization:
942 if (curaccess->organization)
943 free(curaccess->organization);
944 curaccess->organization = xstrdup(tok->name);
945 SET_CONFIG(oldtype);
946 break;
947 case PERMmoderatormailer:
948 if (curaccess->moderatormailer)
949 free(curaccess->moderatormailer);
950 curaccess->moderatormailer = xstrdup(tok->name);
951 SET_CONFIG(oldtype);
952 break;
953 case PERMdomain:
954 if (curaccess->domain)
955 free(curaccess->domain);
956 curaccess->domain = xstrdup(tok->name);
957 SET_CONFIG(oldtype);
958 break;
959 case PERMcomplaints:
960 if (curaccess->complaints)
961 free(curaccess->complaints);
962 curaccess->complaints = xstrdup(tok->name);
963 SET_CONFIG(oldtype);
964 break;
965 case PERMspoolfirst:
966 if (boolval != -1) curaccess->spoolfirst = boolval;
967 SET_CONFIG(oldtype);
968 break;
969 case PERMcheckincludedtext:
970 if (boolval != -1) curaccess->checkincludedtext = boolval;
971 SET_CONFIG(oldtype);
972 break;
973 case PERMclienttimeout:
974 curaccess->clienttimeout = atoi(tok->name);
975 SET_CONFIG(oldtype);
976 break;
977 case PERMlocalmaxartsize:
978 curaccess->localmaxartsize = strtoul(tok->name, NULL, 10);
979 SET_CONFIG(oldtype);
980 break;
981 case PERMreadertrack:
982 if (boolval != -1) curaccess->readertrack = boolval;
983 SET_CONFIG(oldtype);
984 break;
985 case PERMstrippostcc:
986 if (boolval != -1) curaccess->strippostcc = boolval;
987 SET_CONFIG(oldtype);
988 break;
989 case PERMaddinjectiondate:
990 if (boolval != -1)
991 curaccess->addinjectiondate = boolval;
992 SET_CONFIG(oldtype);
993 break;
994 case PERMaddinjectionpostingaccount:
995 if (boolval != -1)
996 curaccess->addinjectionpostingaccount = boolval;
997 SET_CONFIG(oldtype);
998 break;
999 case PERMaddinjectionpostinghost:
1000 if (boolval != -1)
1001 curaccess->addinjectionpostinghost = boolval;
1002 SET_CONFIG(oldtype);
1003 break;
1004 case PERMnnrpdposthost:
1005 if (curaccess->nnrpdposthost)
1006 free(curaccess->nnrpdposthost);
1007 curaccess->nnrpdposthost = xstrdup(tok->name);
1008 SET_CONFIG(oldtype);
1009 break;
1010 case PERMnnrpdpostport:
1011 curaccess->nnrpdpostport = strtoul(tok->name, NULL, 10);
1012 SET_CONFIG(oldtype);
1013 break;
1014 case PERMnnrpdoverstats:
1015 if (boolval != -1) curaccess->nnrpdoverstats = boolval;
1016 SET_CONFIG(oldtype);
1017 break;
1018 case PERMbackoff_auth:
1019 if (boolval != -1) curaccess->backoff_auth = boolval;
1020 SET_CONFIG(oldtype);
1021 break;
1022 case PERMbackoff_db:
1023 if (curaccess->backoff_db)
1024 free(curaccess->backoff_db);
1025 curaccess->backoff_db = xstrdup(tok->name);
1026 SET_CONFIG(oldtype);
1027 break;
1028 case PERMbackoff_k:
1029 curaccess->backoff_k = strtoul(tok->name, NULL, 10);
1030 SET_CONFIG(oldtype);
1031 break;
1032 case PERMbackoff_postfast:
1033 curaccess->backoff_postfast = strtoul(tok->name, NULL, 10);
1034 SET_CONFIG(oldtype);
1035 break;
1036 case PERMbackoff_postslow:
1037 curaccess->backoff_postslow = strtoul(tok->name, NULL, 10);
1038 SET_CONFIG(oldtype);
1039 break;
1040 case PERMbackoff_trigger:
1041 curaccess->backoff_trigger = strtoul(tok->name, NULL, 10);
1042 SET_CONFIG(oldtype);
1043 break;
1044 case PERMnnrpdcheckart:
1045 if (boolval != -1) curaccess->nnrpdcheckart = boolval;
1046 SET_CONFIG(oldtype);
1047 break;
1048 case PERMnnrpdauthsender:
1049 if (boolval != -1) curaccess->nnrpdauthsender = boolval;
1050 SET_CONFIG(oldtype);
1051 break;
1052 case PERMvirtualhost:
1053 if (boolval != -1) curaccess->virtualhost = boolval;
1054 SET_CONFIG(oldtype);
1055 break;
1056 case PERMnewsmaster:
1057 if (curaccess->newsmaster)
1058 free(curaccess->newsmaster);
1059 curaccess->newsmaster = xstrdup(tok->name);
1060 SET_CONFIG(oldtype);
1061 break;
1062 case PERMmaxbytespersecond:
1063 curaccess->maxbytespersecond = atol(tok->name);
1064 SET_CONFIG(oldtype);
1065 break;
1066 default:
1067 snprintf(buff, sizeof(buff), "Unexpected token '%s'.", tok->name);
1068 ReportError(f, buff);
1069 break;
1070 }
1071 }
1072
1073 static void
PERMvectortoaccess(ACCESSGROUP * acc,const char * name,struct vector * access_vec)1074 PERMvectortoaccess(ACCESSGROUP *acc, const char *name,
1075 struct vector *access_vec)
1076 {
1077 CONFTOKEN *tok = NULL;
1078 CONFFILE *file;
1079 char *str;
1080 unsigned int i;
1081
1082 file = xcalloc(1, sizeof(CONFFILE));
1083 file->array = access_vec->strings;
1084 file->array_len = access_vec->count;
1085
1086 memset(ConfigBit, '\0', ConfigBitsize);
1087
1088 SetDefaultAccess(acc);
1089 str = xstrdup(name);
1090 acc->name = str;
1091 file->filename = str;
1092
1093 for (i = 0; i <= access_vec->count; i++) {
1094 tok = CONFgettoken(PERMtoks, file);
1095
1096 if (tok != NULL) {
1097 accessdecl_parse(acc, file, tok);
1098 }
1099 }
1100
1101 /* No need to free str here; it is used by acc, and will be
1102 * free'd when the access block is free'd. */
1103 free(file);
1104 return;
1105 }
1106
1107 static void
PERMreadfile(char * filename)1108 PERMreadfile(char *filename)
1109 {
1110 CONFCHAIN *cf = NULL,
1111 *hold = NULL;
1112 CONFTOKEN *tok = NULL;
1113 int inwhat;
1114 GROUP *curgroup = NULL,
1115 *newgroup = NULL;
1116 ACCESSGROUP *curaccess = NULL;
1117 AUTHGROUP *curauth = NULL;
1118 int oldtype;
1119 char *str = NULL;
1120 char *path = NULL;
1121 char buff[SMBUF];
1122
1123 if(filename != NULL) {
1124 syslog(L_TRACE, "Reading access from %s",
1125 filename == NULL ? "(NULL)" : filename);
1126 }
1127
1128 cf = xmalloc(sizeof(CONFCHAIN));
1129 if ((cf->f = CONFfopen(filename)) == NULL) {
1130 syslog(L_ERROR, "%s cannot open %s: %m", Client.host, filename);
1131 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
1132 ExitWithStats(1, true);
1133 }
1134 cf->parent = 0;
1135
1136 /* Are we editing an auth or access group? */
1137
1138 inwhat = 0;
1139 curgroup = 0;
1140
1141 tok = CONFgettoken(PERMtoks, cf->f);
1142
1143 while (tok != NULL) {
1144 if (inwhat == 0) {
1145 /* Top-level parser. */
1146
1147 switch (tok->type) {
1148 /* Include a child file. */
1149
1150 case PERMinclude:
1151 tok = CONFgettoken(0, cf->f);
1152
1153 if (tok == NULL) {
1154 ReportError(cf->f, "Expected filename after 'include'.");
1155 }
1156
1157 hold = xmalloc(sizeof(CONFCHAIN));
1158 hold->parent = cf;
1159
1160 /* Unless the filename's path is fully qualified, open it
1161 * relative to <pathetc>. */
1162 path = concatpath(innconf->pathetc, tok->name);
1163 hold->f = CONFfopen(path);
1164 free(path);
1165
1166 if (hold->f == NULL) {
1167 ReportError(cf->f, "Could not open 'include' filename.");
1168 }
1169
1170 cf = hold;
1171 goto again;
1172 break;
1173
1174 /* Nested group declaration. */
1175 case PERMgroup:
1176 tok = CONFgettoken(PERMtoks, cf->f);
1177
1178 if (tok == NULL) {
1179 ReportError(cf->f, "Unexpected EOF at group name.");
1180 }
1181
1182 newgroup = xmalloc(sizeof(GROUP));
1183 newgroup->above = curgroup;
1184 newgroup->name = xstrdup(tok->name);
1185 memset(ConfigBit, '\0', ConfigBitsize);
1186
1187 tok = CONFgettoken(PERMtoks, cf->f);
1188
1189 if (tok == NULL || tok->type != PERMlbrace) {
1190 ReportError(cf->f, "Expected '{' after group name.");
1191 }
1192
1193 /* Nested group declaration. */
1194 if (curgroup) {
1195 newgroup->auth = copy_authgroup(curgroup->auth);
1196 newgroup->access = copy_accessgroup(curgroup->access);
1197 } else {
1198 newgroup->auth = 0;
1199 newgroup->access = 0;
1200 }
1201
1202 curgroup = newgroup;
1203 break;
1204
1205 /* Beginning of an auth or access group declaration. */
1206 case PERMauth:
1207 case PERMaccess:
1208 oldtype = tok->type;
1209
1210 if ((tok = CONFgettoken(PERMtoks, cf->f)) == NULL) {
1211 ReportError(cf->f, "Expected identifier.");
1212 }
1213
1214 str = xstrdup(tok->name);
1215
1216 tok = CONFgettoken(PERMtoks, cf->f);
1217
1218 if (tok == NULL || tok->type != PERMlbrace) {
1219 ReportError(cf->f, "Expected '{'.");
1220 }
1221
1222 switch (oldtype) {
1223 case PERMauth:
1224 if (curgroup && curgroup->auth) {
1225 curauth = copy_authgroup(curgroup->auth);
1226 } else {
1227 curauth = xcalloc(1, sizeof(AUTHGROUP));
1228 memset(ConfigBit, '\0', ConfigBitsize);
1229 SetDefaultAuth(curauth);
1230 }
1231
1232 curauth->name = str;
1233 inwhat = 1;
1234 break;
1235
1236 case PERMaccess:
1237 if (curgroup && curgroup->access)
1238 curaccess = copy_accessgroup(curgroup->access);
1239 else {
1240 curaccess = xcalloc(1, sizeof(ACCESSGROUP));
1241 memset(ConfigBit, '\0', ConfigBitsize);
1242 SetDefaultAccess(curaccess);
1243 }
1244 curaccess->name = str;
1245 inwhat = 2;
1246 break;
1247 }
1248
1249 break;
1250
1251 /* End of a group declaration. */
1252
1253 case PERMrbrace:
1254 if (curgroup == NULL) {
1255 ReportError(cf->f, "Unmatched '}'.");
1256 }
1257
1258 newgroup = curgroup;
1259 curgroup = curgroup->above;
1260 if (newgroup->auth)
1261 free_authgroup(newgroup->auth);
1262 if (newgroup->access)
1263 free_accessgroup(newgroup->access);
1264 free(newgroup->name);
1265 free(newgroup);
1266 break;
1267
1268 /* Stuff that belongs to an auth group. */
1269 case PERMhost:
1270 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
1271 case PERMrequire_ssl:
1272 #endif
1273 case PERMauthprog:
1274 case PERMresprog:
1275 case PERMdefuser:
1276 case PERMdefdomain:
1277 if (curgroup == NULL) {
1278 curgroup = xcalloc(1, sizeof(GROUP));
1279 memset(ConfigBit, '\0', ConfigBitsize);
1280 }
1281 if (curgroup->auth == NULL) {
1282 curgroup->auth = xcalloc(1, sizeof(AUTHGROUP));
1283 memset(ConfigBit, '\0', ConfigBitsize);
1284 SetDefaultAuth(curgroup->auth);
1285 }
1286 authdecl_parse(curgroup->auth, cf->f, tok);
1287 break;
1288
1289 /* Stuff that belongs to an access group. */
1290 case PERMusers:
1291 case PERMrejectwith:
1292 case PERMnewsgroups:
1293 case PERMread:
1294 case PERMpost:
1295 case PERMaccessrp:
1296 case PERMlocaltime:
1297 case PERMstrippath:
1298 case PERMnnrpdperlfilter:
1299 case PERMnnrpdpythonfilter:
1300 case PERMfromhost:
1301 case PERMpathhost:
1302 case PERMorganization:
1303 case PERMmoderatormailer:
1304 case PERMdomain:
1305 case PERMcomplaints:
1306 case PERMspoolfirst:
1307 case PERMcheckincludedtext:
1308 case PERMclienttimeout:
1309 case PERMlocalmaxartsize:
1310 case PERMreadertrack:
1311 case PERMstrippostcc:
1312 case PERMaddinjectiondate:
1313 case PERMaddinjectionpostingaccount:
1314 case PERMaddinjectionpostinghost:
1315 case PERMnnrpdposthost:
1316 case PERMnnrpdpostport:
1317 case PERMnnrpdoverstats:
1318 case PERMbackoff_auth:
1319 case PERMbackoff_db:
1320 case PERMbackoff_k:
1321 case PERMbackoff_postfast:
1322 case PERMbackoff_postslow:
1323 case PERMbackoff_trigger:
1324 case PERMnnrpdcheckart:
1325 case PERMnnrpdauthsender:
1326 case PERMvirtualhost:
1327 case PERMnewsmaster:
1328 if (!curgroup) {
1329 curgroup = xcalloc(1, sizeof(GROUP));
1330 memset(ConfigBit, '\0', ConfigBitsize);
1331 }
1332 if (!curgroup->access) {
1333 curgroup->access = xcalloc(1, sizeof(ACCESSGROUP));
1334 memset(ConfigBit, '\0', ConfigBitsize);
1335 SetDefaultAccess(curgroup->access);
1336 }
1337 accessdecl_parse(curgroup->access, cf->f, tok);
1338 break;
1339 default:
1340 snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
1341 ReportError(cf->f, buff);
1342 break;
1343 }
1344 } else if (inwhat == 1) {
1345 /* Auth group parser. */
1346 if (tok->type == PERMrbrace) {
1347 inwhat = 0;
1348
1349 if (curauth->name
1350 && MatchHost(curauth->hosts, Client.host, Client.ip)) {
1351 if (!MatchHost(curauth->localaddress, Client.serverhost, Client.serverip)) {
1352 syslog(L_TRACE, "Auth strategy '%s' does not match localhost. Removing.",
1353 curauth->name == NULL ? "(NULL)" : curauth->name);
1354 free_authgroup(curauth);
1355 } else
1356 add_authgroup(curauth);
1357 } else {
1358 syslog(L_TRACE, "Auth strategy '%s' does not match client. Removing.",
1359 curauth->name == NULL ? "(NULL)" : curauth->name);
1360 free_authgroup(curauth);
1361 }
1362 curauth = NULL;
1363 goto again;
1364 }
1365
1366 authdecl_parse(curauth, cf->f, tok);
1367 } else if (inwhat == 2) {
1368 /* Access group parser. */
1369 if (tok->type == PERMrbrace) {
1370 inwhat = 0;
1371
1372 if (curaccess->name)
1373 add_accessgroup(curaccess);
1374 else
1375 free_accessgroup(curaccess);
1376 curaccess = NULL;
1377 goto again;
1378 }
1379
1380 accessdecl_parse(curaccess, cf->f, tok);
1381 } else {
1382 /* Should never happen. */
1383 syslog(L_TRACE, "SHOULD NEVER HAPPEN!");
1384 }
1385 again:
1386
1387
1388 /* Go back up the 'include' chain. */
1389 tok = CONFgettoken(PERMtoks, cf->f);
1390
1391 while (tok == NULL && cf) {
1392 hold = cf;
1393 cf = hold->parent;
1394 CONFfclose(hold->f);
1395 free(hold);
1396 if (cf) {
1397 tok = CONFgettoken(PERMtoks, cf->f);
1398 }
1399 }
1400 }
1401
1402 return;
1403 }
1404
1405 void
PERMgetinitialaccess(char * readersconf)1406 PERMgetinitialaccess(char *readersconf)
1407 {
1408 int i;
1409
1410 auth_realms = NULL;
1411 access_realms = NULL;
1412 success_auth = NULL;
1413
1414 #ifdef HAVE_SASL
1415 PERMcanauthenticate = true;
1416 #else
1417 PERMcanauthenticate = false;
1418 #endif
1419 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
1420 PERMcanauthenticatewithoutSSL = false;
1421 #endif
1422 PERMgroupmadeinvalid = false;
1423 PERMcanpostgreeting = false;
1424 PERMcanread = PERMcanpost = false;
1425 PERMreadlist = PERMpostlist = NULL;
1426 PERMaccessconf = NULL;
1427
1428 if (ConfigBit == NULL) {
1429 if (PERMMAX % 8 == 0) {
1430 ConfigBitsize = PERMMAX/8;
1431 } else {
1432 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1433 }
1434 ConfigBit = xcalloc(ConfigBitsize, 1);
1435 }
1436
1437 /* Parse the readers.conf file. */
1438 PERMreadfile(readersconf);
1439
1440 /* Remove unused access groups. */
1441 strip_accessgroups();
1442
1443 if (auth_realms == NULL) {
1444 /* No one can talk, empty file. */
1445 syslog(L_NOTICE, "%s no_permission", Client.host);
1446 Reply("%d You have no permission to talk. Goodbye!\r\n",
1447 NNTP_ERR_ACCESS);
1448 ExitWithStats(1, true);
1449 }
1450
1451 /* auth_realms are all expected to match the user.
1452 * Be careful whether an encryption layer is required, though. */
1453 for (i = 0; auth_realms[i] != NULL; i++) {
1454 if (auth_realms[i]->auth_methods != NULL) {
1455 PERMcanauthenticate = true;
1456 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
1457 if (!auth_realms[i]->require_ssl)
1458 PERMcanauthenticatewithoutSSL = true;
1459 #endif
1460 }
1461 /* We assume that an access or dynamic script will allow
1462 * the user to post when authenticated, so that a 200 greeting
1463 * code can be sent. */
1464 if (auth_realms[i]->access_script != NULL
1465 || auth_realms[i]->dynamic_script != NULL)
1466 PERMcanpostgreeting = true;
1467 }
1468 }
1469
1470 void
PERMgetaccess(bool initialconnection)1471 PERMgetaccess(bool initialconnection)
1472 {
1473 char *uname;
1474 int i;
1475
1476 if (ConfigBit == NULL) {
1477 if (PERMMAX % 8 == 0) {
1478 ConfigBitsize = PERMMAX/8;
1479 } else {
1480 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1481 }
1482 ConfigBit = xcalloc(ConfigBitsize, 1);
1483 }
1484
1485 if (auth_realms == NULL) {
1486 return;
1487 }
1488
1489 for (i = 0; auth_realms[i] != NULL; i++) {
1490 ;
1491 }
1492
1493 uname = NULL;
1494 while (uname == NULL && i-- > 0) {
1495 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
1496 /* If an encryption layer is required, check that the connection
1497 * really uses one. */
1498 if (auth_realms[i]->require_ssl && !encryption_layer_on) {
1499 continue;
1500 }
1501 #endif
1502 if ((uname = ResolveUser(auth_realms[i])) != NULL) {
1503 PERMauthorized = true;
1504 }
1505 if (uname == NULL && auth_realms[i]->default_user != NULL) {
1506 uname = xstrdup(auth_realms[i]->default_user);
1507 }
1508 }
1509 if (uname != NULL) {
1510 strlcpy(PERMuser, uname, sizeof(PERMuser));
1511 free(uname);
1512 uname = strchr(PERMuser, '@');
1513 if (uname == NULL && auth_realms[i]->default_domain != NULL) {
1514 /* Append the default domain to the username. */
1515 strlcat(PERMuser, "@", sizeof(PERMuser));
1516 strlcat(PERMuser, auth_realms[i]->default_domain,
1517 sizeof(PERMuser));
1518 }
1519 PERMneedauth = false;
1520 success_auth = auth_realms[i];
1521 syslog(L_TRACE, "%s res %s", Client.host, PERMuser);
1522 } else if (initialconnection && !PERMcanauthenticate) {
1523 /* Couldn't resolve the user. */
1524 syslog(L_NOTICE, "%s no_user", Client.host);
1525 Reply("%d Could not get your access name. Goodbye!\r\n",
1526 NNTP_ERR_ACCESS);
1527 ExitWithStats(1, true);
1528 } else {
1529 PERMneedauth = true;
1530 }
1531
1532 if (initialconnection) {
1533 /* Check maximum allowed permissions for any host that matches (for
1534 * the greeting string). */
1535 for (i = 0; access_realms[i] != NULL; i++) {
1536 if (!PERMcanread) {
1537 PERMcanread = (access_realms[i]->read != NULL);
1538 }
1539 if (!PERMcanpost) {
1540 PERMcanpost = (access_realms[i]->post != NULL);
1541 }
1542 if (!PERMcanpostgreeting) {
1543 PERMcanpostgreeting = (access_realms[i]->post != NULL);
1544 }
1545 }
1546 if (i == 0) {
1547 /* No applicable access groups. Zeroing all these makes INN
1548 * return permission denied to client. */
1549 PERMcanread = PERMcanpost = PERMneedauth = false;
1550 }
1551 }
1552 }
1553
1554 void
PERMlogin(char * uname,char * pass,int * code,char * errorstr)1555 PERMlogin(char *uname, char *pass, int *code, char *errorstr)
1556 {
1557 int i = 0;
1558 char *runame;
1559
1560 if (ConfigBit == NULL) {
1561 if (PERMMAX % 8 == 0)
1562 ConfigBitsize = PERMMAX/8;
1563 else
1564 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1565 ConfigBit = xcalloc(ConfigBitsize, 1);
1566 }
1567 /* The check in CMDauthinfo uses the value of PERMneedauth to know if
1568 * authentication succeeded or not. By default, authentication doesn't
1569 * succeed. */
1570 PERMneedauth = true;
1571
1572 if(auth_realms != NULL) {
1573 for (i = 0; auth_realms[i]; i++) {
1574 ;
1575 }
1576 }
1577
1578 runame = NULL;
1579
1580 while (runame == NULL && i--)
1581 runame = AuthenticateUser(auth_realms[i], uname, pass, code, errorstr);
1582 if (runame) {
1583 strlcpy(PERMuser, runame, sizeof(PERMuser));
1584 free(runame);
1585 uname = strchr(PERMuser, '@');
1586 if (!uname && auth_realms[i]->default_domain) {
1587 /* Append the default domain to the username. */
1588 strlcat(PERMuser, "@", sizeof(PERMuser));
1589 strlcat(PERMuser, auth_realms[i]->default_domain,
1590 sizeof(PERMuser));
1591 }
1592 PERMneedauth = false;
1593 PERMauthorized = true;
1594 PERMcanauthenticate = false;
1595 success_auth = auth_realms[i];
1596 }
1597 }
1598
1599 static int
MatchUser(char * pat,char * user)1600 MatchUser(char *pat, char *user)
1601 {
1602 char *cp, **list;
1603 char *userlist[2];
1604 int ret;
1605
1606 if (!pat)
1607 return(1);
1608 if (!user || !*user)
1609 return(0);
1610 cp = xstrdup(pat);
1611 list = 0;
1612 NGgetlist(&list, cp);
1613 userlist[0] = user;
1614 userlist[1] = 0;
1615 ret = PERMmatch(list, userlist);
1616 free(cp);
1617 free(list[0]);
1618 free(list);
1619 return(ret);
1620 }
1621
1622 void
PERMgetpermissions(void)1623 PERMgetpermissions(void)
1624 {
1625 int i;
1626 char *cp, **list;
1627 char *user[2];
1628 static ACCESSGROUP *noaccessconf;
1629
1630 if (ConfigBit == NULL) {
1631 if (PERMMAX % 8 == 0)
1632 ConfigBitsize = PERMMAX/8;
1633 else
1634 ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
1635 ConfigBit = xcalloc(ConfigBitsize, 1);
1636 }
1637 if (!success_auth) {
1638 /* If we haven't successfully authenticated, we can't do anything. */
1639 syslog(L_TRACE, "%s no_success_auth", Client.host);
1640 if (!noaccessconf)
1641 noaccessconf = xmalloc(sizeof(ACCESSGROUP));
1642 PERMaccessconf = noaccessconf;
1643 SetDefaultAccess(PERMaccessconf);
1644 return;
1645 #ifdef DO_PERL
1646 } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMperl_access)) {
1647 char *uname;
1648 char *cpp, *script_path;
1649 char **args;
1650 struct vector *access_vec;
1651
1652 i = 0;
1653 cpp = xstrdup(success_auth->access_script);
1654 args = 0;
1655 Argify(cpp, &args);
1656 script_path = concat(args[0], (char *) 0);
1657 if ((script_path != NULL) && (strlen(script_path) > 0)) {
1658 if(!PerlLoaded) {
1659 loadPerl();
1660 }
1661 PERLsetup(NULL, script_path, "access");
1662 free(script_path);
1663
1664 uname = xstrdup(PERMuser);
1665
1666 access_vec = vector_new();
1667
1668 perlAccess(uname, access_vec);
1669 free(uname);
1670
1671 access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
1672
1673 PERMvectortoaccess(access_realms[0], "perl_access-block", access_vec);
1674
1675 vector_free(access_vec);
1676 } else {
1677 syslog(L_ERROR, "No script specified in perl_access method.\n");
1678 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
1679 ExitWithStats(1, true);
1680 }
1681 free(cpp);
1682 free(args);
1683 #endif /* DO_PERL */
1684 #ifdef DO_PYTHON
1685 } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMpython_access)) {
1686 char *uname;
1687 char *cpp, *script_path;
1688 char **args;
1689 struct vector *access_vec;
1690
1691 i = 0;
1692 cpp = xstrdup(success_auth->access_script);
1693 args = 0;
1694 Argify(cpp, &args);
1695 script_path = concat(args[0], (char *) 0);
1696 if ((script_path != NULL) && (strlen(script_path) > 0)) {
1697 uname = xstrdup(PERMuser);
1698 access_vec = vector_new();
1699
1700 PY_access(script_path, access_vec, uname);
1701 free(script_path);
1702 free(uname);
1703 free(args);
1704
1705 access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
1706 memset(access_realms[0], 0, sizeof(ACCESSGROUP));
1707
1708 PERMvectortoaccess(access_realms[0], "python_access-block", access_vec);
1709
1710 vector_free(access_vec);
1711 } else {
1712 syslog(L_ERROR, "No script specified in python_access method.\n");
1713 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
1714 ExitWithStats(1, true);
1715 }
1716 free(cpp);
1717 #endif /* DO_PYTHON */
1718 } else {
1719 for (i = 0; access_realms[i]; i++)
1720 ;
1721 user[0] = PERMuser;
1722 user[1] = 0;
1723 while (i--) {
1724 if ((!success_auth->key && !access_realms[i]->key) ||
1725 (access_realms[i]->key && success_auth->key &&
1726 strcmp(access_realms[i]->key, success_auth->key) == 0)) {
1727 if (!access_realms[i]->users)
1728 break;
1729 else if (!*PERMuser)
1730 continue;
1731 cp = xstrdup(access_realms[i]->users);
1732 list = 0;
1733 NGgetlist(&list, cp);
1734 if (PERMmatch(list, user)) {
1735 syslog(L_TRACE, "%s match_user %s %s", Client.host,
1736 PERMuser, access_realms[i]->users);
1737 free(cp);
1738 free(list[0]);
1739 free(list);
1740 break;
1741 } else
1742 syslog(L_TRACE, "%s no_match_user %s %s", Client.host,
1743 PERMuser, access_realms[i]->users);
1744 free(cp);
1745 free(list[0]);
1746 free(list);
1747 }
1748 }
1749 }
1750 if (i >= 0) {
1751 /* Found the right access group. */
1752 if (access_realms[i]->rejectwith) {
1753 syslog(L_NOTICE, "%s rejected by rule (%s)",
1754 Client.host, access_realms[i]->rejectwith);
1755 Reply("%d Permission denied: %s\r\n",
1756 NNTP_FAIL_TERMINATING, access_realms[i]->rejectwith);
1757 ExitWithStats(1, true);
1758 }
1759 if (access_realms[i]->read) {
1760 cp = xstrdup(access_realms[i]->read);
1761 PERMspecified = NGgetlist(&PERMreadlist, cp);
1762 free(cp);
1763 PERMcanread = true;
1764 } else {
1765 syslog(L_TRACE, "%s no_read %s", Client.host, access_realms[i]->name);
1766 PERMcanread = false;
1767 }
1768 if (access_realms[i]->post) {
1769 cp = xstrdup(access_realms[i]->post);
1770 NGgetlist(&PERMpostlist, cp);
1771 free(cp);
1772 PERMcanpost = true;
1773 } else {
1774 syslog(L_TRACE, "%s no_post %s", Client.host, access_realms[i]->name);
1775 PERMcanpost = false;
1776 }
1777 PERMaccessconf = access_realms[i];
1778 MaxBytesPerSecond = PERMaccessconf->maxbytespersecond;
1779 if (PERMaccessconf->virtualhost) {
1780 if (PERMaccessconf->domain == NULL) {
1781 syslog(L_ERROR, "%s virtualhost needs domain parameter (%s).",
1782 Client.host, PERMaccessconf->name);
1783 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
1784 ExitWithStats(1, true);
1785 }
1786 if (VirtualPath)
1787 free(VirtualPath);
1788 if (strcasecmp(innconf->pathhost, PERMaccessconf->pathhost) == 0) {
1789 /* Use domain, if pathhost in access realm matches one in
1790 * inn.conf to differentiate virtual host. */
1791 if (innconf->domain != NULL && strcasecmp(innconf->domain, PERMaccessconf->domain) == 0) {
1792 syslog(L_ERROR, "%s domain parameter (%s) in readers.conf must be different from the one in inn.conf.",
1793 Client.host, PERMaccessconf->name);
1794 Reply("%d NNTP server unavailable. Try later!\r\n", NNTP_FAIL_TERMINATING);
1795 ExitWithStats(1, true);
1796 }
1797 VirtualPath = concat(PERMaccessconf->domain, "!", (char *) 0);
1798 } else {
1799 VirtualPath = concat(PERMaccessconf->pathhost, "!",
1800 (char *) 0);
1801 }
1802 VirtualPathlen = strlen(VirtualPath);
1803 } else
1804 VirtualPathlen = 0;
1805 } else {
1806 if (!noaccessconf)
1807 noaccessconf = xmalloc(sizeof(ACCESSGROUP));
1808 PERMaccessconf = noaccessconf;
1809 SetDefaultAccess(PERMaccessconf);
1810 syslog(L_TRACE, "%s no_access_realm", Client.host);
1811 }
1812 /* Check if dynamic access control is enabled; if so, init it. */
1813 #ifdef DO_PYTHON
1814 if ((success_auth->dynamic_type == PERMpython_dynamic) && success_auth->dynamic_script) {
1815 PY_dynamic_init(success_auth->dynamic_script);
1816 }
1817 #endif /* DO_PYTHON */
1818 }
1819
1820 /* Strip blanks out of a string. */
1821 static void
CompressList(char * list)1822 CompressList(char *list)
1823 {
1824 char *cpto;
1825 bool inword = false;
1826
1827 for (cpto = list; *list; ) {
1828 if (strchr("\n \t,", *list) != NULL) {
1829 list++;
1830 if(inword) {
1831 *cpto++ = ',';
1832 inword = false;
1833 }
1834 } else {
1835 *cpto++ = *list++;
1836 inword = true;
1837 }
1838 }
1839 *cpto = '\0';
1840 }
1841
1842 static bool
MatchHost(char * hostlist,char * host,char * ip)1843 MatchHost(char *hostlist, char *host, char *ip)
1844 {
1845 int i;
1846 char *cp, *pat, *mask;
1847 char **list = NULL;
1848 bool match = false;
1849
1850 /* If no hostlist are specified, by default they match. */
1851 if (hostlist == NULL)
1852 return true;
1853
1854 cp = xstrdup(hostlist);
1855 NGgetlist(&list, cp);
1856
1857 /* Start searching from the end of the list. The default is no access. */
1858 for (i = 0; list[i] != NULL; i++)
1859 ;
1860 while (!match && i-- > 0) {
1861 pat = list[i];
1862 match = uwildmat(host, pat);
1863 if (!match && ip != NULL && *ip != '\0') {
1864 match = uwildmat(ip, pat);
1865 if (match)
1866 break;
1867 mask = strchr(pat, '/');
1868 if (mask == NULL)
1869 continue;
1870 *mask = '\0';
1871 mask++;
1872 match = network_addr_match(ip, pat, mask);
1873 }
1874 }
1875 free(list[0]);
1876 free(list);
1877 free(cp);
1878 return match;
1879 }
1880
1881 static void
add_authgroup(AUTHGROUP * group)1882 add_authgroup(AUTHGROUP *group)
1883 {
1884 int i;
1885
1886 if (auth_realms == NULL) {
1887 i = 0;
1888 auth_realms = xmalloc(2 * sizeof(AUTHGROUP *));
1889 } else {
1890 for (i = 0; auth_realms[i]; i++)
1891 ;
1892 auth_realms = xrealloc(auth_realms, (i + 2) * sizeof(AUTHGROUP *));
1893 }
1894 auth_realms[i] = group;
1895 auth_realms[i+1] = 0;
1896 }
1897
1898 static void
add_accessgroup(ACCESSGROUP * group)1899 add_accessgroup(ACCESSGROUP *group)
1900 {
1901 int i;
1902
1903 if (access_realms == NULL) {
1904 i = 0;
1905 access_realms = xmalloc(2 * sizeof(ACCESSGROUP *));
1906 } else {
1907 for (i = 0; access_realms[i]; i++)
1908 ;
1909 access_realms = xrealloc(access_realms, (i + 2) * sizeof(ACCESSGROUP *));
1910 }
1911 access_realms[i] = group;
1912 access_realms[i+1] = 0;
1913 }
1914
1915
1916 /*
1917 ** Clean out access groups that don't apply to any of our auth groups.
1918 */
1919 static void
strip_accessgroups(void)1920 strip_accessgroups(void)
1921 {
1922 int i, j;
1923
1924 /* Flag the access group as used or not. */
1925 if(access_realms != NULL) {
1926 for (j = 0; access_realms[j] != NULL; j++) {
1927 access_realms[j]->used = 0;
1928 }
1929 } else {
1930 syslog(L_TRACE, "No access realms to check!");
1931 return;
1932 }
1933
1934 /* If there are auth realms to check... */
1935 if(auth_realms != NULL) {
1936 /* ... Then for each auth realm... */
1937 for (i = 0; auth_realms[i] != NULL; i++) {
1938 /* ... for each access realm... */
1939 for (j = 0; access_realms[j] != NULL; j++) {
1940 /* If the access realm isn't already in use... */
1941 if (! access_realms[j]->used) {
1942 /* Check to see if both the access_realm key and
1943 * auth_realm key are NULL... */
1944 if (!access_realms[j]->key && !auth_realms[i]->key) {
1945 /* If so, mark the realm in use and continue on... */
1946 access_realms[j]->used = 1;
1947 } else {
1948 /* If not, check to see if both the access_realm and
1949 auth_realm are NOT _both_ NULL, and see if they are
1950 equal... */
1951 if (access_realms[j]->key && auth_realms[i]->key &&
1952 strcmp(access_realms[j]->key, auth_realms[i]->key) == 0) {
1953 /* And if so, mark the realm in use. */
1954 access_realms[j]->used = 1;
1955 }
1956 }
1957 }
1958 }
1959 }
1960 } else {
1961 syslog(L_TRACE, "No auth realms to check!");
1962 }
1963
1964 /* Strip out unused access groups. */
1965 i = j = 0;
1966
1967 while (access_realms[i] != NULL) {
1968 if (access_realms[i]->used)
1969 access_realms[j++] = access_realms[i];
1970 else
1971 syslog(L_TRACE, "%s removing irrelevant access group %s",
1972 Client.host, access_realms[i]->name);
1973 i++;
1974 }
1975 access_realms[j] = 0;
1976 }
1977
1978
1979 /*
1980 ** Execute a series of resolvers to get the remote username. If one is
1981 ** found, return it in newly allocated space; otherwise, return NULL.
1982 */
1983 static char *
ResolveUser(AUTHGROUP * auth)1984 ResolveUser(AUTHGROUP *auth)
1985 {
1986 int i, j;
1987 char *command;
1988 char *user = NULL;
1989 char *resdir;
1990 char *tmp;
1991
1992 if (auth->res_methods == NULL)
1993 return NULL;
1994
1995 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
1996 /* If an encryption layer is required, check that the connection
1997 * really uses one. */
1998 if (auth->require_ssl && !encryption_layer_on)
1999 return NULL;
2000 #endif
2001
2002 tmp = concatpath(innconf->pathbin, INN_PATH_AUTHDIR);
2003 resdir = concatpath(tmp, INN_PATH_AUTHDIR_NOPASS);
2004 free(tmp);
2005
2006 for (i = 0; auth->res_methods[i]; i++) {
2007 command = auth->res_methods[i]->program;
2008 syslog(L_TRACE, "%s res starting resolver %s", Client.host, command);
2009 if (auth->res_methods[i]->extra_logs) {
2010 for (j = 0; auth->res_methods[i]->extra_logs[j]; j++)
2011 syslog(L_NOTICE, "%s res also-log: %s", Client.host,
2012 auth->res_methods[i]->extra_logs[j]);
2013 }
2014 user = auth_external(&Client, command, resdir, NULL, NULL);
2015 if (user == NULL)
2016 syslog(L_TRACE, "%s res resolver failed", Client.host);
2017 else {
2018 syslog(L_TRACE, "%s res resolver successful, user %s",
2019 Client.host, user);
2020 break;
2021 }
2022 }
2023 free(resdir);
2024 return user;
2025 }
2026
2027
2028 /*
2029 ** Execute a series of authenticators to get the remote username. If one is
2030 ** found, return it in newly allocated space; otherwise, return NULL. Also
2031 ** handles running the Perl and Python authentication functions.
2032 */
2033 static char *
AuthenticateUser(AUTHGROUP * auth,char * username,char * password,int * code UNUSED,char * errorstr UNUSED)2034 AuthenticateUser(AUTHGROUP *auth, char *username, char *password,
2035 int *code UNUSED, char *errorstr UNUSED)
2036 {
2037 int i, j;
2038 char *command;
2039 char *user = NULL;
2040 char *resdir;
2041 char *tmp;
2042
2043 if (auth->auth_methods == NULL)
2044 return NULL;
2045
2046 #if defined(HAVE_OPENSSL) || defined(HAVE_SASL)
2047 /* If an encryption layer is required, check that the connection
2048 * really uses one. */
2049 if (auth->require_ssl && !encryption_layer_on)
2050 return NULL;
2051 #endif
2052
2053 tmp = concatpath(innconf->pathbin, INN_PATH_AUTHDIR);
2054 resdir = concatpath(tmp, INN_PATH_AUTHDIR_PASSWD);
2055 free(tmp);
2056
2057 for (i = 0; auth->auth_methods[i]; i++) {
2058 if (auth->auth_methods[i]->type == PERMperl_auth) {
2059 #ifdef DO_PERL
2060 char *script_path, *cp;
2061 char **args;
2062 char newUser[BIG_BUFFER];
2063
2064 cp = xstrdup(auth->auth_methods[i]->program);
2065 args = 0;
2066 Argify(cp, &args);
2067 script_path = concat(args[0], (char *) 0);
2068 if ((script_path != NULL) && (strlen(script_path) > 0)) {
2069 if (!PerlLoaded)
2070 loadPerl();
2071 PERLsetup(NULL, script_path, "authenticate");
2072 free(script_path);
2073 perlAuthInit();
2074
2075 newUser[0] = '\0';
2076 perlAuthenticate(username, password, code, errorstr, newUser);
2077 if (*code == NNTP_OK_AUTHINFO) {
2078 if (newUser[0] != '\0')
2079 user = xstrdup(newUser);
2080 else
2081 user = xstrdup(username);
2082 syslog(L_NOTICE, "%s user %s", Client.host, user);
2083 if (LLOGenable) {
2084 fprintf(locallog, "%s user %s\n", Client.host, user);
2085 fflush(locallog);
2086 }
2087 break;
2088 } else {
2089 syslog(L_NOTICE, "%s bad_auth", Client.host);
2090 }
2091 } else {
2092 syslog(L_ERROR, "no script specified in auth method");
2093 }
2094 #endif /* DO_PERL */
2095 } else if (auth->auth_methods[i]->type == PERMpython_auth) {
2096 #ifdef DO_PYTHON
2097 char *script_path, *cp;
2098 char **args;
2099 char newUser[BIG_BUFFER];
2100
2101 cp = xstrdup(auth->auth_methods[i]->program);
2102 args = 0;
2103 Argify(cp, &args);
2104 script_path = concat(args[0], (char *) 0);
2105 if ((script_path != NULL) && (strlen(script_path) > 0)) {
2106 newUser[0] = '\0';
2107 PY_authenticate(script_path, username, password,
2108 code, errorstr, newUser);
2109 free(script_path);
2110 if (*code == NNTP_OK_AUTHINFO) {
2111 if (newUser[0] != '\0')
2112 user = xstrdup(newUser);
2113 else
2114 user = xstrdup(username);
2115 syslog(L_NOTICE, "%s user %s", Client.host, user);
2116 if (LLOGenable) {
2117 fprintf(locallog, "%s user %s\n", Client.host, user);
2118 fflush(locallog);
2119 }
2120 break;
2121 } else if (*code < 0) {
2122 syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
2123 } else {
2124 syslog(L_NOTICE, "%s bad_auth", Client.host);
2125 }
2126 } else {
2127 syslog(L_ERROR, "no script specified in auth method");
2128 }
2129 #endif /* DO_PYTHON */
2130 } else {
2131 if (auth->auth_methods[i]->users &&
2132 !MatchUser(auth->auth_methods[i]->users, username))
2133 continue;
2134
2135 command = auth->auth_methods[i]->program;
2136 syslog(L_TRACE, "%s res starting authenticator %s", Client.host,
2137 command);
2138 if (auth->auth_methods[i]->extra_logs) {
2139 for (j = 0; auth->auth_methods[i]->extra_logs[j]; j++)
2140 syslog(L_NOTICE, "%s auth also-log: %s", Client.host,
2141 auth->auth_methods[i]->extra_logs[j]);
2142 }
2143 user = auth_external(&Client, command, resdir, username, password);
2144 if (user == NULL)
2145 syslog(L_TRACE, "%s auth authenticator failed", Client.host);
2146 else {
2147 syslog(L_TRACE, "%s auth authenticator successful, user %s",
2148 Client.host, user);
2149 break;
2150 }
2151 }
2152 }
2153 free(resdir);
2154 return user;
2155 }
2156