Mercurial > hg > xemacs-beta
annotate lib-src/gnuserv.c @ 5364:0f9aa4eb4bec
Make my Lisp a little more sophisticated, select.el.
2011-03-08 Aidan Kehoe <kehoea@parhasard.net>
* select.el (selection-preferred-types):
* select.el (cut-copy-clear-internal):
* select.el (create-image-functions):
* select.el (select-convert-from-image/gif):
* select.el (select-convert-from-image/jpeg):
* select.el (select-convert-from-image/png):
* select.el (select-convert-from-image/tiff):
* select.el (select-convert-from-image/xpm):
* select.el (select-convert-from-image/xbm):
* select.el (selection-converter-in-alist):
Make my Lisp a little more sophisticated in this file.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Tue, 08 Mar 2011 21:00:36 +0000 |
parents | e6508b64ee08 |
children | b9167d522a9a |
rev | line source |
---|---|
428 | 1 /* -*-C-*- |
2 Server code for handling requests from clients and forwarding them | |
613 | 3 on to the XEmacs process. |
428 | 4 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
5 Copyright (C) 1989 Free Software Foundation, Inc. |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
6 |
613 | 7 This file is part of XEmacs. |
428 | 8 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
9 XEmacs is free software; you can redistribute it and/or modify it |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
10 under the terms of the GNU General Public License as published by |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
11 the Free Software Foundation; either version 2, or (at your option) |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
12 any later version. |
428 | 13 |
5290
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
14 XEmacs is distributed in the hope that it will be useful, but |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
15 WITHOUT ANY WARRANTY; without even the implied warranty of |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
17 General Public License for more details. |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
18 |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
19 You should have received a copy of the GNU General Public License |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
20 along with XEmacs; see the file COPYING. If not, write to the Free |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
e6508b64ee08
More permission consistency.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
2286
diff
changeset
|
22 Boston, MA 02110-1301, USA. |
428 | 23 |
24 Author: Andy Norman (ange@hplb.hpl.hp.com), based on 'etc/server.c' | |
25 from the 18.52 GNU Emacs distribution. | |
26 | |
27 Please mail bugs and suggestions to the author at the above address. | |
28 */ | |
29 | |
442 | 30 /* HISTORY |
31 * 11-Nov-1990 bristor@simba | |
428 | 32 * Added EOT stuff. |
33 */ | |
34 | |
35 /* | |
36 * This file incorporates new features added by Bob Weiner <weiner@mot.com>, | |
37 * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>. | |
38 * Please see the note at the end of the README file for details. | |
39 * | |
40 * (If gnuserv came bundled with your emacs, the README file is probably | |
41 * ../etc/gnuserv.README relative to the directory containing this file) | |
42 */ | |
43 | |
456 | 44 #include "gnuserv.h" |
428 | 45 |
456 | 46 char gnuserv_version[] = "gnuserv version" GNUSERV_VERSION; |
47 | |
428 | 48 |
49 #ifdef USE_LITOUT | |
50 #ifdef linux | |
51 #include <bsd/sgtty.h> | |
52 #else | |
53 #include <sgtty.h> | |
54 #endif | |
55 #endif | |
56 | |
57 #ifdef AIX | |
58 #include <sys/select.h> | |
59 #endif | |
60 | |
61 #include <stdlib.h> | |
62 #include <stdio.h> | |
63 #include <sys/types.h> | |
64 #include <sys/stat.h> | |
65 | |
66 #ifdef HAVE_UNISTD_H | |
67 #include <unistd.h> | |
68 #endif /* HAVE_UNISTD_H */ | |
69 | |
70 #ifdef HAVE_STRING_H | |
71 #include <string.h> | |
72 #endif /* HAVE_STRING_H */ | |
73 | |
2286 | 74 #include "compiler.h" |
75 | |
428 | 76 #if !defined(SYSV_IPC) && !defined(UNIX_DOMAIN_SOCKETS) && \ |
77 !defined(INTERNET_DOMAIN_SOCKETS) | |
2286 | 78 int main () |
428 | 79 { |
80 fprintf (stderr,"Sorry, the Emacs server is only supported on systems that have\n"); | |
81 fprintf (stderr,"Unix Domain sockets, Internet Domain sockets or System V IPC\n"); | |
82 exit (1); | |
83 } /* main */ | |
84 #else /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */ | |
85 | |
86 #ifdef SYSV_IPC | |
87 | |
88 int ipc_qid = 0; /* ipc message queue id */ | |
89 pid_t ipc_wpid = 0; /* watchdog task pid */ | |
90 | |
91 | |
92 /* | |
93 ipc_exit -- clean up the queue id and queue, then kill the watchdog task | |
94 if it exists. exit with the given status. | |
95 */ | |
96 void | |
97 ipc_exit (int stat) | |
98 { | |
99 msgctl (ipc_qid,IPC_RMID,0); | |
442 | 100 |
428 | 101 if (ipc_wpid != 0) |
102 kill (ipc_wpid, SIGKILL); | |
103 | |
104 exit (stat); | |
105 } /* ipc_exit */ | |
106 | |
107 | |
108 /* | |
109 ipc_handle_signal -- catch the signal given and clean up. | |
110 */ | |
111 void | |
112 ipc_handle_signal(int sig) | |
113 { | |
114 ipc_exit (0); | |
115 } /* ipc_handle_signal */ | |
116 | |
117 | |
442 | 118 /* |
428 | 119 ipc_spawn_watchdog -- spawn a watchdog task to clean up the message queue should the |
120 server process die. | |
121 */ | |
122 void | |
123 ipc_spawn_watchdog (void) | |
124 { | |
125 if ((ipc_wpid = fork ()) == 0) | |
126 { /* child process */ | |
127 pid_t ppid = getppid (); /* parent's process id */ | |
128 | |
129 setpgrp(); /* gnu kills process group on exit */ | |
130 | |
131 while (1) | |
132 { | |
133 if (kill (ppid, 0) < 0) /* ppid is no longer valid, parent | |
134 may have died */ | |
135 { | |
136 ipc_exit (0); | |
137 } /* if */ | |
138 | |
139 sleep(10); /* have another go later */ | |
140 } /* while */ | |
141 } /* if */ | |
142 | |
143 } /* ipc_spawn_watchdog */ | |
144 | |
145 | |
146 /* | |
147 ipc_init -- initialize server, setting the global msqid that can be listened on. | |
148 */ | |
149 void | |
150 ipc_init (struct msgbuf **msgpp) | |
151 { | |
152 key_t key; /* messge key */ | |
153 char buf[GSERV_BUFSZ]; /* pathname for key */ | |
154 | |
155 sprintf (buf,"%s/gsrv%d",tmpdir,(int)geteuid ()); | |
156 creat (buf,0600); | |
157 key = ftok (buf,1); | |
158 | |
159 if ((ipc_qid = msgget (key,0600|IPC_CREAT)) == -1) | |
160 { | |
161 perror (progname); | |
162 fprintf (stderr, "%s: unable to create msg queue\n", progname); | |
163 ipc_exit (1); | |
164 } /* if */ | |
165 | |
166 ipc_spawn_watchdog (); | |
167 | |
168 signal (SIGTERM,ipc_handle_signal); | |
169 signal (SIGINT,ipc_handle_signal); | |
170 | |
171 if ((*msgpp = (struct msgbuf *) | |
172 malloc (sizeof **msgpp + GSERV_BUFSZ)) == NULL) | |
173 { | |
174 fprintf (stderr, | |
175 "%s: unable to allocate space for message buffer\n", progname); | |
176 ipc_exit(1); | |
177 } /* if */ | |
178 } /* ipc_init */ | |
179 | |
180 | |
181 /* | |
182 handle_ipc_request -- accept a request from a client, pass the request on | |
613 | 183 to the XEmacs process, then wait for its reply and |
428 | 184 pass that on to the client. |
185 */ | |
186 void | |
187 handle_ipc_request (struct msgbuf *msgp) | |
188 { | |
189 struct msqid_ds msg_st; /* message status */ | |
190 char buf[GSERV_BUFSZ]; | |
191 int len; /* length of message / read */ | |
192 int s, result_len; /* tag fields on the response from emacs */ | |
193 int offset = 0; | |
194 int total = 1; /* # bytes that will actually be sent off */ | |
195 | |
196 if ((len = msgrcv (ipc_qid, msgp, GSERV_BUFSZ - 1, 1, 0)) < 0) | |
197 { | |
198 perror (progname); | |
199 fprintf (stderr, "%s: unable to receive\n", progname); | |
200 ipc_exit (1); | |
201 } /* if */ | |
202 | |
203 msgctl (ipc_qid, IPC_STAT, &msg_st); | |
204 strncpy (buf, msgp->mtext, len); | |
205 buf[len] = '\0'; /* terminate */ | |
442 | 206 |
428 | 207 printf ("%d %s", ipc_qid, buf); |
208 fflush (stdout); | |
209 | |
210 /* now for the response from gnu */ | |
211 msgp->mtext[0] = '\0'; | |
212 | |
213 #if 0 | |
214 if ((len = read(0,buf,GSERV_BUFSZ-1)) < 0) | |
215 { | |
216 perror (progname); | |
217 fprintf (stderr, "%s: unable to read\n", progname); | |
218 ipc_exit (1); | |
219 } /* if */ | |
220 | |
221 sscanf (buf, "%d:%[^\n]\n", &junk, msgp->mtext); | |
222 #else | |
223 | |
224 /* read in "n/m:" (n=client fd, m=message length) */ | |
225 | |
442 | 226 while (offset < (GSERV_BUFSZ-1) && |
428 | 227 ((len = read (0, buf + offset, 1)) > 0) && |
228 buf[offset] != ':') | |
229 { | |
230 offset += len; | |
231 } | |
232 | |
233 if (len < 0) | |
234 { | |
235 perror (progname); | |
236 fprintf (stderr, "%s: unable to read\n", progname); | |
237 exit(1); | |
238 } | |
239 | |
240 /* parse the response from emacs, getting client fd & result length */ | |
241 buf[offset] = '\0'; | |
242 sscanf (buf, "%d/%d", &s, &result_len); | |
243 | |
244 while (result_len > 0) | |
245 { | |
246 if ((len = read(0, buf, min2 (result_len, GSERV_BUFSZ - 1))) < 0) | |
247 { | |
248 perror (progname); | |
249 fprintf (stderr, "%s: unable to read\n", progname); | |
250 exit (1); | |
251 } | |
252 | |
442 | 253 /* Send this string off, but only if we have enough space */ |
428 | 254 |
255 if (GSERV_BUFSZ > total) | |
256 { | |
257 if (total + len <= GSERV_BUFSZ) | |
258 buf[len] = 0; | |
259 else | |
260 buf[GSERV_BUFSZ - total] = 0; | |
261 | |
262 send_string(s,buf); | |
263 total += strlen(buf); | |
264 } | |
265 | |
266 result_len -= len; | |
267 } | |
268 | |
269 /* eat the newline */ | |
270 while ((len = read (0,buf,1)) == 0) | |
271 ; | |
272 if (len < 0) | |
273 { | |
274 perror(progname); | |
275 fprintf (stderr,"%s: unable to read\n", progname); | |
276 exit (1); | |
277 } | |
278 if (buf[0] != '\n') | |
279 { | |
280 fprintf (stderr,"%s: garbage after result [%c]\n", progname, buf[0]); | |
281 exit (1); | |
282 } | |
283 #endif | |
284 | |
285 /* Send a response back to the client. */ | |
286 | |
287 msgp->mtype = msg_st.msg_lspid; | |
288 if (msgsnd (ipc_qid,msgp,strlen(msgp->mtext)+1,0) < 0) | |
289 perror ("msgsend(gnuserv)"); | |
290 | |
291 } /* handle_ipc_request */ | |
292 #endif /* SYSV_IPC */ | |
293 | |
294 | |
295 #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS) | |
296 /* | |
297 echo_request -- read request from a given socket descriptor, and send the information | |
298 to stdout (the gnu process). | |
299 */ | |
300 static void | |
301 echo_request (int s) | |
302 { | |
303 char buf[GSERV_BUFSZ]; | |
304 int len; | |
305 | |
306 printf("%d ",s); | |
442 | 307 |
428 | 308 /* read until we get a newline or no characters */ |
309 while ((len = recv(s,buf,GSERV_BUFSZ-1,0)) > 0) { | |
310 buf[len] = '\0'; | |
311 printf("%s",buf); | |
312 | |
313 if (buf[len-1] == EOT_CHR) { | |
314 fflush(stdout); | |
315 break; /* end of message */ | |
316 } | |
317 | |
318 } /* while */ | |
319 | |
320 if (len < 0) { | |
321 perror(progname); | |
322 fprintf(stderr,"%s: unable to recv\n",progname); | |
323 exit(1); | |
324 } /* if */ | |
442 | 325 |
428 | 326 } /* echo_request */ |
327 | |
328 | |
329 /* | |
330 handle_response -- accept a response from stdin (the gnu process) and pass the | |
331 information on to the relevant client. | |
332 */ | |
333 static void | |
334 handle_response (void) | |
335 { | |
336 char buf[GSERV_BUFSZ+1]; | |
337 int offset=0; | |
338 int s; | |
339 int len = 0; | |
340 int result_len; | |
341 | |
342 /* read in "n/m:" (n=client fd, m=message length) */ | |
442 | 343 while (offset < GSERV_BUFSZ && |
428 | 344 ((len = read(0,buf+offset,1)) > 0) && |
345 buf[offset] != ':') { | |
346 offset += len; | |
347 } | |
348 | |
349 if (len < 0) { | |
350 perror(progname); | |
351 fprintf(stderr,"%s: unable to read\n",progname); | |
352 exit(1); | |
353 } | |
442 | 354 |
428 | 355 /* parse the response from emacs, getting client fd & result length */ |
356 buf[offset] = '\0'; | |
357 sscanf(buf,"%d/%d", &s, &result_len); | |
358 | |
359 while (result_len > 0) { | |
360 if ((len = read(0,buf,min2(result_len,GSERV_BUFSZ))) < 0) { | |
361 perror(progname); | |
362 fprintf(stderr,"%s: unable to read\n",progname); | |
363 exit(1); | |
364 } | |
365 buf[len] = '\0'; | |
366 send_string(s,buf); | |
367 result_len -= len; | |
368 } | |
369 | |
370 /* eat the newline */ | |
371 while ((len = read(0,buf,1)) == 0) | |
372 ; | |
373 if (len < 0) | |
374 { | |
375 perror(progname); | |
376 fprintf(stderr,"%s: unable to read\n",progname); | |
377 exit(1); | |
378 } | |
379 if (buf[0] != '\n') | |
380 { | |
381 fprintf(stderr,"%s: garbage after result\n",progname); | |
382 exit(1); | |
383 } | |
384 /* send the newline */ | |
385 buf[1] = '\0'; | |
386 send_string(s,buf); | |
442 | 387 close(s); |
428 | 388 |
389 } /* handle_response */ | |
390 #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */ | |
391 | |
392 | |
393 #ifdef INTERNET_DOMAIN_SOCKETS | |
394 struct entry { | |
458 | 395 unsigned long host_addr; |
428 | 396 struct entry *next; |
397 }; | |
398 | |
399 struct entry *permitted_hosts[TABLE_SIZE]; | |
400 | |
401 #ifdef AUTH_MAGIC_COOKIE | |
402 # include <X11/X.h> | |
403 # include <X11/Xauth.h> | |
404 | |
405 static Xauth *server_xauth = NULL; | |
442 | 406 #endif |
428 | 407 |
442 | 408 static int |
428 | 409 timed_read (int fd, char *buf, int max, int timeout, int one_line) |
410 { | |
411 fd_set rmask; | |
412 struct timeval tv; /* = {timeout, 0}; */ | |
413 char c = 0; | |
414 int nbytes = 0; | |
415 int r; | |
442 | 416 |
428 | 417 tv.tv_sec = timeout; |
418 tv.tv_usec = 0; | |
419 | |
420 FD_ZERO(&rmask); | |
421 FD_SET(fd, &rmask); | |
442 | 422 |
428 | 423 do |
424 { | |
425 r = select(fd + 1, &rmask, NULL, NULL, &tv); | |
426 | |
427 if (r > 0) | |
428 { | |
429 if (read (fd, &c, 1) == 1 ) | |
430 { | |
431 *buf++ = c; | |
432 ++nbytes; | |
433 } | |
434 else | |
435 { | |
436 printf ("read error on socket\004\n"); | |
437 return -1; | |
438 } | |
439 } | |
440 else if (r == 0) | |
441 { | |
442 printf ("read timed out\004\n"); | |
443 return -1; | |
444 } | |
445 else | |
446 { | |
447 printf ("error in select\004\n"); | |
448 return -1; | |
449 } | |
450 } while ((nbytes < max) && !(one_line && (c == '\n'))); | |
451 | |
452 --buf; | |
453 if (one_line && *buf == '\n') | |
454 { | |
455 *buf = 0; | |
456 } | |
457 | |
458 return nbytes; | |
459 } | |
442 | 460 |
461 | |
428 | 462 |
463 /* | |
464 permitted -- return whether a given host is allowed to connect to the server. | |
465 */ | |
466 static int | |
458 | 467 permitted (unsigned long host_addr, int fd) |
428 | 468 { |
469 int key; | |
470 struct entry *entry; | |
471 | |
442 | 472 char auth_protocol[128]; |
428 | 473 char buf[1024]; |
474 int auth_data_len; | |
475 | |
476 if (fd > 0) | |
477 { | |
478 /* we are checking permission on a real connection */ | |
479 | |
480 /* Read auth protocol name */ | |
442 | 481 |
428 | 482 if (timed_read(fd, auth_protocol, AUTH_NAMESZ, AUTH_TIMEOUT, 1) <= 0) |
483 return FALSE; | |
484 | |
485 if (strcmp (auth_protocol, DEFAUTH_NAME) && | |
486 strcmp (auth_protocol, MCOOKIE_NAME)) | |
487 { | |
442 | 488 printf ("authentication protocol (%s) from client is invalid...\n", |
428 | 489 auth_protocol); |
490 printf ("... Was the client an old version of gnuclient/gnudoit?\004\n"); | |
442 | 491 |
428 | 492 return FALSE; |
493 } | |
494 | |
495 if (!strcmp(auth_protocol, MCOOKIE_NAME)) | |
496 { | |
497 | |
498 /* | |
499 * doing magic cookie auth | |
500 */ | |
501 | |
647 | 502 if (timed_read (fd, buf, 10, AUTH_TIMEOUT, 1) <= 0) |
428 | 503 return FALSE; |
504 | |
647 | 505 auth_data_len = atoi (buf); |
428 | 506 |
647 | 507 if (auth_data_len <= 0 || auth_data_len > (int) sizeof (buf)) |
456 | 508 { |
509 return FALSE; | |
510 } | |
511 | |
647 | 512 if (timed_read (fd, buf, auth_data_len, AUTH_TIMEOUT, 0) != |
513 auth_data_len) | |
428 | 514 return FALSE; |
442 | 515 |
428 | 516 #ifdef AUTH_MAGIC_COOKIE |
456 | 517 if (server_xauth && server_xauth->data) |
462 | 518 { |
456 | 519 /* Do a compare without comprising info about |
520 the size of the cookie */ | |
460 | 521 int auth_data_pos; |
522 int auth_mismatches = | |
456 | 523 ( auth_data_len ^ |
524 server_xauth->data_length ); | |
525 | |
647 | 526 for(auth_data_pos = 0; auth_data_pos < auth_data_len; |
527 ++auth_data_pos) | |
456 | 528 auth_mismatches |= |
529 ( buf[auth_data_pos] ^ | |
647 | 530 server_xauth->data[auth_data_pos % |
531 server_xauth->data_length]); | |
456 | 532 |
533 if (auth_mismatches == 0) | |
428 | 534 return TRUE; |
456 | 535 |
536 for(;rand() % 1000;); | |
462 | 537 } |
456 | 538 |
442 | 539 #else |
428 | 540 printf ("client tried Xauth, but server is not compiled with Xauth\n"); |
541 #endif | |
442 | 542 |
428 | 543 /* |
544 * auth failed, but allow this to fall through to the GNU_SECURE | |
545 * protocol.... | |
546 */ | |
547 | |
548 printf ("Xauth authentication failed, trying GNU_SECURE auth...\004\n"); | |
549 | |
550 } | |
442 | 551 |
428 | 552 /* Other auth protocols go here, and should execute only if the |
553 * auth_protocol name matches. | |
554 */ | |
555 | |
556 } | |
557 | |
558 | |
559 /* Now, try the old GNU_SECURE stuff... */ | |
442 | 560 |
428 | 561 /* First find the hash key */ |
562 key = HASH(host_addr) % TABLE_SIZE; | |
442 | 563 |
428 | 564 /* Now check the chain for that hash key */ |
565 for(entry=permitted_hosts[key]; entry != NULL; entry=entry->next) | |
442 | 566 if (host_addr == entry->host_addr) |
428 | 567 return(TRUE); |
442 | 568 |
428 | 569 return(FALSE); |
570 | |
571 } /* permitted */ | |
572 | |
573 | |
442 | 574 /* |
428 | 575 add_host -- add the given host to the list of permitted hosts, provided it isn't |
576 already there. | |
442 | 577 */ |
428 | 578 static void |
458 | 579 add_host (unsigned long host_addr) |
428 | 580 { |
581 int key; | |
582 struct entry *new_entry; | |
442 | 583 |
428 | 584 if (!permitted(host_addr, -1)) |
585 { | |
586 if ((new_entry = (struct entry *) malloc(sizeof(struct entry))) == NULL) { | |
587 fprintf(stderr,"%s: unable to malloc space for permitted host entry\n", | |
588 progname); | |
589 exit(1); | |
590 } /* if */ | |
591 | |
592 new_entry->host_addr = host_addr; | |
593 key = HASH(host_addr) % TABLE_SIZE; | |
594 new_entry->next = permitted_hosts[key]; | |
595 permitted_hosts[key] = new_entry; | |
596 } /* if */ | |
597 | |
598 } /* add_host */ | |
599 | |
600 | |
601 /* | |
602 setup_table -- initialize the table of hosts allowed to contact the server, | |
603 by reading from the file specified by the GNU_SECURE | |
604 environment variable | |
605 Put in the local machine, and, if a security file is specifed, | |
606 add each host that is named in the file. | |
607 Return the number of hosts added. | |
608 */ | |
609 static int | |
610 setup_table (void) | |
611 { | |
612 FILE *host_file; | |
613 char *file_name; | |
614 char hostname[HOSTNAMSZ]; | |
458 | 615 unsigned int host_addr; |
428 | 616 int i, hosts=0; |
442 | 617 |
428 | 618 /* Make sure every entry is null */ |
619 for (i=0; i<TABLE_SIZE; i++) | |
620 permitted_hosts[i] = NULL; | |
621 | |
622 gethostname(hostname,HOSTNAMSZ); | |
623 | |
647 | 624 if ((host_addr = internet_addr (hostname)) == (unsigned int) -1) |
428 | 625 { |
442 | 626 fprintf(stderr,"%s: unable to find %s in /etc/hosts or from YP", |
428 | 627 progname,hostname); |
628 exit(1); | |
629 } /* if */ | |
630 | |
631 #ifdef AUTH_MAGIC_COOKIE | |
442 | 632 |
633 server_xauth = XauGetAuthByAddr (FamilyInternet, | |
428 | 634 sizeof(host_addr), (char *)&host_addr, |
442 | 635 strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN, |
428 | 636 strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME); |
637 hosts++; | |
638 | |
639 #endif /* AUTH_MAGIC_COOKIE */ | |
442 | 640 |
428 | 641 |
642 #if 0 /* Don't even want to allow access from the local host by default */ | |
643 add_host(host_addr); /* add local host */ | |
442 | 644 #endif |
428 | 645 |
646 if (((file_name = getenv("GNU_SECURE")) != NULL && /* security file */ | |
647 (host_file = fopen(file_name,"r")) != NULL)) /* opened ok */ | |
648 { | |
649 while ((fscanf(host_file,"%s",hostname) != EOF)) /* find a host */ | |
647 | 650 if ((host_addr = internet_addr(hostname)) != (unsigned int) -1) |
651 /* get its addr */ | |
428 | 652 { |
647 | 653 add_host(host_addr); /* add the addr */ |
428 | 654 hosts++; |
655 } | |
656 fclose(host_file); | |
657 } /* if */ | |
658 | |
659 return hosts; | |
660 } /* setup_table */ | |
661 | |
662 | |
663 /* | |
664 internet_init -- initialize server, returning an internet socket that can | |
665 be listened on. | |
666 */ | |
667 static int | |
668 internet_init (void) | |
669 { | |
670 int ls; /* socket descriptor */ | |
671 struct servent *sp; /* pointer to service information */ | |
672 struct sockaddr_in server; /* for local socket address */ | |
673 char *ptr; /* ptr to return from getenv */ | |
674 | |
442 | 675 if (setup_table() == 0) |
428 | 676 return -1; |
677 | |
678 /* clear out address structure */ | |
442 | 679 memset (&server, '\0', sizeof (server)); |
680 | |
428 | 681 /* Set up address structure for the listen socket. */ |
682 server.sin_family = AF_INET; | |
683 server.sin_addr.s_addr = INADDR_ANY; | |
684 | |
685 /* Find the information for the gnu server | |
686 * in order to get the needed port number. | |
687 */ | |
688 if ((ptr=getenv("GNU_PORT")) != NULL) | |
689 server.sin_port = htons(atoi(ptr)); | |
690 else if ((sp = getservbyname ("gnuserv", "tcp")) == NULL) | |
691 server.sin_port = htons(DEFAULT_PORT+getuid()); | |
692 else | |
693 server.sin_port = sp->s_port; | |
442 | 694 |
428 | 695 /* Create the listen socket. */ |
696 if ((ls = socket (AF_INET,SOCK_STREAM, 0)) == -1) | |
697 { | |
698 perror(progname); | |
699 fprintf(stderr,"%s: unable to create socket\n",progname); | |
700 exit(1); | |
701 } /* if */ | |
442 | 702 |
428 | 703 /* Bind the listen address to the socket. */ |
704 if (bind(ls,(struct sockaddr *) &server,sizeof(struct sockaddr_in)) == -1) | |
705 { | |
706 perror(progname); | |
707 fprintf(stderr,"%s: unable to bind socket\n",progname); | |
708 exit(1); | |
709 } /* if */ | |
710 | |
711 /* Initiate the listen on the socket so remote users | |
442 | 712 * can connect. |
428 | 713 */ |
714 if (listen(ls,20) == -1) | |
715 { | |
716 perror(progname); | |
717 fprintf(stderr,"%s: unable to listen\n",progname); | |
718 exit(1); | |
719 } /* if */ | |
720 | |
721 return(ls); | |
722 | |
723 } /* internet_init */ | |
724 | |
725 | |
726 /* | |
727 handle_internet_request -- accept a request from a client and send the information | |
728 to stdout (the gnu process). | |
729 */ | |
730 static void | |
731 handle_internet_request (int ls) | |
732 { | |
733 int s; | |
442 | 734 socklen_t addrlen = sizeof (struct sockaddr_in); |
428 | 735 struct sockaddr_in peer; /* for peer socket address */ |
736 | |
442 | 737 memset (&peer, '\0', sizeof (peer)); |
428 | 738 |
440 | 739 if ((s = accept(ls,(struct sockaddr *)&peer, &addrlen)) == -1) |
428 | 740 { |
741 perror(progname); | |
742 fprintf(stderr,"%s: unable to accept\n",progname); | |
743 exit(1); | |
744 } /* if */ | |
442 | 745 |
428 | 746 /* Check that access is allowed - if not return crud to the client */ |
747 if (!permitted(peer.sin_addr.s_addr, s)) | |
748 { | |
749 send_string(s,"gnudoit: Connection refused\ngnudoit: unable to connect to remote"); | |
750 close(s); | |
751 | |
752 printf("Refused connection from %s\004\n", inet_ntoa(peer.sin_addr)); | |
753 return; | |
754 } /* if */ | |
755 | |
756 echo_request(s); | |
442 | 757 |
428 | 758 } /* handle_internet_request */ |
759 #endif /* INTERNET_DOMAIN_SOCKETS */ | |
760 | |
761 | |
762 #ifdef UNIX_DOMAIN_SOCKETS | |
763 /* | |
764 unix_init -- initialize server, returning an unix-domain socket that can | |
765 be listened on. | |
766 */ | |
767 static int | |
768 unix_init (void) | |
769 { | |
770 int ls; /* socket descriptor */ | |
771 struct sockaddr_un server; /* unix socket address */ | |
442 | 772 socklen_t bindlen; |
428 | 773 |
774 if ((ls = socket(AF_UNIX,SOCK_STREAM, 0)) < 0) | |
775 { | |
776 perror(progname); | |
777 fprintf(stderr,"%s: unable to create socket\n",progname); | |
778 exit(1); | |
779 } /* if */ | |
780 | |
781 /* Set up address structure for the listen socket. */ | |
782 #ifdef HIDE_UNIX_SOCKET | |
783 sprintf(server.sun_path,"%s/gsrvdir%d",tmpdir,(int)geteuid()); | |
784 if (mkdir(server.sun_path, 0700) < 0) | |
785 { | |
786 /* assume it already exists, and try to set perms */ | |
787 if (chmod(server.sun_path, 0700) < 0) | |
788 { | |
789 perror(progname); | |
790 fprintf(stderr,"%s: can't set permissions on %s\n", | |
791 progname, server.sun_path); | |
792 exit(1); | |
793 } | |
794 } | |
795 strcat(server.sun_path,"/gsrv"); | |
796 unlink(server.sun_path); /* remove old file if it exists */ | |
797 #else /* HIDE_UNIX_SOCKET */ | |
798 sprintf(server.sun_path,"%s/gsrv%d",tmpdir,(int)geteuid()); | |
799 unlink(server.sun_path); /* remove old file if it exists */ | |
800 #endif /* HIDE_UNIX_SOCKET */ | |
801 | |
802 server.sun_family = AF_UNIX; | |
803 #ifdef HAVE_SOCKADDR_SUN_LEN | |
804 /* See W. R. Stevens "Advanced Programming in the Unix Environment" | |
805 p. 502 */ | |
806 bindlen = (sizeof (server.sun_len) + sizeof (server.sun_family) | |
807 + strlen (server.sun_path) + 1); | |
808 server.sun_len = bindlen; | |
809 #else | |
810 bindlen = strlen (server.sun_path) + sizeof (server.sun_family); | |
811 #endif | |
442 | 812 |
428 | 813 if (bind(ls,(struct sockaddr *)&server,bindlen) < 0) |
814 { | |
815 perror(progname); | |
816 fprintf(stderr,"%s: unable to bind socket\n",progname); | |
817 exit(1); | |
818 } /* if */ | |
819 | |
820 chmod(server.sun_path,0700); /* only this user can send commands */ | |
821 | |
822 if (listen(ls,20) < 0) { | |
823 perror(progname); | |
824 fprintf(stderr,"%s: unable to listen\n",progname); | |
825 exit(1); | |
826 } /* if */ | |
827 | |
828 /* #### there are also better ways of dealing with this when | |
829 sigvec() is present. */ | |
830 #if defined (HAVE_SIGPROCMASK) | |
442 | 831 { |
428 | 832 sigset_t _mask; |
833 sigemptyset (&_mask); | |
834 sigaddset (&_mask, SIGPIPE); | |
835 sigprocmask (SIG_BLOCK, &_mask, NULL); | |
836 } | |
837 #else | |
838 signal(SIGPIPE,SIG_IGN); /* in case user kills client */ | |
839 #endif | |
840 | |
841 return(ls); | |
842 | |
843 } /* unix_init */ | |
844 | |
845 | |
846 /* | |
847 handle_unix_request -- accept a request from a client and send the information | |
848 to stdout (the gnu process). | |
849 */ | |
850 static void | |
851 handle_unix_request (int ls) | |
852 { | |
853 int s; | |
442 | 854 socklen_t len = sizeof (struct sockaddr_un); |
428 | 855 struct sockaddr_un server; /* for unix socket address */ |
856 | |
857 server.sun_family = AF_UNIX; | |
858 | |
440 | 859 if ((s = accept(ls,(struct sockaddr *)&server, &len)) < 0) |
428 | 860 { |
861 perror(progname); | |
862 fprintf(stderr,"%s: unable to accept\n",progname); | |
863 } /* if */ | |
864 | |
865 echo_request(s); | |
442 | 866 |
428 | 867 } /* handle_unix_request */ |
868 #endif /* UNIX_DOMAIN_SOCKETS */ | |
869 | |
870 | |
871 int | |
2286 | 872 main (int UNUSED (argc), char *argv[]) |
428 | 873 { |
874 int chan; /* temporary channel number */ | |
875 #ifdef SYSV_IPC | |
876 struct msgbuf *msgp; /* message buffer */ | |
877 #else | |
878 int ils = -1; /* internet domain listen socket */ | |
879 int uls = -1; /* unix domain listen socket */ | |
880 #endif /* SYSV_IPC */ | |
881 | |
882 progname = argv[0]; | |
883 | |
884 for(chan=3; chan < _NFILE; close(chan++)) /* close unwanted channels */ | |
885 ; | |
886 | |
771 | 887 |
888 #ifdef WIN32_NATIVE | |
889 tmpdir = getenv ("TEMP"); | |
890 if (!tmpdir) | |
891 tmpdir = getenv ("TMP"); | |
892 if (!tmpdir) | |
893 tmpdir = "c:\\"; | |
894 #else | |
428 | 895 #ifdef USE_TMPDIR |
771 | 896 tmpdir = getenv ("TMPDIR"); |
428 | 897 #endif |
898 if (!tmpdir) | |
899 tmpdir = "/tmp"; | |
771 | 900 #endif /* WIN32_NATIVE */ |
428 | 901 #ifdef USE_LITOUT |
902 { | |
903 /* this is to allow ^D to pass to emacs */ | |
904 int d = LLITOUT; | |
905 (void) ioctl(fileno(stdout), TIOCLBIS, &d); | |
906 } | |
907 #endif | |
908 | |
909 #ifdef SYSV_IPC | |
910 ipc_init(&msgp); /* get a msqid to listen on, and a message buffer */ | |
911 #endif /* SYSV_IPC */ | |
912 | |
913 #ifdef INTERNET_DOMAIN_SOCKETS | |
914 ils = internet_init(); /* get an internet domain socket to listen on */ | |
915 #endif /* INTERNET_DOMAIN_SOCKETS */ | |
916 | |
917 #ifdef UNIX_DOMAIN_SOCKETS | |
918 uls = unix_init(); /* get a unix domain socket to listen on */ | |
919 #endif /* UNIX_DOMAIN_SOCKETS */ | |
920 | |
921 while (1) { | |
922 #ifdef SYSV_IPC | |
923 handle_ipc_request(msgp); | |
924 #else /* NOT SYSV_IPC */ | |
925 fd_set rmask; | |
926 FD_ZERO(&rmask); | |
927 FD_SET(fileno(stdin), &rmask); | |
928 if (uls >= 0) | |
929 FD_SET(uls, &rmask); | |
930 if (ils >= 0) | |
931 FD_SET(ils, &rmask); | |
442 | 932 |
933 if (select(max2(fileno(stdin),max2(uls,ils)) + 1, &rmask, | |
428 | 934 (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL) < 0) |
935 { | |
936 perror(progname); | |
937 fprintf(stderr,"%s: unable to select\n",progname); | |
442 | 938 return 1; |
428 | 939 } /* if */ |
940 | |
941 #ifdef UNIX_DOMAIN_SOCKETS | |
942 if (uls > 0 && FD_ISSET(uls, &rmask)) | |
943 handle_unix_request(uls); | |
944 #endif | |
945 | |
946 #ifdef INTERNET_DOMAIN_SOCKETS | |
947 if (ils > 0 && FD_ISSET(ils, &rmask)) | |
948 handle_internet_request(ils); | |
949 #endif /* INTERNET_DOMAIN_SOCKETS */ | |
950 | |
951 if (FD_ISSET(fileno(stdin), &rmask)) /* from stdin (gnu process) */ | |
952 handle_response(); | |
953 #endif /* NOT SYSV_IPC */ | |
442 | 954 } /* while (1) */ |
428 | 955 } /* main */ |
956 | |
957 #endif /* SYSV_IPC || UNIX_DOMAIN_SOCKETS || INTERNET_DOMAIN_SOCKETS */ |