void KillOldLink(char *name, char *defs) { char linkbuf[CF_BUFSIZE]; char linkpath[CF_BUFSIZE],*sp; struct stat statbuf; Debug("KillOldLink(%s)\n",name); memset(linkbuf,0,CF_BUFSIZE); memset(linkpath,0,CF_BUFSIZE); if (readlink(name,linkbuf,CF_BUFSIZE-1) == -1) { snprintf(g_output,CF_BUFSIZE*2, "(Can't read link %s while checking for deadlinks)\n",name); CfLog(cfverbose,g_output,""); return; } if (linkbuf[0] != '/') { strcpy(linkpath,name); /* Get path to link */ for (sp = linkpath+strlen(linkpath); (*sp != '/') && (sp >= linkpath); sp-- ) { *sp = '\0'; } } strcat(linkpath,linkbuf); CompressPath(g_vbuff,linkpath); /* link points nowhere */ if (stat(g_vbuff,&statbuf) == -1) { if (g_killoldlinks || g_debug || g_d2) { snprintf(g_output, CF_BUFSIZE*2, "%s is a link which points to %s, " "but that file doesn't seem to exist\n", name, g_vbuff); CfLog(cfverbose,g_output,""); } if (g_killoldlinks) { snprintf(g_output,CF_BUFSIZE*2,"Removing dead link %s\n",name); CfLog(cfinform,g_output,""); if (! g_dontdo) { /* May not work on a client-mounted system ! */ unlink(name); AddMultipleClasses(defs); } } } }
void DoHardLink(char *from, char *to, char *defines) { if (g_dontdo) { printf("Hardlink files %s -> %s\n\n",from,to); } else { snprintf(g_output, CF_BUFSIZE*2, "Hardlinking files %s -> %s\n", from, to); CfLog(cfinform,g_output,""); if (link(to,from) == -1) { CfLog(cferror,"","link"); } else { AddMultipleClasses(defines); } } }
int DoLink(char *from, char *to, char *defines) { if (g_dontdo) { printf("cfagent: Need to link files %s -> %s\n",from,to); } else { snprintf(g_output,CF_BUFSIZE*2,"Linking files %s -> %s\n",from,to); CfLog(cfinform,g_output,""); if (symlink(to,from) == -1) { snprintf(g_output,CF_BUFSIZE*2,"Couldn't link %s to %s\n",to,from); CfLog(cferror,g_output,"symlink"); return false; } else { AddMultipleClasses(defines); return true; } } return true; }
/* should return true if 'to' found */ int HardLinkFiles(char *from, char *to, struct Item *inclusions, struct Item *exclusions, struct Item *copy, short nofile, struct Link *ptr) { struct stat frombuf,tobuf; char saved[CF_BUFSIZE], *lastnode; struct UidList fakeuid; struct Image ip; char stamp[CF_BUFSIZE]; time_t STAMPNOW; STAMPNOW = time((time_t *)NULL); for (lastnode = from+strlen(from); *lastnode != '/'; lastnode--) { } lastnode++; if (inclusions != NULL && !IsWildItemIn(inclusions,lastnode)) { Verbose("%s: Skipping non-included pattern %s\n",g_vprefix,from); return true; } if (IsWildItemIn(g_vexcludelink,lastnode) || IsWildItemIn(exclusions,lastnode)) { Verbose("%s: Skipping excluded pattern %s\n",g_vprefix,from); return true; } if (IsWildItemIn(g_vcopylinks,lastnode) || IsWildItemIn(copy,lastnode)) { fakeuid.uid = CF_SAME_OWNER; fakeuid.next = NULL; ip.plus = CF_SAMEMODE; ip.minus = CF_SAMEMODE; ip.uid = &fakeuid; ip.gid = (struct GidList *) &fakeuid; ip.action = "do"; ip.recurse = 0; ip.type = 't'; ip.backup = true; ip.plus_flags = 0; ip.minus_flags = 0; ip.exclusions = NULL; ip.symlink = NULL; Verbose("%s: Link item %s marked for copying instead\n", g_vprefix, from); CheckImage(to,from,&ip); return true; } if (stat(to,&tobuf) == -1) { /* no error warning, since the higher level routine uses this */ return(false); } if (! S_ISREG(tobuf.st_mode)) { snprintf(g_output, CF_BUFSIZE*2, "%s: will only hard link regular files " "and %s is not regular\n", g_vprefix, to); CfLog(cfsilent,g_output,""); return true; } Debug2("Trying to (hard) link %s -> %s\n",from,to); if (stat(from,&frombuf) == -1) { DoHardLink(from,to,ptr->defines); return true; } /* * Both files exist, but are they the same file? POSIX says the * files could be on different devices, but unix doesn't allow this * behaviour so the tests below are theoretical... */ if (frombuf.st_ino != tobuf.st_ino && frombuf.st_dev != frombuf.st_dev) { Verbose("If this is POSIX, unable to determine if %s is " "hard link is correct\n", from); Verbose("since it points to a different filesystem!\n"); if (frombuf.st_mode == tobuf.st_mode && frombuf.st_size == tobuf.st_size) { snprintf(g_output,CF_BUFSIZE*2, "Hard link (%s->%s) on different device APPEARS okay\n", from,to); CfLog(cfverbose,g_output,""); AddMultipleClasses(ptr->elsedef); return true; } } if (frombuf.st_ino == tobuf.st_ino && frombuf.st_dev == frombuf.st_dev) { snprintf(g_output,CF_BUFSIZE*2, "Hard link (%s->%s) exists and is okay.\n",from,to); CfLog(cfverbose,g_output,""); AddMultipleClasses(ptr->elsedef); return true; } snprintf(g_output,CF_BUFSIZE*2, "%s does not appear to be a hard link to %s\n",from,to); CfLog(cfinform,g_output,""); if (g_enforcelinks) { snprintf(g_output, CF_BUFSIZE*2, "Moving %s to %s.%s\n", from, from, CF_SAVED); CfLog(cfinform,g_output,""); if (g_dontdo) { return true; } saved[0] = '\0'; strcpy(saved,from); sprintf(stamp, "_%d_%s", g_cfstarttime, CanonifyName(ctime(&STAMPNOW))); strcat(saved,stamp); strcat(saved,CF_SAVED); if (rename(from,saved) == -1) { perror("rename"); return(true); } DoHardLink(from,to,ptr->defines); } return(true); }
/* should return true if 'to' found */ int LinkFiles(char *from,char *to_tmp, struct Item *inclusions,struct Item *exclusions,struct Item *copy, short nofile,struct Link *ptr) { struct stat buf,savebuf; char to[CF_BUFSIZE], linkbuf[CF_BUFSIZE]; char saved[CF_BUFSIZE],absto[CF_BUFSIZE],*lastnode; struct UidList fakeuid; struct Image ip; char stamp[CF_BUFSIZE]; time_t STAMPNOW; STAMPNOW = time((time_t *)NULL); memset(to,0,CF_BUFSIZE); memset(&ip,0, sizeof(ip)); /* links without a directory reference */ if ((*to_tmp != '/') && (*to_tmp != '.')) { strcpy(to,"./"); } if (strlen(to_tmp)+3 > CF_BUFSIZE) { printf("%s: CF_BUFSIZE boundaries exceeded in LinkFiles(%s->%s)\n", g_vprefix,from,to_tmp); return false; } strcat(to,to_tmp); Debug2("Linkfiles(%s,%s)\n",from,to); for (lastnode = from+strlen(from); *lastnode != '/'; lastnode--) { } lastnode++; if (IgnoredOrExcluded(links,lastnode,inclusions,exclusions)) { Verbose("%s: Skipping non-included pattern %s\n",g_vprefix,from); return true; } if (IsWildItemIn(g_vcopylinks,lastnode) || IsWildItemIn(copy,lastnode)) { fakeuid.uid = CF_SAME_OWNER; fakeuid.next = NULL; ip.plus = CF_SAMEMODE; ip.minus = CF_SAMEMODE; ip.uid = &fakeuid; ip.gid = (struct GidList *) &fakeuid; ip.action = "do"; ip.recurse = 0; ip.type = 't'; ip.defines = ptr->defines; ip.elsedef = ptr->elsedef; ip.backup = true; ip.exclusions = NULL; ip.inclusions = NULL; ip.symlink = NULL; ip.classes = NULL; ip.plus_flags = 0; ip.size = CF_NOSIZE; ip.linktype = 's'; ip.minus_flags = 0; ip.server = strdup("localhost"); Verbose("%s: Link item %s marked for copying instead\n", g_vprefix, from); MakeDirectoriesFor(to,'n'); CheckImage(to,from,&ip); free(ip.server); return true; } /* relative path, must still check if exists */ if (*to != '/') { Debug("Relative link destination detected: %s\n",to); strcpy(absto,AbsLinkPath(from,to)); Debug("Absolute path to relative link = %s, from %s\n",absto,from); } else { strcpy(absto,to); } if (!nofile) { if (stat(absto,&buf) == -1) { /* no error warning, since the higher level routine uses this */ return(false); } } Debug2("Trying to link %s -> %s (%s)\n",from,to,absto); if (lstat(from,&buf) == 0) { if (! S_ISLNK(buf.st_mode) && ! g_enforcelinks) { snprintf(g_output,CF_BUFSIZE*2,"Error linking %s -> %s\n",from,to); CfLog(cfsilent,g_output,""); snprintf(g_output, CF_BUFSIZE*2, "Cannot make link: %s exists and is not a link! " "(uid %d)\n", from, buf.st_uid); CfLog(cfsilent,g_output,""); return(true); } if (S_ISREG(buf.st_mode) && g_enforcelinks) { snprintf(g_output, CF_BUFSIZE*2, "Moving %s to %s%s\n", from, from, CF_SAVED); CfLog(cfsilent,g_output,""); if (g_dontdo) { return true; } saved[0] = '\0'; strcpy(saved,from); sprintf(stamp, "_%d_%s", g_cfstarttime, CanonifyName(ctime(&STAMPNOW))); strcat(saved,stamp); strcat(saved,CF_SAVED); if (rename(from,saved) == -1) { snprintf(g_output, CF_BUFSIZE*2, "Can't rename %s to %s\n", from,saved); CfLog(cferror,g_output,"rename"); return(true); } if (Repository(saved,g_vrepository)) { unlink(saved); } } if (S_ISDIR(buf.st_mode) && g_enforcelinks) { snprintf(g_output,CF_BUFSIZE*2,"Moving directory %s to %s%s.dir\n", from,from,CF_SAVED); CfLog(cfsilent,g_output,""); if (g_dontdo) { return true; } saved[0] = '\0'; strcpy(saved,from); sprintf(stamp, "_%d_%s", g_cfstarttime, CanonifyName(ctime(&STAMPNOW))); strcat(saved,stamp); strcat(saved,CF_SAVED); strcat(saved,".dir"); if (stat(saved,&savebuf) != -1) { snprintf(g_output,CF_BUFSIZE*2, "Couldn't save directory %s, " "since %s exists already\n", from,saved); CfLog(cferror,g_output,""); snprintf(g_output,CF_BUFSIZE*2, "Unable to force link to " "existing directory %s\n",from); CfLog(cferror,g_output,""); return true; } if (rename(from,saved) == -1) { snprintf(g_output, CF_BUFSIZE*2, "Can't rename %s to %s\n", from,saved); CfLog(cferror,g_output,"rename"); return(true); } } } memset(linkbuf,0,CF_BUFSIZE); if (readlink(from,linkbuf,CF_BUFSIZE-1) == -1) { /* link doesn't exist */ if (! MakeDirectoriesFor(from,'n')) { snprintf(g_output,CF_BUFSIZE*2, "Couldn't build directory tree up to %s!\n",from); CfLog(cfsilent,g_output,""); snprintf(g_output,CF_BUFSIZE*2, "One element was a plain file, not a directory!\n"); CfLog(cfsilent,g_output,""); return(true); } } else { int off1 = 0, off2 = 0; DeleteSlash(linkbuf); /* Ignore ./ at beginning */ if (strncmp(linkbuf,"./",2) == 0) { off1 = 2; } if (strncmp(to,"./",2) == 0) { off2 = 2; } if (strcmp(linkbuf+off1,to+off2) != 0) { if (g_enforcelinks) { snprintf(g_output,CF_BUFSIZE*2,"Removing link %s\n",from); CfLog(cfinform,g_output,""); if (!g_dontdo) { if (unlink(from) == -1) { perror("unlink"); return true; } return DoLink(from,to,ptr->defines); } } else { snprintf(g_output,CF_BUFSIZE*2, "Old link %s points somewhere else. Doing nothing!\n", from); CfLog(cfsilent,g_output,""); snprintf(g_output, CF_BUFSIZE*2, "(Link points to %s not %s)\n\n", linkbuf,to); CfLog(cfsilent,g_output,""); return(true); } } else { snprintf(g_output, CF_BUFSIZE*2, "Link (%s->%s) exists.\n", from, to_tmp); CfLog(cfverbose,g_output,""); if (!nofile) { /* Check whether link points somewhere */ KillOldLink(from,ptr->defines); return true; } AddMultipleClasses(ptr->elsedef); return(true); } } return DoLink(from,to,ptr->defines); }
void DoProcessCheck(struct Process *pp,struct Item *procdata) { char line[CF_BUFSIZE]; int matches=0,dosignals=true; mode_t maskval; struct stat statbuf; struct Item *killlist = NULL; matches = FindMatches(pp,procdata,&killlist); if (matches > 0) { Verbose("Defining classes %s\n",pp->defines); AddMultipleClasses(pp->defines); } else { Verbose("Defining classes %s\n",pp->elsedef); AddMultipleClasses(pp->elsedef); } if (pp->matches >= 0) { if (pp->action == 'm') { dosignals = false; } switch (pp->comp) { case '=': if (matches != (int)pp->matches) { snprintf(g_output,CF_BUFSIZE*2, "%d processes matched %s (should be %d)\n", matches,pp->expr,pp->matches); CfLog(cferror,g_output,""); if (pp->action == 'm') { dosignals = true; } } break; case '>': if (matches < (int)pp->matches) { snprintf(g_output,CF_BUFSIZE*2, "%d processes matched %s (should be >=%d)\n", matches,pp->expr,pp->matches); CfLog(cferror,g_output,""); if (pp->action == 'm') { dosignals = true; } } break; case '<': if (matches > (int)pp->matches) { snprintf(g_output,CF_BUFSIZE*2, "%d processes matched %s (should be <=%d)\n", matches,pp->expr,pp->matches); CfLog(cferror,g_output,""); if (pp->action == 'm') { dosignals = true; } } } } if (dosignals) { DoSignals(pp,killlist); } DeleteItemList(killlist); if ((pp->action == 'm') && !dosignals && (matches != 0)) { Verbose("%s: Process matches found for %s - no restart necessary\n", g_vprefix,pp->expr); return; } if (strlen(pp->restart) != 0) { char argz[256]; Verbose("Existing restart sequence found (%s)\n",pp->restart); if ((matches != 0) && (pp->signal != cfkill) && (pp->signal != cfterm)) { Verbose("%s: Process matches found for %s - " "no restart necessary\n", g_vprefix,pp->expr); return; } sscanf(pp->restart,"%255s",argz); if ((stat(argz,&statbuf) != -1) && (statbuf.st_mode & 0111 == 0)) { snprintf(g_output, CF_BUFSIZE, "Restart sequence %s could not be executed " "(mode=%o), while searching (%s)", pp->restart, statbuf.st_mode & 7777, pp->expr); CfLog(cferror,g_output,""); return; } snprintf(g_output, CF_BUFSIZE*2, "Executing shell command: %s\n", pp->restart); CfLog(cfinform,g_output,""); if (g_dontdo) { return; } Verbose ("(Setting umask to %o)\n",pp->umask); maskval = umask(pp->umask); if (pp->umask == 0) { snprintf(g_output,CF_BUFSIZE*2, "Programming %s running with umask 0! Use umask= to set\n", pp->restart); CfLog(cfsilent,g_output,""); } if (pp->useshell == 'y') { if ((PIPE = cfpopen_shsetuid(pp->restart,"r", pp->uid,pp->gid,pp->chdir,pp->chroot)) == NULL) { snprintf(g_output,CF_BUFSIZE*2, "Process restart execution failed on %s\n",pp->restart); CfLog(cferror,g_output,"popen"); return; } } else { if ((PIPE = cfpopensetuid(pp->restart,"r",pp->uid,pp->gid, pp->chdir,pp->chroot)) == NULL) { snprintf(g_output,CF_BUFSIZE*2, "Process restart execution failed on %s\n",pp->restart); CfLog(cferror,g_output,"popen"); return; } } DEADLOCK = false; while (!feof(PIPE)) { /* dumb shell */ if (pp->useshell == 'd') { fgets(line,1,PIPE); break; } ReadLine(line,CF_BUFSIZE,PIPE); if (feof(PIPE) || ferror(PIPE)) { break; } if (strstr(line,"cfengine-die")) { break; } /* patch for ERESTARTSYSTEM bug in popen */ if (strstr(line,"cfd: start") || DEADLOCK) { break; } snprintf(g_output,CF_BUFSIZE*2,"Restart: %s",line); CfLog(cfinform,g_output,""); } if (pp->useshell == 'y') { pclose(PIPE); } else { cfpclose(PIPE); } snprintf(g_output,CF_BUFSIZE*2,"(Done with %s)\n",pp->restart); CfLog(cfinform,g_output,""); umask(maskval); } }
void SetDefaultRoute() { int sk, defaultokay = 1; struct sockaddr_in sindst,singw; char oldroute[INET_ADDRSTRLEN]; char routefmt[CF_MAXVARSIZE]; /* These OSes have these structs defined but use the route command */ # if defined DARWIN || defined FREEBSD || defined OPENBSD || defined SOLARIS # undef HAVE_RTENTRY # undef HAVE_ORTENTRY # endif # ifdef HAVE_ORTENTRY struct ortentry route; # else # if HAVE_RTENTRY struct rtentry route; # endif # endif FILE *pp; Verbose("Looking for a default route...\n"); if (!IsPrivileged()) { snprintf(OUTPUT,CF_BUFSIZE*2,"Only root can set a default route."); CfLog(cfinform,OUTPUT,""); return; } if (VDEFAULTROUTE == NULL) { Verbose("cfengine: No default route is defined. Ignoring the routing tables.\n"); return; } if ((pp = cfpopen(VNETSTAT[VSYSTEMHARDCLASS],"r")) == NULL) { snprintf(OUTPUT,CF_BUFSIZE*2,"Failed to open pipe from %s\n",VNETSTAT[VSYSTEMHARDCLASS]); CfLog(cferror,OUTPUT,"popen"); return; } while (!feof(pp)) { ReadLine(VBUFF,CF_BUFSIZE,pp); Debug("LINE: %s = %s?\n",VBUFF,VDEFAULTROUTE->name); if ((strncmp(VBUFF,"default",7) == 0)||(strncmp(VBUFF,"0.0.0.0",7) == 0)) { /* extract the default route */ /* format: default|0.0.0.0 <whitespace> route <whitespace> etc */ if ((sscanf(VBUFF, "%*[default0. ]%s%*[ ]", &oldroute)) == 1) { if ((strncmp(VDEFAULTROUTE->name, oldroute, INET_ADDRSTRLEN)) == 0) { Verbose("cfengine: default route is already set to %s\n",VDEFAULTROUTE->name); defaultokay = 1; break; } else { Verbose("cfengine: default route is set to %s, but should be %s.\n",oldroute,VDEFAULTROUTE->name); defaultokay = 2; break; } } } else { Debug("No default route is yet registered\n"); defaultokay = 0; } } cfpclose(pp); if (defaultokay == 1) { Verbose("Default route is set and agrees with conditional policy\n"); return; } if (defaultokay == 0) { AddMultipleClasses("no_default_route"); } if (IsExcluded(VDEFAULTROUTE->classes)) { Verbose("cfengine: No default route is applicable. Ignoring the routing tables.\n"); return; } CfLog(cferror,"The default route is incorrect, trying to correct\n",""); if ( strcmp(VROUTE[VSYSTEMHARDCLASS], "-") != 0 ) { Debug ("Using route shell commands to set default route\n"); if (defaultokay == 2) { if (! DONTDO) { /* get the route command and the format for the delete argument */ snprintf(routefmt,CF_MAXVARSIZE,"%s %s",VROUTE[VSYSTEMHARDCLASS],VROUTEDELFMT[VSYSTEMHARDCLASS]); snprintf(VBUFF,CF_MAXVARSIZE,routefmt,"default",VDEFAULTROUTE->name); if (ShellCommandReturnsZero(VBUFF,false)) { CfLog(cfinform,"Removing old default route",""); CfLog(cfinform,VBUFF,""); } else { CfLog(cferror,"Error removing route",""); } } } if (! DONTDO) { snprintf(routefmt,CF_MAXVARSIZE,"%s %s",VROUTE[VSYSTEMHARDCLASS],VROUTEADDFMT[VSYSTEMHARDCLASS]); snprintf(VBUFF,CF_MAXVARSIZE,routefmt,"default",VDEFAULTROUTE->name); if (ShellCommandReturnsZero(VBUFF,false)) { CfLog(cfinform,"Setting default route",""); CfLog(cfinform,VBUFF,""); } else { CfLog(cferror,"Error setting route",""); } } return; } else { #if defined HAVE_RTENTRY || defined HAVE_ORTENTRY Debug ("Using route ioctl to set default route\n"); if ((sk = socket(AF_INET,SOCK_RAW,0)) == -1) { CfLog(cferror,"System class: ", CLASSTEXT[VSYSTEMHARDCLASS]); CfLog(cferror,"","Error in SetDefaultRoute():"); perror("cfengine: socket"); } else { sindst.sin_family = AF_INET; singw.sin_family = AF_INET; sindst.sin_addr.s_addr = INADDR_ANY; singw.sin_addr.s_addr = inet_addr(VDEFAULTROUTE->name); route.rt_dst = *(struct sockaddr *)&sindst; /* This disgusting method is necessary */ route.rt_gateway = *(struct sockaddr *)&singw; route.rt_flags = RTF_GATEWAY; if (! DONTDO) { if (ioctl(sk,SIOCADDRT, (caddr_t) &route) == -1) /* Get the device status flags */ { CfLog(cferror,"Error setting route:",""); perror("cfengine: ioctl SIOCADDRT:"); } else { CfLog(cferror,"Setting default route.\n",""); snprintf(OUTPUT,CF_BUFSIZE*2,"I'm setting it to %s\n",VDEFAULTROUTE->name); CfLog(cferror,OUTPUT,""); } } } #else /* Socket routing - don't really know how to do this yet */ Verbose("Sorry don't know how to do routing on this platform\n"); #endif } }
void PersistentClassesToHeap() { DBT key,value; DB *dbp; DBC *dbcp; DB_ENV *dbenv = NULL; int ret; time_t now = time(NULL); struct CfState q; char filename[CF_BUFSIZE]; Banner("Loading persistent classes"); snprintf(filename,CF_BUFSIZE,"%s/state/%s",VLOCKDIR,CF_STATEDB_FILE); if ((errno = db_create(&dbp,dbenv,0)) != 0) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open checksum database %s\n",filename); CfLog(cferror,OUTPUT,"db_open"); return; } #ifdef CF_OLD_DB if ((errno = (dbp->open)(dbp,filename,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #else if ((errno = (dbp->open)(dbp,NULL,filename,NULL,DB_BTREE,DB_CREATE,0644)) != 0) #endif { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open persistent state database %s\n",filename); CfLog(cferror,OUTPUT,"db_open"); dbp->close(dbp,0); return; } /* Acquire a cursor for the database. */ if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) { CfLog(cferror,"Error reading from persistent state database",""); dbp->err(dbp, ret, "DB->cursor"); return; } /* Initialize the key/data return pair. */ memset(&key, 0, sizeof(key)); memset(&value, 0, sizeof(value)); /* Walk through the database and print out the key/data pairs. */ while (dbcp->c_get(dbcp, &key, &value, DB_NEXT) == 0) { memcpy((void *)&q,value.data,sizeof(struct CfState)); Debug(" - Found key %s...\n",key.data); if (now > q.expires) { Verbose(" Persistent class %s expired\n",key.data); if ((errno = dbp->del(dbp,NULL,&key,0)) != 0) { CfLog(cferror,"","db_store"); } } else { Verbose(" Persistent class %s for %d more minutes\n",key.data,(q.expires-now)/60); Verbose(" Adding persistent class %s to heap\n",key.data); AddMultipleClasses(key.data); } } dbcp->c_close(dbcp); dbp->close(dbp,0); Banner("Loaded persistent memory"); }
int CheckForModule(char *actiontxt,char *args) { struct stat statbuf; char line[CF_BUFSIZE],command[CF_EXPANDSIZE],name[CF_MAXVARSIZE],content[CF_BUFSIZE],ebuff[CF_EXPANDSIZE],*sp; FILE *pp; int print; if (NOMODULES) { return false; } if (*actiontxt == '/') { snprintf(OUTPUT,CF_BUFSIZE,"Absolute module path (%s) should be named relative to the authorized module directory",actiontxt); CfLog(cferror,OUTPUT,""); } if (GetMacroValue(CONTEXTID,"moduledirectory")) { ExpandVarstring("$(moduledirectory)",ebuff,NULL); } else { snprintf(ebuff,CF_BUFSIZE,"%s/modules",VLOCKDIR); } AddSlash(ebuff); strcat(ebuff,actiontxt); if (stat(ebuff,&statbuf) == -1) { snprintf(OUTPUT,CF_BUFSIZE*2,"(Plug-in %s not found)",ebuff); Banner(OUTPUT); return false; } if ((statbuf.st_uid != 0) && (statbuf.st_uid != getuid())) { snprintf(OUTPUT,CF_BUFSIZE*2,"Module %s was not owned by uid=%d executing cfagent\n",ebuff,getuid()); CfLog(cferror,OUTPUT,""); return false; } snprintf(OUTPUT,CF_BUFSIZE*2,"Plug-in `%s\'",actiontxt); Banner(OUTPUT); strcat(ebuff," "); if (BufferOverflow(ebuff,args)) { snprintf(OUTPUT,CF_BUFSIZE*2,"Culprit: class list for module (shouldn't happen)\n" ); CfLog(cferror,OUTPUT,""); return false; } strcat(ebuff,args); ExpandVarstring(ebuff,command,NULL); Verbose("Exec module [%s]\n",command); if ((pp = cfpopen(command,"r")) == NULL) { snprintf(OUTPUT,CF_BUFSIZE*2,"Couldn't open pipe from %s\n",actiontxt); CfLog(cferror,OUTPUT,"cfpopen"); return false; } while (!feof(pp)) { if (ferror(pp)) /* abortable */ { snprintf(OUTPUT,CF_BUFSIZE*2,"Shell command pipe %s\n",actiontxt); CfLog(cferror,OUTPUT,"ferror"); break; } ReadLine(line,CF_BUFSIZE,pp); if (strlen(line) > CF_BUFSIZE - 80) { snprintf(OUTPUT,CF_BUFSIZE*2,"Line from module %s is too long to be sensible\n",actiontxt); CfLog(cferror,OUTPUT,""); break; } if (ferror(pp)) /* abortable */ { snprintf(OUTPUT,CF_BUFSIZE*2,"Shell command pipe %s\n",actiontxt); CfLog(cferror,OUTPUT,"ferror"); break; } print = false; for (sp = line; *sp != '\0'; sp++) { if (! isspace((int)*sp)) { print = true; break; } } switch (*line) { case '+': Verbose("Activated classes: %s\n",line+1); CheckClass(line+1,command); AddMultipleClasses(line+1); break; case '-': Verbose("Deactivated classes: %s\n",line+1); CheckClass(line+1,command); NegateCompoundClass(line+1,&VNEGHEAP); break; case '=': content[0] = '\0'; sscanf(line+1,"%[^=]=%[^\n]",name,content); Verbose("Defined Macro: %s, Value: %s\n",name,content); AddMacroValue(CONTEXTID,name,content); break; default: if (print) { snprintf(OUTPUT,CF_BUFSIZE,"%s: %s\n",actiontxt,line); CfLog(cferror,OUTPUT,""); } } } cfpclose(pp); return true; }