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