@@ -152,6 +152,15 @@ PHP_MINIT_FUNCTION(ldap)
152
152
REGISTER_LONG_CONSTANT ("LDAP_DEREF_FINDING" , LDAP_DEREF_FINDING , CONST_PERSISTENT | CONST_CS );
153
153
REGISTER_LONG_CONSTANT ("LDAP_DEREF_ALWAYS" , LDAP_DEREF_ALWAYS , CONST_PERSISTENT | CONST_CS );
154
154
155
+ /* Constants to be used with ldap_modify_batch() */
156
+ REGISTER_LONG_CONSTANT ("LDAP_MODIFY_BATCH_ADD" , LDAP_MODIFY_BATCH_ADD , CONST_PERSISTENT | CONST_CS );
157
+ REGISTER_LONG_CONSTANT ("LDAP_MODIFY_BATCH_REMOVE" , LDAP_MODIFY_BATCH_REMOVE , CONST_PERSISTENT | CONST_CS );
158
+ REGISTER_LONG_CONSTANT ("LDAP_MODIFY_BATCH_REMOVE_ALL" , LDAP_MODIFY_BATCH_REMOVE_ALL , CONST_PERSISTENT | CONST_CS );
159
+ REGISTER_LONG_CONSTANT ("LDAP_MODIFY_BATCH_REPLACE" , LDAP_MODIFY_BATCH_REPLACE , CONST_PERSISTENT | CONST_CS );
160
+ REGISTER_STRING_CONSTANT ("LDAP_MODIFY_BATCH_ATTRIB" , LDAP_MODIFY_BATCH_ATTRIB , CONST_PERSISTENT | CONST_CS );
161
+ REGISTER_STRING_CONSTANT ("LDAP_MODIFY_BATCH_MODTYPE" , LDAP_MODIFY_BATCH_MODTYPE , CONST_PERSISTENT | CONST_CS );
162
+ REGISTER_STRING_CONSTANT ("LDAP_MODIFY_BATCH_VALUES" , LDAP_MODIFY_BATCH_VALUES , CONST_PERSISTENT | CONST_CS );
163
+
155
164
#if (LDAP_API_VERSION > 2000 ) || HAVE_NSLDAP || HAVE_ORALDAP_10
156
165
/* LDAP options */
157
166
REGISTER_LONG_CONSTANT ("LDAP_OPT_DEREF" , LDAP_OPT_DEREF , CONST_PERSISTENT | CONST_CS );
@@ -1432,6 +1441,355 @@ PHP_FUNCTION(ldap_delete)
1432
1441
}
1433
1442
/* }}} */
1434
1443
1444
+ /* {{{ _ldap_str_equal_to_const
1445
+ */
1446
+ static int _ldap_str_equal_to_const (const char * str , uint str_len , const char * cstr )
1447
+ {
1448
+ int i ;
1449
+
1450
+ if (strlen (cstr ) != str_len )
1451
+ return 0 ;
1452
+
1453
+ for (i = 0 ; i < str_len ; ++ i ) {
1454
+ if (str [i ] != cstr [i ]) {
1455
+ return 0 ;
1456
+ }
1457
+ }
1458
+
1459
+ return 1 ;
1460
+ }
1461
+ /* }}} */
1462
+
1463
+ /* {{{ _ldap_strlen_max
1464
+ */
1465
+ static int _ldap_strlen_max (const char * str , uint max_len )
1466
+ {
1467
+ int i ;
1468
+
1469
+ for (i = 0 ; i < max_len ; ++ i ) {
1470
+ if (str [i ] == '\0' ) {
1471
+ return i ;
1472
+ }
1473
+ }
1474
+
1475
+ return max_len ;
1476
+ }
1477
+ /* }}} */
1478
+
1479
+ /* {{{ _ldap_hash_fetch
1480
+ */
1481
+ static void _ldap_hash_fetch (zval * hashTbl , const char * key , zval * * out )
1482
+ {
1483
+ zval * * fetched ;
1484
+ if (zend_hash_find (Z_ARRVAL_P (hashTbl ), key , strlen (key )+ 1 , (void * * ) & fetched ) == SUCCESS ) {
1485
+ * out = * fetched ;
1486
+ }
1487
+ else {
1488
+ * out = NULL ;
1489
+ }
1490
+ }
1491
+ /* }}} */
1492
+
1493
+ /* {{{ proto bool ldap_modify_batch(resource link, string dn, array modifs)
1494
+ Perform multiple modifications as part of one operation */
1495
+ PHP_FUNCTION (ldap_modify_batch )
1496
+ {
1497
+ ldap_linkdata * ld ;
1498
+ zval * link , * mods , * mod , * modinfo , * modval ;
1499
+ zval * attrib , * modtype , * vals ;
1500
+ zval * * fetched ;
1501
+ char * dn ;
1502
+ int dn_len ;
1503
+ int i , j , k ;
1504
+ int num_mods , num_modprops , num_modvals ;
1505
+ LDAPMod * * ldap_mods ;
1506
+ uint oper ;
1507
+
1508
+ /*
1509
+ $mods = array(
1510
+ array(
1511
+ "attrib" => "unicodePwd",
1512
+ "modtype" => LDAP_MODIFY_BATCH_REMOVE,
1513
+ "values" => array($oldpw)
1514
+ ),
1515
+ array(
1516
+ "attrib" => "unicodePwd",
1517
+ "modtype" => LDAP_MODIFY_BATCH_ADD,
1518
+ "values" => array($newpw)
1519
+ ),
1520
+ array(
1521
+ "attrib" => "userPrincipalName",
1522
+ "modtype" => LDAP_MODIFY_BATCH_REPLACE,
1523
+ "values" => array("janitor@corp.contoso.com")
1524
+ ),
1525
+ array(
1526
+ "attrib" => "userCert",
1527
+ "modtype" => LDAP_MODIFY_BATCH_REMOVE_ALL
1528
+ )
1529
+ );
1530
+ */
1531
+
1532
+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "rsa" , & link , & dn , & dn_len , & mods ) != SUCCESS ) {
1533
+ return ;
1534
+ }
1535
+
1536
+ ZEND_FETCH_RESOURCE (ld , ldap_linkdata * , & link , -1 , "ldap link" , le_link );
1537
+
1538
+ /* perform validation */
1539
+ {
1540
+ char * modkey ;
1541
+ uint modkeylen ;
1542
+ long modtype ;
1543
+
1544
+ /* to store the wrongly-typed keys */
1545
+ ulong tmpUlong ;
1546
+
1547
+ /* make sure the DN contains no NUL bytes */
1548
+ if (_ldap_strlen_max (dn , dn_len ) != dn_len ) {
1549
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "DN must not contain NUL bytes" );
1550
+ RETURN_FALSE ;
1551
+ }
1552
+
1553
+ /* make sure the top level is a normal array */
1554
+ zend_hash_internal_pointer_reset (Z_ARRVAL_P (mods ));
1555
+ if (zend_hash_get_current_key_type (Z_ARRVAL_P (mods )) != HASH_KEY_IS_LONG ) {
1556
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Modifications array must not be string-indexed" );
1557
+ RETURN_FALSE ;
1558
+ }
1559
+
1560
+ num_mods = zend_hash_num_elements (Z_ARRVAL_P (mods ));
1561
+
1562
+ for (i = 0 ; i < num_mods ; i ++ ) {
1563
+ /* is the numbering consecutive? */
1564
+ if (zend_hash_index_find (Z_ARRVAL_P (mods ), i , (void * * ) & fetched ) != SUCCESS ) {
1565
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Modifications array must have consecutive indices 0, 1, ..." );
1566
+ RETURN_FALSE ;
1567
+ }
1568
+ mod = * fetched ;
1569
+
1570
+ /* is it an array? */
1571
+ if (Z_TYPE_P (mod ) != IS_ARRAY ) {
1572
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Each entry of modifications array must be an array itself" );
1573
+ RETURN_FALSE ;
1574
+ }
1575
+
1576
+ /* for the modification hashtable... */
1577
+ zend_hash_internal_pointer_reset (Z_ARRVAL_P (mod ));
1578
+ num_modprops = zend_hash_num_elements (Z_ARRVAL_P (mod ));
1579
+
1580
+ for (j = 0 ; j < num_modprops ; j ++ ) {
1581
+ /* are the keys strings? */
1582
+ if (zend_hash_get_current_key_ex (Z_ARRVAL_P (mod ), & modkey , & modkeylen , & tmpUlong , 0 , NULL ) != HASH_KEY_IS_STRING ) {
1583
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Each entry of modifications array must be string-indexed" );
1584
+ RETURN_FALSE ;
1585
+ }
1586
+
1587
+ /* modkeylen includes the terminating NUL byte; remove that */
1588
+ -- modkeylen ;
1589
+
1590
+ /* is this a valid entry? */
1591
+ if (
1592
+ !_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_ATTRIB ) &&
1593
+ !_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_MODTYPE ) &&
1594
+ !_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_VALUES )
1595
+ ) {
1596
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "The only allowed keys in entries of the modifications array are '" LDAP_MODIFY_BATCH_ATTRIB "', '" LDAP_MODIFY_BATCH_MODTYPE "' and '" LDAP_MODIFY_BATCH_VALUES "'" );
1597
+ RETURN_FALSE ;
1598
+ }
1599
+
1600
+ zend_hash_get_current_data (Z_ARRVAL_P (mod ), (void * * ) & fetched );
1601
+ modinfo = * fetched ;
1602
+
1603
+ /* does the value type match the key? */
1604
+ if (_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_ATTRIB )) {
1605
+ if (Z_TYPE_P (modinfo ) != IS_STRING ) {
1606
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must be a string" );
1607
+ RETURN_FALSE ;
1608
+ }
1609
+
1610
+ if (Z_STRLEN_P (modinfo ) != _ldap_strlen_max (Z_STRVAL_P (modinfo ), Z_STRLEN_P (modinfo ))) {
1611
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_ATTRIB "' value must not contain NUL bytes" );
1612
+ RETURN_FALSE ;
1613
+ }
1614
+ }
1615
+ else if (_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_MODTYPE )) {
1616
+ if (Z_TYPE_P (modinfo ) != IS_LONG ) {
1617
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_MODTYPE "' value must be a long" );
1618
+ RETURN_FALSE ;
1619
+ }
1620
+
1621
+ /* is the value in range? */
1622
+ modtype = Z_LVAL_P (modinfo );
1623
+ if (
1624
+ modtype != LDAP_MODIFY_BATCH_ADD &&
1625
+ modtype != LDAP_MODIFY_BATCH_REMOVE &&
1626
+ modtype != LDAP_MODIFY_BATCH_REPLACE &&
1627
+ modtype != LDAP_MODIFY_BATCH_REMOVE_ALL
1628
+ ) {
1629
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "The '" LDAP_MODIFY_BATCH_MODTYPE "' value must match one of the LDAP_MODIFY_BATCH_* constants" );
1630
+ RETURN_FALSE ;
1631
+ }
1632
+
1633
+ /* if it's REMOVE_ALL, there must not be a values array; otherwise, there must */
1634
+ if (modtype == LDAP_MODIFY_BATCH_REMOVE_ALL ) {
1635
+ if (zend_hash_exists (Z_ARRVAL_P (mod ), LDAP_MODIFY_BATCH_VALUES , strlen (LDAP_MODIFY_BATCH_VALUES ) + 1 )) {
1636
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "If '" LDAP_MODIFY_BATCH_MODTYPE "' is LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must not be provided" );
1637
+ RETURN_FALSE ;
1638
+ }
1639
+ }
1640
+ else {
1641
+ if (!zend_hash_exists (Z_ARRVAL_P (mod ), LDAP_MODIFY_BATCH_VALUES , strlen (LDAP_MODIFY_BATCH_VALUES ) + 1 )) {
1642
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "If '" LDAP_MODIFY_BATCH_MODTYPE "' is not LDAP_MODIFY_BATCH_REMOVE_ALL, a '" LDAP_MODIFY_BATCH_VALUES "' array must be provided" );
1643
+ RETURN_FALSE ;
1644
+ }
1645
+ }
1646
+ }
1647
+ else if (_ldap_str_equal_to_const (modkey , modkeylen , LDAP_MODIFY_BATCH_VALUES )) {
1648
+ if (Z_TYPE_P (modinfo ) != IS_ARRAY ) {
1649
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_VALUES "' value must be an array" );
1650
+ RETURN_FALSE ;
1651
+ }
1652
+
1653
+ /* is the array not empty? */
1654
+ zend_hash_internal_pointer_reset (Z_ARRVAL_P (modinfo ));
1655
+ num_modvals = zend_hash_num_elements (Z_ARRVAL_P (modinfo ));
1656
+ if (num_modvals == 0 ) {
1657
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_VALUES "' array must have at least one element" );
1658
+ RETURN_FALSE ;
1659
+ }
1660
+
1661
+ /* are its keys integers? */
1662
+ if (zend_hash_get_current_key_type (Z_ARRVAL_P (modinfo )) != HASH_KEY_IS_LONG ) {
1663
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_VALUES "' array must not be string-indexed" );
1664
+ RETURN_FALSE ;
1665
+ }
1666
+
1667
+ /* are the keys consecutive? */
1668
+ for (k = 0 ; k < num_modvals ; k ++ ) {
1669
+ if (zend_hash_index_find (Z_ARRVAL_P (modinfo ), k , (void * * ) & fetched ) != SUCCESS ) {
1670
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "A '" LDAP_MODIFY_BATCH_VALUES "' array must have consecutive indices 0, 1, ..." );
1671
+ RETURN_FALSE ;
1672
+ }
1673
+ modval = * fetched ;
1674
+
1675
+ /* is the data element a string? */
1676
+ if (Z_TYPE_P (modval ) != IS_STRING ) {
1677
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Each element of a '" LDAP_MODIFY_BATCH_VALUES "' array must be a string" );
1678
+ RETURN_FALSE ;
1679
+ }
1680
+ }
1681
+ }
1682
+
1683
+ zend_hash_move_forward (Z_ARRVAL_P (mod ));
1684
+ }
1685
+ }
1686
+ }
1687
+ /* validation was successful */
1688
+
1689
+ /* allocate array of modifications */
1690
+ ldap_mods = safe_emalloc ((num_mods + 1 ), sizeof (LDAPMod * ), 0 );
1691
+
1692
+ /* for each modification */
1693
+ for (i = 0 ; i < num_mods ; i ++ ) {
1694
+ /* allocate the modification struct */
1695
+ ldap_mods [i ] = safe_emalloc (1 , sizeof (LDAPMod ), 0 );
1696
+
1697
+ /* fetch the relevant data */
1698
+ zend_hash_index_find (Z_ARRVAL_P (mods ), i , (void * * ) & fetched );
1699
+ mod = * fetched ;
1700
+
1701
+ _ldap_hash_fetch (mod , LDAP_MODIFY_BATCH_ATTRIB , & attrib );
1702
+ _ldap_hash_fetch (mod , LDAP_MODIFY_BATCH_MODTYPE , & modtype );
1703
+ _ldap_hash_fetch (mod , LDAP_MODIFY_BATCH_VALUES , & vals );
1704
+
1705
+ /* map the modification type */
1706
+ switch (Z_LVAL_P (modtype )) {
1707
+ case LDAP_MODIFY_BATCH_ADD :
1708
+ oper = LDAP_MOD_ADD ;
1709
+ break ;
1710
+ case LDAP_MODIFY_BATCH_REMOVE :
1711
+ case LDAP_MODIFY_BATCH_REMOVE_ALL :
1712
+ oper = LDAP_MOD_DELETE ;
1713
+ break ;
1714
+ case LDAP_MODIFY_BATCH_REPLACE :
1715
+ oper = LDAP_MOD_REPLACE ;
1716
+ break ;
1717
+ default :
1718
+ php_error_docref (NULL TSRMLS_CC , E_ERROR , "Unknown and uncaught modification type." );
1719
+ RETURN_FALSE ;
1720
+ }
1721
+
1722
+ /* fill in the basic info */
1723
+ ldap_mods [i ]-> mod_op = oper | LDAP_MOD_BVALUES ;
1724
+ ldap_mods [i ]-> mod_type = estrndup (Z_STRVAL_P (attrib ), Z_STRLEN_P (attrib ));
1725
+
1726
+ if (Z_LVAL_P (modtype ) == LDAP_MODIFY_BATCH_REMOVE_ALL ) {
1727
+ /* no values */
1728
+ ldap_mods [i ]-> mod_bvalues = NULL ;
1729
+ }
1730
+ else {
1731
+ /* allocate space for the values as part of this modification */
1732
+ num_modvals = zend_hash_num_elements (Z_ARRVAL_P (vals ));
1733
+ ldap_mods [i ]-> mod_bvalues = safe_emalloc ((num_modvals + 1 ), sizeof (struct berval * ), 0 );
1734
+
1735
+ /* for each value */
1736
+ for (j = 0 ; j < num_modvals ; j ++ ) {
1737
+ /* fetch it */
1738
+ zend_hash_index_find (Z_ARRVAL_P (vals ), j , (void * * ) & fetched );
1739
+ modval = * fetched ;
1740
+
1741
+ /* allocate the data struct */
1742
+ ldap_mods [i ]-> mod_bvalues [j ] = safe_emalloc (1 , sizeof (struct berval ), 0 );
1743
+
1744
+ /* fill it */
1745
+ ldap_mods [i ]-> mod_bvalues [j ]-> bv_len = Z_STRLEN_P (modval );
1746
+ ldap_mods [i ]-> mod_bvalues [j ]-> bv_val = estrndup (Z_STRVAL_P (modval ), Z_STRLEN_P (modval ));
1747
+ }
1748
+
1749
+ /* NULL-terminate values */
1750
+ ldap_mods [i ]-> mod_bvalues [num_modvals ] = NULL ;
1751
+ }
1752
+ }
1753
+
1754
+ /* NULL-terminate modifications */
1755
+ ldap_mods [num_mods ] = NULL ;
1756
+
1757
+ /* perform (finally) */
1758
+ if ((i = ldap_modify_ext_s (ld -> link , dn , ldap_mods , NULL , NULL )) != LDAP_SUCCESS ) {
1759
+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Batch Modify: %s" , ldap_err2string (i ));
1760
+ RETVAL_FALSE ;
1761
+ } else RETVAL_TRUE ;
1762
+
1763
+ /* clean up */
1764
+ {
1765
+ for (i = 0 ; i < num_mods ; i ++ ) {
1766
+ /* attribute */
1767
+ efree (ldap_mods [i ]-> mod_type );
1768
+
1769
+ if (ldap_mods [i ]-> mod_bvalues != NULL ) {
1770
+ /* each BER value */
1771
+ for (j = 0 ; ldap_mods [i ]-> mod_bvalues [j ] != NULL ; j ++ ) {
1772
+ /* free the data bytes */
1773
+ efree (ldap_mods [i ]-> mod_bvalues [j ]-> bv_val );
1774
+
1775
+ /* free the bvalue struct */
1776
+ efree (ldap_mods [i ]-> mod_bvalues [j ]);
1777
+ }
1778
+
1779
+ /* the BER value array */
1780
+ efree (ldap_mods [i ]-> mod_bvalues );
1781
+ }
1782
+
1783
+ /* the modification */
1784
+ efree (ldap_mods [i ]);
1785
+ }
1786
+
1787
+ /* the modifications array */
1788
+ efree (ldap_mods );
1789
+ }
1790
+ }
1791
+ /* }}} */
1792
+
1435
1793
/* {{{ proto int ldap_errno(resource link)
1436
1794
Get the current ldap error number */
1437
1795
PHP_FUNCTION (ldap_errno )
@@ -2516,6 +2874,12 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_ldap_modify, 0, 0, 3)
2516
2874
ZEND_ARG_INFO (0 , entry )
2517
2875
ZEND_END_ARG_INFO ()
2518
2876
2877
+ ZEND_BEGIN_ARG_INFO_EX (arginfo_ldap_modify_batch , 0 , 0 , 3 )
2878
+ ZEND_ARG_INFO (0 , link_identifier )
2879
+ ZEND_ARG_INFO (0 , dn )
2880
+ ZEND_ARG_ARRAY_INFO (0 , modifications_info , 0 )
2881
+ ZEND_END_ARG_INFO ()
2882
+
2519
2883
ZEND_BEGIN_ARG_INFO_EX (arginfo_ldap_mod_add , 0 , 0 , 3 )
2520
2884
ZEND_ARG_INFO (0 , link_identifier )
2521
2885
ZEND_ARG_INFO (0 , dn )
@@ -2669,6 +3033,7 @@ const zend_function_entry ldap_functions[] = {
2669
3033
PHP_FE (ldap_dn2ufn , arginfo_ldap_dn2ufn )
2670
3034
PHP_FE (ldap_add , arginfo_ldap_add )
2671
3035
PHP_FE (ldap_delete , arginfo_ldap_delete )
3036
+ PHP_FE (ldap_modify_batch , arginfo_ldap_modify_batch )
2672
3037
PHP_FALIAS (ldap_modify , ldap_mod_replace , arginfo_ldap_modify )
2673
3038
2674
3039
/* additional functions for attribute based modifications, Gerrit Thomson */
0 commit comments