commit 763843c16a86885947dae98e7c0a68b6b3515d01 Author: Deon George Date: Tue Jun 30 18:05:37 2009 +1000 RELEASE 0.9.0 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..fea99f9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,40 @@ +These instructions assume that you have a working install of: + a. A web server (Apache, IIS, etc). + b. PHP (with LDAP support) + +Installing phpLDAPAdmin in 4 easy steps: + +1. Untar the archive (if you're reading this, you've already done that). +2. Put the resulting phpldapadmin directory somewhere in your webroot. +3. Copy 'config.php.example' to 'config.php' and edit to taste. +4. Then, point your browser to the phpldapadmin directory. + +Browsers + +phpLDAPAdmin was developed on Mozilla, and will most likely run best thereon. +However, testing has been done on Internet Explorer, and it should work +well also. No testing has been done on either Konqueror (or any khtml-based +browser like Safari) or Opera. If you find a browser incompatibility, +please report it. + +Contributors (thank you!) + + Patch writers: + + - Mario Valdez jpegPhoto support, localization (not yet in 0.8.x), html fixes + - Bayu Irawan userPassword encryption support, html fixes, ldap_modify fixes + - Uwe Ebel short_open_tags fix-it script + - Philippe Broussard form auth_type bug report + - Andrew Tipton SUP support in schema-fetching + - Eigil Bjørgum UTF-8 support + - Brandon Lederer DNS entry template + Nathan Rotschafer + - Steve Rigler Password hash patch + - Chric Jackson Blowfish and md5crypt passwords + + Bug reporters: + + - Colin Tinker (short_open_tags bug report) + - Greg Felix (multi-value update bug report) + - Moritz Mertinkat (creation bug report) + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..022e560 --- /dev/null +++ b/LICENSE @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..ac39a10 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.9.0 diff --git a/add_oclass.php b/add_oclass.php new file mode 100644 index 0000000..3c5986e --- /dev/null +++ b/add_oclass.php @@ -0,0 +1,55 @@ + $new_oclass ); + +if( is_array( $new_attrs ) && count( $new_attrs ) > 0 ) + foreach( $new_attrs as $attr => $val ) + $new_entry[ $attr ] = $val; + +//echo "
"; 
+//print_r( $new_entry );
+//exit;
+
+$ds = pla_ldap_connect( $server_id ) or pla_error( "Could not connect to LDAP server." );
+$add_res = @ldap_mod_add( $ds, $dn, $new_entry );
+
+if( ! $add_res )
+{
+	pla_error( "Could not perform ldap_mod_add operation", ldap_error( $ds ), ldap_errno( $ds ) );
+}
+else
+{
+	header( "Location: edit.php?server_id=$server_id&dn=$encoded_dn" );
+}
+
+?>
diff --git a/add_oclass_form.php b/add_oclass_form.php
new file mode 100644
index 0000000..36c0e9f
--- /dev/null
+++ b/add_oclass_form.php
@@ -0,0 +1,108 @@
+ $junk )
+	$current_attrs[] = strtolower($attr);
+// grab the required attributes for the new objectClass
+$must_attrs = get_schema_objectclasses( $server_id );
+$must_attrs = $must_attrs[ strtolower($new_oclass) ]['must_attrs'];
+sort( $must_attrs );
+// build a list of the attributes that this new objectClass requires,
+// but that the object does not currently contain
+$needed_attrs = array();
+foreach( $must_attrs as $attr )
+	if( ! in_array( strtolower($attr), $current_attrs ) )
+		$needed_attrs[] = $attr;
+
+if( count( $needed_attrs ) > 0 )
+{
+	?>
+
+
+	
+	
+	
+	

New Required Attributes

+

This action requires you to add new attribute1?'s':''); ?>

+ + + Instrucitons: In order to add the objectClass to the object , + you must specify new attribute1?'s':''); ?> that this + objectClass requires. You can do so in this form. + +
+
+ +
+ + + + + + + + $attr ) { ?> + + + + + + + + + +
New Required Attributes
+
+
+
+
+
+ + + + + $new_oclass ) ); + if( ! $add_res ) + pla_error( "Could not perform ldap_mod_add operation.", ldap_error( $ds ), ldap_errno( $ds ) ); + else + header( "Location: edit.php?server_id=$server_id&dn=$encoded_dn" ); + +} + +?> diff --git a/add_value.php b/add_value.php new file mode 100644 index 0000000..49d584d --- /dev/null +++ b/add_value.php @@ -0,0 +1,52 @@ + $new_value ); + +$add_result = @ldap_mod_add( $ds, $dn, $new_entry ); + +if( ! $add_result ) + pla_error( "Could not perform ldap_mod_add operation.", ldap_error( $ds ), ldap_errno( $ds ) ); + +header( "Location: edit.php?server_id=$server_id&dn=$encoded_dn&updated_attr=$encoded_attr" ); + +?> diff --git a/add_value_form.php b/add_value_form.php new file mode 100644 index 0000000..013be2c --- /dev/null +++ b/add_value_form.php @@ -0,0 +1,133 @@ + + + + + + +

New value for

+

Server:     Distinguished Name:

+ +Current list of value1?'s':''; ?> + for attribute : + + + +
+ +
+ + +

+ Note: You will get an "inappropriate matching" error if you have not
+ setup an EQUALITY rule on your LDAP server for jpegPhoto attributes. +

+ + + + +
    + 1 )*/ { + foreach( $current_values as $val ) { ?> + +
  • + + + + +
  • + + +
+ + + +Enter the value you would like to add:
+
+ + + +
+ + + + +
Note: you may be required to enter new attributes
+ that this objectClass requires (MUST attrs)
+ + + + + + + +
+
+ + + + + + + + + + +
+ Syntax: +
+ + + + + diff --git a/collapse.php b/collapse.php new file mode 100644 index 0000000..153ced2 --- /dev/null +++ b/collapse.php @@ -0,0 +1,43 @@ + diff --git a/config.php.example b/config.php.example new file mode 100644 index 0000000..14f75d1 --- /dev/null +++ b/config.php.example @@ -0,0 +1,163 @@ + 'User', + 'icon' => 'images/user.png', + 'handler' => 'new_user_template.php' ); + +$templates[] = + array( 'desc' => 'inetOrgPerson', + 'icon' => 'images/user.png', + 'handler' => 'new_address_template.php' ); + +$templates[] = + array( 'desc' => 'Organizational Unit', + 'icon' => 'images/ou.png', + 'handler' => 'new_ou_template.php' ); + +$templates[] = + array( 'desc' => 'Samba NT Machine', + 'icon' => 'images/terminal.png', + 'handler' => 'new_nt_machine.php' ); + +$templates[] = + array( 'desc' => 'DNS Entry', + 'icon' => 'images/dc.png', + 'handler' => 'new_dns_entry.php' ); + +/** **/ +/** User-friendly attribute translation **/ +/** **/ + +$friendly_attrs = array(); + +// Use this array to map attribute names to user friendly names. For example, if you +// don't want to see "facsimileTelephoneNumber" but rather "Fax". + +$friendly_attrs[ 'facsimileTelephoneNumber' ] = 'Fax'; +$friendly_attrs[ 'telephoneNumber' ] = 'Phone'; + +/** **/ +/** Some phpLDAPAdmin code to be executed. No touchy. **/ +/** **/ + +// Turn off notices about referencing arrays and such, but leave everything else on. +error_reporting( E_ALL ^ E_NOTICE ); + +// Always including the 'custom' template (the most generic and flexible) +$templates['custom'] = + array( 'desc' => 'Custom', + 'icon' => 'images/object.png', + 'handler' => 'custom.php' ); + +?> diff --git a/copy.php b/copy.php new file mode 100644 index 0000000..127ae86 --- /dev/null +++ b/copy.php @@ -0,0 +1,167 @@ +\n"; + echo "

Copying " . htmlspecialchars( $source_dn ) . "

\n"; + echo "

Recursive copy progress

\n"; + echo "

"; + echo "\n"; + echo "Building snapshot of tree to copy... "; + flush(); + build_tree( $source_server_id, $source_dn, $snapshot_tree ); + echo " Success
\n"; + flush(); + + // prevent script from bailing early on a long delete + @set_time_limit( 0 ); + + $copy_result = r_copy_dn( $source_server_id, $dest_server_id, $snapshot_tree, $source_dn, $dest_dn ); + echo "
\n"; +} else { + $copy_result = copy_dn( $source_server_id, $source_dn, $dest_server_id, $dest_dn ); +} + +if( $copy_result ) +{ + $edit_url="edit.php?server_id=$dest_server_id&dn=" . rawurlencode( $dest_dn ); + $new_rdn = get_rdn( $dest_dn ); + $container = get_container( $dest_dn ); + if( session_is_registered( 'tree' ) ) + { + $tree = $_SESSION['tree']; + $tree_icons = $_SESSION['tree_icons']; + if( isset( $tree[$dest_server_id][$container] ) ) + { + $tree[$dest_server_id][$container][] = $dest_dn; + $tree_icons[$dest_server_id][$dest_dn] = get_icon( $dest_server_id, $dest_dn ); + $_SESSION['tree'] = $tree; + $_SESSION['tree_icons'] = $tree_icons; + session_write_close(); + } + } + + ?> + + +
+ Copy successful! Would you like to view the new entry? +
+
+
+
+ + + Copying " . htmlspecialchars( utf8_decode( $root_dn ) ) . "..."; + flush(); + $copy_result = copy_dn( $source_server_id, $root_dn, $dest_server_id, $dest_dn ); + + if( ! $copy_result ) { + global $R_COPY_ERROR; + return false; + } + + echo "Success
\n"; + flush(); + + $children = $tree[ $root_dn ]; + if( is_array( $children ) && count( $children ) > 0 ) + { + foreach( $children as $child_dn ) { + $child_rdn = get_rdn( $child_dn ); + $new_dest_dn = $child_rdn . ',' . $dest_dn; + r_copy_dn( $source_server_id, $dest_server_id, $tree, $child_dn, $new_dest_dn ); + } + } + else + { + return true; + } + + return true; +} + +function copy_dn( $source_server_id, $source_dn, $dest_server_id, $dest_dn ) +{ + global $ds; + $ds = pla_ldap_connect( $dest_server_id ) or pla_error( "Could not connect to LDAP server" ); + $attrs = get_object_attrs( $source_server_id, $source_dn ); + $new_entry = $attrs; + // modify the prefix-value (ie "bob" in cn=bob) to match the destination DN's value. + $rdn_attr = substr( $dest_dn, 0, strpos( $dest_dn, '=' ) ); + $rdn_value = get_rdn( $dest_dn ); + $rdn_value = substr( $rdn_value, strpos( $rdn_value, '=' ) + 1 ); + $new_entry[ $rdn_attr ] = $rdn_value; + // don't need a dn attribute in the new entry + unset( $new_entry['dn'] ); + $add_result = @ldap_add( $ds, $dest_dn, $new_entry ); + if( ! $add_result ) { + echo "

"; + pla_error( "Failed to copy $source_dn (server: $source_server_id) to " . + "$dest_dn (server: $dest_server_id)", ldap_error( $ds ), ldap_errno( $ds ) ); + } + + return $add_result; +} + +function build_tree( $source_server_id, $root_dn, &$tree ) +{ + $children = get_container_contents( $source_server_id, $root_dn ); + if( is_array( $children ) && count( $children ) > 0 ) + { + $tree[ $root_dn ] = $children; + foreach( $children as $child_dn ) + build_tree( $source_server_id, $child_dn, $tree ); + } + +} diff --git a/copy_form.php b/copy_form.php new file mode 100644 index 0000000..a37a909 --- /dev/null +++ b/copy_form.php @@ -0,0 +1,86 @@ + $server ) +{ + if( $server['host'] ) + { + $select_server_html .= "\n"; + } +} + +$children = get_container_contents( $server_id, $dn ); + +?> + + + + +

Copy

+

Server:     Distinguished Name:

+ +
+Copy to a new object:
+
+
+ + + + + + + + + + + + + + + + + + 0 ) { ?> + + + + + + + + +
Destination DN: + +
Destination Server:
Note: Copying between different servers only works if there are no schema violations
+ Recursively copy all children of this object as well.
+
+ +
+ + diff --git a/create.php b/create.php new file mode 100644 index 0000000..1f643a8 --- /dev/null +++ b/create.php @@ -0,0 +1,114 @@ + $val ) + { + if( $val == '' ) + pla_error( "Error, you left the value for required attribute " . + htmlspecialchars( $attr ) . " blank." ); + + $attr = stripslashes( $attr ); + $val = stripslashes( $val ); + $new_entry[ $attr ][] = utf8_encode( $val ); + } +} + +if( isset( $vals ) && is_array( $vals ) ) +{ + foreach( $vals as $i => $val ) + { + $val = stripslashes( $val ); + $attr = $attrs[$i]; + $attr = stripslashes( $attr ); + if( trim($val) ) + $new_entry[ $attr ][] = utf8_encode( $val ); + } +} + +$new_entry['objectClass'] = $object_classes; +if( ! in_array( 'top', $new_entry['objectClass'] ) ) + $new_entry['objectClass'][] = 'top'; + +$ds = pla_ldap_connect( $server_id ); +$add_result = @ldap_add( $ds, $new_dn, $new_entry ); +if( $add_result ) +{ + $edit_url="edit.php?server_id=$server_id&dn=" . rawurlencode( $new_dn ); + + // update the session tree to reflect the change + session_start(); + if( session_is_registered( 'tree' ) ) + { + $tree = $_SESSION['tree']; + $tree_icons = $_SESSION['tree_icons']; + + if( isset( $tree[$server_id][$container] ) ) { + $tree[$server_id][$container][] = $new_dn; + $tree_icons[$server_id][$new_dn] = get_icon( $server_id, $new_dn ); + } + + $_SESSION['tree'] = $tree; + $_SESSION['tree_icons'] = $tree_icons; + session_write_close(); + } + + ?> + + + + + + + + + + + + + Redirecting... here. + + + diff --git a/create_form.php b/create_form.php new file mode 100644 index 0000000..53f9c13 --- /dev/null +++ b/create_form.php @@ -0,0 +1,81 @@ +'; +$js_dn_list = ''; +foreach( $servers as $id => $server ) { + if( $server['host'] ) { + $server_menu_html .= ''; + } +} +$server_menu_html .= ''; + +?> + + + + + +

Create Object

+

Choose a template

+

Select a template for the creation process

+
+ + + + + + + + + + + + + + + +
Server:
Template: + + + $template ) { ?> + + + + + + +
+
+ +
+ + + diff --git a/creation_template.php b/creation_template.php new file mode 100644 index 0000000..238a2ca --- /dev/null +++ b/creation_template.php @@ -0,0 +1,45 @@ + + + +

Create Object

+

On server '', + using template ''

+ +" . htmlspecialchars( $template['handler'] ) . + " for this template. But, this handler does not exist in the 'templates/creation' directory." ); + + diff --git a/delete.php b/delete.php new file mode 100644 index 0000000..786bf61 --- /dev/null +++ b/delete.php @@ -0,0 +1,65 @@ + $subtree ) + foreach( $subtree as $key => $sub_tree_dn ) + if( 0 == strcasecmp( $sub_tree_dn, $dn ) ) + unset( $tree[$server_id][$tree_dn][$key] ); + } + + $_SESSION['tree'] = $tree; + session_write_close(); + + ?> + + + + Object deleted successfully. + + 0 ? true : false; + +?> + + + + +

Delete

+

Server:     Distinguished Name:

+ + + +
You cannot delete the base DN entry of the LDAP server.
+ + + + + + + + + +
Permanently delete all children also?

+ + + + + +
+ +

This object is the root of a sub-tree containing objects + +phpLDAPAdmin can recursively delete this object and all of its children. See below for a list of DNs +that this will delete. Do you want to do this?
+
+Note: This is potentially very dangerous and you do this at your own risk. This operation cannot be undone. +Take into consideration aliases and other such things that may cause problems. +
+
+ + + + + + +
+
+
+ + + +
+
+
+
+ + + +
+
+
+

+ +
+
+A list of all the DNs that this action will delete:
+ + +
+ + + +
+ + + +
+ +Are you sure you want to permanently delete this object?
+
+DN:
+
Server:
+
+ + + + + + +
+
+
+ + + +
+ +
+
+
+ + + +
+
+
+ +
+ +
+ + + + + + + + diff --git a/edit.php b/edit.php new file mode 100644 index 0000000..2935dad --- /dev/null +++ b/edit.php @@ -0,0 +1,472 @@ + + + + + +

+

Server:     Distinguished Name:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 ) { + if( $children_count == $max_children ) + $children_count = $children_count . '+'; + +?> + + + + + + + + + 0 ) { ?> + + + + + + + + + + + + + + + + + +
Refresh
Delete this entry
Copy this entry
Export to LDIF + (mac) + (win) + (unix) +
">Create a child entry
View
Export subtree to LDIF + (mac) + (win) + (unix) +
Add a jpegPhoto
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + $val ) { + $counter++ + ?> + + + + + \n"; +} + +?> + + + + + + + + + + + + + + + + + $vals ) { + flush(); + if( $attr == 'dn' ) + continue; + + // is there a user-friendly translation available for this attribute? + if( isset( $friendly_attrs[ strtolower( $attr ) ] ) ) { + $attr_display = "" . + $friendly_attrs[ strtolower( $attr ) ] . ""; + } else { + $attr_display = $attr; + } + + ?> + + + + + + + + + + + + + + + + + + + + + + + + $val ) { ?> + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Rename Entry + +
+ + + + +
+
+
+ + Add New Attribute + + + 0 ) { ?> + + + + + + + + (no new attributes available for this entry) + + +
+ + + + +Internal Attriubtes + + + + + +Internal Attriubtes +(hidden) + + + + +
(none)
+ + Modify Attributes + +
+
+ (add value) +
+ + + + + + + + This attribute contains binary data,
+ which cannot be safely displayed
+ or edited in a web-browser.
+
+ + + + + +
+ + + +
+ + + diff --git a/entry_chooser.js b/entry_chooser.js new file mode 100644 index 0000000..4f0aeca --- /dev/null +++ b/entry_chooser.js @@ -0,0 +1,6 @@ +function dnChooserPopup( form_element ) +{ + mywindow=open('entry_chooser.php','myname','resizable=no,width=600,height=370,scrollbars=1'); + mywindow.location.href = 'entry_chooser.php?form_element=' + form_element; + if (mywindow.opener == null) mywindow.opener = self; +} diff --git a/entry_chooser.php b/entry_chooser.php new file mode 100644 index 0000000..f71fc87 --- /dev/null +++ b/entry_chooser.php @@ -0,0 +1,73 @@ +Automagic Entry Chooser\n"; + +if( $container ) { + echo "Server: " . htmlspecialchars( $servers[ $server_id ][ 'name' ] ) . "
\n"; + echo "Looking in: " . htmlspecialchars( $container ) . "
\n"; +} + +if( $server_id !== false && $container !== false ) +{ + check_server_id( $server_id ) or pla_error( "Bad server_id: " . htmlspecialchars( $server_id ) ); + have_auth_info( $server_id ) or pla_error( "Not enough information to login to server. ". + "Please check your configuration." ); + pla_ldap_connect( $server_id ) or pla_error( "Coult not connect to LDAP server." ); + $dn_list = get_container_contents( $server_id, $container ); + + $base_dn = $servers[ $server_id ][ 'base' ]; + if( ! $base_dn ) + $base_dn = try_to_get_root_dn( $server_id ); + + if( $container == $base_dn ) { + $parent_container = false; + $up_href = "entry_chooser.php?form_element=$return_form_element"; + } else { + $parent_container = get_container( $container ); + $up_href = "entry_chooser.php?form_element=$return_form_element&server_id=$server_id&container=" . + rawurlencode( $parent_container ); + } + echo " " . + " Back Up...
\n"; + + if( count( $dn_list ) == 0 ) + echo "   (no entries)
\n"; + else + foreach( $dn_list as $dn ) { + $href = "javascript:returnDN( '$dn' )"; + echo "    " . + "" . htmlspecialchars( $dn ) . "
\n"; + } +} +else +{ + foreach( $servers as $id => $server ) { + if( $server['host'] ) { + echo htmlspecialchars( $server['name'] ) . "
\n"; + $dn = ( $server['base'] ? $server['base'] : try_to_get_root_dn( $id ) ); + $href = "javascript:returnDN( '$dn' )"; + echo "    " . + "" . htmlspecialchars( $dn ) . "
\n"; + } + } +} + +?> + + diff --git a/expand.php b/expand.php new file mode 100644 index 0000000..d8bbbcb --- /dev/null +++ b/expand.php @@ -0,0 +1,60 @@ + diff --git a/functions.php b/functions.php new file mode 100644 index 0000000..9b134cb --- /dev/null +++ b/functions.php @@ -0,0 +1,1174 @@ + $class ) + $object_classes[$i] = strtolower( $class ); + + // get the prefix (ie: dc, ou, cn, uid) + $exploded_dn = ldap_explode_dn( $dn, 0 ); + $rdn = $dn[0]; + $prefix = explode( '=', $rdn ); + $prefix = $prefix[0]; + + // Is it a person or some type of account/user? + if( in_array( 'person', $object_classes ) || + in_array( 'organizationalperson', $object_classes ) || + in_array( 'inetorgperson', $object_classes ) || + in_array( 'account', $object_classes ) || + in_array( 'posixaccount', $object_classes ) ) + return 'user.png'; + // Is it an organization? + elseif ( in_array( 'organization', $object_classes ) ) + return 'o.png'; + // Is it an organizational Unit? + elseif( in_array( 'organizationalunit', $object_classes ) ) + return 'ou.png'; + // Is it a domain controler (dc) + elseif( in_array( 'dcobject', $object_classes ) || + in_array( 'domainrelatedobject', $object_classes ) ) + return 'dc.png'; + elseif( in_array( 'country', $object_classes ) ) + return 'country.png'; + elseif( in_array( 'jammvirtualdomain', $object_classes ) ) + return 'mail.png'; + elseif( in_array( 'locality', $object_classes ) ) + return 'locality.png'; + // Oh well, I don't know what it is. Use a generic icon. + else + return 'object.png'; +} + +/* + * Given a server_id, returns whether or not we have enough information + * to authenticate against the server. For example, if the user specifies + * 'cookie' in the config for that server, it checks the $_COOKIE array to + * see if the cookie username and password is set for the server. + */ +function have_auth_info( $server_id ) +{ + global $servers; + + if( ! is_numeric( $server_id ) || ! isset( $servers[$server_id] ) ) + return false; + + $server = $servers[$server_id]; + + if( $server['auth_type'] == 'form' ) + { + global $_COOKIE; + if( isset( $_COOKIE[ 'pla_login_dn_' . $server_id ] ) && + isset( $_COOKIE[ 'pla_pass_' . $server_id ] ) ) + return true; + else + return false; + } + // whether or not the login_dn or pass is specified, we return + // true here. (if they are blank, we do an anonymous bind anyway) + elseif( $server['auth_type'] == 'config' ) + { + return true; + } + else + { + pla_error( "Error: You have an error in your config file. The only two allowed + values for 'auth_type' in the $servers section are 'config' and + 'form'. You entered '" . htmlspecialchars($server['auth_type']) . "', which + is not allowed. " ); + } +} + +function get_logged_in_pass( $server_id ) +{ + global $_COOKIE; + $pass = $_COOKIE[ 'pla_login_pass_' . $server_id ]; + + if( $pass == '0' ) + return false; + else + return $pass; +} +function get_logged_in_dn( $server_id ) +{ + global $_COOKIE; + $dn = $_COOKIE[ 'pla_login_dn_' . $server_id ]; + + if( $dn == '0' ) + return 'Anonymous'; + else + return $dn; +} + +/* + * Specify a $server_id (0,1,2...) based on the order it appears in config.php. + * The first is 0, the second is 1, etc. You rarely will need to consult + * config.php since those values are usually generated dynamically in hrefs. + */ +function pla_ldap_connect( $server_id ) +{ + if( ! check_server_id( $server_id ) ) + return false; + + if( ! have_auth_info( $server_id ) ) + return false; + + global $servers; + + // cache the connection, so if we are called multiple + // times, we don't have to reauthenticate with the LDAP server + + static $conns; + if( $conns[$server_id] ) + return $conns[$server_id]; + + $host = $servers[$server_id]['host']; + $port = $servers[$server_id]['port']; + if( ! $port ) $port = 389; + + $conn = @ldap_connect( $host, $port ); + + if( ! $conn ) return false; + + // go with LDAP version 3 if possible (needed for renaming and Novell schema fetching) + @ldap_set_option( $conn, LDAP_OPT_PROTOCOL_VERSION, 3 ); + + // try to fire up TLS is specified in the config + if( $servers[ $server_id ][ 'tls' ] == true ) { + function_exists( 'ldap_start_tls' ) or pla_error( "Your PHP install does not support TLS" ); + @ldap_start_tls( $conn ) or pla_error( "Could not start TLS.
Please check your ". + "LDAP server configuration." ); + } + + // grab the auth info based on the auth_type for this server + if( $servers[ $server_id ][ 'auth_type' ] == 'config' ) { + $login_dn = $servers[$server_id]['login_dn']; + $login_pass = $servers[$server_id]['login_pass']; + } elseif( $servers[ $server_id ][ 'auth_type' ] == 'form' ) { + global $_COOKIE; + $login_dn = $_COOKIE['pla_login_dn_' . $server_id ]; + $login_pass = $_COOKIE['pla_pass_' . $server_id ]; + + // Was this an anonyous bind (the cookie stores 0 if so)? + if( '0' == $login_dn ) { + $login_dn = null; + $login_pass = null; + } + } else { + pla_error( "You have an error in your config file. auth_type of " . + htmlspecialchars( $servers[ $server_id ][ 'auth_type' ] ) . + " is not valid." ); + } + + $res = @ldap_bind( $conn, $login_dn, $login_pass ); + + if( ! $res ) return false; + + // store the cached connection resource + $conns[$server_id] = $conn; + + return $conn; +} + +/* + * Returns an array listing the DNs contained by the specified $dn + */ +function get_container_contents( $server_id, $dn, $size_limit=0 ) +{ + $con = pla_ldap_connect( $server_id ); + if( ! $con ) return false; + + $search = @ldap_list( $con, $dn, 'objectClass=*', array( 'dn' ), 1, $size_limit ); + if( ! $search ) + return array(); + $search = ldap_get_entries( $con, $search ); + + $return = array(); + + for( $i=0; $i<$search['count']; $i++ ) + { + $entry = $search[$i]; + $dn = $entry['dn']; + $return[] = $dn; + } + + return $return; +} + +/* + * Builds the initial tree that is stored in the session variable 'tree'. + * Simply returns an array with an entry for each active server in + * config.php + */ +function build_initial_tree() +{ + global $servers; + $tree = array(); + foreach( $servers as $id => $server ) { + if( $server['host'] == '' ) { + continue; + /* + $root_dn = try_to_get_root_dn( $id ); + echo "Root is $root_dn
"; + if( $root_dn ) + $tree[$id][$root_dn] = array(); + */ + } + + $dn = $server['base']; + $tree[$id] = array(); + } + + return $tree; +} + +/* + * Builds the initial array that stores the icon-lookup for each DN in the tree browser + */ +function build_initial_tree_icons() +{ + global $servers; + $tree_icons = array(); + + // initialize an empty array for each server + foreach( $servers as $id => $server ) { + if( $server['host'] == '' ) + continue; + $tree_icons[ $id ] = array(); + $tree_icons[ $id ][ $server['base'] ] = get_icon( $id, $server['base'] ); + } + + return $tree_icons; +} + +function get_entry_system_attrs( $server_id, $dn ) +{ + $conn = pla_ldap_connect( $server_id ); + if( ! $conn ) return false; + + $search = @ldap_read( $conn, $dn, '(objectClass=*)', array("+"), 0, 200, 0, LDAP_DEREF_ALWAYS ); + + if( ! $search ) + return false; + + $entry = ldap_first_entry( $conn, $search ); + $attrs = ldap_get_attributes( $conn, $entry ); + foreach( $attrs as $name => $vals ) + if( is_numeric( $name ) || $name == 'count' ) + unset( $attrs[$name] ); + else + $attrs[$name] = $vals[0]; + return $attrs; +} + +/* + * Returns the attribute/value pairs for the given $dn on the given + * $server_id. If the attribute is single valued, it will return + * a single value for that attribute. Otherwise, it will return an + * array of values for that attribute. Here's a sample return value: + * + * Array + * ( + * [objectclass] => Array + * ( + * [0] => organizationalRole + * [1] => krb5principal + * [2] => kerberosSecurityObject + * ) + * [cn] => Manager + * [krbname] => phpldap@EXAMPLE.COM + * [dn] => cn=Manager,dc=example,dc=com + * ) + */ +function get_object_attrs( $server_id, $dn, $lower_case_attr_names = false ) +{ + $conn = pla_ldap_connect( $server_id ); + if( ! $conn ) return false; + + $search = @ldap_read( $conn, $dn, '(objectClass=*)' ); + + if( ! $search ) + return false; + + $entry = ldap_first_entry( $conn, $search ); + $attrs = ldap_get_attributes( $conn, $entry ); + //$attrs = ldap_get_entries( $conn, $search ); + + if( ! $attrs || $attrs['count'] == 0 ) + return false; + + //$attrs = $attrs[0]; + $num_attrs = $attrs['count']; + unset( $attrs['count'] ); + + for( $i=0; $i<$num_attrs; $i++ ) + unset( $attrs[$i] ); + + $return_array = array(); + foreach( $attrs as $attr => $vals ) { + if( $lower_case_attr_names ) + $attr = strtolower( $attr ); + $count = $vals['count']; + unset( $vals['count'] ); + if( $count == 1 ) + $return_array[ $attr ] = $vals[0]; + else + $return_array[ $attr ] = $vals; + } + + ksort( $return_array ); + + return $return_array; +} + +/* + * Returns true if the passed string $temp contains all printable + * ASCII characters. Otherwise (like if it contains binary data), + * returns false. + */ +function is_printable_str($temp) { + $len = strlen($temp); + for ($i=0; $i<$len; $i++) { + $ascii_val = ord( substr( $temp,$i,1 ) ); + if( $ascii_val < 32 || $ascii_val > 126 ) + return false; + } + + return true; +} + +/* + * Much like get_object_attrs(), but only returns the entry for + * one attribute of an object. Again, if the attribute contains + * multiple values, returns an array of values. Otherwise, it + * returns the single attribute value. + * TODO: Don't call get_object_attrs() and filter. Do the actual ldap_read() ourselves (for efficiencey) + */ +function get_object_attr( $server_id, $dn, $attr ) +{ + $attr = strtolower( $attr ); + $attrs = get_object_attrs( $server_id, $dn, true ); + if( isset( $attrs[$attr] ) ) + return $attrs[$attr]; + else + return false; +} + +/* + * Returns true if $var is not white space only, and false otherwise. + */ +function not_white( $var ) +{ + return trim($var) != "" ? true : false; +} + +/* + * Returns an associative array of objectClasses for the specified + * $server_id. Each array entry's key is the name of the objectClass + * in lower-case. + * The sub-entries consist of sub-arrays called 'must_attrs' and + * 'may_attrs', and sub-entries called 'oid', 'name' and 'description'. + * + * The bulk of this function came from the good code in the + * GPL'ed LDAP Explorer project. Thank you. + */ +function get_schema_objectclasses( $server_id ) +{ + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + // get all the objectClasses + $result = @ldap_read($ds, 'cn=subschema', '(objectClass=*)', + array( 'objectclasses' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + if( ! $result ) + $result = @ldap_read($ds, 'cn=schema', '(objectClass=*)', + array( 'objectclasses' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + + if( ! $result ) return false; + if( $result ) $raw_oclasses = ldap_get_entries($ds,$result ); + + // build the array of objectClasses + $oclasses = array(); + for( $att=0; $att < count( $raw_oclasses[0]["objectclasses"] ); $att++ ) + { + $class = $raw_oclasses[0]["objectclasses"][$att]; + + preg_match( "/[\s]+NAME[\s'\(]+([a-zA-Z0-9\-_]+)[\s'\)]/" , $class, $name); + preg_match( "/[\s]+([\d\.]+)[\s]+NAME/", $class, $oid ); + preg_match( "/[\s]+DESC[\s]+'([a-zA-Z0-9\-_ ]+)'/", $class, $description ); + preg_match( "/[\s]+SUP[\s]+([a-zA-Z0-9\-_]+)[\s]/", $class, $sup ); + + $key = strtolower( trim( $name[1] ) ); + $oclass_name = trim( $name[1] ); + if( ! $key ) continue; + + $oclasses[$key] = array(); + $oclasses[$key]['oid'] = trim( $oid[1] ); + $oclasses[$key]['description'] = trim( $description[1] ); + $oclasses[$key]['sup'] = trim( $sup[1] ); + + unset( $name ); + unset( $syntax ); + unset( $desription ); + + // get all the required attributes + preg_match( "/MUST[\s\(]+([a-zA-Z0-9\s$]+)(MAY|\))/" , $class, $must_attrs ); + $must_attrs = str_replace( ' ', '', $must_attrs[1] ); + $oclasses[$key]['must_attrs'] = array_filter( explode( '$', $must_attrs ), "not_white" ); + + // get all the optional attributes + preg_match( "/MAY[\s\(]+([a-zA-Z0-9\s$]+)(MUST|\))/" , $class, $may_attrs ); + $may_attrs = str_replace( ' ', '', $may_attrs[1] ); + $oclasses[$key]['may_attrs'] = array_filter( array_merge( $oclasses[$key]['must_attrs'], explode( '$', $may_attrs) ), "not_white" ); + unset( $must_attrs ); + unset( $may_attrs ); + + $oclasses[$key]['name'] = $oclass_name; + } + + // go back and add any inherited MUST/MAY attrs to each objectClass + foreach( $oclasses as $oclass => $attrs ) + { + $new_must = $attrs['must_attrs']; + $new_may = $attrs['may_attrs']; + $sup_attr = $attrs['sup']; + + while( $sup_attr && $sup_attr != "top" ) { + $new_must = array_merge( $new_must, $oclasses[strtolower($sup_attr)]['must_attrs'] ); + $new_may = array_merge( $new_may, $oclasses[strtolower($sup_attr)]['may_attrs'] ); + $sup_attr = $oclasses[strtolower($sup_attr)]['sup']; + } + + $oclasses[$oclass]['must_attrs'] = array_unique( $new_must ); + $oclasses[$oclass]['may_attrs'] = array_unique( $new_may ); + } + + ksort( $oclasses ); + + return $oclasses; + +} + +/* + * Returns an associate array of the server's schema matching rules + */ +function get_schema_matching_rules( $server_id ) +{ + static $cache; + + if( isset( $cache[$server_id] ) ) + return $cache[$server_id]; + + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + // get all the attributeTypes + $result = @ldap_read($ds, 'cn=subschema', '(objectClass=*)', + array( 'matchingRules', 'matchingRuleUse' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + if( ! $result ) + $result = @ldap_read($ds, 'cn=schema', '(objectClass=*)', + array( 'matchingRules', 'matchingRuleUse' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + + if( $result ) + $raw = ldap_get_entries( $ds, $result ); + else + return( array() ); + + // build the array of attributes + $rules = array(); + for( $i=0; $i < $raw[0]['matchingrules']['count']; $i++ ) + { + $rule = $raw[0]['matchingrules'][$i]; + preg_match( "/[\s]+([\d\.]+)[\s]+/", $rule, $oid); + preg_match( "/[\s]+NAME[\s]+'([\)\(:?\.a-zA-Z0-9\-_ ]+)'/", $rule, $name ); + + $key = strtolower( trim( $oid[1] ) ); + if( ! $key ) continue; + + $rules[$key] = $name[1]; + //$rules[$key]['name'] = $name[1]; + } + + ksort( $rules ); + $cache[$server_id] = $rules; + return $rules; +} + + +/* + * Returns an associate array of the syntax OIDs that this LDAP server uses mapped to + * their descriptions. + */ +function get_schema_syntaxes( $server_id ) +{ + static $cache; + + if( isset( $cache[$server_id] ) ) + return $cache[$server_id]; + + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + // get all the attributeTypes + $result = @ldap_read($ds, 'cn=subschema', '(objectClass=*)', + array( 'ldapSyntaxes' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + if( ! $result ) + $result = @ldap_read($ds, 'cn=schema', '(objectClass=*)', + array( 'ldapSyntaxes' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + + if( $result ) + $raw = ldap_get_entries( $ds, $result ); + else + return( array() ); + + // build the array of attributes + $syntaxes = array(); + for( $i=0; $i < $raw[0]['ldapsyntaxes']['count']; $i++ ) + { + $syntax = $raw[0]['ldapsyntaxes'][$i]; + preg_match( "/[\s]+([\d\.]+)[\s]+/", $syntax, $oid); + preg_match( "/[\s]+DESC[\s]+'([\)\(:?\.a-zA-Z0-9\-_ ]+)'/", $syntax, $description ); + + $key = strtolower( trim( $oid[1] ) ); + if( ! $key ) continue; + + $syntaxes[$key] = array(); + $syntaxes[$key]['description'] = $description[1]; + } + + ksort( $syntaxes ); + + $cache[$server_id] = $syntaxes; + + return $syntaxes; +} + +/* + * Returns an associative array of attributes for the specified + * $server_id. Each array entry's key is the name of the attribute, + * in lower-case. + * The sub-entries are 'oid', 'syntax', 'equality', 'substr', 'name', + * and 'single_value'. + * + * The bulk of this function came from the good code in the + * GPL'ed LDAP Explorer project. Thank you. It was extended + * considerably for application here. + */ +function get_schema_attributes( $server_id ) +{ + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + // get all the attributeTypes + $result = @ldap_read($ds, 'cn=subschema', '(objectClass=*)', + array( 'attributeTypes' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + if( ! $result ) + $result = @ldap_read($ds, 'cn=schema', '(objectClass=*)', + array( 'attributeTypes' ), 0, 200, 0, LDAP_DEREF_ALWAYS ); + + if( $result ) + $raw_attrs = ldap_get_entries( $ds, $result ); + else + $raw_attrs = array(); + $syntaxes = get_schema_syntaxes( $server_id ); + + // build the array of attributes + $attrs = array(); + for( $i=0; $i < $raw_attrs[0]['attributetypes']['count']; $i++ ) + { + $attr = $raw_attrs[0]['attributetypes'][$i]; + + preg_match( "/[\s]+NAME[\s'\(]+([a-zA-Z0-9\-_]+)[\s'\)]/" , $attr, $name); + preg_match( "/\s+NAME\s+'([a-zA-Z0-9\-_]+)'\s/" , $attr, $name); + preg_match( "/[\s]+([\d\.]+)[\s]+NAME/", $attr, $oid ); + preg_match( "/[\s]+DESC[\s]+'([\)\(:?\.a-zA-Z0-9\-_ ]+)'/", $attr, $description ); + preg_match( "/[\s]+SYNTAX[\s]+([\d\.]+)/", $attr, $syntax); + preg_match( "/[\s]+EQUALITY[\s]+([a-zA-Z]+)/", $attr, $equality); + preg_match( "/[\s]+SUBSTR[\s]+([a-zA-Z]+)/", $attr, $substr); + preg_match( "/[\s]+SUP[\s]+([a-zA-Z0-9\-_]+)/", $attr, $sup ); + + if( preg_match( "/[\s]+SINGLE-VALUE[\s]+/", $attr, $single_value ) ) + $single_value = 'Yes'; + else + $single_value = 'No'; + + // If this schema attribute has multiple names (like: "NAME ( 'uid' 'userid' )"), then we need + // to create a matching attribute entry for each name it bares. + if( preg_match( "/\s+NAME\s+\(\s*['\sa-zA-Z0-9\-_]+\s*\)/", $attr, $multi_name ) ) { + $multi_name = $multi_name[0]; + preg_match_all( "/'([a-zA-Z0-9\-_]+)'/", $multi_name, $multiple_names ); + $multiple_names = $multiple_names[1]; + //print_r( $multiple_names ); + + foreach( $multiple_names as $name ) { + $key = strtolower( trim( $name ) ); + $attr_name = trim( $name ); + if( ! $key ) continue; + + $attrs[$key] = array(); + $attrs[$key]['oid'] = trim( $oid[1] ); + $attrs[$key]['description'] = trim( $description[1] ); + $attrs[$key]['syntax'] = trim( $syntax[1] ); + $attrs[$key]['type'] = $syntaxes[ trim($syntax[1]) ]['description']; + $attrs[$key]['equality'] = trim( $equality[1] ); + $attrs[$key]['substr'] = trim( $substr[1] ); + $attrs[$key]['single_value'] = $single_value; + $attrs[$key]['sup'] = trim( $sup[1] ); + $attrs[$key]['name'] = $attr_name; + + $count = 1; + for( $j=0; $j $desc ) + { + $sup_attr = $desc['sup']; + while( $sup_attr ) { + if( ! $attrs[ $sup_attr ]['sup'] ) { + $attrs[ $attr ][ 'syntax' ] = $attrs[ $sup_attr ]['syntax']; + $attrs[ $attr ][ 'equality' ] = $attrs[ $sup_attr ]['equality']; + $attrs[ $attr ][ 'substr' ] = $attrs[ $sup_attr ]['substr']; + $attrs[ $attr ][ 'single_value' ] = $attrs[ $sup_attr ]['single_value']; + break; + } else { + $sup_attr = $attrs[ $sup_attr ]['sup']; + } + } + } + + ksort( $attrs ); + + return $attrs; +} + +/* + * A wrapper function to save you from having to call get_schema_objectclasses() + * and get_schema_attributes(). Returns an array with two indexes: 'oclasses' + * and 'attributes', as defined by their respective functions above. + */ +function get_schema( $server_id ) +{ + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + $attrs = get_schema_attributes($server_id, $lower_case_all ); + $oclasses = get_schema_objectclasses($server_id, $lower_case_all ); + + if( ! $oclasses ) + return false; + + $schema = array( 'attrs' => $attrs, + 'oclasses' => $oclasses ); + return $schema; +} + +/* + * A do-it-all ldap_search function. You can even specify the search scope. Other than + * that, it's pretty much the same as the PHP ldap_search() call, except it returns + * an array of results, rather than an LDAP result resource. + */ +function pla_ldap_search( $server_id, $filter, $base_dn=null, $attrs=array(), $scope='sub', $sort_results=true ) +{ + global $servers; + + if( ! isset($servers[$server_id]) || $servers[$server_id]['host'] == '' ) + return false; + + if( $base_dn == null ) + $base_dn = $servers[$server_id]['base']; + + $ds = pla_ldap_connect( $server_id ); + if( ! $ds ) + return false; + + switch( $scope ) { + case 'base': + $search = @ldap_read( $ds, $base_dn, $filter, $attrs ); + break; + case 'one': + $search = @ldap_list( $ds, $base_dn, $filter, $attrs ); + break; + case 'sub': + default: + $search = @ldap_search( $ds, $base_dn, $filter, $attrs ); + break; + } + + if( ! $search ) + return array(); + + $search = ldap_get_entries( $ds, $search ); + + $return = array(); + foreach( $search as $id => $attrs ) { + if( ! is_array( $attrs ) ) + continue; + for( $i=0; $i<$attrs['count']; $i++ ) + unset( $attrs[$i] ); + $dn = $attrs['dn']; + foreach( $attrs as $attr => $vals ) { + $count = $vals['count']; + unset( $vals['count'] ); + if( $count == 1 ) + $return[$dn][$attr] = $vals[0]; + else + $return[$dn][$attr] = $vals; + } + } + + if( $sort_results ) ksort( $return ); + return $return; + +} + +/* + * Transforms the user-configured lists into arrays and such. This is a little weird, but + * it takes the comma-separated lists (like the search result attribute list) in config.php + * and turns them into arrays. Only call this ONCE per script. Any subsequent call will + * mess up the arrays. This function operates only on global variables defined in config.php. + */ +function process_config() +{ + global $search_result_attributes; + $search_result_attributes = explode( ",", $search_result_attributes ); + array_walk( $search_result_attributes, "trim_it" ); + + global $search_attributes_display; + $search_attributes_display = explode( ",", $search_attributes_display ); + array_walk( $search_attributes_display, "trim_it" ); + + global $search_attributes; + $search_attributes= explode( ",", $search_attributes); + array_walk( $search_attributes, "trim_it" ); + + global $search_criteria_options; + $search_criteria_options= explode( ",", $search_criteria_options); + array_walk( $search_criteria_options, "trim_it" ); +} + +/* + * Call-by-reference to trim a string. Used to filter empty entries out of the arrays + * that we generate in process_config(). + */ +function trim_it( &$str ) +{ + $str = trim($str); +} + +/* + * Checks the server id for sanity. Ensures that the server is indeed in the configured list and active + */ +function check_server_id( $server_id ) +{ + global $servers; + if( ! is_numeric( $server_id ) || ! isset( $servers[$server_id] ) || $servers[$server_id]['host'] == '' ) + return false; + else + return true; +} + +/* + * Used to generate a random salt for crypt-style passwords + * --- added 20021125 by bayu irawan --- + * --- ammended 20030625 by S C Rigler --- + */ +function random_salt( $length ) +{ + $possible = '0123456789'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + './'; + $str = ""; + mt_srand((double)microtime() * 1000000); + while( strlen( $str ) < $length ) + { + $str .= substr( $possible, ( rand() % strlen( $possible ) ), 1 ); + } + /* + * Commented out following line because of problem + * with crypt function in update.php + * --- 20030625 by S C Rigler --- + */ + //$str = "\$1\$".$str."\$"; + return $str; +} + +/* + * Goes through the user-configured server list and looks for an available server_id, + * ie one that has specified enough information to login. This is for choosing the + * server to display in the drop-down box in search.php mostly. + */ +function get_avail_server_id() +{ + global $servers; + + for( $i=0; $i 0 ) { + return $err_codes[ $err_no ]; + } else { + } + + $err_codes_file = 'ldap_error_codes.txt'; + + if( ! file_exists( $err_codes_file ) ) + return false; + if( ! is_readable( $err_codes_file ) ) + return false; + if( ! ($f = fopen( $err_codes_file, 'r' )) ) + return false; + + $contents = fread( $f, filesize( $err_codes_file ) ); + preg_match_all( "/0x[A-Fa-f0-9][A-Za-z0-9]\s+[0-9A-Za-z_]+\s+\"[^\"]*\"\n/", $contents, $entries ); + $err_codes = array(); + foreach( $entries[0] as $e ) + { + preg_match( "/(0x[A-Za-z0-9][A-Za-z0-9])\s+([0-9A-Za-z_]+)\s+\"([^\"]*)\"/", $e, $entry ); + $hex_code = $entry[1]; + $title = $entry[2]; + $desc = $entry[3]; + $desc = preg_replace( "/\s+/", " ", $desc ); + $err_codes[ $hex_code ] = array( 'title' => $title, 'desc' => $desc ); + } + + return $err_codes[ $err_no ]; +} + +/* + * Spits out an HTML-formatted error string. If you specify the optional + * parameters, pla_error will lookup the error number and display a + * verbose message in addition to the message you pass it. + */ +function pla_error( $msg, $ldap_err_msg=null, $ldap_err_no=-1 ) +{ + include_once 'header.php'; + + echo "
"; + echo "
\n\n"; + echo "

Error

\n\n"; + echo "
$msg
"; + echo "

\n"; + + if( $ldap_err_msg ) + echo "LDAP Server Said: " . htmlspecialchars( $ldap_err_msg ) . "

\n"; + + if( $ldap_err_no != -1 ) { + $ldap_err_no = ( '0x' . str_pad( dechex( $ldap_err_no ), 2, 0, STR_PAD_LEFT ) ); + $verbose_error = pla_verbose_error( $ldap_err_no ); + + if( $verbose_error ) { + echo "Error number: $ldap_err_no (" . + $verbose_error['title'] . ")

\n"; + echo "Description: " . $verbose_error['desc'] . "

\n\n"; + } else { + echo "Error number: $ldap_err_no

\n"; + echo "Description: (no description available)
\n\n"; + } + } + + echo "
\n"; + echo "
"; + die(); +} + +/* + * Reads the friendly_attrs array as defined in config.php and lower-cases all + * the keys. Will return an empty array if the friendly_attrs array is not defined + * in config.php. + */ +function process_friendly_attr_table() +{ + require 'config.php'; + global $friendly_attrs; + $attrs_table = array(); + if( isset( $friendly_attrs ) && is_array( $friendly_attrs ) ) + foreach( $friendly_attrs as $old_name => $new_name ) + $attrs_table[ strtolower( $old_name ) ] = $new_name; + else + return array(); + + return $attrs_table; +} + +/* + * Returns true if the specified DN exists on the specified server, or false otherwise + */ +function dn_exists( $server_id, $dn ) +{ + if( ! check_server_id( $server_id ) ) + return false; + + $ds = pla_ldap_connect( $server_id ); + + if( ! $ds ) + return false; + + $search_result = @ldap_read( $ds, $dn, 'objectClass=*', array('dn') ); + + if( ! $search_result ) + return false; + + $num_entries = ldap_count_entries( $ds, $search_result ); + + if( $num_entries > 0 ) + return true; + else + return false; +} + +/* + * Given a DN and server_id, this draws fetches the jpegPhoto binary data and echo's the + * HTML necesary to draw it. You can optionally have it draw the 'delete' button below + * each image. This function supports multiple jpegPhotos. + */ +function draw_jpeg_photos( $server_id, $dn, $draw_delete_buttons=false ) +{ + global $jpeg_temp_dir; + global $jpeg_tmp_keep_time; + + $conn = pla_ldap_connect( $server_id ); + $search_result = ldap_search( $conn, $dn, 'objectClass=*', array( 'jpegPhoto' ) ); + $entry = ldap_first_entry( $conn, $search_result ); + + echo "
\n\n"; + // for each jpegPhoto in the entry, draw it (there may be only one, and that's okay) + $jpeg_data = ldap_get_values_len( $conn, $entry, "jpegphoto"); + for( $i=0; $i<$jpeg_data['count']; $i++ ) + { + $jpeg_filename = $jpeg_temp_dir . '/' . basename( tempnam ('.', 'djp') ); + $outjpeg = fopen($jpeg_filename, "wb"); + fwrite($outjpeg, $jpeg_data[$i]); + fclose ($outjpeg); + $jpeg_data_size = filesize( $jpeg_filename ); + if( $jpeg_data_size < 6 ) { + echo "jpegPhoto contains errors
"; + echo 'Delete Photo'; + continue; + } + + $jpeg_dimensions = getimagesize ($jpeg_filename); + $width = $jpeg_dimensions[0]; + $height = $jpeg_dimensions[1]; + if( $width > 300 ) { + $scale_factor = 300 / $width; + $img_width = 300; + $img_height = $height * $scale_factor; + } else { + $img_width = $width; + $img_height = $height; + } + echo "
\n"; + echo "" . number_format($jpeg_data_size) . " bytes. "; + echo "$width x $height pixels.
\n\n"; + + if( $draw_delete_buttons ) + { ?> + + Delete Photo +
\n\n"; + + // If they have misconfigured their config.php, use default values + if( ! isset( $jpeg_tmp_keep_time ) ) + $jpeg_tmp_keep_time = 120; + + if( $jpeg_tmp_keep_time == 0 ) + $jpeg_tmp_keep_time = 10; + + // delete old jpeg files. + $jpegtmp_wildcard = "djp.*"; + $handle = opendir($jpeg_temp_dir); + while (($file = readdir($handle)) != false) + if (eregi($jpegtmp_wildcard, $file)) + { + $file = "$jpeg_temp_dir/$file"; + if ((time() - filemtime($file)) > $jpeg_tmp_keep_time) + unlink ( $file ); + } + closedir($handle); + +} + +/* + * Returns the root DN of the specified server_id, or false if it + * can't find it (ie, the server won't give it to us). + * Tested with OpenLDAP 2.0, Netscape iPlanet, and Novell eDirectory 8.7 (nldap.com) + * Please report any and all bugs!! + */ +function try_to_get_root_dn( $server_id ) +{ + if( ! have_auth_info( $server_id ) ) + return false; + + $ds = pla_ldap_connect( $server_id ); + if( ! $ds ) + return false; + + $r = @ldap_read( $ds, '', 'objectClass=*', array( 'namingContexts' ) ); + if( ! $r ) + return false; + + $r = @ldap_get_entries( $ds, $r ); + if( isset( $r[0]['namingcontexts'][0] ) ) { + $root_dn = $r[0]['namingcontexts'][0]; + return $root_dn; + } else { + return false; + } +} + +/* + * Hashes a password and returns the hash based on the enc_type, which can be one of + * crypt, md5, sha, or clear. + */ +function password_hash( $password_clear, $enc_type ) +{ + switch( $enc_type ) + { + case 'crypt': + $new_value = '{crypt}' . crypt( $password_clear, random_salt(2) ); + break; + case 'md5': + $new_value = '{md5}' . base64_encode( pack( 'H*' , md5( $password_clear) ) ); + break; + case 'md5crypt': + $new_value = '{crypt}' . crypt( $password_clear , '$1$' . random_salt(9) ); + break; + case 'blowfish': + $new_value = '{crypt}' . crypt( $password_clear , '$2$' . random_salt(13) ); + break; + case 'sha': + if( function_exists( 'mhash' ) ) { + $new_value = '{sha}' . base64_encode( mhash( MHASH_SHA1, $password_clear) ); + } else { + pla_error( "Your PHP install does not have the mhash() function." . + " Cannot do SHA hashes." ); + } + break; + case 'clear': + default: + $new_value = $password_clear; + } + + return $new_value; +} + +/* + * Returns the version as a string as stored in the VERSION file. + */ +function pla_version() +{ + if( ! file_exists( 'VERSION' ) ) + return 'unknown version'; + + $f = fopen( 'VERSION', 'r' ); + $version = fread( $f, filesize( 'VERSION' ) ); + fclose( $f ); + return $version; +} + +function draw_chooser_link( $form_element ) +{ + $href = "javascript:dnChooserPopup('$form_element');"; + echo ""; + echo "browse\n"; +} + +?> diff --git a/header.php b/header.php new file mode 100644 index 0000000..4f79c7e --- /dev/null +++ b/header.php @@ -0,0 +1,11 @@ +\n"; ?> + + + + + phpLDAPAdmin + + + diff --git a/images/bug.png b/images/bug.png new file mode 100644 index 0000000..132f93f Binary files /dev/null and b/images/bug.png differ diff --git a/images/children.png b/images/children.png new file mode 100644 index 0000000..e3495eb Binary files /dev/null and b/images/children.png differ diff --git a/images/country.png b/images/country.png new file mode 100644 index 0000000..7640da3 Binary files /dev/null and b/images/country.png differ diff --git a/images/cut.png b/images/cut.png new file mode 100644 index 0000000..3c21b9b Binary files /dev/null and b/images/cut.png differ diff --git a/images/dc.png b/images/dc.png new file mode 100644 index 0000000..2769a47 Binary files /dev/null and b/images/dc.png differ diff --git a/images/find.png b/images/find.png new file mode 100644 index 0000000..ed5c07e Binary files /dev/null and b/images/find.png differ diff --git a/images/folder.png b/images/folder.png new file mode 100644 index 0000000..cce6d34 Binary files /dev/null and b/images/folder.png differ diff --git a/images/light.png b/images/light.png new file mode 100644 index 0000000..8859899 Binary files /dev/null and b/images/light.png differ diff --git a/images/locality.png b/images/locality.png new file mode 100644 index 0000000..c80540b Binary files /dev/null and b/images/locality.png differ diff --git a/images/lock.png b/images/lock.png new file mode 100644 index 0000000..ff35893 Binary files /dev/null and b/images/lock.png differ diff --git a/images/mail.png b/images/mail.png new file mode 100644 index 0000000..bd77aff Binary files /dev/null and b/images/mail.png differ diff --git a/images/minus.png b/images/minus.png new file mode 100644 index 0000000..6ff9066 Binary files /dev/null and b/images/minus.png differ diff --git a/images/move.png b/images/move.png new file mode 100644 index 0000000..9542d51 Binary files /dev/null and b/images/move.png differ diff --git a/images/o.png b/images/o.png new file mode 100644 index 0000000..dfb89eb Binary files /dev/null and b/images/o.png differ diff --git a/images/object.png b/images/object.png new file mode 100644 index 0000000..a77ff35 Binary files /dev/null and b/images/object.png differ diff --git a/images/ou.png b/images/ou.png new file mode 100644 index 0000000..3e767c7 Binary files /dev/null and b/images/ou.png differ diff --git a/images/phone.png b/images/phone.png new file mode 100644 index 0000000..f319d1a Binary files /dev/null and b/images/phone.png differ diff --git a/images/photo.png b/images/photo.png new file mode 100644 index 0000000..f957404 Binary files /dev/null and b/images/photo.png differ diff --git a/images/plus.png b/images/plus.png new file mode 100644 index 0000000..f66b1a8 Binary files /dev/null and b/images/plus.png differ diff --git a/images/refresh.png b/images/refresh.png new file mode 100644 index 0000000..05fb5f3 Binary files /dev/null and b/images/refresh.png differ diff --git a/images/save.png b/images/save.png new file mode 100644 index 0000000..a7811a4 Binary files /dev/null and b/images/save.png differ diff --git a/images/server.png b/images/server.png new file mode 100644 index 0000000..4f6c2a4 Binary files /dev/null and b/images/server.png differ diff --git a/images/star.png b/images/star.png new file mode 100644 index 0000000..458c730 Binary files /dev/null and b/images/star.png differ diff --git a/images/terminal.png b/images/terminal.png new file mode 100644 index 0000000..8f07296 Binary files /dev/null and b/images/terminal.png differ diff --git a/images/trash.png b/images/trash.png new file mode 100644 index 0000000..d88ddbb Binary files /dev/null and b/images/trash.png differ diff --git a/images/uid.png b/images/uid.png new file mode 100644 index 0000000..7be48fb Binary files /dev/null and b/images/uid.png differ diff --git a/images/up.png b/images/up.png new file mode 100644 index 0000000..865ec15 Binary files /dev/null and b/images/up.png differ diff --git a/images/user.png b/images/user.png new file mode 100644 index 0000000..647e429 Binary files /dev/null and b/images/user.png differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..008a941 --- /dev/null +++ b/index.php @@ -0,0 +1,161 @@ + + + + + + + + + phpLDAPAdmin - <?php echo pla_version(); ?> + + + + +

Configure phpLDAPAdmin

+
+
+
+You need to configure phpLDAPAdmin. Edit the file 'config.php' to do so.
+
+An example config file is provided in 'config.php.example' + +
+ + + +\n"; + +?> + + + +phpLDAPAdmin - <?php echo pla_version(); ?> + + + + + + + + + + + + + + + + + phpLDAPAdmin Config File Error + + + + +

Config file error

+

Syntax error on line

+ +
+ Looks like your config file has a syntax error on line . + Here is a snippet around that line +
+
+
+ + "; + if( $i < 0 ) + continue; + echo "" . ($i+1) . ": " . htmlspecialchars($file[ $i ]) . "
"; + if( $i+1 == $line_num ) + echo "
"; + } + ?> + + +
+ Hint: Sometimes these errors are caused by lines preceding the line reported. + + + + $server ) + if( $server['host'] ) + $count++; + if( $count == 0 ) + { + echo "None of the " . count($servers) . " servers in your \$servers array is "; + echo "active in config.php. phpLDAPAdmin cannot proceed util you correct this."; + return false; + } + + return true; +} + +?> diff --git a/ldap_error_codes.txt b/ldap_error_codes.txt new file mode 100644 index 0000000..4cec107 --- /dev/null +++ b/ldap_error_codes.txt @@ -0,0 +1,85 @@ +0x00 LDAP_SUCCESS "The operation completed successfully." +0x01 LDAP_OPERATIONS_ERROR "An operations error occurred." +0x02 LDAP_PROTOCOL_ERROR "A protocol violation was detected." +0x03 LDAP_TIMELIMIT_EXCEEDED "The operation timed out waiting to complete." +0x04 LDAP_SIZELIMIT_EXCEEDED "The LDAP sever refused to serve such a large result set." +0x05 LDAP_COMPARE_FALSE "A compare operation returned false." +0x06 LDAP_COMPARE_TRUE "A compare operation returned true." +0x07 LDAP_AUTH_METHOD_NOT_SUPPORTED "The authentication method you specified is not supported by + the LDAP server." +0x08 LDAP_STRONG_AUTH_REQUIRED "This LDAP server requires strong (encrypted) authentication, + not clear text." +0x09 LDAP_PARTIAL_RESULTS "The result set received is a partial result set." +0x0a LDAP_REFERRAL "" +0x0b LDAP_ADMINLIMIT_EXCEEDED "" +0x0c LDAP_UNAVAILABLE_CRITICAL_EXTENSION "" +0x0d LDAP_CONFIDENTIALITY_REQUIRED "" +0x0e LDAP_SASL_BIND_INPROGRESS "" +0x10 LDAP_NO_SUCH_ATTRIBUTE "That entry does not contain the attribute specified." +0x11 LDAP_UNDEFINED_TYPE "The attribute type specified is invalid." +0x12 LDAP_INAPPROPRIATE_MATCHING "This usually means that your LDAP server has not defined an equality rule + for the attribute you are trying to alter. This is not phpLDAPAdmin's fault as the + LDAP server has refused to perform the operation (as well it should if there is + no equality rule for it to use for the operation)." +0x13 LDAP_CONSTRAINT_VIOLATION "Some constraint would be violated by performing the action. This can happen when + you try to add a second value to a single-valued attribute, for example." +0x14 LDAP_TYPE_OR_VALUE_EXISTS "An attribute type or attribute value + specified already exists in the entry" +0x15 LDAP_INVALID_SYNTAX "An invalid attribute value was specified." +0x20 LDAP_NO_SUCH_OBJECT "That object does not exist." +0x21 LDAP_ALIAS_PROBLEM "An alias in the directory points to a + non-existent entry." +0x22 LDAP_INVALID_DN_SYNTAX "You used an invalid syntax in the specified DN." +0x23 LDAP_IS_LEAF "The object specified is a leaf" +0x24 LDAP_ALIAS_DEREF_PROBLEM "A problem was encountereed when + dereferencing an alias" +0x30 LDAP_INAPPROPRIATE_AUTH "Inappropriate authentication was + specifiedi (e.g., LDAP_AUTH_SIMPLE was + specified and the entry does not have + a userPassword attribute)." +0x31 LDAP_INVALID_CREDENTIALS "Incorrect login DN and/or password." +0x32 LDAP_INSUFFICIENT_ACCESS "You do not have sufficient permissions + to perform that operation." +0x33 LDAP_BUSY "The LDAP server is busy." +0x34 LDAP_UNAVAILABLE "The LDAP server is unavailable." +0x35 LDAP_UNWILLING_TO_PERFORM "The LDAP server refused to perform the operation." +0x36 LDAP_LOOP_DETECT "A loop was detected." +0x3C LDAP_SORT_CONTROL_MISSING "" +0x3D LDAP_INDEX_RANGE_ERROR "" +0x40 LDAP_NAMING_VIOLATION "A naming violation occurred." +0x41 LDAP_OBJECT_CLASS_VIOLATION "You tried to perform an operation that would cause an undefined attribute + to exist or that would remove a required attribute, given the current list + of ObjectClasses." +0x42 LDAP_NOT_ALLOWED_ON_NONLEAF "The entry you tried to operate on has children. (usually this means you + tried to delete the entry, which you cannot do to an entry with children)." +0x43 LDAP_NOT_ALLOWED_ON_RDN "You cannot preform that operation on a the relative distinguished name + (RDN) of an object." +0x44 LDAP_ALREADY_EXISTS "The object already exists (usually you are trying to create a new object + on top of an existing one)" +0x45 LDAP_NO_OBJECT_CLASS_MODS "ObjectClass modifications are not + allolwed." +0x46 LDAP_RESULTS_TOO_LARGE "" +0x47 LDAP_AFFECTS_MULTIPLE_DSAS "" +0x50 LDAP_OTHER "" +0x51 LDAP_SERVER_DOWN "The LDAP server is down." +0x52 LDAP_LOCAL_ERROR "" +0x53 LDAP_ENCODING_ERROR "" +0x54 LDAP_DECODING_ERROR "" +0x55 LDAP_TIMEOUT "" +0x56 LDAP_AUTH_UNKNOWN "" +0x57 LDAP_FILTER_ERROR "The LDAP search filter specified is inavlid." +0x58 LDAP_USER_CANCELLED "The user cancelled the LDAP operation." +0x59 LDAP_PARAM_ERROR "An ldap routine was called with a bad + parameter." +0x5a LDAP_NO_MEMORY "An memory allocation (e.g., malloc(3) + or other dynamic memory allocator) + call failed in an ldap library rou- + tine." +0x5b LDAP_CONNECT_ERROR "" +0x5c LDAP_NOT_SUPPORTED "The requested operation is not supported by the LDAP server." +0x5d LDAP_CONTROL_NOT_FOUND "" +0x5e LDAP_NO_RESULTS_RETURNED "The search came back empty." +0x5f LDAP_MORE_RESULTS_TO_RETURN "The LDAP server has more results that it would like to return." +0x60 LDAP_CLIENT_LOOP "" +0x61 LDAP_REFERRAL_LIMIT_EXCEEDED "This means that a search was performed that required the LDAP + server to follow a chain of referrals that was too lengthy." diff --git a/ldif_export.php b/ldif_export.php new file mode 100644 index 0000000..6c30fdc --- /dev/null +++ b/ldif_export.php @@ -0,0 +1,93 @@ +"; +//print_r( $objects ); +//exit; + +$rdn = get_rdn( $dn ); + +switch( $format ) { + case 'win': $br = "\r\n"; break; + case 'mac': $br = "\r"; break; + case 'unix': + default: $br = "\n"; break; +} + +if( ! $objects ) + pla_error( "Search on dn (" . htmlspecialchars($dn) . ") came back empty" ); + +header( "Content-type: text/plain" ); +header( "Content-disposition: attachment; filename=\"$rdn.ldif\"" ); +header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" ); +header( "Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT" ); +header( "Cache-Control: post-check=0, pre-check=0", false ); +header( "Pragma: no-cache" ); + +echo "version: 1$br$br"; +echo "# LDIF Export for: $rdn$br"; +echo "# Scope: $scope, " . count( $objects ) . " entries$br"; +echo "# Generated by phpLDAPAdmin on " . date("F j, Y g:i a") . "$br"; +echo $br; + +foreach( $objects as $dn => $attrs ) +{ + unset( $attrs['dn'] ); + unset( $attrs['count'] ); + + if( is_safe_ascii( $dn ) ) + echo "dn: $dn$br"; + else + echo "dn:: " . base64_encode( $dn ) . $br; + + foreach( $attrs as $attr => $val ) { + if( is_array( $val ) ) { + foreach( $val as $v ) { + if( is_safe_ascii( $v ) ) { + echo "$attr: $v$br"; + } else { + echo "$attr:: " . base64_encode( $v ) . $br; + } + } + } else { + $v = $val; + if( is_safe_ascii( $v ) ) { + echo "$attr: $v$br"; + } else { + echo "$attr:: " . base64_encode( $v ) . $br; + } + } + } + echo $br; +} + +function is_safe_ascii( $str ) +{ + for( $i=0; $i 127 ) + return false; + return true; +} diff --git a/login.php b/login.php new file mode 100644 index 0000000..2c80ae0 --- /dev/null +++ b/login.php @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + Redirecting... Click here if nothing happens.
+ + + +
+
+
+ Logged in to
+ + (anonymous bind) + +
+
+
+ Click here to go to the search form. +
+ + + + + + diff --git a/login_form.php b/login_form.php new file mode 100644 index 0000000..e09eec6 --- /dev/null +++ b/login_form.php @@ -0,0 +1,79 @@ + + + + + + + +
+

Authenticate to server

+
+ + + +Warning: this is an insecure (non-SSL) connection!
+ SSL is recommended when transmitting sensitive passwords.
+
+ + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + +
diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..86f0fc7 --- /dev/null +++ b/logout.php @@ -0,0 +1,54 @@ + + + + + + + + + + +
+
+
+ Logged out successfully from
+
+ + + + diff --git a/new_attr.php b/new_attr.php new file mode 100644 index 0000000..f9d36fb --- /dev/null +++ b/new_attr.php @@ -0,0 +1,46 @@ + $val ); +$result = @ldap_mod_add( $ds, $dn, $new_entry ); + +if( $result ) + header( "Location: edit.php?server_id=$server_id&dn=$encoded_dn&updated_attr=$encoded_attr" ); +else + pla_error( "Failed to add the attribute.", ldap_error( $ds ) , ldap_errno( $ds ) ); diff --git a/new_jpeg_photo_form.php b/new_jpeg_photo_form.php new file mode 100644 index 0000000..a97598f --- /dev/null +++ b/new_jpeg_photo_form.php @@ -0,0 +1,46 @@ + + + + +

Add a jpegPhoto to

+

Server2:     Distinguished Name: +

+ + +Select a jpeg file:
+
+ +
+ + + +
+
+ +
+ + + + diff --git a/rdelete.php b/rdelete.php new file mode 100644 index 0000000..6e78aa0 --- /dev/null +++ b/rdelete.php @@ -0,0 +1,113 @@ +\n"; +echo "

Deleting" . htmlspecialchars( $dn) . "

\n"; +echo "

Recursive delete progress

\n"; +echo "

"; +echo "\n"; +flush(); + +// prevent script from bailing early on a long delete +@set_time_limit( 0 ); + +$del_result = pla_rdelete( $server_id, $dn ); +echo "
\n"; +if( $del_result ) +{ + // kill the DN from the tree browser session variable and + // refresh the tree viewer frame (left_frame) + + if( session_is_registered( 'tree' ) ) + { + $tree = $_SESSION['tree']; + + // does it have children? (it shouldn't, but hey, you never know) + if( isset( $tree[$server_id][$dn] ) ) + unset( $tree[$server_id][$dn] ); + + // search and destroy + foreach( $tree[$server_id] as $tree_dn => $subtree ) + foreach( $subtree as $key => $sub_tree_dn ) + if( 0 == strcasecmp( $sub_tree_dn, $dn ) ) + unset( $tree[$server_id][$tree_dn][$key] ); + } + + $_SESSION['tree'] = $tree; + session_write_close(); + + ?> + + + + Object and sub-tree deleted successfully. + + Deleting " . htmlspecialchars( utf8_decode( $dn ) ) . "..."; + flush(); + if( ldap_delete( $ds, $dn ) ) { + echo " Success
\n"; + return true; + } else { + pla_error( "Failed to delete dn: " . htmlspecialchars( utf8_decode( $dn ) ), + ldap_error( $ds ), ldap_errno( $ds ) ); + } + } else { + foreach( $children as $child_dn ) { + pla_rdelete( $server_id, $child_dn ); + } + echo "Deleting " . htmlspecialchars( utf8_decode( $dn ) ) . "..."; + flush(); + if( ldap_delete( $ds, $dn ) ) { + echo " Success
\n"; + return true; + } else { + pla_errror( "Failed to delete dn: " . htmlspecialchars( utf8_decode( $dn ) ), + ldap_error( $ds ), ldap_errno( $ds ) ); + } + } + +} diff --git a/refresh.php b/refresh.php new file mode 100644 index 0000000..b446218 --- /dev/null +++ b/refresh.php @@ -0,0 +1,54 @@ + $children ) + { + $tree[$server_id][$dn] = get_container_contents( $server_id, $dn ); + foreach( $tree[$server_id][$dn] as $child_dn ) + $tree_icons[$server_id][$child_dn] = get_icon( $server_id, $child_dn ); + sort( $tree[ $server_id ][ $dn ] ); + } +} +else +{ + header( "Location: tree.php#$server_id" ); +} + +$_SESSION['tree'] = $tree; +$_SESSION['tree_icons'] = $tree_icons; +session_write_close(); + +header( "Location: tree.php#$server_id" ); + + +?> diff --git a/rename.php b/rename.php new file mode 100644 index 0000000..095cd64 --- /dev/null +++ b/rename.php @@ -0,0 +1,91 @@ + $children ) { + foreach( $children as $i => $child_dn ) { + if( 0 == strcasecmp( $child_dn, $old_dn ) ) { + $tree[$server_id][$parent_dn][$i] = $new_dn; + } + } + } + // Update the icon tree to reflect the change (remove the old DN and add the new one) + $tree_icons[ $server_id ][ $new_dn ] = $tree_icons[ $server_id ][ $old_dn ]; + unset( $tree_icons[ $server_id ][ $old_dn ] ); + + $_SESSION['tree'] = $tree; + $_SESSION['tree_icons'] = $tree_icons; + session_write_close(); + + $edit_url="edit.php?server_id=$server_id&dn=" . rawurlencode( "$new_rdn,$container" ); + + ?> + + + + + + + + + + + Redirecting... click here if you're impatient. + + + + + + + +" . htmlspecialchars($servers[$server_id]['name']) . ".
+
+ This could happen for several reasons, the most probable of which are: +
    +
  • The server does not fully support the LDAP protocol.
  • +
  • Your version of PHP does not correctly perform the query.
  • +
  • Or lastly, phpLDAPAdmin doesn't know how to fetch the schema for your server.
  • +
+ Please report this + as a bug. + " ); + +} else { ?> + +

Schema for server

+ +
+
+ objectClasses' ); ?> + | + Syntaxes' ); ?> + | + Attributes' ); ?> + | + Matching Rules' ); ?> +
+
+ + + + + '; print_r( $schema['attrs'] ); + ?> + +
+ Attribute definition for

+ + + $val ) + { + if( $key != 'val' && $val != null ) { + $counter++; + echo "\n"; + } + } + } + else + pla_error( "Bad schema entry for attribute: " . htmlspecialchars( $attr ) ); + + ?> + +
$key$val
+
+ + The following syntaxes are supported by this LDAP server

\n\n"; + echo "\n\n\n"; + echo "\n"; + $counter=1; + foreach( get_schema_syntaxes( $server_id ) as $oid => $desc ) { + $counter++; + $oid = htmlspecialchars( $oid ); + $desc = htmlspecialchars( $desc['description'] ); + echo "\n"; + } + echo "
Syntax OIDDescription
$oid$desc
\n"; + + } elseif( $view == 'attributes' ) { + echo "
The following attributes are supported by this LDAP server

\n\n"; + echo "\n"; + foreach( get_schema_attributes( $server_id ) as $attr ) { + echo "\n"; + $counter = 0; + foreach( $attr as $key => $val ) + { + if( $key != 'val' && $val != null ) { + $counter++; + echo ""; + echo "\n"; + } + } + } + echo "
" . $attr['name'] . "
$key$val
\n"; + } elseif( $view == 'matching_rules' ) { + echo "
The following matching rules are supported by this LDAP server

\n\n"; + echo "\n\n\n"; + echo "\n"; + $counter=1; + foreach( get_schema_matching_rules( $server_id ) as $oid => $attr ) { + $counter++; + $oid = htmlspecialchars( $oid ); + $desc = htmlspecialchars( $attr ); + echo "\n"; + } + echo "
Matching Rule OIDDescription
$oid$attr
\n"; + + + + } else { ?> + + Jump to an objectClass: + +
+ + $attrs ) { ?> + + [top] +

objectClass

+

OID

+ +

Description

+ +

Inherits

+
+ + + + + + + + + +
Required AttributesOptional Attributes
+ 0 ) { + echo ' + + 0 ) { + echo ' +
+ + + + + + + + diff --git a/search.php b/search.php new file mode 100644 index 0000000..e264bbc --- /dev/null +++ b/search.php @@ -0,0 +1,212 @@ +'; +$js_dn_list = ''; +foreach( $servers as $id => $server ) { + $base_dn = $server['base'] ? $server['base'] : try_to_get_root_dn( $id ); + $js_dn_list .= '"' . $server['base'] . '",'; + if( $server['host'] ) { + $server_menu_html .= ''; + } +} +// trim off the trailing comma +$js_dn_list = substr( $js_dn_list, 0, strlen($js_dn_list)-1 ); +$server_menu_html .= ''; + +$filter = stripslashes( $_GET['filter'] ); +$filter = utf8_encode($filter); +$attr = stripslashes( $_GET['attribute'] ); + +// grab the base dn for the search +if( isset( $_GET['base_dn'] ) ) + $base_dn = $_GET['base_dn']; +elseif( '' != $servers[$server_id]['base'] ) + $base_dn = $servers[$server_id]['base']; +else + $base_dn = try_to_get_root_dn( $server_id ); + +$criterion = stripslashes( $_GET['criterion'] ); +$form = stripslashes( $_GET['form'] ); +$scope = $_GET['scope'] ? $_GET['scope'] : 'sub'; +//echo "
";print_r( $_GET );echo "
"; +?> + + + + +
+ + + +
+ + + + +
+
+ You haven't logged into server + yet. Go to the login form to do so. +
+ + +
+
Found . + + +
Filter performed:
+ + +
+ + + + $attrs ) { ?> + + +
+ + + +
+ + + + + + + + + +
+ + +
+ + + + +
+ + + +

+
Search happily performed by phpLDAPAdmin in + seconds.
+ + + + + + diff --git a/search_form_advanced.php b/search_form_advanced.php new file mode 100644 index 0000000..230d63a --- /dev/null +++ b/search_form_advanced.php @@ -0,0 +1,50 @@ + + + diff --git a/search_form_simple.php b/search_form_simple.php new file mode 100644 index 0000000..3a23006 --- /dev/null +++ b/search_form_simple.php @@ -0,0 +1,42 @@ + + diff --git a/server_info.php b/server_info.php new file mode 100644 index 0000000..af4762f --- /dev/null +++ b/server_info.php @@ -0,0 +1,49 @@ +"; print_r( $attrs ); echo "
"; + +include 'header.php'; +?> + +

Server info for

+

Server reports the following information about itself

+ + + +

This server has nothing to report.
+ + + + + +
"; + echo htmlspecialchars($attr) . ""; + for( $j=0; $j<$attrs[ $attr ][ 'count' ]; $j++ ) + echo htmlspecialchars( $attrs[ $attr ][ $j ] ) . "
\n"; +} +?> + +
diff --git a/style.css b/style.css new file mode 100644 index 0000000..6303a18 --- /dev/null +++ b/style.css @@ -0,0 +1,360 @@ +table.schema_oclasses td { + vertical-align: top; + text-align: left; +} + +table.schema_attr th { + background-color: #016; + padding: 5px; + color: white; + font-weight: normal; +} + +table.schema_attr td { + padding: 5px; +} + +table.schema_attr tr.even { + background-color: #eee; +} + +table.schema_attr tr.odd { + background-color: #ccc; +} + +div.error { + background-color: #eec; + border: solid black 1px; + padding: 15px; + padding-top: 0px; + width: 380px; + text-align: left; +} + +table.confirm th { + background-color: #016; + padding: 5px; + color: white; + font-weight: normal; +} + +table.confirm tr.spacer { + background-color: #ddd; +} + +table.confirm tr.even { + background-color: #ccc; +} + +table.confirm tr.odd{ + background-color: #eee; +} + +table.confirm tr td { + padding: 4px; + vertical-align: top; +} + +table.confirm tr td.heading { + font-size: 75%; +} + +table.templates tr td { + text-align: left; + vertical-align: center; +} + +table.templates tr { + height: 25px; +} + + +a img { + border: 0px; +} + +body { + font-family: arial, helvetica, sans-serif; + background-color: white; + font-size: 12pt; +} + +table.tree { + border: 0px; +} + +table.tree img { + border: 0px; +} + +table.tree td { + padding: 2px; + border: 0px solid black; +} + +table.tree tr { +} + +table.tree tr.server { + vertical-align: top; +} + +table.tree td.icon { + text-align: center; + padding: 0px; + width: 22px; +} + +table.tree td.rdn a { + text-decoration: none; + color: black; +} + +table.tree td.rdn a:hover { + text-decoration: underline; + color: blue; +} + +table.tree td.create a { + text-decoration: none; + color: black; +} + +table.tree td.create a:hover { + text-decoration: underline; + color: blue; +} + + +table.tree td.spacer { + width: 22px; +} + +table.tree td.expander { + text-align: center; + width: 22px; + min-width: 22px; +} + +table.tree td span.count { + color: gray; + font-size: 85%; +} + +h3.title { + text-align: center; + margin: 0px; + padding: 10px; + color: white; + background-color: #018; + border: 1px solid black; + font-weight: normal; + font-size: 150%; +} + +h3.subtitle { + text-align: center; + margin: 0px; + margin-bottom: 15px; + font-size: 75%; + color: white; + border-bottom: 1px solid black; + border-left: 1px solid black; + border-right: 1px solid black; + background: #018; + padding: 4px; + font-weight: normal; +} + +table.edit_dn tr.spacer td { + height: 20px; +} + +table.edit_dn { + width: 100%; +} + +table.edit_dn th { + background: #777; + color: white; + font-weight: normal; + font-size: 125%; + padding: 5px; +} + +table.edit_dn tr td { + padding: 4px; +} + +table.edit_dn tr td.attr { + vertical-align: top; +} + +table.edit_dn tr td.heading { + border-top: 3px solid #ccc; + font-weight: bold; +} + +table.edit_dn tr td.val { + text-align: right; + vertical-align: center; +} + +table.edit_dn tr.updated_attr { + background: #def; +} + +table.edit_dn tr.updated_attr td { + border-top: 1px solid black; + border-bottom: 1px solid black; + color: #005; +} + +table.edit_dn tr.updated_attr a { +} + +table.edit_dn tr.mod_dn { + background: #def; +} + +table.edit_dn tr.row1 { + background: #eee; +} + +table.edit_dn tr.row2 { + background: #ccc; +} + +input.update_dn { + font-size: 65%; +} + +small { + font-size: 10pt; +} + +form.edit_dn { + margin: 0px; + padding: 0px; +} + +h4.oclass { + background: #88b; + padding: 5px; + margin: 0px; + margin-top: 8px; + font-weight: normal; + border: 1px solid black; + font-size: 140%; + color: white; +} + +h4.oclass_sub { + background: #dde; + border: 1px solid black; + border-top: 0px; + font-weight: normal; + margin: 0px; + padding: 2px; + padding-left: 5px; + font-size: 80%; +} + +ul.schema { + margin: 5px; +} + +ul.schema li { + margin-left: 10px; +} + +ul.current_values { + padding: 5px; + padding-left: 25px; + width: 200px; + margin-left: 50px; +} + +form.new_value { + margin-left: 70px; +} + +ul.search { + font-weight: bold; +} + +div.search_result { + list-style-type: none; + background: #ffb; + padding: 6px; + padding-left: 10px; + margin-right: 40px; +} + +table.attrs { + font-weight: normal; + font-size: 75%; + margin: 0px; +} + +table.attrs td { + padding-right: 10px; +} + +table.attrs td.attr { + color: #aaa; + padding-left: 15px; +} + +form.search { + width: 500px; + background-color: #ddf; + padding: 5px; +} + +table.edit_dn_menu { + font-size: 75%; +} + +input.scary { + background: red; + font-weight: bold; + color: white; +} + +input.cancel { + padding-left: 10px; + padding-right: 10px; + font-weight: bold; +} + +input.happy { + background: green; + font-weight: bold; + color: white; +} + +table.delete_confirm { + width: 76%; + background-color: #ddf; + padding: 20px; + text-align: left; +} + +table.login { + background-color: #ddf; + padding: 10px; +} + +table.login td { + padding: 5px; +} + +table.create { + font-size: 75%; +} + +table.create td.heading { + vertical-align: top; + padding: 10px; +} diff --git a/templates/creation/custom.php b/templates/creation/custom.php new file mode 100644 index 0000000..68de800 --- /dev/null +++ b/templates/creation/custom.php @@ -0,0 +1,186 @@ + + +

Step 1 of 2: Name and ObjectClass(es)

+ +
+ + + + + + + + + + + + + + + + + + + + + +
RDN: (example: cn=MyNewObject)
Container: +
ObjectClass(es): + +
+
+ + $attr_display\n"; + } + + // add the required attribute based on the RDN provided by the user + // (ie, if the user specifies "cn=Bob" for their RDN, make sure "cn" is + // in the list of required attributes. + $rdn_attr = trim( substr( $rdn, 0, strpos( $rdn, '=' ) ) ); + $rdn_value = trim( substr( $rdn, strpos( $rdn, '=' ) + 1 ) ); + if( ! in_array( $rdn_attr, $required_attrs ) ) + $required_attrs[] = $rdn_attr; + + ?> + + +

Step 2 of 2: Specify attributes and values

+ + + + + + + +
+ Creating entry with DN: + + Instrucions: Enter values for the + required attributes. Then create any optional attributes. You + can specify multi-valued attributes as well.
+
+ +
+ + + + + + + + + + $attr ) { ?> + + + + + + + + + + + + + + + + + + + + +
Required Attributes
" . + htmlspecialchars( $friendly_attrs[ strtolower( $attr ) ] ) . ""; + } else { + $attr_display = htmlspecialchars( $attr ); + } + + echo $attr_display; + + ?> +
Optional Attributes
+
+ +
+ +
+ + + diff --git a/templates/creation/new_address_template.php b/templates/creation/new_address_template.php new file mode 100755 index 0000000..681e420 --- /dev/null +++ b/templates/creation/new_address_template.php @@ -0,0 +1,210 @@ + + + + +

New Address Book Entry
+(InetOrgPerson)

+
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name: + + +
Common name:
Organization:
Address:
City:
Postal code:
Work phone:
Fax:
Mobile:
Email:
Container: +

+
+ + +

Confirm entry creation:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + +
Common name:
First name:
Last name:
Organization:
City:
Postal code:
Street:
Work phone:
Fax:
Mobile:
Email:
Container:
+
+
+ + diff --git a/templates/creation/new_dns_entry.php b/templates/creation/new_dns_entry.php new file mode 100755 index 0000000..ec9689f --- /dev/null +++ b/templates/creation/new_dns_entry.php @@ -0,0 +1,91 @@ + + +

New DNS Entry

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
DC Name: (hint: don't include "dc=")
Associated Domain:
Container DN: +

+
+ + + + + + + + + + + + + + + + + + +
+ Really create this new DC entry?
+
+ + + + + +
Name
Domain
Container
+
+
+ + diff --git a/templates/creation/new_nt_machine.php b/templates/creation/new_nt_machine.php new file mode 100644 index 0000000..dc6fc7e --- /dev/null +++ b/templates/creation/new_nt_machine.php @@ -0,0 +1,128 @@ + + +

New Samba NT Machine

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Machine Name: (hint: don't include "$" at the end)
UID Number:
Container: +

+





+ This will create a new NT machine with:
+ +
    +
  • gidNumber
  • +
  • acctFlags
  • +
  • cn
  • +
  • in container
  • +
+ To change these values, edit the template file: + templates/creation/new_nt_machine.php
+ Note: You must have the samba schema installed on your LDAP server. +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Realy create this new Samba machine?
+
+ + + + +
Name
UID
Container
+
+
+ + diff --git a/templates/creation/new_ou_template.php b/templates/creation/new_ou_template.php new file mode 100644 index 0000000..c7f572c --- /dev/null +++ b/templates/creation/new_ou_template.php @@ -0,0 +1,84 @@ + + +

New Organizational Unit

+ + + + + + + + +
+ + + + + + + + + + + + + + + +
OU Name: (hint: don't include "ou=")
Container DN: +

+
+ + + + + + + + + + + + + + + + +
+ Really create this new OU?
+
+ + + + +
Name
Container
+
+
+ + + diff --git a/templates/creation/new_user_template.php b/templates/creation/new_user_template.php new file mode 100644 index 0000000..d2845f1 --- /dev/null +++ b/templates/creation/new_user_template.php @@ -0,0 +1,242 @@ + + + + +

New User Account

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
First name:
Last name:
User name:
Password:
Password:
Encryption:
Login Shell: + +
Container: +
UID Number:
Group:
Home Directory:

+
+ + +

Confirm account creation:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
User name:
First name:
Last name:
Password:[secret]
Login Shell:
UID Number:
GID Number:
Container:
Home dir:
+
+
+ + diff --git a/tree.php b/tree.php new file mode 100644 index 0000000..c45093c --- /dev/null +++ b/tree.php @@ -0,0 +1,281 @@ +_, so if I wanted to scroll to + * dc=example,dc=com for server 3, the URL would be: + * tree.php#3_dc%3Dexample%2Cdc%3Dcom + */ + +require 'config.php'; +require_once 'functions.php'; + +// no expire header stuff +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +// The entire visible tree is stored in the session. +session_start(); + +// do we not have a tree yet? Build a new one. +if( ! session_is_registered( 'tree' ) ) { + session_register( 'tree' ); + $_SESSION['tree'] = build_initial_tree(); + session_register( 'tree_icons' ); + $_SESSION['tree_icons'] = build_initial_tree_icons(); +} + +// grab the tree out of the session variable +$tree = $_SESSION['tree']; +$tree_icons = $_SESSION['tree_icons']; +?> + + + + + + + +

phpLDAPAdmin -

+ + + + + + + + + +
Request a new feature + (see open requests)
Report a bug + (see open bugs)
+
+ + + $server_tree ) { + + if( $servers[$server_id]['host'] != '' ) { + + $server_name = $servers[$server_id]['name']; + echo ''; + echo ''; + echo ''; + + $rdn = utf8_decode( $dn ); + if( null == $servers[ $server_id ]['base'] ) { + $base_dn = try_to_get_root_dn( $server_id ); + } else { + $base_dn = $servers[ $server_id ]['base']; + } + + // Did we get a base_dn for this server somehow? + if( $base_dn ) { + // is the root of the tree expanded already? + if( isset( $tree[$server_id][$base_dn] ) ) { + $expand_href = "collapse.php?server_id=$server_id&" . + "dn=" . rawurlencode( $base_dn ); + $expand_img = "images/minus.png"; + } else { + $expand_href = "expand.php?server_id=$server_id&" . + "dn=" . rawurlencode( $base_dn ); + $expand_img = "images/plus.png"; + } + + $edit_href = "edit.php?server_id=$server_id&dn=" . rawurlencode( $base_dn ); + + $icon = get_icon( $server_id, $base_dn ); + echo "\n"; + echo ""; + echo "\n"; + echo "\n"; + echo "\n"; + } else { + if( "" === $base_dn || null === $base_dn ) { + // The server refuses to give out the base dn + echo ""; + // Proceed to the next server. We cannot draw anything else for this server. + continue; + } else { + // For some unknown reason, we couldn't determine the base dn + echo ""; + // Proceed to the next server. We cannot draw anything else for this server. + continue; + } + } + + flush(); + + // Is the root of the tree expanded already? + if( isset( $tree[$server_id][$base_dn] ) ) { + foreach( $tree[ $server_id ][ $base_dn ] as $child_dn ) + draw_tree_html( $child_dn, $server_id, 1 ); + echo ''; + echo ''; + echo ''; + echo ''; + } + } + else // have_auth_info() returned false. + { + // We don't have enough information to login to this server + $login_href = "login_form.php?server_id=$server_id"; + echo '   '; + echo 'login '; + echo 'login...'; + echo ''; + } + + } +} + +?> + +
server' . htmlspecialchars( $server_name ) . '
'; + + + // do we have what it takes to authenticate here, or do we need to + // present the user with a login link (for 'form' auth_types)? + if( have_auth_info( $server_id ) ) + { + $schema_href = 'schema.php?server_id=' . $server_id . '" target="right_frame'; + $search_href= 'search.php?server_id=' . $server_id . '" target="right_frame'; + $refresh_href = 'refresh.php?server_id=' . $server_id; + $create_href = 'create_form.php?server_id=' . $server_id . '&container=' . + rawurlencode( $servers[$server_id]['base'] ); + $logout_href = 'logout.php?server_id=' . $server_id; + $info_href = 'server_info.php?server_id=' . $server_id; + + if( $servers[$server_id]['auth_type'] == 'form' && have_auth_info( $server_id ) ) + echo "Logged in as: " . htmlspecialchars(get_logged_in_dn($server_id)) . "
"; + + // Draw the quick-links below the server name: + // ( schema | search | refresh | create ) + echo '('; + echo 'schema | '; + echo 'search | '; + echo 'refresh | '; + echo 'create | '; + echo 'info'; + if( $servers[ $server_id ][ 'auth_type' ] == 'form' ) + echo ' | logout'; + echo ')
$base_dn
Could not determine "; + echo "the root of your LDAP tree.
It appears that the LDAP server has "; + echo "been configured to not give it out. Please specify it in config.php"; + echo "
Could not determine "; + echo "the root of your LDAP tree.
Please specify it in config.php"; + echo "
Create New
+ + + +'; + + for( $i=0; $i<=$level; $i++ ) { + echo ''; + } + + // is this node expanded? + if( isset( $tree[$server_id][$dn] ) ) { ?> + + + plus + + + (' . count( $tree[$server_id][$dn] ) . ')'; ?> + + + + minus + + + + + + + + + + + + + + + + + '; + for( $i=0; $i<=$level; $i++ ) { + echo ''; + } + echo ''; + echo ''; + echo 'Create New'; + } + + echo ''; + +} + +?> diff --git a/update.php b/update.php new file mode 100644 index 0000000..8c58bf7 --- /dev/null +++ b/update.php @@ -0,0 +1,49 @@ +"; print_r( $update_array ); echo ""; + +check_server_id( $server_id ) or pla_error( "Bad server_id: " . htmlspecialchars( $server_id ) ); +have_auth_info( $server_id ) or pla_error( "Not enough information to login to server. Please check your configuration." ); +is_array( $update_array ) or pla_error( "update_array is malformed. This might be a phpLDAPAdmin bug. Please report it." ); + +foreach( $update_array as $attr => $val ) + if( ! is_array( $val ) ) + if( $val == '' ) + $update_array[ $attr ] = array(); + +$ds = pla_ldap_connect( $server_id ); +$res = @ldap_modify( $ds, $dn, $update_array ); +if( $res ) +{ + $redirect_url = "edit.php?server_id=$server_id&dn=$encoded_dn"; + foreach( $update_array as $attr => $junk ) + $redirect_url .= "&modified_attrs[]=$attr"; + header( "Location: $redirect_url" ); +} +else +{ + pla_error( "Could not perform ldap_modify operation.", ldap_error( $ds ), ldap_errno( $ds ) ); +} + +?> diff --git a/update_confirm.php b/update_confirm.php new file mode 100644 index 0000000..4c32cff --- /dev/null +++ b/update_confirm.php @@ -0,0 +1,143 @@ + + + + +

+

Server:     Distinguished Name:

+ + $new_val ) +{ + // did the user change the field? + if( $new_val != $old_values[ $attr ] ) { + + // special case for userPassword attributes + if( 0 == strcasecmp( $attr, 'userPassword' ) ) + { + $enc_type = $_POST['enc_type']; + $new_val = password_hash( $new_val, $enc_type ); + } + + $update_array[ $attr ] = $new_val; + } +} + +//echo "
"; print_r( $update_array ); echo "
"; + +?> + 0 ) { ?> + +
+
+ Do you want to make these changes? +
+
+ + + + $new_val ) { $counter++ ?> + + + + \n\n"; + } + + ?> + +
AttributeOld ValueNew Value
+ "; + else + echo htmlspecialchars( $old_values[ $attr ] ) . "
"; + echo "
"; + if( is_array( $new_val ) ) + foreach( $new_val as $i => $v ) + if( $v == '' ) { + // remove it from the update array if it's empty + unset( $update_array[ $attr ][ $i ] ); + $update_array[ $attr ] = array_values( $update_array[ $attr ] ); + } else + echo htmlspecialchars( $v ) . "
"; + else + if( $new_val != '' ) + echo htmlspecialchars( $new_val ) . "
"; + echo "
+
+ + + + + + +
+ + + + + $val ) { ?> + + $v ) { ?> + + + + + + + + + + +
+ + + +
+
+
+ + + + +
+ You made no changes. + Go back. +
+ + + + + + + diff --git a/view_jpeg_photo.php b/view_jpeg_photo.php new file mode 100644 index 0000000..f524716 --- /dev/null +++ b/view_jpeg_photo.php @@ -0,0 +1,28 @@ +