1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2011-2012 Planets Communications B.V.
5    Copyright (C) 2013-2013 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,
120                             (void *)&cdb, cdb_len,
121                             (void *)&cmd_page, cmd_page_len);
122 }
123 
124 /*
125  * Set an encryption key used by a tape drive
126  * using a lowlevel SCSI interface.
127  *
128  * The device is send a:
129  * - SPOUT Security Protocol OUT SCSI CDB. (0xB5)
130  * - SPOUT Send Encryption Key Page. (0x10)
131  *
132  * The Send Encryption Key page has the encryption
133  * and decryption set to not disabled and the key is filled.
134  */
SetScsiEncryptionKey(int fd,const char * device_name,char * encryption_key)135 bool SetScsiEncryptionKey(int fd, const char *device_name, char *encryption_key)
136 {
137    /*
138     * Create a SPOUT Set Encryption Key CDB and
139     *        a SPOUT Send Encryption Key Page
140     */
141    SPP_SCSI_CDB cdb;
142    SPP_PAGE_BUFFER cmd_page;
143    SPP_PAGE_SDE *sps;
144    int cmd_page_len, cdb_len;
145 
146    /*
147     * Put a SPOUT Set Data Encryption page into the start of
148     * the generic cmd_page structure.
149     */
150    memset(&cmd_page, 0, sizeof(cmd_page));
151    sps = (SPP_PAGE_SDE *)&cmd_page;
152    set_2_byte_value(sps->pageCode, SPOUT_SET_DATA_ENCRYPTION_PAGE);
153    sps->nexusScope = SPP_NEXUS_SC_ALL_I_T_NEXUS;
154    sps->encryptionMode = SPP_ENCR_MODE_ENCRYPT;
155    sps->decryptionMode = SPP_DECR_MODE_MIXED;
156    sps->algorithmIndex = 0x01;
157    sps->kadFormat = SPP_KAD_KEY_FORMAT_NORMAL;
158    set_2_byte_value(sps->keyLength, SPP_KEY_LENGTH);
159    bstrncpy((char *)sps->keyData, encryption_key, SPP_KEY_LENGTH);
160 
161    /*
162     * Set the length to the size of the SPP_PAGE_SDE we just filled.
163     */
164    cmd_page_len = sizeof(SPP_PAGE_SDE);
165 
166    /*
167     * Set the actual size of the cmd_page - 4 into the cmd_page length field
168     * (without the pageCode and pageLength)
169     */
170    set_2_byte_value(cmd_page.length, cmd_page_len - 4);
171 
172    /*
173     * Fill the SCSI CDB.
174     */
175    cdb_len = sizeof(cdb);
176    memset(&cdb, 0, cdb_len);
177    cdb.opcode = SCSI_SPOUT_OPCODE;
178    cdb.scp = SPP_SP_PROTOCOL_TDE;
179    set_2_byte_value(cdb.scp_specific, SPOUT_SET_DATA_ENCRYPTION_PAGE);
180    set_4_byte_value(cdb.allocation_length, cmd_page_len);
181 
182    /*
183     * Set the new encryption key.
184     */
185    return send_scsi_cmd_page(fd, device_name,
186                             (void *)&cdb, cdb_len,
187                             (void *)&cmd_page, cmd_page_len);
188 }
189 
190 /*
191  * Request the encryption state of a drive
192  * using a lowlevel SCSI interface.
193  *
194  * The device is send a:
195  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
196  * - SPIN Get Data Encryption Status page. (0x20)
197  *
198  * The return data is interpreted and a status report is build.
199  */
GetScsiDriveEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)200 int GetScsiDriveEncryptionStatus(int fd, const char *device_name,
201                                      POOLMEM *&status, 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,
225                           (void *)&cdb, cdb_len,
226                           (void *)&cmd_page, cmd_page_len)) {
227       return 0;
228    }
229 
230    /*
231     * We got a response which should contain a SPP_PAGE_DES.
232     * Create a pointer to the beginning of the generic
233     * cmd_page structure.
234     */
235    spd = (SPP_PAGE_DES *)&cmd_page;
236 
237    PmStrcpy(status, "");
238    IndentStatusMsg(status, _("Drive encryption status:\n"), indent);
239 
240    /*
241     * See what encrption mode is enabled.
242     */
243    switch (spd->encryptionMode) {
244    case SPP_ENCR_MODE_DISABLE:
245       IndentStatusMsg(status,
246                         _("Encryption Mode: Disabled\n"),
247                         indent + 3);
248       break;
249    case SPP_ENCR_MODE_EXTERNAL:
250       IndentStatusMsg(status,
251                         _("Encryption Mode: External\n"),
252                         indent + 3);
253       break;
254    case SPP_ENCR_MODE_ENCRYPT:
255       IndentStatusMsg(status,
256                         _("Encryption Mode: Encrypt\n"),
257                         indent + 3);
258       break;
259    default:
260       break;
261    }
262 
263    /*
264     * See what decryption mode is enabled.
265     */
266    switch (spd->decryptionMode) {
267    case SPP_DECR_MODE_DISABLE:
268       IndentStatusMsg(status,
269                         _("Decryption Mode: Disabled\n"),
270                         indent + 3);
271       break;
272    case SPP_DECR_MODE_RAW:
273       IndentStatusMsg(status,
274                         _("Decryption Mode: Raw\n"),
275                         indent + 3);
276       break;
277    case SPP_DECR_MODE_DECRYPT:
278       IndentStatusMsg(status,
279                         _("Decryption Mode: Decrypt\n"),
280                         indent + 3);
281       break;
282    case SPP_DECR_MODE_MIXED:
283       IndentStatusMsg(status,
284                         _("Decryption Mode: Mixed\n"),
285                         indent + 3);
286       break;
287    default:
288       break;
289    }
290 
291    /*
292     * See if RDMD is enabled.
293     */
294    if (spd->RDMD) {
295       IndentStatusMsg(status,
296                         _("Raw Decryption Mode Disabled (RDMD): Enabled\n"),
297                         indent + 3);
298    } else {
299       IndentStatusMsg(status,
300                         _("Raw Decryption Mode Disabled (RDMD): Disabled\n"),
301                         indent + 3);
302    }
303 
304    /*
305     * See what Check External Encryption Mode Status is set.
306     */
307    switch (spd->CEEMS) {
308    case SPP_CEEM_NO_ENCR_CHECK:
309       IndentStatusMsg(status,
310                         _("Check External Encryption Mode Status (CEEMS) : No\n"),
311                         indent + 3);
312       break;
313    case SPP_CEEM_CHECK_EXTERNAL:
314       IndentStatusMsg(status,
315                         _("Check External Encryption Mode Status (CEEMS) : External\n"),
316                         indent + 3);
317       break;
318    case SPP_CEEM_CHECK_ENCR:
319       IndentStatusMsg(status,
320                         _("Check External Encryption Mode Status (CEEMS) : Encrypt\n"),
321                         indent + 3);
322       break;
323    default:
324       break;
325    }
326 
327    /*
328     * See if VCELB is enabled.
329     */
330    if (spd->VCELB) {
331       IndentStatusMsg(status,
332                         _("Volume Contains Encrypted Logical Blocks (VCELB): Enabled\n"),
333                         indent + 3);
334    } else {
335       IndentStatusMsg(status,
336                         _("Volume Contains Encrypted Logical Blocks (VCELB): Disabled\n"),
337                         indent + 3);
338    }
339 
340    /*
341     * See what is providing the encryption keys.
342     */
343    switch (spd->parametersControl) {
344    case SPP_PARM_LOG_BLOCK_ENCR_NONE:
345       IndentStatusMsg(status,
346                         _("Logical Block encryption parameters: No report\n"),
347                         indent + 3);
348       break;
349    case SPP_PARM_LOG_BLOCK_ENCR_AME:
350       IndentStatusMsg(status,
351                         _("Logical Block encryption parameters: Application Managed\n"),
352                         indent + 3);
353       break;
354    case SPP_PARM_LOG_BLOCK_ENCR_DRIVE:
355       IndentStatusMsg(status,
356                         _("Logical Block encryption parameters: Drive Managed\n"),
357                         indent + 3);
358       break;
359    case SPP_PARM_LOG_BLOCK_LME_ADC:
360       IndentStatusMsg(status,
361                         _("Logical Block encryption parameters: Library/Key Management Appliance Managed\n"),
362                         indent + 3);
363       break;
364    case SPP_PARM_LOG_BLOCK_UNSUP:
365       IndentStatusMsg(status,
366                         _("Logical Block encryption parameters: Unsupported\n"),
367                         indent + 3);
368       break;
369    default:
370       break;
371    }
372 
373    /*
374     * Only when both encryption and decryption are disabled skip the KAD Format field.
375     */
376    if (spd->encryptionMode != SPP_ENCR_MODE_DISABLE &&
377        spd->decryptionMode != SPP_DECR_MODE_DISABLE) {
378       switch (spd->kadFormat) {
379       case SPP_KAD_KEY_FORMAT_NORMAL:
380          IndentStatusMsg(status,
381                            _("Key Associated Data (KAD) Descriptor: Normal key\n"),
382                            indent + 3);
383          break;
384       case SPP_KAD_KEY_FORMAT_REFERENCE:
385          IndentStatusMsg(status,
386                            _("Key Associated Data (KAD) Descriptor: Vendor-specific reference\n"),
387                            indent + 3);
388          break;
389       case SPP_KAD_KEY_FORMAT_WRAPPED:
390          IndentStatusMsg(status,
391                            _("Key Associated Data (KAD) Descriptor: Wrapped public key\n"),
392                            indent + 3);
393          break;
394       case SPP_KAD_KEY_FORMAT_ESP_SCSI:
395          IndentStatusMsg(status,
396                            _("Key Associated Data (KAD) Descriptor: Key using ESP-SCSI\n"),
397                            indent + 3);
398          break;
399       default:
400          break;
401       }
402    }
403 
404    return strlen(status);
405 }
406 
407 /*
408  * Request the encryption state of the next block
409  * using a lowlevel SCSI interface.
410  *
411  * The device is send a:
412  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
413  * - SPIN Get Data Encryption Status page. (0x21)
414  *
415  * The return data is interpreted and a status report is build.
416  */
GetScsiVolumeEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)417 int GetScsiVolumeEncryptionStatus(int fd, const char *device_name,
418                                       POOLMEM *&status, int indent)
419 {
420    SPP_SCSI_CDB cdb;
421    SPP_PAGE_BUFFER cmd_page;
422    SPP_PAGE_NBES *spnb;
423    int cmd_page_len, cdb_len;
424 
425    cmd_page_len = sizeof(cmd_page);
426    memset(&cmd_page, 0, cmd_page_len);
427 
428    /*
429     * Fill the SCSI CDB.
430     */
431    cdb_len = sizeof(cdb);
432    memset(&cdb, 0, cdb_len);
433    cdb.opcode = SCSI_SPIN_OPCODE;
434    cdb.scp = SPP_SP_PROTOCOL_TDE;
435    set_2_byte_value(cdb.scp_specific, SPIN_NEXT_BLOCK_ENCR_STATUS_PAGE);
436    set_4_byte_value(cdb.allocation_length, cmd_page_len);
437 
438    /*
439     * Retrieve the volume encryption status.
440     */
441    if (!RecvScsiCmdPage(fd, device_name,
442                           (void *)&cdb, cdb_len,
443                           (void *)&cmd_page, cmd_page_len)) {
444       return 0;
445    }
446 
447    /*
448     * We got a response which should contain a SPP_PAGE_NBES.
449     * Create a pointer to the beginning of the generic
450     * cmd_page structure.
451     */
452    spnb = (SPP_PAGE_NBES *)&cmd_page;
453 
454    PmStrcpy(status, "");
455    IndentStatusMsg(status, _("Volume encryption status:\n"), indent);
456 
457    switch (spnb->compressionStatus) {
458    case SPP_COMP_STATUS_UNKNOWN:
459       IndentStatusMsg(status,
460                         _("Compression Status: Unknown\n"),
461                         indent + 3);
462       break;
463    case SPP_COMP_STATUS_UNAVAIL:
464       IndentStatusMsg(status,
465                         _("Compression Status: Unavailable\n"),
466                         indent + 3);
467       break;
468    case SPP_COMP_STATUS_ILLEGAL:
469       IndentStatusMsg(status,
470                         _("Compression Status: Illegal logical block\n"),
471                         indent + 3);
472       break;
473    case SPP_COMP_STATUS_UNCOMPRESSED:
474       IndentStatusMsg(status,
475                         _("Compression Status: Compression Disabled\n"),
476                         indent + 3);
477       break;
478    case SPP_COMP_STATUS_COMPRESSED:
479       IndentStatusMsg(status,
480                         _("Compression Status: Compression Enabled\n"),
481                         indent + 3);
482       break;
483    default:
484       break;
485    }
486 
487    switch (spnb->encryptionStatus) {
488    case SPP_ENCR_STATUS_UNKNOWN:
489       IndentStatusMsg(status,
490                         _("Encryption Status: Unknown\n"),
491                         indent + 3);
492       break;
493    case SPP_ENCR_STATUS_UNAVAIL:
494       IndentStatusMsg(status,
495                         _("Encryption Status: Unavailable\n"),
496                         indent + 3);
497       break;
498    case SPP_ENCR_STATUS_ILLEGAL:
499       IndentStatusMsg(status,
500                         _("Encryption Status: Illegal logical block\n"),
501                         indent + 3);
502       break;
503    case SPP_ENCR_STATUS_NOT_ENCRYPTED:
504       IndentStatusMsg(status,
505                         _("Encryption Status: Encryption Disabled\n"),
506                         indent + 3);
507       break;
508    case SPP_ENCR_STATUS_ENCR_ALG_NOT_SUPP:
509       IndentStatusMsg(status,
510                         _("Encryption Status: Encryption Enabled but with non supported algorithm\n"),
511                         indent + 3);
512       break;
513    case SPP_ENCR_STATUS_ENCRYPTED:
514       IndentStatusMsg(status,
515                         _("Encryption Status: Encryption Enabled\n"),
516                         indent + 3);
517       break;
518    case SPP_ENCR_STATUS_ENCR_NOT_AVAIL:
519       IndentStatusMsg(status,
520                         _("Encryption Status: Encryption Enabled but no valid key available for decryption\n"),
521                         indent + 3);
522       break;
523    default:
524       break;
525    }
526 
527    if (spnb->RDMDS) {
528       IndentStatusMsg(status,
529                         _("Raw Decryption Mode Disabled Status (RDMDS): Enabled\n"),
530                         indent + 3);
531    } else {
532       IndentStatusMsg(status,
533                         _("Raw Decryption Mode Disabled Status (RDMDS): Disabled\n"),
534                         indent + 3);
535    }
536 
537    if (spnb->EMES) {
538       IndentStatusMsg(status,
539                         _("Encryption Mode External Status (EMES): Enabled\n"),
540                         indent + 3);
541    } else {
542       IndentStatusMsg(status,
543                         _("Encryption Mode External Status (EMES): Disabled\n"),
544                         indent + 3);
545    }
546 
547    /*
548     * Only when the encryption status is set to SPP_ENCR_STATUS_ENCRYPTED we
549     * can use the nextBlockKADFormat otherwise that value is bogus.
550     */
551    if (spnb->encryptionStatus == SPP_ENCR_STATUS_ENCRYPTED) {
552       switch (spnb->nextBlockKADFormat) {
553       case SPP_KAD_KEY_FORMAT_NORMAL:
554          IndentStatusMsg(status,
555                            _("Next Block Key Associated Data (KAD) Descriptor: Normal key\n"),
556                            indent + 3);
557          break;
558       case SPP_KAD_KEY_FORMAT_REFERENCE:
559          IndentStatusMsg(status,
560                            _("Next Block Key Associated Data (KAD) Descriptor: Vendor-specific reference\n"),
561                            indent + 3);
562          break;
563       case SPP_KAD_KEY_FORMAT_WRAPPED:
564          IndentStatusMsg(status,
565                            _("Next Block Key Associated Data (KAD) Descriptor: Wrapped public key\n"),
566                            indent + 3);
567          break;
568       case SPP_KAD_KEY_FORMAT_ESP_SCSI:
569          IndentStatusMsg(status,
570                            _("Next Block Key Associated Data (KAD) Descriptor: Key using ESP-SCSI\n"),
571                            indent + 3);
572          break;
573       default:
574          break;
575       }
576    }
577 
578    return strlen(status);
579 }
580 
581 /*
582  * See if we need a decryption key to read the next block
583  * using a lowlevel SCSI interface.
584  *
585  * The device is send a:
586  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
587  * - SPIN Get Data Encryption Status page. (0x21)
588  */
NeedScsiCryptoKey(int fd,const char * device_name,bool use_drive_status)589 bool NeedScsiCryptoKey(int fd, const char *device_name, bool use_drive_status)
590 {
591    SPP_SCSI_CDB cdb;
592    SPP_PAGE_BUFFER cmd_page;
593    SPP_PAGE_DES *spd;
594    SPP_PAGE_NBES *spnb;
595    int cmd_page_len, cdb_len;
596 
597    cmd_page_len = sizeof(cmd_page);
598    memset(&cmd_page, 0, cmd_page_len);
599 
600    /*
601     * Fill the SCSI CDB.
602     */
603    cdb_len = sizeof(cdb);
604    memset(&cdb, 0, cdb_len);
605    cdb.opcode = SCSI_SPIN_OPCODE;
606    cdb.scp = SPP_SP_PROTOCOL_TDE;
607    if (use_drive_status) {
608       set_2_byte_value(cdb.scp_specific, SPIN_DATA_ENCR_STATUS_PAGE);
609    } else {
610       set_2_byte_value(cdb.scp_specific, SPIN_NEXT_BLOCK_ENCR_STATUS_PAGE);
611    }
612    set_4_byte_value(cdb.allocation_length, cmd_page_len);
613 
614    /*
615     * Retrieve the volume encryption status.
616     */
617    if (!RecvScsiCmdPage(fd, device_name,
618                           (void *)&cdb, cdb_len,
619                           (void *)&cmd_page, cmd_page_len)) {
620       return false;
621    }
622 
623    if (use_drive_status) {
624       /*
625        * We got a response which should contain a SPP_PAGE_DES.
626        * Create a pointer to the beginning of the generic
627        * cmd_page structure.
628        */
629       spd = (SPP_PAGE_DES *)&cmd_page;
630 
631       /*
632        * Return the status of the Volume Contains Encrypted Logical Blocks (VCELB) field.
633        */
634       return (spd->VCELB) ? true : false;
635    } else {
636       /*
637        * We got a response which should contain a SPP_PAGE_NBES.
638        * Create a pointer to the beginning of the generic
639        * cmd_page structure.
640        */
641       spnb = (SPP_PAGE_NBES *)&cmd_page;
642 
643       /*
644        * If the encryptionStatus is set to encrypted or encrypted but valid key not available
645        * we know we need to load a key to decrypt the data.
646        */
647       switch (spnb->encryptionStatus) {
648       case SPP_ENCR_STATUS_ENCRYPTED:
649       case SPP_ENCR_STATUS_ENCR_NOT_AVAIL:
650          return true;
651       default:
652          break;
653       }
654    }
655 
656    return false;
657 }
658 
659 /*
660  * See if encryption is enabled on a device using a lowlevel SCSI interface.
661  *
662  * The device is send a:
663  * - SPIN Security Protocol IN SCSI CDB. (0xA2)
664  * - SPIN Get Data Encryption Status page. (0x20)
665  */
IsScsiEncryptionEnabled(int fd,const char * device_name)666 bool IsScsiEncryptionEnabled(int fd, const char *device_name)
667 {
668    SPP_SCSI_CDB cdb;
669    SPP_PAGE_BUFFER cmd_page;
670    SPP_PAGE_DES *spd;
671    int cmd_page_len, cdb_len;
672 
673    cmd_page_len = sizeof(cmd_page);
674    memset(&cmd_page, 0, cmd_page_len);
675 
676    /*
677     * Fill the SCSI CDB.
678     */
679    cdb_len = sizeof(cdb);
680    memset(&cdb, 0, cdb_len);
681    cdb.opcode = SCSI_SPIN_OPCODE;
682    cdb.scp = SPP_SP_PROTOCOL_TDE;
683    set_2_byte_value(cdb.scp_specific, SPIN_DATA_ENCR_STATUS_PAGE);
684    set_4_byte_value(cdb.allocation_length, cmd_page_len);
685 
686    /*
687     * Retrieve the drive encryption status.
688     */
689    if (!RecvScsiCmdPage(fd, device_name,
690                           (void *)&cdb, cdb_len,
691                           (void *)&cmd_page, cmd_page_len)) {
692       return false;
693    }
694 
695    /*
696     * We got a response which should contain a SPP_PAGE_DES.
697     * Create a pointer to the beginning of the generic
698     * cmd_page structure.
699     */
700    spd = (SPP_PAGE_DES *)&cmd_page;
701 
702    /*
703     * When either encryptionMode or decryptionMode are not disabled we return true
704     */
705    return (spd->encryptionMode != SPP_ENCR_MODE_DISABLE) ||
706           (spd->decryptionMode != SPP_DECR_MODE_DISABLE);
707 }
708 
709 #else
710 
ClearScsiEncryptionKey(int fd,const char * device_name)711 bool ClearScsiEncryptionKey(int fd, const char *device_name)
712 {
713    return false;
714 }
715 
SetScsiEncryptionKey(int fd,const char * device_name,char * encryption_key)716 bool SetScsiEncryptionKey(int fd, const char *device_name, char *encryption_key)
717 {
718    return false;
719 }
720 
GetScsiDriveEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)721 int GetScsiDriveEncryptionStatus(int fd, const char *device_name,
722                                      POOLMEM *&status, int indent)
723 {
724    PmStrcpy(status, "");
725    IndentStatusMsg(status, _("Drive encryption status: Unknown\n"), indent);
726    return strlen(status);
727 }
728 
GetScsiVolumeEncryptionStatus(int fd,const char * device_name,POOLMEM * & status,int indent)729 int GetScsiVolumeEncryptionStatus(int fd, const char *device_name,
730                                       POOLMEM *&status, int indent)
731 {
732    PmStrcpy(status, "");
733    IndentStatusMsg(status, _("Volume encryption status: Unknown\n"), indent);
734    return strlen(status);
735 }
736 
NeedScsiCryptoKey(int fd,const char * device_name,bool use_drive_status)737 bool NeedScsiCryptoKey(int fd, const char *device_name, bool use_drive_status)
738 {
739    return false;
740 }
741 
GetScsiEncryptionEnabled(int fd,const char * device_name)742 bool GetScsiEncryptionEnabled(int fd, const char *device_name)
743 {
744    return false;
745 }
746 #endif /* HAVE_LOWLEVEL_SCSI_INTERFACE */
747 
IndentStatusMsg(POOLMEM * & status,const char * msg,int indent)748 static void IndentStatusMsg(POOLMEM *&status, const char *msg, int indent)
749 {
750    int cnt;
751    char indent_level[17];
752 
753    /*
754     * See if we need to indent the line.
755     */
756    if (indent > 0) {
757       for (cnt = 0; cnt < indent && cnt < 16; cnt++) {
758          indent_level[cnt] = ' ';
759       }
760       indent_level[cnt] = '\0';
761       PmStrcat(status, indent_level);
762    }
763 
764    PmStrcat(status, msg);
765 }
766