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