Projet

Général

Profil

Paste
Télécharger (9,21 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / security_review / security_review.drush.inc @ bb746689

1
<?php
2

    
3
/**
4
 * @file
5
 * Drush commands for Security Review module.
6
 */
7

    
8
// Include security_review.inc file for when invoked from outside the site.
9
include_once dirname(__FILE__) . '/security_review.inc';
10

    
11
/**
12
 * Implementation of hook_drush_command().
13
 */
14
function security_review_drush_command() {
15
  $items = array();
16

    
17
  $items['security-review'] = array(
18
    'callback' => 'security_review_drush',
19
    'aliases' => array('secrev'),
20
    'description' => "Run the Security Review checklist",
21
    'options' => array(
22
      'store' => 'Write results to the database',
23
      'log' => 'Log results of each check to watchdog, defaults to off',
24
      'lastrun' => 'Do not run the checklist, just print last results',
25
      'check' => 'Comma-separated list of specified checks to run. See README.txt for list of options',
26
      'skip' => 'Invert behavior of --check. Run all checks except specified checks',
27
      'short' => "Short result messages instead of full description (e.g. 'Text formats').",
28
      'results' => 'Show the incorrect settings for failed checks.',
29
    ),
30
    'examples' => array(
31
      'secrev' => 'Run the checklist and output the results',
32
      'secrev --store' => 'Run the checklist, store, and output the results',
33
      'secrev --lastrun' => 'Output the stored results from the last run of the checklist'
34
    ),
35
  );
36
  $items['password-check-setup'] = array(
37
    'callback' => 'security_review_drush_hash_setup',
38
    'aliases' => array('passset'),
39
    'description' => "Create and load a rainbow table for password checking",
40
  );
41

    
42
  return $items;
43
}
44

    
45
/**
46
 * Implementation of hook_drush_help().
47
 */
48
function security_review_drush_help($section) {
49
  switch ($section) {
50
    case 'drush:security-review':
51
      return dt("Run configuration security checks on your Drupal site.");
52
    case 'drush:password-check-setup':
53
      return dt("Creates a table and fills it with dictionary words for rainbow testing.");
54
  }
55
}
56

    
57
/**
58
 * Run checklist and display results command.
59
 */
60
function security_review_drush() {
61
  if (!function_exists('security_review_get_checklist')) {
62
    return drush_set_error('REQUIREMENTS_ERROR', 'File security_review.inc is required to run the checklist.');
63
  }
64
  // Retrieve the checklist.
65
  $checklist = security_review_get_checklist();
66

    
67
  $store = drush_get_option('store');
68
  $log = drush_get_option('log');
69
  $lastrun = drush_get_option('lastrun');
70
  if (!function_exists('security_review_menu')) {
71
    // Checklist is being executed when module is disabled . Deny these
72
    // features.
73
    $store = $log = $lastrun = FALSE;
74
  }
75
  $specific_checks = drush_get_option_list('check');
76
  $skip = drush_get_option('skip');
77
  $short_titles = drush_get_option('short');
78
  if (!empty($short_titles)) {
79
    $short_titles = TRUE;
80
  }
81
  else {
82
    $short_titles = FALSE;
83
  }
84
  // Show failed check results only if security_review.help.inc exists.
85
  $show_results = drush_get_option('results');
86
  if ($show_results && file_exists(__DIR__ . '/security_review.help.inc')) {
87
    include_once __DIR__ . '/security_review.help.inc';
88
  }
89
  else {
90
    $show_results = FALSE;
91
  }
92

    
93
  if (!$lastrun) {
94
    if (!empty($specific_checks)) {
95
      // Get specified checks.
96
      $specific_checklist = array();
97
      foreach ($specific_checks as $check_name) {
98
        if (empty($check_name)) {
99
          continue; // Can happen if user puts space after comma.
100
        }
101
        if (strpos($check_name, ':') !== FALSE) {
102
          list($module, $check_name) = explode(':', $check_name);
103
        }
104
        else {
105
          $module = 'security_review';
106
        }
107
        if (isset($checklist[$module][$check_name])) {
108
          $specific_checklist[$module][$check_name] = $checklist[$module][$check_name];
109
        }
110
      }
111
      if ($skip) {
112
        // Run all checks except specified checks.
113
        foreach ($specific_checklist as $module => $checks) {
114
          foreach (array_keys($checks) as $check_name) {
115
            unset($checklist[$module][$check_name]);
116
          }
117
        }
118
      }
119
      else {
120
        // Run only specified checks.
121
        $checklist = $specific_checklist;
122
      }
123
    }
124
    else {
125
      // Unset file_perms of security_review because drush is running as a
126
      // different user.
127
      unset($checklist['security_review']['file_perms']);
128
    }
129
    // Remove checks that are being skipped if storing.
130
    if ($store) {
131
      $skipped = security_review_skipped_checks();
132
      if (!empty($skipped)) {
133
        foreach ($skipped as $module => $checks) {
134
          foreach ($checks as $check_name => $check) {
135
            unset($checklist[$module][$check_name]);
136
          }
137
          if (empty($checklist[$module])) {
138
            unset($checklist[$module]);
139
          }
140
        }
141
      }
142
    }
143
    if (empty($checklist)) {
144
      return drush_set_error('EMPTY_CHECKLIST', dt("No checks to run. Run 'drush help secrev' for option use or consult the drush section of README.txt for further help."));
145
    }
146
    // Run the checklist.
147
    $checklist_results = security_review_run($checklist, $log ? TRUE : NULL);
148
    if ($store) {
149
      security_review_store_results($checklist_results);
150
    }
151
    // Print results.
152
    foreach ($checklist_results as $module => $checks) {
153
      foreach ($checks as $check_name => $check) {
154
        _security_review_drush_print_result($check, $short_titles, $show_results);
155
      }
156
    }
157
  }
158
  elseif ($lastrun) {
159
    // Retrieve results from last run of the checklist.
160
    $results = security_review_get_stored_results();
161
    // Print results.
162
    if (!empty($results)) {
163
      foreach ($results as $result) {
164
        if (isset($checklist[$result['namespace']][$result['reviewcheck']])) {
165
          $check = array_merge($result, $checklist[$result['namespace']][$result['reviewcheck']]);
166
          _security_review_drush_print_result($check, $short_titles, $show_results);
167
        }
168
      }
169
    }
170
  }
171
}
172

    
173
/**
174
 * Helper function to print Security Review results using drush_log().
175
 *
176
 * @param array $check
177
 *   Check array with keys 'title', 'success', 'failure', 'result'
178
 * @param boolean $short_titles
179
 *   Whether to use short message (check title) or full check success or failure
180
 *   message.
181
 * @param boolean $show_results
182
 *   Whether to print failed check results.
183
 * @return NULL
184
 */
185
function _security_review_drush_print_result($check, $short_titles = FALSE, $show_results = FALSE) {
186
  if (is_null($check['result'])) {
187
    // Do nothing if result is NULL.
188
    return;
189
  }
190
  elseif ($check['result']) {
191
    $element = $short_titles ? 'title' : 'success';
192
    $message = $check[$element];
193
    $status = 'success';
194
  }
195
  else {
196
    $element = $short_titles ? 'title' : 'failure';
197
    $message = $check[$element];
198
    if ($show_results) {
199
      $results = _security_review_drush_findings_output($check);
200
      if (!empty($results)) {
201
        $message .= "\n";
202
        foreach ($results as $item) {
203
          $message .= "\t" . $item . "\n";
204
        }
205
      }
206
    }
207
    $status = 'error';
208
  }
209
  drush_log($message, $status);
210
}
211

    
212
function _security_review_drush_findings_output($check) {
213
  $findings = array();
214
  if (isset($check['help'])) {
215
    $findings[] = $check['help'];
216
  }
217
  elseif (isset($check['callback'])) {
218
    if (isset($check['file'])) {
219
      // Handle Security Review defining checks for other modules.
220
      if (isset($check['module'])) {
221
        $module = $check['module'];
222
      }
223
      module_load_include('inc', $module, $check['file']);
224
    }
225
    $function = $check['callback'] . '_help';
226
    if (function_exists($function)) {
227
      $element = $function($check);
228
      if (is_array($element['findings']['items'])) {
229
        foreach ($element['findings']['items'] as $item) {
230
          if (is_array($item) && isset($item['raw'])) {
231
            $findings[] = $item['raw'];
232
          }
233
        }
234
      }
235

    
236
    }
237
  }
238
  return $findings;
239
}
240

    
241
function security_review_drush_hash_setup() {
242
  $args = func_get_args();
243
  if (empty($args)) {
244
    drush_set_error('SECURITY_REVIEW_ERROR', dt('Dictionary filename required'));
245
    return FALSE;
246
  }
247
  if (file_exists($args[0])) {
248
    $ret = array();
249
    // Create the rainbow table.
250
    if (!db_table_exists('security_review_rainbow')) {
251
      $schema = array(
252
        'fields' => array(
253
          'hash_id' => array(
254
            'type' => 'serial',
255
          ),
256
          'hash_word' => array(
257
            'type' => 'varchar',
258
            'length' => 20,
259
          ),
260
          'hash_hash' => array(
261
            'type' => 'varchar',
262
            'length' => 32,
263
          ),
264
        ),
265
        'primary key' => array('hash_id'),
266
        'indexes' => array('hash_hash' => array('hash_hash')),
267
      );
268
      db_create_table($ret, 'security_review_rainbow', $schema);
269
    }
270
    // Put an index on users.pass.
271
    db_drop_index($ret, 'users', 'pass'); // Drop in case this has already run.
272
    db_add_index($ret, 'users', 'pass', array('pass'));
273

    
274
    $handle = fopen($args[0], 'r');
275
    if ($handle) {
276
      $count = 0;
277
      while (!feof($handle)) {
278
        $buffer = fgets($handle, 4096);
279
        $word = trim($buffer);
280
        $hash = md5($hash);
281
        $sql = "INSERT INTO {security_review_rainbow} (hash_word, hash_hash) VALUES ('%s', '%s')";
282
        db_query($sql, $word, $hash);
283
        $count++;
284
      }
285
      fclose($handle);
286
      drush_log(dt('!count records inserted into rainbow table', array('!count' => $count)), 'success');
287
    }
288
  }
289
  else {
290
    drush_die('File not found');
291
  }
292
}