// FtpServer.bcpl - Subsystem version // Copyright Xerox Corporation 1979, 1980, 1981, 1982 // Last modified May 13, 1982 4:45 PM by Boggs get "Pup.decl" get "FtpProt.decl" get "AltoFileSys.d" get "Disks.d" external [ // outgoing procedures FtpServer; FtpServFinishProc FtpSStore; FtpSStoreFile; FtpSStoreCleanup FtpSRetrieve; FtpSRetrieveFile; FtpSRetrieveCleanup FtpSDelete; FtpSDeleteFile; FtpSRename FtpSDirectory; FtpSVersion // incoming procedures FtpServProt; FreePList; InitPList Allocate; Zero; Block; MoveBlock; Password ExtractSubstring; ConcatenateStrings; PutTemplate DiskToNet; NetToDisk; FTPM; FileType OtherPup; MakeNAMB; CloseLocalFile; PrintPort OpenFile; DeleteFile; RenameFile; Closes; Wss ReadLeaderPage; WriteLeaderPage; SetFilePos; ReadBlock OpenLevel1Socket; OpenRTPSocket; CreateBSPStream CloseLevel1Socket; CloseRTPSocket; CloseBSPSocket // outgoing statics protectedServer; overwriteServer; killServer // incoming statics ftpDisk; defaultPL; debugFlag; CtxRunning serverDsp; serverCtx; serverSoc; serverUFP sysZone; fpSysBoot; lvUserFinishProc ] static [ diskPsw = 0 protectedServer = false overwriteServer = false killServer = false abortFlag = false firstTime = true ] //----------------------------------------------------------------------------------------- let FtpServer() be //----------------------------------------------------------------------------------------- [ OpenLevel1Socket(serverSoc, table [ 0; 0; socketFTP ] ) OpenRTPSocket(serverSoc, 0, modeListenAndReturn, 0, OtherPup) until serverSoc>>BSPSoc.state eq stateOpen do Block() PutTemplate(serverDsp, "*NConnection Open with $P", PrintPort, lv serverSoc>>BSPSoc.frnPort) CtxRunning>>FtpCtx.bspStream = CreateBSPStream(serverSoc) CtxRunning>>FtpCtx.connFlag = true FtpServProt(18000) //3 minute top level command timeout Wss(serverDsp, "*NServer Connection Closed") if abortFlag then Block() repeat if killServer then finish ] repeat //----------------------------------------------------------------------------------------- and FtpServFinishProc() be //----------------------------------------------------------------------------------------- [ abortFlag = true if serverCtx>>FtpCtx.connFlag then [ serverCtx>>FtpCtx.connFlag = false CloseBSPSocket(serverSoc, 0) ] @lvUserFinishProc = serverUFP ] //----------------------------------------------------------------------------------------- and FtpSRetrieve(remotePL, localPL) = valof //----------------------------------------------------------------------------------------- [ localPL = FreePList(localPL) unless firstTime do [ firstTime = true; resultis false ] unless CheckAccess(remotePL) resultis false MakeSFIL(remotePL) CtxRunning>>FtpCtx.diskStream = OpenFile(remotePL>>PL.SFIL, ksTypeReadOnly, charItem, 0, 0, 0, 0, 0, ftpDisk) if CtxRunning>>FtpCtx.diskStream eq 0 then [ FTPM(markNo, 100b, "No such file"); resultis false ] // setup outgoing property list let ok = true localPL = FtpSFillPLFromLD(remotePL) if remotePL>>PL.TYPE ne 0 & localPL>>PL.TYPE ne remotePL>>PL.TYPE then test localPL>>PL.TYPE eq Binary ifso [ FTPM(markNo, 102b, "File is Binary, not Text") ok = false ] ifnot [ FTPM(markComment, 0, "Warning: file may be text") localPL>>PL.TYPE = Binary ] if ok then test localPL>>PL.TYPE eq Binary ifso test remotePL>>PL.BYTE eq 0 ifnot localPL>>PL.BYTE = remotePL>>PL.BYTE ifso localPL>>PL.BYTE = 8 ifnot test remotePL>>PL.EOLC eq CRLF ifnot localPL>>PL.EOLC = CR ifso [ FTPM(markNo, 102b, "CRLF Conversion not supported") ok = false ] firstTime = false unless ok do [ CloseLocalFile() localPL = FreePList(localPL) ] resultis localPL ] //----------------------------------------------------------------------------------------- and FtpSRetrieveFile(localPL, remotePL) = valof //----------------------------------------------------------------------------------------- [ PutTemplate(serverDsp, "*NRetrieve $S: ", localPL>>PL.SFIL) resultis DiskToNet(remotePL, localPL) ] //----------------------------------------------------------------------------------------- and FtpSRetrieveCleanup(localPL, ok, remotePL) be //----------------------------------------------------------------------------------------- Closes(CtxRunning>>FtpCtx.diskStream) //----------------------------------------------------------------------------------------- and FtpSStore(remotePL) = valof //----------------------------------------------------------------------------------------- [ unless CheckAccess(remotePL) resultis false if protectedServer then [ FTPM(markNo, 101b, "Store is not permitted") resultis false ] if remotePL>>PL.EOLC eq CRLF then [ FTPM(markNo, 102b, "CRLF conversion not supported") resultis false ] MakeSFIL(remotePL) let hintFP = vec lFP; Zero(hintFP, lFP) let diskStream = OpenFile(remotePL>>PL.SFIL, ksTypeReadOnly, charItem, 0, hintFP, 0, 0, 0, ftpDisk) if diskStream ne 0 then [ Closes(diskStream) unless overwriteServer do [ FTPM(markNo, 101b, "File exists - can't overwrite") resultis false ] ] CtxRunning>>FtpCtx.diskStream = OpenFile(remotePL>>PL.SFIL, ksTypeWriteOnly, charItem, 0, hintFP, 0, 0, 0, ftpDisk) if CtxRunning>>FtpCtx.diskStream eq 0 then [ FTPM(markNo, 100b, "Unable to open that file") resultis false ] resultis FtpSFillPLFromLD(remotePL) ] //----------------------------------------------------------------------------------------- and FtpSStoreFile(remotePL, localPL) = valof //----------------------------------------------------------------------------------------- [ let buffer = CtxRunning>>FtpCtx.buffer ReadLeaderPage(CtxRunning>>FtpCtx.diskStream, buffer) if remotePL>>PL.CDAT.h ne 0 then MoveBlock(lv buffer>>LD.created, lv remotePL>>PL.CDAT, 2) WriteLeaderPage(CtxRunning>>FtpCtx.diskStream, buffer) PutTemplate(serverDsp, "*NStore $S: ", remotePL>>PL.SFIL) resultis NetToDisk(remotePL, localPL) ] //----------------------------------------------------------------------------------------- and FtpSStoreCleanup(remotePL, ok, localPL) be //----------------------------------------------------------------------------------------- [ FreePList(localPL) Closes(CtxRunning>>FtpCtx.diskStream) unless ok do DeleteFile(remotePL>>PL.SFIL, 0, 0, 0, 0, ftpDisk) ] //----------------------------------------------------------------------------------------- and FtpSVersion(bspStream, nil) be //----------------------------------------------------------------------------------------- Wss(bspStream, "BCPL Pup Ftp Server, 13 May 82 ") //----------------------------------------------------------------------------------------- and FtpSDirectory(remotePL, localPL) = valof //----------------------------------------------------------------------------------------- [ localPL = FreePList(localPL) unless firstTime do [ firstTime = true; resultis false ] unless CheckAccess(remotePL) resultis false MakeSFIL(remotePL) CtxRunning>>FtpCtx.diskStream = OpenFile(remotePL>>PL.SFIL, ksTypeReadOnly, charItem, 0, 0, 0, 0, 0, ftpDisk) if CtxRunning>>FtpCtx.diskStream eq 0 then [ FTPM(markNo, 100b, "No such file"); resultis false ] PutTemplate(serverDsp, "*NDirectory $S", remotePL>>PL.SFIL) // setup property list localPL = FtpSFillPLFromLD(remotePL) Closes(CtxRunning>>FtpCtx.diskStream) firstTime = false resultis localPL ] //----------------------------------------------------------------------------------------- and FtpSRename(oldPL, newPL) = valof //----------------------------------------------------------------------------------------- [ unless CheckAccess(oldPL) resultis false MakeSFIL(oldPL) MakeSFIL(newPL) if not overwriteServer % protectedServer then [ FTPM(markNo, 101b, "Rename is not permitted") resultis false ] PutTemplate(serverDsp, "*NRename $S to $S", oldPL>>PL.SFIL, newPL>>PL.SFIL) if RenameFile(oldPL>>PL.SFIL, newPL>>PL.SFIL, 0, 0, 0, ftpDisk) resultis true FTPM(markNo, 0, "Rename failed") resultis false ] //----------------------------------------------------------------------------------------- and FtpSDelete(remotePL, localPL) = valof //----------------------------------------------------------------------------------------- [ FreePList(localPL) unless firstTime do [ firstTime = true; resultis false ] unless CheckAccess(remotePL) resultis false MakeSFIL(remotePL) if not overwriteServer % protectedServer then [ FTPM(markNo, 101b, "Delete is not permitted") resultis false ] CtxRunning>>FtpCtx.diskStream = OpenFile(remotePL>>PL.SFIL, ksTypeReadOnly, charItem, 0, 0, 0, 0, 0, ftpDisk) if CtxRunning>>FtpCtx.diskStream eq 0 then [ FTPM(markNo, 100b, "No such file"); resultis false ] // setup property list localPL = FtpSFillPLFromLD(remotePL) Closes(CtxRunning>>FtpCtx.diskStream) firstTime = false resultis localPL ] //----------------------------------------------------------------------------------------- and FtpSDeleteFile(localPL, remotePL) = valof //----------------------------------------------------------------------------------------- [ PutTemplate(serverDsp, "*NDelete $S", localPL>>PL.SFIL) resultis DeleteFile(localPL>>PL.SFIL, 0, 0, 0, 0, ftpDisk) ] //----------------------------------------------------------------------------------------- and MakeSFIL(pl) be //----------------------------------------------------------------------------------------- // Construct (and default) a server filename [ if pl>>PL.NAMB eq 0 then pl>>PL.NAMB = ExtractSubstring("") if pl>>PL.SFIL eq 0 then pl>>PL.SFIL = ExtractSubstring(pl>>PL.NAMB) if pl>>PL.DIRE ne 0 & pl>>PL.SFIL>>String.char↑1 ne $< then [ pl>>PL.SFIL = ConcatenateStrings(">", pl>>PL.SFIL, false, true) pl>>PL.SFIL = ConcatenateStrings(pl>>PL.DIRE, pl>>PL.SFIL, false, true) pl>>PL.SFIL = ConcatenateStrings("<", pl>>PL.SFIL, false, true) ] if pl>>PL.DEVI ne 0 then [ pl>>PL.SFIL = ConcatenateStrings(":", pl>>PL.SFIL, false, true) pl>>PL.SFIL = ConcatenateStrings(pl>>PL.DEVI, pl>>PL.SFIL, false, true) ] ] //----------------------------------------------------------------------------------------- and FtpSFillPLFromLD(remotePL) = valof //----------------------------------------------------------------------------------------- // setup property list [ let dprp = remotePL>>PL.DPRP //desired properties if dprp eq 0 then dprp = -1 //if none specified, request all properties let pl = InitPList() if dprp<<DPRP.SFIL then pl>>PL.SFIL = ExtractSubstring(remotePL>>PL.SFIL) if dprp<<DPRP.NAMB then pl>>PL.NAMB = MakeNAMB(remotePL>>PL.SFIL) if dprp<<DPRP.TYPE then pl>>PL.TYPE = FileType() manifest requiresLD = 1b15 rshift offset DPRP.SIZE % 1b15 rshift offset DPRP.CDAT % 1b15 rshift offset DPRP.WDAT % 1b15 rshift offset DPRP.RDAT if (dprp & requiresLD) ne 0 then [ let ld = CtxRunning>>FtpCtx.buffer ReadLeaderPage(CtxRunning>>FtpCtx.diskStream, ld) if dprp<<DPRP.CDAT then MoveBlock(lv pl>>PL.CDAT, lv ld>>LD.created, 2) if dprp<<DPRP.RDAT then MoveBlock(lv pl>>PL.RDAT, lv ld>>LD.read, 2) if dprp<<DPRP.WDAT then MoveBlock(lv pl>>PL.WDAT, lv ld>>LD.written, 2) if dprp<<DPRP.SIZE then [ let siz = lv pl>>PL.SIZE let fa = lv ld>>LD.hintLastPageFa let lnBytes = ftpDisk>>DSK.lnPageSize +1 let numPages = fa>>FA.pageNumber -1 if numPages ne -1 then [ siz!0 = numPages rshift (16-lnBytes) siz!1 = numPages lshift lnBytes + fa>>FA.charPos ] ] ] resultis pl ] //----------------------------------------------------------------------------------------- and CheckAccess(pl) = valof //----------------------------------------------------------------------------------------- // If the disk is password protected, then check the password, // otherwise don't (just return true). // Checking the password means: // If there is a password in core, and it matches the password // on the disk, then success (regardless of the password in // the pl - it is assumed that the disk owner has booted // the disk and is controlling access via the server option // switches (noOverwrite, Protected, noServer etc)). // If there isn't a password in core, or it doesn't match the // password in pl, then the password in the pl must equal // the password on the disk. [ if diskPsw eq 0 then [ let sysBoot = OpenFile("Sys.boot", ksTypeReadOnly, wordItem, 0, fpSysBoot) SetFilePos(sysBoot, 0, 1400b) //see Password.bcpl in OS diskPsw = Allocate(sysZone, 9) ReadBlock(sysBoot,diskPsw, 9) Closes(sysBoot) ] if diskPsw!0 then [ let uPsw = defaultPL>>PL.UPSW if uPsw & uPsw>>String.length ne 0 then if Password(uPsw, diskPsw, false) resultis true if pl>>PL.UPSW & pl>>PL.UPSW>>String.length ne 0 then if Password(pl>>PL.UPSW, diskPsw, false) resultis true FTPM(markNo, 21b, "Incorrect User-password") resultis false ] resultis true ]