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

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

Python code can read an authorisation message from the client.

Test cases confirm message passing client->server->python is working.

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#include <Python.h>
13
14extern char **environ;
15/*
16 * variables and prototypes from bbftpd source
17 */
18
19extern int be_daemon;
20extern int newcontrolport;
21
22int bbftpd_main(int argc, char **argv, char **envp);
23int bbftpd_private_send(char *buffertosend, int buffertosendlength, char *logmessage) ;
24int bbftpd_private_recv(char *buffertorecv, int lengthtorecv, char *logmessage) ;
25
26/*
27 * Static variables.
28 */
29static PyObject *authContext = NULL;
30static PyObject *authzContext = NULL;
31
32/*---------------------------------------------------------------------------------------------------
33 * The following functions interact with bbftpd_private_user.  They are placed here to separate
34 * python and bbftp APIs.
35 *
36 */
37
38/**
39 * Make a callback bbftpd->python to handle authentication.
40 *
41 * @param[out] logmessage filled with an error message on failure
42 * @return 0 on success, -1 on failure
43 */
44int bbftpd_private_auth_callback(char *logmessage) {
45
46  if (authzContext != NULL) {
47    sprintf(logmessage, "bbftpd_private_auth_callback: authzContext already present");
48    return -1;
49  }
50 
51  if (authContext == NULL) {
52    sprintf(logmessage, "bbftpd_private_auth_callback: no authContext set");
53    return -1;
54  }
55
56  if ((authzContext = PyObject_CallMethod(authContext, "authorise", "")) == NULL) {
57    //!TODO: should probably read the exception object to fill logmessage.
58    sprintf(logmessage, "bbftpd_private_auth_callback: authContext.authorise() failed");
59    return -1;
60  }
61
62  /* If authContext.authorise() returned None then authorisation failed.  */
63  if (authzContext == Py_None) {
64    sprintf(logmessage, "bbftpd_private_auth_callback: python authorisation failed");
65    return -1;
66  }
67
68  return 0;
69}
70
71/**
72 * retrieve the username from authzContext.
73 *
74 * @param[out] logmessage filled with an error message on failure
75 * @return pointer to the username or NULL on failure
76 */
77char *bbftpd_private_auth_getusername(char *logmessage) {
78  char *username;
79  PyObject *str_obj;
80
81  if (authzContext == NULL) {
82    sprintf(logmessage, "bbftpd_private_auth_getusername: no authzContext set");
83    return NULL;
84  }
85
86  if ((str_obj = PyObject_GetAttrString(authzContext, "username")) == NULL) {
87    sprintf(logmessage, "bbftpd_private_auth_getusername: authzContext.username lookup failed");
88    return NULL;
89  }
90
91  if ((username = PyString_AsString(str_obj)) == NULL) {
92    Py_DECREF(str_obj);
93    sprintf(logmessage, "bbftpd_private_auth_getusername: authzContext.username not a string");
94    return NULL;
95  }
96
97  return username;
98}
99     
100/*-------------------------------------------------------------------------------------------------
101 * Functions exported to python
102 *
103 */
104
105/* send(string) */
106static PyObject *bbftpd_send(PyObject *self, PyObject *args) {
107  char *buffer, logmessage[1024];
108  int len;
109
110  if (!PyArg_ParseTuple(args, "s#", &buffer, &len)) {
111    return NULL;
112  }
113
114  if (authContext == NULL) {
115    PyErr_SetString(PyExc_RuntimeError, "Must be called within a bbftpd callback");
116    return NULL;
117  }
118
119  if (bbftpd_private_send(buffer, len, logmessage) == -1) {
120    PyErr_SetString(PyExc_IOError, logmessage);
121    return NULL;
122  }
123
124  Py_RETURN_NONE;
125}
126
127/* recv(length) -> string */
128static PyObject *bbftpd_recv(PyObject *self, PyObject *args) {
129  char *buffer, logmessage[1024];
130  int len;
131
132  if (!PyArg_ParseTuple(args, "i", &len)) {
133    return NULL;
134  }
135
136  if (authContext == NULL) {
137    PyErr_SetString(PyExc_RuntimeError, "Must be called within a bbftpd callback");
138    return NULL;
139  }
140  if ((buffer = (char*)malloc(len*sizeof(char))) == NULL) {
141    PyErr_NoMemory();
142    return NULL;
143  }
144
145  if (bbftpd_private_recv(buffer, len, logmessage) == -1) {
146    PyErr_SetString(PyExc_IOError, logmessage);
147    free(buffer);
148    return NULL;
149  }
150
151  return Py_BuildValue("s#", buffer, len);
152}
153
154
155/**
156 * Main entry point for the python module.
157 */
158static PyObject *bbftpd_run(PyObject *self, PyObject *args) {
159  int argc, i;
160  char **argv, **arg_p;
161  int pid;
162  char preargs[2][20] = { "bbftpd_embedded", "-b" };
163  PyObject *daemon_args, *item;
164
165  if (!PyArg_ParseTuple(args, "OO", &authContext, &daemon_args)) {
166    return NULL;
167  }
168  Py_INCREF(authContext);
169  Py_INCREF(daemon_args);
170
171  /*
172   * Convert arguments into a standard argv sequence.
173   */
174  argc = PySequence_Size(daemon_args);
175  if ((argv = (char**)malloc((argc + 2)*sizeof(char*))) == NULL) {
176    PyErr_SetString(PyExc_MemoryError, "malloc failed");
177    Py_DECREF(daemon_args);
178    return NULL;
179  }
180
181  // Add fixed arguments to daemon's argv
182  arg_p = argv;
183  *arg_p = preargs[0]; arg_p++;
184  *arg_p = preargs[1]; arg_p++;
185
186  for (i=0; i<argc; i++) {
187    if ((item = PySequence_GetItem(daemon_args, i)) == NULL) {
188      Py_DECREF(authContext);
189      Py_DECREF(daemon_args);
190      return NULL;
191    }
192    if ((*arg_p = PyString_AsString(item)) == NULL) {
193      free(argv);
194      Py_DECREF(item);
195      Py_DECREF(authContext);
196      Py_DECREF(daemon_args);
197      return NULL;
198    }
199    arg_p++;
200    Py_DECREF(item);
201  }
202
203  /*
204   * We must reset some global variables so that bbftpd_run can be executed multiple times.
205   */
206  be_daemon = 0;
207
208  pid = bbftpd_main(argc+2, argv, environ);
209
210  free(argv);
211  Py_DECREF(authContext); authContext = NULL;
212  Py_DECREF(daemon_args);
213
214  return Py_BuildValue("i", pid);
215}
216
217static PyMethodDef BbftpdMethods[] = {
218  {
219    "run", bbftpd_run, METH_VARARGS, 
220    "Execute the bbftpd server.\n"
221    "\n"
222    "Forks an embedded bbftpd process as if it were executed\n"
223    "with the command line $ bbftpd -b <args>."
224    "\n"
225    "@param args: command line arguments to pass to the server\n"
226    "@return: the PID of the server process\n"
227  },
228  {
229    "send", bbftpd_send, METH_VARARGS,
230    "Send an authentication message to the client.\n"
231    "\n"
232    "Equivilent to bbftpd_private_send() C call.\n"
233    "\n"
234    "@param buffer: A string containing the message\n"
235    "@raise IOError: if bbftpd_private_send() call fails\n"
236  },
237  {
238    "recv", bbftpd_recv, METH_VARARGS,
239    "Receive an authentication message from the client.\n"
240    "\n"
241    "Equivilent to bbftpd_private_recv() C call.\n"
242    "\n"
243    "@param len: The length of message to expect\n"
244    "@return: A string containing the message\n"
245    "@raise IOError: if bbftpd_private_recv() call fails\n"
246  },
247  {NULL, NULL, 0, NULL}
248};
249
250PyMODINIT_FUNC initbbftpd(void) {
251  (void) Py_InitModule("bbftpd", BbftpdMethods);
252}
253
Note: See TracBrowser for help on using the repository browser.