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