1 /* A multi-threaded telnet-like server that gives a Python prompt.
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!
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
24 Python.h defines a typedef destructor, which conflicts with pthread.h.
25 So Python.h must be included after pthread.h. */
29 extern int Py_VerboseFlag
;
41 struct sockaddr_in addr
;
45 static void init_python(void);
46 static void usage(void);
47 static void oprogname(void);
48 static void main_thread(int);
49 static void create_thread(int, struct sockaddr_in
*);
50 static void *service_thread(struct workorder
*);
51 static void run_interpreter(FILE *, FILE *);
52 static int run_command(char *, PyObject
*);
55 static char *progname
= "pysvr";
57 static PyThreadState
*gtstate
;
59 main(int argc
, char **argv
)
64 if (argc
> 0 && argv
[0] != NULL
&& argv
[0][0] != '\0')
67 while ((c
= getopt(argc
, argv
, "v")) != EOF
) {
78 if (optind
+1 < argc
) {
80 fprintf(stderr
, "too many arguments\n");
83 port
= atoi(argv
[optind
]);
85 fprintf(stderr
, "bad port (%s)\n", argv
[optind
]);
92 fprintf(stderr
, "Bye.\n");
97 static char usage_line
[] = "usage: %s [port]\n";
102 fprintf(stderr
, usage_line
, progname
);
107 main_thread(int port
)
109 int sock
, conn
, size
, i
;
110 struct sockaddr_in addr
, clientaddr
;
112 sock
= socket(PF_INET
, SOCK_STREAM
, 0);
115 perror("can't create socket");
121 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &i
, sizeof i
);
124 memset((char *)&addr
, '\0', sizeof addr
);
125 addr
.sin_family
= AF_INET
;
126 addr
.sin_port
= htons(port
);
127 addr
.sin_addr
.s_addr
= 0L;
128 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof addr
) < 0) {
130 perror("can't bind socket to address");
134 if (listen(sock
, 5) < 0) {
136 perror("can't listen on socket");
140 fprintf(stderr
, "Listening on port %d...\n", port
);
143 size
= sizeof clientaddr
;
144 memset((char *) &clientaddr
, '\0', size
);
145 conn
= accept(sock
, (struct sockaddr
*) &clientaddr
, &size
);
148 perror("can't accept connection from socket");
153 memset((char *) &addr
, '\0', size
);
154 if (getsockname(conn
, (struct sockaddr
*)&addr
, &size
) < 0) {
156 perror("can't get socket name of connection");
159 if (clientaddr
.sin_addr
.s_addr
!= addr
.sin_addr
.s_addr
) {
161 perror("connection from non-local host refused");
162 fprintf(stderr
, "(addr=%lx, clientaddr=%lx)\n",
163 ntohl(addr
.sin_addr
.s_addr
),
164 ntohl(clientaddr
.sin_addr
.s_addr
));
172 create_thread(conn
, &clientaddr
);
178 PyEval_AcquireThread(gtstate
);
181 /* And a second time, just because we can. */
182 Py_Finalize(); /* This should be harmless. */
188 create_thread(int conn
, struct sockaddr_in
*addr
)
190 struct workorder
*work
;
193 work
= malloc(sizeof(struct workorder
));
196 fprintf(stderr
, "out of memory for thread.\n");
205 if (pthread_create(&tdata
, NULL
, (void *)service_thread
, work
) < 0) {
207 perror("can't create new thread");
212 if (pthread_detach(tdata
) < 0) {
214 perror("can't detach from thread");
218 static PyThreadState
*the_tstate
;
219 static PyInterpreterState
*the_interp
;
220 static PyObject
*the_builtins
;
227 Py_Initialize(); /* Initialize the interpreter */
228 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
229 gtstate
= PyEval_SaveThread(); /* Release the thread state */
233 service_thread(struct workorder
*work
)
235 FILE *input
, *output
;
237 fprintf(stderr
, "Start thread for connection %d.\n", work
->conn
);
241 input
= fdopen(work
->conn
, "r");
244 perror("can't create input stream");
248 output
= fdopen(work
->conn
, "w");
249 if (output
== NULL
) {
251 perror("can't create output stream");
256 setvbuf(input
, NULL
, _IONBF
, 0);
257 setvbuf(output
, NULL
, _IONBF
, 0);
259 run_interpreter(input
, output
);
265 fprintf(stderr
, "End thread for connection %d.\n", work
->conn
);
274 fprintf(stderr
, "%s: ", progname
);
279 run_interpreter(FILE *input
, FILE *output
)
281 PyThreadState
*tstate
;
282 PyObject
*new_stdin
, *new_stdout
;
283 PyObject
*mainmod
, *globals
;
288 PyEval_AcquireLock();
289 tstate
= Py_NewInterpreter();
290 if (tstate
== NULL
) {
291 fprintf(output
, "Sorry -- can't create an interpreter\n");
295 mainmod
= PyImport_AddModule("__main__");
296 globals
= PyModule_GetDict(mainmod
);
299 new_stdin
= PyFile_FromFile(input
, "<socket-in>", "r", NULL
);
300 new_stdout
= PyFile_FromFile(output
, "<socket-out>", "w", NULL
);
302 PySys_SetObject("stdin", new_stdin
);
303 PySys_SetObject("stdout", new_stdout
);
304 PySys_SetObject("stderr", new_stdout
);
306 for (n
= 1; !PyErr_Occurred(); n
++) {
307 Py_BEGIN_ALLOW_THREADS
308 fprintf(output
, "%d> ", n
);
309 p
= fgets(buffer
, sizeof buffer
, input
);
314 if (p
[0] == '\377' && p
[1] == '\354')
317 q
= strrchr(p
, '\r');
318 if (q
&& q
[1] == '\n' && q
[2] == '\0') {
323 while (*p
&& isspace(*p
))
325 if (p
[0] == '#' || p
[0] == '\0')
328 end
= run_command(buffer
, globals
);
337 Py_XDECREF(new_stdin
);
338 Py_XDECREF(new_stdout
);
340 Py_EndInterpreter(tstate
);
341 PyEval_ReleaseLock();
343 fprintf(output
, "Goodbye!\n");
347 run_command(char *buffer
, PyObject
*globals
)
350 fprintf(stderr
, "run_command: %s", buffer
);
351 if (strchr(buffer
, '\n') == NULL
)
352 fprintf(stderr
, "\n");
353 v
= PyRun_String(buffer
, Py_single_input
, globals
, globals
);
355 if (PyErr_Occurred() == PyExc_SystemExit
) {
370 sprintf(buffer
, "ps -l -p %d </dev/null | tail +2l\n", getpid());