source: TI05-delivery/trunk/src/python_ext/bbftpd.c @ 1332

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/trunk/src/python_ext/bbftpd.c@1332
Revision 1332, 9.5 KB checked in by spascoe, 13 years ago (diff)

Added an API hook to use bbftpd_log to log messages from python code.

Line 
1/**
2 * NDG python embedded bbftp daemon module.
3 *
4 * @author Stephen Pascoe
5 *
6 * Copyright (C) 2006 CCLRC & NERC
7 *
8 * This software may be distributed under the terms of the Q Public Licence, version 1.0 or later.
9 *
10 */
11
12
13#include <Python.h>
14#include <ndg.h>
15#include "util.h"
16#include <structures.h>
17#include <bbftpd_log.h>
18
19extern char **environ;
20/*
21 * variables and prototypes from bbftpd source
22 */
23
24extern int be_daemon;
25extern int newcontrolport;
26
27int bbftpd_main(int argc, char **argv, char **envp);
28int ndg_message_send(char *buffer, int buffertosendlength, char *logmessage) ;
29int ndg_message_recv(char **buffer, int *length, char *logmessage) ;
30
31/*
32 * Static variables.
33 */
34static PyObject *authHandler = NULL;
35static PyObject *authzHandler = NULL;
36
37/*---------------------------------------------------------------------------------------------------
38 * The following functions interact with bbftpd_private_user.  They are placed here to separate
39 * python and bbftp APIs.
40 *
41 */
42
43
44/**
45 * Make a callback bbftpd->python to handle authentication.
46 *
47 * @param logmessage a pointer to a buffer of length \c NDG_MAX_LOGMESSAGE
48 *     for storing an error message when returning -1.
49 * @return 0 on success, -1 on failure
50 */
51int ndg_auth(char *logmessage) {
52
53  if (authzHandler != NULL) {
54    sprintf(logmessage, "ndg_auth: authzHandler already present");
55    return -1;
56  }
57 
58  if (authHandler == NULL) {
59    sprintf(logmessage, "ndg_auth: no authHandler set");
60    return -1;
61  }
62
63  /** @todo exceptions of type delivery.server.AuthenticationFailure should be logged as
64   *      failure rather than error.
65   */
66  if ((authzHandler = PyObject_CallMethod(authHandler, "authenticate", "")) == NULL) {
67    ndg_pyerr_to_logmessage(logmessage, "ndg_auth");
68    return -1;
69  }
70
71  /* Authorisation is considered failed if the return value isn't True.  */
72  if (!PyObject_IsTrue(authzHandler)) {
73    sprintf(logmessage, "ndg_auth: python authentication failed");
74    return -1;
75  }
76
77  return 0;
78}
79
80/**
81 * retrieve the username from authzHandler.
82 *
83 * @param logmessage a pointer to a buffer of length \c NDG_MAX_LOGMESSAGE
84 *     for storing an error message when returning NULL.
85 * @return pointer to the username or NULL on failure
86 */
87char *ndg_getusername(char *logmessage) {
88  char *username;
89  PyObject *str_obj;
90
91  if (authzHandler == NULL) {
92    sprintf(logmessage, "bbftpd_private_auth_getusername: no authzHandler set");
93    return NULL;
94  }
95
96  if ((str_obj = PyObject_GetAttrString(authzHandler, "username")) == NULL) {
97    ndg_pyerr_to_logmessage(logmessage, "ndg_getusername");
98    return NULL;
99  }
100
101  if ((username = PyString_AsString(str_obj)) == NULL) {
102    ndg_pyerr_to_logmessage(logmessage, "ndg_getusername");
103    Py_DECREF(str_obj);
104    return NULL;
105  }
106
107  return username;
108}
109
110
111/**
112 * Make a callback to do authorisation of a control command.
113 *
114 * @see bbftpd_private_authz_control()
115 */
116int ndg_authz_control(int msgcode, int transferoption, char *path, char *logmessage) {
117  PyObject *ret_obj;
118
119  if (authzHandler == NULL) {
120    sprintf(logmessage, "ndg_authz_control: no authzHandler set");
121    return -1;
122  }
123 
124  if ((ret_obj = PyObject_CallMethod(authzHandler, "authzControl", "iis", msgcode, transferoption, path)) == NULL) {
125    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_control");
126    return -1;
127  }
128 
129  /* Authorisation fails if ret_obj is false. */
130  if (!PyObject_IsTrue(ret_obj)) {
131    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_control");
132    Py_DECREF(ret_obj);
133    return -1;
134  }
135
136  return 0;
137}
138
139/**
140 * Make a callback to do authorisation of a retr command.
141 *
142 * @see bbftpd_private_authz_retr()
143 */
144int ndg_authz_retr(char *path, char *logmessage) {
145  PyObject *ret_obj;
146
147  if (authzHandler == NULL) {
148    sprintf(logmessage, "ndg_authz_retr: no authzHandler set");
149    return -1;
150  }
151 
152  if ((ret_obj = PyObject_CallMethod(authzHandler, "authzRetr", "s", path)) == NULL) {
153    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_retr");
154    return -1;
155  }
156 
157  /* Authorisation fails if ret_obj is false. */
158  if (!PyObject_IsTrue(ret_obj)) {
159    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_retr");
160    Py_DECREF(ret_obj);
161    return -1;
162  }
163
164  return 0;
165}
166
167
168/**
169 * Make a callback to do authorisation of a store command.
170 *
171 * @see bbftpd_private_authz_store()
172 */
173int ndg_authz_store(char *path, char *logmessage) {
174  PyObject *ret_obj;
175
176  if (authzHandler == NULL) {
177    sprintf(logmessage, "ndg_authz_store: no authzHandler set");
178    return -1;
179  }
180 
181  if ((ret_obj = PyObject_CallMethod(authzHandler, "authzStore", "s", path)) == NULL) {
182    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_store");
183    return -1;
184  }
185 
186  /* Authorisation fails if ret_obj is false. */
187  if (!PyObject_IsTrue(ret_obj)) {
188    ndg_pyerr_to_logmessage(logmessage, "ndg_authz_store");
189    Py_DECREF(ret_obj);
190    return -1;
191  }
192
193  return 0;
194}
195 
196
197     
198/*-------------------------------------------------------------------------------------------------
199 * Functions exported to python
200 *
201 */
202
203/* log message to bbftpd logger */
204static PyObject *pybbftpd_log(PyObject *self, PyObject *args) {
205  int priority;
206  char *message;
207
208  if (!PyArg_ParseTuple(args, "is", &priority, &message)) {
209    return NULL;
210  }
211
212  bbftpd_log(priority, message);
213
214  Py_RETURN_NONE;
215}
216
217/* send(string) */
218static PyObject *pybbftpd_send(PyObject *self, PyObject *args) {
219  char *buffer, logmessage[1024];
220  int len;
221
222  if (!PyArg_ParseTuple(args, "s#", &buffer, &len)) {
223    return NULL;
224  }
225
226  if (authHandler == NULL) {
227    PyErr_SetString(PyExc_RuntimeError, "Must be called within a bbftpd callback");
228    return NULL;
229  }
230
231  if (ndg_message_send(buffer, len, logmessage) == -1) {
232    PyErr_SetString(PyExc_IOError, logmessage);
233    return NULL;
234  }
235
236  Py_RETURN_NONE;
237}
238
239/* recv(length) -> string */
240static PyObject *pybbftpd_recv(PyObject *self, PyObject *args) {
241  char *buffer, logmessage[1024];
242  int len;
243  PyObject *ret;
244
245  if (!PyArg_ParseTuple(args, "")) {
246    return NULL;
247  }
248
249  if (authHandler == NULL) {
250    PyErr_SetString(PyExc_RuntimeError, "Must be called within a bbftpd callback");
251    return NULL;
252  }
253
254  if (ndg_message_recv(&buffer, &len, logmessage) == -1) {
255    PyErr_SetString(PyExc_IOError, logmessage);
256    free(buffer);
257    return NULL;
258  }
259
260  ret = Py_BuildValue("s#", buffer, len);
261  free(buffer);
262  return ret;
263}
264
265
266
267/**
268 * Main entry point for the python module.
269 */
270static PyObject *pybbftpd_run(PyObject *self, PyObject *args) {
271  int argc, i;
272  char **argv, **arg_p;
273  int pid;
274  char preargs[2][20] = { "bbftpd_embedded", "-b" };
275  PyObject *daemon_args, *item;
276
277  if (!PyArg_ParseTuple(args, "OO", &authHandler, &daemon_args)) {
278    return NULL;
279  }
280  Py_INCREF(authHandler);
281  Py_INCREF(daemon_args);
282
283  /*
284   * Convert arguments into a standard argv sequence.
285   */
286  argc = PySequence_Size(daemon_args);
287  if ((argv = (char**)malloc((argc + 2)*sizeof(char*))) == NULL) {
288    PyErr_SetString(PyExc_MemoryError, "malloc failed");
289    Py_DECREF(daemon_args);
290    return NULL;
291  }
292
293  // Add fixed arguments to daemon's argv
294  arg_p = argv;
295  *arg_p = preargs[0]; arg_p++;
296  *arg_p = preargs[1]; arg_p++;
297
298  for (i=0; i<argc; i++) {
299    if ((item = PySequence_GetItem(daemon_args, i)) == NULL) {
300      free(argv);
301      Py_DECREF(authHandler);
302      Py_DECREF(daemon_args);
303      return NULL;
304    }
305    if ((*arg_p = PyString_AsString(item)) == NULL) {
306      free(argv);
307      Py_DECREF(item);
308      Py_DECREF(authHandler);
309      Py_DECREF(daemon_args);
310      return NULL;
311    }
312    arg_p++;
313    Py_DECREF(item);
314  }
315
316  /*
317   * We must reset some global variables so that bbftpd_run can be executed multiple times.
318   */
319  be_daemon = 0;
320
321  pid = bbftpd_main(argc+2, argv, environ);
322
323  free(argv);
324  Py_DECREF(authHandler); authHandler = NULL;
325  Py_DECREF(daemon_args);
326
327  return Py_BuildValue("i", pid);
328}
329
330static PyMethodDef BbftpdMethods[] = {
331  {
332    "run", pybbftpd_run, METH_VARARGS, 
333    "Execute the bbftpd server.\n"
334    "\n"
335    "Forks an embedded bbftpd process as if it were executed\n"
336    "with the command line $ bbftpd -b <args>."
337    "\n"
338    "@param args: command line arguments to pass to the server\n"
339    "@return: the PID of the server process\n"
340  },
341  {
342    "send", pybbftpd_send, METH_VARARGS,
343    "Send an authentication message to the client.\n"
344    "\n"
345    "Equivilent to bbftpd_private_send() C call.\n"
346    "\n"
347    "@param buffer: A string containing the message\n"
348    "@raise IOError: if bbftpd_private_send() call fails\n"
349  },
350  {
351    "recv", pybbftpd_recv, METH_VARARGS,
352    "Receive an authentication message from the client.\n"
353    "\n"
354    "Equivilent to bbftpd_private_recv() C call.\n"
355    "\n"
356    "@param len: The length of message to expect\n"
357    "@return: A string containing the message\n"
358    "@raise IOError: if bbftpd_private_recv() call fails\n"
359  },
360  {
361    "log", pybbftpd_log, METH_VARARGS,
362    "Send a message to the bbftpd logger.\n"
363    "\n"
364    "@param priority: as syslog priority\n"
365    "@param message: A string containing the message to send\n"
366  },
367  {NULL, NULL, 0, NULL}
368};
369
370
371#define ADDCONST(m,x) PyModule_AddIntConstant(m, #x, x)
372
373PyMODINIT_FUNC initbbftpd(void) {
374  PyObject *mod;
375
376  mod = Py_InitModule("bbftpd", BbftpdMethods);
377
378  ADDCONST(mod, MSG_CHDIR_V2);
379  ADDCONST(mod, MSG_CHDIR_V2);
380  ADDCONST(mod, MSG_LIST_V2);
381  ADDCONST(mod, MSG_MKDIR_V2);
382  ADDCONST(mod, MSG_RM);
383  ADDCONST(mod, MSG_STAT);
384  ADDCONST(mod, MSG_DF);
385 
386  ADDCONST(mod, TROPT_TMP);
387  ADDCONST(mod, TROPT_ACC);
388  ADDCONST(mod, TROPT_MODE);
389  ADDCONST(mod, TROPT_DIR);
390  ADDCONST(mod, TROPT_GZIP);
391  ADDCONST(mod, TROPT_RFIO);
392  ADDCONST(mod, TROPT_RFIO_O);
393  ADDCONST(mod, TROPT_QBSS);
394 
395}
396
Note: See TracBrowser for help on using the repository browser.