/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
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;
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);
897
918
      free(direntries[i]);
898
919
      continue;
899
920
    }
908
929
                plugindir != NULL ? plugindir : PDIR,
909
930
                direntries[i]->d_name);
910
931
      }
911
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
932
      close(plugin_fd);
912
933
      free(direntries[i]);
913
934
      continue;
914
935
    }
916
937
    plugin *p = getplugin(direntries[i]->d_name);
917
938
    if(p == NULL){
918
939
      error(0, errno, "getplugin");
919
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
940
      close(plugin_fd);
920
941
      free(direntries[i]);
921
942
      continue;
922
943
    }
925
946
        fprintf(stderr, "Ignoring disabled plugin \"%s\"\n",
926
947
                direntries[i]->d_name);
927
948
      }
928
 
      TEMP_FAILURE_RETRY(close(plugin_fd));
 
949
      close(plugin_fd);
929
950
      free(direntries[i]);
930
951
      continue;
931
952
    }
971
992
    if(pipefd[0] >= FD_SETSIZE){
972
993
      fprintf(stderr, "pipe()[0] (%d) >= FD_SETSIZE (%d)", pipefd[0],
973
994
              FD_SETSIZE);
974
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
975
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
995
      close(pipefd[0]);
 
996
      close(pipefd[1]);
976
997
      exitstatus = EX_OSERR;
977
998
      free(direntries[i]);
978
999
      goto fallback;
982
1003
    ret = set_cloexec_flag(pipefd[0]);
983
1004
    if(ret < 0){
984
1005
      error(0, errno, "set_cloexec_flag");
985
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
986
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1006
      close(pipefd[0]);
 
1007
      close(pipefd[1]);
987
1008
      exitstatus = EX_OSERR;
988
1009
      free(direntries[i]);
989
1010
      goto fallback;
991
1012
    ret = set_cloexec_flag(pipefd[1]);
992
1013
    if(ret < 0){
993
1014
      error(0, errno, "set_cloexec_flag");
994
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
995
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1015
      close(pipefd[0]);
 
1016
      close(pipefd[1]);
996
1017
      exitstatus = EX_OSERR;
997
1018
      free(direntries[i]);
998
1019
      goto fallback;
1017
1038
      error(0, errno, "fork");
1018
1039
      TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
1019
1040
                                     &sigchld_action.sa_mask, NULL));
1020
 
      TEMP_FAILURE_RETRY(close(pipefd[0]));
1021
 
      TEMP_FAILURE_RETRY(close(pipefd[1]));
 
1041
      close(pipefd[0]);
 
1042
      close(pipefd[1]);
1022
1043
      exitstatus = EX_OSERR;
1023
1044
      free(direntries[i]);
1024
1045
      goto fallback;
1052
1073
      /* no return */
1053
1074
    }
1054
1075
    /* Parent process */
1055
 
    TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
1056
 
                                             pipe */
1057
 
    TEMP_FAILURE_RETRY(close(plugin_fd));
 
1076
    close(pipefd[1]);           /* Close unused write end of pipe */
 
1077
    close(plugin_fd);
1058
1078
    plugin *new_plugin = getplugin(direntries[i]->d_name);
1059
1079
    if(new_plugin == NULL){
1060
1080
      error(0, errno, "getplugin");
1084
1104
      goto fallback;
1085
1105
    }
1086
1106
    
1087
 
#if defined (__GNUC__) and defined (__GLIBC__)
1088
 
#if not __GLIBC_PREREQ(2, 16)
1089
 
#pragma GCC diagnostic push
1090
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1091
 
#endif
1092
 
#endif
1093
 
    FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
1094
 
                                          -Wconversion in GNU libc
1095
 
                                          before 2.16 */
1096
 
#if defined (__GNUC__) and defined (__GLIBC__)
1097
 
#if not __GLIBC_PREREQ(2, 16)
1098
 
#pragma GCC diagnostic pop
1099
 
#endif
1100
 
#endif
 
1107
    FD_SET(new_plugin->fd, &rfds_all);
1101
1108
    
1102
1109
    if(maxfd < new_plugin->fd){
1103
1110
      maxfd = new_plugin->fd;
1106
1113
  
1107
1114
  free(direntries);
1108
1115
  direntries = NULL;
1109
 
  TEMP_FAILURE_RETRY(close(dir_fd));
 
1116
  close(dir_fd);
1110
1117
  dir_fd = -1;
1111
1118
  free_plugin(getplugin(NULL));
1112
1119
  
1159
1166
          }
1160
1167
          
1161
1168
          /* Remove the plugin */
1162
 
#if defined (__GNUC__) and defined (__GLIBC__)
1163
 
#if not __GLIBC_PREREQ(2, 16)
1164
 
#pragma GCC diagnostic push
1165
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1166
 
#endif
1167
 
#endif
1168
 
          FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
1169
 
                                          -Wconversion in GNU libc
1170
 
                                          before 2.16 */
1171
 
#if defined (__GNUC__) and defined (__GLIBC__)
1172
 
#if not __GLIBC_PREREQ(2, 16)
1173
 
#pragma GCC diagnostic pop
1174
 
#endif
1175
 
#endif
 
1169
          FD_CLR(proc->fd, &rfds_all);
1176
1170
          
1177
1171
          /* Block signal while modifying process_list */
1178
1172
          ret = (int)TEMP_FAILURE_RETRY(sigprocmask
1218
1212
      }
1219
1213
      
1220
1214
      /* This process has not completed.  Does it have any output? */
1221
 
#if defined (__GNUC__) and defined (__GLIBC__)
1222
 
#if not __GLIBC_PREREQ(2, 16)
1223
 
#pragma GCC diagnostic push
1224
 
#pragma GCC diagnostic ignored "-Wsign-conversion"
1225
 
#endif
1226
 
#endif
1227
 
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
1228
 
                                                         warning from
1229
 
                                                         -Wconversion
1230
 
                                                         in GNU libc
1231
 
                                                         before
1232
 
                                                         2.16 */
1233
 
#if defined (__GNUC__) and defined (__GLIBC__)
1234
 
#if not __GLIBC_PREREQ(2, 16)
1235
 
#pragma GCC diagnostic pop
1236
 
#endif
1237
 
#endif
 
1215
      if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
1238
1216
        /* This process had nothing to say at this time */
1239
1217
        proc = proc->next;
1240
1218
        continue;
1310
1288
  free(direntries);
1311
1289
  
1312
1290
  if(dir_fd != -1){
1313
 
    TEMP_FAILURE_RETRY(close(dir_fd));
 
1291
    close(dir_fd);
1314
1292
  }
1315
1293
  
1316
1294
  /* Kill the processes */
1336
1314
  free_plugin_list();
1337
1315
  
1338
1316
  free(plugindir);
 
1317
  free(pluginhelperdir);
1339
1318
  free(argfile);
1340
1319
  
1341
1320
  return exitstatus;