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 char * p; 252 long startp; /* checkpoint restart point */ 253 long actualsize; /* actual file size */ 254 long im; 255 long lfilemode; 256 mode_t filemode; 257 int status; 258 int i, narg; 259 int mailopt, ntfyopt; 260 int ret; 261 char tbuf[TBUFSIZE]; 262 char rqstr[BUFSIZ]; /* contains the current request message */ 263 char msg[BUFSIZ]; 264 char filename[MAXFULLNAME], wrktype; 265 char fsize[NAMESIZE]; /* holds file size/checkpoint string */ 266 char localname[MAXFULLNAME]; /* real local system name */ 267 char Recspool[MAXFULLNAME]; /* spool area for slave uucico */ 268 static pid_t pnum; 269 extern int uuxqtflag; /* set if received X. or D. file */ 270 271 pnum = getpid(); 272 Wfile[0] = '\0'; 273 (void) sprintf(Recspool, "%s/%s", SPOOL, Rmtname); 274 top: 275 (void) strcpy(User, Uucp); 276 statfopt = 0; 277 *Jobid = '\0'; 278 DEBUG(4, "*** TOP *** - Role=%d, ", Role); 279 setline(RESET); 280 if (Role == MASTER) { 281 282 /* 283 * get work 284 */ 285 pfFindFile(); 286 if ((narg = gtwvec(Wfile, wrkvec, W_MAX)) == 0) { 287 acEnd(COMPLETE); /*stop collecting accounting log */ 288 WMESG(HUP, ""); /* I(master) am done. want me to quit? */ 289 RMESG(HUP, msg); 290 goto process; 291 } 292 DEBUG(7, "Wfile - %s,", Wfile); 293 strncpy(Jobid, BASENAME(Wfile, '/')+2, NAMESIZE); 294 Jobid[NAMESIZE-1] = '\0'; 295 DEBUG(7, "Jobid = %s\n", Jobid); 296 wrktype = W_TYPE[0]; 297 pfFound(Jobid, W_OPTNS, Nstat.t_qtime); 298 mailopt = strchr(W_OPTNS, 'm') != NULL; 299 statfopt = strchr(W_OPTNS, 'o') != NULL; 300 ntfyopt = strchr(W_OPTNS, 'n') != NULL; 301 302 uucpname(localname); /* get real local machine name */ 303 acDojob(Jobid, localname, W_USER); 304 scRequser(W_USER); /* log requestor user id */ 305 306 /* 307 * We used to check for corrupt workfiles here (narg < 5), 308 * but we were doing it wrong, and besides, anlwrk.c is the 309 * appropriate place to do it. 310 */ 311 312 (void) sprintf(User, "%s", W_USER); 313 if (wrktype == SNDFILE ) { 314 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname, 315 W_FILE1, Rmtname, W_FILE2, User); 316 317 /* log destination node, user and file name */ 318 319 scDest(Rmtname,NOTAVAIL,W_FILE2); 320 321 /* log source node, file owner, file name, mod time and size */ 322 323 scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1) 324 ,scSize(W_FILE1)); 325 326 logent(rqstr, "REQUEST"); 327 CDEBUG(1, "Request: %s\n", rqstr); 328 mf = W_SFILE; 329 (void) strcpy(filename, W_FILE1); 330 expfile(filename); 331 (void) strcpy(Dfile, W_DFILE); 332 if ( (fp = fopen(Dfile, "r")) == NULL) { 333 if ( (fp = fopen(filename, "r")) == NULL) { 334 /* cannot read spool or original file */ 335 unlinkdf(Dfile); 336 lnotify(User, rqstr, "can't access"); 337 (void) sprintf(msg, "CAN'T READ %s %d", 338 filename, errno); 339 logent(msg, "FAILED"); 340 CDEBUG(1, "Failed: Can't Read %s\n", filename); 341 scWrite(); /* log the security violation */ 342 goto top; 343 } else { 344 /* ensure original file is publicly readable */ 345 if ( !F_READANY(fileno(fp)) ) { 346 /* access denied */ 347 logent("DENIED", "ACCESS"); 348 unlinkdf(W_DFILE); 349 lnotify(User, rqstr, "access denied"); 350 CDEBUG(1, "Failed: Access Denied\n%s", ""); 351 scWrite(); /* log the security violation */ 352 goto top; 353 } 354 } 355 } 356 357 if (Restart && !(fstat(fileno(fp), &stbuf))) { 358 (void) sprintf(fsize, "0x%lx", stbuf.st_size); 359 W_FSIZE = fsize; /* set file size in vector */ 360 } 361 362 /* Check whether remote's ulimit is exceeded */ 363 if (SizeCheck) { 364 if (((stbuf.st_size-1)/512 + 1) > RemUlimit) { 365 /* remote ulimit exceeded */ 366 unlinkdf(Dfile); 367 lnotify(User, rqstr, "remote ulimit exceeded"); 368 logent("DENIED", "REMOTE ULIMIT EXCEEDED"); 369 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename); 370 scWrite(); 371 (void) fclose(fp); 372 goto top; 373 } 374 } 375 } 376 377 if (wrktype == RCVFILE) { 378 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname, 379 W_FILE1, Myname, W_FILE2, User); 380 381 /* log destination node, user and file name */ 382 383 scDest(Myname,NOTAVAIL,W_FILE2); 384 385 /* log source node, file owner, file name, mod time and size */ 386 387 scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL); 388 389 logent(rqstr, "REQUEST"); 390 CDEBUG(1, "Request: %s\n", rqstr); 391 mf = W_RFILE; 392 (void) strcpy(filename, W_FILE2); 393 394 /* change Wrkdir to SPOOL/Rmtname in case the file being 395 ** requested is needed for some remote execution. 396 */ 397 398 (void) strcpy(Wrkdir, Recspool); 399 expfile(filename); 400 401 /* now change Wrkdir back to what it was 402 ** just being paranoid. 403 */ 404 405 (void) strcpy(Wrkdir, RemSpool); 406 if (chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) { 407 408 /* access denied */ 409 logent("DENIED", "ACCESS"); 410 lnotify(User, rqstr, "access denied"); 411 CDEBUG(1, "Failed: Access Denied--File: %s\n", 412 filename); 413 scWrite(); /* log the security violation */ 414 goto top; 415 } 416 417 /* 418 * If we are not going to spool the file in the spool 419 * directory, just use the destination file name. If we 420 * are not supporting restart, wipe out the target file. 421 * else: 422 * 423 * If restart is enabled, make up the Point file name 424 * as the file to open, else use the TM style name. 425 * 426 * If we run into a spool name of "D.0", this implies 427 * that someone forgot to install the new uucp and 428 * uux commands. Such jobs will not be checkpointed. 429 */ 430 431 432 if (Restart && (strlen(W_RDFILE) > (size_t) 6)) { 433 if (noSpool()) { 434 strcpy(Dfile, filename); /* use Dest file directly */ 435 Pname(W_RDFILE, Dfile, TRUE); 436 } 437 else 438 Pname(W_RDFILE, Dfile, FALSE); 439 } 440 else { 441 TMname(Dfile, pnum); /* get TM file name */ 442 unlink(Dfile); 443 } 444 445 /* 446 * If the spool file exists, it better have the right owner 447 * and permissions! 448 */ 449 450 if (Restart && noSpool()) { 451 if ((! stat(Dfile, &stbuf)) && 452 ((stbuf.st_mode != (DFILEMODE|S_IFREG)) || 453 ((stbuf.st_gid != UUCPGID) || 454 (stbuf.st_uid != UUCPUID)))) { 455 lnotify(User, rqstr, 456 "bad spool file ownership/permissions"); 457 logent("BAD DESTFILE OWNER/PERMS", "FAIL"); 458 CDEBUG(1, "Failed: bad dest file owner/perms 0%o; fail\n", stbuf.st_mode); 459 goto top; 460 } 461 } 462 if ( ((fp = fopen(Dfile, "a+")) == NULL) 463 || nospace(Dfile)) { 464 465 /* can not create temp */ 466 if (noSpool()) 467 logent("CAN'T CREATE/OPEN DEST FILE", "FAILED"); 468 else 469 logent("CAN'T CREATE TM FILE", "FAILED"); 470 CDEBUG(1, "Failed: No Space!\n%s", ""); 471 unlinkdf(Dfile); 472 assert(Ct_CREATE, Dfile, nospace(Dfile), 473 __FILE__, __LINE__); 474 cleanup(FAIL); 475 } 476 477 /* 478 * Send the W_POINT value to the other side. 479 */ 480 481 if (Restart) { 482 if (fstat (fileno(fp), &stbuf)) { 483 logent("CAN'T STAT DFILE", "START FROM BEGINNING"); 484 stbuf.st_size = 0L; 485 } 486 487 /* 488 * find a good start point. Take care of simple 489 * underflow and the signed nature of longs. 490 */ 491 492 DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size); 493 startp = stbuf.st_size - (stbuf.st_size % BUFSIZ); 494 if((stbuf.st_size >= 0) && (startp < 0)) 495 startp = 0; 496 497 if(startp) 498 { 499 if(startp < 0) 500 sprintf(tbuf,"start=0x%lx", startp); 501 else 502 sprintf(tbuf,"start=%ld", startp); 503 504 logent(tbuf, "RESTART"); 505 } 506 507 sprintf(fsize, "0x%lx", startp); 508 W_POINT = fsize; /* set start point in vector */ 509 if (lseek(fileno(fp), startp, 0) == -1) { 510 WMESG(SNDFILE, EM_SEEK); 511 logent("CAN'T SEEK", "DENIED"); 512 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", ""); 513 unlinkdf(Dfile); 514 goto top; 515 } 516 fp->_cnt = 0; 517 fp->_ptr = fp->_base; 518 } 519 520 Seqn++; 521 chmod(Dfile, DFILEMODE); /* no peeking! */ 522 chown(Dfile, UUCPUID, UUCPGID); 523 524 } 525 DEBUG(4, "wrktype - %c\n ", wrktype); 526 527 /* Build up the message itself */ 528 529 msg[0] = '\0'; 530 for (i = 1; i < narg; i++) { 531 (void) strcat(msg, " "); 532 (void) strcat(msg, wrkvec[i]); 533 } 534 535 WMESG(wrktype, msg); /* I(master) am sending you our work file */ 536 RMESG(wrktype, msg); /* I(master) am waiting for your response */ 537 goto process; 538 } 539 540 /* 541 * role is slave 542 */ 543 544 RAMESG(msg); /* I(slave) am waiting for our work file */ 545 546 process: 547 548 DEBUG(4, " PROCESS: msg - %s\n", msg); 549 switch (msg[0]) { 550 551 case RQSTCMPT: 552 DEBUG(4, "%s\n", "RQSTCMPT:"); 553 if (msg[1] == 'N') { 554 i = atoi(&msg[2]); 555 if (i < 0 || i > EM_MAX) 556 i = 0; 557 logent(Em_msg[i], "REQUESTED"); 558 } 559 if (Role == MASTER) { 560 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 561 } 562 pfEndfile(""); /* "" indicates the file transfer completely */ 563 goto top; 564 565 case HUP: 566 DEBUG(4, "%s\n", "HUP:"); 567 if (msg[1] == 'Y') { 568 WMESG(HUP, YES); /* let's quit */ 569 (*Turnoff)(); 570 Rdmsg = imsg; 571 Wrmsg = omsg; 572 Turnoff = turnoff; 573 return(0); 574 } 575 576 if (msg[1] == 'N') { 577 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 578 Role = SLAVE; 579 scReqsys(Rmtname); /* log requestor system */ 580 chremdir(Rmtname); 581 goto top; 582 } 583 584 /* 585 * get work 586 */ 587 if ( (switchRole() == FALSE) || !iswrk(Wfile) ) { 588 DEBUG(5, "SLAVE-switchRole (%s)\n", 589 switchRole() ? "TRUE" : "FALSE"); 590 WMESG(HUP, YES); /* let's quit */ 591 RMESG(HUP, msg); 592 goto process; 593 } 594 595 /* Note that Wfile is the first C. to process at top 596 * set above by iswrk() call 597 */ 598 if (uuxqtflag) { 599 xuuxqt(uuxqtarg); 600 uuxqtflag = 0; 601 } 602 WMESG(HUP, NO); /* don't quit. I(slave) have more to do */ 603 Role = MASTER; 604 uucpname(localname); /* get real local machine name */ 605 scReqsys(localname); /* log requestor system */ 606 acInit("xfer"); 607 goto top; 608 609 case XUUCP: 610 /* 611 * slave part 612 * No longer accepted 613 */ 614 615 WMESG(XUUCP, NO); 616 goto top; 617 618 case SNDFILE: 619 620 /* 621 * MASTER section of SNDFILE 622 */ 623 DEBUG(4, "%s\n", "SNDFILE:"); 624 if (msg[1] == 'N') 625 { 626 i = atoi(&msg[2]); 627 if (i < 0 || i > EM_MAX) 628 i = 0; 629 logent(Em_msg[i], "REQUEST"); 630 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 631 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 632 (void) fclose(fp); 633 /* if remote is out of tmp space, then just hang up */ 634 ASSERT(i != 4, Em_msg[4], Rmtname, i); /* EM_NOTMP */ 635 unlinkdf(W_DFILE); 636 scWrite(); /* something is wrong on other side, 637 log the security violation */ 638 Seqn++; 639 goto top; 640 } 641 642 if (msg[1] == 'Y') { 643 644 /* 645 * send file 646 */ 647 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 648 if (fstat(fileno(fp), &stbuf)) /* never fail but .. */ 649 stbuf.st_size = 0; /* for time loop calculation */ 650 651 /* 652 * If checkpoint restart is enabled, seek to the 653 * starting point in the file. We use hex because 654 * C doesn't support unsigned long directly. 655 */ 656 657 if (Restart) { 658 if((startp = strtol(&msg[2], (char **) 0, FLENRADIX))) { 659 CDEBUG(1, "Restart point=0x%lx\n", startp); 660 if(startp < 0) 661 sprintf(tbuf,"start=0x%lx", startp); 662 else 663 sprintf(tbuf,"start=%ld", startp); 664 p = tbuf + strlen(tbuf); 665 if (stbuf.st_size < 0) 666 sprintf(p,", length=0x%lx", stbuf.st_size); 667 else 668 sprintf(p,", length=%ld", stbuf.st_size); 669 670 logent(tbuf, "RESTART"); 671 errno = 0; 672 if (lseek(fileno(fp), startp, 0) == -1) { 673 logent(strerror(errno), "FSEEK ERROR"); 674 (void) fclose(fp); 675 (*Turnoff)(); 676 Seqn++; 677 return(FAIL); 678 } 679 fp->_cnt = 0; 680 fp->_ptr = fp->_base; 681 } 682 } 683 (void) millitick(); /* start msec timer */ 684 pfStrtXfer(MCHAR, SNDFILE); 685 scStime(); /* log start transfer time for security log */ 686 687 /* (ret != 0) implies the trammission error occurred. 688 If checkpoint protocol is available then the next 689 transfer will restart from the breakpoint of the file, 690 otherwise from the beginning of the file */ 691 692 ret = (*Wrdata)(fp, Ofn); 693 694 /* the second millitick() returns the duration between 695 the first and second call. 696 writes "PARTIAL FILE to the transfer log indicating 697 a transmission error. */ 698 699 statlog( "->", getfilesize(), millitick(), 700 (ret) ? "PARTIAL FILE" : "" ); 701 702 acInc(); /* increment job size in accounting log */ 703 pfEndXfer(); 704 scEtime(); /* log end transfer time for security log */ 705 Seqn++; 706 (void) fclose(fp); 707 if (ret != 0) { 708 pfEndfile("PARTIAL FILE"); 709 acEnd(PARTIAL); /*stop collecting accounting log */ 710 (*Turnoff)(); 711 return(FAIL); 712 } 713 714 /* loop depending on the size of the file */ 715 /* give an extra try for each megabyte */ 716 for (im = stbuf.st_size >> 10; im >= 0; --im) { 717 if ((ret = rmesg(RQSTCMPT, msg)) == 0) 718 break; /* got message */ 719 } 720 if (ret != 0) { 721 (*Turnoff)(); 722 return(FAIL); 723 } 724 unlinkdf(W_DFILE); 725 goto process; 726 } 727 728 /* 729 * SLAVE section of SNDFILE 730 */ 731 ASSERT(Role == SLAVE, Wr_ROLE, "", Role); 732 733 /* 734 * request to receive file 735 * check permissions 736 */ 737 i = getargs(msg, wrkvec, W_MAX); 738 739 scRequser(W_USER); /* log requestor user id */ 740 741 /* log destination node, user and file name */ 742 743 scDest(Myname,NOTAVAIL,W_FILE2); 744 745 /* log source node, file owner, file name, mod time and size */ 746 747 scSrc(Rmtname,NOTAVAIL,W_FILE1,NOTAVAIL,NOTAVAIL); 748 749 /* Check for bad request */ 750 if (i < W_MIN) { 751 WMESG(SNDFILE, EM_BADUUCP); /* you(remote master) gave me 752 bad work file */ 753 logent("DENIED", "TOO FEW ARGS IN SLAVE SNDFILE"); 754 goto top; 755 } 756 /* SLAVE gets the original filesize from sender (MASTER) */ 757 /* This will be used to check the length of the P. file */ 758 if (Restart) { 759 if (W_FSIZE && (*W_FSIZE != '\0')) { 760 actualsize = strtol(W_FSIZE, (char **) 0, FLENRADIX); 761 CDEBUG(7, "Actual File Length %ld\n", actualsize); 762 } else { 763 actualsize = -1; 764 CDEBUG(7, "Actual File Length Not Provided\n%s", ""); 765 } 766 } 767 768 mf = W_SFILE; 769 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Rmtname, 770 W_FILE1, Myname, W_FILE2, W_USER); 771 logent(rqstr, "REMOTE REQUESTED"); 772 DEBUG(4, "msg - %s\n", msg); 773 CDEBUG(1, "Remote Requested: %s\n", rqstr); 774 (void) strcpy(filename, W_FILE2); 775 expfile(filename); 776 DEBUG(4, "SLAVE - filename: %s\n", filename); 777 if (chkpth(filename, CK_WRITE) 778 || chkperm(W_FILE1, filename, strchr(W_OPTNS, 'd'))) { 779 WMESG(SNDFILE, EM_RMTACC); /* you(remote master) can't 780 send data to this file(directory) */ 781 logent("DENIED", "PERMISSION"); 782 CDEBUG(1, "Failed: Access Denied\n%s", ""); 783 scWrite(); /* log security violation */ 784 goto top; 785 } 786 (void) sprintf(User, "%s", W_USER); 787 788 DEBUG(4, "chkpth ok Rmtname - %s\n", Rmtname); 789 790 791 792 if (Restart && (strlen(W_DFILE) > (size_t) 6)) { 793 if (noSpool()) { 794 strcpy(Dfile, filename); /* use Dest file directly */ 795 Pname(W_DFILE, Dfile, TRUE); 796 if (! Restart) 797 unlink(Dfile); 798 } 799 else 800 Pname(W_DFILE, Dfile, FALSE); 801 } 802 else { 803 TMname(Dfile, pnum); /* get TM file name */ 804 unlink(Dfile); 805 } 806 807 /* 808 * If the spool file exists, it better have the right owner 809 * and permissions! 810 */ 811 812 if (Restart && noSpool()) { 813 if ((! stat(Dfile, &stbuf)) && 814 ((stbuf.st_mode != (DFILEMODE|S_IFREG)) || 815 ((stbuf.st_gid != UUCPGID) || 816 (stbuf.st_uid != UUCPUID)))) { 817 WMESG(SNDFILE, EM_NOTMP); /* I(slave) see bad perms */ 818 logent("BAD DESTFILE OWNER/PERMS", "FAILED"); 819 CDEBUG(1, "Failed: bad dest file owner/perms 0%o\n", stbuf.st_mode); 820 goto top; 821 } 822 } 823 if ( ((fp = fopen(Dfile, "a+")) == NULL) || nospace(Dfile) ) { 824 WMESG(SNDFILE, EM_NOTMP); /* I(slave) can't create TM file */ 825 logent("CAN'T OPEN", "DENIED"); 826 CDEBUG(1, "Failed: Can't Create Temp File\n%s", ""); 827 unlinkdf(Dfile); 828 goto top; 829 } 830 chmod(Dfile, DFILEMODE); /* no peeking! */ 831 chown(Dfile, UUCPUID, UUCPGID); 832 if (Restart && (strlen(W_DFILE) > (size_t) 6)) { 833 if(fstat(fileno(fp), &stbuf)) { 834 WMESG(SNDFILE, EM_NOTMP); 835 logent("CAN'T STAT", "DENIED"); 836 CDEBUG(1, "Failed: Can't Stat Temp File\n%s", ""); 837 unlinkdf(Dfile); 838 Seqn++; 839 goto top; 840 } 841 /* 842 * find a good start point. Take care of simple underflow 843 * and the signed nature of longs. 844 */ 845 846 DEBUG(7, "Dfile length 0x%lx\n", stbuf.st_size); 847 startp = stbuf.st_size - (stbuf.st_size % BUFSIZ); 848 if((stbuf.st_size >= 0) && (startp < 0)) 849 startp = 0; 850 851 if(startp) 852 { 853 if(startp < 0) 854 sprintf(tbuf,"start=0x%lx", startp); 855 else 856 sprintf(tbuf,"start=%ld", startp); 857 858 logent(tbuf, "RESTART"); 859 } 860 861 sprintf(tbuf, "%s 0x%lx", YES, startp); 862 if (lseek(fileno(fp), startp, 0) == -1) { 863 WMESG(SNDFILE, EM_SEEK); 864 logent("CAN'T SEEK", "DENIED"); 865 CDEBUG(1, "Failed, Can't seek in Dfile\n%s", ""); 866 unlinkdf(Dfile); 867 Seqn++; 868 goto top; 869 } 870 fp->_cnt = 0; 871 fp->_ptr = fp->_base; 872 CDEBUG(1," restart msg %s\n", tbuf); 873 WMESG(SNDFILE, tbuf); 874 } 875 else 876 WMESG(SNDFILE, YES); /* I(slave) clear to send */ 877 (void) millitick(); /* start msec timer */ 878 pfStrtXfer(SCHAR, RCVFILE); 879 scStime(); /* log start transfer time for security log */ 880 /* (ret != 0) implies the trammission error occurred. 881 If checkpoint protocol is available then the next 882 recieve will restart from the breakpoint of the file, 883 otherwise from the beginning of the file */ 884 885 setline(RCVFILE); 886 ret = (*Rddata)(Ifn, fp); 887 setline(SNDFILE); 888 889 /* the second millitick() returns the duration between 890 the first and second call. 891 writes "PARTIAL FILE to the transfer log indicating 892 a transmission error. */ 893 894 statlog( "<-", getfilesize(), millitick(), 895 (ret) ? "PARTIAL FILE" : "" ); 896 897 pfEndXfer(); 898 scEtime(); /* log end transfer time for security log */ 899 Seqn++; 900 901 if (ret != 0) { 902 pfEndfile("PARTIAL FILE"); 903 (void) fclose(fp); 904 if ( ret == EFBIG ) { 905 WMESG(RQSTCMPT, EM_ULIMIT); 906 logent("FILE EXCEEDS ULIMIT","FAILED"); 907 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", ""); 908 goto top; 909 } 910 (*Turnoff)(); 911 logent("INPUT FAILURE", "IN SEND/SLAVE MODE"); 912 return(FAIL); 913 } 914 if (Restart && (actualsize != -1)) { 915 if (fstat(fileno(fp), &stbuf)) { 916 (void) fclose(fp); 917 unlinkdf(Dfile); 918 (*Turnoff)(); 919 logent("CAN'T STAT PFILE", "FAILED"); 920 return(FAIL); 921 } 922 if (stbuf.st_size != actualsize) { 923 (void) fclose(fp); 924 unlinkdf(Dfile); 925 (*Turnoff)(); 926 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED"); 927 CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size); 928 CDEBUG(1, "not equal to actual size %ld\n", actualsize); 929 return(FAIL); 930 } 931 } 932 (void) fclose(fp); 933 934 /* copy to user directory */ 935 ntfyopt = strchr(W_OPTNS, 'n') != NULL; 936 937 /* 938 * See if spool file and target file in the same file system 939 */ 940 941 ret = 0; 942 if (p = strrchr(Dfile, '/')) 943 { 944 *p = '\0'; 945 ret = PREFIX(Dfile, filename); 946 *p = '/'; 947 } 948 949 if (noSpool() && ret) 950 { 951 /* 952 * if we are not already in the right file, and 953 * it is theoretically in the same file system, 954 * link it there... 955 */ 956 957 if(strcmp (filename, Dfile)) { 958 unlink(filename); 959 if(link(Dfile, filename)) 960 { 961 logent("FAILED", "MOVE"); 962 scWrite(); 963 putinpub(filename, Dfile, BASENAME(W_USER,'!')); 964 } 965 else 966 DEBUG(7, "linked Point file to %s\n", filename); 967 unlink(Dfile); 968 } 969 else 970 DEBUG(7, "Point file and %s the same\n", filename); 971 status = 0; /* all done */ 972 } 973 else 974 status = xmv(Dfile, filename); 975 976 scSize(Dfile); /* log source file size */ 977 WMESG(RQSTCMPT, status ? EM_RMTCP : YES); 978 if (status == 0) { 979 sscanf(W_MODE, "%lo", &lfilemode); 980 if (lfilemode <= 0) 981 filemode = PUB_FILEMODE; 982 else 983 filemode = (mode_t)lfilemode; 984 if (PREFIX(RemSpool, filename)) 985 chmod(filename, DFILEMODE); 986 else 987 chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE); 988 arrived(ntfyopt, filename, W_NUSER, Rmtname, User); 989 } else { 990 logent("FAILED", "COPY"); 991 scWrite(); /* log the security violation */ 992 status = putinpub(filename, Dfile, 993 BASENAME(W_USER, '!')); 994 DEBUG(4, "->PUBDIR %d\n", status); 995 if (status == 0) 996 arrived(ntfyopt, filename, W_NUSER, 997 Rmtname, User); 998 } 999 pfEndfile(""); /* "" indicates the file transfer completely */ 1000 if ( W_FILE2[1] == '.' && 1001 (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) ) 1002 uuxqtflag = 1; 1003 goto top; 1004 1005 case RCVFILE: 1006 1007 /* 1008 * MASTER section of RCVFULE 1009 */ 1010 DEBUG(4, "%s\n", "RCVFILE:"); 1011 if (msg[1] == 'N') { 1012 i = atoi(&msg[2]); 1013 if (i < 0 || i > EM_MAX) 1014 i = 0; 1015 logent(Em_msg[i], "REQUEST"); 1016 notify(mailopt, W_USER, rqstr, Rmtname, &msg[1]); 1017 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 1018 (void) fclose(fp); 1019 unlinkdf(Dfile); 1020 scWrite(); /* something is wrong on other side, 1021 log the security violation */ 1022 goto top; 1023 } 1024 1025 if (msg[1] == 'Y') { 1026 1027 /* MASTER gets the original filesize from sender (SLAVE) */ 1028 /* This will be used to check the length of the P. file */ 1029 if (Restart) { 1030 *fsize = '\0'; 1031 sscanf(&msg[2], "%*o %s", fsize); 1032