1 /* A multi-threaded telnet-like server that gives a Python prompt.
2
3 Usage: pysvr [port]
4
5 For security reasons, it only accepts requests from the current host.
6 This can still be insecure, but restricts violations from people who
7 can log in on your machine. Use with caution!
8
9 */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <errno.h>
16
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20
21 #include <pthread.h>
22 #include <getopt.h>
23
24 /* XXX Umpfh.
25 Python.h defines a typedef destructor, which conflicts with pthread.h.
26 So Python.h must be included after pthread.h. */
27
28 #include "Python.h"
29
30 extern int Py_VerboseFlag;
31
32 #ifndef PORT
33 #define PORT 4000
34 #endif
35
36 struct workorder {
37 int conn;
38 struct sockaddr_in addr;
39 };
40
41 /* Forward */
42 static void init_python(void);
43 static void usage(void);
44 static void oprogname(void);
45 static void main_thread(int);
46 static void create_thread(int, struct sockaddr_in *);
47 static void *service_thread(struct workorder *);
48 static void run_interpreter(FILE *, FILE *);
49 static int run_command(char *, PyObject *);
50 static void ps(void);
51
52 static char *progname = "pysvr";
53
54 static PyThreadState *gtstate;
55
main(int argc,char ** argv)56 main(int argc, char **argv)
57 {
58 int port = PORT;
59 int c;
60
61 if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
62 progname = argv[0];
63
64 while ((c = getopt(argc, argv, "v")) != EOF) {
65 switch (c) {
66 case 'v':
67 Py_VerboseFlag++;
68 break;
69 default:
70 usage();
71 }
72 }
73
74 if (optind < argc) {
75 if (optind+1 < argc) {
76 oprogname();
77 fprintf(stderr, "too many arguments\n");
78 usage();
79 }
80 port = atoi(argv[optind]);
81 if (port <= 0) {
82 fprintf(stderr, "bad port (%s)\n", argv[optind]);
83 usage();
84 }
85 }
86
87 main_thread(port);
88
89 fprintf(stderr, "Bye.\n");
90
91 exit(0);
92 }
93
94 static char usage_line[] = "usage: %s [port]\n";
95
96 static void
usage(void)97 usage(void)
98 {
99 fprintf(stderr, usage_line, progname);
100 exit(2);
101 }
102
103 static void
main_thread(int port)104 main_thread(int port)
105 {
106 int sock, conn, size, i;
107 struct sockaddr_in addr, clientaddr;
108
109 sock = socket(PF_INET, SOCK_STREAM, 0);
110 if (sock < 0) {
111 oprogname();
112 perror("can't create socket");
113 exit(1);
114 }
115
116 #ifdef SO_REUSEADDR
117 i = 1;
118 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof i);
119 #endif
120
121 memset((char *)&addr, '\0', sizeof addr);
122 addr.sin_family = AF_INET;
123 addr.sin_port = htons(port);
124 addr.sin_addr.s_addr = 0L;
125 if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
126 oprogname();
127 perror("can't bind socket to address");
128 exit(1);
129 }
130
131 if (listen(sock, 5) < 0) {
132 oprogname();
133 perror("can't listen on socket");
134 exit(1);
135 }
136
137 fprintf(stderr, "Listening on port %d...\n", port);
138
139 for (i = 0; ; i++) {
140 size = sizeof clientaddr;
141 memset((char *) &clientaddr, '\0', size);
142 conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
143 if (conn < 0) {
144 oprogname();
145 perror("can't accept connection from socket");
146 exit(1);
147 }
148
149 size = sizeof addr;
150 memset((char *) &addr, '\0', size);
151 if (getsockname(conn, (struct sockaddr *)&addr, &size) < 0) {
152 oprogname();
153 perror("can't get socket name of connection");
154 exit(1);
155 }
156 if (clientaddr.sin_addr.s_addr != addr.sin_addr.s_addr) {
157 oprogname();
158 perror("connection from non-local host refused");
159 fprintf(stderr, "(addr=%lx, clientaddr=%lx)\n",
160 ntohl(addr.sin_addr.s_addr),
161 ntohl(clientaddr.sin_addr.s_addr));
162 close(conn);
163 continue;
164 }
165 if (i == 4) {
166 close(conn);
167 break;
168 }
169 create_thread(conn, &clientaddr);
170 }
171
172 close(sock);
173
174 if (gtstate) {
175 PyEval_AcquireThread(gtstate);
176 gtstate = NULL;
177 Py_Finalize();
178 /* And a second time, just because we can. */
179 Py_Finalize(); /* This should be harmless. */
180 }
181 exit(0);
182 }
183
184 static void
create_thread(int conn,struct sockaddr_in * addr)185 create_thread(int conn, struct sockaddr_in *addr)
186 {
187 struct workorder *work;
188 pthread_t tdata;
189
190 work = malloc(sizeof(struct workorder));
191 if (work == NULL) {
192 oprogname();
193 fprintf(stderr, "out of memory for thread.\n");
194 close(conn);
195 return;
196 }
197 work->conn = conn;
198 work->addr = *addr;
199
200 init_python();
201
202 if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
203 oprogname();
204 perror("can't create new thread");
205 close(conn);
206 return;
207 }
208
209 if (pthread_detach(tdata) < 0) {
210 oprogname();
211 perror("can't detach from thread");
212 }
213 }
214
215 static PyThreadState *the_tstate;
216 static PyInterpreterState *the_interp;
217 static PyObject *the_builtins;
218
219 static void
init_python(void)220 init_python(void)
221 {
222 if (gtstate)
223 return;
224 Py_Initialize(); /* Initialize the interpreter */
225 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
226 gtstate = PyEval_SaveThread(); /* Release the thread state */
227 }
228
229 static void *
service_thread(struct workorder * work)230 service_thread(struct workorder *work)
231 {
232 FILE *input, *output;
233
234 fprintf(stderr, "Start thread for connection %d.\n", work->conn);
235
236 ps();
237
238 input = fdopen(work->conn, "r");
239 if (input == NULL) {
240 oprogname();
241 perror("can't create input stream");
242 goto done;
243 }
244
245 output = fdopen(work->conn, "w");
246 if (output == NULL) {
247 oprogname();
248 perror("can't create output stream");
249 fclose(input);
250 goto done;
251 }
252
253 setvbuf(input, NULL, _IONBF, 0);
254 setvbuf(output, NULL, _IONBF, 0);
255
256 run_interpreter(input, output);
257
258 fclose(input);
259 fclose(output);
260
261 done:
262 fprintf(stderr, "End thread for connection %d.\n", work->conn);
263 close(work->conn);
264 free(work);
265 }
266
267 static void
oprogname(void)268 oprogname(void)
269 {
270 int save = errno;
271 fprintf(stderr, "%s: ", progname);
272 errno = save;
273 }
274
275 static void
run_interpreter(FILE * input,FILE * output)276 run_interpreter(FILE *input, FILE *output)
277 {
278 PyThreadState *tstate;
279 PyObject *new_stdin, *new_stdout;
280 PyObject *mainmod, *globals;
281 char buffer[1000];
282 char *p, *q;
283 int n, end;
284
285 PyEval_AcquireLock();
286 tstate = Py_NewInterpreter();
287 if (tstate == NULL) {
288 fprintf(output, "Sorry -- can't create an interpreter\n");
289 return;
290 }
291
292 mainmod = PyImport_AddModule("__main__");
293 globals = PyModule_GetDict(mainmod);
294 Py_INCREF(globals);
295
296 new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
297 new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
298
299 PySys_SetObject("stdin", new_stdin);
300 PySys_SetObject("stdout", new_stdout);
301 PySys_SetObject("stderr", new_stdout);
302
303 for (n = 1; !PyErr_Occurred(); n++) {
304 Py_BEGIN_ALLOW_THREADS
305 fprintf(output, "%d> ", n);
306 p = fgets(buffer, sizeof buffer, input);
307 Py_END_ALLOW_THREADS
308
309 if (p == NULL)
310 break;
311 if (p[0] == '\377' && p[1] == '\354')
312 break;
313
314 q = strrchr(p, '\r');
315 if (q && q[1] == '\n' && q[2] == '\0') {
316 *q++ = '\n';
317 *q++ = '\0';
318 }
319
320 while (*p && isspace(*p))
321 p++;
322 if (p[0] == '#' || p[0] == '\0')
323 continue;
324
325 end = run_command(buffer, globals);
326 if (end < 0)
327 PyErr_Print();
328
329 if (end)
330 break;
331 }
332
333 Py_XDECREF(globals);
334 Py_XDECREF(new_stdin);
335 Py_XDECREF(new_stdout);
336
337 Py_EndInterpreter(tstate);
338 PyEval_ReleaseLock();
339
340 fprintf(output, "Goodbye!\n");
341 }
342
343 static int
run_command(char * buffer,PyObject * globals)344 run_command(char *buffer, PyObject *globals)
345 {
346 PyObject *m, *d, *v;
347 fprintf(stderr, "run_command: %s", buffer);
348 if (strchr(buffer, '\n') == NULL)
349 fprintf(stderr, "\n");
350 v = PyRun_String(buffer, Py_single_input, globals, globals);
351 if (v == NULL) {
352 if (PyErr_Occurred() == PyExc_SystemExit) {
353 PyErr_Clear();
354 return 1;
355 }
356 PyErr_Print();
357 return 0;
358 }
359 Py_DECREF(v);
360 return 0;
361 }
362
363 static void
ps(void)364 ps(void)
365 {
366 char buffer[100];
367 PyOS_snprintf(buffer, sizeof(buffer),
368 "ps -l -p %d </dev/null | sed 1d\n", getpid());
369 system(buffer);
370 }
371