|
|
1.1 root 1: #include "mgr.h"
2: #include <sys/param.h>
3: #include <errno.h>
4: #include <ctype.h>
5: #include <signal.h>
6: #include <sys/filio.h>
7: #include <libc.h>
8: #include <pwd.h>
9:
10: extern int debug;
11:
12: static fd_set listenset; /* set of fd's on which we are listening */
13: static Service *svchead; /* head of services */
14: static Service *nsvchead; /* new head of services */
15: static int toannounce; /* true if there's anything to announce */
16:
17: /*
18: * Parse a service definition line. The line is of the form:
19: * `service action+action+action+... source'
20: */
21: Service *
22: newservice(cp)
23: char *cp;
24: {
25: # define MAXACTS 32
26: char *arg;
27: char *acts[MAXACTS];
28: Service *sp=(Service *)malloc(sizeof(Service));
29: int i, n, plus;
30: Action *lap;
31:
32: if(sp==NULL) {
33: logevent("out of memory parsing service\n");
34: return NULL;
35: }
36: sp->ap = NULL;
37: sp->listen = -1;
38: sp->name = NULL;
39: sp->next = (Service *)NULL;
40: sp->accept = 0;
41: sp->lasttime = 1;
42: sp->from = NULL;
43: sp->same = NULL;
44:
45: /* find service name */
46: for(; isspace(*cp); cp++)
47: ;
48: for(arg=cp; *arg && !isspace(*arg); arg++)
49: ;
50: if(isspace(*arg))
51: *arg++ = '\0';
52: sp->name = strdup(cp);
53:
54: /*
55: * separate actions. actions are separated by '+'s and
56: * whitespace. actions may have arguments in ()'s.
57: */
58: for(; isspace(*arg); arg++)
59: ;
60: for(plus=1, n=0; *arg && n<MAXACTS && plus; n++) {
61: /* find next action */
62: acts[n] = arg;
63: for(plus = 0;;arg++)
64: if(*arg=='(') {
65: for(;;arg++)
66: if(*arg=='\\' && *(arg+1)==')')
67: arg++;
68: else if(*arg==')')
69: break;
70: } else if(*arg=='+') {
71: plus = 1;
72: *arg++ = '\0';
73: break;
74: } else if(isspace(*arg)) {
75: *arg++ = '\0';
76: break;
77: } else if(*arg=='\0')
78: break;
79:
80: /* dump whitespace */
81: for(;; arg++)
82: if(*arg=='+')
83: plus = 1;
84: else if(!isspace(*arg))
85: break;
86: }
87: if (n <= 0) {
88: logevent("service with no action `%s'\n", cp);
89: freeservice(sp);
90: return NULL;
91: }
92:
93: /* parse actions */
94: for(lap=NULL, i=0; i<n; i++) {
95: if (lap==NULL)
96: sp->ap = lap = newaction(acts[i]);
97: else
98: lap = lap->next = newaction(acts[i]);
99: if (lap==NULL) {
100: freeservice(sp);
101: return NULL;
102: }
103: lap->next = NULL;
104: sp->accept |= lap->accept;
105: }
106:
107: /* look for source specifier */
108: if(*arg){
109: acts[0] = arg;
110: while(*arg && !isspace(*arg))
111: arg++;
112: *arg = 0;
113: if((sp->from=newre(acts[0]))==NULL){
114: logevent("illegal reg exp in service `%s %s'\n", sp->name,
115: acts[0]);
116: freeservice(sp);
117: return NULL;
118: }
119: }
120:
121: if(sp->from)
122: logevent("newservice(%s for %s)\n", sp->name, acts[0]);
123: else
124: logevent("newservice(%s)\n", sp->name);
125: return sp;
126: }
127:
128: freeservice(sp)
129: Service *sp;
130: {
131: if(sp==NULL)
132: return;
133: if(sp->listen>=0) {
134: logevent("denouncing %s\n", sp->name);
135: close(sp->listen);
136: FD_CLR(sp->listen, listenset);
137: }
138: if(sp->name!=NULL)
139: free(sp->name);
140: for(; sp->ap!=NULL; sp->ap=sp->ap->next)
141: freeaction(sp->ap);
142: if(sp->from)
143: freere(sp->from);
144: if(sp->same)
145: freeservice(sp->same);
146: free((char *)sp);
147: }
148:
149: /*
150: * Add a service to the ones for which we are listening
151: */
152: addservice(sp)
153: Service *sp;
154: {
155: Service *p;
156:
157: /* look through new list for a previous version */
158: for(p=nsvchead; p; p=p->next)
159: if (strcmp(sp->name, p->name)==0){
160: /* string after previous versions */
161: for(; p->same; p=p->same)
162: ;
163: p->same = sp;
164: return 0;
165: }
166:
167: /* look for an announced version of the service */
168: for(p=svchead; p; p=p->next)
169: if (strcmp(sp->name, p->name)==0)
170: break;
171:
172: /* inherit fd from old service */
173: if (p) {
174: sp->listen = p->listen;
175: p->listen = -1;
176: } else
177: toannounce=1;
178:
179: /* add the new service */
180: sp->next = nsvchead;
181: nsvchead = sp;
182: return 0;
183: }
184:
185: /*
186: * Start the listening process on any services not already listening.
187: */
188: startsvcs()
189: {
190: Service *p, *np;
191:
192: /* denounce old services */
193: for(p=svchead; p; p=np) {
194: np = p->next;
195: freeservice(p);
196: }
197:
198: /* install new services */
199: svchead = nsvchead;
200: nsvchead = (Service *)NULL;
201:
202: announcesvcs();
203: }
204:
205: /*
206: * Announce any services not already listening
207: */
208: announcesvcs()
209: {
210: Service *p;
211:
212:
213: /* announce new services */
214: toannounce=0;
215: for(p=svchead; p; p=p->next) {
216: if (p->listen>=0)
217: continue;
218: logevent("announcing %s\n", p->name);
219: p->listen = ipccreat(p->name, "light");
220: if (p->listen<0) {
221: logevent("failed\n");
222: toannounce=1;
223: continue;
224: }
225: chmod(p->name, 0666);
226: FD_SET(p->listen, listenset);
227: }
228: }
229:
230: /*
231: * Reset all services
232: */
233: resetsvcs()
234: {
235: Service *p, *np;
236:
237: /* shut down all listeners */
238: logevent("resetsrvcs()\n");
239: for(p=svchead; p; p=np) {
240: logevent("retracting %s\n", p->name);
241: np = p->next;
242: freeservice(p);
243: }
244: svchead = (Service *)NULL;
245: readfiles();
246: }
247:
248: /*
249: * An alarm during a listen
250: */
251: int
252: dingaling()
253: {
254: signal(SIGALRM, dingaling);
255: logevent("timout in listen\n");
256: alarm(5);
257: }
258:
259: /*
260: * A Zombie exists
261: */
262: int
263: sigchild()
264: {
265: }
266:
267: /*
268: * Get a request and vector to the appropriate service
269: */
270: Request *
271: listen()
272: {
273: fd_set readset;
274: Service *sp;
275: static Request rp;
276: ipcinfo *ip;
277: int n;
278: int (*sigalrm)();
279: long lastcheck = 0;
280: static char line[ARB];
281: struct passwd *pwsearch();
282:
283: for(;;) {
284: /*
285: * clean up utmp and make entries to wtmp
286: */
287: checkkids();
288:
289: /*
290: * wait for
291: * - a child to die
292: * - a call in
293: * - 30 seconds to elapse
294: */
295: signal(SIGCHLD, sigchild);
296: readset = listenset;
297: n = select(NOFILE, &readset, (fd_set *)NULL, 30*1000);
298: signal(SIGCHLD, SIG_IGN);
299:
300: /*
301: * every 2 minutes see if the configuration has
302: * changed. this is fairly costly so don't do it too
303: * often.
304: */
305: if(time((long *)0) - lastcheck > 2*60){
306: pwsearch((char *)0, 0, line); /* prime the pump */
307: if(checkfiles())
308: readfiles();
309: lastcheck = time((long *)0);
310: }
311: if(toannounce)
312: announcesvcs();
313: if(n<=0)
314: continue;
315:
316: /*
317: * a call has arrived
318: */
319: if(debug)
320: logtime("request\n");
321: for(sp=svchead; sp; sp=sp->next) {
322: if (sp->listen<0)
323: continue;
324: if (FD_ISSET(sp->listen, readset))
325: break;
326: }
327: if (!sp) {
328: logevent("listen on bad fd\n");
329: resetsvcs();
330: continue;
331: }
332: sigalrm=signal(SIGALRM, dingaling);
333: alarm(5);
334: if ((ip = ipclisten(sp->listen)) == NULL) {
335: logevent("%s: bad listen: %s %d\n", sp->name,
336: errstr, errno);
337: close(sp->listen);
338: FD_CLR(sp->listen, listenset);
339: sp->listen = -1;
340: toannounce=1;
341: signal(SIGALRM, SIG_IGN); /* close race */
342: alarm(0);
343: signal(SIGALRM, sigalrm);
344: continue;
345: }
346: if(sp->ap->func == 0){
347: close(ipcaccept(ip));
348: logstatus("in", ip);
349: readfiles();
350: continue;
351: }
352: signal(SIGALRM, SIG_IGN); /* close race */
353: alarm(0);
354: signal(SIGALRM, sigalrm);
355: if (ip->machine==NULL || ip->user==NULL) {
356: ipcreject(ip, EACCES, "no machine or user name");
357: logstatus("in", ip);
358: continue;
359: }
360: for(; sp; sp = sp->same){
361: if(!sp->from)
362: break;
363: if(execre(sp->from, ip->machine, (regsubexp *)0, 0))
364: break;
365: }
366: if(sp==0){
367: ipcreject(ip, EACCES, "no such service");
368: logstatus("in", ip);
369: continue;
370: }
371: if(!(sp->accept) && ipcaccept(ip)<0) {
372: logstatus("in", ip);
373: continue;
374: }
375: #ifdef PEX
376: ioctl(ip->cfd, FIOANPX, 0);
377: #endif PEX
378: return(newrequest(ip, sp));
379: }
380: }
381:
382: /*
383: * Close all service fds
384: */
385: closesvcs()
386: {
387: Service *p;
388:
389: toannounce=1;
390: for(p=svchead; p; p=p->next)
391: close(p->listen);
392: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.