1: static char sccsid[] = "@(#)net.c 4.2 (Berkeley) 9/12/82"; 2: 3: /* sccs id variable */ 4: static char *net_sid = "@(#)net.c 1.8"; 5: 6: # include "defs.h" 7: /* must be setuid root */ 8: /* 9: net - -b -c cmd -f -i file -l name -mmach -n -o file -p passwd 10: -r file -s file -u uid -w -x -y -z command 11: 12: - take from standard input 13: -b never send anything back 14: -c cmd think of this as a "cmd" * 15: -f force prompting of user name and password 16: -i file remote stdin * 17: -l name remote login name 18: -m Mach remote machine 19: -n do not write back anything, always mail them back 20: -o file remote stdout & stderr * 21: -p pass remote password 22: -q quiet option, send back only if rcode !=0 or if there is stdout 23: -r file local response file 24: -s file local stdin file * 25: 26: (super users only, always skip login/passwd check:) 27: -u uid net queue files should be owned by uid (16 bits) 28: -w this is a write/mail response cmd * 29: -x this is being forwarded through us to another machine * 30: -y skip login/password check * 31: -z this is a response file being returned * 32: 33: * = not documented in net(NEW) 34: 35: */ 36: /* 37: code option reason 38: q normal request 39: w -w message to be written back 40: -x being forwarded through us 41: y -y simply skips login check (used by netlpr) 42: s -z normal response 43: */ 44: /* global variables */ 45: struct userinfo status; 46: 47: /* local variables */ 48: static char dfname[]= DFNAME; 49: 50: main(argc, argv) 51: char **argv; { 52: register int i; 53: int outerror(),uid; 54: char localin[FNS], skey[30]; 55: char buf[BUFSIZ], suid[10]; 56: char sin =0, zopt = 0, wopt = 0, yopt = 0, xopt = 0; 57: char *s,**sargv; 58: long cnt = 0L, maxfile = MAXFILELARGE; 59: FILE *file, *temp, *rfile; 60: struct utmp *putmp; 61: struct stat statbuf; 62: struct header hd; 63: 64: debugflg = DBV; 65: hd.hd_scmdact[0] = hd.hd_srespfile[0] = hd.hd_soutfile[0] = 0; 66: hd.hd_sinfile[0] = hd.hd_scmdvirt[0] = hd.hd_sttyname[0] = 0; 67: localin[0] = 0; 68: suid[0] = 0; 69: sargv = argv; 70: 71: if(isatty(0)) strcat(hd.hd_sttyname,ttyname(0)); 72: else if(isatty(2)) strcat(hd.hd_sttyname,ttyname(2)); 73: remote = 0; 74: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 75: signal(SIGHUP, outerror); 76: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 77: signal(SIGQUIT, outerror); 78: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 79: signal(SIGINT, outerror); 80: if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 81: signal(SIGTERM, outerror); 82: 83: while(argc > 1 && argv[1][0] == '-'){ 84: argc--; argv++; 85: switch(argv[0][1]){ 86: case 0: 87: sin++; 88: break; 89: case 'b': 90: status.nonotify++; 91: break; 92: case 'c': 93: harg(hd.hd_scmdvirt); 94: break; 95: case 'f': 96: status.force++; 97: break; 98: case 'i': 99: harg(hd.hd_sinfile); 100: break; 101: case 'l': 102: harg(status.login); 103: break; 104: case 'm': 105: harg(buf); 106: remote = lookup(buf); 107: if(remote == 0){ 108: fprintf(stderr,"Unknown machine %s\n",buf); 109: exit(EX_NOHOST); 110: } 111: break; 112: case 'n': 113: status.nowrite++; 114: break; 115: case 'o': 116: harg(hd.hd_soutfile); 117: break; 118: case 'p': 119: harg(status.mpasswd); 120: if(status.mpasswd[0] == 0) 121: strcpy(status.mpasswd,"\n\n"); 122: break; 123: case 'q': 124: status.quiet++; 125: break; 126: case 'r': 127: harg(buf); 128: addir(hd.hd_srespfile,buf); 129: break; 130: case 's': 131: harg(localin); 132: break; 133: case 'u': 134: harg(suid); 135: break; 136: case 'w': 137: wopt++; 138: break; 139: case 'x': 140: xopt++; 141: break; 142: case 'y': 143: yopt++; 144: break; 145: case 'z': 146: zopt++; 147: break; 148: default: 149: fprintf(stderr,"Unknown option %s\n",argv[0]); 150: break; 151: } 152: } 153: while(argc > 1){ 154: argc--; argv++; 155: strcat(hd.hd_scmdact,argv[0]); 156: strcat(hd.hd_scmdact," "); 157: } 158: sargv[1] = 0; /* so ps won't show passwd ??? */ 159: hd.hd_uidfrom = uid = getuid(); 160: hd.hd_gidfrom = getgid(); 161: hd.hd_code = 'q'; 162: if(zopt || wopt || yopt || xopt || suid[0] != 0){ 163: /* check z or w or y or x option permission */ 164: # ifndef TESTING 165: /* check effective user id ?? */ 166: if (uid != SUPERUSER && uid != NUID) { 167: fprintf(stderr, "Error: Not super-user\n"); 168: fprintf(stderr,"zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid); 169: fprintf(stderr,"uid %d\n", uid); 170: debugflg = 1; 171: printhd(&hd); 172: outerror(EX_UNAVAILABLE); 173: } 174: # endif 175: hd.hd_code = zopt? 's': 'w'; 176: hd.hd_code = yopt? 'y': hd.hd_code; 177: if (status.mpasswd[0] == 0) /* no passwd required */ 178: strcpy(status.mpasswd, "\n"); 179: debug("zopt %d wopt %d yopt %d xopt %d suid[0] %s\n", zopt, wopt, yopt, xopt, suid); 180: debug("uid %d\n", uid); 181: if(xopt) 182: setuid(SUPERUSER); 183: } 184: #ifdef CRN 185: strcpy( status.jobno, MAGICCRN ); /* default (invalid) crn */ 186: #else 187: strcpy( status.jobno, "XYZZ"); /* default (invalid) crn */ 188: #endif 189: 190: if(hd.hd_code == 'q' && !xopt){ 191: /* read passwd file, get status.localname & crn */ 192: passwdent(); 193: } 194: 195: /* sets remote,status.login,status.force,status.mpasswd, 196: status.nonotify, status.nowrite */ 197: /* may read passwd file if getenv(HOME) reads it */ 198: commandfile(); 199: if(status.force)status.login[0] = status.mpasswd[0] = 0; 200: 201: /* look up login name and passwd in the environment */ 202: envloginpasswd(remote,status.login,status.mpasswd); 203: 204: 205: if(remote == 0)remote = getremote(local); 206: # ifndef TESTING 207: if(remote == local){ 208: fprintf(stderr,"Request sent to local machine - doesn't make sense\n"); 209: /* outerror(); */ 210: } 211: # endif 212: strcat(status.defcmd," "); 213: if(strlen(hd.hd_scmdact) == 0)strcpy(hd.hd_scmdact,status.defcmd); 214: hd.hd_scmdact[strlen(hd.hd_scmdact)-1] = 0; 215: do { 216: mktemp(dfname); /* make until unique!! */ 217: } while(stat(dfname,&statbuf) >= 0); 218: /* determine through machine */ 219: i = gothru(local,remote); 220: if(i == 0){ 221: s = longname(remote); 222: if(s != 0)fprintf(stderr,"No path to %s machine.\n",s); 223: else fprintf(stderr,"Unknown machine\n"); 224: outerror(EX_NOHOST); 225: } 226: dfname[strlen(dfname)-11] = i; /* set directory */ 227: dfname[strlen(dfname)-7] = i; /* set file (unused) */ 228: /* check to see if data files are directories */ 229: if(isdirectory(hd.hd_srespfile) || isdirectory(hd.hd_sinfile) || isdirectory(hd.hd_soutfile)){ 230: fprintf(stderr,"%s is a directory, must be a file\n", 231: isdirectory(hd.hd_srespfile) ? hd.hd_srespfile : 232: isdirectory(hd.hd_sinfile) ? hd.hd_sinfile : 233: hd.hd_soutfile); 234: outerror(EX_USAGE); 235: } 236: if(suid[0] != 0)uid = atoi(suid); 237: if(hd.hd_srespfile[0]){ 238: if(strcmp(hd.hd_srespfile,"/dev/tty") == 0){ 239: fprintf(stderr,"Can't have /dev/tty as response file.\n"); 240: outerror(EX_USAGE); 241: } 242: if(stat(hd.hd_srespfile,&statbuf) == -1){ 243: strcpy(buf,hd.hd_srespfile); 244: s = &buf[0]; 245: s = s + strlen(buf) - 1; 246: while(*s != '/' && s > &(buf[0]))s--; 247: *s = 0; 248: debug("chkdir %s",buf); 249: if(strlen(buf) == 0)strcpy(buf,"."); 250: if(access(buf,2) == -1){ 251: perror(buf); 252: outerror(EX_USAGE); 253: } 254: if((rfile=fopen(hd.hd_srespfile,"w")) == NULL){ 255: perror(hd.hd_srespfile); 256: outerror(EX_USAGE); 257: } 258: chmod(hd.hd_srespfile,0600); 259: fclose(rfile); 260: mchown(hd.hd_srespfile,uid,hd.hd_gidfrom); 261: } 262: else if(access(hd.hd_srespfile,2) == -1){ 263: perror(hd.hd_srespfile); 264: outerror(EX_USAGE); 265: } 266: else if(getsize(&statbuf) != 0L){ 267: fprintf(stderr,"%s must have 0-length or not exist\n", 268: hd.hd_srespfile); 269: outerror(EX_USAGE); 270: } 271: } 272: /* go ahead and prompt for login name and passwd, if neccessary, 273: as long as the X option has not been specified */ 274: if(hd.hd_code == 'q' && !xopt)promptlogin(remote); 275: 276: /* at this point, we create the dfa... file */ 277: file = fopen(dfname,"w"); 278: if(file == NULL){ 279: perror(dfname); 280: outerror(EX_OSERR); 281: } 282: chmod(dfname,0600); 283: mchown(dfname,uid,getgid()); 284: if(xopt)goto stickit; 285: if(status.mpasswd[0] == '\n') 286: status.mpasswd[0] = 0; 287: if(status.mpasswd[0] == 0 && hd.hd_code == 'q' && 288: strcmp(status.login,"network") != 0){ 289: fprintf(stderr,"Zero-length password not allowed\n"); 290: outerror(EX_USAGE); 291: } 292: if(hd.hd_code == 'q' && (streql(status.login,"root") == 0 || 293: streql(status.login,"ruut") == 0)){ 294: fprintf(stderr,"Can't login as root through the network\n"); 295: outerror(EX_USAGE); 296: } 297: makeuukey(skey,status.login,remote); 298: nbsencrypt(status.mpasswd,skey,hd.hd_sencpasswd); 299: enmask(status.mpasswd); 300: hd.hd_lttytime = 0; 301: if(hd.hd_sttyname[0] && status.nowrite == 0){ 302: putmp = getutmp(hd.hd_sttyname); 303: if(putmp != NULL) hd.hd_lttytime = putmp->ut_time; 304: } 305: /* 306: debug("p:%s:\n",status.mpasswd); 307: */ 308: /* write the header info onto 'file' */ 309: hd.hd_mchto = remote; 310: hd.hd_mesgid.msg_mch = hd.hd_mchfrom = local; 311: hd.hd_vmajor = VMAJOR; 312: hd.hd_vminor = VMINOR; 313: strcpy(hd.hd_snto,status.login); 314: strcpy(hd.hd_snfrom,status.localname); 315: strcpy(hd.hd_spasswd,status.mpasswd); 316: strcpy(hd.hd_ijobno, status.jobno ); 317: hd.hd_mesgid.msg_ltime = hd.hd_ltimesent = gettime(); 318: hd.hd_fquiet = status.quiet; 319: hd.hd_fnonotify = status.nonotify; 320: hd.hd_mesgid.msg_pid = getpid(); 321: hd.hd_fcompressed = 0; 322: /* handle account pairs, accounts which do not require 323: a passwd if you are logged in on the same one here */ 324: hd.hd_facctpair = fisacctpair(&hd); 325: 326: writehdfd(&hd,file); 327: printhd(&hd); 328: stickit: 329: if(sin) 330: while((i = fread(buf,1,BUFSIZ,stdin)) > 0){ 331: if(fwrite(buf,1,i,file) != i){ 332: perror("net queue file"); 333: outerror(EX_OSFILE); 334: } 335: if((cnt += i) > maxfile)goto toobig; 336: if(feof(stdin))break; 337: } 338: else if(localin[0]){ 339: if(access(localin,4) == -1){ 340: perror(localin); 341: outerror(EX_OSFILE); 342: } 343: temp = fopen(localin,"r"); 344: if(temp == NULL){ 345: perror(localin); 346: outerror(EX_OSFILE); 347: } 348: while((i = fread(buf,1,BUFSIZ,temp)) > 0){ 349: if((cnt += i) > maxfile)goto toobig; 350: if(fwrite(buf,1,i,file) != i){ 351: perror("net queue file"); 352: outerror(EX_OSFILE); 353: } 354: } 355: fclose(temp); 356: } 357: fclose(file); 358: chmod(dfname,0400); 359: dfname[strlen(dfname)-9] = 'c'; 360: file = fopen(dfname,"w"); 361: chmod(dfname,0400); 362: fclose(file); 363: mchown(dfname,uid,getgid()); 364: exit(EX_OK); 365: toobig: 366: fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile); 367: outerror(EX_USAGE); /* no return */ 368: } 369: /* 370: called if there is an error, makes sure that the files created 371: are deleted and the terminal is reset to echo 372: */ 373: outerror(ret){ 374: register int i; 375: struct sgttyb stt; 376: signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); 377: signal(SIGQUIT,SIG_IGN); signal(SIGTERM,SIG_IGN); 378: unlink(dfname); 379: i = strlen(dfname) - 9; 380: dfname[i] = (dfname[i] == 'c' ? 'd' : 'c'); 381: unlink(dfname); 382: if(gtty(0,&stt) >= 0){ 383: stt.sg_flags |= ECHO; 384: stty(0,&stt); 385: } 386: exit(ret); 387: } 388: enmask(s) 389: register char *s; { 390: while(*s){ 391: *s &= 0177; /* strip quote bites */ 392: *s++ ^= 040; /* invert upper-lower */ 393: } 394: } 395: addir(s,t) 396: register char *s, *t; { 397: if(t[0] == '/')strcpy(s,t); 398: else { 399: gwd(s); 400: strcat(s,t); 401: } 402: } 403: 404: /* returns true if phd is an account pair, false otherwise */ 405: fisacctpair(phd) 406: register struct header *phd; 407: { 408: return(0); 409: } 410: 411: 412: 413: static struct stat x; 414: static struct direct y; 415: static int off = -1; 416: 417: 418: /* these three routines gwd, cat, ckroot and 419: data structures x, y, off, do a pwd to string name */ 420: #ifdef V6 421: static FILE *file; 422: 423: gwd(name) 424: register char *name; { 425: *name = 0; 426: for(;;){ 427: stat(".",&x); 428: if((file = fopen("..","r")) == NULL)break; 429: do { 430: if(fread(&y,1,sizeof y,file) != sizeof y)break; 431: } while(y.d_ino != x.st_ino); 432: fclose(file); 433: if(y.d_ino == ROOTINO){ 434: ckroot(name); 435: break; 436: } 437: if(cat(name))break; 438: chdir(".."); 439: } 440: chdir(name); 441: } 442: ckroot(name) 443: char *name; { 444: register int i; 445: if(stat(y.d_name,&x) < 0)return; 446: i = x.st_dev; 447: if(chdir("/") < 0)return; 448: if((file = fopen("/","r")) == NULL)return; 449: do { 450: if(fread(&y,1,sizeof y,file) != sizeof y)return; 451: if(y.d_ino == 0)continue; 452: if(stat(y.d_name,&x) < 0)return; 453: } while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR); 454: if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0) 455: if(cat(name))return; 456: i = strlen(name); 457: name[i+1] = 0; 458: while(--i >= 0)name[i + 1] = name[i]; 459: name[0] = '/'; 460: return; 461: } 462: #else 463: static DIR *file; 464: static struct stat xx; 465: 466: gwd(name) 467: register char *name; { 468: int rdev, rino; 469: register int i; 470: register struct direct *dp; 471: 472: *name = 0; 473: stat("/", &x); 474: rdev = x.st_dev; 475: rino = x.st_ino; 476: for (;;) { 477: stat(".", &x); 478: if (x.st_ino == rino && x.st_dev == rdev) 479: break; 480: if ((file = opendir("..")) == NULL) 481: break; 482: fstat(file->dd_fd, &xx); 483: chdir(".."); 484: if (x.st_dev == xx.st_dev) { 485: if (x.st_ino == xx.st_ino) 486: break; 487: do 488: if ((dp = readdir(file)) == NULL) 489: break; 490: while (dp->d_ino != x.st_ino); 491: } 492: else do { 493: if ((dp = readdir(file)) == NULL) 494: break; 495: stat(dp->d_name, &xx); 496: } while (xx.st_ino != x.st_ino || xx.st_dev != x.st_dev); 497: blkcpy(dp, &y, DIRSIZ(dp)); 498: closedir(file); 499: if (cat(name)) 500: break; 501: } 502: i = strlen(name); 503: name[i+1] = 0; 504: while (--i >= 0) name[i+1] = name[i]; 505: name[0] = '/'; 506: } 507: #endif 508: 509: cat(name) 510: register char *name; { /* return 1 to exit */ 511: register int i,j; 512: i = -1; 513: while(y.d_name[++i] != 0); 514: if((off+i+2) > 511)return(1); 515: for(j = off +1; j >= 0; --j)name[j+i+1] = name[j]; 516: off = i + off + 1; 517: name[i] = '/'; 518: for(--i; i>= 0; --i)name[i] = y.d_name[i]; 519: return(0); 520: } 521: 522: 523: /* 524: this function takes a file name and tells whether it is a 525: directory or on. Returns 1 if so, 0 otherwise. 526: null strings etc. return 0. 527: */ 528: isdirectory(fn) 529: char *fn; 530: { 531: int i,ret=0; 532: if(fn == NULL || *fn == 0)return(0); 533: i = strlen(fn); 534: if(i == 1){ 535: if(strcmp(fn,".") == 0)ret = 1; 536: if(strcmp(fn,"/") == 0)ret = 1; 537: } 538: else if(i == 2){ 539: if(strcmp(fn,"..") == 0)ret = 1; 540: if(strcmp(fn,"/.") == 0)ret = 1; 541: } 542: else { 543: if(strcmp(fn+i-2,"/.") == 0)ret = 1; 544: if(strcmp(fn+i-3,"/..") == 0)ret = 1; 545: } 546: return(ret); 547: } 548: 549: blkcpy(from, to, size) 550: register *from, *to; 551: register int size; 552: { 553: while (size-- > 0) 554: *to++ = *from++; 555: }