SNET: fix writing of files.
[citadel.git] / citadel / modules / network / serv_netconfig.c
index cfcc20b6f84ca3fee5b678a3eb2387adfa6dadbe..12662f066564a786d71137f963c92dcb3e14715b 100644 (file)
@@ -5,19 +5,13 @@
  * Copyright (c) 2000-2012 by the citadel.org team
  *
  *  This program is open source 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 3 of the License, or
- *  (at your option) any later version.
+ *  it under the terms of the GNU General Public License, version 3.
  *
  *  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
- *
  * ** NOTE **   A word on the S_NETCONFIGS semaphore:
  * This is a fairly high-level type of critical section.  It ensures that no
  * two threads work on the netconfigs files at the same time.  Since we do
 #include "file_ops.h"
 #include "citadel_dirs.h"
 #include "threads.h"
-
-#ifndef HAVE_SNPRINTF
-#include "snprintf.h"
-#endif
-
 #include "context.h"
 #include "netconfig.h"
 #include "netspool.h"
@@ -352,22 +341,39 @@ int is_valid_node(const StrBuf **nexthop,
 }
 
 
-
 void cmd_gnet(char *argbuf)
 {
        char filename[PATH_MAX];
        char buf[SIZ];
        FILE *fp;
 
-       if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
-               /* users can edit the netconfigs for their own mailbox rooms */
-       }
-       else if (CtdlAccessCheck(ac_room_aide)) return;
 
-       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
-       cprintf("%d Network settings for room #%ld <%s>\n",
-               LISTING_FOLLOWS,
-               CC->room.QRnumber, CC->room.QRname);
+       if (!IsEmptyStr(argbuf))
+       {
+               if (CtdlAccessCheck(ac_aide)) return;
+               if (strcmp(argbuf, FILE_MAILALIAS))
+               {
+                       cprintf("%d No such file or directory\n",
+                               ERROR + INTERNAL_ERROR);
+                       return;
+               }
+               safestrncpy(filename, file_mail_aliases, sizeof(filename));
+               cprintf("%d Settings for <%s>\n",
+                       LISTING_FOLLOWS,
+                       filename);
+       }
+       else
+       {
+               if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
+                       /* users can edit the netconfigs for their own mailbox rooms */
+               }
+               else if (CtdlAccessCheck(ac_room_aide)) return;
+               
+               assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
+               cprintf("%d Network settings for room #%ld <%s>\n",
+                       LISTING_FOLLOWS,
+                       CC->room.QRnumber, CC->room.QRname);
+       }
 
        fp = fopen(filename, "r");
        if (fp != NULL) {
@@ -381,6 +387,14 @@ void cmd_gnet(char *argbuf)
        cprintf("000\n");
 }
 
+#define nForceAliases 5
+const ConstStr ForceAliases[nForceAliases] = {
+       {HKEY("bbs,")},
+       {HKEY("root,")},
+       {HKEY("Auto,")},
+       {HKEY("postmaster,")},
+       {HKEY("abuse,")}
+};
 
 void cmd_snet(char *argbuf) {
        char tempfilename[PATH_MAX];
@@ -390,17 +404,35 @@ void cmd_snet(char *argbuf) {
        struct stat StatBuf;
        long len;
        int rc;
+       int IsMailAlias = 0;
+       int MailAliasesFound[nForceAliases];
 
        unbuffer_output();
 
-       if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
-               /* users can edit the netconfigs for their own mailbox rooms */
+       if (!IsEmptyStr(argbuf))
+       {
+               if (CtdlAccessCheck(ac_aide)) return;
+               if (strcmp(argbuf, FILE_MAILALIAS))
+               {
+                       cprintf("%d No such file or directory\n",
+                               ERROR + INTERNAL_ERROR);
+                       return;
+               }
+               len = safestrncpy(filename, file_mail_aliases, sizeof(filename));
+               memset(MailAliasesFound, 0, sizeof(MailAliasesFound));
+               memcpy(tempfilename, filename, len + 1);
+               IsMailAlias = 1;
+       }
+       else
+       {
+               if ( (CC->room.QRflags & QR_MAILBOX) && (CC->user.usernum == atol(CC->room.QRname)) ) {
+                       /* users can edit the netconfigs for their own mailbox rooms */
+               }
+               else if (CtdlAccessCheck(ac_room_aide)) return;
+               
+               len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
+               memcpy(tempfilename, filename, len + 1);
        }
-       else if (CtdlAccessCheck(ac_room_aide)) return;
-
-       len = assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
-       memcpy(tempfilename, filename, len + 1);
-
        memset(&StatBuf, 0, sizeof(struct stat));
        if ((stat(filename, &StatBuf)  == -1) || (StatBuf.st_size == 0))
                StatBuf.st_size = 80; /* Not there or empty? guess 80 chars line. */
@@ -445,6 +477,24 @@ void cmd_snet(char *argbuf) {
        {
                if ((rc == 3) && (strcmp(ChrPtr(Line), "000") == 0))
                        break;
+               if (IsMailAlias)
+               {
+                       int i;
+
+                       for (i = 0; i < nForceAliases; i++)
+                       {
+                               if ((!MailAliasesFound[i]) && 
+                                   (strncmp(ForceAliases[i].Key, 
+                                            ChrPtr(Line),
+                                            ForceAliases[i].len) == 0)
+                                       )
+                                   {
+                                           MailAliasesFound[i] = 1;
+                                           break;
+                                   }
+                       }
+               }
+
                StrBufAppendBufPlain(Line, HKEY("\n"), 0);
                write(TmpFD, ChrPtr(Line), StrLength(Line));
                len += StrLength(Line);
@@ -453,6 +503,28 @@ void cmd_snet(char *argbuf) {
        ftruncate(TmpFD, len);
        close(TmpFD);
 
+       if (IsMailAlias)
+       {
+               int i, state;
+               /*
+                * Sanity check whether all aliases required by the RFCs were set
+                * else bail out.
+                */
+               state = 1;
+               for (i = 0; i < nForceAliases; i++)
+               {
+                       if (!MailAliasesFound[i]) 
+                               state = 0;
+               }
+               if (state == 0)
+               {
+                       cprintf("%d won't do this - you're missing an RFC required alias.\n",
+                               ERROR + INTERNAL_ERROR);
+                       unlink(tempfilename);
+                       return;
+               }
+       }
+
        /* Now copy the temp file to its permanent location.
         * (We copy instead of link because they may be on different filesystems)
         */
@@ -467,20 +539,22 @@ void cmd_snet(char *argbuf) {
  */
 void cmd_netp(char *cmdbuf)
 {
+       struct CitContext *CCC = CC;
        HashList *working_ignetcfg;
-       char node[256];
+       char *node;
        StrBuf *NodeStr;
        long nodelen;
-       char pass[256];
        int v;
+       long lens[2];
+       const char *strs[2];
 
        const StrBuf *secret = NULL;
        const StrBuf *nexthop = NULL;
        char err_buf[SIZ] = "";
 
        /* Authenticate */
-       nodelen = extract_token(node, cmdbuf, 0, '|', sizeof node);
-       extract_token(pass, cmdbuf, 1, '|', sizeof pass);
+       node = CCC->curr_user;
+       nodelen = extract_token(CCC->curr_user, cmdbuf, 0, '|', sizeof CCC->curr_user);
        NodeStr = NewStrBufPlain(node, nodelen);
        /* load the IGnet Configuration to check node validity */
        working_ignetcfg = load_ignetcfg();
@@ -488,24 +562,47 @@ void cmd_netp(char *cmdbuf)
        if (v != 0) {
                snprintf(err_buf, sizeof err_buf,
                        "An unknown Citadel server called \"%s\" attempted to connect from %s [%s].\n",
-                       node, CC->cs_host, CC->cs_addr
+                       node, CCC->cs_host, CCC->cs_addr
                );
                syslog(LOG_WARNING, "%s", err_buf);
                cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
-               CtdlAideMessage(err_buf, "IGNet Networking.");
+
+               strs[0] = CCC->cs_addr;
+               lens[0] = strlen(CCC->cs_addr);
+               
+               strs[1] = "SRV_UNKNOWN";
+               lens[1] = sizeof("SRV_UNKNOWN" - 1);
+
+               CtdlAideFPMessage(
+                       err_buf,
+                       "IGNet Networking.",
+                       2, strs, (long*) &lens);
+
                DeleteHash(&working_ignetcfg);
                FreeStrBuf(&NodeStr);
                return;
        }
 
-       if (strcasecmp(pass, ChrPtr(secret))) {
+       extract_token(CCC->user.password, cmdbuf, 1, '|', sizeof CCC->user.password);
+       if (strcasecmp(CCC->user.password, ChrPtr(secret))) {
                snprintf(err_buf, sizeof err_buf,
                        "A Citadel server at %s [%s] failed to authenticate as network node \"%s\".\n",
-                       CC->cs_host, CC->cs_addr, node
+                       CCC->cs_host, CCC->cs_addr, node
                );
                syslog(LOG_WARNING, "%s", err_buf);
                cprintf("%d authentication failed\n", ERROR + PASSWORD_REQUIRED);
-               CtdlAideMessage(err_buf, "IGNet Networking.");
+
+               strs[0] = CCC->cs_addr;
+               lens[0] = strlen(CCC->cs_addr);
+               
+               strs[1] = "SRV_PW";
+               lens[1] = sizeof("SRV_PW" - 1);
+
+               CtdlAideFPMessage(
+                       err_buf,
+                       "IGNet Networking.",
+                       2, strs, (long*) &lens);
+
                DeleteHash(&working_ignetcfg);
                FreeStrBuf(&NodeStr);
                return;
@@ -518,13 +615,12 @@ void cmd_netp(char *cmdbuf)
                FreeStrBuf(&NodeStr);
                return;
        }
-
-       safestrncpy(CC->net_node, node, sizeof CC->net_node);
-       network_talking_to(node, nodelen, NTT_ADD);
+       nodelen = safestrncpy(CCC->net_node, node, sizeof CCC->net_node);
+       network_talking_to(CCC->net_node, nodelen, NTT_ADD);
        syslog(LOG_NOTICE, "Network node <%s> logged in from %s [%s]\n",
-               CC->net_node, CC->cs_host, CC->cs_addr
+               CCC->net_node, CCC->cs_host, CCC->cs_addr
        );
-       cprintf("%d authenticated as network node '%s'\n", CIT_OK, CC->net_node);
+       cprintf("%d authenticated as network node '%s'\n", CIT_OK, CCC->net_node);
        DeleteHash(&working_ignetcfg);
        FreeStrBuf(&NodeStr);
 }