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 if (*fsize != '\0') { 1033 actualsize = strtol(fsize, (char **) 0, FLENRADIX); 1034 CDEBUG(7, "Actual File Length %ld\n", actualsize); 1035 } else { 1036 actualsize = -1; 1037 CDEBUG(7, "Actual File Length Not Provided\n%s", ""); 1038 } 1039 } 1040 1041 /* 1042 * receive file 1043 */ 1044 ASSERT(Role == MASTER, Wr_ROLE, "", Role); 1045 (void) millitick(); /* start msec timer */ 1046 pfStrtXfer(MCHAR, SNDFILE); 1047 scStime(); 1048 /* (ret != 0) implies the trammission error occurred. 1049 If checkpoint protocol is available then the next 1050 recieve will restart from the breakpoint of the file, 1051 otherwise from the beginning of the file */ 1052 1053 ret = (*Rddata)(Ifn, fp); 1054 1055 /* the second millitick() returns the duration between 1056 the first and second call. 1057 writes "PARTIAL FILE to the transfer log indicating 1058 a transmission error. */ 1059 1060 statlog( "<-", getfilesize(), millitick(), 1061 (ret) ? "PARTIAL FILE" : "" ); 1062 pfEndXfer(); 1063 scEtime(); 1064 if (ret != 0) { 1065 pfEndfile("PARTIAL FILE"); 1066 (void) fclose(fp); 1067 if ( ret == EFBIG ) { 1068 WMESG(RQSTCMPT, EM_ULIMIT); 1069 logent("FILE EXCEEDS ULIMIT","FAILED"); 1070 CDEBUG(1, "Failed: file size exceeds ulimit%s\n", ""); 1071 goto top; 1072 } 1073 (*Turnoff)(); 1074 logent("INPUT FAILURE", "IN RECEIVE/MASTER MODE"); 1075 return(FAIL); 1076 } 1077 if (Restart && (actualsize != -1)) { 1078 if (fstat(fileno(fp), &stbuf)) { 1079 (void) fclose(fp); 1080 unlinkdf(Dfile); 1081 (*Turnoff)(); 1082 logent("CAN'T STAT PFILE", "FAILED"); 1083 return(FAIL); 1084 } 1085 if (stbuf.st_size != actualsize) { 1086 (void) fclose(fp); 1087 unlinkdf(Dfile); 1088 (*Turnoff)(); 1089 logent("RECEIVED SIZE NOT EQUAL TO ACTUAL SIZE", "FAILED"); 1090 CDEBUG(1, "Failed: receive size %ld ", stbuf.st_size); 1091 CDEBUG(1, "not equal to actual size %ld\n", actualsize); 1092 return(FAIL); 1093 } 1094 } 1095 (void) fclose(fp); 1096 1097 /* 1098 * See if spool file and target file in the same file system 1099 */ 1100 1101 ret = 0; 1102 if (p = strrchr(Dfile, '/')) 1103 { 1104 *p = '\0'; 1105 ret = PREFIX(Dfile, filename); 1106 *p = '/'; 1107 } 1108 1109 if (noSpool() && ret) 1110 { 1111 /* 1112 * if we are not already in the right file, and 1113 * it is theoretically in the same file system, 1114 * link it there... 1115 */ 1116 1117 if(strcmp (filename, Dfile)) { 1118 unlink(filename); 1119 if(link(Dfile, filename)) 1120 { 1121 logent("FAILED", "MOVE"); 1122 scWrite(); 1123 putinpub(filename, Dfile, W_USER); 1124 } 1125 else 1126 DEBUG(7, "linked Point file to %s\n", filename); 1127 unlink(Dfile); 1128 } 1129 else 1130 DEBUG(7, "Point file and %s the same\n", filename); 1131 status = 0; /* all done */ 1132 } 1133 else 1134 status = xmv(Dfile, filename); 1135 1136 WMESG(RQSTCMPT, status ? EM_RMTCP : YES); 1137 notify(mailopt, W_USER, rqstr, Rmtname, 1138 status ? EM_LOCCP : YES); 1139 if (status == 0) { 1140 sscanf(&msg[2], "%lo", &lfilemode); 1141 if (lfilemode <= 0) 1142 filemode = PUB_FILEMODE; 1143 else 1144 filemode = (mode_t)lfilemode; 1145 if (PREFIX(RemSpool, filename)) 1146 chmod(filename, DFILEMODE); 1147 else 1148 chmod(filename, (filemode & LEGALMODE) | PUB_FILEMODE); 1149 } else { 1150 logent("FAILED", "COPY"); 1151 scWrite(); /* log the security violation */ 1152 putinpub(filename, Dfile, W_USER); 1153 } 1154 pfEndfile(""); /* "" indicates the file transfer completely */ 1155 if ( W_FILE2[1] == '.' && 1156 (W_FILE2[0] == XQTPRE || W_FILE2[0] == DATAPRE) ) 1157 uuxqtflag = 1; 1158 goto top; 1159 } 1160 1161 /* 1162 * SLAVE section of RCVFILE 1163 * (request to send file) 1164 */ 1165 ASSERT(Role == SLAVE, Wr_ROLE, "", Role); 1166 1167 /* check permissions */ 1168 i = getargs(msg, wrkvec, W_MAX); 1169 1170 scRequser(W_USER); /* log requestor user id */ 1171 1172 /* log destination node, user and file name */ 1173 1174 scDest(Rmtname,NOTAVAIL,W_FILE2); 1175 1176 /* log source node, file owner, file name, mod time and size */ 1177 1178 scSrc(Myname,scOwn(W_FILE1),W_FILE1,scMtime(W_FILE1),scSize(W_FILE1)); 1179 /* Check for bad request */ 1180 if (i < 5) { 1181 WMESG(RCVFILE, EM_BADUUCP); /* you(remote master) gave me 1182 bad work file */ 1183 logent("DENIED", "TOO FEW ARGS IN SLAVE RCVFILE"); 1184 goto top; 1185 } 1186 1187 (void) sprintf(rqstr, "%s!%s --> %s!%s (%s)", Myname, 1188 W_FILE1, Rmtname, W_FILE2, W_USER); 1189 logent(rqstr, "REMOTE REQUESTED"); 1190 CDEBUG(1, "Remote Requested: %s\n", rqstr); 1191 mf = W_RFILE; 1192 DEBUG(4, "msg - %s\n", msg); 1193 DEBUG(4, "W_FILE1 - %s\n", W_FILE1); 1194 (void) strcpy(filename, W_FILE1); 1195 expfile(filename); 1196 if (DIRECTORY(filename)) { 1197 (void) strcat(filename, "/"); 1198 (void) strcat(filename, BASENAME(W_FILE2, '/')); 1199 } 1200 (void) sprintf(User, "%s", W_USER); 1201 1202 if (requestOK() == FALSE) { 1203 /* remote can't request data from my system */ 1204 WMESG(RCVFILE, EM_RMTACC); 1205 logent("DENIED", "REQUESTING"); 1206 CDEBUG(1, "Failed: Access Denied\n%s", ""); 1207 scWrite(); /* log the security violation */ 1208 goto top; 1209 } 1210 DEBUG(4, "requestOK for Loginuser - %s\n", Loginuser); 1211 1212 if ((fp = fopen(filename, "r")) == NULL) { 1213 WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't 1214 read my file */ 1215 logent("CAN'T OPEN", "DENIED"); 1216 CDEBUG(1, "Failed: Can't Open %s\n", filename); 1217 scWrite(); /* log the security violation */ 1218 goto top; 1219 } 1220 1221 if (chkpth(filename, CK_READ) || !F_READANY(fileno(fp))) { 1222 WMESG(RCVFILE, EM_RMTACC); /* you(remote master) can't 1223 retrive my file */ 1224 logent("DENIED", "PERMISSION"); 1225 CDEBUG(1, "Failed: Access Denied\n%s", ""); 1226 scWrite(); /* log the security violation */ 1227 fclose(fp); 1228 goto top; 1229 } 1230 DEBUG(4, "chkpth ok Loginuser - %s\n", Loginuser); 1231 1232 ASSERT(fstat(fileno(fp), &stbuf) == 0, Ct_STAT, 1233 filename, errno); 1234 1235 /* Check whether remote's ulimit is exceeded */ 1236 if (SizeCheck) { 1237 if (((stbuf.st_size-1)/512 + 1) > RemUlimit) { 1238 /* remote ulimit exceeded */ 1239 WMESG(RCVFILE, EM_ULIMIT); 1240 logent("DENIED", "REMOTE ULIMIT EXCEEDED"); 1241 CDEBUG(1, "Denied: remote ulimit exceeded %s\n", filename); 1242 scWrite(); 1243 (void) fclose(fp); 1244 goto top; 1245 } 1246 } 1247 1248 /* 1249 * ok to send file 1250 */ 1251 1252 if (Restart && i >= 10) { 1253 if (startp = strtol(W_POINT, (char **) 0, FLENRADIX)) { 1254 CDEBUG(1,"Restart point=0x%lx\n", startp); 1255 errno = 0; 1256 if (lseek(fileno(fp), startp, 0) == -1) { 1257 WMESG(RCVFILE, EM_SEEK); 1258 logent(strerror(errno), "FSEEK ERROR"); 1259 (void) fclose(fp); 1260 goto top; 1261 } 1262 fp->_cnt = 0; 1263 fp->_ptr = fp->_base; 1264 if(startp < 0) 1265 sprintf(tbuf,"start=0x%lx", startp); 1266 else 1267 sprintf(tbuf,"start=%ld", startp); 1268 p = tbuf + strlen(tbuf); 1269 if (stbuf.st_size < 0) 1270 sprintf(p,", length=0x%lx", stbuf.st_size); 1271 else 1272 sprintf(p,", length=%ld", stbuf.st_size); 1273 1274 logent(tbuf, "RESTART"); 1275 } 1276 } 1277 1278 if (Restart) 1279 (void) sprintf(msg, "%s %lo 0x%lx", YES, 1280 (long) (stbuf.st_mode & LEGALMODE), 1281 (long) stbuf.st_size); 1282 else 1283 (void) sprintf(msg, "%s %lo", YES, 1284 (long) (stbuf.st_mode & LEGALMODE)); 1285 WMESG(RCVFILE, msg); /* I(slave) send you my file now */ 1286 Seqn++; 1287 (void) millitick(); /* start msec timer */ 1288 scStime(); 1289 pfStrtXfer(SCHAR, SNDFILE); 1290 /* (ret != 0) implies the trammission error occurred. 1291 If checkpoint protocol is available then the next 1292 transfer will restart from the breakpoint of the file, 1293 otherwise from the beginning of the file */ 1294 1295 ret = (*Wrdata)(fp, Ofn); 1296 1297 /* the second millitick() returns the duration between 1298 the first and second call. 1299 writes "PARTIAL FILE to the transfer log indicating 1300 a transmission error. */ 1301 1302 statlog( "->", getfilesize(), millitick(), 1303 (ret) ? "PARTIAL FILE" : "" ); 1304 pfEndXfer(); 1305 scEtime(); 1306 1307 (void) fclose(fp); 1308 if (ret != 0) { 1309 pfEndfile("PARTIAL FILE"); 1310 (*Turnoff)(); 1311 return(FAIL); 1312 } 1313 1314 /* loop depending on the size of the file */ 1315 /* give an extra try for each megabyte */ 1316 /* stbuf set in fstat several lines back */ 1317 for (im = stbuf.st_size >> 10; im >= 0; --im) { 1318 if ((ret = rmesg(RQSTCMPT, msg)) == 0) 1319 break; /* got message */ 1320 } 1321 if (ret != 0) { 1322 (*Turnoff)(); 1323 return(FAIL); 1324 } 1325 goto process; 1326 } 1327 (*Turnoff)(); 1328 return(FAIL); 1329 } 1330 1331 1332 1333 /* 1334 * read message 1335 * returns: 1336 * 0 -> success 1337 * FAIL -> failure 1338 */ 1339 int 1340 rmesg(c, msg) 1341 char *msg, c; 1342 { 1343 char str[50]; 1344 1345 DEBUG(4, "rmesg - '%c' ", c); 1346 if ((*Rdmsg)(msg, Ifn) != 0) { 1347 DEBUG(4, "got %s\n", "FAIL"); 1348 (void) sprintf(str, "expected '%c' got FAIL", c); 1349 logent(str, "BAD READ"); 1350 return(FAIL); 1351 } 1352 if (c != '\0' && msg[0] != c) { 1353 DEBUG(4, "got %s\n", msg); 1354 (void) sprintf(str, "expected '%c' got %s", c, msg); 1355 logent(str, "BAD READ"); 1356 return(FAIL); 1357 } 1358 DEBUG(4, "got %s\n", msg); 1359 return(0); 1360 } 1361 1362 1363 /* 1364 * write a message 1365 * returns: 1366 * 0 -> ok 1367 * FAIL -> ng 1368 */ 1369 int 1370 wmesg(m, s) 1371 char *s, m; 1372 { 1373 CDEBUG(4, "wmesg '%c'", m); 1374 CDEBUG(4, "%s\n", s); 1375 return((*Wrmsg)(m, s, Ofn)); 1376 } 1377 1378 1379 /* 1380 * mail results of command 1381 * return: 1382 * none 1383 */ 1384 void 1385 notify(mailopt, user, msgin, sys, msgcode) 1386 char *user, *msgin, *sys; 1387 char *msgcode; 1388 { 1389 int i; 1390 char str[BUFSIZ]; 1391 char *msg; 1392 1393 DEBUG(4,"mailopt %d, ", mailopt); 1394 DEBUG(4,"statfopt %d\n", statfopt); 1395 if (statfopt == 0 && mailopt == 0 && *msgcode == 'Y') 1396 return; 1397 if (*msgcode == 'Y') 1398 msg = "copy succeeded"; 1399 else { 1400 i = atoi(msgcode + 1); 1401 if (i < 1 || i > EM_MAX) 1402 i = 0; 1403 msg = Em_msg[i]; 1404 } 1405 if(statfopt){ 1406 stmesg(msgin, msg); 1407 return; 1408 } 1409 (void) sprintf(str, "REQUEST: %s\n(SYSTEM: %s) %s\n", 1410 msgin, sys, msg); 1411 mailst(user, msg, str, "", ""); 1412 return; 1413 } 1414 1415 /* 1416 * local notify 1417 * return: 1418 * none 1419 */ 1420 void 1421 lnotify(user, msgin, mesg) 1422 char *user, *msgin, *mesg; 1423 { 1424 char mbuf[BUFSIZ]; 1425 1426 if(statfopt){ 1427 stmesg(msgin, mesg); 1428 return; 1429 } 1430 (void) sprintf(mbuf, "REQUEST: %s\n(SYSTEM: %s) %s\n", 1431 msgin, Myname, mesg); 1432 mailst(user, mesg, mbuf, "", ""); 1433 return; 1434 } 1435 1436 /*ARGSUSED*/ 1437 static void 1438 stmesg(f, m) 1439 char *f, *m; 1440 { 1441 #ifdef notdef 1442 FILE *Cf; 1443 time_t clock; 1444 long td, th, tm, ts; 1445 #endif 1446 char msg[BUFSIZ]; 1447 1448 DEBUG(4,"STMES %s\n",mf); 1449 sprintf(msg, "STMESG - %s", mf); 1450 logent("DENIED", msg); 1451 #ifdef notdef 1452 /* 1453 * This code is a giant security hole. 1454 * No checking is done on what file is 1455 * written and chmod'ed. For now we 1456 * just ifdef this out. 1457 */ 1458 if((Cf = fopen(mf, "a+")) == NULL){ 1459 chmod(mf, PUB_FILEMODE); 1460 return; 1461 } 1462 (void) time(&clock); 1463 (void) fprintf(Cf, "uucp job: %s (%s) ", Jobid, timeStamp()); 1464 td = clock - Nstat.t_qtime; 1465 ts = td%60; 1466 td /= 60; 1467 tm = td%60; 1468 td /= 60; 1469 th = td; 1470 (void) fprintf(Cf, "(%ld:%ld:%ld)\n%s\n%s\n\n", th, tm, ts, f, m); 1471 (void) fclose(Cf); 1472 chmod(mf, PUB_FILEMODE); 1473 #endif 1474 } 1475 1476 /* 1477 * converse with the remote machine, agree upon a 1478 * protocol (if possible) and start the protocol. 1479 * return: 1480 * SUCCESS -> successful protocol selection 1481 * FAIL -> can't find common or open failed 1482 */ 1483 int 1484 startup(void) 1485 { 1486 extern void blptcl(); 1487 extern int fptcl(); 1488 char msg[BUFSIZ], str[BUFSIZ]; 1489 1490 Rdmsg = imsg; 1491 Wrmsg = omsg; 1492 Turnoff = turnoff; 1493 blptcl(str); 1494 if (Role == MASTER) { 1495 RMESG(SLTPTCL, msg); 1496 if ( fptcl(&msg[1], str) == FAIL) { 1497 /* no protocol match */ 1498 WMESG(USEPTCL, NO); 1499 return(FAIL); 1500 } else { 1501 /* got protocol match */ 1502 WMESG(USEPTCL, &msg[1]); 1503 return(stptcl(&msg[1])); 1504 } 1505 } else { 1506 WMESG(SLTPTCL, str); 1507 RMESG(USEPTCL, msg); 1508 if ( fptcl(&msg[1], str) == FAIL ) { 1509 return(FAIL); 1510 } else { 1511 return(stptcl(&msg[1])); 1512 } 1513 } 1514 } 1515 1516 /* 1517 * choose a protocol from the input string (str) 1518 * and return the found letter. 1519 * Use the MASTER string (valid) for order of selection. 1520 * return: 1521 * '\0' -> no acceptable protocol 1522 * any character -> the chosen protocol 1523 */ 1524 int 1525 fptcl(str, valid) 1526 char *str, *valid; 1527 { 1528 char *l; 1529 1530 DEBUG(9, "Slave protocol list(%s)\n", str); 1531 DEBUG(9, "Master protocol list(%s)\n", valid); 1532 1533 for (l = valid; *l != '\0'; l++) { 1534 if ( strchr(str, *l) != NULL) { 1535 *str = *l; 1536 *(str+1) = '\0'; 1537 /* also update string with parms */ 1538 strcpy(_Protocol, findProto(_Protocol, *str)); 1539 return(SUCCESS); 1540 } 1541 } 1542 return(FAIL); 1543 } 1544 1545 /* 1546 * build a string of the letters of the available 1547 * protocols and return the string (str). The string consists of protocols 1548 * that are specified in the Systems and Devices files. If nothing was 1549 * specified in those files, then the string is the list of protocols from 1550 * our Ptble. 1551 * 1552 * str = place to put the protocol list 1553 * length = size of buffer at str 1554 * 1555 * return: 1556 * a pointer to string (str) 1557 */ 1558 void 1559 blptcl(str) 1560 char *str; 1561 { 1562 struct Proto *p; 1563 char *validPtr; 1564 1565 /* Build list of valid protocols. */ 1566 for (validPtr = str, p = Ptbl; (*validPtr = p->P_id) != NULLCHAR; 1567 validPtr++, p++); 1568 1569 /* Build _Protocol */ 1570 (void) protoString(str); /* Get desired protocols. */ 1571 return; 1572 } 1573 1574 /* 1575 * set up the six routines (Rdmg. Wrmsg, Rddata 1576 * Wrdata, Turnon, Turnoff) for the desired protocol. 1577 * returns: 1578 * SUCCESS -> ok 1579 * FAIL -> no find or failed to open 1580 */ 1581 int 1582 stptcl(c) 1583 char *c; 1584 { 1585 struct Proto *p; 1586 1587 for (p = Ptbl; p->P_id != '\0'; p++) { 1588 if (*c == p->P_id) { 1589 1590 /* 1591 * found protocol 1592 * set routine 1593 */ 1594 Rdmsg = p->P_rdmsg; 1595 Wrmsg = p->P_wrmsg; 1596 Rddata = p->P_rddata; 1597 Wrdata = p->P_wrdata; 1598 Turnon = p->P_turnon; 1599 Turnoff = p->P_turnoff; 1600 if ((*Turnon)() != 0) 1601 break; 1602 CDEBUG(4, "Proto started %c\n", *c); 1603 pfPtcl(c); 1604 return(SUCCESS); 1605 } 1606 } 1607 CDEBUG(4, "Proto start-fail %c\n", *c); 1608 return(FAIL); 1609 } 1610 1611 /* 1612 * unlink D. file 1613 * returns: 1614 * none 1615 */ 1616 void 1617 unlinkdf(file) 1618 char *file; 1619 { 1620 if (strlen(file) > (size_t) 6) 1621 (void) unlink(file); 1622 return; 1623 } 1624 1625 /* 1626 * notify receiver of arrived file 1627 * returns: 1628 * none 1629 */ 1630 void 1631 arrived(opt, file, nuser, rmtsys, rmtuser) 1632 char *file, *nuser, *rmtsys, *rmtuser; 1633 { 1634 char mbuf[200]; 1635 1636 if (!opt) 1637 return; 1638 (void) sprintf(mbuf, "%s from %s!%s arrived\n", file, rmtsys, rmtuser); 1639 mailst(nuser, mbuf, mbuf, "", ""); 1640 return; 1641 } 1642 1643 1644 /* 1645 * Check to see if there is space for file 1646 */ 1647 1648 #define FREESPACE 50 /* Minimum freespace in blocks to permit transfer */ 1649 #define FREENODES 5 /* Minimum number of inodes to permit transfer */ 1650 1651 /*ARGSUSED*/ 1652 static int 1653 nospace(name) 1654 char *name; 1655 #ifdef NOUSTAT 1656 {return(FALSE);} 1657 #else 1658 { 1659 struct stat statb; 1660 #ifdef STATFS 1661 struct statfs statfsb; 1662 #else 1663 struct ustat ustatb; 1664 #endif 1665 1666 if( stat(name, &statb) < 0 ) 1667 return(TRUE); 1668 #ifdef RT 1669 if( (statb.st_mode|S_IFMT) == S_IFREG || 1670 (statb.st_mode|S_IFMT) == S_IFEXT || 1671 (statb.st_mode&S_IFMT) == S_IF1EXT ) 1672 #else 1673 if( (statb.st_mode&S_IFMT) == S_IFREG ) 1674 #endif 1675 { 1676 #ifdef STATFS 1677 if( statfs(name, &statfsb)<0 ) 1678 #else 1679 if( ustat(statb.st_dev, &ustatb)<0 ) 1680 #endif 1681 return(TRUE); 1682 #ifdef STATFS 1683 /* 1684 * Use 512-byte blocks, because that's the unit "ustat" tends 1685 * to work in. 1686 */ 1687 if( ((statfsb.f_bavail*statfsb.f_bsize)/512) < FREESPACE ) 1688 #else 1689 if( ustatb.f_tfree < FREESPACE ) 1690 #endif 1691 { 1692 logent("FREESPACE IS LOW","REMOTE TRANSFER DENIED - "); 1693 return(TRUE); 1694 } 1695 #ifdef STATFS 1696 /* 1697 * The test for "> 0" is there because the @$%#@#@$ NFS 1698 * protocol doesn't pass the number of free files over the 1699 * wire, so "statfs" on an NFS file system always returns -1. 1700 */ 1701 if( statfsb.f_ffree > 0 1702 && statfsb.f_ffree < FREENODES ) 1703 #else 1704 if( ustatb.f_tinode < FREENODES ) 1705 #endif 1706 { 1707 logent("TOO FEW INODES","REMOTE TRANSFER DENIED - "); 1708 return(TRUE); 1709 } 1710 } 1711 return(FALSE); 1712 } 1713 #endif 1714 1715 #ifdef V7USTAT 1716 int 1717 ustat(dev, ustat) 1718 int dev; 1719 struct ustat *ustat; 1720 { 1721 FILE *dfp, *popen(); 1722 char *fval, buf[BUFSIZ]; 1723 1724 sprintf(buf, "%s %d %d 2>&1", V7USTAT, major(dev), minor(dev)); 1725 if ((dfp = popen(buf, "r")) == NULL) 1726 return(-1); 1727 fval = fgets(buf, sizeof(buf), dfp); 1728 if (pclose(dfp) != 0 1729 || fval == NULL 1730 || sscanf(buf, "%d %d", &ustat->f_tfree, &ustat->f_tinode) != 2) 1731 return(-1); 1732 return(0); 1733 } 1734 #endif /* V7USTAT */ 1735