1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" 32 33 #include "uucp.h" 34 #include "log.h" 35 36 void notify(), lnotify(), unlinkdf(), arrived(); 37 static void stmesg(); 38 static int nospace(); 39 40 struct Proto { 41 char P_id; 42 int (*P_turnon)(); 43 int (*P_rdmsg)(); 44 int (*P_wrmsg)(); 45 int (*P_rddata)(); 46 int (*P_wrdata)(); 47 int (*P_turnoff)(); 48 }; 49 50 extern char _Protocol[]; 51 extern char *findProto(); 52 53 extern char uuxqtarg[]; 54 55 extern int gturnon(), gturnoff(); 56 extern int grdmsg(), grddata(); 57 extern int gwrmsg(), gwrdata(); 58 59 extern int wmesg(), rmesg(), expfile(), putinpub(), stptcl(); 60 extern void setline(), TMname(), cleanup(), pfEndfile(), statlog(), mailst(); 61 62 #ifdef D_PROTOCOL 63 extern int dturnon(), dturnoff(); 64 extern int drdmsg(), drddata(); 65 extern int dwrmsg(), dwrdata(); 66 #endif /* D_PROTOCOL */ 67 68 #ifdef X_PROTOCOL 69 extern int xturnon(), xturnoff(); 70 extern int xrdmsg(), xrddata(); 71 extern int xwrmsg(), xwrdata(); 72 #endif /* X_PROTOCOL */ 73 74 #ifdef E_PROTOCOL 75 extern int eturnon(), eturnoff(); 76 extern int erdmsg(), erddata(); 77 extern int ewrmsg(), ewrdata(); 78 extern int trdmsg(), twrmsg(); 79 extern int trddata(), twrdata(); 80 #endif /* E_PROTOCOL */ 81 82 #ifdef F_PROTOCOL 83 extern int fturnon(), fturnoff(); 84 extern int frdmsg(), frddata(); 85 extern int fwrmsg(), fwrdata(); 86 #endif /* F_PROTOCOL */ 87 88 extern int imsg(); 89 extern int omsg(); 90 extern int turnoff(); 91 extern long strtol(); 92 93 struct Proto Ptbl[]={ 94 {'g', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff}, 95 {'G', gturnon, grdmsg, gwrmsg, grddata, gwrdata, gturnoff}, 96 97 #ifdef E_PROTOCOL 98 {'e', eturnon, erdmsg, ewrmsg, erddata, ewrdata, eturnoff}, 99 {'t', eturnon, trdmsg, twrmsg, trddata, twrdata, eturnoff}, 100 #endif /* E_PROTOCOL */ 101 102 #ifdef D_PROTOCOL 103 {'d', dturnon, drdmsg, dwrmsg, drddata, dwrdata, dturnoff}, 104 #endif /* D_PROTOCOL */ 105 106 #ifdef X_PROTOCOL 107 {'x', xturnon, xrdmsg, xwrmsg, xrddata, xwrdata, xturnoff}, 108 #endif /* X_PROTOCOL */ 109 110 #ifdef F_PROTOCOL 111 {'f', fturnon, frdmsg, fwrmsg, frddata, fwrdata, fturnoff}, 112 #endif /* F_PROTOCOL */ 113 '\0' 114 }; 115 116 #define VALIDSIZE sizeof(Ptbl)/sizeof(struct Proto) 117 118 int (*Rdmsg)()=imsg, (*Rddata)(); 119 int (*Wrmsg)()=omsg, (*Wrdata)(); 120 int (*Turnon)(), (*Turnoff)()=turnoff; 121 122 123 #define YES "Y" 124 #define NO "N" 125 126 #define TBUFSIZE 128 /* temporary buffer size */ 127 #define FLENRADIX (16) /* output radix for file start point */ 128 129 /* 130 * failure messages 131 */ 132 #define EM_MAX 10 133 #define EM_LOCACC "N1" /* local access to file denied */ 134 #define EM_RMTACC "N2" /* remote access to file/path denied */ 135 #define EM_BADUUCP "N3" /* a bad uucp command was generated */ 136 #define EM_NOTMP "N4" /* remote error - can't create temp */ 137 #define EM_RMTCP "N5" /* can't copy to remote directory - file in public */ 138 #define EM_LOCCP "N6" /* can't copy on local system */ 139 #define EM_SEEK "N7" /* can't seek to checkpoint */ 140 /* EM_ "N8" */ /* placeholder*/ 141 /* EM_ "N9" */ /* placeholder*/ 142 #define EM_ULIMIT "N10" /* receiver ulimit exceeded */ 143 144 char *Em_msg[] = { 145 "COPY FAILED (reason not given by remote)", 146 "local access to file denied", 147 "remote access to path/file denied", 148 "system error - bad uucp command generated", 149 "remote system can't create temp file", 150 "can't copy to file/directory - file left in PUBDIR/user/file", 151 "can't copy to file/directory - file left in PUBDIR/user/file", 152 "can't seek to checkpoint", 153 "COPY FAILED (reason not given by remote)", /* placeholder */ 154 "COPY FAILED (reason not given by remote)", /* placeholder */ 155 "file exceeds ulimit of receiving system", 156 "forwarding error" 157 }; 158 159 160 #define XUUCP 'X' /* execute uucp (string) */ 161 #define SLTPTCL 'P' /* select protocol (string) */ 162 #define USEPTCL 'U' /* use protocol (character) */ 163 #define RCVFILE 'R' /* receive file (string) */ 164 #define SNDFILE 'S' /* send file (string) */ 165 #define RQSTCMPT 'C' /* request complete (string - yes | no) */ 166 #define HUP 'H' /* ready to hangup (string - yes | no) */ 167 #define RESET 'X' /* reset line modes */ 168 169 #define W_MAX 10 /* maximum number of C. files per line */ 170 #define W_MIN 7 /* min number of entries */ 171 #define W_TYPE wrkvec[0] 172 #define W_FILE1 wrkvec[1] 173 #define W_FILE2 wrkvec[2] 174 #define W_USER wrkvec[3] 175 #define W_OPTNS wrkvec[4] 176 #define W_DFILE wrkvec[5] 177 #define W_MODE wrkvec[6] 178 #define W_NUSER wrkvec[7] 179 #define W_SFILE wrkvec[8] 180 #define W_RDFILE wrkvec[8] 181 #define W_POINT wrkvec[9] 182 #define W_FSIZE wrkvec[9] 183 #define W_RFILE wrkvec[5] 184 #define W_XFILE wrkvec[5] 185 char *mf; 186 187 #define RMESG(m, s) if (rmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);} 188 #define RAMESG(s) if (rmesg('\0', s) != 0) {(*Turnoff)(); return(FAIL);} 189 #define WMESG(m, s) if(wmesg(m, s) != 0) {(*Turnoff)(); return(FAIL);} 190 191 char Wfile[MAXFULLNAME] = {'\0'}; 192 char Dfile[MAXFULLNAME]; 193 194 char *wrkvec[W_MAX+1]; 195 int statfopt; 196 197 /* 198 * Create restart point filename 199 */ 200 201 static void 202 Pname(fileid, dfile, direct) 203 char *fileid; 204 char *dfile; 205 int direct; /* indicates a direct delivery temp file nameneeded */ 206 { 207 char *p; 208 209 /* 210 * If the file is direct delivery, then its name is: 211 * 212 * /dir/dir/dir/.Pnnnnnnnn 213 * 214 * in the target directory. We create this by replacing the 215 * name of the target file with the D.nnnnnn name from the 216 * work vector, and then overwriting the D. with .P 217 */ 218 219 if (direct) { 220 if (p = strrchr(dfile, '/')) { /* find the last slash */ 221 p++; 222 strcpy(p, fileid); /* append D.nnnnn name to dir */ 223 *p++ = '.'; 224 *p = 'P'; /* replace beginning with .P */ 225 DEBUG(7, "Point file (direct) =%s\n", dfile); 226 return; 227 } 228 } 229 strcpy(dfile, RemSpool); 230 strcat(dfile, "/"); 231 p = dfile + strlen(Dfile); 232 strcat(dfile, fileid); 233 *p = 'P'; 234 DEBUG(7, "Point file=%s\n", dfile); 235 return; 236 } 237 238 239 /* 240 * execute the conversation between the two machines 241 * after both programs are running. 242 * returns: 243 * SUCCESS -> ok 244 * FAIL -> failed 245 */ 246 int 247 cntrl() 248 { 249 FILE * fp; 250 struct stat stbuf; 251 extern (*Rdmsg)(), (*Wrmsg)(); 252 char * p; 253 long startp; /* checkpoint restart point */ 254 long actualsize; /* actual file size */ 255 long im; 256 long lfilemode; 257 mode_t filemode; 258 int status; 259 int i, narg; 260 int mailopt, ntfyopt; 261 int ret; 262 char tbuf[TBUFSIZE]; 263 char rqstr[BUFSIZ]; /* contains the current request message */ 264 char msg[BUFSIZ]; 265 char filename[MAXFULLNAME], wrktype; 266 char fsize[NAMESIZE]; /* holds file size/checkpoint string */ 267 char localname[MAXFULLNAME]; /* real local system name */ 268 char Recspool[MAXFULLNAME]; /* spool area for slave uucico */ 269 static pid_t pnum; 270 extern int uuxqtflag; /* set if received X. or D. file */ 271 272 pnum = getpid(); 273 Wfile[0] = '\0'; 274 (void) sprintf(Recspool, "%s/%s", SPOOL, Rmtname); 275 top: 276 (void) strcpy(User, Uucp); 277 statfopt = 0; 278 *Jobid = '\0'; 279 DEBUG(4, "*** TOP *** - Role=%d, ", Role); 280 setline(RESET); 281 if (Role == MASTER) { 282 283 /* 284 * get work 285 */ 286 pfFindFile(); 287 if ((narg = gtwvec(Wfile, wrkvec, W_MAX)) == 0) { 288 acEnd(COMPLETE); /*stop collecting accounting log */ 289 WMESG(HUP, ""); /* I(master) am done. want me to quit? */ 290 RMESG(HUP, msg); 291 goto process; 292 } 293 DEBUG(7, "Wfile - %s,", Wfile); 294 strncpy(Jobid, BASENAME(Wfile, '/')+2, NAMESIZE); 295 Jobid[NAMESIZE-1] = '\0'; 296 DEBUG(7, "Jobid = %s\n", Jobid); 297 wrktype = W_TYPE[0]; 298 pfFound(Jobid, W_OPTNS, Nstat.t_qtime); 299 mailopt = strchr(W_OPTNS, 'm') != NULL; 300 statfopt = strchr(W_OPTNS, 'o') != NULL; 301 ntfyopt = strchr(W_OPTNS, 'n') != NULL; 302 303 uucpname(localname); /* get real local machine name */ 304 acDojob(Jobid, localname, W_USER); 305 scRequser(W_USER); /* log requestor user id */ 306 307 /* 308 * We used to check for corrupt workfiles here (narg < 5), 309 * but we were doing it wrong, and besides, anlwrk.c is the 310 * appropriate place to do it. 311 */ 312 313 (void) sprintf(User, "%s", W_USER); 314 if (wrktype == SNDFILE ) { 315 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname, 316 W_FILE1, Rmtname, W_FILE2, User); 317 318 /* log destination node, user and file name */ 319 320 scDest(Rmtname,NOTAVAIL,W_FILE2); 321 322 /* log source node, file owner, file name, mod time and size */ 323 324 scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1) 325 ,scSize(W_FILE1)); 326 327 logent(rqstr, "REQUEST"); 328 CDEBUG(1, "Request: %s\n", rqstr); 329 mf = W_SFILE; 330 (void) strcpy(filename, W_FILE1); 331 expfile(filename); 332 (void) strcpy(Dfile, W_DFILE); 333 if ( (fp = fopen(Dfile, "r")) == NULL) { 334 if ( (fp = fopen(filename, "r")) == NULL) { 335 /* cannot read spool or original file */ 336 unlinkdf(Dfile); 337 lnotify(User, rqstr, "can't access"); 338 (void) sprintf(msg, "CAN'T READ %s %d", 339 filename, errno); 340 logent(msg, "FAILED"); 341 CDEBUG(1, "Failed: Can't Read %s\n", filename); 342 scWrite(); /* log the security violation */ 343 goto top; 344 } else { 345 /* ensure original file is publicly readable */ 346 if ( !F_READANY(fileno(fp)) ) { 347 /* access denied */ 348 logent("DENIED", "ACCESS"); 349 unlinkdf(W_DFILE); 350 lnotify(User, rqstr, "access denied"); 351 CDEBUG(1, "Failed: Access Denied\n%s", ""); 352 scWrite(); /* log the security violation */ 353 goto top; 354 } 355 } 356 } 357 358 if (Restart && !(fstat(fileno(fp), &stbuf))) { 359 (void) sprintf(fsize, "0x%lx", stbuf.st_size); 360 W_FSIZE = fsize; /* set file size in vector */ 361 } 362 363 /* Check whether remote's ulimit is exceeded */ 364 if (SizeCheck) { 365 if (((stbuf.st_size-1)/512 + 1) > RemUlimit) { 366 /* remote ulimit exceeded */ 367 unlinkdf(Dfile); 368 lnotify(User, rqstr, "remote ulimit exceeded"); 369 logent("DENIED", "REMOTE ULIMIT EXCEEDED"); 370 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename); 371 scWrite(); 372 (void) fclose(fp); 373 goto top; 374 } 375 } 376 } 377 378 if (wrktype == RCVFILE) { 379 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname, 380 W_FILE1, Myname, W_FILE2, User); 381 382 /* log destination node, user and file name */ 383 384 scDest(Myname,NOTAVAIL,W_FILE2); 385 386 /* log source node, file owner, file name, mod time and size */ 387 388 scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL); 389 390 logent(rqstr, "REQUEST"); 391 CDEBUG(1, "Request: %s\n", rqstr); 392 mf = W_RFILE; 393 (void) strcpy(filename, W_FILE2); 394 395 /* change Wrkdir to SPOOL/Rmtname in case the file being 396 ** requested is needed for some remote execution. 397 */ 398 399 (void) strcpy(Wrkdir, Recspool); 400 expfile(filename); 401 402 /* now change Wrkdir back to what it was 403 ** just being paranoid. 404 */ 405 406 (void) strcpy(Wrkdir, RemSpool); 407 if (chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) { 408 409 /* access denied */ 410 logent("DENIED", "ACCESS"); 411 lnotify(User, rqstr, "access denied"); 412 CDEBUG(1, "Failed: Access Denied--File: %s\n", 413 filename); 414 scWrite(); /* log the security violation */ 415 goto top; 416 } 417 418 /* 419 * If we are not going to spool the file in the spool 420 * directory, just use the destination file name. If we 421 * are not supporting restart, wipe out the target file. 422 * else: 423 * 424 * If restart is enabled, make up the Point file name 425 * as the file to open, else use the TM style name. 426 * 427 * If we run into a spool name of "D.0", this implies 428 * that someone forgot to install the new uucp and 429 * uux commands. Such jobs will not be checkpointed. 430 */ 431 432 433 if (Restart && (strlen(W_RDFILE) > (size_t) 6)) { 434 if (noSpool()) { 435 strcpy(Dfile, filename); /* use Dest file directly */ 436 Pname(W_RDFILE, Dfile, TRUE); 437 } 438 else 439 Pname(W_RDFILE, Dfile, FALSE); 440 } 441 else { 442 TMname(Dfile, pnum); /* get TM file name */ 443 unlink(Dfile); 444 } 445 446 /* 447 * If the spool file exists, it better have the right owner 448 * and permissions! 449 */ 450 451 if (Restart && noSpool()) { 452 if ((! stat(Dfile, &stbuf)) && 453 ((stbuf.st_mode != (DFILEMODE|S_IFREG)) || 454 ((stbuf.st_gid != UUCPGID) || 455 (stbuf.st_uid != UUCPUID)))) { 456 lnotify(User, rqstr, 457 "bad spool file ownership/permissions"); 458 logent("BAD DESTFILE OWNER/PERMS", "FAIL"); 459 CDEBUG(1, "Failed: bad dest file owner/perms 0%o; fail\n", stbuf.st_mode); 460 goto top; 461 } 462 } 463 if ( ((fp = fopen(Dfile, "a+")) == NULL) 464 || nospace(Dfile)) { 465 466 /* can not create temp */ 467 if (noSpool()) 468 logent("CAN'T CREATE/OPEN DEST FILE", "FAILED"); 469 else 470 logent("CAN'T CREATE TM FILE", "FAILED"); 471 CDEBUG(1, "Failed: No Space!\n%s", ""); 472 unlinkdf(Dfile); 473 assert(Ct_CREATE, Dfile, nospace(Dfile), 474 __FILE__, __LINE__); 475 cleanup(FAIL); 476 } 477 478 /* 479 * Send the W_POINT value to the other side. 480 */ 481 482 if (Restart) { 483 if (fstat (fileno(fp), &stbuf)) { 484 logent("CAN'T STAT DFILE", "START FROM BEGINNING"); 485 stbuf.st_size = 0L; 486 } 487 488 /* 489 * find a good start point. Take care of simple 490 * underflow and the signed nature of longs. 491 */ 492 493 DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size); 494 startp = stbuf.st_size - (stbuf.st_size % BUFSIZ); 495 if((stbuf.st_size >= 0) && (startp < 0)) 496 startp = 0; 497 498 if(startp) 499 { 500 if(startp < 0) 501 sprintf(tbuf,"start=0x%lx", startp); 502 else 503 sprintf(tbuf,"start=%ld", startp); 504 505 logent(tbuf, "RESTART"); 506 } 507 508 sprintf(fsize, "0x%lx", startp); 509 W_POINT = fsize; /* set start point in vector */ 510 if (lseek(fileno(fp), startp, 0) == -1) { 511 WMESG(SNDFILE, EM_SEEK); 512 logent("CAN'T SEEK", "DENIED"); 513 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", ""); 514 unlinkdf(Dfile); 515 goto top; 516 } 517 fp->_cnt = 0; 518 fp->_ptr = fp->_base; 519 } 520 521 Seqn++; 522 chmod(Dfile, DFILEMODE); /* no peeking! */ 523 chown(Dfile, UUCPUID, UUCPGID); 524 525 } 526 DEBUG(4, "wrktype - %c\n ", wrktype); 527 528 /* Build up the message itself */ 529 530 msg[0] = '\0'; 531 for (i = 1; i < narg; i++) { 532 (void) strcat(msg, " "); 533 (void) strcat(msg, wrkvec[i]); 534 } 535 536 WMESG(wrktype, msg); /* I(master) am sending you our work file */ 537 RMESG(wrktype, msg); /* I(master) am waiting for your response */ 538 goto process; 539 } 540 541 /* 542 * role is slave 543 */ 544 545 RAMESG(msg); /* I(slave) am waiting for our work file */ 546 547 process: 548 549 DEBUG(4, " PROCESS: msg - %s\n", msg); 550 switch (msg[0]) { 551 552 case RQSTCMPT: 553 DEBUG(4, "%s\n", "RQSTCMPT:"); 554 if (msg[1] == 'N') { 555 i = atoi(&msg[2]); 556 if (i < 0 || i > EM_MAX) 557 i = 0; 558 logent(Em_msg[i], "REQUESTED"); 559 } 560 if (Role == MASTER) { 561 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 562 } 563 pfEndfile(""); /* "" indicates the file transfer completely */ 564 goto top; 565 566 case HUP: 567 DEBUG(4, "%s\n", "HUP:"); 568 if (msg[1] == 'Y') { 569 WMESG(HUP, YES); /* let's quit */ 570 (*Turnoff)(); 571 Rdmsg = imsg; 572 Wrmsg = omsg; 573 Turnoff = turnoff; 574 return(0); 575 } 576 577 if (msg[1] == 'N') { 578 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 579 Role = SLAVE; 580 scReqsys(Rmtname); /* log requestor system */ 581 chremdir(Rmtname); 582 goto top; 583 } 584 585 /* 586 * get work 587 */ 588 if ( (switchRole() == FALSE) || !iswrk(Wfile) ) { 589 DEBUG(5, "SLAVE-switchRole (%s)\n", 590 switchRole() ? "TRUE" : "FALSE"); 591 WMESG(HUP, YES); /* let's quit */ 592 RMESG(HUP, msg); 593 goto process; 594 } 595 596 /* Note that Wfile is the first C. to process at top 597 * set above by iswrk() call 598 */ 599 if (uuxqtflag) { 600 xuuxqt(uuxqtarg); 601 uuxqtflag = 0; 602 } 603 WMESG(HUP, NO); /* don't quit. I(slave) have more to do */ 604 Role = MASTER; 605 uucpname(localname); /* get real local machine name */ 606 scReqsys(localname); /* log requestor system */ 607 acInit("xfer"); 608 goto top; 609 610 case XUUCP: 611 /* 612 * slave part 613 * No longer accepted 614 */ 615 616 WMESG(XUUCP, NO); 617 goto top; 618 619 case SNDFILE: 620 621 /* 622 * MASTER section of SNDFILE 623 */ 624 DEBUG(4, "%s\n", "SNDFILE:"); 625 if (msg[1] == 'N') 626 { 627 i = atoi(&msg[2]); 628 if (i < 0 || i > EM_MAX) 629 i = 0; 630 logent(Em_msg[i], "REQUEST"); 631 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 632 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 633 (void) fclose(fp); 634 /* if remote is out of tmp space, then just hang up */ 635 ASSERT(i != 4, Em_msg[4], Rmtname, i); /* EM_NOTMP */ 636 unlinkdf(W_DFILE); 637 scWrite(); /* something is wrong on other side, 638 log the security violation */ 639 Seqn++; 640 goto top; 641 } 642 643 if (msg[1] == 'Y') { 644 645 /* 646 * send file 647 */ 648 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 649 if (fstat(fileno(fp), &stbuf)) /* never fail but .. */ 650 stbuf.st_size = 0; /* for time loop calculation */ 651 652 /* 653 * If checkpoint restart is enabled, seek to the 654 * starting point in the file. We use hex because 655 * C doesn't support unsigned long directly. 656 */ 657 658 if (Restart) { 659 if((startp = strtol(&msg[2], (char **) 0, FLENRADIX))) { 660 CDEBUG(1, "Restart point=0x%lx\n", startp); 661 if(startp < 0) 662 sprintf(tbuf,"start=0x%lx", startp); 663 else 664 sprintf(tbuf,"start=%ld", startp); 665 p = tbuf + strlen(tbuf); 666 if (stbuf.st_size < 0) 667 sprintf(p,", length=0x%lx", stbuf.st_size); 668 else 669 sprintf(p,", length=%ld", stbuf.st_size); 670 671 logent(tbuf, "RESTART"); 672 errno = 0; 673 if (lseek(fileno(fp), startp, 0) == -1) { 674 logent(strerror(errno), "FSEEK ERROR"); 675 (void) fclose(fp); 676 (*Turnoff)(); 677 Seqn++; 678 return(FAIL); 679 } 680 fp->_cnt = 0; 681 fp->_ptr = fp->_base; 682 } 683 } 684 (void) millitick(); /* start msec timer */ 685 pfStrtXfer(MCHAR, SNDFILE); 686 scStime(); /* log start transfer time for security log */ 687 688 /* (ret != 0) implies the trammission error occurred. 689 If checkpoint protocol is available then the next 690 transfer will restart from the breakpoint of the file, 691 otherwise from the beginning of the file */ 692 693 ret = (*Wrdata)(fp, Ofn); 694 695 /* the second millitick() returns the duration between 696 the first and second call. 697 writes "PARTIAL FILE to the transfer log indicating 698 a transmission error. */ 699 700 statlog( "->", getfilesize(), millitick(), 701 (ret) ? "PARTIAL FILE" : "" ); 702 703 acInc(); /* increment job size in accounting log */ 704 pfEndXfer(); 705 scEtime(); /* log end transfer time for security log */ 706 Seqn++; 707 (void) fclose(fp); 708 if (ret != 0) { 709 pfEndfile("PARTIAL FILE"); 710 acEnd(PARTIAL); /*stop collecting accounting log */ 711 (*Turnoff)(); 712 return(FAIL); 713 } 714 715 /* loop depending on the size of the file */ 716 /* give an extra try for each megabyte */ 717 for (im = stbuf.st_size >> 10; im >= 0; --im) { 718 if ((ret = rmesg(RQSTCMPT, msg)) == 0) 719 break; /* got message */ 720 } 721 if (ret != 0) { 722 (*Turnoff)(); 723 return(FAIL); 724 } 725 unlinkdf(W_DFILE); 726 goto process; 727 } 728 729 /* 730 * SLAVE section of SNDFILE 731 */ 732 ASSERT(Role == SLAVE, Wr_ROLE, "", Role); 733 734 /* 735 * request to receive file 736 * check permissions 737 */ 738 i = getargs(msg, wrkvec, W_MAX); 739 740 scRequser(W_USER); /* log requestor user id */ 741 742 /* log destination node, user and file name */ 743 744 scDest(Myname,NOTAVAIL,W_FILE2); 745 746 /* log source node, file owner, file name, mod time and size */ 747 748 scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL); 749 750 /* Check for bad request */ 751 if (i < W_MIN) { 752 WMESG(SNDFILE, EM_BADUUCP); /* you(remote master) gave me 753 bad work file */ 754 logent("DENIED", "TOO FEW ARGS IN SLAVE SNDFILE"); 755 goto top; 756 } 757 /* SLAVE gets the original filesize from sender (MASTER) */ 758 /* This will be used to check the length of the P. file */ 759 if (Restart) { 760 if (W_FSIZE && (*W_FSIZE != '\0')) { 761 actualsize = strtol(W_FSIZE, (char **) 0, FLENRADIX); 762 CDEBUG(7, "Actual File Length %ld\n", actualsize); 763 } else { 764 actualsize = -1; 765 CDEBUG(7, "Actual File Length Not Provided\n%s", ""); 766 } 767 } 768 769 mf = W_SFILE; 770 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname, 771 W_FILE1, Myname, W_FILE2, W_USER); 772 logent(rqstr, "REMOTE REQUESTED"); 773 DEBUG(4, "msg - %s\n", msg); 774 CDEBUG(1, "Remote Requested: %s\n", rqstr); 775 (void) strcpy(filename, W_FILE2); 776 expfile(filename); 777 DEBUG(4, "SLAVE - filename: %s\n", filename); 778 if (chkpth(filename, CK_WRITE) 779 || chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) { 780 WMESG(SNDFILE, EM_RMTACC); /* you(remote master) can't 781 send data to this file(directory) */ 782 logent("DENIED", "PERMISSION"); 783 CDEBUG(1, "Failed: Access Denied\n%s", ""); 784 scWrite(); /* log security violation */ 785 goto top; 786 } 787 (void) sprintf(User, "%s", W_USER); 788 789 DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname); 790 791 792 793 if (Restart && (strlen(W_DFILE) > (size_t) 6)) { 794 if (noSpool()) { 795 strcpy(Dfile, filename); /* use Dest file directly */ 796 Pname(W_DFILE, Dfile, TRUE); 797 if (! Restart) 798 unlink(Dfile); 799 } 800 else 801 Pname(W_DFILE, Dfile, FALSE); 802 } 803 else { 804 TMname(Dfile, pnum); /* get TM file name */ 805 unlink(Dfile); 806 } 807 808 /* 809 * If the spool file exists, it better have the right owner 810 * and permissions! 811 */ 812 813 if (Restart && noSpool()) { 814 if ((! stat(Dfile, &stbuf)) && 815 ((stbuf.st_mode != (DFILEMODE|S_IFREG)) || 816 ((stbuf.st_gid != UUCPGID) || 817 (stbuf.st_uid != UUCPUID)))) { 818 WMESG(SNDFILE, EM_NOTMP); /* I(slave) see bad perms */ 819 logent("BAD DESTFILE OWNER/PERMS", "FAILED"); 820 CDEBUG(1, "Failed: bad dest file owner/perms 0%o\n", stbuf.st_mode); 821 goto top; 822 } 823 } 824 if ( ((fp = fopen(Dfile, "a+")) == NULL) || nospace(Dfile) ) { 825 WMESG(SNDFILE, EM_NOTMP); /* I(slave) can't create TM file */ 826 logent("CAN'T OPEN", "DENIED"); 827 CDEBUG(1, "Failed: Can't Create Temp File\n%s", ""); 828 unlinkdf(Dfile); 829 goto top; 830 } 831 chmod(Dfile, DFILEMODE); /* no peeking! */ 832 chown(Dfile, UUCPUID, UUCPGID); 833 if (Restart && (strlen(W_DFILE) > (size_t) 6)) { 834 if(fstat(fileno(fp), &stbuf)) { 835 WMESG(SNDFILE, EM_NOTMP); 836 logent("CAN'T STAT", "DENIED"); 837 CDEBUG(1, "Failed: Can't Stat Temp File\n%s", ""); 838 unlinkdf(Dfile); 839 Seqn++; 840 goto top; 841 } 842 /* 843 * find a good start point. Take care of simple underflow 844 * and the signed nature of longs. 845 */ 846 847 DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size); 848 startp = stbuf.st_size - (stbuf.st_size % BUFSIZ); 849 if((stbuf.st_size >= 0) && (startp < 0)) 850 startp = 0; 851 852 if(startp) 853 { 854 if(startp < 0) 855 sprintf(tbuf,"start=0x%lx", startp); 856 else 857 sprintf(tbuf,"start=%ld", startp); 858 859 logent(tbuf, "RESTART"); 860 } 861 862 sprintf(tbuf, "%s 0x%lx", YES, startp); 863 if (lseek(fileno(fp), startp, 0) == -1) { 864 WMESG(SNDFILE, EM_SEEK); 865 logent("CAN'T SEEK", "DENIED"); 866 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", ""); 867 unlinkdf(Dfile); 868 Seqn++; 869 goto top; 870 } 871 fp->_cnt = 0; 872 fp->_ptr = fp->_base; 873 CDEBUG(1," restart msg %s\n", tbuf); 874 WMESG(SNDFILE, tbuf); 875 } 876 else 877 WMESG(SNDFILE, YES); /* I(slave) clear to send */ 878 (void) millitick(); /* start msec timer */ 879 pfStrtXfer(SCHAR, RCVFILE); 880 scStime(); /* log start transfer time for security log */ 881 /* (ret != 0) implies the trammission error occurred. 882 If checkpoint protocol is available then the next 883 recieve will restart from the breakpoint of the file, 884 otherwise from the beginning of the file */ 885 886 setline(RCVFILE); 887 ret = (*Rddata)(Ifn, fp); 888 setline(SNDFILE); 889 890 /* the second millitick() returns the duration between 891 the first and second call. 892 writes "PARTIAL FILE to the transfer log indicating 893 a transmission error. */ 894 895 statlog( "<-", getfilesize(), millitick(), 896 (ret) ? "PARTIAL FILE" : "" ); 897 898 pfEndXfer(); 899 scEtime(); /* log end transfer time for security log */ 900 Seqn++; 901 902 if (ret != 0) { 903 pfEndfile("PARTIAL FILE"); 904 (void) fclose(fp); 905 if ( ret == EFBIG ) { 906 WMESG(RQSTCMPT, EM_ULIMIT); 907 logent("FILE EXCEEDS ULIMIT","FAILED"); 908 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", ""); 909 goto top; 910 } 911 (*Turnoff)(); 912 logent("INPUT FAILURE", "IN SEND/SLAVE MODE"); 913 return(FAIL); 914 } 915 if (Restart && (actualsize != -1)) { 916 if (fstat(fileno(fp), &stbuf)) { 917 (void) fclose(fp); 918 unlinkdf(Dfile); 919 (*Turnoff)(); 920 logent("CAN'T STAT PFILE", "FAILED"); 921 return(FAIL); 922 } 923 if (stbuf.st_size != actualsize) { 924 (void) fclose(fp); 925 unlinkdf(Dfile); 926 (*Turnoff)(); 927 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED"); 928 CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size); 929 CDEBUG(1, "not equal to actual size %ld\n", actualsize); 930 return(FAIL); 931 } 932 } 933 (void) fclose(fp); 934 935 /* copy to user directory */ 936 ntfyopt = strchr(W_OPTNS, 'n') != NULL; 937 938 /* 939 * See if spool file and target file in the same file system 940 */ 941 942 ret = 0; 943 if (p = strrchr(Dfile, '/')) 944 { 945 *p = '\0'; 946 ret = PREFIX(Dfile, filename); 947 *p = '/'; 948 } 949 950 if (noSpool() && ret) 951 { 952 /* 953 * if we are not already in the right file, and 954 * it is theoretically in the same file system, 955 * link it there... 956 */ 957 958 if(strcmp (filename, Dfile)) { 959 unlink(filename); 960 if(link(Dfile, filename)) 961 { 962 logent("FAILED", "MOVE"); 963 scWrite(); 964 putinpub(filename, Dfile, BASENAME(W_USER,'!')); 965 } 966 else 967 DEBUG(7, "linked Point file to %s\n", filename); 968 unlink(Dfile); 969 } 970 else 971 DEBUG(7, "Point file and %s the same\n", filename); 972 status = 0; /* all done */ 973 } 974 else 975 status = xmv(Dfile, filename); 976 977 scSize(Dfile); /* log source file size */ 978 WMESG(RQSTCMPT, status ? EM_RMTCP : YES); 979 if (status == 0) { 980 sscanf(W_MODE, "%lo", &lfilemode); 981 if (lfilemode <= 0) 982 filemode = PUB_FILEMODE; 983 else 984 filemode = (mode_t)lfilemode; 985 if (PREFIX(RemSpool, filename)) 986 chmod(filename, DFILEMODE); 987 else 988 chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE); 989 arrived(ntfyopt, filename, W_NUSER, Rmtname, User); 990 } else { 991 logent("FAILED", "COPY"); 992 scWrite(); /* log the security violation */ 993 status = putinpub(filename, Dfile, 994 BASENAME(W_USER, '!')); 995 DEBUG(4, "->PUBDIR %d\n", status); 996 if (status == 0) 997 arrived(ntfyopt, filename, W_NUSER, 998 Rmtname, User); 999 } 1000 pfEndfile(""); /* "" indicates the file transfer completely */ 1001 if ( W_FILE2[1] == '.' && 1002 (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) ) 1003 uuxqtflag = 1; 1004 goto top; 1005 1006 case RCVFILE: 1007 1008 /* 1009 * MASTER section of RCVFULE 1010 */ 1011 DEBUG(4, "%s\n", "RCVFILE:"); 1012 if (msg[1] == 'N') { 1013 i = atoi(&msg[2]); 1014 if (i < 0 || i > EM_MAX) 1015 i = 0; 1016 logent(Em_msg[i], "REQUEST"); 1017 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 1018 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 1019 (void) fclose(fp); 1020 unlinkdf(Dfile); 1021 scWrite(); /* something is wrong on other side, 1022 log the security violation */ 1023 goto top; 1024 } 1025 1026 if (msg[1] == 'Y') { 1027 1028 /* MASTER gets the original filesize from sender (SLAVE) */ 1029 /* This will be used to check the length of the P. file */ 1030 if (Restart) { 1031 *fsize = '\0'; 1032 sscanf(&msg[2], "%*o %s", fsize); 1033 if (*fsize != '\0') { 1034 actualsize = strtol(fsize, (char **) 0, FLENRADIX); 1035 CDEBUG(7, "Actual File Length %ld\n", actualsize); 1036 } else { 1037 actualsize = -1; 1038 CDEBUG(7, "Actual File Length Not Provided\n%s", ""); 1039 } 1040 } 1041 1042 /* 1043 * receive file 1044 */ 1045 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 1046 (void) millitick(); /* start msec timer */ 1047 pfStrtXfer(MCHAR, SNDFILE); 1048 scStime(); 1049 /* (ret != 0) implies the trammission error occurred. 1050 If checkpoint protocol is available then the next 1051 recieve will restart from the breakpoint of the file, 1052 otherwise from the beginning of the file */ 1053 1054 ret = (*Rddata)(Ifn, fp); 1055 1056 /* the second millitick() returns the duration between 1057 the first and second call. 1058 writes "PARTIAL FILE to the transfer log indicating 1059 a transmission error. */ 1060 1061 statlog( "<-", getfilesize(), millitick(), 1062 (ret) ? "PARTIAL FILE" : "" ); 1063 pfEndXfer(); 1064 scEtime(); 1065 if (ret != 0) { 1066 pfEndfile("PARTIAL FILE"); 1067 (void) fclose(fp); 1068 if ( ret == EFBIG ) { 1069 WMESG(RQSTCMPT, EM_ULIMIT); 1070 logent("FILE EXCEEDS ULIMIT","FAILED"); 1071 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", ""); 1072 goto top; 1073 } 1074 (*Turnoff)(); 1075 logent("INPUT FAILURE", "IN RECEIVE/MASTER MODE"); 1076 return(FAIL); 1077 } 1078 if (Restart && (actualsize != -1)) { 1079 if (fstat(fileno(fp), &stbuf)) { 1080 (void) fclose(fp); 1081 unlinkdf(Dfile); 1082 (*Turnoff)(); 1083 logent("CAN'T STAT PFILE", "FAILED"); 1084 return(FAIL); 1085 } 1086 if (stbuf.st_size != actualsize) { 1087 (void) fclose(fp); 1088 unlinkdf(Dfile); 1089 (*Turnoff)(); 1090 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED"); 1091 CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size); 1092 CDEBUG(1, "not equal to actual size %ld\n", actualsize); 1093 return(FAIL); 1094 } 1095 } 1096 (void) fclose(fp); 1097 1098 /* 1099 * See if spool file and target file in the same file system 1100 */ 1101 1102 ret = 0; 1103 if (p = strrchr(Dfile, '/')) 1104 { 1105 *p = '\0'; 1106 ret = PREFIX(Dfile, filename); 1107 *p = '/'; 1108 } 1109 1110 if (noSpool() && ret) 1111 { 1112 /* 1113 * if we are not already in the right file, and 1114 * it is theoretically in the same file system, 1115 * link it there... 1116 */ 1117 1118 if(strcmp (filename, Dfile)) { 1119 unlink(filename); 1120 if(link(Dfile, filename)) 1121 { 1122 logent("FAILED", "MOVE"); 1123 scWrite(); 1124 putinpub(filename, Dfile, W_USER); 1125 } 1126 else 1127 DEBUG(7, "linked Point file to %s\n", filename); 1128 unlink(Dfile); 1129 } 1130 else 1131 DEBUG(7, "Point file and %s the same\n", filename); 1132 status = 0; /* all done */ 1133 } 1134 else 1135 status = xmv(Dfile, filename); 1136 1137 WMESG(RQSTCMPT, status ? EM_RMTCP : YES); 1138 notify(mailopt, W_USER, rqstr, Rmtname, 1139 status ? EM_LOCCP : YES); 1140 if (status == 0) { 1141 sscanf(&msg[2], "%lo", &lfilemode); 1142 if (lfilemode <= 0) 1143 filemode = PUB_FILEMODE; 1144 else 1145 filemode = (mode_t)lfilemode; 1146 if (PREFIX(RemSpool, filename)) 1147 chmod(filename, DFILEMODE); 1148 else 1149 chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE); 1150 } else { 1151 logent("FAILED", "COPY"); 1152 scWrite(); /* log the security violation */ 1153 putinpub(filename, Dfile, W_USER); 1154 } 1155 pfEndfile(""); /* "" indicates the file transfer completely */ 1156 if ( W_FILE2[1] == '.' && 1157 (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) ) 1158 uuxqtflag = 1; 1159 goto top; 1160 } 1161 1162 /* 1163 * SLAVE section of RCVFILE 1164 * (request to send file) 1165 */ 1166 ASSERT(Role == SLAVE, Wr_ROLE, "", Role); 1167 1168 /* check permissions */ 1169 i = getargs(msg, wrkvec, W_MAX); 1170 1171 scRequser(W_USER); /* log requestor user id */ 1172 1173 /* log destination node, user and file name */ 1174 1175 scDest(Rmtname,NOTAVAIL,W_FILE2); 1176 1177 /* log source node, file owner, file name, mod time and size */ 1178 1179 scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1),scSize(W_FILE1)); 1180 /* Check for bad request */ 1181 if (i < 5) { 1182 WMESG(RCVFILE, EM_BADUUCP); /* you(remote master) gave me 1183 bad work file */ 1184 logent("DENIED", "TOO FEW ARGS IN SLAVE RCVFILE"); 1185 goto top; 1186 } 1187 1188 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname, 1189 W_FILE1, Rmtname, W_FILE2, W_USER); 1190 logent(rqstr, "REMOTE REQUESTED"); 1191 CDEBUG(1, "Remote Requested: %s\n", rqstr); 1192 mf = W_RFILE; 1193 DEBUG(4, "msg - %s\n", msg); 1194 DEBUG(4, "W_FILE1 - %s\n", W_FILE1); 1195 (void) strcpy(filename, W_FILE1); 1196 expfile(filename); 1197 if (DIRECTORY(filename)) { 1198 (void) strcat(filename, "/"); 1199 (void) strcat(filename, BASENAME(W_FILE2, '/')); 1200 } 1201 (void) sprintf(User, "%s", W_USER); 1202 1203 if (requestOK() == FALSE) { 1204 /* remote can't request data from my system */ 1205 WMESG(RCVFILE, EM_RMTACC); 1206 logent("DENIED", "REQUESTING"); 1207 CDEBUG(1, "Failed: Access Denied\n%s", ""); 1208 scWrite(); /* log the security violation */ 1209 goto top; 1210 } 1211 DEBUG(4, "requestOK for Loginuser - %s\n", Loginuser); 1212 1213 if ((fp = fopen(filename, "r")) == NULL) { 1214 WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't 1215 read my file */ 1216 logent("CAN'T OPEN", "DENIED"); 1217 CDEBUG(1, "Failed: Can't Open %s\n", filename); 1218 scWrite(); /* log the security violation */ 1219 goto top; 1220 } 1221 1222 if (chkpth(filename, CK_READ) || !F_READANY(fileno(fp))) { 1223 WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't 1224 retrive my file */ 1225 logent("DENIED", "PERMISSION"); 1226 CDEBUG(1, "Failed: Access Denied\n%s", ""); 1227 scWrite(); /* log the security violation */ 1228 fclose(fp); 1229 goto top; 1230 } 1231 DEBUG(4, "chkpth ok Loginuser - %s\n", Loginuser); 1232 1233 ASSERT(fstat(fileno(fp), &stbuf) == 0, Ct_STAT, 1234 filename, errno); 1235 1236 /* Check whether remote's ulimit is exceeded */ 1237 if (SizeCheck) { 1238 if (((stbuf.st_size-1)/512 + 1) > RemUlimit) { 1239 /* remote ulimit exceeded */ 1240 WMESG(RCVFILE, EM_ULIMIT); 1241 logent("DENIED", "REMOTE ULIMIT EXCEEDED"); 1242 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename); 1243 scWrite(); 1244 (void) fclose(fp); 1245 goto top; 1246 } 1247 } 1248 1249 /* 1250 * ok to send file 1251 */ 1252 1253 if (Restart && i >= 10) { 1254 if (startp = strtol(W_POINT, (char **) 0, FLENRADIX)) { 1255 CDEBUG(1,"Restart point=0x%lx\n", startp); 1256 errno = 0; 1257 if (lseek(fileno(fp), startp, 0) == -1) { 1258 WMESG(RCVFILE, EM_SEEK); 1259 logent(strerror(errno), "FSEEK ERROR"); 1260 (void) fclose(fp); 1261 goto top; 1262 } 1263 fp->_cnt = 0; 1264 fp->_ptr = fp->_base; 1265 if(startp < 0) 1266 sprintf(tbuf,"start=0x%lx", startp); 1267 else 1268 sprintf(tbuf,"start=%ld", startp); 1269 p = tbuf + strlen(tbuf); 1270 if (stbuf.st_size < 0) 1271 sprintf(p,", length=0x%lx", stbuf.st_size); 1272 else 1273 sprintf(p,", length=%ld", stbuf.st_size); 1274 1275 logent(tbuf, "RESTART"); 1276 } 1277 } 1278 1279 if (Restart) 1280 (void) sprintf(msg, "%s %lo 0x%lx", YES, 1281 (long) (stbuf.st_mode & LEGALMODE), 1282 (long) stbuf.st_size); 1283 else 1284 (void) sprintf(msg, "%s %lo", YES, 1285 (long) (stbuf.st_mode & LEGALMODE)); 1286 WMESG(RCVFILE, msg); /* I(slave) send you my file now */ 1287 Seqn++; 1288 (void) millitick(); /* start msec timer */ 1289 scStime(); 1290 pfStrtXfer(SCHAR, SNDFILE); 1291 /* (ret != 0) implies the trammission error occurred. 1292 If checkpoint protocol is available then the next 1293 transfer will restart from the breakpoint of the file, 1294 otherwise from the beginning of the file */ 1295 1296 ret = (*Wrdata)(fp, Ofn); 1297 1298 /* the second millitick() returns the duration between 1299 the first and second call. 1300 writes "PARTIAL FILE to the transfer log indicating 1301 a transmission error. */ 1302 1303 statlog( "->", getfilesize(), millitick(), 1304 (ret) ? "PARTIAL FILE" : "" ); 1305 pfEndXfer(); 1306 scEtime(); 1307 1308 (void) fclose(fp); 1309 if (ret != 0) { 1310 pfEndfile("PARTIAL FILE"); 1311 (*Turnoff)(); 1312 return(FAIL); 1313 } 1314 1315 /* loop depending on the size of the file */ 1316 /* give an extra try for each megabyte */ 1317 /* stbuf set in fstat several lines back */ 1318 for (im = stbuf.st_size >> 10; im >= 0; --im) { 1319 if ((ret = rmesg(RQSTCMPT, msg)) == 0) 1320 break; /* got message */ 1321 } 1322 if (ret != 0) { 1323 (*Turnoff)(); 1324 return(FAIL); 1325 } 1326 goto process; 1327 } 1328 (*Turnoff)(); 1329 return(FAIL); 1330 } 1331 1332 1333 1334 /* 1335 * read message 1336 * returns: 1337 * 0 -> success 1338 * FAIL -> failure 1339 */ 1340 int 1341 rmesg(c, msg) 1342 char *msg, c; 1343 { 1344 char str[50]; 1345 1346 DEBUG(4, "rmesg - '%c' ", c); 1347 if ((*Rdmsg)(msg, Ifn) != 0) { 1348 DEBUG(4, "got %s\n", "FAIL"); 1349 (void) sprintf(str, "expected '%c' got FAIL", c); 1350 logent(str, "BAD READ"); 1351 return(FAIL); 1352 } 1353 if (c != '\0' && msg[0] != c) { 1354 DEBUG(4, "got %s\n", msg); 1355 (void) sprintf(str, "expected '%c' got %s", c, msg); 1356 logent(str, "BAD READ"); 1357 return(FAIL); 1358 } 1359 DEBUG(4, "got %s\n", msg); 1360 return(0); 1361 } 1362 1363 1364 /* 1365 * write a message 1366 * returns: 1367 * 0 -> ok 1368 * FAIL -> ng 1369 */ 1370 int 1371 wmesg(m, s) 1372 char *s, m; 1373 { 1374 CDEBUG(4, "wmesg '%c'", m); 1375 CDEBUG(4, "%s\n", s); 1376 return((*Wrmsg)(m, s, Ofn)); 1377 } 1378 1379 1380 /* 1381 * mail results of command 1382 * return: 1383 * none 1384 */ 1385 void 1386 notify(mailopt, user, msgin, sys, msgcode) 1387 char *user, *msgin, *sys; 1388 register char *msgcode; 1389 { 1390 register int i; 1391 char str[BUFSIZ]; 1392 register char *msg; 1393 1394 DEBUG(4,"mailopt %d, ", mailopt); 1395 DEBUG(4,"statfopt %d\n", statfopt); 1396 if (statfopt == 0 && mailopt == 0 && *msgcode == 'Y') 1397 return; 1398 if (*msgcode == 'Y') 1399 msg = "copy succeeded"; 1400 else { 1401 i = atoi(msgcode + 1); 1402 if (i < 1 || i > EM_MAX) 1403 i = 0; 1404 msg = Em_msg[i]; 1405 } 1406 if(statfopt){ 1407 stmesg(msgin, msg); 1408 return; 1409 } 1410 (void) sprintf(str, "REQUEST: %s\n(SYSTEM: %s) %s\n", 1411 msgin, sys, msg); 1412 mailst(user, msg, str, "", ""); 1413 return; 1414 } 1415 1416 /* 1417 * local notify 1418 * return: 1419 * none 1420 */ 1421 void 1422 lnotify(user, msgin, mesg) 1423 char *user, *msgin, *mesg; 1424 { 1425 char mbuf[BUFSIZ]; 1426 1427 if(statfopt){ 1428 stmesg(msgin, mesg); 1429 return; 1430 } 1431 (void) sprintf(mbuf, "REQUEST: %s\n(SYSTEM: %s) %s\n", 1432 msgin, Myname, mesg); 1433 mailst(user, mesg, mbuf, "", ""); 1434 return; 1435 } 1436 1437 /*ARGSUSED*/ 1438 static void 1439 stmesg(f, m) 1440 char *f, *m; 1441 { 1442 #ifdef notdef 1443 FILE *Cf; 1444 time_t clock; 1445 long td, th, tm, ts; 1446 #endif 1447 char msg[BUFSIZ]; 1448 1449 DEBUG(4,"STMES %s\n",mf); 1450 sprintf(msg, "STMESG - %s", mf); 1451 logent("DENIED", msg); 1452 #ifdef notdef 1453 /* 1454 * This code is a giant security hole. 1455 * No checking is done on what file is 1456 * written and chmod'ed. For now we 1457 * just ifdef this out. 1458 */ 1459 if((Cf = fopen(mf, "a+")) == NULL){ 1460 chmod(mf, PUB_FILEMODE); 1461 return; 1462 } 1463 (void) time(&clock); 1464 (void) fprintf(Cf, "uucp job: %s (%s) ", Jobid, timeStamp()); 1465 td = clock - Nstat.t_qtime; 1466 ts = td%60; 1467 td /= 60; 1468 tm = td%60; 1469 td /= 60; 1470 th = td; 1471 (void) fprintf(Cf, "(%ld:%ld:%ld)\n%s\n%s\n\n", th, tm, ts, f, m); 1472 (void) fclose(Cf); 1473 chmod(mf, PUB_FILEMODE); 1474 #endif 1475 } 1476 1477 /* 1478 * converse with the remote machine, agree upon a 1479 * protocol (if possible) and start the protocol. 1480 * return: 1481 * SUCCESS -> successful protocol selection 1482 * FAIL -> can't find common or open failed 1483 */ 1484 startup() 1485 { 1486 extern (*Rdmsg)(), (*Wrmsg)(); 1487 extern imsg(), omsg(); 1488 extern void blptcl(); 1489 extern int fptcl(); 1490 char msg[BUFSIZ], str[BUFSIZ]; 1491 1492 Rdmsg = imsg; 1493 Wrmsg = omsg; 1494 Turnoff = turnoff; 1495 blptcl(str); 1496 if (Role == MASTER) { 1497 RMESG(SLTPTCL, msg); 1498 if ( fptcl(&msg[1], str) == FAIL) { 1499 /* no protocol match */ 1500 WMESG(USEPTCL, NO); 1501 return(FAIL); 1502 } else { 1503 /* got protocol match */ 1504 WMESG(USEPTCL, &msg[1]); 1505 return(stptcl(&msg[1])); 1506 } 1507 } else { 1508 WMESG(SLTPTCL, str); 1509 RMESG(USEPTCL, msg); 1510 if ( fptcl(&msg[1], str) == FAIL ) { 1511 return(FAIL); 1512 } else { 1513 return(stptcl(&msg[1])); 1514 } 1515 } 1516 } 1517 1518 /* 1519 * choose a protocol from the input string (str) 1520 * and return the found letter. 1521 * Use the MASTER string (valid) for order of selection. 1522 * return: 1523 * '\0' -> no acceptable protocol 1524 * any character -> the chosen protocol 1525 */ 1526 int 1527 fptcl(str, valid) 1528 register char *str, *valid; 1529 { 1530 char *l; 1531 1532 DEBUG(9, "Slave protocol list(%s)\n", str); 1533 DEBUG(9, "Master protocol list(%s)\n", valid); 1534 1535 for (l = valid; *l != '\0'; l++) { 1536 if ( strchr(str, *l) != NULL) { 1537 *str = *l; 1538 *(str+1) = '\0'; 1539 /* also update string with parms */ 1540 strcpy(_Protocol, findProto(_Protocol, *str)); 1541 return(SUCCESS); 1542 } 1543 } 1544 return(FAIL); 1545 } 1546 1547 /* 1548 * build a string of the letters of the available 1549 * protocols and return the string (str). The string consists of protocols 1550 * that are specified in the Systems and Devices files. If nothing was 1551 * specified in those files, then the string is the list of protocols from 1552 * our Ptble. 1553 * 1554 * str = place to put the protocol list 1555 * length = size of buffer at str 1556 * 1557 * return: 1558 * a pointer to string (str) 1559 */ 1560 void 1561 blptcl(str) 1562 register char *str; 1563 { 1564 register struct Proto *p; 1565 register char *validPtr; 1566 1567 /* Build list of valid protocols. */ 1568 for (validPtr = str, p = Ptbl; (*validPtr = p->P_id) != NULLCHAR; 1569 validPtr++, p++); 1570 1571 /* Build _Protocol */ 1572 (void) protoString(str); /* Get desired protocols. */ 1573 return; 1574 } 1575 1576 /* 1577 * set up the six routines (Rdmg. Wrmsg, Rddata 1578 * Wrdata, Turnon, Turnoff) for the desired protocol. 1579 * returns: 1580 * SUCCESS -> ok 1581 * FAIL -> no find or failed to open 1582 */ 1583 int 1584 stptcl(c) 1585 register char *c; 1586 { 1587 register struct Proto *p; 1588 1589 for (p = Ptbl; p->P_id != '\0'; p++) { 1590 if (*c == p->P_id) { 1591 1592 /* 1593 * found protocol 1594 * set routine 1595 */ 1596 Rdmsg = p->P_rdmsg; 1597 Wrmsg = p->P_wrmsg; 1598 Rddata = p->P_rddata; 1599 Wrdata = p->P_wrdata; 1600 Turnon = p->P_turnon; 1601 Turnoff = p->P_turnoff; 1602 if ((*Turnon)() != 0) 1603 break; 1604 CDEBUG(4, "Proto started %c\n", *c); 1605 pfPtcl(c); 1606 return(SUCCESS); 1607 } 1608 } 1609 CDEBUG(4, "Proto start-fail %c\n", *c); 1610 return(FAIL); 1611 } 1612 1613 /* 1614 * unlink D. file 1615 * returns: 1616 * none 1617 */ 1618 void 1619 unlinkdf(file) 1620 register char *file; 1621 { 1622 if (strlen(file) > (size_t) 6) 1623 (void) unlink(file); 1624 return; 1625 } 1626 1627 /* 1628 * notify receiver of arrived file 1629 * returns: 1630 * none 1631 */ 1632 void 1633 arrived(opt, file, nuser, rmtsys, rmtuser) 1634 char *file, *nuser, *rmtsys, *rmtuser; 1635 { 1636 char mbuf[200]; 1637 1638 if (!opt) 1639 return; 1640 (void) sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser); 1641 mailst(nuser, mbuf, mbuf, "", ""); 1642 return; 1643 } 1644 1645 1646 /* 1647 * Check to see if there is space for file 1648 */ 1649 1650 #define FREESPACE 50 /* Minimum freespace in blocks to permit transfer */ 1651 #define FREENODES 5 /* Minimum number of inodes to permit transfer */ 1652 1653 /*ARGSUSED*/ 1654 static int 1655 nospace(name) 1656 char *name; 1657 #ifdef NOUSTAT 1658 {return(FALSE);} 1659 #else 1660 { 1661 struct stat statb; 1662 #ifdef STATFS 1663 struct statfs statfsb; 1664 #else 1665 struct ustat ustatb; 1666 #endif 1667 1668 if( stat(name, &statb) < 0 ) 1669 return(TRUE); 1670 #ifdef RT 1671 if( (statb.st_mode|S_IFMT) == S_IFREG || 1672 (statb.st_mode|S_IFMT) == S_IFEXT || 1673 (statb.st_mode&S_IFMT) == S_IF1EXT ) 1674 #else 1675 if( (statb.st_mode&S_IFMT) == S_IFREG ) 1676 #endif 1677 { 1678 #ifdef STATFS 1679 if( statfs(name, &statfsb)<0 ) 1680 #else 1681 if( ustat(statb.st_dev, &ustatb)<0 ) 1682 #endif 1683 return(TRUE); 1684 #ifdef STATFS 1685 /* 1686 * Use 512-byte blocks, because that's the unit "ustat" tends 1687 * to work in. 1688 */ 1689 if( ((statfsb.f_bavail*statfsb.f_bsize)/512) < FREESPACE ) 1690 #else 1691 if( ustatb.f_tfree < FREESPACE ) 1692 #endif 1693 { 1694 logent("FREESPACE IS LOW","REMOTE TRANSFER DENIED - "); 1695 return(TRUE); 1696 } 1697 #ifdef STATFS 1698 /* 1699 * The test for "> 0" is there because the @$%#@#@$ NFS 1700 * protocol doesn't pass the number of free files over the 1701 * wire, so "statfs" on an NFS file system always returns -1. 1702 */ 1703 if( statfsb.f_ffree > 0 1704 && statfsb.f_ffree < FREENODES ) 1705 #else 1706 if( ustatb.f_tinode < FREENODES ) 1707 #endif 1708 { 1709 logent("TOO FEW INODES","REMOTE TRANSFER DENIED - "); 1710 return(TRUE); 1711 } 1712 } 1713 return(FALSE); 1714 } 1715 #endif 1716 1717 #ifdef V7USTAT 1718 int 1719 ustat(dev, ustat) 1720 int dev; 1721 struct ustat *ustat; 1722 { 1723 FILE *dfp, *popen(); 1724 char *fval, buf[BUFSIZ]; 1725 1726 sprintf(buf, "%s %d %d 2>&1", V7USTAT, major(dev), minor(dev)); 1727 if ((dfp = popen(buf, "r")) == NULL) 1728 return(-1); 1729 fval = fgets(buf, sizeof(buf), dfp); 1730 if (pclose(dfp) != 0 1731 || fval == NULL 1732 || sscanf(buf, "%d %d", &ustat->f_tfree, &ustat->f_tinode) != 2) 1733 return(-1); 1734 return(0); 1735 } 1736 #endif /* V7USTAT */ 1737