Patch for integration of Python hooks and readers.conf
Erik Klavon
erik at eriq.org
Mon Aug 19 22:54:15 UTC 2002
Greetings
Enclosed below is a patch against CURRENT for the integration of the
Python authentication and access control hooks with the functionality
of readers.conf. The effect of these modifications mirror closely that
of the earlier integration of the Perl hooks with readers.conf.
Below is a description of the new behavior implemented by this
patch. Note that this differs slightly from the description in my
previous post to inn-workers in the following way: use of both perl
and python hooks simultaneously is not currently supported. Everything
compiles fine, but there are problems I haven't fully figured out yet
(nnrpd dumps core - I think its related to the redirection of stdout
and stderr). Fixing that problem shouldn't change the behavior
implemented in this patch (or that of the existing perl hooks). I'm
also not sure about the effects of having both interpreters compiled
in on innd and its filtering hooks. Has anyone tried this?
I'll start work on documentation changes and wrapper scripts, but
these may be delayed somewhat/greatly; the fall semester begins
for me in a week and I need to wrap up a project at work before that.
Three new auth group parameter/value pairs are added to readers.conf:
python_auth, python_access and python_dynamic. All three of these take
as their value a filename such as ldap_auth.py which is located in the
filter path (pathfilter) specified in inn.conf. Whenever one of them
is encountered in the processing of readers.conf, Python is loaded (if
it has yet to be), the specified module is loaded (if it has yet to
be), and the init method for the parameter is run (if it has yet to be).
Finally, the main method for the parameter is run. When nnrpd closes, all
of the close methods for any parameters encountered in the processing of
readers.conf are run. Each of the python modules must meet all
previous criteria with the exception of the naming of the methods and
some new return values which will be detailed below.
python_auth makes use of the following methods of the class
defined in its argument python module: authen_init, authenticate and
authen_close. authen_init is called once with no arguments when the
python_auth parameter is encountered for the first time with the
value of the given file. Values returned by authen_init are
ignored. authen_close is called with no arguments when nnrpd
closes. Values returned by authen_close are ignored. authenticate is
called with a dictionary as argument containing the hostname, ip
address, interface, username and password of the client. authenticate
returns a dictionary containing the nnrp response code for the
authentication session and an error string which will be passed to the
client if the error code indicates that the authentication attempt
failed. If other means to authenticate the client have not yet been
attempted, the error string will not be returned to the client.
Multiple, mixed use of python_auth with other auth statements is
permitted. auth statements are evaluated in the order they appear in
readers.conf. Use of python_auth in combination with perl_auth is
currently not supported.
python_access makes use of the following methods of the class
defined in its argument python module: access_init, access and
access_close. access_init is called once with no arguments when the
python_access parameter is encountered for the first time with the
value of the given file. Values returned by access_init are
ignored. access_close is called with no arguments when nnrpd
closes. Values returned by access_close are ignored. access is
called with a dictionary as argument containing the hostname, ip
address, interface, username and password of the client. access
should return a dictionary containing valid access group
parameter/value pairs. These pairs will be used to create an access
group that will then be used to determine the access rights of the
client. This feature overrides all access groups in readers.conf.
Only one python_access statement may be used in an auth group. Unlike
auth statements, only one python_access statement is
allowed. python_access should not be used in combination with
perl_access.
Dynamic access control on a per newsgroup basis rather then per
connection is preserved. The relevant methods of the class are
dynamic_init, dynamic_close and dynamic. dynamic_init and
dynamic_close behave in the same way as the corresponding functions in
authenticate and access. The dynamic method has the same domain and
range as the authorize method. I have chosen to rename authorize to
make clear its differences from authenticate and access.
Only one python_dynamic statement is allowed in any auth group.
The __init__ method is still called when the class is instantiated. If
any of the three functions of the class share resources that must all
be initialized at once, you might find it useful to use an __init__
method to do this.
Erik
--
erik | "It is idle to think that, by means of words, | Maurice
kl at von | any real communication can ever pass | Maeterlinck
eriq.org | from one [human] to another." | Silence
diff -urb inn/nnrpd/commands.c inn_patch/nnrpd/commands.c
--- inn/nnrpd/commands.c Sun Aug 11 15:36:10 2002
+++ inn_patch/nnrpd/commands.c Mon Aug 19 14:34:56 2002
@@ -224,9 +224,6 @@
static char Password[SMBUF];
char accesslist[BIG_BUFFER];
char errorstr[BIG_BUFFER];
-#ifdef DO_PYTHON
- int code;
-#endif
if (caseEQ(av[1], "generic")) {
char *logrec = Glom(av);
@@ -289,37 +286,6 @@
Password[sizeof Password - 1] = 0;
}
-#ifdef DO_PYTHON
- if (innconf->nnrppythonauth) {
- if ((code = PY_authenticate(ClientHost, ClientIpString, ServerHost, User, Password, accesslist)) < 0) {
- syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
- } else {
- if (code == NNTP_AUTH_OK_VAL) {
- PERMspecified = NGgetlist(&PERMreadlist, accesslist);
- PERMpostlist = PERMreadlist;
- syslog(L_NOTICE, "%s user %s", ClientHost, User);
- if (LLOGenable) {
- fprintf(locallog, "%s user (%s):%s\n", ClientHost, Username, User);
- fflush(locallog);
- }
- Reply("%d Ok\r\n", NNTP_AUTH_OK_VAL);
- /* save these values in case you need them later */
- strncpy(PERMuser, User, sizeof(PERMuser) - 1);
- PERMuser[sizeof(PERMuser) - 1] = '\0';
- strncpy(PERMpass, Password, sizeof(PERMpass) - 1);
- PERMpass[sizeof(PERMpass) - 1] = '\0';
- PERMneedauth = FALSE;
- PERMauthorized = TRUE;
- return;
- } else {
- syslog(L_NOTICE, "%s bad_auth", ClientHost);
- Reply("%d Authentication error\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, FALSE);
- }
- }
- } else {
-#endif /* DO_PYTHON */
-
if (EQ(User, PERMuser) && EQ(Password, PERMpass)) {
syslog(L_NOTICE, "%s user %s", ClientHost, User);
if (LLOGenable) {
@@ -347,13 +313,10 @@
PERMauthorized = TRUE;
return;
}
-#ifdef DO_PYTHON
- }
-#endif /* DO_PYTHON */
syslog(L_NOTICE, "%s bad_auth", ClientHost);
if (errorstr[0] != '\0') {
- syslog(L_NOTICE, "%s perl error str: %s", ClientHost, errorstr);
+ syslog(L_NOTICE, "%s script error str: %s", ClientHost, errorstr);
Reply("%d %s\r\n", NNTP_ACCESS_VAL, errorstr);
} else {
Reply("%d Authentication error\r\n", NNTP_ACCESS_VAL);
diff -urb inn/nnrpd/group.c inn_patch/nnrpd/group.c
--- inn/nnrpd/group.c Sun Aug 11 15:36:10 2002
+++ inn_patch/nnrpd/group.c Mon Aug 19 14:28:59 2002
@@ -48,17 +48,18 @@
}
#ifdef DO_PYTHON
- if (innconf->nnrppythonauth) {
+ if (PY_use_dynamic) {
char *reply;
- /* Authorize user at a Python authorization module */
- if (PY_authorize(ClientHost, ClientIpString, ServerHost, PERMuser, group, FALSE, &reply) < 0) {
- syslog(L_NOTICE, "PY_authorize(): authorization skipped due to no Python authorization method defined.");
+ /* Authorize user using Python module method dynamic */
+ if (PY_dynamic(ClientHost, ClientIpString, ServerHost, PERMuser, group, FALSE, &reply) < 0) {
+ syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
} else {
if (reply != NULL) {
- syslog(L_TRACE, "PY_authorize() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, group, reply);
+ syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, group, reply);
Reply("%d %s\r\n", NNTP_ACCESS_VAL, reply);
DISPOSE(group);
+ DISPOSE(reply);
return;
}
}
diff -urb inn/nnrpd/misc.c inn_patch/nnrpd/misc.c
--- inn/nnrpd/misc.c Sat Aug 10 11:51:36 2002
+++ inn_patch/nnrpd/misc.c Mon Aug 19 14:28:59 2002
@@ -163,15 +163,16 @@
}
#ifdef DO_PYTHON
- if (innconf->nnrppythonauth) {
+ if (PY_use_dynamic) {
char *reply;
/* Authorize user at a Python authorization module */
- if (PY_authorize(ClientHost, ClientIpString, ServerHost, PERMuser, p, FALSE, &reply) < 0) {
- syslog(L_NOTICE, "PY_authorize(): authorization skipped due to no Python authorization method defined.");
+ if (PY_dynamic(ClientHost, ClientIpString, ServerHost, PERMuser, p, FALSE, &reply) < 0) {
+ syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
} else {
if (reply != NULL) {
- syslog(L_TRACE, "PY_authorize() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
+ syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
+ DISPOSE(reply);
return TRUE;
}
}
diff -urb inn/nnrpd/nnrpd.c inn_patch/nnrpd/nnrpd.c
--- inn/nnrpd/nnrpd.c Thu Aug 15 01:11:18 2002
+++ inn_patch/nnrpd/nnrpd.c Mon Aug 19 14:40:44 2002
@@ -119,6 +119,10 @@
bool PerlLoaded = FALSE;
#endif /* DO_PERL */
+#ifdef DO_PYTHON
+bool PY_use_dynamic = FALSE;
+#endif /* DO_PYTHON */
+
bool LLOGenable;
static char CMDfetchhelp[] = "[MessageID|Number]";
@@ -242,9 +246,8 @@
SMshutdown();
#ifdef DO_PYTHON
- if (innconf->nnrppythonauth)
- PY_close();
-#endif
+ PY_close_python();
+#endif /* DO_PYTHON */
HISclose(History);
@@ -536,11 +539,6 @@
{
struct sockaddr_storage ssc, sss;
socklen_t length;
-#ifdef DO_PYTHON
- char accesslist[BIG_BUFFER];
- int code;
- static ACCESSGROUP *authconf;
-#endif
const char *default_host_error = "unknown error";
ClientIpAddr = 0L;
@@ -645,31 +643,9 @@
LogName[sizeof(LogName) - 1] = '\0';
syslog(L_NOTICE, "%s (%s) connect", ClientHost, ClientIpString);
-#ifdef DO_PYTHON
- if (innconf->nnrppythonauth) {
- if ((code = PY_authenticate(ClientHost, ClientIpString, ServerHost, NULL, NULL, accesslist)) < 0) {
- syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
- } else {
- if (code == 502) {
- syslog(L_NOTICE, "%s no_access", ClientHost);
- Printf("%d You are not in my access file. Goodbye.\r\n",
- NNTP_ACCESS_VAL);
- ExitWithStats(1, TRUE);
- }
- PERMspecified = NGgetlist(&PERMreadlist, accesslist);
- PERMpostlist = PERMreadlist;
- }
- if (!authconf)
- authconf = NEW(ACCESSGROUP, 1);
- PERMaccessconf = authconf;
- SetDefaultAccess(PERMaccessconf);
- } else {
-#endif /* DO_PYTHON */
+
PERMgetaccess(NNRPACCESS);
PERMgetpermissions();
-#ifdef DO_PYTHON
- }
-#endif /* DO_PYTHON */
}
@@ -785,13 +761,6 @@
static void SetupDaemon(void) {
bool val;
time_t statinterval;
-
-#ifdef DO_PYTHON
- /* Load the Python code */
- if (innconf->nnrppythonauth) {
- PY_setup();
- }
-#endif /* defined(DO_PYTHON) */
History = HISopen(HISTORY, innconf->hismethod, HIS_RDONLY);
if (!History) {
diff -urb inn/nnrpd/nnrpd.h inn_patch/nnrpd/nnrpd.h
--- inn/nnrpd/nnrpd.h Thu Aug 15 01:11:18 2002
+++ inn_patch/nnrpd/nnrpd.h Mon Aug 19 14:28:59 2002
@@ -238,6 +238,10 @@
extern void SetDefaultAccess(ACCESSGROUP*);
extern void Reply(const char *fmt, ...);
+#ifdef DO_PYTHON
+extern bool PY_use_dynamic;
+#endif
+
#ifdef HAVE_SSL
extern void Printf(const char *fmt, ...);
#else
@@ -279,10 +283,10 @@
#endif /* DO_PERL */
#ifdef DO_PYTHON
-int PY_authenticate(char *clientHost, char *clientIpString, char *serverHost, char *username, char *password, char *accesslist);
-int PY_authorize(char *clientHost, char *clientIpString, char *serverHost, char *username, char *NewsGroup, int PostFlag, char **reply_message);
-void PY_close(void);
-void PY_setup(void);
+int PY_authenticate(char *path, char *clientHost, char *clientIpString, char *serverHost, char *Username, char *Password, char *errorstring);
+void PY_access(char* path, struct vector *access_vec, char *clientHost, char *clientIpString, char *serverHost, char *Username);
+int PY_dynamic(char *clientHost, char *clientIpString, char *ServerHost, char *Username, char *NewsGroup, int PostFlag, char **reply_message);
+void PY_dynamic_init (char* file);
#endif /* DO_PYTHON */
void line_free(struct line *);
diff -urb inn/nnrpd/perm.c inn_patch/nnrpd/perm.c
--- inn/nnrpd/perm.c Sun Aug 11 22:34:50 2002
+++ inn_patch/nnrpd/perm.c Mon Aug 19 14:28:59 2002
@@ -28,7 +28,7 @@
typedef struct _METHOD {
char *name;
char *program;
- int type; /* for seperating perl_auth from auth */
+ int type; /* type of auth (perl, python or external) */
char *users; /* only used for auth_methods, not for res_methods. */
char **extra_headers;
char **extra_logs;
@@ -46,7 +46,10 @@
char *default_user;
char *default_domain;
char *localaddress;
- char *perl_access;
+ char *access_script;
+ int access_type; /* type of access (perl or python) */
+ char *dynamic_script;
+ int dynamic_type; /* type of dynamic authorization (python only) */
} AUTHGROUP;
typedef struct _GROUP {
@@ -149,12 +152,15 @@
#define PERMrejectwith 54
#define PERMmaxbytespersecond 55
#define PERMperl_auth 56
-#define PERMperl_access 57
+#define PERMpython_auth 57
+#define PERMperl_access 58
+#define PERMpython_access 59
+#define PERMpython_dynamic 60
#ifdef HAVE_SSL
-#define PERMrequire_ssl 58
-#define PERMMAX 59
+#define PERMrequire_ssl 61
+#define PERMMAX 62
#else
-#define PERMMAX 58
+#define PERMMAX 61
#endif
#define TEST_CONFIG(a, b) \
@@ -236,7 +242,10 @@
{ PERMrejectwith, "reject_with:" },
{ PERMmaxbytespersecond, "max_rate:" },
{ PERMperl_auth, "perl_auth:" },
+ { PERMpython_auth, "python_auth:" },
{ PERMperl_access, "perl_access:" },
+ { PERMpython_access, "python_access:" },
+ { PERMpython_dynamic, "python_dynamic:" },
#ifdef HAVE_SSL
{ PERMrequire_ssl, "require_ssl:" },
#endif
@@ -374,10 +383,25 @@
else
ret->localaddress = 0;
- if (orig->perl_access)
- ret->perl_access = COPY(orig->perl_access);
+ if (orig->access_script)
+ ret->access_script = COPY(orig->access_script);
else
- ret->perl_access = 0;
+ ret->access_script = 0;
+
+ if (orig->access_type)
+ ret->access_type = orig->access_type;
+ else
+ ret->access_type = 0;
+
+ if (orig->dynamic_script)
+ ret->dynamic_script = COPY(orig->dynamic_script);
+ else
+ ret->dynamic_script = 0;
+
+ if (orig->dynamic_type)
+ ret->dynamic_type = orig->dynamic_type;
+ else
+ ret->dynamic_type = 0;
return(ret);
}
@@ -513,8 +537,10 @@
DISPOSE(del->default_domain);
if (del->localaddress)
DISPOSE(del->localaddress);
- if (del->perl_access)
- DISPOSE(del->perl_access);
+ if (del->access_script)
+ DISPOSE(del->access_script);
+ if (del->dynamic_script)
+ DISPOSE(del->dynamic_script);
DISPOSE(del);
}
@@ -690,6 +716,7 @@
break;
case PERMauth:
case PERMperl_auth:
+ case PERMpython_auth:
case PERMauthprog:
m = NEW(METHOD, 1);
memset(m, 0, sizeof(METHOD));
@@ -705,6 +732,13 @@
#else
ReportError(f, "perl_auth can not be used in readers.conf: inn not compiled with perl support enabled.");
#endif
+ } else if (oldtype == PERMpython_auth) {
+#ifdef DO_PYTHON
+ m->type = PERMpython_auth;
+ m->program = COPY(tok->name);
+#else
+ ReportError(f, "python_auth can not be used in readers.conf: inn not compiled with python support enabled.");
+#endif
} else {
m->name = COPY(tok->name);
tok = CONFgettoken(PERMtoks, f);
@@ -727,11 +761,28 @@
break;
case PERMperl_access:
#ifdef DO_PERL
- curauth->perl_access = COPY(tok->name);
+ curauth->access_script = COPY(tok->name);
+ curauth->access_type = PERMperl_access;
#else
ReportError(f, "perl_access can not be used in readers.conf: inn not compiled with perl support enabled.");
#endif
break;
+ case PERMpython_access:
+#ifdef DO_PYTHON
+ curauth->access_script = COPY(tok->name);
+ curauth->access_type = PERMpython_access;
+#else
+ ReportError(f, "python_access can not be used in readers.conf: inn not compiled with python support enabled.");
+#endif
+ break;
+ case PERMpython_dynamic:
+#ifdef DO_PYTHON
+ curauth->dynamic_script = COPY(tok->name);
+ curauth->dynamic_type = PERMpython_dynamic;
+#else
+ ReportError(f, "python_dynamic can not be used in readers.conf: inn not compiled with python support enabled.");
+#endif
+ break;
case PERMlocaladdress:
curauth->localaddress = COPY(tok->name);
CompressList(curauth->localaddress);
@@ -1476,7 +1527,7 @@
char *user[2];
static ACCESSGROUP *noaccessconf;
char *uname;
- char *cpp, *perl_path;
+ char *cpp, *script_path;
char **args;
struct vector *access_vec;
@@ -1497,18 +1548,18 @@
SetDefaultAccess(PERMaccessconf);
return;
#ifdef DO_PERL
- } else if (success_auth->perl_access != NULL) {
+ } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMperl_access)) {
i = 0;
- cpp = COPY(success_auth->perl_access);
+ cpp = COPY(success_auth->access_script);
args = 0;
Argify(cpp, &args);
- perl_path = concat(args[0], (char *) 0);
- if ((perl_path != NULL) && (strlen(perl_path) > 0)) {
+ script_path = concat(args[0], (char *) 0);
+ if ((script_path != NULL) && (strlen(script_path) > 0)) {
if(!PerlLoaded) {
loadPerl();
}
- PERLsetup(NULL, perl_path, "access");
- free(perl_path);
+ PERLsetup(NULL, script_path, "access");
+ free(script_path);
uname = COPY(PERMuser);
DISPOSE(args);
@@ -1521,17 +1572,45 @@
access_realms[0] = NEW(ACCESSGROUP, 1);
memset(access_realms[0], 0, sizeof(ACCESSGROUP));
- PERMvectortoaccess(access_realms[0], "perl-dyanmic", access_vec);
+ PERMvectortoaccess(access_realms[0], "perl-dynamic", access_vec);
vector_free(access_vec);
} else {
- syslog(L_ERROR, "No script specified in auth method.\n");
+ syslog(L_ERROR, "No script specified in perl_access method.\n");
Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
ExitWithStats(1, TRUE);
}
DISPOSE(cpp);
- DISPOSE(args);
#endif /* DO_PERL */
+#ifdef DO_PYTHON
+ } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMpython_access)) {
+ i = 0;
+ cpp = COPY(success_auth->access_script);
+ args = 0;
+ Argify(cpp, &args);
+ script_path = concat(args[0], (char *) 0);
+ if ((script_path != NULL) && (strlen(script_path) > 0)) {
+ uname = COPY(PERMuser);
+ access_vec = vector_new();
+
+ PY_access(script_path, access_vec, ClientHost, ClientIpString, ServerHost, uname);
+ free(script_path);
+ DISPOSE(uname);
+ DISPOSE(args);
+
+ access_realms[0] = NEW(ACCESSGROUP, 1);
+ memset(access_realms[0], 0, sizeof(ACCESSGROUP));
+
+ PERMvectortoaccess(access_realms[0], "python-dynamic", access_vec);
+
+ vector_free(access_vec);
+ } else {
+ syslog(L_ERROR, "No script specified in python_access method.\n");
+ Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
+ ExitWithStats(1, TRUE);
+ }
+ DISPOSE(cpp);
+#endif /* DO_PYTHON */
} else {
for (i = 0; access_realms[i]; i++)
;
@@ -1626,6 +1705,12 @@
SetDefaultAccess(PERMaccessconf);
syslog(L_TRACE, "%s no_access_realm", ClientHost);
}
+ /* check if dynamic access control is enabled, if so init it */
+#ifdef DO_PYTHON
+ if ((success_auth->dynamic_type == PERMpython_dynamic) && success_auth->dynamic_script) {
+ PY_dynamic_init(success_auth->dynamic_script);
+ }
+#endif /* DO_PYTHON */
}
/* strip blanks out of a string */
@@ -2142,7 +2227,7 @@
char *arg0;
char *resdir;
char *tmp;
- char *perl_path;
+ char *script_path;
EXECSTUFF *foo;
int done = 0;
int code;
@@ -2157,18 +2242,18 @@
ubuf[0] = '\0';
for (i = 0; auth->auth_methods[i]; i++) {
-#ifdef DO_PERL
if (auth->auth_methods[i]->type == PERMperl_auth) {
+#ifdef DO_PERL
cp = COPY(auth->auth_methods[i]->program);
args = 0;
Argify(cp, &args);
- perl_path = concat(args[0], (char *) 0);
- if ((perl_path != NULL) && (strlen(perl_path) > 0)) {
+ script_path = concat(args[0], (char *) 0);
+ if ((script_path != NULL) && (strlen(script_path) > 0)) {
if(!PerlLoaded) {
loadPerl();
}
- PERLsetup(NULL, perl_path, "authenticate");
- free(perl_path);
+ PERLsetup(NULL, script_path, "authenticate");
+ free(script_path);
perlAuthInit();
code = perlAuthenticate(ClientHost, ClientIpString, ServerHost, username, password, errorstr);
@@ -2188,8 +2273,38 @@
} else {
syslog(L_ERROR, "No script specified in auth method.\n");
}
- } else if (auth->auth_methods[i]->type == PERMauthprog) {
#endif /* DO_PERL */
+ } else if (auth->auth_methods[i]->type == PERMpython_auth) {
+#ifdef DO_PYTHON
+ cp = COPY(auth->auth_methods[i]->program);
+ args = 0;
+ Argify(cp, &args);
+ script_path = concat(args[0], (char *) 0);
+ if ((script_path != NULL) && (strlen(script_path) > 0)) {
+ code = PY_authenticate(script_path, ClientHost, ClientIpString, ServerHost, username, password, errorstr);
+ free(script_path);
+ if (code < 0) {
+ syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
+ } else {
+ if (code == NNTP_AUTH_OK_VAL) {
+ syslog(L_NOTICE, "%s user %s", ClientHost, username);
+ if (LLOGenable) {
+ fprintf(locallog, "%s user %s\n", ClientHost, username);
+ fflush(locallog);
+ }
+
+ /* save these values in case you need them later */
+ strcpy(ubuf, username);
+ break;
+ } else {
+ syslog(L_NOTICE, "%s bad_auth", ClientHost);
+ }
+ }
+ } else {
+ syslog(L_ERROR, "No script specified in auth method.\n");
+ }
+#endif /* DO_PYTHON */
+ } else {
if (auth->auth_methods[i]->users &&
!MatchUser(auth->auth_methods[i]->users, username))
continue;
@@ -2233,9 +2348,7 @@
if (done)
/* this authenticator succeeded */
break;
-#ifdef DO_PERL
}
-#endif /* DO_PERL */
}
DISPOSE(resdir);
if (ubuf[0])
diff -urb inn/nnrpd/post.c inn_patch/nnrpd/post.c
--- inn/nnrpd/post.c Sun Aug 11 15:36:11 2002
+++ inn_patch/nnrpd/post.c Mon Aug 19 14:28:59 2002
@@ -726,16 +726,17 @@
switch (flag) {
case NF_FLAG_OK:
#ifdef DO_PYTHON
- if (innconf->nnrppythonauth) {
+ if (PY_use_dynamic) {
char *reply;
- /* Authorize user at a Python authorization module */
- if (PY_authorize(ClientHost, ClientIpString, ServerHost, PERMuser, p, TRUE, &reply) < 0) {
- syslog(L_NOTICE, "PY_authorize(): authorization skipped due to no Python authorization method defined.");
+ /* Authorize user using a Python module method dynamic */
+ if (PY_dynamic(ClientHost, ClientIpString, ServerHost, PERMuser, p, TRUE, &reply) < 0) {
+ syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
} else {
if (reply != NULL) {
- syslog(L_TRACE, "PY_authorize() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
- snprintf(Error, sizeof(Error), "%s\r\n", reply);
+ syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
+ (void)sprintf(Error, "%s\r\n", reply);
+ DISPOSE(reply);
break;
}
}
diff -urb inn/nnrpd/python.c inn_patch/nnrpd/python.c
--- inn/nnrpd/python.c Sat Mar 9 21:45:36 2002
+++ inn_patch/nnrpd/python.c Mon Aug 19 14:49:52 2002
@@ -14,96 +14,127 @@
#include "clibrary.h"
#include "nnrpd.h"
+#include "inn/hashtab.h"
#if defined(DO_PYTHON)
#include "Python.h"
+/* values relate name of hook to array index */
+#define PYTHONauthen 1
+#define PYTHONaccess 2
+#define PYTHONdynamic 3
+
+#define PYTHONtypes_max 4
+
+/* values relate type of method to array index */
+#define PYTHONmain 1
+#define PYTHONinit 2
+#define PYTHONclose 3
+
+#define PYTHONmethods_max 4
+
+/* key names for attributes dictionary */
+#define PYTHONhostname "hostname"
+#define PYTHONipaddress "ipaddress"
+#define PYTHONinterface "interface"
+#define PYTHONuser "user"
+#define PYTHONpass "pass"
+#define PYTHONtype "type"
+#define PYTHONnewsgroup "newsgroup"
+
+/* Max number of items in dictionary to pass to auth methods */
+#define _PY_MAX_AUTH_ITEM 7
+
/* Pointers to external Python objects */
PyObject *PYAuthObject = NULL;
-PyObject *PYAuthModule = NULL;
/* Dictionary of params to pass to authentication methods */
PyObject *PYauthinfo = NULL;
PyObject **PYauthitem = NULL;
-PyObject **PYauthkey = NULL;
-
-/* Max number of items in dictionary to pass to auth methods */
-#define _PY_MAX_AUTH_ITEM 10
/* These are pointers to Python methods specified in auth module */
-PyObject *authenticate_method = NULL;
-PyObject *authorize_method = NULL;
-PyObject *close_method = NULL;
+static PyMethodDef nnrpdPyMethods[];
/* Forward declaration */
static PyObject *PY_set_auth_hook(PyObject *dummy, PyObject *args);
+void PY_load_python(void);
+PyObject* PY_setup(int type, int method, char *file);
+static const void *file_key(const void *p);
+static bool file_equal(const void *k, const void *p);
+static void file_free(void *p);
+static void file_trav(void *data, void* null);
+
+bool PythonLoaded = FALSE;
+
+/* structure for storage of attributes for a module file */
+typedef struct PyFile {
+ char *file;
+ bool loaded[PYTHONtypes_max];
+ PyObject *procs[PYTHONtypes_max][PYTHONmethods_max];
+} PyFile;
+
+/* hash for storing files */
+struct hash *files;
-/* These variable defined in other C modules */
-extern char accesslist[];
+/* for passing the dynamic module filename from perm.c */
+char* dynamic_file;
/*
-** Authenticate connecting host by IP address or username&password.
+** Authenticate connecting host by username&password.
**
** Return NNTP reply code as returned by Python method or -1 if method
** is not defined.
*/
-int PY_authenticate(char *clientHost, char *clientIpString, char *serverHost, char *Username, char *Password, char *accesslist) {
- PyObject *result, *item;
- char *type;
+int PY_authenticate(char* file, char *clientHost, char *clientIpString, char *serverHost, char *Username, char *Password, char *errorstring) {
+ PyObject *result, *item, *proc;
int authnum;
int code, i;
+ char *temp;
+
+ PY_load_python();
+ proc = PY_setup(PYTHONauthen, PYTHONmain, file);
/* Return if authentication method is not defined */
- if (authenticate_method == NULL)
+ if (proc == NULL)
return -1;
- /* Figure out authentication type */
- if (Username == NULL)
- type = "connect";
- else
- type = "authinfo";
-
/* Initialize PythonAuthObject with connect method specific items */
authnum = 0;
- /* Authentication type */
- PYauthitem[authnum] = PyBuffer_FromMemory(type, strlen(type));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
-
/* Client hostname */
PYauthitem[authnum] = PyBuffer_FromMemory(clientHost, strlen(clientHost));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
/* Client IP number */
PYauthitem[authnum] = PyBuffer_FromMemory(clientIpString, strlen(clientIpString));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
/* Server interface the connection comes to */
PYauthitem[authnum] = PyBuffer_FromMemory(serverHost, strlen(serverHost));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
/* Username if known */
if (Username == NULL)
PYauthitem[authnum] = Py_None;
else
PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
/* Password if known */
if (Password == NULL)
PYauthitem[authnum] = Py_None;
else
PYauthitem[authnum] = PyBuffer_FromMemory(Password, strlen(Password));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
/* Now invoke authenticate method and see if it likes this user */
- result = PyObject_CallFunction(authenticate_method, "O", PYauthinfo);
+ result = PyObject_CallFunction(proc, "O", PYauthinfo);
/* Check the response */
if (result == NULL || !PyTuple_Check(result))
{
- syslog(L_ERROR, "python authenticate_method (type %s) returned wrong result", type);
+ syslog(L_ERROR, "python authenticate method returned wrong result");
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, TRUE);
}
@@ -114,7 +145,7 @@
/* Check the item */
if (!PyInt_Check(item))
{
- syslog(L_ERROR, "python authenticate_method (type %s) returned bad NNTP response code", type);
+ syslog(L_ERROR, "python authenticate method returned bad NNTP response code");
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, TRUE);
}
@@ -122,57 +153,127 @@
/* Store the code */
code = PyInt_AS_LONG(item);
- /* Get the CanPost setting */
+ /* Get the error string */
item = PyTuple_GetItem(result, 1);
/* Check the item */
- if (!PyInt_Check(item))
+ if (!PyString_Check(item))
{
- syslog(L_ERROR, "python authenticate_method (type %s) returned bad CanPost setting", type);
+ syslog(L_ERROR, "python authenticate method returned bad error string");
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, TRUE);
}
- /* Store the setting */
- PERMcanpost = PyInt_AS_LONG(item);
+ /* Store error string */
+ temp = PyString_AS_STRING(item);
+ strcpy(errorstring, temp);
- /* Get the CanRead setting */
- item = PyTuple_GetItem(result, 2);
+ /* Clean up the dictionary object */
+ PyDict_Clear(PYauthinfo);
- /* Check the item */
- if (!PyInt_Check(item))
+ /* Clean up dictionary items */
+ for (i = 0; i < authnum; i++)
{
- syslog(L_ERROR, "python authenticate_method (type %s) returned bad CanRead setting", type);
+ if (PYauthitem[i] != Py_None)
+ {
+ Py_DECREF(PYauthitem[i]);
+ }
+ }
+
+ /* Log auth result */
+ syslog(L_NOTICE, "python authenticate method succeeded, return code %d, error string %s", code, errorstring);
+
+ /* Return response code */
+ return code;
+}
+
+/*
+** Create an access group based on the values returned by the script in file
+**
+*/
+void PY_access(char* file, struct vector *access_vec, char *clientHost, char *clientIpString, char *serverHost, char *Username) {
+ PyObject *result, *key, *value, *proc;
+ char *skey, *svalue, *temp;
+ int authnum;
+ int i;
+
+ PY_load_python();
+ proc = PY_setup(PYTHONaccess, PYTHONmain, file);
+
+ /* Exit if access method is not defined */
+ if (proc == NULL) {
+ syslog(L_ERROR, "python access method not defined");
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, TRUE);
}
- /* Store the setting */
- PERMcanread = PyInt_AS_LONG(item);
+ /* Initialize PythonAuthObject with group method specific items */
+ authnum = 0;
- /* Get the access list */
- item = PyTuple_GetItem(result, 3);
+ /* Client hostname */
+ PYauthitem[authnum] = PyBuffer_FromMemory(clientHost, strlen(clientHost));
+ PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
- /* Check the item */
- if (!PyString_Check(item))
+ /* Client IP number */
+ PYauthitem[authnum] = PyBuffer_FromMemory(clientIpString, strlen(clientIpString));
+ PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
+
+ /* Server interface the connection comes to */
+ PYauthitem[authnum] = PyBuffer_FromMemory(serverHost, strlen(serverHost));
+ PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
+
+ /* Username */
+ PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
+ PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
+
+ /* Password is not known */
+ PYauthitem[authnum] = Py_None;
+ PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
+
+ /*
+ * Now invoke newsgroup access method
+ */
+ result = PyObject_CallFunction(proc, "O", PYauthinfo);
+
+ /* Check the response */
+ if (result == NULL || result == Py_None || !PyDict_Check(result))
{
- syslog(L_ERROR, "python authenticate_method (type %s) returned bad access list value", type);
+ syslog(L_ERROR, "python access method returned wrong result - expected a dictionary");
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, TRUE);
}
- /* Store access list*/
- strcpy(accesslist, PyString_AS_STRING(item));
+ /* resize vector to dictionary length */
+ vector_resize(access_vec, PyDict_Size(result) - 1);
- /* Fix the NNTP response code */
- if ((code == NNTP_POSTOK_VAL) || (code == NNTP_NOPOSTOK_VAL))
- {
- code = PERMcanpost ? NNTP_POSTOK_VAL : NNTP_NOPOSTOK_VAL;
+ /* store dict values in proper format in access vector */
+ i = 0;
+ while(PyDict_Next(result, &i, &key, &value)) {
+ if (!PyString_Check(key)) {
+ syslog(L_ERROR, "python access method return dictionary key %i not a string", i);
+ Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
+ ExitWithStats(1, FALSE);
}
+ if (!PyString_Check(value)) {
+ syslog(L_ERROR, "python access method return dictionary value %i not a string", i);
+ Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
+ ExitWithStats(1, FALSE);
+ }
+
+ temp = PyString_AsString(key);
+ skey = COPY(temp);
+
+ temp = PyString_AsString(value);
+ svalue = COPY(temp);
- /* Initialize needauth flag */
- if (code == NNTP_AUTH_NEEDED_VAL)
- PERMneedauth = TRUE;
+ skey = strcat(skey, ": \"");
+ skey = strcat(skey, svalue);
+ skey = strcat(skey, "\"\n");
+ vector_add(access_vec, skey);
+
+ free(skey);
+ free(svalue);
+ }
/* Clean up the dictionary object */
PyDict_Clear(PYauthinfo);
@@ -187,80 +288,93 @@
}
/* Log auth result */
- syslog(L_NOTICE, "python authenticate_method (type %s) succeeded, return code %d", type, code);
-
- /* Return response code */
- return code;
+ syslog(L_NOTICE, "python access method succeeded");
}
+/*
+** Initialize dynamic access control code
+*/
+
+void PY_dynamic_init (char* file) {
+ dynamic_file = malloc(strlen(file));
+ dynamic_file = COPY(file);
+ PY_use_dynamic = TRUE;
+}
/*
-** Authorize user access to a newsgroup.
+** Determine dynamic user access rights to a given newsgroup.
**
** Return 0 if requested privelege is granted or positive value
** and a reply_message pointer initialized with reply message.
-** Return negative value if authorize method is not defined.
+** Return negative value if dynamic method is not defined.
*/
-int PY_authorize(char *clientHost, char *clientIpString, char *serverHost, char *Username, char *NewsGroup, int PostFlag, char **reply_message) {
- PyObject *result, *item;
- char *string;
+int PY_dynamic(char *clientHost, char *clientIpString, char *serverHost, char *Username, char *NewsGroup, int PostFlag, char **reply_message) {
+ PyObject *result, *item, *proc;
+ char *string, *temp;
int authnum;
int i;
- /* Return if authorize_method is not defined */
- if (authorize_method == NULL)
+ PY_load_python();
+ proc = PY_setup(PYTHONdynamic, PYTHONmain, dynamic_file);
+
+ /* Return if dyanmic method is not defined */
+ if (proc == NULL) {
return -1;
+ }
/* Initialize PythonAuthObject with group method specific items */
authnum = 0;
- /* Assign authentication type */
- PYauthitem[authnum] = PyBuffer_FromMemory(PostFlag ? "post" : "read", 4);
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
-
/* Client hostname */
PYauthitem[authnum] = PyBuffer_FromMemory(clientHost, strlen(clientHost));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
/* Client IP number */
PYauthitem[authnum] = PyBuffer_FromMemory(clientIpString, strlen(clientIpString));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
/* Server interface the connection comes to */
PYauthitem[authnum] = PyBuffer_FromMemory(serverHost, strlen(serverHost));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
/* Username */
PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
/* Password is not known */
PYauthitem[authnum] = Py_None;
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
+
+ /* Assign authentication type */
+ PYauthitem[authnum] = PyBuffer_FromMemory(PostFlag ? "post" : "read", 4);
+ PyDict_SetItemString(PYauthinfo, PYTHONtype, PYauthitem[authnum++]);
/* Newsgroup user tries to access */
- PYauthitem[authnum] = PyBuffer_FromMemory(NewsGroup, strlen(NewsGroup));;
- PyDict_SetItem(PYauthinfo, PYauthkey[authnum], PYauthitem[authnum++]);
+ PYauthitem[authnum] = PyBuffer_FromMemory(NewsGroup, strlen(NewsGroup));
+ PyDict_SetItemString(PYauthinfo, PYTHONnewsgroup, PYauthitem[authnum++]);
/*
- * Now invoke newsgroup access authorization method and see if
+ * Now invoke newsgroup dynamic access method and see if
* it likes this user to access this newsgroup.
*/
- result = PyObject_CallFunction(authorize_method, "O", PYauthinfo);
+
+ result = PyObject_CallFunction(proc, "O", PYauthinfo);
/* Check the response */
if (result == NULL || result != Py_None && !PyString_Check(result))
{
- syslog(L_ERROR, "python authorize_method (%s access) returned wrong result", PostFlag ? "post" : "read");
+ syslog(L_ERROR, "python dyanmic method (%s access) returned wrong result: %s", PostFlag ? "post" : "read", result);
Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
ExitWithStats(1, FALSE);
}
/* Get the response string */
- if (result == Py_None)
+ if (result == Py_None) {
string = NULL;
- else
- string = PyString_AS_STRING(result);
+ } else {
+ temp = PyString_AS_STRING(result);
+ string = COPY(temp);
+ }
/* Clean up the dictionary object */
PyDict_Clear(PYauthinfo);
@@ -275,7 +389,7 @@
}
/* Log auth result */
- syslog(L_NOTICE, "python authorize_method (%s access) succeeded, refusion string: %s", PostFlag ? "post" : "read", string == NULL ? "<empty>" : string);
+ syslog(L_NOTICE, "python dynamic method (%s access) succeeded, refusion string: %s", PostFlag ? "post" : "read", string == NULL ? "<empty>" : string);
/* Initialize reply string */
if (reply_message != NULL)
@@ -290,14 +404,34 @@
** This runs when nnrpd shuts down.
*/
void
-PY_close(void)
+PY_close_python(void)
{
- PyObject *result;
+ hash_traverse(files, file_trav, NULL);
- if (close_method != NULL) {
- result = PyObject_CallFunction(close_method, NULL);
+ hash_free(files);
+
+ free(dynamic_file);
+}
+
+/*
+** Traversal function for PY_close_python
+*/
+void
+file_trav(void *data, void* null)
+{
+ PyFile *fp = data;
+ int j;
+ PyObject *result, *func;
+
+ for (j = 1; j < PYTHONtypes_max; j++) {
+ if (fp->loaded[j] != FALSE) {
+ func = fp->procs[j][PYTHONclose];
+ if (func != NULL) {
+ result = PyObject_CallFunction(func, NULL);
Py_XDECREF(result);
+ }
}
+ }
}
@@ -374,17 +508,63 @@
return result;
}
+/*
+** Load the Python interpreter
+*/
+
+void PY_load_python() {
+ int i, authnum;
+
+ if (!PythonLoaded) {
+ /* add path for nnrpd module */
+ setenv("PYTHONPATH", innconf->pathfilter, 1);
+
+ /* Load up the interpreter ;-O */
+ Py_Initialize();
+
+ /* It makes Python sad when its stdout and stderr are closed. */
+ if (feof(stdout) || feof(stderr))
+ PyRun_SimpleString
+ ("import sys; sys.stdout=sys.stderr=open('/dev/null', 'a')");
+
+ /* See if Python initialized OK */
+ if (!Py_IsInitialized ()) {
+ syslog(L_ERROR, "python interpreter NOT initialized");
+ return;
+ }
+
+
+ /* Build a module interface to certain nnrpd functions */
+ (void) Py_InitModule("nnrpd", nnrpdPyMethods);
+
+ /*
+ ** Grab space for authinfo dictionary so we aren't forever
+ ** recreating them.
+ */
+ PYauthinfo = PyDict_New();
+ PYauthitem = NEW(PyObject *, _PY_MAX_AUTH_ITEM);
+
+ /* create hash to store file attributes */
+
+ files = hash_create(4, hash_string, file_key,
+ file_equal, file_free);
+
+ PythonLoaded = TRUE;
+
+ syslog(L_NOTICE, "python interpreter initialized OK");
+ }
+}
/*
** Check that a method exists and is callable. Set up a pointer to
** the corresponding PyObject, or NULL if not found.
*/
void
-PYdefonemethod(methptr, methname)
- PyObject **methptr;
- char *methname;
+PYdefonemethod(PyFile *fp, int type, int method, char *methname)
{
- Py_XDECREF(*methptr);
+ PyObject **methptr;
+
+ methptr = &fp->procs[type][method];
/* Get a pointer to given method */
*methptr = PyObject_GetAttrString(PYAuthObject, methname);
@@ -404,82 +584,133 @@
/*
-** Look up all the known authentication/authorization methods and set up
+** Look up all the known python methods and set up
** pointers to them so that we could call them from nnrpd.
*/
void
-PYdefmethods(void)
+PYdefmethods(PyFile *fp)
{
/* Get a reference to authenticate() method */
- PYdefonemethod(&authenticate_method, "authenticate");
+ PYdefonemethod(fp, PYTHONauthen, PYTHONmain, "authenticate");
- /* Get a reference to authorize() method */
- PYdefonemethod(&authorize_method, "authorize");
+ /* Get a reference to authen_init() method */
+ PYdefonemethod(fp, PYTHONauthen, PYTHONinit, "authen_init");
+
+ /* Get a reference to authen_close() method */
+ PYdefonemethod(fp, PYTHONauthen, PYTHONclose, "authen_close");
- /* Get a reference to close() method */
- PYdefonemethod(&close_method, "close");
-}
+ /* Get a reference to access() method */
+ PYdefonemethod(fp, PYTHONaccess, PYTHONmain, "access");
+
+ /* Get a reference to access_init() method */
+ PYdefonemethod(fp, PYTHONaccess, PYTHONinit, "access_init");
+
+ /* Get a reference to access_close() method */
+ PYdefonemethod(fp, PYTHONaccess, PYTHONclose, "access_close");
+
+ /* Get a reference to dynamic() method */
+ PYdefonemethod(fp, PYTHONdynamic, PYTHONmain, "dynamic");
+
+ /* Get a reference to dynamic_init() method */
+ PYdefonemethod(fp, PYTHONdynamic, PYTHONinit, "dynamic_init");
+
+ /* Get a reference to dynamic_close() method */
+ PYdefonemethod(fp, PYTHONdynamic, PYTHONclose, "dynamic_close");
+}
/*
-** Called when nnrpd starts -- this gets the scripts hooked in.
+** Called when a python hook is needed -- this gets the scripts hooked in.
*/
-void
-PY_setup(void)
+PyObject*
+PY_setup(int type, int method, char *file)
{
- int authnum;
+ int i;
+ PyFile *fp;
+ char *temp;
+ PyObject *result;
- /* Export $PYTHONPATH to let Python find the scripts */
- setenv("PYTHONPATH", innconf->pathfilter, 1);
+ /* check to see if this file is in files */
+ if (!(fp = hash_lookup(files, file))) {
+ fp = malloc(sizeof(PyFile));
- /* Load up the interpreter ;-O */
- Py_Initialize();
+ fp->file = malloc(strlen(file));
+ fp->file = COPY(file);
- /* It makes Python sad when its stdout and stderr are closed. */
- if (feof(stdout) || feof(stderr))
- PyRun_SimpleString
- ("import sys; sys.stdout=sys.stderr=open('/dev/null', 'a')");
-
- /* See it Python initialized OK */
- if (!Py_IsInitialized ()) {
- syslog(L_ERROR, "python interpreter NOT initialized");
- return;
+ for (i = 1; i < PYTHONtypes_max; i++) {
+ fp->loaded[i] = FALSE;
}
- syslog(L_NOTICE, "python interpreter initialized OK");
-
- /* Build a module interface to certain nnrpd functions */
- (void) Py_InitModule("nnrpd", nnrpdPyMethods);
- /* Load up external nntpd auth module */
- PYAuthModule = PyImport_ImportModule(_PATH_PYTHON_AUTH_M);
- if (PYAuthModule == NULL)
- syslog(L_ERROR, "failed to import external python module");
+ /* Load up external module */
+ (void) PyImport_ImportModule(file);
/* See if nnrpd auth object is defined in auth module */
- if (PYAuthObject == NULL)
+ if (PYAuthObject == NULL) {
syslog(L_ERROR, "python auth object is not defined");
- else {
+ Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
+ PY_close_python();
+ ExitWithStats(1, FALSE);
+ } else {
/* Set up pointers to known Python methods */
- PYdefmethods();
- syslog(L_NOTICE, "some python methods defined. good.");
+ PYdefmethods(fp);
+ }
+ hash_insert(files, file, fp);
}
- /*
- ** Grab space for authinfo dictionary so we aren't forever
- ** recreating them.
- */
- PYauthinfo = PyDict_New();
- PYauthitem = NEW(PyObject *, _PY_MAX_AUTH_ITEM);
- PYauthkey = NEW(PyObject *, _PY_MAX_AUTH_ITEM);
+ if ((!fp->loaded[type]) && (fp->procs[type][PYTHONinit] != NULL)) {
+ result = PyObject_CallFunction(fp->procs[type][PYTHONinit], NULL);
+ if (result != NULL) {
+ Py_XDECREF(result);
+ }
+ fp->loaded[type] = TRUE;
+ }
+ return fp->procs[type][method];
+}
- /* Preallocate keys for the authinfo dictionary (up to PY_MAX_AUTH_ITEM) */
- authnum = 0;
- PYauthkey[authnum++] = PyString_InternFromString("type");
- PYauthkey[authnum++] = PyString_InternFromString("hostname");
- PYauthkey[authnum++] = PyString_InternFromString("ipaddress");
- PYauthkey[authnum++] = PyString_InternFromString("interface");
- PYauthkey[authnum++] = PyString_InternFromString("user");
- PYauthkey[authnum++] = PyString_InternFromString("pass");
- PYauthkey[authnum++] = PyString_InternFromString("newsgroup");
+/*
+** Return the key (filename) from a file struct, used by the hash table.
+*/
+static const void *
+file_key(const void *p)
+{
+ const struct PyFile *f = p;
+
+ return f->file;
}
+
+/*
+** Check to see if a provided key matches the key of a PyFile struct,
+** used by the hash table.
+*/
+static bool
+file_equal(const void *k, const void *p)
+{
+ const char *key = k;
+ const struct PyFile *f = p;
+
+ return EQ(key, f->file);
+}
+
+/*
+** Free a file, used by the hash table.
+*/
+static void
+file_free(void *p)
+{
+ struct PyFile *fp = p;
+ int i, j;
+
+ free(fp->file);
+
+ for (i = 1; i < PYTHONtypes_max; i++) {
+ for (j = 1; j < PYTHONmethods_max; j++) {
+ if (fp->procs[i][j] != NULL) {
+ Py_DECREF(fp->procs[i][j]);
+ }
+ }
+ }
+
+ free(fp);
+}
+
#endif /* defined(DO_PYTHON) */
More information about the inn-patches
mailing list