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

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

Changed the interface to authentication context objects. Now call the object
rather than invoke the method authorise() to start a session.

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[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_CallObject(authContext, NULL)) == 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 (ndg_message_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  PyObject *ret;
132
133  if (!PyArg_ParseTuple(args, "")) {
134    return NULL;
135  }
136
137  if (authContext == NULL) {
138    PyErr_SetString(PyExc_RuntimeError, "Must be called within a bbftpd callback");
139    return NULL;
140  }
141
142  if (ndg_message_recv(&buffer, &len, logmessage) == -1) {
143    PyErr_SetString(PyExc_IOError, logmessage);
144    free(buffer);
145    return NULL;
146  }
147
148  ret = Py_BuildValue("s#", buffer, len);
149  free(buffer);
150  return ret;
151}
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.