1*219b2ee8SDavid du Colombier #include <u.h> 2*219b2ee8SDavid du Colombier #include <libc.h> 3*219b2ee8SDavid du Colombier #include <bio.h> 4*219b2ee8SDavid du Colombier #include <auth.h> 5*219b2ee8SDavid du Colombier #include "authsrv.h" 6*219b2ee8SDavid du Colombier 7*219b2ee8SDavid du Colombier char CRONLOG[] = "cron"; 8*219b2ee8SDavid du Colombier 9*219b2ee8SDavid du Colombier typedef struct Job Job; 10*219b2ee8SDavid du Colombier typedef struct Time Time; 11*219b2ee8SDavid du Colombier typedef struct User User; 12*219b2ee8SDavid du Colombier 13*219b2ee8SDavid du Colombier struct Time{ /* bit masks for each valid time */ 14*219b2ee8SDavid du Colombier ulong min; /* actually 1 bit for every 2 min */ 15*219b2ee8SDavid du Colombier ulong hour; 16*219b2ee8SDavid du Colombier ulong mday; 17*219b2ee8SDavid du Colombier ulong wday; 18*219b2ee8SDavid du Colombier ulong mon; 19*219b2ee8SDavid du Colombier }; 20*219b2ee8SDavid du Colombier 21*219b2ee8SDavid du Colombier struct Job{ 22*219b2ee8SDavid du Colombier char host[NAMELEN]; /* where ... */ 23*219b2ee8SDavid du Colombier Time time; /* when ... */ 24*219b2ee8SDavid du Colombier char *cmd; /* and what to execute */ 25*219b2ee8SDavid du Colombier Job *next; 26*219b2ee8SDavid du Colombier }; 27*219b2ee8SDavid du Colombier 28*219b2ee8SDavid du Colombier struct User{ 29*219b2ee8SDavid du Colombier char name[NAMELEN]; /* who ... */ 30*219b2ee8SDavid du Colombier Job *jobs; /* wants to execute these jobs */ 31*219b2ee8SDavid du Colombier }; 32*219b2ee8SDavid du Colombier 33*219b2ee8SDavid du Colombier User *users; 34*219b2ee8SDavid du Colombier int nuser; 35*219b2ee8SDavid du Colombier int maxuser; 36*219b2ee8SDavid du Colombier char *savec; 37*219b2ee8SDavid du Colombier char *savetok; 38*219b2ee8SDavid du Colombier int tok; 39*219b2ee8SDavid du Colombier int debug; 40*219b2ee8SDavid du Colombier ulong lexval; 41*219b2ee8SDavid du Colombier 42*219b2ee8SDavid du Colombier void rexec(User*, Job*); 43*219b2ee8SDavid du Colombier void readalljobs(void); 44*219b2ee8SDavid du Colombier Job *readjobs(char*, User*); 45*219b2ee8SDavid du Colombier int getname(char*); 46*219b2ee8SDavid du Colombier ulong gettime(int, int); 47*219b2ee8SDavid du Colombier int gettok(int, int); 48*219b2ee8SDavid du Colombier void pushtok(void); 49*219b2ee8SDavid du Colombier void usage(void); 50*219b2ee8SDavid du Colombier void freejobs(Job*); 51*219b2ee8SDavid du Colombier User *newuser(char*); 52*219b2ee8SDavid du Colombier void *emalloc(ulong); 53*219b2ee8SDavid du Colombier void *erealloc(void*, ulong); 54*219b2ee8SDavid du Colombier int myauth(int, char*); 55*219b2ee8SDavid du Colombier void createuser(void); 56*219b2ee8SDavid du Colombier int mkcmd(char*, char*, int); 57*219b2ee8SDavid du Colombier void printjobs(void); 58*219b2ee8SDavid du Colombier 59*219b2ee8SDavid du Colombier void 60*219b2ee8SDavid du Colombier main(int argc, char *argv[]) 61*219b2ee8SDavid du Colombier { 62*219b2ee8SDavid du Colombier Job *j; 63*219b2ee8SDavid du Colombier Tm tm; 64*219b2ee8SDavid du Colombier Time t; 65*219b2ee8SDavid du Colombier ulong now, last, x; 66*219b2ee8SDavid du Colombier int i; 67*219b2ee8SDavid du Colombier 68*219b2ee8SDavid du Colombier debug = 0; 69*219b2ee8SDavid du Colombier ARGBEGIN{ 70*219b2ee8SDavid du Colombier case 'c': 71*219b2ee8SDavid du Colombier createuser(); 72*219b2ee8SDavid du Colombier exits(0); 73*219b2ee8SDavid du Colombier case 'd': 74*219b2ee8SDavid du Colombier debug = 1; 75*219b2ee8SDavid du Colombier break; 76*219b2ee8SDavid du Colombier default: 77*219b2ee8SDavid du Colombier usage(); 78*219b2ee8SDavid du Colombier }ARGEND 79*219b2ee8SDavid du Colombier USED(argc, argv); 80*219b2ee8SDavid du Colombier 81*219b2ee8SDavid du Colombier if(debug){ 82*219b2ee8SDavid du Colombier readalljobs(); 83*219b2ee8SDavid du Colombier printjobs(); 84*219b2ee8SDavid du Colombier exits(0); 85*219b2ee8SDavid du Colombier } 86*219b2ee8SDavid du Colombier 87*219b2ee8SDavid du Colombier switch(fork()){ 88*219b2ee8SDavid du Colombier case -1: 89*219b2ee8SDavid du Colombier error("can't fork"); 90*219b2ee8SDavid du Colombier case 0: 91*219b2ee8SDavid du Colombier break; 92*219b2ee8SDavid du Colombier default: 93*219b2ee8SDavid du Colombier exits(0); 94*219b2ee8SDavid du Colombier } 95*219b2ee8SDavid du Colombier 96*219b2ee8SDavid du Colombier argv0 = "cron"; 97*219b2ee8SDavid du Colombier srand(getpid()*time(0)); 98*219b2ee8SDavid du Colombier last = time(0) / 60; 99*219b2ee8SDavid du Colombier for(;;){ 100*219b2ee8SDavid du Colombier readalljobs(); 101*219b2ee8SDavid du Colombier now = time(0) / 60; 102*219b2ee8SDavid du Colombier for(; last <= now; last += 2){ 103*219b2ee8SDavid du Colombier tm = *localtime(last*60); 104*219b2ee8SDavid du Colombier t.min = 1 << tm.min/2; 105*219b2ee8SDavid du Colombier t.hour = 1 << tm.hour; 106*219b2ee8SDavid du Colombier t.wday = 1 << tm.wday; 107*219b2ee8SDavid du Colombier t.mday = 1 << tm.mday; 108*219b2ee8SDavid du Colombier t.mon = 1 << (tm.mon + 1); 109*219b2ee8SDavid du Colombier for(i = 0; i < nuser; i++) 110*219b2ee8SDavid du Colombier for(j = users[i].jobs; j; j = j->next) 111*219b2ee8SDavid du Colombier if(j->time.min & t.min && j->time.hour & t.hour 112*219b2ee8SDavid du Colombier && j->time.wday & t.wday 113*219b2ee8SDavid du Colombier && j->time.mday & t.mday 114*219b2ee8SDavid du Colombier && j->time.mon & t.mon) 115*219b2ee8SDavid du Colombier rexec(&users[i], j); 116*219b2ee8SDavid du Colombier } 117*219b2ee8SDavid du Colombier x = time(0) / 60; 118*219b2ee8SDavid du Colombier if(x - now < 2) 119*219b2ee8SDavid du Colombier sleep((2 - (x - now))*60*1000); 120*219b2ee8SDavid du Colombier } 121*219b2ee8SDavid du Colombier exits(0); 122*219b2ee8SDavid du Colombier } 123*219b2ee8SDavid du Colombier 124*219b2ee8SDavid du Colombier void 125*219b2ee8SDavid du Colombier createuser(void) 126*219b2ee8SDavid du Colombier { 127*219b2ee8SDavid du Colombier Dir d; 128*219b2ee8SDavid du Colombier char file[3*NAMELEN], *user; 129*219b2ee8SDavid du Colombier int fd; 130*219b2ee8SDavid du Colombier 131*219b2ee8SDavid du Colombier user = getuser(); 132*219b2ee8SDavid du Colombier sprint(file, "/cron/%s", user); 133*219b2ee8SDavid du Colombier fd = create(file, OREAD, 0755|CHDIR); 134*219b2ee8SDavid du Colombier if(fd < 0){ 135*219b2ee8SDavid du Colombier fprint(2, "couldn't create %s: %r\n", file); 136*219b2ee8SDavid du Colombier exits("create"); 137*219b2ee8SDavid du Colombier } 138*219b2ee8SDavid du Colombier dirfstat(fd, &d); 139*219b2ee8SDavid du Colombier strncpy(d.gid, user, NAMELEN); 140*219b2ee8SDavid du Colombier dirfwstat(fd, &d); 141*219b2ee8SDavid du Colombier close(fd); 142*219b2ee8SDavid du Colombier sprint(file, "/cron/%s/cron", user); 143*219b2ee8SDavid du Colombier fd = create(file, OREAD, 0644); 144*219b2ee8SDavid du Colombier if(fd < 0){ 145*219b2ee8SDavid du Colombier fprint(2, "couldn't create %s: %r\n", file); 146*219b2ee8SDavid du Colombier exits("create"); 147*219b2ee8SDavid du Colombier } 148*219b2ee8SDavid du Colombier dirfstat(fd, &d); 149*219b2ee8SDavid du Colombier strncpy(d.gid, user, NAMELEN); 150*219b2ee8SDavid du Colombier dirfwstat(fd, &d); 151*219b2ee8SDavid du Colombier close(fd); 152*219b2ee8SDavid du Colombier } 153*219b2ee8SDavid du Colombier 154*219b2ee8SDavid du Colombier void 155*219b2ee8SDavid du Colombier readalljobs(void) 156*219b2ee8SDavid du Colombier { 157*219b2ee8SDavid du Colombier User *u; 158*219b2ee8SDavid du Colombier Dir d[64], db; 159*219b2ee8SDavid du Colombier char file[3*NAMELEN]; 160*219b2ee8SDavid du Colombier int i, n, fd; 161*219b2ee8SDavid du Colombier ulong now; 162*219b2ee8SDavid du Colombier static ulong lasttime; 163*219b2ee8SDavid du Colombier 164*219b2ee8SDavid du Colombier now = time(0); 165*219b2ee8SDavid du Colombier fd = open("/cron", OREAD); 166*219b2ee8SDavid du Colombier if(fd < 0) 167*219b2ee8SDavid du Colombier error("can't open /cron\n"); 168*219b2ee8SDavid du Colombier while((n = dirread(fd, d, sizeof d)) > 0){ 169*219b2ee8SDavid du Colombier n /= sizeof d[0]; 170*219b2ee8SDavid du Colombier for(i = 0; i < n; i++){ 171*219b2ee8SDavid du Colombier if(strcmp(d[i].name, "log") == 0) 172*219b2ee8SDavid du Colombier continue; 173*219b2ee8SDavid du Colombier if(strcmp(d[i].name, d[i].uid) != 0){ 174*219b2ee8SDavid du Colombier syslog(1, CRONLOG, "cron for %s owned by %s\n", d[i].name, d[i].uid); 175*219b2ee8SDavid du Colombier continue; 176*219b2ee8SDavid du Colombier } 177*219b2ee8SDavid du Colombier u = newuser(d[i].name); 178*219b2ee8SDavid du Colombier sprint(file, "/cron/%s/cron", d[i].name); 179*219b2ee8SDavid du Colombier if(dirstat(file, &db) < 0) 180*219b2ee8SDavid du Colombier continue; 181*219b2ee8SDavid du Colombier if(lasttime < db.mtime){ 182*219b2ee8SDavid du Colombier freejobs(u->jobs); 183*219b2ee8SDavid du Colombier u->jobs = readjobs(file, u); 184*219b2ee8SDavid du Colombier } 185*219b2ee8SDavid du Colombier } 186*219b2ee8SDavid du Colombier } 187*219b2ee8SDavid du Colombier lasttime = now; 188*219b2ee8SDavid du Colombier close(fd); 189*219b2ee8SDavid du Colombier } 190*219b2ee8SDavid du Colombier 191*219b2ee8SDavid du Colombier /* 192*219b2ee8SDavid du Colombier * parse user's cron file 193*219b2ee8SDavid du Colombier * other lines: minute hour monthday month weekday host command 194*219b2ee8SDavid du Colombier */ 195*219b2ee8SDavid du Colombier Job * 196*219b2ee8SDavid du Colombier readjobs(char *file, User *user) 197*219b2ee8SDavid du Colombier { 198*219b2ee8SDavid du Colombier Biobuf *b; 199*219b2ee8SDavid du Colombier Job *j, *jobs; 200*219b2ee8SDavid du Colombier int line; 201*219b2ee8SDavid du Colombier 202*219b2ee8SDavid du Colombier b = Bopen(file, OREAD); 203*219b2ee8SDavid du Colombier if(!b) 204*219b2ee8SDavid du Colombier return 0; 205*219b2ee8SDavid du Colombier jobs = 0; 206*219b2ee8SDavid du Colombier for(line = 1; savec = Brdline(b, '\n'); line++){ 207*219b2ee8SDavid du Colombier savec[Blinelen(b) - 1] = '\0'; 208*219b2ee8SDavid du Colombier while(*savec == ' ' || *savec == '\t') 209*219b2ee8SDavid du Colombier savec++; 210*219b2ee8SDavid du Colombier if(*savec == '#' || *savec == '\0') 211*219b2ee8SDavid du Colombier continue; 212*219b2ee8SDavid du Colombier if(strlen(savec) > 1024){ 213*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: line %d: line too long", user->name, line); 214*219b2ee8SDavid du Colombier continue; 215*219b2ee8SDavid du Colombier } 216*219b2ee8SDavid du Colombier j = emalloc(sizeof *j); 217*219b2ee8SDavid du Colombier if((j->time.min = gettime(0, 59)) 218*219b2ee8SDavid du Colombier && (j->time.hour = gettime(0, 23)) 219*219b2ee8SDavid du Colombier && (j->time.mday = gettime(1, 31)) 220*219b2ee8SDavid du Colombier && (j->time.mon = gettime(1, 12)) 221*219b2ee8SDavid du Colombier && (j->time.wday = gettime(0, 6)) 222*219b2ee8SDavid du Colombier && getname(j->host)){ 223*219b2ee8SDavid du Colombier j->cmd = emalloc(strlen(savec) + 1); 224*219b2ee8SDavid du Colombier strcpy(j->cmd, savec); 225*219b2ee8SDavid du Colombier j->next = jobs; 226*219b2ee8SDavid du Colombier jobs = j; 227*219b2ee8SDavid du Colombier }else{ 228*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: line %d: syntax error", user->name, line); 229*219b2ee8SDavid du Colombier free(j); 230*219b2ee8SDavid du Colombier } 231*219b2ee8SDavid du Colombier } 232*219b2ee8SDavid du Colombier Bterm(b); 233*219b2ee8SDavid du Colombier return jobs; 234*219b2ee8SDavid du Colombier } 235*219b2ee8SDavid du Colombier 236*219b2ee8SDavid du Colombier void 237*219b2ee8SDavid du Colombier printjobs(void) 238*219b2ee8SDavid du Colombier { 239*219b2ee8SDavid du Colombier char buf[8*1024]; 240*219b2ee8SDavid du Colombier Job *j; 241*219b2ee8SDavid du Colombier int i; 242*219b2ee8SDavid du Colombier 243*219b2ee8SDavid du Colombier for(i = 0; i < nuser; i++){ 244*219b2ee8SDavid du Colombier print("user %s\n", users[i].name); 245*219b2ee8SDavid du Colombier for(j = users[i].jobs; j; j = j->next){ 246*219b2ee8SDavid du Colombier if(!mkcmd(j->cmd, buf, sizeof buf)) 247*219b2ee8SDavid du Colombier print("\tbad job %s on host %s\n", j->cmd, j->host); 248*219b2ee8SDavid du Colombier else 249*219b2ee8SDavid du Colombier print("\tjob %s on host %s\n", buf, j->host); 250*219b2ee8SDavid du Colombier } 251*219b2ee8SDavid du Colombier } 252*219b2ee8SDavid du Colombier } 253*219b2ee8SDavid du Colombier 254*219b2ee8SDavid du Colombier User * 255*219b2ee8SDavid du Colombier newuser(char *name) 256*219b2ee8SDavid du Colombier { 257*219b2ee8SDavid du Colombier int i; 258*219b2ee8SDavid du Colombier 259*219b2ee8SDavid du Colombier for(i = 0; i < nuser; i++) 260*219b2ee8SDavid du Colombier if(strcmp(users[i].name, name) == 0) 261*219b2ee8SDavid du Colombier return &users[i]; 262*219b2ee8SDavid du Colombier if(nuser == maxuser){ 263*219b2ee8SDavid du Colombier maxuser += 32; 264*219b2ee8SDavid du Colombier users = erealloc(users, maxuser * sizeof *users); 265*219b2ee8SDavid du Colombier } 266*219b2ee8SDavid du Colombier strcpy(users[nuser].name, name); 267*219b2ee8SDavid du Colombier users[nuser].jobs = 0; 268*219b2ee8SDavid du Colombier return &users[nuser++]; 269*219b2ee8SDavid du Colombier } 270*219b2ee8SDavid du Colombier 271*219b2ee8SDavid du Colombier void 272*219b2ee8SDavid du Colombier freejobs(Job *j) 273*219b2ee8SDavid du Colombier { 274*219b2ee8SDavid du Colombier Job *fj; 275*219b2ee8SDavid du Colombier 276*219b2ee8SDavid du Colombier for(fj = j; fj; fj = j){ 277*219b2ee8SDavid du Colombier j = j->next; 278*219b2ee8SDavid du Colombier free(fj); 279*219b2ee8SDavid du Colombier } 280*219b2ee8SDavid du Colombier } 281*219b2ee8SDavid du Colombier 282*219b2ee8SDavid du Colombier int 283*219b2ee8SDavid du Colombier getname(char *name) 284*219b2ee8SDavid du Colombier { 285*219b2ee8SDavid du Colombier int c; 286*219b2ee8SDavid du Colombier int i; 287*219b2ee8SDavid du Colombier 288*219b2ee8SDavid du Colombier if(!savec) 289*219b2ee8SDavid du Colombier return 0; 290*219b2ee8SDavid du Colombier while(*savec == ' ' || *savec == '\t') 291*219b2ee8SDavid du Colombier savec++; 292*219b2ee8SDavid du Colombier for(i = 0; (c = *savec) && c != ' ' && c != '\t'; i++){ 293*219b2ee8SDavid du Colombier if(i == NAMELEN - 1) 294*219b2ee8SDavid du Colombier return 0; 295*219b2ee8SDavid du Colombier name[i] = *savec++; 296*219b2ee8SDavid du Colombier } 297*219b2ee8SDavid du Colombier name[i] = '\0'; 298*219b2ee8SDavid du Colombier while(*savec == ' ' || *savec == '\t') 299*219b2ee8SDavid du Colombier savec++; 300*219b2ee8SDavid du Colombier return i; 301*219b2ee8SDavid du Colombier } 302*219b2ee8SDavid du Colombier 303*219b2ee8SDavid du Colombier /* 304*219b2ee8SDavid du Colombier * return the next time range in the file: 305*219b2ee8SDavid du Colombier * times: '*' 306*219b2ee8SDavid du Colombier * | range 307*219b2ee8SDavid du Colombier * range: number 308*219b2ee8SDavid du Colombier * | number '-' number 309*219b2ee8SDavid du Colombier * | range ',' range 310*219b2ee8SDavid du Colombier * a return of zero means a syntax error was discovered 311*219b2ee8SDavid du Colombier */ 312*219b2ee8SDavid du Colombier ulong 313*219b2ee8SDavid du Colombier gettime(int min, int max) 314*219b2ee8SDavid du Colombier { 315*219b2ee8SDavid du Colombier ulong n, m, e; 316*219b2ee8SDavid du Colombier 317*219b2ee8SDavid du Colombier if(gettok(min, max) == '*') 318*219b2ee8SDavid du Colombier return ~0; 319*219b2ee8SDavid du Colombier n = 0; 320*219b2ee8SDavid du Colombier while(tok == '1'){ 321*219b2ee8SDavid du Colombier m = 1 << lexval; 322*219b2ee8SDavid du Colombier n |= m; 323*219b2ee8SDavid du Colombier if(gettok(0, 0) == '-'){ 324*219b2ee8SDavid du Colombier if(gettok(lexval, max) != '1') 325*219b2ee8SDavid du Colombier return 0; 326*219b2ee8SDavid du Colombier e = 1 << lexval; 327*219b2ee8SDavid du Colombier for( ; m <= e; m <<= 1) 328*219b2ee8SDavid du Colombier n |= m; 329*219b2ee8SDavid du Colombier gettok(min, max); 330*219b2ee8SDavid du Colombier } 331*219b2ee8SDavid du Colombier if(tok != ',') 332*219b2ee8SDavid du Colombier break; 333*219b2ee8SDavid du Colombier if(gettok(min, max) != '1') 334*219b2ee8SDavid du Colombier return 0; 335*219b2ee8SDavid du Colombier } 336*219b2ee8SDavid du Colombier pushtok(); 337*219b2ee8SDavid du Colombier return n; 338*219b2ee8SDavid du Colombier } 339*219b2ee8SDavid du Colombier 340*219b2ee8SDavid du Colombier void 341*219b2ee8SDavid du Colombier pushtok(void) 342*219b2ee8SDavid du Colombier { 343*219b2ee8SDavid du Colombier savec = savetok; 344*219b2ee8SDavid du Colombier } 345*219b2ee8SDavid du Colombier 346*219b2ee8SDavid du Colombier int 347*219b2ee8SDavid du Colombier gettok(int min, int max) 348*219b2ee8SDavid du Colombier { 349*219b2ee8SDavid du Colombier char c; 350*219b2ee8SDavid du Colombier 351*219b2ee8SDavid du Colombier savetok = savec; 352*219b2ee8SDavid du Colombier if(!savec) 353*219b2ee8SDavid du Colombier return tok = 0; 354*219b2ee8SDavid du Colombier while((c = *savec) == ' ' || c == '\t') 355*219b2ee8SDavid du Colombier savec++; 356*219b2ee8SDavid du Colombier switch(c){ 357*219b2ee8SDavid du Colombier case '0': case '1': case '2': case '3': case '4': 358*219b2ee8SDavid du Colombier case '5': case '6': case '7': case '8': case '9': 359*219b2ee8SDavid du Colombier lexval = strtoul(savec, &savec, 10); 360*219b2ee8SDavid du Colombier if(lexval < min || lexval > max) 361*219b2ee8SDavid du Colombier return tok = 0; 362*219b2ee8SDavid du Colombier if(max > 32) 363*219b2ee8SDavid du Colombier lexval /= 2; /* yuk: correct min by / 2 */ 364*219b2ee8SDavid du Colombier return tok = '1'; 365*219b2ee8SDavid du Colombier case '*': case '-': case ',': 366*219b2ee8SDavid du Colombier savec++; 367*219b2ee8SDavid du Colombier return tok = c; 368*219b2ee8SDavid du Colombier default: 369*219b2ee8SDavid du Colombier return tok = 0; 370*219b2ee8SDavid du Colombier } 371*219b2ee8SDavid du Colombier } 372*219b2ee8SDavid du Colombier 373*219b2ee8SDavid du Colombier int 374*219b2ee8SDavid du Colombier call(char *host) 375*219b2ee8SDavid du Colombier { 376*219b2ee8SDavid du Colombier char *na, *p; 377*219b2ee8SDavid du Colombier 378*219b2ee8SDavid du Colombier na = netmkaddr(host, 0, "rexexec"); 379*219b2ee8SDavid du Colombier p = utfrune(na, L'!'); 380*219b2ee8SDavid du Colombier if(!p) 381*219b2ee8SDavid du Colombier return -1; 382*219b2ee8SDavid du Colombier p = utfrune(p+1, L'!'); 383*219b2ee8SDavid du Colombier if(!p) 384*219b2ee8SDavid du Colombier return -1; 385*219b2ee8SDavid du Colombier if(strcmp(p, "!rexexec") != 0) 386*219b2ee8SDavid du Colombier return -2; 387*219b2ee8SDavid du Colombier return dial(na, 0, 0, 0); 388*219b2ee8SDavid du Colombier } 389*219b2ee8SDavid du Colombier 390*219b2ee8SDavid du Colombier /* 391*219b2ee8SDavid du Colombier * convert command to run properly on the remote machine 392*219b2ee8SDavid du Colombier * need to escape the quotes wo they don't get stripped 393*219b2ee8SDavid du Colombier */ 394*219b2ee8SDavid du Colombier int 395*219b2ee8SDavid du Colombier mkcmd(char *cmd, char *buf, int len) 396*219b2ee8SDavid du Colombier { 397*219b2ee8SDavid du Colombier char *p; 398*219b2ee8SDavid du Colombier int n, m; 399*219b2ee8SDavid du Colombier 400*219b2ee8SDavid du Colombier n = sizeof "exec rc -c '" -1; 401*219b2ee8SDavid du Colombier if(n >= len) 402*219b2ee8SDavid du Colombier return 0; 403*219b2ee8SDavid du Colombier strcpy(buf, "exec rc -c '"); 404*219b2ee8SDavid du Colombier while(p = utfrune(cmd, L'\'')){ 405*219b2ee8SDavid du Colombier p++; 406*219b2ee8SDavid du Colombier m = p - cmd; 407*219b2ee8SDavid du Colombier if(n + m + 1 >= len) 408*219b2ee8SDavid du Colombier return 0; 409*219b2ee8SDavid du Colombier strncpy(&buf[n], cmd, m); 410*219b2ee8SDavid du Colombier n += m; 411*219b2ee8SDavid du Colombier buf[n++] = '\''; 412*219b2ee8SDavid du Colombier cmd = p; 413*219b2ee8SDavid du Colombier } 414*219b2ee8SDavid du Colombier m = strlen(cmd); 415*219b2ee8SDavid du Colombier if(n + m + sizeof "'</dev/null>/dev/null>[2=1]" >= len) 416*219b2ee8SDavid du Colombier return 0; 417*219b2ee8SDavid du Colombier strcpy(&buf[n], cmd); 418*219b2ee8SDavid du Colombier strcpy(&buf[n+m], "'</dev/null>/dev/null>[2=1]"); 419*219b2ee8SDavid du Colombier return 1; 420*219b2ee8SDavid du Colombier } 421*219b2ee8SDavid du Colombier 422*219b2ee8SDavid du Colombier void 423*219b2ee8SDavid du Colombier rexec(User *user, Job *j) 424*219b2ee8SDavid du Colombier { 425*219b2ee8SDavid du Colombier char buf[8*1024], key[DESKEYLEN], err[ERRLEN]; 426*219b2ee8SDavid du Colombier int fd; 427*219b2ee8SDavid du Colombier 428*219b2ee8SDavid du Colombier switch(rfork(RFPROC|RFNOWAIT|RFNAMEG|RFENVG|RFFDG)){ 429*219b2ee8SDavid du Colombier case 0: 430*219b2ee8SDavid du Colombier break; 431*219b2ee8SDavid du Colombier case -1: 432*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "can't fork a job for %s: %r\n", user->name); 433*219b2ee8SDavid du Colombier default: 434*219b2ee8SDavid du Colombier return; 435*219b2ee8SDavid du Colombier } 436*219b2ee8SDavid du Colombier if(findkey(KEYDB, user->name, key) == 0){ 437*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: key not found", user->name); 438*219b2ee8SDavid du Colombier _exits(0); 439*219b2ee8SDavid du Colombier } 440*219b2ee8SDavid du Colombier 441*219b2ee8SDavid du Colombier if(!mkcmd(j->cmd, buf, sizeof buf)){ 442*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "internal error: cmd buffer overflow"); 443*219b2ee8SDavid du Colombier _exits(0); 444*219b2ee8SDavid du Colombier } 445*219b2ee8SDavid du Colombier 446*219b2ee8SDavid du Colombier /* 447*219b2ee8SDavid du Colombier * remote call, auth, cmd with no i/o 448*219b2ee8SDavid du Colombier * give it 2 min to complete 449*219b2ee8SDavid du Colombier */ 450*219b2ee8SDavid du Colombier alarm(2*60*1000); 451*219b2ee8SDavid du Colombier fd = call(j->host); 452*219b2ee8SDavid du Colombier if(fd < 0){ 453*219b2ee8SDavid du Colombier if(fd == -2){ 454*219b2ee8SDavid du Colombier syslog(0, AUTHLOG, "%s: dangerous host %s", user->name, j->host); 455*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: dangerous host %s", user->name, j->host); 456*219b2ee8SDavid du Colombier } 457*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: can't call '%s'", user->name, j->host); 458*219b2ee8SDavid du Colombier _exits(0); 459*219b2ee8SDavid du Colombier } 460*219b2ee8SDavid du Colombier if(myauth(fd, user->name) < 0){ 461*219b2ee8SDavid du Colombier errstr(err); 462*219b2ee8SDavid du Colombier syslog(0, CRONLOG, "%s: can't auth %s on %s: %s", user->name, j->cmd, j->host, err); 463*219b2ee8SDavid du Colombier _exits(0); 464*219b2ee8SDavid du Colombier } 465*219b2ee8SDavid du Colombier write(fd, buf, strlen(buf)+1); 466*219b2ee8SDavid du Colombier write(fd, buf, 0); 467*219b2ee8SDavid du Colombier while(read(fd, buf, sizeof buf) > 0) 468*219b2ee8SDavid du Colombier ; 469*219b2ee8SDavid du Colombier _exits(0); 470*219b2ee8SDavid du Colombier } 471*219b2ee8SDavid du Colombier 472*219b2ee8SDavid du Colombier void * 473*219b2ee8SDavid du Colombier emalloc(ulong n) 474*219b2ee8SDavid du Colombier { 475*219b2ee8SDavid du Colombier void *p; 476*219b2ee8SDavid du Colombier 477*219b2ee8SDavid du Colombier if(p = malloc(n)) 478*219b2ee8SDavid du Colombier return p; 479*219b2ee8SDavid du Colombier error("out of memory"); 480*219b2ee8SDavid du Colombier return 0; 481*219b2ee8SDavid du Colombier } 482*219b2ee8SDavid du Colombier 483*219b2ee8SDavid du Colombier void * 484*219b2ee8SDavid du Colombier erealloc(void *p, ulong n) 485*219b2ee8SDavid du Colombier { 486*219b2ee8SDavid du Colombier if(p = realloc(p, n)) 487*219b2ee8SDavid du Colombier return p; 488*219b2ee8SDavid du Colombier error("out of memory"); 489*219b2ee8SDavid du Colombier return 0; 490*219b2ee8SDavid du Colombier } 491*219b2ee8SDavid du Colombier 492*219b2ee8SDavid du Colombier void 493*219b2ee8SDavid du Colombier usage(void) 494*219b2ee8SDavid du Colombier { 495*219b2ee8SDavid du Colombier fprint(2, "usage: cron [-c]\n"); 496*219b2ee8SDavid du Colombier exits("usage"); 497*219b2ee8SDavid du Colombier } 498*219b2ee8SDavid du Colombier 499*219b2ee8SDavid du Colombier int 500*219b2ee8SDavid du Colombier myauth(int fd, char *user) 501*219b2ee8SDavid du Colombier { 502*219b2ee8SDavid du Colombier int i; 503*219b2ee8SDavid du Colombier char hkey[DESKEYLEN]; 504*219b2ee8SDavid du Colombier char buf[512]; 505*219b2ee8SDavid du Colombier Ticketreq tr; 506*219b2ee8SDavid du Colombier Ticket t; 507*219b2ee8SDavid du Colombier Authenticator a; 508*219b2ee8SDavid du Colombier 509*219b2ee8SDavid du Colombier /* get ticket request from remote machine */ 510*219b2ee8SDavid du Colombier if(readn(fd, buf, TICKREQLEN) < 0){ 511*219b2ee8SDavid du Colombier werrstr("bad request"); 512*219b2ee8SDavid du Colombier return -1; 513*219b2ee8SDavid du Colombier } 514*219b2ee8SDavid du Colombier convM2TR(buf, &tr); 515*219b2ee8SDavid du Colombier if(tr.type != AuthTreq){ 516*219b2ee8SDavid du Colombier werrstr("bad request"); 517*219b2ee8SDavid du Colombier return -1; 518*219b2ee8SDavid du Colombier } 519*219b2ee8SDavid du Colombier if(findkey(KEYDB, tr.authid, hkey) == 0){ 520*219b2ee8SDavid du Colombier werrstr("no key for authid %s", tr.authid); 521*219b2ee8SDavid du Colombier return -1; 522*219b2ee8SDavid du Colombier } 523*219b2ee8SDavid du Colombier 524*219b2ee8SDavid du Colombier /* create ticket+authenticator and send to destination */ 525*219b2ee8SDavid du Colombier memset(&t, 0, sizeof t); 526*219b2ee8SDavid du Colombier memmove(t.chal, tr.chal, CHALLEN); 527*219b2ee8SDavid du Colombier strcpy(t.cuid, user); 528*219b2ee8SDavid du Colombier strcpy(t.suid, user); 529*219b2ee8SDavid du Colombier srand(time(0)); 530*219b2ee8SDavid du Colombier for(i = 0; i < DESKEYLEN; i++) 531*219b2ee8SDavid du Colombier t.key[i] = nrand(256); 532*219b2ee8SDavid du Colombier t.num = AuthTs; 533*219b2ee8SDavid du Colombier convT2M(&t, buf, hkey); 534*219b2ee8SDavid du Colombier memmove(a.chal, tr.chal, CHALLEN); 535*219b2ee8SDavid du Colombier a.id = 0; 536*219b2ee8SDavid du Colombier a.num = AuthAc; 537*219b2ee8SDavid du Colombier convA2M(&a, buf+TICKETLEN, t.key); 538*219b2ee8SDavid du Colombier if(write(fd, buf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN){ 539*219b2ee8SDavid du Colombier werrstr("connection dropped: %r"); 540*219b2ee8SDavid du Colombier return -1; 541*219b2ee8SDavid du Colombier } 542*219b2ee8SDavid du Colombier 543*219b2ee8SDavid du Colombier /* get authenticator from server and check */ 544*219b2ee8SDavid du Colombier if(readn(fd, buf, AUTHENTLEN) < 0){ 545*219b2ee8SDavid du Colombier werrstr("connection dropped: %r"); 546*219b2ee8SDavid du Colombier return -1; 547*219b2ee8SDavid du Colombier } 548*219b2ee8SDavid du Colombier convM2A(buf, &a, t.key); 549*219b2ee8SDavid du Colombier if(a.num != AuthAs){ 550*219b2ee8SDavid du Colombier werrstr("bad reply authenticator"); 551*219b2ee8SDavid du Colombier return -1; 552*219b2ee8SDavid du Colombier } 553*219b2ee8SDavid du Colombier return 0; 554*219b2ee8SDavid du Colombier } 555