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