comparison src/server.c @ 288:c02c4eb95f95 noffle

[svn] * src/configfile.h,src/configfile.c,docs/noffle.conf.5: Add noffle-user and noffle-group configs. * src/configfile.c,src/fetch.c,src/fetchlist.c,src/protocol.c, src/server.c: Replace strcpy() with Utl_cpyStr() where appropriate. See Debian bug 168128. * src/control.c,src/configfile.c,src/noffle.c: Replace [s]scanf("%s") with [s]scanf(MAXCHAR_FMT). * src/noffle.c: Log warning if noffle.conf is world readable. * src/noffle.c: Restrict most options to news admins; i.e. those who are root or news on running Noffle. * Makefile.in,acconfig.h,aclocal.m4,config.h.in,configure,configure.in, docs/Makefile.in,docs/noffle.conf.5,packages/Makefile.in, packages/redhat/Makefile.in,src/Makefile.am,src/Makefile.in, src/authenticate.c,src/authenticate.h,src/noffle.c,src/server.c: Add basic authentication using either Noffle-specific user file or authenticating via PAM (service 'noffle'). PAM authentication needs to run as root, so a Noffle server that needs PAM must be started by root. Helpful (?) error messages will be logged if not. Noffle will switch ruid and euid to 'news' (or whatever is configured) ASAP. * src/noffle.c: Add uid checking.
author bears
date Fri, 10 Jan 2003 23:25:45 +0000
parents 3477050e8d10
children f81fdcc2696b
comparison
equal deleted inserted replaced
287:01755687c565 288:c02c4eb95f95
1 /* 1 /*
2 server.c 2 server.c
3 3
4 $Id: server.c 403 2002-11-10 11:32:17Z bears $ 4 $Id: server.c 420 2003-01-10 23:25:45Z bears $
5 */ 5 */
6 6
7 #if HAVE_CONFIG_H 7 #if HAVE_CONFIG_H
8 #include <config.h> 8 #include <config.h>
9 #endif 9 #endif
24 #include <errno.h> 24 #include <errno.h>
25 #include <signal.h> 25 #include <signal.h>
26 #include <stdarg.h> 26 #include <stdarg.h>
27 #include <sys/types.h> 27 #include <sys/types.h>
28 #include <unistd.h> 28 #include <unistd.h>
29 #include "authenticate.h"
29 #include "client.h" 30 #include "client.h"
30 #include "common.h" 31 #include "common.h"
31 #include "configfile.h" 32 #include "configfile.h"
32 #include "content.h" 33 #include "content.h"
33 #include "database.h" 34 #include "database.h"
47 #include "server.h" 48 #include "server.h"
48 #include "util.h" 49 #include "util.h"
49 #include "wildmat.h" 50 #include "wildmat.h"
50 #include "portable.h" 51 #include "portable.h"
51 52
53 enum AuthState {
54 NEED_USER,
55 NEED_PASS,
56 AUTH_DONE
57 };
58
52 struct 59 struct
53 { 60 {
54 Bool running; 61 Bool running;
55 time_t lastServerOpen; 62 time_t lastServerOpen;
56 int artPtr; 63 int artPtr;
57 Str grp; /* selected group, "" if none */ 64 Str grp; /* selected group, "" if none */
58 DynStr *reply; 65 DynStr *reply;
59 Bool eotAfterReply; 66 Bool eotAfterReply;
60 Bool groupReady; 67 Bool groupReady;
61 } server = { FALSE, 0L, 0, "", NULL, FALSE, FALSE }; 68 enum AuthState auth;
69 char *user;
70 } server = {
71 FALSE, /* running */
72 0L, /* lastServerOpen */
73 0, /* artPtr */
74 "", /* grp */
75 NULL, /* reply */
76 FALSE, /* eotAfterReply */
77 FALSE, /* groupReady */
78 NEED_USER, /* auth */
79 NULL /* user */
80 };
62 81
63 typedef struct Cmd 82 typedef struct Cmd
64 { 83 {
65 const char *name; 84 const char *name;
66 const char *syntax; 85 const char *syntax;
86 Bool needAuth;
67 /* Returns false, if quit cmd */ 87 /* Returns false, if quit cmd */
68 Bool (*cmdProc)( char *arg, const struct Cmd *cmd ); 88 Bool (*cmdProc)( char *arg, const struct Cmd *cmd );
69 } 89 }
70 Cmd; 90 Cmd;
71 91
72 static Bool doArt( char *arg, const Cmd *cmd ); 92 static Bool doArt( char *arg, const Cmd *cmd );
93 static Bool doAuthinfo( char *arg, const Cmd *cmd );
73 static Bool doBody( char *arg, const Cmd *cmd ); 94 static Bool doBody( char *arg, const Cmd *cmd );
74 static Bool doGrp( char *arg, const Cmd *cmd ); 95 static Bool doGrp( char *arg, const Cmd *cmd );
75 static Bool doHead( char *arg, const Cmd *cmd ); 96 static Bool doHead( char *arg, const Cmd *cmd );
76 static Bool doHelp( char *arg, const Cmd *cmd ); 97 static Bool doHelp( char *arg, const Cmd *cmd );
77 static Bool doIhave( char *arg, const Cmd *cmd ); 98 static Bool doIhave( char *arg, const Cmd *cmd );
94 static void closeServer( void ); 115 static void closeServer( void );
95 static Bool initServer( void ); 116 static Bool initServer( void );
96 117
97 Cmd commands[] = 118 Cmd commands[] =
98 { 119 {
99 { "article", "ARTICLE [msg-id|n]", &doArt }, 120 { "article", "ARTICLE [msg-id|n]", TRUE, &doArt },
100 { "body", "BODY [msg-id|n]", &doBody }, 121 { "authinfo", "AUTHINFO USER username|PASS password", FALSE, &doAuthinfo },
101 { "head", "HEAD [msg-id|n]", &doHead }, 122 { "body", "BODY [msg-id|n]", TRUE, &doBody },
102 { "group", "GROUP grp", &doGrp }, 123 { "head", "HEAD [msg-id|n]", TRUE, &doHead },
103 { "help", "HELP", &doHelp }, 124 { "group", "GROUP grp", TRUE, &doGrp },
104 { "ihave", "IHAVE (ignored)", &doIhave }, 125 { "help", "HELP", FALSE, &doHelp },
105 { "last", "LAST", &doLast }, 126 { "ihave", "IHAVE (ignored)", TRUE, &doIhave },
127 { "last", "LAST", TRUE, &doLast },
106 { "list", "LIST [ACTIVE [pat]]|ACTIVE.TIMES [pat]|" 128 { "list", "LIST [ACTIVE [pat]]|ACTIVE.TIMES [pat]|"
107 "EXTENSIONS|NEWSGROUPS [pat]|OVERVIEW.FMT", &doList }, 129 "EXTENSIONS|NEWSGROUPS [pat]|OVERVIEW.FMT", TRUE, &doList },
108 { "listgroup", "LISTGROUP grp", &doListgrp }, 130 { "listgroup", "LISTGROUP grp", TRUE, &doListgrp },
109 { "mode", "MODE (ignored)", &doMode }, 131 { "mode", "MODE (ignored)", FALSE, &doMode },
110 { "newgroups", "NEWGROUPS [xx]yymmdd hhmmss [GMT]", &doNewgrps }, 132 { "newgroups", "NEWGROUPS [xx]yymmdd hhmmss [GMT]", TRUE, &doNewgrps },
111 { "newnews", "NEWNEWS (not implemented)", &notImplemented }, 133 { "newnews", "NEWNEWS (not implemented)", TRUE, &notImplemented },
112 { "next", "NEXT", &doNext }, 134 { "next", "NEXT", TRUE, &doNext },
113 { "post", "POST", &doPost }, 135 { "post", "POST", TRUE, &doPost },
114 { "quit", "QUIT", &doQuit }, 136 { "quit", "QUIT", FALSE, &doQuit },
115 { "slave", "SLAVE (ignored)", &doSlave }, 137 { "slave", "SLAVE (ignored)", TRUE, &doSlave },
116 { "stat", "STAT [msg-id|n]", &doStat }, 138 { "stat", "STAT [msg-id|n]", TRUE, &doStat },
117 { "xhdr", "XHDR over-field [msg-id|m[-[n]]]", &doXhdr }, 139 { "xhdr", "XHDR over-field [msg-id|m[-[n]]]", TRUE, &doXhdr },
118 { "xpat", "XPAT over-field msg-id|m[-[n]] pat", &doXpat }, 140 { "xpat", "XPAT over-field msg-id|m[-[n]] pat", TRUE, &doXpat },
119 { "xover", "XOVER [m[-[n]]]", &doXOver } 141 { "xover", "XOVER [m[-[n]]]", TRUE, &doXOver }
120 }; 142 };
121 143
122 /* 144 /*
123 Notice interest in reading this group. 145 Notice interest in reading this group.
124 Automatically subscribe if option set in config file. 146 Automatically subscribe if option set in config file.
662 noteInterest(); 684 noteInterest();
663 return TRUE; 685 return TRUE;
664 } 686 }
665 687
666 static Bool 688 static Bool
689 doAuthinfo( char *line, const Cmd *cmd )
690 {
691 #if USE_AUTH
692 Str s, arg;
693 const char *data;
694
695 if ( ! Cfg_needClientAuth() )
696 {
697 putStat( STAT_AUTH_REJECTED, "Authentication not required" );
698 return TRUE;
699 }
700
701 if ( sscanf( line, MAXCHAR_FMT, s ) != 1 )
702 {
703 badsyntax:
704 if ( server.auth != AUTH_DONE )
705 server.auth = NEED_USER;
706 putSyntax( cmd );
707 }
708 else
709 {
710 Utl_toLower( s );
711 Utl_cpyStr( arg, Utl_restOfLn( line, 1 ) );
712 data = Utl_stripWhiteSpace( arg );
713
714 if ( strcmp( "user", s ) != 0 && strcmp( "pass", s ) != 0 )
715 goto badsyntax;
716
717 if ( strcmp( "user", s ) == 0 && server.auth == NEED_USER )
718 {
719 if ( server.user != NULL )
720 free( server.user );
721 Utl_allocAndCpy( &server.user, data );
722 server.auth = NEED_PASS;
723 putStat( STAT_MORE_AUTH_REQUIRED, "More authentication required" );
724 }
725 else if ( strcmp( "pass", s ) == 0 && server.auth == NEED_PASS )
726 {
727 enum AuthResult authRes = Auth_authenticate( server.user, data );
728 char *p;
729
730 /* Zap the password */
731 for ( p = line; *p != '\0'; p++ )
732 *p = 'X';
733
734 switch ( authRes )
735 {
736 case AUTH_OK:
737 server.auth = AUTH_DONE;
738 putStat( STAT_AUTH_ACCEPTED, "Authentication accepted" );
739 Log_inf( "User %s authenticated", server.user );
740 break;
741
742 case AUTH_FAILED:
743 server.auth = NEED_USER;
744 putStat( STAT_NO_PERMISSION, "No permission");
745 Log_dbg( LOG_DBG_AUTH, "User %s password %s rejected",
746 server.user, data );
747 break;
748
749 case AUTH_DISCONNECT:
750 putStat( STAT_NO_PERMISSION, "No permission - disconnecting" );
751 Log_dbg( LOG_DBG_AUTH,
752 "User %s password %s rejected - disconnecting",
753 server.user, data );
754 return FALSE;
755
756 default: /* AUTH_ERROR */
757 putStat( STAT_PROGRAM_FAULT, "Authentication program error" );
758 Log_dbg( LOG_DBG_AUTH,
759 "Error authenticating User %s password %s",
760 server.user, data );
761 return FALSE;
762 }
763 }
764 else
765 {
766 if ( server.auth == AUTH_DONE )
767 putStat( STAT_AUTH_REJECTED, "Reauthentication not possible" );
768 else
769 {
770 putStat( STAT_AUTH_REJECTED, "Authentication rejected" );
771 server.auth = NEED_USER;
772 }
773 }
774 }
775 #else
776 UNUSED( line );
777 UNUSED( cmd );
778
779 putStat( STAT_AUTH_REJECTED, "Authentication not possible" );
780 #endif
781 return TRUE;
782 }
783
784 static Bool
667 doHelp( char *arg, const Cmd *cmd ) 785 doHelp( char *arg, const Cmd *cmd )
668 { 786 {
669 unsigned int i; 787 unsigned int i;
670 788
671 UNUSED( arg ); 789 UNUSED( arg );
837 if ( sscanf( line, MAXCHAR_FMT, s ) != 1 ) 955 if ( sscanf( line, MAXCHAR_FMT, s ) != 1 )
838 doListActive( "*" ); 956 doListActive( "*" );
839 else 957 else
840 { 958 {
841 Utl_toLower( s ); 959 Utl_toLower( s );
842 strcpy( arg, Utl_restOfLn( line, 1 ) ); 960 Utl_cpyStr( arg, Utl_restOfLn( line, 1 ) );
843 pat = Utl_stripWhiteSpace( arg ); 961 pat = Utl_stripWhiteSpace( arg );
844 if ( pat[ 0 ] == '\0' ) 962 if ( pat[ 0 ] == '\0' )
845 pat = "*"; 963 pat = "*";
846 if ( strcmp( "active", s ) == 0 ) 964 if ( strcmp( "active", s ) == 0 )
847 doListActive( pat ); 965 doListActive( pat );
1435 putStat( STAT_PROGRAM_FAULT, "%s", s ); 1553 putStat( STAT_PROGRAM_FAULT, "%s", s );
1436 } 1554 }
1437 1555
1438 /* Parse line, execute command and return FALSE, if it was the quit command. */ 1556 /* Parse line, execute command and return FALSE, if it was the quit command. */
1439 static Bool 1557 static Bool
1440 parseAndExecute( Str line ) 1558 parseAndExecute( Str line, Bool authDone )
1441 { 1559 {
1442 unsigned int i, n; 1560 unsigned int i, n;
1443 Cmd *c; 1561 Cmd *c;
1444 Str s, arg; 1562 Str s, arg;
1445 Bool ret; 1563 Bool ret;
1446 1564
1447 if ( sscanf( line, MAXCHAR_FMT, s ) == 1 ) 1565 if ( sscanf( line, MAXCHAR_FMT, s ) == 1 )
1448 { 1566 {
1449 Utl_toLower( s ); 1567 Utl_toLower( s );
1450 strcpy( arg, Utl_restOfLn( line, 1 ) ); 1568 Utl_cpyStr( arg, Utl_restOfLn( line, 1 ) );
1451 n = sizeof( commands ) / sizeof( commands[ 0 ] ); 1569 n = sizeof( commands ) / sizeof( commands[ 0 ] );
1452 for ( i = 0, c = commands; i < n; ++i, ++c ) 1570 for ( i = 0, c = commands; i < n; ++i, ++c )
1453 if ( strcmp( c->name, s ) == 0 ) 1571 if ( strcmp( c->name, s ) == 0 )
1454 { 1572 {
1573 #if USE_AUTH
1574 if ( c->needAuth && ! authDone )
1575 {
1576 putStat( STAT_AUTH_REQUIRED, "Authentication required" );
1577 return TRUE;
1578 }
1579 #else
1580 UNUSED( authDone );
1581 #endif
1455 ret = c->cmdProc( Utl_stripWhiteSpace( arg ), c ); 1582 ret = c->cmdProc( Utl_stripWhiteSpace( arg ), c );
1456 return ret; 1583 return ret;
1457 } 1584 }
1458 } 1585 }
1459 putStat( STAT_NO_SUCH_CMD, "Command not recognized" ); 1586 putStat( STAT_NO_SUCH_CMD, "Command not recognized" );
1499 { 1626 {
1500 Bool done; 1627 Bool done;
1501 Str line; 1628 Str line;
1502 1629
1503 putWelcome(); 1630 putWelcome();
1631
1632 #if USE_AUTH
1633 /*
1634 * If authentication is required, we issue the welcome message and
1635 * go into a command loop that doesn't open the databases and just
1636 * accepts authentication commands. Once successfully authenticated,
1637 * we drop root privs (if we have them - they are needed for PAM
1638 * authentication to work) and proceed to the normal loop.
1639 */
1640 if ( Cfg_needClientAuth() )
1641 {
1642 if ( ! Auth_open() )
1643 {
1644 initOutput();
1645 putFatal( "Cannot open authorisation" );
1646 sendOutput();
1647 return;
1648 }
1649
1650 done = FALSE;
1651 while ( ! done )
1652 {
1653 if ( Prt_getLn( line, stdin, -1 ) )
1654 {
1655 initOutput();
1656
1657 if ( ! parseAndExecute( line, FALSE ) )
1658 done = TRUE;
1659
1660 if ( server.auth == AUTH_DONE )
1661 done = TRUE;
1662
1663 sendOutput();
1664 }
1665 else
1666 {
1667 Log_inf( "Client disconnected. Terminating." );
1668 done = TRUE;
1669 }
1670 }
1671
1672 Auth_close();
1673
1674 /* Did we finish because we successfully authenticated? */
1675 if ( server.auth != AUTH_DONE )
1676 return;
1677 }
1678 #endif
1679
1680 if ( ! Auth_dropPrivs() )
1681 {
1682 initOutput();
1683 putFatal( "Cannot set user privs" );
1684 sendOutput();
1685 return;
1686 }
1687
1504 done = FALSE; 1688 done = FALSE;
1505 while ( ! done ) 1689 while ( ! done )
1506 { 1690 {
1507 if ( Prt_getLn( line, stdin, -1 ) ) 1691 if ( Prt_getLn( line, stdin, -1 ) )
1508 { 1692 {
1513 putFatal( "Cannot init server" ); 1697 putFatal( "Cannot init server" );
1514 done = TRUE; 1698 done = TRUE;
1515 } 1699 }
1516 else 1700 else
1517 { 1701 {
1518 if ( ! parseAndExecute( line ) ) 1702 if ( ! parseAndExecute( line, TRUE ) )
1519 done = TRUE; 1703 done = TRUE;
1520 } 1704 }
1521 1705
1522 if ( server.running ) 1706 if ( server.running )
1523 closeServer(); 1707 closeServer();