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

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

Renamed some internal functions binding python to the server.

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