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: /* global variables */ 40: struct userinfo status; 41: 42: /* local variables */ 43: static char dfname[]= DFNAME; 44: 45: main(argc, argv) 46: char **argv; { 47: register int i; 48: int outerror(),uid; 49: char localin[FNS], skey[30]; 50: char buf[BUFSIZ], suid[10]; 51: char sin =0, zopt = 0, wopt = 0, yopt = 0, xopt = 0; 52: char *s,**sargv; 53: long cnt = 0L, maxfile = MAXFILE; 54: FILE *file, *temp, *rfile; 55: struct utmp *putmp; 56: struct stat statbuf; 57: struct header hd; 58: 59: debugflg = DBV; 60: hd.hd_scmdact[0] = hd.hd_srespfile[0] = hd.hd_soutfile[0] = 0; 61: hd.hd_sinfile[0] = hd.hd_scmdvirt[0] = hd.hd_sttyname[0] = 0; 62: localin[0] = 0; 63: suid[0] = 0; 64: sargv = argv; 65: 66: if(isatty(0)) strcat(hd.hd_sttyname,ttyname(0)); 67: else if(isatty(2)) strcat(hd.hd_sttyname,ttyname(2)); 68: remote = 0; 69: if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 70: signal(SIGHUP, outerror); 71: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 72: signal(SIGQUIT, outerror); 73: if (signal(SIGINT, SIG_IGN) != SIG_IGN) 74: signal(SIGINT, outerror); 75: if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 76: signal(SIGTERM, outerror); 77: 78: while(argc > 1 && argv[1][0] == '-'){ 79: argc--; argv++; 80: switch(argv[0][1]){ 81: case 0: sin++; break; 82: case 'b': status.nonotify++; break; 83: case 'c': harg(hd.hd_scmdvirt,&argc,&argv); break; 84: case 'f': status.force++; break; 85: case 'i': harg(hd.hd_sinfile,&argc,&argv); break; 86: case 'l': harg(status.login,&argc,&argv); break; 87: case 'm': harg(buf,&argc,&argv); remote = lookup(buf); 88: if(remote == 0){ 89: fprintf(stderr,"Unknown machine %s\n",buf); 90: exit(EX_NOHOST); 91: } 92: break; 93: case 'n': status.nowrite++; break; 94: case 'o': harg(hd.hd_soutfile,&argc,&argv); break; 95: case 'p': 96: harg(status.mpasswd,&argc,&argv); 97: if(status.mpasswd[0] == 0) 98: strcpy(status.mpasswd,"\n\n"); 99: break; 100: case 'q': status.quiet++; break; 101: case 'r': harg(buf,&argc,&argv); addir(hd.hd_srespfile,buf); break; 102: case 's': harg(localin,&argc,&argv); break; 103: case 'u': harg(suid,&argc,&argv); break; 104: case 'w': wopt++; break; 105: case 'x': xopt++; break; 106: case 'y': yopt++; break; 107: case 'z': zopt++; break; 108: default: 109: fprintf(stderr,"Unknown option %s\n",argv[0]); 110: break; 111: } 112: } 113: while(argc > 1){ 114: argc--; argv++; 115: strcat(hd.hd_scmdact,argv[0]); 116: strcat(hd.hd_scmdact," "); 117: } 118: sargv[1] = 0; /* so ps won't show passwd ??? */ 119: hd.hd_uidfrom = uid = getuid(); 120: hd.hd_gidfrom = getgid(); 121: hd.hd_code = 'q'; 122: if(zopt || wopt || yopt || xopt || suid[0] != 0){ 123: /* check z or w or y or x option permission */ 124: # ifndef TESTING 125: if(uid != SUPERUSER){ 126: fprintf(stderr,"Error: Not super-user"); 127: outerror(EX_UNAVAILABLE); 128: } 129: # endif 130: hd.hd_code = zopt ? 's' : 'w'; 131: hd.hd_code = yopt ? 'y' : hd.hd_code; 132: if(status.mpasswd[0] == 0) /* no passwd required */ 133: strcpy(status.mpasswd,"\n"); 134: } 135: 136: status.jobno = 32767; /* default (invalid) job number */ 137: if(hd.hd_code == 'q' && !xopt){ 138: /* read passwd file, get status.localname & jobno */ 139: passwdent(); 140: } 141: 142: /* sets remote,status.login,status.force,status.mpasswd, 143: status.nonotify, status.nowrite */ 144: /* may read passwd file if getenv(HOME) reads it */ 145: commandfile(); 146: if(status.force)status.login[0] = status.mpasswd[0] = 0; 147: 148: /* look up login name and passwd in the environment */ 149: envloginpasswd(remote,status.login,status.mpasswd); 150: 151: 152: if(remote == 0)remote = getremote(local); 153: # ifndef TESTING 154: if(remote == local){ 155: fprintf(stderr,"Request sent to local machine - doesn't make sense\n"); 156: /* outerror(); */ 157: } 158: # endif 159: strcat(status.defcmd," "); 160: if(strlen(hd.hd_scmdact) == 0)strcpy(hd.hd_scmdact,status.defcmd); 161: hd.hd_scmdact[strlen(hd.hd_scmdact)-1] = 0; 162: mktemp(dfname); 163: /* determine through machine */ 164: i = gothru(local,remote); 165: if(i == 0){ 166: s = longname(remote); 167: if(s != 0)fprintf(stderr,"No path to %s machine.\n",s); 168: else fprintf(stderr,"Unknown machine\n"); 169: outerror(EX_NOHOST); 170: } 171: dfname[strlen(dfname)-11] = i; /* set directory */ 172: dfname[strlen(dfname)-7] = i; /* set file (unused) */ 173: /* check to see if data files are directories */ 174: if(isdirectory(hd.hd_srespfile) || isdirectory(hd.hd_sinfile) || isdirectory(hd.hd_soutfile)){ 175: fprintf(stderr,"%s is a directory, must be a file\n", 176: isdirectory(hd.hd_srespfile) ? hd.hd_srespfile : 177: isdirectory(hd.hd_sinfile) ? hd.hd_sinfile : 178: hd.hd_soutfile); 179: outerror(EX_USAGE); 180: } 181: if(suid[0] != 0)uid = atoi(suid); 182: if(hd.hd_srespfile[0]){ 183: if(strcmp(hd.hd_srespfile,"/dev/tty") == 0){ 184: fprintf(stderr,"Can't have /dev/tty as response file.\n"); 185: outerror(EX_USAGE); 186: } 187: if(stat(hd.hd_srespfile,&statbuf) == -1){ 188: strcpy(buf,hd.hd_srespfile); 189: s = &buf[0]; 190: s = s + strlen(buf) - 1; 191: while(*s != '/' && s > &(buf[0]))s--; 192: *s = 0; 193: debug("chkdir %s",buf); 194: if(strlen(buf) == 0)strcpy(buf,"."); 195: if(access(buf,2) == -1){ 196: perror(buf); 197: outerror(EX_USAGE); 198: } 199: if((rfile=fopen(hd.hd_srespfile,"w")) == NULL){ 200: perror(hd.hd_srespfile); 201: outerror(EX_USAGE); 202: } 203: chmod(hd.hd_srespfile,0600); 204: fclose(rfile); 205: mchown(hd.hd_srespfile,uid,hd.hd_gidfrom); 206: } 207: else if(access(hd.hd_srespfile,2) == -1){ 208: perror(hd.hd_srespfile); 209: outerror(EX_USAGE); 210: } 211: else if(getsize(&statbuf) != 0L){ 212: fprintf(stderr,"%s must have 0-length or not exist\n", 213: hd.hd_srespfile); 214: outerror(EX_USAGE); 215: } 216: } 217: /* go ahead and prompt for login name and passwd, if neccessary, 218: as long as the X option has not been specified */ 219: if(hd.hd_code == 'q' && !xopt)promptlogin(remote); 220: 221: /* at this point, we create the dfa... file */ 222: file = fopen(dfname,"w"); 223: if(file == NULL){ 224: perror(dfname); 225: outerror(EX_OSERR); 226: } 227: chmod(dfname,0600); 228: mchown(dfname,uid,getgid()); 229: if(xopt)goto stickit; 230: if(status.mpasswd[0] == '\n') 231: status.mpasswd[0] = 0; 232: if(machtype[local-'a'] == M_CC && machtype[remote-'a'] == M_CC 233: && status.mpasswd[0] != 0){ 234: s = crypt(status.mpasswd); 235: strcpy(status.mpasswd,s); 236: } 237: if(status.mpasswd[0] == 0 && hd.hd_code == 'q' && 238: strcmp(status.login,"network") != 0){ 239: fprintf(stderr,"Zero-length password not allowed\n"); 240: outerror(EX_USAGE); 241: } 242: if(hd.hd_code == 'q' && (streql(status.login,"root") == 0 || 243: streql(status.login,"ruut") == 0)){ 244: fprintf(stderr,"Can't login as root through the network\n"); 245: outerror(EX_USAGE); 246: } 247: makeuukey(skey,status.login,remote); 248: nbsencrypt(status.mpasswd,skey,hd.hd_sencpasswd); 249: enmask(status.mpasswd); 250: hd.hd_lttytime = 0; 251: if(hd.hd_sttyname[0] && status.nowrite == 0){ 252: putmp = getutmp(hd.hd_sttyname); 253: if(putmp != NULL) hd.hd_lttytime = putmp->ut_time; 254: } 255: /* 256: debug("p:%s:\n",status.mpasswd); 257: */ 258: /* write the header info onto 'file' */ 259: hd.hd_mchto = remote; 260: hd.hd_mesgid.msg_mch = hd.hd_mchfrom = local; 261: hd.hd_vmajor = VMAJOR; 262: hd.hd_vminor = VMINOR; 263: strcpy(hd.hd_snto,status.login); 264: strcpy(hd.hd_snfrom,status.localname); 265: strcpy(hd.hd_spasswd,status.mpasswd); 266: hd.hd_ijobno = status.jobno; 267: hd.hd_mesgid.msg_ltime = hd.hd_ltimesent = gettime(); 268: hd.hd_fquiet = status.quiet; 269: hd.hd_fnonotify = status.nonotify; 270: hd.hd_mesgid.msg_pid = getpid(); 271: hd.hd_fcompress = 0; 272: /* handle account pairs, accounts which do not require 273: a passwd if you are logged in on the same one here */ 274: hd.hd_facctpair = fisacctpair(&hd); 275: 276: writehdfd(&hd,file); 277: printhd(&hd); 278: stickit: 279: /* between ingres machines, allow long files */ 280: /* this should be parametrized on a per machine pair basis */ 281: if(machtype[local - 'a'] == M_INGRES && 282: machtype[remote - 'a'] == M_INGRES) 283: maxfile = MAXFILELARGE; 284: if(sin) 285: while((i = fread(buf,1,BUFSIZ,stdin)) > 0){ 286: if(fwrite(buf,1,i,file) != i){ 287: perror("net queue file"); 288: outerror(EX_OSFILE); 289: } 290: if((cnt += i) > maxfile)goto toobig; 291: if(feof(stdin))break; 292: } 293: else if(localin[0]){ 294: if(access(localin,4) == -1){ 295: perror(localin); 296: outerror(EX_OSFILE); 297: } 298: temp = fopen(localin,"r"); 299: if(temp == NULL){ 300: perror(localin); 301: outerror(EX_OSFILE); 302: } 303: while((i = fread(buf,1,BUFSIZ,temp)) > 0){ 304: if((cnt += i) > maxfile)goto toobig; 305: if(fwrite(buf,1,i,file) != i){ 306: perror("net queue file"); 307: outerror(EX_OSFILE); 308: } 309: } 310: fclose(temp); 311: } 312: fclose(file); 313: chmod(dfname,0400); 314: dfname[strlen(dfname)-9] = 'c'; 315: file = fopen(dfname,"w"); 316: chmod(dfname,0400); 317: fclose(file); 318: mchown(dfname,uid,getgid()); 319: exit(EX_OK); 320: toobig: 321: fprintf(stderr,"No more than %ld bytes can be sent\n",maxfile); 322: outerror(EX_USAGE); /* no return */ 323: } 324: /* 325: called if there is an error, makes sure that the files created 326: are deleted and the terminal is reset to echo 327: */ 328: outerror(ret){ 329: register int i; 330: struct sgttyb stt; 331: signal(SIGHUP,SIG_IGN); signal(SIGINT,SIG_IGN); 332: signal(SIGQUIT,SIG_IGN); signal(SIGTERM,SIG_IGN); 333: unlink(dfname); 334: i = strlen(dfname) - 9; 335: dfname[i] = (dfname[i] == 'c' ? 'd' : 'c'); 336: unlink(dfname); 337: if(gtty(0,&stt) >= 0){ 338: stt.sg_flags |= ECHO; 339: stty(0,&stt); 340: } 341: exit(ret); 342: } 343: enmask(s) 344: register char *s; { 345: while(*s){ 346: *s &= 0177; /* strip quote bites */ 347: *s++ ^= 040; /* invert upper-lower */ 348: } 349: } 350: addir(s,t) 351: register char *s, *t; { 352: if(t[0] == '/')strcpy(s,t); 353: else { 354: gwd(s); 355: strcat(s,t); 356: } 357: } 358: 359: /* returns true if phd is an account pair, false otherwise */ 360: fisacctpair(phd) 361: register struct header *phd; 362: { 363: return(0); 364: } 365: 366: 367: static struct stat x; 368: static struct direct y; 369: static FILE *file; 370: static int off = -1; 371: 372: 373: /* these three routines gwd, cat, ckroot and 374: data structures x, y, off, do a pwd to string name */ 375: gwd(name) 376: register char *name; { 377: *name = 0; 378: for(;;){ 379: stat(".",&x); 380: if((file = fopen("..","r")) == NULL)break; 381: do { 382: if(fread(&y,1,sizeof y,file) != sizeof y)break; 383: } while(y.d_ino != x.st_ino); 384: fclose(file); 385: if(y.d_ino == ROOTINO){ 386: ckroot(name); 387: break; 388: } 389: if(cat(name))break; 390: chdir(".."); 391: } 392: chdir(name); 393: } 394: 395: cat(name) 396: register char *name; { /* return 1 to exit */ 397: register int i,j; 398: i = -1; 399: while(y.d_name[++i] != 0); 400: if((off+i+2) > 511)return(1); 401: for(j = off +1; j >= 0; --j)name[j+i+1] = name[j]; 402: off = i + off + 1; 403: name[i] = '/'; 404: for(--i; i>= 0; --i)name[i] = y.d_name[i]; 405: return(0); 406: } 407: 408: ckroot(name) 409: char *name; { 410: register int i; 411: if(stat(y.d_name,&x) < 0)return; 412: i = x.st_dev; 413: if(chdir("/") < 0)return; 414: if((file = fopen("/","r")) == NULL)return; 415: do { 416: if(fread(&y,1,sizeof y,file) != sizeof y)return; 417: if(y.d_ino == 0)continue; 418: if(stat(y.d_name,&x) < 0)return; 419: } while(x.st_dev!=i || (x.st_mode&S_IFMT)!=S_IFDIR); 420: if(strcmp(y.d_name,".") != 0 && strcmp(y.d_name,"..") != 0) 421: if(cat(name))return; 422: i = strlen(name); 423: name[i+1] = 0; 424: while(--i >= 0)name[i + 1] = name[i]; 425: name[0] = '/'; 426: return; 427: } 428: /* 429: this function takes a file name and tells whether it is a 430: directory or on. Returns 1 if so, 0 otherwise. 431: null strings etc. return 0. 432: */ 433: isdirectory(fn) 434: char *fn; 435: { 436: int i,ret=0; 437: if(fn == NULL || *fn == 0)return(0); 438: i = strlen(fn); 439: if(i == 1){ 440: if(strcmp(fn,".") == 0)ret = 1; 441: if(strcmp(fn,"/") == 0)ret = 1; 442: } 443: else if(i == 2){ 444: if(strcmp(fn,"..") == 0)ret = 1; 445: if(strcmp(fn,"/.") == 0)ret = 1; 446: } 447: else { 448: if(strcmp(fn+i-2,"/.") == 0)ret = 1; 449: if(strcmp(fn+i-3,"/..") == 0)ret = 1; 450: } 451: return(ret); 452: }