python3-ldap-0.9.4.2/0000777000000000000000000000000012355117540012343 5ustar 00000000000000python3-ldap-0.9.4.2/COPYING.LESSER.txt0000666000000000000000000001720612355103746015221 0ustar 00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.python3-ldap-0.9.4.2/COPYING.txt0000666000000000000000000010575312355103746014232 0ustar 00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. 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 them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. 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. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey 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; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU 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 that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. 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. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 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. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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 Lesser General Public License instead of this License. But first, please read .python3-ldap-0.9.4.2/LICENSE.txt0000666000000000000000000000125312355103746014172 0ustar 00000000000000This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program in the COPYING and COPYING.LESSER files. If not, see .python3-ldap-0.9.4.2/MANIFEST.in0000666000000000000000000000012012355103746014075 0ustar 00000000000000include COPYING.txt COPYING.LESSER.txt LICENSE.txt README.txt requirements.txt python3-ldap-0.9.4.2/PKG-INFO0000666000000000000000000000175412355117540013447 0ustar 00000000000000Metadata-Version: 1.1 Name: python3-ldap Version: 0.9.4.2 Summary: A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible Home-page: https://www.assembla.com/spaces/python3-ldap Author: Giovanni Cannata Author-email: python3ldap@gmail.com License: LGPL v3 Description: UNKNOWN Keywords: python3 python2 ldap Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: Linux Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP python3-ldap-0.9.4.2/python3-ldap/0000777000000000000000000000000012355117540014665 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/0000777000000000000000000000000012355117540015670 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/0000777000000000000000000000000012355117540017473 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/attrDef.py0000666000000000000000000000673512355103746021454 0ustar 00000000000000""" Created on 2014.01.11 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.exceptions import LDAPKeyError class AttrDef(object): """ Attribute definition for abstract layer: 'name' is the real attribute name 'key' is the friendly name to use in query and while accessing the attribute, if not set is the same of name 'default' is the value returned if the attribute is not present 'validate' is an optional callable, called to check if the value in the query is valid, the callable is called with the value parameter 'preQuery' is an optional callable, called to transform values to be searched 'postQuery' is an optional callable, called to transform values returned by search 'dereference_dn' is a reference to an ObjectDef instance. When the attribute value contains a dn it will be searched and substituted in the entry AttrDef('name') creates an AttrDef object for attribute 'name' with all default values """ def __init__(self, name, key=None, validate=None, pre_query=None, post_query=None, default=None, dereference_dn=None): self.name = name self.key = ''.join(key.split()) if key else name # key set to name if not present self.validate = validate self.pre_query = pre_query self.post_query = post_query self.default = default self.dereference_dn = dereference_dn def __repr__(self): r = 'AttrDef(key={0.key!r}'.format(self) r += ', name={0.name!r}'.format(self) r += '' if self.validate is None else ', validate={0.validate!r}'.format(self) r += '' if self.pre_query is None else ', pre_query={0.pre_query!r}'.format(self) r += '' if self.post_query is None else ', post_query={0.post_query!r}'.format(self) r += '' if self.default is None else ', default={0.default!r}'.format(self) r += '' if self.dereference_dn is None else ', dereference_dn={0.dereference_dn!r}'.format(self) r += ')' return r def __str__(self): return self.__repr__() def __eq__(self, other): if isinstance(other, AttrDef): return self.key == other.key return False def __lt__(self, other): if isinstance(other, AttrDef): return self.key < other.key return False def __hash__(self): if self.key: return hash(self.key) else: return id(self) # unique for each instance def __setattr__(self, key, value): if hasattr(self, 'key') and key == 'key': # key cannot be changed because is being used for __hash__ raise LDAPKeyError('key already set') else: object.__setattr__(self, key, value) python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/attribute.py0000666000000000000000000000473312355103746022062 0ustar 00000000000000""" Created on 2014.01.06 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep from ..core.exceptions import LDAPAttributeError # noinspection PyUnresolvedReferences class Attribute(object): """ Attribute/values object, it includes the search result (after post_query transformation) of each attribute in an entry Attribute object is read only 'values' contains the processed attribute values 'raw_values' contains the unprocessed attribute values """ def __init__(self, attr_def, entry): self.__dict__['key'] = attr_def.key self.__dict__['definition'] = attr_def self.__dict__['values'] = [] self.__dict__['raw_values'] = [] self.__dict__['entry'] = entry def __repr__(self): if len(self.values) == 1: r = self.key + ': ' + str(self.values[0]) elif len(self.values) > 1: r = self.key + ': ' + str(self.values[0]) filler = ' ' * (len(self.key) + 6) for value in sorted(self.values[1:]): r += linesep + filler + str(value) else: r = '' return r def __str__(self): if len(self.values) == 1: return self.values[0] else: return str(self.values) def __len__(self): return len(self.values) def __iter__(self): return self.values.__iter__() def __getitem__(self, item): return self.values[item] def __setattr__(self, item, value): raise LDAPAttributeError('attribute is read only') @property def value(self): return self.__dict__['values'][0] if len(self.__dict__['values']) == 1 else self.__dict__['values'] python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/entry.py0000666000000000000000000000751112355103746021215 0ustar 00000000000000""" Created on 2014.01.06 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep from ..core.exceptions import LDAPKeyError, LDAPAttributeError, LDAPEntryError class Entry(object): """ The Entry object contains a single entry from the result of an LDAP search. Attributes can be accessed either by sequence, by assignment or as dictionary keys. Keys are not case sensitive. - The DN is retrieved by get_entry_dn() - The Reader reference is in get_entry_reader() - Raw attributes values are retrieved by the get_raw_attributes() and get_raw_attribute() methods The Entry object is read only """ def __init__(self, dn, reader): self.__dict__['_attributes'] = dict() self.__dict__['_dn'] = dn self.__dict__['_raw_attributes'] = None self.__dict__['_reader'] = reader def __repr__(self): if self._dn: r = 'DN: ' + str(self._dn) + linesep if self._attributes: for attr in sorted(self._attributes): r += ' ' * 4 + repr(self._attributes[attr]) + linesep return r else: return object.__repr__(self) def __str__(self): return self.__repr__() def __iter__(self): for attribute in self._attributes: yield self._attributes[attribute] raise StopIteration def __contains__(self, item): return True if self.__getitem__(item) else False def __getattr__(self, item): if isinstance(item, str): item = ''.join(item.split()).lower() for attr in self._attributes: if item == attr.lower(): break else: raise LDAPKeyError('key not found') return self._attributes[attr] raise LDAPKeyError('key must be a string') def __setattr__(self, item, value): if item in self._attributes: raise LDAPAttributeError('attribute is read only') else: raise LDAPEntryError('entry is read only') def __getitem__(self, item): return self.__getattr__(item) def __eq__(self, other): if isinstance(other, Entry): return self._dn == other.get_entry_dn() return False def __lt__(self, other): if isinstance(other, Entry): return self._dn <= other.get_entry_dn() return False def get_entry_dn(self): return self._dn def get_entry_reader(self): return self._reader def get_raw_attributes(self): return self._raw_attributes def get_raw_attribute(self, name): return self._raw_attributes[name] if name in self._raw_attributes else None # noinspection PyProtectedMember def refresh(self): temp_entry = self.get_entry_reader().search_object(self.get_entry_dn()) self.__dict__['_attributes'] = temp_entry._attributes self.__dict__['_raw_attributes'] = temp_entry._raw_attributes del temp_entry return self python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/objectDef.py0000666000000000000000000001031012355103746021730 0ustar 00000000000000""" Created on 2014.02.02 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep from .attrDef import AttrDef from ..core.exceptions import LDAPKeyError, LDAPObjectError, LDAPAttributeError, LDAPTypeError class ObjectDef(object): """ AttrDefs are stored in a dictionary; the key is the friendly name defined in AttrDef AttrDefs can be added and removed using the += ad -= operators ObjectDef can be accessed either as a sequence and a dictionary. When accessed the whole AttrDef instance is returned """ def __init__(self, object_class=None): self.__dict__['object_class'] = object_class self.__dict__['_attributes'] = dict() def __repr__(self): r = 'object_class: ' + str(self.object_class) if self.object_class else '' for attr in self._attributes: r += linesep + ' ' + self._attributes[attr].__repr__() + ', ' return r[:-2] if r[-2] == ',' else r def __str__(self): return self.__repr__() def __getitem__(self, item): return self.__getattr__(item) def __getattr__(self, item): item = ''.join(item.split()).lower() for attr in self._attributes: if item == attr.lower(): break else: raise LDAPKeyError('key not present') return self._attributes[attr] def __setattr__(self, key, value): raise LDAPObjectError('object is read only') def __iadd__(self, other): self.add(other) return self def __isub__(self, other): if isinstance(other, AttrDef): self.remove(other.key) elif isinstance(other, str): self.remove(other) return self def __iter__(self): for attribute in self._attributes: yield self._attributes[attribute] def __len__(self): return len(self._attributes) def __contains__(self, item): try: self.__getitem__(item) except KeyError: return False return True def add(self, definition=None): if isinstance(definition, str): element = AttrDef(definition) self.add(element) elif isinstance(definition, AttrDef): key = definition.key for attr in self._attributes: if key.lower() == attr.lower(): raise LDAPAttributeError('attribute already present') self._attributes[key] = definition self.__dict__[key] = definition elif isinstance(definition, (list, tuple)): for element in definition: self.add(element) else: raise LDAPObjectError('unable to add element to object definition') def remove(self, item): key = None if isinstance(item, str): key = ''.join(item.split()).lower() elif isinstance(item, AttrDef): key = item.key if key: for attr in self._attributes: if item == attr.lower(): del self._attributes[attr] break else: raise LDAPKeyError('key ' + str(key) + 'not present') else: raise LDAPTypeError('key must be str or AttrDef not ' + str(type(key))) def clear(self): self.__dict__['object_class'] = None self.__dict__['_attributes'] = dict() python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/operationalAttribute.py0000666000000000000000000000363012355103746024253 0ustar 00000000000000""" Created on 2014.02.09 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep from .attribute import Attribute # noinspection PyUnresolvedReferences,PyMissingConstructor class OperationalAttribute(Attribute): """ Operational attribute/values object, it includes the search result of an operational attribute in an entry Attribute object is read only 'values' contains the processed attribute values 'raw_values' contains the unprocessed attribute values It doesn't have any AttrDef """ def __init__(self, key, entry): self.__dict__['key'] = key self.__dict__['entry'] = entry self.__dict__['values'] = [] self.__dict__['raw_values'] = [] def __repr__(self): if len(self.values) == 1: r = self.key + ' [OPERATIONAL]: ' + str(self.values[0]) elif len(self.values) > 1: r = self.key + ' [OPERATIONAL]: ' + str(self.values[0]) filler = ' ' * (len(self.key) + 6) for value in sorted(self.values[1:]): r += linesep + filler + str(value) else: r = '' return r python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/reader.py0000666000000000000000000004433212355103746021320 0ustar 00000000000000""" Created on 2014.01.06 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from datetime import datetime from os import linesep from .. import SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_SCOPE_SINGLE_LEVEL, SEARCH_DEREFERENCE_ALWAYS, SEARCH_SCOPE_BASE_OBJECT, ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX from .attribute import Attribute from .entry import Entry from ..core.exceptions import LDAPReaderError from .operationalAttribute import OperationalAttribute def _ret_search_value(value): return value[0] + '=' + value[1:] if value[0] in '<>~' and value[1] != '=' else value def _create_query_dict(query_text): """ Create a dictionary with query key:value definitions query_text is a comma delimited key:value sequence """ query_dict = dict() if query_text: for arg_value_str in query_text.split(','): if ':' in arg_value_str: arg_value_list = arg_value_str.split(':') query_dict[arg_value_list[0].strip()] = arg_value_list[1].strip() return query_dict class Reader(object): """ Reader object perform the search with the requested parameters: 'connection': the connection to use 'object_def': the definition of the LDAP object to be returned 'query': the simplified query to be transformed in an LDAP filter 'base': starting base of the DIT 'components_in_and': specify if components of query mus be all satisfied or not (AND/OR) 'sub_tree': a boolean to specify if the search must be performed ad Single Level (False) or Whole SubTree (True) 'get_operational_attributes': a boolean to specify if operational attributes are returned or not 'controls': controls to be used in search """ def __init__(self, connection, object_def, query, base, components_in_and=True, sub_tree=True, get_operational_attributes=False, controls=None): self.connection = connection self._definition = object_def self.base = base self._components_in_and = components_in_and self.attributes = sorted([attr.name for attr in self._definition]) self.get_operational_attributes = get_operational_attributes self.controls = controls self.sub_tree = sub_tree self._query = query self.dereference_aliases = SEARCH_DEREFERENCE_ALWAYS self.size_limit = 0 self.time_limit = 0 self.types_only = False self.paged_size = None self.paged_criticality = False self.validated_query = None self._query_dict = dict() self._validated_query_dict = dict() self.execution_time = None self.query_filter = None self.entries = [] self.paged_cookie = None self.last_sub_tree = None self.reset() @property def definition(self): return self._definition @property def query(self): return self._query @query.setter def query(self, value): self._query = value self.reset() @property def components_in_and(self): return self._components_in_and @components_in_and.setter def components_in_and(self, value): self._components_in_and = value self.reset() def __repr__(self): r = 'CONN : ' + str(self.connection) + linesep r += 'BASE : ' + repr(self.base) + (' [SUB]' if self.sub_tree else ' [LEVEL]') + linesep r += 'DEFS : ' + repr(self._definition.object_class) + ' [' for attr_def in sorted(self._definition): r += (attr_def.key if attr_def.key == attr_def.name else (attr_def.key + ' <' + attr_def.name + '>')) + ', ' if r[-2] == ',': r = r[:-2] r += ']' + linesep r += 'QUERY : ' + repr(self._query) + (' [AND]' if self.components_in_and else ' [OR]') + linesep r += 'PARSED : ' + repr(self.validated_query) + (' [AND]' if self.components_in_and else ' [OR]') + linesep r += 'ATTRS : ' + repr(self.attributes) + (' [OPERATIONAL]' if self.get_operational_attributes else '') + linesep r += 'FILTER : ' + repr(self.query_filter) + linesep if self.execution_time: r += 'ENTRIES: ' + str(len(self.entries)) r += ' [SUB]' if self.last_sub_tree else ' [level]' r += ' [SIZE LIMIT: ' + str(self.size_limit) + ']' if self.size_limit else '' r += ' [TIME LIMIT: ' + str(self.time_limit) + ']' if self.time_limit else '' r += ' [executed at: ' + str(self.execution_time.isoformat()) + ']' + linesep return r def __str__(self): return self.__repr__() def clear(self): self.dereference_aliases = SEARCH_DEREFERENCE_ALWAYS self.size_limit = 0 self.time_limit = 0 self.types_only = False self.paged_size = None self.paged_criticality = False def reset(self): self.clear() self.validated_query = None self._query_dict = dict() self._validated_query_dict = dict() self.execution_time = None self.query_filter = None self.entries = [] self.paged_cookie = None self.last_sub_tree = None self._create_query_filter() def __iter__(self): return self.entries.__iter__() def __getitem__(self, item): return self.entries[item] def __len__(self): return len(self.entries) def _validate_query(self): """ Processes the text query and verifies that the requested friendly names are in the Reader dictionary If the AttrDef has a 'validate' property the callable is executed and if it returns False an Exception is raised """ if not self._query_dict: self._query_dict = _create_query_dict(self._query) query = '' for d in sorted(self._query_dict): attr = d[1:] if d[0] in '&|' else d for attr_def in self._definition: if ''.join(attr.split()).lower() == attr_def.key.lower(): attr = attr_def.key break if attr in self._definition: vals = sorted(self._query_dict[d].split(';')) query += (d[0] + attr if d[0] in '&|' else attr) + ': ' for val in vals: val = val.strip() val_not = True if val[0] == '!' else False val_search_operator = '=' # default if val_not: if val[1:].lstrip()[0] not in '=<>~': value = val[1:].lstrip() else: val_search_operator = val[1:].lstrip()[0] value = val[1:].lstrip()[1:] else: if val[0] not in '=<>~': value = val.lstrip() else: val_search_operator = val[0] value = val[1:].lstrip() if self._definition[attr].validate: if not self._definition[attr].validate(self._definition[attr].key, value): raise LDAPReaderError('validation failed for attribute %s and value %s' % (d, val)) if val_not: query += '!' + val_search_operator + value else: query += val_search_operator + value query += ';' query = query[:-1] + ', ' self.validated_query = query[:-2] self._validated_query_dict = _create_query_dict(self.validated_query) def _create_query_filter(self): """ Converts the query dictionary in the filter text """ if self._query and self._query.startswith('(') and self._query.stopswith(')'): # query is already an LDAP filter self.query_filter = self._query return self.query_filter = '' if self._definition.object_class: self.query_filter += '(&' if isinstance(self._definition.object_class, str): self.query_filter += '(objectClass=' + self._definition.object_class + ')' elif isinstance(self._definition.object_class, (list, tuple)): self.query_filter += '(&' for object_class in self._definition.object_class: self.query_filter += '(objectClass=' + object_class + ')' self.query_filter += ')' else: raise LDAPReaderError('object_class must be a string or a list') if not self.components_in_and: self.query_filter += '(|' elif not self._definition.object_class: self.query_filter += '(&' self._validate_query() attr_counter = 0 for attr in sorted(self._validated_query_dict): attr_counter += 1 multi = True if ';' in self._validated_query_dict[attr] else False vals = sorted(self._validated_query_dict[attr].split(';')) attr_def = self._definition[attr[1:]] if attr[0] in '&|' else self._definition[attr] if attr_def.pre_query: modvals = [] for val in vals: modvals.append(val[0] + attr_def.pre_query(attr_def.key, val[1:])) vals = modvals if multi: if attr[0] in '&|': self.query_filter += '(' + attr[0] else: self.query_filter += '(|' for val in vals: if val[0] == '!': self.query_filter += '(!(' + attr_def.name + _ret_search_value(val[1:]) + '))' else: self.query_filter += '(' + attr_def.name + _ret_search_value(val) + ')' if multi: self.query_filter += ')' if not self.components_in_and: self.query_filter += '))' else: self.query_filter += ')' if not self._definition.object_class and attr_counter == 1: # remove unneeded starting filter self.query_filter = self.query_filter[2:-1] def _get_attributes(self, result, attr_defs, entry): """ Assign the result of the LDAP query to the Entry object dictionary. If the optional 'post_query' callable is present in the AttrDef it is called with each value of the attribute and the callable result is stored in the attribute Returns the default value for missing attributes If the 'dereference_dn' in AttrDef is a ObjectDef then the attribute values are treated as distinguished name and the relevant entry is retrieved and stored in the attribute value """ attributes = dict() used_attribute_names = [] for attr_def in attr_defs: name = None for attr_name in result['attributes']: if attr_def.name.lower() == attr_name.lower(): name = attr_name break if name or attr_def.default: # attribute value found in result or default value present attribute = Attribute(attr_def, entry) attribute.__dict__['raw_values'] = result['raw_attributes'][name] if name else None if attr_def.post_query and attr_def.name in result['attributes']: attribute.__dict__['values'] = attr_def.post_query(attr_def.key, result['attributes'][name]) else: attribute.__dict__['values'] = result['attributes'][name] if name else (attr_def.default if isinstance(attr_def.default, (list, tuple)) else [attr_def.default]) if attr_def.dereference_dn: # try to get object referenced in value # noinspection PyUnresolvedReferences if attribute.values: temp_reader = Reader(self.connection, attr_def.dereference_dn, query=None, base=None, get_operational_attributes=self.get_operational_attributes, controls=self.controls) temp_values = [] # noinspection PyUnresolvedReferences for element in attribute.values: temp_values.append(temp_reader.search_object(element)) del temp_reader # remove the temporary Reader attribute.__dict__['values'] = temp_values # noinspection PyUnresolvedReferences attributes[attribute.key] = attribute used_attribute_names.append(name) for name in result['attributes']: if name not in used_attribute_names: attribute = OperationalAttribute(ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name, entry) attribute.__dict__['raw_values'] = result['raw_attributes'][name] attribute.__dict__['values'] = result['attributes'][name] if (ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name) not in attributes: attributes[ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX + name] = attribute return attributes def _get_entry(self, result): if not result['type'] == 'searchResEntry': return None entry = Entry(result['dn'], self) entry.__dict__['_attributes'] = self._get_attributes(result, self._definition, entry) entry.__dict__['_raw_attributes'] = result['raw_attributes'] for attr in entry: # returns the whole attribute object attr_name = attr.key entry.__dict__[attr_name] = attr return entry def _execute_query(self, query_scope): if not self.connection: raise LDAPReaderError('no connection established') self._create_query_filter() with self.connection: result = self.connection.search(search_base=self.base, search_filter=self.query_filter, search_scope=query_scope, dereference_aliases=self.dereference_aliases, attributes=self.attributes, size_limit=self.size_limit, time_limit=self.time_limit, types_only=self.types_only, get_operational_attributes=self.get_operational_attributes, controls=self.controls, paged_size=self.paged_size, paged_criticality=self.paged_criticality, paged_cookie=self.paged_cookie) if not self.connection.strategy.sync: response, _ = self.connection.get_response(result) else: response = self.connection.response self.entries = [] for r in response: entry = self._get_entry(r) self.entries.append(entry) self.last_sub_tree = self.sub_tree self.execution_time = datetime.now() def search(self): self.clear() query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL self._execute_query(query_scope) return self.entries def search_level(self): self.clear() self._execute_query(SEARCH_SCOPE_SINGLE_LEVEL) return self.entries def search_subtree(self): self.clear() self._execute_query(SEARCH_SCOPE_WHOLE_SUBTREE) return self.entries def search_object(self, entry_dn=None): # base must be a single dn self.clear() if entry_dn: old_base = self.base self.base = entry_dn self._execute_query(SEARCH_SCOPE_BASE_OBJECT) self.base = old_base else: self._execute_query(SEARCH_SCOPE_BASE_OBJECT) return self.entries[0] if len(self.entries) > 0 else None def search_size_limit(self, size_limit): self.clear() self.size_limit = size_limit query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL self._execute_query(query_scope) return self.entries def search_time_limit(self, time_limit): self.clear() self.time_limit = time_limit query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL self._execute_query(query_scope) return self.entries def search_types_only(self): self.clear() self.types_only = True query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL self._execute_query(query_scope) return self.entries def search_paged(self, paged_size, paged_criticality=True): if not self.paged_cookie: self.clear() self.paged_size = paged_size self.paged_criticality = paged_criticality query_scope = SEARCH_SCOPE_WHOLE_SUBTREE if self.sub_tree else SEARCH_SCOPE_SINGLE_LEVEL self._execute_query(query_scope) if self.entries: yield self.entries else: raise StopIteration python3-ldap-0.9.4.2/python3-ldap/ldap3/abstract/__init__.py0000666000000000000000000000201012355103746021600 0ustar 00000000000000""" Created on 2014.01.06 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from .attribute import Attribute from .operationalAttribute import OperationalAttribute from .attrDef import AttrDef from .objectDef import ObjectDef from .entry import Entry from .reader import Reader python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/0000777000000000000000000000000012355117540017153 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/connection.py0000666000000000000000000000712612355103746021675 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.connection import Connection as newConnection from .. import SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_DEREFERENCE_ALWAYS, STRATEGY_SYNC # noinspection PyPep8Naming class Connection(newConnection): """ Proxy class (with camel case parameters) to new Connection class (pep8 compliant) """ def __init__(self, server, user=None, password=None, autoBind=False, version=3, authentication=None, clientStrategy=STRATEGY_SYNC, autoReferrals=True, saslMechanism=None, saslCredentials=None, collectUsage=False, readOnly=False, lazy=False): newConnection.__init__(self, server, user, password, autoBind, version, authentication, clientStrategy, autoReferrals, saslMechanism, saslCredentials, collectUsage, readOnly, lazy) def search(self, searchBase, searchFilter, searchScope=SEARCH_SCOPE_WHOLE_SUBTREE, dereferenceAliases=SEARCH_DEREFERENCE_ALWAYS, attributes=None, sizeLimit=0, timeLimit=0, typesOnly=False, getOperationalAttributes=False, controls=None, pagedSize=None, pagedCriticality=False, pagedCookie=None): return newConnection.search(self, searchBase, searchFilter, searchScope, dereferenceAliases, attributes, sizeLimit, timeLimit, typesOnly, getOperationalAttributes, controls, pagedSize, pagedCriticality, pagedCookie) def add(self, dn, objectClass=None, attributes=None, controls=None): """ Add DN to the DIB, objectClass is None, a class name or a list of class names. attributes is a dictionary in the form 'attr': 'val' or 'attr': ['val1', 'val2', 'valN'] for multivalued types. """ return newConnection.add(dn, objectClass, attributes, controls) def modifyDn(self, dn, relativeDn, deleteOldDn=True, newSuperior=None, controls=None): """ Modify DN of the entry and optionally performs a move of the entry in the DIB. """ return newConnection.modify_dn(self, dn, relativeDn, deleteOldDn, newSuperior, controls) def abandon(self, messageId, controls=None): """ Abandon the operation indicated by messageId. """ return newConnection.abandon(self, messageId, controls) def extended(self, requestName, requestValue=None, controls=None): """ Perform an extended operation. """ return newConnection.extended(self, requestName, requestValue, controls) def startTls(self): return newConnection.start_tls(self) def doSaslBind(self, controls): return newConnection.do_sasl_bind(self, controls) def refreshDsaInfo(self): return newConnection.refresh_dsa_info(self) def responseToLdif(self, searchResult=None, allBase64=False): return newConnection.response_to_ldif(self, searchResult, allBase64) python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/server.py0000666000000000000000000000214612355103746021041 0ustar 00000000000000""" Created on 2014.03.10 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.server import Server as newServer # noinspection PyPep8Naming class Server(newServer): def __init__(self, host, port=389, useSsl=False, allowedReferralHosts=None, getInfo=None, tls=None): newServer.__init__(self, host, port, useSsl, allowedReferralHosts, getInfo, tls) python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/tls.py0000666000000000000000000000302012355103746020325 0ustar 00000000000000""" Created on 2014.03.10 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.exceptions import LDAPSSLNotSupportedError from ..core.tls import Tls as newTls try: # noinspection PyUnresolvedReferences import ssl except ImportError: raise LDAPSSLNotSupportedError('SSL not supported in this Python interpreter') # noinspection PyPep8Naming class Tls(newTls): """ tls/ssl configuration for Server object """ def __init__(self, localPrivateKeyFile=None, localCertificateFile=None, validate=ssl.CERT_NONE, version=ssl.PROTOCOL_TLSv1, caCertsFile=None): newTls.__init__(self, localPrivateKeyFile, localCertificateFile, validate, version, caCertsFile) def startTls(self, connection): return newTls.start_tls(self, connection) python3-ldap-0.9.4.2/python3-ldap/ldap3/compat/__init__.py0000666000000000000000000000000012355103746021255 0ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/core/0000777000000000000000000000000012355117540016620 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/core/connection.py0000666000000000000000000006640012355110215021327 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep from pyasn1.codec.ber import encoder from .. import AUTH_ANONYMOUS, AUTH_SIMPLE, AUTH_SASL, MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, SEARCH_DEREFERENCE_ALWAYS, SEARCH_SCOPE_WHOLE_SUBTREE, STRATEGY_ASYNC_THREADED, STRATEGY_SYNC, CLIENT_STRATEGIES, RESULT_SUCCESS, \ RESULT_COMPARE_TRUE, NO_ATTRIBUTES, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, MODIFY_INCREMENT, STRATEGY_LDIF_PRODUCER, SASL_AVAILABLE_MECHANISMS, STRATEGY_SYNC_RESTARTABLE, POOLING_STRATEGY_ROUND_ROBIN, \ STRATEGY_REUSABLE_THREADED, DEFAULT_POOL_NAME from ..extend import ExtendedOperationsContainer from .pooling import ServerPool from .server import Server from ..strategy.reusableThreaded import ReusableThreadedStrategy from ..operation.abandon import abandon_operation from ..operation.add import add_operation from ..operation.bind import bind_operation from ..operation.compare import compare_operation from ..operation.delete import delete_operation from ..operation.extended import extended_operation from ..operation.modify import modify_operation from ..operation.modifyDn import modify_dn_operation from ..operation.search import search_operation from ..protocol.rfc2849 import operation_to_ldif, add_ldif_header from ..protocol.sasl.digestMd5 import sasl_digest_md5 from ..protocol.sasl.external import sasl_external from ..strategy.asyncThreaded import AsyncThreadedStrategy from ..strategy.ldifProducer import LdifProducerStrategy from ..strategy.syncWait import SyncWaitStrategy from ..strategy.syncWaitRestartable import SyncWaitRestartableStrategy from ..operation.unbind import unbind_operation from ..protocol.rfc2696 import RealSearchControlValue, Cookie, Size from .usage import ConnectionUsage from .tls import Tls from .exceptions import LDAPUnknownStrategyError, LDAPBindError, LDAPUnknownAuthenticationMethodError, LDAPInvalidServerError, LDAPSASLMechanismNotSupportedError, LDAPObjectClassError, LDAPConnectionIsReadOnlyError, LDAPChangesError, LDAPExceptionError from ..utils.conv import prepare_for_stream # noinspection PyProtectedMember class Connection(object): """ Main ldap connection class. Controls, if used, must be a list of tuples. Each tuple must have 3 elements, the control OID, a boolean meaning if the control is critical, a value. If the boolean is set to True the server must honor the control or refuse the operation Mixing controls must be defined in controls specification (as per RFC 4511.) """ def __init__(self, server, user=None, password=None, auto_bind=False, version=3, authentication=None, client_strategy=STRATEGY_SYNC, auto_referrals=True, sasl_mechanism=None, sasl_credentials=None, check_names=True, collect_usage=False, read_only=False, lazy=False, raise_exceptions=False, pool_name=None, pool_size=None, pool_lifetime=None): if client_strategy not in CLIENT_STRATEGIES: self.last_error = 'unknown client connection strategy' raise LDAPUnknownStrategyError(self.last_error) self.strategy_type = client_strategy self.user = user self.password = password if self.user and self.password and not authentication: self.authentication = AUTH_SIMPLE elif not authentication: self.authentication = AUTH_ANONYMOUS elif authentication in [AUTH_SIMPLE, AUTH_ANONYMOUS, AUTH_SASL]: self.authentication = authentication else: self.last_error = 'unknown authentication method' raise LDAPUnknownAuthenticationMethodError(self.last_error) self.version = version self.auto_referrals = True if auto_referrals else False self.request = None self.response = None self.result = None self.bound = False self.listening = False self.closed = True self.last_error = None self.auto_bind = True if auto_bind else False self.sasl_mechanism = sasl_mechanism self.sasl_credentials = sasl_credentials self._usage = ConnectionUsage() if collect_usage else None self.socket = None self.tls_started = False self.sasl_in_progress = False self.read_only = read_only self._context_state = [] self._deferred_open = False self._deferred_bind = False self._deferred_start_tls = False self._bind_controls = None self._executing_deferred = False self.lazy = lazy self.pool_name = pool_name if pool_name else DEFAULT_POOL_NAME self.pool_size = pool_size self.pool_lifetime = pool_lifetime self.starting_tls = False self.check_names = check_names self.raise_exceptions = raise_exceptions self.extend = ExtendedOperationsContainer(self) if isinstance(server, str): server = Server(server) if isinstance(server, (list, tuple)): server = ServerPool(server, POOLING_STRATEGY_ROUND_ROBIN, active=True, exhaust=True) if isinstance(server, ServerPool): self.server_pool = server self.server_pool.initialize(self) self.server = self.server_pool.get_current_server(self) else: self.server_pool = None self.server = server if self.strategy_type == STRATEGY_SYNC: self.strategy = SyncWaitStrategy(self) elif self.strategy_type == STRATEGY_ASYNC_THREADED: self.strategy = AsyncThreadedStrategy(self) elif self.strategy_type == STRATEGY_LDIF_PRODUCER: self.strategy = LdifProducerStrategy(self) elif self.strategy_type == STRATEGY_SYNC_RESTARTABLE: self.strategy = SyncWaitRestartableStrategy(self) elif self.strategy_type == STRATEGY_REUSABLE_THREADED: self.strategy = ReusableThreadedStrategy(self) else: self.last_error = 'unknown strategy' raise LDAPUnknownStrategyError(self.last_error) # map strategy functions to connection functions self.send = self.strategy.send self.open = self.strategy.open self.get_response = self.strategy.get_response self.post_send_single_response = self.strategy.post_send_single_response self.post_send_search = self.strategy.post_send_search if not self.strategy.no_real_dsa and self.server.is_valid(): if self.auto_bind: self.open() self.bind() if not self.bound: self.last_error = 'automatic bind not successful' + (' - ' + self.last_error if self.last_error else '') raise LDAPBindError(self.last_error) elif self.strategy.no_real_dsa: self.server = None else: self.last_error = 'invalid LDAP server' raise LDAPInvalidServerError(self.last_error) def __str__(self): s = [ str(self.server) if self.server and self.server.is_valid else 'None', 'user: ' + str(self.user), 'unbound' if not self.bound else ('deferred bind' if self._deferred_bind else 'bound'), 'closed' if self.closed else ('deferred open' if self._deferred_open else 'open'), 'tls not started' if not self.tls_started else('deferred start_tls' if self._deferred_start_tls else 'tls started'), 'listening' if self.listening else 'not listening', self.strategy.__class__.__name__ ] return ' - '.join(s) def __repr__(self): if self.server_pool: r = 'Connection(server={0.server_pool!r}'.format(self) else: r = 'Connection(server={0.server!r}'.format(self) r += '' if self.user is None else ', user={0.user!r}'.format(self) r += '' if self.password is None else ', password={0.password!r}'.format(self) r += '' if self.auto_bind is None else ', auto_bind={0.auto_bind!r}'.format(self) r += '' if self.version is None else ', version={0.version!r}'.format(self) r += '' if self.authentication is None else ', authentication={0.authentication!r}'.format(self) r += '' if self.strategy_type is None else ', client_strategy={0.strategy_type!r}'.format(self) r += '' if self.auto_referrals is None else ', auto_referrals={0.auto_referrals!r}'.format(self) r += '' if self.sasl_mechanism is None else ', sasl_mechanism={0.auto_sasl_mechanism!r}'.format(self) r += '' if self.sasl_credentials is None else ', sasl_credentials={0.sasl_credentials!r}'.format(self) r += '' if self.check_names is None else ', check_names={0.check_names!r}'.format(self) r += '' if self.usage is None else (', collect_usage=' + 'True' if self.usage else 'False') r += '' if self.read_only is None else ', read_only={0.read_only!r}'.format(self) r += '' if self.lazy is None else ', lazy={0.lazy!r}'.format(self) r += '' if self.raise_exceptions is None else ', raise_exceptions={0.raise_exceptions!r}'.format(self) r += '' if (self.pool_name is None or self.pool_name == DEFAULT_POOL_NAME) else ', pool_name={0.pool_name!r}'.format(self) r += '' if self.pool_size is None else ', pool_size={0.pool_size!r}'.format(self) r += '' if self.pool_lifetime is None else ', pool_lifetime={0.pool_lifetime!r}'.format(self) r += ')' return r @property def stream(self): """ returns a reference to the response stream if defined in the strategy. Used in the LDIFProducer to accumulate the ldif-change operations with a single LDIF header """ return self.strategy.get_stream() if self.strategy.can_stream else None @stream.setter def stream(self, value): if self.strategy.can_stream: self.strategy.set_stream(value) @property def usage(self): if not self._usage: return None if self.strategy.pooled: self._usage.reset() for connection in self.strategy.pool.connections: self._usage += connection.connection.usage self._usage += self.strategy.pool.terminated_usage return self._usage def __enter__(self): self._context_state.append((self.bound, self.closed)) # save status out of context as a tuple in a list if self.closed: self.open() if not self.bound: self.bind() return self # noinspection PyUnusedLocal def __exit__(self, exc_type, exc_val, exc_tb): context_bound, context_closed = self._context_state.pop() if (not context_bound and self.bound) or self.stream: # restore status prior to entering context try: self.unbind() except LDAPExceptionError: pass if not context_closed and self.closed: self.open() if not exc_type is None: return False # re-raise LDAPExceptionError def bind(self, controls=None): """ Bind to ldap with the user defined in Server object """ if self.lazy and not self._executing_deferred: self._deferred_bind = True self._bind_controls = controls self.bound = True else: self._deferred_bind = False self._bind_controls = None if self.closed: # try to open connection if closed self.open() if self.authentication == AUTH_ANONYMOUS: request = bind_operation(self.version, self.authentication, '', '') response = self.post_send_single_response(self.send('bindRequest', request, controls)) elif self.authentication == AUTH_SIMPLE: request = bind_operation(self.version, self.authentication, self.user, self.password) response = self.post_send_single_response(self.send('bindRequest', request, controls)) elif self.authentication == AUTH_SASL: if self.sasl_mechanism in SASL_AVAILABLE_MECHANISMS: response = self.do_sasl_bind(controls) else: self.last_error = 'requested SASL mechanism not supported' raise LDAPSASLMechanismNotSupportedError(self.last_error) else: self.last_error = 'unknown authentication method' raise LDAPUnknownAuthenticationMethodError(self.last_error) if not self.strategy.sync and self.authentication != AUTH_SASL: # get response if async except for sasl that return the bind result even for async response, result = self.get_response(response) else: result = self.result if result is None: self.bound = True if self.strategy_type == STRATEGY_REUSABLE_THREADED else False else: self.bound = True if result['result'] == RESULT_SUCCESS else False if not self.bound and result and result['description']: self.last_error = result['description'] if self.bound and not self.strategy.pooled: self.refresh_dsa_info() return self.bound def unbind(self, controls=None): """ Unbinds the connected user Unbind implies closing session as per RFC4511 (4.3) """ if self.lazy and not self._executing_deferred and (self._deferred_bind or self._deferred_open): # clear deferred status self.strategy.close() self._deferred_open = False self._deferred_bind = False self._deferred_start_tls = False elif not self.closed: request = unbind_operation() self.send('unbindRequest', request, controls) self.strategy.close() return True def search(self, search_base, search_filter, search_scope=SEARCH_SCOPE_WHOLE_SUBTREE, dereference_aliases=SEARCH_DEREFERENCE_ALWAYS, attributes=None, size_limit=0, time_limit=0, types_only=False, get_operational_attributes=False, controls=None, paged_size=None, paged_criticality=False, paged_cookie=None): """ Perform an ldap search: - If attributes is empty no attribute is returned - If attributes is ALL_ATTRIBUTES all attributes are returned - If paged_size is an int greater than 0 a simple paged search is tried as described in RFC2696 with the specified size - If paged is 0 and cookie is present the search is abandoned on server - Cookie is an opaque string received in the last paged search and must be used on the next paged search response - If lazy = True open and bind will be deferred until another LDAP operation is performed """ self._fire_deferred() if not attributes: attributes = [NO_ATTRIBUTES] elif attributes == ALL_ATTRIBUTES: attributes = ['*'] if get_operational_attributes: attributes.append(ALL_OPERATIONAL_ATTRIBUTES) if isinstance(paged_size, int): real_search_control_value = RealSearchControlValue() real_search_control_value['size'] = Size(paged_size) real_search_control_value['cookie'] = Cookie(paged_cookie) if paged_cookie else Cookie('') if controls is None: controls = [] controls.append(('1.2.840.113556.1.4.319', paged_criticality if isinstance(paged_criticality, bool) else False, encoder.encode(real_search_control_value))) request = search_operation(search_base, search_filter, search_scope, dereference_aliases, attributes, size_limit, time_limit, types_only, self.server.schema if self.server and self.check_names else None) response = self.post_send_search(self.send('searchRequest', request, controls)) if isinstance(response, int): return response if self.result['type'] == 'searchResDone' and len(response) > 0: return True return False def compare(self, dn, attribute, value, controls=None): """ Perform a compare operation """ self._fire_deferred() request = compare_operation(dn, attribute, value, self.server.schema if self.server and self.check_names else None) response = self.post_send_single_response(self.send('compareRequest', request, controls)) if isinstance(response, int): return response return True if self.result['type'] == 'compareResponse' and self.result['result'] == RESULT_COMPARE_TRUE else False def add(self, dn, object_class=None, attributes=None, controls=None): """ Add dn to the DIT, object_class is None, a class name or a list of class names. Attributes is a dictionary in the form 'attr': 'val' or 'attr': ['val1', 'val2', ...] for multivalued attributes """ self._fire_deferred() attr_object_class = [] if object_class is None: parm_object_class = [] else: parm_object_class = object_class if isinstance(object_class, (list, tuple)) else [object_class] object_class_attr_name = '' if attributes: for attr in attributes: if attr.lower() == 'objectclass': object_class_attr_name = attr attr_object_class = attributes[object_class_attr_name] if isinstance(attributes[object_class_attr_name], (list, tuple)) else [attributes[object_class_attr_name]] else: attributes = dict() if not object_class_attr_name: object_class_attr_name = 'objectClass' attributes[object_class_attr_name] = list(set([object_class.lower() for object_class in parm_object_class + attr_object_class])) # remove duplicate ObjectClasses if not attributes[object_class_attr_name]: self.last_error = 'ObjectClass attribute is mandatory' raise LDAPObjectClassError(self.last_error) request = add_operation(dn, attributes, self.server.schema if self.server and self.check_names else None) response = self.post_send_single_response(self.send('addRequest', request, controls)) if isinstance(response, (int, str)): return response return True if self.result['type'] == 'addResponse' and self.result['result'] == RESULT_SUCCESS else False def delete(self, dn, controls=None): """ Delete the entry identified by the DN from the DIB. """ self._fire_deferred() if self.read_only: self.last_error = 'connection is read-only' raise LDAPConnectionIsReadOnlyError(self.last_error) request = delete_operation(dn) response = self.post_send_single_response(self.send('delRequest', request, controls)) if isinstance(response, (int, str)): return response return True if self.result['type'] == 'delResponse' and self.result['result'] == RESULT_SUCCESS else False def modify(self, dn, changes, controls=None): """ Modify attributes of entry - Changes is a dictionary in the form {'attribute1': (operation, [val1, val2]), 'attribute2': (operation, [val1, val2])} - Operation is 0 (MODIFY_ADD), 1 (MODIFY_DELETE), 2 (MODIFY_REPLACE), 3 (MODIFY_INCREMENT) """ self._fire_deferred() if self.read_only: self.last_error = 'connection is read-only' raise LDAPConnectionIsReadOnlyError(self.last_error) if not isinstance(changes, dict): self.last_error = 'changes must be a dictionary' raise LDAPChangesError(self.last_error) if not changes: self.last_error = 'no changes in modify request' raise LDAPChangesError(self.last_error) for change in changes: if len(changes[change]) != 2: self.last_error = 'malformed change' raise LDAPChangesError(self.last_error) elif changes[change][0] not in [MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE, MODIFY_INCREMENT]: self.last_error = 'unknown change type' raise LDAPChangesError(self.last_error) request = modify_operation(dn, changes, self.server.schema if self.server and self.check_names else None) response = self.post_send_single_response(self.send('modifyRequest', request, controls)) if isinstance(response, (int, str)): return response return True if self.result['type'] == 'modifyResponse' and self.result['result'] == RESULT_SUCCESS else False def modify_dn(self, dn, relative_dn, delete_old_dn=True, new_superior=None, controls=None): """ Modify DN of the entry or performs a move of the entry in the DIT. """ self._fire_deferred() if self.read_only: self.last_error = 'connection is read-only' raise LDAPConnectionIsReadOnlyError(self.last_error) if new_superior and not dn.startswith(relative_dn): # as per RFC4511 (4.9) self.last_error = 'DN cannot change while moving' raise LDAPChangesError(self.last_error) request = modify_dn_operation(dn, relative_dn, delete_old_dn, new_superior) response = self.post_send_single_response(self.send('modDNRequest', request, controls)) if isinstance(response, (int, str)): return response return True if self.result['type'] == 'modDNResponse' and self.result['result'] == RESULT_SUCCESS else False def abandon(self, message_id, controls=None): """ Abandon the operation indicated by message_id """ self._fire_deferred() if self.strategy._outstanding: if message_id in self.strategy._outstanding and self.strategy._outstanding[message_id]['type'] not in ['abandonRequest', 'bindRequest', 'unbindRequest']: request = abandon_operation(message_id) self.send('abandonRequest', request, controls) self.response = None self.result = None return True return False def extended(self, request_name, request_value=None, controls=None): """ Performs an extended operation """ self._fire_deferred() request = extended_operation(request_name, request_value) response = self.post_send_single_response(self.send('extendedReq', request, controls)) if isinstance(response, int): return response return True if self.result['type'] == 'extendedResp' and self.result['result'] == RESULT_SUCCESS else False def start_tls(self): # as per RFC4511. Removal of TLS is defined as MAY in RFC4511 so the client can't implement a generic stop_tls method0 if not self.server.tls: self.server.tls = Tls() if self.lazy and not self._executing_deferred: self._deferred_start_tls = True self.tls_started = True return True else: self._deferred_start_tls = False if self.server.tls.start_tls(self): self.refresh_dsa_info() # refresh server info as per RFC4515 (3.1.5) return True return False def do_sasl_bind(self, controls): response = None if not self.sasl_in_progress: self.sasl_in_progress = True if self.sasl_mechanism == 'EXTERNAL': response = sasl_external(self, controls) elif self.sasl_mechanism == 'DIGEST-MD5': response = sasl_digest_md5(self, controls) self.sasl_in_progress = False return response def refresh_dsa_info(self): if not self.closed: self.server.get_info_from_server(self) def response_to_ldif(self, search_result=None, all_base64=False, line_separator=None, sort_order=None, stream=None): if search_result is None: search_result = self.response if isinstance(search_result, (list, tuple)): ldif_lines = operation_to_ldif('searchResponse', search_result, all_base64, sort_order=sort_order) ldif_lines = add_ldif_header(ldif_lines) line_separator = line_separator or linesep ldif_output = line_separator.join(ldif_lines) if stream: if stream.tell() == 0: header = add_ldif_header(['-'])[0] stream.write(prepare_for_stream(header + line_separator + line_separator)) stream.write(prepare_for_stream(ldif_output + line_separator + line_separator)) return ldif_output return None def _fire_deferred(self): if self.lazy: self._executing_deferred = True try: if self._deferred_open: self.open() if self._deferred_bind: self.bind(self._bind_controls) if self._deferred_start_tls: self.start_tls() except LDAPExceptionError: raise # re-raise LDAPExceptionError finally: self._executing_deferred = False python3-ldap-0.9.4.2/python3-ldap/ldap3/core/exceptions.py0000666000000000000000000003576312355103746021374 0ustar 00000000000000""" Created on 2014.05.14 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from .. import RESULT_OPERATIONS_ERROR, RESULT_PROTOCOL_ERROR, RESULT_TIME_LIMIT_EXCEEDED, RESULT_SIZE_LIMIT_EXCEEDED, \ RESULT_STRONGER_AUTH_REQUIRED, RESULT_REFERRAL, RESULT_ADMIN_LIMIT_EXCEEDED, RESULT_UNAVAILABLE_CRITICAL_EXTENSION, \ RESULT_AUTH_METHOD_NOT_SUPPORTED, RESULT_UNDEFINED_ATTRIBUTE_TYPE, RESULT_NO_SUCH_ATTRIBUTE, \ RESULT_SASL_BIND_IN_PROGRESS, RESULT_CONFIDENTIALITY_REQUIRED, RESULT_INAPPROPRIATE_MATCHING, \ RESULT_CONSTRAINT_VIOLATION, \ RESULT_ATTRIBUTE_OR_VALUE_EXISTS, RESULT_INVALID_ATTRIBUTE_SYNTAX, RESULT_NO_SUCH_OBJECT, RESULT_ALIAS_PROBLEM, \ RESULT_INVALID_DN_SYNTAX, RESULT_ALIAS_DEREFERENCING_PROBLEM, RESULT_INVALID_CREDENTIALS, RESULT_LOOP_DETECTED, \ RESULT_ENTRY_ALREADY_EXISTS, RESULT_LCUP_SECURITY_VIOLATION, RESULT_CANCELED, RESULT_E_SYNC_REFRESH_REQUIRED, \ RESULT_NO_SUCH_OPERATION, RESULT_LCUP_INVALID_DATA, RESULT_OBJECT_CLASS_MODS_PROHIBITED, RESULT_NAMING_VIOLATION, \ RESULT_INSUFFICIENT_ACCESS_RIGHTS, RESULT_OBJECT_CLASS_VIOLATION, RESULT_TOO_LATE, RESULT_CANNOT_CANCEL, \ RESULT_LCUP_UNSUPPORTED_SCHEME, RESULT_BUSY, RESULT_AFFECT_MULTIPLE_DSAS, RESULT_UNAVAILABLE, \ RESULT_NOT_ALLOWED_ON_NON_LEAF, \ RESULT_UNWILLING_TO_PERFORM, RESULT_OTHER, RESULT_LCUP_RELOAD_REQUIRED, RESULT_ASSERTION_FAILED, \ RESULT_AUTHORIZATION_DENIED, RESULT_LCUP_RESOURCES_EXHAUSTED, RESULT_NOT_ALLOWED_ON_RDN, \ RESULT_INAPPROPRIATE_AUTHENTICATION import socket # LDAPException hierarchy class LDAPException(Exception): pass class LDAPOperationResult(LDAPException): def __new__(cls, result=None, description=None, dn=None, message=None, response_type=None, response=None): if cls is LDAPOperationResult and result and result in exception_table: exc = super(LDAPOperationResult, exception_table[result]).__new__( exception_table[result]) # create an exception of the required result error exc.result = result exc.description = description exc.dn = dn exc.message = message exc.type = response_type exc.response = response else: exc = super(LDAPOperationResult, cls).__new__(cls) return exc def __init__(self, result=None, description=None, dn=None, message=None, response_type=None, response=None): self.result = result self.description = description self.dn = dn self.message = message self.type = response_type self.response = response def __str__(self): s = [self.__class__.__name__, str(self.result) if self.result else None, self.description if self.description else None, self.dn if self.dn else None, self.message if self.message else None, self.type if self.type else None, self.response if self.response else None] return ' - '.join(filter(None, s)) def __repr__(self): return self.__str__() class LDAPOperationsErrorResult(LDAPOperationResult): pass class LDAPProtocolErrorResult(LDAPOperationResult): pass class LDAPTimeLimitExceededResult(LDAPOperationResult): pass class LDAPSizeLimitExceededResult(LDAPOperationResult): pass class LDAPAuthMethodNotSupportedResult(LDAPOperationResult): pass class LDAPStrongerAuthRequiredResult(LDAPOperationResult): pass class LDAPReferralResult(LDAPOperationResult): pass class LDAPAdminLimitExceededResult(LDAPOperationResult): pass class LDAPUnavailableCriticalExtensionResult(LDAPOperationResult): pass class LDAPConfidentialityRequiredResult(LDAPOperationResult): pass class LDAPSASLBindInProgressResult(LDAPOperationResult): pass class LDAPNoSuchAttributeResult(LDAPOperationResult): pass class LDAPUndefinedAttributeTypeResult(LDAPOperationResult): pass class LDAPInappropriateMatchingResult(LDAPOperationResult): pass class LDAPConstraintViolationResult(LDAPOperationResult): pass class LDAPAttributeOrValueExistsResult(LDAPOperationResult): pass class LDAPInvalidAttributeSyntaxResult(LDAPOperationResult): pass class LDAPNoSuchObjectResult(LDAPOperationResult): pass class LDAPAliasProblemResult(LDAPOperationResult): pass class LDAPInvalidDNSyntaxResult(LDAPOperationResult): pass class LDAPAliasDereferencingProblemResult(LDAPOperationResult): pass class LDAPInappropriateAuthenticationResult(LDAPOperationResult): pass class LDAPInvalidCredentialsResult(LDAPOperationResult): pass class LDAPInsufficientAccessRightsResult(LDAPOperationResult): pass class LDAPBusyResult(LDAPOperationResult): pass class LDAPUnavailableResult(LDAPOperationResult): pass class LDAPUnwillingToPerformResult(LDAPOperationResult): pass class LDAPLoopDetectedResult(LDAPOperationResult): pass class LDAPNamingViolationResult(LDAPOperationResult): pass class LDAPObjectClassViolationResult(LDAPOperationResult): pass class LDAPNotAllowedOnNotLeafResult(LDAPOperationResult): pass class LDAPNotAllowedOnRDNResult(LDAPOperationResult): pass class LDAPEntryAlreadyExistsResult(LDAPOperationResult): pass class LDAPObjectClassModsProhibitedResult(LDAPOperationResult): pass class LDAPAffectMultipleDSASResult(LDAPOperationResult): pass class LDAPOtherResult(LDAPOperationResult): pass class LDAPLCUPResourcesExhaustedResult(LDAPOperationResult): pass class LDAPLCUPSecurityViolationResult(LDAPOperationResult): pass class LDAPLCUPInvalidDataResult(LDAPOperationResult): pass class LDAPLCUPUnsupportedSchemeResult(LDAPOperationResult): pass class LDAPLCUPReloadRequiredResult(LDAPOperationResult): pass class LDAPCanceledResult(LDAPOperationResult): pass class LDAPNoSuchOperationResult(LDAPOperationResult): pass class LDAPTooLateResult(LDAPOperationResult): pass class LDAPCannotCancelResult(LDAPOperationResult): pass class LDAPAssertionFailedResult(LDAPOperationResult): pass class LDAPAuthorizationDeniedResult(LDAPOperationResult): pass class LDAPESyncRefreshRequiredResult(LDAPOperationResult): pass exception_table = {RESULT_OPERATIONS_ERROR: LDAPOperationsErrorResult, RESULT_PROTOCOL_ERROR: LDAPProtocolErrorResult, RESULT_TIME_LIMIT_EXCEEDED: LDAPTimeLimitExceededResult, RESULT_SIZE_LIMIT_EXCEEDED: LDAPSizeLimitExceededResult, RESULT_AUTH_METHOD_NOT_SUPPORTED: LDAPAuthMethodNotSupportedResult, RESULT_STRONGER_AUTH_REQUIRED: LDAPStrongerAuthRequiredResult, RESULT_REFERRAL: LDAPReferralResult, RESULT_ADMIN_LIMIT_EXCEEDED: LDAPAdminLimitExceededResult, RESULT_UNAVAILABLE_CRITICAL_EXTENSION: LDAPUnavailableCriticalExtensionResult, RESULT_CONFIDENTIALITY_REQUIRED: LDAPConfidentialityRequiredResult, RESULT_SASL_BIND_IN_PROGRESS: LDAPSASLBindInProgressResult, RESULT_NO_SUCH_ATTRIBUTE: LDAPNoSuchAttributeResult, RESULT_UNDEFINED_ATTRIBUTE_TYPE: LDAPUndefinedAttributeTypeResult, RESULT_INAPPROPRIATE_MATCHING: LDAPInappropriateMatchingResult, RESULT_CONSTRAINT_VIOLATION: LDAPConstraintViolationResult, RESULT_ATTRIBUTE_OR_VALUE_EXISTS: LDAPAttributeOrValueExistsResult, RESULT_INVALID_ATTRIBUTE_SYNTAX: LDAPInvalidAttributeSyntaxResult, RESULT_NO_SUCH_OBJECT: LDAPNoSuchObjectResult, RESULT_ALIAS_PROBLEM: LDAPAliasProblemResult, RESULT_INVALID_DN_SYNTAX: LDAPInvalidDNSyntaxResult, RESULT_ALIAS_DEREFERENCING_PROBLEM: LDAPAliasDereferencingProblemResult, RESULT_INAPPROPRIATE_AUTHENTICATION: LDAPInappropriateAuthenticationResult, RESULT_INVALID_CREDENTIALS: LDAPInvalidCredentialsResult, RESULT_INSUFFICIENT_ACCESS_RIGHTS: LDAPInsufficientAccessRightsResult, RESULT_BUSY: LDAPBusyResult, RESULT_UNAVAILABLE: LDAPUnavailableResult, RESULT_UNWILLING_TO_PERFORM: LDAPUnwillingToPerformResult, RESULT_LOOP_DETECTED: LDAPLoopDetectedResult, RESULT_NAMING_VIOLATION: LDAPNamingViolationResult, RESULT_OBJECT_CLASS_VIOLATION: LDAPObjectClassViolationResult, RESULT_NOT_ALLOWED_ON_NON_LEAF: LDAPNotAllowedOnNotLeafResult, RESULT_NOT_ALLOWED_ON_RDN: LDAPNotAllowedOnRDNResult, RESULT_ENTRY_ALREADY_EXISTS: LDAPEntryAlreadyExistsResult, RESULT_OBJECT_CLASS_MODS_PROHIBITED: LDAPObjectClassModsProhibitedResult, RESULT_AFFECT_MULTIPLE_DSAS: LDAPAffectMultipleDSASResult, RESULT_OTHER: LDAPOtherResult, RESULT_LCUP_RESOURCES_EXHAUSTED: LDAPLCUPResourcesExhaustedResult, RESULT_LCUP_SECURITY_VIOLATION: LDAPLCUPSecurityViolationResult, RESULT_LCUP_INVALID_DATA: LDAPLCUPInvalidDataResult, RESULT_LCUP_UNSUPPORTED_SCHEME: LDAPLCUPUnsupportedSchemeResult, RESULT_LCUP_RELOAD_REQUIRED: LDAPLCUPReloadRequiredResult, RESULT_CANCELED: LDAPCanceledResult, RESULT_NO_SUCH_OPERATION: LDAPNoSuchOperationResult, RESULT_TOO_LATE: LDAPTooLateResult, RESULT_CANNOT_CANCEL: LDAPCannotCancelResult, RESULT_ASSERTION_FAILED: LDAPAssertionFailedResult, RESULT_AUTHORIZATION_DENIED: LDAPAuthorizationDeniedResult, RESULT_E_SYNC_REFRESH_REQUIRED: LDAPESyncRefreshRequiredResult} class LDAPExceptionError(LDAPException): pass # abstract layer exceptions class LDAPKeyError(LDAPExceptionError, KeyError): pass class LDAPAttributeError(LDAPExceptionError, AttributeError): pass class LDAPEntryError(LDAPExceptionError): pass class LDAPObjectError(LDAPExceptionError, ValueError): pass class LDAPTypeError(LDAPExceptionError, TypeError): pass class LDAPReaderError(LDAPExceptionError): pass # tls exceptions class LDAPSSLNotSupportedError(LDAPExceptionError, ImportError): pass # connection exceptions class LDAPUnknownStrategyError(LDAPExceptionError): pass class LDAPUnknownAuthenticationMethodError(LDAPExceptionError): pass class LDAPBindError(LDAPExceptionError): pass class LDAPInvalidServerError(LDAPExceptionError): pass class LDAPSASLMechanismNotSupportedError(LDAPExceptionError): pass class LDAPConnectionIsReadOnlyError(LDAPExceptionError): pass class LDAPChangesError(LDAPExceptionError, ValueError): pass class LDAPServerPoolError(LDAPExceptionError): pass class LDAPServerPoolExhaustedError(LDAPExceptionError): pass class LDAPInvalidPort(LDAPExceptionError): pass class LDAPSSLConfigurationError(LDAPExceptionError): pass class LDAPStartTLSError(LDAPExceptionError): pass class LDAPCertificateError(LDAPExceptionError): pass class LDAPPasswordIsMandatoryError(LDAPExceptionError): pass class LDAPInvalidFilterError(LDAPExceptionError): pass class LDAPInvalidScopeError(LDAPExceptionError, ValueError): pass class LDAPInvalidDereferenceAliasesError(LDAPExceptionError, ValueError): pass class LDAPControlsError(LDAPExceptionError, ValueError): pass class LDAPExtensionError(LDAPExceptionError, ValueError): pass class LDAPLDIFError(LDAPExceptionError): pass class LDAPSchemaError(LDAPExceptionError): pass class LDAPSASLPrepError(LDAPExceptionError): pass class LDAPSASLBindInProgressError(LDAPExceptionError): pass class LDAPMetricsError(LDAPExceptionError): pass class LDAPObjectClassError(LDAPExceptionError): pass # communication exceptions class LDAPCommunicationError(LDAPExceptionError): pass class LDAPSocketOpenError(LDAPCommunicationError): pass class LDAPSocketCloseError(LDAPCommunicationError): pass class LDAPSocketReceiveError(LDAPCommunicationError, socket.error): pass class LDAPSocketSendError(LDAPCommunicationError, socket.error): pass class LDAPSessionTerminatedByServer(LDAPCommunicationError): pass class LDAPUnknownResponseError(LDAPCommunicationError): pass class LDAPUnknownRequestError(LDAPCommunicationError): pass class LDAPReferralError(LDAPCommunicationError): pass # pooling exceptions class LDAPConnectionPoolNameIsMandatoryError(LDAPExceptionError): pass class LDAPConnectionPoolNotStartedError(LDAPExceptionError): pass # restartable strategy class LDAPMaximumRetriesError(LDAPExceptionError): def __str__(self): if self.args: if isinstance(self.args, tuple): if len(self.args) > 0: print('Error: ' + self.args[0]) if len(self.args) > 1: print('Exceptions history:') for i, exc in enumerate(self.args[1]): # args[1] contains exception history print(str(i).rjust(5), str(exc[0]), ':', exc[1], '-', exc[2]) if len(self.args) > 2: print('Maximum number of retries reached: ' + str(self.args[2])) # exception factories def communication_exception_factory(exc_to_raise, exc): """ Generates a new exception class of the requested type (subclass of LDAPCommunication) merged with the exception raised by the interpreter """ if exc_to_raise.__name__ in [cls.__name__ for cls in LDAPCommunicationError.__subclasses__()]: return type(exc_to_raise.__name__, (type(exc), LDAPCommunicationError), dict()) else: raise LDAPExceptionError('unable to generate exception type ' + str(exc_to_raise)) python3-ldap-0.9.4.2/python3-ldap/ldap3/core/pooling.py0000666000000000000000000002166312355103746020654 0ustar 00000000000000""" Created on 2014.03.14 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from datetime import datetime from os import linesep from random import randint from .. import POOLING_STRATEGY_FIRST, POOLING_STRATEGY_ROUND_ROBIN, POOLING_STRATEGY_RANDOM, POOLING_STRATEGIES from .exceptions import LDAPUnknownStrategyError, LDAPServerPoolError, LDAPServerPoolExhaustedError from .server import Server class ServerPoolState(object): def __init__(self, server_pool): self.servers = [] self.strategy = server_pool.strategy self.server_pool = server_pool self.refresh() self.initialize_time = datetime.now() self.last_used_server = randint(0, len(self.servers)-1) def __str__(self): s = 'servers: ' if self.servers: for server in self.servers: s += str(server) + linesep else: s += 'None' s += 'Pool strategy: ' + str(self.strategy) s += ' - Last used server: ' + ('None' if self.last_used_server == -1 else str(self.servers[self.last_used_server])) return s def refresh(self): self.servers = [] for server in self.server_pool.servers: self.servers.append(server) self.last_used_server = randint(0, len(self.servers) - 1) def get_current_server(self): return self.servers[self.last_used_server] def get_server(self): if self.servers: if self.server_pool.strategy == POOLING_STRATEGY_FIRST: if self.server_pool.active: # returns the first active server self.last_used_server = self.find_active_server(starting=0, exhaust=self.server_pool.exhaust) else: # returns always the first server - no pooling self.last_used_server = 0 elif self.server_pool.strategy == POOLING_STRATEGY_ROUND_ROBIN: if self.server_pool.active: # returns the next active server in a circular range self.last_used_server = self.find_active_server(self.last_used_server + 1, exhaust=self.server_pool.exhaust) else: # returns the next server in a circular range self.last_used_server = self.last_used_server + 1 if (self.last_used_server + 1) < len(self.servers) else 0 elif self.server_pool.strategy == POOLING_STRATEGY_RANDOM: if self.server_pool.active: self.last_used_server = self.find_active_random_server(exhaust=self.server_pool.exhaust) else: # returns a random server in the pool self.last_used_server = randint(0, len(self.servers)) else: raise LDAPUnknownStrategyError('unknown server pooling strategy') return self.servers[self.last_used_server] else: raise LDAPServerPoolError('no servers in server pool') def find_active_random_server(self, exhaust=True): while True: temp_list = self.servers[:] # copy while temp_list: # pops a random server from a temp list and checks its # availability, if not available tries another one server = temp_list.pop(randint(0, len(temp_list) - 1)) if server.check_availability(): # returns a random active server in the pool return self.servers.index(server) if exhaust: raise LDAPServerPoolExhaustedError('no random active server in server pool') def find_active_server(self, starting=0, exhaust=True): while True: index = starting while index < len(self.servers): if self.servers[index].check_availability(): break index += 1 else: # if no server found in the list (from starting index) # checks starting from the base of the list index = 0 while index < starting: if self.servers[index].check_availability(): break index += 1 else: if exhaust: raise LDAPServerPoolExhaustedError('no active server available in server pool') else: continue return index def __len__(self): return len(self.servers) class ServerPool(object): def __init__(self, servers=None, pool_strategy=POOLING_STRATEGY_ROUND_ROBIN, active=True, exhaust=False): if pool_strategy not in POOLING_STRATEGIES: raise LDAPUnknownStrategyError('unknown pooling strategy') if exhaust and not active: raise LDAPServerPoolError('pools can be exhausted only when checking for active servers') self.servers = [] self.pool_states = dict() self.active = active self.exhaust = exhaust if isinstance(servers, (list, tuple)): for server in servers: self.add(server) elif isinstance(servers, Server): self.add(servers) self.strategy = pool_strategy def __str__(self): s = 'servers: ' if self.servers: for server in self.servers: s += str(server) + linesep else: s += 'None' s += 'Pool strategy: ' + str(self.strategy) s += ' - ' + 'active only: ' + ('True' if self.active else 'False') s += ' - ' + 'exhaust pool: ' + ('True' if self.exhaust else 'False') return s def __repr__(self): r = 'ServerPool(servers=' if self.servers: r += '[' for server in self.servers: r += server.__repr__() + ', ' r = r[:-2] + ']' else: r += 'None' r += ', pool_strategy={0.strategy!r}'.format(self) r += ', active={0.active!r}'.format(self) r += ', exhaust={0.exhaust!r}'.format(self) r += ')' return r def __len__(self): return len(self.servers) def __getitem__(self, item): return self.servers[item] def __iter__(self): return self.servers.__iter__() def add(self, servers): if isinstance(servers, Server): if servers not in self.servers: self.servers.append(servers) elif isinstance(servers, (list, tuple)): for server in servers: if isinstance(server, Server): self.servers.append(server) else: raise LDAPServerPoolError('server in ServerPool must be a Server') else: raise LDAPServerPoolError('server must be a Server or a list of Server') for connection in self.pool_states: # notifies connections using this pool to refresh self.pool_states[connection].refresh() def remove(self, server): if server in self.servers: self.servers.remove(server) else: raise LDAPServerPoolError('server not in server pool') for connection in self.pool_states: # notifies connections using this pool to refresh self.pool_states[connection].refresh() def initialize(self, connection): pool_state = ServerPoolState(self) # registers pool_state in ServerPool object self.pool_states[connection] = pool_state def get_server(self, connection): if connection in self.pool_states: return self.pool_states[connection].get_server() else: raise LDAPServerPoolError('connection not in ServerPoolState') def get_current_server(self, connection): if connection in self.pool_states: return self.pool_states[connection].get_current_server() else: raise LDAPServerPoolError('connection not in ServerPoolState') python3-ldap-0.9.4.2/python3-ldap/ldap3/core/server.py0000666000000000000000000002155112355103746020507 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from socket import getaddrinfo, gaierror from .. import GET_NO_INFO, GET_DSA_INFO, GET_SCHEMA_INFO, GET_ALL_INFO, ALL_ATTRIBUTES, SEARCH_SCOPE_BASE_OBJECT, LDAP_MAX_INT from threading import Lock from .exceptions import LDAPInvalidPort from ..protocol.rfc4512 import SchemaInfo, DsaInfo from .tls import Tls import socket class Server(object): """ LDAP Server definition class Allowed_referral_hosts can be None (default), or a list of tuples of allowed servers ip address or names to contact while redirecting search to referrals. The second element of the tuple is a boolean to indicate if authentication to that server is allowed; if False only anonymous bind will be used. Per RFC 4516. Use ('*', False) to allow any host with anonymous bind, use ('*', True) to allow any host with same authentication of Server. """ _real_servers = dict() # dictionary of real servers currently active, the key is the host part of the server address # and the value is the messageId counter for all connection to that host) def __init__(self, host, port=None, use_ssl=False, allowed_referral_hosts=None, get_info=GET_NO_INFO, tls=None): if not use_ssl and not port: port = 389 elif use_ssl and not port: port = 636 if host.startswith('ldap://'): self.host = host[7:] elif host.startswith('ldaps://'): self.host = host[8:] else: self.host = host try: self.address = getaddrinfo(self.host, port)[0][4][0] except gaierror: self.address = self.host if isinstance(port, int): self.port = port else: raise LDAPInvalidPort('port must be an integer') if isinstance(allowed_referral_hosts, (list, tuple)): self.allowed_referral_hosts = [] for refServer in allowed_referral_hosts: if isinstance(refServer, tuple): if isinstance(refServer[1], bool): self.allowed_referral_hosts.append(refServer) elif isinstance(allowed_referral_hosts, tuple): if isinstance(allowed_referral_hosts[1], bool): self.allowed_referral_hosts = [allowed_referral_hosts] else: self.allowed_referral_hosts = [] self.ssl = True if use_ssl else False self.tls = Tls() if self.ssl and not tls else tls self.name = ('ldaps' if self.ssl else 'ldap') + '://' + self.host + ':' + str(self.port) self.get_info = get_info self._dsa_info = None self._schema_info = None self.lock = Lock() self.message_id_lock = Lock() def __str__(self): if self.host: s = self.name + (' - ssl' if self.ssl else ' - cleartext') else: s = object.__str__(self) return s def __repr__(self): r = 'Server(host={0.host!r}, port={0.port!r}, use_ssl={0.ssl!r}'.format(self) r += '' if not self.allowed_referral_hosts else ', allowed_referral_hosts={0.allowed_referral_hosts!r}'.format(self) r += '' if self.tls is None else ', tls={0.tls!r}'.format(self) r += '' if not self.get_info else ', get_info={0.get_info!r}'.format(self) r += ')' return r def is_valid(self): return True if self.address else False def check_availability(self): """ Tries to open, connect and close a socket to specified address and port to check availability. """ available = True temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: temp_socket.connect((self.host, self.port)) except socket.error: available = False finally: try: temp_socket.shutdown(socket.SHUT_RDWR) temp_socket.close() except socket.error: available = False return available def next_message_id(self): """ messageId is unique in all connections to the server. """ with self.message_id_lock: if self.address and self.address in Server._real_servers: Server._real_servers[self.address] += 1 if Server._real_servers[self.address] >= LDAP_MAX_INT: # wrap as per MAXINT (2147483647) in RFC4511 specification Server._real_servers[self.address] = 1 # 0 is reserved for Unsolicited messages else: Server._real_servers[self.address] = 1 return Server._real_servers[self.address] def _get_dsa_info(self, connection): """ Retrieve DSE operational attribute as per RFC4512 (5.1). """ result = connection.search('', '(objectClass=*)', SEARCH_SCOPE_BASE_OBJECT, attributes=ALL_ATTRIBUTES, get_operational_attributes=True) self._dsa_info = None with self.lock: if isinstance(result, bool): # sync request self._dsa_info = DsaInfo(connection.response[0]['attributes']) if result else None elif result: # async request, must check if attributes in response results, _ = connection.get_response(result) if len(results) == 1 and 'attributes' in results[0]: self._dsa_info = DsaInfo(results[0]['attributes']) def _get_schema_info(self, connection, entry=''): """ Retrieve schema from subschemaSubentry DSE attribute, per RFC 4512 (4.4 and 5.1); entry = '' means DSE. """ schema_entry = None if self._dsa_info and entry == '': # subschemaSubentry already present in dsaInfo schema_entry = self._dsa_info.schema_entry[0] if self._dsa_info.schema_entry else None else: result = connection.search(entry, '(objectClass=*)', SEARCH_SCOPE_BASE_OBJECT, attributes=['subschemaSubentry'], get_operational_attributes=True) if isinstance(result, bool): # sync request schema_entry = connection.response[0]['attributes']['subschemaSubentry'][0] if result else None else: # async request, must check if subschemaSubentry in attributes results, _ = connection.get_response(result) if len(results) == 1 and 'attributes' in results[0] and 'subschemaSubentry' in results[0]['attributes']: schema_entry = results[0]['attributes']['subschemaSubentry'][0] result = None if schema_entry: result = connection.search(schema_entry, search_filter='(objectClass=subschema)', search_scope=SEARCH_SCOPE_BASE_OBJECT, attributes=ALL_ATTRIBUTES, get_operational_attributes=True) with self.lock: self._schema_info = None if result: if isinstance(result, bool): # sync request self._schema_info = SchemaInfo(schema_entry, connection.response[0]['attributes']) if result else None else: # async request, must check if attributes in response results, _ = connection.get_response(result) if len(results) == 1 and 'attributes' in results[0]: self._schema_info = SchemaInfo(schema_entry, results[0]['attributes']) def get_info_from_server(self, connection): """ read info from DSE and from subschema """ if not connection.closed: if self.get_info in [GET_DSA_INFO, GET_ALL_INFO]: self._get_dsa_info(connection) if self.get_info in [GET_SCHEMA_INFO, GET_ALL_INFO]: self._get_schema_info(connection) connection.response = None connection.result = None @property def info(self): return self._dsa_info @property def schema(self): return self._schema_info python3-ldap-0.9.4.2/python3-ldap/ldap3/core/tls.py0000666000000000000000000003167312355110261017777 0ustar 00000000000000""" Created on 2013.08.05 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ import re from .exceptions import LDAPSSLNotSupportedError, LDAPSSLConfigurationError, LDAPStartTLSError, LDAPCertificateError try: # noinspection PyUnresolvedReferences import ssl except ImportError: raise LDAPSSLNotSupportedError('SSL not supported in this Python interpreter') try: # noinspection PyUnresolvedReferences from ssl import CertificateError except ImportError: class CertificateError(ValueError): # fix for Python 2, code from Python 3.3 standard library pass try: # noinspection PyUnresolvedReferences from ssl import create_default_context, Purpose # defined in Python 3.4 use_ssl_context = True except ImportError: use_ssl_context = False from os import path # noinspection PyProtectedMember class Tls(object): """ tls/ssl configuration for Server object Starting from python 3-4 it uses the SSLContext object that tries to read the CAs defined at system level ca_certs_path and ca_certs_data are valid only when using SSLContext local_private_key_password is valid only when using SSLContext """ def __init__(self, local_private_key_file=None, local_certificate_file=None, validate=ssl.CERT_NONE, version=None, ca_certs_file=None, valid_names=None, ca_certs_path=None, ca_certs_data=None, local_private_key_password=None): if validate in [ssl.CERT_NONE, ssl.CERT_OPTIONAL, ssl.CERT_REQUIRED]: self.validate = validate elif validate: raise LDAPSSLConfigurationError('invalid validate parameter') if ca_certs_file and path.exists(ca_certs_file): self.ca_certs_file = ca_certs_file elif ca_certs_file: raise LDAPSSLConfigurationError('invalid CA public key file') else: self.ca_certs_file = None if ca_certs_path and use_ssl_context and path.exists(ca_certs_path): self.ca_certs_path = ca_certs_path elif ca_certs_path and not use_ssl_context: raise LDAPSSLNotSupportedError('cannot use CA public keys path, SSLContext not available') elif ca_certs_path: raise LDAPSSLConfigurationError('invalid CA public keys path') else: self.ca_certs_path = None if ca_certs_data and use_ssl_context: self.ca_certs_data = ca_certs_data elif ca_certs_data: raise LDAPSSLNotSupportedError('cannot use CA data, SSLContext not available') else: self.ca_certs_data = None if local_private_key_password and use_ssl_context: self.private_key_password = local_private_key_password elif local_private_key_password: raise LDAPSSLNotSupportedError('cannot use local private key password, SSLContext is not available') else: self.private_key_password = None self.version = version self.private_key_file = local_private_key_file self.certificate_file = local_certificate_file self.valid_names = valid_names def __str__(self): s = [ 'protocol: ' + str(self.version), 'client private key: ' + ('present ' if self.private_key_file else 'not present'), 'client certificate: ' + ('present ' if self.certificate_file else 'not present'), 'private key password: ' + ('present ' if self.private_key_password else 'not present'), 'CA certificates file: ' + ('present ' if self.ca_certs_file else 'not present'), 'CA certificates path: ' + ('present ' if self.ca_certs_path else 'not present'), 'CA certificates data: ' + ('present ' if self.ca_certs_data else 'not present'), 'verify mode: ' + str(self.validate), 'valid names: ' + str(self.valid_names) ] return ' - '.join(s) def __repr__(self): r = '' if self.private_key_file is None else ', local_private_key_file={0.private_key_file!r}'.format(self) r += '' if self.certificate_file is None else ', local_certificate_file={0.certificate_file!r}'.format(self) r += '' if self.validate is None else ', validate={0.validate!r}'.format(self) r += '' if self.version is None else ', version={0.version!r}'.format(self) r += '' if self.ca_certs_file is None else ', ca_certs_file={0.ca_certs_file!r}'.format(self) r += '' if self.ca_certs_path is None else ', ca_certs_path={0.ca_certs_path!r}'.format(self) r += '' if self.ca_certs_data is None else ', ca_certs_data={0.ca_certs_data!r}'.format(self) r = 'Tls(' + r[2:] + ')' return r def wrap_socket(self, connection, do_handshake=False): """ Adds TLS to the connection socket """ if use_ssl_context: ssl_context = create_default_context(purpose=Purpose.SERVER_AUTH, cafile=self.ca_certs_file, capath=self.ca_certs_path, cadata=self.ca_certs_data) if self.private_key_file: ssl_context.load_cert_chain(self.certificate_file, keyfile=self.private_key_file, password=self.private_key_password) ssl_context.check_hostname = False ssl_context.verify_mode = self.validate if not self.version is None: # if version is present overrides the default context version ssl_context.protocol = self.version wrapped_socket = ssl_context.wrap_socket(connection.socket, server_side=False, do_handshake_on_connect=do_handshake) else: if self.version is None: self.version = ssl.PROTOCOL_SSLv23 wrapped_socket = ssl.wrap_socket(connection.socket, keyfile=self.private_key_file, certfile=self.certificate_file, server_side=False, cert_reqs=self.validate, ssl_version=self.version, ca_certs=self.ca_certs_file, do_handshake_on_connect=do_handshake) if do_handshake and (self.validate == ssl.CERT_REQUIRED or self.validate == ssl.CERT_OPTIONAL): check_hostname(wrapped_socket, connection.server.host, self.valid_names) connection.socket = wrapped_socket return def start_tls(self, connection): if connection.server.ssl: # ssl already established at server level return False if (connection.tls_started and not connection._executing_deferred) or connection.strategy._outstanding or connection.sasl_in_progress: # Per RFC 4513 (3.1.1) return False connection.starting_tls = True result = connection.extended('1.3.6.1.4.1.1466.20037') if not connection.strategy.sync: # async - _start_tls must be executed by the strategy connection.get_response(result) return True else: if connection.result['description'] not in ['success']: # startTLS failed connection.last_error = 'startTLS failed - ' + str(connection.result['description']) raise LDAPStartTLSError(connection.last_error) return self._start_tls(connection) def _start_tls(self, connection): self.wrap_socket(connection, do_handshake=True) if connection.usage: connection._usage.wrapped_sockets += 1 connection.starting_tls = False connection.tls_started = True return True def _dnsname_match_backport(dn, hostname, max_wildcards=1): """Matching according to RFC 6125, section 6.4.3 http://tools.ietf.org/html/rfc6125#section-6.4.3 """ pats = [] if not dn: return False dn_array = dn.split(r'.') leftmost = dn_array[0] remainder = dn_array[1:] wildcards = leftmost.count('*') if wildcards > max_wildcards: # Issue #17980: avoid denials of service by refusing more # than one wildcard per fragment. A survery of established # policy among SSL implementations showed it to be a # reasonable choice. raise CertificateError( "too many wildcards in certificate DNS name: " + repr(dn)) # speed up common case w/o wildcards if not wildcards: return dn.lower() == hostname.lower() # RFC 6125, section 6.4.3, subitem 1. # The client SHOULD NOT attempt to match a presented identifier in which # the wildcard character comprises a label other than the left-most label. if leftmost == '*': # When '*' is a fragment by itself, it matches a non-empty dotless # fragment. pats.append('[^.]+') elif leftmost.startswith('xn--') or hostname.startswith('xn--'): # RFC 6125, section 6.4.3, subitem 3. # The client SHOULD NOT attempt to match a presented identifier # where the wildcard character is embedded within an A-label or # U-label of an internationalized domain name. pats.append(re.escape(leftmost)) else: # Otherwise, '*' matches any dotless string, e.g. www* pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) # add the remaining fragments, ignore any wildcards for frag in remainder: pats.append(re.escape(frag)) pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) return pat.match(hostname) def match_hostname_backport(cert, hostname): """ Fix for Python2; code from Python 3.4.1 standard library. Verify that *cert* (in decoded format as returned by SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 rules are followed, but IP addresses are not accepted for *hostname*. CertificateError is raised on failure. On success, the function returns nothing. """ if not cert: raise ValueError("empty or no certificate, match_hostname needs a " "SSL socket or SSL context with either " "CERT_OPTIONAL or CERT_REQUIRED") dnsnames = [] san = cert.get('subjectAltName', ()) for key, value in san: if key == 'DNS': if _dnsname_match_backport(value, hostname): return dnsnames.append(value) if not dnsnames: # The subject is only checked when there is no dNSName entry # in subjectAltName for sub in cert.get('subject', ()): for key, value in sub: # XXX according to RFC 2818, the most specific Common Name # must be used. if key == 'commonName': if _dnsname_match_backport(value, hostname): return dnsnames.append(value) if len(dnsnames) > 1: raise CertificateError("hostname %r doesn't match either of %s" % (hostname, ', '.join(map(repr, dnsnames)))) elif len(dnsnames) == 1: raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) else: raise CertificateError("no appropriate commonName or subjectAltName fields were found") def check_hostname(sock, server_name, additional_names): server_certificate = sock.getpeercert() host_names = [server_name] + (additional_names if isinstance(additional_names, (list, tuple)) else [additional_names]) for host_name in host_names: if host_name is None: continue elif host_name == '*': return try: ssl.match_hostname(server_certificate, host_name) # raise CertificateError if certificate doesn't match server name return except AttributeError: match_hostname_backport(server_certificate, host_name) return except CertificateError: pass raise LDAPCertificateError("hostname doesn't match") python3-ldap-0.9.4.2/python3-ldap/ldap3/core/usage.py0000666000000000000000000002215312355103746020304 0ustar 00000000000000""" Created on 2014.03.15 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from datetime import datetime, timedelta from os import linesep from .exceptions import LDAPMetricsError class ConnectionUsage(object): """ Collect statistics on connection usage """ def reset(self): self.opened_sockets = 0 self.closed_sockets = 0 self.wrapped_sockets = 0 self.bytes_transmitted = 0 self.bytes_received = 0 self.messages_transmitted = 0 self.messages_received = 0 self.operations = 0 self.abandon_operations = 0 self.add_operations = 0 self.bind_operations = 0 self.compare_operations = 0 self.delete_operations = 0 self.extended_operations = 0 self.modify_operations = 0 self.modify_dn_operations = 0 self.search_operations = 0 self.unbind_operations = 0 self.referrals_received = 0 self.referrals_followed = 0 self.restartable_failures = 0 self.restartable_successes = 0 self.servers_from_pool = 0 def __init__(self): self.initial_connection_start_time = None self.open_socket_start_time = None self.connection_stop_time = None self.opened_sockets = 0 self.closed_sockets = 0 self.wrapped_sockets = 0 self.bytes_transmitted = 0 self.bytes_received = 0 self.messages_transmitted = 0 self.messages_received = 0 self.operations = 0 self.abandon_operations = 0 self.add_operations = 0 self.bind_operations = 0 self.compare_operations = 0 self.delete_operations = 0 self.extended_operations = 0 self.modify_operations = 0 self.modify_dn_operations = 0 self.search_operations = 0 self.unbind_operations = 0 self.referrals_received = 0 self.referrals_followed = 0 self.restartable_failures = 0 self.restartable_successes = 0 self.servers_from_pool = 0 def __repr__(self): r = 'Connection Usage:' + linesep r += ' Time: [elapsed: ' + str(self.elapsed_time) + ']' + linesep r += ' Initial start time: ' + (str(self.initial_connection_start_time.isoformat()) if self.initial_connection_start_time else '') + linesep r += ' Open socket time: ' + (str(self.open_socket_start_time.isoformat()) if self.open_socket_start_time else '') + linesep r += ' Close socket time: ' + (str(self.connection_stop_time.isoformat()) if self.connection_stop_time else '') + linesep r += ' Server:' + linesep r += ' Servers from pool: ' + str(self.servers_from_pool) + linesep r += ' Sockets opened: ' + str(self.opened_sockets) + linesep r += ' Sockets closed: ' + str(self.closed_sockets) + linesep r += ' Sockets wrapped: ' + str(self.wrapped_sockets) + linesep r += ' Bytes: ' + str(self.bytes_transmitted + self.bytes_received) + linesep r += ' Transmitted: ' + str(self.bytes_transmitted) + linesep r += ' Received: ' + str(self.bytes_received) + linesep r += ' Messages: ' + str(self.messages_transmitted + self.messages_received) + linesep r += ' Transmitted: ' + str(self.messages_transmitted) + linesep r += ' Received: ' + str(self.messages_received) + linesep r += ' Operations: ' + str(self.operations) + linesep r += ' Abandon: ' + str(self.abandon_operations) + linesep r += ' Bind: ' + str(self.bind_operations) + linesep r += ' Compare: ' + str(self.compare_operations) + linesep r += ' Delete: ' + str(self.delete_operations) + linesep r += ' Extended: ' + str(self.extended_operations) + linesep r += ' Modify: ' + str(self.modify_operations) + linesep r += ' ModifyDn: ' + str(self.modify_dn_operations) + linesep r += ' Search: ' + str(self.search_operations) + linesep r += ' Unbind: ' + str(self.unbind_operations) + linesep r += ' Referrals: ' + linesep r += ' Received: ' + str(self.referrals_received) + linesep r += ' Followed: ' + str(self.referrals_followed) + linesep r += ' Restartable tries: ' + str(self.restartable_failures + self.restartable_successes) + linesep r += ' Failed restarts: ' + str(self.restartable_failures) + linesep r += ' Successful restarts: ' + str(self.restartable_successes) + linesep return r def __str__(self): return self.__repr__() def __iadd__(self, other): if not isinstance(other, ConnectionUsage): raise LDAPMetricsError('unable to add to ConnectionUsage') self.opened_sockets += other.opened_sockets self.closed_sockets += other.closed_sockets self.wrapped_sockets += other.wrapped_sockets self.bytes_transmitted += other.bytes_transmitted self.bytes_received += other.bytes_received self.messages_transmitted += other.messages_transmitted self.messages_received += other.messages_received self.operations += other.operations self.abandon_operations += other.abandon_operations self.add_operations += other.add_operations self.bind_operations += other.bind_operations self.compare_operations += other.compare_operations self.delete_operations += other.delete_operations self.extended_operations += other.extended_operations self.modify_operations += other.modify_operations self.modify_dn_operations += other.modify_dn_operations self.search_operations += other.search_operations self.unbind_operations += other.unbind_operations self.referrals_received += other.referrals_received self.referrals_followed += other.referrals_followed self.restartable_failures += other.restartable_failures self.restartable_successes += other.restartable_successes self.servers_from_pool += other.servers_from_pool return self def transmitted_message(self, message, length): self.bytes_transmitted += length self.operations += 1 self.messages_transmitted += 1 if message['type'] == 'abandonRequest': self.abandon_operations += 1 elif message['type'] == 'addRequest': self.add_operations += 1 elif message['type'] == 'bindRequest': self.bind_operations += 1 elif message['type'] == 'compareRequest': self.compare_operations += 1 elif message['type'] == 'delRequest': self.delete_operations += 1 elif message['type'] == 'extendedReq': self.extended_operations += 1 elif message['type'] == 'modifyRequest': self.modify_operations += 1 elif message['type'] == 'modDNRequest': self.modify_dn_operations += 1 elif message['type'] == 'searchRequest': self.search_operations += 1 elif message['type'] == 'unbindRequest': self.unbind_operations += 1 else: raise LDAPMetricsError('unable to collect usage for unknown message type') def received_message(self, length): self.bytes_received += length self.messages_received += 1 def start(self, reset=True): if reset: self.reset() self.open_socket_start_time = datetime.now() self.connection_stop_time = None if not self.initial_connection_start_time: self.initial_connection_start_time = self.open_socket_start_time def stop(self): if self.open_socket_start_time: self.connection_stop_time = datetime.now() @property def elapsed_time(self): if self.connection_stop_time: return self.connection_stop_time - self.open_socket_start_time else: # noinspection PyTypeChecker return (datetime.now() - self.open_socket_start_time) if self.open_socket_start_time else timedelta(0) python3-ldap-0.9.4.2/python3-ldap/ldap3/core/__init__.py0000666000000000000000000000146612355103746020743 0ustar 00000000000000""" Created on 2014.03.14 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/0000777000000000000000000000000012355117540017157 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/getBindDn.py0000666000000000000000000000327412355110214021364 0ustar 00000000000000""" Created on 2014.04.30 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.exceptions import LDAPExtensionError from ..protocol.novell import Identity from pyasn1.codec.ber import decoder def get_bind_dn(connection): resp = connection.extended('2.16.840.1.113719.1.27.100.31', None) if not connection.strategy.sync: _, result = connection.get_response(resp) else: result = connection.result connection.response = decode_response(result) populate_result_dict(result, connection.response) return connection.response def populate_result_dict(result, value): result['identity'] = value def decode_response(result): if result['responseValue']: decoded, unprocessed = decoder.decode(result['responseValue'], asn1Spec=Identity()) if unprocessed: raise LDAPExtensionError('error decoding extended response value') return str(decoded) return None python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/modifyPassword.py0000666000000000000000000000436712355110214022544 0ustar 00000000000000""" Created on 2014.04.30 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.exceptions import LDAPExtensionError from ..protocol.rfc3062 import PasswdModifyRequestValue, PasswdModifyResponseValue from pyasn1.codec.ber import decoder def modify_password(connection, user=None, old_password=None, new_password=None): request = PasswdModifyRequestValue() if user: request['userIdentity'] = user if old_password: request['oldPasswd'] = old_password if new_password: request['newPasswd'] = new_password resp = connection.extended('1.3.6.1.4.1.4203.1.11.1', request) if not connection.strategy.sync: _, result = connection.get_response(resp) else: result = connection.result connection.response = decode_response(result) populate_result_dict(result, connection.response) return connection.response def populate_result_dict(result, value): result['genPasswd'] = value def modify_password_request_to_dict(request): return {'userIdentity': str(request['userIdentity']), 'oldPasswd': str(request['oldPasswd']), 'newPasswd': str(request['newPasswd'])} def decode_response(result): if result['responseValue']: decoded, unprocessed = decoder.decode(result['responseValue'], asn1Spec=PasswdModifyResponseValue()) if unprocessed: raise LDAPExtensionError('error decoding extended response value') return str(decoded['genPasswd']) return None python3-ldap-0.9.4.2/python3-ldap/ldap3/extend/whoAmI.py0000666000000000000000000000266612355106765020736 0ustar 00000000000000""" Created on 2014.04.30 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ # implements rfc4532 def who_am_i(connection): resp = connection.extended('1.3.6.1.4.1.4203.1.11.3', None) if not connection.strategy.sync: _, result = connection.get_response(resp) else: result = connection.result connection.response = decode_response(result) populate_result_dict(result, connection.response) return connection.response def populate_result_dict(result, value): result['AuthzId'] = value def decode_response(result): if result['responseValue']: decoded = result['responseValue'].decode('utf-8') return decoded return Nonepython3-ldap-0.9.4.2/python3-ldap/ldap3/extend/__init__.py0000666000000000000000000000346512355103746021303 0ustar 00000000000000""" Created on 2014.04.28 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..extend.whoAmI import who_am_i from ..extend.getBindDn import get_bind_dn from ..extend.modifyPassword import modify_password class ExtendedOperationsContainer(object): class StandardExtendedOperations(object): def __init__(self, container): self._container = container def who_am_i(self): return who_am_i(self._container.connection) def modify_password(self, user=None, old_password=None, new_password=None): return modify_password(self._container.connection, user, old_password, new_password) class NovellExtendedOperations(object): def __init__(self, container): self._container = container def get_bind_dn(self): return get_bind_dn(self._container.connection) def __init__(self, connection): self.connection = connection self.novell = self.NovellExtendedOperations(self) self.standard = self.StandardExtendedOperations(self)python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/0000777000000000000000000000000012355117540017670 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/abandon.py0000666000000000000000000000215212355103746021647 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import AbandonRequest, MessageID # AbandonRequest ::= [APPLICATION 16] MessageID def abandon_operation(msg_id): request = AbandonRequest(MessageID(msg_id)) return request def abandon_request_to_dict(request): return {'messageId': str(request[0]), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/add.py0000666000000000000000000000475012355103746021003 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import AddRequest, LDAPDN, AttributeList, Attribute, AttributeDescription, ValsAtLeast1, ResultCode from ..protocol.convert import referrals_to_list, attributes_to_dict, validate_attribute_value # AddRequest ::= [APPLICATION 8] SEQUENCE { # entry LDAPDN, # attributes AttributeList } def add_operation(dn, attributes, schema=None): # attributes is a dictionary in the form 'attribute': ['val1', 'val2', 'valN'] attribute_list = AttributeList() for pos, attribute in enumerate(attributes): attribute_list[pos] = Attribute() attribute_list[pos]['type'] = AttributeDescription(attribute) vals = ValsAtLeast1() if isinstance(attributes[attribute], (list, tuple)): for index, value in enumerate(attributes[attribute]): vals.setComponentByPosition(index, validate_attribute_value(schema, attribute, value)) else: vals.setComponentByPosition(0, validate_attribute_value(schema, attribute, attributes[attribute])) attribute_list[pos]['vals'] = vals request = AddRequest() request['entry'] = LDAPDN(dn) request['attributes'] = attribute_list return request def add_request_to_dict(request): return {'entry': str(request['entry']), 'attributes': attributes_to_dict(request['attributes'])} def add_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/bind.py0000666000000000000000000000624612355103746021171 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from .. import AUTH_SIMPLE, AUTH_ANONYMOUS, AUTH_SASL from ..core.exceptions import LDAPPasswordIsMandatoryError, LDAPUnknownAuthenticationMethodError from ..protocol.sasl.sasl import validate_simple_password from ..protocol.rfc4511 import Version, AuthenticationChoice, Simple, BindRequest, ResultCode, SaslCredentials from ..protocol.convert import authentication_choice_to_dict, referrals_to_list # BindRequest ::= [APPLICATION 0] SEQUENCE { # version INTEGER (1 .. 127), # name LDAPDN, # authentication AuthenticationChoice } def bind_operation(version, authentication, name='', password=None, sasl_mechanism=None, sasl_credentials=None): request = BindRequest() request['version'] = Version(version) if name is None: name = '' request['name'] = name if authentication == AUTH_SIMPLE: if password: request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(validate_simple_password(password))) else: raise LDAPPasswordIsMandatoryError('password is mandatory') elif authentication == AUTH_SASL: sasl_creds = SaslCredentials() sasl_creds['mechanism'] = sasl_mechanism if sasl_credentials: sasl_creds['credentials'] = sasl_credentials request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_creds) elif authentication == AUTH_ANONYMOUS: request['name'] = '' request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple('')) else: raise LDAPUnknownAuthenticationMethodError('unknown authentication method') return request def bind_request_to_dict(request): return {'version': int(request['version']), 'name': str(request['name']), 'authentication': authentication_choice_to_dict(request['authentication'])} def bind_response_to_dict(response): return {'result': int(response['resultCode']), 'description': ResultCode().getNamedValues().getName(response['resultCode']), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), 'saslCreds': str(response['serverSaslCreds'])} python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/compare.py0000666000000000000000000000414212355103746021674 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.convert import validate_attribute_value from ..protocol.rfc4511 import CompareRequest, AttributeValueAssertion, AttributeDescription, LDAPDN, AssertionValue, ResultCode from ..operation.search import ava_to_dict from ..operation.bind import referrals_to_list # CompareRequest ::= [APPLICATION 14] SEQUENCE { # entry LDAPDN, # ava AttributeValueAssertion } def compare_operation(dn, attribute, value, schema=None): ava = AttributeValueAssertion() ava['attributeDesc'] = AttributeDescription(attribute) ava['assertionValue'] = AssertionValue(validate_attribute_value(schema, attribute, value)) request = CompareRequest() request['entry'] = LDAPDN(dn) request['ava'] = ava return request def compare_request_to_dict(request): ava = ava_to_dict(request['ava']) return {'entry': str(request['entry']), 'attribute': ava['attribute'], 'value': ava['value']} def compare_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/delete.py0000666000000000000000000000263512355103746021515 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import DelRequest, LDAPDN, ResultCode from ..operation.bind import referrals_to_list # DelRequest ::= [APPLICATION 10] LDAPDN def delete_operation(dn): request = DelRequest(LDAPDN(dn)) return request def delete_request_to_dict(request): return {'entry': str(request)} def delete_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'referrals': referrals_to_list(response['referral']), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/extended.py0000666000000000000000000000520712355106663022052 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from pyasn1.type.univ import OctetString from ..core.exceptions import LDAPExtensionError from ..protocol.rfc4511 import ExtendedRequest, RequestName, ResultCode, RequestValue from ..protocol.convert import decode_referrals from pyasn1.codec.ber import encoder # ExtendedRequest ::= [APPLICATION 23] SEQUENCE { # requestName [0] LDAPOID, # requestValue [1] OCTET STRING OPTIONAL } def extended_operation(request_name, request_value=None): request = ExtendedRequest() request['requestName'] = RequestName(request_name) if request_value and not isinstance(request_value, (str, bytes, bytearray)): request['requestValue'] = RequestValue(encoder.encode(request_value)) elif request_value and isinstance(request_value, (str, bytes, bytearray)): request['requestValue'] = RequestValue(encoder.encode(OctetString(request_value))) elif request_value is not None: raise LDAPExtensionError('unable to encode value for extended operation') return request def extended_request_to_dict(request): return {'name': str(request['requestName']), 'value': str(request['requestValue']) if request['requestValue'] else None} def extended_response_to_dict(response): return {'result': int(response[0]), 'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']), 'description': ResultCode().getNamedValues().getName(response[0]), 'referrals': decode_referrals(response['referral']), 'responseName': str(response['responseName']), 'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()} def intermediate_response_to_dict(response): return {'responseName': str(response['responseName']), 'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()} python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/modify.py0000666000000000000000000000606012355103747021537 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import ModifyRequest, LDAPDN, Changes, Change, Operation, PartialAttribute, AttributeDescription, Vals, ResultCode from ..operation.bind import referrals_to_list from ..protocol.convert import changes_to_list, validate_attribute_value # ModifyRequest ::= [APPLICATION 6] SEQUENCE { # object LDAPDN, # changes SEQUENCE OF change SEQUENCE { # operation ENUMERATED { # add (0), # delete (1), # replace (2), # ... }, # modification PartialAttribute } } def modify_operation(dn, changes, schema=None): # changes is a dictionary in the form {'attribute1': (operation, [val1, val2, ...]], 'attribute2': (operation, [val1, val2, ...]), ...} # operation is 0 (add), 1 (delete), 2 (replace), 3 (increment) # increment as per RFC4525 change_list = Changes() for pos, attribute in enumerate(changes): partial_attribute = PartialAttribute() partial_attribute['type'] = AttributeDescription(attribute) partial_attribute['vals'] = Vals() if isinstance(changes[attribute][1], (list, tuple)): for index, value in enumerate(changes[attribute][1]): partial_attribute['vals'].setComponentByPosition(index, validate_attribute_value(schema, attribute, value)) else: partial_attribute['vals'].setComponentByPosition(0, validate_attribute_value(schema, attribute, changes[attribute][1])) change = Change() change['operation'] = Operation(changes[attribute][0]) change['modification'] = partial_attribute change_list[pos] = change request = ModifyRequest() request['object'] = LDAPDN(dn) request['changes'] = change_list return request def modify_request_to_dict(request): return {'entry': str(request['object']), 'changes': changes_to_list(request['changes'])} def modify_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'message': str(response['diagnosticMessage']), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral']), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/modifyDn.py0000666000000000000000000000420512355103747022020 0ustar 00000000000000""" Created on 2013.05.31 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import ModifyDNRequest, LDAPDN, RelativeLDAPDN, DeleteOldRDN, NewSuperior, ResultCode from ..operation.bind import referrals_to_list # ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { # entry LDAPDN, # newrdn RelativeLDAPDN, # deleteoldrdn BOOLEAN, # newSuperior [0] LDAPDN OPTIONAL } def modify_dn_operation(dn, new_relative_dn, delete_old_rdn=True, new_superior=None): request = ModifyDNRequest() request['entry'] = LDAPDN(dn) request['newrdn'] = RelativeLDAPDN(new_relative_dn) request['deleteoldrdn'] = DeleteOldRDN(delete_old_rdn) if new_superior: request['newSuperior'] = NewSuperior(new_superior) return request def modify_dn_request_to_dict(request): return {'entry': str(request['entry']), 'newRdn': str(request['newrdn']), 'deleteOldRdn': bool(request['deleteoldrdn']), 'newSuperior': str(request['newSuperior']) if request['newSuperior'] else None} def modify_dn_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral']), 'message': str(response['diagnosticMessage']), } python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/search.py0000666000000000000000000005107512355103747021523 0ustar 00000000000000""" Created on 2013.06.02 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from string import whitespace from os import linesep from .. import SEARCH_NEVER_DEREFERENCE_ALIASES, SEARCH_SCOPE_BASE_OBJECT, SEARCH_SCOPE_SINGLE_LEVEL, SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_DEREFERENCE_IN_SEARCHING, SEARCH_DEREFERENCE_FINDING_BASE_OBJECT, SEARCH_DEREFERENCE_ALWAYS, NO_ATTRIBUTES from ..core.exceptions import LDAPInvalidFilterError, LDAPAttributeError, LDAPInvalidScopeError, LDAPInvalidDereferenceAliasesError from ..protocol.rfc4511 import SearchRequest, LDAPDN, Scope, DerefAliases, Integer0ToMax, TypesOnly, AttributeSelection, Selector, EqualityMatch, AttributeDescription, AssertionValue, Filter, Not, And, Or, ApproxMatch, GreaterOrEqual, LessOrEqual, \ ExtensibleMatch, Present, SubstringFilter, Substrings, Final, Initial, Any, ResultCode, Substring, MatchingRule, Type, MatchValue, DnAttributes from ..operation.bind import referrals_to_list from ..protocol.convert import ava_to_dict, attributes_to_list, search_refs_to_list, validate_assertion_value # SearchRequest ::= [APPLICATION 3] SEQUENCE { # baseObject LDAPDN, # scope ENUMERATED { # baseObject (0), # singleLevel (1), # wholeSubtree (2), # ... }, # derefAliases ENUMERATED { # neverDerefAliases (0), # derefInSearching (1), # derefFindingBaseObj (2), # derefAlways (3) }, # sizeLimit INTEGER (0 .. maxInt), # timeLimit INTEGER (0 .. maxInt), # typesOnly BOOLEAN, # filter Filter, # attributes AttributeSelection } ROOT = 0 AND = 1 OR = 2 NOT = 3 MATCH_APPROX = 4 MATCH_GREATER_OR_EQUAL = 5 MATCH_LESS_OR_EQUAL = 6 MATCH_EXTENSIBLE = 7 MATCH_PRESENT = 8 MATCH_SUBSTRING = 9 MATCH_EQUAL = 10 SEARCH_OPEN = 20 SEARCH_OPEN_OR_CLOSE = 21 SEARCH_MATCH_OR_CLOSE = 22 SEARCH_MATCH_OR_CONTROL = 23 class FilterNode(): def __init__(self, tag=None, assertion=None): self.tag = tag self.parent = None self.assertion = assertion self.elements = [] def append(self, filter_node): filter_node.parent = self self.elements.append(filter_node) return filter_node def __str__(self, pos=0): self.__repr__(pos) def __repr__(self, pos=0): node_tags = ['ROOT', 'AND', 'OR', 'NOT', 'MATCH_APPROX', 'MATCH_GREATER_OR_EQUAL', 'MATCH_LESS_OR_EQUAL', 'MATCH_EXTENSIBLE', 'MATCH_PRESENT', 'MATCH_SUBSTRING', 'MATCH_EQUAL'] representation = ' ' * pos + 'tag: ' + node_tags[self.tag] + ' - assertion: ' + str(self.assertion) if self.elements: representation += ' - elements: ' + str(len(self.elements)) for element in self.elements: representation += linesep + ' ' * pos + element.__repr__(pos + 2) return representation def evaluate_match(match, schema): match = match.strip() if '~=' in match: tag = MATCH_APPROX left_part, _, right_part = match.split('~=') left_part = left_part.strip() right_part = right_part.strip() assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)} elif '>=' in match: tag = MATCH_GREATER_OR_EQUAL left_part, _, right_part = match.partition('>=') left_part = left_part.strip() right_part = right_part.strip() assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)} elif '<=' in match: tag = MATCH_LESS_OR_EQUAL left_part, _, right_part = match.partition('<=') left_part = left_part.strip() right_part = right_part.strip() assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)} elif ':=' in match: tag = MATCH_EXTENSIBLE left_part, _, right_part = match.partition(':=') left_part = left_part.strip() right_part = right_part.strip() extended_filter_list = left_part.split(':') matching_rule = None dn_attributes = None attribute_name = None if extended_filter_list[0] == '': # extensible filter format [:dn]:matchingRule:=assertionValue if len(extended_filter_list) == 2 and extended_filter_list[1].lower().strip() != 'dn': matching_rule = extended_filter_list[1] elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn': dn_attributes = True matching_rule = extended_filter_list[2] else: raise LDAPInvalidFilterError('invalid extensible filter') elif len(extended_filter_list) <= 3: # extensible filter format attr[:dn][:matchingRule]:=assertionValue if len(extended_filter_list) == 1: attribute_name = extended_filter_list[0] elif len(extended_filter_list) == 2: attribute_name = extended_filter_list[0] if extended_filter_list[1].lower().strip() == 'dn': dn_attributes = True else: matching_rule = extended_filter_list[1] elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn': attribute_name = extended_filter_list[0] dn_attributes = True matching_rule = extended_filter_list[2] else: raise LDAPInvalidFilterError('invalid extensible filter') if not attribute_name and not matching_rule: raise LDAPInvalidFilterError('invalid extensible filter') attribute_name = attribute_name.strip() if attribute_name else None matching_rule = matching_rule.strip() if matching_rule else None assertion = {'attr': attribute_name, 'value': validate_assertion_value(schema, attribute_name, right_part), 'matchingRule': matching_rule, 'dnAttributes': dn_attributes} elif match.endswith('=*'): tag = MATCH_PRESENT assertion = {'attr': match[:-2]} elif '=' in match and '*' in match: tag = MATCH_SUBSTRING left_part, _, right_part = match.partition('=') left_part = left_part.strip() right_part = right_part.strip() substrings = right_part.split('*') initial = validate_assertion_value(schema, left_part, substrings[0]) if substrings[0] else None final = validate_assertion_value(schema, left_part, substrings[-1]) if substrings[-1] else None any_string = [validate_assertion_value(schema, left_part, substring) for substring in substrings[1:-1] if substring] assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final} elif '=' in match: tag = MATCH_EQUAL left_part, _, right_part = match.partition('=') left_part = left_part.strip() right_part = right_part.strip() assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part)} else: raise LDAPInvalidFilterError('invalid matching assertion') return FilterNode(tag, assertion) def parse_filter(search_filter, schema): search_filter = search_filter.strip() if search_filter and search_filter.count('(') == search_filter.count(')') and search_filter.startswith('(') and search_filter.endswith(')'): state = SEARCH_OPEN_OR_CLOSE root = FilterNode(ROOT) current_node = root start_pos = None skip_white_space = True just_closed = False for pos, c in enumerate(search_filter): if skip_white_space and c in whitespace: continue elif (state == SEARCH_OPEN or state == SEARCH_OPEN_OR_CLOSE) and c == '(': state = SEARCH_MATCH_OR_CONTROL just_closed = False elif state == SEARCH_MATCH_OR_CONTROL and c in '&!|': if c == '&': current_node = current_node.append(FilterNode(AND)) elif c == '|': current_node = current_node.append(FilterNode(OR)) elif c == '!': current_node = current_node.append(FilterNode(NOT)) state = SEARCH_OPEN elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_OPEN_OR_CLOSE) and c == ')': if just_closed: current_node = current_node.parent else: just_closed = True skip_white_space = True end_pos = pos if start_pos: if current_node.tag == NOT and len(current_node.elements) > 0: raise LDAPInvalidFilterError('not clause in filter cannot be multiple') current_node.append(evaluate_match(search_filter[start_pos:end_pos], schema)) start_pos = None state = SEARCH_OPEN_OR_CLOSE elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_MATCH_OR_CONTROL) and c not in '()': skip_white_space = False if not start_pos: start_pos = pos state = SEARCH_MATCH_OR_CLOSE else: raise LDAPInvalidFilterError('malformed filter') if len(root.elements) != 1: raise LDAPInvalidFilterError('missing boolean operator in filter') return root else: raise LDAPInvalidFilterError('invalid filter') def compile_filter(filter_node): compiled_filter = Filter() if filter_node.tag == AND: boolean_filter = And() pos = 0 for element in filter_node.elements: boolean_filter[pos] = compile_filter(element) pos += 1 compiled_filter['and'] = boolean_filter elif filter_node.tag == OR: boolean_filter = Or() pos = 0 for element in filter_node.elements: boolean_filter[pos] = compile_filter(element) pos += 1 compiled_filter['or'] = boolean_filter elif filter_node.tag == NOT: boolean_filter = Not() boolean_filter['innerNotFilter'] = compile_filter(filter_node.elements[0]) compiled_filter['notFilter'] = boolean_filter elif filter_node.tag == MATCH_APPROX: matching_filter = ApproxMatch() matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr']) matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value']) compiled_filter['approxMatch'] = matching_filter elif filter_node.tag == MATCH_GREATER_OR_EQUAL: matching_filter = GreaterOrEqual() matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr']) matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value']) compiled_filter['greaterOrEqual'] = matching_filter elif filter_node.tag == MATCH_LESS_OR_EQUAL: matching_filter = LessOrEqual() matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr']) matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value']) compiled_filter['lessOrEqual'] = matching_filter elif filter_node.tag == MATCH_EXTENSIBLE: matching_filter = ExtensibleMatch() if filter_node.assertion['matchingRule']: matching_filter['matchingRule'] = MatchingRule(filter_node.assertion['matchingRule']) if filter_node.assertion['attr']: matching_filter['type'] = Type(filter_node.assertion['attr']) matching_filter['matchValue'] = MatchValue(filter_node.assertion['value']) matching_filter['dnAttributes'] = DnAttributes(filter_node.assertion['dnAttributes']) compiled_filter['extensibleMatch'] = matching_filter elif filter_node.tag == MATCH_PRESENT: matching_filter = Present(AttributeDescription(filter_node.assertion['attr'])) compiled_filter['present'] = matching_filter elif filter_node.tag == MATCH_SUBSTRING: matching_filter = SubstringFilter() matching_filter['type'] = AttributeDescription(filter_node.assertion['attr']) substrings = Substrings() pos = 0 if filter_node.assertion['initial']: substrings[pos] = Substring().setComponentByName('initial', Initial(filter_node.assertion['initial'])) pos += 1 if filter_node.assertion['any']: for substring in filter_node.assertion['any']: substrings[pos] = Substring().setComponentByName('any', Any(substring)) pos += 1 if filter_node.assertion['final']: substrings[pos] = Substring().setComponentByName('final', Final(filter_node.assertion['final'])) matching_filter['substrings'] = substrings compiled_filter['substringFilter'] = matching_filter elif filter_node.tag == MATCH_EQUAL: matching_filter = EqualityMatch() matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr']) matching_filter['assertionValue'] = AssertionValue(filter_node.assertion['value']) compiled_filter.setComponentByName('equalityMatch', matching_filter) else: raise LDAPInvalidFilterError('unknown filter node tag') return compiled_filter def build_filter(search_filter, schema): return compile_filter(parse_filter(search_filter, schema).elements[0]) def build_attribute_selection(attribute_list, schema): attribute_selection = AttributeSelection() for index, attribute in enumerate(attribute_list): if schema: if not attribute.lower() in schema.attribute_types and attribute not in '+*1.1': raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute) attribute_selection[index] = Selector(attribute) return attribute_selection def search_operation(search_base, search_filter, search_scope, dereference_aliases, attributes, size_limit, time_limit, types_only, schema=None): request = SearchRequest() request['baseObject'] = LDAPDN(search_base) if search_scope == SEARCH_SCOPE_BASE_OBJECT: request['scope'] = Scope('baseObject') elif search_scope == SEARCH_SCOPE_SINGLE_LEVEL: request['scope'] = Scope('singleLevel') elif search_scope == SEARCH_SCOPE_WHOLE_SUBTREE: request['scope'] = Scope('wholeSubtree') else: raise LDAPInvalidScopeError('invalid scope type') if dereference_aliases == SEARCH_NEVER_DEREFERENCE_ALIASES: request['derefAliases'] = DerefAliases('neverDerefAliases') elif dereference_aliases == SEARCH_DEREFERENCE_IN_SEARCHING: request['derefAliases'] = DerefAliases('derefInSearching') elif dereference_aliases == SEARCH_DEREFERENCE_FINDING_BASE_OBJECT: request['derefAliases'] = DerefAliases('derefFindingBaseObj') elif dereference_aliases == SEARCH_DEREFERENCE_ALWAYS: request['derefAliases'] = DerefAliases('derefAlways') else: raise LDAPInvalidDereferenceAliasesError('invalid dereference aliases type') request['sizeLimit'] = Integer0ToMax(size_limit) request['timeLimit'] = Integer0ToMax(time_limit) request['typesOnly'] = TypesOnly(True) if types_only else TypesOnly(False) request['filter'] = build_filter(search_filter, schema) # parse the searchFilter string and compile it starting from the root node if not isinstance(attributes, (list, tuple)): attributes = [NO_ATTRIBUTES] request['attributes'] = build_attribute_selection(attributes, schema) return request def decode_vals(vals): if vals: return [str(val) for val in vals if val] else: return None def attributes_to_dict(attribute_list): attributes = dict() for attribute in attribute_list: attributes[str(attribute['type'])] = decode_vals(attribute['vals']) return attributes def decode_raw_vals(vals): return [bytes(val) for val in vals] if vals else None def raw_attributes_to_dict(attribute_list): attributes = dict() for attribute in attribute_list: attributes[str(attribute['type'])] = decode_raw_vals(attribute['vals']) return attributes def matching_rule_assertion_to_string(matching_rule_assertion): return str(matching_rule_assertion) def filter_to_string(filter_object): filter_type = filter_object.getName() filter_string = '(' if filter_type == 'and': filter_string += '&' for f in filter_object['and']: filter_string += filter_to_string(f) elif filter_type == 'or': filter_string += '!' for f in filter_object['or']: filter_string += filter_to_string(f) elif filter_type == 'notFilter': filter_string += '!' + filter_to_string(filter_object['notFilter']['innerNotFilter']) elif filter_type == 'equalityMatch': ava = ava_to_dict(filter_object['equalityMatch']) filter_string += ava['attribute'] + '=' + ava['value'] elif filter_type == 'substringFilter': attribute = filter_object['substringFilter']['type'] filter_string += str(attribute) + '=' for substring in filter_object['substringFilter']['substrings']: if substring['initial']: filter_string += str(substring['initial']) + '*' elif substring['any']: filter_string += str(substring['any']) if filter_string.endswith('*') else '*' + str(substring['any']) filter_string += '*' elif substring['final']: filter_string += '*' + str(substring['final']) elif filter_type == 'greaterOrEqual': ava = ava_to_dict(filter_object['greaterOrEqual']) filter_string += ava['attribute'] + '>=' + ava['value'] elif filter_type == 'lessOrEqual': ava = ava_to_dict(filter_object['lessOrEqual']) filter_string += ava['attribute'] + '<=' + ava['value'] elif filter_type == 'present': filter_string += str(filter_object['present']) + '=*' elif filter_type == 'approxMatch': ava = ava_to_dict(filter_object['approxMatch']) filter_string += ava['attribute'] + '~=' + ava['value'] elif filter_type == 'extensibleMatch': filter_string += matching_rule_assertion_to_string(filter_object['extensibleMatch']) else: raise LDAPInvalidFilterError('error converting filter to string') filter_string += ')' return filter_string def search_request_to_dict(request): return {'base': str(request['baseObject']), 'scope': int(request['scope']), 'dereferenceAlias': int(request['derefAliases']), 'sizeLimit': int(request['sizeLimit']), 'timeLimit': int(request['timeLimit']), 'typeOnly': bool(request['typesOnly']), 'filter': filter_to_string(request['filter']), 'attributes': attributes_to_list(request['attributes'])} def search_result_entry_response_to_dict(response): return {'dn': str(response['object']), 'attributes': attributes_to_dict(response['attributes']), 'raw_attributes': raw_attributes_to_dict(response['attributes'])} def search_result_done_response_to_dict(response): return {'result': int(response[0]), 'description': ResultCode().getNamedValues().getName(response[0]), 'message': str(response['diagnosticMessage']), 'dn': str(response['matchedDN']), 'referrals': referrals_to_list(response['referral'])} def search_result_reference_response_to_dict(response): return {'uri': search_refs_to_list(response)} python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/unbind.py0000666000000000000000000000166612355103747021536 0ustar 00000000000000""" Created on 2013.09.03 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..protocol.rfc4511 import UnbindRequest def unbind_operation(): request = UnbindRequest() return request python3-ldap-0.9.4.2/python3-ldap/ldap3/operation/__init__.py0000666000000000000000000000000012355103746021772 0ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/0000777000000000000000000000000012355117540017531 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/convert.py0000666000000000000000000001267312355103747021600 0ustar 00000000000000""" Created on 2013.07.24 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from ..core.exceptions import LDAPControlsError, LDAPAttributeError, LDAPObjectClassError from .rfc4511 import Controls, Control def attribute_to_dict(attribute): return {'type': str(attribute['type']), 'values': [str(val) for val in attribute['vals']]} def attributes_to_dict(attributes): attributes_dict = dict() for attribute in attributes: attribute_dict = attribute_to_dict(attribute) attributes_dict[attribute_dict['type']] = attribute_dict['values'] return attributes_dict def referrals_to_list(referrals): return [str(referral) for referral in referrals if referral] if referrals else None def search_refs_to_list(search_refs): return [str(search_ref) for search_ref in search_refs if search_ref] if search_refs else None def sasl_to_dict(sasl): return {'mechanism': str(sasl['mechanism']), 'credentials': str(sasl['credentials'])} def authentication_choice_to_dict(authentication_choice): return {'simple': str(authentication_choice['simple']) if authentication_choice.getName() == 'simple' else None, 'sasl': sasl_to_dict(authentication_choice['sasl']) if authentication_choice.getName() == 'sasl' else None} def decode_referrals(referrals): return [str(referral) for referral in referrals if referral] if referrals else None def partial_attribute_to_dict(modification): return {'type': str(modification['type']), 'value': [str(value) for value in modification['vals']]} def change_to_dict(change): return {'operation': int(change['operation']), 'attribute': partial_attribute_to_dict(change['modification'])} def changes_to_list(changes): return [change_to_dict(change) for change in changes] def attributes_to_list(attributes): return [str(attribute) for attribute in attributes] def ava_to_dict(ava): return {'attribute': str(ava['attributeDesc']), 'value': str(ava['assertionValue'])} def substring_to_dict(substring): return {'initial': substring['initial'] if substring['initial'] else '', 'any': [middle for middle in substring['any']] if substring['any'] else '', 'final': substring['final'] if substring['final'] else ''} def prepare_changes_for_request(changes): prepared = {} for change in changes: prepared[change['attribute']['type']] = (change['operation'], change['attribute']['value']) return prepared def build_controls_list(controls): """ controls is a list of tuple each tuple must have 3 elements: the control OID, the criticality, the value criticality must be a boolean """ if not controls: return None if not isinstance(controls, (list, tuple)): raise LDAPControlsError('controls must be a list') built_controls = Controls() for idx, control in enumerate(controls): if len(control) == 3 and isinstance(control[1], bool): built_control = Control() built_control['controlType'] = control[0] built_control['criticality'] = control[1] built_control['controlValue'] = control[2] built_controls.setComponentByPosition(idx, built_control) else: raise LDAPControlsError('control must be a tuple of 3 elements: controlType, criticality (boolean) and controlValue') return built_controls def validate_assertion_value(schema, name, value): if schema: if not name.lower() in schema.attribute_types: raise LDAPAttributeError('invalid attribute type in assertion: ' + name) if not '\\' in value: return value.encode('utf-8') validated_value = bytearray() pos = 0 while pos < len(value): if value[pos] == '\\': byte = value[pos + 1: pos + 3] if len(byte) == 2: try: validated_value.append(int(value[pos + 1: pos + 3], 16)) pos += 3 continue except ValueError: pass validated_value += value[pos].encode('utf-8') pos += 1 return bytes(validated_value) def validate_attribute_value(schema, name, value): if schema: if not name.lower() in schema.attribute_types: raise LDAPAttributeError('invalid attribute type in attribute') if name.lower() == 'objectclass': if value.lower() not in schema.object_classes: raise LDAPObjectClassError('invalid class in ObjectClass attribute: ' + value) if isinstance(value, str): return validate_assertion_value(None, name, value) # schema already checked, no need to check again return value python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/novell.py0000666000000000000000000000163012355106663021406 0ustar 00000000000000""" Created on 2014.06.27 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from pyasn1.type.univ import OctetString class Identity(OctetString): encoding = 'utf-8'python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/oid.py0000666000000000000000000035304512355103747020674 0ustar 00000000000000""" Created on 2013.08.30 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from collections import namedtuple from .. import OID_CONTROL, OID_EXTENSION, OID_FEATURE, OID_UNSOLICITED_NOTICE, OID_LDAP_SYNTAX, OID_ATTRIBUTE_TYPE, OID_MATCHING_RULE, OID_NAME_FORM, OID_OBJECT_CLASS, OID_ADMINISTRATIVE_ROLE, OID_DIT_CONTENT_RULE, OID_LDAP_URL_EXTENSION, \ OID_FAMILY # Holds info about OIDs. # Each OID info is a named tuple with the following attributes: # oid - the OID number # type - type of OID # name - description of OID # doc - reference document of OID # obsolete - boolean to define an historic state of the OID # # Source of information is IANA ldap-parameters.txt, oid-registry and products documentation as of 2013.08.21 def constant_to_oid_kind(oid_kind): if oid_kind == OID_CONTROL: return 'Control' elif oid_kind == OID_EXTENSION: return 'Extension' elif oid_kind == OID_FEATURE: return 'Feature' elif oid_kind == OID_UNSOLICITED_NOTICE: return 'Unsolicited Notice' elif oid_kind == OID_ATTRIBUTE_TYPE: return 'Attribute Type' elif oid_kind == OID_DIT_CONTENT_RULE: return 'DIT Content Rule' elif oid_kind == OID_LDAP_URL_EXTENSION: return 'LDAP URL Extension' elif oid_kind == OID_FAMILY: return 'Family' elif oid_kind == OID_MATCHING_RULE: return 'Matching Rule' elif oid_kind == OID_NAME_FORM: return 'Name Form' elif oid_kind == OID_OBJECT_CLASS: return 'Object Class' elif oid_kind == OID_ADMINISTRATIVE_ROLE: return 'Administrative Role' elif oid_kind == OID_LDAP_SYNTAX: return 'LDAP Syntax' else: return 'Unknown' def decode_oids(sequence): if sequence: return [Oids.get(oid, OidInfo(oid, None, None, None)) for oid in sequence if oid] return list() def decode_syntax(syntax): if not syntax: return None syntax = syntax.strip() pos = 0 for pos, c in enumerate(syntax): if not c in '0123456789.': break return Oids.get(syntax[:pos], None) class OidInfo(namedtuple('OidInfo', 'oid, kind, name, docs')): def __str__(self): r = self.oid + ' - ' if self.name: r += ((', '.join(self.name)) if isinstance(self.name, (list, tuple)) else self.name) + ' - ' r += constant_to_oid_kind(self.kind) + ' - ' if self.kind is not None else '' r += self.docs + ' - ' if self.docs else '' return r[:-3] def __repr__(self): return self.__str__() # noinspection PyPep8 Oids = { # administrative role '2.5.23.1': OidInfo('2.5.23.1', OID_ADMINISTRATIVE_ROLE, 'autonomousArea', 'RFC3672'), '2.5.23.2': OidInfo('2.5.23.2', OID_ADMINISTRATIVE_ROLE, 'accessControlSpecificArea', 'RFC3672'), '2.5.23.3': OidInfo('2.5.23.3', OID_ADMINISTRATIVE_ROLE, 'accessControlInnerArea', 'RFC3672'), '2.5.23.4': OidInfo('2.5.23.4', OID_ADMINISTRATIVE_ROLE, 'subschemaAdminSpecificArea', 'RFC3672'), '2.5.23.5': OidInfo('2.5.23.5', OID_ADMINISTRATIVE_ROLE, 'collectiveAttributeSpecificArea', 'RFC3672'), '2.5.23.6': OidInfo('2.5.23.6', OID_ADMINISTRATIVE_ROLE, 'collectiveAttributeInnerArea', 'RFC3672'), # attributes type '0.9.2342.19200300.100.1.1': OidInfo('0.9.2342.19200300.100.1.1', OID_ATTRIBUTE_TYPE, ['uid', 'userId'], 'RFC4519'), '0.9.2342.19200300.100.1.2': OidInfo('0.9.2342.19200300.100.1.2', OID_ATTRIBUTE_TYPE, 'textEncodedORAddress', 'RFC1274'), '0.9.2342.19200300.100.1.3': OidInfo('0.9.2342.19200300.100.1.3', OID_ATTRIBUTE_TYPE, ['mail', 'RFC822Mailbox'], 'RFC4524'), '0.9.2342.19200300.100.1.4': OidInfo('0.9.2342.19200300.100.1.4', OID_ATTRIBUTE_TYPE, 'info', 'RFC4524'), '0.9.2342.19200300.100.1.5': OidInfo('0.9.2342.19200300.100.1.5', OID_ATTRIBUTE_TYPE, ['drink', 'favouriteDrink'], 'RFC4524'), '0.9.2342.19200300.100.1.6': OidInfo('0.9.2342.19200300.100.1.6', OID_ATTRIBUTE_TYPE, 'roomNumber', 'RFC4524'), '0.9.2342.19200300.100.1.7': OidInfo('0.9.2342.19200300.100.1.7', OID_ATTRIBUTE_TYPE, 'photo', 'RFC1274'), '0.9.2342.19200300.100.1.8': OidInfo('0.9.2342.19200300.100.1.8', OID_ATTRIBUTE_TYPE, 'userClass', 'RFC4524'), '0.9.2342.19200300.100.1.9': OidInfo('0.9.2342.19200300.100.1.9', OID_ATTRIBUTE_TYPE, 'host', 'RFC4524'), '0.9.2342.19200300.100.1.10': OidInfo('0.9.2342.19200300.100.1.10', OID_ATTRIBUTE_TYPE, 'manager', 'RFC4524'), '0.9.2342.19200300.100.1.11': OidInfo('0.9.2342.19200300.100.1.11', OID_ATTRIBUTE_TYPE, 'documentIdentifier', 'RFC4524'), '0.9.2342.19200300.100.1.12': OidInfo('0.9.2342.19200300.100.1.12', OID_ATTRIBUTE_TYPE, 'documentTitle', 'RFC4524'), '0.9.2342.19200300.100.1.13': OidInfo('0.9.2342.19200300.100.1.13', OID_ATTRIBUTE_TYPE, 'documentVersion', 'RFC4524'), '0.9.2342.19200300.100.1.14': OidInfo('0.9.2342.19200300.100.1.14', OID_ATTRIBUTE_TYPE, 'documentAuthor', 'RFC4524'), '0.9.2342.19200300.100.1.15': OidInfo('0.9.2342.19200300.100.1.15', OID_ATTRIBUTE_TYPE, 'documentLocation', 'RFC4524'), '0.9.2342.19200300.100.1.20': OidInfo('0.9.2342.19200300.100.1.20', OID_ATTRIBUTE_TYPE, ['homePhone', 'homeTelephone'], 'RFC4524'), '0.9.2342.19200300.100.1.21': OidInfo('0.9.2342.19200300.100.1.21', OID_ATTRIBUTE_TYPE, 'secretary', 'RFC4524'), '0.9.2342.19200300.100.1.22': OidInfo('0.9.2342.19200300.100.1.22', OID_ATTRIBUTE_TYPE, 'otherMailbox', 'RFC1274'), '0.9.2342.19200300.100.1.23': OidInfo('0.9.2342.19200300.100.1.23', OID_ATTRIBUTE_TYPE, 'lastModifiedTime', 'RFC1274'), '0.9.2342.19200300.100.1.24': OidInfo('0.9.2342.19200300.100.1.24', OID_ATTRIBUTE_TYPE, 'lastModifiedBy', 'RFC1274'), '0.9.2342.19200300.100.1.25': OidInfo('0.9.2342.19200300.100.1.25', OID_ATTRIBUTE_TYPE, ['DC', 'domainComponent'], 'RFC4519'), '0.9.2342.19200300.100.1.26': OidInfo('0.9.2342.19200300.100.1.26', OID_ATTRIBUTE_TYPE, 'aRecord', 'RFC1274'), '0.9.2342.19200300.100.1.27': OidInfo('0.9.2342.19200300.100.1.27', OID_ATTRIBUTE_TYPE, 'mDRecord', 'RFC1274'), '0.9.2342.19200300.100.1.28': OidInfo('0.9.2342.19200300.100.1.28', OID_ATTRIBUTE_TYPE, 'mXRecord', 'RFC1274'), '0.9.2342.19200300.100.1.29': OidInfo('0.9.2342.19200300.100.1.29', OID_ATTRIBUTE_TYPE, 'nSRecord', 'RFC1274'), '0.9.2342.19200300.100.1.30': OidInfo('0.9.2342.19200300.100.1.30', OID_ATTRIBUTE_TYPE, 'sOARecord', 'RFC1274'), '0.9.2342.19200300.100.1.31': OidInfo('0.9.2342.19200300.100.1.31', OID_ATTRIBUTE_TYPE, 'cNAMERecord', 'RFC1274'), '0.9.2342.19200300.100.1.37': OidInfo('0.9.2342.19200300.100.1.37', OID_ATTRIBUTE_TYPE, 'associatedDomain', 'RFC4524'), '0.9.2342.19200300.100.1.38': OidInfo('0.9.2342.19200300.100.1.38', OID_ATTRIBUTE_TYPE, 'associatedName', 'RFC4524'), '0.9.2342.19200300.100.1.39': OidInfo('0.9.2342.19200300.100.1.39', OID_ATTRIBUTE_TYPE, 'homePostalAddress', 'RFC4524'), '0.9.2342.19200300.100.1.40': OidInfo('0.9.2342.19200300.100.1.40', OID_ATTRIBUTE_TYPE, 'personalTitle', 'RFC4524'), '0.9.2342.19200300.100.1.41': OidInfo('0.9.2342.19200300.100.1.41', OID_ATTRIBUTE_TYPE, ['mobile', 'mobileTelephoneNumber'], 'RFC4524'), '0.9.2342.19200300.100.1.42': OidInfo('0.9.2342.19200300.100.1.42', OID_ATTRIBUTE_TYPE, ['pager', 'pagerTelephoneNumber'], 'RFC4524'), '0.9.2342.19200300.100.1.43': OidInfo('0.9.2342.19200300.100.1.43', OID_ATTRIBUTE_TYPE, ['co', 'friendlyCountryName'], 'RFC4524'), '0.9.2342.19200300.100.1.44': OidInfo('0.9.2342.19200300.100.1.44', OID_ATTRIBUTE_TYPE, 'uniqueIdentifier', 'RFC4524'), '0.9.2342.19200300.100.1.45': OidInfo('0.9.2342.19200300.100.1.45', OID_ATTRIBUTE_TYPE, 'organizationalStatus', 'RFC4524'), '0.9.2342.19200300.100.1.46': OidInfo('0.9.2342.19200300.100.1.46', OID_ATTRIBUTE_TYPE, 'janetMailbox', 'RFC1274'), '0.9.2342.19200300.100.1.47': OidInfo('0.9.2342.19200300.100.1.47', OID_ATTRIBUTE_TYPE, 'mailPreferenceOption', 'RFC1274'), '0.9.2342.19200300.100.1.48': OidInfo('0.9.2342.19200300.100.1.48', OID_ATTRIBUTE_TYPE, 'buildingName', 'RFC4524'), '0.9.2342.19200300.100.1.49': OidInfo('0.9.2342.19200300.100.1.49', OID_ATTRIBUTE_TYPE, 'dSAQuality', 'RFC1274'), '0.9.2342.19200300.100.1.50': OidInfo('0.9.2342.19200300.100.1.50', OID_ATTRIBUTE_TYPE, 'singleLevelQuality', 'RFC4524'), '0.9.2342.19200300.100.1.51': OidInfo('0.9.2342.19200300.100.1.51', OID_ATTRIBUTE_TYPE, 'subtreeMinimumQuality', 'RFC1274'), '0.9.2342.19200300.100.1.52': OidInfo('0.9.2342.19200300.100.1.52', OID_ATTRIBUTE_TYPE, 'subtreeMaximumQuality', 'RFC1274'), '0.9.2342.19200300.100.1.53': OidInfo('0.9.2342.19200300.100.1.53', OID_ATTRIBUTE_TYPE, 'personalSignature', 'RFC1274'), '0.9.2342.19200300.100.1.54': OidInfo('0.9.2342.19200300.100.1.54', OID_ATTRIBUTE_TYPE, 'dITRedirect', 'RFC1274'), '0.9.2342.19200300.100.1.55': OidInfo('0.9.2342.19200300.100.1.55', OID_ATTRIBUTE_TYPE, 'audio', 'RFC1274'), '0.9.2342.19200300.100.1.56': OidInfo('0.9.2342.19200300.100.1.56', OID_ATTRIBUTE_TYPE, 'documentPublisher', 'RFC4524'), '0.9.2342.19200300.100.1.60': OidInfo('0.9.2342.19200300.100.1.60', OID_ATTRIBUTE_TYPE, 'jpegPhoto', 'RFC2798'), '1.2.840.113549.1.9.1': OidInfo('1.2.840.113549.1.9.1', OID_ATTRIBUTE_TYPE, ['email', 'emailAddress'], 'RFC3280'), '1.2.840.113556.1.4.478': OidInfo('1.2.840.113556.1.4.478', OID_ATTRIBUTE_TYPE, 'calCalURI', 'RFC2739'), '1.2.840.113556.1.4.479': OidInfo('1.2.840.113556.1.4.479', OID_ATTRIBUTE_TYPE, 'calFBURL', 'RFC2739'), '1.2.840.113556.1.4.480': OidInfo('1.2.840.113556.1.4.480', OID_ATTRIBUTE_TYPE, 'calCAPURI', 'RFC2739'), '1.2.840.113556.1.4.481': OidInfo('1.2.840.113556.1.4.481', OID_ATTRIBUTE_TYPE, 'calCalAdrURI', 'RFC2739'), '1.2.840.113556.1.4.482': OidInfo('1.2.840.113556.1.4.482', OID_ATTRIBUTE_TYPE, 'calOtherCalURIs', 'RFC2739'), '1.2.840.113556.1.4.483': OidInfo('1.2.840.113556.1.4.483', OID_ATTRIBUTE_TYPE, 'calOtherFBURLs', 'RFC2739'), '1.2.840.113556.1.4.484': OidInfo('1.2.840.113556.1.4.484', OID_ATTRIBUTE_TYPE, 'calOtherCAPURIs', 'RFC2739'), '1.2.840.113556.1.4.485': OidInfo('1.2.840.113556.1.4.485', OID_ATTRIBUTE_TYPE, 'calOtherCalAdrURIs', 'RFC2739'), '1.3.18.0.2.4.1107': OidInfo('1.3.18.0.2.4.1107', OID_ATTRIBUTE_TYPE, 'printer-xri-supported', 'RFC3712'), '1.3.18.0.2.4.1108': OidInfo('1.3.18.0.2.4.1108', OID_ATTRIBUTE_TYPE, 'printer-aliases', 'RFC3712'), '1.3.18.0.2.4.1109': OidInfo('1.3.18.0.2.4.1109', OID_ATTRIBUTE_TYPE, 'printer-charset-configured', 'RFC3712'), '1.3.18.0.2.4.1110': OidInfo('1.3.18.0.2.4.1110', OID_ATTRIBUTE_TYPE, 'printer-job-priority-supported', 'RFC3712'), '1.3.18.0.2.4.1111': OidInfo('1.3.18.0.2.4.1111', OID_ATTRIBUTE_TYPE, 'printer-job-k-octets-supported', 'RFC3712'), '1.3.18.0.2.4.1112': OidInfo('1.3.18.0.2.4.1112', OID_ATTRIBUTE_TYPE, 'printer-current-operator', 'RFC3712'), '1.3.18.0.2.4.1113': OidInfo('1.3.18.0.2.4.1113', OID_ATTRIBUTE_TYPE, 'printer-service-person', 'RFC3712'), '1.3.18.0.2.4.1114': OidInfo('1.3.18.0.2.4.1114', OID_ATTRIBUTE_TYPE, 'printer-delivery-orientation-supported', 'RFC3712'), '1.3.18.0.2.4.1115': OidInfo('1.3.18.0.2.4.1115', OID_ATTRIBUTE_TYPE, 'printer-stacking-order-supported', 'RFC3712'), '1.3.18.0.2.4.1116': OidInfo('1.3.18.0.2.4.1116', OID_ATTRIBUTE_TYPE, 'printer-output-features-supported', 'RFC3712'), '1.3.18.0.2.4.1117': OidInfo('1.3.18.0.2.4.1117', OID_ATTRIBUTE_TYPE, 'printer-media-local-supported', 'RFC3712'), '1.3.18.0.2.4.1118': OidInfo('1.3.18.0.2.4.1118', OID_ATTRIBUTE_TYPE, 'printer-copies-supported', 'RFC3712'), '1.3.18.0.2.4.1119': OidInfo('1.3.18.0.2.4.1119', OID_ATTRIBUTE_TYPE, 'printer-natural-language-configured', 'RFC3712'), '1.3.18.0.2.4.1120': OidInfo('1.3.18.0.2.4.1120', OID_ATTRIBUTE_TYPE, 'printer-print-quality-supported', 'RFC3712'), '1.3.18.0.2.4.1121': OidInfo('1.3.18.0.2.4.1121', OID_ATTRIBUTE_TYPE, 'printer-resolution-supported', 'RFC3712'), '1.3.18.0.2.4.1122': OidInfo('1.3.18.0.2.4.1122', OID_ATTRIBUTE_TYPE, 'printer-media-supported', 'RFC3712'), '1.3.18.0.2.4.1123': OidInfo('1.3.18.0.2.4.1123', OID_ATTRIBUTE_TYPE, 'printer-sides-supported', 'RFC3712'), '1.3.18.0.2.4.1124': OidInfo('1.3.18.0.2.4.1124', OID_ATTRIBUTE_TYPE, 'printer-number-up-supported', 'RFC3712'), '1.3.18.0.2.4.1125': OidInfo('1.3.18.0.2.4.1125', OID_ATTRIBUTE_TYPE, 'printer-finishings-supported', 'RFC3712'), '1.3.18.0.2.4.1126': OidInfo('1.3.18.0.2.4.1126', OID_ATTRIBUTE_TYPE, 'printer-pages-per-minute-color', 'RFC3712'), '1.3.18.0.2.4.1127': OidInfo('1.3.18.0.2.4.1127', OID_ATTRIBUTE_TYPE, 'printer-pages-per-minute', 'RFC3712'), '1.3.18.0.2.4.1128': OidInfo('1.3.18.0.2.4.1128', OID_ATTRIBUTE_TYPE, 'printer-compression-supported', 'RFC3712'), '1.3.18.0.2.4.1129': OidInfo('1.3.18.0.2.4.1129', OID_ATTRIBUTE_TYPE, 'printer-color-supported', 'RFC3712'), '1.3.18.0.2.4.1130': OidInfo('1.3.18.0.2.4.1130', OID_ATTRIBUTE_TYPE, 'printer-document-format-supported', 'RFC3712'), '1.3.18.0.2.4.1131': OidInfo('1.3.18.0.2.4.1131', OID_ATTRIBUTE_TYPE, 'printer-charset-supported', 'RFC3712'), '1.3.18.0.2.4.1132': OidInfo('1.3.18.0.2.4.1132', OID_ATTRIBUTE_TYPE, 'printer-multiple-document-jobs-supported', 'RFC3712'), '1.3.18.0.2.4.1133': OidInfo('1.3.18.0.2.4.1133', OID_ATTRIBUTE_TYPE, 'printer-ipp-versions-supported', 'RFC3712'), '1.3.18.0.2.4.1134': OidInfo('1.3.18.0.2.4.1134', OID_ATTRIBUTE_TYPE, 'printer-more-info', 'RFC3712'), '1.3.18.0.2.4.1135': OidInfo('1.3.18.0.2.4.1135', OID_ATTRIBUTE_TYPE, 'printer-name', 'RFC3712'), '1.3.18.0.2.4.1136': OidInfo('1.3.18.0.2.4.1136', OID_ATTRIBUTE_TYPE, 'printer-location', 'RFC3712'), '1.3.18.0.2.4.1137': OidInfo('1.3.18.0.2.4.1137', OID_ATTRIBUTE_TYPE, 'printer-generated-natural-language-supported', 'RFC3712'), '1.3.18.0.2.4.1138': OidInfo('1.3.18.0.2.4.1138', OID_ATTRIBUTE_TYPE, 'printer-make-and-model', 'RFC3712'), '1.3.18.0.2.4.1139': OidInfo('1.3.18.0.2.4.1139', OID_ATTRIBUTE_TYPE, 'printer-info', 'RFC3712'), '1.3.18.0.2.4.1140': OidInfo('1.3.18.0.2.4.1140', OID_ATTRIBUTE_TYPE, 'printer-uri', 'RFC3712'), '1.3.6.1.1.10.4.1': OidInfo('1.3.6.1.1.10.4.1', OID_ATTRIBUTE_TYPE, 'uddiBusinessKey', 'RFC4403'), '1.3.6.1.1.10.4.2': OidInfo('1.3.6.1.1.10.4.2', OID_ATTRIBUTE_TYPE, 'uddiAuthorizedName', 'RFC4403'), '1.3.6.1.1.10.4.3': OidInfo('1.3.6.1.1.10.4.3', OID_ATTRIBUTE_TYPE, 'uddiOperator', 'RFC4403'), '1.3.6.1.1.10.4.4': OidInfo('1.3.6.1.1.10.4.4', OID_ATTRIBUTE_TYPE, 'uddiName', 'RFC4403'), '1.3.6.1.1.10.4.5': OidInfo('1.3.6.1.1.10.4.5', OID_ATTRIBUTE_TYPE, 'uddiDescription', 'RFC4403'), '1.3.6.1.1.10.4.6': OidInfo('1.3.6.1.1.10.4.6', OID_ATTRIBUTE_TYPE, 'uddiDiscoveryURLs', 'RFC4403'), '1.3.6.1.1.10.4.7': OidInfo('1.3.6.1.1.10.4.7', OID_ATTRIBUTE_TYPE, 'uddiUseType', 'RFC4403'), '1.3.6.1.1.10.4.8': OidInfo('1.3.6.1.1.10.4.8', OID_ATTRIBUTE_TYPE, 'uddiPersonName', 'RFC4403'), '1.3.6.1.1.10.4.9': OidInfo('1.3.6.1.1.10.4.9', OID_ATTRIBUTE_TYPE, 'uddiPhone', 'RFC4403'), '1.3.6.1.1.10.4.10': OidInfo('1.3.6.1.1.10.4.10', OID_ATTRIBUTE_TYPE, 'uddiEMail', 'RFC4403'), '1.3.6.1.1.10.4.11': OidInfo('1.3.6.1.1.10.4.11', OID_ATTRIBUTE_TYPE, 'uddiSortCode', 'RFC4403'), '1.3.6.1.1.10.4.12': OidInfo('1.3.6.1.1.10.4.12', OID_ATTRIBUTE_TYPE, 'uddiTModelKey', 'RFC4403'), '1.3.6.1.1.10.4.13': OidInfo('1.3.6.1.1.10.4.13', OID_ATTRIBUTE_TYPE, 'uddiAddressLine', 'RFC4403'), '1.3.6.1.1.10.4.14': OidInfo('1.3.6.1.1.10.4.14', OID_ATTRIBUTE_TYPE, 'uddiIdentifierBag', 'RFC4403'), '1.3.6.1.1.10.4.15': OidInfo('1.3.6.1.1.10.4.15', OID_ATTRIBUTE_TYPE, 'uddiCategoryBag', 'RFC4403'), '1.3.6.1.1.10.4.16': OidInfo('1.3.6.1.1.10.4.16', OID_ATTRIBUTE_TYPE, 'uddiKeyedReference', 'RFC4403'), '1.3.6.1.1.10.4.17': OidInfo('1.3.6.1.1.10.4.17', OID_ATTRIBUTE_TYPE, 'uddiServiceKey', 'RFC4403'), '1.3.6.1.1.10.4.18': OidInfo('1.3.6.1.1.10.4.18', OID_ATTRIBUTE_TYPE, 'uddiBindingKey', 'RFC4403'), '1.3.6.1.1.10.4.19': OidInfo('1.3.6.1.1.10.4.19', OID_ATTRIBUTE_TYPE, 'uddiAccessPoint', 'RFC4403'), '1.3.6.1.1.10.4.20': OidInfo('1.3.6.1.1.10.4.20', OID_ATTRIBUTE_TYPE, 'uddiHostingRedirector', 'RFC4403'), '1.3.6.1.1.10.4.21': OidInfo('1.3.6.1.1.10.4.21', OID_ATTRIBUTE_TYPE, 'uddiInstanceDescription', 'RFC4403'), '1.3.6.1.1.10.4.22': OidInfo('1.3.6.1.1.10.4.22', OID_ATTRIBUTE_TYPE, 'uddiInstanceParms', 'RFC4403'), '1.3.6.1.1.10.4.23': OidInfo('1.3.6.1.1.10.4.23', OID_ATTRIBUTE_TYPE, 'uddiOverviewDescription', 'RFC4403'), '1.3.6.1.1.10.4.24': OidInfo('1.3.6.1.1.10.4.24', OID_ATTRIBUTE_TYPE, 'uddiOverviewURL', 'RFC4403'), '1.3.6.1.1.10.4.25': OidInfo('1.3.6.1.1.10.4.25', OID_ATTRIBUTE_TYPE, 'uddiFromKey', 'RFC4403'), '1.3.6.1.1.10.4.26': OidInfo('1.3.6.1.1.10.4.26', OID_ATTRIBUTE_TYPE, 'uddiToKey', 'RFC4403'), '1.3.6.1.1.10.4.27': OidInfo('1.3.6.1.1.10.4.27', OID_ATTRIBUTE_TYPE, 'uddiUUID', 'RFC4403'), '1.3.6.1.1.10.4.28': OidInfo('1.3.6.1.1.10.4.28', OID_ATTRIBUTE_TYPE, 'uddiIsHidden', 'RFC4403'), '1.3.6.1.1.10.4.29': OidInfo('1.3.6.1.1.10.4.29', OID_ATTRIBUTE_TYPE, 'uddiIsProjection', 'RFC4403'), '1.3.6.1.1.10.4.30': OidInfo('1.3.6.1.1.10.4.30', OID_ATTRIBUTE_TYPE, 'uddiLang', 'RFC4403'), '1.3.6.1.1.10.4.31': OidInfo('1.3.6.1.1.10.4.31', OID_ATTRIBUTE_TYPE, 'uddiv3BusinessKey', 'RFC4403'), '1.3.6.1.1.10.4.32': OidInfo('1.3.6.1.1.10.4.32', OID_ATTRIBUTE_TYPE, 'uddiv3ServiceKey', 'RFC4403'), '1.3.6.1.1.10.4.33': OidInfo('1.3.6.1.1.10.4.33', OID_ATTRIBUTE_TYPE, 'uddiv3BindingKey', 'RFC4403'), '1.3.6.1.1.10.4.34': OidInfo('1.3.6.1.1.10.4.34', OID_ATTRIBUTE_TYPE, 'uddiv3TmodelKey', 'RFC4403'), '1.3.6.1.1.10.4.35': OidInfo('1.3.6.1.1.10.4.35', OID_ATTRIBUTE_TYPE, 'uddiv3DigitalSignature', 'RFC4403'), '1.3.6.1.1.10.4.36': OidInfo('1.3.6.1.1.10.4.36', OID_ATTRIBUTE_TYPE, 'uddiv3NodeId', 'RFC4403'), '1.3.6.1.1.10.4.37': OidInfo('1.3.6.1.1.10.4.37', OID_ATTRIBUTE_TYPE, 'uddiv3EntityModificationTime', 'RFC4403'), '1.3.6.1.1.10.4.38': OidInfo('1.3.6.1.1.10.4.38', OID_ATTRIBUTE_TYPE, 'uddiv3SubscriptionKey', 'RFC4403'), '1.3.6.1.1.10.4.39': OidInfo('1.3.6.1.1.10.4.39', OID_ATTRIBUTE_TYPE, 'uddiv3SubscriptionFilter', 'RFC4403'), '1.3.6.1.1.10.4.40': OidInfo('1.3.6.1.1.10.4.40', OID_ATTRIBUTE_TYPE, 'uddiv3NotificationInterval', 'RFC4403'), '1.3.6.1.1.10.4.41': OidInfo('1.3.6.1.1.10.4.41', OID_ATTRIBUTE_TYPE, 'uddiv3MaxEntities', 'RFC4403'), '1.3.6.1.1.10.4.42': OidInfo('1.3.6.1.1.10.4.42', OID_ATTRIBUTE_TYPE, 'uddiv3ExpiresAfter', 'RFC4403'), '1.3.6.1.1.10.4.43': OidInfo('1.3.6.1.1.10.4.43', OID_ATTRIBUTE_TYPE, 'uddiv3BriefResponse', 'RFC4403'), '1.3.6.1.1.10.4.44': OidInfo('1.3.6.1.1.10.4.44', OID_ATTRIBUTE_TYPE, 'uddiv3EntityKey', 'RFC4403'), '1.3.6.1.1.10.4.45': OidInfo('1.3.6.1.1.10.4.45', OID_ATTRIBUTE_TYPE, 'uddiv3EntityCreationTime', 'RFC4403'), '1.3.6.1.1.10.4.46': OidInfo('1.3.6.1.1.10.4.46', OID_ATTRIBUTE_TYPE, 'uddiv3EntityDeletionTime', 'RFC4403'), '1.3.6.1.1.11.2.1': OidInfo('1.3.6.1.1.11.2.1', OID_ATTRIBUTE_TYPE, 'vPIMTelephoneNumber', 'RFC4237'), '1.3.6.1.1.11.2.2': OidInfo('1.3.6.1.1.11.2.2', OID_ATTRIBUTE_TYPE, 'vPIMRfc822Mailbox', 'RFC4237'), '1.3.6.1.1.11.2.3': OidInfo('1.3.6.1.1.11.2.3', OID_ATTRIBUTE_TYPE, 'vPIMSpokenName', 'RFC4237'), '1.3.6.1.1.11.2.4': OidInfo('1.3.6.1.1.11.2.4', OID_ATTRIBUTE_TYPE, 'vPIMSupportedUABehaviors', 'RFC4237'), '1.3.6.1.1.11.2.5': OidInfo('1.3.6.1.1.11.2.5', OID_ATTRIBUTE_TYPE, 'vPIMSupportedAudioMediaTypes', 'RFC4237'), '1.3.6.1.1.11.2.6': OidInfo('1.3.6.1.1.11.2.6', OID_ATTRIBUTE_TYPE, 'vPIMSupportedMessageContext', 'RFC4237'), '1.3.6.1.1.11.2.7': OidInfo('1.3.6.1.1.11.2.7', OID_ATTRIBUTE_TYPE, 'vPIMTextName', 'RFC4237'), '1.3.6.1.1.11.2.8': OidInfo('1.3.6.1.1.11.2.8', OID_ATTRIBUTE_TYPE, 'vPIMExtendedAbsenceStatus', 'RFC4237'), '1.3.6.1.1.11.2.9': OidInfo('1.3.6.1.1.11.2.9', OID_ATTRIBUTE_TYPE, 'vPIMMaxMessageSize', 'RFC4237'), '1.3.6.1.1.11.2.10': OidInfo('1.3.6.1.1.11.2.10', OID_ATTRIBUTE_TYPE, 'vPIMSubMailboxes', 'RFC4237'), '1.3.6.1.1.16.4': OidInfo('1.3.6.1.1.16.4', OID_ATTRIBUTE_TYPE, 'entryUUID', 'RFC4530'), '1.3.6.1.1.20': OidInfo('1.3.6.1.1.20', OID_ATTRIBUTE_TYPE, 'entryDN', 'RFC5020'), '1.3.6.1.1.6.2.3': OidInfo('1.3.6.1.1.6.2.3', OID_ATTRIBUTE_TYPE, 'pcimKeywords', 'RFC3703'), '1.3.6.1.1.6.2.4': OidInfo('1.3.6.1.1.6.2.4', OID_ATTRIBUTE_TYPE, 'pcimGroupName', 'RFC3703'), '1.3.6.1.1.6.2.5': OidInfo('1.3.6.1.1.6.2.5', OID_ATTRIBUTE_TYPE, 'pcimRuleName', 'RFC3703'), '1.3.6.1.1.6.2.6': OidInfo('1.3.6.1.1.6.2.6', OID_ATTRIBUTE_TYPE, 'pcimRuleEnabled', 'RFC3703'), '1.3.6.1.1.6.2.7': OidInfo('1.3.6.1.1.6.2.7', OID_ATTRIBUTE_TYPE, 'pcimRuleConditionListType', 'RFC3703'), '1.3.6.1.1.6.2.8': OidInfo('1.3.6.1.1.6.2.8', OID_ATTRIBUTE_TYPE, 'pcimRuleConditionList', 'RFC3703'), '1.3.6.1.1.6.2.9': OidInfo('1.3.6.1.1.6.2.9', OID_ATTRIBUTE_TYPE, 'pcimRuleActionList', 'RFC3703'), '1.3.6.1.1.6.2.10': OidInfo('1.3.6.1.1.6.2.10', OID_ATTRIBUTE_TYPE, 'pcimRuleValidityPeriodList', 'RFC3703'), '1.3.6.1.1.6.2.11': OidInfo('1.3.6.1.1.6.2.11', OID_ATTRIBUTE_TYPE, 'pcimRuleUsage', 'RFC3703'), '1.3.6.1.1.6.2.12': OidInfo('1.3.6.1.1.6.2.12', OID_ATTRIBUTE_TYPE, 'pcimRulePriority', 'RFC3703'), '1.3.6.1.1.6.2.13': OidInfo('1.3.6.1.1.6.2.13', OID_ATTRIBUTE_TYPE, 'pcimRuleMandatory', 'RFC3703'), '1.3.6.1.1.6.2.14': OidInfo('1.3.6.1.1.6.2.14', OID_ATTRIBUTE_TYPE, 'pcimRuleSequencedActions', 'RFC3703'), '1.3.6.1.1.6.2.15': OidInfo('1.3.6.1.1.6.2.15', OID_ATTRIBUTE_TYPE, 'pcimRoles', 'RFC3703'), '1.3.6.1.1.6.2.16': OidInfo('1.3.6.1.1.6.2.16', OID_ATTRIBUTE_TYPE, 'pcimConditionGroupNumber', 'RFC3703'), '1.3.6.1.1.6.2.17': OidInfo('1.3.6.1.1.6.2.17', OID_ATTRIBUTE_TYPE, 'pcimConditionNegated', 'RFC3703'), '1.3.6.1.1.6.2.18': OidInfo('1.3.6.1.1.6.2.18', OID_ATTRIBUTE_TYPE, 'pcimConditionName', 'RFC3703'), '1.3.6.1.1.6.2.19': OidInfo('1.3.6.1.1.6.2.19', OID_ATTRIBUTE_TYPE, 'pcimConditionDN', 'RFC3703'), '1.3.6.1.1.6.2.20': OidInfo('1.3.6.1.1.6.2.20', OID_ATTRIBUTE_TYPE, 'pcimValidityConditionName', 'RFC3703'), '1.3.6.1.1.6.2.21': OidInfo('1.3.6.1.1.6.2.21', OID_ATTRIBUTE_TYPE, 'pcimTimePeriodConditionDN', 'RFC3703'), '1.3.6.1.1.6.2.22': OidInfo('1.3.6.1.1.6.2.22', OID_ATTRIBUTE_TYPE, 'pcimActionName', 'RFC3703'), '1.3.6.1.1.6.2.23': OidInfo('1.3.6.1.1.6.2.23', OID_ATTRIBUTE_TYPE, 'pcimActionOrder', 'RFC3703'), '1.3.6.1.1.6.2.24': OidInfo('1.3.6.1.1.6.2.24', OID_ATTRIBUTE_TYPE, 'pcimActionDN', 'RFC3703'), '1.3.6.1.1.6.2.25': OidInfo('1.3.6.1.1.6.2.25', OID_ATTRIBUTE_TYPE, 'pcimTPCTime', 'RFC3703'), '1.3.6.1.1.6.2.26': OidInfo('1.3.6.1.1.6.2.26', OID_ATTRIBUTE_TYPE, 'pcimTPCMonthOfYearMask', 'RFC3703'), '1.3.6.1.1.6.2.27': OidInfo('1.3.6.1.1.6.2.27', OID_ATTRIBUTE_TYPE, 'pcimTPCDayOfMonthMask', 'RFC3703'), '1.3.6.1.1.6.2.28': OidInfo('1.3.6.1.1.6.2.28', OID_ATTRIBUTE_TYPE, 'pcimTPCDayOfWeekMask', 'RFC3703'), '1.3.6.1.1.6.2.29': OidInfo('1.3.6.1.1.6.2.29', OID_ATTRIBUTE_TYPE, 'pcimTPCTimeOfDayMask', 'RFC3703'), '1.3.6.1.1.6.2.30': OidInfo('1.3.6.1.1.6.2.30', OID_ATTRIBUTE_TYPE, 'pcimTPCLocalOrUtcTime', 'RFC3703'), '1.3.6.1.1.6.2.31': OidInfo('1.3.6.1.1.6.2.31', OID_ATTRIBUTE_TYPE, 'pcimVendorConstraintData', 'RFC3703'), '1.3.6.1.1.6.2.32': OidInfo('1.3.6.1.1.6.2.32', OID_ATTRIBUTE_TYPE, 'pcimVendorConstraintEncoding', 'RFC3703'), '1.3.6.1.1.6.2.33': OidInfo('1.3.6.1.1.6.2.33', OID_ATTRIBUTE_TYPE, 'pcimVendorActionData', 'RFC3703'), '1.3.6.1.1.6.2.34': OidInfo('1.3.6.1.1.6.2.34', OID_ATTRIBUTE_TYPE, 'pcimVendorActionEncoding', 'RFC3703'), '1.3.6.1.1.6.2.35': OidInfo('1.3.6.1.1.6.2.35', OID_ATTRIBUTE_TYPE, 'pcimPolicyInstanceName', 'RFC3703'), '1.3.6.1.1.6.2.36': OidInfo('1.3.6.1.1.6.2.36', OID_ATTRIBUTE_TYPE, 'pcimRepositoryName', 'RFC3703'), '1.3.6.1.1.6.2.37': OidInfo('1.3.6.1.1.6.2.37', OID_ATTRIBUTE_TYPE, 'pcimSubtreesAuxContainedSet', 'RFC3703'), '1.3.6.1.1.6.2.38': OidInfo('1.3.6.1.1.6.2.38', OID_ATTRIBUTE_TYPE, 'pcimGroupsAuxContainedSet', 'RFC3703'), '1.3.6.1.1.6.2.39': OidInfo('1.3.6.1.1.6.2.39', OID_ATTRIBUTE_TYPE, 'pcimRulesAuxContainedSet', 'RFC3703'), '1.3.6.1.1.9.2.1': OidInfo('1.3.6.1.1.9.2.1', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetName', 'RFC4104'), '1.3.6.1.1.9.2.2': OidInfo('1.3.6.1.1.9.2.2', OID_ATTRIBUTE_TYPE, 'pcelsDecisionStrategy', 'RFC4104'), '1.3.6.1.1.9.2.3': OidInfo('1.3.6.1.1.9.2.3', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetList', 'RFC4104'), '1.3.6.1.1.9.2.4': OidInfo('1.3.6.1.1.9.2.4', OID_ATTRIBUTE_TYPE, 'pcelsPriority', 'RFC4104'), '1.3.6.1.1.9.2.5': OidInfo('1.3.6.1.1.9.2.5', OID_ATTRIBUTE_TYPE, 'pcelsPolicySetDN', 'RFC4104'), '1.3.6.1.1.9.2.6': OidInfo('1.3.6.1.1.9.2.6', OID_ATTRIBUTE_TYPE, 'pcelsConditionListType', 'RFC4104'), '1.3.6.1.1.9.2.7': OidInfo('1.3.6.1.1.9.2.7', OID_ATTRIBUTE_TYPE, 'pcelsConditionList', 'RFC4104'), '1.3.6.1.1.9.2.8': OidInfo('1.3.6.1.1.9.2.8', OID_ATTRIBUTE_TYPE, 'pcelsActionList', 'RFC4104'), '1.3.6.1.1.9.2.9': OidInfo('1.3.6.1.1.9.2.9', OID_ATTRIBUTE_TYPE, 'pcelsSequencedActions', 'RFC4104'), '1.3.6.1.1.9.2.10': OidInfo('1.3.6.1.1.9.2.10', OID_ATTRIBUTE_TYPE, 'pcelsExecutionStrategy', 'RFC4104'), '1.3.6.1.1.9.2.11': OidInfo('1.3.6.1.1.9.2.11', OID_ATTRIBUTE_TYPE, 'pcelsVariableDN', 'RFC4104'), '1.3.6.1.1.9.2.12': OidInfo('1.3.6.1.1.9.2.12', OID_ATTRIBUTE_TYPE, 'pcelsValueDN', 'RFC4104'), '1.3.6.1.1.9.2.13': OidInfo('1.3.6.1.1.9.2.13', OID_ATTRIBUTE_TYPE, 'pcelsIsMirrored', 'RFC4104'), '1.3.6.1.1.9.2.14': OidInfo('1.3.6.1.1.9.2.14', OID_ATTRIBUTE_TYPE, 'pcelsVariableName', 'RFC4104'), '1.3.6.1.1.9.2.15': OidInfo('1.3.6.1.1.9.2.15', OID_ATTRIBUTE_TYPE, 'pcelsExpectedValueList', 'RFC4104'), '1.3.6.1.1.9.2.16': OidInfo('1.3.6.1.1.9.2.16', OID_ATTRIBUTE_TYPE, 'pcelsVariableModelClass', 'RFC4104'), '1.3.6.1.1.9.2.17': OidInfo('1.3.6.1.1.9.2.17', OID_ATTRIBUTE_TYPE, 'pcelsVariableModelProperty', 'RFC4104'), '1.3.6.1.1.9.2.18': OidInfo('1.3.6.1.1.9.2.18', OID_ATTRIBUTE_TYPE, 'pcelsExpectedValueTypes', 'RFC4104'), '1.3.6.1.1.9.2.19': OidInfo('1.3.6.1.1.9.2.19', OID_ATTRIBUTE_TYPE, 'pcelsValueName', 'RFC4104'), '1.3.6.1.1.9.2.20': OidInfo('1.3.6.1.1.9.2.20', OID_ATTRIBUTE_TYPE, 'pcelsIPv4AddrList', 'RFC4104'), '1.3.6.1.1.9.2.21': OidInfo('1.3.6.1.1.9.2.21', OID_ATTRIBUTE_TYPE, 'pcelsIPv6AddrList', 'RFC4104'), '1.3.6.1.1.9.2.22': OidInfo('1.3.6.1.1.9.2.22', OID_ATTRIBUTE_TYPE, 'pcelsMACAddrList', 'RFC4104'), '1.3.6.1.1.9.2.23': OidInfo('1.3.6.1.1.9.2.23', OID_ATTRIBUTE_TYPE, 'pcelsStringList', 'RFC4104'), '1.3.6.1.1.9.2.24': OidInfo('1.3.6.1.1.9.2.24', OID_ATTRIBUTE_TYPE, 'pcelsBitStringList', 'RFC4104'), '1.3.6.1.1.9.2.25': OidInfo('1.3.6.1.1.9.2.25', OID_ATTRIBUTE_TYPE, 'pcelsIntegerList', 'RFC4104'), '1.3.6.1.1.9.2.26': OidInfo('1.3.6.1.1.9.2.26', OID_ATTRIBUTE_TYPE, 'pcelsBoolean', 'RFC4104'), '1.3.6.1.1.9.2.27': OidInfo('1.3.6.1.1.9.2.27', OID_ATTRIBUTE_TYPE, 'pcelsReusableContainerName', 'RFC4104'), '1.3.6.1.1.9.2.28': OidInfo('1.3.6.1.1.9.2.28', OID_ATTRIBUTE_TYPE, 'pcelsReusableContainerList', 'RFC4104'), '1.3.6.1.1.9.2.29': OidInfo('1.3.6.1.1.9.2.29', OID_ATTRIBUTE_TYPE, 'pcelsRole', 'RFC4104'), '1.3.6.1.1.9.2.30': OidInfo('1.3.6.1.1.9.2.30', OID_ATTRIBUTE_TYPE, 'pcelsRoleCollectionName', 'RFC4104'), '1.3.6.1.1.9.2.31': OidInfo('1.3.6.1.1.9.2.31', OID_ATTRIBUTE_TYPE, 'pcelsElementList', 'RFC4104'), '1.3.6.1.1.9.2.32': OidInfo('1.3.6.1.1.9.2.32', OID_ATTRIBUTE_TYPE, 'pcelsFilterName', 'RFC4104'), '1.3.6.1.1.9.2.33': OidInfo('1.3.6.1.1.9.2.33', OID_ATTRIBUTE_TYPE, 'pcelsFilterIsNegated', 'RFC4104'), '1.3.6.1.1.9.2.34': OidInfo('1.3.6.1.1.9.2.34', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrVersion', 'RFC4104'), '1.3.6.1.1.9.2.35': OidInfo('1.3.6.1.1.9.2.35', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceAddress', 'RFC4104'), '1.3.6.1.1.9.2.36': OidInfo('1.3.6.1.1.9.2.36', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceAddressEndOfRange', 'RFC4104'), '1.3.6.1.1.9.2.37': OidInfo('1.3.6.1.1.9.2.37', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourceMask', 'RFC4104'), '1.3.6.1.1.9.2.38': OidInfo('1.3.6.1.1.9.2.38', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestAddress', 'RFC4104'), '1.3.6.1.1.9.2.39': OidInfo('1.3.6.1.1.9.2.39', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestAddressEndOfRange', 'RFC4104'), '1.3.6.1.1.9.2.40': OidInfo('1.3.6.1.1.9.2.40', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestMask', 'RFC4104'), '1.3.6.1.1.9.2.41': OidInfo('1.3.6.1.1.9.2.41', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrProtocolID', 'RFC4104'), '1.3.6.1.1.9.2.42': OidInfo('1.3.6.1.1.9.2.42', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourcePortStart', 'RFC4104'), '1.3.6.1.1.9.2.43': OidInfo('1.3.6.1.1.9.2.43', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrSourcePortEnd', 'RFC4104'), '1.3.6.1.1.9.2.44': OidInfo('1.3.6.1.1.9.2.44', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestPortStart', 'RFC4104'), '1.3.6.1.1.9.2.45': OidInfo('1.3.6.1.1.9.2.45', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDestPortEnd', 'RFC4104'), '1.3.6.1.1.9.2.46': OidInfo('1.3.6.1.1.9.2.46', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrDSCPList', 'RFC4104'), '1.3.6.1.1.9.2.47': OidInfo('1.3.6.1.1.9.2.47', OID_ATTRIBUTE_TYPE, 'pcelsIPHdrFlowLabel', 'RFC4104'), '1.3.6.1.1.9.2.48': OidInfo('1.3.6.1.1.9.2.48', OID_ATTRIBUTE_TYPE, 'pcels8021HdrSourceMACAddress', 'RFC4104'), '1.3.6.1.1.9.2.49': OidInfo('1.3.6.1.1.9.2.49', OID_ATTRIBUTE_TYPE, 'pcels8021HdrSourceMACMask', 'RFC4104'), '1.3.6.1.1.9.2.50': OidInfo('1.3.6.1.1.9.2.50', OID_ATTRIBUTE_TYPE, 'pcels8021HdrDestMACAddress', 'RFC4104'), '1.3.6.1.1.9.2.51': OidInfo('1.3.6.1.1.9.2.51', OID_ATTRIBUTE_TYPE, 'pcels8021HdrDestMACMask', 'RFC4104'), '1.3.6.1.1.9.2.52': OidInfo('1.3.6.1.1.9.2.52', OID_ATTRIBUTE_TYPE, 'pcels8021HdrProtocolID', 'RFC4104'), '1.3.6.1.1.9.2.53': OidInfo('1.3.6.1.1.9.2.53', OID_ATTRIBUTE_TYPE, 'pcels8021HdrPriority', 'RFC4104'), '1.3.6.1.1.9.2.54': OidInfo('1.3.6.1.1.9.2.54', OID_ATTRIBUTE_TYPE, 'pcels8021HdrVLANID', 'RFC4104'), '1.3.6.1.1.9.2.55': OidInfo('1.3.6.1.1.9.2.55', OID_ATTRIBUTE_TYPE, 'pcelsFilterListName', 'RFC4104'), '1.3.6.1.1.9.2.56': OidInfo('1.3.6.1.1.9.2.56', OID_ATTRIBUTE_TYPE, 'pcelsFilterDirection', 'RFC4104'), '1.3.6.1.1.9.2.57': OidInfo('1.3.6.1.1.9.2.57', OID_ATTRIBUTE_TYPE, 'pcelsFilterEntryList', 'RFC4104'), '1.3.6.1.1.9.2.58': OidInfo('1.3.6.1.1.9.2.58', OID_ATTRIBUTE_TYPE, 'pcelsVendorVariableData', 'RFC4104'), '1.3.6.1.1.9.2.59': OidInfo('1.3.6.1.1.9.2.59', OID_ATTRIBUTE_TYPE, 'pcelsVendorVariableEncoding', 'RFC4104'), '1.3.6.1.1.9.2.60': OidInfo('1.3.6.1.1.9.2.60', OID_ATTRIBUTE_TYPE, 'pcelsVendorValueData', 'RFC4104'), '1.3.6.1.1.9.2.61': OidInfo('1.3.6.1.1.9.2.61', OID_ATTRIBUTE_TYPE, 'pcelsVendorValueEncoding', 'RFC4104'), '1.3.6.1.1.9.2.62': OidInfo('1.3.6.1.1.9.2.62', OID_ATTRIBUTE_TYPE, 'pcelsRuleValidityPeriodList', 'RFC4104'), '1.3.6.1.4.1.11.1.3.1.1.0': OidInfo('1.3.6.1.4.1.11.1.3.1.1.0', OID_ATTRIBUTE_TYPE, 'defaultServerList', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.1': OidInfo('1.3.6.1.4.1.11.1.3.1.1.1', OID_ATTRIBUTE_TYPE, 'defaultSearchBase', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.2': OidInfo('1.3.6.1.4.1.11.1.3.1.1.2', OID_ATTRIBUTE_TYPE, 'preferredServerList', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.3': OidInfo('1.3.6.1.4.1.11.1.3.1.1.3', OID_ATTRIBUTE_TYPE, 'search_time_limit', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.4': OidInfo('1.3.6.1.4.1.11.1.3.1.1.4', OID_ATTRIBUTE_TYPE, 'bindTimeLimit', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.5': OidInfo('1.3.6.1.4.1.11.1.3.1.1.5', OID_ATTRIBUTE_TYPE, 'followReferrals', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.6': OidInfo('1.3.6.1.4.1.11.1.3.1.1.6', OID_ATTRIBUTE_TYPE, 'authenticationMethod', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.7': OidInfo('1.3.6.1.4.1.11.1.3.1.1.7', OID_ATTRIBUTE_TYPE, 'profileTTL', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.9': OidInfo('1.3.6.1.4.1.11.1.3.1.1.9', OID_ATTRIBUTE_TYPE, 'attributeMap', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.10': OidInfo('1.3.6.1.4.1.11.1.3.1.1.10', OID_ATTRIBUTE_TYPE, 'credentialLevel', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.11': OidInfo('1.3.6.1.4.1.11.1.3.1.1.11', OID_ATTRIBUTE_TYPE, 'objectclassMap', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.12': OidInfo('1.3.6.1.4.1.11.1.3.1.1.12', OID_ATTRIBUTE_TYPE, 'defaultSearchScope', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.13': OidInfo('1.3.6.1.4.1.11.1.3.1.1.13', OID_ATTRIBUTE_TYPE, 'serviceCredentialLevel', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.14': OidInfo('1.3.6.1.4.1.11.1.3.1.1.14', OID_ATTRIBUTE_TYPE, 'serviceSearchDescriptor', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.15': OidInfo('1.3.6.1.4.1.11.1.3.1.1.15', OID_ATTRIBUTE_TYPE, 'serviceAuthenticationMethod', 'RFC4876'), '1.3.6.1.4.1.11.1.3.1.1.16': OidInfo('1.3.6.1.4.1.11.1.3.1.1.16', OID_ATTRIBUTE_TYPE, 'dereferenceAliases', 'RFC4876'), '1.3.6.1.4.1.1466.101.119.3': OidInfo('1.3.6.1.4.1.1466.101.119.3', OID_ATTRIBUTE_TYPE, 'entryTtl', 'RFC2589'), '1.3.6.1.4.1.1466.101.119.4': OidInfo('1.3.6.1.4.1.1466.101.119.4', OID_ATTRIBUTE_TYPE, 'dynamicSubtrees', 'RFC2589'), '1.3.6.1.4.1.1466.101.120.1': OidInfo('1.3.6.1.4.1.1466.101.120.1', OID_ATTRIBUTE_TYPE, 'administratorsAddress', 'Mark_Wahl'), '1.3.6.1.4.1.1466.101.120.5': OidInfo('1.3.6.1.4.1.1466.101.120.5', OID_ATTRIBUTE_TYPE, 'namingContexts', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.6': OidInfo('1.3.6.1.4.1.1466.101.120.6', OID_ATTRIBUTE_TYPE, 'altServer', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.7': OidInfo('1.3.6.1.4.1.1466.101.120.7', OID_ATTRIBUTE_TYPE, 'supportedExtension', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.13': OidInfo('1.3.6.1.4.1.1466.101.120.13', OID_ATTRIBUTE_TYPE, 'supportedControl', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.14': OidInfo('1.3.6.1.4.1.1466.101.120.14', OID_ATTRIBUTE_TYPE, 'supportedSASLMechanisms', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.15': OidInfo('1.3.6.1.4.1.1466.101.120.15', OID_ATTRIBUTE_TYPE, 'supportedLDAPVersion', 'RFC4512'), '1.3.6.1.4.1.1466.101.120.16': OidInfo('1.3.6.1.4.1.1466.101.120.16', OID_ATTRIBUTE_TYPE, 'ldapSyntaxes', 'RFC4512'), '1.3.6.1.4.1.16572.2.2.1': OidInfo('1.3.6.1.4.1.16572.2.2.1', OID_ATTRIBUTE_TYPE, 'providerCertificateHash', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.2': OidInfo('1.3.6.1.4.1.16572.2.2.2', OID_ATTRIBUTE_TYPE, 'providerCertificate', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.3': OidInfo('1.3.6.1.4.1.16572.2.2.3', OID_ATTRIBUTE_TYPE, 'providerName', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.4': OidInfo('1.3.6.1.4.1.16572.2.2.4', OID_ATTRIBUTE_TYPE, 'mailReceipt', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.5': OidInfo('1.3.6.1.4.1.16572.2.2.5', OID_ATTRIBUTE_TYPE, 'managedDomains', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.6': OidInfo('1.3.6.1.4.1.16572.2.2.6', OID_ATTRIBUTE_TYPE, 'LDIFLocationURL', 'RFC6109'), '1.3.6.1.4.1.16572.2.2.7': OidInfo('1.3.6.1.4.1.16572.2.2.7', OID_ATTRIBUTE_TYPE, 'providerUnit', 'RFC6109'), '1.3.6.1.4.1.250.1.57': OidInfo('1.3.6.1.4.1.250.1.57', OID_ATTRIBUTE_TYPE, 'labeledURI', 'RFC2079'), '1.3.6.1.4.1.31103.1.1': OidInfo('1.3.6.1.4.1.31103.1.1', OID_ATTRIBUTE_TYPE, 'fedfsUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.2': OidInfo('1.3.6.1.4.1.31103.1.2', OID_ATTRIBUTE_TYPE, 'fedfsNetAddr', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.3': OidInfo('1.3.6.1.4.1.31103.1.3', OID_ATTRIBUTE_TYPE, 'fedfsNetPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.4': OidInfo('1.3.6.1.4.1.31103.1.4', OID_ATTRIBUTE_TYPE, 'fedfsFsnUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.5': OidInfo('1.3.6.1.4.1.31103.1.5', OID_ATTRIBUTE_TYPE, 'fedfsNsdbName', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.6': OidInfo('1.3.6.1.4.1.31103.1.6', OID_ATTRIBUTE_TYPE, 'fedfsNsdbPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.7': OidInfo('1.3.6.1.4.1.31103.1.7', OID_ATTRIBUTE_TYPE, 'fedfsNcePrefix', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.8': OidInfo('1.3.6.1.4.1.31103.1.8', OID_ATTRIBUTE_TYPE, 'fedfsFslUuid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.9': OidInfo('1.3.6.1.4.1.31103.1.9', OID_ATTRIBUTE_TYPE, 'fedfsFslHost', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.10': OidInfo('1.3.6.1.4.1.31103.1.10', OID_ATTRIBUTE_TYPE, 'fedfsFslPort', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.11': OidInfo('1.3.6.1.4.1.31103.1.11', OID_ATTRIBUTE_TYPE, 'fedfsFslTTL', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.12': OidInfo('1.3.6.1.4.1.31103.1.12', OID_ATTRIBUTE_TYPE, 'fedfsAnnotation', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.13': OidInfo('1.3.6.1.4.1.31103.1.13', OID_ATTRIBUTE_TYPE, 'fedfsDescr', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.14': OidInfo('1.3.6.1.4.1.31103.1.14', OID_ATTRIBUTE_TYPE, 'fedfsNceDN', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.15': OidInfo('1.3.6.1.4.1.31103.1.15', OID_ATTRIBUTE_TYPE, 'fedfsFsnTTL', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.100': OidInfo('1.3.6.1.4.1.31103.1.100', OID_ATTRIBUTE_TYPE, 'fedfsNfsPath', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.101': OidInfo('1.3.6.1.4.1.31103.1.101', OID_ATTRIBUTE_TYPE, 'fedfsNfsMajorVer', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.102': OidInfo('1.3.6.1.4.1.31103.1.102', OID_ATTRIBUTE_TYPE, 'fedfsNfsMinorVer', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.103': OidInfo('1.3.6.1.4.1.31103.1.103', OID_ATTRIBUTE_TYPE, 'fedfsNfsCurrency', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.104': OidInfo('1.3.6.1.4.1.31103.1.104', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagWritable', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.105': OidInfo('1.3.6.1.4.1.31103.1.105', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagGoing', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.106': OidInfo('1.3.6.1.4.1.31103.1.106', OID_ATTRIBUTE_TYPE, 'fedfsNfsGenFlagSplit', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.107': OidInfo('1.3.6.1.4.1.31103.1.107', OID_ATTRIBUTE_TYPE, 'fedfsNfsTransFlagRdma', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.108': OidInfo('1.3.6.1.4.1.31103.1.108', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassSimul', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.109': OidInfo('1.3.6.1.4.1.31103.1.109', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassHandle', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.110': OidInfo('1.3.6.1.4.1.31103.1.110', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassFileid', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.111': OidInfo('1.3.6.1.4.1.31103.1.111', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassWritever', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.112': OidInfo('1.3.6.1.4.1.31103.1.112', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassChange', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.113': OidInfo('1.3.6.1.4.1.31103.1.113', OID_ATTRIBUTE_TYPE, 'fedfsNfsClassReaddir', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.114': OidInfo('1.3.6.1.4.1.31103.1.114', OID_ATTRIBUTE_TYPE, 'fedfsNfsReadRank', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.115': OidInfo('1.3.6.1.4.1.31103.1.115', OID_ATTRIBUTE_TYPE, 'fedfsNfsReadOrder', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.116': OidInfo('1.3.6.1.4.1.31103.1.116', OID_ATTRIBUTE_TYPE, 'fedfsNfsWriteRank', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.117': OidInfo('1.3.6.1.4.1.31103.1.117', OID_ATTRIBUTE_TYPE, 'fedfsNfsWriteOrder', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.118': OidInfo('1.3.6.1.4.1.31103.1.118', OID_ATTRIBUTE_TYPE, 'fedfsNfsVarSub', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.119': OidInfo('1.3.6.1.4.1.31103.1.119', OID_ATTRIBUTE_TYPE, 'fedfsNfsValidFor', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.120': OidInfo('1.3.6.1.4.1.31103.1.120', OID_ATTRIBUTE_TYPE, 'fedfsNfsURI', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.4203.1.3.5': OidInfo('1.3.6.1.4.1.4203.1.3.5', OID_ATTRIBUTE_TYPE, 'supportedFeatures', 'RFC4512'), '1.3.6.1.4.1.453.7.2.1': OidInfo('1.3.6.1.4.1.453.7.2.1', OID_ATTRIBUTE_TYPE, 'textTableKey', 'RFC2293'), '1.3.6.1.4.1.453.7.2.2': OidInfo('1.3.6.1.4.1.453.7.2.2', OID_ATTRIBUTE_TYPE, 'textTableValue', 'RFC2293'), '1.3.6.1.4.1.453.7.2.3': OidInfo('1.3.6.1.4.1.453.7.2.3', OID_ATTRIBUTE_TYPE, ['associatedX400Gateway', 'distinguishedNameTableKey'], 'RFC2164-RFC2293'), '1.3.6.1.4.1.453.7.2.6': OidInfo('1.3.6.1.4.1.453.7.2.6', OID_ATTRIBUTE_TYPE, 'associatedORAddress', 'RFC2164'), '1.3.6.1.4.1.453.7.2.7': OidInfo('1.3.6.1.4.1.453.7.2.7', OID_ATTRIBUTE_TYPE, 'oRAddressComponentType', 'RFC2164'), '1.3.6.1.4.1.453.7.2.8': OidInfo('1.3.6.1.4.1.453.7.2.8', OID_ATTRIBUTE_TYPE, 'associatedInternetGateway', 'RFC2164'), '1.3.6.1.4.1.453.7.2.9': OidInfo('1.3.6.1.4.1.453.7.2.9', OID_ATTRIBUTE_TYPE, 'mcgamTables', 'RFC2164'), '2.16.840.1.113730.3.1.34': OidInfo('2.16.840.1.113730.3.1.34', OID_ATTRIBUTE_TYPE, 'ref', 'RFC3296'), '2.5.18.1': OidInfo('2.5.18.1', OID_ATTRIBUTE_TYPE, 'createTimestamp', 'RFC4512'), '2.5.18.2': OidInfo('2.5.18.2', OID_ATTRIBUTE_TYPE, 'modifyTimestamp', 'RFC4512'), '2.5.18.3': OidInfo('2.5.18.3', OID_ATTRIBUTE_TYPE, 'creatorsName', 'RFC4512'), '2.5.18.4': OidInfo('2.5.18.4', OID_ATTRIBUTE_TYPE, 'modifiersName', 'RFC4512'), '2.5.18.5': OidInfo('2.5.18.5', OID_ATTRIBUTE_TYPE, 'administrativeRole', 'RFC3672'), '2.5.18.6': OidInfo('2.5.18.6', OID_ATTRIBUTE_TYPE, 'subtreeSpecification', 'RFC3672'), '2.5.18.7': OidInfo('2.5.18.7', OID_ATTRIBUTE_TYPE, 'collectiveExclusions', 'RFC3671'), '2.5.18.10': OidInfo('2.5.18.10', OID_ATTRIBUTE_TYPE, 'subschemaSubentry', 'RFC4512'), '2.5.18.12': OidInfo('2.5.18.12', OID_ATTRIBUTE_TYPE, 'collectiveAttributeSubentries', 'RFC3671'), '2.5.21.1': OidInfo('2.5.21.1', OID_ATTRIBUTE_TYPE, 'dITStructureRules', 'RFC4512'), '2.5.21.2': OidInfo('2.5.21.2', OID_ATTRIBUTE_TYPE, 'dITContentRules', 'RFC4512'), '2.5.21.4': OidInfo('2.5.21.4', OID_ATTRIBUTE_TYPE, 'matchingRules', 'RFC4512'), '2.5.21.5': OidInfo('2.5.21.5', OID_ATTRIBUTE_TYPE, 'attributeTypes', 'RFC4512'), '2.5.21.6': OidInfo('2.5.21.6', OID_ATTRIBUTE_TYPE, 'objectClasses', 'RFC4512'), '2.5.21.7': OidInfo('2.5.21.7', OID_ATTRIBUTE_TYPE, 'nameForms', 'RFC4512'), '2.5.21.8': OidInfo('2.5.21.8', OID_ATTRIBUTE_TYPE, 'matchingRuleUse', 'RFC4512'), '2.5.21.9': OidInfo('2.5.21.9', OID_ATTRIBUTE_TYPE, 'structuralObjectClass', 'RFC4512'), '2.5.21.10': OidInfo('2.5.21.10', OID_ATTRIBUTE_TYPE, 'governingStructureRule', 'RFC4512'), '2.5.4.0': OidInfo('2.5.4.0', OID_ATTRIBUTE_TYPE, 'objectClass', 'RFC4512'), '2.5.4.1': OidInfo('2.5.4.1', OID_ATTRIBUTE_TYPE, ['aliasedEntryName', 'aliasedObjectName'], 'X.501-RFC4512'), '2.5.4.2': OidInfo('2.5.4.2', OID_ATTRIBUTE_TYPE, 'knowledgeInformation', 'RFC2256'), '2.5.4.3': OidInfo('2.5.4.3', OID_ATTRIBUTE_TYPE, ['cn', 'commonName'], 'RFC4519'), '2.5.4.4': OidInfo('2.5.4.4', OID_ATTRIBUTE_TYPE, ['sn', 'surname'], 'RFC4519'), '2.5.4.5': OidInfo('2.5.4.5', OID_ATTRIBUTE_TYPE, 'serialNumber', 'RFC4519'), '2.5.4.6': OidInfo('2.5.4.6', OID_ATTRIBUTE_TYPE, ['c', 'countryName'], 'RFC4519'), '2.5.4.7': OidInfo('2.5.4.7', OID_ATTRIBUTE_TYPE, ['L', 'localityName'], 'RFC4519'), '2.5.4.7.1': OidInfo('2.5.4.7.1', OID_ATTRIBUTE_TYPE, 'c-l', 'RFC3671'), '2.5.4.8': OidInfo('2.5.4.8', OID_ATTRIBUTE_TYPE, ['st', 'stateOrProvinceName'], 'RFC4519-RFC2256'), '2.5.4.8.1': OidInfo('2.5.4.8.1', OID_ATTRIBUTE_TYPE, 'c-st', 'RFC3671'), '2.5.4.9': OidInfo('2.5.4.9', OID_ATTRIBUTE_TYPE, ['street', 'streetAddress'], 'RFC4519-RFC2256'), '2.5.4.9.1': OidInfo('2.5.4.9.1', OID_ATTRIBUTE_TYPE, 'c-street', 'RFC3671'), '2.5.4.10': OidInfo('2.5.4.10', OID_ATTRIBUTE_TYPE, 'o, organizationName', 'RFC4519'), '2.5.4.10.1': OidInfo('2.5.4.10.1', OID_ATTRIBUTE_TYPE, 'c-o', 'RFC3671'), '2.5.4.11': OidInfo('2.5.4.11', OID_ATTRIBUTE_TYPE, ['ou', 'organizationalUnitName'], 'RFC4519'), '2.5.4.11.1': OidInfo('2.5.4.11.1', OID_ATTRIBUTE_TYPE, 'c-ou', 'RFC3671'), '2.5.4.12': OidInfo('2.5.4.12', OID_ATTRIBUTE_TYPE, 'title', 'RFC4519'), '2.5.4.13': OidInfo('2.5.4.13', OID_ATTRIBUTE_TYPE, 'description', 'RFC4519'), '2.5.4.14': OidInfo('2.5.4.14', OID_ATTRIBUTE_TYPE, 'searchGuide', 'RFC4519'), '2.5.4.15': OidInfo('2.5.4.15', OID_ATTRIBUTE_TYPE, 'businessCategory', 'RFC4519'), '2.5.4.16': OidInfo('2.5.4.16', OID_ATTRIBUTE_TYPE, 'postalAddress', 'RFC4519'), '2.5.4.16.1': OidInfo('2.5.4.16.1', OID_ATTRIBUTE_TYPE, 'c-PostalAddress', 'RFC3671'), '2.5.4.17': OidInfo('2.5.4.17', OID_ATTRIBUTE_TYPE, 'postalCode', 'RFC4519'), '2.5.4.17.1': OidInfo('2.5.4.17.1', OID_ATTRIBUTE_TYPE, 'c-PostalCode', 'RFC3671'), '2.5.4.18': OidInfo('2.5.4.18', OID_ATTRIBUTE_TYPE, 'postOfficeBox', 'RFC4519'), '2.5.4.18.1': OidInfo('2.5.4.18.1', OID_ATTRIBUTE_TYPE, 'c-PostOfficeBox', 'RFC3671'), '2.5.4.19': OidInfo('2.5.4.19', OID_ATTRIBUTE_TYPE, 'physicalDeliveryOfficeName', 'RFC4519'), '2.5.4.19.1': OidInfo('2.5.4.19.1', OID_ATTRIBUTE_TYPE, 'c-PhysicalDeliveryOffice', 'RFC3671'), '2.5.4.20': OidInfo('2.5.4.20', OID_ATTRIBUTE_TYPE, 'telephoneNumber', 'RFC4519'), '2.5.4.20.1': OidInfo('2.5.4.20.1', OID_ATTRIBUTE_TYPE, 'c-TelephoneNumber', 'RFC3671'), '2.5.4.21': OidInfo('2.5.4.21', OID_ATTRIBUTE_TYPE, 'telexNumber', 'RFC4519'), '2.5.4.21.1': OidInfo('2.5.4.21.1', OID_ATTRIBUTE_TYPE, 'c-TelexNumber', 'RFC3671'), '2.5.4.22': OidInfo('2.5.4.22', OID_ATTRIBUTE_TYPE, 'teletexTerminalIdentifier', 'RFC4519'), '2.5.4.23': OidInfo('2.5.4.23', OID_ATTRIBUTE_TYPE, 'facsimileTelephoneNumber', 'RFC4519'), '2.5.4.23.1': OidInfo('2.5.4.23.1', OID_ATTRIBUTE_TYPE, 'c-FacsimileTelephoneNumber', 'RFC3671'), '2.5.4.24': OidInfo('2.5.4.24', OID_ATTRIBUTE_TYPE, 'x121Address', 'RFC4519'), '2.5.4.25': OidInfo('2.5.4.25', OID_ATTRIBUTE_TYPE, 'internationaliSDNNumber', 'RFC4519'), '2.5.4.25.1': OidInfo('2.5.4.25.1', OID_ATTRIBUTE_TYPE, 'c-InternationalISDNNumber', 'RFC3671'), '2.5.4.26': OidInfo('2.5.4.26', OID_ATTRIBUTE_TYPE, 'registeredAddress', 'RFC4519'), '2.5.4.27': OidInfo('2.5.4.27', OID_ATTRIBUTE_TYPE, 'destinationIndicator', 'RFC4519'), '2.5.4.28': OidInfo('2.5.4.28', OID_ATTRIBUTE_TYPE, 'preferredDeliveryMethod', 'RFC4519'), '2.5.4.29': OidInfo('2.5.4.29', OID_ATTRIBUTE_TYPE, 'presentationAddress', 'RFC2256'), '2.5.4.30': OidInfo('2.5.4.30', OID_ATTRIBUTE_TYPE, 'supportedApplicationContext', 'RFC2256'), '2.5.4.31': OidInfo('2.5.4.31', OID_ATTRIBUTE_TYPE, 'member', 'RFC4519'), '2.5.4.32': OidInfo('2.5.4.32', OID_ATTRIBUTE_TYPE, 'owner', 'RFC4519'), '2.5.4.33': OidInfo('2.5.4.33', OID_ATTRIBUTE_TYPE, 'roleOccupant', 'RFC4519'), '2.5.4.34': OidInfo('2.5.4.34', OID_ATTRIBUTE_TYPE, 'seeAlso', 'RFC4519'), '2.5.4.35': OidInfo('2.5.4.35', OID_ATTRIBUTE_TYPE, 'userPassword', 'RFC4519'), '2.5.4.36': OidInfo('2.5.4.36', OID_ATTRIBUTE_TYPE, 'userCertificate', 'RFC4523'), '2.5.4.37': OidInfo('2.5.4.37', OID_ATTRIBUTE_TYPE, 'cACertificate', 'RFC4523'), '2.5.4.38': OidInfo('2.5.4.38', OID_ATTRIBUTE_TYPE, 'authorityRevocationList', 'RFC4523'), '2.5.4.39': OidInfo('2.5.4.39', OID_ATTRIBUTE_TYPE, 'certificateRevocationList', 'RFC4523'), '2.5.4.40': OidInfo('2.5.4.40', OID_ATTRIBUTE_TYPE, 'crossCertificatePair', 'RFC4523'), '2.5.4.41': OidInfo('2.5.4.41', OID_ATTRIBUTE_TYPE, 'name', 'RFC4519'), '2.5.4.42': OidInfo('2.5.4.42', OID_ATTRIBUTE_TYPE, 'givenName', 'RFC4519'), '2.5.4.43': OidInfo('2.5.4.43', OID_ATTRIBUTE_TYPE, 'initials', 'RFC4519'), '2.5.4.44': OidInfo('2.5.4.44', OID_ATTRIBUTE_TYPE, 'generationQualifier', 'RFC4519'), '2.5.4.45': OidInfo('2.5.4.45', OID_ATTRIBUTE_TYPE, 'x500UniqueIdentifier', 'RFC4519'), '2.5.4.46': OidInfo('2.5.4.46', OID_ATTRIBUTE_TYPE, 'dnQualifier', 'RFC4519'), '2.5.4.47': OidInfo('2.5.4.47', OID_ATTRIBUTE_TYPE, 'enhancedSearchGuide', 'RFC4519'), '2.5.4.48': OidInfo('2.5.4.48', OID_ATTRIBUTE_TYPE, 'protocolInformation', 'RFC2256'), '2.5.4.49': OidInfo('2.5.4.49', OID_ATTRIBUTE_TYPE, 'distinguishedName', 'RFC4519'), '2.5.4.50': OidInfo('2.5.4.50', OID_ATTRIBUTE_TYPE, 'uniqueMember', 'RFC4519'), '2.5.4.51': OidInfo('2.5.4.51', OID_ATTRIBUTE_TYPE, 'houseIdentifier', 'RFC4519'), '2.5.4.52': OidInfo('2.5.4.52', OID_ATTRIBUTE_TYPE, 'supportedAlgorithms', 'RFC4523'), '2.5.4.53': OidInfo('2.5.4.53', OID_ATTRIBUTE_TYPE, 'deltaRevocationList', 'RFC4523'), '2.5.4.54': OidInfo('2.5.4.54', OID_ATTRIBUTE_TYPE, 'dmdName', 'RFC2256'), '2.5.4.65': OidInfo('2.5.4.65', OID_ATTRIBUTE_TYPE, 'pseudonym', 'RFC3280'), # controls '1.2.826.0.1.3344810.2.3': OidInfo('1.2.826.0.1.3344810.2.3', OID_CONTROL, 'Matched Values', 'RFC3876'), '1.2.840.113556.1.4.319': OidInfo('1.2.840.113556.1.4.319', OID_CONTROL, 'LDAP Simple Paged Results', 'RFC2696'), '1.2.840.113556.1.4.417': OidInfo('1.2.840.113556.1.4.417', OID_CONTROL, 'LDAP server show deleted objects', 'MICROSOFT'), '1.2.840.113556.1.4.473': OidInfo('1.2.840.113556.1.4.473', OID_CONTROL, 'Sort Request', 'RFC2891'), '1.2.840.113556.1.4.474': OidInfo('1.2.840.113556.1.4.474', OID_CONTROL, 'Sort Response', 'RFC2891'), '1.2.840.113556.1.4.521': OidInfo('1.2.840.113556.1.4.521', OID_CONTROL, 'Cross-domain move', 'MICROSOFT'), '1.2.840.113556.1.4.528': OidInfo('1.2.840.113556.1.4.528', OID_CONTROL, 'Server search notification', 'MICROSOFT'), '1.2.840.113556.1.4.529': OidInfo('1.2.840.113556.1.4.529', OID_CONTROL, 'Extended DN', 'MICROSOFT'), '1.2.840.113556.1.4.619': OidInfo('1.2.840.113556.1.4.619', OID_CONTROL, 'Lazy commit', 'MICROSOFT'), '1.2.840.113556.1.4.801': OidInfo('1.2.840.113556.1.4.801', OID_CONTROL, 'Security descriptor flags', 'MICROSOFT'), '1.2.840.113556.1.4.802': OidInfo('1.2.840.113556.1.4.802', OID_CONTROL, 'Range option', 'MICROSOFT'), '1.2.840.113556.1.4.805': OidInfo('1.2.840.113556.1.4.805', OID_CONTROL, 'Tree delete', 'MICROSOFT'), '1.2.840.113556.1.4.841': OidInfo('1.2.840.113556.1.4.841', OID_CONTROL, 'Directory synchronization', 'MICROSOFT'), '1.2.840.113556.1.4.970': OidInfo('1.2.840.113556.1.4.970', OID_CONTROL, 'Get stats', 'MICROSOFT'), '1.2.840.113556.1.4.1338': OidInfo('1.2.840.113556.1.4.1338', OID_CONTROL, 'Verify name', 'MICROSOFT'), '1.2.840.113556.1.4.1339': OidInfo('1.2.840.113556.1.4.1339', OID_CONTROL, 'Domain scope', 'MICROSOFT'), '1.2.840.113556.1.4.1340': OidInfo('1.2.840.113556.1.4.1340', OID_CONTROL, 'Search options', 'MICROSOFT'), '1.2.840.113556.1.4.1341': OidInfo('1.2.840.113556.1.4.1341', OID_CONTROL, 'RODC DCPROMO', 'MICROSOFT'), '1.2.840.113556.1.4.1413': OidInfo('1.2.840.113556.1.4.1413', OID_CONTROL, 'Permissive modify', 'MICROSOFT'), '1.2.840.113556.1.4.1504': OidInfo('1.2.840.113556.1.4.1504', OID_CONTROL, 'Attribute scoped query', 'MICROSOFT'), '1.2.840.113556.1.4.1852': OidInfo('1.2.840.113556.1.4.1852', OID_CONTROL, 'User quota', 'MICROSOFT'), '1.2.840.113556.1.4.1907': OidInfo('1.2.840.113556.1.4.1907', OID_CONTROL, 'Server shutdown notify', 'MICROSOFT'), '1.2.840.113556.1.4.1948': OidInfo('1.2.840.113556.1.4.1948', OID_CONTROL, 'Range retrieval no error', 'MICROSOFT'), '1.2.840.113556.1.4.1974': OidInfo('1.2.840.113556.1.4.1974', OID_CONTROL, 'Server force update', 'MICROSOFT'), '1.2.840.113556.1.4.2026': OidInfo('1.2.840.113556.1.4.2026', OID_CONTROL, 'Input DN', 'MICROSOFT'), '1.2.840.113556.1.4.2064': OidInfo('1.2.840.113556.1.4.2064', OID_CONTROL, 'Show recycled', 'MICROSOFT'), '1.2.840.113556.1.4.2065': OidInfo('1.2.840.113556.1.4.2065', OID_CONTROL, 'Show deactivated link', 'MICROSOFT'), '1.2.840.113556.1.4.2066': OidInfo('1.2.840.113556.1.4.2066', OID_CONTROL, 'Policy hints (deprecated)', 'MICROSOFT'), '1.2.840.113556.1.4.2090': OidInfo('1.2.840.113556.1.4.2090', OID_CONTROL, 'DirSync EX', 'MICROSOFT'), '1.2.840.113556.1.4.2204': OidInfo('1.2.840.113556.1.4.2204', OID_CONTROL, 'Tree deleted EX', 'MICROSOFT'), '1.2.840.113556.1.4.2205': OidInfo('1.2.840.113556.1.4.2205', OID_CONTROL, 'Updates stats', 'MICROSOFT'), '1.2.840.113556.1.4.2206': OidInfo('1.2.840.113556.1.4.2206', OID_CONTROL, 'Search hints', 'MICROSOFT'), '1.2.840.113556.1.4.2211': OidInfo('1.2.840.113556.1.4.2211', OID_CONTROL, 'Expected entry count', 'MICROSOFT'), '1.2.840.113556.1.4.2239': OidInfo('1.2.840.113556.1.4.2239', OID_CONTROL, 'Policy hints', 'MICROSOFT'), '1.2.840.113556.1.4.2255': OidInfo('1.2.840.113556.1.4.2255', OID_CONTROL, 'Set owner', 'MICROSOFT'), '1.2.840.113556.1.4.2256': OidInfo('1.2.840.113556.1.4.2256', OID_CONTROL, 'Bypass quota', 'MICROSOFT'), '1.3.6.1.1.7.1': OidInfo('1.3.6.1.1.7.1', OID_CONTROL, 'LCUP Sync Request', 'RFC3928'), '1.3.6.1.1.7.2': OidInfo('1.3.6.1.1.7.2', OID_CONTROL, 'LCUP Sync Update', 'RFC3928'), '1.3.6.1.1.7.3': OidInfo('1.3.6.1.1.7.3', OID_CONTROL, 'LCUP Sync Done', 'RFC3928'), '1.3.6.1.1.12': OidInfo('1.3.6.1.1.12', OID_CONTROL, 'Assertion', 'RFC4528'), '1.3.6.1.1.13.1': OidInfo('1.3.6.1.1.13.1', OID_CONTROL, 'LDAP Pre-read', 'RFC4527'), '1.3.6.1.1.13.2': OidInfo('1.3.6.1.1.13.2', OID_CONTROL, 'LDAP Post-read', 'RFC4527'), '1.3.6.1.1.21.2': OidInfo('1.3.6.1.1.21.2', OID_CONTROL, 'Transaction Specification', 'RFC5805'), '1.3.6.1.1.22': OidInfo('1.3.6.1.1.22', OID_CONTROL, "LDAP Don't Use Copy", 'RFC6171'), '1.3.6.1.4.1.42.2.27.8.5.1': OidInfo('1.3.6.1.4.1.42.2.27.8.5.1', OID_CONTROL, 'Password policy', 'IETF DRAFT behera-ldap-password-policy'), '1.3.6.1.4.1.42.2.27.9.5.2': OidInfo('1.3.6.1.4.1.42.2.27.9.5.2', OID_CONTROL, 'Get effective rights', 'IETF DRAFT draft-ietf-ldapext-acl-model'), '1.3.6.1.4.1.42.2.27.9.5.8': OidInfo('1.3.6.1.4.1.42.2.27.9.5.8', OID_CONTROL, 'Account usability', 'SUN microsystems'), '1.3.6.1.4.1.4203.1.9.1.1': OidInfo('1.3.6.1.4.1.4203.1.9.1.1', OID_CONTROL, 'LDAP content synchronization', 'RFC4533'), '1.3.6.1.4.1.4203.1.10.1': OidInfo('1.3.6.1.4.1.4203.1.10.1', OID_CONTROL, 'Subentries', 'RFC3672'), '1.3.6.1.4.1.4203.1.10.2': OidInfo('1.3.6.1.4.1.4203.1.10.2', OID_CONTROL, 'No-Operation', 'IETF DRAFT draft-zeilenga-ldap-noop'), '1.3.6.1.4.1.7628.5.101.1': OidInfo('1.3.6.1.4.1.7628.5.101.1', OID_CONTROL, 'LDAP subentries', 'IETF DRAFT draft-ietf-ldup-subentry'), '1.3.6.1.4.1.26027.1.5.2': OidInfo('1.3.6.1.4.1.26027.1.5.2', OID_CONTROL, 'Replication repair', 'OpenDS'), '2.16.840.1.113719.1.27.101.5': OidInfo('2.16.840.1.113719.1.27.101.5', OID_CONTROL, 'Simple password', 'NOVELL'), '2.16.840.1.113719.1.27.101.6': OidInfo('2.16.840.1.113719.1.27.101.6', OID_CONTROL, 'Forward reference', 'NOVELL'), '2.16.840.1.113719.1.27.103.7': OidInfo('2.16.840.1.113719.1.27.103.7', OID_CONTROL, 'Grouping', 'NOVELL'), '2.16.840.1.113730.3.4.2': OidInfo('2.16.840.1.113730.3.4.2', OID_CONTROL, 'ManageDsaIT', 'RFC3296'), '2.16.840.1.113730.3.4.3': OidInfo('2.16.840.1.113730.3.4.3', OID_CONTROL, 'Persistent Search', 'IETF'), '2.16.840.1.113730.3.4.4': OidInfo('2.16.840.1.113730.3.4.4', OID_CONTROL, 'Netscape Password Expired', 'Netscape'), '2.16.840.1.113730.3.4.5': OidInfo('2.16.840.1.113730.3.4.5', OID_CONTROL, 'Netscape Password Expiring', 'Netscape'), '2.16.840.1.113730.3.4.6': OidInfo('2.16.840.1.113730.3.4.6', OID_CONTROL, 'Netscape NT Synchronization Client', 'Netscape'), '2.16.840.1.113730.3.4.7': OidInfo('2.16.840.1.113730.3.4.7', OID_CONTROL, 'Entry Change Notification', 'Netscape'), '2.16.840.1.113730.3.4.9': OidInfo('2.16.840.1.113730.3.4.9', OID_CONTROL, 'Virtual List View Request', 'IETF'), '2.16.840.1.113730.3.4.10': OidInfo('2.16.840.1.113730.3.4.10', OID_CONTROL, 'Virtual List View Response', 'IETF'), '2.16.840.1.113730.3.4.12': OidInfo('2.16.840.1.113730.3.4.12', OID_CONTROL, 'Proxied Authorization (old)', 'Netscape'), '2.16.840.1.113730.3.4.13': OidInfo('2.16.840.1.113730.3.4.13', OID_CONTROL, 'iPlanet Directory Server Replication Update Information', 'iPlanet'), '2.16.840.1.113730.3.4.14': OidInfo('2.16.840.1.113730.3.4.14', OID_CONTROL, 'Search on specific database', 'iPlanet'), '2.16.840.1.113730.3.4.15': OidInfo('2.16.840.1.113730.3.4.15', OID_CONTROL, 'Authorization Identity Response Control', 'RFC3829'), '2.16.840.1.113730.3.4.16': OidInfo('2.16.840.1.113730.3.4.16', OID_CONTROL, 'Authorization Identity Request Control', 'RFC3829'), '2.16.840.1.113730.3.4.17': OidInfo('2.16.840.1.113730.3.4.17', OID_CONTROL, 'Real attribute only request', 'iPlanet'), '2.16.840.1.113730.3.4.18': OidInfo('2.16.840.1.113730.3.4.18', OID_CONTROL, 'Proxy Authorization Control', 'RFC6171'), '2.16.840.1.113730.3.4.19': OidInfo('2.16.840.1.113730.3.4.19', OID_CONTROL, 'Virtual attribute only request', 'iPlanet'), # dit content rules # extensions '1.2.840.113556.1.4.1781': OidInfo('1.2.840.113556.1.4.1781', OID_EXTENSION, 'Fast concurrent bind', 'MICROSOFT'), '1.2.840.113556.1.4.2212': OidInfo('1.2.840.113556.1.4.2212', OID_EXTENSION, 'Batch request', 'MICROSOFT'), '1.3.6.1.1.8': OidInfo('1.3.6.1.1.8', OID_EXTENSION, 'Cancel Operation', 'RFC3909'), '1.3.6.1.1.21.1': OidInfo('1.3.6.1.1.21.1', OID_EXTENSION, 'Start Transaction Extended Request', 'RFC5805'), '1.3.6.1.1.21.3': OidInfo('1.3.6.1.1.21.3', OID_EXTENSION, 'End Transaction Extended Request', 'RFC5805'), '1.3.6.1.4.1.1466.101.119.1': OidInfo('1.3.6.1.4.1.1466.101.119.1', OID_EXTENSION, 'Dynamic Refresh', 'RFC2589'), '1.3.6.1.4.1.1466.20037': OidInfo('1.3.6.1.4.1.1466.20037', OID_EXTENSION, 'StartTLS', 'RFC4511-RFC4513'), '1.3.6.1.4.1.4203.1.11.1': OidInfo('1.3.6.1.4.1.4203.1.11.1', OID_EXTENSION, 'Modify Password', 'RFC3062'), '1.3.6.1.4.1.4203.1.11.3': OidInfo('1.3.6.1.4.1.4203.1.11.3', OID_EXTENSION, 'Who am I', 'RFC4532'), '1.3.6.1.1.17.1': OidInfo('1.3.6.1.1.17.1', OID_EXTENSION, 'StartLBURPRequest LDAP ExtendedRequest message', 'RFC4373'), '1.3.6.1.1.17.2': OidInfo('1.3.6.1.1.17.2', OID_EXTENSION, 'StartLBURPResponse LDAP ExtendedResponse message', 'RFC4373'), '1.3.6.1.1.17.3': OidInfo('1.3.6.1.1.17.3', OID_EXTENSION, 'EndLBURPRequest LDAP ExtendedRequest message', 'RFC4373'), '1.3.6.1.1.17.4': OidInfo('1.3.6.1.1.17.4', OID_EXTENSION, 'EndLBURPResponse LDAP ExtendedResponse message', 'RFC4373'), '1.3.6.1.1.17.5': OidInfo('1.3.6.1.1.17.5', OID_EXTENSION, 'LBURPUpdateRequest LDAP ExtendedRequest message', 'RFC4373'), '1.3.6.1.1.17.6': OidInfo('1.3.6.1.1.17.6', OID_EXTENSION, 'LBURPUpdateResponse LDAP ExtendedResponse message', 'RFC4373'), '1.3.6.1.1.19': OidInfo('1.3.6.1.1.19', OID_EXTENSION, 'LDAP Turn Operation', 'RFC4531'), '1.3.6.1.4.1.26027.1.6.1': OidInfo('1.3.6.1.4.1.26027.1.6.1', OID_CONTROL, 'Password policy state', 'OpenDS'), '1.3.6.1.4.1.26027.1.6.2': OidInfo('1.3.6.1.4.1.26027.1.6.2', OID_CONTROL, 'Get connection ID', 'OpenDS'), '1.3.6.1.4.1.26027.1.6.3': OidInfo('1.3.6.1.4.1.26027.1.6.3', OID_CONTROL, 'Get symmetric key', 'OpenDS'), '2.16.840.1.113719.1.14.100.1': OidInfo('2.16.840.1.113719.1.14.100.1', OID_EXTENSION, 'getDriverSetRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.2': OidInfo('2.16.840.1.113719.1.14.100.2', OID_EXTENSION, 'getDriverSetResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.3': OidInfo('2.16.840.1.113719.1.14.100.3', OID_EXTENSION, 'setDriverSetRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.4': OidInfo('2.16.840.1.113719.1.14.100.4', OID_EXTENSION, 'setDriverSetResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.5': OidInfo('2.16.840.1.113719.1.14.100.5', OID_EXTENSION, 'clearDriverSetRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.6': OidInfo('2.16.840.1.113719.1.14.100.6', OID_EXTENSION, 'clearDriverSetResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.7': OidInfo('2.16.840.1.113719.1.14.100.7', OID_EXTENSION, 'getDriverStartOptionRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.8': OidInfo('2.16.840.1.113719.1.14.100.8', OID_EXTENSION, 'getDriverStartOptionResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.9': OidInfo('2.16.840.1.113719.1.14.100.9', OID_EXTENSION, 'setDriverStartOptionRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.10': OidInfo('2.16.840.1.113719.1.14.100.10', OID_EXTENSION, 'setDriverStartOptionResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.11': OidInfo('2.16.840.1.113719.1.14.100.11', OID_EXTENSION, 'getVersionRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.12': OidInfo('2.16.840.1.113719.1.14.100.12', OID_EXTENSION, 'getVersionResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.13': OidInfo('2.16.840.1.113719.1.14.100.13', OID_EXTENSION, 'getDriverStateRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.14': OidInfo('2.16.840.1.113719.1.14.100.14', OID_EXTENSION, 'getDriverStateResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.15': OidInfo('2.16.840.1.113719.1.14.100.15', OID_EXTENSION, 'startDriverRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.16': OidInfo('2.16.840.1.113719.1.14.100.16', OID_EXTENSION, 'startDriverResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.17': OidInfo('2.16.840.1.113719.1.14.100.17', OID_EXTENSION, 'stopDriverRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.18': OidInfo('2.16.840.1.113719.1.14.100.18', OID_EXTENSION, 'stopDriverResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.19': OidInfo('2.16.840.1.113719.1.14.100.19', OID_EXTENSION, 'getDriverStatsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.20': OidInfo('2.16.840.1.113719.1.14.100.20', OID_EXTENSION, 'getDriverStatsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.21': OidInfo('2.16.840.1.113719.1.14.100.21', OID_EXTENSION, 'driverGetSchemaRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.22': OidInfo('2.16.840.1.113719.1.14.100.22', OID_EXTENSION, 'driverGetSchemaResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.23': OidInfo('2.16.840.1.113719.1.14.100.23', OID_EXTENSION, 'driverResyncRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.24': OidInfo('2.16.840.1.113719.1.14.100.24', OID_EXTENSION, 'driverResyncResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.25': OidInfo('2.16.840.1.113719.1.14.100.25', OID_EXTENSION, 'migrateAppRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.26': OidInfo('2.16.840.1.113719.1.14.100.26', OID_EXTENSION, 'migrateAppResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.27': OidInfo('2.16.840.1.113719.1.14.100.27', OID_EXTENSION, 'queueEventRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.28': OidInfo('2.16.840.1.113719.1.14.100.28', OID_EXTENSION, 'queueEventResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.29': OidInfo('2.16.840.1.113719.1.14.100.29', OID_EXTENSION, 'submitCommandRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.30': OidInfo('2.16.840.1.113719.1.14.100.30', OID_EXTENSION, 'submitCommandResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.31': OidInfo('2.16.840.1.113719.1.14.100.31', OID_EXTENSION, 'submitEventRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.32': OidInfo('2.16.840.1.113719.1.14.100.32', OID_EXTENSION, 'submitEventResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.33': OidInfo('2.16.840.1.113719.1.14.100.33', OID_EXTENSION, 'getChunkedResultRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.34': OidInfo('2.16.840.1.113719.1.14.100.34', OID_EXTENSION, 'getChunkedResultResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.35': OidInfo('2.16.840.1.113719.1.14.100.35', OID_EXTENSION, 'closeChunkedResultRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.36': OidInfo('2.16.840.1.113719.1.14.100.36', OID_EXTENSION, 'closeChunkedResultResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.37': OidInfo('2.16.840.1.113719.1.14.100.37', OID_EXTENSION, 'checkObjectPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.38': OidInfo('2.16.840.1.113719.1.14.100.38', OID_EXTENSION, 'checkObjectPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.39': OidInfo('2.16.840.1.113719.1.14.100.39', OID_EXTENSION, 'initDriverObjectRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.40': OidInfo('2.16.840.1.113719.1.14.100.40', OID_EXTENSION, 'initDriverObjectResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.41': OidInfo('2.16.840.1.113719.1.14.100.41', OID_EXTENSION, 'viewCacheEntriesRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.42': OidInfo('2.16.840.1.113719.1.14.100.42', OID_EXTENSION, 'viewCacheEntriesResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.43': OidInfo('2.16.840.1.113719.1.14.100.43', OID_EXTENSION, 'deleteCacheEntriesRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.44': OidInfo('2.16.840.1.113719.1.14.100.44', OID_EXTENSION, 'deleteCacheEntriesResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.45': OidInfo('2.16.840.1.113719.1.14.100.45', OID_EXTENSION, 'getPasswordsStateRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.46': OidInfo('2.16.840.1.113719.1.14.100.46', OID_EXTENSION, 'getPasswordsStateResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.47': OidInfo('2.16.840.1.113719.1.14.100.47', OID_EXTENSION, 'regenerateKeyRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.48': OidInfo('2.16.840.1.113719.1.14.100.48', OID_EXTENSION, 'regenerateKeyResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.49': OidInfo('2.16.840.1.113719.1.14.100.49', OID_EXTENSION, 'getServerCertRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.50': OidInfo('2.16.840.1.113719.1.14.100.50', OID_EXTENSION, 'getServerCertResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.51': OidInfo('2.16.840.1.113719.1.14.100.51', OID_EXTENSION, 'discoverJobsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.52': OidInfo('2.16.840.1.113719.1.14.100.52', OID_EXTENSION, 'discoverJobsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.53': OidInfo('2.16.840.1.113719.1.14.100.53', OID_EXTENSION, 'notifyJobUpdateRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.54': OidInfo('2.16.840.1.113719.1.14.100.54', OID_EXTENSION, 'notifyJobUpdateResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.55': OidInfo('2.16.840.1.113719.1.14.100.55', OID_EXTENSION, 'startJobRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.56': OidInfo('2.16.840.1.113719.1.14.100.56', OID_EXTENSION, 'startJobResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.57': OidInfo('2.16.840.1.113719.1.14.100.57', OID_EXTENSION, 'abortJobRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.58': OidInfo('2.16.840.1.113719.1.14.100.58', OID_EXTENSION, 'abortJobresponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.59': OidInfo('2.16.840.1.113719.1.14.100.59', OID_EXTENSION, 'getJobStateRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.60': OidInfo('2.16.840.1.113719.1.14.100.60', OID_EXTENSION, 'getJobStateResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.61': OidInfo('2.16.840.1.113719.1.14.100.61', OID_EXTENSION, 'checkJobConfigRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.62': OidInfo('2.16.840.1.113719.1.14.100.62', OID_EXTENSION, 'checkJobConfigResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.63': OidInfo('2.16.840.1.113719.1.14.100.63', OID_EXTENSION, 'setLogEventsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.64': OidInfo('2.16.840.1.113719.1.14.100.64', OID_EXTENSION, 'setLogEventsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.65': OidInfo('2.16.840.1.113719.1.14.100.65', OID_EXTENSION, 'clearLogEventsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.66': OidInfo('2.16.840.1.113719.1.14.100.66', OID_EXTENSION, 'clearLogEventsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.67': OidInfo('2.16.840.1.113719.1.14.100.67', OID_EXTENSION, 'setAppPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.68': OidInfo('2.16.840.1.113719.1.14.100.68', OID_EXTENSION, 'setAppPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.69': OidInfo('2.16.840.1.113719.1.14.100.69', OID_EXTENSION, 'clearAppPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.70': OidInfo('2.16.840.1.113719.1.14.100.70', OID_EXTENSION, 'clearAppPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.71': OidInfo('2.16.840.1.113719.1.14.100.71', OID_EXTENSION, 'setRemoteLoaderPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.72': OidInfo('2.16.840.1.113719.1.14.100.72', OID_EXTENSION, 'setRemoteLoaderPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.73': OidInfo('2.16.840.1.113719.1.14.100.73', OID_EXTENSION, 'clearRemoteLoaderPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.74': OidInfo('2.16.840.1.113719.1.14.100.74', OID_EXTENSION, 'clearRemoteLoaderPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.75': OidInfo('2.16.840.1.113719.1.14.100.75', OID_EXTENSION, 'setNamedPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.76': OidInfo('2.16.840.1.113719.1.14.100.76', OID_EXTENSION, 'setNamedPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.77': OidInfo('2.16.840.1.113719.1.14.100.77', OID_EXTENSION, 'removeNamedPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.78': OidInfo('2.16.840.1.113719.1.14.100.78', OID_EXTENSION, 'removeNamedPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.79': OidInfo('2.16.840.1.113719.1.14.100.79', OID_EXTENSION, 'removeAllNamedPasswordsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.80': OidInfo('2.16.840.1.113719.1.14.100.80', OID_EXTENSION, 'removeAllNamedPasswordsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.81': OidInfo('2.16.840.1.113719.1.14.100.81', OID_EXTENSION, 'listNamedPasswordsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.82': OidInfo('2.16.840.1.113719.1.14.100.82', OID_EXTENSION, 'listNamedPasswordsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.83': OidInfo('2.16.840.1.113719.1.14.100.83', OID_EXTENSION, 'getDefaultReciprocalAttrsMapRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.84': OidInfo('2.16.840.1.113719.1.14.100.84', OID_EXTENSION, 'getDefaultReciprocalAttrsMapResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.85': OidInfo('2.16.840.1.113719.1.14.100.85', OID_EXTENSION, 'resetDriverStatsRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.86': OidInfo('2.16.840.1.113719.1.14.100.86', OID_EXTENSION, 'resetDriverStatsResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.87': OidInfo('2.16.840.1.113719.1.14.100.87', OID_EXTENSION, 'regenerateAllKeysRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.88': OidInfo('2.16.840.1.113719.1.14.100.88', OID_EXTENSION, 'regenerateAllKeysResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.89': OidInfo('2.16.840.1.113719.1.14.100.89', OID_EXTENSION, 'getDriverGCVRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.90': OidInfo('2.16.840.1.113719.1.14.100.90', OID_EXTENSION, 'getDriverGCVResponse', 'NOVELL'), '2.16.840.1.113719.1.14.100.91': OidInfo('2.16.840.1.113719.1.14.100.91', OID_EXTENSION, 'getNamedPasswordRequest', 'NOVELL'), '2.16.840.1.113719.1.14.100.92': OidInfo('2.16.840.1.113719.1.14.100.92', OID_EXTENSION, 'getNamedPasswordResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.1': OidInfo('2.16.840.1.113719.1.27.100.1', OID_EXTENSION, 'ndsToLdapResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.2': OidInfo('2.16.840.1.113719.1.27.100.2', OID_EXTENSION, 'ndsToLdapRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.3': OidInfo('2.16.840.1.113719.1.27.100.3', OID_EXTENSION, 'splitPartitionRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.4': OidInfo('2.16.840.1.113719.1.27.100.4', OID_EXTENSION, 'splitPartitionResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.5': OidInfo('2.16.840.1.113719.1.27.100.5', OID_EXTENSION, 'mergePartitionRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.6': OidInfo('2.16.840.1.113719.1.27.100.6', OID_EXTENSION, 'mergePartitionResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.7': OidInfo('2.16.840.1.113719.1.27.100.7', OID_EXTENSION, 'addReplicaRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.8': OidInfo('2.16.840.1.113719.1.27.100.8', OID_EXTENSION, 'addReplicaResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.9': OidInfo('2.16.840.1.113719.1.27.100.9', OID_EXTENSION, 'refreshLDAPServerRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.10': OidInfo('2.16.840.1.113719.1.27.100.10', OID_EXTENSION, 'refreshLDAPServerResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.11': OidInfo('2.16.840.1.113719.1.27.100.11', OID_EXTENSION, 'removeReplicaRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.12': OidInfo('2.16.840.1.113719.1.27.100.12', OID_EXTENSION, 'removeReplicaResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.13': OidInfo('2.16.840.1.113719.1.27.100.13', OID_EXTENSION, 'partitionEntryCountRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.14': OidInfo('2.16.840.1.113719.1.27.100.14', OID_EXTENSION, 'partitionEntryCountResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.15': OidInfo('2.16.840.1.113719.1.27.100.15', OID_EXTENSION, 'changeReplicaTypeRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.16': OidInfo('2.16.840.1.113719.1.27.100.16', OID_EXTENSION, 'changeReplicaTypeResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.17': OidInfo('2.16.840.1.113719.1.27.100.17', OID_EXTENSION, 'getReplicaInfoRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.18': OidInfo('2.16.840.1.113719.1.27.100.18', OID_EXTENSION, 'getReplicaInfoResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.19': OidInfo('2.16.840.1.113719.1.27.100.19', OID_EXTENSION, 'listReplicaRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.20': OidInfo('2.16.840.1.113719.1.27.100.20', OID_EXTENSION, 'listReplicaResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.21': OidInfo('2.16.840.1.113719.1.27.100.21', OID_EXTENSION, 'receiveAllUpdatesRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.22': OidInfo('2.16.840.1.113719.1.27.100.22', OID_EXTENSION, 'receiveAllUpdatesResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.23': OidInfo('2.16.840.1.113719.1.27.100.23', OID_EXTENSION, 'sendAllUpdatesRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.24': OidInfo('2.16.840.1.113719.1.27.100.24', OID_EXTENSION, 'sendAllUpdatesResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.25': OidInfo('2.16.840.1.113719.1.27.100.25', OID_EXTENSION, 'requestPartitionSyncRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.26': OidInfo('2.16.840.1.113719.1.27.100.26', OID_EXTENSION, 'requestPartitionSyncResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.27': OidInfo('2.16.840.1.113719.1.27.100.27', OID_EXTENSION, 'requestSchemaSyncRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.28': OidInfo('2.16.840.1.113719.1.27.100.28', OID_EXTENSION, 'requestSchemaSyncResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.29': OidInfo('2.16.840.1.113719.1.27.100.29', OID_EXTENSION, 'abortPartitionOperationRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.30': OidInfo('2.16.840.1.113719.1.27.100.30', OID_EXTENSION, 'abortPartitionOperationResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.31': OidInfo('2.16.840.1.113719.1.27.100.31', OID_EXTENSION, 'getBindDNRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.32': OidInfo('2.16.840.1.113719.1.27.100.32', OID_EXTENSION, 'getBindDNResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.33': OidInfo('2.16.840.1.113719.1.27.100.33', OID_EXTENSION, 'getEffectivePrivilegesRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.34': OidInfo('2.16.840.1.113719.1.27.100.34', OID_EXTENSION, 'getEffectivePrivilegesResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.35': OidInfo('2.16.840.1.113719.1.27.100.35', OID_EXTENSION, 'setReplicationFilterRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.36': OidInfo('2.16.840.1.113719.1.27.100.36', OID_EXTENSION, 'setReplicationFilterResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.37': OidInfo('2.16.840.1.113719.1.27.100.37', OID_EXTENSION, 'getReplicationFilterRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.38': OidInfo('2.16.840.1.113719.1.27.100.38', OID_EXTENSION, 'getReplicationFilterResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.39': OidInfo('2.16.840.1.113719.1.27.100.39', OID_EXTENSION, 'splitOrphanPartitionRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.40': OidInfo('2.16.840.1.113719.1.27.100.40', OID_EXTENSION, 'splitOrphanPartitionResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.41': OidInfo('2.16.840.1.113719.1.27.100.41', OID_EXTENSION, 'removeOrphanPartitionRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.42': OidInfo('2.16.840.1.113719.1.27.100.42', OID_EXTENSION, 'removeOrphanPartitionResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.43': OidInfo('2.16.840.1.113719.1.27.100.43', OID_EXTENSION, 'triggerBKLinkerRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.44': OidInfo('2.16.840.1.113719.1.27.100.44', OID_EXTENSION, 'triggerBKLinkerResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.45': OidInfo('2.16.840.1.113719.1.27.100.45', OID_EXTENSION, 'triggerDRLProcessRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.46': OidInfo('2.16.840.1.113719.1.27.100.46', OID_EXTENSION, 'triggerDRLProcessResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.47': OidInfo('2.16.840.1.113719.1.27.100.47', OID_EXTENSION, 'triggerJanitorRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.48': OidInfo('2.16.840.1.113719.1.27.100.48', OID_EXTENSION, 'triggerJanitorResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.49': OidInfo('2.16.840.1.113719.1.27.100.49', OID_EXTENSION, 'triggerLimberRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.50': OidInfo('2.16.840.1.113719.1.27.100.50', OID_EXTENSION, 'triggerLimberResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.51': OidInfo('2.16.840.1.113719.1.27.100.51', OID_EXTENSION, 'triggerSkulkerRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.52': OidInfo('2.16.840.1.113719.1.27.100.52', OID_EXTENSION, 'triggerSkulkerResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.53': OidInfo('2.16.840.1.113719.1.27.100.53', OID_EXTENSION, 'triggerSchemaSyncRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.54': OidInfo('2.16.840.1.113719.1.27.100.54', OID_EXTENSION, 'triggerSchemaSyncResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.55': OidInfo('2.16.840.1.113719.1.27.100.55', OID_EXTENSION, 'triggerPartitionPurgeRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.56': OidInfo('2.16.840.1.113719.1.27.100.56', OID_EXTENSION, 'triggerPartitionPurgeResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.79': OidInfo('2.16.840.1.113719.1.27.100.79', OID_EXTENSION, 'eventMonitorRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.80': OidInfo('2.16.840.1.113719.1.27.100.80', OID_EXTENSION, 'eventMonitorResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.81': OidInfo('2.16.840.1.113719.1.27.100.81', OID_EXTENSION, 'nldapEventNotification', 'NOVELL'), '2.16.840.1.113719.1.27.100.84': OidInfo('2.16.840.1.113719.1.27.100.84', OID_EXTENSION, 'filteredEventMonitorRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.85': OidInfo('2.16.840.1.113719.1.27.100.85', OID_EXTENSION, 'filteredEventMonitorResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.96': OidInfo('2.16.840.1.113719.1.27.100.96', OID_EXTENSION, 'ldapBackupRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.97': OidInfo('2.16.840.1.113719.1.27.100.97', OID_EXTENSION, 'ldapBackupResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.98': OidInfo('2.16.840.1.113719.1.27.100.98', OID_EXTENSION, 'ldapRestoreRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.99': OidInfo('2.16.840.1.113719.1.27.100.99', OID_EXTENSION, 'ldapRestoreResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.101': OidInfo('2.16.840.1.113719.1.27.100.101', OID_EXTENSION, 'LDAPDNStoX500DNRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.102': OidInfo('2.16.840.1.113719.1.27.100.102', OID_EXTENSION, 'LDAPDNStoX500DNResponse', 'NOVELL'), '2.16.840.1.113719.1.27.100.103': OidInfo('2.16.840.1.113719.1.27.100.103', OID_EXTENSION, 'getPrivilegesListRequest', 'NOVELL'), '2.16.840.1.113719.1.27.100.104': OidInfo('2.16.840.1.113719.1.27.100.104', OID_EXTENSION, 'getPrivilegesListResponse', 'NOVELL'), '2.16.840.1.113719.1.27.103.1': OidInfo('2.16.840.1.113719.1.27.103.1', OID_EXTENSION, 'createGroupingRequest', 'NOVELL'), '2.16.840.1.113719.1.27.103.2': OidInfo('2.16.840.1.113719.1.27.103.2', OID_EXTENSION, 'endGroupingRequest', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.1': OidInfo('2.16.840.1.113719.1.39.42.100.1', OID_EXTENSION, 'NMAS Put Login Configuration', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.3': OidInfo('2.16.840.1.113719.1.39.42.100.3', OID_EXTENSION, 'NMAS Get Login Configuration', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.5': OidInfo('2.16.840.1.113719.1.39.42.100.5', OID_EXTENSION, 'NMAS Delete Login Configuration', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.7': OidInfo('2.16.840.1.113719.1.49.42.100.7', OID_EXTENSION, 'NMAS Put Login Secret', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.9': OidInfo('2.16.840.1.113719.1.39.42.100.9', OID_EXTENSION, 'NMAS Delete Login Secret', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.11': OidInfo('2.16.840.1.113719.1.39.42.100.11', OID_EXTENSION, 'NMAS Set Universal Password', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.13': OidInfo('2.16.840.1.113719.1.39.42.100.13', OID_EXTENSION, 'NMAS Get Universal Password', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.15': OidInfo('2.16.840.1.113719.1.39.42.100.15', OID_EXTENSION, 'NMAS Delete Universal Password', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.17': OidInfo('2.16.840.1.113719.1.39.42.100.17', OID_EXTENSION, 'NMAS Check password against password policy', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.19': OidInfo('2.16.840.1.113719.1.39.42.100.19', OID_EXTENSION, 'NMAS Get password policy information', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.21': OidInfo('2.16.840.1.113719.1.39.42.100.21', OID_EXTENSION, 'NMAS Change Universal Password', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.23': OidInfo('2.16.840.1.113719.1.39.42.100.23', OID_EXTENSION, 'NMAS Graded Authentication management', 'NOVELL'), '2.16.840.1.113719.1.39.42.100.25': OidInfo('2.16.840.1.113719.1.39.42.100.25', OID_EXTENSION, 'NMAS management (new with NMAS 3.1.0)', 'NOVELL'), '2.16.840.1.113719.1.142.1.4.1': OidInfo('2.16.840.1.113719.1.142.1.4.1', OID_EXTENSION, 'LBURPIncUpdate', 'NOVELL'), '2.16.840.1.113719.1.142.1.4.2': OidInfo('2.16.840.1.113719.1.142.1.4.2', OID_EXTENSION, 'LBURPFullUpdate', 'NOVELL'), '2.16.840.1.113719.1.142.100.1': OidInfo('2.16.840.1.113719.1.142.100.1', OID_EXTENSION, 'LBURPStartReplRequest', 'NOVELL'), '2.16.840.1.113719.1.142.100.2': OidInfo('2.16.840.1.113719.1.142.100.2', OID_EXTENSION, 'LBURPStartReplResponse', 'NOVELL'), '2.16.840.1.113719.1.142.100.4': OidInfo('2.16.840.1.113719.1.142.100.4', OID_EXTENSION, 'LBURPEndReplRequest', 'NOVELL'), '2.16.840.1.113719.1.142.100.5': OidInfo('2.16.840.1.113719.1.142.100.5', OID_EXTENSION, 'LBURPEndReplResponse', 'NOVELL'), '2.16.840.1.113719.1.142.100.6': OidInfo('2.16.840.1.113719.1.142.100.6', OID_EXTENSION, 'LBURPOperationRequest', 'NOVELL'), '2.16.840.1.113719.1.142.100.7': OidInfo('2.16.840.1.113719.1.142.100.7', OID_EXTENSION, 'LBURPOperationResponse', 'NOVELL'), '2.16.840.1.113719.1.148.100.1': OidInfo('2.16.840.1.113719.1.148.100.1', OID_EXTENSION, 'SSLDAP_GET_SERVICE_INFO_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.2': OidInfo('2.16.840.1.113719.1.148.100.2', OID_EXTENSION, 'SSLDAP_GET_SERVICE_INFO_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.3': OidInfo('2.16.840.1.113719.1.148.100.3', OID_EXTENSION, 'SSLDAP_READ_SECRET_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.4': OidInfo('2.16.840.1.113719.1.148.100.4', OID_EXTENSION, 'SSLDAP_READ_SECRET_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.5': OidInfo('2.16.840.1.113719.1.148.100.5', OID_EXTENSION, 'SSLDAP_WRITE_SECRET_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.6': OidInfo('2.16.840.1.113719.1.148.100.6', OID_EXTENSION, 'SSLDAP_WRITE_SECRET_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.7': OidInfo('2.16.840.1.113719.1.148.100.7', OID_EXTENSION, 'SSLDAP_ADD_SECRET_ID_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.8': OidInfo('2.16.840.1.113719.1.148.100.8', OID_EXTENSION, 'SSLDAP_ADD_SECRET_ID_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.9': OidInfo('2.16.840.1.113719.1.148.100.9', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.10': OidInfo('2.16.840.1.113719.1.148.100.10', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.11': OidInfo('2.16.840.1.113719.1.148.100.11', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_STORE_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.12': OidInfo('2.16.840.1.113719.1.148.100.12', OID_EXTENSION, 'SSLDAP_REMOVE_SECRET_STORE_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.13': OidInfo('2.16.840.1.113719.1.148.100.13', OID_EXTENSION, 'SSLDAP_ENUMERATE_SECRET_IDS_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.14': OidInfo('2.16.840.1.113719.1.148.100.14', OID_EXTENSION, 'SSLDAP_ENUMERATE_SECRET_IDS_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.15': OidInfo('2.16.840.1.113719.1.148.100.15', OID_EXTENSION, 'SSLDAP_UNLOCK_SECRETS_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.16': OidInfo('2.16.840.1.113719.1.148.100.16', OID_EXTENSION, 'SSLDAP_UNLOCK_SECRETS_REPLY', 'NOVELL'), '2.16.840.1.113719.1.148.100.17': OidInfo('2.16.840.1.113719.1.148.100.17', OID_EXTENSION, 'SSLDAP_SET_EP_MASTER_PASSWORD_REQUEST', 'NOVELL'), '2.16.840.1.113719.1.148.100.18': OidInfo('2.16.840.1.113719.1.148.100.18', OID_EXTENSION, 'SSLDAP_SET_EP_MASTER_PASSWORD_REPLY', 'NOVELL'), # features (capabilities) '1.2.840.113556.1.4.800': OidInfo('1.2.840.113556.1.4.800', OID_FEATURE, 'Active directory', 'MICROSOFT'), '1.2.840.113556.1.4.1670': OidInfo('1.2.840.113556.1.4.1670', OID_FEATURE, 'Active directory V51', 'MICROSOFT'), '1.2.840.113556.1.4.1791': OidInfo('1.2.840.113556.1.4.1791', OID_FEATURE, 'Active directory LDAP Integration', 'MICROSOFT'), '1.2.840.113556.1.4.1880': OidInfo('1.2.840.113556.1.4.1880', OID_FEATURE, 'Active directory ADAM digest', 'MICROSOFT'), '1.2.840.113556.1.4.1851': OidInfo('1.2.840.113556.1.4.1851', OID_FEATURE, 'Active directory ADAM', 'MICROSOFT'), '1.2.840.113556.1.4.1920': OidInfo('1.2.840.113556.1.4.1920', OID_FEATURE, 'Active directory partial secrets', 'MICROSOFT'), '1.2.840.113556.1.4.1935': OidInfo('1.2.840.113556.1.4.1935', OID_FEATURE, 'Active directory V60', 'MICROSOFT'), '1.2.840.113556.1.4.2080': OidInfo('1.2.840.113556.1.4.2080', OID_FEATURE, 'Active directory V61 R2', 'MICROSOFT'), '1.2.840.113556.1.4.2237': OidInfo('1.2.840.113556.1.4.2237', OID_FEATURE, 'Active directory W8', 'MICROSOFT'), '1.3.6.1.1.14': OidInfo('1.3.6.1.1.14', OID_FEATURE, 'Modify-Increment', 'RFC4525'), '1.3.6.1.1.17.7': OidInfo('1.3.6.1.1.17.7', OID_FEATURE, 'LBURP Incremental Update style OID', 'RFC4373'), '1.3.6.1.4.1.4203.1.5.1': OidInfo('1.3.6.1.4.1.4203.1.5.1', OID_FEATURE, 'All Op Attrs', 'RFC3673'), '1.3.6.1.4.1.4203.1.5.2': OidInfo('1.3.6.1.4.1.4203.1.5.2', OID_FEATURE, 'OC AD Lists', 'RFC4529'), '1.3.6.1.4.1.4203.1.5.3': OidInfo('1.3.6.1.4.1.4203.1.5.3', OID_FEATURE, 'True/False filters', 'RFC4526'), '1.3.6.1.4.1.4203.1.5.4': OidInfo('1.3.6.1.4.1.4203.1.5.4', OID_FEATURE, 'Language Tag Options', 'RFC3866'), '1.3.6.1.4.1.4203.1.5.5': OidInfo('1.3.6.1.4.1.4203.1.5.5', OID_FEATURE, 'language Range Options', 'RFC3866'), '2.16.840.1.113719.1.27.99.1': OidInfo('2.16.840.1.113719.1.27.99.1', OID_FEATURE, 'Superior References', 'NOVELL'), # ldap syntaxes '1.3.6.1.1.16.1': OidInfo('1.3.6.1.1.16.1', OID_LDAP_SYNTAX, 'UUID', 'RFC4530'), '1.3.6.1.4.1.1466.115.121.1.3': OidInfo('1.3.6.1.4.1.1466.115.121.1.3', OID_LDAP_SYNTAX, 'Attribute Type Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.6': OidInfo('1.3.6.1.4.1.1466.115.121.1.6', OID_LDAP_SYNTAX, 'Bit String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.7': OidInfo('1.3.6.1.4.1.1466.115.121.1.7', OID_LDAP_SYNTAX, 'Boolean', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.11': OidInfo('1.3.6.1.4.1.1466.115.121.1.11', OID_LDAP_SYNTAX, 'Country String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.12': OidInfo('1.3.6.1.4.1.1466.115.121.1.12', OID_LDAP_SYNTAX, 'DN', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.14': OidInfo('1.3.6.1.4.1.1466.115.121.1.14', OID_LDAP_SYNTAX, 'Delivery Method', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.15': OidInfo('1.3.6.1.4.1.1466.115.121.1.15', OID_LDAP_SYNTAX, 'Directory String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.16': OidInfo('1.3.6.1.4.1.1466.115.121.1.16', OID_LDAP_SYNTAX, 'DIT Content Rule Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.17': OidInfo('1.3.6.1.4.1.1466.115.121.1.17', OID_LDAP_SYNTAX, 'DIT Structure Rule Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.21': OidInfo('1.3.6.1.4.1.1466.115.121.1.21', OID_LDAP_SYNTAX, 'Enhanced Guide', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.22': OidInfo('1.3.6.1.4.1.1466.115.121.1.22', OID_LDAP_SYNTAX, 'Facsimile Telephone Number', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.23': OidInfo('1.3.6.1.4.1.1466.115.121.1.23', OID_LDAP_SYNTAX, 'Fax', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.24': OidInfo('1.3.6.1.4.1.1466.115.121.1.24', OID_LDAP_SYNTAX, 'Generalized Time', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.25': OidInfo('1.3.6.1.4.1.1466.115.121.1.25', OID_LDAP_SYNTAX, 'Guide', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.26': OidInfo('1.3.6.1.4.1.1466.115.121.1.26', OID_LDAP_SYNTAX, 'IA5 String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.27': OidInfo('1.3.6.1.4.1.1466.115.121.1.27', OID_LDAP_SYNTAX, 'Integer', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.28': OidInfo('1.3.6.1.4.1.1466.115.121.1.28', OID_LDAP_SYNTAX, 'JPEG', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.30': OidInfo('1.3.6.1.4.1.1466.115.121.1.30', OID_LDAP_SYNTAX, 'Matching Rule Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.31': OidInfo('1.3.6.1.4.1.1466.115.121.1.31', OID_LDAP_SYNTAX, 'Matching Rule Use Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.34': OidInfo('1.3.6.1.4.1.1466.115.121.1.34', OID_LDAP_SYNTAX, 'Name And Optional UID', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.35': OidInfo('1.3.6.1.4.1.1466.115.121.1.35', OID_LDAP_SYNTAX, 'Name Form Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.36': OidInfo('1.3.6.1.4.1.1466.115.121.1.36', OID_LDAP_SYNTAX, 'Numeric String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.37': OidInfo('1.3.6.1.4.1.1466.115.121.1.37', OID_LDAP_SYNTAX, 'Object Class Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.38': OidInfo('1.3.6.1.4.1.1466.115.121.1.38', OID_LDAP_SYNTAX, 'OID', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.39': OidInfo('1.3.6.1.4.1.1466.115.121.1.39', OID_LDAP_SYNTAX, 'Other Mailbox', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.40': OidInfo('1.3.6.1.4.1.1466.115.121.1.40', OID_LDAP_SYNTAX, 'Octet String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.41': OidInfo('1.3.6.1.4.1.1466.115.121.1.41', OID_LDAP_SYNTAX, 'Postal Address', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.44': OidInfo('1.3.6.1.4.1.1466.115.121.1.44', OID_LDAP_SYNTAX, 'Printable String', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.50': OidInfo('1.3.6.1.4.1.1466.115.121.1.50', OID_LDAP_SYNTAX, 'Telephone Number', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.51': OidInfo('1.3.6.1.4.1.1466.115.121.1.52', OID_LDAP_SYNTAX, 'Teletex Terminal Identifier', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.52': OidInfo('1.3.6.1.4.1.1466.115.121.1.52', OID_LDAP_SYNTAX, 'Telex Number', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.53': OidInfo('1.3.6.1.4.1.1466.115.121.1.53', OID_LDAP_SYNTAX, 'UTC Time', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.54': OidInfo('1.3.6.1.4.1.1466.115.121.1.54', OID_LDAP_SYNTAX, 'LDAP Syntax Description', 'RFC4517'), '1.3.6.1.4.1.1466.115.121.1.58': OidInfo('1.3.6.1.4.1.1466.115.121.1.58', OID_LDAP_SYNTAX, 'Substring Assertion', 'RFC4517'), # ldap url extensions # matching rules '1.2.36.79672281.1.13.2': OidInfo('1.2.36.79672281.1.13.2', OID_MATCHING_RULE, 'componentFilterMatch', 'RFC3687'), '1.2.36.79672281.1.13.3': OidInfo('1.2.36.79672281.1.13.3', OID_MATCHING_RULE, 'rdnMatch', 'RFC3687'), '1.2.36.79672281.1.13.5': OidInfo('1.2.36.79672281.1.13.5', OID_MATCHING_RULE, 'presentMatch', 'RFC3687'), '1.2.36.79672281.1.13.6': OidInfo('1.2.36.79672281.1.13.6', OID_MATCHING_RULE, 'allComponentsMatch', 'RFC3687'), '1.2.36.79672281.1.13.7': OidInfo('1.2.36.79672281.1.13.7', OID_MATCHING_RULE, 'directoryComponentsMatch', 'RFC3687'), '1.2.840.113556.1.4.803': OidInfo('1.2.840.113556.1.4.803', OID_MATCHING_RULE, 'Bit AND', 'MICROSOFT'), '1.2.840.113556.1.4.804': OidInfo('1.2.840.113556.1.4.804', OID_MATCHING_RULE, 'Bit OR', 'MICROSOFT'), '1.2.840.113556.1.4.1941': OidInfo('1.2.840.113556.1.4.1941', OID_MATCHING_RULE, 'Transitive Evaluation', 'MICROSOFT'), '1.2.840.113556.1.4.2253': OidInfo('1.2.840.113556.1.4.2253', OID_MATCHING_RULE, 'DN with data', 'MICROSOFT'), '1.3.6.1.1.16.2': OidInfo('1.3.6.1.1.16.2', OID_MATCHING_RULE, 'uuidMatch', 'RFC4530'), '1.3.6.1.1.16.3': OidInfo('1.3.6.1.1.16.3', OID_MATCHING_RULE, 'uuidOrderingMatch', 'RFC4530'), '1.3.6.1.4.1.1466.109.114.1': OidInfo('1.3.6.1.4.1.1466.109.114.1', OID_MATCHING_RULE, 'caseExactIA5Match', 'RFC4517'), '1.3.6.1.4.1.1466.109.114.2': OidInfo('1.3.6.1.4.1.1466.109.114.2', OID_MATCHING_RULE, 'caseIgnoreIA5Match', 'RFC4517'), '1.3.6.1.4.1.1466.109.114.3': OidInfo('1.3.6.1.4.1.1466.109.114.3', OID_MATCHING_RULE, 'caseIgnoreIA5SubstringsMatch', 'RFC4517'), '2.5.13.0': OidInfo('2.5.13.0', OID_MATCHING_RULE, 'objectIdentifierMatch', 'RFC4517'), '2.5.13.1': OidInfo('2.5.13.1', OID_MATCHING_RULE, 'distinguishedNameMatch', 'RFC4517'), '2.5.13.2': OidInfo('2.5.13.2', OID_MATCHING_RULE, 'caseIgnoreMatch', 'RFC4517'), '2.5.13.3': OidInfo('2.5.13.3', OID_MATCHING_RULE, 'caseIgnoreOrderingMatch', 'RFC4517'), '2.5.13.4': OidInfo('2.5.13.4', OID_MATCHING_RULE, 'caseIgnoreSubstringsMatch', 'RFC4517'), '2.5.13.5': OidInfo('2.5.13.5', OID_MATCHING_RULE, 'caseExactMatch', 'RFC4517'), '2.5.13.6': OidInfo('2.5.13.6', OID_MATCHING_RULE, 'caseExactOrderingMatch', 'RFC4517'), '2.5.13.7': OidInfo('2.5.13.7', OID_MATCHING_RULE, 'caseExactSubstringsMatch', 'RFC4517'), '2.5.13.8': OidInfo('2.5.13.8', OID_MATCHING_RULE, 'numericStringMatch', 'RFC4517'), '2.5.13.9': OidInfo('2.5.13.9', OID_MATCHING_RULE, 'numericStringOrderingMatch', 'RFC4517'), '2.5.13.10': OidInfo('2.5.13.10', OID_MATCHING_RULE, 'numericStringSubstringsMatch', 'RFC4517'), '2.5.13.11': OidInfo('2.5.13.11', OID_MATCHING_RULE, 'caseIgnoreListMatch', 'RFC4517'), '2.5.13.12': OidInfo('2.5.13.12', OID_MATCHING_RULE, 'caseIgnoreListSubstringsMatch', 'RFC4517'), '2.5.13.13': OidInfo('2.5.13.13', OID_MATCHING_RULE, 'booleanMatch', 'RFC4517'), '2.5.13.14': OidInfo('2.5.13.14', OID_MATCHING_RULE, 'integerMatch', 'RFC4517'), '2.5.13.15': OidInfo('2.5.13.15', OID_MATCHING_RULE, 'integerOrderingMatch', 'RFC4517'), '2.5.13.16': OidInfo('2.5.13.16', OID_MATCHING_RULE, 'bitStringMatch', 'RFC4517'), '2.5.13.17': OidInfo('2.5.13.17', OID_MATCHING_RULE, 'octetStringMatch', 'RFC4517'), '2.5.13.18': OidInfo('2.5.13.18', OID_MATCHING_RULE, 'octetStringOrderingMatch', 'RFC4517'), '2.5.13.20': OidInfo('2.5.13.20', OID_MATCHING_RULE, 'telephoneNumberMatch', 'RFC4517'), '2.5.13.21': OidInfo('2.5.13.21', OID_MATCHING_RULE, 'telephoneNumberSubstringsMatch', 'RFC4517'), '2.5.13.22': OidInfo('2.5.13.22', OID_MATCHING_RULE, 'presentationAddressMatch', 'RFC2252'), '2.5.13.23': OidInfo('2.5.13.23', OID_MATCHING_RULE, 'uniqueMemberMatch', 'RFC4517'), '2.5.13.24': OidInfo('2.5.13.24', OID_MATCHING_RULE, 'protocolInformationMatch', 'RFC2252'), '2.5.13.27': OidInfo('2.5.13.27', OID_MATCHING_RULE, 'generalizedTimeMatch', 'RFC4517'), '2.5.13.28': OidInfo('2.5.13.28', OID_MATCHING_RULE, 'generalizedTimeOrderingMatch', 'RFC4517'), '2.5.13.29': OidInfo('2.5.13.29', OID_MATCHING_RULE, 'integerFirstComponentMatch', 'RFC4517'), '2.5.13.30': OidInfo('2.5.13.30', OID_MATCHING_RULE, 'objectIdentifierFirstComponentMatch', 'RFC4517'), '2.5.13.31': OidInfo('2.5.13.31', OID_MATCHING_RULE, 'directoryStringFirstComponentMatch', 'RFC4517'), '2.5.13.32': OidInfo('2.5.13.32', OID_MATCHING_RULE, 'wordMatch', 'RFC4517'), '2.5.13.33': OidInfo('2.5.13.33', OID_MATCHING_RULE, 'keywordMatch', 'RFC4517'), '2.5.13.34': OidInfo('2.5.13.34', OID_MATCHING_RULE, 'certificateExactMatch', 'RFC4523'), '2.5.13.35': OidInfo('2.5.13.35', OID_MATCHING_RULE, 'certificateMatch', 'RFC4523'), '2.5.13.36': OidInfo('2.5.13.36', OID_MATCHING_RULE, 'certificatePairExactMatch', 'RFC4523'), '2.5.13.37': OidInfo('2.5.13.37', OID_MATCHING_RULE, 'certificatePairMatch', 'RFC4523'), '2.5.13.38': OidInfo('2.5.13.38', OID_MATCHING_RULE, 'certificateListExactMatch', 'RFC4523'), '2.5.13.39': OidInfo('2.5.13.39', OID_MATCHING_RULE, 'certificateListMatch', 'RFC4523'), '2.5.13.40': OidInfo('2.5.13.40', OID_MATCHING_RULE, 'algorithmIdentifierMatch', 'RFC4523'), '2.5.13.41': OidInfo('2.5.13.41', OID_MATCHING_RULE, 'storedPrefixMatch', 'RFC3698'), # name forms '1.3.6.1.1.10.15.1': OidInfo('1.3.6.1.1.10.15.1', OID_NAME_FORM, 'uddiBusinessEntityNameForm', 'RFC4403'), '1.3.6.1.1.10.15.2': OidInfo('1.3.6.1.1.10.15.2', OID_NAME_FORM, 'uddiContactNameForm', 'RFC4403'), '1.3.6.1.1.10.15.3': OidInfo('1.3.6.1.1.10.15.3', OID_NAME_FORM, 'uddiAddressNameForm', 'RFC4403'), '1.3.6.1.1.10.15.4': OidInfo('1.3.6.1.1.10.15.4', OID_NAME_FORM, 'uddiBusinessServiceNameForm', 'RFC4403'), '1.3.6.1.1.10.15.5': OidInfo('1.3.6.1.1.10.15.5', OID_NAME_FORM, 'uddiBindingTemplateNameForm', 'RFC4403'), '1.3.6.1.1.10.15.6': OidInfo('1.3.6.1.1.10.15.6', OID_NAME_FORM, 'uddiTModelInstanceInfoNameForm', 'RFC4403'), '1.3.6.1.1.10.15.7': OidInfo('1.3.6.1.1.10.15.7', OID_NAME_FORM, 'uddiTModelNameForm', 'RFC4403'), '1.3.6.1.1.10.15.8': OidInfo('1.3.6.1.1.10.15.8', OID_NAME_FORM, 'uddiPublisherAssertionNameForm', 'RFC4403'), '1.3.6.1.1.10.15.9': OidInfo('1.3.6.1.1.10.15.9', OID_NAME_FORM, 'uddiv3SubscriptionNameForm', 'RFC4403'), '1.3.6.1.1.10.15.10': OidInfo('1.3.6.1.1.10.15.10', OID_NAME_FORM, 'uddiv3EntityObituaryNameForm', 'RFC4403'), '1.3.6.1.4.1.1466.345': OidInfo('1.3.6.1.4.1.1466.345', OID_NAME_FORM, 'domainNameForm', 'RFC2247'), # object classes '0.9.2342.19200300.100.4.3': OidInfo('0.9.2342.19200300.100.4.3', OID_OBJECT_CLASS, 'pilotObject', 'RFC1274'), '0.9.2342.19200300.100.4.4': OidInfo('0.9.2342.19200300.100.4.4', OID_OBJECT_CLASS, 'pilotPerson', 'RFC1274'), '0.9.2342.19200300.100.4.5': OidInfo('0.9.2342.19200300.100.4.5', OID_OBJECT_CLASS, 'account', 'RFC4524'), '0.9.2342.19200300.100.4.6': OidInfo('0.9.2342.19200300.100.4.6', OID_OBJECT_CLASS, 'document', 'RFC4524'), '0.9.2342.19200300.100.4.7': OidInfo('0.9.2342.19200300.100.4.7', OID_OBJECT_CLASS, 'room', 'RFC4524'), '0.9.2342.19200300.100.4.8': OidInfo('0.9.2342.19200300.100.4.8', OID_OBJECT_CLASS, 'documentSeries', 'RFC4524'), '0.9.2342.19200300.100.4.13': OidInfo('0.9.2342.19200300.100.4.13', OID_OBJECT_CLASS, 'domain', 'RFC4524'), '0.9.2342.19200300.100.4.14': OidInfo('0.9.2342.19200300.100.4.14', OID_OBJECT_CLASS, 'RFC822LocalPart', 'RFC4524'), '0.9.2342.19200300.100.4.15': OidInfo('0.9.2342.19200300.100.4.15', OID_OBJECT_CLASS, 'dNSDomain', 'RFC1274'), '0.9.2342.19200300.100.4.17': OidInfo('0.9.2342.19200300.100.4.17', OID_OBJECT_CLASS, 'domainRelatedObject', 'RFC4524'), '0.9.2342.19200300.100.4.18': OidInfo('0.9.2342.19200300.100.4.18', OID_OBJECT_CLASS, 'friendlyCountry', 'RFC4524'), '0.9.2342.19200300.100.4.19': OidInfo('0.9.2342.19200300.100.4.19', OID_OBJECT_CLASS, 'simpleSecurityObject', 'RFC4524'), '0.9.2342.19200300.100.4.20': OidInfo('0.9.2342.19200300.100.4.20', OID_OBJECT_CLASS, 'pilotOrganization', 'RFC1274'), '0.9.2342.19200300.100.4.21': OidInfo('0.9.2342.19200300.100.4.21', OID_OBJECT_CLASS, 'pilotDSA', 'RFC1274'), '0.9.2342.19200300.100.4.22': OidInfo('0.9.2342.19200300.100.4.22', OID_OBJECT_CLASS, 'qualityLabelledData', 'RFC1274'), '1.2.840.113556.1.5.87': OidInfo('1.2.840.113556.1.5.87', OID_OBJECT_CLASS, 'calEntry', 'RFC2739'), '1.3.18.0.2.6.253': OidInfo('1.3.18.0.2.6.253', OID_OBJECT_CLASS, 'printerLPR', 'RFC3712'), '1.3.18.0.2.6.254': OidInfo('1.3.18.0.2.6.254', OID_OBJECT_CLASS, 'slpServicePrinter', 'RFC3712'), '1.3.18.0.2.6.255': OidInfo('1.3.18.0.2.6.255', OID_OBJECT_CLASS, 'printerService', 'RFC3712'), '1.3.18.0.2.6.256': OidInfo('1.3.18.0.2.6.256', OID_OBJECT_CLASS, 'printerIPP', 'RFC3712'), '1.3.18.0.2.6.257': OidInfo('1.3.18.0.2.6.257', OID_OBJECT_CLASS, 'printerServiceAuxClass', 'RFC3712'), '1.3.18.0.2.6.258': OidInfo('1.3.18.0.2.6.258', OID_OBJECT_CLASS, 'printerAbstract', 'RFC3712'), '1.3.6.1.1.10.6.1': OidInfo('1.3.6.1.1.10.6.1', OID_OBJECT_CLASS, 'uddiBusinessEntity', 'RFC4403'), '1.3.6.1.1.10.6.2': OidInfo('1.3.6.1.1.10.6.2', OID_OBJECT_CLASS, 'uddiContact', 'RFC4403'), '1.3.6.1.1.10.6.3': OidInfo('1.3.6.1.1.10.6.3', OID_OBJECT_CLASS, 'uddiAddress', 'RFC4403'), '1.3.6.1.1.10.6.4': OidInfo('1.3.6.1.1.10.6.4', OID_OBJECT_CLASS, 'uddiBusinessService', 'RFC4403'), '1.3.6.1.1.10.6.5': OidInfo('1.3.6.1.1.10.6.5', OID_OBJECT_CLASS, 'uddiBindingTemplate', 'RFC4403'), '1.3.6.1.1.10.6.6': OidInfo('1.3.6.1.1.10.6.6', OID_OBJECT_CLASS, 'uddiTModelInstanceInfo', 'RFC4403'), '1.3.6.1.1.10.6.7': OidInfo('1.3.6.1.1.10.6.7', OID_OBJECT_CLASS, 'uddiTModel', 'RFC4403'), '1.3.6.1.1.10.6.8': OidInfo('1.3.6.1.1.10.6.8', OID_OBJECT_CLASS, 'uddiPublisherAssertion', 'RFC4403'), '1.3.6.1.1.10.6.9': OidInfo('1.3.6.1.1.10.6.9', OID_OBJECT_CLASS, 'uddiv3Subscription', 'RFC4403'), '1.3.6.1.1.10.6.10': OidInfo('1.3.6.1.1.10.6.10', OID_OBJECT_CLASS, 'uddiv3EntityObituary', 'RFC4403'), '1.3.6.1.1.11.1.1': OidInfo('1.3.6.1.1.11.1.1', OID_OBJECT_CLASS, 'vPIMUser', 'RFC4237'), '1.3.6.1.1.3.1': OidInfo('1.3.6.1.1.3.1', OID_OBJECT_CLASS, 'uidObject', 'RFC4519'), '1.3.6.1.1.6.1.1': OidInfo('1.3.6.1.1.6.1.1', OID_OBJECT_CLASS, 'pcimPolicy', 'RFC3703'), '1.3.6.1.1.6.1.2': OidInfo('1.3.6.1.1.6.1.2', OID_OBJECT_CLASS, 'pcimGroup', 'RFC3703'), '1.3.6.1.1.6.1.3': OidInfo('1.3.6.1.1.6.1.3', OID_OBJECT_CLASS, 'pcimGroupAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.4': OidInfo('1.3.6.1.1.6.1.4', OID_OBJECT_CLASS, 'pcimGroupInstance', 'RFC3703'), '1.3.6.1.1.6.1.5': OidInfo('1.3.6.1.1.6.1.5', OID_OBJECT_CLASS, 'pcimRule', 'RFC3703'), '1.3.6.1.1.6.1.6': OidInfo('1.3.6.1.1.6.1.6', OID_OBJECT_CLASS, 'pcimRuleAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.7': OidInfo('1.3.6.1.1.6.1.7', OID_OBJECT_CLASS, 'pcimRuleInstance', 'RFC3703'), '1.3.6.1.1.6.1.8': OidInfo('1.3.6.1.1.6.1.8', OID_OBJECT_CLASS, 'pcimRuleConditionAssociation', 'RFC3703'), '1.3.6.1.1.6.1.9': OidInfo('1.3.6.1.1.6.1.9', OID_OBJECT_CLASS, 'pcimRuleValidityAssociation', 'RFC3703'), '1.3.6.1.1.6.1.10': OidInfo('1.3.6.1.1.6.1.10', OID_OBJECT_CLASS, 'pcimRuleActionAssociation', 'RFC3703'), '1.3.6.1.1.6.1.11': OidInfo('1.3.6.1.1.6.1.11', OID_OBJECT_CLASS, 'pcimConditionAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.12': OidInfo('1.3.6.1.1.6.1.12', OID_OBJECT_CLASS, 'pcimTPCAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.13': OidInfo('1.3.6.1.1.6.1.13', OID_OBJECT_CLASS, 'pcimConditionVendorAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.14': OidInfo('1.3.6.1.1.6.1.14', OID_OBJECT_CLASS, 'pcimActionAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.15': OidInfo('1.3.6.1.1.6.1.15', OID_OBJECT_CLASS, 'pcimActionVendorAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.16': OidInfo('1.3.6.1.1.6.1.16', OID_OBJECT_CLASS, 'pcimPolicyInstance', 'RFC3703'), '1.3.6.1.1.6.1.17': OidInfo('1.3.6.1.1.6.1.17', OID_OBJECT_CLASS, 'pcimElementAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.18': OidInfo('1.3.6.1.1.6.1.18', OID_OBJECT_CLASS, 'pcimRepository', 'RFC3703'), '1.3.6.1.1.6.1.19': OidInfo('1.3.6.1.1.6.1.19', OID_OBJECT_CLASS, 'pcimRepositoryAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.20': OidInfo('1.3.6.1.1.6.1.20', OID_OBJECT_CLASS, 'pcimRepositoryInstance', 'RFC3703'), '1.3.6.1.1.6.1.21': OidInfo('1.3.6.1.1.6.1.21', OID_OBJECT_CLASS, 'pcimSubtreesPtrAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.22': OidInfo('1.3.6.1.1.6.1.22', OID_OBJECT_CLASS, 'pcimGroupContainmentAuxClass', 'RFC3703'), '1.3.6.1.1.6.1.23': OidInfo('1.3.6.1.1.6.1.23', OID_OBJECT_CLASS, 'pcimRuleContainmentAuxClass', 'RFC3703'), '1.3.6.1.1.9.1.1': OidInfo('1.3.6.1.1.9.1.1', OID_OBJECT_CLASS, 'pcelsPolicySet', 'RFC4104'), '1.3.6.1.1.9.1.2': OidInfo('1.3.6.1.1.9.1.2', OID_OBJECT_CLASS, 'pcelsPolicySetAssociation', 'RFC4104'), '1.3.6.1.1.9.1.3': OidInfo('1.3.6.1.1.9.1.3', OID_OBJECT_CLASS, 'pcelsGroup', 'RFC4104'), '1.3.6.1.1.9.1.4': OidInfo('1.3.6.1.1.9.1.4', OID_OBJECT_CLASS, 'pcelsGroupAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.5': OidInfo('1.3.6.1.1.9.1.5', OID_OBJECT_CLASS, 'pcelsGroupInstance', 'RFC4104'), '1.3.6.1.1.9.1.6': OidInfo('1.3.6.1.1.9.1.6', OID_OBJECT_CLASS, 'pcelsRule', 'RFC4104'), '1.3.6.1.1.9.1.7': OidInfo('1.3.6.1.1.9.1.7', OID_OBJECT_CLASS, 'pcelsRuleAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.8': OidInfo('1.3.6.1.1.9.1.8', OID_OBJECT_CLASS, 'pcelsRuleInstance', 'RFC4104'), '1.3.6.1.1.9.1.9': OidInfo('1.3.6.1.1.9.1.9', OID_OBJECT_CLASS, 'pcelsConditionAssociation', 'RFC4104'), '1.3.6.1.1.9.1.10': OidInfo('1.3.6.1.1.9.1.10', OID_OBJECT_CLASS, 'pcelsActionAssociation', 'RFC4104'), '1.3.6.1.1.9.1.11': OidInfo('1.3.6.1.1.9.1.11', OID_OBJECT_CLASS, 'pcelsSimpleConditionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.12': OidInfo('1.3.6.1.1.9.1.12', OID_OBJECT_CLASS, 'pcelsCompoundConditionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.13': OidInfo('1.3.6.1.1.9.1.13', OID_OBJECT_CLASS, 'pcelsCompoundFilterConditionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.14': OidInfo('1.3.6.1.1.9.1.14', OID_OBJECT_CLASS, 'pcelsSimpleActionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.15': OidInfo('1.3.6.1.1.9.1.15', OID_OBJECT_CLASS, 'pcelsCompoundActionAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.16': OidInfo('1.3.6.1.1.9.1.16', OID_OBJECT_CLASS, 'pcelsVariable', 'RFC4104'), '1.3.6.1.1.9.1.17': OidInfo('1.3.6.1.1.9.1.17', OID_OBJECT_CLASS, 'pcelsExplicitVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.18': OidInfo('1.3.6.1.1.9.1.18', OID_OBJECT_CLASS, 'pcelsImplicitVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.19': OidInfo('1.3.6.1.1.9.1.19', OID_OBJECT_CLASS, 'pcelsSourceIPv4VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.20': OidInfo('1.3.6.1.1.9.1.20', OID_OBJECT_CLASS, 'pcelsSourceIPv6VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.21': OidInfo('1.3.6.1.1.9.1.21', OID_OBJECT_CLASS, 'pcelsDestinationIPv4VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.22': OidInfo('1.3.6.1.1.9.1.22', OID_OBJECT_CLASS, 'pcelsDestinationIPv6VariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.23': OidInfo('1.3.6.1.1.9.1.23', OID_OBJECT_CLASS, 'pcelsSourcePortVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.24': OidInfo('1.3.6.1.1.9.1.24', OID_OBJECT_CLASS, 'pcelsDestinationPortVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.25': OidInfo('1.3.6.1.1.9.1.25', OID_OBJECT_CLASS, 'pcelsIPProtocolVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.26': OidInfo('1.3.6.1.1.9.1.26', OID_OBJECT_CLASS, 'pcelsIPVersionVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.27': OidInfo('1.3.6.1.1.9.1.27', OID_OBJECT_CLASS, 'pcelsIPToSVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.28': OidInfo('1.3.6.1.1.9.1.28', OID_OBJECT_CLASS, 'pcelsDSCPVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.29': OidInfo('1.3.6.1.1.9.1.29', OID_OBJECT_CLASS, 'pcelsFlowIdVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.30': OidInfo('1.3.6.1.1.9.1.30', OID_OBJECT_CLASS, 'pcelsSourceMACVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.31': OidInfo('1.3.6.1.1.9.1.31', OID_OBJECT_CLASS, 'pcelsDestinationMACVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.32': OidInfo('1.3.6.1.1.9.1.32', OID_OBJECT_CLASS, 'pcelsVLANVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.33': OidInfo('1.3.6.1.1.9.1.33', OID_OBJECT_CLASS, 'pcelsCoSVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.34': OidInfo('1.3.6.1.1.9.1.34', OID_OBJECT_CLASS, 'pcelsEthertypeVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.35': OidInfo('1.3.6.1.1.9.1.35', OID_OBJECT_CLASS, 'pcelsSourceSAPVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.36': OidInfo('1.3.6.1.1.9.1.36', OID_OBJECT_CLASS, 'pcelsDestinationSAPVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.37': OidInfo('1.3.6.1.1.9.1.37', OID_OBJECT_CLASS, 'pcelsSNAPOUIVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.38': OidInfo('1.3.6.1.1.9.1.38', OID_OBJECT_CLASS, 'pcelsSNAPTypeVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.39': OidInfo('1.3.6.1.1.9.1.39', OID_OBJECT_CLASS, 'pcelsFlowDirectionVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.40': OidInfo('1.3.6.1.1.9.1.40', OID_OBJECT_CLASS, 'pcelsValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.41': OidInfo('1.3.6.1.1.9.1.41', OID_OBJECT_CLASS, 'pcelsIPv4AddrValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.42': OidInfo('1.3.6.1.1.9.1.42', OID_OBJECT_CLASS, 'pcelsIPv6AddrValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.43': OidInfo('1.3.6.1.1.9.1.43', OID_OBJECT_CLASS, 'pcelsMACAddrValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.44': OidInfo('1.3.6.1.1.9.1.44', OID_OBJECT_CLASS, 'pcelsStringValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.45': OidInfo('1.3.6.1.1.9.1.45', OID_OBJECT_CLASS, 'pcelsBitStringValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.46': OidInfo('1.3.6.1.1.9.1.46', OID_OBJECT_CLASS, 'pcelsIntegerValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.47': OidInfo('1.3.6.1.1.9.1.47', OID_OBJECT_CLASS, 'pcelsBooleanValueAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.48': OidInfo('1.3.6.1.1.9.1.48', OID_OBJECT_CLASS, 'pcelsReusableContainer', 'RFC4104'), '1.3.6.1.1.9.1.49': OidInfo('1.3.6.1.1.9.1.49', OID_OBJECT_CLASS, 'pcelsReusableContainerAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.50': OidInfo('1.3.6.1.1.9.1.50', OID_OBJECT_CLASS, 'pcelsReusableContainerInstance', 'RFC4104'), '1.3.6.1.1.9.1.51': OidInfo('1.3.6.1.1.9.1.51', OID_OBJECT_CLASS, 'pcelsRoleCollection', 'RFC4104'), '1.3.6.1.1.9.1.52': OidInfo('1.3.6.1.1.9.1.52', OID_OBJECT_CLASS, 'pcelsFilterEntryBase', 'RFC4104'), '1.3.6.1.1.9.1.53': OidInfo('1.3.6.1.1.9.1.53', OID_OBJECT_CLASS, 'pcelsIPHeadersFilter', 'RFC4104'), '1.3.6.1.1.9.1.54': OidInfo('1.3.6.1.1.9.1.54', OID_OBJECT_CLASS, 'pcels8021Filter', 'RFC4104'), '1.3.6.1.1.9.1.55': OidInfo('1.3.6.1.1.9.1.55', OID_OBJECT_CLASS, 'pcelsFilterListAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.56': OidInfo('1.3.6.1.1.9.1.56', OID_OBJECT_CLASS, 'pcelsVendorVariableAuxClass', 'RFC4104'), '1.3.6.1.1.9.1.57': OidInfo('1.3.6.1.1.9.1.57', OID_OBJECT_CLASS, 'pcelsVendorValueAuxClass', 'RFC4104'), '1.3.6.1.4.1.11.1.3.1.2.5': OidInfo('1.3.6.1.4.1.11.1.3.1.2.5', OID_OBJECT_CLASS, 'DUAConfigProfile', 'RFC4876'), '1.3.6.1.4.1.1466.101.119.2': OidInfo('1.3.6.1.4.1.1466.101.119.2', OID_OBJECT_CLASS, 'dynamicObject', 'RFC2589'), '1.3.6.1.4.1.1466.101.120.111': OidInfo('1.3.6.1.4.1.1466.101.120.111', OID_OBJECT_CLASS, 'extensibleObject', 'RFC4512'), '1.3.6.1.4.1.1466.344': OidInfo('1.3.6.1.4.1.1466.344', OID_OBJECT_CLASS, 'dcObject', 'RFC4519'), '1.3.6.1.4.1.16572.2.1.1': OidInfo('1.3.6.1.4.1.16572.2.1.1', OID_OBJECT_CLASS, 'LDIFLocationURLObject', 'RFC6109'), '1.3.6.1.4.1.16572.2.1.2': OidInfo('1.3.6.1.4.1.16572.2.1.2', OID_OBJECT_CLASS, 'provider', 'RFC6109'), '1.3.6.1.4.1.250.3.15': OidInfo('1.3.6.1.4.1.250.3.15', OID_OBJECT_CLASS, 'labeledURIObject', 'RFC2079'), '1.3.6.1.4.1.31103.1.1001': OidInfo('1.3.6.1.4.1.31103.1.1001', OID_OBJECT_CLASS, 'fedfsNsdbContainerInfo', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.1002': OidInfo('1.3.6.1.4.1.31103.1.1002', OID_OBJECT_CLASS, 'fedfsFsn', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.1003': OidInfo('1.3.6.1.4.1.31103.1.1003', OID_OBJECT_CLASS, 'fedfsFsl', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.31103.1.1004': OidInfo('1.3.6.1.4.1.31103.1.1004', OID_OBJECT_CLASS, 'fedfsNfsFsl', 'RFC-ietf-nfsv4-federated-fs-protocol-15'), '1.3.6.1.4.1.453.7.1.1': OidInfo('1.3.6.1.4.1.453.7.1.1', OID_OBJECT_CLASS, ['rFC822ToX400Mapping', 'subtree'], 'RFC2164-RFC2293'), '1.3.6.1.4.1.453.7.1.2': OidInfo('1.3.6.1.4.1.453.7.1.2', OID_OBJECT_CLASS, ['x400ToRFC822Mapping', 'table'], 'RFC2164-RFC2293'), '1.3.6.1.4.1.453.7.1.3': OidInfo('1.3.6.1.4.1.453.7.1.3', OID_OBJECT_CLASS, ['omittedORAddressComponent', 'tableEntry'], 'RFC2164-RFC2293'), '1.3.6.1.4.1.453.7.1.4': OidInfo('1.3.6.1.4.1.453.7.1.4', OID_OBJECT_CLASS, ['mixerGateway', 'textTableEntry'], 'RFC2164-RFC2293'), '1.3.6.1.4.1.453.7.1.5': OidInfo('1.3.6.1.4.1.453.7.1.5', OID_OBJECT_CLASS, 'distinguishedNameTableEntry', 'RFC2293'), '2.16.840.1.113730.3.2.6': OidInfo('2.16.840.1.113730.3.2.6', OID_OBJECT_CLASS, 'referral', 'RFC3296'), '2.5.17.0': OidInfo('2.5.17.0', OID_OBJECT_CLASS, 'subentry', 'RFC3672'), '2.5.20.1': OidInfo('2.5.20.1', OID_OBJECT_CLASS, 'subschema', 'RFC4512'), '2.5.20.2': OidInfo('2.5.20.2', OID_OBJECT_CLASS, 'collectiveAttributeSubentry', 'RFC3671'), '2.5.6.0': OidInfo('2.5.6.0', OID_OBJECT_CLASS, 'top', 'RFC4512'), '2.5.6.1': OidInfo('2.5.6.1', OID_OBJECT_CLASS, 'alias', 'RFC4512'), '2.5.6.2': OidInfo('2.5.6.2', OID_OBJECT_CLASS, 'country', 'RFC4519'), '2.5.6.3': OidInfo('2.5.6.3', OID_OBJECT_CLASS, 'locality', 'RFC4519'), '2.5.6.4': OidInfo('2.5.6.4', OID_OBJECT_CLASS, 'organization', 'RFC4519'), '2.5.6.5': OidInfo('2.5.6.5', OID_OBJECT_CLASS, 'organizationalUnit', 'RFC4519'), '2.5.6.6': OidInfo('2.5.6.6', OID_OBJECT_CLASS, 'person', 'RFC4519'), '2.5.6.7': OidInfo('2.5.6.7', OID_OBJECT_CLASS, 'organizationalPerson', 'RFC4519'), '2.5.6.8': OidInfo('2.5.6.8', OID_OBJECT_CLASS, 'organizationalRole', 'RFC4519'), '2.5.6.9': OidInfo('2.5.6.9', OID_OBJECT_CLASS, 'groupOfNames', 'RFC4519'), '2.5.6.10': OidInfo('2.5.6.10', OID_OBJECT_CLASS, 'residentialPerson', 'RFC4519'), '2.5.6.11': OidInfo('2.5.6.11', OID_OBJECT_CLASS, 'applicationProcess', 'RFC4519'), '2.5.6.12': OidInfo('2.5.6.12', OID_OBJECT_CLASS, 'applicationEntity', 'RFC2256'), '2.5.6.13': OidInfo('2.5.6.13', OID_OBJECT_CLASS, 'dSA', 'RFC2256'), '2.5.6.14': OidInfo('2.5.6.14', OID_OBJECT_CLASS, 'device', 'RFC4519'), '2.5.6.15': OidInfo('2.5.6.15', OID_OBJECT_CLASS, 'strongAuthenticationUser', 'RFC4523'), '2.5.6.16': OidInfo('2.5.6.16', OID_OBJECT_CLASS, 'certificationAuthority', 'RFC4523'), '2.5.6.16.2': OidInfo('2.5.6.16.2', OID_OBJECT_CLASS, 'certificationAuthority-V2', 'RFC4523'), '2.5.6.17': OidInfo('2.5.6.17', OID_OBJECT_CLASS, 'groupOfUniqueNames', 'RFC4519'), '2.5.6.18': OidInfo('2.5.6.18', OID_OBJECT_CLASS, 'userSecurityInformation', 'RFC4523'), '2.5.6.19': OidInfo('2.5.6.19', OID_OBJECT_CLASS, 'cRLDistributionPoint', 'RFC4523'), '2.5.6.20': OidInfo('2.5.6.20', OID_OBJECT_CLASS, 'dmd', 'RFC2256'), '2.5.6.21': OidInfo('2.5.6.21', OID_OBJECT_CLASS, 'pkiUser', 'RFC4523'), '2.5.6.22': OidInfo('2.5.6.22', OID_OBJECT_CLASS, 'pkiCA', 'RFC4523'), '2.5.6.23': OidInfo('2.5.6.23', OID_OBJECT_CLASS, 'deltaCRL', 'RFC4523'), # unsolicited notices '1.3.6.1.1.21.4': OidInfo('1.3.6.1.1.21.4', OID_UNSOLICITED_NOTICE, 'Aborted Transaction Notice', 'RFC5805'), '1.3.6.1.4.1.1466.20036': OidInfo('1.3.6.1.4.1.1466.20036', OID_UNSOLICITED_NOTICE, 'Notice of Disconnection', 'RFC4511')} python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc2696.py0000666000000000000000000000357412355103747021221 0ustar 00000000000000""" Created on 2013.10.15 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from pyasn1.type.univ import OctetString, Integer, Sequence from pyasn1.type.namedtype import NamedTypes, NamedType from pyasn1.type.constraint import ValueRangeConstraint # constants # maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- MAXINT = Integer(2147483647) # constraints rangeInt0ToMaxConstraint = ValueRangeConstraint(0, MAXINT) class Integer0ToMax(Integer): subtypeSpec = Integer.subtypeSpec + rangeInt0ToMaxConstraint class Size(Integer0ToMax): """ Size INTEGER (0..maxInt) """ pass class Cookie(OctetString): """ cookie OCTET STRING """ pass class RealSearchControlValue(Sequence): """ realSearchControlValue ::= SEQUENCE { size INTEGER (0..maxInt), -- requested page size from client -- result set size estimate from server cookie OCTET STRING """ componentType = NamedTypes(NamedType('size', Size()), NamedType('cookie', Cookie())) python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc2849.py0000666000000000000000000001717212355103747021220 0ustar 00000000000000""" Created on 2013.12.08 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from base64 import b64encode from .. import LDIF_LINE_LENGTH from ..core.exceptions import LDAPLDIFError # LDIF converter RFC 2849 compliant def safe_ldif_string(bytes_value): if not bytes_value: return True # check SAFE-INIT-CHAR: < 127, not NUL, LF, CR, SPACE, COLON, LESS-THAN if bytes_value[0] > 127 or bytes_value[0] in [0, 10, 13, 32, 58, 60]: return False # check SAFE-CHAR: < 127 not NUL, LF, CR if 0 in bytes_value or 10 in bytes_value or 13 in bytes_value: return False # check last char for SPACE if bytes_value[-1] == 32: return False for byte in bytes_value: if byte > 127: return False return True def convert_to_ldif(descriptor, value, base64): if not value: value = '' if isinstance(value, str): value = bytearray(value, encoding='utf-8') if base64 or not safe_ldif_string(value): try: encoded = b64encode(value) except TypeError: encoded = b64encode(str(value)) # patch for Python 2.6 if not isinstance(encoded, str): # in Python 3 b64encode returns bytes in Python 2 returns str encoded = str(encoded, encoding='ascii') # Python 3 line = descriptor + ':: ' + encoded else: if not str == bytes: # Python 3 value = str(value, encoding='ascii') else: # Python 2 value = str(value) line = descriptor + ': ' + value return line def add_controls(controls, all_base64): lines = [] if controls: for control in controls: line = 'control: ' + control[0] line += ' ' + ('true' if control[1] else 'false') if control[2]: lines.append(convert_to_ldif(line, control[2], all_base64)) return lines def add_attributes(attributes, all_base64): lines = [] oc_attr = None # objectclass first, even if this is not specified in the RFC for attr in attributes: if attr.lower() == 'objectclass': for val in attributes[attr]: lines.append(convert_to_ldif(attr, val, all_base64)) oc_attr = attr break # remaining attributes for attr in attributes: if attr != oc_attr: for val in attributes[attr]: lines.append(convert_to_ldif(attr, val, all_base64)) return lines def search_response_to_ldif(entries, all_base64): lines = [] for entry in entries: if 'dn' in entry: lines.append(convert_to_ldif('dn', entry['dn'], all_base64)) lines.extend(add_attributes(entry['raw_attributes'], all_base64)) else: raise LDAPLDIFError('unable to convert to LDIF-CONTENT - missing DN') lines.append('') if lines: lines.append('') lines.append('# total number of entries: ' + str(len(entries))) return lines def add_request_to_ldif(entry, all_base64): lines = [] if 'entry' in entry: lines.append(convert_to_ldif('dn', entry['entry'], all_base64)) lines.extend(add_controls(entry['controls'], all_base64)) lines.append('changetype: add') lines.extend(add_attributes(entry['attributes'], all_base64)) else: raise LDAPLDIFError('unable to convert to LDIF-CHANGE-ADD - missing DN ') return lines def delete_request_to_ldif(entry, all_base64): lines = [] if 'entry' in entry: lines.append(convert_to_ldif('dn', entry['entry'], all_base64)) lines.append(add_controls(entry['controls'], all_base64)) lines.append('changetype: delete') else: raise LDAPLDIFError('unable to convert to LDIF-CHANGE-DELETE - missing DN ') return lines def modify_request_to_ldif(entry, all_base64): lines = [] if 'entry' in entry: lines.append(convert_to_ldif('dn', entry['entry'], all_base64)) lines.extend(add_controls(entry['controls'], all_base64)) lines.append('changetype: modify') if 'changes' in entry: for change in entry['changes']: lines.append(['add', 'delete', 'replace', 'increment'][change['operation']] + ': ' + change['attribute']['type']) for value in change['attribute']['value']: lines.append(convert_to_ldif(change['attribute']['type'], value, all_base64)) lines.append('-') return lines def modify_dn_request_to_ldif(entry, all_base64): lines = [] if 'entry' in entry: lines.append(convert_to_ldif('dn', entry['entry'], all_base64)) lines.extend(add_controls(entry['controls'], all_base64)) lines.append('changetype: modrdn') if 'newSuperior' in entry and entry['newSuperior'] else lines.append('changetype: moddn') lines.append(convert_to_ldif('newrdn', entry['newRdn'], all_base64)) lines.append('deleteoldrdn: ' + ('1' if entry['deleteOldRdn'] else '0')) if 'newSuperior' in entry and entry['newSuperior']: lines.append(convert_to_ldif('newsuperior', entry['newSuperior'], all_base64)) else: raise LDAPLDIFError('unable to convert to LDIF-CHANGE-MODDN - missing DN ') return lines def operation_to_ldif(operation_type, entries, all_base64=False, sort_order=None): if operation_type == 'searchResponse': lines = search_response_to_ldif(entries, all_base64) elif operation_type == 'addRequest': lines = add_request_to_ldif(entries, all_base64) elif operation_type == 'delRequest': lines = delete_request_to_ldif(entries, all_base64) elif operation_type == 'modifyRequest': lines = modify_request_to_ldif(entries, all_base64) elif operation_type == 'modDNRequest': lines = modify_dn_request_to_ldif(entries, all_base64) else: lines = [] # sort lines as per custom sort_order # sort order is a list of descriptors, lines will be sorted following the same sequence if sort_order: lines = sorted(lines, key=lambda x: ldif_sort(x, sort_order)) ldif_record = [] # check max line length and split as per note 2 of RFC 2849 for line in lines: if line: ldif_record.append(line[0:LDIF_LINE_LENGTH]) ldif_record.extend([' ' + line[i: i + LDIF_LINE_LENGTH - 1] for i in range(LDIF_LINE_LENGTH, len(line), LDIF_LINE_LENGTH - 1)] if len(line) > LDIF_LINE_LENGTH else []) return ldif_record def add_ldif_header(ldif_lines): if ldif_lines: ldif_lines.insert(0, 'version: 1') return ldif_lines def ldif_sort(line, sort_order): for i, descriptor in enumerate(sort_order): if line and line.startswith(descriptor): return i return len(sort_order) + 1 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc3062.py0000666000000000000000000000557012355107014021172 0ustar 00000000000000""" Created on 2014.04.28 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from pyasn1.type.univ import OctetString, Sequence from pyasn1.type.namedtype import NamedTypes, OptionalNamedType from pyasn1.type.tag import Tag, tagClassContext, tagFormatSimple #Modify password extended operation #passwdModifyOID OBJECT IDENTIFIER ::= 1.3.6.1.4.1.4203.1.11.1 #PasswdModifyRequestValue ::= SEQUENCE { # userIdentity [0] OCTET STRING OPTIONAL # oldPasswd [1] OCTET STRING OPTIONAL # newPasswd [2] OCTET STRING OPTIONAL } # # PasswdModifyResponseValue ::= SEQUENCE { # genPasswd [0] OCTET STRING OPTIONAL } class UserIdentity(OctetString): """ userIdentity [0] OCTET STRING OPTIONAL """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) encoding = 'utf-8' class OldPasswd(OctetString): """ oldPasswd [1] OCTET STRING OPTIONAL """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1)) encoding = 'utf-8' class NewPasswd(OctetString): """ newPasswd [2] OCTET STRING OPTIONAL """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2)) encoding = 'utf-8' class GenPasswd(OctetString): """ newPasswd [2] OCTET STRING OPTIONAL """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) encoding = 'utf-8' class PasswdModifyRequestValue(Sequence): """ PasswdModifyRequestValue ::= SEQUENCE { userIdentity [0] OCTET STRING OPTIONAL oldPasswd [1] OCTET STRING OPTIONAL newPasswd [2] OCTET STRING OPTIONAL } """ componentType = NamedTypes(OptionalNamedType('userIdentity', UserIdentity()), OptionalNamedType('oldPasswd', OldPasswd()), OptionalNamedType('newPasswd', NewPasswd())) class PasswdModifyResponseValue(Sequence): """ PasswdModifyResponseValue ::= SEQUENCE { genPasswd [0] OCTET STRING OPTIONAL } """ componentType = NamedTypes(OptionalNamedType('genPasswd', GenPasswd())) python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4511.py0000666000000000000000000012065412355103747021204 0ustar 00000000000000""" Created on 2013.05.15 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ # ldap ASN.1 Definition # from RFC4511 - Appendix B # extended with result codes from IANA ldap-parameters as of 2013.08.21 # extended with modify_increment from RFC4525 # Lightweight-Directory-Access-Protocol-V3 {1 3 6 1 1 18} # -- Copyright (C) The Internet Society (2006). This version of # -- this ASN.1 module is part of RFC 4511; see the RFC itself # -- for full legal notices. # DEFINITIONS # IMPLICIT TAGS # EXTENSIBILITY IMPLIED from pyasn1.type.univ import OctetString, Integer, Sequence, Choice, SequenceOf, Boolean, Null, Enumerated, SetOf from pyasn1.type.namedtype import NamedTypes, NamedType, OptionalNamedType, DefaultedNamedType from pyasn1.type.constraint import ValueRangeConstraint, SingleValueConstraint, ValueSizeConstraint from pyasn1.type.namedval import NamedValues from pyasn1.type.tag import tagClassApplication, tagFormatConstructed, Tag, tagClassContext, tagFormatSimple from .. import LDAP_MAX_INT # constants # maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- MAXINT = Integer(LDAP_MAX_INT) # constraints rangeInt0ToMaxConstraint = ValueRangeConstraint(0, MAXINT) rangeInt1To127Constraint = ValueRangeConstraint(1, 127) size1ToMaxConstraint = ValueSizeConstraint(1, MAXINT) responseValueConstraint = SingleValueConstraint(0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 32, 33, 34, 36, 48, 49, 50, 51, 52, 53, 54, 64, 65, 66, 67, 68, 69, 71, 80, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 4096) # custom constraints numericOIDConstraint = None # tbd distinguishedNameConstraint = None # tbd nameComponentConstraint = None # tbd attributeDescriptionConstraint = None # tbd uriConstraint = None # tbd attributeSelectorConstraint = None # tbd class Integer0ToMax(Integer): subtypeSpec = Integer.subtypeSpec + rangeInt0ToMaxConstraint class LDAPString(OctetString): """ LDAPString ::= OCTET STRING -- UTF-8 encoded, -- [ISO10646] characters """ encoding = 'utf-8' class MessageID(Integer0ToMax): """ MessageID ::= INTEGER (0 .. maxInt) """ pass class LDAPOID(OctetString): """ LDAPOID ::= OCTET STRING -- Constrained to -- [RFC4512] """ # subtypeSpec = numericOIDConstraint pass class LDAPDN(LDAPString): """ LDAPDN ::= LDAPString -- Constrained to -- [RFC4514] """ # subtypeSpec = distinguishedName pass class RelativeLDAPDN(LDAPString): """ RelativeLDAPDN ::= LDAPString -- Constrained to -- [RFC4514] """ # subtypeSpec = LDAPString.subtypeSpec + nameComponentConstraint pass class AttributeDescription(LDAPString): """ AttributeDescription ::= LDAPString -- Constrained to -- [RFC4512] """ # subtypeSpec = LDAPString.subtypeSpec + attributeDescriptionConstraint pass class AttributeValue(OctetString): """ AttributeValue ::= OCTET STRING """ encoding = 'utf-8' class AssertionValue(OctetString): """ AssertionValue ::= OCTET STRING """ encoding = 'utf-8' class AttributeValueAssertion(Sequence): """ AttributeValueAssertion ::= SEQUENCE { attributeDesc AttributeDescription, assertionValue AssertionValue } """ componentType = NamedTypes(NamedType('attributeDesc', AttributeDescription()), NamedType('assertionValue', AssertionValue())) class MatchingRuleId(LDAPString): """ MatchingRuleId ::= LDAPString """ pass class Vals(SetOf): """ vals SET OF value AttributeValue } """ componentType = AttributeValue() class ValsAtLeast1(SetOf): """ vals SET OF value AttributeValue } """ componentType = AttributeValue() subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint class PartialAttribute(Sequence): """ PartialAttribute ::= SEQUENCE { type AttributeDescription, vals SET OF value AttributeValue } """ componentType = NamedTypes(NamedType('type', AttributeDescription()), NamedType('vals', Vals())) class Attribute(Sequence): """ Attribute ::= PartialAttribute(WITH COMPONENTS { ..., vals (SIZE(1..MAX))}) """ componentType = NamedTypes(NamedType('type', AttributeDescription()), NamedType('vals', ValsAtLeast1())) class AttributeList(SequenceOf): """ AttributeList ::= SEQUENCE OF attribute Attribute """ componentType = Attribute() class Simple(OctetString): """ simple [0] OCTET STRING, """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) encoding = 'utf-8' class Credentials(OctetString): """ credentials OCTET STRING """ encoding = 'utf-8' class SaslCredentials(Sequence): """ SaslCredentials ::= SEQUENCE { mechanism LDAPString, credentials OCTET STRING OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3)) componentType = NamedTypes(NamedType('mechanism', LDAPString()), OptionalNamedType('credentials', Credentials())) class AuthenticationChoice(Choice): """ AuthenticationChoice ::= CHOICE { simple [0] OCTET STRING, -- 1 and 2 reserved sasl [3] SaslCredentials, ... } """ componentType = NamedTypes(NamedType('simple', Simple()), NamedType('sasl', SaslCredentials())) class Version(Integer): """ version INTEGER (1 .. 127), """ subtypeSpec = Integer.subtypeSpec + rangeInt1To127Constraint class ResultCode(Enumerated): """ resultCode ENUMERATED { success (0), operationsError (1), protocolError (2), timeLimitExceeded (3), sizeLimitExceeded (4), compareFalse (5), compareTrue (6), authMethodNotSupported (7), strongerAuthRequired (8), -- 9 reserved -- referral (10), adminLimitExceeded (11), unavailableCriticalExtension (12), confidentialityRequired (13), saslBindInProgress (14), noSuchAttribute (16), undefinedAttributeType (17), inappropriateMatching (18), constraintViolation (19), attributeOrValueExists (20), invalidAttributeSyntax (21), -- 22-31 unused -- noSuchObject (32), aliasProblem (33), invalidDNSyntax (34), -- 35 reserved for undefined isLeaf -- aliasDereferencingProblem (36), -- 37-47 unused -- inappropriateAuthentication (48), invalidCredentials (49), insufficientAccessRights (50), busy (51), unavailable (52), unwillingToPerform (53), loopDetect (54), -- 55-63 unused -- namingViolation (64), objectClassViolation (65), notAllowedOnNonLeaf (66), notAllowedOnRDN (67), entryAlreadyExists (68), objectClassModsProhibited (69), -- 70 reserved for CLDAP -- affectsMultipleDSAs (71), -- 72-79 unused -- other (80), ... } from IANA ldap-parameters: lcupResourcesExhausted 113 IESG [RFC3928] lcupSecurityViolation 114 IESG [RFC3928] lcupInvalidData 115 IESG [RFC3928] lcupUnsupportedScheme 116 IESG [RFC3928] lcupReloadRequired 117 IESG [RFC3928] canceled 118 IESG [RFC3909] noSuchOperation 119 IESG [RFC3909] tooLate 120 IESG [RFC3909] cannotCancel 121 IESG [RFC3909] assertionFailed 122 IESG [RFC4528] authorizationDenied 123 WELTMAN [RFC4370] e-syncRefreshRequired 4096 [Kurt_Zeilenga] [Jong_Hyuk_Choi] [RFC4533] """ namedValues = NamedValues(('success', 0), ('operationsError', 1), ('protocolError', 2), ('timeLimitExceeded', 3), ('sizeLimitExceeded', 4), ('compareFalse', 5), ('compareTrue', 6), ('authMethodNotSupported', 7), ('strongerAuthRequired', 8), ('referral', 10), ('adminLimitExceeded', 11), ('unavailableCriticalExtension', 12), ('confidentialityRequired', 13), ('saslBindInProgress', 14), ('noSuchAttribute', 16), ('undefinedAttributeType', 17), ('inappropriateMatching', 18), ('constraintViolation', 19), ('attributeOrValueExists', 20), ('invalidAttributeSyntax', 21), ('noSuchObject', 32), ('aliasProblem', 33), ('invalidDNSyntax', 34), ('aliasDereferencingProblem', 36), ('inappropriateAuthentication', 48), ('invalidCredentials', 49), ('insufficientAccessRights', 50), ('busy', 51), ('unavailable', 52), ('unwillingToPerform', 53), ('loopDetected', 54), ('namingViolation', 64), ('objectClassViolation', 65), ('notAllowedOnNonLeaf', 66), ('notAllowedOnRDN', 67), ('entryAlreadyExists', 68), ('objectClassModsProhibited', 69), ('affectMultipleDSAs', 71), ('other', 80), ('lcupResourcesExhausted', 113), ('lcupSecurityViolation', 114), ('lcupInvalidData', 115), ('lcupUnsupportedScheme', 116), ('lcupReloadRequired', 117), ('canceled', 118), ('noSuchOperation', 119), ('tooLate', 120), ('cannotCancel', 121), ('assertionFailed', 122), ('authorizationDenied', 123), ('e-syncRefreshRequired', 4096)) subTypeSpec = Enumerated.subtypeSpec + responseValueConstraint class URI(LDAPString): """ URI ::= LDAPString -- limited to characters permitted in -- URIs """ # subtypeSpec = LDAPString.subTypeSpec + uriConstrain pass class Referral(SequenceOf): """ Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI """ tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3)) componentType = URI() class ServerSaslCreds(OctetString): """ serverSaslCreds [7] OCTET STRING OPTIONAL """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 7)) encoding = 'utf-8' class LDAPResult(Sequence): """ LDAPResult ::= SEQUENCE { resultCode ENUMERATED { success (0), operationsError (1), protocolError (2), timeLimitExceeded (3), sizeLimitExceeded (4), compareFalse (5), compareTrue (6), authMethodNotSupported (7), strongerAuthRequired (8), -- 9 reserved -- referral (10), adminLimitExceeded (11), unavailableCriticalExtension (12), confidentialityRequired (13), saslBindInProgress (14), noSuchAttribute (16), undefinedAttributeType (17), inappropriateMatching (18), constraintViolation (19), attributeOrValueExists (20), invalidAttributeSyntax (21), -- 22-31 unused -- noSuchObject (32), aliasProblem (33), invalidDNSyntax (34), -- 35 reserved for undefined isLeaf -- aliasDereferencingProblem (36), -- 37-47 unused -- inappropriateAuthentication (48), invalidCredentials (49), insufficientAccessRights (50), busy (51), unavailable (52), unwillingToPerform (53), loopDetect (54), -- 55-63 unused -- namingViolation (64), objectClassViolation (65), notAllowedOnNonLeaf (66), notAllowedOnRDN (67), entryAlreadyExists (68), objectClassModsProhibited (69), -- 70 reserved for CLDAP -- affectsMultipleDSAs (71), -- 72-79 unused -- other (80), ... }, matchedDN LDAPDN, diagnosticMessage LDAPString, referral [3] Referral OPTIONAL } """ componentType = NamedTypes(NamedType('resultCode', ResultCode()), NamedType('matchedDN', LDAPDN()), NamedType('diagnosticMessage', LDAPString()), OptionalNamedType('referral', Referral())) class Criticality(Boolean): """ criticality BOOLEAN DEFAULT FALSE """ defaultValue = False class ControlValue(OctetString): """ controlValue OCTET STRING """ encoding = 'utf-8' class Control(Sequence): """ Control ::= SEQUENCE { controlType LDAPOID, criticality BOOLEAN DEFAULT FALSE, controlValue OCTET STRING OPTIONAL } """ componentType = NamedTypes(NamedType('controlType', LDAPOID()), DefaultedNamedType('criticality', Criticality()), OptionalNamedType('controlValue', ControlValue())) class Controls(SequenceOf): """ Controls ::= SEQUENCE OF control Control """ tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0)) componentType = Control() class Scope(Enumerated): """ scope ENUMERATED { baseObject (0), singleLevel (1), wholeSubtree (2), """ namedValues = NamedValues(('baseObject', 0), ('singleLevel', 1), ('wholeSubtree', 2)) class DerefAliases(Enumerated): """ derefAliases ENUMERATED { neverDerefAliases (0), derefInSearching (1), derefFindingBaseObj (2), derefAlways (3) }, """ namedValues = NamedValues(('neverDerefAliases', 0), ('derefInSearching', 1), ('derefFindingBaseObj', 2), ('derefAlways', 3)) class TypesOnly(Boolean): """ typesOnly BOOLEAN """ pass class Selector(LDAPString): """ -- The LDAPString is constrained to -- in Section 4.5.1.8 """ # subtypeSpec = LDAPString.subtypeSpec + attributeSelectorConstraint pass class AttributeSelection(SequenceOf): """ AttributeSelection ::= SEQUENCE OF selector LDAPString -- The LDAPString is constrained to -- in Section 4.5.1.8 """ componentType = Selector() class MatchingRule(MatchingRuleId): """ matchingRule [1] MatchingRuleId """ tagSet = MatchingRuleId.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1)) class Type(AttributeDescription): """ type [2] AttributeDescription """ tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2)) class MatchValue(AssertionValue): """ matchValue [3] AssertionValue, """ tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 3)) class DnAttributes(Boolean): """ dnAttributes [4] BOOLEAN DEFAULT FALSE } """ tagSet = Boolean.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 4)) defaultValue = Boolean(False) class MatchingRuleAssertion(Sequence): """ MatchingRuleAssertion ::= SEQUENCE { matchingRule [1] MatchingRuleId OPTIONAL, type [2] AttributeDescription OPTIONAL, matchValue [3] AssertionValue, dnAttributes [4] BOOLEAN DEFAULT FALSE } """ componentType = NamedTypes(OptionalNamedType('matchingRule', MatchingRule()), OptionalNamedType('type', Type()), NamedType('matchValue', MatchValue()), DefaultedNamedType('dnAttributes', DnAttributes())) class Initial(AssertionValue): """ initial [0] AssertionValue, -- can occur at most once """ tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) class Any(AssertionValue): """ any [1] AssertionValue, """ tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1)) class Final(AssertionValue): """ final [1] AssertionValue, -- can occur at most once """ tagSet = AssertionValue.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 2)) class Substring(Choice): """ substring CHOICE { initial [0] AssertionValue, -- can occur at most once any [1] AssertionValue, final [2] AssertionValue } -- can occur at most once } """ componentType = NamedTypes(NamedType('initial', Initial()), NamedType('any', Any()), NamedType('final', Final())) class Substrings(SequenceOf): """ substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { ... } """ subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint componentType = Substring() class SubstringFilter(Sequence): """ SubstringFilter ::= SEQUENCE { type AttributeDescription, substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE { initial [0] AssertionValue, -- can occur at most once any [1] AssertionValue, final [2] AssertionValue } -- can occur at most once } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 4)) componentType = NamedTypes(NamedType('type', AttributeDescription()), NamedType('substrings', Substrings())) class And(SetOf): """ and [0] SET SIZE (1..MAX) OF filter Filter """ tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 0)) subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint class Or(SetOf): """ or [1] SET SIZE (1..MAX) OF filter Filter """ tagSet = SetOf.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 1)) subtypeSpec = SetOf.subtypeSpec + size1ToMaxConstraint class Not(Choice): """ not [2] Filter """ pass # defined after Filter definition to allow recursion class EqualityMatch(AttributeValueAssertion): """ equalityMatch [3] AttributeValueAssertion """ tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 3)) class GreaterOrEqual(AttributeValueAssertion): """ greaterOrEqual [5] AttributeValueAssertion """ tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 5)) class LessOrEqual(AttributeValueAssertion): """ lessOrEqual [6] AttributeValueAssertion """ tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 6)) class Present(AttributeDescription): """ present [7] AttributeDescription """ tagSet = AttributeDescription.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 7)) class ApproxMatch(AttributeValueAssertion): """ approxMatch [8] AttributeValueAssertion """ tagSet = AttributeValueAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 8)) class ExtensibleMatch(MatchingRuleAssertion): """ extensibleMatch [9] MatchingRuleAssertion """ tagSet = MatchingRuleAssertion.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatConstructed, 9)) class Filter(Choice): """ Filter ::= CHOICE { and [0] SET SIZE (1..MAX) OF filter Filter, or [1] SET SIZE (1..MAX) OF filter Filter, not [2] Filter, equalityMatch [3] AttributeValueAssertion, substrings [4] SubstringFilter, greaterOrEqual [5] AttributeValueAssertion, lessOrEqual [6] AttributeValueAssertion, present [7] AttributeDescription, approxMatch [8] AttributeValueAssertion, extensibleMatch [9] MatchingRuleAssertion, ... } """ componentType = NamedTypes(NamedType('and', And()), NamedType('or', Or()), NamedType('notFilter', Not()), NamedType('equalityMatch', EqualityMatch()), NamedType('substringFilter', SubstringFilter()), NamedType('greaterOrEqual', GreaterOrEqual()), NamedType('lessOrEqual', LessOrEqual()), NamedType('present', Present()), NamedType('approxMatch', ApproxMatch()), NamedType('extensibleMatch', ExtensibleMatch())) And.componentType = Filter() Or.componentType = Filter() Not.componentType = NamedTypes(NamedType('innerNotFilter', Filter())) Not.tagSet = Filter.tagSet.tagExplicitly(Tag(tagClassContext, tagFormatConstructed, 2)) # as per RFC4511 page 23 class PartialAttributeList(SequenceOf): """ PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute """ componentType = PartialAttribute() class Operation(Enumerated): """ operation ENUMERATED { add (0), delete (1), replace (2), ... } """ namedValues = NamedValues(('add', 0), ('delete', 1), ('replace', 2), ('increment', 3)) class Change(Sequence): """ change SEQUENCE { operation ENUMERATED { add (0), delete (1), replace (2), ... }, modification PartialAttribute } } """ componentType = NamedTypes(NamedType('operation', Operation()), NamedType('modification', PartialAttribute())) class Changes(SequenceOf): """ changes SEQUENCE OF change SEQUENCE """ componentType = Change() class DeleteOldRDN(Boolean): """ deleteoldrdn BOOLEAN """ pass class NewSuperior(LDAPDN): """ newSuperior [0] LDAPDN """ tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) class RequestName(LDAPOID): """ requestName [0] LDAPOID """ tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) class RequestValue(OctetString): """ requestValue [1] OCTET STRING """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1)) encoding = 'utf-8' class ResponseName(LDAPOID): """ responseName [10] LDAPOID """ tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 10)) class ResponseValue(OctetString): """ responseValue [11] OCTET STRING """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 11)) encoding = 'utf-8' class IntermediateResponseName(LDAPOID): """ responseName [0] LDAPOID """ tagSet = LDAPOID.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 0)) class IntermediateResponseValue(OctetString): """ responseValue [1] OCTET STRING """ tagSet = OctetString.tagSet.tagImplicitly(Tag(tagClassContext, tagFormatSimple, 1)) encoding = 'utf-8' # operations class BindRequest(Sequence): """ BindRequest ::= [APPLICATION 0] SEQUENCE { version INTEGER (1 .. 127), name LDAPDN, authentication AuthenticationChoice } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 0)) componentType = NamedTypes(NamedType('version', Version()), NamedType('name', LDAPDN()), NamedType('authentication', AuthenticationChoice())) class BindResponse(Sequence): """ BindResponse ::= [APPLICATION 1] SEQUENCE { COMPONENTS OF LDAPResult, serverSaslCreds [7] OCTET STRING OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 1)) componentType = NamedTypes(NamedType('resultCode', ResultCode()), NamedType('matchedDN', LDAPDN()), NamedType('diagnosticMessage', LDAPString()), OptionalNamedType('referral', Referral()), OptionalNamedType('serverSaslCreds', ServerSaslCreds())) class UnbindRequest(Null): """ UnbindRequest ::= [APPLICATION 2] NULL """ tagSet = Null.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 2)) class SearchRequest(Sequence): """ SearchRequest ::= [APPLICATION 3] SEQUENCE { baseObject LDAPDN, scope ENUMERATED { baseObject (0), singleLevel (1), wholeSubtree (2), ... }, derefAliases ENUMERATED { neverDerefAliases (0), derefInSearching (1), derefFindingBaseObj (2), derefAlways (3) }, sizeLimit INTEGER (0 .. maxInt), timeLimit INTEGER (0 .. maxInt), typesOnly BOOLEAN, filter Filter, attributes AttributeSelection } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 3)) componentType = NamedTypes(NamedType('baseObject', LDAPDN()), NamedType('scope', Scope()), NamedType('derefAliases', DerefAliases()), NamedType('sizeLimit', Integer0ToMax()), NamedType('timeLimit', Integer0ToMax()), NamedType('typesOnly', TypesOnly()), NamedType('filter', Filter()), NamedType('attributes', AttributeSelection())) class SearchResultReference(SequenceOf): """ SearchResultReference ::= [APPLICATION 19] SEQUENCE SIZE (1..MAX) OF uri URI """ tagSet = SequenceOf.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 19)) subtypeSpec = SequenceOf.subtypeSpec + size1ToMaxConstraint componentType = URI() class SearchResultEntry(Sequence): """ SearchResultEntry ::= [APPLICATION 4] SEQUENCE { objectName LDAPDN, attributes PartialAttributeList } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 4)) componentType = NamedTypes(NamedType('object', LDAPDN()), NamedType('attributes', PartialAttributeList())) class SearchResultDone(LDAPResult): """ SearchResultDone ::= [APPLICATION 5] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 5)) class ModifyRequest(Sequence): """ ModifyRequest ::= [APPLICATION 6] SEQUENCE { object LDAPDN, changes SEQUENCE OF change SEQUENCE { operation ENUMERATED { add (0), delete (1), replace (2), ... }, modification PartialAttribute } } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 6)) componentType = NamedTypes(NamedType('object', LDAPDN()), NamedType('changes', Changes())) class ModifyResponse(LDAPResult): """ ModifyResponse ::= [APPLICATION 7] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 7)) class AddRequest(Sequence): """ AddRequest ::= [APPLICATION 8] SEQUENCE { entry LDAPDN, attributes AttributeList } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 8)) componentType = NamedTypes(NamedType('entry', LDAPDN()), NamedType('attributes', AttributeList())) class AddResponse(LDAPResult): """ AddResponse ::= [APPLICATION 9] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 9)) class DelRequest(LDAPDN): """ DelRequest ::= [APPLICATION 10] LDAPDN """ tagSet = LDAPDN.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 10)) class DelResponse(LDAPResult): """ DelResponse ::= [APPLICATION 11] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 11)) class ModifyDNRequest(Sequence): """ ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { entry LDAPDN, newrdn RelativeLDAPDN, deleteoldrdn BOOLEAN, newSuperior [0] LDAPDN OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 12)) componentType = NamedTypes(NamedType('entry', LDAPDN()), NamedType('newrdn', RelativeLDAPDN()), NamedType('deleteoldrdn', DeleteOldRDN()), OptionalNamedType('newSuperior', NewSuperior())) class ModifyDNResponse(LDAPResult): """ ModifyDNResponse ::= [APPLICATION 13] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 13)) class CompareRequest(Sequence): """ CompareRequest ::= [APPLICATION 14] SEQUENCE { entry LDAPDN, ava AttributeValueAssertion } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 14)) componentType = NamedTypes(NamedType('entry', LDAPDN()), NamedType('ava', AttributeValueAssertion())) class CompareResponse(LDAPResult): """ CompareResponse ::= [APPLICATION 15] LDAPResult """ tagSet = LDAPResult.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 15)) class AbandonRequest(MessageID): """ AbandonRequest ::= [APPLICATION 16] MessageID """ tagSet = MessageID.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatSimple, 16)) class ExtendedRequest(Sequence): """ ExtendedRequest ::= [APPLICATION 23] SEQUENCE { requestName [0] LDAPOID, requestValue [1] OCTET STRING OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 23)) componentType = NamedTypes(NamedType('requestName', RequestName()), OptionalNamedType('requestValue', RequestValue())) class ExtendedResponse(Sequence): """ ExtendedResponse ::= [APPLICATION 24] SEQUENCE { COMPONENTS OF LDAPResult, responseName [10] LDAPOID OPTIONAL, responseValue [11] OCTET STRING OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 24)) componentType = NamedTypes(NamedType('resultCode', ResultCode()), NamedType('matchedDN', LDAPDN()), NamedType('diagnosticMessage', LDAPString()), OptionalNamedType('referral', Referral()), OptionalNamedType('responseName', ResponseName()), OptionalNamedType('responseValue', ResponseValue())) class IntermediateResponse(Sequence): """ IntermediateResponse ::= [APPLICATION 25] SEQUENCE { responseName [0] LDAPOID OPTIONAL, responseValue [1] OCTET STRING OPTIONAL } """ tagSet = Sequence.tagSet.tagImplicitly(Tag(tagClassApplication, tagFormatConstructed, 25)) componentType = NamedTypes(OptionalNamedType('responseName', IntermediateResponseName()), OptionalNamedType('responseValue', IntermediateResponseValue())) class ProtocolOp(Choice): """ protocolOp CHOICE { bindRequest BindRequest, bindResponse BindResponse, unbindRequest UnbindRequest, searchRequest SearchRequest, searchResEntry SearchResultEntry, searchResDone SearchResultDone, searchResRef SearchResultReference, modifyRequest ModifyRequest, modifyResponse ModifyResponse, addRequest AddRequest, addResponse AddResponse, delRequest DelRequest, delResponse DelResponse, modDNRequest ModifyDNRequest, modDNResponse ModifyDNResponse, compareRequest CompareRequest, compareResponse CompareResponse, abandonRequest AbandonRequest, extendedReq ExtendedRequest, extendedResp ExtendedResponse, ..., intermediateResponse IntermediateResponse } """ componentType = NamedTypes(NamedType('bindRequest', BindRequest()), NamedType('bindResponse', BindResponse()), NamedType('unbindRequest', UnbindRequest()), NamedType('searchRequest', SearchRequest()), NamedType('searchResEntry', SearchResultEntry()), NamedType('searchResDone', SearchResultDone()), NamedType('searchResRef', SearchResultReference()), NamedType('modifyRequest', ModifyRequest()), NamedType('modifyResponse', ModifyResponse()), NamedType('addRequest', AddRequest()), NamedType('addResponse', AddResponse()), NamedType('delRequest', DelRequest()), NamedType('delResponse', DelResponse()), NamedType('modDNRequest', ModifyDNRequest()), NamedType('modDNResponse', ModifyDNResponse()), NamedType('compareRequest', CompareRequest()), NamedType('compareResponse', CompareResponse()), NamedType('abandonRequest', AbandonRequest()), NamedType('extendedReq', ExtendedRequest()), NamedType('extendedResp', ExtendedResponse()), NamedType('intermediateResponse', IntermediateResponse())) class LDAPMessage(Sequence): """ LDAPMessage ::= SEQUENCE { messageID MessageID, protocolOp CHOICE { bindRequest BindRequest, bindResponse BindResponse, unbindRequest UnbindRequest, searchRequest SearchRequest, searchResEntry SearchResultEntry, searchResDone SearchResultDone, searchResRef SearchResultReference, modifyRequest ModifyRequest, modifyResponse ModifyResponse, addRequest AddRequest, addResponse AddResponse, delRequest DelRequest, delResponse DelResponse, modDNRequest ModifyDNRequest, modDNResponse ModifyDNResponse, compareRequest CompareRequest, compareResponse CompareResponse, abandonRequest AbandonRequest, extendedReq ExtendedRequest, extendedResp ExtendedResponse, ..., intermediateResponse IntermediateResponse }, controls [0] Controls OPTIONAL } """ componentType = NamedTypes(NamedType('messageID', MessageID()), NamedType('protocolOp', ProtocolOp()), OptionalNamedType('controls', Controls())) python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4512.py0000666000000000000000000006536612355103747021215 0ustar 00000000000000""" Created on 2013.09.11 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from os import linesep import re from .. import CLASS_ABSTRACT, CLASS_STRUCTURAL, CLASS_AUXILIARY, ATTRIBUTE_USER_APPLICATION, ATTRIBUTE_DIRECTORY_OPERATION, ATTRIBUTE_DISTRIBUTED_OPERATION, ATTRIBUTE_DSA_OPERATION from .oid import Oids, decode_oids, decode_syntax from ..core.exceptions import LDAPSchemaError def constant_to_class_kind(value): if value == CLASS_STRUCTURAL: return 'Structural' elif value == CLASS_ABSTRACT: return 'Abstract' elif value == CLASS_AUXILIARY: return 'Auxiliary' else: return 'unknown' def constant_to_attribute_usage(value): if value == ATTRIBUTE_USER_APPLICATION: return 'User Application' elif value == ATTRIBUTE_DIRECTORY_OPERATION: return "Directory operation" elif value == ATTRIBUTE_DISTRIBUTED_OPERATION: return 'Distributed operation' elif value == ATTRIBUTE_DSA_OPERATION: return 'DSA operation' else: return 'unknown' def attribute_usage_to_constant(value): if value == 'userApplications': return ATTRIBUTE_USER_APPLICATION elif value == 'directoryOperation': return ATTRIBUTE_DIRECTORY_OPERATION elif value == 'distributedOperation': return ATTRIBUTE_DISTRIBUTED_OPERATION elif value == 'dsaOperation': return ATTRIBUTE_DSA_OPERATION else: return 'unknown' def quoted_string_to_list(quoted_string): string = quoted_string.strip() if string[0] == '(' and string[-1] == ')': string = string[1:-1] elements = string.split("'") return [element.strip("'").strip() for element in elements if element.strip()] def oids_string_to_list(oid_string): string = oid_string.strip() if string[0] == '(' and string[-1] == ')': string = string[1:-1] elements = string.split('$') return [element.strip() for element in elements if element.strip()] def extension_to_tuple(extension_string): string = extension_string.strip() name, _, values = string.partition(' ') return name, quoted_string_to_list(values) def list_to_string(list_object): if not isinstance(list_object, (list, tuple)): return list_object r = '' for element in list_object: r += (list_to_string(element) if isinstance(element, (list, tuple)) else str(element)) + ', ' return r[:-2] if r else '' class DsaInfo(object): """ This class contains info about the ldap server (DSA) read from DSE as defined in RFC4512 and RFC3045. Unknown attributes are stored in the "other" dict """ def __init__(self, attributes): self.alt_servers = attributes.pop('altServer', None) self.naming_contexts = attributes.pop('namingContexts', None) self.supported_controls = decode_oids(attributes.pop('supportedControl', None)) self.supported_extensions = decode_oids(attributes.pop('supportedExtension', None)) self.supported_features = decode_oids(attributes.pop('supportedFeatures', None)) + decode_oids(attributes.pop('supportedCapabilities', None)) self.supported_ldap_versions = attributes.pop('supportedLDAPVersion', None) self.supported_sasl_mechanisms = attributes.pop('supportedSASLMechanisms', None) self.vendor_name = attributes.pop('vendorName', None) self.vendor_version = attributes.pop('vendorVersion', None) self.schema_entry = attributes.pop('subschemaSubentry', None) self.other = attributes def __str__(self): return self.__repr__() def __repr__(self): r = 'DSA info (from DSE):' + linesep r += (' Supported LDAP Versions: ' + ', '.join([s for s in self.supported_ldap_versions]) + linesep) if self.supported_ldap_versions else '' r += (' Naming Contexts:' + linesep + linesep.join([' ' + s for s in self.naming_contexts]) + linesep) if self.naming_contexts else '' r += (' Alternative Servers:' + linesep + linesep.join([' ' + s for s in self.alt_servers]) + linesep) if self.alt_servers else '' r += (' Supported Controls:' + linesep + linesep.join([' ' + str(s) for s in self.supported_controls]) + linesep) if self.supported_controls else '' r += (' Supported Extensions:' + linesep + linesep.join([' ' + str(s) for s in self.supported_extensions]) + linesep) if self.supported_extensions else '' r += (' Supported Features:' + linesep + linesep.join([' ' + str(s) for s in self.supported_features]) + linesep) if self.supported_features else '' r += (' Supported SASL Mechanisms:' + linesep + ' ' + ', '.join([s for s in self.supported_sasl_mechanisms]) + linesep) if self.supported_sasl_mechanisms else '' r += (' Schema Entry:' + linesep + linesep.join([' ' + s for s in self.schema_entry]) + linesep) if self.schema_entry else '' r += 'Other:' + linesep for k, v in self.other.items(): r += ' ' + k + ': ' + linesep if isinstance(v, (list, tuple)): r += linesep.join([' ' + str(s) for s in v]) + linesep else: r += v + linesep return r class SchemaInfo(object): """ This class contains info about the ldap server schema read from an entry (default entry is DSE) as defined in RFC4512. Unknown attributes are stored in the "other" dict """ def __init__(self, schema_entry, attributes): self.schema_entry = schema_entry self.create_time_stamp = attributes.pop('createTimestamp', None) self.modify_time_stamp = attributes.pop('modifyTimestamp', None) self.attribute_types = AttributeTypeInfo.from_definition(attributes.pop('attributeTypes', [])) self.object_classes = ObjectClassInfo.from_definition(attributes.pop('objectClasses', [])) self.matching_rules = MatchingRuleInfo.from_definition(attributes.pop('matchingRules', [])) self.matching_rule_uses = MatchingRuleUseInfo.from_definition(attributes.pop('matchingRuleUse', [])) self.dit_content_rules = DitContentRuleInfo.from_definition(attributes.pop('dITContentRules', [])) self.dit_structure_rules = DitStructureRuleInfo.from_definition(attributes.pop('dITStructureRules', [])) self.name_forms = NameFormInfo.from_definition(attributes.pop('nameForms', [])) self.ldap_syntaxes = LdapSyntaxInfo.from_definition(attributes.pop('ldapSyntaxes', [])) self.other = attributes # remaining attributes not in RFC4512 def __str__(self): return self.__repr__() def __repr__(self): r = 'DSA Schema from: ' + self.schema_entry + linesep r += (' Attribute types:' + linesep + ' ' + ', '.join([str(self.attribute_types[s]) for s in self.attribute_types]) + linesep) if self.attribute_types else '' r += (' Object classes:' + linesep + ' ' + ', '.join([str(self.object_classes[s]) for s in self.object_classes]) + linesep) if self.object_classes else '' r += (' Matching rules:' + linesep + ' ' + ', '.join([str(self.matching_rules[s]) for s in self.matching_rules]) + linesep) if self.matching_rules else '' r += (' Matching rule uses:' + linesep + ' ' + ', '.join([str(self.matching_rule_uses[s]) for s in self.matching_rule_uses]) + linesep) if self.matching_rule_uses else '' r += (' DIT content rule:' + linesep + ' ' + ', '.join([str(self.dit_content_rules[s]) for s in self.dit_content_rules]) + linesep) if self.dit_content_rules else '' r += (' DIT structure rule:' + linesep + ' ' + ', '.join([str(self.dit_structure_rules[s]) for s in self.dit_structure_rules]) + linesep) if self.dit_structure_rules else '' r += (' Name forms:' + linesep + ' ' + ', '.join([str(self.name_forms[s]) for s in self.name_forms]) + linesep) if self.name_forms else '' r += (' LDAP syntaxes:' + linesep + ' ' + ', '.join([str(self.ldap_syntaxes[s]) for s in self.ldap_syntaxes]) + linesep) if self.ldap_syntaxes else '' r += 'Other:' + linesep for k, v in self.other.items(): r += ' ' + k + ': ' + linesep r += (linesep.join([' ' + str(s) for s in v])) if isinstance(v, (list, tuple)) else v + linesep return r class BaseObjectInfo(object): """ Base class for objects defined in the schema as per RFC4512 """ def __init__(self, oid=None, name=None, description=None, obsolete=False, extensions=None, experimental=None, definition=None): self.oid = oid self.name = name self.description = description self.obsolete = obsolete self.extensions = extensions self.experimental = experimental self.raw_definition = definition self._oid_info = None @property def oid_info(self): if self._oid_info is None and self.oid: self._oid_info = Oids.get(self.oid, '') return self._oid_info if self._oid_info else None def __str__(self): return self.__repr__() def __repr__(self): r = ': ' + self.oid r += ' [OBSOLETE]' if self.obsolete else '' r += (linesep + ' Short name: ' + list_to_string(self.name)) if self.name else '' r += (linesep + ' Description: ' + self.description) if self.description else '' r += '<__desc__>' r += (linesep + ' Extensions:' + linesep + linesep.join([' ' + s[0] + ': ' + list_to_string(s[1]) for s in self.extensions])) if self.extensions else '' r += (linesep + ' Experimental:' + linesep + linesep.join([' ' + s[0] + ': ' + list_to_string(s[1]) for s in self.experimental])) if self.experimental else '' r += (linesep + ' OidInfo: ' + str(self.oid_info)) if self.oid_info else '' r += linesep return r @classmethod def from_definition(cls, definitions): if not definitions: return None ret_dict = dict() for object_definition in definitions: if [object_definition[0] == ')' and object_definition[:-1] == ')']: if cls is MatchingRuleInfo: pattern = '| SYNTAX ' elif cls is ObjectClassInfo: pattern = '| SUP | ABSTRACT| STRUCTURAL| AUXILIARY| MUST | MAY ' elif cls is AttributeTypeInfo: pattern = '| SUP | EQUALITY | ORDERING | SUBSTR | SYNTAX | SINGLE-VALUE| COLLECTIVE| NO-USER-MODIFICATION| USAGE ' elif cls is MatchingRuleUseInfo: pattern = '| APPLIES ' elif cls is DitContentRuleInfo: pattern = '| AUX ' elif cls is LdapSyntaxInfo: pattern = '' elif cls is DitContentRuleInfo: pattern = '| AUX | MUST | MAY | NOT ' elif cls is DitStructureRuleInfo: pattern = '| FORM | SUP ' elif cls is NameFormInfo: pattern = '| OC | MUST | MAY ' else: raise LDAPSchemaError('unknown schema definition class') splitted = re.split('( NAME | DESC | OBSOLETE| X-| E-' + pattern + ')', object_definition[1:-1]) values = splitted[::2] separators = splitted[1::2] separators.insert(0, 'OID') defs = list(zip(separators, values)) object_def = cls() for d in defs: key = d[0].strip() value = d[1].strip() if key == 'OID': object_def.oid = value elif key == 'NAME': object_def.name = quoted_string_to_list(value) elif key == 'DESC': object_def.description = value.strip("'") elif key == 'OBSOLETE': object_def.obsolete = True elif key == 'SYNTAX': object_def.syntax = oids_string_to_list(value) elif key == 'SUP': object_def.superior = oids_string_to_list(value) elif key == 'ABSTRACT': object_def.kind = CLASS_ABSTRACT elif key == 'STRUCTURAL': object_def.kind = CLASS_STRUCTURAL elif key == 'AUXILIARY': object_def.kind = CLASS_AUXILIARY elif key == 'MUST': object_def.must_contain = oids_string_to_list(value) elif key == 'MAY': object_def.may_contain = oids_string_to_list(value) elif key == 'EQUALITY': object_def.equality = oids_string_to_list(value) elif key == 'ORDERING': object_def.ordering = oids_string_to_list(value) elif key == 'SUBSTR': object_def.substr = oids_string_to_list(value) elif key == 'SINGLE-VALUE': object_def.single_value = True elif key == 'COLLECTIVE': object_def.collective = True elif key == 'NO-USER-MODIFICATION': object_def.no_user_modification = True elif key == 'USAGE': object_def.usage = attribute_usage_to_constant(value) elif key == 'APPLIES': object_def.apply_to = oids_string_to_list(value) elif key == 'AUX': object_def.auxiliary_classes = oids_string_to_list(value) elif key == 'FORM': object_def.name_form = oids_string_to_list(value) elif key == 'OC': object_def.object_class = oids_string_to_list(value) elif key == 'X-': if not object_def.extensions: object_def.extensions = [] object_def.extensions.append(extension_to_tuple('X-' + value)) elif key == 'E-': if not object_def.experimental: object_def.experimental = [] object_def.experimental.append(extension_to_tuple('E-' + value)) else: raise LDAPSchemaError('malformed schema definition key:' + key) object_def.raw_definition = object_definition if hasattr(object_def, 'syntax') and object_def.syntax and len(object_def.syntax) == 1: object_def.syntax = object_def.syntax[0] if hasattr(object_def, 'name') and object_def.name: for name in object_def.name: ret_dict[name.lower()] = object_def else: ret_dict[object_def.oid] = object_def else: raise LDAPSchemaError('malformed schema definition') return ret_dict class MatchingRuleInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.3) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, syntax=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.syntax = syntax def __repr__(self): r = (linesep + ' Syntax: ' + list_to_string(self.syntax)) if self.syntax else '' return 'Matching rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class MatchingRuleUseInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.4) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, apply_to=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.apply_to = apply_to def __repr__(self): r = (linesep + ' Apply to: ' + list_to_string(self.apply_to)) if self.apply_to else '' return 'Matching rule use' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class ObjectClassInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.1) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, superior=None, kind=None, must_contain=None, may_contain=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.superior = superior self.kind = kind self.must_contain = must_contain self.may_contain = may_contain def __repr__(self): r = '' r += (linesep + ' Type: ' + constant_to_class_kind(self.kind)) if isinstance(self.kind, int) else '' r += (linesep + ' Must contain attributes: ' + list_to_string(self.must_contain)) if self.must_contain else '' r += (linesep + ' May contain attributes: ' + list_to_string(self.may_contain)) if self.may_contain else '' return 'Object Class' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class AttributeTypeInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.2) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, superior=None, equality=None, ordering=None, substring=None, syntax=None, single_value=False, collective=False, no_user_modification=False, usage=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.superior = superior self.equality = equality self.ordering = ordering self.substring = substring self.syntax = syntax self.single_value = single_value self.collective = collective self.no_user_modification = no_user_modification self.usage = usage def __repr__(self): r = '' r += linesep + ' Single Value: True' if self.single_value else '' r += linesep + ' Collective: True' if self.collective else '' r += linesep + ' No user modification: True' if self.no_user_modification else '' r += (linesep + ' Usage: ' + constant_to_attribute_usage(self.usage)) if self.usage else '' r += (linesep + ' Equality rule: ' + list_to_string(self.equality)) if self.equality else '' r += (linesep + ' Ordering rule: ' + list_to_string(self.ordering)) if self.ordering else '' r += (linesep + ' Substring rule: ' + list_to_string(self.substring)) if self.substring else '' r += (linesep + ' Syntax: ' + (self.syntax + ' - ' + str(decode_syntax(self.syntax)))) if self.syntax else '' return 'Attribute type' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class LdapSyntaxInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.5) """ def __init__(self, oid=None, description=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=None, description=description, obsolete=False, extensions=extensions, experimental=experimental, definition=definition) def __repr__(self): return 'LDAP syntax' + BaseObjectInfo.__repr__(self).replace('<__desc__>', '') class DitContentRuleInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.6) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, auxiliary_classes=None, must_contain=None, may_contain=None, not_contains=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.auxiliary_classes = auxiliary_classes self.must_contain = must_contain self.may_contain = may_contain self.not_contains = not_contains def __repr__(self): r = (linesep + ' Auxiliary classes: ' + list_to_string(self.auxiliary_classes)) if self.auxiliary_classes else '' r += (linesep + ' Must contain: ' + list_to_string(self.must_contain)) if self.must_contain else '' r += (linesep + ' May contain: ' + list_to_string(self.may_contain)) if self.may_contain else '' r += (linesep + ' Not contains: ' + list_to_string(self.not_contains)) if self.not_contains else '' return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class DitStructureRuleInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.7.1) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, name_form=None, superior=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.superior = superior self.name_form = name_form def __repr__(self): r = (linesep + ' Superior rules: ' + list_to_string(self.superior)) if self.superior else '' r += (linesep + ' Name form: ' + list_to_string(self.name_form)) if self.name_form else '' return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) class NameFormInfo(BaseObjectInfo): """ As per RFC 4512 (4.1.7.2) """ def __init__(self, oid=None, name=None, description=None, obsolete=False, object_class=None, must_contain=None, may_contain=None, extensions=None, experimental=None, definition=None): BaseObjectInfo.__init__(self, oid=oid, name=name, description=description, obsolete=obsolete, extensions=extensions, experimental=experimental, definition=definition) self.object_class = object_class self.must_contain = must_contain self.may_contain = may_contain def __repr__(self): r = (linesep + ' Object class: ' + self.object_class) if self.object_class else '' r += (linesep + ' Must contain: ' + list_to_string(self.must_contain)) if self.must_contain else '' r += (linesep + ' May contain: ' + list_to_string(self.may_contain)) if self.may_contain else '' return 'DIT content rule' + BaseObjectInfo.__repr__(self).replace('<__desc__>', r) python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/rfc4532.py0000666000000000000000000000206312355106663021200 0ustar 00000000000000""" Created on 2014.06.30 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from pyasn1.type.univ import OctetString from pyasn1.type.tag import Tag, tagFormatSimple, tagClassContext class AuthzId(OctetString): tagSet = OctetString.tagSet.tagExplicitly(Tag(tagClassContext, tagFormatSimple, 4)) encoding = 'utf-8'python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/0000777000000000000000000000000012355117540020473 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/digestMd5.py0000666000000000000000000001022112355103747022672 0ustar 00000000000000""" Created on 2014.01.04 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from binascii import hexlify import hashlib import hmac from .sasl import abort_sasl_negotiation, send_sasl_negotiation, random_hex_string def md5_h(value): if not isinstance(value, bytes): value = value.encode() return hashlib.md5(value).digest() def md5_kd(k, s): if not isinstance(k, bytes): k = k.encode() if not isinstance(s, bytes): s = s.encode() return md5_h(k + b':' + s) def md5_hex(value): if not isinstance(value, bytes): value = value.encode() return hexlify(value) def md5_hmac(k, s): if not isinstance(k, bytes): k = k.encode() if not isinstance(s, bytes): s = s.encode() return hmac.new(k, s).hexdigest() def sasl_digest_md5(connection, controls): # sasl_credential must be a tuple made up of the following elements: (realm, user, password, authorization_id) # if realm is None will be used the realm received from the server, if available if not isinstance(connection.sasl_credentials, tuple) or not len(connection.sasl_credentials) == 4: return None # step One of RFC2831 result = send_sasl_negotiation(connection, controls, None) if 'saslCreds' in result and result['saslCreds'] != 'None': server_directives = dict((attr[0], attr[1].strip('"')) for attr in [line.split('=') for line in result['saslCreds'].split(',')]) # convert directives to dict, unquote values else: return None if 'realm' not in server_directives or 'nonce' not in server_directives or 'algorithm' not in server_directives: # mandatory directives, as per RFC2831 abort_sasl_negotiation(connection, controls) return None # step Two of RFC2831 charset = server_directives['charset'] if 'charset' in server_directives and server_directives['charset'].lower() == 'utf-8' else 'iso8859-1' user = connection.sasl_credentials[1].encode(charset) realm = (connection.sasl_credentials[0] if connection.sasl_credentials[0] else (server_directives['realm'] if 'realm' in server_directives else '')).encode(charset) password = connection.sasl_credentials[2].encode(charset) authz_id = connection.sasl_credentials[3].encode(charset) if connection.sasl_credentials[3] else b'' nonce = server_directives['nonce'].encode(charset) cnonce = random_hex_string(16).encode(charset) uri = b'ldap/' qop = b'auth' digest_response = b'username="' + user + b'",' digest_response += b'realm="' + realm + b'",' digest_response += b'nonce="' + nonce + b'",' digest_response += b'cnonce="' + cnonce + b'",' digest_response += b'digest-uri="' + uri + b'",' digest_response += b'qop=' + qop + b',' digest_response += b'nc=00000001' + b',' if charset == 'utf-8': digest_response += b'charset="utf-8",' a0 = md5_h(b':'.join([user, realm, password])) a1 = b':'.join([a0, nonce, cnonce, authz_id]) if authz_id else b':'.join([a0, nonce, cnonce]) a2 = b'AUTHENTICATE:' + uri + (':00000000000000000000000000000000' if qop in [b'auth-int', b'auth-conf'] else b'') digest_response += b'response="' + md5_hex(md5_kd(md5_hex(md5_h(a1)), b':'.join([nonce, b'00000001', cnonce, qop, md5_hex(md5_h(a2))]))) + b'"' result = send_sasl_negotiation(connection, controls, digest_response) return result python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/external.py0000666000000000000000000000177312355103747022703 0ustar 00000000000000""" Created on 2014.01.04 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from .sasl import send_sasl_negotiation def sasl_external(connection, controls): result = send_sasl_negotiation(connection, controls, connection.sasl_credentials) return result python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/sasl.py0000666000000000000000000001641012355103747022015 0ustar 00000000000000""" Created on 2013.09.11 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ import stringprep from unicodedata import ucd_3_2_0 as unicode32 from os import urandom from binascii import hexlify from ... import AUTH_SASL, RESULT_AUTH_METHOD_NOT_SUPPORTED from ...core.exceptions import LDAPSASLPrepError, LDAPPasswordIsMandatoryError def sasl_prep(data): """ implement SASLPrep profile as per RFC4013: it defines the "SASLprep" profile of the "stringprep" algorithm [StringPrep]. The profile is designed for use in Simple Authentication and Security Layer ([SASL]) mechanisms, such as [PLAIN], [CRAM-MD5], and [DIGEST-MD5]. It may be applicable where simple user names and passwords are used. This profile is not intended for use in preparing identity strings that are not simple user names (e.g., email addresses, domain names, distinguished names), or where identity or password strings that are not character data, or require different handling (e.g., case folding). """ # mapping prepared_data = '' for c in data: if stringprep.in_table_c12(c): # non-ASCII space characters [StringPrep, C.1.2] that can be mapped to SPACE (U+0020) prepared_data += ' ' elif stringprep.in_table_b1(c): # the "commonly mapped to nothing" characters [StringPrep, B.1] that can be mapped to nothing. pass else: prepared_data += c # normalizing # This profile specifies using Unicode normalization form KC # The repertoire is Unicode 3.2 as per RFC 4013 (2) prepared_data = unicode32.normalize('NFKC', prepared_data) if not prepared_data: raise LDAPSASLPrepError('SASLprep error: unable to normalize string') # prohibit for c in prepared_data: if stringprep.in_table_c12(c): # Non-ASCII space characters [StringPrep, C.1.2] raise LDAPSASLPrepError('SASLprep error: non-ASCII space character present') elif stringprep.in_table_c21(c): # ASCII control characters [StringPrep, C.2.1] raise LDAPSASLPrepError('SASLprep error: ASCII control character present') elif stringprep.in_table_c22(c): # Non-ASCII control characters [StringPrep, C.2.2] raise LDAPSASLPrepError('SASLprep error: non-ASCII control character present') elif stringprep.in_table_c3(c): # Private Use characters [StringPrep, C.3] raise LDAPSASLPrepError('SASLprep error: private character present') elif stringprep.in_table_c4(c): # Non-character code points [StringPrep, C.4] raise LDAPSASLPrepError('SASLprep error: non-character code point present') elif stringprep.in_table_c5(c): # Surrogate code points [StringPrep, C.5] raise LDAPSASLPrepError('SASLprep error: surrogate code point present') elif stringprep.in_table_c6(c): # Inappropriate for plain text characters [StringPrep, C.6] raise LDAPSASLPrepError('SASLprep error: inappropriate for plain text character present') elif stringprep.in_table_c7(c): # Inappropriate for canonical representation characters [StringPrep, C.7] raise LDAPSASLPrepError('SASLprep error: inappropriate for canonical representation character present') elif stringprep.in_table_c8(c): # Change display properties or deprecated characters [StringPrep, C.8] raise LDAPSASLPrepError('SASLprep error: change display property or deprecated character present') elif stringprep.in_table_c9(c): # Tagging characters [StringPrep, C.9] raise LDAPSASLPrepError('SASLprep error: tagging character present') # check bidi # if a string contains any r_and_al_cat character, the string MUST NOT contain any l_cat character. flag_r_and_al_cat = False flag_l_cat = False for c in prepared_data: if stringprep.in_table_d1(c): flag_r_and_al_cat = True elif stringprep.in_table_d2(c): flag_l_cat = True if flag_r_and_al_cat and flag_l_cat: raise LDAPSASLPrepError('SASLprep error: string cannot contain (R or AL) and L bidirectional chars') # If a string contains any r_and_al_cat character, a r_and_al_cat character MUST be the first character of the string # and a r_and_al_cat character MUST be the last character of the string. if flag_r_and_al_cat and not stringprep.in_table_d1(prepared_data[0]) and not stringprep.in_table_d2(prepared_data[-1]): raise LDAPSASLPrepError('r_and_al_cat character present, must be first and last character of the string') return prepared_data def validate_simple_password(password): """ validate simple password as per RFC4013 using sasl_prep: """ if password == '' or password is None: raise LDAPPasswordIsMandatoryError("simple password can't be empty") if not isinstance(password, bytes): # bytes are returned raw, as per RFC (4.2) password = sasl_prep(password) return password # def addSaslCredentialsToBindRequest(request, mechanism, credentials): # sasl_credentials = SaslCredentials() # sasl_credentials['mechanism'] = mechanism # if credentials: # sasl_credentials['credentials'] = credentials # request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_credentials) # # return request def abort_sasl_negotiation(connection, controls): from ...operation.bind import bind_operation request = bind_operation(connection.version, AUTH_SASL, None, None, '', None) response = connection.post_send_single_response(connection.send('bindRequest', request, controls)) result = connection.get_response(response)[0][0] if isinstance(response, int) else connection.result return True if result['result'] == RESULT_AUTH_METHOD_NOT_SUPPORTED else False def send_sasl_negotiation(connection, controls, payload): from ...operation.bind import bind_operation request = bind_operation(connection.version, AUTH_SASL, None, None, connection.sasl_mechanism, payload) response = connection.post_send_single_response(connection.send('bindRequest', request, controls)) result = connection.get_response(response)[1] if isinstance(response, int) else connection.result return result def random_hex_string(size): return str(hexlify(urandom(size)).decode('ascii')) # str fix for Python 2 python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/sasl/__init__.py0000666000000000000000000000000012355103747022576 0ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/protocol/__init__.py0000666000000000000000000000000012355103747021634 0ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/0000777000000000000000000000000012355117540017532 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/asyncThreaded.py0000666000000000000000000002016212355103747022667 0ustar 00000000000000""" Created on 2013.07.15 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from threading import Thread, Lock from pyasn1.codec.ber import decoder from .. import RESPONSE_COMPLETE, SOCKET_SIZE, RESULT_REFERRAL from ..core.exceptions import LDAPSSLConfigurationError, LDAPStartTLSError from ..strategy.baseStrategy import BaseStrategy from ..protocol.rfc4511 import LDAPMessage # noinspection PyProtectedMember class AsyncThreadedStrategy(BaseStrategy): """ This strategy is asynchronous. You send the request and get the messageId of the request sent Receiving data from socket is managed in a separated thread in a blocking mode Requests return an int value to indicate the messageId of the requested Operation You get the response with get_response, it has a timeout to wait for response to appear Connection.response will contain the whole LDAP response for the messageId requested in a dict form Connection.request will contain the result LDAP message in a dict form Response appear in strategy._responses dictionary """ # noinspection PyProtectedMember class ReceiverSocketThread(Thread): """ The thread that actually manage the receiver socket """ def __init__(self, ldap_connection): Thread.__init__(self) self.connection = ldap_connection def run(self): """ Wait for data on socket, compute the length of the message and wait for enough bytes to decode the message Message are appended to strategy._responses """ unprocessed = b'' get_more_data = True listen = True data = b'' while listen: if get_more_data: try: data = self.connection.socket.recv(SOCKET_SIZE) except OSError: listen = False if len(data) > 0: unprocessed += data data = b'' else: listen = False length = BaseStrategy.compute_ldap_message_size(unprocessed) if length == -1 or len(unprocessed) < length: get_more_data = True elif len(unprocessed) >= length: # add message to message list if self.connection._usage: self.connection._usage.received_message(length) ldap_resp = decoder.decode(unprocessed[:length], asn1Spec=LDAPMessage())[0] message_id = int(ldap_resp['messageID']) dict_response = BaseStrategy.decode_response(ldap_resp) if dict_response['type'] == 'extendedResp' and dict_response['responseName'] == '1.3.6.1.4.1.1466.20037': if dict_response['result'] == 0: # StartTls in progress if self.connection.server.tls: self.connection.server.tls._start_tls(self.connection) else: self.connection.last_error = 'no Tls defined in Server' raise LDAPSSLConfigurationError(self.connection.last_error) else: self.connection.last_error = 'asynchronous StartTls failed' raise LDAPStartTLSError(self.connection.last_error) if message_id != 0: # 0 is reserved for 'Unsolicited Notification' from server as per RFC4511 (paragraph 4.4) with self.connection.strategy.lock: if message_id in self.connection.strategy._responses: self.connection.strategy._responses[message_id].append(dict_response) else: self.connection.strategy._responses[message_id] = [dict_response] if dict_response['type'] not in ['searchResEntry', 'searchResRef', 'intermediateResponse']: self.connection.strategy._responses[message_id].append(RESPONSE_COMPLETE) unprocessed = unprocessed[length:] get_more_data = False if unprocessed else True listen = True if self.connection.listening or unprocessed else False else: # Unsolicited Notification if dict_response['responseName'] == '1.3.6.1.4.1.1466.20036': # Notice of Disconnection as per RFC4511 (paragraph 4.4.1) listen = False self.connection.strategy.close() def __init__(self, ldap_connection): BaseStrategy.__init__(self, ldap_connection) self.sync = False self.no_real_dsa = False self.pooled = False self.has_stream_capapbility = False self._responses = None self.receiver = None self.lock = Lock() def open(self, reset_usage=True): """ Open connection and start listen on the socket in a different thread """ with self.lock: BaseStrategy.open(self, reset_usage=True) self._responses = dict() self.connection.refresh_dsa_info() def close(self): """ Close connection and stop socket thread """ with self.lock: BaseStrategy.close(self) def post_send_search(self, message_id): """ Clears connection.response and returns messageId """ self.connection.response = None self.connection.result = message_id return message_id def post_send_single_response(self, message_id): """ Clears connection.response and returns messageId. """ self.connection.response = None self.connection.result = message_id return message_id def _start_listen(self): """ Start thread in daemon mode """ if not self.connection.listening: self.receiver = AsyncThreadedStrategy.ReceiverSocketThread(self.connection) self.connection.listening = True self.receiver.daemon = True self.receiver.start() def _get_response(self, message_id): """ Performs the capture of LDAP response for this strategy Checks lock to avoid race condition with receiver thread """ with self.lock: responses = self._responses.pop(message_id) if message_id in self._responses and self._responses[message_id][-1] == RESPONSE_COMPLETE else None if responses is not None and responses[-2]['result'] == RESULT_REFERRAL: if self.connection._usage: self.connection._usage.referrals_followed += 1 if self.connection.auto_referrals: ref_response, ref_result = self.do_operation_on_referral(self._outstanding[message_id], responses[-2]['referrals']) if ref_response is not None: responses = ref_response + [ref_result] responses.append(RESPONSE_COMPLETE) elif ref_result is not None: responses = [ref_result, RESPONSE_COMPLETE] self._referrals = [] return responses python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/baseStrategy.py0000666000000000000000000006677512355107541022566 0ustar 00000000000000""" Created on 15/lug/2013 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ import socket from time import sleep from random import choice from pyasn1.codec.ber import encoder, decoder from .. import SESSION_TERMINATED_BY_SERVER, RESPONSE_SLEEPTIME, RESPONSE_WAITING_TIMEOUT, SEARCH_SCOPE_BASE_OBJECT, SEARCH_SCOPE_WHOLE_SUBTREE, SEARCH_SCOPE_SINGLE_LEVEL, STRATEGY_SYNC, AUTH_ANONYMOUS, DO_NOT_RAISE_EXCEPTIONS from ..core.exceptions import LDAPOperationResult, LDAPSASLBindInProgressError, LDAPSocketOpenError, LDAPSessionTerminatedByServer, LDAPUnknownResponseError, LDAPUnknownRequestError, LDAPReferralError, communication_exception_factory, \ LDAPSocketSendError, LDAPExceptionError, LDAPSocketCloseError from ..protocol.rfc4511 import LDAPMessage, ProtocolOp, MessageID from ..operation.add import add_response_to_dict, add_request_to_dict from ..operation.modify import modify_request_to_dict, modify_response_to_dict from ..operation.search import search_result_reference_response_to_dict, search_result_done_response_to_dict, search_result_entry_response_to_dict, search_request_to_dict from ..operation.bind import bind_response_to_dict, bind_request_to_dict from ..operation.compare import compare_response_to_dict, compare_request_to_dict from ..operation.extended import extended_request_to_dict, extended_response_to_dict, intermediate_response_to_dict from ..core.server import Server from ..operation.modifyDn import modify_dn_request_to_dict, modify_dn_response_to_dict from ..operation.delete import delete_response_to_dict, delete_request_to_dict from ..protocol.convert import prepare_changes_for_request, build_controls_list from ..operation.abandon import abandon_request_to_dict from ..core.tls import Tls from ..protocol.oid import Oids from ..protocol.rfc2696 import RealSearchControlValue # noinspection PyProtectedMember class BaseStrategy(object): """ Base class for connection strategy """ def __init__(self, ldap_connection): self.connection = ldap_connection self._outstanding = dict() self._referrals = [] self.sync = None # indicates a synchronous connection self.no_real_dsa = None # indicates a connection to a fake LDAP server self.pooled = None # Indicates a connection with a connection pool self.can_stream = False # indicate if a strategy keep a stream of responses (i.e. LDIFProducer can accumulate responses with a single header). Stream must be initilized and closed in _start_listen() and _stop_listen() def open(self, reset_usage=True): """ Open a socket to a server. Choose a server from the server pool if available """ if self.connection.lazy and not self.connection._executing_deferred: self.connection._deferred_open = True self.connection.closed = False else: if not self.connection.closed and not self.connection._executing_deferred: # try to close connection if still open self.close() self._outstanding = dict() if self.connection._usage: if reset_usage or not self.connection._usage.initial_connection_start_time: self.connection._usage.start() if self.connection.server_pool: new_server = self.connection.server_pool.get_server(self.connection) # get a server from the server_pool if available if self.connection.server != new_server: self.connection.server = new_server if self.connection._usage: self.connection._usage.servers_from_pool += 1 if not self.no_real_dsa: self._open_socket(self.connection.server.ssl) self.connection._deferred_open = False self._start_listen() def close(self): """ Close connection """ if self.connection.lazy and not self.connection._executing_deferred and (self.connection._deferred_bind or self.connection._deferred_open): self.connection.listening = False self.connection.closed = True else: if not self.connection.closed: self._stop_listen() if not self. no_real_dsa: self._close_socket() self.connection.bound = False self.connection.request = None self.connection.response = None self.connection.tls_started = False self._outstanding = dict() self._referrals = [] if self.connection._usage: self.connection._usage.stop() def _open_socket(self, use_ssl=False): """ Tries to open and connect a socket to a Server raise LDAPExceptionError if unable to open or connect socket """ exc = None try: self.connection.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except Exception as e: self.connection.last_error = 'socket creation error: ' + str(e) exc = e if exc: raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error) try: self.connection.socket.connect((self.connection.server.host, self.connection.server.port)) except socket.error as e: self.connection.last_error = 'socket connection error: ' + str(e) exc = e if exc: raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error) if use_ssl: try: self.connection.server.tls.wrap_socket(self.connection, do_handshake=True) if self.connection._usage: self.connection._usage.wrapped_sockets += 1 except Exception as e: self.connection.last_error = 'socket ssl wrapping error: ' + str(e) exc = e if exc: raise communication_exception_factory(LDAPSocketOpenError, exc)(self.connection.last_error) if self.connection._usage: self.connection._usage.opened_sockets += 1 self.connection.closed = False def _close_socket(self): """ Try to close a socket raise LDAPExceptionError if unable to close socket """ exc = None try: self.connection.socket.shutdown(socket.SHUT_RDWR) self.connection.socket.close() except Exception as e: self.connection.last_error = 'socket closing error' + str(e) exc = e if exc: raise communication_exception_factory(LDAPSocketCloseError, exc)(self.connection.last_error) self.connection.socket = None self.connection.closed = True if self.connection._usage: self.connection._usage.closed_sockets += 1 def _stop_listen(self): self.connection.listening = False def send(self, message_type, request, controls=None): """ Send an LDAP message Returns the message_id """ exc = None self.connection.request = None if self.connection.listening: if self.connection.sasl_in_progress and message_type not in ['bindRequest']: # as per RFC4511 (4.2.1) self.connection.last_error = 'cannot send operation requests while SASL bind is in progress' raise LDAPSASLBindInProgressError(self.connection.last_error) message_id = self.connection.server.next_message_id() ldap_message = LDAPMessage() ldap_message['messageID'] = MessageID(message_id) ldap_message['protocolOp'] = ProtocolOp().setComponentByName(message_type, request) message_controls = build_controls_list(controls) if message_controls is not None: ldap_message['controls'] = message_controls try: encoded_message = encoder.encode(ldap_message) self.connection.socket.sendall(encoded_message) except socket.error as e: self.connection.last_error = 'socket sending error' + str(e) encoded_message = None exc = e if exc: raise communication_exception_factory(LDAPSocketSendError, exc)(self.connection.last_error) self.connection.request = BaseStrategy.decode_request(ldap_message) self.connection.request['controls'] = controls self._outstanding[message_id] = self.connection.request if self.connection._usage: self.connection._usage.transmitted_message(self.connection.request, len(encoded_message)) else: self.connection.last_error = 'unable to send message, socket is not open' raise LDAPSocketOpenError(self.connection.last_error) return message_id def get_response(self, message_id, timeout=RESPONSE_WAITING_TIMEOUT): """ Get response LDAP messages Responses are returned by the underlying connection strategy Check if message_id LDAP message is still outstanding and wait for timeout to see if it appears in _get_response Result is stored in connection.result Responses without result is stored in connection.response A tuple (responses, result) is returned """ response = None result = None if self._outstanding and message_id in self._outstanding: while timeout >= 0: # waiting for completed message to appear in responses responses = self._get_response(message_id) if responses == SESSION_TERMINATED_BY_SERVER: try: # try to close the session but don't raise any error if server has already closed the session self.close() except (socket.error, LDAPExceptionError): pass self.connection.last_error = 'session terminated by server' raise LDAPSessionTerminatedByServer(self.connection.last_error) if not responses: sleep(RESPONSE_SLEEPTIME) timeout -= RESPONSE_SLEEPTIME else: if responses: self._outstanding.pop(message_id) result = responses[-2] response = responses[:-2] self.connection.result = result self.connection.response = None break if self.connection.raise_exceptions and result and result['result'] not in DO_NOT_RAISE_EXCEPTIONS: raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'], response=response) return response, result @classmethod def compute_ldap_message_size(cls, data): """ Compute LDAP Message size according to BER definite length rules Returns -1 if too few data to compute message length """ if isinstance(data, str): # fix for Python 2, data is string not bytes data = bytearray(data) # Python 2 bytearray is equivalent to Python 3 bytes ret_value = -1 if len(data) > 2: if data[1] <= 127: # BER definite length - short form. Highest bit of byte 1 is 0, message length is in the last 7 bits - Value can be up to 127 bytes long ret_value = data[1] + 2 else: # BER definite length - long form. Highest bit of byte 1 is 1, last 7 bits counts the number of following octets containing the value length bytes_length = data[1] - 128 if len(data) >= bytes_length + 2: value_length = 0 cont = bytes_length for byte in data[2:2 + bytes_length]: cont -= 1 value_length += byte * (256 ** cont) ret_value = value_length + 2 + bytes_length return ret_value @classmethod def decode_response(cls, ldap_message): """ Convert received LDAPMessage to a dict """ message_type = ldap_message.getComponentByName('protocolOp').getName() component = ldap_message['protocolOp'].getComponent() controls = ldap_message['controls'] if message_type == 'bindResponse': result = bind_response_to_dict(component) elif message_type == 'searchResEntry': result = search_result_entry_response_to_dict(component) elif message_type == 'searchResDone': result = search_result_done_response_to_dict(component) elif message_type == 'searchResRef': result = search_result_reference_response_to_dict(component) elif message_type == 'modifyResponse': result = modify_response_to_dict(component) elif message_type == 'addResponse': result = add_response_to_dict(component) elif message_type == 'delResponse': result = delete_response_to_dict(component) elif message_type == 'modDNResponse': result = modify_dn_response_to_dict(component) elif message_type == 'compareResponse': result = compare_response_to_dict(component) elif message_type == 'extendedResp': result = extended_response_to_dict(component) elif message_type == 'intermediateResponse': result = intermediate_response_to_dict(component) else: raise LDAPUnknownResponseError('unknown response') result['type'] = message_type if controls: result['controls'] = dict() for control in controls: decoded_control = cls.decode_control(control) result['controls'][decoded_control[0]] = decoded_control[1] return result @classmethod def decode_control(cls, control): """ decode control, return a 2-element tuple where the first element is the control oid and the second element is a dictionary with description (from Oids), criticality and decoded control value """ control_type = str(control['controlType']) criticality = bool(control['criticality']) control_value = bytes(control['controlValue']) if control_type == '1.2.840.113556.1.4.319': # simple paged search as per RFC2696 control_resp, unprocessed = decoder.decode(control_value, asn1Spec=RealSearchControlValue()) control_value = dict() control_value['size'] = int(control_resp['size']) control_value['cookie'] = bytes(control_resp['cookie']) return control_type, {'description': Oids.get(control_type, ''), 'criticality': criticality, 'value': control_value} @classmethod def decode_request(cls, ldap_message): message_type = ldap_message.getComponentByName('protocolOp').getName() component = ldap_message['protocolOp'].getComponent() if message_type == 'bindRequest': result = bind_request_to_dict(component) elif message_type == 'unbindRequest': result = dict() elif message_type == 'addRequest': result = add_request_to_dict(component) elif message_type == 'compareRequest': result = compare_request_to_dict(component) elif message_type == 'delRequest': result = delete_request_to_dict(component) elif message_type == 'extendedReq': result = extended_request_to_dict(component) elif message_type == 'modifyRequest': result = modify_request_to_dict(component) elif message_type == 'modDNRequest': result = modify_dn_request_to_dict(component) elif message_type == 'searchRequest': result = search_request_to_dict(component) elif message_type == 'abandonRequest': result = abandon_request_to_dict(component) else: raise LDAPUnknownRequestError('unknown request') result['type'] = message_type return result def valid_referral_list(self, referrals): referral_list = [] for referral in referrals: candidate_referral = BaseStrategy.decode_referral(referral) if candidate_referral: for ref_host in self.connection.server.allowed_referral_hosts: if ref_host[0] == candidate_referral['host'] or ref_host[0] == '*': if candidate_referral['host'] not in self._referrals: candidate_referral['anonymousBindOnly'] = not ref_host[1] referral_list.append(candidate_referral) break return referral_list @classmethod def decode_referral(cls, uri): """ Decode referral URI as specified in RFC 4516 relaxing specifications permitting 'ldaps' as scheme meaning ssl-ldap ldapurl = scheme COLON SLASH SLASH [host [COLON port]] [SLASH dn [QUESTION [attributes] [QUESTION [scope] [QUESTION [filter] [QUESTION extensions]]]]] ; and are defined ; in Sections 3.2.2 and 3.2.3 ; of [RFC3986]. ; is from Section 3 of ; [RFC4515], subject to the ; provisions of the ; "Percent-Encoding" section ; below. scheme = "ldap" / "ldaps" <== not RFC4516 compliant (original is 'scheme = "ldap"') dn = distinguishedName ; From Section 3 of [RFC4514], ; subject to the provisions of ; the "Percent-Encoding" ; section below. attributes = attrdesc *(COMMA attrdesc) attrdesc = selector *(COMMA selector) selector = attributeSelector ; From Section 4.5.1 of ; [RFC4511], subject to the ; provisions of the ; "Percent-Encoding" section ; below. scope = "base" / "one" / "sub" extensions = extension *(COMMA extension) extension = [EXCLAMATION] extype [EQUALS exvalue] extype = oid ; From section 1.4 of [RFC4512]. exvalue = LDAPString ; From section 4.1.2 of ; [RFC4511], subject to the ; provisions of the ; "Percent-Encoding" section ; below. EXCLAMATION = %x21 ; exclamation mark ("!") SLASH = %x2F ; forward slash ("/") COLON = %x3A ; colon (":") QUESTION = %x3F ; question mark ("?") """ referral = dict() parts = uri.split('?') scheme, sep, remain = parts[0].partition('://') if sep != '://' or scheme not in ['ldap', 'ldaps']: return None address, _, referral['base'] = remain.partition('/') referral['ssl'] = True if scheme == 'ldaps' else False referral['host'], sep, referral['port'] = address.partition(':') if sep != ':': referral['port'] = None else: if not referral['port'].isdigit() or not (0 < int(referral['port']) < 65536): return None else: referral['port'] = int(referral['port']) referral['attributes'] = parts[1].split(',') if len(parts) > 1 else None referral['scope'] = parts[2] if len(parts) > 2 else None if referral['scope'] == 'base': referral['scope'] = SEARCH_SCOPE_BASE_OBJECT elif referral['scope'] == 'sub': referral['scope'] = SEARCH_SCOPE_WHOLE_SUBTREE elif referral['scope'] == 'one': referral['scope'] = SEARCH_SCOPE_SINGLE_LEVEL elif referral['scope']: return None referral['filter'] = parts[3] if len(parts) > 3 else None referral['extensions'] = parts[3].split(',') if len(parts) > 4 else None return referral def do_operation_on_referral(self, request, referrals): valid_referral_list = self.valid_referral_list(referrals) if valid_referral_list: preferred_referral_list = [referral for referral in valid_referral_list if referral['ssl'] == self.connection.server.ssl] selected_referral = choice(preferred_referral_list) if preferred_referral_list else choice(valid_referral_list) referral_server = Server(host=selected_referral['host'], port=selected_referral['port'] or self.connection.server.port, use_ssl=selected_referral['ssl'], allowed_referral_hosts=self.connection.server.allowed_referral_hosts, tls=Tls(local_private_key_file=self.connection.server.tls.private_key_file, local_certificate_file=self.connection.server.tls.certificate_file, validate=self.connection.server.tls.validate, version=self.connection.server.tls.version, ca_certs_file=self.connection.server.tls.ca_certs_file) if selected_referral['ssl'] else None) from ..core.connection import Connection referral_connection = Connection(server=referral_server, user=self.connection.user if not selected_referral['anonymousBindOnly'] else None, password=self.connection.password if not selected_referral['anonymousBindOnly'] else None, version=self.connection.version, authentication=self.connection.authentication if not selected_referral['anonymousBindOnly'] else AUTH_ANONYMOUS, client_strategy=STRATEGY_SYNC, auto_referrals=True, read_only=self.connection.read_only) if self.connection._usage: self.connection._usage.referrals_followed += 1 referral_connection.open() referral_connection.strategy._referrals = self._referrals if self.connection.bound: referral_connection.bind() if request['type'] == 'searchRequest': referral_connection.search(selected_referral['base'] or request['base'], selected_referral['filter'] or request['filter'], selected_referral['scope'] or request['scope'], request['dereferenceAlias'], selected_referral['attributes'] or request['attributes'], request['sizeLimit'], request['timeLimit'], request['typeOnly'], controls=request['controls']) elif request['type'] == 'addRequest': referral_connection.add(selected_referral['base'] or request['entry'], None, request['attributes'], controls=request['controls']) elif request['type'] == 'compareRequest': referral_connection.compare(selected_referral['base'] or request['entry'], request['attribute'], request['value'], controls=request['controls']) elif request['type'] == 'delRequest': referral_connection.delete(selected_referral['base'] or request['entry'], controls=request['controls']) elif request['type'] == 'extendedRequest': # tbd raise NotImplementedError() elif request['type'] == 'modifyRequest': referral_connection.modify(selected_referral['base'] or request['entry'], prepare_changes_for_request(request['changes']), controls=request['controls']) elif request['type'] == 'modDNRequest': referral_connection.modify_dn(selected_referral['base'] or request['entry'], request['newRdn'], request['deleteOldRdn'], request['newSuperior'], controls=request['controls']) else: self.connection.last_error = 'referral operation not permitted' raise LDAPReferralError(self.connection.last_error) response = referral_connection.response result = referral_connection.result referral_connection.unbind() else: response = None result = None return response, result def _start_listen(self): #overridden on strategy class raise NotImplementedError def _get_response(self, message_id): # overridden in strategy class raise NotImplementedError def receiving(self): # overridden in strategy class raise NotImplementedError def post_send_single_response(self, message_id): # overridden in strategy class raise NotImplementedError def post_send_search(self, message_id): # overridden in strategy class raise NotImplementedError def get_stream(self): raise NotImplementedError def set_stream(self, value): raise NotImplementedErrorpython3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/ldifProducer.py0000666000000000000000000001207112355103747022533 0ustar 00000000000000""" Created on 2013.07.15 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from io import StringIO from os import linesep import random from .. import LDAP_MAX_INT from ..core.exceptions import LDAPLDIFError from ..utils.conv import prepare_for_stream from ..protocol.rfc4511 import LDAPMessage, MessageID, ProtocolOp from ..protocol.rfc2849 import operation_to_ldif, add_ldif_header from ..protocol.convert import build_controls_list from .baseStrategy import BaseStrategy class LdifProducerStrategy(BaseStrategy): """ This strategy is used to create the LDIF stream for the Add, Delete, Modify, ModifyDn operations. You send the request and get the request in the ldif-change representation of the operation. NO OPERATION IS SENT TO THE LDAP SERVER! Connection.request will contain the result LDAP message in a dict form Connection.response will contain the ldif-change format of the requested operation if available You don't need a real server to connect to for this strategy """ def __init__(self, ldap_connection): BaseStrategy.__init__(self, ldap_connection) self.sync = True self.no_real_dsa = True self.pooled = False self.can_stream = True self.line_separator = linesep self.all_base64 = False self.stream = None self.order = dict() self._header_added = False random.seed() def _start_listen(self): self.connection.listening = True self.connection.closed = False self._header_added = False if not self.stream or (isinstance(self.stream, StringIO) and self.stream.closed): self.set_stream(StringIO()) def _stop_listen(self): self.stream.close() self.connection.listening = False self.connection.closed = True def receiving(self): return None def send(self, message_type, request, controls=None): """ Build the LDAPMessage without sending to server """ message_id = random.randint(0, LDAP_MAX_INT) ldap_message = LDAPMessage() ldap_message['messageID'] = MessageID(message_id) ldap_message['protocolOp'] = ProtocolOp().setComponentByName(message_type, request) message_controls = build_controls_list(controls) if message_controls is not None: ldap_message['controls'] = message_controls self.connection.request = BaseStrategy.decode_request(ldap_message) self.connection.request['controls'] = controls self._outstanding[message_id] = self.connection.request return message_id def post_send_single_response(self, message_id): self.connection.response = None self.connection.result = None if self._outstanding and message_id in self._outstanding: request = self._outstanding.pop(message_id) ldif_lines = operation_to_ldif(self.connection.request['type'], request, self.all_base64, self.order.get(self.connection.request['type'])) if self.stream and ldif_lines and not self.connection.closed: self.accumulate_stream(self.line_separator.join(ldif_lines)) ldif_lines = add_ldif_header(ldif_lines) self.connection.response = self.line_separator.join(ldif_lines) return self.connection.response return None def post_send_search(self, message_id): raise LDAPLDIFError('LDIF-CONTENT cannot be produced for Search Operations') def _get_response(self, message_id): pass def accumulate_stream(self, fragment): if not self._header_added and self.stream.tell() == 0: self._header_added = True header = add_ldif_header(['-'])[0] self.stream.write(prepare_for_stream(header + self.line_separator + self.line_separator)) self.stream.write(prepare_for_stream(fragment + self.line_separator + self.line_separator)) def get_stream(self): return self.stream def set_stream(self, value): error = False try: if not value.writable(): error = True except (ValueError, AttributeError): error = True if error: raise LDAPLDIFError('stream must be writable') self.stream = value python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/reusableThreaded.py0000666000000000000000000003760012355117035023354 0ustar 00000000000000""" Created on 2014.03.23 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from datetime import datetime from os import linesep from threading import Thread, Lock from time import sleep from .. import REUSABLE_POOL_SIZE, REUSABLE_CONNECTION_LIFETIME, STRATEGY_SYNC_RESTARTABLE, TERMINATE_REUSABLE, RESPONSE_WAITING_TIMEOUT, LDAP_MAX_INT, RESPONSE_SLEEPTIME from .baseStrategy import BaseStrategy from ..core.usage import ConnectionUsage from ..core.exceptions import LDAPConnectionPoolNameIsMandatoryError, LDAPConnectionPoolNotStartedError from ..core.exceptions import LDAPOperationResult from ldap3.core.exceptions import LDAPExceptionError try: from queue import Queue except ImportError: # Python 2 # noinspection PyUnresolvedReferences from Queue import Queue # noinspection PyProtectedMember class ReusableThreadedStrategy(BaseStrategy): """ A pool of reusable SyncWaitRestartable connections with lazy behaviour and limited lifetime. The connection using this strategy presents itself as a normal connection, but internally the strategy has a pool of connections that can be used as needed. Each connection lives in its own thread and has a busy/available status. The strategy performs the requested operation on the first available connection. The pool of connections is instantiated at strategy initialization. Strategy has two customizable properties, the total number of connections in the pool and the lifetime of each connection. When lifetime is expired the connection is closed and will be opened again when needed. """ pools = dict() # noinspection PyProtectedMember class ConnectionPool(object): def __new__(cls, connection): if connection.pool_name in ReusableThreadedStrategy.pools: # returns existing connection pool pool = ReusableThreadedStrategy.pools[connection.pool_name] if not pool.started: # if pool is not started remove it from the pools singleton and create a new onw del ReusableThreadedStrategy.pools[connection.pool_name] return object.__new__(cls) if connection.pool_lifetime and pool.lifetime != connection.pool_lifetime: # change lifetime pool.lifetime = connection.pool_lifetime if connection.pool_size and pool.pool_size != connection.pool_size: # if pool size has changed terminate and recreate the connections pool.terminate_pool() pool.pool_size = connection.pool_size return pool else: return object.__new__(cls) def __init__(self, connection): if not hasattr(self, 'connections'): self.name = connection.pool_name self.original_connection = connection self.connections = [] self.pool_size = connection.pool_size or REUSABLE_POOL_SIZE self.lifetime = connection.pool_lifetime or REUSABLE_CONNECTION_LIFETIME self.request_queue = Queue() self.open_pool = False self.bind_pool = False self.tls_pool = False self._incoming = dict() self.counter = 0 self.terminated_usage = ConnectionUsage() if connection._usage else None self.terminated = False self.lock = Lock() ReusableThreadedStrategy.pools[self.name] = self self.started = False def __str__(self): s = str(self.name) + ' - ' + ('started' if self.started else 'terminated') + linesep s += 'original connection: ' + str(self.original_connection) + linesep s += 'response pool length: ' + str(len(self._incoming)) s += ' - pool size: ' + str(self.pool_size) s += ' - lifetime: ' + str(self.lifetime) s += ' - open: ' + str(self.open_pool) s += ' - bind: ' + str(self.bind_pool) s += ' - tls: ' + str(self.tls_pool) for connection in self.connections: s += linesep s += str(connection) return s def __repr__(self): return self.__str__() def start_pool(self): if not self.started: self.create_pool() for connection in self.connections: connection.thread.start() self.started = True return True return False def create_pool(self): self.connections = [ReusableThreadedStrategy.ReusableConnection(self.original_connection, self.request_queue) for _ in range(self.pool_size)] def terminate_pool(self): self.started = False self.request_queue.join() # wait for all queue pending operations for _ in range(len([connection for connection in self.connections if connection.thread.is_alive()])): # put a TERMINATE signal on the queue for each active thread self.request_queue.put((TERMINATE_REUSABLE, None, None, None)) self.request_queue.join() # wait for all queue terminate operations class PooledConnectionThread(Thread): def __init__(self, reusable_connection, original_connection): Thread.__init__(self) self.daemon = True self.active_connection = reusable_connection self.original_connection = original_connection # noinspection PyProtectedMember def run(self): self.active_connection.running = True terminate = False pool = self.original_connection.strategy.pool while not terminate: counter, message_type, request, controls = pool.request_queue.get() self.active_connection.busy = True if counter == TERMINATE_REUSABLE: terminate = True if self.active_connection.connection.bound: try: self.active_connection.connection.unbind() except LDAPExceptionError: pass else: if (datetime.now() - self.active_connection.creation_time).seconds >= self.original_connection.strategy.pool.lifetime: # destroy and create a new connection try: self.active_connection.connection.unbind() except LDAPExceptionError: pass self.active_connection.new_connection() if message_type not in ['bindRequest', 'unbindRequest']: if pool.open_pool and self.active_connection.connection.closed: self.active_connection.connection.open() if pool.bind_pool and not self.active_connection.connection.bound: self.active_connection.connection.bind() if pool.tls_pool and not self.active_connection.connection.tls_started: self.active_connection.connection.start_tls() # noinspection PyProtectedMember self.active_connection.connection._fire_deferred() # force deferred operations exc = None response = None result = None try: if message_type == 'searchRequest': response = self.active_connection.connection.post_send_search(self.active_connection.connection.send(message_type, request, controls)) else: response = self.active_connection.connection.post_send_single_response(self.active_connection.connection.send(message_type, request, controls)) result = self.active_connection.connection.result except LDAPOperationResult as e: # raise_exceptions has raise an exception. It must be redirected to the original connection thread exc = e with pool.lock: if exc: pool._incoming[counter] = (exc, None) else: pool._incoming[counter] = (response, result) self.original_connection.busy = False pool.request_queue.task_done() if self.original_connection.usage: pool.terminated_usage += self.active_connection.connection.usage self.active_connection.running = False class ReusableConnection(object): """ Container for the Restartable connection. it includes a thread and a lock to execute the connection in the pool """ def __init__(self, connection, request_queue): self.original_connection = connection self.request_queue = request_queue self.running = False self.busy = False self.connection = None self.creation_time = None self.new_connection() self.thread = ReusableThreadedStrategy.PooledConnectionThread(self, connection) def __str__(self): s = str(self.connection) + linesep s += 'running ' if self.running else '-halted' s += ' - ' + ('busy' if self.busy else ' available') s += ' - ' + ('creation time: ' + self.creation_time.isoformat()) return s def new_connection(self): from ..core.connection import Connection # noinspection PyProtectedMember self.connection = Connection(server=self.original_connection.server_pool if self.original_connection.server_pool else self.original_connection.server, user=self.original_connection.user, password=self.original_connection.password, version=self.original_connection.version, authentication=self.original_connection.authentication, client_strategy=STRATEGY_SYNC_RESTARTABLE, raise_exceptions=self.original_connection.raise_exceptions, check_names=self.original_connection.check_names, auto_referrals=self.original_connection.auto_referrals, sasl_mechanism=self.original_connection.sasl_mechanism, sasl_credentials=self.original_connection.sasl_credentials, collect_usage=True if self.original_connection._usage else False, read_only=self.original_connection.read_only, auto_bind=self.original_connection.auto_bind, lazy=True) if self.original_connection.server_pool: self.connection.server_pool = self.original_connection.server_pool self.connection.server_pool.initialize(self.connection) self.creation_time = datetime.now() def __init__(self, ldap_connection): BaseStrategy.__init__(self, ldap_connection) self.sync = False self.no_real_dsa = False self.pooled = True self.can_stream = False if hasattr(ldap_connection, 'pool_name') and ldap_connection.pool_name: self.pool = ReusableThreadedStrategy.ConnectionPool(ldap_connection) else: raise LDAPConnectionPoolNameIsMandatoryError('reusable connection must have a pool_name') def open(self, reset_usage=True): self.pool.open_pool = True self.pool.start_pool() self.connection.closed = False if self.connection._usage: if reset_usage or not self.connection._usage.initial_connection_start_time: self.connection._usage.start() def terminate(self): self.pool.terminate_pool() self.pool.open_pool = False self.connection.bound = False self.connection.closed = True self.pool.bind_pool = False self.pool.tls_pool = False def _close_socket(self): """ Doesn't really close the socket """ self.connection.closed = True if self.connection._usage: self.connection._usage.closed_sockets += 1 def send(self, message_type, request, controls=None): if self.pool.started: if message_type == 'bindRequest': self.pool.bind_pool = True counter = -1 # -1 stands for bind request elif message_type == 'unbindRequest': self.pool.bind_pool = False counter = -2 # -1 stands for unbind request elif message_type == 'extendedReq' and self.connection.starting_tls: self.pool.tls_pool = True counter = -3 # -1 stands for start_tls extended request else: with self.pool.lock: self.pool.counter += 1 if self.pool.counter > LDAP_MAX_INT: self.pool.counter = 1 counter = self.pool.counter self.pool.request_queue.put((counter, message_type, request, controls)) return counter raise LDAPConnectionPoolNotStartedError('reusable connection pool not started') def get_response(self, counter, timeout=RESPONSE_WAITING_TIMEOUT): if counter == -1: # send a bogus bindResponse return list(), {'description': 'success', 'referrals': None, 'type': 'bindResponse', 'result': 0, 'dn': '', 'message': '', 'saslCreds': 'None'} elif counter == -2: # bogus unbind return None elif counter == -3: # bogus startTls extended request return list(), {'result': 0, 'referrals': None, 'responseName': '1.3.6.1.4.1.1466.20037', 'type': 'extendedResp', 'description': 'success', 'responseValue': 'None', 'dn': '', 'message': ''} response = None result = None while timeout >= 0: # waiting for completed message to appear in _incoming try: with self.connection.strategy.pool.lock: response, result = self.connection.strategy.pool._incoming.pop(counter) except KeyError: sleep(RESPONSE_SLEEPTIME) timeout -= RESPONSE_SLEEPTIME continue break if isinstance(response, LDAPOperationResult): raise response # an exception has been raised with raise_connections return response, result def post_send_single_response(self, counter): return counter def post_send_search(self, counter): return counter python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/syncWait.py0000666000000000000000000001744112355107125021712 0ustar 00000000000000""" Created on 2013.07.15 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ import socket from pyasn1.codec.ber import decoder from .. import SESSION_TERMINATED_BY_SERVER, RESPONSE_COMPLETE, SOCKET_SIZE, RESULT_REFERRAL from ..core.exceptions import LDAPSocketReceiveError, communication_exception_factory, LDAPExceptionError from ..strategy.baseStrategy import BaseStrategy from ..protocol.rfc4511 import LDAPMessage # noinspection PyProtectedMember class SyncWaitStrategy(BaseStrategy): """ This strategy is synchronous. You send the request and get the response Requests return a boolean value to indicate the result of the requested Operation Connection.response will contain the whole LDAP response for the messageId requested in a dict form Connection.request will contain the result LDAP message in a dict form """ def __init__(self, ldap_connection): BaseStrategy.__init__(self, ldap_connection) self.sync = True self.no_real_dsa = False self.pooled = False self.can_stream = False def open(self, reset_usage=True): BaseStrategy.open(self, reset_usage) self.connection.refresh_dsa_info() def _start_listen(self): if not self.connection.listening and not self.connection.closed: self.connection.listening = True def receiving(self): """ Receive data over the socket Checks if the socket is closed """ messages = [] receiving = True unprocessed = b'' data = b'' get_more_data = True exc = None while receiving: if get_more_data: try: data = self.connection.socket.recv(SOCKET_SIZE) except (OSError, socket.error, AttributeError) as e: self.connection.last_error = 'error receiving data: ' + str(e) exc = e if exc: try: # try to close the connection before raising exception self.close() except (socket.error, LDAPExceptionError): pass raise communication_exception_factory(LDAPSocketReceiveError, exc)(self.connection.last_error) unprocessed += data if len(data) > 0: length = BaseStrategy.compute_ldap_message_size(unprocessed) if length == -1: # too few data to decode message length get_more_data = True continue if len(unprocessed) < length: get_more_data = True else: messages.append(unprocessed[:length]) unprocessed = unprocessed[length:] get_more_data = False if len(unprocessed) == 0: receiving = False else: receiving = False return messages def post_send_single_response(self, message_id): """ Executed after an Operation Request (except Search) Returns the result message or None """ responses, result = self.get_response(message_id) if result['type'] == 'intermediateResponse': # checks that all responses are intermediates (there should be only one) for response in responses: if response['type'] != 'intermediateResponse': self.connection.last_error = 'multiple messages error' raise LDAPSocketReceiveError(self.connection.last_error) responses.append(result) return responses def post_send_search(self, message_id): """ Executed after a search request Returns the result message and store in connection.response the objects found """ responses, result = self.get_response(message_id) if isinstance(responses, (list, tuple)): self.connection.response = responses[:] # copy search result entries without result return responses self.connection.last_error = 'error receiving response' raise LDAPSocketReceiveError(self.connection.last_error) def _get_response(self, message_id): """ Performs the capture of LDAP response for SyncWaitStrategy """ ldap_responses = [] response_complete = False while not response_complete: responses = self.receiving() if responses: for response in responses: while len(response) > 0: if self.connection._usage: self.connection._usage.received_message(len(response)) ldap_resp, unprocessed = decoder.decode(response, asn1Spec=LDAPMessage()) if int(ldap_resp['messageID']) == message_id: dict_response = BaseStrategy.decode_response(ldap_resp) ldap_responses.append(dict_response) if dict_response['type'] not in ['searchResEntry', 'searchResRef', 'intermediateResponse']: response_complete = True elif int(ldap_resp['messageID']) == 0: # 0 is reserved for 'Unsolicited Notification' from server as per RFC4511 (paragraph 4.4) dict_response = BaseStrategy.decode_response(ldap_resp) if dict_response['responseName'] == '1.3.6.1.4.1.1466.20036': # Notice of Disconnection as per RFC4511 (paragraph 4.4.1) return SESSION_TERMINATED_BY_SERVER else: self.connection.last_error = 'invalid messageId received' raise LDAPSocketReceiveError(self.connection.last_error) response = unprocessed if response: # if this statement is removed unprocessed data will be processed as another message self.connection.last_error = 'unprocessed substrate error' raise LDAPSocketReceiveError(self.connection.last_error) else: return SESSION_TERMINATED_BY_SERVER ldap_responses.append(RESPONSE_COMPLETE) if ldap_responses[-2]['result'] == RESULT_REFERRAL: if self.connection._usage: self.connection._usage.referrals_received += 1 if self.connection.auto_referrals: ref_response, ref_result = self.do_operation_on_referral(self._outstanding[message_id], ldap_responses[-2]['referrals']) if ref_response is not None: ldap_responses = ref_response + [ref_result] ldap_responses.append(RESPONSE_COMPLETE) elif ref_result is not None: ldap_responses = [ref_result, RESPONSE_COMPLETE] self._referrals = [] return ldap_responses python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/syncWaitRestartable.py0000666000000000000000000002353612355107541024107 0ustar 00000000000000""" Created on 2014.03.04 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from sys import exc_info from time import sleep import socket from datetime import datetime from .. import RESTARTABLE_SLEEPTIME, RESTARTABLE_TRIES from .syncWait import SyncWaitStrategy from ..core.exceptions import LDAPSocketOpenError, LDAPOperationResult, LDAPMaximumRetriesError # noinspection PyBroadException,PyProtectedMember class SyncWaitRestartableStrategy(SyncWaitStrategy): def __init__(self, ldap_connection): SyncWaitStrategy.__init__(self, ldap_connection) self.sync = True self.no_real_dsa = False self.pooled = False self.can_stream = False self.restartable_sleep_time = RESTARTABLE_SLEEPTIME self.restartable_tries = RESTARTABLE_TRIES self._restarting = False self._last_bind_controls = None self._current_message_type = None self._current_request = None self._current_controls = None self._restart_tls = None self.exception_history = [] def open(self, reset_usage=False): SyncWaitStrategy.open(self, reset_usage) def _open_socket(self, use_ssl=False): """ Try to open and connect a socket to a Server raise LDAPExceptionError if unable to open or connect socket if connection is restartable tries for the number of restarting requested or forever """ try: SyncWaitStrategy._open_socket(self, use_ssl) # try to open socket using SyncWait self._reset_exception_history() return except Exception: # machinery for restartable connection self._add_exception_to_history() if not self._restarting: # if not already performing a restart self._restarting = True counter = self.restartable_tries while counter > 0: sleep(self.restartable_sleep_time) if not self.connection.closed: try: # resetting connection self.connection.close() except (socket.error, LDAPSocketOpenError): # don't trace catch socket errors because socket could already be closed pass except Exception: self._add_exception_to_history() try: # reissuing same operation if self.connection.server_pool: new_server = self.connection.server_pool.get_server(self.connection) # get a server from the server_pool if available if self.connection.server != new_server: self.connection.server = new_server if self.connection._usage: self.connection._usage.servers_from_pool += 1 SyncWaitStrategy._open_socket(self, use_ssl) # calls super (not restartable) _open_socket() if self.connection._usage: self.connection._usage.restartable_successes += 1 self.connection.closed = False self._restarting = False self._reset_exception_history() return except Exception: self._add_exception_to_history() if self.connection._usage: self.connection._usage.restartable_failures += 1 if not isinstance(self.restartable_tries, bool): counter -= 1 self._restarting = False self.connection.last_error = 'restartable connection strategy failed while opening socket' raise LDAPMaximumRetriesError(self.connection.last_error, self.exception_history, self.restartable_tries) def send(self, message_type, request, controls=None): self._current_message_type = message_type self._current_request = request self._current_controls = controls if not self._restart_tls: # RFCs doesn't define how to stop tls once started self._restart_tls = self.connection.tls_started if message_type == 'bindRequest': # store controls used in bind to be used again when restarting the connection self._last_bind_controls = controls try: message_id = SyncWaitStrategy.send(self, message_type, request, controls) # try to send using SyncWait self._reset_exception_history() return message_id except Exception: self._add_exception_to_history() if not self._restarting: # machinery for restartable connection self._restarting = True counter = self.restartable_tries while counter > 0: sleep(self.restartable_sleep_time) if not self.connection.closed: try: # resetting connection self.connection.close() except (socket.error, LDAPSocketOpenError): # don't trace socket errrors because socket could already be closed pass except Exception: self._add_exception_to_history() failure = False try: # reopening connection self.connection.open(reset_usage=False) if self._restart_tls: # restart tls if start_tls was previously used self.connection.start_tls() if message_type != 'bindRequest': self.connection.bind(self._last_bind_controls) # binds with previously used controls unless the request is already a bindRequest except Exception: self._add_exception_to_history() failure = True if not failure: try: # reissuing same operation ret_value = self.connection.send(message_type, request, controls) if self.connection._usage: self.connection._usage.restartable_successes += 1 self._restarting = False self._reset_exception_history() return ret_value # successful send except Exception: self._add_exception_to_history() failure = True if failure and self.connection._usage: self.connection._usage.restartable_failures += 1 if not isinstance(self.restartable_tries, bool): counter -= 1 self._restarting = False self.connection.last_error = 'restartable connection failed to send' raise LDAPMaximumRetriesError(self.connection.last_error, self.exception_history, self.restartable_tries) def post_send_single_response(self, message_id): try: ret_value = SyncWaitStrategy.post_send_single_response(self, message_id) self._reset_exception_history() return ret_value except Exception: self._add_exception_to_history() # if an LDAPExceptionError is raised then resend the request try: ret_value = SyncWaitStrategy.post_send_single_response(self, self.send(self._current_message_type, self._current_request, self._current_controls)) self._reset_exception_history() return ret_value except Exception as e: self._add_exception_to_history() exc = e if exc: if not isinstance(exc, LDAPOperationResult): self.connection.last_error = 'restartable connection strategy failed in post_send_single_response' raise exc def post_send_search(self, message_id): try: ret_value = SyncWaitStrategy.post_send_search(self, message_id) self._reset_exception_history() return ret_value except Exception: self._add_exception_to_history() # if an LDAPExceptionError is raised then resend the request try: ret_value = SyncWaitStrategy.post_send_search(self, self.connection.send(self._current_message_type, self._current_request, self._current_controls)) self._reset_exception_history() return ret_value except Exception as e: self._add_exception_to_history() exc = e if exc: if not isinstance(exc, LDAPOperationResult): self.connection.last_error = exc.args raise exc def _add_exception_to_history(self): if not isinstance(self.restartable_tries, bool): # doesn't accumulate when restarting forever if not isinstance(exc_info()[1], LDAPMaximumRetriesError): # doesn't add the LDAPMaximumRetriesError exception self.exception_history.append((datetime.now(), exc_info()[0], exc_info()[1])) def _reset_exception_history(self): if self.exception_history: self.exception_history = [] python3-ldap-0.9.4.2/python3-ldap/ldap3/strategy/__init__.py0000666000000000000000000000000012355103747021635 0ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/0000777000000000000000000000000012355117540017030 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/conv.py0000666000000000000000000000267012355103747020360 0ustar 00000000000000""" Created on 2014.04.26 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ def escape_bytes(bytes_value): if str != bytes: # Python 3 if isinstance(bytes_value, str): bytes_value = bytearray(bytes_value, encoding='utf-8') escaped = '\\'.join([('%02x' % int(b)) for b in bytes_value]) else: # Python 2 if isinstance(bytes_value, unicode): bytes_value = bytes_value.encode('utf-8') escaped = '\\'.join([('%02x' % ord(b)) for b in bytes_value]) return ('\\' + escaped) if escaped else '' def prepare_for_stream(value): if str != bytes: # Python 3 return value else: # Python 2 return value.decode() python3-ldap-0.9.4.2/python3-ldap/ldap3/utils/__init__.py0000666000000000000000000000146612355103747021154 0ustar 00000000000000""" Created on 2014.04.26 @author: Giovanni Cannata Copyright 2014 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ python3-ldap-0.9.4.2/python3-ldap/ldap3/__init__.py0000666000000000000000000002003312355103746020002 0ustar 00000000000000""" @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ # authentication AUTH_ANONYMOUS = 0 AUTH_SIMPLE = 1 AUTH_SASL = 2 SASL_AVAILABLE_MECHANISMS = ['EXTERNAL', 'DIGEST-MD5'] AUTHZ_STATE_CLOSED = 0 AUTHZ_STATE_ANONYMOUS = 1 AUTHZ_STATE_UNAUTHENTICATED = 2 # search scope SEARCH_SCOPE_BASE_OBJECT = 0 SEARCH_SCOPE_SINGLE_LEVEL = 1 SEARCH_SCOPE_WHOLE_SUBTREE = 2 # search alias SEARCH_NEVER_DEREFERENCE_ALIASES = 0 SEARCH_DEREFERENCE_IN_SEARCHING = 1 SEARCH_DEREFERENCE_FINDING_BASE_OBJECT = 2 SEARCH_DEREFERENCE_ALWAYS = 3 # search attributes ALL_ATTRIBUTES = '*' NO_ATTRIBUTES = '1.1' # as per RFC 4511 ALL_OPERATIONAL_ATTRIBUTES = '+' # as per RFC 3673 # modify type MODIFY_ADD = 0 MODIFY_DELETE = 1 MODIFY_REPLACE = 2 MODIFY_INCREMENT = 3 # client strategies STRATEGY_SYNC = 0 STRATEGY_ASYNC_THREADED = 1 STRATEGY_LDIF_PRODUCER = 2 STRATEGY_SYNC_RESTARTABLE = 3 STRATEGY_REUSABLE_THREADED = 4 CLIENT_STRATEGIES = [STRATEGY_SYNC, STRATEGY_ASYNC_THREADED, STRATEGY_LDIF_PRODUCER, STRATEGY_SYNC_RESTARTABLE, STRATEGY_REUSABLE_THREADED] # communication SESSION_TERMINATED_BY_SERVER = 0 RESPONSE_COMPLETE = -1 RESPONSE_SLEEPTIME = 0.02 # seconds to wait while waiting for a response in asynchronous strategies RESPONSE_WAITING_TIMEOUT = 10 # waiting timeout for receiving a response in asynchronous strategies SOCKET_SIZE = 4096 # socket byte size # restartable strategy RESTARTABLE_SLEEPTIME = 2 # time to wait in a restartable strategy before retrying the request RESTARTABLE_TRIES = 50 # number of times to retry in a restartable strategy before giving up. Set to True for unlimited retries # reusable strategy TERMINATE_REUSABLE = -1 REUSABLE_POOL_SIZE = 10 REUSABLE_CONNECTION_LIFETIME = 3600 DEFAULT_POOL_NAME = 'connection_pool' # LDAP protocol LDAP_MAX_INT = 2147483647 # LDIF LDIF_LINE_LENGTH = 78 # result codes RESULT_SUCCESS = 0 RESULT_OPERATIONS_ERROR = 1 RESULT_PROTOCOL_ERROR = 2 RESULT_TIME_LIMIT_EXCEEDED = 3 RESULT_SIZE_LIMIT_EXCEEDED = 4 RESULT_COMPARE_FALSE = 5 RESULT_COMPARE_TRUE = 6 RESULT_AUTH_METHOD_NOT_SUPPORTED = 7 RESULT_STRONGER_AUTH_REQUIRED = 8 RESULT_REFERRAL = 10 RESULT_ADMIN_LIMIT_EXCEEDED = 11 RESULT_UNAVAILABLE_CRITICAL_EXTENSION = 12 RESULT_CONFIDENTIALITY_REQUIRED = 13 RESULT_SASL_BIND_IN_PROGRESS = 14 RESULT_NO_SUCH_ATTRIBUTE = 16 RESULT_UNDEFINED_ATTRIBUTE_TYPE = 17 RESULT_INAPPROPRIATE_MATCHING = 18 RESULT_CONSTRAINT_VIOLATION = 19 RESULT_ATTRIBUTE_OR_VALUE_EXISTS = 20 RESULT_INVALID_ATTRIBUTE_SYNTAX = 21 RESULT_NO_SUCH_OBJECT = 32 RESULT_ALIAS_PROBLEM = 33 RESULT_INVALID_DN_SYNTAX = 34 RESULT_ALIAS_DEREFERENCING_PROBLEM = 36 RESULT_INAPPROPRIATE_AUTHENTICATION = 48 RESULT_INVALID_CREDENTIALS = 49 RESULT_INSUFFICIENT_ACCESS_RIGHTS = 50 RESULT_BUSY = 51 RESULT_UNAVAILABLE = 52 RESULT_UNWILLING_TO_PERFORM = 53 RESULT_LOOP_DETECTED = 54 RESULT_NAMING_VIOLATION = 64 RESULT_OBJECT_CLASS_VIOLATION = 65 RESULT_NOT_ALLOWED_ON_NON_LEAF = 66 RESULT_NOT_ALLOWED_ON_RDN = 67 RESULT_ENTRY_ALREADY_EXISTS = 68 RESULT_OBJECT_CLASS_MODS_PROHIBITED = 69 RESULT_AFFECT_MULTIPLE_DSAS = 71 RESULT_OTHER = 80 RESULT_LCUP_RESOURCES_EXHAUSTED = 113 RESULT_LCUP_SECURITY_VIOLATION = 114 RESULT_LCUP_INVALID_DATA = 115 RESULT_LCUP_UNSUPPORTED_SCHEME = 116 RESULT_LCUP_RELOAD_REQUIRED = 117 RESULT_CANCELED = 118 RESULT_NO_SUCH_OPERATION = 119 RESULT_TOO_LATE = 120 RESULT_CANNOT_CANCEL = 121 RESULT_ASSERTION_FAILED = 122 RESULT_AUTHORIZATION_DENIED = 123 RESULT_E_SYNC_REFRESH_REQUIRED = 4096 # do not raise exception for (in raise_exceptions connection mode) DO_NOT_RAISE_EXCEPTIONS = [RESULT_SUCCESS, RESULT_COMPARE_FALSE, RESULT_COMPARE_TRUE, RESULT_REFERRAL] # get rootDSE info GET_NO_INFO = 0 GET_DSA_INFO = 1 GET_SCHEMA_INFO = 2 GET_ALL_INFO = 3 # OID database definition OID_CONTROL = 0 OID_EXTENSION = 1 OID_FEATURE = 2 OID_UNSOLICITED_NOTICE = 3 OID_ATTRIBUTE_TYPE = 4 OID_DIT_CONTENT_RULE = 5 OID_LDAP_URL_EXTENSION = 6 OID_FAMILY = 7 OID_MATCHING_RULE = 8 OID_NAME_FORM = 9 OID_OBJECT_CLASS = 10 OID_ADMINISTRATIVE_ROLE = 11 OID_LDAP_SYNTAX = 12 # class kind CLASS_STRUCTURAL = 0 CLASS_ABSTRACT = 1 CLASS_AUXILIARY = 2 # attribute kind ATTRIBUTE_USER_APPLICATION = 0 ATTRIBUTE_DIRECTORY_OPERATION = 1 ATTRIBUTE_DISTRIBUTED_OPERATION = 2 ATTRIBUTE_DSA_OPERATION = 3 # abstraction layer ABSTRACTION_OPERATIONAL_ATTRIBUTE_PREFIX = 'OP_' # server pooling POOLING_STRATEGY_FIRST = 0 POOLING_STRATEGY_ROUND_ROBIN = 1 POOLING_STRATEGY_RANDOM = 2 POOLING_STRATEGIES = [POOLING_STRATEGY_FIRST, POOLING_STRATEGY_ROUND_ROBIN, POOLING_STRATEGY_RANDOM] from .core.server import Server from .core.connection import Connection from .core.tls import Tls from .core.pooling import ServerPool from .abstract import ObjectDef, AttrDef, Attribute, Entry, Reader, OperationalAttribute from .core.exceptions import LDAPException, LDAPExceptionError, LDAPSocketCloseError, LDAPReferralError, LDAPAttributeError, LDAPBindError, LDAPCertificateError, LDAPChangesError, LDAPCommunicationError, LDAPConnectionIsReadOnlyError, \ LDAPConnectionPoolNameIsMandatoryError, LDAPConnectionPoolNotStartedError, LDAPControlsError, LDAPEntryError, LDAPInvalidDereferenceAliasesError, LDAPInvalidFilterError, LDAPInvalidScopeError, LDAPInvalidServerError, LDAPKeyError, LDAPLDIFError, \ LDAPMetricsError, LDAPObjectClassError, LDAPObjectError, LDAPPasswordIsMandatoryError, LDAPReaderError, LDAPSASLBindInProgressError, LDAPSASLMechanismNotSupportedError, LDAPSASLPrepError, LDAPSchemaError, LDAPServerPoolError, \ LDAPServerPoolExhaustedError, LDAPSocketOpenError, LDAPSocketReceiveError, LDAPSocketSendError, LDAPSSLConfigurationError, LDAPSSLNotSupportedError, LDAPStartTLSError, LDAPTypeError, LDAPUnknownAuthenticationMethodError, LDAPUnknownRequestError, \ LDAPUnknownResponseError, LDAPUnknownStrategyError from .core.exceptions import LDAPAdminLimitExceededResult, LDAPAffectMultipleDSASResult, LDAPAliasDereferencingProblemResult, LDAPAliasProblemResult, LDAPAssertionFailedResult, LDAPAttributeOrValueExistsResult, LDAPAuthMethodNotSupportedResult, \ LDAPAuthorizationDeniedResult, LDAPBusyResult, LDAPCanceledResult, LDAPCannotCancelResult, LDAPConfidentialityRequiredResult, LDAPConstraintViolationResult, LDAPEntryAlreadyExistsResult, LDAPESyncRefreshRequiredResult, \ LDAPInappropriateAuthenticationResult, LDAPInappropriateMatchingResult, LDAPInsufficientAccessRightsResult, LDAPInvalidAttributeSyntaxResult, LDAPInvalidCredentialsResult, LDAPInvalidDNSyntaxResult, LDAPLCUPInvalidDataResult, \ LDAPLCUPReloadRequiredResult, LDAPLCUPResourcesExhaustedResult, LDAPLCUPSecurityViolationResult, LDAPLCUPUnsupportedSchemeResult, LDAPLoopDetectedResult, LDAPNamingViolationResult, LDAPNoSuchAttributeResult, LDAPNoSuchObjectResult, \ LDAPNoSuchOperationResult, LDAPNotAllowedOnNotLeafResult, LDAPNotAllowedOnRDNResult, LDAPObjectClassModsProhibitedResult, LDAPObjectClassViolationResult, LDAPOperationResult, LDAPOperationsErrorResult, LDAPOtherResult, LDAPProtocolErrorResult, \ LDAPReferralResult, LDAPSASLBindInProgressResult, LDAPSizeLimitExceededResult, LDAPStrongerAuthRequiredResult, LDAPTimeLimitExceededResult, LDAPTooLateResult, LDAPUnavailableCriticalExtensionResult, LDAPUnavailableResult, \ LDAPUndefinedAttributeTypeResult, LDAPUnwillingToPerformResult, LDAPMaximumRetriesError, LDAPExtensionError python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/0000777000000000000000000000000012355117540020763 5ustar 00000000000000python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/dependency_links.txt0000666000000000000000000000000112355117540025031 0ustar 00000000000000 python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/PKG-INFO0000666000000000000000000000175412355117540022067 0ustar 00000000000000Metadata-Version: 1.1 Name: python3-ldap Version: 0.9.4.2 Summary: A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible Home-page: https://www.assembla.com/spaces/python3-ldap Author: Giovanni Cannata Author-email: python3ldap@gmail.com License: LGPL v3 Description: UNKNOWN Keywords: python3 python2 ldap Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX :: Linux Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/requires.txt0000666000000000000000000000002012355117540023353 0ustar 00000000000000pyasn1 == 0.1.7 python3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/SOURCES.txt0000666000000000000000000000503612355117540022653 0ustar 00000000000000COPYING.LESSER.txt COPYING.txt LICENSE.txt MANIFEST.in README.txt requirements.txt setup.cfg setup.py python3-ldap/ldap3/__init__.py python3-ldap/ldap3/abstract/__init__.py python3-ldap/ldap3/abstract/attrDef.py python3-ldap/ldap3/abstract/attribute.py python3-ldap/ldap3/abstract/entry.py python3-ldap/ldap3/abstract/objectDef.py python3-ldap/ldap3/abstract/operationalAttribute.py python3-ldap/ldap3/abstract/reader.py python3-ldap/ldap3/compat/__init__.py python3-ldap/ldap3/compat/connection.py python3-ldap/ldap3/compat/server.py python3-ldap/ldap3/compat/tls.py python3-ldap/ldap3/core/__init__.py python3-ldap/ldap3/core/connection.py python3-ldap/ldap3/core/exceptions.py python3-ldap/ldap3/core/pooling.py python3-ldap/ldap3/core/server.py python3-ldap/ldap3/core/tls.py python3-ldap/ldap3/core/usage.py python3-ldap/ldap3/extend/__init__.py python3-ldap/ldap3/extend/getBindDn.py python3-ldap/ldap3/extend/modifyPassword.py python3-ldap/ldap3/extend/whoAmI.py python3-ldap/ldap3/operation/__init__.py python3-ldap/ldap3/operation/abandon.py python3-ldap/ldap3/operation/add.py python3-ldap/ldap3/operation/bind.py python3-ldap/ldap3/operation/compare.py python3-ldap/ldap3/operation/delete.py python3-ldap/ldap3/operation/extended.py python3-ldap/ldap3/operation/modify.py python3-ldap/ldap3/operation/modifyDn.py python3-ldap/ldap3/operation/search.py python3-ldap/ldap3/operation/unbind.py python3-ldap/ldap3/protocol/__init__.py python3-ldap/ldap3/protocol/convert.py python3-ldap/ldap3/protocol/novell.py python3-ldap/ldap3/protocol/oid.py python3-ldap/ldap3/protocol/rfc2696.py python3-ldap/ldap3/protocol/rfc2849.py python3-ldap/ldap3/protocol/rfc3062.py python3-ldap/ldap3/protocol/rfc4511.py python3-ldap/ldap3/protocol/rfc4512.py python3-ldap/ldap3/protocol/rfc4532.py python3-ldap/ldap3/protocol/sasl/__init__.py python3-ldap/ldap3/protocol/sasl/digestMd5.py python3-ldap/ldap3/protocol/sasl/external.py python3-ldap/ldap3/protocol/sasl/sasl.py python3-ldap/ldap3/strategy/__init__.py python3-ldap/ldap3/strategy/asyncThreaded.py python3-ldap/ldap3/strategy/baseStrategy.py python3-ldap/ldap3/strategy/ldifProducer.py python3-ldap/ldap3/strategy/reusableThreaded.py python3-ldap/ldap3/strategy/syncWait.py python3-ldap/ldap3/strategy/syncWaitRestartable.py python3-ldap/ldap3/utils/__init__.py python3-ldap/ldap3/utils/conv.py python3-ldap/python3_ldap.egg-info/PKG-INFO python3-ldap/python3_ldap.egg-info/SOURCES.txt python3-ldap/python3_ldap.egg-info/dependency_links.txt python3-ldap/python3_ldap.egg-info/requires.txt python3-ldap/python3_ldap.egg-info/top_level.txtpython3-ldap-0.9.4.2/python3-ldap/python3_ldap.egg-info/top_level.txt0000666000000000000000000000000612355117540023511 0ustar 00000000000000ldap3 python3-ldap-0.9.4.2/README.txt0000666000000000000000000003307712355112231014043 0ustar 00000000000000License ------- The python3-ldap project is open source and released under the LGPL v3 license. PEP8 Compliance --------------- python3-ldap is PEP8 compliance (except for line length) starting from version 0.9.0. Mailing List ------------ You can join the python3-ldap mailing list at http://mail.python.org/mailman/listinfo/python3-ldap Home Page --------- Project home page is https://bitbucket.org/python3ldap/python3-ldap Documentation ------------- Documentation is available at http://pythonhosted.org/python3-ldap Download -------- Package download is available at https://pypi.python.org/pypi/python3-ldap or via pip Mercurial (hg) repository ------------------------- You can download the latest source at https://bitbucket.org/python3ldap/python3-ldap Support ------- You can submit support tickets on https://bitbucket.org/python3ldap/python3-ldap/issues Acknowledgements ---------------- * I wish to thank **Ilya Etingof**, the author of the *pyasn1* package for his excellent work and support. * I wish to thank **Mark Lutz** for his *Learning Python* and *Programming Python* excellent books series and **John Goerzen** and **Brandon Rhodes** for their book *Foundations of Python Network Programming*. These books are wonderful tools for learning Python and this project owes a lot to them. * I wish to thank **JetBrains** for donating to this project the Open Source license of *PyCharm 3 Professional*. * I wish to thank **Atlassian** for providing the *free source repository space and the tools* I use to develop this project. Contact me ---------- For information and suggestions you can contact me at python3ldap@gmail.com or you can join the python3-ldap mailing list at http://mail.python.org/mailman/listinfo/python3-ldap. You can also open a support ticket on https://www.assembla.com/spaces/python3-ldap/support/tickets CHANGELOG ========= * 0.9.4.2 2014.07.03 - Moved to Bitbucket + Mercurial - Fixed import in core.tls package - Removed unneeded imports * 0.9.4.1 2014.07.02 - included missing extend package (thanks to debnet) * 0.9.4 2014.07.02 - when running in python 3.4 or newer now Tls class uses SSLContext object with default secure setting - added parameters ca_certs_path, ca_certs_data, local_private_key_password to Tls object creation, valid when using SSLContext - in python 3.4 or newer the system CA certificates configuration can be used (just leave ca_cert_file, ca_certs_path and ca_certs_data set to None) - removed TLSv1 as default for Tls connection - upgraded backported ssl function from python 3.4.1 when using with python 2 - when creating a connection server can now be a string, the name of the server to connect in cleartext on default port 389 - fixed bug in ldap3.util.conv.escape_bytes() - attributes parameter in search can be a tuple - check_names parameter in connection now defaults to True (so if schema info is available attribute and class name will be checked when performing LDAP operations) - remove the connection.close() method - you must use connection.unbind() - new exception LDAPExtensionError for signaling when the requestValue of extended operation is of unknown ASN1 type - exiting connection manager doesn't raise exception if unbind is not successful (needed in long operations) - new extended operation: modify_password (RFC3062) - new extended operation: who_am_i (RFC4532) - new extended operation: get_bind_dn (Novell) - updated setuptools to version 5.3 * 0.9.3.5 2014.06.22 - Exception history in restartable strategy is printed when reached the maximum number of retries - Fixed conditions on terminated_by_server unsolicited message - Added python2.6 egg installation package * 0.9.3.4 2014.06.16 - Exception can now be imported from ldap3 package - Escape_bytes return '' for empty string instead of None (thanks Brian) - Added exception history to restartable connection (except than for infinite retries) - Fixed start_tls retrying in restartable connection (thanks Brian) - New exception LDAPMaximumRetriesError for signaling when the SyncRestartable Strategy has reached the maximum number of retries while performing an operation - Inverted deleteoldrdn value in LDIF output (thanks Joseph) * 0.9.3.3 2014.06.01 - Fixed a bug in LDIFProducer when using context manager for connection - LDIF header in stream is added only whene there are actua data in the stream - Now LDIF stream can be added to an existing file - version header will not be written if stream is not empty * 0.9.3.2 2014.05.30 - Fixed a bug while reading schema - Add an implicit open() when trying binding on a closed connection * 0.9.3.1 2014.05.28 - Added stream capability to LDIFProducer strategy - Customizable line separator for ldif output - Customizable sorting order in ldif output - object_class parameter is now optional in connection.add() - Fixed objectClass attribute case sensitive dependency in add operation - Added stream capability to response_to_ldif() while searching * 0.9.3 2014.05.20 - Now the key in server.schema.attribute_type is the attribute name (was the oid) - Now the key in server.schema.object_classes is the class name (was the oid) - Added check_names to Connection definition to have the names of attributes and object class checked against the schema - Updated setuptools to 3.6 - Added wheel installation format - Added raise_exceptions mode for connection - Exception hierarchy reworked - Added locking to Server object (for multithreading) * 0.9.2.2 2014.04.30 - fixed a bug from 0.9.1 that broke start_tls() (thanks Mark) * 0.9.2.1 2014.04.28 - fixed a bug in 0.9.2 that allowed only string attributes in add, modify and compare operations (thank Mladen) * 0.9.2 2014.04.26 - changed return value in get_response from response to (response, result) - helpful for multi threaded connections - added ReusableStrategy for pooling connections - refined docstrings (thanks Will) - result and response attributes don't overlap anymore. Operation result is only in result attribute. - fixed search for binary values (thanks Marcin) - added convenience function to convert bytes to LDAP binary value string format for search filter * 0.9.1 2014.03.30 - added laziness flag to test suite - changed ServerPool signature to accept active and exhaust parameters - removed unneeded start_listen parameter - added 'lazy' parameter to open, to bind and to unbind a connection only when an effective operation is performed - fixed start_tls in SyncWaitRestartable strategy - fixed certificate name checking while opening an ssl connection - fixed syntax error during installation - socket operations now raises proper exception, not generic LDAPException (thanks Joseph) - tested against Python 3.4, 3.3, 2.7, 2.6 - updated setuptools to 3.3 * 0.9.0 2014.03.20 - PEP8 compliance - added ldap3.compat package with older (non PEP8 compliant) signatures - renamed ldap3.abstraction to ldap3.abstract - moved connection.py, server.py and tls.py files to ldap3.core - fixed SyncWaitRestartableStrategy (thanks Christoph) * 0.8.3 2014.03.08 - added SyncWaitRestartable strategy - removed useless forceBind parameter - usage statistics updated with restartable success/failure counters and open/closed/wrapped socket counters * 0.8.2 2014.03.04 - Added refresh() method to Entry object to read again the attributes from the Reader in the abstraction layer - Fixed Python 2.6 issues - Fixed test suite for Python 2.6 * 0.8,1 2014.02.12 - Changed exceptions returned by the library to LDAPException, a subclass of Exception. - Fixed documentation typos * 0.8.0 - 2014.02.08 - Added abstraction layer (for searching) - Added context manager to Connection class - Added readOnly parameter to Connection class - Fixed a bug in search with 'less than' parameter - Remove validation of available SSL protocols because different Python interpreters can use different ssl packages * 0.7.3 - 2014.01.05 - Added SASL DIGEST-MD5 support - Moved to intrapackage (relative) imports * 0.7.2 - 2013.12.30 - Fixed a bug when parentheses are used in search filter as ASCII escaped sequences * 0.7.1 - 2013.12.21 - Completed support for LDFI as per RFC2849 - Added new LDIF_PRODUCER strategy to generate LDIF-CHANGE stream - Fixed a bug in the autoReferral feature when controls where used in operation * 0.7.0 - 2013.12.12 - Added support for LDIF as per RFC2849 - Added LDIF-CONTENT compliant search responses - Added exception when using autoBind if connection is not successful * 0.6.7 - 2013.12.03 - Fixed exception when DSA is not willing to return rootDSE and schema info * 0.6.6 - 2013.11.13 - Added parameters to test suite * 0.6.5 - 2013.11.05 - Modified rawAttributes decoding, now null (empty) values are returned * 0.6.4 - 2013.10.16 - Added simple paged search as per RFC2696 - Controls return values are decoded and stored in result attribute of connection * 0.6.3 - 2013.10.07 - Added Extesible Filter syntax to search filter - Fixed exception while closing connection in AsyncThreaded strategy * 0.6.2 - 2013.10.01 - Fix for referrals in searchRefResult - Disabled schema reading on Active Directory * 0.6.1 - 2013.09.22 - Experimental support for Python 2 - no unicode - Added backport of ssl.match_name for Python 2 - Minor fixes for using the client in Python 2 - Fix for getting schema info with AsyncThreaded strategy * 0.6.0 - 2013.09.16 - Moved to beta! - Added support site hosted on www.assembla.com - Added public svn repository on www.assembla.com - Added getInfo to server object, parameter can be: GET_NO_INFO, GET_DSA_INFO, GET_SCHEMA_INFO, GET_ALL_INFO - Added method to read the schema from the server. Schema is decoded and returned in different dictionaries of the server.schema object - Updated connection usage info (elapsed time is now computed when connection is closed) - Updated OID dictionary with extensions and controls from Active Directory specifications. * 0.5.3 - 2013.09.03 - Added getOperationalAttributes boolean to Search operation to fetch the operational attributes during search - Added increment operation to modify operation as per RFC4525 - Added dictionary of OID descriptions (for DSE and schema decoding) - Added method to get Info from DSE (returned in server.info object) - Modified exceptions for sending controls in LDAP request - Added connection usage (in connection.usage if collectUsage=True in connection definition) - Fixed StartTls in asynchronous client strategy * 0.5.2 - 2013.08.27 - Added SASLprep profile for validating password - Fixed RFC4511 asn1 definitions * 0.5.1 - 2013.08.17 - Refactored package structure - Project description reformatted with reStructuredText - Added Windows graphical installation * 0.5.0 - 2013.08.15 - Added reference to LGPL v3 license - Added Tls object to hold ssl/tls configuration - Added StartTLS feature - Added SASL feature - Added SASL EXTERNAL mechanism - Fixed Unbind - connection.close in now an alias for connection.unbind * 0.4.4 - 2013.08.01 - Added 'Controls' to all LDAP Requests - Added Extended Request feature - Added Intermediate Response feature - Added namespace 'ldap3' * 0.4.3 - 2013.07.31 - Test suite refactored - Fixed single object search response error - Changed attributes returned in search from tuple to dict - Added 'raw_attributes' key in search response to hold undecoded (binary) attribute values read from ldap - Added __repr__ for Server and Connection objects to re-create the object instance * 0.4.2 - 2013.07.29 - Added autoReferral feature as per RFC4511 (4.1.10) - Added allowedReferralHosts to conform to Security considerations of RFC4516 * 0.4.1 - 2013.07.20 - Add validation to Abandon operation - Added connection.request to hold a dictionary of infos about last request - Added info about outstanding operation in connection.strategy._oustanding - Implemented RFC4515 for search filter coding and decoding - Added a parser to build filter string from LdapMessage * 0.4.0 - 2013.07.15 - Refactoring of the connection and strategy classes - Added the ldap3.strategy namespace to contain client connection strategies - Added ssl authentication - Moved authentication parameters from Server object to Connection object - Added ssl parameters to Server Object * 0.3.0 - 2013.07.14 - Fixed AsyncThreaded strategy with _outstanding and _responses attributes to hold the pending requests and the not-yet-read responses - Added Extended Operation - Added "Unsolicited Notification" discover logic - Added managing of "Notice of Disconnection" from server to properly close connection * 0.2.0 - 2013.07.13 - Update setup with setuptools 0.7 - Docstrings added to class - Removed ez_setup dependency - Removed distribute dependency * 0.1.0 - 2013.07.12 - Initial upload on pypi - PyASN1 RFC4511 module completed and tested - Synchronous client working properly - Asynchronous client working but not fully tested - Basic authentication working python3-ldap-0.9.4.2/requirements.txt0000666000000000000000000000001712355103747015631 0ustar 00000000000000pyasn1==0.1.7 python3-ldap-0.9.4.2/setup.cfg0000666000000000000000000000013212355117540014160 0ustar 00000000000000[wheel] universal = 1 [egg_info] tag_date = 0 tag_svn_revision = 0 tag_build = python3-ldap-0.9.4.2/setup.py0000666000000000000000000000454212355105074014061 0ustar 00000000000000""" Created on 2013.07.11 @author: Giovanni Cannata Copyright 2013 Giovanni Cannata This file is part of python3-ldap. python3-ldap is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. python3-ldap 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with python3-ldap in the COPYING and COPYING.LESSER files. If not, see . """ from setuptools import setup setup(name='python3-ldap', version='0.9.4.2', packages=['ldap3', 'ldap3.core', 'ldap3.abstract', 'ldap3.operation', 'ldap3.protocol', 'ldap3.protocol.sasl', 'ldap3.strategy', 'ldap3.compat', 'ldap3.utils', 'ldap3.extend' ], package_dir={'': 'python3-ldap'}, install_requires=['pyasn1 == 0.1.7'], license='LGPL v3', author='Giovanni Cannata', author_email='python3ldap@gmail.com', description='A strictly RFC 4511 conforming LDAP V3 pure Python 3 client - Python 2 compatible', keywords='python3 python2 ldap', url='https://www.assembla.com/spaces/python3-ldap', classifiers=['Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP'] )