shithub: libdvdcss

Download patch

ref: 95671de3719a6b0943d7c86766e29c5646d191d8
parent: 3adf615d8ed7c70804844131e808ffaec923cb10
author: Gildas Bazin <gbazin@videolan.org>
date: Thu Oct 10 08:44:28 EDT 2002

* src/css.c, src/device.c, src/ioctl.[ch]: We don't need to be in administrator mode
anymore to authenticate the drive on Windows NT/2k/XP. As a result any user can now
play a DVD on these OSs :)
* src/ioctl.c: fixed ioctl_ReadTitleKey which wasn't working on Windows NT/2k/XP.
Because of this bug, the disc and key methods for key decryption where not working.


--- a/AUTHORS
+++ b/AUTHORS
@@ -58,3 +58,7 @@
 E: tanis@gaspode.franken.de
 D: FreeBSD DVD input patch
 
+N: Gildas Bazin
+E: gbazin@netcourrier.com
+C: gbazin
+D: various fixes to the Win32 port
--- a/src/css.c
+++ b/src/css.c
@@ -2,7 +2,7 @@
  * css.c: Functions for DVD authentication and descrambling
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: css.c,v 1.15 2002/08/10 21:19:55 sam Exp $
+ * $Id: css.c,v 1.16 2002/10/10 12:44:28 gbazin Exp $
  *
  * Author: St�phane Borel <stef@via.ecp.fr>
  *         H�kan Hjort <d95hjort@dtek.chalmers.se>
@@ -83,13 +83,7 @@
         /* Since it's the first ioctl we try to issue, we add a notice */
         _dvdcss_error( dvdcss, "css error: ioctl_ReadCopyright failed, "
                        "make sure there is a DVD in the drive, and that "
-                       "you have used the correct device node."
-#if defined( WIN32 )
-                       "\nAlso note that if you are using Windows NT/2000/XP "
-                       "you need to have administrator priviledges to be able "
-                       "to use ioctls."
-#endif
-                     );
+                       "you have used the correct device node." );
 
         return i_ret;
     }
--- a/src/device.c
+++ b/src/device.c
@@ -2,7 +2,7 @@
  * device.h: DVD device access
  *****************************************************************************
  * Copyright (C) 1998-2002 VideoLAN
- * $Id: device.c,v 1.3 2002/08/10 17:42:09 sam Exp $
+ * $Id: device.c,v 1.4 2002/10/10 12:44:28 gbazin Exp $
  *
  * Authors: St�phane Borel <stef@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -169,10 +169,12 @@
         char psz_dvd[7];
         _snprintf( psz_dvd, 7, "\\\\.\\%c:", psz_device[0] );
 
-        /* To have access to ioctls, we need read and write access to the
-         * device. This is only allowed if you have administrator priviledges
-         * so we allow for a fallback method where ioctls are not available but
-         * we at least have read access to the device.
+        /* To work around an M$ bug in IOCTL_DVD_READ_STRUCTURE, we need read
+         * _and_ write access to the device (so we can make SCSI Pass Through
+         * Requests). Unfortunately this is only allowed if you have
+         * administrator priviledges so we allow for a fallback method with
+         * only read access to the device (in this case ioctl_ReadCopyright()
+         * won't send back the right result).
          * (See Microsoft Q241374: Read and Write Access Required for SCSI
          * Pass Through Requests) */
         (HANDLE) dvdcss->i_fd =
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -2,7 +2,7 @@
  * ioctl.c: DVD ioctl replacement function
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: ioctl.c,v 1.13 2002/08/10 17:42:09 sam Exp $
+ * $Id: ioctl.c,v 1.14 2002/10/10 12:44:28 gbazin Exp $
  *
  * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
  *          Samuel Hocevar <sam@zoy.org>
@@ -11,6 +11,7 @@
  *          Eugenio Jarosiewicz <ej0@cise.ufl.edu>
  *          David Sieb�rger <drs-videolan@rucus.ru.ac.za>
  *          Alex Strelnikov <lelik@os2.ru>
+ *          Gildas Bazin <gbazin@netcourrier.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -210,19 +211,21 @@
     *pi_copyright = dvdbs.copyrightProtectionSystemType;
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 p_buffer[ 8 ];
         SCSI_PASS_THROUGH_DIRECT sptd;
 
-        memset( &sptd, 0, sizeof( sptd ) );
-        memset( &p_buffer, 0, sizeof( p_buffer ) );
-   
         /*  When using IOCTL_DVD_READ_STRUCTURE and 
             DVD_COPYRIGHT_DESCRIPTOR, CopyrightProtectionType
-            is always 6. So we send a raw scsi command instead. */
+            seems to be always 6 ???
+            To work around this M$ bug we try to send a raw scsi command
+            instead (if we've got enough privileges to do so). */
 
+        memset( &sptd, 0, sizeof( sptd ) );
+        memset( &p_buffer, 0, sizeof( p_buffer ) );
+
         sptd.Length             = sizeof( SCSI_PASS_THROUGH_DIRECT );
         sptd.CdbLength          = 12;
         sptd.DataIn             = SCSI_IOCTL_DATA_IN;
@@ -241,7 +244,30 @@
                              &sptd, sizeof( SCSI_PASS_THROUGH_DIRECT ),
                              &tmp, NULL ) ? 0 : -1;
 
-        *pi_copyright = p_buffer[ 4 ];
+        if( i_ret == 0 )
+        {
+            *pi_copyright = p_buffer[ 4 ];
+        }
+        else
+        {
+            /* We don't have the privileges to send a SCSI_PASS_THROUGH
+               command, let's try the buggy IOCTL_DVD_READ_STRUCTURE anyway */
+
+            DVD_READ_STRUCTURE dvd_struct;
+            DVD_COPYRIGHT_DESCRIPTOR dvd_descr;
+
+            memset( &dvd_struct, 0, sizeof( DVD_READ_STRUCTURE ) );
+
+            dvd_struct.Format = DvdCopyrightDescriptor;
+            dvd_struct.LayerNumber = i_layer;
+
+            i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_STRUCTURE,
+                                 &dvd_struct, sizeof(DVD_READ_STRUCTURE),
+                                 &dvd_descr, sizeof(DVD_COPYRIGHT_DESCRIPTOR),
+                                 &tmp, NULL ) ? 0 : -1;
+
+            *pi_copyright = dvd_descr.CopyrightProtectionType;
+        }
     }
     else
     {
@@ -383,7 +409,7 @@
     memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_DISK_KEY_LENGTH];
@@ -551,7 +577,7 @@
     memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_BUS_KEY_LENGTH];
@@ -563,7 +589,8 @@
         key->SessionId  = *pi_agid;
         key->KeyType    = DvdTitleKey;
         key->KeyFlags   = 0;
-        key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos;
+        key->Parameters.TitleOffset.QuadPart = (LONGLONG) i_pos *
+                                                   2048 /*DVDCSS_BLOCK_SIZE*/;
 
         i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_READ_KEY, key, 
                 key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
@@ -696,7 +723,7 @@
     *pi_agid = dvdbs.grantID;
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         ULONG id;
         DWORD tmp;
@@ -817,7 +844,7 @@
     memcpy( p_challenge, dvdbs.challengeKeyValue, DVD_CHALLENGE_SIZE );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
@@ -949,7 +976,7 @@
     *pi_asf = dvdbs.successFlag;
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_ASF_LENGTH];
@@ -1084,7 +1111,7 @@
     memcpy( p_key, dvdbs.key1Value, DVD_KEY_SIZE );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_BUS_KEY_LENGTH];
@@ -1201,7 +1228,7 @@
     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
 
@@ -1329,7 +1356,7 @@
     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_CHALLENGE_KEY_LENGTH];
@@ -1466,7 +1493,7 @@
     i_ret = ioctl( i_fd, DKIOCDVDSENDKEY, &dvd );
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[DVD_BUS_KEY_LENGTH];
@@ -1612,7 +1639,7 @@
     *p_scheme = dvdbs.rpcScheme;
 
 #elif defined( WIN32 )
-    if( WIN2K ) /* NT/Win2000/Whistler */
+    if( WIN2K ) /* NT/2k/XP */
     {
         DWORD tmp;
         u8 buffer[ DVD_REGION_LENGTH ];
@@ -1624,19 +1651,19 @@
                 region, DVD_REGION_LENGTH, &tmp, NULL ) ? 0 : -1;
 
         /* Someone who has the headers should correct all this. */
-	/* Use the IOCTL_SCSI_PASS_THROUGH_DIRECT so we get the real
-	 * values of theses entities?  */
+        /* Use the IOCTL_SCSI_PASS_THROUGH_DIRECT so we get the real
+         * values of theses entities?  */
         if(region->SystemRegion != 0) {
-	    *p_type = region->ResetCount > 1 ? 1 : 3 - region->ResetCount;
-	    *p_mask =  0xff ^ (1 << (region->SystemRegion - 1));
-	    *p_scheme = 1;
-	}
-	else
-	{
-	    *p_type = 0;  /* ?? */
-	    *p_mask = 0xff;
-	    *p_scheme = 1; /* ?? */
-	}
+            *p_type = region->ResetCount > 1 ? 1 : 3 - region->ResetCount;
+            *p_mask =  0xff ^ (1 << (region->SystemRegion - 1));
+            *p_scheme = 1;
+        }
+        else
+        {
+            *p_type = 0;  /* ?? */
+            *p_mask = 0xff;
+            *p_scheme = 1; /* ?? */
+        }
     }
     else
     {
@@ -1878,7 +1905,7 @@
     p_cpt->cam_cdb[ 9 ] =  p_cpt->cam_dxfer_len       & 0xff;
     p_cpt->cam_cdb_len = 12;
 
-	p_cpt->cam_timeout = CAM_TIME_DEFAULT;
+    p_cpt->cam_timeout = CAM_TIME_DEFAULT;
 }
 #endif
 
--- a/src/ioctl.h
+++ b/src/ioctl.h
@@ -2,7 +2,7 @@
  * ioctl.h: DVD ioctl replacement function
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: ioctl.h,v 1.7 2002/08/10 17:42:09 sam Exp $
+ * $Id: ioctl.h,v 1.8 2002/10/10 12:44:28 gbazin Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -188,7 +188,7 @@
 #define IOCTL_DVD_END_SESSION           CTL_CODE(FILE_DEVICE_DVD, 0x0403, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_DVD_GET_REGION            CTL_CODE(FILE_DEVICE_DVD, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_DVD_SEND_KEY2             CTL_CODE(FILE_DEVICE_DVD, 0x0406, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-
+#define IOCTL_DVD_READ_STRUCTURE        CTL_CODE(FILE_DEVICE_DVD, 0x0450, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_SCSI_PASS_THROUGH_DIRECT  CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
 
 #define DVD_CHALLENGE_KEY_LENGTH        (12 + sizeof(DVD_COPY_PROTECT_KEY))
@@ -202,6 +202,28 @@
 #define SCSI_IOCTL_DATA_IN              1
 
 typedef ULONG DVD_SESSION_ID, *PDVD_SESSION_ID;
+
+typedef enum DVD_STRUCTURE_FORMAT {
+    DvdPhysicalDescriptor,
+    DvdCopyrightDescriptor,
+    DvdDiskKeyDescriptor,
+    DvdBCADescriptor,
+    DvdManufacturerDescriptor,
+    DvdMaxDescriptor
+} DVD_STRUCTURE_FORMAT, *PDVD_STRUCTURE_FORMAT;
+
+typedef struct DVD_READ_STRUCTURE {
+    LARGE_INTEGER BlockByteOffset;
+    DVD_STRUCTURE_FORMAT Format;
+    DVD_SESSION_ID SessionId;
+    UCHAR LayerNumber;
+} DVD_READ_STRUCTURE, *PDVD_READ_STRUCTURE;
+
+typedef struct _DVD_COPYRIGHT_DESCRIPTOR {
+    UCHAR CopyrightProtectionType;
+    UCHAR RegionManagementInformation;
+    USHORT Reserved;
+} DVD_COPYRIGHT_DESCRIPTOR, *PDVD_COPYRIGHT_DESCRIPTOR;
 
 typedef enum
 {