Adding Authinfo Support
Starling <[email protected]>
| Newsgroups | gmane.network.sn |
|---|---|
| Message-ID | <[email protected]> |
Say um... shouldn't sn do some form of authinfo? I mean, a local news server would be perfect for a message board if it had authinfo (and perhaps stunnel but that's another story...). Is anyone working on this? Eh, well regardless I added authinfo for write-access support to my copy of sn yesterday. Might as well attach the diff. Sorry for stepping on anyone's toes. I think it's pretty much bug free. I've never done a diff before. Is this the right numbering scheme, diff format, et. al? Starling Who's going to do some homework now.
sn.diff
(text/x-patch, 11.5 KB)
diff -U 3 --new-file sn-0.3.5/CHANGES sn-0.3.6/CHANGES --- sn-0.3.5/CHANGES Sat Jul 6 08:38:51 2002 +++ sn-0.3.6/CHANGES Mon Dec 9 20:51:37 2002 @@ -1,5 +1,26 @@ -- -0.3.5 Sat Jul 6 18:37:50 EEST 2002 +0.3.6 Sun Dec 8 21:17:30 PDT 2002 +Added AUTHINFO functionality. I mean, jeez... +New configuration files: +SNROOT/user.allow + file with "user:password" pairs, one per line + Note, the "user:password" line has a MAX of 200 characters, + 'cause I'm too lazy to use dynamic memory. Administrators + beware. + Note, this file has to be chown news.news and chmod o-rw or snntpd + will not use it and post a warning log. + +SNROOT/.auth + presence activates authentication + +The RFC didn't say to drop the connection on failed authentication, +but my emacs gnus seems to depend on that and I noticed another news +server doing it so... + +entry by Starling ([email protected]) + +-- +0.3.5 Sat Jul 6 18:37:50 EEST 2002 Added an FAQ, containg the solution to the infamous POST problem. NEWGROUPS and NEWNEWS now works properly during DST. (Was offset one hour.) Made "sncat -i foo" work for users with read-only access to the spool. @@ -34,7 +55,7 @@ snexpire bug related to =junk. writefifo has been failing for a few revs now! Fixed. -- -0.3.2 Fri Mar 3 22:33:02 SGT 2000 +0.3.2 Fri Mar 3 22:33:02 SGT 2000 Changed ctime to mtime, when checking .created. Date conversion error, e.g. for NEWGROUPS and NEWNEWS. Doc error, command line example using tcpserver. @@ -99,14 +120,14 @@ snget (and others) takes -P, passes to snfetch. 0-length article bodies now legal in snntpd and snscan. -- -0.2.3 Mon Dec 7 12:44:03 SGT 1998 +0.2.3 Mon Dec 7 12:44:03 SGT 1998 Option -m for snget to limit initial articles. snpost locking now performed. snmail EOL conversion error; rewrite. snntpd LIST command output format error. snfetch rnews format error. -- -0.2.2 Thu Oct 8 11:02:54 SGT 1998 +0.2.2 Thu Oct 8 11:02:54 SGT 1998 -r option in snstore, snfetch, sncat. Rewrote snget as binary instead of script. Merged dh_dump() into sndumpdb.c, it didn't belong in dhash.c. @@ -125,7 +146,7 @@ Better snpost reporting. Off-by-one in art.c, resulting in random crashes. -- -0.2.1 Wed Aug 5 18:29:37 SGT 1998 +0.2.1 Wed Aug 5 18:29:37 SGT 1998 Missing realloc in subscribed.c, reorg in newsgroup.c. -- 0.2.0 Sat Jul 11 13:34:03 SGT 1998 diff -U 3 --new-file sn-0.3.5/Makefile sn-0.3.6/Makefile --- sn-0.3.5/Makefile Wed Jun 12 03:16:33 2002 +++ sn-0.3.6/Makefile Sun Dec 8 23:14:06 2002 @@ -10,14 +10,14 @@ ## No: Leave ZLIB undefined. #ZLIB = ## Where the news spool will be, e.g.: SNROOT=/var/spool/news -SNROOT =/home/patrik/spool/news +SNROOT =/var/spool/news ## Where to install the executables, e.g.: BINDIR=/usr/local/sbin -BINDIR =/home/patrik/sn/bin +BINDIR =/usr/local/news/bin ## Where to install the man pages, e.g.: MANDIR=/usr/local/man -MANDIR =/home/patrik/sn/man +MANDIR =/usr/local/news/man ## Where to send mail for the admin if neither the NEWSMASTER nor ## the LOGNAME environment variable is set -DEFAULT_ADMIN_EMAIL =newsmaster +DEFAULT_ADMIN_EMAIL =news # # OS-specific settings. Uncomment only one section below. @@ -47,7 +47,7 @@ # VERSION =0.3.5 -AOBJS =art.o cache.o group.o times.o dh_find.o dhash.o \ +AOBJS =art.o auth.o cache.o group.o times.o dh_find.o dhash.o \ allocate.o newsgroup.o hostname.o \ store.o parameters.o args.o body.o unfold.o path.o \ addr.o valid.o key.o field.o @@ -166,6 +166,7 @@ ## DO NOT REMOVE ## art.o: art.c config.h art.h artfile.h cache.h +auth.o: auth.c auth.h cache.o: cache.c cache.h group.o: group.c config.h cache.h group.h artfile.h times.o: times.c config.h times.h cache.h diff -U 3 --new-file sn-0.3.5/auth.c sn-0.3.6/auth.c --- sn-0.3.5/auth.c Wed Dec 31 16:00:00 1969 +++ sn-0.3.6/auth.c Mon Dec 9 20:43:48 2002 @@ -0,0 +1,111 @@ +#include "auth.h" +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +extern void log (char *fmt, ...); + +struct authinfo auth; +int auth_required = 0; + +#define BUFSIZE 200 + +static char complete[BUFSIZE]; +static char buffer[BUFSIZE]; + +int checkperms(int fd) +{ + struct stat statbuf; + + if(fstat(fd, &statbuf)) + { + log("Stat error! %s\n", strerror(errno)); + return 0; + } + + if(statbuf.st_mode & ( S_IWOTH | S_IROTH | S_IXOTH) || + statbuf.st_uid != getuid() || + statbuf.st_gid != getgid()) + { + log("user.allow needs to be chown news.news or chmod 660."); + return 0; + } + + return 1; +} + +int find_user(char* data) +{ + FILE* db = fopen("user.allow", "r"); + int len = 0; + + if(!db) goto FAIL; + + if(!checkperms(fileno(db))) goto FAIL; + + while(fgets(buffer, BUFSIZE, db)) + { + if((len = (int) (strchr(buffer, ':') - buffer))) + { + strncpy(complete, buffer, len); + if(!strncmp(complete, data, strlen(data))) + { + fclose(db); + return 1; + } + } + } + + FAIL: + + bzero(complete, BUFSIZE); + + fclose(db); + return 0; +} + +int find_pass(char* data) +{ + FILE* db = fopen("user.allow", "r"); + + if(!db) goto FAIL; + if(!checkperms(fileno(db))) goto FAIL; + + strcat(complete, ":"); + + if(strlen(data) + strlen(complete) > BUFSIZE) goto FAIL; + + strcat(complete, data); + + while(fgets(buffer, BUFSIZE, db)) + { + char* p = strchr(buffer, '\n'); + if(p) *p = '\0'; + + if(!strcmp(buffer, complete)) + { + fclose(db); + return 1; + } + } + + FAIL: + + bzero(complete, BUFSIZE); + + fclose(db); + return 0; +} + +void check_user(char* data) +{ + auth.user = find_user(data); +} + +void check_pass(char* data) +{ + auth.pass = auth.user = find_pass(data); +} diff -U 3 --new-file sn-0.3.5/auth.h sn-0.3.6/auth.h --- sn-0.3.5/auth.h Wed Dec 31 16:00:00 1969 +++ sn-0.3.6/auth.h Sun Dec 8 23:14:06 2002 @@ -0,0 +1,12 @@ +/* Interface for authorization. */ + +struct authinfo { + int user; + int pass; +}; + +extern struct authinfo auth; +extern int auth_required; + +void check_user(char* data); +void check_pass(char* data); diff -U 3 --new-file sn-0.3.5/commands.c sn-0.3.6/commands.c --- sn-0.3.5/commands.c Tue May 28 14:31:44 2002 +++ sn-0.3.6/commands.c Sun Dec 8 23:26:35 2002 @@ -27,6 +27,7 @@ #include "body.h" #include "snntpd.h" #include "key.h" +#include "auth.h" #include <b.h> #include <tokensep.h> #include <wildmat.h> @@ -37,18 +38,76 @@ #define putdot() args_write(1, ".\r\n") -void do_ihave (void) { args_write(1, "435 I'm happy for you\r\n"); } +void do_ihave (void) { args_write(1, "435 I'm happy for you. Try post.\r\n"); } void do_sendme (void) { args_write(1, "500 No thanks\r\n"); } -void do_slave (void) { args_write(1, "202 Whatever\r\n"); } +void do_slave (void) { args_write(1, "202 Not since the civil war, yank.\r\n"); } void do_help (void) { args_write(1, "100 Help yourself\r\n.\r\n"); } void do_mode (void) { - if (posting_ok) - args_write(1, "200 Hi, you can post (sn version " VERSION ")\r\n"); - else - args_write(1, "201 Hi, you can't post (sn version " VERSION ")\r\n"); + if (posting_ok) + args_write(1, "200 Hi, you can post (sn version " VERSION ")\r\n"); + else + args_write(1, "201 Hi, you can't post (sn version " VERSION ")\r\n"); } + +/* Authorization mode. */ + +extern void do_quit(void); + +void do_authinfo(void) +{ + char flag; + char* data; + + if(!auth_required) + { + args_write(1, "102 No authorization required.\r\n"); + return; + } + + if(strcasecmp(args[1],"user") && strcasecmp(args[1], "pass")) { + args_write(1, "501 Usage authinfo user <user> then authinfo pass <pass>\r\n"); + return; + } + + flag = args[1][0]; + data = args[2]; + + switch(flag) + { + case 'u': + case 'U': + check_user(data); + args_write(1, "381 PASS required for %s\r\n", data); + break; + case 'p': + case 'P': + if(!auth.user) + { + args_write(1, "482 USER required\r\n"); + break; + } else { + check_pass(data); + if(!auth.pass) + { + args_write(1, "502 Authentication failed\r\n"); + do_quit(); + } + } + break; + default: + args_write(1, "502 %s doesn't start with '%c'?\r\n", args[1], flag); + break; + }; + + if(auth.user && auth.pass) + { + posting_ok = 1; + args_write(1, "281 I know you! You can post\r\n"); + } +} + /* Several ways to specify an article. The group may be the current one, or it may be a different one */ Common subdirectories: sn-0.3.5/lib and sn-0.3.6/lib diff -U 3 --new-file sn-0.3.5/parameters.c sn-0.3.6/parameters.c --- sn-0.3.5/parameters.c Thu May 23 17:37:11 2002 +++ sn-0.3.6/parameters.c Sun Dec 8 23:14:06 2002 @@ -27,7 +27,7 @@ snroot = SNROOT; if (-1 == stat(snroot, &st)) - fail(2, "Can't find \"%s\":%m"); + fail(2, "Can't find \"%s\":%m", snroot); if (!S_ISDIR(st.st_mode)) fail(2, "%s is not a directory"); snuid = st.st_uid; diff -U 3 --new-file sn-0.3.5/post.c sn-0.3.6/post.c --- sn-0.3.5/post.c Sat Oct 6 09:39:48 2001 +++ sn-0.3.6/post.c Sun Dec 8 23:14:06 2002 @@ -98,7 +98,10 @@ if (!posting_ok) { - args_write(1, "440 Posting not allowed\r\n"); + if(!auth_required) + args_write(1, "440 Posting not allowed\r\n"); + else + args_write(1, "480 Authorization required\r\n"); return; } diff -U 3 --new-file sn-0.3.5/snntpd.8.in sn-0.3.6/snntpd.8.in --- sn-0.3.5/snntpd.8.in Mon Jul 26 02:55:49 1999 +++ sn-0.3.6/snntpd.8.in Mon Dec 9 20:45:40 2002 @@ -48,7 +48,7 @@ .SH POSTING AND POSTING PERMISSIONS Posts are usually handled externally by the .RB !!BINDIR!!/ POST -script, +script, which is responsible for fine-grain posting control; handling of control messages; and the ultimate distribution of the posted article. @@ -73,6 +73,19 @@ .RB $ POSTING_OK is not currently used, but is reserved. + +.TP +.B AUTHINFO +If +.RB !!SNROOT!!/ .auth +exists, authinfo support is enabled. + +.RB !!SNROOT!!/ user.access +should have a list of newline delineated user:pass pairs for +which user is authorized by which password. These do not +correspond to login users. user.access must be owned by +news.news and not world read or writeable. + .SH FILES .TP .RB !!SNROOT!!/ .fifo @@ -94,6 +107,12 @@ .TP .RB !!SNROOT!!/ .nopost +See +.B POSTING PERMISSIONS +above. + +.TP +.RB !!SNROOT!!/ .auth See .B POSTING PERMISSIONS above. diff -U 3 --new-file sn-0.3.5/snntpd.c sn-0.3.6/snntpd.c --- sn-0.3.5/snntpd.c Mon May 27 13:17:35 2002 +++ sn-0.3.6/snntpd.c Sun Dec 8 23:14:06 2002 @@ -55,6 +55,7 @@ extern int currentserial; extern void do_article (void); +extern void do_authinfo(void); extern void do_body (void); extern void do_group (void); extern void do_head (void); @@ -91,6 +92,7 @@ static struct cmd cmds[] = { DEF(article, 1, 0, 0, 0) + DEF(authinfo, 3, 0, 0, 0) DEF(body, 1, 0, 0, 0) DEF(group, 2, 0, 0, 1) DEF(head, 1, 0, 0, 0) @@ -199,6 +201,15 @@ posting_ok = 1; else posting_ok = 0; + + if (0 == stat(".auth", &st)) + { + auth_required = 1; + posting_ok = 0; + } + else + auth_required = 0; + openfifo(); checkservice = 0; } diff -U 3 --new-file sn-0.3.5/snntpd.h sn-0.3.6/snntpd.h --- sn-0.3.5/snntpd.h Sat Oct 6 10:27:33 2001 +++ sn-0.3.6/snntpd.h Sun Dec 8 23:14:06 2002 @@ -9,6 +9,7 @@ #define SNNTPD_H extern int posting_ok; +extern int auth_required; extern char *client_ip; extern char *me; extern struct readln input; diff -U 3 --new-file sn-0.3.5/user.allow.EXAMPLE sn-0.3.6/user.allow.EXAMPLE --- sn-0.3.5/user.allow.EXAMPLE Wed Dec 31 16:00:00 1969 +++ sn-0.3.6/user.allow.EXAMPLE Sun Dec 8 23:45:52 2002 @@ -0,0 +1,6 @@ +ima_user:mypassword +Foobar:eatshorts +Hmm:dmm +Dorothy:toto +legolas:gandalf +ozy:millie \ No newline at end of file