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. */
39 struct sockaddr_in addr
;
43 static void init_python(void);
44 static void usage(void);
45 static void oprogname(void);
46 static void main_thread(int);
47 static void create_thread(int, struct sockaddr_in
*);
48 static void *service_thread(struct workorder
*);
49 static void run_interpreter(FILE *, FILE *);
50 static int run_command(char *, PyObject
*);
53 static char *progname
= "pysvr";
55 static PyThreadState
*gtstate
;
57 main(int argc
, char **argv
)
62 if (argc
> 0 && argv
[0] != NULL
&& argv
[0][0] != '\0')
65 while ((c
= getopt(argc
, argv
, "")) != EOF
) {
73 if (optind
+1 < argc
) {
75 fprintf(stderr
, "too many arguments\n");
78 port
= atoi(argv
[optind
]);
80 fprintf(stderr
, "bad port (%s)\n", argv
[optind
]);
87 fprintf(stderr
, "Bye.\n");
92 static char usage_line
[] = "usage: %s [port]\n";
97 fprintf(stderr
, usage_line
, progname
);
102 main_thread(int port
)
104 int sock
, conn
, size
, i
;
105 struct sockaddr_in addr
, clientaddr
;
107 sock
= socket(PF_INET
, SOCK_STREAM
, 0);
110 perror("can't create socket");
116 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &i
, sizeof i
);
119 memset((char *)&addr
, '\0', sizeof addr
);
120 addr
.sin_family
= AF_INET
;
121 addr
.sin_port
= htons(port
);
122 addr
.sin_addr
.s_addr
= 0L;
123 if (bind(sock
, (struct sockaddr
*)&addr
, sizeof addr
) < 0) {
125 perror("can't bind socket to address");
129 if (listen(sock
, 5) < 0) {
131 perror("can't listen on socket");
135 fprintf(stderr
, "Listening on port %d...\n", port
);
138 size
= sizeof clientaddr
;
139 memset((char *) &clientaddr
, '\0', size
);
140 conn
= accept(sock
, (struct sockaddr
*) &clientaddr
, &size
);
143 perror("can't accept connection from socket");
148 memset((char *) &addr
, '\0', size
);
149 if (getsockname(conn
, (struct sockaddr
*)&addr
, &size
) < 0) {
151 perror("can't get socket name of connection");
154 if (clientaddr
.sin_addr
.s_addr
!= addr
.sin_addr
.s_addr
) {
156 perror("connection from non-local host refused");
157 fprintf(stderr
, "(addr=%lx, clientaddr=%lx)\n",
158 ntohl(addr
.sin_addr
.s_addr
),
159 ntohl(clientaddr
.sin_addr
.s_addr
));
167 create_thread(conn
, &clientaddr
);
173 PyEval_AcquireThread(gtstate
);
182 create_thread(int conn
, struct sockaddr_in
*addr
)
184 struct workorder
*work
;
187 work
= malloc(sizeof(struct workorder
));
190 fprintf(stderr
, "out of memory for thread.\n");
199 if (pthread_create(&tdata
, NULL
, (void *)service_thread
, work
) < 0) {
201 perror("can't create new thread");
206 if (pthread_detach(tdata
) < 0) {
208 perror("can't detach from thread");
212 static PyThreadState
*the_tstate
;
213 static PyInterpreterState
*the_interp
;
214 static PyObject
*the_builtins
;
221 Py_Initialize(); /* Initialize the interpreter */
222 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
223 gtstate
= PyEval_SaveThread(); /* Release the thread state */
227 service_thread(struct workorder
*work
)
229 FILE *input
, *output
;
231 fprintf(stderr
, "Start thread for connection %d.\n", work
->conn
);
235 input
= fdopen(work
->conn
, "r");
238 perror("can't create input stream");
242 output
= fdopen(work
->conn
, "w");
243 if (output
== NULL
) {
245 perror("can't create output stream");
250 setvbuf(input
, NULL
, _IONBF
, 0);
251 setvbuf(output
, NULL
, _IONBF
, 0);
253 run_interpreter(input
, output
);
259 fprintf(stderr
, "End thread for connection %d.\n", work
->conn
);
268 fprintf(stderr
, "%s: ", progname
);
273 run_interpreter(FILE *input
, FILE *output
)
275 PyThreadState
*tstate
;
276 PyObject
*new_stdin
, *new_stdout
;
277 PyObject
*mainmod
, *globals
;
282 PyEval_AcquireLock();
283 tstate
= Py_NewInterpreter();
284 if (tstate
== NULL
) {
285 fprintf(output
, "Sorry -- can't create an interpreter\n");
289 mainmod
= PyImport_AddModule("__main__");
290 globals
= PyModule_GetDict(mainmod
);
293 new_stdin
= PyFile_FromFile(input
, "<socket-in>", "r", NULL
);
294 new_stdout
= PyFile_FromFile(output
, "<socket-out>", "w", NULL
);
296 PySys_SetObject("stdin", new_stdin
);
297 PySys_SetObject("stdout", new_stdout
);
298 PySys_SetObject("stderr", new_stdout
);
300 for (n
= 1; !PyErr_Occurred(); n
++) {
301 Py_BEGIN_ALLOW_THREADS
302 fprintf(output
, "%d> ", n
);
303 p
= fgets(buffer
, sizeof buffer
, input
);
308 if (p
[0] == '\377' && p
[1] == '\354')
311 q
= strrchr(p
, '\r');
312 if (q
&& q
[1] == '\n' && q
[2] == '\0') {
317 while (*p
&& isspace(*p
))
319 if (p
[0] == '#' || p
[0] == '\0')
322 end
= run_command(buffer
, globals
);
331 Py_XDECREF(new_stdin
);
332 Py_XDECREF(new_stdout
);
334 Py_EndInterpreter(tstate
);
335 PyEval_ReleaseLock();
337 fprintf(output
, "Goodbye!\n");
341 run_command(char *buffer
, PyObject
*globals
)
344 fprintf(stderr
, "run_command: %s", buffer
);
345 if (strchr(buffer
, '\n') == NULL
)
346 fprintf(stderr
, "\n");
347 v
= PyRun_String(buffer
, Py_single_input
, globals
, globals
);
349 if (PyErr_Occurred() == PyExc_SystemExit
) {
364 sprintf(buffer
, "ps -l -p %d </dev/null | tail +2l\n", getpid());