1 /*****************************************************************************
2  * ioctl.c: DVD ioctl replacement function
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  *
6  * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
7  *          Sam Hocevar <sam@zoy.org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Håkan Hjort <d95hjort@dtek.chalmers.se>
10  *          Eugenio Jarosiewicz <ej0@cise.ufl.edu>
11  *          David Siebörger <drs-videolan@rucus.ru.ac.za>
12  *          Alex Strelnikov <lelik@os2.ru>
13  *          Gildas Bazin <gbazin@netcourrier.com>
14  *
15  * libdvdcss is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * libdvdcss is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with libdvdcss; if not, write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28  *****************************************************************************/
29 
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include "config.h"
34 
35 #include <stdio.h>
36 
37 #include <string.h>                                    /* memcpy(), memset() */
38 #include <sys/types.h>
39 
40 #if defined( _WIN32 )
41 #   include <windows.h>
42 #   include <winioctl.h>
43 #elif defined ( __OS2__ )
44 #   define INCL_DOSFILEMGR
45 #   define INCL_DOSDEVICES
46 #   define INCL_DOSDEVIOCTL
47 #   define INCL_DOSERRORS
48 #   include <os2.h>
49 #   include <sys/ioctl.h>
50 #else
51 #   include <netinet/in.h>
52 #   include <sys/ioctl.h>
53 #endif
54 
55 #ifdef DVD_STRUCT_IN_SYS_CDIO_H
56 #   include <sys/cdio.h>
57 #endif
58 #ifdef DVD_STRUCT_IN_SYS_DVDIO_H
59 #   include <sys/dvdio.h>
60 #endif
61 #ifdef DVD_STRUCT_IN_LINUX_CDROM_H
62 #   include <linux/cdrom.h>
63 #endif
64 #ifdef DVD_STRUCT_IN_DVD_H
65 #   include <dvd.h>
66 #endif
67 #ifdef __HAIKU__
68 #   include <malloc.h>
69 #   include <scsi.h>
70 #endif
71 #ifdef SOLARIS_USCSI
72 #   include <dlfcn.h>
73 #   include <unistd.h>
74 #   include <stropts.h>
75 #   include <sys/scsi/scsi_types.h>
76 #   include <sys/scsi/impl/uscsi.h>
77 #endif
78 #ifdef DARWIN_DVD_IOCTL
79 #   include <IOKit/storage/IODVDMediaBSDClient.h>
80 #endif
81 #ifdef __QNXNTO__
82 #   include <sys/mman.h>
83 #   include <sys/dcmd_cam.h>
84 #endif
85 
86 #include "dvdcss/dvdcss.h"
87 #include "common.h"
88 #include "css.h"
89 #include "ioctl.h"
90 
91 #define DVD_CHALLENGE_SIZE 10
92 
93 /*****************************************************************************
94  * Local prototypes, OS-specific
95  *****************************************************************************/
96 #if defined( __HAIKU__ )
97 static void BeInitRDC ( raw_device_command *, int );
98 #elif defined( SOLARIS_USCSI )
99 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type );
100 static int SolarisSendUSCSI( int fd, struct uscsi_cmd *p_sc );
101 #elif defined( _WIN32 )
102 static void WinInitSPTD ( SCSI_PASS_THROUGH_DIRECT *, int );
103 #elif defined( __QNXNTO__ )
104 static void QNXInitCPT ( CAM_PASS_THRU *, int );
105 #elif defined( __OS2__ )
106 static void OS2InitSDC( struct OS2_ExecSCSICmd *, int );
107 #endif
108 
109 /*****************************************************************************
110  * ioctl_ReadCopyright: check whether the disc is encrypted or not
111  *****************************************************************************/
ioctl_ReadCopyright(int i_fd,int i_layer,int * pi_copyright)112 int ioctl_ReadCopyright( int i_fd, int i_layer, int *pi_copyright )
113 {
114     int i_ret;
115 
116 #if defined( HAVE_LINUX_DVD_STRUCT )
117     dvd_struct dvd = { 0 };
118 
119     dvd.type = DVD_STRUCT_COPYRIGHT;
120     dvd.copyright.layer_num = i_layer;
121 
122     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
123 
124     *pi_copyright = dvd.copyright.cpst;
125 
126 #elif defined( HAVE_BSD_DVD_STRUCT )
127     struct dvd_struct dvd = { 0 };
128 
129     dvd.format = DVD_STRUCT_COPYRIGHT;
130     dvd.layer_num = i_layer;
131 
132     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
133 
134     *pi_copyright = dvd.cpst;
135 
136 #elif defined( __HAIKU__ )
137     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, 8 );
138 
139     rdc.command[ 6 ] = i_layer;
140     rdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
141 
142     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
143 
144     *pi_copyright = p_buffer[ 4 ];
145 
146 #elif defined( SOLARIS_USCSI )
147     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, 8 );
148 
149     rs_cdb.cdb_opaque[ 6 ] = i_layer;
150     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_COPYRIGHT;
151 
152     i_ret = SolarisSendUSCSI(i_fd, &sc);
153 
154     if( i_ret < 0 || sc.uscsi_status ) {
155         i_ret = -1;
156     }
157 
158     *pi_copyright = p_buffer[ 4 ];
159     /* s->copyright.rmi = p_buffer[ 5 ]; */
160 
161 #elif defined( DARWIN_DVD_IOCTL )
162     INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDCopyrightInfo,
163                    kDVDStructureFormatCopyrightInfo );
164 
165     dvd.layer = i_layer;
166 
167     i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
168 
169     *pi_copyright = dvdbs.copyrightProtectionSystemType;
170 
171 #elif defined( _WIN32 )
172     DWORD tmp;
173     SCSI_PASS_THROUGH_DIRECT sptd = { 0 };
174     uint8_t p_buffer[8];
175     sptd.Length = sizeof( SCSI_PASS_THROUGH_DIRECT );
176     sptd.DataBuffer = p_buffer;
177     sptd.DataTransferLength = sizeof( p_buffer );
178     WinInitSPTD( &sptd, GPCMD_READ_DVD_STRUCTURE );
179 
180     /*  When using IOCTL_DVD_READ_STRUCTURE and
181         DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
182         seems to be always 6 ???
183         To work around this MS bug we try to send a raw SCSI command
184         instead (if we've got enough privileges to do so). */
185 
186     sptd.Cdb[ 6 ] = i_layer;
187     sptd.Cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
188 
189     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_SCSI_PASS_THROUGH_DIRECT,
190                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
191                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
192                              &tmp, NULL ) ? 0 : -1;
193 
194     if( i_ret == 0 )
195     {
196         *pi_copyright = p_buffer[ 4 ];
197     }
198 
199 #elif defined( __QNXNTO__ )
200 
201     INIT_CPT( GPCMD_READ_DVD_STRUCTURE, 8 );
202 
203     p_cpt->cam_cdb[ 6 ] = i_layer;
204     p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_COPYRIGHT;
205 
206     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
207 
208     *pi_copyright = p_buffer[4];
209 
210 #elif defined( __OS2__ )
211     INIT_SSC( GPCMD_READ_DVD_STRUCTURE, 8 );
212 
213     sdc.command[ 6 ] = i_layer;
214     sdc.command[ 7 ] = DVD_STRUCT_COPYRIGHT;
215 
216     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
217                         &sdc, sizeof(sdc), &ulParamLen,
218                         p_buffer, sizeof(p_buffer), &ulDataLen);
219 
220     *pi_copyright = p_buffer[ 4 ];
221 
222 #else
223 #   error "DVD ioctls are unavailable on this system"
224 
225 #endif
226     return i_ret;
227 }
228 
229 /*****************************************************************************
230  * ioctl_ReadDiscKey: get the disc key
231  *****************************************************************************/
ioctl_ReadDiscKey(int i_fd,const int * pi_agid,uint8_t * p_key)232 int ioctl_ReadDiscKey( int i_fd, const int *pi_agid, uint8_t *p_key )
233 {
234     int i_ret;
235 
236 #if defined( HAVE_LINUX_DVD_STRUCT )
237     dvd_struct dvd = { 0 };
238 
239     dvd.type = DVD_STRUCT_DISCKEY;
240     dvd.disckey.agid = *pi_agid;
241 
242     i_ret = ioctl( i_fd, DVD_READ_STRUCT, &dvd );
243 
244     if( i_ret < 0 )
245     {
246         return i_ret;
247     }
248 
249     memcpy( p_key, dvd.disckey.value, DVD_DISCKEY_SIZE );
250 
251 #elif defined( HAVE_BSD_DVD_STRUCT )
252     struct dvd_struct dvd = { 0 };
253 
254     dvd.format = DVD_STRUCT_DISCKEY;
255     dvd.agid = *pi_agid;
256 
257     i_ret = ioctl( i_fd, DVDIOCREADSTRUCTURE, &dvd );
258 
259     if( i_ret < 0 )
260     {
261         return i_ret;
262     }
263 
264     memcpy( p_key, dvd.data, DVD_DISCKEY_SIZE );
265 
266 #elif defined( __HAIKU__ )
267     INIT_RDC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
268 
269     rdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
270     rdc.command[ 10 ] = *pi_agid << 6;
271 
272     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
273 
274     if( i_ret < 0 )
275     {
276         return i_ret;
277     }
278 
279     memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
280 
281 #elif defined( SOLARIS_USCSI )
282     INIT_USCSI( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
283 
284     rs_cdb.cdb_opaque[ 7 ] = DVD_STRUCT_DISCKEY;
285     rs_cdb.cdb_opaque[ 10 ] = *pi_agid << 6;
286 
287     i_ret = SolarisSendUSCSI( i_fd, &sc );
288 
289     if( i_ret < 0 || sc.uscsi_status )
290     {
291         i_ret = -1;
292         return i_ret;
293     }
294 
295     memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
296 
297 #elif defined( DARWIN_DVD_IOCTL )
298     INIT_DVDIOCTL( dk_dvd_read_structure_t, DVDDiscKeyInfo,
299                    kDVDStructureFormatDiscKeyInfo );
300 
301     dvd.grantID = *pi_agid;
302 
303     i_ret = ioctl( i_fd, DKIOCDVDREADSTRUCTURE, &dvd );
304 
305     memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
306 
307 #elif defined( _WIN32 )
308     DWORD tmp;
309     uint8_t buffer[DVD_DISK_KEY_LENGTH] = { 0 };
310     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
311 
312     key->KeyLength  = DVD_DISK_KEY_LENGTH;
313     key->SessionId  = *pi_agid;
314     key->KeyType    = DvdDiskKey;
315     key->KeyFlags   = 0;
316 
317     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
318             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
319 
320     if( i_ret < 0 )
321     {
322         return i_ret;
323     }
324 
325     memcpy( p_key, key->KeyData, DVD_DISCKEY_SIZE );
326 
327 #elif defined( __QNXNTO__ )
328 
329     INIT_CPT( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
330 
331     p_cpt->cam_cdb[ 7 ] = DVD_STRUCT_DISCKEY;
332     p_cpt->cam_cdb[ 10 ] = *pi_agid << 6;
333 
334     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
335 
336     memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
337 
338 #elif defined ( __OS2__ )
339     INIT_SSC( GPCMD_READ_DVD_STRUCTURE, DVD_DISCKEY_SIZE + 4 );
340 
341     sdc.command[ 7 ]  = DVD_STRUCT_DISCKEY;
342     sdc.command[ 10 ] = *pi_agid << 6;
343 
344     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
345                         &sdc, sizeof(sdc), &ulParamLen,
346                         p_buffer, sizeof(p_buffer), &ulDataLen);
347 
348     if( i_ret < 0 )
349     {
350         return i_ret;
351     }
352 
353     memcpy( p_key, p_buffer + 4, DVD_DISCKEY_SIZE );
354 
355 #else
356 #   error "DVD ioctls are unavailable on this system"
357 
358 #endif
359     return i_ret;
360 }
361 
362 /*****************************************************************************
363  * ioctl_ReadTitleKey: get the title key
364  *****************************************************************************/
ioctl_ReadTitleKey(int i_fd,const int * pi_agid,int i_pos,uint8_t * p_key)365 int ioctl_ReadTitleKey( int i_fd, const int *pi_agid, int i_pos, uint8_t *p_key )
366 {
367     int i_ret;
368 
369 #if defined( HAVE_LINUX_DVD_STRUCT )
370     dvd_authinfo auth_info = { 0 };
371 
372     auth_info.type = DVD_LU_SEND_TITLE_KEY;
373     auth_info.lstk.agid = *pi_agid;
374     auth_info.lstk.lba = i_pos;
375 
376     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
377 
378     memcpy( p_key, auth_info.lstk.title_key, DVD_KEY_SIZE );
379 
380 #elif defined( HAVE_BSD_DVD_STRUCT )
381     struct dvd_authinfo auth_info = { 0 };
382 
383     auth_info.format = DVD_REPORT_TITLE_KEY;
384     auth_info.agid = *pi_agid;
385     auth_info.lba = i_pos;
386 
387     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
388 
389     memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
390 
391 #elif defined( __HAIKU__ )
392     INIT_RDC( GPCMD_REPORT_KEY, 12 );
393 
394     rdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
395     rdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
396     rdc.command[ 4 ] = ( i_pos >>  8 ) & 0xff;
397     rdc.command[ 5 ] = ( i_pos       ) & 0xff;
398     rdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
399 
400     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
401 
402     memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
403 
404 #elif defined( SOLARIS_USCSI )
405     INIT_USCSI( GPCMD_REPORT_KEY, 12 );
406 
407     rs_cdb.cdb_opaque[ 2 ] = ( i_pos >> 24 ) & 0xff;
408     rs_cdb.cdb_opaque[ 3 ] = ( i_pos >> 16 ) & 0xff;
409     rs_cdb.cdb_opaque[ 4 ] = ( i_pos >>  8 ) & 0xff;
410     rs_cdb.cdb_opaque[ 5 ] = ( i_pos       ) & 0xff;
411     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
412 
413     i_ret = SolarisSendUSCSI( i_fd, &sc );
414 
415     if( i_ret < 0 || sc.uscsi_status )
416     {
417         i_ret = -1;
418     }
419 
420     /* Do we want to return the cp_sec flag perhaps? */
421     /* a->lstk.cpm    = (buf[ 4 ] >> 7) & 1; */
422     /* a->lstk.cp_sec = (buf[ 4 ] >> 6) & 1; */
423     /* a->lstk.cgms   = (buf[ 4 ] >> 4) & 3; */
424 
425     memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
426 
427 #elif defined( DARWIN_DVD_IOCTL )
428     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDTitleKeyInfo,
429                    kDVDKeyFormatTitleKey );
430 
431     dvd.address = i_pos;
432     dvd.grantID = *pi_agid;
433     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
434 
435     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
436 
437     memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
438 
439 #elif defined( _WIN32 )
440     DWORD tmp;
441     uint8_t buffer[DVD_TITLE_KEY_LENGTH] = { 0 };
442     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
443 
444     key->KeyLength  = DVD_TITLE_KEY_LENGTH;
445     key->SessionId  = *pi_agid;
446     key->KeyType    = DvdTitleKey;
447     key->KeyFlags   = 0;
448     key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
449                                            DVDCSS_BLOCK_SIZE;
450 
451     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
452             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
453 
454     memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
455 
456 #elif defined( __QNXNTO__ )
457 
458     INIT_CPT( GPCMD_REPORT_KEY, 12 );
459 
460     p_cpt->cam_cdb[ 2 ] = ( i_pos >> 24 ) & 0xff;
461     p_cpt->cam_cdb[ 3 ] = ( i_pos >> 16 ) & 0xff;
462     p_cpt->cam_cdb[ 4 ] = ( i_pos >>  8 ) & 0xff;
463     p_cpt->cam_cdb[ 5 ] = ( i_pos       ) & 0xff;
464     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
465 
466     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
467 
468     memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
469 
470 #elif defined( __OS2__ )
471     INIT_SSC( GPCMD_REPORT_KEY, 12 );
472 
473     sdc.command[ 2 ] = ( i_pos >> 24 ) & 0xff;
474     sdc.command[ 3 ] = ( i_pos >> 16 ) & 0xff;
475     sdc.command[ 4 ] = ( i_pos >>  8 ) & 0xff;
476     sdc.command[ 5 ] = ( i_pos       ) & 0xff;
477     sdc.command[ 10 ] = DVD_REPORT_TITLE_KEY | (*pi_agid << 6);
478 
479     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
480                         &sdc, sizeof(sdc), &ulParamLen,
481                         p_buffer, sizeof(p_buffer), &ulDataLen);
482 
483     memcpy( p_key, p_buffer + 5, DVD_KEY_SIZE );
484 
485 #else
486 #   error "DVD ioctls are unavailable on this system"
487 
488 #endif
489 
490     return i_ret;
491 }
492 
493 
494 /*****************************************************************************
495  * ioctl_ReportAgid: get AGID from the drive
496  *****************************************************************************/
ioctl_ReportAgid(int i_fd,int * pi_agid)497 int ioctl_ReportAgid( int i_fd, int *pi_agid )
498 {
499     int i_ret;
500 
501 #if defined( HAVE_LINUX_DVD_STRUCT )
502     dvd_authinfo auth_info = { 0 };
503 
504     auth_info.type = DVD_LU_SEND_AGID;
505     auth_info.lsa.agid = *pi_agid;
506 
507     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
508 
509     *pi_agid = auth_info.lsa.agid;
510 
511 #elif defined( HAVE_BSD_DVD_STRUCT )
512     struct dvd_authinfo auth_info = { 0 };
513 
514     auth_info.format = DVD_REPORT_AGID;
515     auth_info.agid = *pi_agid;
516 
517     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
518 
519     *pi_agid = auth_info.agid;
520 
521 #elif defined( __HAIKU__ )
522     INIT_RDC( GPCMD_REPORT_KEY, 8 );
523 
524     rdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
525 
526     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
527 
528     *pi_agid = p_buffer[ 7 ] >> 6;
529 
530 #elif defined( SOLARIS_USCSI )
531     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
532 
533     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
534 
535     i_ret = SolarisSendUSCSI( i_fd, &sc );
536 
537     if( i_ret < 0 || sc.uscsi_status )
538     {
539         i_ret = -1;
540     }
541 
542     *pi_agid = p_buffer[ 7 ] >> 6;
543 
544 #elif defined( DARWIN_DVD_IOCTL )
545     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationGrantIDInfo,
546                    kDVDKeyFormatAGID_CSS );
547 
548     dvd.grantID = *pi_agid;
549     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
550 
551     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
552 
553     *pi_agid = dvdbs.grantID;
554 
555 #elif defined( _WIN32 )
556     DWORD tmp = 0;
557 
558     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION, &tmp, 4,
559                              pi_agid, sizeof( *pi_agid ), &tmp, NULL ) ? 0 : -1;
560 
561 #elif defined( __QNXNTO__ )
562 
563     INIT_CPT( GPCMD_REPORT_KEY, 8 );
564 
565     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
566 
567     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
568 
569     *pi_agid = p_buffer[ 7 ] >> 6;
570 
571 #elif defined( __OS2__ )
572     INIT_SSC( GPCMD_REPORT_KEY, 8 );
573 
574     sdc.command[ 10 ] = DVD_REPORT_AGID | (*pi_agid << 6);
575 
576     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
577                         &sdc, sizeof(sdc), &ulParamLen,
578                         p_buffer, sizeof(p_buffer), &ulDataLen);
579 
580     *pi_agid = p_buffer[ 7 ] >> 6;
581 
582 #else
583 #   error "DVD ioctls are unavailable on this system"
584 
585 #endif
586     return i_ret;
587 }
588 
589 /*****************************************************************************
590  * ioctl_ReportChallenge: get challenge from the drive
591  *****************************************************************************/
ioctl_ReportChallenge(int i_fd,const int * pi_agid,uint8_t * p_challenge)592 int ioctl_ReportChallenge( int i_fd, const int *pi_agid, uint8_t *p_challenge )
593 {
594     int i_ret;
595 
596 #if defined( HAVE_LINUX_DVD_STRUCT )
597     dvd_authinfo auth_info = { 0 };
598 
599     auth_info.type = DVD_LU_SEND_CHALLENGE;
600     auth_info.lsc.agid = *pi_agid;
601 
602     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
603 
604     memcpy( p_challenge, auth_info.lsc.chal, DVD_CHALLENGE_SIZE );
605 
606 #elif defined( HAVE_BSD_DVD_STRUCT )
607     struct dvd_authinfo auth_info =  { 0 };
608 
609     auth_info.format = DVD_REPORT_CHALLENGE;
610     auth_info.agid = *pi_agid;
611 
612     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
613 
614     memcpy( p_challenge, auth_info.keychal, DVD_CHALLENGE_SIZE );
615 
616 #elif defined( __HAIKU__ )
617     INIT_RDC( GPCMD_REPORT_KEY, 16 );
618 
619     rdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
620 
621     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
622 
623     memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
624 
625 #elif defined( SOLARIS_USCSI )
626     INIT_USCSI( GPCMD_REPORT_KEY, 16 );
627 
628     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
629 
630     i_ret = SolarisSendUSCSI( i_fd, &sc );
631 
632     if( i_ret < 0 || sc.uscsi_status )
633     {
634         i_ret = -1;
635     }
636 
637     memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
638 
639 #elif defined( DARWIN_DVD_IOCTL )
640     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDChallengeKeyInfo,
641                    kDVDKeyFormatChallengeKey );
642 
643     dvd.grantID = *pi_agid;
644 
645     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
646 
647     memcpy( p_challenge, dvdbs.challengeKeyValue, DVD_CHALLENGE_SIZE );
648 
649 #elif defined( _WIN32 )
650     DWORD tmp;
651     uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
652     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
653 
654     key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
655     key->SessionId  = *pi_agid;
656     key->KeyType    = DvdChallengeKey;
657     key->KeyFlags   = 0;
658 
659     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
660             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
661 
662     if( i_ret < 0 )
663     {
664         return i_ret;
665     }
666 
667     memcpy( p_challenge, key->KeyData, DVD_CHALLENGE_SIZE );
668 
669 #elif defined( __QNXNTO__ )
670 
671     INIT_CPT( GPCMD_REPORT_KEY, 16 );
672 
673     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
674 
675     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
676 
677     memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
678 
679 #elif defined( __OS2__ )
680     INIT_SSC( GPCMD_REPORT_KEY, 16 );
681 
682     sdc.command[ 10 ] = DVD_REPORT_CHALLENGE | (*pi_agid << 6);
683 
684     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
685                         &sdc, sizeof(sdc), &ulParamLen,
686                         p_buffer, sizeof(p_buffer), &ulDataLen);
687 
688     memcpy( p_challenge, p_buffer + 4, DVD_CHALLENGE_SIZE );
689 
690 #else
691 #   error "DVD ioctls are unavailable on this system"
692 
693 #endif
694     return i_ret;
695 }
696 
697 /*****************************************************************************
698  * ioctl_ReportASF: get ASF from the drive
699  *****************************************************************************/
ioctl_ReportASF(int i_fd,int * pi_asf)700 int ioctl_ReportASF( int i_fd, int *pi_asf )
701 {
702     int i_ret;
703 
704 #if defined( HAVE_LINUX_DVD_STRUCT )
705     dvd_authinfo auth_info = { 0 };
706 
707     auth_info.type = DVD_LU_SEND_ASF;
708     auth_info.lsasf.asf = *pi_asf;
709 
710     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
711 
712     *pi_asf = auth_info.lsasf.asf;
713 
714 #elif defined( HAVE_BSD_DVD_STRUCT )
715     struct dvd_authinfo auth_info =  { 0 };
716 
717     auth_info.format = DVD_REPORT_ASF;
718     auth_info.asf = *pi_asf;
719 
720     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
721 
722     *pi_asf = auth_info.asf;
723 
724 #elif defined( __HAIKU__ )
725     INIT_RDC( GPCMD_REPORT_KEY, 8 );
726 
727     rdc.command[ 10 ] = DVD_REPORT_ASF;
728 
729     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
730 
731     *pi_asf = p_buffer[ 7 ] & 1;
732 
733 #elif defined( SOLARIS_USCSI )
734     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
735 
736     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_ASF;
737 
738     i_ret = SolarisSendUSCSI( i_fd, &sc );
739 
740     if( i_ret < 0 || sc.uscsi_status )
741     {
742         i_ret = -1;
743     }
744 
745     *pi_asf = p_buffer[ 7 ] & 1;
746 
747 #elif defined( DARWIN_DVD_IOCTL )
748     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDAuthenticationSuccessFlagInfo,
749                    kDVDKeyFormatASF );
750 
751     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
752 
753     *pi_asf = dvdbs.successFlag;
754 
755 #elif defined( _WIN32 )
756     DWORD tmp;
757     uint8_t buffer[DVD_ASF_LENGTH] = { 0 };
758     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
759     PDVD_ASF keyData;
760 
761     key->KeyLength  = DVD_ASF_LENGTH;
762     key->KeyType    = DvdAsf;
763     key->KeyFlags   = 0;
764 
765     keyData = (PDVD_ASF)key->KeyData;
766     keyData->SuccessFlag = *pi_asf;
767 
768     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
769             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
770 
771     if( i_ret < 0 )
772     {
773         return i_ret;
774     }
775 
776     keyData = (PDVD_ASF)key->KeyData;
777     *pi_asf = keyData->SuccessFlag;
778 
779 #elif defined( __QNXNTO__ )
780 
781     INIT_CPT( GPCMD_REPORT_KEY, 8 );
782 
783     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_ASF;
784 
785     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
786 
787     *pi_asf = p_buffer[ 7 ] & 1;
788 
789 #elif defined( __OS2__ )
790     INIT_SSC( GPCMD_REPORT_KEY, 8 );
791 
792     sdc.command[ 10 ] = DVD_REPORT_ASF;
793 
794     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
795                         &sdc, sizeof(sdc), &ulParamLen,
796                         p_buffer, sizeof(p_buffer), &ulDataLen);
797 
798     *pi_asf = p_buffer[ 7 ] & 1;
799 
800 #else
801 #   error "DVD ioctls are unavailable on this system"
802 
803 #endif
804     return i_ret;
805 }
806 
807 /*****************************************************************************
808  * ioctl_ReportKey1: get the first key from the drive
809  *****************************************************************************/
ioctl_ReportKey1(int i_fd,const int * pi_agid,uint8_t * p_key)810 int ioctl_ReportKey1( int i_fd, const int *pi_agid, uint8_t *p_key )
811 {
812     int i_ret;
813 
814 #if defined( HAVE_LINUX_DVD_STRUCT )
815     dvd_authinfo auth_info = { 0 };
816 
817     auth_info.type = DVD_LU_SEND_KEY1;
818     auth_info.lsk.agid = *pi_agid;
819 
820     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
821 
822     memcpy( p_key, auth_info.lsk.key, DVD_KEY_SIZE );
823 
824 #elif defined( HAVE_BSD_DVD_STRUCT )
825     struct dvd_authinfo auth_info = { 0 };
826 
827     auth_info.format = DVD_REPORT_KEY1;
828     auth_info.agid = *pi_agid;
829 
830     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
831 
832     memcpy( p_key, auth_info.keychal, DVD_KEY_SIZE );
833 
834 #elif defined( __HAIKU__ )
835     INIT_RDC( GPCMD_REPORT_KEY, 12 );
836 
837     rdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
838 
839     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
840 
841     memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
842 
843 #elif defined( SOLARIS_USCSI )
844     INIT_USCSI( GPCMD_REPORT_KEY, 12 );
845 
846     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
847 
848     i_ret = SolarisSendUSCSI( i_fd, &sc );
849 
850     if( i_ret < 0 || sc.uscsi_status )
851     {
852         i_ret = -1;
853     }
854 
855     memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
856 
857 #elif defined( DARWIN_DVD_IOCTL )
858     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDKey1Info,
859                    kDVDKeyFormatKey1 );
860 
861     dvd.grantID = *pi_agid;
862 
863     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
864 
865     memcpy( p_key, dvdbs.key1Value, DVD_KEY_SIZE );
866 
867 #elif defined( _WIN32 )
868     DWORD tmp;
869     uint8_t buffer[DVD_BUS_KEY_LENGTH] = { 0 };
870     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
871 
872     key->KeyLength  = DVD_BUS_KEY_LENGTH;
873     key->SessionId  = *pi_agid;
874     key->KeyType    = DvdBusKey1;
875     key->KeyFlags   = 0;
876 
877     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
878             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
879 
880     memcpy( p_key, key->KeyData, DVD_KEY_SIZE );
881 
882 #elif defined( __QNXNTO__ )
883 
884     INIT_CPT( GPCMD_REPORT_KEY, 12 );
885 
886     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
887 
888     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
889 
890     memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
891 
892 #elif defined( __OS2__ )
893     INIT_SSC( GPCMD_REPORT_KEY, 12 );
894 
895     sdc.command[ 10 ] = DVD_REPORT_KEY1 | (*pi_agid << 6);
896 
897     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
898                         &sdc, sizeof(sdc), &ulParamLen,
899                         p_buffer, sizeof(p_buffer), &ulDataLen);
900 
901     memcpy( p_key, p_buffer + 4, DVD_KEY_SIZE );
902 
903 #else
904 #   error "DVD ioctls are unavailable on this system"
905 
906 #endif
907     return i_ret;
908 }
909 
910 /*****************************************************************************
911  * ioctl_InvalidateAgid: invalidate the current AGID
912  *****************************************************************************/
ioctl_InvalidateAgid(int i_fd,int * pi_agid)913 int ioctl_InvalidateAgid( int i_fd, int *pi_agid )
914 {
915     int i_ret;
916 
917 #if defined( HAVE_LINUX_DVD_STRUCT )
918     dvd_authinfo auth_info = { 0 };
919 
920     auth_info.type = DVDCSS_INVALIDATE_AGID;
921     auth_info.lsa.agid = *pi_agid;
922 
923     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
924 
925 #elif defined( HAVE_BSD_DVD_STRUCT )
926     struct dvd_authinfo auth_info = { 0 };
927 
928     auth_info.format = DVDCSS_INVALIDATE_AGID;
929     auth_info.agid = *pi_agid;
930 
931     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
932 
933 #elif defined( __HAIKU__ )
934     INIT_RDC( GPCMD_REPORT_KEY, 0 );
935 
936     rdc.command[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
937 
938     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
939 
940 #elif defined( SOLARIS_USCSI )
941     INIT_USCSI( GPCMD_REPORT_KEY, 0 );
942 
943     rs_cdb.cdb_opaque[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
944 
945     i_ret = SolarisSendUSCSI( i_fd, &sc );
946 
947     if( i_ret < 0 || sc.uscsi_status )
948     {
949         i_ret = -1;
950     }
951 
952 #elif defined( DARWIN_DVD_IOCTL )
953     INIT_DVDIOCTL( dk_dvd_send_key_t, DVDAuthenticationGrantIDInfo,
954                    kDVDKeyFormatAGID_Invalidate );
955 
956     dvd.grantID = *pi_agid;
957 
958     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
959 
960 #elif defined( _WIN32 )
961     DWORD tmp;
962 
963     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_END_SESSION,
964                 pi_agid, sizeof( *pi_agid ), NULL, 0, &tmp, NULL ) ? 0 : -1;
965 
966 #elif defined( __QNXNTO__ )
967 
968     INIT_CPT( GPCMD_REPORT_KEY, 0 );
969 
970     p_cpt->cam_cdb[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
971 
972     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
973 
974 #elif defined( __OS2__ )
975     INIT_SSC( GPCMD_REPORT_KEY, 1 );
976 
977     sdc.data_length = 0;
978     sdc.command[ 8 ] = 0;
979     sdc.command[ 9 ] = 0;
980 
981     sdc.command[ 10 ] = DVDCSS_INVALIDATE_AGID | (*pi_agid << 6);
982 
983     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
984                         &sdc, sizeof(sdc), &ulParamLen,
985                         NULL, 0, &ulDataLen);
986 #else
987 #   error "DVD ioctls are unavailable on this system"
988 
989 #endif
990     return i_ret;
991 }
992 
993 /*****************************************************************************
994  * ioctl_SendChallenge: send challenge to the drive
995  *****************************************************************************/
ioctl_SendChallenge(int i_fd,const int * pi_agid,const uint8_t * p_challenge)996 int ioctl_SendChallenge( int i_fd, const int *pi_agid, const uint8_t *p_challenge )
997 {
998     int i_ret;
999 
1000 #if defined( HAVE_LINUX_DVD_STRUCT )
1001     dvd_authinfo auth_info = { 0 };
1002 
1003     auth_info.type = DVD_HOST_SEND_CHALLENGE;
1004     auth_info.hsc.agid = *pi_agid;
1005 
1006     memcpy( auth_info.hsc.chal, p_challenge, DVD_CHALLENGE_SIZE );
1007 
1008     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1009 
1010 #elif defined( HAVE_BSD_DVD_STRUCT )
1011     struct dvd_authinfo auth_info = { 0 };
1012 
1013     auth_info.format = DVD_SEND_CHALLENGE;
1014     auth_info.agid = *pi_agid;
1015 
1016     memcpy( auth_info.keychal, p_challenge, DVD_CHALLENGE_SIZE );
1017 
1018     i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1019 
1020 #elif defined( __HAIKU__ )
1021     INIT_RDC( GPCMD_SEND_KEY, 16 );
1022 
1023     rdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1024 
1025     p_buffer[ 1 ] = 0xe;
1026     memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1027 
1028     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1029 
1030 #elif defined( SOLARIS_USCSI )
1031     INIT_USCSI( GPCMD_SEND_KEY, 16 );
1032 
1033     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1034 
1035     p_buffer[ 1 ] = 0xe;
1036     memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1037 
1038     if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
1039     {
1040         return -1;
1041     }
1042 
1043     i_ret = 0;
1044 
1045 #elif defined( DARWIN_DVD_IOCTL )
1046     INIT_DVDIOCTL( dk_dvd_send_key_t, DVDChallengeKeyInfo,
1047                    kDVDKeyFormatChallengeKey );
1048 
1049     dvd.grantID = *pi_agid;
1050     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1051 
1052     dvdbs.dataLength[ 1 ] = 0xe;
1053     memcpy( dvdbs.challengeKeyValue, p_challenge, DVD_CHALLENGE_SIZE );
1054 
1055     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1056 
1057 #elif defined( _WIN32 )
1058     DWORD tmp;
1059     uint8_t buffer[DVD_CHALLENGE_KEY_LENGTH] = { 0 };
1060     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1061 
1062     key->KeyLength  = DVD_CHALLENGE_KEY_LENGTH;
1063     key->SessionId  = *pi_agid;
1064     key->KeyType    = DvdChallengeKey;
1065     key->KeyFlags   = 0;
1066 
1067     memcpy( key->KeyData, p_challenge, DVD_CHALLENGE_SIZE );
1068 
1069     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1070              key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1071 
1072 #elif defined( __QNXNTO__ )
1073 
1074     INIT_CPT( GPCMD_SEND_KEY, 16 );
1075 
1076     p_cpt->cam_cdb[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1077 
1078     p_buffer[ 1 ] = 0xe;
1079     memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1080 
1081     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1082 
1083 #elif defined( __OS2__ )
1084     INIT_SSC( GPCMD_SEND_KEY, 16 );
1085 
1086     sdc.command[ 10 ] = DVD_SEND_CHALLENGE | (*pi_agid << 6);
1087 
1088     p_buffer[ 1 ] = 0xe;
1089     memcpy( p_buffer + 4, p_challenge, DVD_CHALLENGE_SIZE );
1090 
1091     i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1092                          &sdc, sizeof(sdc), &ulParamLen,
1093                          p_buffer, sizeof(p_buffer), &ulDataLen );
1094 
1095 #else
1096 #   error "DVD ioctls are unavailable on this system"
1097 
1098 #endif
1099     return i_ret;
1100 }
1101 
1102 /*****************************************************************************
1103  * ioctl_SendKey2: send the second key to the drive
1104  *****************************************************************************/
ioctl_SendKey2(int i_fd,const int * pi_agid,const uint8_t * p_key)1105 int ioctl_SendKey2( int i_fd, const int *pi_agid, const uint8_t *p_key )
1106 {
1107     int i_ret;
1108 
1109 #if defined( HAVE_LINUX_DVD_STRUCT )
1110     dvd_authinfo auth_info = { 0 };
1111 
1112     auth_info.type = DVD_HOST_SEND_KEY2;
1113     auth_info.hsk.agid = *pi_agid;
1114 
1115     memcpy( auth_info.hsk.key, p_key, DVD_KEY_SIZE );
1116 
1117     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1118 
1119 #elif defined( HAVE_BSD_DVD_STRUCT )
1120     struct dvd_authinfo auth_info = { 0 };
1121 
1122     auth_info.format = DVD_SEND_KEY2;
1123     auth_info.agid = *pi_agid;
1124 
1125     memcpy( auth_info.keychal, p_key, DVD_KEY_SIZE );
1126 
1127     i_ret = ioctl( i_fd, DVDIOCSENDKEY, &auth_info );
1128 
1129 #elif defined( __HAIKU__ )
1130     INIT_RDC( GPCMD_SEND_KEY, 12 );
1131 
1132     rdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1133 
1134     p_buffer[ 1 ] = 0xa;
1135     memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1136 
1137     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1138 
1139 #elif defined( SOLARIS_USCSI )
1140     INIT_USCSI( GPCMD_SEND_KEY, 12 );
1141 
1142     rs_cdb.cdb_opaque[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1143 
1144     p_buffer[ 1 ] = 0xa;
1145     memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1146 
1147     if( SolarisSendUSCSI( i_fd, &sc ) < 0 || sc.uscsi_status )
1148     {
1149         return -1;
1150     }
1151 
1152     i_ret = 0;
1153 
1154 #elif defined( DARWIN_DVD_IOCTL )
1155     INIT_DVDIOCTL( dk_dvd_send_key_t, DVDKey2Info,
1156                    kDVDKeyFormatKey2 );
1157 
1158     dvd.grantID = *pi_agid;
1159     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1160 
1161     dvdbs.dataLength[ 1 ] = 0xa;
1162     memcpy( dvdbs.key2Value, p_key, DVD_KEY_SIZE );
1163 
1164     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
1165 
1166 #elif defined( _WIN32 )
1167     DWORD tmp;
1168     uint8_t buffer[DVD_BUS_KEY_LENGTH] = { 0 };
1169     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1170 
1171     key->KeyLength  = DVD_BUS_KEY_LENGTH;
1172     key->SessionId  = *pi_agid;
1173     key->KeyType    = DvdBusKey2;
1174     key->KeyFlags   = 0;
1175 
1176     memcpy( key->KeyData, p_key, DVD_KEY_SIZE );
1177 
1178     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
1179              key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1180 
1181 #elif defined( __QNXNTO__ )
1182 
1183     INIT_CPT( GPCMD_SEND_KEY, 12 );
1184 
1185     p_cpt->cam_cdb[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1186 
1187     p_buffer[ 1 ] = 0xa;
1188     memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1189 
1190     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1191 
1192 #elif defined( __OS2__ )
1193     INIT_SSC( GPCMD_SEND_KEY, 12 );
1194 
1195     sdc.command[ 10 ] = DVD_SEND_KEY2 | (*pi_agid << 6);
1196 
1197     p_buffer[ 1 ] = 0xa;
1198     memcpy( p_buffer + 4, p_key, DVD_KEY_SIZE );
1199 
1200     i_ret = DosDevIOCtl( i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1201                          &sdc, sizeof(sdc), &ulParamLen,
1202                          p_buffer, sizeof(p_buffer), &ulDataLen );
1203 
1204 #else
1205 #   error "DVD ioctls are unavailable on this system"
1206 
1207 #endif
1208     return i_ret;
1209 }
1210 
1211 /*****************************************************************************
1212  * ioctl_ReportRPC: get RPC (Regional Playback Control) status for the drive
1213  *****************************************************************************/
ioctl_ReportRPC(int i_fd,int * p_type,int * p_mask,int * p_scheme)1214 int ioctl_ReportRPC( int i_fd, int *p_type, int *p_mask, int *p_scheme )
1215 {
1216     int i_ret;
1217 
1218 #if defined( HAVE_LINUX_DVD_STRUCT ) && defined( DVD_LU_SEND_RPC_STATE )
1219     dvd_authinfo auth_info = { 0 };
1220 
1221     auth_info.type = DVD_LU_SEND_RPC_STATE;
1222 
1223     i_ret = ioctl( i_fd, DVD_AUTH, &auth_info );
1224 
1225     *p_type = auth_info.lrpcs.type;
1226     *p_mask = auth_info.lrpcs.region_mask;
1227     *p_scheme = auth_info.lrpcs.rpc_scheme;
1228 
1229 #elif defined( HAVE_LINUX_DVD_STRUCT )
1230     /* FIXME: OpenBSD doesn't know this */
1231     i_ret = -1;
1232 
1233 #elif defined( HAVE_BSD_DVD_STRUCT )
1234     struct dvd_authinfo auth_info = { 0 };
1235 
1236     auth_info.format = DVD_REPORT_RPC;
1237 
1238     i_ret = ioctl( i_fd, DVDIOCREPORTKEY, &auth_info );
1239 
1240     *p_type = auth_info.reg_type;
1241     *p_mask = auth_info.region; // ??
1242     *p_scheme = auth_info.rpc_scheme;
1243 
1244 #elif defined( __HAIKU__ )
1245     INIT_RDC( GPCMD_REPORT_KEY, 8 );
1246 
1247     rdc.command[ 10 ] = DVD_REPORT_RPC;
1248 
1249     i_ret = ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
1250 
1251     *p_type = p_buffer[ 4 ] >> 6;
1252     *p_mask = p_buffer[ 5 ];
1253     *p_scheme = p_buffer[ 6 ];
1254 
1255 #elif defined( SOLARIS_USCSI )
1256     INIT_USCSI( GPCMD_REPORT_KEY, 8 );
1257 
1258     rs_cdb.cdb_opaque[ 10 ] = DVD_REPORT_RPC;
1259 
1260     i_ret = SolarisSendUSCSI( i_fd, &sc );
1261 
1262     if( i_ret < 0 || sc.uscsi_status )
1263     {
1264         i_ret = -1;
1265     }
1266 
1267     *p_type = p_buffer[ 4 ] >> 6;
1268     *p_mask = p_buffer[ 5 ];
1269     *p_scheme = p_buffer[ 6 ];
1270 
1271 #elif defined( DARWIN_DVD_IOCTL )
1272     INIT_DVDIOCTL( dk_dvd_report_key_t, DVDRegionPlaybackControlInfo,
1273                    kDVDKeyFormatRegionState );
1274 
1275     dvd.keyClass = kDVDKeyClassCSS_CPPM_CPRM;
1276 
1277     i_ret = ioctl( i_fd, DKIOCDVDREPORTKEY, &dvd );
1278 
1279     *p_type = dvdbs.typeCode;
1280     *p_mask = dvdbs.driveRegion;
1281     *p_scheme = dvdbs.rpcScheme;
1282 
1283 #elif defined( _WIN32 )
1284     DWORD tmp;
1285     uint8_t buffer[DVD_RPC_KEY_LENGTH] = { 0 };
1286     PDVD_COPY_PROTECT_KEY key = (PDVD_COPY_PROTECT_KEY) &buffer;
1287     PDVD_RPC_KEY keyData;
1288 
1289     key->KeyLength  = DVD_RPC_KEY_LENGTH;
1290     key->KeyType    = DvdGetRpcKey;
1291     key->KeyFlags   = 0;
1292 
1293     i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key,
1294             key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
1295 
1296     if( i_ret < 0 )
1297     {
1298         return i_ret;
1299     }
1300 
1301     keyData = (PDVD_RPC_KEY)key->KeyData;
1302     *p_type = keyData->TypeCode;
1303     *p_mask = keyData->RegionMask;
1304     *p_scheme = keyData->RpcScheme;
1305 
1306 #elif defined( __QNXNTO__ )
1307 
1308     INIT_CPT( GPCMD_REPORT_KEY, 8 );
1309 
1310     p_cpt->cam_cdb[ 10 ] = DVD_REPORT_RPC;
1311 
1312     i_ret = devctl(i_fd, DCMD_CAM_PASS_THRU, p_cpt, structSize, NULL);
1313 
1314     *p_type = p_buffer[ 4 ] >> 6;
1315     *p_mask = p_buffer[ 5 ];
1316     *p_scheme = p_buffer[ 6 ];
1317 
1318 #elif defined( __OS2__ )
1319     INIT_SSC( GPCMD_REPORT_KEY, 8 );
1320 
1321     sdc.command[ 10 ] = DVD_REPORT_RPC;
1322 
1323     i_ret = DosDevIOCtl(i_fd, IOCTL_CDROMDISK, CDROMDISK_EXECMD,
1324                         &sdc, sizeof(sdc), &ulParamLen,
1325                         p_buffer, sizeof(p_buffer), &ulDataLen);
1326 
1327     *p_type = p_buffer[ 4 ] >> 6;
1328     *p_mask = p_buffer[ 5 ];
1329     *p_scheme = p_buffer[ 6 ];
1330 
1331 #else
1332 #   error "DVD ioctls are unavailable on this system"
1333 
1334 #endif
1335     return i_ret;
1336 }
1337 
1338 /* Local prototypes */
1339 
1340 #if defined( __HAIKU__ )
1341 /*****************************************************************************
1342  * BeInitRDC: initialize a RDC structure for the Haiku kernel
1343  *****************************************************************************
1344  * This function initializes a Haiku raw device command structure for future
1345  * use, either a read command or a write command.
1346  *****************************************************************************/
BeInitRDC(raw_device_command * p_rdc,int i_type)1347 static void BeInitRDC( raw_device_command *p_rdc, int i_type )
1348 {
1349     memset( p_rdc->data, 0, p_rdc->data_length );
1350 
1351     switch( i_type )
1352     {
1353         case GPCMD_SEND_KEY:
1354             /* leave the flags to 0 */
1355             break;
1356 
1357         case GPCMD_READ_DVD_STRUCTURE: case GPCMD_REPORT_KEY:
1358     p_rdc->flags = B_RAW_DEVICE_DATA_IN; break; }
1359 
1360     p_rdc->command[ 0 ]      = i_type;
1361 
1362     p_rdc->command[ 8 ]      = (p_rdc->data_length >> 8) & 0xff;
1363     p_rdc->command[ 9 ]      =  p_rdc->data_length       & 0xff;
1364     p_rdc->command_length    = 12;
1365 
1366     p_rdc->sense_data        = NULL;
1367     p_rdc->sense_data_length = 0;
1368 
1369     p_rdc->timeout           = 1000000;
1370 }
1371 #endif
1372 
1373 #if defined( SOLARIS_USCSI )
1374 /*****************************************************************************
1375  * SolarisInitUSCSI: initialize a USCSICMD structure for the Solaris kernel
1376  *****************************************************************************
1377  * This function initializes a Solaris userspace SCSI command structure for
1378  * future use, either a read command or a write command.
1379  *****************************************************************************/
SolarisInitUSCSI(struct uscsi_cmd * p_sc,int i_type)1380 static void SolarisInitUSCSI( struct uscsi_cmd *p_sc, int i_type )
1381 {
1382     union scsi_cdb *rs_cdb;
1383     memset( p_sc->uscsi_cdb, 0, sizeof( union scsi_cdb ) );
1384     memset( p_sc->uscsi_bufaddr, 0, p_sc->uscsi_buflen );
1385 
1386     switch( i_type )
1387     {
1388         case GPCMD_SEND_KEY:
1389             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_WRITE;
1390             break;
1391 
1392         case GPCMD_READ_DVD_STRUCTURE:
1393         case GPCMD_REPORT_KEY:
1394             p_sc->uscsi_flags = USCSI_ISOLATE | USCSI_READ;
1395             break;
1396     }
1397 
1398     rs_cdb = (union scsi_cdb *)p_sc->uscsi_cdb;
1399 
1400     rs_cdb->scc_cmd = i_type;
1401 
1402     rs_cdb->cdb_opaque[ 8 ] = (p_sc->uscsi_buflen >> 8) & 0xff;
1403     rs_cdb->cdb_opaque[ 9 ] =  p_sc->uscsi_buflen       & 0xff;
1404     p_sc->uscsi_cdblen = 12;
1405     p_sc->uscsi_timeout = 15;
1406 }
1407 
1408 /*****************************************************************************
1409  * SolarisSendUSCSI: send a USCSICMD structure to the Solaris kernel
1410  * for execution
1411  *****************************************************************************
1412  * When available, this function uses the function smedia_uscsi_cmd()
1413  * from Solaris' libsmedia library (Solaris 9 or newer) to execute the
1414  * USCSI command.  smedia_uscsi_cmd() allows USCSI commands for
1415  * non-root users on removable media devices on Solaris 9; sending the
1416  * USCSI command directly to the device using the USCSICMD ioctl fails
1417  * with an EPERM error on Solaris 9.
1418  *
1419  * The code will fall back to the USCSICMD ioctl method, when
1420  * libsmedia.so is not available or does not export the
1421  * smedia_uscsi_cmd() function (on Solaris releases up to and including
1422  * Solaris 8). Fortunately, on these old releases non-root users are
1423  * allowed to perform USCSICMD ioctls on removable media devices.
1424  *****************************************************************************/
SolarisSendUSCSI(int i_fd,struct uscsi_cmd * p_sc)1425 static int SolarisSendUSCSI( int i_fd, struct uscsi_cmd *p_sc )
1426 {
1427     void *p_handle;
1428 
1429     /* We use static variables to keep track of the libsmedia symbols, which
1430      * is harmless even in a multithreaded program because the library and
1431      * its symbols will always be mapped at the same address. */
1432     static int b_tried = 0;
1433     static int b_have_sm = 0;
1434     static void * (*p_get_handle) ( int32_t );
1435     static int (*p_uscsi_cmd) ( void *, struct uscsi_cmd * );
1436     static int (*p_release_handle) ( void * );
1437 
1438     if( !b_tried )
1439     {
1440         void *p_lib;
1441 
1442         p_lib = dlopen( "libsmedia.so", RTLD_NOW );
1443         if( p_lib )
1444         {
1445             p_get_handle = dlsym( p_lib, "smedia_get_handle" );
1446             p_uscsi_cmd = dlsym( p_lib, "smedia_uscsi_cmd" );
1447             p_release_handle = dlsym( p_lib, "smedia_release_handle" );
1448 
1449             if( p_get_handle && p_uscsi_cmd && p_release_handle )
1450             {
1451                 b_have_sm = 1;
1452             }
1453             else
1454             {
1455                 dlclose( p_lib );
1456             }
1457         }
1458 
1459         b_tried = 1;
1460     }
1461 
1462     if( b_have_sm && (p_handle = p_get_handle(i_fd)) )
1463     {
1464         int i_ret = p_uscsi_cmd( p_handle, p_sc );
1465         p_release_handle( p_handle );
1466         return i_ret;
1467     }
1468 
1469     return ioctl( i_fd, USCSICMD, p_sc );
1470 }
1471 #endif /* defined( SOLARIS_USCSI ) */
1472 
1473 #if defined( _WIN32 )
1474 /*****************************************************************************
1475  * WinInitSPTD: initialize a sptd structure
1476  *****************************************************************************
1477  * This function initializes a SCSI pass through command structure for future
1478  * use, either a read command or a write command.
1479  *****************************************************************************/
WinInitSPTD(SCSI_PASS_THROUGH_DIRECT * p_sptd,int i_type)1480 static void WinInitSPTD( SCSI_PASS_THROUGH_DIRECT *p_sptd, int i_type )
1481 {
1482     memset( p_sptd->DataBuffer, 0, p_sptd->DataTransferLength );
1483 
1484     switch( i_type )
1485     {
1486         case GPCMD_SEND_KEY:
1487             p_sptd->DataIn = SCSI_IOCTL_DATA_OUT;
1488             break;
1489 
1490         case GPCMD_READ_DVD_STRUCTURE:
1491         case GPCMD_REPORT_KEY:
1492             p_sptd->DataIn = SCSI_IOCTL_DATA_IN;
1493             break;
1494     }
1495 
1496     p_sptd->Cdb[ 0 ] = i_type;
1497     p_sptd->Cdb[ 8 ] = (uint8_t)(p_sptd->DataTransferLength >> 8) & 0xff;
1498     p_sptd->Cdb[ 9 ] = (uint8_t) p_sptd->DataTransferLength       & 0xff;
1499     p_sptd->CdbLength = 12;
1500 
1501     p_sptd->TimeOutValue = 2;
1502 }
1503 #endif /* defined( _WIN32 ) */
1504 
1505 #if defined( __QNXNTO__ )
1506 /*****************************************************************************
1507  * QNXInitCPT: initialize a CPT structure for QNX Neutrino
1508  *****************************************************************************
1509  * This function initializes a cpt command structure for future use,
1510  * either a read command or a write command.
1511  *****************************************************************************/
QNXInitCPT(CAM_PASS_THRU * p_cpt,int i_type)1512 static void QNXInitCPT( CAM_PASS_THRU * p_cpt, int i_type )
1513 {
1514     switch( i_type )
1515     {
1516         case GPCMD_SEND_KEY:
1517             p_cpt->cam_flags = CAM_DIR_OUT;
1518             break;
1519 
1520         case GPCMD_READ_DVD_STRUCTURE:
1521         case GPCMD_REPORT_KEY:
1522             p_cpt->cam_flags = CAM_DIR_IN;
1523             break;
1524     }
1525 
1526     p_cpt->cam_cdb[0] = i_type;
1527 
1528     p_cpt->cam_cdb[ 8 ] = (p_cpt->cam_dxfer_len >> 8) & 0xff;
1529     p_cpt->cam_cdb[ 9 ] =  p_cpt->cam_dxfer_len       & 0xff;
1530     p_cpt->cam_cdb_len = 12;
1531 
1532     p_cpt->cam_timeout = CAM_TIME_DEFAULT;
1533 }
1534 #endif /* defined( __QNXNTO__ ) */
1535 
1536 #if defined( __OS2__ )
1537 /*****************************************************************************
1538  * OS2InitSDC: initialize a SDC structure for the Execute SCSI-command
1539  *****************************************************************************
1540  * This function initializes an OS/2 'execute SCSI command' structure for
1541  * future use, either a read command or a write command.
1542  *****************************************************************************/
OS2InitSDC(struct OS2_ExecSCSICmd * p_sdc,int i_type)1543 static void OS2InitSDC( struct OS2_ExecSCSICmd *p_sdc, int i_type )
1544 {
1545     switch( i_type )
1546     {
1547         case GPCMD_SEND_KEY:
1548             p_sdc->flags = 0;
1549             break;
1550 
1551         case GPCMD_READ_DVD_STRUCTURE:
1552         case GPCMD_REPORT_KEY:
1553             p_sdc->flags = EX_DIRECTION_IN;
1554             break;
1555     }
1556 
1557     p_sdc->command[ 0 ] = i_type;
1558     p_sdc->command[ 8 ] = (p_sdc->data_length >> 8) & 0xff;
1559     p_sdc->command[ 9 ] = p_sdc->data_length        & 0xff;
1560     p_sdc->id_code      = 0x31304443;    // 'CD01'
1561     p_sdc->cmd_length   = 12;
1562 }
1563 #endif /* defined( __OS2__ ) */
1564