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>
25 Python.h defines a typedef destructor, which conflicts with pthread.h.
26 So Python.h must be included after pthread.h. */
30 extern int Py_VerboseFlag
;
38 struct sockaddr_in addr
;
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
*);
52 static char *progname
= "pysvr";
54 static PyThreadState
*gtstate
;
56 main(int argc
, char **argv
)
61 if (argc
> 0 && argv
[0] != NULL
&& argv
[0][0] != '\0')
64 while ((c
= getopt(argc
, argv
, "v")) != EOF
) {
75 if (optind
+1 < argc
) {
77 fprintf(stderr
, "too many arguments\n");
80 port
= atoi(argv
[optind
]);
82 fprintf(stderr
, "bad port (%s)\n", argv
[optind
]);
89 fprintf(stderr
, "Bye.\n");
94 static char usage_line
[] = "usage: %s [port]\n";
99 fprintf(stderr
, usage_line
, progname
);
104 main_thread(int port
)
106 int sock
, conn
, size
, i
;
107 struct sockaddr_in addr
, clientaddr
;
109 sock
= socket(PF_INET
, SOCK_STREAM
, 0);
112 perror("can't create socket");
118 setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &i
, sizeof i
);
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) {
127 perror("can't bind socket to address");
131 if (listen(sock
, 5) < 0) {
133 perror("can't listen on socket");
137 fprintf(stderr
, "Listening on port %d...\n", port
);
140 size
= sizeof clientaddr
;
141 memset((char *) &clientaddr
, '\0', size
);
142 conn
= accept(sock
, (struct sockaddr
*) &clientaddr
, &size
);
145 perror("can't accept connection from socket");
150 memset((char *) &addr
, '\0', size
);
151 if (getsockname(conn
, (struct sockaddr
*)&addr
, &size
) < 0) {
153 perror("can't get socket name of connection");
156 if (clientaddr
.sin_addr
.s_addr
!= addr
.sin_addr
.s_addr
) {
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
));
169 create_thread(conn
, &clientaddr
);
175 PyEval_AcquireThread(gtstate
);
178 /* And a second time, just because we can. */
179 Py_Finalize(); /* This should be harmless. */
185 create_thread(int conn
, struct sockaddr_in
*addr
)
187 struct workorder
*work
;
190 work
= malloc(sizeof(struct workorder
));
193 fprintf(stderr
, "out of memory for thread.\n");
202 if (pthread_create(&tdata
, NULL
, (void *)service_thread
, work
) < 0) {
204 perror("can't create new thread");
209 if (pthread_detach(tdata
) < 0) {
211 perror("can't detach from thread");
215 static PyThreadState
*the_tstate
;
216 static PyInterpreterState
*the_interp
;
217 static PyObject
*the_builtins
;
224 Py_Initialize(); /* Initialize the interpreter */
225 PyEval_InitThreads(); /* Create (and acquire) the interpreter lock */
226 gtstate
= PyEval_SaveThread(); /* Release the thread state */
230 service_thread(struct workorder
*work
)
232 FILE *input
, *output
;
234 fprintf(stderr
, "Start thread for connection %d.\n", work
->conn
);
238 input
= fdopen(work
->conn
, "r");
241 perror("can't create input stream");
245 output
= fdopen(work
->conn
, "w");
246 if (output
== NULL
) {
248 perror("can't create output stream");
253 setvbuf(input
, NULL
, _IONBF
, 0);
254 setvbuf(output
, NULL
, _IONBF
, 0);
256 run_interpreter(input
, output
);
262 fprintf(stderr
, "End thread for connection %d.\n", work
->conn
);
271 fprintf(stderr
, "%s: ", progname
);
276 run_interpreter(FILE *input
, FILE *output
)
278 PyThreadState
*tstate
;
279 PyObject
*new_stdin
, *new_stdout
;
280 PyObject
*mainmod
, *globals
;
285 PyEval_AcquireLock();
286 tstate
= Py_NewInterpreter();
287 if (tstate
== NULL
) {
288 fprintf(output
, "Sorry -- can't create an interpreter\n");
292 mainmod
= PyImport_AddModule("__main__");
293 globals
= PyModule_GetDict(mainmod
);
296 new_stdin
= PyFile_FromFile(input
, "<socket-in>", "r", NULL
);
297 new_stdout
= PyFile_FromFile(output
, "<socket-out>", "w", NULL
);
299 PySys_SetObject("stdin", new_stdin
);
300 PySys_SetObject("stdout", new_stdout
);
301 PySys_SetObject("stderr", new_stdout
);
303 for (n
= 1; !PyErr_Occurred(); n
++) {
304 Py_BEGIN_ALLOW_THREADS
305 fprintf(output
, "%d> ", n
);
306 p
= fgets(buffer
, sizeof buffer
, input
);
311 if (p
[0] == '\377' && p
[1] == '\354')
314 q
= strrchr(p
, '\r');
315 if (q
&& q
[1] == '\n' && q
[2] == '\0') {
320 while (*p
&& isspace(*p
))
322 if (p
[0] == '#' || p
[0] == '\0')
325 end
= run_command(buffer
, globals
);
334 Py_XDECREF(new_stdin
);
335 Py_XDECREF(new_stdout
);
337 Py_EndInterpreter(tstate
);
338 PyEval_ReleaseLock();
340 fprintf(output
, "Goodbye!\n");
344 run_command(char *buffer
, PyObject
*globals
)
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
);
352 if (PyErr_Occurred() == PyExc_SystemExit
) {
367 PyOS_snprintf(buffer
, sizeof(buffer
),
368 "ps -l -p %d </dev/null | sed 1d\n", getpid());