Mercurial > noffle
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)", ¬Implemented }, | 133 { "newnews", "NEWNEWS (not implemented)", TRUE, ¬Implemented }, |
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(); |