|
|
1.1 ! root 1: # include "defs.h" ! 2: /* must be setuid root */ ! 3: /* ! 4: net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd ! 5: -r file -s file -u uid -w -x -y -z command ! 6: ! 7: - take from standard input ! 8: -b never send anything back ! 9: -c cmd think of this as a "cmd" * ! 10: -f force prompting of user name and password ! 11: -i file remote stdin * ! 12: -l name remote login name ! 13: -m Mach remote machine ! 14: -n do not write back anything, always mail them back ! 15: -o file remote stdout & stderr * ! 16: -p pass remote password ! 17: -q quiet option, send back only if rcode !=0 or if there is stdout ! 18: -r file local response file ! 19: -s file local stdin file * ! 20: ! 21: (super users only, always skip login/passwd check:) ! 22: -u uid net queue files should be owned by uid (16 bits) ! 23: -w this is a write/mail response cmd * ! 24: -x this is being forwarded through us to another machine * ! 25: -y skip login/password check * ! 26: -z this is a response file being returned * ! 27: ! 28: * = not documented in net(NEW) ! 29: ! 30: */ ! 31: /* ! 32: code option reason ! 33: q normal request ! 34: w -w message to be written back ! 35: -x being forwarded through us ! 36: y -y simply skips login check (used by netlpr) ! 37: s -z normal response ! 38: */ ! 39: static char dfname[]= DFNAME; ! 40: ! 41: main(argc, argv) ! 42: char **argv; { ! 43: register int i; ! 44: int outerror(),uid; ! 45: char *genparmlist(); ! 46: char resp[FNS], infile[FNS], outfile[FNS], localin[FNS]; ! 47: char buf[BUFSIZ], suid[10]; ! 48: char sin =0, code, zopt = 0, wopt = 0, yopt = 0, xopt = 0; ! 49: char *s,*sn; ! 50: char sTtyname[20], sCmdAct[BUFSIZ], sCmdVirt[BUFSIZ]; ! 51: long cnt = 0L, maxfile = MAXFILE, lTtytime; ! 52: char cflag = 'a'; ! 53: FILE *file, *temp, *rfile; ! 54: struct utmp utmpstr; ! 55: struct stat statbuf; ! 56: ! 57: debugflg = DBV; ! 58: argv[argc] = 0; ! 59: sCmdAct[0] = resp[0] = outfile[0] = infile[0] = 0; ! 60: sCmdVirt[0] = localin[0] = 0; ! 61: sTtyname[0] = 0; ! 62: suid[0] = 0; ! 63: ! 64: if(isatty(0)) strcat(sTtyname,ttyname(0)); ! 65: else if(isatty(2)) strcat(sTtyname,ttyname(2)); ! 66: remote = 0; ! 67: signal(SIGHUP,outerror); ! 68: signal(SIGQUIT,outerror); ! 69: signal(SIGINT,outerror); ! 70: signal(SIGTRM,outerror); ! 71: ! 72: while(argc > 1 && argv[1][0] == '-'){ ! 73: argc--; argv++; ! 74: switch(argv[0][1]){ ! 75: case 0: sin++; break; ! 76: case 'b': status.nonotify++; break; ! 77: case 'c': harg(sCmdVirt,&argc,&argv); break; ! 78: case 'f': status.force++; break; ! 79: case 'i': harg(infile,&argc,&argv); break; ! 80: case 'l': harg(status.login,&argc,&argv); break; ! 81: case 'm': harg(buf,&argc,&argv); remote = lookup(buf); break; ! 82: case 'n': status.nowrite++; break; ! 83: case 'o': harg(outfile,&argc,&argv); break; ! 84: case 'p': ! 85: harg(status.mpasswd,&argc,&argv); ! 86: if(status.mpasswd[0] == 0) ! 87: strcpy(status.mpasswd,"\n\n"); ! 88: break; ! 89: case 'q': status.quiet++; break; ! 90: case 'r': harg(buf,&argc,&argv); addir(resp,buf); break; ! 91: case 's': harg(localin,&argc,&argv); break; ! 92: case 'u': harg(suid,&argc,&argv); break; ! 93: case 'w': wopt++; break; ! 94: case 'x': xopt++; break; ! 95: case 'y': yopt++; break; ! 96: case 'z': zopt++; break; ! 97: default: ! 98: fprintf(stderr,"Unknown option %s\n",argv[0]); ! 99: break; ! 100: } ! 101: } ! 102: while(argc > 1){ ! 103: argc--; argv++; ! 104: strcat(sCmdAct,argv[0]); ! 105: strcat(sCmdAct," "); ! 106: } ! 107: uid = getuid(); ! 108: code = 'q'; ! 109: if(zopt || wopt || yopt || xopt || suid[0] != 0){ ! 110: /* check z or w or y or x option permission */ ! 111: # ifndef TESTING ! 112: if(uid != SUPERUSER){ ! 113: fprintf(stderr,"Error: Not super-user"); ! 114: outerror(); ! 115: } ! 116: # endif ! 117: code = zopt ? 's' : 'w'; ! 118: code = yopt ? 'y' : code; ! 119: if(status.mpasswd[0] == 0) /* no passwd required */ ! 120: strcpy(status.mpasswd,"\n"); ! 121: } ! 122: ! 123: status.jobno = 32767; /* default (invalid) job number */ ! 124: if(code == 'q' && !xopt){ ! 125: if((sn = SnCurrent()) == NULL ! 126: /* || machtype[local-'a'] == M_CC */) ! 127: /* turns out we never use jobno, except in netlpr */ ! 128: /* read passwd file, get status.localname & jobno */ ! 129: passwdent(); ! 130: else ! 131: /* don't bother reading passwd file, don't need jobno */ ! 132: strcpy(status.localname,sn); ! 133: } ! 134: ! 135: /* sets remote,status.login,status.force,status.mpasswd, ! 136: status.nonotify, status.nowrite */ ! 137: /* may read passwd file if getenv(HOME) reads it */ ! 138: commandfile(); ! 139: ! 140: if(remote == 0)remote = getremote(local); ! 141: # ifndef TESTING ! 142: if(remote == local){ ! 143: fprintf(stderr,"Request sent to local machine - doesn't make sense\n"); ! 144: /* outerror(); */ ! 145: } ! 146: # endif ! 147: strcat(status.defcmd," "); ! 148: if(strlen(sCmdAct) == 0)strcpy(sCmdAct,status.defcmd); ! 149: sCmdAct[strlen(sCmdAct)-1] = 0; ! 150: mktemp(dfname); ! 151: /* determine through machine */ ! 152: i = gothru(local,remote); ! 153: if(i == 0){ ! 154: s = longname(remote); ! 155: if(s != 0)fprintf(stderr,"No path to %s machine.\n",s); ! 156: else fprintf(stderr,"Unknown machine\n"); ! 157: outerror(); ! 158: } ! 159: dfname[strlen(dfname)-11] = i; /* set directory */ ! 160: dfname[strlen(dfname)-7] = i; /* set file (unused) */ ! 161: /* check to see if data files are directories */ ! 162: if(isdirectory(resp) || isdirectory(infile) || isdirectory(outfile)){ ! 163: fprintf(stderr,"%s is a directory, must be a file\n", ! 164: isdirectory(resp) ? resp : ! 165: isdirectory(infile) ? infile : ! 166: outfile); ! 167: outerror(); ! 168: } ! 169: if(suid[0] != 0)uid = atoi(suid); ! 170: if(resp[0]){ ! 171: if(strcmp(resp,"/dev/tty") == 0){ ! 172: fprintf(stderr,"Can't have /dev/tty as response file.\n"); ! 173: outerror(); ! 174: } ! 175: if(stat(resp,&statbuf) == -1){ ! 176: strcpy(buf,resp); ! 177: s = &buf[0]; ! 178: s = s + strlen(buf) - 1; ! 179: while(*s != '/' && s > &(buf[0]))s--; ! 180: *s = 0; ! 181: debug("chkdir %s",buf); ! 182: if(strlen(buf) == 0)strcpy(buf,"."); ! 183: if(access(buf,2) == -1){ ! 184: perror(buf); ! 185: outerror(); ! 186: } ! 187: if((rfile=fopen(resp,"w")) == NULL){ ! 188: perror(resp); ! 189: outerror(); ! 190: } ! 191: chmod(resp,0600); ! 192: fclose(rfile); ! 193: mchown(resp,uid,getgid()); ! 194: } ! 195: else if(access(resp,2) == -1){ ! 196: perror(resp); ! 197: outerror(); ! 198: } ! 199: } ! 200: /* go ahead and prompt for login name and passwd, if neccessary, ! 201: as long as the X option has not been specified */ ! 202: if(code == 'q' && !xopt)promptlogin(remote); ! 203: ! 204: /* at this point, we create the dfa... file */ ! 205: file = fopen(dfname,"w"); ! 206: if(file == NULL){ ! 207: perror(dfname); ! 208: outerror(); ! 209: } ! 210: chmod(dfname,0600); ! 211: mchown(dfname,uid,getgid()); ! 212: if(xopt)goto stickit; ! 213: if(status.mpasswd[0] == '\n') ! 214: status.mpasswd[0] = 0; ! 215: # ifndef NEWPROT ! 216: if(machtype[local-'a'] == M_CC && machtype[remote-'a'] == M_CC ! 217: && status.mpasswd[0] != 0){ ! 218: s = crypt(status.mpasswd); ! 219: strcpy(status.mpasswd,s); ! 220: } ! 221: # endif ! 222: if(status.mpasswd[0] == 0 && code == 'q' && ! 223: strcmp(status.login,"network") != 0){ ! 224: fprintf(stderr,"Zero-length password not allowed\n"); ! 225: outerror(); ! 226: } ! 227: if(code == 'q' && (streql(status.login,"root") == 0 || ! 228: streql(status.login,"ruut") == 0)){ ! 229: fprintf(stderr,"Can't login as root through the network\n"); ! 230: outerror(); ! 231: } ! 232: # ifdef SPACCT ! 233: /* handle special accounts */ ! 234: /* give a value for mgid and muid */ ! 235: strcpy(status.mpasswd,handlesp(status.login,status.mpasswd, ! 236: status.localname,status.muid,status.mgid)); ! 237: # endif ! 238: enmask(status.mpasswd); ! 239: lTtytime = 0; ! 240: if(sTtyname[0] && status.nowrite == 0){ ! 241: temp = fopen("/etc/utmp","r"); ! 242: if(temp == NULL){ ! 243: perror("/etc/utmp"); ! 244: outerror(); ! 245: } ! 246: while(fread(&utmpstr,1,sizeof utmpstr,temp) == sizeof utmpstr) ! 247: # ifdef OLDTTY ! 248: if(utmpstr.ut_tty == sTtyname[8]){ ! 249: # else ! 250: if(strcmp(utmpstr.ut_line,sTtyname+5) == 0){ ! 251: # endif ! 252: lTtytime = utmpstr.ut_time; ! 253: break; ! 254: } ! 255: } ! 256: /* ! 257: debug("p:%s:\n",status.mpasswd); ! 258: */ ! 259: /* cflag is initially 'a'. Add the flags as needed. */ ! 260: if(status.nonotify)cflag += F_NONOTIFY; ! 261: if(status.quiet)cflag += F_QUIET; ! 262: /* ! 263: protocol: ! 264: code, remote mach, local mach, version stamp (2), remote login name, ! 265: password, -i, -o, -r files, ! 266: local login name, terminal, flag, utmp tty login time, ! 267: cc jobno(variable parameter list), current time, ! 268: command '\n' real command '\n' ! 269: any data ! 270: ! 271: changes: ! 272: 1) remove header ! 273: 3) use ascii length instead of 4 bytes ! 274: 4) encrypt the login name, command, and part of data as well ! 275: */ ! 276: ! 277: fprintf(file, ! 278: "%c :%c :%c :%c :%c :%s :%s :%s :%s :%s :%s :%s :%c :%lo :%d%s :%ld :", ! 279: code,remote,local,VMAJOR+'a',VMINOR+'a',status.login, ! 280: status.mpasswd,infile,outfile,resp, ! 281: status.localname,sTtyname,cflag,lTtytime, ! 282: status.jobno,genparmlist(),gettime()-TIMEBASE); ! 283: fputs(sCmdAct,file); ! 284: putc('\n',file); ! 285: fputs(sCmdVirt,file); ! 286: putc('\n',file); ! 287: stickit: ! 288: /* between ingres machines, allow long files */ ! 289: /* this should be parametrized on a per machine pair basis */ ! 290: if(machtype[local - 'a'] == M_INGRES && ! 291: machtype[remote - 'a'] == M_INGRES) ! 292: maxfile = MAXFILELARGE; ! 293: if(sin) ! 294: while((i = fread(buf,1,BUFSIZ,stdin)) > 0){ ! 295: if(fwrite(buf,1,i,file) != i){ ! 296: perror("net queue file"); ! 297: outerror(); ! 298: } ! 299: if((cnt += i) > maxfile)goto toobig; ! 300: if(feof(stdin))break; ! 301: } ! 302: else if(localin[0]){ ! 303: if(access(localin,4) == -1){ ! 304: perror(localin); ! 305: outerror(); ! 306: } ! 307: temp = fopen(localin,"r"); ! 308: if(temp == NULL){ ! 309: perror(localin); ! 310: outerror(); ! 311: } ! 312: while((i = fread(buf,1,BUFSIZ,temp)) > 0){ ! 313: if((cnt += i) > maxfile)goto toobig; ! 314: if(fwrite(buf,1,i,file) != i){ ! 315: perror("net queue file"); ! 316: outerror(); ! 317: } ! 318: } ! 319: fclose(temp); ! 320: } ! 321: fclose(file); ! 322: chmod(dfname,0400); ! 323: dfname[strlen(dfname)-9] = 'c'; ! 324: file = fopen(dfname,"w"); ! 325: chmod(dfname,0400); ! 326: fclose(file); ! 327: mchown(dfname,uid,getgid()); ! 328: exit(0); ! 329: toobig: ! 330: fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile); ! 331: outerror(); /* no return */ ! 332: } ! 333: /* ! 334: called if there is an error, makes sure that the files created ! 335: are deleted and the terminal is reset to echo ! 336: */ ! 337: outerror(){ ! 338: register int i; ! 339: struct sgttyb stt; ! 340: signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); ! 341: signal(SIGQUIT,SIG_IGN); signal(SIGTRM,SIG_IGN); ! 342: unlink(dfname); ! 343: i = strlen(dfname) - 9; ! 344: dfname[i] = (dfname[i] == 'c' ? 'd' : 'c'); ! 345: unlink(dfname); ! 346: if(gtty(0,&stt) >= 0){ ! 347: stt.sg_flags |= ECHO; ! 348: stty(0,&stt); ! 349: } ! 350: exit(1); ! 351: } ! 352: enmask(s) ! 353: register char *s; { ! 354: # ifdef NEWPROT ! 355: static char buf[20]; ! 356: strcpy(s,nbsencrypt(s,THEKEY,buf)); ! 357: # else ! 358: while(*s){ ! 359: *s &= 0177; /* strip quote bites */ ! 360: *s++ ^= 040; /* invert upper-lower */ ! 361: } ! 362: # endif ! 363: } ! 364: addir(s,t) ! 365: register char *s, *t; { ! 366: if(t[0] == '/')strcpy(s,t); ! 367: else { ! 368: gwd(s); ! 369: strcat(s,t); ! 370: } ! 371: } ! 372: /* returns pass if not special, otherwise returns funny passwd */ ! 373: /* list of special accounts must be consistent - with netdaemon.c */ ! 374: char *handlesp(log,pass,localname,luid,lgid) ! 375: char *log,*pass,*localname;{ ! 376: /* experimental */ ! 377: # ifdef SPACCT ! 378: long lt; ! 379: char str[20]; ! 380: if(strcmp(log,localname) == 0 && luid != 0 && lgid == 0 && ( ! 381: strcmp(log,"source") == 0 ! 382: || strcmp(log,"daemon") == 0 ! 383: )) { ! 384: lt = lgid; ! 385: lt = (lt << 16) | luid; ! 386: sprintf(str,"%ld",lt); ! 387: return(str); ! 388: } ! 389: # endif ! 390: return(pass); ! 391: } ! 392: ! 393: ! 394: ! 395: static struct stat x; ! 396: static struct direct y; ! 397: static FILE *file; ! 398: static int off = -1; ! 399: ! 400: ! 401: /* these three routines gwd, cat, ckroot and ! 402: data structures x, y, off, do a pwd to string name */ ! 403: gwd(name) ! 404: register char *name; { ! 405: *name = 0; ! 406: for(;;){ ! 407: stat(".",&x); ! 408: if((file = fopen("..","r")) == NULL)break; ! 409: do { ! 410: if(fread(&y,1,sizeof y,file) != sizeof y)break; ! 411: } while(y.d_ino != x.st_ino); ! 412: fclose(file); ! 413: if(y.d_ino == ROOTINO){ ! 414: ckroot(name); ! 415: break; ! 416: } ! 417: if(cat(name))break; ! 418: chdir(".."); ! 419: } ! 420: chdir(name); ! 421: } ! 422: ! 423: cat(name) ! 424: register char *name; { /* return 1 to exit */ ! 425: register int i,j; ! 426: i = -1; ! 427: while(y.d_name[++i] != 0); ! 428: if((off+i+2) > 511)return(1); ! 429: for(j = off +1; j >= 0; --j)name[j+i+1] = name[j]; ! 430: off = i + off + 1; ! 431: name[i] = '/'; ! 432: for(--i; i>= 0; --i)name[i] = y.d_name[i]; ! 433: return(0); ! 434: } ! 435: ! 436: ckroot(name) ! 437: char *name; { ! 438: register int i; ! 439: if(stat(y.d_name,&x) < 0)return; ! 440: i = x.st_dev; ! 441: if(chdir("/") < 0)return; ! 442: if((file = fopen("/","r")) == NULL)return; ! 443: do { ! 444: if(fread(&y,1,sizeof y,file) != sizeof y)return; ! 445: if(y.d_ino == 0)continue; ! 446: if(stat(y.d_name,&x) < 0)return; ! 447: } while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR); ! 448: if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0) ! 449: if(cat(name))return; ! 450: i = strlen(name); ! 451: name[i+1] = 0; ! 452: while(--i >= 0)name[i + 1] = name[i]; ! 453: name[0] = '/'; ! 454: return; ! 455: } ! 456: /* ! 457: this function takes a file name and tells whether it is a ! 458: directory or on. Returns 1 if so, 0 otherwise. ! 459: null strings etc. return 0. ! 460: */ ! 461: isdirectory(fn) ! 462: char *fn; ! 463: { ! 464: int i,ret=0; ! 465: if(fn == NULL || *fn == 0)return(0); ! 466: i = strlen(fn); ! 467: if(i == 1){ ! 468: if(strcmp(fn,".") == 0)ret = 1; ! 469: if(strcmp(fn,"/") == 0)ret = 1; ! 470: } ! 471: else if(i == 2){ ! 472: if(strcmp(fn,"..") == 0)ret = 1; ! 473: if(strcmp(fn,"/.") == 0)ret = 1; ! 474: } ! 475: else { ! 476: if(strcmp(fn+i-2,"/.") == 0)ret = 1; ! 477: if(strcmp(fn+i-3,"/..") == 0)ret = 1; ! 478: } ! 479: return(ret); ! 480: } ! 481: /* ! 482: generate a variable parameter list ! 483: the format is: ! 484: (name value, name value, ..., name value) ! 485: where names are unquoted single words and values ! 486: are unquoted if a single alphanumeric word, and are ! 487: surrounded by {} otherwise. \ quotes { and }. ! 488: the values are escape-processed, e.g. \n becomes 012. ! 489: this function returns such a list. ! 490: Returns the null parm list if nothing to give, i.e. "()" ! 491: ! 492: Should also default so single keywords can have on/off ! 493: states, and so do not require a value. ! 494: ! 495: Things this variable protocol should specify: ! 496: EPASSWD encrypted passwd ! 497: FILEMODE file mode ! 498: FROMUID from users' uid ! 499: FROMGID from users' gid ! 500: COMPRESS use colin's compression ! 501: SPACCT handle special accounts. ! 502: MESSAGEID unique number identifying this request. ! 503: VTOUSERNAME name netq should display as being "To:" ! 504: FILENAME when omitted by netcp, will use FILENAME ext. ! 505: MACHINE2 a second machine (e.g. 3way netcp) ! 506: LOGIN2 a second login name ! 507: PASSWD2 a second passwd ! 508: REPLYTO the person the response should be sent to ! 509: ! 510: */ ! 511: char *genparmlist(){ ! 512: static char returnstr[PARMLIST]; ! 513: strcpy(returnstr,"()"); ! 514: return(returnstr); ! 515: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.