|
|
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.