/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugin-runner.c

  • Committer: Teddy Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • 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
354
  struct dirent **direntries = NULL;
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
  
860
891
    return 1;
861
892
  }
862
893
  
863
 
#ifdef __GLIBC__
864
 
#if __GLIBC_PREREQ(2, 15)
865
894
  int numplugins = scandirat(dir_fd, ".", &direntries, good_name,
866
895
                             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
896
  if(numplugins == -1){
876
897
    error(0, errno, "Could not scan plugin dir");
877
898
    direntries = NULL;
887
908
    int plugin_fd = openat(dir_fd, direntries[i]->d_name, O_RDONLY);
888
909
    if(plugin_fd == -1){
889
910
      error(0, errno, "Could not open plugin");
 
911
      free(direntries[i]);
890
912
      continue;
891
913
    }
892
914
    ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st));
893
915
    if(ret == -1){
894
916
      error(0, errno, "stat");
895
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
917
      close(plugin_fd);
 
918
      free(direntries[i]);
896
919
      continue;
897
920
    }
898
921
    
906
929
                plugindir != NULL ? plugindir : PDIR,
907
930
                direntries[i]->d_name);
908
931
      }
909
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
932
      close(plugin_fd);
 
933
      free(direntries[i]);
910
934
      continue;
911
935
    }
912
936
    
913
937
    plugin *p = getplugin(direntries[i]->d_name);
914
938
    if(p == NULL){
915
939
      error(0, errno, "getplugin");
916
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
940
      close(plugin_fd);
 
941
      free(direntries[i]);
917
942
      continue;
918
943
    }
919
944
    if(p->disabled){
921
946
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
922
947
                direntries[i]->d_name);
923
948
      }
924
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
949
      close(plugin_fd);
 
950
      free(direntries[i]);
925
951
      continue;
926
952
    }
927
953
    {
960
986
    if(ret == -1){
961
987
      error(0, errno, "pipe");
962
988
      exitstatus = EX_OSERR;
 
989
      free(direntries[i]);
963
990
      goto fallback;
964
991
    }
965
992
    if(pipefd[0] >= FD_SETSIZE){
966
993
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
967
994
              FD_SETSIZE);
968
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
969
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
995
      close(pipefd[0]);
 
996
      close(pipefd[1]);
970
997
      exitstatus = EX_OSERR;
 
998
      free(direntries[i]);
971
999
      goto fallback;
972
1000
    }
973
1001
#ifndef O_CLOEXEC
975
1003
    ret = set_cloexec_flag(pipefd[0]);
976
1004
    if(ret < 0){
977
1005
      error(0, errno, "set_cloexec_flag");
978
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
979
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
980
1008
      exitstatus = EX_OSERR;
 
1009
      free(direntries[i]);
981
1010
      goto fallback;
982
1011
    }
983
1012
    ret = set_cloexec_flag(pipefd[1]);
984
1013
    if(ret < 0){
985
1014
      error(0, errno, "set_cloexec_flag");
986
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
987
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1015
      close(pipefd[0]);
 
1016
      close(pipefd[1]);
988
1017
      exitstatus = EX_OSERR;
 
1018
      free(direntries[i]);
989
1019
      goto fallback;
990
1020
    }
991
1021
#endif  /* not O_CLOEXEC */
996
1026
    if(ret < 0){
997
1027
      error(0, errno, "sigprocmask");
998
1028
      exitstatus = EX_OSERR;
 
1029
      free(direntries[i]);
999
1030
      goto fallback;
1000
1031
    }
1001
1032
    /* Starting a new process to be watched */
1007
1038
      error(0, errno, "fork");
1008
1039
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1009
1040
                                     &sigchld_action.sa_mask, NULL));
1010
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1011
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1041
      close(pipefd[0]);
 
1042
      close(pipefd[1]);
1012
1043
      exitstatus = EX_OSERR;
 
1044
      free(direntries[i]);
1013
1045
      goto fallback;
1014
1046
    }
1015
1047
    if(pid == 0){
1041
1073
      /* no return */
1042
1074
    }
1043
1075
    /* Parent process */
1044
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1045
 
                                             pipe */
1046
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1076
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1077
    close(plugin_fd);
1047
1078
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1048
1079
    if(new_plugin == NULL){
1049
1080
      error(0, errno, "getplugin");
1054
1085
        error(0, errno, "sigprocmask");
1055
1086
      }
1056
1087
      exitstatus = EX_OSERR;
 
1088
      free(direntries[i]);
1057
1089
      goto fallback;
1058
1090
    }
 
1091
    free(direntries[i]);
1059
1092
    
1060
1093
    new_plugin->pid = pid;
1061
1094
    new_plugin->fd = pipefd[0];
1071
1104
      goto fallback;
1072
1105
    }
1073
1106
    
1074
 
#if defined (__GNUC__) and defined (__GLIBC__)
1075
 
#if not __GLIBC_PREREQ(2, 16)
1076
 
#pragma GCC diagnostic push
1077
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1078
 
#endif
1079
 
#endif
1080
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1081
 
                                          -Wconversion in GNU libc
1082
 
                                          before 2.16 */
1083
 
#if defined (__GNUC__) and defined (__GLIBC__)
1084
 
#if not __GLIBC_PREREQ(2, 16)
1085
 
#pragma GCC diagnostic pop
1086
 
#endif
1087
 
#endif
 
1107
    FD_SET(new_plugin->fd, &rfds_all);
1088
1108
    
1089
1109
    if(maxfd < new_plugin->fd){
1090
1110
      maxfd = new_plugin->fd;
1093
1113
  
1094
1114
  free(direntries);
1095
1115
  direntries = NULL;
1096
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1116
  close(dir_fd);
1097
1117
  dir_fd = -1;
1098
1118
  free_plugin(getplugin(NULL));
1099
1119
  
1146
1166
          }
1147
1167
          
1148
1168
          /* Remove the plugin */
1149
 
#if defined (__GNUC__) and defined (__GLIBC__)
1150
 
#if not __GLIBC_PREREQ(2, 16)
1151
 
#pragma GCC diagnostic push
1152
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1153
 
#endif
1154
 
#endif
1155
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1156
 
                                          -Wconversion in GNU libc
1157
 
                                          before 2.16 */
1158
 
#if defined (__GNUC__) and defined (__GLIBC__)
1159
 
#if not __GLIBC_PREREQ(2, 16)
1160
 
#pragma GCC diagnostic pop
1161
 
#endif
1162
 
#endif
 
1169
          FD_CLR(proc->fd, &rfds_all);
1163
1170
          
1164
1171
          /* Block signal while modifying process_list */
1165
1172
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1205
1212
      }
1206
1213
      
1207
1214
      /* This process has not completed.  Does it have any output? */
1208
 
#if defined (__GNUC__) and defined (__GLIBC__)
1209
 
#if not __GLIBC_PREREQ(2, 16)
1210
 
#pragma GCC diagnostic push
1211
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1212
 
#endif
1213
 
#endif
1214
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1215
 
                                                         warning from
1216
 
                                                         -Wconversion
1217
 
                                                         in GNU libc
1218
 
                                                         before
1219
 
                                                         2.16 */
1220
 
#if defined (__GNUC__) and defined (__GLIBC__)
1221
 
#if not __GLIBC_PREREQ(2, 16)
1222
 
#pragma GCC diagnostic pop
1223
 
#endif
1224
 
#endif
 
1215
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1225
1216
        /* This process had nothing to say at this time */
1226
1217
        proc = proc->next;
1227
1218
        continue;
1297
1288
  free(direntries);
1298
1289
  
1299
1290
  if(dir_fd != -1){
1300
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1291
    close(dir_fd);
1301
1292
  }
1302
1293
  
1303
1294
  /* Kill the processes */
1323
1314
  free_plugin_list();
1324
1315
  
1325
1316
  free(plugindir);
 
1317
  free(pluginhelperdir);
1326
1318
  free(argfile);
1327
1319
  
1328
1320
  return exitstatus;