1 static char sccsid[] = "@(#)net.c 4.2 (Berkeley) 09/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 } 556