From 56d8a80761d68c123d55778d73b66268dabd3e34 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Mon, 9 Nov 2009 18:16:08 +0000 Subject: [PATCH 1/1] Initial commit as found --- .gitignore | 14 + crontab | 7 + inews | 43 + inews.test | 43 + stump/LICENSE | 355 ++++++++ stump/README | 25 + stump/bin/acceptFromMod.pl | 155 ++++ stump/bin/activity | 3 + stump/bin/addKey | 8 + stump/bin/antivirus | Bin 0 -> 7300 bytes stump/bin/bogusMessage | 5 + stump/bin/buildNewsgroupsDB | 15 + stump/bin/checkquot | Bin 0 -> 7160 bytes stump/bin/createArchive | 19 + stump/bin/cuthead | Bin 0 -> 7135 bytes stump/bin/decodeBase64 | 62 ++ stump/bin/email-server.pl | 413 +++++++++ stump/bin/isbinary | Bin 0 -> 6758 bytes stump/bin/listKeys | 9 + stump/bin/logArt | 46 + stump/bin/needAck | 69 ++ stump/bin/noAck | 11 + stump/bin/preApprove | 11 + stump/bin/processApproved | 103 +++ stump/bin/processNoack.pl | 39 + stump/bin/processPreapproved | 49 ++ stump/bin/processRejected | 62 ++ stump/bin/report.sh | 53 ++ stump/bin/robomod.pl | 52 ++ stump/bin/send_pgp_key | 21 + stump/bin/stump-pgp | 24 + stump/bin/stump-report.pl | 37 + stump/bin/stump.pl | 22 + stump/bin/submission.pl | 465 +++++++++++ stump/bin/submitFailed | 9 + stump/bin/suspicious.pl | 179 ++++ stump/bin/verifySignature | 60 ++ stump/c/antivirus.c | 101 +++ stump/c/checkquot.c | 54 ++ stump/c/compile | 13 + stump/c/cuthead.c | 38 + stump/c/isbinary.c | 39 + stump/doc/README | 3 + stump/doc/VERSION | 32 + stump/etc/README | 116 +++ stump/etc/my_rnews | 20 + stump/etc/procmailrc | 135 +++ stump/local/README | 580 +++++++++++++ stump/local/bin/pmapp | 301 +++++++ stump/local/bin/pmcanon | 38 + stump/local/bin/pmcheck | 185 +++++ stump/local/bin/pmnewsgroups | 16 + stump/local/doc/PGPMoose.README | 580 +++++++++++++ stump/local/man/man1/pmapp.1 | 90 ++ stump/local/man/man1/pmcanon.1 | 44 + stump/local/man/man1/pmcheck.1 | 83 ++ stump/local/man/man1/pmnewsgroups.1 | 22 + stump/local/src/PGPMoose.shar.gz | Bin 0 -> 16949 bytes webstump/LICENSE | 355 ++++++++ webstump/Makefile | 23 + webstump/README | 40 + webstump/TODO | 1 + webstump/config/convert-newsgroups.sh | 2 + webstump/config/motd | 2 + webstump/demo/error.html | 7 + webstump/demo/login.html | 38 + webstump/demo/main-screen.html | 46 + webstump/demo/password.html | 21 + webstump/demo/review.html | 48 ++ webstump/demo/welcome.html | 18 + webstump/doc/help/bad.posters.list.html | 13 + webstump/doc/help/bad.subjects.list.html | 17 + webstump/doc/help/bad.words.list.html | 21 + webstump/doc/help/filter-lists.html | 48 ++ webstump/doc/help/good.posters.list.html | 20 + webstump/doc/help/good.subjects.list.html | 13 + webstump/doc/help/watch.posters.list.html | 17 + webstump/doc/help/watch.subjects.list.html | 15 + webstump/doc/help/watch.words.list.html | 24 + webstump/images/bg1.jpg | Bin 0 -> 2414 bytes webstump/images/construction.gif | Bin 0 -> 242 bytes webstump/images/help.gif | Bin 0 -> 110 bytes webstump/images/new_tiny2.gif | Bin 0 -> 131 bytes webstump/images/no_image.gif | Bin 0 -> 211 bytes webstump/images/smiley.gif | Bin 0 -> 89 bytes webstump/images/star.gif | Bin 0 -> 115 bytes webstump/images/warning_big.gif | Bin 0 -> 288 bytes webstump/index.html | 22 + webstump/scripts/create-newsgroup.pl | 52 ++ webstump/scripts/file-message.pl | 97 +++ webstump/scripts/filter.lib.pl | 143 ++++ webstump/scripts/gatekeeper-file-message.pl | 42 + webstump/scripts/gatekeeper.lib | 115 +++ webstump/scripts/html_output.pl | 877 ++++++++++++++++++++ webstump/scripts/mime-parsing.lib | 177 ++++ webstump/scripts/strip-ats.pl | 12 + webstump/scripts/webstump.lib.pl | 733 ++++++++++++++++ webstump/scripts/webstump.pl | 44 + webstump/src/Makefile | 8 + webstump/src/wrapper.c | 122 +++ webstump/test/mm-test.pl | 5 + webstump/tmp/demo.happy99.txt | 569 +++++++++++++ webstump/tmp/demo.mime.txt | 845 +++++++++++++++++++ webstump/tmp/demo.text.txt | 33 + xlog/bin/record | 105 +++ xlog/bin/report | 117 +++ 106 files changed, 9885 insertions(+) create mode 100644 .gitignore create mode 100644 crontab create mode 100755 inews create mode 100755 inews.test create mode 100644 stump/LICENSE create mode 100644 stump/README create mode 100755 stump/bin/acceptFromMod.pl create mode 100755 stump/bin/activity create mode 100755 stump/bin/addKey create mode 100755 stump/bin/antivirus create mode 100755 stump/bin/bogusMessage create mode 100755 stump/bin/buildNewsgroupsDB create mode 100755 stump/bin/checkquot create mode 100755 stump/bin/createArchive create mode 100755 stump/bin/cuthead create mode 100755 stump/bin/decodeBase64 create mode 100755 stump/bin/email-server.pl create mode 100755 stump/bin/isbinary create mode 100755 stump/bin/listKeys create mode 100755 stump/bin/logArt create mode 100755 stump/bin/needAck create mode 100755 stump/bin/noAck create mode 100755 stump/bin/preApprove create mode 100755 stump/bin/processApproved create mode 100755 stump/bin/processNoack.pl create mode 100755 stump/bin/processPreapproved create mode 100755 stump/bin/processRejected create mode 100755 stump/bin/report.sh create mode 100755 stump/bin/robomod.pl create mode 100755 stump/bin/send_pgp_key create mode 100755 stump/bin/stump-pgp create mode 100755 stump/bin/stump-report.pl create mode 100755 stump/bin/stump.pl create mode 100755 stump/bin/submission.pl create mode 100755 stump/bin/submitFailed create mode 100755 stump/bin/suspicious.pl create mode 100755 stump/bin/verifySignature create mode 100644 stump/c/antivirus.c create mode 100644 stump/c/checkquot.c create mode 100755 stump/c/compile create mode 100644 stump/c/cuthead.c create mode 100644 stump/c/isbinary.c create mode 100644 stump/doc/README create mode 100644 stump/doc/VERSION create mode 100644 stump/etc/README create mode 100755 stump/etc/my_rnews create mode 100644 stump/etc/procmailrc create mode 100644 stump/local/README create mode 100755 stump/local/bin/pmapp create mode 100755 stump/local/bin/pmcanon create mode 100755 stump/local/bin/pmcheck create mode 100755 stump/local/bin/pmnewsgroups create mode 100644 stump/local/doc/PGPMoose.README create mode 100644 stump/local/man/man1/pmapp.1 create mode 100644 stump/local/man/man1/pmcanon.1 create mode 100644 stump/local/man/man1/pmcheck.1 create mode 100644 stump/local/man/man1/pmnewsgroups.1 create mode 100644 stump/local/src/PGPMoose.shar.gz create mode 100644 webstump/LICENSE create mode 100644 webstump/Makefile create mode 100644 webstump/README create mode 100644 webstump/TODO create mode 100755 webstump/config/convert-newsgroups.sh create mode 100644 webstump/config/motd create mode 100644 webstump/demo/error.html create mode 100644 webstump/demo/login.html create mode 100644 webstump/demo/main-screen.html create mode 100644 webstump/demo/password.html create mode 100644 webstump/demo/review.html create mode 100644 webstump/demo/welcome.html create mode 100644 webstump/doc/help/bad.posters.list.html create mode 100644 webstump/doc/help/bad.subjects.list.html create mode 100644 webstump/doc/help/bad.words.list.html create mode 100644 webstump/doc/help/filter-lists.html create mode 100644 webstump/doc/help/good.posters.list.html create mode 100644 webstump/doc/help/good.subjects.list.html create mode 100644 webstump/doc/help/watch.posters.list.html create mode 100644 webstump/doc/help/watch.subjects.list.html create mode 100644 webstump/doc/help/watch.words.list.html create mode 100644 webstump/images/bg1.jpg create mode 100644 webstump/images/construction.gif create mode 100644 webstump/images/help.gif create mode 100644 webstump/images/new_tiny2.gif create mode 100644 webstump/images/no_image.gif create mode 100644 webstump/images/smiley.gif create mode 100644 webstump/images/star.gif create mode 100644 webstump/images/warning_big.gif create mode 100644 webstump/index.html create mode 100755 webstump/scripts/create-newsgroup.pl create mode 100755 webstump/scripts/file-message.pl create mode 100644 webstump/scripts/filter.lib.pl create mode 100755 webstump/scripts/gatekeeper-file-message.pl create mode 100644 webstump/scripts/gatekeeper.lib create mode 100644 webstump/scripts/html_output.pl create mode 100644 webstump/scripts/mime-parsing.lib create mode 100755 webstump/scripts/strip-ats.pl create mode 100644 webstump/scripts/webstump.lib.pl create mode 100755 webstump/scripts/webstump.pl create mode 100644 webstump/src/Makefile create mode 100644 webstump/src/wrapper.c create mode 100755 webstump/test/mm-test.pl create mode 100644 webstump/tmp/demo.happy99.txt create mode 100644 webstump/tmp/demo.mime.txt create mode 100644 webstump/tmp/demo.text.txt create mode 100755 xlog/bin/record create mode 100755 xlog/bin/report diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0299241 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*~ +/archive +/errs +/errs.[0-9] +/errs.[0-9].gz +/stump/data +/stump/tmp +/webstump/bin/q +/webstump/bin/wrapper +/webstump/config/* +/webstump/queues/*/dir_* +/xlog/log/*/event.log +/xlog/log/*/event.log.[0-9] +/xlog/log/*/event.log.[0-9].gz diff --git a/crontab b/crontab new file mode 100644 index 0000000..602ab06 --- /dev/null +++ b/crontab @@ -0,0 +1,7 @@ +# +# install with +# ssh webstump@chiark crontab live/crontab +# +#m h d m dow +50 7 12 * * savelog live/xlog/log/uk.rec.cycling.moderated/event.log +50 7 12 * * savelog live/errs diff --git a/inews b/inews new file mode 100755 index 0000000..6ee5968 --- /dev/null +++ b/inews @@ -0,0 +1,43 @@ +#!/bin/sh +set -e + +#real=false +real=true + +export NNTPSERVER=nnrp.chiark.greenend.org.uk +export NNTPAUTH='md5cookie1way chiark' + +trap 'rm -f "$tf"' 0 + +tf=`mktemp` + +sed '${ /^$/d }' >$tf + +set +e +output=` + set -e + exec 2>&1 + if $real; then + inews -h -Q -R <$tf + else + (set -e + echo "Newsgroups: chiark.test.moderated" + sed 's/^Newsgroups:/X-Would-Newsgroups:/' $tf) | inews -h + fi +` +rc=$? +set -e + +if [ $rc = 0 ] +then + echo 'posted ok!' + $HOME/live/xlog/bin/record posted uk.rec.cycling.moderated <$tf + exit 0 +fi + +( + printf "Errors: %s" "$output" + echo + echo ====================== + cat $tf +) | mail -s 'lost moderated newsgroup submission' webstump diff --git a/inews.test b/inews.test new file mode 100755 index 0000000..6ee5968 --- /dev/null +++ b/inews.test @@ -0,0 +1,43 @@ +#!/bin/sh +set -e + +#real=false +real=true + +export NNTPSERVER=nnrp.chiark.greenend.org.uk +export NNTPAUTH='md5cookie1way chiark' + +trap 'rm -f "$tf"' 0 + +tf=`mktemp` + +sed '${ /^$/d }' >$tf + +set +e +output=` + set -e + exec 2>&1 + if $real; then + inews -h -Q -R <$tf + else + (set -e + echo "Newsgroups: chiark.test.moderated" + sed 's/^Newsgroups:/X-Would-Newsgroups:/' $tf) | inews -h + fi +` +rc=$? +set -e + +if [ $rc = 0 ] +then + echo 'posted ok!' + $HOME/live/xlog/bin/record posted uk.rec.cycling.moderated <$tf + exit 0 +fi + +( + printf "Errors: %s" "$output" + echo + echo ====================== + cat $tf +) | mail -s 'lost moderated newsgroup submission' webstump diff --git a/stump/LICENSE b/stump/LICENSE new file mode 100644 index 0000000..5107f64 --- /dev/null +++ b/stump/LICENSE @@ -0,0 +1,355 @@ +What this legalese means is basically two things: + +1) There is NO WARRANTY +2) You are free to copy and modify this program as long as you do +not impose more restrictive terms on its copying. + +igor + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place - +Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom +to share and change it. By contrast, the GNU General Public License is +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. This General Public +License applies to most of the Free Software Foundation's software and +to any other program whose authors commit to using it. (Some other Free +Software Foundation software is covered by the GNU Library General Public +License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone +to deny you these rights or to ask you to surrender the rights. These +restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And +you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, +we want its recipients to know that what they have is not the original, +so that any problems introduced by others will not reflect on the original +authors' reputations. + +Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, either +verbatim or with modifications and/or translated into another language. +(Hereinafter, translation is included without limitation in the term +"modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +the Program is not restricted, and the output from the Program is covered +only if its contents constitute a work based on the Program (independent +of having been made by running the Program). Whether that is true depends +on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously +and appropriately publish on each copy an appropriate copyright notice +and disclaimer of warranty; keep intact all the notices that refer to +this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of +it, thus forming a work based on the Program, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any part + thereof, to be licensed as a whole at no charge to all third parties + under the terms of this License. + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive + use in the most ordinary way, to print or display an announcement + including an appropriate copyright notice and a notice that there + is no warranty (or else, saying that you provide a warranty) and + that users may redistribute the program under these conditions, and + telling the user how to view a copy of this License. (Exception: if + the Program itself is interactive but does not normally print such + an announcement, your work based on the Program is not required to + print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be +reasonably considered independent and separate works in themselves, +then this License, and its terms, do not apply to those sections when +you distribute them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the Program, the +distribution of the whole must be on the terms of this License, whose +permissions for other licensees extend to the entire whole, and thus to +each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works +based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of a +storage or distribution medium does not bring the other work under the +scope of this License. + +3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections 1 + and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, + to give any third party, for a charge no more than your cost of + physically performing source distribution, a complete machine-readable + copy of the corresponding source code, to be distributed under the + terms of Sections 1 and 2 above on a medium customarily used for + software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed + only for noncommercial distribution and only if you received the + program in object code or executable form with such an offer, in + accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the executable. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major components +(compiler, kernel, and so on) of the operating system on which the +executable runs, unless that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access +to copy from a designated place, then offering equivalent access to +copy the source code from the same place counts as distribution of the +source code, even though third parties are not compelled to copy the +source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt otherwise +to copy, modify, sublicense or distribute the Program is void, and will +automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will +not have their licenses terminated so long as such parties remain in +full compliance. + +5. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute +the Program or its derivative works. These actions are prohibited +by law if you do not accept this License. Therefore, by modifying or +distributing the Program (or any work based on the Program), you indicate +your acceptance of this License to do so, and all its terms and conditions +for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further restrictions +on the recipients' exercise of the rights granted herein. You are not +responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License +and any other pertinent obligations, then as a consequence you may not +distribute the Program at all. For example, if a patent license would +not permit royalty-free redistribution of the Program by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any such +claims; this section has the sole purpose of protecting the integrity of +the free software distribution system, which is implemented by public +license practices. Many people have made generous contributions to the +wide range of software distributed through that system in reliance on +consistent application of that system; it is up to the author/donor to +decide if he or she is willing to distribute software through any other +system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original +copyright holder who places the Program under this License may add an +explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail +to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Program does not specify a version +number of this License, you may choose any version ever published by +the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software +and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK +AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING +BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY +HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + +one line to give the program's name and an idea of what it does. +Copyright (C) 19yy name of author + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision +comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is +free software, and you are welcome to redistribute it under certain +conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the commands +you use may be called something other than `show w' and `show c'; they +could even be mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the program, +if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program +`Gnomovision' (which makes passes at compilers) written by James Hacker. + +signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice + +This General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications +with the library. If this is what you want to do, use the GNU Library +General Public License instead of this License. + +Return to GNU's home page. + +FSF & GNU inquiries & questions to gnu@gnu.org. Other ways to contact +the FSF. + +Comments on these web pages to webmasters@www.gnu.org, send other +questions to gnu@gnu.org. + +Copyright notice above. Free Software Foundation, Inc., 59 Temple Place - +Suite 330, Boston, MA 02111, USA + +Updated: 16 Feb 1998 tower + diff --git a/stump/README b/stump/README new file mode 100644 index 0000000..756d768 --- /dev/null +++ b/stump/README @@ -0,0 +1,25 @@ +STUMP is a free robomoderator program for moderators of USENET +newsgroups and mailing lists. + +STUMP is covered by the GNU Public License (see file LICENSE). This means +that you can use this code as you see fit, however I am not liable for +any damages whatsoever that can result in connection with your use of +this program. + +For installation instructions and general information, please see + + http://www.algebra.com/~ichudov/stump/ + +Note that even though STUMP is free, for those without Unix background +or a Unix account I provide commercial moderation bot hosting. See the +webpage for details. + +If you have installation questions (and even if you do not), please +join the stump-users mailing list. To subscribe, send email to +majordomo@algebra.com, saying (in the message body) + +subscribe stump-users + +Send your messages to the mailing list to stump-users@algebra.com. I +monitor this list and try to answer questions. Along with your questions, +please tell us the name of your newsgroup. diff --git a/stump/bin/acceptFromMod.pl b/stump/bin/acceptFromMod.pl new file mode 100755 index 0000000..9927f5c --- /dev/null +++ b/stump/bin/acceptFromMod.pl @@ -0,0 +1,155 @@ +# +# This script accepts an email from moderators and processes +# an approval or a rejection. +# + +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "\$MNG_ROOT is not defined"; + +$Prefix = $ENV{'BOT_SUBJECT_PREFIX'} + || die "\$BOT_SUBJECT_PREFIX is not defined"; + +$MessageNumber = ""; +$Error = ""; + +####################################################################### +# notifies the bot supporter +# +sub processError { + $msg = pop( @_ ); + +print STDERR "Approval error: " . $msg . "\n"; + + if( $MessageFile && -r $MessageFile ) { + system( "suspicious no NOTICE: This message is being RE-SENT to you because of the following error in your approval: $msg < $MessageFile" ); + } else { + print STDERR "ERROR: Completely bogus approval from $From, $msg\n"; + } + + exit 1; +} + +####################################################################### main +# handling headers +# +while( ) { + + chop; + + if( /^$/ ) { + goto after_header; + } + + if( /^Subject: /i && !$Subject ) { + + $Subject = $_; + $Subject =~ s/^Subject: //i; + + if( /::$Prefix\// ) { + + $MessageNumber = $Subject; + $MessageNumber =~ s/^.*::$Prefix\///; + $MessageNumber =~ /(\d+)/; + $MessageNumber = $1; + + $MessageFile = "$MNG_ROOT/tmp/messages/$MessageNumber"; + + if( !($MessageNumber =~ /[0-9]+/) || !(-r $MessageFile) ) + { + $Error = "Message number in subject incorrect"; + } + + } else { + $Error = "no message number"; + } + + } elsif ( /^From: /i ) { + $From = $_; + $From =~ s/^From: //i; + } +} + + +after_header: + +&processError($Error) if( $Error ); + +# +# Now we are looking at the body +# + +$done = ""; +$command = ""; +$comment = ""; + +while( ) { + + chop; + + if( /preapprove/i ) { + $command = "processPreapproved xxx"; + $done = "yes"; + goto after_body; + } + + if( /approve/i ) { + $command = "processApproved xxx "; + $done = "yes"; + goto after_body; + } + + if( /reject/i ) { + + $reason = $_; + $reason =~ s/^.*reject //i; + $reason =~ s/( |`|'|"|;|\.|\/|\\)//g; + &processError( "wrong rejection reason" ) if( !$reason ); + + &processError( "Wrong rejection reason" ) + if( !( -r "$MNG_ROOT/etc/messages/$reason" ) + && ($reason ne "custom") + ); + + $command = "processRejected xxx $reason"; + + $done = "yes"; + goto after_body; + } +} + +after_body: +print STDERR "After body\n"; + +&processError( "No Command Specified" ) if( !$command ); + +while( <> ) { + if( /^comment/ ) { + s/^comment//; + $comment = $_; + $comment .= $_ while( <> ); + } +} + +print STDERR "Comment is: $comment\n" if( $comment ); + +$ENV{'EXPLANATION'} = $comment; + +open( COMMAND, "| $command" ) || &processError( "$command failed" ); + + open( MESSAGE, "$MessageFile" ) || &processError( "Can't open $MessageFile" ); + print COMMAND while( ); + close( MESSAGE ); + +# if( $comment && !($command =~ '^processRejected') ) { +# print COMMAND +# "\n======================================= MODERATOR'S COMMENT: \n" . +# $comment; +# } +#close( COMMAND ); + +&processError( "No action specified" ) + if( $done ne "yes" ); + +unlink( $MessageFile ); + + +1; diff --git a/stump/bin/activity b/stump/bin/activity new file mode 100755 index 0000000..f8d008e --- /dev/null +++ b/stump/bin/activity @@ -0,0 +1,3 @@ +#!/bin/sh + +grep '^Activity' < $HOME/Mail/from | less diff --git a/stump/bin/addKey b/stump/bin/addKey new file mode 100755 index 0000000..69da919 --- /dev/null +++ b/stump/bin/addKey @@ -0,0 +1,8 @@ +#!/bin/sh + +# $Id: addKey,v 1.2 2007/05/03 23:47:11 rram Exp $ +# Modified to work with GPG + +PUBRING=$MNG_ROOT/data/pubring.gpg + +gpg --import --armor --no-default-keyring --keyring $PUBRING diff --git a/stump/bin/antivirus b/stump/bin/antivirus new file mode 100755 index 0000000000000000000000000000000000000000..a513c35650b5ca947f1bdfebde67f651d7d34591 GIT binary patch literal 7300 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 + +cat | mail -s "Bogus Message" $ADMIN diff --git a/stump/bin/buildNewsgroupsDB b/stump/bin/buildNewsgroupsDB new file mode 100755 index 0000000..d8b5323 --- /dev/null +++ b/stump/bin/buildNewsgroupsDB @@ -0,0 +1,15 @@ +#!/usr/bin/perl + +$DataDir = $ENV{'MNG_ROOT'} . "/data"; +$NewsgroupsDBFile = "$DataDir/Newsgroups"; + +# Open message-ID database +dbmopen( %NewsgroupsDB, "$NewsgroupsDBFile", 0644 ); + + +while( <> ) { + ($group, $q1, $q2, $flag) = split; + $NewsgroupsDB{$group} = $flag; +} + +print "test: $NewsgroupsDB{'soc.culture.russian'}.\n" diff --git a/stump/bin/checkquot b/stump/bin/checkquot new file mode 100755 index 0000000000000000000000000000000000000000..dcda917a4e3c22935138059ec53c0c1312a45c19 GIT binary patch literal 7160 zcmdT}eQaCR6~FKKIZbJ3o3udrcGk2M(Yz$3l(xWVlekSG(6mjVP})}~ez83qJJ`=% zIzc~h0t72lG(ek>n5aM#+Lw?vp#l>t3L;|yt>Z5!E9*3>xipiC)FB21@Atd+-NbH( z1lnIa$$9tw?m73KbH6{lFWkA#Fbtu|6agX8kX5}LiPjt?SuR3ihFBsRM7^j&5@pNx zLkD~uadHrBfdk!tTUVsb@VA`eJ zL@)^bLCDBQfXS5826+kem%uhT1WeYlO((o4;CZC;HzgB2P046uGLgy++S#HGRSx5~WqgL$gKtn&rnnP9jkZ6S~ZS0qu7d00>ClbD}rlu?he{Y#{~GVPbQ|NU@m zYlNmNNSDdP5O_5spa&qRLwK7+LcHu_+sCMil!tx1(8p_he7TRW_3@WJz6@dKqgFNB zuvW~G{r})kG+rQtmJXG^8h@Vj2HcokBMi%@KF3}tQG{?>TuhA!kRE$YUXc}k0D zInLlp=~+BP{H(6nd}{IWVF?IjvA%;!xSs^RYx=bcr(ZnjQktc_8sG+yT$15 zuAx54&ren#^q@O@*sD9lG(=`jSPe`o9eHbfY_zk%g3F}`&O&?Bfyp<}HzT9nUzAD{ z;nU185uRjls;&^8oERGRAR*3&CyfISO)|dsL}8d2@+*zKR~4ROw9snh4_gH>Vl@?U)FkVNFh1`S2N|5I!^KrJX{e8@(_xI?R&k%>7?t zEFaE2TnL}ODg4piHr>80Xy1Zr->wg=hS6w)^+EXbU+#GC{kM*u{Oj?b?yf<%VdRVA z9+Xht{BJ_QiWGN2P(HxWqZkg};55&hQ0y;x^@ z95$Z@{~Y`Z_>bVD;E%ytN33saTOC@`?)D@isnBx!dV5)8i`{aqii-bZG0rQfq$x)6 z#o`2FAAbiS`$QEM!kJ#SWE_T{r{jXGm4=B(KuX3hF8lF*ud6rF&zkEv+8 zqS8*B+`%ZW5?3Sh>tBxQ#pIG z(C$t5_q%8xJL>l2VooFzNyS{2BH=);2L(*yM5-^XWs#nqjJsPST;t$^%7rG;QNK9d zz~3O`-H79kgInHh0m|2MIVK_F#Kg5g>d8AO1R-EeYNZ$A1|)E5vpnwk9nibkPeUMg z1nRbcKgGUGJ)Q}Mpx1yn^OC4Tz6s280rhxRcmaCPBF?h|qEd%@e;YUemUgk%cOZh< zHAU1VaqZ^0fOC^WbOhyM=;K_#M_88BVKM7P{hEvX30D}i=2fX{n6#I z4jl0GMeFhGQUhnX^-zy{me$*YIDMrZ&YO1V(XJ-ykvPS)9_Nk+z5NvUL_P98u+|gY zEs?mC4doMkB@KhM9_Q&&boLceqCPB(Q~*t;aKKC-jz3!6)jFC%{_IgPsRH{7;cC`yHe(opyOsdJur) zM3dHg7YQs+6ZPKL0HKzBP!^|n8wO(+BR**#J_go#D0%^Ui+mjhTK0KaoaygCZ=V*H z$@msgmMl6knYnLk(lWlS={RMtLXQs&nshYe>oxm=<7kxUv=Tz`IuB&-0lKjwlt$IHum@=}cJvW&VssGUb# zf0^jNR?4?Ng;fDuPZd@cxNa(}Mg!MJh1KfAJC?#6>1w@G7=s-Q(bb^jUW#o`38uCFj_#i!@snV495JQ(JDQ3tI1 zJA@a5D}nhI$eB?G`;EYIKlJf(VxK|?+s?sv19SYcefU%-N`aoV~!Zgx61Z0W{3yW_N1pxfHY zMA5VpOQw4wNk^W%ok(s_;8Z=3bUim}-*98|3PFLBhz=616!N(4M05T9d$gVKo$b=h zy3K3v2s;|ljE+xRk;i;xCGPg#|3D6>dN{nkb7Sk;PG{q~bz8#SPWRf@&M+Nk^>C`s zMD{ptDq5K!e?|~a`#pEAy<Q%I$k`Ny5H^@6!O;;+3w;$vNd4~ literal 0 HcmV?d00001 diff --git a/stump/bin/createArchive b/stump/bin/createArchive new file mode 100755 index 0000000..13fde59 --- /dev/null +++ b/stump/bin/createArchive @@ -0,0 +1,19 @@ +#!/bin/sh + +DATE="`date +%y%m%d`" + +ArchFile() { + FILE=$1 + DEST=$MNG_ROOT/archive/old/$FILE.$DATE + mv $MNG_ROOT/archive/$FILE $DEST + gzip -9 $MNG_ROOT/archive/old/$FILE.$DATE + chmod 644 $DEST.gz + ln -fs $DEST.gz $MNG_ROOT/archive/old/$FILE.current +} + +ArchFile approved +ArchFile rejected +ArchFile incoming + +echo New copy of archive has been created. Please update your home page \ + | mail $ADMIN diff --git a/stump/bin/cuthead b/stump/bin/cuthead new file mode 100755 index 0000000000000000000000000000000000000000..5469dfc518a3ee221aaccc3c97ee131e78b8a38c GIT binary patch literal 7135 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 u{@L)C>B-~o3`d^N_&) { + chop; + + last if( /^$/ ); + + $FullHeaders .= "$_\n"; + + if( /^Content-Transfer-Encoding: BASE64/i ) { + + $isEncoded = 1; + $switch = "-b"; # base64 - default + + } elsif( /^Content-Transfer-Encoding: quoted-printable/i ) { + + $isEncoded = 1; + $switch = "-q"; # quoted-printable + + } elsif( ! /^Mime-Version: /i && ! /Content-Type: /i ) { + $DecodedHeaders .= "$_\n"; + } +} + +# body + +if( !$isEncoded ) { + print $FullHeaders . "\n"; + while( <> ) { + print; + } + exit 0; +} + +print $DecodedHeaders . "\n"; + +if( $ENV{'TMP'} ) { + $TmpFile = "$ENV{'TMP'}/letter.$$"; +} else { + $TmpFile = "/tmp/letter.$$"; +} + +open( DECODE, "|mimencode -u $switch > $TmpFile" ) + || die "Can't run mmencode writing to $TmpFile"; + + while( <> ) { + print DECODE; + } +close( DECODE ); + +open( DECODED, $TmpFile ) || die "Can't open just decoded file $TmpFile"; + while( ) { + print; + } +close( DECODED ); + +unlink( $TmpFile ); diff --git a/stump/bin/email-server.pl b/stump/bin/email-server.pl new file mode 100755 index 0000000..c54de15 --- /dev/null +++ b/stump/bin/email-server.pl @@ -0,0 +1,413 @@ +#!/usr/bin/perl +###################################################################### +# This perl script is a file server. It allows users +# to retrieve and alter certain files. +# Its purpose is to allow them to manage their installations +# without the need to log in remotely and without the need to know +# anything about Unix(tm). +# +# It only allows retrieving and updating files that have been +# explicitly mentioned as available in its configuration file. +# +# USAGE: +# +# First, you have to come up with a password (I strongly suggest using +# a password that is DIFFERENT from your regular Unix password). +# +# Save it in file $HOME/.email-server.pwd +# +# Second, create a file $HOME/.email-server.cfg and list files (and their +# optional text descriptions) like this: +# +# stump-faq tmp/stump-users-faq.txt FAQ for STUMP users +# rw:mydir some/dir/mydir Directory with test files +# +# The syntax of this file is as follows: +# +# [mode:]filehandle fullpath comment +# +# where mode is either r or rw. r means read only (which is the +# default mode that is used if no mode is mentioned], and rw means that +# the file can be both read and changed. +# +# filehandle is the "external" name by +# which the file will be known to the email user. It may be different from +# the actual file name. +# +# fullpath is the actual path to the file or directory that you want +# to make available, RELATIVE to your home directory. +# +# This script is supposed to be called from your .procmailrc. To recognize +# your requests to this script from other emails, perhaps you could send +# them with a different To: address, for example you could always use +# +# To: your@email.address (Email File Server) +# +# and then use a procmail recipe like +# +# :0: +# * ^To: .*Email File Server +# | email-server.pl +# +# Copyright(C) 1998 Igor Chudov, ichudov@algebra.com, +# +# http://www.algebra.com/~ichudov. +# +# GNU Public License applies. +# There is NO WARRANTY WHATSOEVER. USE THIS PROGRAM AT YOUR OWN RISK. +# +###################################################################### + +sub read_config { + my $config_file = "$SERVER_ROOT/.email-server.cfg"; + open( CONFIG, $config_file ) + || die "Config file $config_file not found."; + while( ) { + chop; + if( ! /^#/ ) { + my ($mode_handle, $file, @explanation) = split; + + my $mode = "r", $handle = $mode_handle; # if no mode is present that's + # the default + + if( $mode_handle =~ /:/ ) { + ($mode, $handle) = split( /:/, $mode_handle ); + } + + print STDERR "File $file served by email server does not exist in $SERVER_ROOT\n" + if( ! -e "$SERVER_ROOT/$file" ); + + print STDERR "Mode must be rw or r" + if( $mode ne "r" && $mode ne "rw" ); + + $served_files{$handle} = $file; + $explanations{$handle} = join( " ", @explanation ); + $file_modes{$handle} = $mode; + } + } + close( CONFIG ); +} + +sub init { + + die "HOME is not defined!!!" + if not defined $ENV{'HOME'}; + + $SERVER_ROOT = $ENV{'HOME'}; + + &read_config; + open( PASSWORD, "$SERVER_ROOT/.email-server.pwd" ); + $password = ; + chop $password if( $password =~ /\n$/ ); + close( PASSWORD ); + + if( defined $ENV{'EMAIL_SERVER_ADDRESS'} ) { + $email_server_address = $ENV{'EMAIL_SERVER_ADDRESS'}; + } else { + $email_server_address = "bad_address\@stump.algebra.com (WRONG ADDRESS)"; + } + + my @sendmail_dirs = ("/bin", "/usr/bin", "/usr/sbin", "/usr/lib" ); + + $sendmail = "/bin/mail"; # last resort... + + foreach (@sendmail_dirs) { + $sendmail = "$_/sendmail" + if( -x "$_/sendmail" ); + } + + $short_help = "\nSend email with 'help' in subject field to receive an\n" . + "explanation on how to work with this email server.\n"; + $long_help = " + +Hi there, + +Thanks for asking for help! Here it is. + +I am an automated email server. I am here to help you manage your files +remotely without the need to log in and use Unix commands to edit your +configuration files. + +You can retrieve this help message by sending me an email with the only +word 'help' in the Subject: field of your message. + +I process your commands. I do a limited set of simple tasks, such as +retrieving and modifying text configuration files. Only certain files +can be retrieved and modified; this is done for your own security. + +Whenever you retrieve a file or want to modify a file, you will have +to provide a password to me, as well as the command that I will execute. +Passwords are used to ensure that only authorized users can perform +important operations; however, anyone can request and receive this +help message. + +IF YOU DO NOT KNOW THE PASSWORD, you have to ask the +administrator of my account to provide you with one. + +All commands, along with passwords, should be specified in the Subject: +field of your messages. A password always goes first, followed by the +command. For example, if your password is 'xyzzy' and the command is +'get moderators' (more on commands later), then the Subject: field +should be + + Subject: xyzzy: get moderators + +Both commands and passwords are NOT case sensitive. You can mix uppercase +with lowercase as you wish. + +COMMANDS: + +Right now, there are three kinds of commands: + +1. help. This command requests help. Requires no password. + +2. get filename. This command requests a file to be sent from the + server to you. The body of your message is ignored. + + Example (assuming your password is xyzzy): + + Subject: xyzzy: get bad.guys.list + + Note that for certain files, their \"names\" may consist of + directory name, followed by a \"/\" (slash) character and the name + of the file. For example, a get command may be of form: + + Subject: xyzzy: get messages/offtopic + +3. set filename. This command requests that the contents of the file be set + to the text in the body of your message. + + Example (assuming your password is xyzzy): + + Subject: xyzzy: set bad.guys.list + + spammer\@cyberpromo.com + flamer\@netcom.com + + + Note that for certain files, their \"names\" may consist of + directory name, followed by a \"/\" (slash) character and the name + of the file. For example, a set command may be of form: + + Subject: xyzzy: set messages/offtopic + + Thanks for submitting your article to comp.sys.foobars.moderated. Your + article is offtopic and is being rejected. Have a nice day! + +FILES THAT CAN BE RETRIEVED AND CHANGED. + +The following are the file names (that you can mention in set and get +commands) that are supported by this installation: + +NAME OF FILE Explanation + +"; + + foreach( keys %served_files ) { + $long_help .= $_ . substr( " ", length( $_ ), 100 ); + + my $mode = $file_modes{$_}; + if( $mode eq "r" ) { $long_help .= "(Read-Only) "; } + else { $long_help .= "(Read-Write) "; } + + $long_help .= $explanations{$_} . "\n"; + + my $file = "$SERVER_ROOT/$served_files{$_}"; + + if( ! -e $file ) { + $long_help .= "(this file does NOT exist)\n"; + } elsif( -d $file ) { + $long_help .= "$_ is a DIRECTORY. Available files are: \n"; + opendir( DIR, $file ); + my $dir = $_; + my $fn; + while( $fn = readdir( DIR ) ) { + my $file1 = "$file/$fn"; + if( ! /^\./ && -f $file1 && -r $file1 ) { + $long_help .= "\t$dir/$fn\n"; + } + } + closedir( DIR ); + } + } +} + +sub reply { + my $msg = pop( @_ ); + + my $address = $From; + $address =~ s/^From: //i; + + if( defined $ReplyTo ) { + $address = $ReplyTo; + $address =~ s/^Reply-To: //i; + $address =~ s/`//g; + $address =~ s/;//g; + } + + open( SENDMAIL, "|$sendmail '$address'" ) + || die "Could not start sendmail in $sendmail"; + + print SENDMAIL "From: $To\n"; + print SENDMAIL "To: $address\n"; + print SENDMAIL "Subject: Re: $Subject\n"; + + print SENDMAIL "\n"; + + print SENDMAIL "$msg\n"; + + close( SENDMAIL ); + +} + +sub user_error { + my ($msg) = pop( @_ ); + &reply( "You made a mistake:\n\n$msg\n$short_help\n" . + "Message Follows:\n\n$Headers\n$Body\n" ); + exit 0; +} + +sub readMessage { + + while() { + s/^From />From /; + last if( /^$/ ); + $Headers .= $_; + chop; + if( /^Subject: / ) { + $Subject = $_; + $Subject =~ s/^Subject: //; + $Subject = "\L$Subject"; + } elsif( /^From: / ) { + $From = $_; + $From =~ s/^From: //; + } elsif( /^To: / ) { + $To = $_; + $To =~ s/^To: //; + } elsif( /^Reply-To: / ) { + $ReplyTo = $_; + $ReplyTo =~ s/^Reply-To: //; + } + } + + while( ) { + s/^From />From /; + $Body .= $_; + } +} + +sub file_from_arg { + my $arg = pop( @_ ); + + if( $arg =~ /\// ) { + my ($dir, $file) = split( /\//, $arg ); + # now clean $file + $file =~ s/\///g; + $file =~ s/^\.//g; + + if( defined $served_files{$dir} ) { + my $fullpath = "$SERVER_ROOT/$served_files{$dir}/$file"; + return $fullpath if( -f $fullpath ); + } + + } else { + if( defined $served_files{$arg} ) { + my $fullpath = "$SERVER_ROOT/$served_files{$arg}"; + return $fullpath if( -f $fullpath ); + } + } +} + +sub mode_from_arg { + my $arg = pop( @_ ); + if( $arg =~ /\// ) { + my ($dir, $file) = split( /\//, $arg ); + return $file_modes{$dir} if( defined $file_modes{$dir} ); + } else { + return $file_modes{$arg}; + } +} + +sub command_get { + my $arg = pop( @_ ); + my $file = &file_from_arg( $arg ); + + &user_error( "File $arg is not in the list of available files. Perhaps\n" . + "it is a directory or maybe you just misspelled its name." ) + if( !$file ); + + if( -r $file ) { + + my $reply_body = ""; + + open( FILE, $file ); + $reply_body .= $_ while( ); + close( FILE ); + + &reply( $reply_body ); + + } else { + &user_error( "File $arg does not exist or is not readable" ); + } +} + +sub command_set { + my $arg = pop( @_ ); + + my $file = &file_from_arg( $arg ); + my $mode = &mode_from_arg( $arg ); + + &user_error( "File $arg is not in the list of available files." ) + if( !$file ); + + if( -w $file && -f $file && $mode eq "rw" ) { + + my $reply_body = "Succeeded in writing to file '$arg':\n\n$Body"; + + if( open( FILE, ">$file" ) ) { + print FILE $Body; + close( FILE ); + } else { + $reply_body = "Failed to write to file $arg:\n\n$Body"; + } + + &reply( $reply_body ); + + } else { + &user_error( "File $arg does not exist or is not writable" ); + } +} + +sub main { + &init; + &readMessage; + &user_error( "No Subject: field provided in your message" ) if( !$Subject ); + + if( $Subject =~ /^help/ ) { + &reply( $long_help ); + } elsif( $Subject =~ /:/ ) { + my ($pass, $command) = split( /:/, $Subject ); + + &user_error("Invalid Password") if( "\L$pass" ne "\L$password" ); + + $command =~ s/^ +//; + + my @command = split / /, $command; + $command = shift @command; + $command = "\L$command"; # lowercase + + my $argument = shift @command; + $argument = "\L$argument"; + + if( $command eq "get" ) { + &command_get( $argument ); + } elsif( $command eq "set" ) { + &command_set( $argument ); + } else { + &user_error( "Invalid command: $command" ); + } + } +} + +###################################################################### +&main; diff --git a/stump/bin/isbinary b/stump/bin/isbinary new file mode 100755 index 0000000000000000000000000000000000000000..5fec6971ca69e8113648ad06808f0e519697e9cf GIT binary patch literal 6758 zcmdT|eQaCR6~FJ78FFqq-}+NrZI$=Ry23bv`z{r8Xey6ckjE& zb6X_P{@SsQ&pjXaoO3_lz4usjaHnAyLW3y+g4{$Y7~Tx})GDRfEFz*-w2M~JB5EL_ zZu10efbXJA3;~0{0I&&8nw|)TiR-`oO142?NhXOZ|Dwll@%ZOJX@4E?!X)|`v{9@PH-kpLulZ&nY&$uc z%i0AumUnGiplgQNC0m6(um{paI%^jTPD03{7)d&A0p)zg$&w7G^6c2%vDf+3O*h<^!j{d%XxUL zv@PPFbt-L)lw$GhyQo%aW5g77XHQF>kyA|j?40D8K?)rx&YqM!Gf73rKMfvKLf1bY zp88Aa%=x_s_NTfr4ynEP+joCz^EZOw@~>dHI9ml?J0|XIg*#E~p1!Ibg%=u-Oh-Nb zURg3{9;j@8t8nAY^9(T4Ydk}XO4B6O%6$7<`MwTq#)>F|%+MS9nk(|2<#@%pU zu0{T(C1cI;ryxGTA)D%N4WH_74T^4Lns};wU zX*1)6)Tnii;&VrZPAGoDU+K z^2lv z9j7yW>$a^p5yXc(hYQ8d;k=u+hCWHX6=$d?aCC_D3`I6sUEA>WGbUmPZpy9*8gHN+ zVKVOMSm*F?*WLqrZ%bN*|2>G&Xtb?fR~J}){pvL;I$Q31s3n=~>@-8jB4~<`$%PPD5T4Ggfqbvbbi-vc#aJQK%3vWJy3gct z3EXJ3w6vHw(HM|$;RHICC7cL--iA_0tVxr$H^`4Twwfrxtx>Gabe=fEbZjo2#N@J4Qi(sVhaRZ+Vsb7{oSzReUCB% z?TB5#5AZ#v9nS)f!LAkMi|y`!jOPK`@r>{^>?Tm=nE^%Vi{Jb{U;s!vo+%L&kro~3^9vB1Z96*up$ZMX_9t4gPcUc?~iTegvUx> zw&R&)4tDL3F)qJZ+HM?W=E^u+H)YsuL|Fsv2wY;?j%%kGjemp+4`@d`2Gn-Emrua% zOH9@S=1Q0ZYCEpew~^R-sZoDA?zCq|7hJ1Luv=cxkZHRoeRkqF);t=dbxz1A4k|fkc(&u4z-dngBJ*P&F9O*w%#ZiS z@@4$7UBC9(@vOQ4y9i_&XhS>&)c)#m-KfW+x?FpI2Rq6cmzSR=*hRX*co6aEo1pZk zfp&k=45-%q*;l6eJnZ(e;DOHJ@8ESEs=A?Q^K3}8?%%#L29V#KrC=s7rw&EXmC43u`n&wF-S6~Q9w)(og_FYgZQV-1hM zZaW=#po^rwWg~WAlYAEgdK2VZfgIZgAol{lzxB;R+~cdL{lV-K;QmXYdPP%jP>NR$ zxSuLsMc}@vct%(IqvEkB0o(@_&zUadey4a0K7jk0;w6#$m*Uw9A@5d-=gmy*M~X+M z1Gw)fo;w))FY~~<9MM0^JO;@J0dcL5V}5+;T7iJzS91jdRXZi^ zd4OGkfZ!X^3IqgiA}bIO5jkhIBq;t>k%@W&^8Rl!d3xl2NfQIN;afm;e;Ih4yB)ml zF9TonUEoi8<70|d^4cIDab*2wkpbmf4`-4gn#I>Z8}N<P*1+#~}~<;&Z>3 z`#cC=;ZA`1xIq6S`H^4V|^R>~uM!ZAb>;Fb`tvCms z&wmd|`&HsY@J*h51NxKio1E_||7Ot)zWa|VU+QllPy24RuUWK!_t$R+{}bIlbCvi4 zc)l}Ui8$=Pe(*f6AUt^N58kza#JfM?QdMw^BO|y<*>>N7J^Ss!fuRF<7q;#GD(;>> zpDK~FlbKvRma*kY+m02F3Y?xzNoD^hSBAfDDqe@qofP*bT*bBXTG}z_w@D*+Ix2H9Eu*W5A^g7MwvHTheLcm zHf}rFM72P^dJDV%!QDOg4fF|K0@OP;%;cjs?)0|2Tr7*LUd!!!j@bL1WV(QhPG2Tg zDBxaTkBr%=uX>N;-Q6p1;mVPGL9Y^D{Cr-etbT;IZC{GGQ{WZ8%Gyp8a&{_~O=KLj zK#rL1z2)YxKcK`_$7_>(*{^cLeu@`Igzd;{5&CfJwyhSP{_U}0+f5a-U$Npxg?#Fl H-7EeJHk`Az literal 0 HcmV?d00001 diff --git a/stump/bin/listKeys b/stump/bin/listKeys new file mode 100755 index 0000000..78f691c --- /dev/null +++ b/stump/bin/listKeys @@ -0,0 +1,9 @@ +#!/bin/sh + +# $Id: listKeys,v 1.2 2007/05/03 23:47:32 rram Exp $ +# Modified to work with GPG + +PUBRING=$MNG_ROOT/data/pubring.gpg + +gpg --list-keys --no-default-keyring --keyring $PUBRING + diff --git a/stump/bin/logArt b/stump/bin/logArt new file mode 100755 index 0000000..13ddaf3 --- /dev/null +++ b/stump/bin/logArt @@ -0,0 +1,46 @@ +#!/usr/bin/perl + +$MNG_ROOT=$ENV{'MNG_ROOT'}; + +$date = `date`; chop $date; + +print STDERR "Activity: $date $ARGV[0] "; shift @ARGV; + +###################################################################### +# Getting data +sub readMessage { + $IsBody = 0; + + while( <> ) { + + chop; + + if( /^$/ ) { + $IsBody = 1; + } + + if( !$IsBody ) { + + if( /^Newsgroups: / ) { + $Newsgroups = $_; + } elsif( /^Subject: / ) { + $Subject = $_; + } elsif( /^From: / ) { + $From = $_; + } elsif( /^Path: / ) { + $Path = $_; + } elsif( /^Keywords: / ) { + $Keywords = $_; + } elsif( /^Summary: / ) { + $Summary = $_; + } elsif( /^Message-ID: / ) { + $Message_ID = $_; + } + + } + } +} + +&readMessage; + +print STDERR "$Message_ID, $Subject from $From \n"; diff --git a/stump/bin/needAck b/stump/bin/needAck new file mode 100755 index 0000000..9b464d3 --- /dev/null +++ b/stump/bin/needAck @@ -0,0 +1,69 @@ +#!/usr/bin/perl +# + +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +require "$MNG_ROOT/bin/robomod.pl"; + +###################################################################### checkAck +# checks if poster needs ack +sub checkAck { + + $needAck = ! &nameIsInList( $From, "noack.list" ); + +} + + +###################################################################### +# Getting data +sub readMessage { + + $IsBody = 0; + + while( <> ) { + $Body .= $_; + + chop; + + if( /^$/ ) { + $IsBody = 1; + } + + if( !$IsBody ) { + + if( /^Newsgroups: / ) { + $Newsgroups = $_; + $Newsgroups =~ s/^Newsgroups: //i; + } elsif( /^Subject: / ) { + $Subject = $_; + } elsif( /^From: / ) { + $From = $_; + } elsif( /^Path: / ) { + $Path = $_; + } elsif( /^Keywords: / ) { + $Keywords = $_; + } elsif( /^Summary: / ) { + $Summary = $_; + } elsif( /^Message-ID: / ) { + $Message_ID = $_; + } + + } + } + + close( TMPFILE ); +} + +###################################################################### +# read the thing +&readMessage(); + +###################################################################### +# process acks +&checkAck; + +if( $needAck ) { + exit 0; +} else { + exit 1; +} diff --git a/stump/bin/noAck b/stump/bin/noAck new file mode 100755 index 0000000..8fde0a5 --- /dev/null +++ b/stump/bin/noAck @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "x$@" = "x" ]; then + + cat >> $MNG_ROOT/data/noack.list + +else + + echo $@ >> $MNG_ROOT/data/noack.list + +fi diff --git a/stump/bin/preApprove b/stump/bin/preApprove new file mode 100755 index 0000000..bb0baa5 --- /dev/null +++ b/stump/bin/preApprove @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ "x$@" = "x" ]; then + + cat >> $MNG_ROOT/data/good.guys.list + +else + + echo $@ >> $MNG_ROOT/data/good.guys.list + +fi diff --git a/stump/bin/processApproved b/stump/bin/processApproved new file mode 100755 index 0000000..9cdf3c6 --- /dev/null +++ b/stump/bin/processApproved @@ -0,0 +1,103 @@ +#!/bin/sh + +NEWSBIN=/var/lib/newsbin; export NEWSBIN +shift +DATE_STAMP="`date +%y%m%d%H%M%S`" + +TMPFILE=$TMP/pa.$DATE_STAMP.$$ + +if [ $PGP = "none" ]; then + PMAPP_PROG=cat +else + PMAPP_PROG="$PMAPP $NEWSGROUP" +fi + +echo Action: processApproved 1>&2 + +cat > $TMPFILE + +save() { + + ( + cat $TMPFILE + ) | procmail -f- $MNG_ROOT/etc/procmail/save-approved +} + +post() { + FAILED=$TMP/failed.$$ + ( + echo Path: "$PATH_SUFFIX" + + cat $MNG_ROOT/etc/added-headers | grep ': ' + # I do grep above because a lot of users inserts empty + # lines in the added headers. + + echo Date: `date -R` + cat $TMPFILE \ + | formail -f -a "Newsgroups: $NEWSGROUP" \ + -I Path: \ + -I X-Moderate-For: \ + -I Return-Path: \ + -I X-Mailer: \ + -I "Date:" \ + -I "X-400-Received:" \ + -I Received: -I "From " \ + -a "Approved: $PMUSER_APPROVAL" \ + -I Lines: \ + -I Cc: \ + -I To: -I Status: \ + -I "X-Delivered-To:" \ + -I "X-Envelope-To:" \ + -I "X-Forwarding-To:" \ + -I "X-Gradwell-Mailfilter:" \ + -I "Delivered-To:" \ + -I "Envelope-To:" \ + -I "X-Priority:" \ + -I "X-Priority:" \ + -I "X-Priority:" \ + -I "X-MSMail-Priority:" \ + -I "X-MimeOLE:" \ + -I "X-RBL-Warning:" \ + -I "X-Scanner:" \ + -I "X-Spam-Checker-Version:" \ + -I "X-Spam-Flag:" \ + -I "X-Spam-Level:" \ + -I "X-Spam-Report" \ + -I "X-Spam-Score:" \ + -I "X-Spam-Status:" \ + -I "X-Scanned-By:" \ + -I "X-Virus-Scanned:" \ + -I "X-Virus-Status:" \ + -I "X-Original-To:" \ + -I "X-UID:" \ + -I "Delivered-To:" \ + -I "DomainKey-Signature:" \ + -I "Thread-Index:" \ + -I "X-X-Sender:" \ + -I "X-PMX-Version:" \ + + if [ -f $MNG_ROOT/etc/added-footer ] ; then + cat $MNG_ROOT/etc/added-footer + fi + + ) \ + | $PMAPP_PROG \ + | tee $FAILED \ + | $RNEWS + if [ "$?" = "0" ] ; then + /bin/rm $FAILED + else + echo IHAVE failed. Look at $FAILED. 1>&2 + fi +} + +PMUSER="$PMUSER_APPROVAL"; export PMUSER +ROBOMOD="$ROBOMOD_APPROVAL"; export ROBOMOD +save +post + +if needAck < $TMPFILE; then + modack.approved $TMPFILE +fi + +rm $TMPFILE diff --git a/stump/bin/processNoack.pl b/stump/bin/processNoack.pl new file mode 100755 index 0000000..38c29fe --- /dev/null +++ b/stump/bin/processNoack.pl @@ -0,0 +1,39 @@ +# +# Processes the "No Ack" request +# + +# get the directory where robomod is residing +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +# common library +require "$MNG_ROOT/bin/robomod.pl"; + +$NoAckFile = "$MNG_ROOT/data/noack.list"; + +$Argv = join( ' ', @ARGV ); + +while( ) { + $From = $_ if( /^From: / ); + + chop; + last if( /^$/ ); +} + +$From =~ s/^From: //; +if( $From =~ m/([\w-\.]*)\@([\w-\.]+)/ ) { + $From = "$1\@$2"; +} else { + print STDERR "From line `$From' is incorrect\n"; + exit 0; +} + +if( !&nameIsInList( $From, "noack.list" ) ) { # need to preapprove + print STDERR "Adding $From to the noack list...\n"; + open( NOACK, ">>$NoAckFile" ); + print NOACK "$From\n"; + close( NOACK ); +} else { + print STDERR "$From already is in noack list\n"; +} + +1; diff --git a/stump/bin/processPreapproved b/stump/bin/processPreapproved new file mode 100755 index 0000000..38eb714 --- /dev/null +++ b/stump/bin/processPreapproved @@ -0,0 +1,49 @@ +#!/usr/bin/perl +# +# Preapproves the person and gets his/her message posted via processApproved +# + +# get the directory where robomod is residing +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +# common library +require "$MNG_ROOT/bin/robomod.pl"; + +$GoodGuys = "$MNG_ROOT/data/good.guys.list"; + +$Argv = join( ' ', @ARGV ); + + +open( PROCESS_APPROVED, "|processApproved $Argv" ); + +while( ) { + $From = $_ if( /^From: / ); + + print PROCESS_APPROVED; + + chop; + last if( /^$/ ); +} + +while( ) { # Body + print PROCESS_APPROVED; +} + +close PROCESS_APPROVED; + +$From =~ s/^From: //g; +if( $From =~ m/([\w-\.]*)\@([\w-\.]+)/ ) { + $From = "$1\@$2"; +} else { + print STDERR "From line `$From' is incorrect\n"; + exit 0; +} + +if( !&nameIsInList( $From, "good.guys.list" ) ) { # need to preapprove + &logAction( "Action: processPreapproved $From\n" ); + open( GOOD_GUYS, ">>$GoodGuys" ); + print GOOD_GUYS "$From\n"; + close( GOOD_GUYS ); +} else { + print STDERR "$From already preapproved\n"; +} diff --git a/stump/bin/processRejected b/stump/bin/processRejected new file mode 100755 index 0000000..212a8f7 --- /dev/null +++ b/stump/bin/processRejected @@ -0,0 +1,62 @@ +#!/bin/sh +# +# This script takes a raw article that is already rejected, creates a +# reply message, signs it with PGP and sends back to the author. +# + +# echo $0 invoked with arguments $@ 1>&2 + +MESSAGE=$TMP/rejected.$$ + +shift; REASON="$1"; export REASON; shift +#EXPLANATION="$@"; export EXPLANATION + +echo Action: processRejected, reason=$REASON 1>&2 + +cat > $MESSAGE + +#save() { +# procmail -p -f- $MNG_ROOT/etc/procmail/save-rejected < $MESSAGE +#} + +reply() { + + if [ "x$REASON" = xdiscard ]; then return; fi + ( + cat $MESSAGE | formail -rt -I "Reply-To: $BOARD" \ + -I "Errors-To: $MUNGED_ADDRESS" \ + -I "X-Webstump-Event: reject $REASON" \ + -I 'Bcc: webstump+urcm-internal-log+mailout' \ + -I 'Bcc: webstump+urcm-internal-reject-copy' + ( + echo "$EXPLANATION" + echo + + if [ "x$REASON" != "xcustom" ] ; then + cat $MNG_ROOT/etc/messages/$REASON + fi + + echo "" + echo ============================================ Full text of your message follows + sed 's/^/> /; s/webstump+[-+/0-9a-z]*@chiark/webstump+?@chiark/' \ + < $MESSAGE + ) | gpg --clearsign --textmode --armor --batch --user "$PMUSER_APPROVAL" \ + --passphrase "$PMPASSWORD" 2>/dev/null \ + ) | sendmail -oi -t -f $MUNGED_ADDRESS +} + +update_rejection_count() { + # don't count forgeries and signature mismatches against the victim + # also don't count thread rejections or duplicates + if [ "x$REASON" != "xforgery" -a "x$REASON" != "xsignature" -a "x$REASON" != "xthread" -a "x$REASON" != "xduplicate" -a "x$REASON" != "xcrosspost" -a "x$REASON" != "xempty" ]; then + cat $MESSAGE | updateActionCount.pl -r + fi +} + +#save +reply $1 +#update_rejection_count +rm $MESSAGE + +# ) | stump-pgp -staf -z "$PMPASSWORD" \ +# -u "$ROBOMOD_APPROVAL" +clearsig=on 2>/dev/null \ diff --git a/stump/bin/report.sh b/stump/bin/report.sh new file mode 100755 index 0000000..13138f1 --- /dev/null +++ b/stump/bin/report.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# posts a nice report +# +# $Id: report.sh,v 1.2 2007/05/03 23:47:49 rram Exp $ +# Modified to work with GPG + +TODAY="`date`" +DATE6="`date +%y%m%d`" + +LOGFILE="$HOME/Mail/from" +LOGFILE_ARCHIVED="$MNG_ROOT/archive/old/from.$DATE6" + +Report() { + echo Subject: $NEWSGROUP report for $TODAY + echo Newsgroups: $NEWSGROUP + echo To: $SUBMIT + echo From: $ADMIN + echo Reply-To: $ADMIN + echo Organization: CrYpToRoBoMoDeRaToR CaBaL + echo "" + +( + echo Subject: $NEWSGROUP report for $TODAY + echo Newsgroups: $NEWSGROUP + echo Date: $TODAY + echo "" + +cat << _EOB_ +This is an automated report about activity of our newsgroup +$NEWSGROUP. It covers period between the +previous report and the current one, ending +on $TODAY. + +Note that we do not report the number of articles cancelled +after they got approved, because the cancellations are done +manually. Typically messages get cancelled by requests of +posters themselves. + +Lastly, the statistics below are skewed towards higher numbers because +there are always some test messages from moderators themselves who +approve and reject them to make sure that our robomoderator functions +properly. + +_EOB_ + + stump-report.pl $LOGFILE +) | stump-pgp --clearsign --textmode --armor --batch --user $PMUSER_APPROVAL --passphrase "$PMPASSWORD" 2>/dev/null +} + +Report | sendmail -t + +mv $LOGFILE $LOGFILE_ARCHIVED +gzip -9 $LOGFILE_ARCHIVED & diff --git a/stump/bin/robomod.pl b/stump/bin/robomod.pl new file mode 100755 index 0000000..3534c5a --- /dev/null +++ b/stump/bin/robomod.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl +# +# Collection of common functions +# + +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +###################################################################### checkAck +# checks if poster needs ack +sub nameIsInList { + local( $listName ) = pop( @_ ); + local( $address ) = pop( @_ ); + + local( $item ); + + $Result = 0; + + open( LIST, "$MNG_ROOT/data/$listName" ); + + while( $item = ) { + + chop $item; + + next if $item =~ /^ *$/; + + if( eval { $address =~ /$item/i; } || "\L$address" eq "\L$item" ) { + $Result = $item; + } + } + + close( LIST ); + + return $Result; +} + +sub logAction { + my $msg = pop( @_ ); + + print STDERR $msg . "\n"; +} + + +###################################################################### +# Setting variables + +if( defined( $ENV{'STUMP_PARANOID_PGP'} ) ) { + $paranoid_pgp = $ENV{'STUMP_PARANOID_PGP'} eq "YES"; +} else { + $paranoid_pgp = 0; +} + +1; diff --git a/stump/bin/send_pgp_key b/stump/bin/send_pgp_key new file mode 100755 index 0000000..4104f1b --- /dev/null +++ b/stump/bin/send_pgp_key @@ -0,0 +1,21 @@ +#!/bin/sh +( + formail -r -I "Subject: $NEWSGROUP Approval PGP Key" \ + -I "Reply-To: devnull@algebra.com" \ + -I "Errors-To: devnull@algebra.com" + + cat << _EOB_ +Hello, + +Thank you for requesting PGP Public Key used to sign submissions to +soc.culture.russian.moderated newsgroup. Please use PGP Moose scripts +to verify integrity of robomod's signatures on your news articles and +report any articles that fail verification to scrm-admin@algebra.com. + +Thanks, + + - Your Friendly $NEWSGROUP Robomoderator. + +_EOB_ + cat $MNG_ROOT/approval.key.txt +) | /usr/sbin/sendmail -t diff --git a/stump/bin/stump-pgp b/stump/bin/stump-pgp new file mode 100755 index 0000000..05425d3 --- /dev/null +++ b/stump/bin/stump-pgp @@ -0,0 +1,24 @@ +#!/bin/sh + +# $Id: stump-pgp,v 1.2 2007/05/03 23:47:55 rram Exp $ +# Modified to work with GPG + +if [ "$PGP" = "none" ] ; then + cat +else + if [ "x$PGP" = "x" ] ; then + if which gpg ; then + gpg $@ + else + cat $@ + echo used cat because gpg was not found 1>&2 + fi + else + if [ -x $PGP ] ; then + $PGP $@ + else + echo Please define variable PGP in your admin/etc/modenv file 1>&2 + gpg $@ + fi + fi +fi diff --git a/stump/bin/stump-report.pl b/stump/bin/stump-report.pl new file mode 100755 index 0000000..253065d --- /dev/null +++ b/stump/bin/stump-report.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +# +# This script processes the logfile given as it first command argument, +# and prints a nice report about approved, rejected, etc postings, to +# stdout. +# +# is called from report.sh +# + +# get the directory where robomod is residing +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +# common library +require "$MNG_ROOT/bin/robomod.pl"; + +$logFile = $ARGV[0] || die "A log file name must be specified"; +open( LOG, $logFile ) || die "Can't open logfile $logFile for reading"; + +$approvedCount = 0; +$autoCount = 0; +$rejectedCount = 0; +$preApprovedCount = 0; + +while( ) { + $approvedCount++ if( /processApproved/i ); + $autoCount++ if( /PREAPPROVED/ ); + $rejectedCount++ if( /processRejected/i ); +# $approvedCount++ if( /processPreapproved/i ); + $preApprovedCount++ if( /processPreapproved/i ); +} + +print " + +Approved: $approvedCount messages (of them, $autoCount automatically) +Rejected: $rejectedCount messages +Preapproved: $preApprovedCount new posters +"; diff --git a/stump/bin/stump.pl b/stump/bin/stump.pl new file mode 100755 index 0000000..3dfa8bc --- /dev/null +++ b/stump/bin/stump.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl + +$MNG_ROOT=$ENV{'MNG_ROOT'} + || die "Newsgroup Root Directory (\$MNG_ROOT) Not Defined!"; + + +sub start { + + my $robomod_pl = "$MNG_ROOT/bin/robomod.pl"; + require "$robomod_pl" if( -f $robomod_pl && -r $robomod_pl ); + + my $script = shift @ARGV + || die "Syntax: $0 script-name [parameters]\n"; + my $script_file = "$MNG_ROOT/bin/$script"; + if( -f $script_file ) { + require $script_file; + } else { + die "ERROR: $script_file not found and could not be executed."; + } +} + +start; diff --git a/stump/bin/submission.pl b/stump/bin/submission.pl new file mode 100755 index 0000000..f978a1f --- /dev/null +++ b/stump/bin/submission.pl @@ -0,0 +1,465 @@ +# +# this script accepts submissions that come to the robomoderator by +# email. It make s a decision whether the submission deserves +# rejection, automatic approval, or is suspicious and should be +# forwarded to human moderators for review. +# +# A decision is essentially a choice of the program that will be +# fed with preprocessed article. +# +# Also note that this script fixes common problems and mistakes in +# newsreaders, newsservers, and users. Even though we have no +# obligation to fix these problems, people get really disappointed +# if we outright reject their bogus messages, because these +# people often have no control over how the posts get delivered to us. +# +# This script supports notion of blacklisting and list of +# preapproved persons. As the names imply, we reject all submissions +# from blacklisted posters and automatically approve all messages submitted +# by preapproved posters (provided that their posts meet other criteria +# imposed by the robomoderator. +# +# For an automatic rejection, it gives a main "reason" for rejection +# +#Currently supported list of reasons: +# +# - crosspost +# - abuse +# - harassing +# - offtopic + +# get the directory where robomod is residing +$MNG_ROOT = $ENV{'MNG_ROOT'} || die "Root dir for moderation not specified"; + +# common library +require "$MNG_ROOT/bin/robomod.pl"; + +# max allowed number of newsgroups in crossposts +# change it if you want, but 5 is really good. +$maxNewsgroups = $ENV{'MAX_CROSSPOSTS'} || 5; + +# should we ALWAYS require preapproved posters to sign their submissions +# with PGP? Turn it on in the `etc/modenv' if you suffer from numerous +# forgeries in the names of preapproved posters. +$PGPCheckPreapproved = $ENV{ "WHITELIST_MUST_SIGN" } eq "YES"; + +# So, what newsgroup I am moderating? +$Newsgroup = $ENV{'NEWSGROUP'}; + +# as the name implies. ATTENTION: $TMP must be mode 700!!! +$TmpFile = "$ENV{'TMP'}/submission.$$"; + +# how do we treat suspicious articles? +$Command_Suspicious = "formail -a \"Newsgroups: $Newsgroup\" " . + "| stump.pl suspicious.pl"; + +# approved +$Command_Approve = "processApproved robomod"; +# rejected +$Command_Reject = "processRejected robomod"; + +# location of blacklist +$badGuys = "bad.guys.list"; + +# location of preapproved list +$goodGuys = "good.guys.list"; + +# words that trigger robomod to mark messages suspicious, even +# when the message comes from a preapproved person. +$badWords = "bad.words.list"; + +# list of people who want all their submissions to be signed +$PGPMustList = "pgp.must.list"; + +# set PMUSER and ROBOMOD to Internal. Will be used by `suspicious' script. +$ENV{'PMUSER'} = $ENV{'PMUSER_INTERNAL'}; +$ENV{'ROBOMOD'} = $ENV{'ROBOMOD_INTERNAL'}; + + +###################################################################### +# Filter rules +# checks if all is OK with newsgroups. +# what's not OK: +# 1. Megacrossposts +# 2. Crossposts to other moderated groups +# 3. Control messages (currently) +# +sub checkNewsgroups { + + # We have not implemented Control: yet... + if( $Control ) { +print STDERR "CONTROL message - rejected\n"; + return "$Command_Reject crosspost You posted a Control message which " . + "is not allowed."; + } + + if( $#newsgroups >= $maxNewsgroups ) { +print STDERR "Too many newsgroups\n"; + return "$Command_Reject crosspost Too many newsgroups, " . + "$maxNewsgroups is maximum."; + } + + local( $good ) = 0; + + for( $i = 0; $i <= $#newsgroups; $i++ ) { + + if( $newsgroups[$i] eq $Newsgroup ) { + $good = 1; + next; + } + + if( $NewsgroupsDB{$newsgroups[$i]} eq 'm' && + $newsgroups[$i] ne $Newsgroup) { +print STDERR "posting to ANOTHER moderated newsgroups\n"; + return "$Command_Reject crosspost You crossposted to another " . + "moderated newsgroup."; + } + + } + + if( !$good ) { # Some fool forgot to list the moderated newsgroup + # in the Newsgroups + $Newsgroups .= ",$Newsgroup"; + if( $#newsgroups + 1 >= $maxNewsgroups ) { +print STDERR "Too many newsgroups\n"; + return "$Command_Reject crosspost Too many newsgroups, FIVE is maximum."; + } + } + + return 0; +} + +###################################################################### checkAck +# checks if poster needs acknowledgment of receipt +# +sub checkAck { + if( &nameIsInList( $From, "noack.list" ) ) { + $needAck = "no"; + } else { + $needAck = "yes"; + } +} + +################################################################### checkPGP +# checks PGP sig IF REQUIRED +# +# we can reject a post if +# +# 1. A post must be signed accordinng to rules OR +# 2. A post is signed but verification fails. +# +# Note that we set From: to the user ID in the PGP signature +# if a signature is present. It allows for identification of trolls +# and for preventing subtle forgeries. +# +sub checkPGP { + + local( $FromSig ) = `verifySignature < $TmpFile`; chop( $FromSig ); + local( $good ) = $? == 0; + +print STDERR "FromSig = $FromSig, good = $good\n" if $FromSig; + + if( !$good ) { + return "$Command_Reject signature Your PGP signature does NOT match, or is not in our keyring"; + } + + if( &nameIsInList( $From, $PGPMustList ) || + ($PGPCheckPreapproved && &nameIsInList($From, $goodGuys) ) ) { + if( $FromSig eq "" ) { + return "$Command_Reject signature You are REQUIRED to sign your posts."; + } + } + + if( $FromSig ) { + $X_Origin = $From; + $From = "From: $FromSig"; + $ReplyTo = $From; + } + + # else nothing to do + return 0; +} + +################################################################ checkCharter +# checks charter calling conforms_charter +# +sub checkCharter { + open( VERIFY, "|conforms_charter" ); + print VERIFY $Body; + close( VERIFY ); + + return $? == 0; +} + +################################################################### Filter +# contains all filtering rules. calls subroutines above. +sub Filter { + + + local( $response ); + + @newsgroups = split( /,/, $Newsgroups ); + + return "Command_Reject charter We do not allow any control and " . + "cancel messages. contact newsgroup administrator" + if( $Control ); + + if( $response = &checkNewsgroups() ) { + return $response; + } + + if( $paranoid_pgp ) { + if( $response = &checkPGP() ) { + return $response; + } + } + + if( &nameIsInList( $From, $badGuys ) ) { + return "$Command_Reject abuse"; + } + + # note that if even a preapproved person uses "BAD words" (that is + # words from a special list), his/her message will be marked + # "suspicious" and will be forwarded to a humen mod for review. + # As an example of a bad word may be "MAKE MONEY FAST - IT REALLY WORKS!!!" + # + if( $badWord = &nameIsInList( $Body, $badWords ) ) { +print STDERR "BAD WORD $badWord FOUND!!!\n"; + return $Command_Suspicious; # messages from approved guys MAY be + # suspicious if they write about + # homosexual forgers + } + + # checking for charter-specific restrictions + if( !&checkCharter || ($Encoding =~ "base64") ) { + return "$Command_Reject charter you sent a " . + "binary encoded file which is not allowed."; + } + + # Checking preapproved list + if( &nameIsInList( $From, $goodGuys ) ) { + local( $from ) = $From; $from =~ s/^From: //i; +print STDERR "$from is a PREAPPROVED person\n"; + return $Command_Approve; + } + + # Here I may put some more rules... + + return $Command_Suspicious; +} + +###################################################################### +# set defaults +sub setDefaults { + if( !$Newsgroups ) { + $Newsgroups = $ENV{ "NEWSGROUP" } || die "No default newsgroup"; + } +} + +################################################################# ignoreHeader +# some of the header fields present in emails must be ignored. +# +sub ignoreHeader { + local( $header ) = pop( @_ ); + +# return 1 if( $header =~ /^Control:/i ); + return 1 if( $header =~ /^Expires:/i ); + return 1 if( $header =~ /^Supersedes:/i ); + return 1 if( $header =~ /^Precedence:/i ); + return 1 if( $header =~ /^Apparently-To:/i ); + return 1 if( $header =~ /^Date:/i ); + return 1 if( $header =~ /^Expires:/i ); + return 1 if( $header =~ /^Distribution:/i ); + return 1 if( $header =~ /^Path:/i ); + return 1 if( $header =~ /^NNTP-Posting-Host:/i ); + return 1 if( $header =~ /^Xref:/i ); + return 1 if( $header =~ /^Status:/i ); + return 1 if( $header =~ /^Lines:/i ); + return 1 if( $header =~ /^Apparently-To:/i ); + return 1 if( $header =~ /^Cc:/i ); + return 1 if( $header =~ /^Sender:/i ); + return 1 if( $header =~ /^In-Reply-To:/i ); + return 1 if( $header =~ /^Originator:/i ); + + return 0; +} + + +###################################################################### +# Getting data +# +# reads message, sets variables describing header fields +# +# it also tries to "fix" the problem with old newsservers (B-News I think) +# when they try to "wrap" a submission in one more layer of meaningless +# headers. It is recognized by STUPID presense of TWO identical To: +# fields. +# + +sub readMessage { + +open IWJL, ">>/home/webstump/t.log"; +print IWJL "=========== SUBMISSION READMESSAGE\n"; + + open( TMPFILE, "> $TmpFile" ); + + $IsBody = 0; + + while( <> ) { +print IWJL "SbRm $_\n"; + $Body .= $_; + + if( !$IsBody && &ignoreHeader( $_ ) ) { + next; + } + + print TMPFILE; + + chop; + + if( /^$/ ) { + if( !$Subject && $From =~ /news\@/) { + $BadNewsserver = 1; + } + + if( $BadNewsserver ) { # just ignore the outer layer of headers + $To = 0; + } else { + $IsBody = 1; + } + } + + if( !$IsBody ) { + + if( /^Newsgroups: / ) { # set Newsgroups, remove spaces + $Newsgroups = $_; + $Newsgroups =~ s/^Newsgroups: //i; + $Newsgroups =~ s/ //g; # some fools put spaces in list of newsgroups + } elsif( /^Subject: / ) { + $Subject = $_; + } elsif( /^From: / ) { + $From = $_; + } elsif( /^To: / ) { + if( $To && ($To eq $_)) { + # Old & crappy news servers that wrap submissions with one more + # layer of headers. For them, I simply ignore the outer + # headers. These (at least I think) submissions may be + # recognized by TWO idiotic To: header fields. +print STDERR "BAD NEWSSERVER\n"; + $BadNewsserver = 1; + } + $To = $_; + } elsif( /^Path: / ) { + $Path = $_; + } elsif( /^Keywords: / ) { + $Keywords = $_; + } elsif( /^Summary: / ) { + $Summary = $_; + } elsif( /^Control: / ) { + $Control = $_; + } elsif( /^Message-ID: / ) { + $Message_ID = $_; + } elsif ( /^Content-Transfer-Encoding: / ) { + $Encoding = $_; + $Encoding =~ s/^Content-Transfer-Encoding: //; + } + + } + } +use IO::Handle; + print IWJL "SbRmE $!\n"; + die "read message $! !" if STDIN->error; + + close( TMPFILE ); +} + +###################################################################### work +# all main work is done here + +###################################################################### +# read the thing +&readMessage(); + +if( !$Newsgroups ) { + $Newsgroups = $Newsgroup; +} + +###################################################################### +# process acks +&checkAck; +$Command_Suspicious .= " $needAck"; + +###################################################################### +# set defaults +&setDefaults(); + +###################################################################### +# Check + +$command = &Filter; + +###################################################################### +# process +print STDERR "command = $command\n"; + +open IWJL, ">>/home/webstump/t.log"; +print IWJL "=========== SUBMISSION MAIN\n"; + +open( COMMAND, "| $command" ); +open( TMPFILE, "$TmpFile" ) || die "cant open tmpfile"; + + $IsBody = 0; + + while( ) { +print IWJL "SbRt $_\n"; + + if( $BadNewsserver && !(/^$/) ) { + next; + } + + if( $BadNewsserver && /^$/ ) { + $BadNewsserver = 0; + next; + } + + if( /^$/ ) { + $IsBody = 1; + } + + if( /^From / ) { + print COMMAND; + print COMMAND "X-Origin: $X_Origin, $_" if $X_Origin; + print STDERR "Subject =`$Subject'\n"; + print COMMAND "Subject: No subject given\n" if !$Subject; + # nothing + } elsif( /^From: / && !$IsBody) { + next if $FromWasUsed; + + $FromWasUsed = 1; # note that some crappy remailers have several + # "From: " fields. We really do NOT want two + # "From: " to go to headers! + + if( $From ) { + print COMMAND "$From\n"; + $From = ""; + } else { + print COMMAND; + } + } elsif( /^Newsgroups: / && !$IsBody ) { + print COMMAND "Newsgroups: $Newsgroups\n"; + } else { + print COMMAND; + } + } + +close( TMPFILE ); +close( COMMAND ); + +################################################################## Archiving +# archive + +#open( COMMAND, "| procmail -f- $MNG_ROOT/etc/procmail/save-incoming" ); +#print COMMAND $Body; +#close( COMMAND ); + +unlink( $TmpFile ); diff --git a/stump/bin/submitFailed b/stump/bin/submitFailed new file mode 100755 index 0000000..938d341 --- /dev/null +++ b/stump/bin/submitFailed @@ -0,0 +1,9 @@ +#!/bin/sh + +cd $MNG_ROOT/tmp + +for i in failed*; do + if $RNEWS < $i; then + /bin/rm $i + fi +done diff --git a/stump/bin/suspicious.pl b/stump/bin/suspicious.pl new file mode 100755 index 0000000..00654b3 --- /dev/null +++ b/stump/bin/suspicious.pl @@ -0,0 +1,179 @@ +# +# this script processes "suspicious" messages. It does basically two things: +# +# 1. Sends an acknowledgment to the author, if necessary (ie if the author did +# not turn ack mode off), and +# 2. Prepares, signs, and sends the message to a randomly chosen human +# moderator for review. +# + +$MNG_ROOT = $ENV{'MNG_ROOT'}; +$Prefix = $ENV{'BOT_SUBJECT_PREFIX'}; +$tempFile = "$ENV{'TMP'}/signed.$$"; + +# name of moderator to test +$TestModerator = "eugenez\@mit.edu"; + +$isTesting = 0; # No testing by default +$TestFlag="test-test"; + +$needAck = $ARGV[0]; shift @ARGV; + +$message = join( " ", @ARGV ); + +print STDERR "Needack = $needAck\n"; + + +###################################################################### +# Getting data +sub readMessage { + $IsBody = 0; + +open IWJL, ">>/home/webstump/t.log"; +print IWJL "=========== SUSPICIOUS READMESSAGE\n"; + + while( ) { +print IWJL "SsRm $_\n"; + + $Body .= $_; + + $isKOI8 = $isKOI8 || $_ =~ /[\x80-\xFF]/; + + chop; + + if( /^$/ ) { + $IsBody = 1; + } + + if( !$IsBody ) { + + if( /^Newsgroups: / ) { + $Newsgroups = $_; + } elsif( /^Subject: / ) { + $Subject = substr( $_, 0, 50 ); + + if( $Subject =~ /$TestFlag/i ) { # special subject + $isTesting = 'y'; + } + + } elsif( /^From: / ) { + $From = $_; + if ($From =~ m/([\w-\.]+)@([\w-\.]*)[^\w-\.]/){ + $From = "From: $1\@$2";} + } elsif( /^Path: / ) { + $Path = $_; + } elsif( /^Keywords: / ) { + $Keywords = $_; + } elsif( /^Summary: / ) { + $Summary = $_; + } elsif( /^Message-ID: / ) { + $Message_ID = $_; + } + + } + } +} + +$MNG_ROOT = "$ENV{'MNG_ROOT'}" || die "Root dir for moderation not specified"; + +&readMessage; + +#$Body =~ s/From /_From /g; + + +if( $isTesting eq 'y' ) { + $moderator = $From; # $TestModerator; + $moderator =~ s/^From: //i; + + } else { # get random moderator + open( MODERATORS, "$MNG_ROOT/etc/moderators" ) + || die "can't open moderators file"; + + while( ) { + next if( /^#/ ); + next if( /^\s*$/ ); + ($name, $priority, $flags) = split; + + if( $priority != 0 && ! ($isKOI8 && $flags =~ /nokoi/i)) { + # priority 0 means "on vacation" + push( @moderators, $name ); + } + } + + close( MODERATORS ); + srand; + + $randNum = rand 100 + time; + + $moderator = $moderators[ $randNum % ($#moderators + 1) ]; +} + + +$modNick = $moderator; + +$modNick =~ s/@.*//; +$modNick =~ s/-.*//; + +$date = `date`; chop $date; + +print STDERR "Activity: $date Forwarding $Message_ID, $Subject from $From ". + "to $moderator for approval\n"; + +$MessageNumber = time . $$; + +print STDERR "Opening $MNG_ROOT/tmp/messages/$MessageNumber\n"; + +open( MESSAGE, "> $MNG_ROOT/tmp/messages/$MessageNumber" ); +print MESSAGE $Body; +close( MESSAGE ); + +$Subject = "Subject: try again" if( !$Subject ); + +open( COMMAND, "| sendmail $moderator > /dev/null" ); + +print COMMAND "From: $ENV{'DECISION_ADDRESS'} +$Subject ::$Prefix/$MessageNumber +To: $moderator +X-Moderate-For: $ENV{'NEWSGROUP'} +Organization: Robots Are Us + +$message + +This is an automated message sent to you as the moderator of +$ENV{'NEWSGROUP'}. Simply reply to this message, +DO NOT quote the message body in your reply, and state your decision ON +THE FIRST LINE, choosing LITERALLY from ONE of the following options +(you can even cut and paste): + +approve +preapprove +"; + +open( REASONS, "$MNG_ROOT/etc/rejection-reasons.lst" ); +while( ) { + ($reason, $explanation) = split( /::/, $_ ); + print COMMAND "reject $reason\n"; +} +close( REASONS ); + +print COMMAND " + +You can also specify a comment, by typing word comment at the +beginning of a line _after_ approve, preapprove, or reject, and +then your comment on one or several lines. Do NOT put your comment +before approve, preapprove, or reject. + +Message follows: +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +"; + +print COMMAND $Body; +close( COMMAND ); + +if( $needAck eq "yes" ) { + open( ACK, "| modack.received" ); + print ACK $Body; + close( ACK ); +} + +1; diff --git a/stump/bin/verifySignature b/stump/bin/verifySignature new file mode 100755 index 0000000..45571a3 --- /dev/null +++ b/stump/bin/verifySignature @@ -0,0 +1,60 @@ +#!/bin/sh + +# $Id: verifySignature,v 1.2 2007/05/03 23:50:21 rram Exp $ +# Modified to work with GPG + +NAME="$1" + +TMPFILE=$TMP/vrfy.$$ + +cat > $TMPFILE + +if grep -e "^$BEGIN_PGP_SIGNED_MESSAGE" < $TMPFILE >/dev/null; then + SIGNED="YES" +else + SIGNED="NO" +fi + +if [ $SIGNED = "NO" ] ; then + if [ "x$1" != "x" ] ; then + echo "No valid sig!" 1>&2 + rm $TMPFILE + exit 1 + else + rm $TMPFILE + exit 0 + fi +fi + +# +# this we do under assumption that message IS signed +# + +GOODSIG="gpg: Good signature from \"" + +DoPGP() { +# stump-pgp -f +batchmode=on +pubring=$MNG_ROOT/data/pubring.pgp < $TMPFILE 2>&1 > /dev/null + stump-pgp --no-default-keyring --keyring $MNG_ROOT/data/pubring.gpg < $TMPFILE 2>&1 > /dev/null +} + +USERID="`DoPGP | grep -e "^$GOODSIG" | sed \"s/^$GOODSIG//\" | sed 's/"\.$//'`" + + +rm $TMPFILE + +echo USERID = "$USERID" 1>&2 + +if [ "x$1" != "x" ]; then + if [ "$USERID" = "$1" ] ; then + exit 0 + else + exit 1 + fi +else + if [ "x$USERID" = "x" ]; then # bad sig! + exit 1; + fi + + echo "$USERID" + exit 0 +fi diff --git a/stump/c/antivirus.c b/stump/c/antivirus.c new file mode 100644 index 0000000..a676c94 --- /dev/null +++ b/stump/c/antivirus.c @@ -0,0 +1,101 @@ +/* antivirus.c - + + This program replaces all "dangerous" characters in the incoming file + to '_' character. Dangerous characters are all characters less than 32 + (space) and not equal to \n, \r, \t, \f and ^H. + + It also notices lines > 1024 characters and splits them, adding space + character in front of the split line. + + In ``fascist'' mode (when called with argument -fascist), it is much + more restrictive: it permits only newlines, space, TAB, lowercase and + uppercase letters, and digits. Everything else is replaced by '_' + character. Fascist mode should be used to filter user input that is + to be used in shell scripts. It may prevent users from being able to + fool poorly written shell scripts that accept user commands into + executing arbitrary programs. Since, unfortunately, it is likely that + some of the scripts would be prone to such attacks, using this + program is highly recommended BEFORE doing anything with user input. + + This program should be used to preprocess all incoming mail before + feeding to mail processing scripts. It in fact may prove useful + against viruses exploiting weaknesses of C programs that overflow + buffers, etc. + + Copyright 1996, Igor Chudov. GNU Public license applies, and I am + not responsible for any damage arising from use of this program. + +*/ + +#include + +#define MAX_CHAR 256 /* max unsigned char */ +#define MAX_LEN 1024 /* max allowed line size */ +#define NEWLINE "\n" /* newline for Unix, for DOS I think "\r\n" */ + +unsigned char charTable[ MAX_CHAR ]; + +#define SET_GOOD_INTERVAL( l, u ) \ + for( i = l; i <= u; ) charTable[i++] = 1; + +void initCharTable( int fascist ) +{ + int i; + + /* bad characters can only be used for viruses */ + for( i=0; i < MAX_CHAR; i++ ) charTable[i] = 0; + + charTable['\n'] = 1; + charTable[' '] = 1; + charTable['\r'] = 1; + charTable['\t'] = 1; + charTable['\f'] = 1; + + if( fascist ) { /* fascist mode - used for shells */ + SET_GOOD_INTERVAL( 'a', 'z' ); + SET_GOOD_INTERVAL( 'A', 'Z' ); + SET_GOOD_INTERVAL( '0', '9' ); + charTable['-'] = 1; + charTable['+'] = 1; + charTable['.'] = 1; + charTable[','] = 1; + } else { /* normal mode - used to filter users' mail. */ + + /* Good characters, incl Cyrillic */ + SET_GOOD_INTERVAL( ' ', MAX_CHAR-1 ); + + charTable[8] = 1; /* 8 is Ctrl-H, BackSpace */ + } +} + +int main( int argc, char **argv ) +{ + int ch, len = 0; + int fascist = 0; + + if( argc == 2 ) { + if( strcmp( argv[1], "-fascist" ) ) { + fprintf( stderr, "Usage: %s [-fascist]\n", argv[0] ); + return( 1 ); + } + fascist = 1; + } else if( argc != 1 ) { + fprintf( stderr, "Usage: %s [-fascist]\n", argv[0] ); + return( 1 ); + } + + initCharTable( fascist ); + + while( (ch = getchar()) != EOF ) + { + if( !charTable[ch] ) ch = '_'; + if( ch == '\n' ) len = 0; else len++; + if( len > MAX_LEN ) { + printf( NEWLINE " " ); + len = 1; /* because I put " " */ + } + putchar( ch ); + } + + return 0; +} diff --git a/stump/c/checkquot.c b/stump/c/checkquot.c new file mode 100644 index 0000000..268a208 --- /dev/null +++ b/stump/c/checkquot.c @@ -0,0 +1,54 @@ +#include +#include + + +main(int argc, char *argv[]) +{ + double Qratio; + int MaxLines; + + FILE *fp; + char buf[100]; + int i, lines=0, prefixes[256]; + + /* initialize array of # of prefixes (for each ascii char) */ + for(i=0; i<256; prefixes[i]=0, i++); + + /* set values for quote ratio and max #lines */ + Qratio = argc>1 ? atof(argv[1]) : .75 ; + MaxLines = argc>2 ? atoi(argv[2]) : 20 ; + + /* open input file or stdin */ + if(argc<=3 || ! ( fp = fopen(argv[3], "r") ) ) + fp = stdin; + + /* read input */ + while( fgets(buf, 99, fp) ) + { + int i; + + /* get to the first non-white char in line */ + for(i=0; buf[i] < 33 && buf[i] > 0; i++); + + /* string is non-empty */ + if( buf[i] != '\0' ) + { + /* increment prefix counter for this prefix */ + prefixes[ (int) buf[i] ]++; + + /* increment line counter */ + lines++; + } + } + + if( lines > MaxLines ) + for( i=0; i<256; i++ ) + + /* overquote with char i */ + if( prefixes[i] > Qratio*lines ) + exit(1); + + /* everytjing seems ok */ + exit(0); +} + diff --git a/stump/c/compile b/stump/c/compile new file mode 100755 index 0000000..dfa0e7b --- /dev/null +++ b/stump/c/compile @@ -0,0 +1,13 @@ +#!/bin/sh + +# define your compiler +CC=cc + +for i in checkquot antivirus cuthead isbinary; do + echo -n Compiling $i.c with $CC... + if $CC -o ../bin/$i $i.c; then + echo  done + else + echo "" + fi +done diff --git a/stump/c/cuthead.c b/stump/c/cuthead.c new file mode 100644 index 0000000..116bfc3 --- /dev/null +++ b/stump/c/cuthead.c @@ -0,0 +1,38 @@ +/* cuthead.c + + This program simply ignires first line, or if argc == 2, first + lines specified by argv[1]. + + I am not responsible for any damages, GNU copyright applies. +*/ + +#include + +#define MAX_BUF 4096 + +const char * Usage = "Usage: %s [number-of-lines]\n"; + +char buf[MAX_BUF]; + +int main( int argc, char **argv ) +{ + int first; + + if( argc == 1 ) first = 1; + else if( argc == 2 ) { + if( (first = atoi( argv[1] ) ) <= 0 ) { + fprintf( stderr, Usage, argv[0] ); + exit( 1 ); + } + } else { + fprintf( stderr, Usage, argv[0] ); + exit( 1 ); + } + + while( fgets( buf, sizeof( buf ), stdin ) ) { + if( first ) + first--; + else + fputs( buf, stdout ); + } +} diff --git a/stump/c/isbinary.c b/stump/c/isbinary.c new file mode 100644 index 0000000..00678e9 --- /dev/null +++ b/stump/c/isbinary.c @@ -0,0 +1,39 @@ +/* + isbinary.c + + This program reads an article from standard input and checks if it + is a uuencoded binary. If it is, exits with exit code 0, otherwise + retcode = 1. + + GNU Copyright applies. ichudov@algebra.com + +*/ + +#include + +#define MAX_BUF 16384 +#define MAX_BINARY_LINES 10 + +char buf[MAX_BUF]; + +int main( int argc, char *argv[] ) +{ + int nBinLines = 0, maxNBinLines = 0; + + /* skip header */ + while( fgets( buf, MAX_BUF, stdin ) ) + if( strlen( buf ) <= 1 ) break; + + while( fgets( buf, MAX_BUF, stdin ) ) { + if( strlen( buf ) > 45 /* buf long enough */ + && (!(strchr( buf, ' ' ) || strchr( buf, '\t' )) /* no spaces */ + || (buf[0] == 'M') ) /* some uuencoded stuff begins with 'M' */ + ) { /* likely a uuencoded line */ + nBinLines++; + maxNBinLines = (nBinLines > maxNBinLines) ? nBinLines : maxNBinLines; + } else nBinLines = 0; + } + + /* more than 10 consecutive 45 char lines with no blank - likely binary */ + return( maxNBinLines < MAX_BINARY_LINES ); +} diff --git a/stump/doc/README b/stump/doc/README new file mode 100644 index 0000000..822c137 --- /dev/null +++ b/stump/doc/README @@ -0,0 +1,3 @@ +All STUMP Documentation can be found on the STUMP home page at + + http://www.algebra.com/~ichudov diff --git a/stump/doc/VERSION b/stump/doc/VERSION new file mode 100644 index 0000000..6bc60aa --- /dev/null +++ b/stump/doc/VERSION @@ -0,0 +1,32 @@ +VERSION: 2.2 + +Changes in v 2.2: + + * Improved protection from bounced rejections, to ease work + with munged addresses + * A single reference to perl, to simplify addressing perl + +Changes in v.2.1: + + * Somewhat cleaned it up, added more explanations, improved + exchange between mods and the bot. + * Cleaned up documentation on the web page + * Added capability for multi-line moderator comments + * Auto-noack is the mainstream feature that is set up by + default. + * The bot forms defensive mail headers in order to avoid + excessive bounces resulting from munged addresses. + +Changes in v.2.0: + + * Changed all the way human mods interact with the bot; + * Made use of PGP optional + * Killed ModScape + * Set up mail2news gateway. + +Cnanges in v.1.1: + + * Changed send-netscape-submission.pl to enable ModScape for + Win95 to work. + + diff --git a/stump/etc/README b/stump/etc/README new file mode 100644 index 0000000..19f77fd --- /dev/null +++ b/stump/etc/README @@ -0,0 +1,116 @@ + STUMP Configuration Directory + +This directory contains files that the supporter of the robomoderator +for your newsgroup (you) is supposed to edit to reflect the +details of your newsgroup. You will have to edit most of the files +under this directory to set such parameters as your newsgroup +name, maximum number of crossposts, specify email addresses of +your human moderators, and so on. + +Below is a short summary of what files you should edit and what they +are for. Refer to comments in individual files for more details on +how you should modify them. + +I suggest editing the files in the order they are listed here. It +is more logical. + +==================================================> added-headers + +Edit this file and put the header lines that you want to see appended +to all approved articles. Put there something to the effect that you +are not responsible for contents of approved posts, put your +submission and complaint addresses, and if possible provide an +URL of the Web page with your FAQ and Charter. + +==================================================> approval.key.txt + +To set this file, you MUST have already created your PGP keys +needed for moderation. Please refer to the online documentation +explaining what keys to create and how to do it. Here's how +to extract the key AFTER you have created it: + +pgp -kxaf csfm-approval-key > $HOME/stump/etc/approval.key.txt + +==================================================> rejection-reasons.lst + +This file should list exactly the same reasons as mentioned +in "reject" perl script, BUT in a different format + +reason::textual explanation of the reason. + +This file is used by the ModScape subsystem. + +==================================================> conforms_charter + +This shell script allows you to define newsgroup-specific +checks for submissions. If conforms_charter returns a non-zero +exit code, the submission will be rejected automatically. +soc.culture.russian.moderated uses this script to reject +all binary files. + +==================================================> crontab + +This file specifies which programs should be run at regular intervals. +You can skip it if you just started setting up STUMP. + +==================================================> messages + +This DIRECTORY contains explanations for various reasons for rejection. +Refer to "reject" script for details on rejection reasons, names and +files. + +==================================================> modack.approved + +This shell script is used to send acknowledgments to posters whose messages +get approved by the robomoderator. Edit this script so that the +text message is specific to your newsgroups. + +==================================================> modack.received + +This shell script is used to send acknowledgments to posters whose +messages were received by the robomoderator. Edit this script so that +the text message is specific to your newsgroups. + +==================================================> modenv + +This is the main configuration file for your newsgroup. It has extensive +instructions. Edit it very carefully and make sure that PATH includes all +common directories. + +==================================================> moderators + +This file lists all human moderators and member of moderator +board for your newsgroup, along with some flags. Please refer to +the file itself for more details. + +Besides initial setup, you will need to edit this file to support +moderators going to vacations. + +==================================================> mods-message + +This shell script is responsible for sending messages for your +moderator board to the members of said board. You do not really +need to edit it. + +==================================================> mods.sig + +Signature for the moderators-only mailing list. It is appended at the +bottom of every message that is distributed to human moderators. +Edit it and put whatever you want there. + +==================================================> posted_log + +This little shell script created a posted log file +in your home directory. Ignore it. + +==================================================> procmail + +This DIRECTORY contains some procmail rc files for archiving +messages. You only need to edit them if you have procmail and +formail in some non-standard place. + +==================================================> procmailrc + +This file defines rules for processing incoming mail. You will +need to edit it extensively if your group relies on different +system of aliases than those that I recommend (a bad idea!). diff --git a/stump/etc/my_rnews b/stump/etc/my_rnews new file mode 100755 index 0000000..8ba5f13 --- /dev/null +++ b/stump/etc/my_rnews @@ -0,0 +1,20 @@ +#!/bin/sh +# +# use this script instead of standard rnews or inews, if you want better +# propagation of your articles. +# + +TEMPFILE=$TMP/posting.$$ + +cat $@ > $TEMPFILE + +if /usr/lib/news/rnews -h news.uu.net -S news.uu.net < $TEMPFILE; then + echo Rnews successful\! +else + exit 1 +fi + +NNTPSERVER=news +export NNTPSERVER + +/usr/lib/news/inews -h < $TEMPFILE & diff --git a/stump/etc/procmailrc b/stump/etc/procmailrc new file mode 100644 index 0000000..2b0b6d7 --- /dev/null +++ b/stump/etc/procmailrc @@ -0,0 +1,135 @@ +# Please check if all the paths in PATH are reachable, remove the ones that +# are not. +# +# NOTE: I use lockfiles extensively (and even excessively) because +# I do not want to overburden the system. Since I am on a +# PPP link that is not always on, sometimes large amounts of +# submissions come in simultaneously and that may impair +# performance of the overall system. You do not REALLY need +# to use these lockfiles otherwise. +# +# STUMP USERS: +# +# * Go through this file and replace urcm and +# uk.rec.cycling.moderated with appropriate text for +# your own group. +# +# * Please remove recipes related to user "mkagalen". He is not +# likely to bother you. +# +# * Replace "ichudov" with the address of the robomod supporter. +# +# good luck. igor +# +################################################################### + +PATH=/bin:/usr/bin:/usr/local/bin:$HOME/stump/bin:$HOME/stump/etc +MAILDIR=$HOME/Mail # You'd better make sure it exists +DEFAULT=$MAILDIR/mbox +# VERBOSE=ON +LOGFILE=$MAILDIR/from +LOCKFILE=$HOME/.lockmail + +:0 c +$MAILDIR/allmail + +############################################################ Begin Mailbombing +:0: +* ^(From|Sender): .*mkagalen@lynx.dac.neu.edu +* TOurcm-board +$MAILDIR/bomb + +:0: +* ^(From|Sender): .*mkagalen@lynx.dac.neu.edu +* TOurcm-mods +$MAILDIR/bomb + +:0 +* ^From: .*mkagalen@lynx.dac.neu.edu +* ^Subject: .*Spongiform +$MAILDIR/bomb + +:0: +* From: "The Filter of mkagalen@lynx" +$MAILDIR/bomb + +# +# This recipe removes duplicates! +# +:0 Wh: msgid.lock +| formail -D 32768 msgid.cache + + +############################################################ End Mailbombing + +# Cabal maillist +:0 +* ^From .*uu.net +* ^To: urcm-board +| modenv mods-message moderators@isc.org ADVICE + +:0 +* ^From .*uu.net +* ^TOmoderators +| modenv mods-message moderators@isc.org ADVICE + +:0 +* ^From .*isc.org +* ^TOmoderators +| modenv mods-message moderators@isc.org ADVICE + + +###################################################################### Standard + +:0 +* ^TOurcm-mods +| modenv mods-message urcm-mods@algebra.com + +:0 +* ^TOurcm-board +| modenv mods-message urcm-mods@algebra.com + +:0 +* ^TOurcm-noack +| modenv stump.pl processNoack.pl + +:0 +* ^TOsoc-culture-russian-moderated +| modenv stump.pl submission.pl + +:0 +* ^TOuk.rec.cycling.moderated +| modenv stump.pl submission.pl + + +:0 +* ^TOurcm-approved +| formail -c | modenv stump.pl acceptFromMod.pl + +:0 +* ^TOurcm-rejected +| modenv stump.pl acceptFromMod.pl + +:0 +* ^TOurcm-admin +!ichudov + +:0 +* ^TOurcm-approval-key +| modenv send_pgp_key + +:0 +* ^Newsgroups: +| modenv stump.pl submission.pl + +:0 +* ^FROM_DAEMON +!ichudov + +:0 +* ^FROM_MAILER +!ichudov + +# Anything that has not been delivered by now is a submission +:0 +| modenv stump.pl submission.pl diff --git a/stump/local/README b/stump/local/README new file mode 100644 index 0000000..e0cedd9 --- /dev/null +++ b/stump/local/README @@ -0,0 +1,580 @@ +PGP Moose +========= +by Greg Rose + +The aim of this software is to monitor the news +postings of moderators of USENET newsgroups, and to +automatically cancel forged messages purporting to +be approved. This can be extended to the approvals +of individual users to automatically cancel messages +that appear without having been authorised by the +user. This has (obviously) been prompted by the +recent spammings and other events. + +This software and protocol is designed around +cryptographic signatures. The protocol is designed +to allow the use of different signature techniques. +This implemention assumes the use of PGP signatures, +but can be easily modified to use others, such as +the Digital Signature Standard. PGP was chosen for +its widespread availability around the world. + +PGP, the crux of the cryptographic software, was +written by Phil Zimmermann , who +otherwise has nothing to do with this. The +cryptographic framework was written by Greg Rose +, as were the INN news system +hooks. + + +Contents: +-------- + +How Does It Work? +The Bits: +How Do You Register For The Service? +Handling Multiple Moderated Groups: +Possible Problems We've Forseen: +Status: +Obtaining, installing, configuring: +It Really Wasn't That Hard. +License Terms: +Version: + +How Does It Work? +----------------- + +This document is written from the point of view of +a newsgroup moderator, but individual users could +also use the facility in analagous ways. + +When a moderator wants to protect their group from +forged/unapproved postings, they should register +their interest with one or more of the sites running +PGP Moose, and pick up the submission script. As +part of this process, the moderator would specify +one or more PGP public keys that are allowed to +approve postings. + +When a post comes in, and the moderator wishes to +approve it, they do whatever they would normally +do before actually using inews (or whatever) to +post the message. As their last action, they run +the PGP Moose Approval program "pmapp". This +inserts a special header which +looks like this: + +X-Auth: PGPMoose V1.0 PGP sci.crypt.research + iQBVAgUBL1/Kg2zWcw3p062JAQEYIgH/Xyrz6LaGG+fHaSxoexMECovzkIoADrQx + l73IXlUQEIoFl5jnDBBdHVvqTMEPS0118ytYVQZoQrdStuXB9Oc9gQ== + =azqs + +If there are multiple moderated newsgroups, there +might be multiple X-Auth: headers, one +for each group that has requested assistance from +the PGP Moose daemon. In this example you can +see that the authentication carries the name of +the authenticating program, a protocol version +number, an identifier of the type of digital +signature (currently only PGP) and the name of +the newsgroup in question. These, as well as the +From:, Subject: and Message-Id: lines, the list +of newsgroups, and the non-blank lines of the +message itself, are used as input to the PGP +program to generate a signature. + +The lines of the message body are preprocessed in +a way that is meant to render harmless any mangling +that a typical news system might do to the article. +The article itself is not changed, only the input +to the signature generation. If a news system +subsequently mangles the article in a "norma" way, +for instance by inserting a ">" in front of a line +starting with "From", it will still pass the signature +check. + +The list of newsgroups must be handled specially, +so that an article posted to multiple moderated +controlled newsgroups can be appropriately +handled. See below for a more detailed treatment +of the issues of posting to multiple moderated +newsgroups. + +The PGP signature is then inserted into the +X-Auth: header, mostly so that it won't +interfere with, or be confused with, any signature +in the body of the message. + +Anybody can check whether the message has been +modified in any significant way, simply by running +the PGP Moose Approval Checking program "pmcheck". +More importantly, though, the sites running the PGP +Moose Checking Daemon will be doing this automatically +for every posting to the registered newsgroups, or +from the registered users. And, if a posting fails +the checks, it may be automatically cancelled, and +a notification sent to the moderator. (Initially, +the automatic cancellation will be disabled, since +it is a pretty powerful sledgehammer, but that is +the intention anyway.) + +This software is made freely available for just +about any purpose, but I've retained copyright so +as to keep some semblance of involvement. See the +last section of this file. + + +The Bits: +--------- + +The approval and checking part of the PGP Moose +consists of a number of Bourne Shell scripts calling +standard Unix utilities and PGP. I could have used +perl more elegantly, but this stuff is marginally +more widely available. If there are Unix version +dependencies, they should be considered to be bugs +and I'll happily attempt to remove them. + +pmapp usage: pmapp [newsgroup|user] [file] + + This script takes the not-yet-posted + article, specified either by filename or + from standard input, and creates a + signature for it, which is then inserted + in the X-Auth: header. The article, + ready for posting, appears on the standard + output. + + In the configuration section at the top of + the script, the moderator may build in the + default name of the newsgroup or user, PGP + User Id to be used for the signature, and + the corresponding password. This is simply + for convenience, since spammers are not so + likely to go cracking the computer to get + the password, and it is a relatively simple + matter to generate a new user if it is, + indeed, compromised. For the paranoid, like + myself, if the password is not configured + into the script it is read from the terminal + instead. + +pmcheck usage: pmcheck [newsgroup|user] [article] + + This script takes the article, specified + either by filename or from standard + input, and checks that the + X-Auth: line is something it + considers to be correct and that the + article has not been tampered with. + Pmcheck returns successfully if + everything checks out. Otherwise it will + return failure and issue one of a number + of error messages, for example: + + Posting for $NEWSGROUP not approved with PGP Moose. + Invalid designated signature from $GROUP + No public key for signature $GROUP + Signature doesn't match $FILE for $GROUP + '$SIG' not accepted for $GROUP. + + Anybody can run pmcheck. It behaves slightly + differently depending on the existence of + a file called (by default) + PGP_Moose_accept, and the presence or + absence of a newsgroup or user argument. + This file, if it exists, should contain + lines with a newsgroup name or email address, + some whitespace, and the PGP User Id approved + by the moderator or user (usually made up + specifically for this purpose). Multiple + lines for the same newsgroup/user are allowed. + For example: + + sci.crypt.research moderator + sci.crypt.research moderator + ggr@sydney.sterling.com Greg's News + + If such a file exists, and a specific + newsgroup or user is specified, pmcheck is silent + if all is well, and issues the last of the + error messages above if everything else + was all right but the signature was from + the wrong person. There must, in this + case, be a signature applying to the + designated newsgroup or user. + + Without such a file, or if no specific + newsgroup or user is given, all the signatures + in the article are checked. In this case + it is not considered an error if the signature + cannot be checked due to a missing public + key. If each signature is otherwise valid + you will get a message like: + + Valid signature from '$SIG'. + + In any case, if there is a problem with a + signature mentioned in the PGP_Moose_accept + file, it will be reported and an error status + will be returned. + +pmcanon +pmnewsgroups + These two scripts are used by pmapp and + pmcheck to recreate the exact input for + the signature, and to extract the list of + newsgroups in the header, respectively. + More documentation is in their manual + pages. + +The PGP Moose checking daemon is packaged +separately, as there would not seem to be a lot +of value in having too many people running it. +Accordingly, I was less precise in making it run +absolutely everywhere. It requires the Korn shell +or equivalent, and perl, and currently only +interfaces to INN. I expect it would be easy to +interface it to CNews, but I don't have one. + +pmdaemon + Runs pmcheck to check the X-Auth: header + for each controlled newsgroup for each + article that arrives in an appropriate + newsgroup. Mail is sent about any errant + articles, and automatic cancellation may + be enabled. + +pmcancel + prepares a cancellation message based on + the headers of another message. + +When (if) I get a chance, I will create mail +server scripts that allow moderators who are not +using Unix to use these facilities. The first +allows a moderator to mail a PGP signed copy of +the article to be posted. The server will then +verify that the moderator sent it, and post it +with a (different but corresponding) approval. +The second will accept an article and return +something that you can check the signature on. +Either way, any moderator will still need PGP. + + +How Do You Register For The Service? +------------------------------------ + +Ahhh, this is the hard part. After all, it would +be pretty undesirable if someone, meaning well, +took any old body's word for it that some +important moderated group should start working +this way, before the moderator was able to start +approving postings. A great way to hijack a +newsgroup. Similarly for hijacking some other +user's postings (tempting though it might be :-). + +Another possibility is that someone, having seen +what the valid signature looks like, simply +creates a whole new PGP key that happens to have +the same PGP User ID. Then they can sign and post +stuff too. + +The solution to both of these problems is the +classical one for public key systems. You need +either a certifying authority or the PGP Web of +Trust. We're using the Web of Trust. If you don't +understand about PGP and the Web of Trust, go away +now and come back after you really do understand +it. + +For each newsgroup that wants to utilise this +program, the moderator will have to create a +special PGP key pair (preferably 512 bits to keep +the X-Auth: down to two full lines), and sign it. They +must then establish a path of trust to someone +who is running the PGP Moose server. It will be +up to the administrator of that server to make +sure that only trusted moderators' keys ever get +into the server's keyring. + +THERE CAN BE NO SHORTCUTS TO THIS PROCEDURE. +Otherwise we are all back where we started. + +In the case of an individual user, again you should +establish this verification path to one of the +administrators of the PGP Moose service. Contact +me (ggr@usenix.org) for the time +being to mutually figure out how to do this. + + +Handling Multiple Moderated Groups: +---------------------------------- + +When I first proposed this tool, I was under the +impression that postings to multiple moderated +groups was an abberation that should be stamped +out. This turns out not to be the case, and +revisions to support this have been the cause of +some delay in the deployment of this tool. + +When the news system sees that an article has been +posted to one or more moderated groups, it checks +for an Approved: header. If the header exists, the +article is accepted and processed normally, +otherwise it is mailed to the moderator of the +first moderated newsgroup mentioned in the +Newsgroups: header. There seem to be three cases of +interest. + +The trivial case, and the most normal one, is +that there is only one moderated newsgroup +mentioned. The moderator approves the posting, and +it is done. + +The next, and probably most important, case, is +when a moderator wants to cross-post a FAQ to +their own group, as well as news.answers (for +example). In this case their approval counts for +both groups, so they can insert the Approved: +header and post away. Presumably the other groups +are not under the control of the PGP Moose Daemon. +In this case the moderator can just go ahead and +put in the Approved: header, and save themself +and pmapp a lot of time. It will be passed right +through. + +The other case is harder to get right. This is when +the article really is meant to be posted to two (or +more) unrelated moderated newsgroups. Now, if the +first moderated group's moderator approves the +posting, the other ones never hear about the article, +at all. If this second group is controlled by the +PGP Moose an automatic cancel will be generated. So +it becomes very important for the moderators to do +what they should have been doing already, namely +forward the article to the next moderator. This tool +can't help people who don't use it, but it provides +some support for those who do. + +The approval script checks whether there are any +moderated newsgroups left that don't have +X-Auth: headers for them. If there are +none left, an Approved: header is inserted and the +article gets posted. Otherwise, it issues a warning, +and re-orders the newsgroups header with a newsgroup +which is moderated but has no X-Auth: line +at the start. When the article is posted, the news +system will forward it to the moderator of the (new) +first moderated group. If all moderators are sensible, +and check for moderated newsgroups in this fashion, +the mess should sort itself out and the last moderator +will go ahead and post it. A warning nessage to +the subsequent moderator NOT to change the +article is also inserted, since such a +modification would invalidate the previous +signatures.. + +To ease this process, a second type of +X-Auth: header is supported. this has +the form: + + X-Auth: None ... Newsgroup + +The important fact about this is that +the newsgroup appears last on the line, allowing a +sort of partial approval, from moderators who +don't use the PGP Moose. + +The Newsgroups: line is split into a sorted list +of newsgroups for the purpose of generating the +digital signature. Note that this means that once +an article has been approved and authenticated by +one moderator, it cannot be altered in any way by +a moderator of a subsequent group, including +altering the set of newsgroups mentioned in the +Newsgroups: header, the body of the posting, or +the other headers mentioned above. + + +Possible Problems We've Forseen: +-------------------------------- + +If an article is truly mangled e.g. by truncation, it +will fail the authentication and be cancelled. +Until it is demonstrated otherwise, this is +assumed to be a rare and minor problem. When a +cancel is issued, mail is sent to the moderator of +the group telling them, and they can tell us if it +becomes a problem. (In the initial deployment we +expect that no automatic cancels will actually be +generated, only the notification mail will be +sent.) + +Currently the signature produced is assumed to be +a PGP version 2.6 compatible one. + + +Status: +------- + +These scripts are implemented already, or as noted +above. They are undergoing beta testing and as soon +as they have settled they will be made available +via anonymous FTP and posting to comp.sources.misc +and sci.crypt.research and the moderators' list. + +In the meantime, if you want to use the tools, or +particularly if you want to run a PGP Moose +checking daemon, contact me (ggr@usenix.org). + + +Obtaining, installing, configuring: +----------------------------------- + +I regret that I don't have a public ftp site, but +I do have a web page where you can get a +compressed tar archive of the approval code. It is + +off my home page. + +It is hard to talk in detail about installation +and configuration, since many users are not in +charge of their own news server configuration. In +my case, I run all of the things out of a +subdirectory of my home directory. The only +thing outside this area which must be changed is +the INN newsfeeds file, if you are running the +checking daemon. So, get the distribution file as +above and unpack it whereever you want it to live. + +There are configuration sections at the top of +pmcheck, pmapp and pmdaemon. I like to think that +they are relatively self-explanatory. One of the +harder decisions is whether to use a separate +keyring for PGP Moose applications or not. It is +very strongly recommended that you do, if you are +going to run the PGP Moose checking daemon, as +the keyring files will need to be readable by the +userid which INN runs under (usually "news"). +Most of these options can also be overridden by +environment variables or command arguments, so it +is possible to leave the scripts unmodified and +simply put a wrapper around them (which is what I +do). + +In the case of pmapp, the newsgroup or user that +the authentication applies to can be specified on +the command itself; The PGP user id and password, +and the Approved: header's contents, can be +specified by environment variables PMUSER, +PMPASSWORD and APP, respectively. + +For pmcheck, the important one is the name of the +configuration file specifying which signatures +are valid for which newsgroups or users. + +Pmdaemon runs from INN, and needs some special +care to set it up. "news" needs access permission +to the directory and files for PGP Moose, and +also read permission on the public keyring. Note +that PGP creates keyrings with only owner +permissions. The search path is rarely correct, +and should be set at the top of the pmdaemon +script. There are also a number of file names and +mail addresses, but the comments should be clear +enough. + +Lastly, you want to incorporate pmapp in your +moderation script and possibly your posting +script. In my case, the last line of my posting +script basically said + + /usr/local/news/inews -S -h +regarding how to donate. You can do it over the +net using PGP! I probably also should thank the +many people who have worked hard to bring +encryption back out of the black chambers. Some +names which directly come to mind are Diffie, +Hellman, Merkle, Rivest, Shamir, Adelman, Lai, +Massey, and probably many others. + +Share and Enjoy! + + +License Terms: +------------- + +This software is copyrighted by Greg Rose, RoSecure +Software, and other parties. The following terms +apply to all files associated with the software +unless explicitly disclaimed in individual +files. + +The authors hereby grant permission to use, copy, +modify, distribute, and license this software and +its documentation for any purpose, provided that +existing copyright notices are retained in all +copies and that this notice is included verbatim +in any distributions. No written agreement, +license, or royalty fee is required for any of +the authorized uses. Modifications to this +software may be copyrighted by their authors and +need not follow the licensing terms described +here, provided that the new terms are clearly +indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE +LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS +DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN +IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY +DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS +PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND +DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + + +Version: +------- + +@(#)README 1.6 (PGPMoose) 95/10/21 diff --git a/stump/local/bin/pmapp b/stump/local/bin/pmapp new file mode 100755 index 0000000..76d4449 --- /dev/null +++ b/stump/local/bin/pmapp @@ -0,0 +1,301 @@ +#!/bin/sh + +# @(#)pmapp 1.18 (PGP Moose) 97/07/10 +# Authorisation script for PGP Moose +# Written by Greg Rose, RoSecure Software, Copyright C 1995. + +# Updated by rec.radio.amateur.moderated moderation team and Tim Skirvin - +# 21 Nov 2006 + +# Debugging +# On most shells the following statements redirect a log of what +# is happening, AND ALL ERROR MESSAGES, to /tmp/pmdebug. Some shells +# (notably /bin/sh on Ultrix systems) do not do the redirection. +#exec 2>/tmp/pmdebug +#set -x + +# Configuration Stuff: + + # Default user / newsgroup. If not set, an argument is mandatory. + #DEFAULT_NEWSGROUP=rec.radio.amateur.moderated + #DEFAULT_NEWSGROUP=misc.test.moderated + #DEFAULT_NEWSGROUP=misc.test + #DEFAULT_NEWSGROUP=panix.test + + # If an Approved: line is to be added, this is what it will say. + # Can be set in the environment. + if [ "x$APP" = "x" ]; then + APP="Authorising user " + fi + + # If a From: line is to be added, this is what it will say. + # Can be set in the environment. + if [ "x$FROM" = "x" ]; then + if [ "x$LOGNAME" = "x" ]; then + LOGNAME=`whoami` + fi + FROM="`grep \^$LOGNAME: /etc/passwd | + awk -F: '{print \$5}'` <$LOGNAME@`hostname`>" + fi + + # The PGP user and (optional) password. The password will be read + # from the controlling terminal if not specified. If the newsgroup/user + # argument is an email address, it is used instead of the configured + # PMUSER. The following line provides a default password if it is unset. + # This password will NOT be used if an email address is presented as an + # argument. + # Can be set in the environment. + if [ "x$PMUSER" = "x" ]; then + PMUSER=pgpmoose + DEFAULT_PASSWORD=t + fi + + # In the case of a user posting, the name desired on the X-Auth + # line might not be the one used by PGP to look up the key. + # In this case, set this variable or import it. By default, though, + # leave it empty and $PMUSER will be used. + # Can be set in the environment. + if [ "x$PGPUSER" = "x" ]; then + PGPUSER= + fi + + # Whether or not to fold long lines. + # Can be set in the environment. + if [ "x$FOLDLINES" = "x" ]; then + FOLDLINES=false # allowed values are 'true' or 'false' + fi + + # Name of the posting host. Must be fully qualified host.domain. + # Unless your hostname is not fuly qualified, or you want to use + # an alias, you may as well just keep it as it is. + HOSTNAME=`hostname` + + # A place to put temp files. These can add up to about twice the + # size of the article being posted. + TMP=/tmp + + # If a Message-ID is being generated, this will appear in it. + DATESTAMP=`date +%Y\%m\%d\%H\%M` # NO WHITESPACE OR METACHARACTERS + + # Where the active file is on this system, for checking crosspostings + # to multiple moderated groups. The check will be disabled if this is + # left empty (and Approved: lines will be added if needed). + ACTIVE=/usr/local/news/active + + # If the article is crossposted to other moderated groups, a warning + # tells you to reorder the newsgroups and submit the article. A copy + # of the article is deposited in this file for you to edit. + SAVED_ARTICLE=$TMP/article + +# End of configuration stuff. + +# Be neat and tidy. +TF=$TMP/pmapp$$ +trap "stty echo /dev/tty 2>/dev/null; rm -f $TF.?; exit 1" 1 2 3 15 + +# Check usage, set arguments +USAGE='echo >&2 "Usage: $0 [newsgroup|user] [article]"; exit 1' +case $# in +1) + if [ ! -r "$1" ]; then + cat >$TF.f + FILE=$TF.f + FILENAME="on standard input" + NEWSGROUP="$1" + elif [ ! "$DEFAULT_NEWSGROUP" ]; then + echo >&2 "$0: No default user or newsgroup set." + eval "$USAGE" + else + FILE="$1" + FILENAME="$1" + NEWSGROUP="$DEFAULT_NEWSGROUP" + PMPASSWORD="$DEFAULT_PASSWORD" + fi + ;; +2) + if [ ! -r $2 ]; then + echo >&2 "$0: Can't read $2" + eval "$USAGE" + fi + FILE="$2" + FILENAME="$2" + NEWSGROUP="$1" + ;; +0) + if [ ! "$DEFAULT_NEWSGROUP" ]; then + echo >&2 "$0: No default user or newsgroup set." + eval "$USAGE" + fi + cat >$TF.f + FILE=$TF.f + FILENAME="on standard input" + NEWSGROUP="$DEFAULT_NEWSGROUP" + PMPASSWORD="$DEFAULT_PASSWORD" + ;; +*) + eval "$USAGE" + ;; +esac + +case "$NEWSGROUP" in +*@*) + USERFLAG=true + PMUSER=$NEWSGROUP + # PMPASSWORD is left either as imported or null in this case. + ;; +*) + USERFLAG=false + PMPASSWORD="${PMPASSWORD-$DEFAULT_PASSWORD}" + ;; +esac + +# Set the user ID to be given to PGP to look up the key. +if [ "x$PGPUSER" = "x" ]; then + PGPUSER=$PMUSER +fi + +# Split the file into headers and body. +# Note long lines in the body may be folded. +sed -n -e '/^ *$/q' -e 'p' $FILE >$TF.h +{ echo ""; sed -e '1,/^ *$/d' $FILE; } >$TF.b +if $FOLDLINES; then + d='..........' + if grep -s "$d$d$d$d$d$d$d$d" $TF.b >/dev/null; then + echo >&2 "$0: warning: lines exceed 80 characters, being folded." + sed -e '/.\{80\}/s/.\{79\}/&\ + /g' $TF.b >$TF.l + mv $TF.l $TF.b + fi +fi + +if [ ! -s $TF.h ]; then + echo "$0: problem with article $FILENAME; header section empty." >&2 + exit 1 +fi + +# If no From: line, add one. +grep -i -s '^From:' $TF.h >/dev/null || + echo "From: $FROM" >>$TF.h + +# If no Message-ID: line, add one. +grep -i -s '^Message-ID:' $TF.h >/dev/null || + echo "Message-ID: " >>$TF.h + +# Check for or Provide a Newsgroups: line if none there, +grep -i -s '^Newsgroups:' $TF.h >/dev/null || \ + if $USERFLAG; then + # that is fine + : + else + echo "Newsgroups: $NEWSGROUP" >>$TF.h + fi + +# Get the list of newsgroups and check that we are in it! +pmnewsgroups $TF.h >$TF.n +$USERFLAG || grep -i -s "^$NEWSGROUP\$" $TF.n >/dev/null || { + echo >&2 "$0: Newsgroup $NEWSGROUP not present in article $FILENAME" + exit 1 +} + +# Read a password if none is configured. +#if [ ! "$PMPASSWORD" ]; then +# stty -echo /dev/tty 2>/dev/null +# echo "Enter PGP passphrase for $PGPUSER:" >/dev/tty +# PMPASSWORD=`head -1 /dev/tty 2>/dev/null +#fi +# --passphrase "$PMPASSWORD" + +# Compute a signature for the important information. +#PGPPASSFD=0 +#export PGPPASSFD +{ + cat $TF.h $TF.b | pmcanon | tee $TF.m +} | gpg --detach-sign --textmode --armor --batch --user "$PMUSER_APPROVAL" >$TF.s 2>$TF.e || { + echo >&2 "$0: PGP signing failed. PGP output:" + cat >&2 $TF.e + exit 1 +} + +# Add an appropriate X-Auth: header +{ + echo "X-Auth: PGPMoose V2.0 PGP $NEWSGROUP" + sed -e '1,/^$/d' -e '/END PGP SIGNATURE/d' -e 's/^/ /' $TF.s +} >>$TF.h + +# Since we are in test mode, disable Google archiving +#grep -i -s '^X-No-Archive:' $TF.h >/dev/null || +# echo "X-No-Archive: yes" >>$TF.h + +# Now one of the hardest parts. If there is no Approved: line, +# check for moderated groups that don't have an X-Auth: line +# and do something sensible. +$USERFLAG || grep -i -s '^Approved:' $TF.h >/dev/null || { + if [ "$ACTIVE" ]; then + # Cut it down to a list of un-X-Auth:ed groups + egrep -i '^X-(Auth.*|Approved):' $TF.h \ + | sed -n -e 's/^.* //p' \ + | sort \ + | comm -23 $TF.n - \ + >$TF.u + # Check if any of these are moderated + if [ -s $TF.u ]; then + badgroup= + for i in `cat $TF.u`; do + qi=`echo "$i" | sed -e 's/\./\\./g' -e 's/\+/\\+/g' ` + if grep -i -s "^$qi[ ].*[ ]m$" $ACTIVE >/dev/null; then + echo >&2 "$0: Newsgroup $i is moderated." + badgroup=$i + fi + done + if [ "x$badgroup" != x ]; then + cat >&2 <>$TF.h <>$TF.h +} + +# recreate the article on standard output. +cat $TF.h $TF.b + +rm -f $TF.? +exit 0 + diff --git a/stump/local/bin/pmcanon b/stump/local/bin/pmcanon new file mode 100755 index 0000000..498dea0 --- /dev/null +++ b/stump/local/bin/pmcanon @@ -0,0 +1,38 @@ +#!/bin/sh + +# @(#)pmcanon 1.9 (PGP Moose) 97/07/10 +# Canonicalisation script for PGP Moose +# (in other words, it takes a news article and turns it +# into something we can compute/check a signature on.) +# Written by Greg Rose, RoSecure Software, Copyright C 1995. + +# Be neat and tidy. +TMP=/tmp +TF=$TMP/pgpmt$$ +trap "rm -f /$TF.?" 0 1 2 3 15 + +# Check usage. File must be specified, and result comes out on stdout. +if [ $# -gt 1 ]; then + echo >&2 "usage: $0 [article]" + exit 1 +fi + +cat $1 >$TF.f +sed '/^ *$/q' $TF.f >$TF.h + +# multiple greps so we can guarantee order +pmnewsgroups $TF.f +{ + grep -i "^From:" "$TF.h" + grep -i "^Subject:" "$TF.h" + grep -i "^Message-ID:" "$TF.h" +} | sed -e 's/^[^:]*: *//' -e 's/: */:/g' -e 's/[ ]*$//' +sed -e '1,/^ *$/d' \ + -e '/^ *$/d' \ + -e 's/^--/- --/' \ + -e 's/^[Ff][Rr][Oo][Mm]/>&/' \ + -e 's/^[Ss][Uu][Bb][Jj][Ee][Cc][Tt]/>&/' \ + -e 's/^\.$/../' \ + -e 's/^\.[^.]/.&/' \ + -e 's/[ ]*$//' \ + "$TF.f" diff --git a/stump/local/bin/pmcheck b/stump/local/bin/pmcheck new file mode 100755 index 0000000..6faeb3f --- /dev/null +++ b/stump/local/bin/pmcheck @@ -0,0 +1,185 @@ +#!/bin/sh + +# @(#)pmcheck 1.9 (PGP Moose) 96/03/04 +# Authorisation checking script for PGP Moose +# Written by Greg Rose, RoSecure Software, Copyright C 1995. + +# Configuration: + # Where to create temporary files. + TMP=/tmp + + # Name of the file with valid moderator's/individual's names + ACCEPT=PGP_Moose_accept + +# End Configuration + +# Be neat and tidy. +TF=$TMP/pmcheck$$ +trap "rm -f $TF.?; exit 1" 1 2 3 15 + +VERBOSE=false +# Usage: $0 [newsgroup|user] [filename] +case $# in +0) + VERBOSE=true + NEWSGROUP=any + cat >$TF.f + FILE=$TF.f + FILENAME="standard input" + ;; +1) + if [ -f "$1" ]; then + VERBOSE=true + NEWSGROUP=any + FILE="$1" + FILENAME="$1" + else + cat >$TF.f + FILE=$TF.f + FILENAME="standard input" + NEWSGROUP="$1" + fi + ;; +2) + NEWSGROUP="$1" + FILE="$2" + FILENAME="$2" + ;; +*) + echo >&2 "Usage: $0 [newsgroup|user] [article]" + echo >&2 " newsgroup may be "any" to check all signatures." + exit 1 + ;; +esac + +# Find all the authentication headers we can handle +grep -i '^X-Auth.*: *PGPMoose ' $FILE | \ + sed -e 's/.* //' >$TF.g + +# For the time being, simply avoid cancel messages. +# Note that pmdaemon authenticates them, but you probably don't +# want to cancel them. +if grep -i -s '^Control:[ ]*cancel' $FILE >/dev/null; then + rm -f $TF.? + exit 0 +fi + +# The designated newsgroup must be validated. +if [ "x$NEWSGROUP" != "xany" ]; then + grep -i -s "^$NEWSGROUP\$" $TF.g >/dev/null || { + echo >&2 "$0: Posting for $NEWSGROUP not approved with PGP Moose." + rm -f $TF.? + exit 1 + } + # Uncomment this line if you only want to check this one group + echo "$NEWSGROUP" >$TF.g +fi + +# Make the document we are going to check signatures on. +pmcanon $FILE >$TF.m + +# Loop checking all X-Auth: lines required +echo 0 >$TF.b +while read GROUP; do + # Check whether this is an interesting X-Auth: line. + # This is determined by the existence of the $ACCEPT file. + # If it exists, only the groups/individuals mentioned are + # relevent. Otherwise, check everything in sight, but don't + # worry if you can't find a key or the signature doesn't match. + # CONTROLLED is 0 if there is a $ACCEPT file and this group/user is + # in it. + [ -f "$ACCEPT" ] && grep -i -s "^$GROUP[ ]" "$ACCEPT" >/dev/null + CONTROLLED=$? + if [ "$CONTROLLED" != 0 -a "$NEWSGROUP" != "any" ]; then + continue + fi + # $1 $2 $3 $4 $5 + # X-Auth: PGPMoose V1.1 PGP sci.crypt.research + set -- `grep -i "^X-Auth.*: *PGPMoose .* $GROUP\$" $FILE` + + # Check for version mismatch, but at the moment we just warn. + # It is pretty hard to know just what to do in this case. + if [ "$3" != "V2.0" -o "$4" != "PGP" ]; then + echo >&2 "$0: warning: version mismatch V2.0 PGP != $3 $4" + fi + + # reconstruct the input signature file. + cat <<-END_OF_SIG >$TF.s + -----BEGIN PGP SIGNATURE----- + Version: GnuPG v1.4.5 (NetBSD) + + END_OF_SIG + sed -n -e "1,/^[Xx]-[Aa][Uu][Tt][Hh].*: *PGPMoose .* $GROUP\$/d" \ + -e '/^ *$/,$d' \ + -e '/^[^ ]/,$d' \ + -e 's/^[ ]*//p' \ + $FILE >>$TF.s + cat <<-END_OF_SIG >>$TF.s + -----END PGP SIGNATURE----- + END_OF_SIG + + # Now we can check the signature. + gpg --verify $TF.s $TF.m >$TF.e 2>&1 + STATUS=$? +# cat >&2 $TF.s +# echo ==== +# cat >&2 $TF.m +# echo ==== +# cat >&2 $TF.e + + # If this is a target newsgroup/user, any error is bad news. + if [ "$CONTROLLED" = 0 -a $STATUS != 0 ]; then + echo >&2 "$0: Invalid designated signature from $GROUP" + echo 2 >$TF.b + continue + fi + # There are various understood error codes, not to mention the others... + # These codes come from the PGP source, and are probably not immutable. + case "$STATUS" in + 0) + # signature checks out... handle that case below + ;; + 11) + # Non-existent key + if [ "$VERBOSE" = true ]; then + echo "No public key for signature $GROUP" + fi + continue + ;; + 30) + # Signature check error + $VERBOSE || echo >&2 "Signature doesn't match $FILE for $GROUP" + echo 2 >$TF.b + continue + ;; + *) + # Some other unknown error. Treat same as Non-existent key. + if [ "$VERBOSE" = true ]; then + echo "Unknown PGP error, status = $STATUS" + cat $TF.e + fi + continue + ;; + esac + + SIG=`sed -n 's/gpg: Good signature from "\(.*\)"/\1/p' $TF.e` + if [ "x$SIG" = "x" ]; then + # this one "can't happen" + echo >&2 "$0: MOOSE ERROR: Invalid signature for $GROUP on $FILE." + fi + if [ "$VERBOSE" = "true" ]; then + echo "$0: Verified signature from '$SIG'." + fi + + # Finally, was it signed by the right person? + if [ "$CONTROLLED" = 0 ]; then + grep -i -s "^$GROUP[ ]*$SIG\$" "$ACCEPT" >/dev/null || { + echo >&2 "$0: '$SIG' not accepted for $GROUP." + echo 2 >$TF.b + } + fi +done <$TF.g + +BADSIG=`cat $TF.b` +rm -f $TF.? +exit $BADSIG diff --git a/stump/local/bin/pmnewsgroups b/stump/local/bin/pmnewsgroups new file mode 100755 index 0000000..e421cbb --- /dev/null +++ b/stump/local/bin/pmnewsgroups @@ -0,0 +1,16 @@ +#!/bin/sh + +# @(#)pmnewsgroups 1.3 (PGP Moose) 95/11/13 +# Return sorted list of newsgroups in message +sed -n -e '/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:/,/^[^ ]/p' \ + -e '/^[ ]*$/q' \ + $* \ + | sed -e 's/^[Nn][Ee][Ww][Ss][Gg][Rr][Oo][Uu][Pp][Ss]:[ ]*/ /' \ + -e '/^[^ ]/d' \ + -e 's/^[ ]*//' \ + -e 's/[ ]*$//' \ + -e 's/,[ ]*/\ +/g' \ + | tr "[A-Z]" "[a-z]" \ + | sort \ + | sed -e '/^[ ]*$/d' diff --git a/stump/local/doc/PGPMoose.README b/stump/local/doc/PGPMoose.README new file mode 100644 index 0000000..61b09f0 --- /dev/null +++ b/stump/local/doc/PGPMoose.README @@ -0,0 +1,580 @@ +PGP Moose +========= +by Greg Rose + +The aim of this software is to monitor the news +postings of moderators of USENET newsgroups, and to +automatically cancel forged messages purporting to +be approved. This can be extended to the approvals +of individual users to automatically cancel messages +that appear without having been authorised by the +user. This has (obviously) been prompted by the +recent spammings and other events. + +This software and protocol is designed around +cryptographic signatures. The protocol is designed +to allow the use of different signature techniques. +This implemention assumes the use of PGP signatures, +but can be easily modified to use others, such as +the Digital Signature Standard. PGP was chosen for +its widespread availability around the world. + +PGP, the crux of the cryptographic software, was +written by Phil Zimmermann , who +otherwise has nothing to do with this. The +cryptographic framework was written by Greg Rose +, as were the INN +news system hooks. + + +Contents: +-------- + +How Does It Work? +The Bits: +How Do You Register For The Service? +Handling Multiple Moderated Groups: +Possible Problems We've Forseen: +Status: +Obtaining, installing, configuring: +It Really Wasn't That Hard. +License Terms: +Version: + +How Does It Work? +----------------- + +This document is written from the point of view of +a newsgroup moderator, but individual users could +also use the facility in analagous ways. + +When a moderator wants to protect their group from +forged/unapproved postings, they should register +their interest with one or more of the sites running +PGP Moose, and pick up the submission script. As +part of this process, the moderator would specify +one or more PGP public keys that are allowed to +approve postings. + +When a post comes in, and the moderator wishes to +approve it, they do whatever they would normally +do before actually using inews (or whatever) to +post the message. As their last action, they run +the PGP Moose Approval program "pmapp". This +inserts a special header which +looks like this: + +X-Auth: PGPMoose V1.0 PGP sci.crypt.research + iQBVAgUBL1/Kg2zWcw3p062JAQEYIgH/Xyrz6LaGG+fHaSxoexMECovzkIoADrQx + l73IXlUQEIoFl5jnDBBdHVvqTMEPS0118ytYVQZoQrdStuXB9Oc9gQ== + =azqs + +If there are multiple moderated newsgroups, there +might be multiple X-Auth: headers, one +for each group that has requested assistance from +the PGP Moose daemon. In this example you can +see that the authentication carries the name of +the authenticating program, a protocol version +number, an identifier of the type of digital +signature (currently only PGP) and the name of +the newsgroup in question. These, as well as the +From:, Subject: and Message-Id: lines, the list +of newsgroups, and the non-blank lines of the +message itself, are used as input to the PGP +program to generate a signature. + +The lines of the message body are preprocessed in +a way that is meant to render harmless any mangling +that a typical news system might do to the article. +The article itself is not changed, only the input +to the signature generation. If a news system +subsequently mangles the article in a "norma" way, +for instance by inserting a ">" in front of a line +starting with "From", it will still pass the signature +check. + +The list of newsgroups must be handled specially, +so that an article posted to multiple moderated +controlled newsgroups can be appropriately +handled. See below for a more detailed treatment +of the issues of posting to multiple moderated +newsgroups. + +The PGP signature is then inserted into the +X-Auth: header, mostly so that it won't +interfere with, or be confused with, any signature +in the body of the message. + +Anybody can check whether the message has been +modified in any significant way, simply by running +the PGP Moose Approval Checking program "pmcheck". +More importantly, though, the sites running the PGP +Moose Checking Daemon will be doing this automatically +for every posting to the registered newsgroups, or +from the registered users. And, if a posting fails +the checks, it may be automatically cancelled, and +a notification sent to the moderator. (Initially, +the automatic cancellation will be disabled, since +it is a pretty powerful sledgehammer, but that is +the intention anyway.) + +This software is made freely available for just +about any purpose, but I've retained copyright so +as to keep some semblance of involvement. See the +last section of this file. + + +The Bits: +--------- + +The approval and checking part of the PGP Moose +consists of a number of Bourne Shell scripts calling +standard Unix utilities and PGP. I could have used +perl more elegantly, but this stuff is marginally +more widely available. If there are Unix version +dependencies, they should be considered to be bugs +and I'll happily attempt to remove them. + +pmapp usage: pmapp [newsgroup|user] [file] + + This script takes the not-yet-posted + article, specified either by filename or + from standard input, and creates a + signature for it, which is then inserted + in the X-Auth: header. The article, + ready for posting, appears on the standard + output. + + In the configuration section at the top of + the script, the moderator may build in the + default name of the newsgroup or user, PGP + User Id to be used for the signature, and + the corresponding password. This is simply + for convenience, since spammers are not so + likely to go cracking the computer to get + the password, and it is a relatively simple + matter to generate a new user if it is, + indeed, compromised. For the paranoid, like + myself, if the password is not configured + into the script it is read from the terminal + instead. + +pmcheck usage: pmcheck [newsgroup|user] [article] + + This script takes the article, specified + either by filename or from standard + input, and checks that the + X-Auth: line is something it + considers to be correct and that the + article has not been tampered with. + Pmcheck returns successfully if + everything checks out. Otherwise it will + return failure and issue one of a number + of error messages, for example: + + Posting for $NEWSGROUP not approved with PGP Moose. + Invalid designated signature from $GROUP + No public key for signature $GROUP + Signature doesn't match $FILE for $GROUP + '$SIG' not accepted for $GROUP. + + Anybody can run pmcheck. It behaves slightly + differently depending on the existence of + a file called (by default) + PGP_Moose_accept, and the presence or + absence of a newsgroup or user argument. + This file, if it exists, should contain + lines with a newsgroup name or email address, + some whitespace, and the PGP User Id approved + by the moderator or user (usually made up + specifically for this purpose). Multiple + lines for the same newsgroup/user are allowed. + For example: + + sci.crypt.research moderator + sci.crypt.research moderator + ggr@sydney.sterling.com Greg's News + + If such a file exists, and a specific + newsgroup or user is specified, pmcheck is silent + if all is well, and issues the last of the + error messages above if everything else + was all right but the signature was from + the wrong person. There must, in this + case, be a signature applying to the + designated newsgroup or user. + + Without such a file, or if no specific + newsgroup or user is given, all the signatures + in the article are checked. In this case + it is not considered an error if the signature + cannot be checked due to a missing public + key. If each signature is otherwise valid + you will get a message like: + + Valid signature from '$SIG'. + + In any case, if there is a problem with a + signature mentioned in the PGP_Moose_accept + file, it will be reported and an error status + will be returned. + +pmcanon +pmnewsgroups + These two scripts are used by pmapp and + pmcheck to recreate the exact input for + the signature, and to extract the list of + newsgroups in the header, respectively. + More documentation is in their manual + pages. + +The PGP Moose checking daemon is packaged +separately, as there would not seem to be a lot +of value in having too many people running it. +Accordingly, I was less precise in making it run +absolutely everywhere. It requires the Korn shell +or equivalent, and perl, and currently only +interfaces to INN. I expect it would be easy to +interface it to CNews, but I don't have one. + +pmdaemon + Runs pmcheck to check the X-Auth: header + for each controlled newsgroup for each + article that arrives in an appropriate + newsgroup. Mail is sent about any errant + articles, and automatic cancellation may + be enabled. + +pmcancel + prepares a cancellation message based on + the headers of another message. + +When (if) I get a chance, I will create mail +server scripts that allow moderators who are not +using Unix to use these facilities. The first +allows a moderator to mail a PGP signed copy of +the article to be posted. The server will then +verify that the moderator sent it, and post it +with a (different but corresponding) approval. +The second will accept an article and return +something that you can check the signature on. +Either way, any moderator will still need PGP. + + +How Do You Register For The Service? +------------------------------------ + +Ahhh, this is the hard part. After all, it would +be pretty undesirable if someone, meaning well, +took any old body's word for it that some +important moderated group should start working +this way, before the moderator was able to start +approving postings. A great way to hijack a +newsgroup. Similarly for hijacking some other +user's postings (tempting though it might be :-). + +Another possibility is that someone, having seen +what the valid signature looks like, simply +creates a whole new PGP key that happens to have +the same PGP User ID. Then they can sign and post +stuff too. + +The solution to both of these problems is the +classical one for public key systems. You need +either a certifying authority or the PGP Web of +Trust. We're using the Web of Trust. If you don't +understand about PGP and the Web of Trust, go away +now and come back after you really do understand +it. + +For each newsgroup that wants to utilise this +program, the moderator will have to create a +special PGP key pair (preferably 512 bits to keep +the X-Auth: down to two full lines), and sign it. They +must then establish a path of trust to someone +who is running the PGP Moose server. It will be +up to the administrator of that server to make +sure that only trusted moderators' keys ever get +into the server's keyring. + +THERE CAN BE NO SHORTCUTS TO THIS PROCEDURE. +Otherwise we are all back where we started. + +In the case of an individual user, again you should +establish this verification path to one of the +administrators of the PGP Moose service. Contact +me (Greg_Rose@sydney.sterling.com) for the time +being to mutually figure out how to do this. + + +Handling Multiple Moderated Groups: +---------------------------------- + +When I first proposed this tool, I was under the +impression that postings to multiple moderated +groups was an abberation that should be stamped +out. This turns out not to be the case, and +revisions to support this have been the cause of +some delay in the deployment of this tool. + +When the news system sees that an article has been +posted to one or more moderated groups, it checks +for an Approved: header. If the header exists, the +article is accepted and processed normally, +otherwise it is mailed to the moderator of the +first moderated newsgroup mentioned in the +Newsgroups: header. There seem to be three cases of +interest. + +The trivial case, and the most normal one, is +that there is only one moderated newsgroup +mentioned. The moderator approves the posting, and +it is done. + +The next, and probably most important, case, is +when a moderator wants to cross-post a FAQ to +their own group, as well as news.answers (for +example). In this case their approval counts for +both groups, so they can insert the Approved: +header and post away. Presumably the other groups +are not under the control of the PGP Moose Daemon. +In this case the moderator can just go ahead and +put in the Approved: header, and save themself +and pmapp a lot of time. It will be passed right +through. + +The other case is harder to get right. This is when +the article really is meant to be posted to two (or +more) unrelated moderated newsgroups. Now, if the +first moderated group's moderator approves the +posting, the other ones never hear about the article, +at all. If this second group is controlled by the +PGP Moose an automatic cancel will be generated. So +it becomes very important for the moderators to do +what they should have been doing already, namely +forward the article to the next moderator. This tool +can't help people who don't use it, but it provides +some support for those who do. + +The approval script checks whether there are any +moderated newsgroups left that don't have +X-Auth: headers for them. If there are +none left, an Approved: header is inserted and the +article gets posted. Otherwise, it issues a warning, +and re-orders the newsgroups header with a newsgroup +which is moderated but has no X-Auth: line +at the start. When the article is posted, the news +system will forward it to the moderator of the (new) +first moderated group. If all moderators are sensible, +and check for moderated newsgroups in this fashion, +the mess should sort itself out and the last moderator +will go ahead and post it. A warning nessage to +the subsequent moderator NOT to change the +article is also inserted, since such a +modification would invalidate the previous +signatures.. + +To ease this process, a second type of +X-Auth: header is supported. this has +the form: + + X-Auth: None ... Newsgroup + +The important fact about this is that +the newsgroup appears last on the line, allowing a +sort of partial approval, from moderators who +don't use the PGP Moose. + +The Newsgroups: line is split into a sorted list +of newsgroups for the purpose of generating the +digital signature. Note that this means that once +an article has been approved and authenticated by +one moderator, it cannot be altered in any way by +a moderator of a subsequent group, including +altering the set of newsgroups mentioned in the +Newsgroups: header, the body of the posting, or +the other headers mentioned above. + + +Possible Problems We've Forseen: +-------------------------------- + +If an article is truly mangled e.g. by truncation, it +will fail the authentication and be cancelled. +Until it is demonstrated otherwise, this is +assumed to be a rare and minor problem. When a +cancel is issued, mail is sent to the moderator of +the group telling them, and they can tell us if it +becomes a problem. (In the initial deployment we +expect that no automatic cancels will actually be +generated, only the notification mail will be +sent.) + +Currently the signature produced is assumed to be +a PGP version 2.6 compatible one. + + +Status: +------- + +These scripts are implemented already, or as noted +above. They are undergoing beta testing and as soon +as they have settled they will be made available +via anonymous FTP and posting to comp.sources.misc +and sci.crypt.research and the moderators' list. + +In the meantime, if you want to use the tools, or +particularly if you want to run a PGP Moose +checking daemon, contact me (Greg_Rose@sydney.sterling.com). + + +Obtaining, installing, configuring: +----------------------------------- + +I regret that I don't have a public ftp site, but +I do have a web page where you can get a +compressed tar archive of the approval code. It is + +off my home page. + +It is hard to talk in detail about installation +and configuration, since many users are not in +charge of their own news server configuration. In +my case, I run all of the things out of a +subdirectory of my home directory. The only +thing outside this area which must be changed is +the INN newsfeeds file, if you are running the +checking daemon. So, get the distribution file as +above and unpack it whereever you want it to live. + +There are configuration sections at the top of +pmcheck, pmapp and pmdaemon. I like to think that +they are relatively self-explanatory. One of the +harder decisions is whether to use a separate +keyring for PGP Moose applications or not. It is +very strongly recommended that you do, if you are +going to run the PGP Moose checking daemon, as +the keyring files will need to be readable by the +userid which INN runs under (usually "news"). +Most of these options can also be overridden by +environment variables or command arguments, so it +is possible to leave the scripts unmodified and +simply put a wrapper around them (which is what I +do). + +In the case of pmapp, the newsgroup or user that +the authentication applies to can be specified on +the command itself; The PGP user id and password, +and the Approved: header's contents, can be +specified by environment variables PMUSER, +PMPASSWORD and APP, respectively. + +For pmcheck, the important one is the name of the +configuration file specifying which signatures +are valid for which newsgroups or users. + +Pmdaemon runs from INN, and needs some special +care to set it up. "news" needs access permission +to the directory and files for PGP Moose, and +also read permission on the public keyring. Note +that PGP creates keyrings with only owner +permissions. The search path is rarely correct, +and should be set at the top of the pmdaemon +script. There are also a number of file names and +mail addresses, but the comments should be clear +enough. + +Lastly, you want to incorporate pmapp in your +moderation script and possibly your posting +script. In my case, the last line of my posting +script basically said + + /usr/local/news/inews -S -h +regarding how to donate. You can do it over the +net using PGP! I probably also should thank the +many people who have worked hard to bring +encryption back out of the black chambers. Some +names which directly come to mind are Diffie, +Hellman, Merkle, Rivest, Shamir, Adelman, Lai, +Massey, and probably many others. + +Share and Enjoy! + + +License Terms: +------------- + +This software is copyrighted by Greg Rose, RoSecure +Software, and other parties. The following terms +apply to all files associated with the software +unless explicitly disclaimed in individual +files. + +The authors hereby grant permission to use, copy, +modify, distribute, and license this software and +its documentation for any purpose, provided that +existing copyright notices are retained in all +copies and that this notice is included verbatim +in any distributions. No written agreement, +license, or royalty fee is required for any of +the authorized uses. Modifications to this +software may be copyrighted by their authors and +need not follow the licensing terms described +here, provided that the new terms are clearly +indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE +LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS +DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN +IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY +DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS +PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND +DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + + +Version: +------- + +@(#)README 1.6 (PGPMoose) 95/10/21 diff --git a/stump/local/man/man1/pmapp.1 b/stump/local/man/man1/pmapp.1 new file mode 100644 index 0000000..0828328 --- /dev/null +++ b/stump/local/man/man1/pmapp.1 @@ -0,0 +1,90 @@ +.TH PMAPP 1 "PGP Moose" +.\"@(#)pmapp.1 1.4 (PGPMoose) 95/10/21 +.SH NAME +pmapp \- insert a verifiable signature into a +news article. +.SH SYNOPSIS +.B pmapp +.I [newsgroups|user] [file] +.SH DESCRIPTION +.I Pmapp +accepts an article from the named +.IR file +(or standard input if not specified), +computes a digital signature from the important +part of the contents, and inserts a special +header into the article which enables subsequent +checking of the signature. The amended article is +produced on standard output, suitable for +injection into the news system. +.LP +The signature is created using the defaults for +the user name (and optionally password) built +into the script when a newsgroup is specified. +This is the most common case for a newsgroup +moderator who will use a customised version of +the script. These defaults can be overridden with +environment variables \f3PMUSER\fP and +\f3PMPASSWORD\fP. +.LP +In any case, whenever the +password is the empty string, a prompt is +written to the controlling terminal and a +password is read from it. +.LP +When a user is specified (by way of an email +address containing an "\fB@\fP") this is used to +select the signing user, and a password will be +requested. +.LP +When the signature is being generated for a +newsgroup, it is assumed that the newsgroup is +moderated and the invoking user is (one of) the +moderator(s). +The simple case is that there is only one +newsgroup specified; an Approved: line is added +as well as the X-Auth: line, and the +article is ready for posting. +.LP +\f2Pmapp\fP goes to some trouble to +handle the case of multiple moderated newsgroups +in the Newsgroups: line. The first, and probably +most important, case, is +when a moderator wants to cross-post a FAQ to +their own group, as well as news.answers (for +example). In this case their approval counts for +both groups, so they can insert the Approved: +header and post away. Presumably the other groups +are not under the contol of the PGP Moose Daemon. +The moderator can just go ahead and +put in the Approved: header, and save themself +and pmapp a lot of time. It will be passed right +through. +.LP +The other case is harder to get right. This is when +the article really is meant to be posted to two (or +more) unrelated moderated newsgroups. The approval +script checks whether there are any moderated +newsgroups left that don't have X-Auth: +headers for them. If there are none left, an Approved: +header is inserted and the article gets posted. +Otherwise, it issues a warning, and re-orders the +newsgroups header with a newsgroup which is moderated +but has no X-Auth: line at the start. +When the article is posted, the news system will +forward it to the moderator of the (new) first +moderated group. If all moderators are sensible, +and check for moderated newsgroups in this fashion, +the mess should sort itself out and the last moderator +will go ahead and post it. A warning message to the +subsequent moderator NOT to change the article is +also inserted. +.\".SH FILES +.SH SEE ALSO +.IR pmcheck (1), +.IR pmcanon (1) +for a description of the fields which go into the +signature calculation, +the PGP User's Manual. +.SH AUTHOR +Greg Rose, RoSecure Software. diff --git a/stump/local/man/man1/pmcanon.1 b/stump/local/man/man1/pmcanon.1 new file mode 100644 index 0000000..f80a566 --- /dev/null +++ b/stump/local/man/man1/pmcanon.1 @@ -0,0 +1,44 @@ +.TH PMCANON 1 "PGP Moose" +.\"@(#)pmcanon.1 1.3 (PGPMoose) 95/10/21 +.SH NAME +pmcanon \- put a news article in canonical format +for signature checking +.SH SYNOPSIS +.BI pmcanon [file] +.SH DESCRIPTION +.I Pmcanon +accepts an article from the named +.I file +(or standard input if not specified), selects +certain of the header fields, +and performs certain transformations intended to +defeat unintentional mangling by news transport +programs. The resulting article is written to +standard output, and is suitable to have a PGP +signature generated or checked for it. +.LP +The output produced consists (in order) of a sorted list, +one per line, of newsgroups; the From:, Subject:, +and Message-ID: lines, and the body of the +article (everything after the first empty line). +Other header lines are discarded. +.LP +The body is further processed by deleting all +blank lines, deleting trailing whitespace on +lines, prefixing lines beginning with "--", +"From", "Subject", and a single "." with "-\ ", +">", ">" and ".", respectively. These +modifications are safe, in that an article which +has already had such modifications will fail to +meet the criterion to have them happen again. +Thus what was used as input when a signature was +generated should still be the same when checked +for validity, even if some of these changes have +happened along the delivery path. +.\".SH FILES +.SH SEE ALSO +.IR pmapp (1), +.IR pmcheck (1), +PGP manual. +.SH AUTHOR +Greg Rose, RoSecure Software. diff --git a/stump/local/man/man1/pmcheck.1 b/stump/local/man/man1/pmcheck.1 new file mode 100644 index 0000000..7a70701 --- /dev/null +++ b/stump/local/man/man1/pmcheck.1 @@ -0,0 +1,83 @@ +.TH PMCHECK 1 "PGP Moose" +.\"@(#)pmcheck.1 1.5 (PGPMoose) 95/11/15 +.SH NAME +pmcheck \- check veracity and applicability of +signatures in news articles. +.SH SYNOPSIS +.B pmcheck +.I [newsgroups|user] [file] +.SH DESCRIPTION +.I Pmcheck +accepts an article from the named +.IR file +(or standard input if not specified), +and performs certain checks against digital +signatures present in X-Auth: headers +in the news articles. There are two common modes +of use +of \f2pmcheck\fP, and these are described +separately for simplicity, even though there is +considerable ability to mix-and-match. +.LP +The first use is when a person is reading news, +and sees an article and wishes to check whether +the article is an approved posting to a moderated +newsgroup, or an approved posting from a +particular individual user. Piping the article +through \f2pmcheck\fP will give a list of valid +signatures (or signatures which couldn't be +checked because corresponding PGP public keys +were unavailable), and of course generate error +messages for invalid signatures, which indicate +either forged or altered articles. Any alteration +might have been intentional, but bear in mind the +possibility that an alteration could have been an +artifact of the news system, despite precautions +against this. +.LP +The second use, and the reason for the existence +of the PGP Moose system, is when an article is +automatically checked upon receipt by a +designated news hub. In this case, a moderated +newsgroup or user name (represented by an +electronic mail address) will be specified, and +it is considered an error if there is no +corresponding X-Auth: header, or if for +any reason it doesn't check out. Furthermore, there +can be a configured file which lists pairs of +newsgroup/user names, and corresponding PGP user +IDs who are allowed to authorise such postings. +Even a valid signature from an individual who is +not listed in this file will be considered an +error. All X-Auth: headers will be +checked if their newsgroup/user name appears in +the checking file, the only way in which the +argument is special is that such a header for +that newsgroup or user \f3must\fP appear. +The intention is that any article which fails +this authentication process will be reported to +the user or newsgroup moderator(s), and might be +automatically cancelled. This is to react quickly +to spamming attacks on moderated newsgroups. +.SH EXIT STATUS +.I Pmcheck +returns an exit status of 0 if everything is all right, and non-zero otherwise. +In particular, an exit status of 1 means that the article was not +approved with the PGP Moose when it should have been, and a status of +2 is returned for all other authentication problems. +.SH SEE ALSO +.IR pmapp (1), +.IR pmcanon (1) +for a description of the fields which go into the +signature calculation, +the PGP User's Manual, +the PGP Moose README file for an understanding of +how it all hangs together. +.SH BUGS +Currently \f3pmcheck\fP always allows cancel +messages to pass, despite the fact that +\f3pmdaemon\fP always authenticates them. The +potential consequences of an automated cancellation-war were +simply too horrible to contemplate. +.SH AUTHOR +Greg Rose, RoSecure Software. diff --git a/stump/local/man/man1/pmnewsgroups.1 b/stump/local/man/man1/pmnewsgroups.1 new file mode 100644 index 0000000..e25e32c --- /dev/null +++ b/stump/local/man/man1/pmnewsgroups.1 @@ -0,0 +1,22 @@ +.TH PMNEWSGROUPS 1 "PGP Moose" +.\"@(#)pmnewsgroups.1 1.3 (PGPMoose) 95/10/21 +.SH NAME +pmnewsgroups \- extract a list of all newsgroups +from an article's headers. +.SH SYNOPSIS +.BI pmnewsgroups [file] +.SH DESCRIPTION +.I Pmnewsgroups +accepts an article from the named +.I file +(or standard input if not specified), selects +the header field, Newsgroups:, +and writes to standard output a sorted list of +the newsgroups present, one per line. +.\".SH FILES +.SH SEE ALSO +.IR pmapp (1), +.IR pmcheck (1), +.IR pmcanon (1), +.SH AUTHOR +Greg Rose, RoSecure Software. diff --git a/stump/local/src/PGPMoose.shar.gz b/stump/local/src/PGPMoose.shar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a2bdc4d8fe58e8f75900f534fd019f76c2b7b6b7 GIT binary patch literal 16949 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 z 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 newsgroups/" $1 "/address.txt";}' diff --git a/webstump/config/motd b/webstump/config/motd new file mode 100644 index 0000000..8be4b7e --- /dev/null +++ b/webstump/config/motd @@ -0,0 +1,2 @@ +Welcome to the new version of WebSTUMP. +This version supports picture attachments and makes other improvements. diff --git a/webstump/demo/error.html b/webstump/demo/error.html new file mode 100644 index 0000000..ce32cb2 --- /dev/null +++ b/webstump/demo/error.html @@ -0,0 +1,7 @@ +These Pages Are Only a Demo + +

These Pages Are Only a Demo

+ +You clicked on a button or a link that is functional in the +real installation of WebSTUMP but is disabled on these +demostration pages. Please try some other features on this page. diff --git a/webstump/demo/login.html b/webstump/demo/login.html new file mode 100644 index 0000000..b4d6be9 --- /dev/null +++ b/webstump/demo/login.html @@ -0,0 +1,38 @@ + +misc.invest.financial-plan login +

misc.invest.financial-plan login

+ + + Please log into misc.invest.financial-plan. You can only log in if + you know your login id and know the secret password. You should not + give your password to any unauthorized user. Your login id and + password are NOT case sentitive, which means that, for example, + "xyzzy" and "XyZZY" are equally valid.

+ + Log in as "admin" if you want to add/delete users or change their + passwords.

+ + First Time Users: You have to log in as admin and add a moderator user + who will be able to moderate the newsgroup. Then log in again as that + user. If you are a new user, you have to have your admin password assigned to + you by the administrator. If you are a former user of a previous version of + WebSTUMP, type "admin" in the username prompt and your old "secret word" + as the admin password.

+ + + (DEMO VERSION: Just enter something and click the SUBMIT button)

+ + +

+ + Login: +
+ Password: +
+ + + +
+ +
Thank you for using
STUMP Robomoderator. +

diff --git a/webstump/demo/main-screen.html b/webstump/demo/main-screen.html new file mode 100644 index 0000000..7c8c1fe --- /dev/null +++ b/webstump/demo/main-screen.html @@ -0,0 +1,46 @@ + +Main Moderation Screen: misc.invest.financial-plan +

Main Moderation Screen: misc.invest.financial-plan

+ +Welcome to the main moderation screen. Its main purpose is to +help you process most messages extremely quickly. For every message, it +presents you who sent it, as well as the first three non-blank lines. +For those messages where the decision is obvious, simply select your +decision (approve/reject etc) and click submit. For those messages which +you would like to review in more details, do not select anything and +use Review/Comment function from this screen or from a subsequent screen. +Remember that if you do not make any decision, the article would stay in the +queue. + +
+ + + + +
+From: "FSU/Professional Education" : FSU Online Certificate in Financial Planning(Review/Comment)
+Approve +PreApprove +Reject Offtopic +Reject Harassing +Reject Formatting +
+>>>>>>  If you need help preparing to sit for the CFP Board Exam vis
+>>>>>>  http://cpd-online.fsu.edu/finplan 
+

From: Leigh in raLeigh <lmenconi@intrex.net>: Re: Capital Gain on sale of new home(Review/Comment)
+Approve +PreApprove +Reject Offtopic +Reject Harassing +Reject Formatting +
+>>>>>>  coastal1 wrote:
+>>>>>>  > 
+>>>>>>  > The sale of a home for $500,000 or less is now tax free
+

+ +Change Password
+ + +
Thank you for using STUMP Robomoderator. +

diff --git a/webstump/demo/password.html b/webstump/demo/password.html new file mode 100644 index 0000000..065d9a4 --- /dev/null +++ b/webstump/demo/password.html @@ -0,0 +1,21 @@ + +Change Password +

Change Password

+ +All usernames and passwords are not case sensitive. +
Use this form to change your password:
+
+ + + + + +
+ New Password: +
+ + +
+ +
Thank you for using STUMP Robomoderator. +

diff --git a/webstump/demo/review.html b/webstump/demo/review.html new file mode 100644 index 0000000..0eb548b --- /dev/null +++ b/webstump/demo/review.html @@ -0,0 +1,48 @@ + +Main Moderation Screen: misc.invest.financial-plan +

Main Moderation Screen: misc.invest.financial-plan

+ +Change Password +
+ + + + +
+Comment:
+ +
+
+ +
+Received: from relay4.UU.NET (relay4.UU.NET [192.48.96.14])
+	by www.video-collage.com (8.8.5/8.8.5) with ESMTP id NAA19091
+	for <mifp@stump.algebra.com>; Thu, 4 Jun 1998 13:01:49 -0400 (EDT)
+Received: from news.fsu.edu by relay4.UU.NET with ESMTP 
+	(peer crosschecked as: news.fsu.edu [128.186.6.106])
+	id QQesim20595; Thu, 4 Jun 1998 13:02:58 -0400 (EDT)
+Received: (from news@localhost) by news.fsu.edu (8.8.3/8.7.3) id NAA20293; Thu, 4 Jun 1998 13:00:22 -0400 (EDT)
+To: misc-invest-financial-plan@uunet.uu.net
+From: "FSU/Professional Education" <mcathcart@cpd.fsu.edu>
+Newsgroups: misc.invest.financial-plan
+Subject: FSU Online Certificate in Financial Planning ::KEGHF894ND50MJ/89697971619105
+Organization: Fsu
+Message-ID: <01bd8fda$7b61ee60$7a4aba80@micr531886-0004.fsu.edu>
+X-Newsreader: Microsoft Internet News 4.70.1161
+
+If you need help preparing to sit for the CFP Board Exam visit this site:
+
+http://cpd-online.fsu.edu/finplan 
+
+
+
+ + +
Thank you for using STUMP Robomoderator. +

diff --git a/webstump/demo/welcome.html b/webstump/demo/welcome.html new file mode 100644 index 0000000..a586b68 --- /dev/null +++ b/webstump/demo/welcome.html @@ -0,0 +1,18 @@ + +Welcome to WebSTUMP +

Welcome to WebSTUMP

+ +Welcome to WebSTUMP, the moderators' front end for STUMP users -- USENET newsgroup +moderators. Only authorized users are allowed to log into this +program. + +
+Newsgroups Status:
+ + + + +
alt.religion.wicca.moderated2 messages in queue
soc.culture.russian.moderated0 messages in queue
misc.invest.financial-plan1 messages in queue
alt.sexual.abuse.recovery.moderated19 messages in queue
+
Thank you for using STUMP Robomoderator. +

diff --git a/webstump/doc/help/bad.posters.list.html b/webstump/doc/help/bad.posters.list.html new file mode 100644 index 0000000..fd086aa --- /dev/null +++ b/webstump/doc/help/bad.posters.list.html @@ -0,0 +1,13 @@ +Bad posters list is the list of email addresses (no names) of posters who +you would like to permanently bar from your newsgroup. It can be a list like +this

+ +

+spammer@savetrees.com
+troll@aol.com
+
+ +Of course, populating this list is a matter of your policy. however, I +want to warn new moderators that blacklisting is a controversial practice, +and if it is ever to be used, it should be used for a really good reason. + diff --git a/webstump/doc/help/bad.subjects.list.html b/webstump/doc/help/bad.subjects.list.html new file mode 100644 index 0000000..d397be2 --- /dev/null +++ b/webstump/doc/help/bad.subjects.list.html @@ -0,0 +1,17 @@ +Banned subects list is the list of fragments of Subject: fields or whole +Subject: fields you would like to permanently bar from your newsgroup. It +can be a list like this

+ +

+Gun control
+Abortion
+
+ +That means that no message containing (in Subject:) words "gun control" +or "abortion" would ever be posted.

+ +Of course, populating this list is a matter of your policy. However, I +want to warn new moderators that banning subjects would also have +the effect of preventing meta-discussions. For instance, someone +suggesting that Abortion should now be discussed would not be able to +post this suggestion. diff --git a/webstump/doc/help/bad.words.list.html b/webstump/doc/help/bad.words.list.html new file mode 100644 index 0000000..43f5261 --- /dev/null +++ b/webstump/doc/help/bad.words.list.html @@ -0,0 +1,21 @@ +Banned words list is the list of fragments of articles which you would +like to permanently bar from your newsgroup. For example, if you +never want articles mentioning 1-900 anywhere, you would put 1-900 +into that list.

+ +It can be a list like this

+ +

+1-900
+make money fast
+XXX
+
+ +That means that no message containing words 1-900, "make money fast", +and "xxx" will ever be posted.

+ +Of course, populating this list is a matter of your policy. However, I +want to warn new moderators that banning words would also have +the effect of preventing meta-discussions. For instance, someone +suggesting that 1-900 should now be discussed would not be able to +post this suggestion. diff --git a/webstump/doc/help/filter-lists.html b/webstump/doc/help/filter-lists.html new file mode 100644 index 0000000..0d41607 --- /dev/null +++ b/webstump/doc/help/filter-lists.html @@ -0,0 +1,48 @@ +WebSTUMP has a capability to process certain articles automatically, +without involving a human moderator. For instance, if you decide that a +certain thread has strayed off topic, and you no longer want ANY articles +from that thread to ever appear, you can add the Subject of that thread +to the list of bad threads. That will cause all submissions with that +subject header to be automatically rejected.

+ +Generally, WebSTUMP users can do filtering by the following criteria: + +

    +
  • By poster +
  • By Subject +
  • use the list of suspicious words +
+ +The algorithm for every incoming article is as follows: + +
    + +
  1. Reject message if the author is listed in the List of Banned Posters.. + +
  2. Reject message if the Subject: field is listed in the List of Banned Subjects. + +
  3. Reject message if the article contains words from the List of Banned Words. + +
  4. File message for human review if the author is listed in the List of Untrusted Posters. + +
  5. File message for human review if the Subject is listed in the List of Suspicious Subjects. + +
  6. File message for human review if the article contains words from the List of Suspicious Words. + +
  7. Approve message if the author is listed in the List of Preapproved Posters. + +
  8. Approve message if the Subject: field is listed in the List of Preapproved Subjects. + +
  9. File all still unprocessed articles for human review. +
+ +To edit filter lists, log in as "admin" to your newsgroup. Choose the +proper list and hit "Edit". be careful not to lose any changes. diff --git a/webstump/doc/help/good.posters.list.html b/webstump/doc/help/good.posters.list.html new file mode 100644 index 0000000..cc5f28e --- /dev/null +++ b/webstump/doc/help/good.posters.list.html @@ -0,0 +1,20 @@ +Good posters list is the list of email addresses (no names) of trusted +posters. All messages coming from "trusted posters", provided that they +do not fall within the purview of (other +filters), are automatically approved.

+ +Exzample:

+ +

+goodguy@aol.com
+nicegal@my-dejanews.com
+racingfan@webtv.net
+
+ +Using a preapproved list extensively does two good things: + +
    +
  • Reduces your workload by up to 90% +
  • Dramatically improves timeliness of discussions and creates a more + discussion-like atmosphere. +
other +filters), are automatically approved.

+ +Example:

+ +

+An interestnig question
+Any fans in here
+
+ diff --git a/webstump/doc/help/watch.posters.list.html b/webstump/doc/help/watch.posters.list.html new file mode 100644 index 0000000..25f355b --- /dev/null +++ b/webstump/doc/help/watch.posters.list.html @@ -0,0 +1,17 @@ +Untrusted posters list is the list of email addresses (no names) of +posters whose posts should always be reviewed by mods, even if they are +posting to a preapproved thread.

+ +Example:

+ +

+anonymous
+nobody
+remailer
+mixmaster
+losingtemper@aol.com
+
+ +The above would ensure that all addresses containing substrings above +would always come to human attention. A nice way to deal with anon +remailers. diff --git a/webstump/doc/help/watch.subjects.list.html b/webstump/doc/help/watch.subjects.list.html new file mode 100644 index 0000000..9747b36 --- /dev/null +++ b/webstump/doc/help/watch.subjects.list.html @@ -0,0 +1,15 @@ +Untrusted subjects list is the list of subjects +which should always be reviewed by mods, even if the messages are posted by +preapproved posters.

+ +Example:

+ +

+abortion
+gun control
+forger
+
+ +The above would ensure that all discussions with Subject: containing one +of the above words would be monitored. A nice way to deal with +controversial topics or flames. diff --git a/webstump/doc/help/watch.words.list.html b/webstump/doc/help/watch.words.list.html new file mode 100644 index 0000000..2b9001a --- /dev/null +++ b/webstump/doc/help/watch.words.list.html @@ -0,0 +1,24 @@ +List of words to watch is the list of text patterns +which, if they appear in a message, should ensure that the message is +not automatically approved and is stored in WebSTUMP for human review.

+ +These words may be an indication of a potential spam, or a flame +etc. Perhaps, for many groups, putting common profanities, as well +as things like XXX and 1-900, is a good strategy. Note however, that +there is generally no reason to forbid the use of profanity, as such.

+ +Example:

+ +

+happy99.exe
+fuck
+shit
+cunt
+XXX
+1-900
+1-800
+make money fast
+
+ +My advice is to watch your group for patterns appearing in offtopic posts, +and use them to your advantage to help you with filtering. diff --git a/webstump/images/bg1.jpg b/webstump/images/bg1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b8edc8a6be797f5b6b3ad4cc1d951c12b355d9f1 GIT binary patch literal 2414 zcmbtTd0Z3M7M>-OK#Z7RqPQzdh*LM*h@zFvBt$E+3|Jn|7Kn&xtVmQ;R2qYbv2Hyh*h7wZHcL^UnO{+S+^Xx;*V>+ba#{0uPJZU82{IS(MFkN|&) z55Y7j0Olhccm#m{$O0e{i-;ElVA!-0bR0*_P3T99umC23CqIUNGcjxEHI?Ze!hWEjrJxHNY#?r>x(CIczD=RCe$yqTO<}}9p zf%ake^V0V*UJ5WQ2t^_oWB?EYgc%@S0bV5PK>s*K4<2n>-yfMQ`u9RmUo1phZn z05Az5n@KtVfiMh_ATk9e93%xHm_Y)NS=LT&KIHKsw%cXQg{RUetXy}yGT*w+MH51w z+eaN7bnsa0r@W{Qlipe4>6n;)ed$Dh(T?)^E(^BYl4>(4?(}Njr5gba7-#ZO_lt_g zo|l_;9!ko{yZf+rIDA+9cbWM=JbLoVnIE`0`tbLc3o4s_e$5qZh}fNwoOQEG|I|2p znb+rA_8d8*Dy(jP_HT5#Fi5;tk)kfDY5C<1adC)Hi6F!sNER@>mADTBCYcl?K7?ZO zcG;l<6G}tVb0jvTBgsD`TK2hS| ztCTB79WAK&_C4b0J3`Hf7B$FOU$ym-(ae9GQZ@6}E)mxHvHP`F`XNlIn;*Ad)@qNS zKZd*valhgdy$teI*~`f7F*H|f)jFXxr?RtktOl<&3<(fdm)Fa*ph5xl7t}|2)-wQv zS;frOQ_o>J(rY&AqfTKR>8aJ&C*nf|E}*faC?Mk`=+;nfLA|8j&{S|-km7zNVqBHT zOL$31Vh-rP1Oxb!C}&5n8$-Qa)p{0Q*WaC3z`rH-gK>z)IHFf`^O@GK&&;H&ruw&+$d1g$awG~J-Z;SQEtcGlm+W!c z>Be%IFWKUc1GkN5BM!Sp1t*17|G24{;uc4BZ}D%qRxZw>=a*-Cp3b>=xvZ^? zRr~iwRVFl3y!V}C9!lM1g9UN(RaMqWLjpSZ_*w1Xk=u&$F1Gbuos9(Dp}CzZgtZE zTX}y7^iX)=04El2GBgO8>%*(aDCgTJm+JU_N|#x?+v<4wAz?aqb!yvrxh<48HT>4& zXl`OHnl@|oI>h6iLu}?+k~59p?_9fJd>uO6w-9|8-LR%PAH#jgOe>$rGuQON+f)Xxl&TPH`70j74q&_gSiJNPQ^DRB<3HdRJJ# z5;|GJ<=xkxaacca?d=d+XFq*R@$?eC>n~U-!km)$cuHPSf5qTG+l#uNT=nOz2!36e zl2trm)e7Rf{*=(&)cw5j=+0Q8iPA6^?A9WYBsZ9utExx}zE6({g|e)Nmbi!tkpMyC z&bA)Qyf6Bkuq#`%!>i(F1p)KQrH`kJ^V(F@;=+*yvY4cx&qJo|5yW(AFgw4-#&gPv zGrMm)mpurK6gQPDwKjE)LG|k0r@DB_iMh#|t!t_AXD`gff%~E^b#7$$^U+V2jo+nC zW~B#hRou{R?)>$!wT3^Ba-wA*7|lnwi(_McD&dOMQ-)S(YKnV`B=L7YDM52)%(y($ MSEnoJCVHj$KL#GyWdHyG literal 0 HcmV?d00001 diff --git a/webstump/images/construction.gif b/webstump/images/construction.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb166f89df9d7813112f803a18f2b98642899fc2 GIT binary patch literal 242 zcmVJJ@bv0B4Iptq;2ZH?!Fp-5iliKfuXw(bYSF*jrNIqf0tg7t)>6in2+6+1`d z#0IQ1ozv(eGkhj(8Y`{KdvcX8pLsYYD^|7aCapdQso-$6cy!l)TXHiC7|7Mv)z;@z zC9ZGFEeSM{>ol4xTGgANnI|b`!_5c6? literal 0 HcmV?d00001 diff --git a/webstump/images/help.gif b/webstump/images/help.gif new file mode 100644 index 0000000000000000000000000000000000000000..0fe148a25c205fdde81f038d378214be946c0e6c GIT binary patch literal 110 zcmZ?wbhEHb`IXCfS-H%*TZFTN7YwLc_wH+>s6F59BmL6&C NTBvbYNSA@Z8UO)?B(eYi literal 0 HcmV?d00001 diff --git a/webstump/images/new_tiny2.gif b/webstump/images/new_tiny2.gif new file mode 100644 index 0000000000000000000000000000000000000000..eacd4d8dcc9a32ae83024834904022bb37fbfc8c GIT binary patch literal 131 zcmZ?wbhEHbRA3NbSjYeZ{}~we@81t(DE?$&WME)o&;f~pj?a_L{^V;gFjxZsQc)dz literal 0 HcmV?d00001 diff --git a/webstump/images/star.gif b/webstump/images/star.gif new file mode 100644 index 0000000000000000000000000000000000000000..853f810bf0ecd09c6da9f63e73a20636ffe07451 GIT binary patch literal 115 zcmZ?wbhEHb6lD-$SjfQeABg@l?BBnifq_BsCkrD30~3P|kj(&+XJB%f(!VmBf#-Jj zY0Fg(J0vo1drDu=JZPbMEo;%6Cv!g8G`G86-zNTC`^x0M4Qns=UG!R}r6$9b5#zdW S+l`NAQ)0GyOj^LeU=0A1f-E@z literal 0 HcmV?d00001 diff --git a/webstump/images/warning_big.gif b/webstump/images/warning_big.gif new file mode 100644 index 0000000000000000000000000000000000000000..881d1fed31ad64fc243819238bdfecb9961ad885 GIT binary patch literal 288 zcmV+*0pI>dNk%w1VL1Rc0HFW?00030|Npbr(oZqF1KY>8LJ?x+FZxARXHoUh5T~^KpO}p@bMT9*{ld zlG$`ZqsD2{hYR4G0-koO%m%)&u$WvHp2uLFHvnL_WnzF`o~GCDXqN447l-Hf0?5~Q zQV26P7RZQrrSaBy2pRc9^9WaIS#-0uDagn(ld0*bIky8Es@dtey6B3UN)y7`>Pi~R z;>swhYl~^>TRcc;LhK71oHwL=%K5na+*=$dJu18~xty)Noq&64434}aTdsbbC~ozB m-UUA|f=++`bg$oFuWebSTUMP + +

WebSTUMP

+ +WebSTUMP is a user interface for STUMP and Gatekeeper users. It gives +moderators an easy and universally accessible Web interface through which +they can moderate newsgroups. Use of WebSTUMP requires NO computer +skills beyond knowing how to operate a Web browser.

+ +The demo pages give you an opportunity to "test drive" STUMP. They +are not functional in the sense that your actions do not affect anyone. +However, they do give you a "look and feel" of how WebSTUMP interface +looks to moderators.

+ +On the next page, click on a newsgroup name to begin. Try clicking on +various links and buttons and see what happens.

+ +

+Begin Test Drive! +

+
+Back to STUMP Homepage diff --git a/webstump/scripts/create-newsgroup.pl b/webstump/scripts/create-newsgroup.pl new file mode 100755 index 0000000..e4e67a7 --- /dev/null +++ b/webstump/scripts/create-newsgroup.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl +# +# This script creates a new newsgroup. +# + +if( !($0 =~ /\/scripts\/create-newsgroup\.pl$/) ) { + die "This script can only be called with full path name!!!"; +} + +$webstump_home = $0; +$webstump_home =~ s/\/scripts\/create-newsgroup\.pl$//; + +require "$webstump_home/config/webstump.cfg"; +require "$webstump_home/scripts/webstump.lib.pl"; + +&init_webstump; + +$newsgroup = @ARGV[0]; +$address = @ARGV[1]; +$password = @ARGV[2]; + +print "Creating newsgroup: +Name: $newsgroup +Approval Address: $address +Admin password: $password +Press ENTER to continue, ^C to interrupt:\n"; + +; + +print "Adding $newsgroup to $webstump_home/config/newsgroups.lst..."; +&append_to_file( "$webstump_home/config/newsgroups.lst", + "$newsgroup $address\n" ); +mkdir "$webstump_home/queues/$newsgroup", 0755; +print " done.\n"; + +$dir = "$webstump_home/config/newsgroups/$newsgroup"; + +print "Creating $dir..."; +mkdir $dir, 0755; +print " done.\n"; + +print "Creating files in $dir..."; + +&append_to_file( "$dir/blacklist", "" ); +&append_to_file( "$dir/moderators", "ADMIN \U$password\n" ); +&append_to_file( "$dir/rejection-reasons", +"offtopic::a blatantly offtopic article, spam +harassing::message of harassing content +charter::message poorly formatted +" ); +&append_to_file( "$dir/whitelist", "" ); +print " done.\n"; diff --git a/webstump/scripts/file-message.pl b/webstump/scripts/file-message.pl new file mode 100755 index 0000000..59d5f17 --- /dev/null +++ b/webstump/scripts/file-message.pl @@ -0,0 +1,97 @@ +#!/usr/bin/perl +# +# This script reads a message from stdin, figures out which newsgroup's +# queue it should be saved to, and saves it. +# +# +# Figure out the home directory +# + +umask 022; + +if( !($0 =~ /\/scripts\/file-message\.pl$/) ) { + die "This script can only be called with full path name!!!"; +} + +$webstump_home = $0; +$webstump_home =~ s/\/scripts\/file-message\.pl$//; + +open STDOUT, ">> $webstump_home/../errs" or die $!; +open STDERR, ">&STDOUT" or die $!; + +require "$webstump_home/config/webstump.cfg"; +require "$webstump_home/scripts/webstump.lib.pl"; +require "$webstump_home/scripts/filter.lib.pl"; +require "$webstump_home/scripts/mime-parsing.lib"; + +&init_webstump; + +$time = time; +$directory = "$webstump_home/tmp/dir_$time" . "_$$"; + +while( ) +{ + chop; + if( /^X-Moderate-For: / ) { + s/^X-Moderate-For: //; + $newsgroup = $_; + } elsif ( /^Subject: / ) { + $Subject = $_; + } elsif ( /^$/ ) { + last; + } +} + +die +"This message did not look like it came from STUMP because it did not +contain the X-Moderate-For: header" + if( !$newsgroup ); + +while( ($_ = ) && !($_ =~ /^\@+$/ )) {}; + +# +# this will also take away the "From " line. +# +while( ($_ = ) && ($_ =~ /^$/ )) {}; + +my ($entity, $prolog); + +if( $use_mime eq "yes" ) { + ($entity, $prolog) = &decode_mime_message( $directory ); +} else { # no MIME + $prolog = &decode_plaintext_message( $directory ); +} + +$prolog = $Subject . "\n" . $prolog; + +die "This message did not look like it came from STUMP because it did not + contain the X-Moderate-For: header" + if( !$newsgroup ); + +$queue_dir = &getQueueDir( $newsgroup ) + || die "Newsgroup $newsgroup is not listed in the newsgroups database"; + +mkdir $queue_dir, 0755; # it is OK if this fails +chmod 0755, $queue_dir; + +die "$queue_dir does not exist or is not writable" + if( ! -d $queue_dir || ! -w $queue_dir ); + +open( PROLOG, ">$directory/stump-prolog.txt" ); +print PROLOG $prolog; +close( PROLOG ); + +#open( FULL, ">$directory/full_message.txt" ); +#print FULL $entity->as_string; +#close( FULL ); + +my $dir = "dir_$time" . "_$$"; +rename $directory, "$queue_dir/$dir"; + +&init_webstump; +$request{"newsgroup"} = $newsgroup; + +#sub review_incoming_message { # Newsgroup, From, Subject, Message, Dir + +&review_incoming_message( $newsgroup, $Article_From, $Subject, + $Article_Subject, $Article_Head . $Article_Body, $dir ); diff --git a/webstump/scripts/filter.lib.pl b/webstump/scripts/filter.lib.pl new file mode 100644 index 0000000..b98b22d --- /dev/null +++ b/webstump/scripts/filter.lib.pl @@ -0,0 +1,143 @@ +# +# +# This library of functions is used for filtering messages. +# + + +# processes approval decision. +# +# Arguments: +# +# Subject, newsgroup, ShortDirectoryName, decision, comment + +sub process_approval_decision { + + my $comment = pop( @_ ); + my $decision = pop( @_ ); + my $ShortDirectoryName = pop( @_ ); + my $newsgroup = pop( @_ ); + my $Subject = pop( @_ ); + + my $address = $newsgroups_index{$newsgroup}; + + my $message = "To: $newsgroups_index{$newsgroup}\n" . + "Subject: $Subject\n" . + "Organization: http://www.algebra.com/~ichudov/stump\n"; + + $message .= "\n$decision\n"; + $message .= "comment $comment\n" if $comment; + &email_message( $message, $address ); + +print STDERR "DECISION: $decision for $ShortDirectoryName sent to $address, for $newsgroup\n"; + + &rmdir_rf( &article_file_name( $ShortDirectoryName ) ); + +} + + +###################################################################### checkAck +# checks the string matches one of the substrings. A name is matched +# against the substrings as regexps and substrings as literal substrings. +# +# Arguments: address, listname +sub name_is_in_list { # address, listname + my $listName = pop( @_ ); + my $address = pop( @_ ); + + my $item = ""; + my $Result = ""; + + $address = "\L$address"; + + open( LIST, &full_config_file_name( $listName ) ) || return ""; + + while( $item = ) { + + chop $item; + + next if $item =~ /^\s*$/; + + my $quoted_item = quotemeta( $item ); + + if( eval { $address =~ /$item/i; } || $address =~ /$quoted_item/i ) { + $Result = $item; + } + } + + close( LIST ); + + return $Result; +} + + +###################################################################### +# reviews incoming message and decides: approve, reject, keep +# in queue for human review +# +# Arguments: Newsgroup, From, Subject, Message, Dir +# +# RealSubject is the shorter subject from original posting +sub review_incoming_message { # Newsgroup, From, Subject, RealSubject, Message, Dir + my $dir = pop( @_ ); + my $message = pop( @_ ); + my $real_subject = pop( @_ ); + my $subject = pop( @_ ); + my $from = pop( @_ ); + my $newsgroup = pop( @_ ); + + if( &name_is_in_list( $from, "bad.posters.list" ) ) { + &process_approval_decision( $subject, $newsgroup, $dir, "reject abuse", "" ); + return; + } + + if( &name_is_in_list( $real_subject, "bad.subjects.list" ) ) { + &process_approval_decision( $subject, $newsgroup, $dir, "reject thread", "" ); + return; + } + + if( &name_is_in_list( $message, "bad.words.list" ) ) { + &process_approval_decision( $subject, $newsgroup, $dir, "reject charter", + "Your message has been autorejected because it appears to be off topic + based on our filtering criteria. Like everything, filters do not + always work perfectly and you can always appeal this decision." ); + return; + } + + my $warning_file = &article_file_name( $dir ) . "/stump-warning.txt"; + my $match; + + $ignore_demo_mode = 1; + + if( $match = &name_is_in_list( $from, "watch.posters.list" ) ) { + &append_to_file( $warning_file, "Warning: poster '$from' matches '$match' from the list of suspicious posters\n" ); +print STDERR "Filing Article for review because poster '$from' matches '$match'\n"; + return; # file message + } + + if( $match = &name_is_in_list( $real_subject, "watch.subjects.list" ) ) { + &append_to_file( $warning_file, "Warning: subject '$real_subject' matches '$match' from the list of suspicious subjects\n" ); +print STDERR "Filing Article for review because subject '$subject' matches '$match'\n"; + return; # file message + } + + if( $match = &name_is_in_list( $message, "watch.words.list" ) ) { + &append_to_file( $warning_file, "Warning: article matches '$match' from the list of suspicious words\n" ); +print STDERR "Filing Article for review because article matches '$match'\n"; + return; # file message + } + + if( &name_is_in_list( $from, "good.posters.list" ) ) { + &process_approval_decision( $subject, $newsgroup, $dir, "approve", "" ); + return; + } + + if( &name_is_in_list( $real_subject, "good.subjects.list" ) ) { + &process_approval_decision( $subject, $newsgroup, $dir, "approve", "" ); + return; + } + + # if the message remains here, it is stored for human review. + +} + +1; diff --git a/webstump/scripts/gatekeeper-file-message.pl b/webstump/scripts/gatekeeper-file-message.pl new file mode 100755 index 0000000..8b0db62 --- /dev/null +++ b/webstump/scripts/gatekeeper-file-message.pl @@ -0,0 +1,42 @@ +#!/usr/bin/perl +# +# This script reads a message from stdin, figures out which newsgroup's +# queue it should be saved to, and saves it. +# +# +# Figure out the home directory +# + +if( !($0 =~ /\/scripts\/gatekeeper-file-message\.pl$/) ) { + die "This script can only be called with full path name!!!"; +} + +$webstump_home = $0; +$webstump_home =~ s/\/scripts\/gatekeeper-file-message\.pl$//; + +require "$webstump_home/config/webstump.cfg"; +require "$webstump_home/scripts/webstump.lib.pl"; + +&init_webstump; + +$Subject = ""; + +$newsgroup = @ARGV[0] || die "Syntax: $0 newsgroup.name"; + +$queue_dir = &getQueueDir( $newsgroup ) + || die "Newsgroup $newsgroup is not listed in the newsgroups database"; + +mkdir $queue_dir, 0700; # it is OK if this fails + +die "$queue_dir does not exist or is not writable" + if( ! -d $queue_dir || ! -w $queue_dir ); + +$time = time; +$file = "$queue_dir/$time.$$"; +open( QUEUE_FILE, ">$file" ) || die "Could not open $file for writing"; + +while( ) { + print QUEUE_FILE; +} + +close( QUEUE_FILE ); diff --git a/webstump/scripts/gatekeeper.lib b/webstump/scripts/gatekeeper.lib new file mode 100644 index 0000000..3adca4b --- /dev/null +++ b/webstump/scripts/gatekeeper.lib @@ -0,0 +1,115 @@ +# These functions are useful for Gatekeeper product. + +# check if the header line is to be ignored +sub ignore_header { + my $header = pop( @_ ); + my @delete_headers = ( "NNTP-Posting-Host", "X-Originating-IP", + "Received", "Recieved", "Date", "X400", + "Approved" ); + foreach (@delete_headers) { + return "yes" if( $header =~ /^$_:/i ); + } + + return ""; # no +} + + +###################################################################### +# this function reads an article from a file and prepares it for posting. +sub prepareArticle { + + my $file = pop( @_ ); + + my @delete_headers = ( "NNTP-Posting-Host", "X-Originating-IP", + "Received", "Recieved", "Date", "X400", + "Approved" ); + + open ARTICLE, $file || return ""; + + my $headers = "", $body = ""; + + # headers + my $header = ""; + my $newsgroups_present = 0; + + # header + while(
) { + + next if( /^From /); + + if( /^$/ || /^\S/ ) { # non-whitespace or empty line + if( $header ) { + # process old header + if( &ignore_header( $header ) ) { + $header = ""; + next; + } + + if( $header =~ /^Newsgroups: / ) { + $newsgroups_present = 1; + if( ! ($header =~ $newsgroup)) { + chop $header; + $header .= ",$newsgroup\n"; + } + } + + $headers .= $header; + last if $_ eq "\n"; + } + + $header = $_; + } else { # whitespace + $header .= $_; + } + } + + $headers .= "$newsgroup\n" if( !$newsgroups_present ); + + $body .= $_ while(
); + +print "Header:\n\n$header\nBody:\n\n$body\n"; + + return $headers . $body; +} + +# processApproved file comment +sub processApproved { + my $comment = pop( @_ ); + my $file = pop( @_ ); + + my $article = &prepareArticle( $file ); + + if( $comment ) { + $article .= " +================================================================= +== Moderator's comment: $comment\n"; + } + + &email_message( $article, $posting_gateway ) if( $posting_gateway ); + + if( $posting_spool_dir ) { + my $time = time; + my $spoolfile = "$posting_spool_dir/$$.$time"; + open( SPOOL, ">$posting_spool_dir/$$.$time" ) + || &error( "Can't open $spoolfile" ); + print SPOOL $message; + close( SPOOL ); + } +} + + +# processDecision file decision+reason comment +sub gk_approval_decision{ + my $comment = pop( @_ ); + my $decision = pop( @_ ); + my $file = pop( @_ ); + + if( $decision eq "approve" ) { + &processApproved( $file, $comment ); + } elsif( $decision eq "reject" ) { + my ($dummy, $reason) = split( $decision ); + &processRejected( $file, $reason, $comment ); + } +} + +1; diff --git a/webstump/scripts/html_output.pl b/webstump/scripts/html_output.pl new file mode 100644 index 0000000..e99c8d1 --- /dev/null +++ b/webstump/scripts/html_output.pl @@ -0,0 +1,877 @@ +# +# This is a module with functions for HTML output. +# +# I separate it from the main STUMP stuff because these functions are +# bulky and not very interesting. +# +# + +use POSIX; + +sub begin_html { + my $title = pop( @_ ); + print +"Content-Type: text/html\n\n +$title + +

$title

\n\n"; + + if( &is_demo_mode ) { + print " You are operating in demonstration mode. User actions will have no effect.
\n"; + } + +} + +sub end_html { + print "\n
Thank you for using STUMP Robomoderator. + +"; +} + +# prints a link to help +# accepts topic id and topic name. +# +sub link_to_help { + my $topic_name = pop( @_ ); + my $topic = pop( @_ ); + + #&print_image( "help.gif", "" ); + + print "Click here for help on $topic_name\n"; +} + +# +# prints image and an alt text +# +sub print_image { # image_file, alt_text + my $alt = pop( @_ ); + my $file = pop( @_ ); + + print "\"$alt\"\n"; +} + +# prints the welcome page and login screen. +sub html_welcome_page { + &begin_html( "Welcome to WebSTUMP" ); + + print + +"Welcome to WebSTUMP, the moderators' front end for STUMP users -- USENET newsgroup +moderators. Only authorized users are allowed to log into this +program. + +
"; + + my $motd_file = "$webstump_home/config/motd"; + + if( -f $motd_file && -r $motd_file ){ + open( MOTD, $motd_file ); + print "Message of the Day:
\n";
+    print while(  );
+    close( MOTD );
+    print "

\n"; + } + + print " +Newsgroups Status:
+\n"; + + for( sort @newsgroups_array ) { + print ""; + + + print ""; +# print "\n"; + } + + print "
"; + + my $count = &get_article_count( $_ ); + + print " $_"; + &print_image( "smiley.gif", "" ) if $count; + print "$count messages in queue
Request creation
\n"; + print "
Note: click on the newsgroup to login in as moderator. +\n
+Click here to administer this WebSTUMP installation +"; + &end_html; +} + +# prints the login screen for newsgroup. +sub html_login_screen { + my $newsgroup = $request{'newsgroup'} || &error( "newsgroup not defined" ); + + my $count = &get_article_count( $newsgroup ); + + + if( $count ) { + &begin_html( "$count articles in queue for $newsgroup" ); + } else { + &begin_html( "Empty Queue for $newsgroup" ); + } + + print +" Welcome to the Moderation Center for $newsgroup. Please bookmark +this page.
"; + + + my $color = "", $end_color = ""; + + if( $count ) { + $color = ""; + $end_color = ""; + } + + print +"
+ + $color ($count "; + + &print_image( "new_tiny2.gif", "new" ) if $count; + + print " articles available)
$end_color + Login: +
+ Password: +
+ + + +

+ Please log into $newsgroup. You can only log in if you know your login id + and know the secret password. You should not give your password to any + unauthorized user. Your login id and password are NOT case sentitive, + which means that, + for example, \"xyzzy\" and \"XyZZY\" are equally valid.

+"; + + print " + Log in as \"admin\" if you want to +

    +
  • edit filtering lists."; + + &link_to_help( "filter-lists", "Filter Lists" ); + + print " +
  • add/delete users or change their passwords. +
  • First Time Users: You have to log in as admin and add a moderator user + who will be able to moderate the newsgroup. Then log in again as that + user. If you are a new user, you have to have your admin password assigned to + you by the administrator. +
+ +"; + &end_html; +} + +# prints the login screen for newsgroup. +sub admin_login_screen { + &begin_html( "Administrative login" ); + + print +" +Attention: this page is only for the maintainer of the whole WebSTUMP +installation. Please return to the main page if you are not the maintainer +of this installation.
+"; + + print +"
+ + Password: +
+ + +
+"; + + &end_html; +} + +# main moderation page -- old version +sub html_moderate_article { + my $newsgroup = &required_parameter( 'newsgroup' ); + my $moderator = $request{'moderator'}; + my $password = $request{'password'}; + my $file = shift @_ || &required_parameter('file'); + + &begin_html( "Main Moderation Screen: $newsgroup" ); + print "
\n"; + + &read_rejection_reasons; + + my $dir = "$queues_dir/$newsgroup"; + + if( -d "$dir/$file" && open( TEXT_FILES, "$dir/$file/text.files.lst" ) ) { + + print "
\n" if &print_article_warning( $file ); + + print "
\n";
+      my $filename;
+      my $inhead= 1;
+      while( $filename =  ) {
+        open( ARTICLE, "$dir/$file/$filename" );
+        while( 
) { + $embolden= m/^(?:from|subject)\s*\:/i; + s/\&/&/g; + s//>/g; + $_= "$_" if $embolden; + print; + $inhead= 0 unless m/\S/; + } + close( ARTICLE ); + $inhead= 0; + } + + print "\n
\n\n"; + + &print_images( $newsgroup, "$dir/$file", $file); + + } else { + print "This message ($dir/$file) no longer exists -- maybe it was " . + "approved or rejected by another moderator."; + } + + print "
+
+"; + + print " +"; + &html_print_credentials; + print "
Comment:
"; + + print "
+Don't change poster's status +Preapprove poster + Ban All Posts by this Person (Careful!) +

+Don't change thread's status + +
+ +Ban Entire Thread By Subject (Careful!) +Put Entire thread on a Watch, by Subject: + +

+ +NOTE: Decisions to ban and preapprove posters and threads can be reversed by +logging in as \"admin\" and editing respective lists of preapproved +and banned threads and posters. +"; + + &link_to_help( "filter-lists", "automatic filtering and filter lists, blacklisting and preapproved threads." ); + + print "Be really careful about blacklisting of everyone except spammers.

+ + + Review ONE article in next screen + + Review multiple articles in next screen +
+ + + + +"; + + print "
\n\n"; + print "
Change Password"; + + closedir( QUEUE ); + &end_html; +} + +# WebSTUMP administrative screen +sub webstump_admin_screen { + + &verify_admin_password; + + my $password = $request{'password'}; + + &begin_html( "WebSTUMP Administration" ); + print " +
+ +\n"; + + + print " +
+Create a new newsgroup on the server:
+ +Newsgroup:

+Address to send approved/rejected messages
+
+Admin Password For this group:

+ +
+"; + + print "
\n\n
\n";
+
+  &end_html;
+}
+
+# WebSTUMP "add newsgroup" function
+sub admin_add_newsgroup {
+
+  &verify_admin_password;
+
+  my $newsgroup = &required_parameter( 'newsgroup_name' );
+
+  $newsgroup =~ s/\///g;
+  $newsgroup = &untaint( $newsgroup );
+
+  my $address = &required_parameter( 'newsgroup_approved_address' );
+  my $password = &required_parameter( 'newsgroup_password' );
+
+  &user_error( "Newsgroup $newsgroup already exists" )
+    if defined $newsgroups_index{$newsgroup};
+
+  &user_error( "Password may only contain letters and digits" )
+    if( ! ($password =~ /^[a-zA-Z0-9]+$/ ) );
+
+  &begin_html( "WebSTUMP Administration: Newsgroup created" );
+
+  print "
\n\n";
+
+  print "Adding $newsgroup to $webstump_home/config/newsgroups.lst...";
+  mkdir "$webstump_home/queues/$newsgroup", 0755;
+  print " done.\n";
+  
+  $dir = "$webstump_home/config/newsgroups/$newsgroup";
+  
+  print "Creating $dir...";
+  mkdir $dir, 0755;
+  print " done.\n";
+  
+  print "Creating files in $dir...";
+  
+  &append_to_file( "$dir/blacklist", "" );
+  &append_to_file( "$dir/address.txt", "$address\n" );
+  &append_to_file( "$dir/moderators", "ADMIN \U$password\n" );
+  &append_to_file( "$dir/rejection-reasons",
+"offtopic::a blatantly offtopic article, spam
+harassing::message of harassing content
+charter::message poorly formatted
+" );
+  &append_to_file( "$dir/whitelist", "" );
+  print " done.\n";
+
+
+  print "
\n"; + + &end_html; +} + +# +# +sub print_images { + $web_subdir = pop( @_ ); + $subdir = pop( @_ ); + $newsgroup = pop( @_ ); + + opendir( SUBDIR, $subdir ); + + my $count = 0; + + while( $_ = readdir( SUBDIR ) ) { + my $file = "$subdir/$_"; + next if( ! -f $file || ! -r $file ); + my $extension = $file; + $extension =~ s/^.*\.//; + $extension = "\L$extension"; + + if( $extension eq "gif" || $extension eq "jpg" || $extension eq "jpeg" ) { + print "

\n"; + $count++; + } else { + my $filename = $_; + $filename =~ s/^.*\///; + next if $filename eq "skeleton.skeleton" + || $filename eq "headers.txt" + || $filename eq "full_message.txt" + || $filename eq "text.files.lst" + || $filename eq "stump-prolog.txt" + || $filename eq "stump-warning.txt" + || $filename =~ /msg-.*\.doc/; + + &print_image( "no_image.gif", "security warning" ); + print "Non-image attachment:$filename NOT SHOWN for security reasons.
\n"; + } + } + return $count; +} + +# prints warning if there is warning stored about the article +sub print_article_warning { # short-subdir + my $file = pop( @_ ); + + my $warning_file = &article_file_name( $file ) . "/stump-warning.txt"; + + if( -r $warning_file ) { + open( WARNING, $warning_file ); + while ($warning = ) { + next unless $warning =~ m/\S/; + $warning =~ s/\&/&/g; + $warning =~ s//>/g; + &print_image( "star.gif", "warning" ); + print "$warning
\n"; + } + close( WARNING ); + return 1; + } + + return 0; +} + +sub get_queue_list ($) { + my ($newsgroup) = @_; + my $dir = "$queues_dir/$newsgroup"; + my %sortkeys; + + opendir(QUEUED, $dir) or &error("could not open directory $dir"); + + for (;;) { + $!=0; + my $subdir= scalar readdir(QUEUED); + last unless defined $subdir; + + my $subpath= "$dir/$subdir"; + next if $subdir =~ /^\.+/; + next unless -d $subpath; + my $sortkey; + if (!stat "$subpath/stump-warning.txt") { + $!==&ENOENT or die "$subpath $!"; + $sortkey= 0; + } else { + $sortkey= (stat _)[9]; + } + $sortkeys{$subdir}= $sortkey; + } + closedir( QUEUED ); + my @articles= sort { $sortkeys{$a} <=> $sortkeys{$b} } keys %sortkeys; + return ($dir, @articles); +} + +# main moderation page +sub html_moderation_screen { + my $newsgroup = &required_parameter( 'newsgroup' ); + my $moderator = $request{'moderator'}; + my $password = $request{'password'}; + + + if( $request{'next_screen'} eq 'single' ) { + # we show a single article if the user so requested. + # just get the first article from the queue if any, otherwise show + # an empty main screen. + + my ($dir, @articles)= get_queue_list($newsgroup); + + my $i; + for ($i=0; $i<@articles; $i++) { + my $subdir= shift @articles; + push @articles, $subdir; + last if $request{"decision_$subdir"}; + } + + while( $subdir = shift @articles ) { + if( -d "$dir/$subdir" && !($subdir =~ /^\.+/) + && open( PROLOG, "$dir/$subdir/stump-prolog.txt" ) ) { + &html_moderate_article( $subdir ); + return; + } + } + } else { + # otherwise just show the moderator an empty main screen. + } + + &begin_html( "Main Moderation Screen: $newsgroup" ); + print "Welcome to the main moderation screen. Its main purpose is to +help you process most messages extremely quickly. For every message, it +presents you who sent it, as well as the first three non-blank lines. +For those messages where the decision is obvious, simply select your +decision (approve/reject etc) and click submit. For those messages which +you would like to review in more details, do not select anything and +use Review/Comment function from this screen or from a subsequent screen. +Remember that if you do not make any decision, the article would stay in the +queue.\n"; + + &read_rejection_reasons; + + my ($dir, @articles)= get_queue_list($newsgroup); + + print " +
+ "; + &html_print_credentials; + + my $file, $subject = "No Subject", $from = "From nobody"; + my $form_not_empty = ""; + my $article_count = 0; + my $warning = ""; + while( ($subdir = shift @articles) && $article_count++ < 40 ) { + $file=$subdir; + if( -d "$dir/$subdir" && !($subdir =~ /^\.+/) + && open( PROLOG, "$dir/$subdir/stump-prolog.txt" ) ) { + while( ) { + chop; + if( /^Real-Subject: /i ) { + s/\&/&/g; + s//>/g; + s/^Real-Subject: //g; + $subject = substr( $_, 0, 50 ); + } elsif( /^From: /i ){ + s/\&/&/g; + s//>/g; + $from = substr( $_, 0, 50 ); + } elsif( /^$/ ) { + last; + } + } + + print "
$from: $subject("; + print "Review/Comment/Preapprove)
\n"; + print "Approve\n"; + print "Leave\n"; + print "Back of queue\n"; + foreach (@short_rejection_reasons) { + print "Reject \u$_\n"; + } + + print "
\n"; + + &print_article_warning( $file ); + + print "
\n";
+
+        my $i = 0;
+
+        while( ($_ = ) && $i < 5 ) {
+            chop;
+	    next if m/^\>/;
+	    s/\&/&/g;
+            s//>/g;
+            if( $_ ne "" ) {
+              print "]  " . substr( $_, 0, 75 ) . "\n";
+              $i++;
+            }
+        }
+
+        print "
"; + $form_not_empty = "yes"; + close( PROLOG ); + $article_count += &print_images( $newsgroup, "$dir/$subdir", $subdir ); + } + } + + if( $form_not_empty ) { + print "
+ +"; + } else { + print " +
+No articles present in the queue + +
\n"; + } + + print "Change Password"; + + print "\n\n"; + + print "
"; + &html_print_credentials; + print " + +
"; + + &end_html; +} + +# prints hidden fields -- credentials +sub html_print_credentials { + my $newsgroup = $request{'newsgroup'}; + my $moderator = $request{'moderator'}; + my $password = $request{'password'}; + + print " + + + \n"; +} + +# newsgroup admin page +sub html_newsgroup_management { + &begin_html( "Administer $request{'newsgroup'}" ); + + print "All usernames and passwords are not case sensitive.\n"; + print "
Use this form to add new moderators or change passwords:
+
+ "; + &html_print_credentials; + print " + Username: +
+ Password: +
+ + +
+"; + + print "
Use this form to delete moderators:
+
+ "; + &html_print_credentials; + print " + Username: +
+ + +

+ +
+ "; + &html_print_credentials; + print " + Configuration List: + + "; + + &link_to_help( "filter-lists", "filtering lists" ); + + print " +

+ + List of current moderators:

+ +

    \n"; + + foreach (keys %moderators) { + print "
  • $_\n"; + } + + print "
\n"; + + &end_html; +} + + +# edit config list +sub edit_configuration_list { + + my $list_to_edit = &required_parameter( 'list_to_edit' ); + + $list_to_edit = &check_config_list( $list_to_edit ); + + my $list_file = &full_config_file_name( $list_to_edit ); + + my $list_content = ""; + + if( open( LIST, $list_file ) ) { + $list_content .= $_ while( ); + close( LIST ); + } + + $list_content =~ s/\&/&/g; + $list_content =~ s//>/g; + + &begin_html( "Edit $list_to_edit" ); + + print +"
+ + "; + &html_print_credentials; + &link_to_help( $list_to_edit, "$list_to_edit" ); + print " + Edit this list:
+ + +
+ +
+"; + + &end_html; +} + +# password change page +sub html_change_password{ + &begin_html( "Change Password" ); + + print "All usernames and passwords are not case sensitive.\n"; + print "
Use this form to change your password:
+
+ "; + &html_print_credentials; + print " +
+ New Password: +
+ + +
+"; + + &end_html; +} + + +# newsgroup creation form +sub init_request_newsgroup_creation{ + my $newsgroup = &required_parameter( 'newsgroup' ); + + &begin_html( "Request Creation of $newsgroup" ); + + print "This page helps you ask the system administrator of your domain +to create $newsgroup on your server. Type in your domain name and +click SUBMIT. An email will be sent to news\@domain and usenet\@domain +and postmaster\@domain +asking them to create your newsgroup. Please do NOT abuse this system. +NOTE: You can give the URL of this page to your group readers so that +they could request creation of their newsgroups by themselves.\n"; + + print "
+
+ \n"; + &html_print_credentials; + print " +
+ Domain Name ONLY: +
+ + +
+"; + + &end_html; +} + + +# newsgroup creation completion +sub complete_newsgroup_creation_request{ + my $newsgroup = &required_parameter( 'newsgroup' ); + my $domain_name = &required_parameter( 'domain_name' ); + + if( !($domain_name =~ /(^[a-zA-Z0-9\.-_]+$)/) ) { + &user_error( "invalid domain name" ); + } + + $domain_name = $1; + + + my $request = "To: news\@$domain_name, usenet\@$domain_name, postmaster\@$domain_name +Subject: Please create $newsgroup (Moderated) +From: devnull\@algebra.com ($newsgroup Moderator) +Organization: stump.algebra.com + +Dear News Administrator: + +A user of $domain_name has requested that you create a newsgroup + + $newsgroup (Moderated) + +on your server. $newsgroup +is a legitimately created moderated newsgroup that is available worldwide. + +Thank you very much for your help and cooperation. + +Sincerely, + + - Moderator of $newsgroup. + +"; + + &email_message( $request, "news\@$domain_name" ); + &email_message( $request, "usenet\@$domain_name" ); + &email_message( $request, "postmaster\@$domain_name" ); + + &begin_html( "Request to create $newsgroup sent" ); + + print "The following request has been sent:
\n";
+
+  print "$request
\n"; + + &end_html; +} + +# displays help +sub display_help { + my $topic_name = &required_parameter( "topic" ); + + $topic_name =~ s/\///g; + $topic_name =~ s/\.\.//g; + $topic_name = &untaint( $topic_name ); + + my $file = "$webstump_home/doc/help/$topic_name.html"; + + &error( "Topic $topic_name not found in $file." ) + if ! -r $file; + + open( FILE, "$file" ); + my $help = ""; + $help .= $_ while( ); + close( FILE ); + + $help =~ s/##/$base_address?action=help&topic=/g; + + &begin_html( "$topic_name" ); + + print $help; + + print "
"; +} + + + + + + + +1; diff --git a/webstump/scripts/mime-parsing.lib b/webstump/scripts/mime-parsing.lib new file mode 100644 index 0000000..4605f10 --- /dev/null +++ b/webstump/scripts/mime-parsing.lib @@ -0,0 +1,177 @@ +# +# this is a library of perl routines for MIME parsing. +# + +if( $use_mime eq "yes" ){ + require MIME::Parser; + require Convert::UU; import uudecode; +} + +sub uudecode_text { + my $dir = pop( @_ ); + my $entity = pop( @_ ); + + my $type = $entity->mime_type; + my $body = $entity->stringify_body; + + if( $type =~ /^text\// ) { + my $filename = $entity->bodyhandle->path; + $filename =~ s/.*\///; + print TEXT_FILES $filename . "\n"; + + my $count = 0; + while(1) { + last if( $count++ > 15 ); + my ($data, $name, $mode ) = &uudecode( $body ); + $name =~ s/\//_/g; + + if( $data && $name ) { + $body =~ s/\nbegin.*?\nend\n/((((Encoded File: $name))))\n/s; + if( open( FILE, ">$dir/$name" ) ) { + print FILE $data; + close FILE; + chmod 0644, $file; + } + my $filename = $entity->bodyhandle->path; + open( REDUCED, ">$filename" ); + print REDUCED $body; + close( REDUCED ); + } else { + last; + } + } + } else { + $body = ""; + } + + $body =~ s/\n+/\n/gs; + + return $body; +} + +sub decode_mime_message { + my $dir = pop( @_ ); + mkdir $dir, 0775; + chmod 0755, $dir; + #chdir $dir; + + # Create parser, and set the output directory: + my $parser = new MIME::Parser; + $parser->output_dir( $dir ); + + # Parse input: + $entity = $parser->read(\*STDIN) or die "couldn't parse MIME stream"; + + open( FULL, ">$dir/full_message.txt" ); + print FULL $entity->as_string; + close( FULL ); + + + my $RealSubject = "Real-Subject: " . $entity->head->get( "Subject" ); + + my $prolog = "From: " . $entity->head->get( "From" ) . "$RealSubject\n"; + + open( SKELETON, ">$dir/skeleton.skeleton" ); + $entity->dump_skeleton( \*SKELETON ); + close( SKELETON ); + + open( HEAD, ">$dir/headers.txt" ); + print HEAD $entity->head->as_string . "\n"; + close( HEAD ); + + open( TEXT_FILES, ">$dir/text.files.lst" ); + + print TEXT_FILES "headers.txt\n"; + + my $body = &uudecode_text( $entity, $dir ); + $body =~ /(.*\n){0,3}/s; + + $prolog .= $1; + + if( $entity->is_multipart ) { + foreach( $entity->parts() ) { + print $_->mime_type . "\n"; + $body = &uudecode_text( $_, $dir ); + $body =~ /(.*\n){0,3}/s; + $prolog .= $1; + } + } + + close( TEXT_FILES ); + + $Article_From = $entity->head->get( "From" ); + chop $Article_From; + $Article_Subject = $entity->head->get( "Subject" ); + chop $Article_Subject; + $Article_Head = $entity->head->as_string; + $Article_Body = $body; + + chmod $dir, 0755; + return ($entity, $prolog); +} + +sub decode_plaintext_message { + my $dir = pop( @_ ); + + $Article_Head = ""; + + while( ) { + $Article_Head .= $_; + chomp; + if( /^From: / ) { + $Article_From = $_; + $Article_From =~ s/^From: //; + } elsif( /^Subject: / ) { + $Article_Subject = $_; + $Article_Subject =~ s/^Subject: //; + } + + last if /^$/; + } + + $Article_Body = ""; + + $Article_Body .= $_ while( ); + + return &file_plaintext_message( $dir ); + +} + +# stores a plaintext message in a fashion similar to a MIME message +sub file_plaintext_message { + my $dir = pop( @_ ); + + mkdir $dir, 0775; + chmod 0755, $dir; + + open( FULL, ">$dir/full_message.txt" ); + print FULL $Article_Body; + close( FULL ); + + + my $prolog = "From: " . $Article_From . "\nReal-Subject: $Article_Subject"; +# . "Subject: " . $entity->head->get( "Subject" ); + + $prolog .= "\n\n"; + + open( SKELETON, ">$dir/skeleton.skeleton" ); + close( SKELETON ); + + open( HEAD, ">$dir/headers.txt" ); + print HEAD $Article_Head . "\n"; + close( HEAD ); + + open( TEXT_FILES, ">$dir/text.files.lst" ); + + print TEXT_FILES "headers.txt\nfull_message.txt\n"; + + my $body = $Article_Body; + $body =~ /(.*\n){0,3}/s; + + $prolog .= $1; + + close( TEXT_FILES ); + + return $prolog; +} +1; diff --git a/webstump/scripts/strip-ats.pl b/webstump/scripts/strip-ats.pl new file mode 100755 index 0000000..f4ab19f --- /dev/null +++ b/webstump/scripts/strip-ats.pl @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +$after_ats = 0; + +while( ) { + + if( $after_ats ) { + print; + } elsif( /^\@\@\@/ ) { + $after_ats = 1; + } +} diff --git a/webstump/scripts/webstump.lib.pl b/webstump/scripts/webstump.lib.pl new file mode 100644 index 0000000..8397f86 --- /dev/null +++ b/webstump/scripts/webstump.lib.pl @@ -0,0 +1,733 @@ +# this is a collection of library functions for stump. + +use IO::Handle; + +# error message +sub error { + my $msg = pop( @_ ); + + if( defined $html_mode ) { + print +"Content-Type: text/html\n\n +WebSTUMP Error + +

You have encountered an error in WebSTUMP.

"; + + &print_image( "construction.gif", "bug in WebSTUMP" ); + + print " $msg
+Please cut and paste this +whole page and send it to $supporter.

+Query Parameters:

\n +