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

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

Client-side authentication handling is implemented but currently broken.
I'm still working out what's wrong.

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