/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: 2016-03-17 20:40:55 UTC
  • mto: (237.7.594 trunk)
  • mto: This revision was merged to the branch mainline in revision 341.
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

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-2014 Teddy Hogeborn
6
 
 * Copyright © 2008-2014 Björn Påhlsson
 
5
 * Copyright © 2008-2016 Teddy Hogeborn
 
6
 * Copyright © 2008-2016 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
76
76
#define BUFFER_SIZE 256
77
77
 
78
78
#define PDIR "/lib/mandos/plugins.d"
 
79
#define PHDIR "/lib/mandos/plugin-helpers"
79
80
#define AFILE "/conf/conf.d/mandos/plugin-runner.conf"
80
81
 
81
82
const char *argp_program_version = "plugin-runner " VERSION;
347
348
 
348
349
int main(int argc, char *argv[]){
349
350
  char *plugindir = NULL;
 
351
  char *pluginhelperdir = NULL;
350
352
  char *argfile = NULL;
351
353
  FILE *conffp;
352
 
  struct dirent **direntries;
 
354
  struct dirent **direntries = NULL;
353
355
  struct stat st;
354
356
  fd_set rfds_all;
355
357
  int ret, maxfd = 0;
414
416
      .doc = "Group ID the plugins will run as", .group = 3 },
415
417
    { .name = "debug", .key = 132,
416
418
      .doc = "Debug mode", .group = 4 },
 
419
    { .name = "plugin-helper-dir", .key = 133,
 
420
      .arg = "DIRECTORY",
 
421
      .doc = "Specify a different plugin helper directory",
 
422
      .group = 2 },
417
423
    /*
418
424
     * These reproduce what we would get without ARGP_NO_HELP
419
425
     */
545
551
    case 132:                   /* --debug */
546
552
      debug = true;
547
553
      break;
 
554
    case 133:                   /* --plugin-helper-dir */
 
555
      free(pluginhelperdir);
 
556
      pluginhelperdir = strdup(arg);
 
557
      if(pluginhelperdir != NULL){
 
558
        errno = 0;
 
559
      }
 
560
      break;
548
561
      /*
549
562
       * These reproduce what we would get without ARGP_NO_HELP
550
563
       */
601
614
    case 130:                   /* --userid */
602
615
    case 131:                   /* --groupid */
603
616
    case 132:                   /* --debug */
 
617
    case 133:                   /* --plugin-helper-dir */
604
618
    case '?':                   /* --help */
605
619
    case -3:                    /* --usage */
606
620
    case 'V':                   /* --version */
687
701
        custom_argc += 1;
688
702
        {
689
703
          char **new_argv = realloc(custom_argv, sizeof(char *)
690
 
                                    * ((unsigned int)
691
 
                                       custom_argc + 1));
 
704
                                    * ((size_t)custom_argc + 1));
692
705
          if(new_argv == NULL){
693
706
            error(0, errno, "realloc");
694
707
            exitstatus = EX_OSERR;
761
774
    goto fallback;
762
775
  }
763
776
  
 
777
  {
 
778
    char *pluginhelperenv;
 
779
    bool bret = true;
 
780
    ret = asprintf(&pluginhelperenv, "MANDOSPLUGINHELPERDIR=%s",
 
781
                   pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
782
    if(ret != -1){
 
783
      bret = add_environment(getplugin(NULL), pluginhelperenv, true);
 
784
    }
 
785
    if(ret == -1 or not bret){
 
786
      error(0, errno, "Failed to set MANDOSPLUGINHELPERDIR"
 
787
            " environment variable to \"%s\" for all plugins\n",
 
788
            pluginhelperdir != NULL ? pluginhelperdir : PHDIR);
 
789
    }
 
790
    if(ret != -1){
 
791
      free(pluginhelperenv);
 
792
    }
 
793
  }
 
794
  
764
795
  if(debug){
765
796
    for(plugin *p = plugin_list; p != NULL; p=p->next){
766
797
      fprintf(stderr, "Plugin: %s has %d arguments\n",
795
826
          }
796
827
        }
797
828
      }
798
 
      TEMP_FAILURE_RETRY(close(plugindir_fd));
 
829
      close(plugindir_fd);
799
830
    }
800
831
  }
801
832
  
829
860
    ret = set_cloexec_flag(dir_fd);
830
861
    if(ret < 0){
831
862
      error(0, errno, "set_cloexec_flag");
832
 
      TEMP_FAILURE_RETRY(close(dir_fd));
833
863
      exitstatus = EX_OSERR;
834
864
      goto fallback;
835
865
    }
861
891
    return 1;
862
892
  }
863
893
  
864
 
#ifdef __GLIBC__
865
 
#if __GLIBC_PREREQ(2, 15)
866
894
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
867
895
                             alphasort);
868
 
#else  /* not __GLIBC_PREREQ(2, 15) */
869
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
870
 
                           &direntries, good_name, alphasort);
871
 
#endif  /* not __GLIBC_PREREQ(2, 15) */
872
 
#else   /* not __GLIBC__ */
873
 
  int numplugins = scandir(plugindir != NULL ? plugindir : PDIR,
874
 
                           &direntries, good_name, alphasort);
875
 
#endif  /* not __GLIBC__ */
876
896
  if(numplugins == -1){
877
897
    error(0, errno, "Could not scan plugin dir");
878
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
898
    direntries = NULL;
879
899
    exitstatus = EX_OSERR;
880
900
    goto fallback;
881
901
  }
888
908
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
889
909
    if(plugin_fd == -1){
890
910
      error(0, errno, "Could not open plugin");
 
911
      free(direntries[i]);
891
912
      continue;
892
913
    }
893
914
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
894
915
    if(ret == -1){
895
916
      error(0, errno, "stat");
896
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
917
      close(plugin_fd);
 
918
      free(direntries[i]);
897
919
      continue;
898
920
    }
899
921
    
907
929
                plugindir != NULL ? plugindir : PDIR,
908
930
                direntries[i]->d_name);
909
931
      }
910
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
932
      close(plugin_fd);
 
933
      free(direntries[i]);
911
934
      continue;
912
935
    }
913
936
    
914
937
    plugin *p = getplugin(direntries[i]->d_name);
915
938
    if(p == NULL){
916
939
      error(0, errno, "getplugin");
917
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
940
      close(plugin_fd);
 
941
      free(direntries[i]);
918
942
      continue;
919
943
    }
920
944
    if(p->disabled){
922
946
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
923
947
                direntries[i]->d_name);
924
948
      }
925
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
949
      close(plugin_fd);
 
950
      free(direntries[i]);
926
951
      continue;
927
952
    }
928
953
    {
961
986
    if(ret == -1){
962
987
      error(0, errno, "pipe");
963
988
      exitstatus = EX_OSERR;
 
989
      free(direntries[i]);
964
990
      goto fallback;
965
991
    }
966
992
    if(pipefd[0] >= FD_SETSIZE){
967
993
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
968
994
              FD_SETSIZE);
969
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
970
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
995
      close(pipefd[0]);
 
996
      close(pipefd[1]);
971
997
      exitstatus = EX_OSERR;
 
998
      free(direntries[i]);
972
999
      goto fallback;
973
1000
    }
974
1001
#ifndef O_CLOEXEC
976
1003
    ret = set_cloexec_flag(pipefd[0]);
977
1004
    if(ret < 0){
978
1005
      error(0, errno, "set_cloexec_flag");
979
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
980
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
981
1008
      exitstatus = EX_OSERR;
 
1009
      free(direntries[i]);
982
1010
      goto fallback;
983
1011
    }
984
1012
    ret = set_cloexec_flag(pipefd[1]);
985
1013
    if(ret < 0){
986
1014
      error(0, errno, "set_cloexec_flag");
987
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
988
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1015
      close(pipefd[0]);
 
1016
      close(pipefd[1]);
989
1017
      exitstatus = EX_OSERR;
 
1018
      free(direntries[i]);
990
1019
      goto fallback;
991
1020
    }
992
1021
#endif  /* not O_CLOEXEC */
997
1026
    if(ret < 0){
998
1027
      error(0, errno, "sigprocmask");
999
1028
      exitstatus = EX_OSERR;
 
1029
      free(direntries[i]);
1000
1030
      goto fallback;
1001
1031
    }
1002
1032
    /* Starting a new process to be watched */
1008
1038
      error(0, errno, "fork");
1009
1039
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1010
1040
                                     &sigchld_action.sa_mask, NULL));
1011
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1012
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1041
      close(pipefd[0]);
 
1042
      close(pipefd[1]);
1013
1043
      exitstatus = EX_OSERR;
 
1044
      free(direntries[i]);
1014
1045
      goto fallback;
1015
1046
    }
1016
1047
    if(pid == 0){
1042
1073
      /* no return */
1043
1074
    }
1044
1075
    /* Parent process */
1045
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1046
 
                                             pipe */
1047
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1076
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1077
    close(plugin_fd);
1048
1078
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1049
1079
    if(new_plugin == NULL){
1050
1080
      error(0, errno, "getplugin");
1055
1085
        error(0, errno, "sigprocmask");
1056
1086
      }
1057
1087
      exitstatus = EX_OSERR;
 
1088
      free(direntries[i]);
1058
1089
      goto fallback;
1059
1090
    }
 
1091
    free(direntries[i]);
1060
1092
    
1061
1093
    new_plugin->pid = pid;
1062
1094
    new_plugin->fd = pipefd[0];
1072
1104
      goto fallback;
1073
1105
    }
1074
1106
    
1075
 
#if defined (__GNUC__) and defined (__GLIBC__)
1076
 
#if not __GLIBC_PREREQ(2, 16)
1077
 
#pragma GCC diagnostic push
1078
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1079
 
#endif
1080
 
#endif
1081
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1082
 
                                          -Wconversion in GNU libc
1083
 
                                          before 2.16 */
1084
 
#if defined (__GNUC__) and defined (__GLIBC__)
1085
 
#if not __GLIBC_PREREQ(2, 16)
1086
 
#pragma GCC diagnostic pop
1087
 
#endif
1088
 
#endif
 
1107
    FD_SET(new_plugin->fd, &rfds_all);
1089
1108
    
1090
1109
    if(maxfd < new_plugin->fd){
1091
1110
      maxfd = new_plugin->fd;
1092
1111
    }
1093
1112
  }
1094
1113
  
1095
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1114
  free(direntries);
 
1115
  direntries = NULL;
 
1116
  close(dir_fd);
 
1117
  dir_fd = -1;
1096
1118
  free_plugin(getplugin(NULL));
1097
1119
  
1098
1120
  for(plugin *p = plugin_list; p != NULL; p = p->next){
1144
1166
          }
1145
1167
          
1146
1168
          /* Remove the plugin */
1147
 
#if defined (__GNUC__) and defined (__GLIBC__)
1148
 
#if not __GLIBC_PREREQ(2, 16)
1149
 
#pragma GCC diagnostic push
1150
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1151
 
#endif
1152
 
#endif
1153
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1154
 
                                          -Wconversion in GNU libc
1155
 
                                          before 2.16 */
1156
 
#if defined (__GNUC__) and defined (__GLIBC__)
1157
 
#if not __GLIBC_PREREQ(2, 16)
1158
 
#pragma GCC diagnostic pop
1159
 
#endif
1160
 
#endif
 
1169
          FD_CLR(proc->fd, &rfds_all);
1161
1170
          
1162
1171
          /* Block signal while modifying process_list */
1163
1172
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1203
1212
      }
1204
1213
      
1205
1214
      /* This process has not completed.  Does it have any output? */
1206
 
#if defined (__GNUC__) and defined (__GLIBC__)
1207
 
#if not __GLIBC_PREREQ(2, 16)
1208
 
#pragma GCC diagnostic push
1209
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1210
 
#endif
1211
 
#endif
1212
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1213
 
                                                         warning from
1214
 
                                                         -Wconversion
1215
 
                                                         in GNU libc
1216
 
                                                         before
1217
 
                                                         2.16 */
1218
 
#if defined (__GNUC__) and defined (__GLIBC__)
1219
 
#if not __GLIBC_PREREQ(2, 16)
1220
 
#pragma GCC diagnostic pop
1221
 
#endif
1222
 
#endif
 
1215
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1223
1216
        /* This process had nothing to say at this time */
1224
1217
        proc = proc->next;
1225
1218
        continue;
1292
1285
    free(custom_argv);
1293
1286
  }
1294
1287
  
 
1288
  free(direntries);
 
1289
  
1295
1290
  if(dir_fd != -1){
1296
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1291
    close(dir_fd);
1297
1292
  }
1298
1293
  
1299
1294
  /* Kill the processes */
1319
1314
  free_plugin_list();
1320
1315
  
1321
1316
  free(plugindir);
 
1317
  free(pluginhelperdir);
1322
1318
  free(argfile);
1323
1319
  
1324
1320
  return exitstatus;