1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2011-2012 Planets Communications B.V.
5    Copyright (C) 2013-2018 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 
23 /*
24  * Low level SCSI interface for SCSI crypto services
25  *
26  * Marco van Wieringen, March 2012
27  */
28 
29 #include "include/bareos.h"
30 
31 /* Forward referenced functions */
32 
33 static void IndentStatusMsg(POOLMEM*& status, const char* msg, int indent);
34 
35 #include "lib/scsi_crypto.h"
36 
37 #ifdef HAVE_LOWLEVEL_SCSI_INTERFACE
38 
39 /*
40  * Store a value as 2 bytes MSB/LSB
41  */
set_2_byte_value(unsigned char * field,int value)42 static inline void set_2_byte_value(unsigned char* field, int value)
43 {
44   field[0] = (unsigned char)((value & 0xff00) >> 8);
45   field[1] = (unsigned char)(value & 0x00ff);
46 }
47 
48 /*
49  * Store a value as 4 bytes MSB/LSB
50  */
set_4_byte_value(unsigned char * field,int value)51 static inline void set_4_byte_value(unsigned char* field, int value)
52 {
53   field[0] = (unsigned char)((value & 0xff000000) >> 24);
54   field[1] = (unsigned char)((value & 0x00ff0000) >> 16);
55   field[2] = (unsigned char)((value & 0x0000ff00) >> 8);
56   field[3] = (unsigned char)(value & 0x000000ff);
57 }
58 
59 /*
60  * Clear an encryption key used by a tape drive
61  * using a lowlevel SCSI interface.
62  *
63  * The device is send a:
64  * - SPOUT Security Protocol OUT SCSI CDB. (0xB5)
65  * - SPOUT Send Encryption Key Page. (0x10)
66  *
67  * The Send Encryption Key page has the encryption
68  * and decryption set to disabled and the key is empty.
69  */
ClearScsiEncryptionKey(int fd,const char * device_name)70 bool ClearScsiEncryptionKey(int fd, const char* device_name)
71 {
72   /*
73    * Create a SPOUT Set Encryption Key CDB and
74    *        a SPOUT Clear Encryption Mode Page
75    */
76   SPP_SCSI_CDB cdb;
77   SPP_PAGE_BUFFER cmd_page;
78   SPP_PAGE_SDE* sps;
79   int cmd_page_len, cdb_len;
80 
81   /*
82    * Put a SPOUT Set Data Encryption page into the start of
83    * the generic cmd_page structure.
84    */
85   memset(&cmd_page, 0, sizeof(cmd_page));
86   sps = (SPP_PAGE_SDE*)&cmd_page;
87   set_2_byte_value(sps->pageCode, SPOUT_SET_DATA_ENCRYPTION_PAGE);
88   sps->nexusScope = SPP_NEXUS_SC_ALL_I_T_NEXUS;
89   sps->encryptionMode = SPP_ENCR_MODE_DISABLE;
90   sps->decryptionMode = SPP_DECR_MODE_DISABLE;
91   sps->algorithmIndex = 0x01;
92   sps->kadFormat = SPP_KAD_KEY_FORMAT_NORMAL;
93   set_2_byte_value(sps->keyLength, SPP_KEY_LENGTH);
94 
95   /*
96    * Set the length to the size of the SPP_PAGE_SDE we just filled.
97    */
98   cmd_page_len = sizeof(SPP_PAGE_SDE);
99 
100   /*
101    * Set the actual size of the cmd_page - 4 into the cmd_page length field
102    * (without the pageCode and pageLength)
103    */
104   set_2_byte_value(cmd_page.length, cmd_page_len - 4);
105 
106   /*
107    * Fill the SCSI CDB.
108    */
109   cdb_len = sizeof(cdb);
110   memset(&cdb, 0, cdb_len);
111   cdb.opcode = SCSI_SPOUT_OPCODE;
112   cdb.scp = SPP_SP_PROTOCOL_TDE;
113   set_2_byte_value(cdb.scp_specific, SPOUT_SET_DATA_ENCRYPTION_PAGE);
114   set_4_byte_value(cdb.allocation_length, cmd_page_len);
115 
116   /*
117    * Clear the encryption key.
118    */
119   return send_scsi_cmd_page(fd, device_name, (void*)&cdb, cdb_len,
120                             (void*)&cmd_page, cmd_page_len);
121 }
122 
123 /*
124  * Set an encryption key used by a tape drive
125  * using a lowlevel SCSI interface.
126  *
127  * The device is send a:
128  * - SPOUT Security Protocol OUT SCSI CDB. (0xB5)
129  * - SPOUT Send Encryption Key Page. (0x10)
130  *
131  * The Send Encryption Key page has the encryption
132  * and decryption set to not disabled and the key is filled.
133  */
SetScsiEncryptionKey(int fd,const char * device_name,char * encryption_key)134 bool SetScsiEncryptionKey(int fd, const char* device_name, char* encryption_key)
135 {
136   /*
137    * Create a SPOUT Set Encryption Key CDB and
138    *        a SPOUT Send Encryption Key Page
139    */
140   SPP_SCSI_CDB cdb;
141   SPP_PAGE_BUFFER cmd_page;
142   SPP_PAGE_SDE* sps;
143   int cmd_page_len, cdb_len;
144 
145   /*
146    * Put a SPOUT Set Data Encryption page into the start of
147    * the generic cmd_page structure.
148    */
149   memset(&cmd_page, 0, sizeof(cmd_page));
150   sps = (SPP_PAGE_SDE*)&cmd_page;
151   set_2_byte_value(sps->pageCode, SPOUT_SET_DATA_ENCRYPTION_PAGE);
152   sps->nexusScope = SPP_NEXUS_SC_ALL_I_T_NEXUS;
153   sps->encryptionMode = SPP_ENCR_MODE_ENCRYPT;
154   sps->decryptionMode = SPP_DECR_MODE_MIXED;
155   sps->algorithmIndex = 0x01;
156   sps->kadFormat = SPP_KAD_KEY_FORMAT_NORMAL;
157   set_2_byte_value(sps->keyLength, SPP_KEY_LENGTH);
158   bstrncpy((char*)sps->keyData, encryption_key, SPP_KEY_LENGTH);
159 
160   /*
161    * Set the length to the size of the SPP_PAGE_SDE we just filled.
162    */
163   cmd_page_len = sizeof(SPP_PAGE_SDE);
164 
165   /*
166    * Set the actual size of the cmd_page - 4 into the cmd_page length field
167    * (without the pageCode and pageLength)
168    */
169   set_2_byte_value(cmd_page.length, cmd_page_len - 4);
170 
171   /*
172    * Fill the SCSI CDB.
173    */
174   cdb_len = sizeof(cdb);
175   memset(&cdb, 0, cdb_len);
176   cdb.opcode = SCSI_SPOUT_OPCODE;
177   cdb.scp = SPP_SP_PROTOCOL_TDE;
178   set_2_byte_value(cdb.scp_specific, SPOUT_SET_DATA_ENCRYPTION_PAGE);
179   set_4_byte_value(cdb.allocation_length, cmd_page_len);
180 
181   /*
182    * Set the new encryption key.
183    */
184   return send_scsi_cmd_page(fd, device_name, (void*)&cdb, cdb_len,
185                             (void*)&cmd_page, cmd_page_len);
186 }
187 
188 /*
189  * Request the encryption state of a drive
190  * using a lowlevel SCSI interface.
191  *
192  * The device is send a:
193  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
194  * - SPIN Get Data Encryption Status page. (0x20)
195  *
196  * The return data is interpreted and a status report is build.
197  */
GetScsiDriveEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)198 int GetScsiDriveEncryptionStatus(int fd,
199                                  const char* device_name,
200                                  POOLMEM*& status,
201                                  int indent)
202 {
203   SPP_SCSI_CDB cdb;
204   SPP_PAGE_BUFFER cmd_page;
205   SPP_PAGE_DES* spd;
206   int cmd_page_len, cdb_len;
207 
208   cmd_page_len = sizeof(cmd_page);
209   memset(&cmd_page, 0, cmd_page_len);
210 
211   /*
212    * Fill the SCSI CDB.
213    */
214   cdb_len = sizeof(cdb);
215   memset(&cdb, 0, cdb_len);
216   cdb.opcode = SCSI_SPIN_OPCODE;
217   cdb.scp = SPP_SP_PROTOCOL_TDE;
218   set_2_byte_value(cdb.scp_specific, SPIN_DATA_ENCR_STATUS_PAGE);
219   set_4_byte_value(cdb.allocation_length, cmd_page_len);
220 
221   /*
222    * Retrieve the drive encryption status.
223    */
224   if (!RecvScsiCmdPage(fd, device_name, (void*)&cdb, cdb_len, (void*)&cmd_page,
225                        cmd_page_len)) {
226     return 0;
227   }
228 
229   /*
230    * We got a response which should contain a SPP_PAGE_DES.
231    * Create a pointer to the beginning of the generic
232    * cmd_page structure.
233    */
234   spd = (SPP_PAGE_DES*)&cmd_page;
235 
236   PmStrcpy(status, "");
237   IndentStatusMsg(status, _("Drive encryption status:\n"), indent);
238 
239   /*
240    * See what encrption mode is enabled.
241    */
242   switch (spd->encryptionMode) {
243     case SPP_ENCR_MODE_DISABLE:
244       IndentStatusMsg(status, _("Encryption Mode: Disabled\n"), indent + 3);
245       break;
246     case SPP_ENCR_MODE_EXTERNAL:
247       IndentStatusMsg(status, _("Encryption Mode: External\n"), indent + 3);
248       break;
249     case SPP_ENCR_MODE_ENCRYPT:
250       IndentStatusMsg(status, _("Encryption Mode: Encrypt\n"), indent + 3);
251       break;
252     default:
253       break;
254   }
255 
256   /*
257    * See what decryption mode is enabled.
258    */
259   switch (spd->decryptionMode) {
260     case SPP_DECR_MODE_DISABLE:
261       IndentStatusMsg(status, _("Decryption Mode: Disabled\n"), indent + 3);
262       break;
263     case SPP_DECR_MODE_RAW:
264       IndentStatusMsg(status, _("Decryption Mode: Raw\n"), indent + 3);
265       break;
266     case SPP_DECR_MODE_DECRYPT:
267       IndentStatusMsg(status, _("Decryption Mode: Decrypt\n"), indent + 3);
268       break;
269     case SPP_DECR_MODE_MIXED:
270       IndentStatusMsg(status, _("Decryption Mode: Mixed\n"), indent + 3);
271       break;
272     default:
273       break;
274   }
275 
276   /*
277    * See if RDMD is enabled.
278    */
279   if (spd->RDMD) {
280     IndentStatusMsg(status, _("Raw Decryption Mode Disabled (RDMD): Enabled\n"),
281                     indent + 3);
282   } else {
283     IndentStatusMsg(status,
284                     _("Raw Decryption Mode Disabled (RDMD): Disabled\n"),
285                     indent + 3);
286   }
287 
288   /*
289    * See what Check External Encryption Mode Status is set.
290    */
291   switch (spd->CEEMS) {
292     case SPP_CEEM_NO_ENCR_CHECK:
293       IndentStatusMsg(status,
294                       _("Check External Encryption Mode Status (CEEMS) : No\n"),
295                       indent + 3);
296       break;
297     case SPP_CEEM_CHECK_EXTERNAL:
298       IndentStatusMsg(
299           status,
300           _("Check External Encryption Mode Status (CEEMS) : External\n"),
301           indent + 3);
302       break;
303     case SPP_CEEM_CHECK_ENCR:
304       IndentStatusMsg(
305           status,
306           _("Check External Encryption Mode Status (CEEMS) : Encrypt\n"),
307           indent + 3);
308       break;
309     default:
310       break;
311   }
312 
313   /*
314    * See if VCELB is enabled.
315    */
316   if (spd->VCELB) {
317     IndentStatusMsg(
318         status,
319         _("Volume Contains Encrypted Logical Blocks (VCELB): Enabled\n"),
320         indent + 3);
321   } else {
322     IndentStatusMsg(
323         status,
324         _("Volume Contains Encrypted Logical Blocks (VCELB): Disabled\n"),
325         indent + 3);
326   }
327 
328   /*
329    * See what is providing the encryption keys.
330    */
331   switch (spd->parametersControl) {
332     case SPP_PARM_LOG_BLOCK_ENCR_NONE:
333       IndentStatusMsg(status,
334                       _("Logical Block encryption parameters: No report\n"),
335                       indent + 3);
336       break;
337     case SPP_PARM_LOG_BLOCK_ENCR_AME:
338       IndentStatusMsg(
339           status,
340           _("Logical Block encryption parameters: Application Managed\n"),
341           indent + 3);
342       break;
343     case SPP_PARM_LOG_BLOCK_ENCR_DRIVE:
344       IndentStatusMsg(status,
345                       _("Logical Block encryption parameters: Drive Managed\n"),
346                       indent + 3);
347       break;
348     case SPP_PARM_LOG_BLOCK_LME_ADC:
349       IndentStatusMsg(status,
350                       _("Logical Block encryption parameters: Library/Key "
351                         "Management Appliance Managed\n"),
352                       indent + 3);
353       break;
354     case SPP_PARM_LOG_BLOCK_UNSUP:
355       IndentStatusMsg(status,
356                       _("Logical Block encryption parameters: Unsupported\n"),
357                       indent + 3);
358       break;
359     default:
360       break;
361   }
362 
363   /*
364    * Only when both encryption and decryption are disabled skip the KAD Format
365    * field.
366    */
367   if (spd->encryptionMode != SPP_ENCR_MODE_DISABLE
368       && spd->decryptionMode != SPP_DECR_MODE_DISABLE) {
369     switch (spd->kadFormat) {
370       case SPP_KAD_KEY_FORMAT_NORMAL:
371         IndentStatusMsg(status,
372                         _("Key Associated Data (KAD) Descriptor: Normal key\n"),
373                         indent + 3);
374         break;
375       case SPP_KAD_KEY_FORMAT_REFERENCE:
376         IndentStatusMsg(status,
377                         _("Key Associated Data (KAD) Descriptor: "
378                           "Vendor-specific reference\n"),
379                         indent + 3);
380         break;
381       case SPP_KAD_KEY_FORMAT_WRAPPED:
382         IndentStatusMsg(
383             status,
384             _("Key Associated Data (KAD) Descriptor: Wrapped public key\n"),
385             indent + 3);
386         break;
387       case SPP_KAD_KEY_FORMAT_ESP_SCSI:
388         IndentStatusMsg(
389             status,
390             _("Key Associated Data (KAD) Descriptor: Key using ESP-SCSI\n"),
391             indent + 3);
392         break;
393       default:
394         break;
395     }
396   }
397 
398   return strlen(status);
399 }
400 
401 /*
402  * Request the encryption state of the next block
403  * using a lowlevel SCSI interface.
404  *
405  * The device is send a:
406  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
407  * - SPIN Get Data Encryption Status page. (0x21)
408  *
409  * The return data is interpreted and a status report is build.
410  */
GetScsiVolumeEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)411 int GetScsiVolumeEncryptionStatus(int fd,
412                                   const char* device_name,
413                                   POOLMEM*& status,
414                                   int indent)
415 {
416   SPP_SCSI_CDB cdb;
417   SPP_PAGE_BUFFER cmd_page;
418   SPP_PAGE_NBES* spnb;
419   int cmd_page_len, cdb_len;
420 
421   cmd_page_len = sizeof(cmd_page);
422   memset(&cmd_page, 0, cmd_page_len);
423 
424   /*
425    * Fill the SCSI CDB.
426    */
427   cdb_len = sizeof(cdb);
428   memset(&cdb, 0, cdb_len);
429   cdb.opcode = SCSI_SPIN_OPCODE;
430   cdb.scp = SPP_SP_PROTOCOL_TDE;
431   set_2_byte_value(cdb.scp_specific, SPIN_NEXT_BLOCK_ENCR_STATUS_PAGE);
432   set_4_byte_value(cdb.allocation_length, cmd_page_len);
433 
434   /*
435    * Retrieve the volume encryption status.
436    */
437   if (!RecvScsiCmdPage(fd, device_name, (void*)&cdb, cdb_len, (void*)&cmd_page,
438                        cmd_page_len)) {
439     return 0;
440   }
441 
442   /*
443    * We got a response which should contain a SPP_PAGE_NBES.
444    * Create a pointer to the beginning of the generic
445    * cmd_page structure.
446    */
447   spnb = (SPP_PAGE_NBES*)&cmd_page;
448 
449   PmStrcpy(status, "");
450   IndentStatusMsg(status, _("Volume encryption status:\n"), indent);
451 
452   switch (spnb->compressionStatus) {
453     case SPP_COMP_STATUS_UNKNOWN:
454       IndentStatusMsg(status, _("Compression Status: Unknown\n"), indent + 3);
455       break;
456     case SPP_COMP_STATUS_UNAVAIL:
457       IndentStatusMsg(status, _("Compression Status: Unavailable\n"),
458                       indent + 3);
459       break;
460     case SPP_COMP_STATUS_ILLEGAL:
461       IndentStatusMsg(status, _("Compression Status: Illegal logical block\n"),
462                       indent + 3);
463       break;
464     case SPP_COMP_STATUS_UNCOMPRESSED:
465       IndentStatusMsg(status, _("Compression Status: Compression Disabled\n"),
466                       indent + 3);
467       break;
468     case SPP_COMP_STATUS_COMPRESSED:
469       IndentStatusMsg(status, _("Compression Status: Compression Enabled\n"),
470                       indent + 3);
471       break;
472     default:
473       break;
474   }
475 
476   switch (spnb->encryptionStatus) {
477     case SPP_ENCR_STATUS_UNKNOWN:
478       IndentStatusMsg(status, _("Encryption Status: Unknown\n"), indent + 3);
479       break;
480     case SPP_ENCR_STATUS_UNAVAIL:
481       IndentStatusMsg(status, _("Encryption Status: Unavailable\n"),
482                       indent + 3);
483       break;
484     case SPP_ENCR_STATUS_ILLEGAL:
485       IndentStatusMsg(status, _("Encryption Status: Illegal logical block\n"),
486                       indent + 3);
487       break;
488     case SPP_ENCR_STATUS_NOT_ENCRYPTED:
489       IndentStatusMsg(status, _("Encryption Status: Encryption Disabled\n"),
490                       indent + 3);
491       break;
492     case SPP_ENCR_STATUS_ENCR_ALG_NOT_SUPP:
493       IndentStatusMsg(status,
494                       _("Encryption Status: Encryption Enabled but with non "
495                         "supported algorithm\n"),
496                       indent + 3);
497       break;
498     case SPP_ENCR_STATUS_ENCRYPTED:
499       IndentStatusMsg(status, _("Encryption Status: Encryption Enabled\n"),
500                       indent + 3);
501       break;
502     case SPP_ENCR_STATUS_ENCR_NOT_AVAIL:
503       IndentStatusMsg(status,
504                       _("Encryption Status: Encryption Enabled but no valid "
505                         "key available for decryption\n"),
506                       indent + 3);
507       break;
508     default:
509       break;
510   }
511 
512   if (spnb->RDMDS) {
513     IndentStatusMsg(status,
514                     _("Raw Decryption Mode Disabled Status (RDMDS): Enabled\n"),
515                     indent + 3);
516   } else {
517     IndentStatusMsg(
518         status, _("Raw Decryption Mode Disabled Status (RDMDS): Disabled\n"),
519         indent + 3);
520   }
521 
522   if (spnb->EMES) {
523     IndentStatusMsg(status,
524                     _("Encryption Mode External Status (EMES): Enabled\n"),
525                     indent + 3);
526   } else {
527     IndentStatusMsg(status,
528                     _("Encryption Mode External Status (EMES): Disabled\n"),
529                     indent + 3);
530   }
531 
532   /*
533    * Only when the encryption status is set to SPP_ENCR_STATUS_ENCRYPTED we
534    * can use the nextBlockKADFormat otherwise that value is bogus.
535    */
536   if (spnb->encryptionStatus == SPP_ENCR_STATUS_ENCRYPTED) {
537     switch (spnb->nextBlockKADFormat) {
538       case SPP_KAD_KEY_FORMAT_NORMAL:
539         IndentStatusMsg(
540             status,
541             _("Next Block Key Associated Data (KAD) Descriptor: Normal key\n"),
542             indent + 3);
543         break;
544       case SPP_KAD_KEY_FORMAT_REFERENCE:
545         IndentStatusMsg(status,
546                         _("Next Block Key Associated Data (KAD) Descriptor: "
547                           "Vendor-specific reference\n"),
548                         indent + 3);
549         break;
550       case SPP_KAD_KEY_FORMAT_WRAPPED:
551         IndentStatusMsg(status,
552                         _("Next Block Key Associated Data (KAD) Descriptor: "
553                           "Wrapped public key\n"),
554                         indent + 3);
555         break;
556       case SPP_KAD_KEY_FORMAT_ESP_SCSI:
557         IndentStatusMsg(status,
558                         _("Next Block Key Associated Data (KAD) Descriptor: "
559                           "Key using ESP-SCSI\n"),
560                         indent + 3);
561         break;
562       default:
563         break;
564     }
565   }
566 
567   return strlen(status);
568 }
569 
570 /*
571  * See if we need a decryption key to read the next block
572  * using a lowlevel SCSI interface.
573  *
574  * The device is send a:
575  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
576  * - SPIN Get Data Encryption Status page. (0x21)
577  */
NeedScsiCryptoKey(int fd,const char * device_name,bool use_drive_status)578 bool NeedScsiCryptoKey(int fd, const char* device_name, bool use_drive_status)
579 {
580   SPP_SCSI_CDB cdb;
581   SPP_PAGE_BUFFER cmd_page;
582   SPP_PAGE_DES* spd;
583   SPP_PAGE_NBES* spnb;
584   int cmd_page_len, cdb_len;
585 
586   cmd_page_len = sizeof(cmd_page);
587   memset(&cmd_page, 0, cmd_page_len);
588 
589   /*
590    * Fill the SCSI CDB.
591    */
592   cdb_len = sizeof(cdb);
593   memset(&cdb, 0, cdb_len);
594   cdb.opcode = SCSI_SPIN_OPCODE;
595   cdb.scp = SPP_SP_PROTOCOL_TDE;
596   if (use_drive_status) {
597     set_2_byte_value(cdb.scp_specific, SPIN_DATA_ENCR_STATUS_PAGE);
598   } else {
599     set_2_byte_value(cdb.scp_specific, SPIN_NEXT_BLOCK_ENCR_STATUS_PAGE);
600   }
601   set_4_byte_value(cdb.allocation_length, cmd_page_len);
602 
603   /*
604    * Retrieve the volume encryption status.
605    */
606   if (!RecvScsiCmdPage(fd, device_name, (void*)&cdb, cdb_len, (void*)&cmd_page,
607                        cmd_page_len)) {
608     return false;
609   }
610 
611   if (use_drive_status) {
612     /*
613      * We got a response which should contain a SPP_PAGE_DES.
614      * Create a pointer to the beginning of the generic
615      * cmd_page structure.
616      */
617     spd = (SPP_PAGE_DES*)&cmd_page;
618 
619     /*
620      * Return the status of the Volume Contains Encrypted Logical Blocks (VCELB)
621      * field.
622      */
623     return (spd->VCELB) ? true : false;
624   } else {
625     /*
626      * We got a response which should contain a SPP_PAGE_NBES.
627      * Create a pointer to the beginning of the generic
628      * cmd_page structure.
629      */
630     spnb = (SPP_PAGE_NBES*)&cmd_page;
631 
632     /*
633      * If the encryptionStatus is set to encrypted or encrypted but valid key
634      * not available we know we need to load a key to decrypt the data.
635      */
636     switch (spnb->encryptionStatus) {
637       case SPP_ENCR_STATUS_ENCRYPTED:
638       case SPP_ENCR_STATUS_ENCR_NOT_AVAIL:
639         return true;
640       default:
641         break;
642     }
643   }
644 
645   return false;
646 }
647 
648 /*
649  * See if encryption is enabled on a device using a lowlevel SCSI interface.
650  *
651  * The device is send a:
652  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
653  * - SPIN Get Data Encryption Status page. (0x20)
654  */
IsScsiEncryptionEnabled(int fd,const char * device_name)655 bool IsScsiEncryptionEnabled(int fd, const char* device_name)
656 {
657   SPP_SCSI_CDB cdb;
658   SPP_PAGE_BUFFER cmd_page;
659   SPP_PAGE_DES* spd;
660   int cmd_page_len, cdb_len;
661 
662   cmd_page_len = sizeof(cmd_page);
663   memset(&cmd_page, 0, cmd_page_len);
664 
665   /*
666    * Fill the SCSI CDB.
667    */
668   cdb_len = sizeof(cdb);
669   memset(&cdb, 0, cdb_len);
670   cdb.opcode = SCSI_SPIN_OPCODE;
671   cdb.scp = SPP_SP_PROTOCOL_TDE;
672   set_2_byte_value(cdb.scp_specific, SPIN_DATA_ENCR_STATUS_PAGE);
673   set_4_byte_value(cdb.allocation_length, cmd_page_len);
674 
675   /*
676    * Retrieve the drive encryption status.
677    */
678   if (!RecvScsiCmdPage(fd, device_name, (void*)&cdb, cdb_len, (void*)&cmd_page,
679                        cmd_page_len)) {
680     return false;
681   }
682 
683   /*
684    * We got a response which should contain a SPP_PAGE_DES.
685    * Create a pointer to the beginning of the generic
686    * cmd_page structure.
687    */
688   spd = (SPP_PAGE_DES*)&cmd_page;
689 
690   /*
691    * When either encryptionMode or decryptionMode are not disabled we return
692    * true
693    */
694   return (spd->encryptionMode != SPP_ENCR_MODE_DISABLE)
695          || (spd->decryptionMode != SPP_DECR_MODE_DISABLE);
696 }
697 
698 #else
699 
ClearScsiEncryptionKey(int fd,const char * device_name)700 bool ClearScsiEncryptionKey(int fd, const char* device_name) { return false; }
701 
SetScsiEncryptionKey(int fd,const char * device_name,char * encryption_key)702 bool SetScsiEncryptionKey(int fd, const char* device_name, char* encryption_key)
703 {
704   return false;
705 }
706 
GetScsiDriveEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)707 int GetScsiDriveEncryptionStatus(int fd,
708                                  const char* device_name,
709                                  POOLMEM*& status,
710                                  int indent)
711 {
712   PmStrcpy(status, "");
713   IndentStatusMsg(status, _("Drive encryption status: Unknown\n"), indent);
714   return strlen(status);
715 }
716 
GetScsiVolumeEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)717 int GetScsiVolumeEncryptionStatus(int fd,
718                                   const char* device_name,
719                                   POOLMEM*& status,
720                                   int indent)
721 {
722   PmStrcpy(status, "");
723   IndentStatusMsg(status, _("Volume encryption status: Unknown\n"), indent);
724   return strlen(status);
725 }
726 
NeedScsiCryptoKey(int fd,const char * device_name,bool use_drive_status)727 bool NeedScsiCryptoKey(int fd, const char* device_name, bool use_drive_status)
728 {
729   return false;
730 }
731 
GetScsiEncryptionEnabled(int fd,const char * device_name)732 bool GetScsiEncryptionEnabled(int fd, const char* device_name) { return false; }
733 #endif /* HAVE_LOWLEVEL_SCSI_INTERFACE */
734 
IndentStatusMsg(POOLMEM * & status,const char * msg,int indent)735 static void IndentStatusMsg(POOLMEM*& status, const char* msg, int indent)
736 {
737   int cnt;
738   char indent_level[17];
739 
740   /*
741    * See if we need to indent the line.
742    */
743   if (indent > 0) {
744     for (cnt = 0; cnt < indent && cnt < 16; cnt++) { indent_level[cnt] = ' '; }
745     indent_level[cnt] = '\0';
746     PmStrcat(status, indent_level);
747   }
748 
749   PmStrcat(status, msg);
750 }
751