/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugin-runner.c

  • Committer: Teddy Hogeborn
  • Date: 2015-03-10 18:03:38 UTC
  • mto: (237.7.304 trunk)
  • mto: This revision was merged to the branch mainline in revision 325.
  • Revision ID: teddy@recompile.se-20150310180338-pcxw6r2qmw9k6br9
Add ":!RSA" to GnuTLS priority string, to disallow non-DHE kx.

If Mandos was somehow made to use a non-ephemeral Diffie-Hellman key
exchange algorithm in the TLS handshake, any saved network traffic
could then be decrypted later if the Mandos client key was obtained.
By default, Mandos uses ephemeral DH key exchanges which does not have
this problem, but a non-ephemeral key exchange algorithm was still
enabled by default.  The simplest solution is to simply turn that off,
which ensures that Mandos will always use ephemeral DH key exchanges.

There is a "PFS" priority string specifier, but we can't use it because:

1. Security-wise, it is a mix between "NORMAL" and "SECURE128" - it
   enables a lot more algorithms than "SECURE256".

2. It is only available since GnuTLS 3.2.4.

Thanks to Andreas Fischer <af@bantuX.org> for reporting this issue.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/*
3
3
 * Mandos plugin runner - Run Mandos plugins
4
4
 *
5
 
 * Copyright © 2008-2013 Teddy Hogeborn
6
 
 * Copyright © 2008-2013 Björn Påhlsson
 
5
 * Copyright © 2008-2014 Teddy Hogeborn
 
6
 * Copyright © 2008-2014 Björn Påhlsson
7
7
 * 
8
8
 * This program is free software: you can redistribute it and/or
9
9
 * modify it under the terms of the GNU General Public License as
23
23
 */
24
24
 
25
25
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), getline(),
26
 
                                   asprintf(), O_CLOEXEC */
 
26
                                   O_CLOEXEC, pipe2() */
27
27
#include <stddef.h>             /* size_t, NULL */
28
28
#include <stdlib.h>             /* malloc(), exit(), EXIT_SUCCESS,
29
29
                                   realloc() */
30
30
#include <stdbool.h>            /* bool, true, false */
31
31
#include <stdio.h>              /* fileno(), fprintf(),
32
 
                                   stderr, STDOUT_FILENO */
33
 
#include <sys/types.h>          /* DIR, fdopendir(), stat(), struct
34
 
                                   stat, waitpid(), WIFEXITED(),
35
 
                                   WEXITSTATUS(), wait(), pid_t,
36
 
                                   uid_t, gid_t, getuid(), getgid(),
37
 
                                   dirfd() */
 
32
                                   stderr, STDOUT_FILENO, fclose() */
 
33
#include <sys/types.h>          /* fstat(), struct stat, waitpid(),
 
34
                                   WIFEXITED(), WEXITSTATUS(), wait(),
 
35
                                   pid_t, uid_t, gid_t, getuid(),
 
36
                                   getgid() */
38
37
#include <sys/select.h>         /* fd_set, select(), FD_ZERO(),
39
38
                                   FD_SET(), FD_ISSET(), FD_CLR */
40
39
#include <sys/wait.h>           /* wait(), waitpid(), WIFEXITED(),
41
40
                                   WEXITSTATUS(), WTERMSIG(),
42
41
                                   WCOREDUMP() */
43
 
#include <sys/stat.h>           /* struct stat, stat(), S_ISREG() */
 
42
#include <sys/stat.h>           /* struct stat, fstat(), S_ISREG() */
44
43
#include <iso646.h>             /* and, or, not */
45
 
#include <dirent.h>             /* DIR, struct dirent, fdopendir(),
46
 
                                   readdir(), closedir(), dirfd() */
47
 
#include <unistd.h>             /* struct stat, stat(), S_ISREG(),
48
 
                                   fcntl(), setuid(), setgid(),
49
 
                                   F_GETFD, F_SETFD, FD_CLOEXEC,
50
 
                                   access(), pipe(), fork(), close()
51
 
                                   dup2(), STDOUT_FILENO, _exit(),
52
 
                                   execv(), write(), read(),
53
 
                                   close() */
 
44
#include <dirent.h>             /* struct dirent, scandirat() */
 
45
#include <unistd.h>             /* fcntl(), F_GETFD, F_SETFD,
 
46
                                   FD_CLOEXEC, write(), STDOUT_FILENO,
 
47
                                   struct stat, fstat(), close(),
 
48
                                   setgid(), setuid(), S_ISREG(),
 
49
                                   faccessat() pipe2(), fork(),
 
50
                                   _exit(), dup2(), fexecve(), read()
 
51
                                */
54
52
#include <fcntl.h>              /* fcntl(), F_GETFD, F_SETFD,
55
 
                                   FD_CLOEXEC */
56
 
#include <string.h>             /* strsep, strlen(), asprintf(),
57
 
                                   strsignal(), strcmp(), strncmp() */
 
53
                                   FD_CLOEXEC, openat(), scandirat(),
 
54
                                   pipe2() */
 
55
#include <string.h>             /* strsep, strlen(), strsignal(),
 
56
                                   strcmp(), strncmp() */
58
57
#include <errno.h>              /* errno */
59
58
#include <argp.h>               /* struct argp_option, struct
60
59
                                   argp_state, struct argp,
72
71
                                   EX_CONFIG, EX_UNAVAILABLE, EX_OK */
73
72
#include <errno.h>              /* errno */
74
73
#include <error.h>              /* error() */
 
74
#include <fnmatch.h>            /* fnmatch() */
75
75
 
76
76
#define BUFFER_SIZE 256
77
77
 
240
240
  return add_to_char_array(def, &(p->environ), &(p->envc));
241
241
}
242
242
 
 
243
#ifndef O_CLOEXEC
243
244
/*
244
245
 * Based on the example in the GNU LibC manual chapter 13.13 "File
245
246
 * Descriptor Flags".
256
257
  return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
257
258
                                       ret | FD_CLOEXEC));
258
259
}
 
260
#endif  /* not O_CLOEXEC */
259
261
 
260
262
 
261
263
/* Mark processes as completed when they exit, and save their exit
347
349
  char *plugindir = NULL;
348
350
  char *argfile = NULL;
349
351
  FILE *conffp;
350
 
  size_t d_name_len;
351
 
  DIR *dir = NULL;
352
 
  struct dirent *dirst;
 
352
  struct dirent **direntries = NULL;
353
353
  struct stat st;
354
354
  fd_set rfds_all;
355
355
  int ret, maxfd = 0;
363
363
                                      .sa_flags = SA_NOCLDSTOP };
364
364
  char **custom_argv = NULL;
365
365
  int custom_argc = 0;
 
366
  int dir_fd = -1;
366
367
  
367
368
  /* Establish a signal handler */
368
369
  sigemptyset(&sigchld_action.sa_mask);
779
780
       <http://bugs.debian.org/633582> */
780
781
    int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY);
781
782
    if(plugindir_fd == -1){
782
 
      error(0, errno, "open");
 
783
      if(errno != ENOENT){
 
784
        error(0, errno, "open(\"" PDIR "\")");
 
785
      }
783
786
    } else {
784
787
      ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st));
785
788
      if(ret == -1){
808
811
  
809
812
  /* Open plugin directory with close_on_exec flag */
810
813
  {
811
 
    int dir_fd = -1;
812
 
    if(plugindir == NULL){
813
 
      dir_fd = open(PDIR, O_RDONLY |
814
 
#ifdef O_CLOEXEC
815
 
                    O_CLOEXEC
816
 
#else  /* not O_CLOEXEC */
817
 
                    0
818
 
#endif  /* not O_CLOEXEC */
819
 
                    );
820
 
    } else {
821
 
      dir_fd = open(plugindir, O_RDONLY |
822
 
#ifdef O_CLOEXEC
823
 
                    O_CLOEXEC
824
 
#else  /* not O_CLOEXEC */
825
 
                    0
826
 
#endif  /* not O_CLOEXEC */
827
 
                    );
828
 
    }
 
814
    dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY |
 
815
#ifdef O_CLOEXEC
 
816
                  O_CLOEXEC
 
817
#else  /* not O_CLOEXEC */
 
818
                  0
 
819
#endif  /* not O_CLOEXEC */
 
820
                  );
829
821
    if(dir_fd == -1){
830
822
      error(0, errno, "Could not open plugin dir");
831
823
      exitstatus = EX_UNAVAILABLE;
837
829
    ret = set_cloexec_flag(dir_fd);
838
830
    if(ret < 0){
839
831
      error(0, errno, "set_cloexec_flag");
840
 
      TEMP_FAILURE_RETRY(close(dir_fd));
841
832
      exitstatus = EX_OSERR;
842
833
      goto fallback;
843
834
    }
844
835
#endif  /* O_CLOEXEC */
845
 
    
846
 
    dir = fdopendir(dir_fd);
847
 
    if(dir == NULL){
848
 
      error(0, errno, "Could not open plugin dir");
849
 
      TEMP_FAILURE_RETRY(close(dir_fd));
850
 
      exitstatus = EX_OSERR;
851
 
      goto fallback;
 
836
  }
 
837
  
 
838
  int good_name(const struct dirent * const dirent){
 
839
    const char * const patterns[] = { ".*", "#*#", "*~", "*.dpkg-new",
 
840
                                      "*.dpkg-old", "*.dpkg-bak",
 
841
                                      "*.dpkg-divert", NULL };
 
842
#ifdef __GNUC__
 
843
#pragma GCC diagnostic push
 
844
#pragma GCC diagnostic ignored "-Wcast-qual"
 
845
#endif
 
846
    for(const char **pat = (const char **)patterns;
 
847
        *pat != NULL; pat++){
 
848
#ifdef __GNUC__
 
849
#pragma GCC diagnostic pop
 
850
#endif
 
851
      if(fnmatch(*pat, dirent->d_name, FNM_FILE_NAME | FNM_PERIOD)
 
852
         != FNM_NOMATCH){
 
853
        if(debug){
 
854
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
 
855
                    " matching pattern %s\n", dirent->d_name, *pat);
 
856
        }
 
857
        return 0;
 
858
      }
852
859
    }
 
860
    return 1;
 
861
  }
 
862
  
 
863
#ifdef __GLIBC__
 
864
#if __GLIBC_PREREQ(2, 15)
 
865
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
 
866
                             alphasort);
 
867
#else  /* not __GLIBC_PREREQ(2, 15) */
 
868
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
869
                           &direntries, good_name, alphasort);
 
870
#endif  /* not __GLIBC_PREREQ(2, 15) */
 
871
#else   /* not __GLIBC__ */
 
872
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
 
873
                           &direntries, good_name, alphasort);
 
874
#endif  /* not __GLIBC__ */
 
875
  if(numplugins == -1){
 
876
    error(0, errno, "Could not scan plugin dir");
 
877
    direntries = NULL;
 
878
    exitstatus = EX_OSERR;
 
879
    goto fallback;
853
880
  }
854
881
  
855
882
  FD_ZERO(&rfds_all);
856
883
  
857
884
  /* Read and execute any executable in the plugin directory*/
858
 
  while(true){
859
 
    do {
860
 
      dirst = readdir(dir);
861
 
    } while(dirst == NULL and errno == EINTR);
862
 
    
863
 
    /* All directory entries have been processed */
864
 
    if(dirst == NULL){
865
 
      if(errno == EBADF){
866
 
        error(0, errno, "readdir");
867
 
        exitstatus = EX_IOERR;
868
 
        goto fallback;
869
 
      }
870
 
      break;
871
 
    }
872
 
    
873
 
    d_name_len = strlen(dirst->d_name);
874
 
    
875
 
    /* Ignore dotfiles, backup files and other junk */
876
 
    {
877
 
      bool bad_name = false;
878
 
      
879
 
      const char * const bad_prefixes[] = { ".", "#", NULL };
880
 
      
881
 
      const char * const bad_suffixes[] = { "~", "#", ".dpkg-new",
882
 
                                           ".dpkg-old",
883
 
                                           ".dpkg-bak",
884
 
                                           ".dpkg-divert", NULL };
885
 
#ifdef __GNUC__
886
 
#pragma GCC diagnostic push
887
 
#pragma GCC diagnostic ignored "-Wcast-qual"
888
 
#endif
889
 
      for(const char **pre = (const char **)bad_prefixes;
890
 
          *pre != NULL; pre++){
891
 
#ifdef __GNUC__
892
 
#pragma GCC diagnostic pop
893
 
#endif
894
 
        size_t pre_len = strlen(*pre);
895
 
        if((d_name_len >= pre_len)
896
 
           and strncmp((dirst->d_name), *pre, pre_len) == 0){
897
 
          if(debug){
898
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
899
 
                    " with bad prefix %s\n", dirst->d_name, *pre);
900
 
          }
901
 
          bad_name = true;
902
 
          break;
903
 
        }
904
 
      }
905
 
      if(bad_name){
906
 
        continue;
907
 
      }
908
 
#ifdef __GNUC__
909
 
#pragma GCC diagnostic push
910
 
#pragma GCC diagnostic ignored "-Wcast-qual"
911
 
#endif
912
 
      for(const char **suf = (const char **)bad_suffixes;
913
 
          *suf != NULL; suf++){
914
 
#ifdef __GNUC__
915
 
#pragma GCC diagnostic pop
916
 
#endif
917
 
        size_t suf_len = strlen(*suf);
918
 
        if((d_name_len >= suf_len)
919
 
           and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf)
920
 
                == 0)){
921
 
          if(debug){
922
 
            fprintf(stderr, "Ignoring plugin dir entry \"%s\""
923
 
                    " with bad suffix %s\n", dirst->d_name, *suf);
924
 
          }
925
 
          bad_name = true;
926
 
          break;
927
 
        }
928
 
      }
929
 
      
930
 
      if(bad_name){
931
 
        continue;
932
 
      }
933
 
    }
934
 
    
935
 
    char *filename;
936
 
    if(plugindir == NULL){
937
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
938
 
                                             dirst->d_name));
939
 
    } else {
940
 
      ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
941
 
                                             plugindir,
942
 
                                             dirst->d_name));
943
 
    }
944
 
    if(ret < 0){
945
 
      error(0, errno, "asprintf");
 
885
  for(int i = 0; i < numplugins; i++){
 
886
    
 
887
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
 
888
    if(plugin_fd == -1){
 
889
      error(0, errno, "Could not open plugin");
 
890
      free(direntries[i]);
946
891
      continue;
947
892
    }
948
 
    
949
 
    ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
 
893
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
950
894
    if(ret == -1){
951
895
      error(0, errno, "stat");
952
 
      free(filename);
 
896
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
897
      free(direntries[i]);
953
898
      continue;
954
899
    }
955
900
    
956
901
    /* Ignore non-executable files */
957
902
    if(not S_ISREG(st.st_mode)
958
 
       or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
 
903
       or (TEMP_FAILURE_RETRY(faccessat(dir_fd, direntries[i]->d_name,
 
904
                                        X_OK, 0)) != 0)){
959
905
      if(debug){
960
 
        fprintf(stderr, "Ignoring plugin dir entry \"%s\""
961
 
                " with bad type or mode\n", filename);
 
906
        fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\""
 
907
                " with bad type or mode\n",
 
908
                plugindir != NULL ? plugindir : PDIR,
 
909
                direntries[i]->d_name);
962
910
      }
963
 
      free(filename);
 
911
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
912
      free(direntries[i]);
964
913
      continue;
965
914
    }
966
915
    
967
 
    plugin *p = getplugin(dirst->d_name);
 
916
    plugin *p = getplugin(direntries[i]->d_name);
968
917
    if(p == NULL){
969
918
      error(0, errno, "getplugin");
970
 
      free(filename);
 
919
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
920
      free(direntries[i]);
971
921
      continue;
972
922
    }
973
923
    if(p->disabled){
974
924
      if(debug){
975
925
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
976
 
                dirst->d_name);
 
926
                direntries[i]->d_name);
977
927
      }
978
 
      free(filename);
 
928
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
929
      free(direntries[i]);
979
930
      continue;
980
931
    }
981
932
    {
995
946
        }
996
947
      }
997
948
    }
998
 
    /* If this plugin has any environment variables, we will call
999
 
       using execve and need to duplicate the environment from this
1000
 
       process, too. */
 
949
    /* If this plugin has any environment variables, we need to
 
950
       duplicate the environment from this process, too. */
1001
951
    if(p->environ[0] != NULL){
1002
952
      for(char **e = environ; *e != NULL; e++){
1003
953
        if(not add_environment(p, *e, false)){
1007
957
    }
1008
958
    
1009
959
    int pipefd[2];
 
960
#ifndef O_CLOEXEC
1010
961
    ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
 
962
#else  /* O_CLOEXEC */
 
963
    ret = (int)TEMP_FAILURE_RETRY(pipe2(pipefd, O_CLOEXEC));
 
964
#endif  /* O_CLOEXEC */
1011
965
    if(ret == -1){
1012
966
      error(0, errno, "pipe");
1013
967
      exitstatus = EX_OSERR;
1014
 
      goto fallback;
1015
 
    }
 
968
      free(direntries[i]);
 
969
      goto fallback;
 
970
    }
 
971
    if(pipefd[0] >= FD_SETSIZE){
 
972
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
 
973
              FD_SETSIZE);
 
974
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
975
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
976
      exitstatus = EX_OSERR;
 
977
      free(direntries[i]);
 
978
      goto fallback;
 
979
    }
 
980
#ifndef O_CLOEXEC
1016
981
    /* Ask OS to automatic close the pipe on exec */
1017
982
    ret = set_cloexec_flag(pipefd[0]);
1018
983
    if(ret < 0){
1019
984
      error(0, errno, "set_cloexec_flag");
 
985
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
986
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1020
987
      exitstatus = EX_OSERR;
 
988
      free(direntries[i]);
1021
989
      goto fallback;
1022
990
    }
1023
991
    ret = set_cloexec_flag(pipefd[1]);
1024
992
    if(ret < 0){
1025
993
      error(0, errno, "set_cloexec_flag");
 
994
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
995
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1026
996
      exitstatus = EX_OSERR;
 
997
      free(direntries[i]);
1027
998
      goto fallback;
1028
999
    }
 
1000
#endif  /* not O_CLOEXEC */
1029
1001
    /* Block SIGCHLD until process is safely in process list */
1030
1002
    ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
1031
1003
                                              &sigchld_action.sa_mask,
1033
1005
    if(ret < 0){
1034
1006
      error(0, errno, "sigprocmask");
1035
1007
      exitstatus = EX_OSERR;
 
1008
      free(direntries[i]);
1036
1009
      goto fallback;
1037
1010
    }
1038
1011
    /* Starting a new process to be watched */
1042
1015
    } while(pid == -1 and errno == EINTR);
1043
1016
    if(pid == -1){
1044
1017
      error(0, errno, "fork");
 
1018
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
 
1019
                                     &sigchld_action.sa_mask, NULL));
 
1020
      TEMP_FAILURE_RETRY(close(pipefd[0]));
 
1021
      TEMP_FAILURE_RETRY(close(pipefd[1]));
1045
1022
      exitstatus = EX_OSERR;
 
1023
      free(direntries[i]);
1046
1024
      goto fallback;
1047
1025
    }
1048
1026
    if(pid == 0){
1064
1042
        _exit(EX_OSERR);
1065
1043
      }
1066
1044
      
1067
 
      if(dirfd(dir) < 0){
1068
 
        /* If dir has no file descriptor, we could not set FD_CLOEXEC
1069
 
           above and must now close it manually here. */
1070
 
        closedir(dir);
1071
 
      }
1072
 
      if(p->environ[0] == NULL){
1073
 
        if(execv(filename, p->argv) < 0){
1074
 
          error(0, errno, "execv for %s", filename);
1075
 
          _exit(EX_OSERR);
1076
 
        }
1077
 
      } else {
1078
 
        if(execve(filename, p->argv, p->environ) < 0){
1079
 
          error(0, errno, "execve for %s", filename);
1080
 
          _exit(EX_OSERR);
1081
 
        }
 
1045
      if(fexecve(plugin_fd, p->argv,
 
1046
                (p->environ[0] != NULL) ? p->environ : environ) < 0){
 
1047
        error(0, errno, "fexecve for %s/%s",
 
1048
              plugindir != NULL ? plugindir : PDIR,
 
1049
              direntries[i]->d_name);
 
1050
        _exit(EX_OSERR);
1082
1051
      }
1083
1052
      /* no return */
1084
1053
    }
1085
1054
    /* Parent process */
1086
1055
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1087
1056
                                             pipe */
1088
 
    free(filename);
1089
 
    plugin *new_plugin = getplugin(dirst->d_name);
 
1057
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1058
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1090
1059
    if(new_plugin == NULL){
1091
1060
      error(0, errno, "getplugin");
1092
1061
      ret = (int)(TEMP_FAILURE_RETRY
1096
1065
        error(0, errno, "sigprocmask");
1097
1066
      }
1098
1067
      exitstatus = EX_OSERR;
 
1068
      free(direntries[i]);
1099
1069
      goto fallback;
1100
1070
    }
 
1071
    free(direntries[i]);
1101
1072
    
1102
1073
    new_plugin->pid = pid;
1103
1074
    new_plugin->fd = pipefd[0];
1133
1104
    }
1134
1105
  }
1135
1106
  
1136
 
  TEMP_FAILURE_RETRY(closedir(dir));
1137
 
  dir = NULL;
 
1107
  free(direntries);
 
1108
  direntries = NULL;
 
1109
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1110
  dir_fd = -1;
1138
1111
  free_plugin(getplugin(NULL));
1139
1112
  
1140
1113
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1334
1307
    free(custom_argv);
1335
1308
  }
1336
1309
  
1337
 
  if(dir != NULL){
1338
 
    closedir(dir);
 
1310
  free(direntries);
 
1311
  
 
1312
  if(dir_fd != -1){
 
1313
    TEMP_FAILURE_RETRY(close(dir_fd));
1339
1314
  }
1340
1315
  
1341
1316
  /* Kill the processes */