├── .gitignore ├── COPYING ├── Makefile ├── README.md ├── SConstruct ├── _config.yml ├── adclient.cpp ├── adclient.h ├── adclient.py ├── adclient.swigcxx ├── adclient_krb.cpp ├── adclient_sasl.cpp ├── adclient_test.go ├── adclient_wrapper.go ├── adclient_wrapper_python2.cpp ├── adclient_wrapper_python3.cpp └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .scon* 2 | *.os 3 | *.so 4 | *.pyc 5 | *.log 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place - Suite 330, Boston, MA 6 | 02111-1307, USA. 7 | Everyone is permitted to copy and distribute verbatim copies 8 | of this license document, but changing it is not allowed. 9 | 10 | Preamble 11 | 12 | The licenses for most software are designed to take away your 13 | freedom to share and change it. By contrast, the GNU General Public 14 | License is intended to guarantee your freedom to share and change free 15 | software--to make sure the software is free for all its users. This 16 | General Public License applies to most of the Free Software 17 | Foundation's software and to any other program whose authors commit to 18 | using it. (Some other Free Software Foundation software is covered by 19 | the GNU Library General Public License instead.) You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | this service if you wish), that you receive source code or can get it 26 | if you want it, that you can change the software or use pieces of it 27 | in new free programs; and that you know you can do these things. 28 | 29 | To protect your rights, we need to make restrictions that forbid 30 | anyone to deny you these rights or to ask you to surrender the rights. 31 | These restrictions translate to certain responsibilities for you if you 32 | distribute copies of the software, or if you modify it. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must give the recipients all the rights that 36 | you have. You must make sure that they, too, receive or can get the 37 | source code. And you must show them these terms so they know their 38 | rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and 41 | (2) offer you this license which gives you legal permission to copy, 42 | distribute and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain 45 | that everyone understands that there is no warranty for this free 46 | software. If the software is modified by someone else and passed on, we 47 | want its recipients to know that what they have is not the original, so 48 | that any problems introduced by others will not reflect on the original 49 | authors' reputations. 50 | 51 | Finally, any free program is threatened constantly by software 52 | patents. We wish to avoid the danger that redistributors of a free 53 | program will individually obtain patent licenses, in effect making the 54 | program proprietary. To prevent this, we have made it clear that any 55 | patent must be licensed for everyone's free use or not licensed at all. 56 | 57 | The precise terms and conditions for copying, distribution and 58 | modification follow. 59 | 60 | GNU GENERAL PUBLIC LICENSE 61 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 62 | 63 | 0. This License applies to any program or other work which contains 64 | a notice placed by the copyright holder saying it may be distributed 65 | under the terms of this General Public License. The "Program", below, 66 | refers to any such program or work, and a "work based on the Program" 67 | means either the Program or any derivative work under copyright law: 68 | that is to say, a work containing the Program or a portion of it, 69 | either verbatim or with modifications and/or translated into another 70 | language. (Hereinafter, translation is included without limitation in 71 | the term "modification".) Each licensee is addressed as "you". 72 | 73 | Activities other than copying, distribution and modification are not 74 | covered by this License; they are outside its scope. The act of 75 | running the Program is not restricted, and the output from the Program 76 | is covered only if its contents constitute a work based on the 77 | Program (independent of having been made by running the Program). 78 | Whether that is true depends on what the Program does. 79 | 80 | 1. You may copy and distribute verbatim copies of the Program's 81 | source code as you receive it, in any medium, provided that you 82 | conspicuously and appropriately publish on each copy an appropriate 83 | copyright notice and disclaimer of warranty; keep intact all the 84 | notices that refer to this License and to the absence of any warranty; 85 | and give any other recipients of the Program a copy of this License 86 | along with the Program. 87 | 88 | You may charge a fee for the physical act of transferring a copy, and 89 | you may at your option offer warranty protection in exchange for a fee. 90 | 91 | 2. You may modify your copy or copies of the Program or any portion 92 | of it, thus forming a work based on the Program, and copy and 93 | distribute such modifications or work under the terms of Section 1 94 | above, provided that you also meet all of these conditions: 95 | 96 | a) You must cause the modified files to carry prominent notices 97 | stating that you changed the files and the date of any change. 98 | 99 | b) You must cause any work that you distribute or publish, that in 100 | whole or in part contains or is derived from the Program or any 101 | part thereof, to be licensed as a whole at no charge to all third 102 | parties under the terms of this License. 103 | 104 | c) If the modified program normally reads commands interactively 105 | when run, you must cause it, when started running for such 106 | interactive use in the most ordinary way, to print or display an 107 | announcement including an appropriate copyright notice and a 108 | notice that there is no warranty (or else, saying that you provide 109 | a warranty) and that users may redistribute the program under 110 | these conditions, and telling the user how to view a copy of this 111 | License. (Exception: if the Program itself is interactive but 112 | does not normally print such an announcement, your work based on 113 | the Program is not required to print an announcement.) 114 | 115 | These requirements apply to the modified work as a whole. If 116 | identifiable sections of that work are not derived from the Program, 117 | and can be reasonably considered independent and separate works in 118 | themselves, then this License, and its terms, do not apply to those 119 | sections when you distribute them as separate works. But when you 120 | distribute the same sections as part of a whole which is a work based 121 | on the Program, the distribution of the whole must be on the terms of 122 | this License, whose permissions for other licensees extend to the 123 | entire whole, and thus to each and every part regardless of who wrote it. 124 | 125 | Thus, it is not the intent of this section to claim rights or contest 126 | your rights to work written entirely by you; rather, the intent is to 127 | exercise the right to control the distribution of derivative or 128 | collective works based on the Program. 129 | 130 | In addition, mere aggregation of another work not based on the Program 131 | with the Program (or with a work based on the Program) on a volume of 132 | a storage or distribution medium does not bring the other work under 133 | the scope of this License. 134 | 135 | 3. You may copy and distribute the Program (or a work based on it, 136 | under Section 2) in object code or executable form under the terms of 137 | Sections 1 and 2 above provided that you also do one of the following: 138 | 139 | a) Accompany it with the complete corresponding machine-readable 140 | source code, which must be distributed under the terms of Sections 141 | 1 and 2 above on a medium customarily used for software interchange; or, 142 | 143 | b) Accompany it with a written offer, valid for at least three 144 | years, to give any third party, for a charge no more than your 145 | cost of physically performing source distribution, a complete 146 | machine-readable copy of the corresponding source code, to be 147 | distributed under the terms of Sections 1 and 2 above on a medium 148 | customarily used for software interchange; or, 149 | 150 | c) Accompany it with the information you received as to the offer 151 | to distribute corresponding source code. (This alternative is 152 | allowed only for noncommercial distribution and only if you 153 | received the program in object code or executable form with such 154 | an offer, in accord with Subsection b above.) 155 | 156 | The source code for a work means the preferred form of the work for 157 | making modifications to it. For an executable work, complete source 158 | code means all the source code for all modules it contains, plus any 159 | associated interface definition files, plus the scripts used to 160 | control compilation and installation of the executable. However, as a 161 | special exception, the source code distributed need not include 162 | anything that is normally distributed (in either source or binary 163 | form) with the major components (compiler, kernel, and so on) of the 164 | operating system on which the executable runs, unless that component 165 | itself accompanies the executable. 166 | 167 | If distribution of executable or object code is made by offering 168 | access to copy from a designated place, then offering equivalent 169 | access to copy the source code from the same place counts as 170 | distribution of the source code, even though third parties are not 171 | compelled to copy the source along with the object code. 172 | 173 | 4. You may not copy, modify, sublicense, or distribute the Program 174 | except as expressly provided under this License. Any attempt 175 | otherwise to copy, modify, sublicense or distribute the Program is 176 | void, and will automatically terminate your rights under this License. 177 | However, parties who have received copies, or rights, from you under 178 | this License will not have their licenses terminated so long as such 179 | parties remain in full compliance. 180 | 181 | 5. You are not required to accept this License, since you have not 182 | signed it. However, nothing else grants you permission to modify or 183 | distribute the Program or its derivative works. These actions are 184 | prohibited by law if you do not accept this License. Therefore, by 185 | modifying or distributing the Program (or any work based on the 186 | Program), you indicate your acceptance of this License to do so, and 187 | all its terms and conditions for copying, distributing or modifying 188 | the Program or works based on it. 189 | 190 | 6. Each time you redistribute the Program (or any work based on the 191 | Program), the recipient automatically receives a license from the 192 | original licensor to copy, distribute or modify the Program subject to 193 | these terms and conditions. You may not impose any further 194 | restrictions on the recipients' exercise of the rights granted herein. 195 | You are not responsible for enforcing compliance by third parties to 196 | this License. 197 | 198 | 7. If, as a consequence of a court judgment or allegation of patent 199 | infringement or for any other reason (not limited to patent issues), 200 | conditions are imposed on you (whether by court order, agreement or 201 | otherwise) that contradict the conditions of this License, they do not 202 | excuse you from the conditions of this License. If you cannot 203 | distribute so as to satisfy simultaneously your obligations under this 204 | License and any other pertinent obligations, then as a consequence you 205 | may not distribute the Program at all. For example, if a patent 206 | license would not permit royalty-free redistribution of the Program by 207 | all those who receive copies directly or indirectly through you, then 208 | the only way you could satisfy both it and this License would be to 209 | refrain entirely from distribution of the Program. 210 | 211 | If any portion of this section is held invalid or unenforceable under 212 | any particular circumstance, the balance of the section is intended to 213 | apply and the section as a whole is intended to apply in other 214 | circumstances. 215 | 216 | It is not the purpose of this section to induce you to infringe any 217 | patents or other property right claims or to contest validity of any 218 | such claims; this section has the sole purpose of protecting the 219 | integrity of the free software distribution system, which is 220 | implemented by public license practices. Many people have made 221 | generous contributions to the wide range of software distributed 222 | through that system in reliance on consistent application of that 223 | system; it is up to the author/donor to decide if he or she is willing 224 | to distribute software through any other system and a licensee cannot 225 | impose that choice. 226 | 227 | This section is intended to make thoroughly clear what is believed to 228 | be a consequence of the rest of this License. 229 | 230 | 8. If the distribution and/or use of the Program is restricted in 231 | certain countries either by patents or by copyrighted interfaces, the 232 | original copyright holder who places the Program under this License 233 | may add an explicit geographical distribution limitation excluding 234 | those countries, so that distribution is permitted only in or among 235 | countries not thus excluded. In such case, this License incorporates 236 | the limitation as if written in the body of this License. 237 | 238 | 9. The Free Software Foundation may publish revised and/or new versions 239 | of the General Public License from time to time. Such new versions will 240 | be similar in spirit to the present version, but may differ in detail to 241 | address new problems or concerns. 242 | 243 | Each version is given a distinguishing version number. If the Program 244 | specifies a version number of this License which applies to it and "any 245 | later version", you have the option of following the terms and conditions 246 | either of that version or of any later version published by the Free 247 | Software Foundation. If the Program does not specify a version number of 248 | this License, you may choose any version ever published by the Free Software 249 | Foundation. 250 | 251 | 10. If you wish to incorporate parts of the Program into other free 252 | programs whose distribution conditions are different, write to the author 253 | to ask for permission. For software which is copyrighted by the Free 254 | Software Foundation, write to the Free Software Foundation; we sometimes 255 | make exceptions for this. Our decision will be guided by the two goals 256 | of preserving the free status of all derivatives of our free software and 257 | of promoting the sharing and reuse of software generally. 258 | 259 | NO WARRANTY 260 | 261 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 262 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 263 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 264 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 265 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 266 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 267 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 268 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 269 | REPAIR OR CORRECTION. 270 | 271 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 272 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 273 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 274 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 275 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 276 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 277 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 278 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 279 | POSSIBILITY OF SUCH DAMAGES. 280 | 281 | END OF TERMS AND CONDITIONS 282 | 283 | Appendix: How to Apply These Terms to Your New Programs 284 | 285 | If you develop a new program, and you want it to be of the greatest 286 | possible use to the public, the best way to achieve this is to make it 287 | free software which everyone can redistribute and change under these terms. 288 | 289 | To do so, attach the following notices to the program. It is safest 290 | to attach them to the start of each source file to most effectively 291 | convey the exclusion of warranty; and each file should have at least 292 | the "copyright" line and a pointer to where the full notice is found. 293 | 294 | 295 | Copyright (C) 19yy 296 | 297 | This program is free software; you can redistribute it and/or modify 298 | it under the terms of the GNU General Public License as published by 299 | the Free Software Foundation; either version 2 of the License, or 300 | (at your option) any later version. 301 | 302 | This program is distributed in the hope that it will be useful, 303 | but WITHOUT ANY WARRANTY; without even the implied warranty of 304 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 305 | GNU General Public License for more details. 306 | 307 | You should have received a copy of the GNU General Public License 308 | along with this program; if not, write to the Free Software 309 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | libadclient: 2 | g++ -o adclient.os -c -O0 -g -Wall -fPIC -I. -I/usr/local/include -I/usr/include adclient.cpp 3 | g++ -o libadclient.so -shared adclient.os -L/usr/lib -L/usr/local/lib -L/lib -lldap -lstdc++ 4 | clean: 5 | rm -f libadclient.so adclient.os 6 | install: libadclient 7 | #install -v -s libadclient.so /usr/local/lib/ 8 | cp -v libadclient.so /usr/local/lib/ 9 | uninstall: 10 | rm -fv /usr/local/lib/libadclient.so 11 | package: clean 12 | rm -f ../libadclient-unix.tar.bz2 && cd ../ && tar --exclude=build --exclude=config.log --exclude=*scon* --exclude=Makefile --exclude=.svn --exclude=temp -cvjf libadclient-unix.tar.bz2 libadclient-unix 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [libadclient](https://paleg.github.io/libadclient/) 2 | 3 | libadclient - Active Directory client for c++, Python and Golang. 4 | 5 | **Table of Contents** 6 | 7 | - [Description](#description) 8 | - [Install](#install) 9 | - [c++ and Python](#c-and-python) 10 | - [OS X > 10.11](#os-x--1011) 11 | - [Golang](#golang) 12 | - [Usage notes](#usage-notes) 13 | - [Active Directory binding](#active-directory-binding) 14 | - [Binary values in object attributes](#binary-values-in-object-attributes) 15 | - [Helper functions](#helper-functions) 16 | - [FileTimeToPOSIX](#filetimetoposix) 17 | - [Decode SID](#decode-sid) 18 | - [IP to int and vise versa](#ip-to-int-and-vise-versa) 19 | - [Getting LDAP URIes list for domain/site](#getting-ldap-uries-list-for-domainsite) 20 | - [Converting domain to distinguished name](#converting-domain-to-distinguished-name) 21 | - [Usage samples](#usage-samples) 22 | - [c++](#c) 23 | - [Python](#python) 24 | - [Golang](#golang-1) 25 | 26 | ## Description 27 | 28 | This simple C++/Python/Golang classes can be used to manipulate Active Directory from c++, Python and Golang programs. 29 | 30 | Full list of supported methods can be found in: 31 | * [adclient.h](https://github.com/paleg/libadclient/blob/master/adclient.h) (for c++) 32 | * [adclient.py](https://github.com/paleg/libadclient/blob/master/adclient.py) (for Python) 33 | * [adclient_wrapper.go](https://github.com/paleg/libadclient/blob/master/adclient_wrapper.go) (for Golang) 34 | 35 | Requirements: 36 | * OpenLDAP or SunLDAP 37 | * SASL (DIGEST-MD5, GSSAPI) 38 | * KRB5 39 | 40 | ## Install 41 | 42 | ### c++ and Python 43 | 44 | Note: you must have [scons](http://www.scons.org/) installed 45 | 46 | ```bash 47 | git clone https://github.com/paleg/libadclient.git 48 | cd libadclient 49 | scons install (to build/install c++ library) 50 | python setup.py install (to build/install Python library) 51 | ``` 52 | 53 | Note: step 4 depends on step 3, if your want to upgrade Python module, you should upgrade c++ library first. 54 | 55 | #### OS X > 10.11 56 | 57 | If you are getting errors in Python while importing module: 58 | ```python 59 | ImportError: dlopen(/Library/Python/2.7/site-packages/_adclient.so, 2): Library not loaded: libadclient.dylib 60 | Referenced from: /Library/Python/2.7/site-packages/_adclient.so 61 | Reason: unsafe use of relative rpath libadclient.dylib in /Library/Python/2.7/site-packages/_adclient.so with restricted binary 62 | ``` 63 | that is because [System Integrity Protection](https://support.apple.com/en-us/HT204899). You can fix it with: 64 | ```bash 65 | sudo install_name_tool -change libadclient.dylib /usr/local/lib/libadclient.dylib /Library/Python/2.7/site-packages/_adclient.so 66 | ``` 67 | 68 | ### Golang 69 | ```shell 70 | go get github.com/paleg/libadclient 71 | ``` 72 | You must have swig >= 3.0.6 and Golang >= 1.4 to compile library. However, Golang >= 1.5.1 is recommended. 73 | When building Golang library **only** openldap >= 2.2 are supported. 74 | 75 | Note: this library is **not safe** for concurrent use. If you need to use library from concurrently executing goroutines, the calls must be mediated by some kind of synchronization mechanism (channels or mutexes). 76 | 77 | ## Usage notes 78 | 79 | ### Active Directory binding 80 | 81 | * boolean `adConnParams.use_tls` and `adConnParams.use_ldaps` choose binding method: 82 | + `adConnParams.use_tls` enables StartTLS extension to the LDAP protocol, normally served on port 389 83 | + `adConnParams.use_ldaps` enables non-standardized LDAP over SSL protocol, normally served on port 636 84 | + these two options are **mutually exclusive** and disabled by default 85 | + you must configure your `ldap.conf` properly for client to be able to validate your server's certificate. Check `man ldap.conf` for details. 86 | + `TLS_REQCERT allow` can be used in `ldap.conf` to ignore server's certificate check. 87 | * boolean `adConnParams.secured` and `adConnParams.use_gssapi` choose login authentication mode: 88 | + `SASL DIGEST-MD5` auth (default). It requires properly configured DNS (both direct and reverse) and SPN records (see [issue 1](https://github.com/paleg/libadclient/issues/1#issuecomment-131693081) for details). 89 | * `adConnParams.secured = true` 90 | * `adConnParams.use_gssapi = false` 91 | + `SASL GSSAPI` auth (`adConnParams.use_gssapi` must be set to `true`). It requires properly configured kerberos library (`krb5.conf`) with `default_keytab_name` set to keytab with computer account. `msktutil` can be used for this purpose, see [Squid Active Directory Integration](http://wiki.squid-cache.org/ConfigExamples/Authenticate/WindowsActiveDirectory#Kerberos) for example. 92 | * `adConnParams.secured = true` 93 | * `adConnParams.use_gssapi = true` 94 | + `simple` auth (clear text username and password). It does not require proper DNS and SPN setup, but with simple auth AD will refuse to do some actions (e.g. change passwords). **For some configurations (2008 domain?)**, to get simple auth to work, binddn must contain domain suffix i.e. `adConnParams.binddn = "user@domain.local"`). 95 | * `adConnParams.secured = false` 96 | * choosing Domain Controller to connect can be performed: 97 | + automatically with domain DNS name (`adConnParams.domain`) with optional [AD site name](https://technet.microsoft.com/en-us/library/cc754697\(v=ws.11\).aspx) (`adConnParams.site`): 98 | * ldap uries for `domain` will be detected via DNS SRV query (`_ldap._tcp.SITE._sites.DOMAIN.LOCAL` / `_ldap._tcp.DOMAIN.LOCAL`) 99 | * if `adConnParams.search_base` is empty - it will be constructed automatically from domain name (`DC=DOMAIN,DC=LOCAL`). 100 | + manually with vector of domain controller DNS names to connect to (`adConnParams.uries`): 101 | * `adConnParams.search_base` must be set explicitly. 102 | * `LDAP_OPT_NETWORK_TIMEOUT` and `LDAP_OPT_TIMEOUT` can be set with `adConnParams.nettimeout`. 103 | * `LDAP_OPT_TIMELIMIT` can be set with `adConnParams.timelimit`. 104 | * after successfull binding following methods can be used to check connection properties: 105 | + `binded_uri()` - to get connected server ldap URI 106 | + `search_base()` - to get current search base 107 | + `bind_method()` - to get method used for binding (`plain`, `StartTLS`, `LDAPS`) 108 | + `login_method()` - to get method used for login (`GSSAPI`, `DIGEST-MD5`, `SIMPLE`) 109 | 110 | ### Binary values in object attributes 111 | 112 | Some object attributes (e.g. `objectSid`) are stored in Active Directory as binary values, so some functions (e.g. `getObjectAttribute(user, "objectSid")`) can return binary data (which can include NULL character as well as any unprintable characters). Usually it is not a problem as in c++, Python and Golang `string` type can hold any values, but: 113 | * calling code should be ready to handle such values 114 | * in Python3, binary data will be returned as `bytes`, not `unicode` strings. 115 | 116 | ### Helper functions 117 | 118 | #### FileTimeToPOSIX 119 | 120 | * `FileTimeToPOSIX(long long filetime)` (c++) 121 | * `adclient.FileTimeToPOSIX(filetime)` (Python) 122 | * `adclient.FileTimeToPOSIX(filetime)` (golang) 123 | 124 | Can be used to convert 18-digit Active Directory timestamp to Unix epoch time. 125 | 126 | The 18-digit timestamps, also named `Windows NT time format`, `Win32 FILETIME or SYSTEMTIME` or `NTFS file time` are used in Microsoft Active Directory for `pwdLastSet`, `accountExpires`, `LastLogon`, `LastLogonTimestamp` and `LastPwdSet`. The timestamp is the number of 100-nanoseconds intervals (1 nanosecond = one billionth of a second) since Jan 1, 1601 UTC. 127 | 128 | ```golang 129 | pw, _ := adclient.GetObjectAttribute(username, "pwdLastSet") 130 | pwNum, _ := strconv.ParseInt(pw[0], 10, 64) 131 | pwPosix := adclient.FileTimeToPOSIX(pwNum) 132 | tm := time.Unix(pwPosix, 0) 133 | fmt.Printf("pw for '%v' was last set at '%v'\n", username, tm) 134 | ``` 135 | will return 136 | ```shell 137 | pw for 'XXX' was last set at '2017-10-23 19:59:47 +0000 UTC' 138 | ``` 139 | 140 | #### decode SID 141 | 142 | * `decodeSID(sid)` (c++) 143 | * `adclient.decodeSID(sid)` (Python) 144 | * `adclient.DecodeSID(sid)` (golang) 145 | 146 | Can be used to convert `objectSid` from binary representation to string value 147 | 148 | ```golang 149 | if sid, err := adclient.GetObjectAttribute(user, "objectSid"); err == nil { 150 | fmt.Printf("objectSid encoded is %q\n", sid[0]) 151 | fmt.Printf("objectSid decoded is %v\n", adclient.DecodeSID(sid[0])) 152 | } 153 | ``` 154 | will return 155 | ```shell 156 | objectSid encoded is "\x01\x05\x00\x00\x00\x00\x00\x05\x15\x00\x00\x00;\x10\x8a\xceui\xab\xc3\xfao\x93\x81\xbe\xa2\x00\x00" 157 | objectSid decoded is S-1-5-21-3465154619-3282790773-2173923322-41662 158 | ``` 159 | 160 | #### IP to int and vise versa 161 | 162 | * `int2ip(string value) / ip2int(string ip)` (c++) 163 | * `adclient.int2ip(string value)` (Python) 164 | * `adclient.Int2ip(value string) / adclient.Ip2int(ip string)` (golang) 165 | 166 | IP addresses (e.g. `msRADIUSFramedIPAddress`) are stored in object attributes as integer, these functions can be used to convert IP to integer and vise versa. 167 | 168 | ```golang 169 | ip := "192.168.1.100" 170 | ipInt := adclient.Ip2int(ip) 171 | fmt.Printf("%s to int: %v\n", ip, ipInt) 172 | ipStr := adclient.Int2ip(strconv.Itoa(ipInt)) 173 | fmt.Printf("%v to string: %s\n", ipInt, ipStr) 174 | ``` 175 | will return 176 | ```shell 177 | 192.168.1.100 to int: -1062731420 178 | -1062731420 to string: 192.168.1.100 179 | ``` 180 | 181 | #### Getting LDAP URIes list for domain/site 182 | * `adclient::get_ldap_servers(domain, site)` (c++) 183 | * `adclient.get_ldap_servers(domain, site)` (Python) 184 | * `adclient.Ldap_servers(domain, site)` (golang) 185 | 186 | Can be used to get information about LDAP servers for domain/site from DNS. `site` parameter can be empty to get servers from domain level. 187 | 188 | #### Converting domain to distinguished name 189 | * `adclient::domain2dn(domain)` (c++) 190 | * `adclient.domain2dn(domain)` (Python) 191 | * `adclient.Domain2dn(domain)` (golang) 192 | 193 | Can be used to perform simple convertion from `DOMAIN.COM` to `DC=DOMAIN,DC=COM`. 194 | 195 | ## Usage samples 196 | 197 | ### c++ 198 | ```cpp 199 | #include "adclient.h" 200 | #include 201 | #include 202 | #include 203 | #include 204 | 205 | using namespace std; 206 | 207 | int main() { 208 | adConnParams params; 209 | // login with a domain name 210 | params.domain = "DOMAIN.LOCAL"; 211 | // choose DC from SITE (optional, can be ommited) 212 | params.site = "SITE"; 213 | // or login with a list of ldap uries 214 | // params.uries.push_back("Server1"); 215 | // params.uries.push_back("Server2"); 216 | // params.search_base = "dc=DOMAIN,dc=LOCAL"; 217 | params.binddn = "user"; 218 | params.bindpw = "password"; 219 | // binding mode (LDAPS) 220 | //params.use_ldaps = true; 221 | // binding mode (StartTLS) 222 | //params.use_tls = true; 223 | 224 | // simple auth mode 225 | // params.secured = false; 226 | 227 | // GSSAPI auth, only domain and use_gssapi required 228 | // params.domain = "DOMAIN.LOCAL"; 229 | // params.site = "SITE"; 230 | // params.use_gssapi = true; 231 | 232 | adclient ad; 233 | try { 234 | ad.login(params); 235 | } 236 | catch(ADBindException& ex) { 237 | cout << "ADBindLogin: " << ex.msg << endl; 238 | return 1; 239 | } 240 | try { 241 | ad.groupRemoveUser("Group", "User"); 242 | vector user_groups = ad.getUserGroups("User"); 243 | vector users_in_group = ad.getUsersInGroup("Groups"); 244 | vector user_lastlogon = ad.getObjectAttribute("User", "lastLogon"); 245 | map > user_attrs = ad.getObjectAttributes("User"); 246 | vector users = ad.getUsers(); 247 | string dn = ad.getObjectDN("User"); 248 | bool result = ad.checkUserPassword("User", "Password"); 249 | bool disabled = ad.ifUserDisabled("User"); 250 | bool locked = ad.ifUserLocked("User"); 251 | } 252 | catch (const ADOperationalException& ex) { 253 | cout << "ADOperationalException: " << ex.msg << endl; 254 | } 255 | catch (const ADSearchException& ex) { 256 | cout << "ADSearchException: " << ex.msg << endl; 257 | } 258 | 259 | return 0; 260 | } 261 | ``` 262 | 263 | ### Python 264 | ```python 265 | import adclient 266 | 267 | params = adclient.ADConnParams() 268 | # login with a domain name 269 | params.domain = "DOMAIN.LOCAL" 270 | # choose DC from SITE (optional, can be ommited) 271 | params.site = "SITE" 272 | # or login with a list of ldap uries 273 | # params.uries = ["Server1", "Server2"] 274 | # params.search_base = "dc=DOMAIN,dc=LOCAL"; 275 | params.binddn = "user" 276 | params.bindpw = "password" 277 | 278 | # binding with TLS or LDAPS 279 | # params.use_ldaps = True 280 | # params.use_tls = True 281 | 282 | # simple auth mode 283 | # params.secured = False; 284 | 285 | # GSSAPI auth, only domain and use_gssapi required 286 | # params.domain = "DOMAIN.LOCAL"; 287 | # params.site = "SITE"; 288 | # params.use_gssapi = True; 289 | 290 | ad = adclient.ADClient() 291 | try: 292 | ad.login(params) 293 | except ADBindError as ex: 294 | print("failed to connect to Active Directory: {}".format(ex)) 295 | exit(1) 296 | 297 | try: 298 | dn = ad.getObjectDN("User"); 299 | except adclient.ADSearchError as ex: 300 | code = ad.get_error_num() 301 | if code == adclient.AD_OBJECT_NOT_FOUND: 302 | print("no such user") 303 | else: 304 | print("unknown search error") 305 | except ADOperationalError: 306 | print("unknown operational error") 307 | ``` 308 | 309 | ### Golang 310 | ```go 311 | package main 312 | 313 | import ( 314 | "github.com/paleg/libadclient" 315 | "fmt" 316 | ) 317 | 318 | func main() { 319 | adclient.New() 320 | defer adclient.Delete() 321 | 322 | params := adclient.DefaultADConnParams() 323 | // login with a domain name 324 | params.Domain = "DOMAIN.LOCAL" 325 | // choose DC from SITE (optional, can be ommited) 326 | params.Site = "SITE" 327 | // or login with a list of ldap uries 328 | // params.Uries = append(params.Uries, "Server1", "Server2") 329 | // params.Search_base = "dc=DOMAIN,dc=LOCAL"; 330 | params.Binddn = "user"; 331 | params.Bindpw = "password"; 332 | 333 | // binding with TLS or LDAPS 334 | // params.UseStartTLS = true 335 | // params.UseLDAPS = true 336 | 337 | // simple auth mode 338 | // params.Secured = false; 339 | 340 | // enable GSSAPI auth 341 | // params.UseGSSAPI = true 342 | 343 | params.Timelimit = 60 344 | params.Nettimeout = 60 345 | 346 | if err := adclient.Login(params); err != nil { 347 | fmt.Printf("Failed to AD login: %v\n", err) 348 | return 349 | } 350 | 351 | group := "Domain Admins" 352 | if users, err := adclient.GetUsersInGroup(group, true); err != nil { 353 | fmt.Printf("Failed to get users in '%v': %v\n", group, err) 354 | } else { 355 | fmt.Printf("Users in '%v':\n", group) 356 | for _, user := range users { 357 | fmt.Printf("\t%v\n", user) 358 | } 359 | } 360 | } 361 | ``` 362 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import platform 4 | 5 | Help(""" 6 | Type: 'scons' to build libadclient library 7 | 'scons install [prefix=/path]' to install libadclient library and header file [to /path/{include,lib}] 8 | 'scons -c install [prefix=/path]' to uninstall libadclient library and header file [from /path/{include,lib}] 9 | """) 10 | 11 | ldap_test_source_file = """ 12 | #include 13 | int main() { 14 | LDAPDN exp_dn; 15 | ldap_str2dn("test", &exp_dn, LDAP_DN_FORMAT_LDAPV3); 16 | return 0; 17 | } 18 | """ 19 | 20 | openldap_test_source_file = """ 21 | #include 22 | #include 23 | int main() { 24 | return strcmp( LDAP_VENDOR_NAME,"OpenLDAP"); 25 | } 26 | """ 27 | 28 | sunldap_test_source_file = """ 29 | #include 30 | #include 31 | int main() { 32 | return strcmp( LDAP_VENDOR_NAME,"Sun Microsystems Inc."); 33 | } 34 | """ 35 | 36 | def sasl_mechanisms_source_file(meh): 37 | return """ 38 | #include 39 | #include 40 | #include 41 | 42 | static sasl_callback_t client_interactions[] = {{ 43 | {{ SASL_CB_GETREALM, NULL, NULL }}, 44 | {{ SASL_CB_USER, NULL, NULL }}, 45 | {{ SASL_CB_AUTHNAME, NULL, NULL }}, 46 | {{ SASL_CB_PASS, NULL, NULL }}, 47 | {{ SASL_CB_LIST_END, NULL, NULL }} 48 | }}; 49 | 50 | int main() {{ 51 | std::string method = "{}"; 52 | if (sasl_client_init(client_interactions) != SASL_OK) return 1; 53 | 54 | sasl_conn_t *conn; 55 | if (sasl_client_new("rcmd", "localhost", NULL, NULL, NULL, 0, &conn) != SASL_OK) return 1; 56 | 57 | const char *mechlist = NULL; 58 | if (sasl_listmech(conn, NULL, ",", ",", ",", &mechlist, NULL, NULL) == SASL_OK) 59 | return (std::string(mechlist).find("," + method + ",") == std::string::npos); 60 | 61 | return 1; 62 | }} 63 | """.format(meh) 64 | 65 | LibPath = ['/usr/lib', '/usr/local/lib'] 66 | IncludePath = ['.', '/usr/local/include', '/usr/include'] 67 | 68 | env = Environment(CCFLAGS = " -O0 -g -Wall ", LIBPATH = LibPath, CPPPATH = IncludePath) 69 | 70 | PREFIX=ARGUMENTS.get('prefix', '/usr/local') 71 | 72 | IGNORE = False 73 | ignore = ['--help', '-h', '-c'] 74 | for arg in ignore: 75 | if arg in sys.argv: 76 | IGNORE = True 77 | break 78 | 79 | def checkLdapVersion(context): 80 | context.Message('Checking for new LDAPDN definition... ') 81 | result = context.TryLink(ldap_test_source_file, ".cpp") 82 | context.Result(result) 83 | return result 84 | 85 | def checkOpenLdap(context): 86 | context.Message('Checking for OPENLDAP definition... ') 87 | result = context.TryRun(openldap_test_source_file, ".cpp") 88 | context.Result(result[0]) 89 | return result[0] 90 | 91 | def checkSundap(context): 92 | context.Message('Checking for SunLDAP definition... ') 93 | result = context.TryRun(sunldap_test_source_file, ".cpp") 94 | context.Result(result[0]) 95 | return result[0] 96 | 97 | def checkSASL_DIGEST_MD5(context): 98 | context.Message('Checking for DIGEST-MD5 mechanisms in sasl ... ') 99 | result = context.TryRun(sasl_mechanisms_source_file("DIGEST-MD5"), ".cpp") 100 | context.Result(result[0]) 101 | return result[0] 102 | 103 | def checkSASL_GSSAPI(context): 104 | context.Message('Checking for GSSAPI mechanisms in sasl ... ') 105 | result = context.TryRun(sasl_mechanisms_source_file("GSSAPI"), ".cpp") 106 | context.Result(result[0]) 107 | return result[0] 108 | 109 | krb5_sources = [] 110 | 111 | if not IGNORE: 112 | conf = Configure(env, custom_tests = {'checkLdapVersion' : checkLdapVersion, 113 | 'openldap' : checkOpenLdap, 'sunldap':checkSundap, 114 | 'sasl_gssapi': checkSASL_GSSAPI, 'sasl_digestmd5': checkSASL_DIGEST_MD5}) 115 | check_c_funcs = ['strdup' , 'strlen', 'strcmp', 'memset', 'bzero'] 116 | for func in check_c_funcs: 117 | if not conf.CheckFunc(func): 118 | print("Failed.") 119 | Exit(1) 120 | 121 | check_c_headers = ['ldap.h', 'sasl/sasl.h'] 122 | for header in check_c_headers: 123 | if not conf.CheckCHeader(header): 124 | print("Failed.") 125 | Exit(1) 126 | 127 | check_cxx_headers = ['string', 'vector'] 128 | for header in check_cxx_headers: 129 | if not conf.CheckCXXHeader(header): 130 | print("Failed.") 131 | Exit(1) 132 | 133 | #env.Append(LIBS=["ldap", "sasl2", "resolv", "stdc++"]) 134 | check_libs = ['ldap', 'sasl2', 'resolv', 'stdc++'] 135 | for lib in check_libs: 136 | if not conf.CheckLib(lib): 137 | print("Failed.") 138 | Exit(1) 139 | 140 | if not conf.sasl_digestmd5(): 141 | print("Failed.") 142 | Exit(1) 143 | 144 | if conf.CheckCHeader("krb5.h") and conf.CheckLib("krb5") and conf.sasl_gssapi(): 145 | env.Append(CCFLAGS=" -DKRB5 ") 146 | krb5_sources = ["adclient_krb.cpp"] 147 | 148 | if conf.openldap(): 149 | env.Append(CCFLAGS=" -DOPENLDAP ") 150 | elif conf.sunldap(): 151 | env.Append(CCFLAGS=" -DSUNLDAP ") 152 | if not conf.checkLdapVersion(): 153 | env.Append(CCFLAGS=" -DLDAP21 ") 154 | env = conf.Finish() 155 | 156 | if platform.system() == "Darwin" and platform.mac_ver()[0] >= '10.11': 157 | # suppress OpenDirectory Framework warnings for OSX >= 10.11 158 | env.Append(CCFLAGS=" -Wno-deprecated ") 159 | 160 | libadclient_target = env.SharedLibrary('adclient', ['adclient.cpp', 'adclient_sasl.cpp'] + krb5_sources) 161 | 162 | lib_install_target = env.Install(PREFIX+'/lib', libadclient_target) 163 | header_install_target = env.Install(PREFIX+'/include', 'adclient.h') 164 | 165 | env.Alias('install', lib_install_target) 166 | env.Alias('install', header_install_target) 167 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /adclient.h: -------------------------------------------------------------------------------- 1 | /* 2 | C++ Active Directory manipulation class. 3 | Based on adtool by Mike Dawson (http://gp2x.org/adtool/). 4 | */ 5 | 6 | #ifndef _ADCLIENT_H_ 7 | #define _ADCLIENT_H_ 8 | 9 | #include 10 | 11 | #ifdef KRB5 12 | #include 13 | #endif 14 | 15 | #if defined( OPENLDAP ) 16 | #define LDAPOPTSUCCESS LDAP_OPT_SUCCESS 17 | #elif defined( SUNLDAP ) 18 | #define LDAPOPTSUCCESS LDAP_SUCCESS 19 | #endif 20 | 21 | /*#include */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include // std::distance 28 | #include // std::out_of_range 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | // for OS X 38 | #ifndef NS_MAXMSG 39 | #define NS_MAXMSG 65535 40 | #include 41 | #endif 42 | 43 | #define AD_SUCCESS 1 44 | #define AD_LDAP_CONNECTION_ERROR 2 45 | #define AD_PARAMS_ERROR 4 46 | #define AD_SERVER_CONNECT_FAILURE 6 47 | #define AD_OBJECT_NOT_FOUND 8 48 | #define AD_ATTRIBUTE_ENTRY_NOT_FOUND 10 49 | #define AD_OU_SYNTAX_ERROR 12 50 | #define AD_LDAP_RESOLV_ERROR 14 51 | 52 | #define MAX_PASSWORD_LENGTH 22 53 | 54 | #define AD_SCOPE_BASE LDAP_SCOPE_BASE 55 | #define AD_SCOPE_BASEOBJECT LDAP_SCOPE_BASEOBJECT 56 | #define AD_SCOPE_ONELEVEL LDAP_SCOPE_ONELEVEL 57 | #define AD_SCOPE_ONE LDAP_SCOPE_ONE 58 | #define AD_SCOPE_SUBTREE LDAP_SCOPE_SUBTREE 59 | #define AD_SCOPE_SUB LDAP_SCOPE_SUB 60 | #define AD_SCOPE_CHILDREN LDAP_SCOPE_CHILDREN 61 | 62 | #ifdef LDAP_SCOPE_SUBORDINATE 63 | #define AD_SCOPE_SUBORDINATE LDAP_SCOPE_SUBORDINATE /* OpenLDAP extension */ 64 | #define AD_SCOPE_DEFAULT LDAP_SCOPE_DEFAULT /* OpenLDAP extension */ 65 | #else 66 | #define AD_SCOPE_SUBORDINATE ((ber_int_t) 0x0003) 67 | #define AD_SCOPE_DEFAULT ((ber_int_t) -1) 68 | #endif 69 | 70 | using std::vector; 71 | using std::map; 72 | using std::string; 73 | using std::cout; 74 | using std::endl; 75 | 76 | #ifdef KRB5 77 | struct krb_struct { 78 | krb5_context context; 79 | char *mem_cache_env; 80 | krb5_ccache cc; 81 | }; 82 | #endif 83 | 84 | class ADException { 85 | public: 86 | ADException(string _msg, int _code) { msg = _msg; code = _code; } 87 | int code; 88 | string msg; 89 | }; 90 | 91 | class ADBindException: public ADException { 92 | public: 93 | ADBindException(string _msg, int _code): ADException(_msg, _code) {} 94 | }; 95 | 96 | class ADSearchException: public ADException { 97 | public: 98 | ADSearchException(string _msg, int _code): ADException(_msg, _code) {} 99 | }; 100 | 101 | class ADOperationalException: public ADException { 102 | public: 103 | ADOperationalException(string _msg, int _code): ADException(_msg, _code) {} 104 | }; 105 | 106 | struct adConnParams { 107 | public: 108 | string domain; 109 | string site; 110 | vector uries; 111 | string binddn; 112 | string bindpw; 113 | string search_base; 114 | bool secured; 115 | bool use_gssapi; 116 | bool use_tls; 117 | bool use_ldaps; 118 | 119 | // LDAP_OPT_NETWORK_TIMEOUT, LDAP_OPT_TIMEOUT 120 | int nettimeout; 121 | // LDAP_OPT_TIMELIMIT 122 | int timelimit; 123 | 124 | adConnParams() : 125 | secured(true), 126 | use_gssapi(false), 127 | use_tls(false), 128 | use_ldaps(false), 129 | // by default do not touch timeouts 130 | nettimeout(-1), timelimit(-1) 131 | {}; 132 | 133 | friend class adclient; 134 | 135 | private: 136 | string uri; 137 | string login_method; 138 | string bind_method; 139 | }; 140 | 141 | 142 | class adclient { 143 | public: 144 | adclient(); 145 | ~adclient(); 146 | 147 | static std::vector get_ldap_servers(string domain, string site = ""); 148 | static string domain2dn(string domain); 149 | 150 | void login(adConnParams _params); 151 | void login(string uri, string binddn, string bindpw, string search_base, bool secured = true); 152 | void login(std::vector uries, string binddn, string bindpw, string search_base, bool secured = true); 153 | 154 | string binded_uri() { return params.uri; } 155 | string search_base() { return params.search_base; } 156 | string bind_method() { return params.bind_method; } 157 | string login_method() { return params.login_method; } 158 | 159 | void groupAddUser(string group, string user); 160 | void groupRemoveUser(string group, string user); 161 | void CreateUser(string cn, string container, string user_short); 162 | void CreateGroup(string cn, string container, string group_short); 163 | void RenameGroup(string group, string shortname, string cn=""); 164 | void CreateComputer(string name, string container); 165 | void CreateOU(string ou); 166 | void DeleteDN(string dn); 167 | void RenameDN(string object, string cn); 168 | void EnableUser(string user); 169 | void DisableUser(string user); 170 | void UnLockUser(string user); 171 | void MoveUser(string user, string new_container); 172 | void RenameUser(string user, string shortname, string cn=""); 173 | void MoveObject(string object, string new_container); 174 | 175 | void setUserPassword(string user, string password); 176 | void changeUserPassword(string user, string old_password, string new_password); 177 | bool checkUserPassword(string user, string password); 178 | void setUserDialinAllowed(string user); 179 | void setUserDialinDisabled(string user); 180 | void setUserSN(string user, string sn); 181 | void setUserInitials(string user, string initials); 182 | void setUserGivenName(string user, string givenName); 183 | void setUserDisplayName(string user, string displayName); 184 | void setUserRoomNumber(string user, string roomNum); 185 | void setUserAddress(string user, string streetAddress); 186 | void setUserInfo(string user, string info); 187 | void setUserTitle(string user, string title); 188 | void setUserDepartment(string user, string department); 189 | void setUserCompany(string user, string company); 190 | void setUserPhone(string user, string phone); 191 | void setUserDescription(string user, string descr); 192 | void setUserIpAddress(string user, string ip); 193 | 194 | void setObjectAttribute(string object, string attr, string value); 195 | void setObjectAttribute(string object, string attr, vector values); 196 | void clearObjectAttribute(string object, string attr); 197 | 198 | std::map getUserControls(string user); 199 | 200 | bool getUserControl(string user, string control); 201 | 202 | bool ifUserExpired(string user); 203 | bool ifUserLocked(string user); 204 | bool ifUserDisabled(string user); 205 | bool ifUserMustChangePassword(string user); 206 | bool ifUserDontExpirePassword(string user); 207 | 208 | string getObjectDN(string object); 209 | string getUserDisplayName(string user); 210 | string getUserIpAddress(string user); 211 | 212 | bool ifDialinUser(string user); 213 | 214 | bool ifDNExists(string object, string objectclass); 215 | bool ifDNExists(string object); 216 | 217 | std::vector getGroups(); 218 | std::vector getUsers(); 219 | std::vector getOUs(); 220 | 221 | std::vector getDialinUsers(); 222 | std::vector getDisabledUsers(); 223 | 224 | std::vector getUserGroups(string user, bool nested = false); 225 | std::vector getUsersInGroup(string group, bool nested = false); 226 | 227 | std::vector getObjectsInOU(string OU, string filter, int scope); 228 | 229 | std::vector getOUsInOU(string OU, int scope); 230 | std::vector getUsersInOU(string OU, int scope); 231 | std::vector getGroupsInOU(string OU, int scope); 232 | std::vector getComputersInOU(string OU, int scope); 233 | 234 | std::vector getObjectAttribute(string object, string attribute); 235 | 236 | std::vector searchDN(string search_base, string filter, int scope); 237 | std::map < string, std::map < string, std::vector > > search(string OU, int scope, string filter, const std::vector &attributes); 238 | 239 | std::map > getObjectAttributes(string object); 240 | std::map > getObjectAttributes(string object, const std::vector &attributes); 241 | 242 | private: 243 | adConnParams params; 244 | 245 | LDAP *ds; 246 | 247 | void login(LDAP **ds, adConnParams& _params); 248 | void logout(LDAP *ds); 249 | 250 | void mod_add(string object, string attribute, string value); 251 | void mod_delete(string object, string attribute, string value); 252 | void mod_rename(string object, string cn); 253 | void mod_replace(string object, string attribute, string value); 254 | void mod_replace(string object, string attribute, vector list); 255 | void mod_move(string object, string new_container); 256 | std::map < string, std::vector > _getvalues(LDAPMessage *entry); 257 | string dn2domain(string dn); 258 | vector < std::pair > explode_dn(string dn); 259 | string merge_dn(vector < std::pair > dn_exploded); 260 | std::vector DNsToShortNames(std::vector &v); 261 | 262 | std::string ldap_prefix; 263 | 264 | static std::vector perform_srv_query(string srv_rec); 265 | static struct berval password2berval(string password); 266 | }; 267 | 268 | inline string upper(string input) { 269 | std::transform(input.begin(), input.end(), input.begin(), ::toupper); 270 | return input; 271 | } 272 | 273 | inline string vector2string(const std::vector &v, std::string separator = ", ") { 274 | std::stringstream ss; 275 | for(size_t i = 0; i < v.size(); ++i) { 276 | if (i != 0) ss << separator; 277 | ss << v[i]; 278 | } 279 | return ss.str(); 280 | } 281 | 282 | // ft is the number of 100-nanosecond intervals since January 1, 1601 (UTC) 283 | inline time_t FileTimeToPOSIX(long long ft) { 284 | // never expired 285 | if (ft == 0) { 286 | ft = 9223372036854775807; 287 | } 288 | 289 | long long result; 290 | // Between Jan 1, 1601 and Jan 1, 1970 there are 11644473600 seconds 291 | // 100-nanoseconds = milliseconds * 10000 = seconds * 1000 * 10000 292 | result = ft - 11644473600 * 1000 * 10000; 293 | // convert back from 100-nanoseconds to seconds 294 | result = result / 10000000; 295 | if (result > std::numeric_limits::max()) { 296 | return std::numeric_limits::max(); 297 | } else { 298 | return result; 299 | } 300 | } 301 | 302 | inline void replace(std::string& subject, const std::string& search, 303 | const std::string& replace) { 304 | size_t pos = 0; 305 | while((pos = subject.find(search, pos)) != std::string::npos) { 306 | subject.replace(pos, search.length(), replace); 307 | pos += replace.length(); 308 | } 309 | } 310 | 311 | inline string itos(int num) { 312 | std::stringstream ss; 313 | ss << num; 314 | return(ss.str()); 315 | } 316 | 317 | inline long long _stoll(string s) { 318 | errno = 0; 319 | char *endptr; 320 | int base = 10; 321 | long long val = strtoll(s.c_str(), &endptr, base); 322 | if ((errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) 323 | || (errno != 0 && val == 0)) { 324 | throw std::invalid_argument("unacceptable input: " + s); 325 | } 326 | string end = string(endptr); 327 | if (end.size() != 0) { 328 | throw std::invalid_argument("invalid input: " + end); 329 | } 330 | return val; 331 | } 332 | 333 | inline string DecToBin(long long number) { 334 | if ( number == 0 ) return "0"; 335 | if ( number == 1 ) return "1"; 336 | 337 | if ( number % 2 == 0 ) 338 | return DecToBin(number / 2) + "0"; 339 | else 340 | return DecToBin(number / 2) + "1"; 341 | } 342 | 343 | inline long long BinToDec(string number) { 344 | long long result = 0, pow = 1; 345 | for ( int i = number.length() - 1; i >= 0; --i, pow <<= 1 ) 346 | result += (number[i] - '0') * pow; 347 | 348 | return result; 349 | } 350 | 351 | inline int ip2int(string ip) { 352 | string ipbin = ""; 353 | std::istringstream iss(ip); 354 | string s; 355 | int iters = 0; 356 | while (getline(iss, s, '.')) { 357 | string bin = DecToBin(_stoll(s)); 358 | if (bin.size() > 8) { 359 | throw std::invalid_argument("wrong ipv4 address: " + ip); 360 | } else if (bin.size() < 8) { 361 | while (bin.size() != 8) { 362 | bin = "0" + bin; 363 | } 364 | } 365 | ipbin = ipbin + bin; 366 | iters++; 367 | } 368 | if (iters != 4) { 369 | throw std::invalid_argument("wrong ipv4 address: " + ip); 370 | } 371 | long long ipdec = BinToDec(ipbin); 372 | if (ipdec > 2147483647) { 373 | ipdec = ipdec - 4294967296; 374 | } 375 | return ipdec; 376 | } 377 | 378 | inline string int2ip(string value) { 379 | long long intip = _stoll(value); 380 | if (intip < 0) { 381 | intip += 4294967296L; 382 | } 383 | string binip = DecToBin(intip); 384 | if (binip.size() > 32) { 385 | throw std::invalid_argument("wrong value: " + binip); 386 | } else if (binip.size() < 32) { 387 | while (binip.size() != 32) { 388 | binip = "0" + binip; 389 | } 390 | } 391 | string firstOctet = binip.substr(0, 8); 392 | string secondOctet = binip.substr(8, 8); 393 | string thirdOctet = binip.substr(16, 8); 394 | string fourthOctet = binip.substr(24, 8); 395 | string ip = itos(BinToDec(firstOctet)) + "."; 396 | ip += itos(BinToDec(secondOctet)) + "."; 397 | ip += itos(BinToDec(thirdOctet)) + "."; 398 | ip += itos(BinToDec(fourthOctet)); 399 | return ip; 400 | } 401 | 402 | inline string decodeSID(string sid) { 403 | /* 404 | It is taken from http://www.adamretter.org.uk/blog/entries/active-directory-ldap-users-primary-group.xml 405 | */ 406 | std::stringstream result; 407 | result << "S-"; 408 | 409 | // version 410 | result << int(sid[0]); 411 | 412 | // count of sub-authorities 413 | int countSubAuths = int(sid[1]) & 0xFF; 414 | 415 | result << "-"; 416 | 417 | // get the authority 418 | long authority = 0; 419 | for (int i = 2; i <= 7; i++) { 420 | authority |= ((long)sid[i]) << (8 * (5 - (i - 2))); 421 | } 422 | result << authority; 423 | 424 | // iterate all the sub-auths 425 | int offset = 8; 426 | int size = 4; // 4 bytes for each sub auth 427 | for (int j = 0; j < countSubAuths; j++) { 428 | long subAuthority = 0; 429 | for (int k = 0; k < size; k++) { 430 | subAuthority |= (long)(sid[offset + k] & 0xFF) << (8 * k); 431 | } 432 | 433 | result << "-"; 434 | result << subAuthority; 435 | 436 | offset += size; 437 | } 438 | 439 | return result.str(); 440 | } 441 | 442 | int sasl_bind_digest_md5(LDAP *ds, string binddn, string bindpw); 443 | int sasl_bind_simple(LDAP *ds, string binddn, string bindpw); 444 | #ifdef KRB5 445 | int krb5_create_cache(const char *domain); 446 | void krb5_cleanup(krb_struct &krb_param); 447 | int sasl_bind_gssapi(LDAP *ds); 448 | int sasl_rebind_gssapi(LDAP * ld, LDAP_CONST char *url, ber_tag_t request, ber_int_t msgid, void *params); 449 | #endif 450 | 451 | #endif // _ADCLIENT_H_ 452 | -------------------------------------------------------------------------------- /adclient.py: -------------------------------------------------------------------------------- 1 | """ 2 | Active Directory manipulation class wrapper for low level c++ class. 3 | """ 4 | 5 | import sys 6 | 7 | import _adclient 8 | from _adclient import * 9 | 10 | class ADConnParams(object): 11 | def __init__(self): 12 | self.domain = "" 13 | self.site = "" 14 | self.binddn = "" 15 | self.bindpw = "" 16 | self.search_base = "" 17 | self.secured = True 18 | self.use_gssapi = False 19 | self.use_tls = False 20 | self.use_ldaps = False 21 | self.nettimeout = -1 22 | self.timelimit = -1 23 | self.uries = [] 24 | 25 | class ADClient(object): 26 | """ 27 | ADClient.login can throw ADBindError on errors. 28 | all search functions can throw ADSearchError on errors. 29 | all modify functions can throw both ADSearchError and ADOperationalError on errors. 30 | text description will be in exception object 31 | numeric code can be obtained from 'get_error_num' function 32 | """ 33 | 34 | def __init__(self): 35 | self.obj = _adclient.new_adclient() 36 | 37 | def login(self, params, binddn="", bindpw="", search_base="", secured=True): 38 | if not isinstance(params, ADConnParams): 39 | uries = params 40 | params = ADConnParams() 41 | if sys.version_info[0] == 3: 42 | string_type = str 43 | else: 44 | string_type = basestring 45 | if isinstance(uries, string_type): 46 | params.domain = uries 47 | elif isinstance(uries, list): 48 | params.uries = uries 49 | params.binddn = binddn 50 | params.bindpw = bindpw 51 | params.search_base = search_base 52 | params.secured = secured 53 | _adclient.login_adclient(self.obj, params.__dict__) 54 | 55 | def binded_uri(self): 56 | return _adclient.binded_uri_adclient(self.obj) 57 | 58 | def search_base(self): 59 | return _adclient.search_base_adclient(self.obj) 60 | 61 | def login_method(self): 62 | return _adclient.login_method_adclient(self.obj) 63 | 64 | def bind_method(self): 65 | return _adclient.bind_method_adclient(self.obj) 66 | 67 | def searchDN(self, search_base, filter, scope): 68 | """ It returns list with DNs found with 'filter' 69 | """ 70 | return _adclient.searchDN_adclient(self.obj, search_base, filter, scope) 71 | 72 | def search(self, ou, scope, filter, attributes): 73 | """ General search function. 74 | It returns dict with users found with 'filter' with specified 'attributes'. 75 | """ 76 | return _adclient.search_adclient(self.obj, ou, scope, filter, attributes) 77 | 78 | def getUserGroups(self, user, nested=False): 79 | """ It returns list with "user" groups if operation was successfull. 80 | """ 81 | return _adclient.getUserGroups_adclient(self.obj, user, nested) 82 | 83 | def getUsersInGroup(self, group, nested=False): 84 | """ It returns list with members of Active Directory "group" if operation was successfull. 85 | """ 86 | return _adclient.getUsersInGroup_adclient(self.obj, group, nested) 87 | 88 | def getUserControls(self, user): 89 | """ It returns map with "user" controls: 90 | ('disabled', 'locked', 'dontExpirePassword', 'mustChangePassword', 'expired'). 91 | """ 92 | return _adclient.getUserControls_adclient(self.obj, user) 93 | 94 | 95 | def groupAddUser(self, group, user): 96 | """ It adds "user" to Active Directory "group". 97 | It returns nothing if operation was successfull. 98 | """ 99 | _adclient.groupAddUser_adclient(self.obj, group, user) 100 | 101 | def groupRemoveUser(self, group, user): 102 | """ It removes "user" from Active Directory "group". 103 | It returns nothing if operation was successfull. 104 | """ 105 | _adclient.groupRemoveUser_adclient(self.obj, group, user) 106 | 107 | def ifDialinUser(self, user): 108 | """ It returns True if msNPAllowDialin user attribute set to TRUE, False - otherwise. 109 | """ 110 | if _adclient.ifDialinUser_adclient(self.obj, user) == 1: 111 | return True 112 | else: 113 | return False 114 | 115 | def getDialinUsers(self): 116 | """ It returns list of all users with msNPAllowDialin = TRUE. 117 | """ 118 | return _adclient.getDialinUsers_adclient(self.obj) 119 | 120 | def getDisabledUsers(self): 121 | """ It returns list of all users with ADS_UF_ACCOUNTDISABLE in userAccountControl. 122 | """ 123 | return _adclient.getDisabledUsers_adclient(self.obj) 124 | 125 | def getObjectDN(self, user): 126 | """ It returns user DN by short name. 127 | """ 128 | return _adclient.getObjectDN_adclient(self.obj, user) 129 | 130 | def ifUserDisabled(self, user): 131 | """ It returns True if UserAccountControl flag contain ACCOUNTDISABLE property, 132 | False - otherwise. 133 | """ 134 | return _adclient.ifUserDisabled_adclient(self.obj, user) 135 | 136 | def ifDNExists(self, dn, objectclass='*'): 137 | """ It returns True of False depends on object DN existence. 138 | dn objectclass can be limited with corresponding argument. 139 | """ 140 | return _adclient.ifDNExists_adclient(self.obj, dn, objectclass) 141 | 142 | def getOUs(self): 143 | """ It returns list of all organizationalUnits in Active Directory. 144 | """ 145 | return _adclient.getOUs_adclient(self.obj) 146 | 147 | def getUsersInOU(self, OU, scope): 148 | """ It returns list of all users in OU. 149 | """ 150 | return _adclient.getUsersInOU_adclient(self.obj, OU, scope) 151 | 152 | def getComputersInOU(self, OU, scope): 153 | """ It returns list of all users in OU. 154 | """ 155 | return _adclient.getComputersInOU_adclient(self.obj, OU, scope) 156 | 157 | def getGroupsInOU(self, OU, scope): 158 | """ It returns list of all users in OU. 159 | """ 160 | return _adclient.getGroupsInOU_adclient(self.obj, OU, scope) 161 | 162 | def getGroups(self): 163 | """ It returns list of all groups in Active Directory. 164 | """ 165 | return _adclient.getGroups_adclient(self.obj) 166 | 167 | def getUsers(self): 168 | """ It returns list of all users in Active Directory. 169 | """ 170 | return _adclient.getUsers_adclient(self.obj) 171 | 172 | def getOUsInOU(self, OU, scope): 173 | """ It returns list of all OUs in OU. 174 | """ 175 | return _adclient.getOUsInOU_adclient(self.obj, OU, scope) 176 | 177 | def getUserDisplayName(self, user): 178 | """ It returns string with user DisplayName property. 179 | """ 180 | return _adclient.getUserDisplayName_adclient(self.obj, user) 181 | 182 | def getUserIpAddress(self, user): 183 | """ It returns string with user msRADIUSFramedIPAddress property. 184 | """ 185 | return _adclient.getUserIpAddress_adclient(self.obj, user) 186 | 187 | def getObjectAttribute(self, object, attribute): 188 | """ It returns list with values of object attribute. 189 | """ 190 | return _adclient.getObjectAttribute_adclient(self.obj, object, attribute) 191 | 192 | def getObjectAttributes(self, object): 193 | """ It returns map of all object attributes. 194 | """ 195 | return _adclient.getObjectAttributes_adclient(self.obj, object) 196 | 197 | def CreateComputer(self, name, container): 198 | """ It creates computer with given name in given container. 199 | """ 200 | _adclient.CreateComputer_adclient(self.obj, name, container) 201 | 202 | def CreateUser(self, cn, container, short_name): 203 | """ It creates user with given common name and short name in given container. 204 | """ 205 | _adclient.CreateUser_adclient(self.obj, cn, container, short_name) 206 | 207 | def CreateGroup(self, cn, container, short_name): 208 | """ It creates user with given common name and short name in given container. 209 | """ 210 | _adclient.CreateGroup_adclient(self.obj, cn, container, short_name) 211 | 212 | def DeleteDN(self, dn): 213 | """ It deletes given DN. 214 | """ 215 | _adclient.DeleteDN_adclient(self.obj, dn) 216 | 217 | def CreateOU(self, ou): 218 | """ It creates given OU (with subOUs if needed). 219 | """ 220 | _adclient.CreateOU_adclient(self.obj, ou) 221 | 222 | def EnableUser(self, short_name): 223 | """ It enables given user. 224 | """ 225 | _adclient.EnableUser_adclient(self.obj, short_name) 226 | 227 | def DisableUser(self, short_name): 228 | """ It disables given user. 229 | """ 230 | _adclient.DisableUser_adclient(self.obj, short_name) 231 | 232 | def setUserDescription(self, dn, descr): 233 | _adclient.setUserDescription_adclient(self.obj, dn, descr) 234 | 235 | def changeUserPassword(self, dn, old_password, new_password): 236 | _adclient.changeUserPassword_adclient(self.obj, dn, old_password, new_password) 237 | 238 | def setUserPassword(self, dn, password): 239 | _adclient.setUserPassword_adclient(self.obj, dn, password) 240 | 241 | def checkUserPassword(self, dn, password): 242 | """ It returns True of False depends on user credentials correctness. """ 243 | return _adclient.checkUserPassword_adclient(self.obj, dn, password) 244 | 245 | def setUserDialinAllowed(self, user): 246 | _adclient.setUserDialinAllowed_adclient(self.obj, user) 247 | 248 | def setUserDialinDisabled(self, user): 249 | _adclient.setUserDialinDisabled_adclient(self.obj, user) 250 | 251 | def setUserSN_adclient(self, user, sn): 252 | _adclient.setUserSN_adclient(self.obj, user, sn) 253 | 254 | def setUserInitials(self, user, initials): 255 | _adclient.setUserInitials_adclient(self.obj, user, initials) 256 | 257 | def setUserGivenName(self, user, givenName): 258 | _adclient.setUserGivenName_adclient(self.obj, user, givenName) 259 | 260 | def setUserDisplayName(self, user, displayName): 261 | _adclient.setUserDisplayName_adclient(self.obj, user, displayName) 262 | 263 | def setUserRoomNumber(self, user, roomNum): 264 | _adclient.setUserRoomNumber_adclient(self.obj, user, roomNum) 265 | 266 | def setUserAddress(self, user, streetAddress): 267 | _adclient.setUserAddress_adclient(self.obj, user, streetAddress) 268 | 269 | def setUserInfo(self, user, info): 270 | _adclient.setUserInfo_adclient(self.obj, user, info) 271 | 272 | def setUserTitle(self, user, title): 273 | _adclient.setUserTitle_adclient(self.obj, user, title) 274 | 275 | def setUserDepartment(self, user, department): 276 | _adclient.setUserDepartment_adclient(self.obj, user, department) 277 | 278 | def setUserCompany(self, user, company): 279 | _adclient.setUserCompany_adclient(self.obj, user, company) 280 | 281 | def setUserPhone(self, user, phone): 282 | _adclient.setUserPhone_adclient(self.obj, user, phone) 283 | 284 | def setUserSN(self, user, phone): 285 | _adclient.setUserSN_adclient(self.obj, user, phone) 286 | 287 | def setUserIpAddress(self, user, ip): 288 | _adclient.setUserIpAddress_adclient(self.obj, user, ip) 289 | 290 | def clearObjectAttribute(self, obj, attr): 291 | _adclient.clearObjectAttribute_adclient(self.obj, obj, attr) 292 | 293 | def setObjectAttribute(self, obj, attr, values): 294 | if not isinstance(values, list): 295 | values = [values] 296 | _adclient.setObjectAttribute_adclient(self.obj, obj, attr, values) 297 | 298 | def UnLockUser(self, user): 299 | """ It unlocks given user. 300 | """ 301 | _adclient.UnLockUser_adclient(self.obj, user) 302 | 303 | def MoveUser(self, user, new_container): 304 | """ It moves given user to new container. 305 | """ 306 | _adclient.MoveUser_adclient(self.obj, user, new_container) 307 | 308 | def MoveObject(self, obj, new_container): 309 | """ It moves given user to new container. 310 | """ 311 | _adclient.MoveObject_adclient(self.obj, obj, new_container) 312 | 313 | def RenameUser(self, user, shortname, cn=""): 314 | """ It renames sAMAccountName, UPN and CN for given user 315 | CN is taken from shortname when empty 316 | """ 317 | _adclient.RenameUser_adclient(self.obj, user, shortname, cn) 318 | 319 | def get_error_num(self): 320 | """ It returns int of last error occured 321 | """ 322 | return _adclient.get_error_num() 323 | 324 | def int2ip(self, ipstr): 325 | return _adclient.int2ip(ipstr) 326 | 327 | def decodeSID(self, sid): 328 | return _adclient.decodeSID(sid) 329 | 330 | def FileTimeToPOSIX(self, filetime): 331 | return _adclient.FileTimeToPOSIX(filetime) 332 | 333 | def domain2dn(self, domain): 334 | return _adclient.domain2dn(domain) 335 | 336 | def get_ldap_servers(self, domain, site=""): 337 | return _adclient.get_ldap_servers(domain, site) 338 | -------------------------------------------------------------------------------- /adclient.swigcxx: -------------------------------------------------------------------------------- 1 | %module adclient 2 | 3 | %{ 4 | #include "adclient.h" 5 | %} 6 | 7 | %include 8 | %include "std_string.i" 9 | %include "std_vector.i" 10 | %include "std_map.i" 11 | 12 | namespace std { 13 | %template(StringVector) vector; 14 | %template(StringBoolMap) map; 15 | %template(String_VectorString_Map) map >; 16 | 17 | %extend map { 18 | std::vector keys(void) { 19 | std::vector k = std::vector(); 20 | for (std::map::iterator iter = self->begin(); iter != self->end(); iter++) { 21 | k.push_back(iter->first); 22 | } 23 | return k; 24 | } 25 | } 26 | %extend map > { 27 | std::vector keys(void) { 28 | std::vector k = std::vector(); 29 | for (std::map >::iterator iter = self->begin(); iter != self->end(); iter++) { 30 | k.push_back(iter->first); 31 | } 32 | return k; 33 | } 34 | } 35 | 36 | } 37 | 38 | %exception { 39 | try { 40 | $action; 41 | } catch (ADException &e) { 42 | std::stringstream ss; 43 | ss << e.code << ":" << e.msg; 44 | _swig_gopanic(ss.str().c_str()); 45 | } catch (std::exception &e) { 46 | _swig_gopanic(e.what()); 47 | } 48 | } 49 | 50 | %include "adclient.h" 51 | 52 | typedef long time_t; 53 | -------------------------------------------------------------------------------- /adclient_krb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Author: Markus Moeller (markus_moeller at compuserve.com) 4 | * ----------------------------------------------------------------------------- 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "adclient.h" 15 | 16 | using std::cout; 17 | using std::endl; 18 | 19 | #define KT_PATH_MAX 256 20 | #define safe_free(x) while ((x)) { free((x)); (x) = NULL; } 21 | 22 | void 23 | krb5_cleanup(krb_struct &krb_param) 24 | { 25 | if (krb_param.context) { 26 | if (krb_param.cc) { 27 | krb5_cc_destroy(krb_param.context, krb_param.cc); 28 | } 29 | krb5_free_context(krb_param.context); 30 | } 31 | } 32 | /* 33 | * create Kerberos memory cache 34 | */ 35 | int 36 | krb5_create_cache(const char *domain) 37 | { 38 | krb_struct krb_param; 39 | krb_param.context = NULL; 40 | krb_param.cc = NULL; 41 | 42 | krb5_keytab keytab = 0; 43 | krb5_keytab_entry entry; 44 | krb5_kt_cursor cursor; 45 | krb5_creds *creds = NULL; 46 | krb5_principal *principal_list = NULL; 47 | krb5_principal principal = NULL; 48 | char *service; 49 | char *keytab_name = NULL, *principal_name = NULL, *mem_cache = NULL; 50 | char buf[KT_PATH_MAX], *p; 51 | size_t j,nprinc = 0; 52 | int retval = 0; 53 | krb5_error_code code = 0; 54 | 55 | if (!domain || !strcmp(domain, "")) 56 | return (1); 57 | 58 | /* 59 | * Initialise Kerberos 60 | */ 61 | 62 | code = krb5_init_context(&krb_param.context); 63 | if (code) { 64 | //const char *s = krb5_get_error_message(krb_param.context, code); 65 | //cout << "%s| %s: ERROR: Error while initialising Kerberos library: " << s << endl; 66 | retval = 1; 67 | goto cleanup; 68 | } 69 | /* 70 | * getting default keytab name 71 | */ 72 | 73 | //cout << "DEBUG: Get default keytab file name" << endl; 74 | krb5_kt_default_name(krb_param.context, buf, KT_PATH_MAX); 75 | p = strchr(buf, ':'); /* Find the end if "FILE:" */ 76 | if (p) 77 | ++p; /* step past : */ 78 | keytab_name = strdup(p ? p : buf); 79 | //cout << "DEBUG: Got default keytab file name " << keytab_name << endl; 80 | 81 | code = krb5_kt_resolve(krb_param.context, keytab_name, &keytab); 82 | if (code) { 83 | //const char *s = krb5_get_error_message(krb_param.context, code); 84 | //cout << "ERROR: Error while resolving keytab " << keytab_name << ": " << s << endl; 85 | retval = 1; 86 | goto cleanup; 87 | } 88 | code = krb5_kt_start_seq_get(krb_param.context, keytab, &cursor); 89 | if (code) { 90 | //const char *s = krb5_get_error_message(krb_param.context, code); 91 | //cout << "ERROR: Error while starting keytab scan: " << s << endl; 92 | retval = 1; 93 | goto cleanup; 94 | } 95 | //cout << "DEBUG: Get principal name from keytab" << keytab_name << endl; 96 | 97 | nprinc = 0; 98 | while ((code = krb5_kt_next_entry(krb_param.context, keytab, &entry, &cursor)) == 0) { 99 | int found = 0; 100 | 101 | krb5_principal *new_principal_list; 102 | new_principal_list = (krb5_principal *) realloc(principal_list, sizeof(krb5_principal) * (nprinc + 1)); 103 | if (!new_principal_list) { 104 | retval = 1; 105 | goto cleanup; 106 | } else { 107 | principal_list = new_principal_list; 108 | } 109 | krb5_copy_principal(krb_param.context, entry.principal, &principal_list[nprinc++]); 110 | //cout << "DEBUG: Keytab entry has realm name: " << krb5_princ_realm(krb_param.context, entry.principal)->data << endl; 111 | if (!strcasecmp(domain, krb5_princ_realm(krb_param.context, entry.principal)->data)) 112 | { 113 | code = krb5_unparse_name(krb_param.context, entry.principal, &principal_name); 114 | if (code) { 115 | //const char *s = krb5_get_error_message(krb_param.context, code); 116 | //cout << "ERROR: Error while unparsing principal name:" << s << endl; 117 | } else { 118 | //cout << "DEBUG: Found principal name:" << principal_name << endl; 119 | found = 1; 120 | } 121 | } 122 | code = krb5_free_keytab_entry_contents(krb_param.context, &entry); 123 | if (code) { 124 | //const char *s = krb5_get_error_message(krb_param.context, code); 125 | //cout << "ERROR: Error while freeing keytab entry: " << s << endl; 126 | retval = 1; 127 | break; 128 | } 129 | if (found) 130 | break; 131 | } 132 | 133 | if (code && code != KRB5_KT_END) { 134 | //const char *s = krb5_get_error_message(krb_param.context, code); 135 | //cout << "ERROR: Error while scanning keytab: " << s << endl; 136 | retval = 1; 137 | goto cleanup; 138 | } 139 | code = krb5_kt_end_seq_get(krb_param.context, keytab, &cursor); 140 | if (code) { 141 | //const char *s = krb5_get_error_message(krb_param.context, code); 142 | //cout << "ERROR: Error while ending keytab scan: " << s << endl; 143 | retval = 1; 144 | goto cleanup; 145 | } 146 | /* 147 | * prepare memory credential cache 148 | */ 149 | #if !defined(HAVE_KRB5_MEMORY_CACHE) || defined(HAVE_SUN_LDAP_SDK) 150 | mem_cache = (char *) malloc(strlen("FILE:/tmp/libadclient_") + 16); 151 | snprintf(mem_cache, strlen("FILE:/tmp/libadclient_") + 16, "FILE:/tmp/libadclient_%d", (int) getpid()); 152 | #else 153 | mem_cache = (char *) malloc(strlen("MEMORY:libadclient_") + 16); 154 | snprintf(mem_cache, strlen("MEMORY:libadclient_") + 16, "MEMORY:libadclient_%d", (int) getpid()); 155 | #endif 156 | 157 | if (!mem_cache) { 158 | retval = 1; 159 | goto cleanup; 160 | } 161 | 162 | setenv("KRB5CCNAME", mem_cache, 1); 163 | //cout << "DEBUG: Set credential cache to " << mem_cache << endl; 164 | code = krb5_cc_resolve(krb_param.context, mem_cache, &krb_param.cc); 165 | if (code) { 166 | //const char *s = krb5_get_error_message(krb_param.context, code); 167 | //cout << "ERROR: Error while resolving memory ccache: " << s << endl; 168 | retval = 1; 169 | goto cleanup; 170 | } 171 | /* 172 | * if no principal name found in keytab for domain use the prinipal name which can get a TGT 173 | */ 174 | if (!principal_name) { 175 | size_t i; 176 | //cout << "DEBUG: Did not find a principal in keytab for domain " << domain << endl; 177 | //cout << "DEBUG: Try to get principal of trusted domain" << endl; 178 | 179 | for (i = 0; i < nprinc; ++i) { 180 | krb5_creds *tgt_creds = NULL; 181 | creds = (krb5_creds *) malloc(sizeof(*creds)); 182 | if (!creds) { 183 | retval = 1; 184 | goto cleanup; 185 | } 186 | memset(creds, 0, sizeof(*creds)); 187 | /* 188 | * get credentials 189 | */ 190 | code = krb5_unparse_name(krb_param.context, principal_list[i], &principal_name); 191 | if (code) { 192 | //const char *s = krb5_get_error_message(krb_param.context, code); 193 | //cout << "DEBUG: Error while unparsing principal name: " << s << endl; 194 | goto loop_end; 195 | } 196 | //cout << "DEBUG: Keytab entry has principal: " << principal_name << endl; 197 | 198 | code = krb5_get_init_creds_keytab(krb_param.context, creds, principal_list[i], keytab, 0, NULL, NULL); 199 | if (code) { 200 | //const char *s = krb5_get_error_message(krb_param.context, code); 201 | //cout << "DEBUG: Error while initialising credentials from keytab: " << s << endl; 202 | goto loop_end; 203 | } 204 | code = krb5_cc_initialize(krb_param.context, krb_param.cc, principal_list[i]); 205 | if (code) { 206 | //const char *s = krb5_get_error_message(krb_param.context, code); 207 | //cout << "ERROR: Error while initializing memory caches: " << s << endl; 208 | goto loop_end; 209 | } 210 | code = krb5_cc_store_cred(krb_param.context, krb_param.cc, creds); 211 | if (code) { 212 | //const char *s = krb5_get_error_message(krb_param.context, code); 213 | //cout << "DEBUG: Error while storing credentials: " << s << endl; 214 | goto loop_end; 215 | } 216 | if (creds->server) 217 | krb5_free_principal(krb_param.context, creds->server); 218 | service = (char *) malloc(strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(krb_param.context, principal_list[i])->data) + 3); 219 | snprintf(service, strlen("krbtgt") + strlen(domain) + strlen(krb5_princ_realm(krb_param.context, principal_list[i])->data) + 3, "krbtgt/%s@%s", domain, krb5_princ_realm(krb_param.context, principal_list[i])->data); 220 | code = krb5_parse_name(krb_param.context, service, &creds->server); 221 | free(service); 222 | if (code) { 223 | //const char *s = krb5_get_error_message(krb_param.context, code); 224 | //cout << "ERROR: Error while initialising TGT credentials: " << s << endl; 225 | goto loop_end; 226 | } 227 | code = krb5_get_credentials(krb_param.context, 0, krb_param.cc, creds, &tgt_creds); 228 | if (code) { 229 | //const char *s = krb5_get_error_message(krb_param.context, code); 230 | //cout << "DEBUG: Error while getting tgt: " << s << endl; 231 | goto loop_end; 232 | } else { 233 | //cout << "DEBUG: Found trusted principal name: " << principal_name << endl; 234 | break; 235 | } 236 | 237 | loop_end: 238 | safe_free(principal_name); 239 | if (tgt_creds) { 240 | krb5_free_creds(krb_param.context, tgt_creds); 241 | tgt_creds = NULL; 242 | } 243 | krb5_free_creds(krb_param.context, creds); 244 | creds = NULL; 245 | 246 | } 247 | 248 | if (creds) 249 | krb5_free_creds(krb_param.context, creds); 250 | creds = NULL; 251 | } 252 | if (principal_name) { 253 | //cout << "DEBUG: Got principal name " << principal_name << endl; 254 | /* 255 | * build principal 256 | */ 257 | code = krb5_parse_name(krb_param.context, principal_name, &principal); 258 | if (code) { 259 | //const char *s = krb5_get_error_message(krb_param.context, code); 260 | //cout << "ERROR: Error while parsing name " << principal_name << ": " << s << endl; 261 | retval = 1; 262 | goto cleanup; 263 | } 264 | creds = (krb5_creds *) malloc(sizeof(*creds)); 265 | if (!creds) { 266 | retval = 1; 267 | goto cleanup; 268 | } 269 | memset(creds, 0, sizeof(*creds)); 270 | 271 | /* 272 | * get credentials 273 | */ 274 | code = krb5_get_init_creds_keytab(krb_param.context, creds, principal, keytab, 0, NULL, NULL); 275 | if (code) { 276 | //const char *s = krb5_get_error_message(krb_param.context, code); 277 | //cout << "ERROR: Error while initialising credentials from keytab: " << s << endl; 278 | retval = 1; 279 | goto cleanup; 280 | } 281 | code = krb5_cc_initialize(krb_param.context, krb_param.cc, principal); 282 | if (code) { 283 | //const char *s = krb5_get_error_message(krb_param.context, code); 284 | //cout << "ERROR: Error while initializing memory caches: " << s << endl; 285 | retval = 1; 286 | goto cleanup; 287 | } 288 | code = krb5_cc_store_cred(krb_param.context, krb_param.cc, creds); 289 | if (code) { 290 | //const char *s = krb5_get_error_message(krb_param.context, code); 291 | //cout << "ERROR: Error while storing credentials: " << s << endl; 292 | retval = 1; 293 | goto cleanup; 294 | } 295 | //cout << "DEBUG: Stored credentials" << endl; 296 | } else { 297 | //cout << "DEBUG: Got no principal name" << endl; 298 | retval = 1; 299 | } 300 | cleanup: 301 | if (keytab) 302 | krb5_kt_close(krb_param.context, keytab); 303 | free(keytab_name); 304 | free(principal_name); 305 | free(mem_cache); 306 | if (principal) 307 | krb5_free_principal(krb_param.context, principal); 308 | for (j = 0; j < nprinc; ++j) { 309 | if (principal_list[j]) 310 | krb5_free_principal(krb_param.context, principal_list[j]); 311 | } 312 | free(principal_list); 313 | if (creds) 314 | krb5_free_creds(krb_param.context, creds); 315 | 316 | krb5_cleanup(krb_param); 317 | return (retval); 318 | } 319 | -------------------------------------------------------------------------------- /adclient_sasl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using std::string; 8 | using std::cout; 9 | using std::endl; 10 | 11 | struct sasl_defaults_digest_md5 { 12 | string username; 13 | string password; 14 | }; 15 | 16 | int sasl_interact_digest_md5(LDAP *ds, unsigned flags, void *indefaults, void *in) { 17 | sasl_defaults_digest_md5 *defaults = static_cast(indefaults); 18 | sasl_interact_t *interact = static_cast(in); 19 | if (ds == NULL) { 20 | return LDAP_PARAM_ERROR; 21 | } 22 | 23 | while(interact->id != SASL_CB_LIST_END) { 24 | const char *dflt = static_cast(interact->defresult); 25 | 26 | switch(interact->id) { 27 | case SASL_CB_GETREALM: 28 | dflt = NULL; 29 | break; 30 | case SASL_CB_USER: 31 | case SASL_CB_AUTHNAME: 32 | dflt = defaults->username.c_str(); 33 | break; 34 | case SASL_CB_PASS: 35 | dflt = defaults->password.c_str(); 36 | break; 37 | } 38 | 39 | interact->result = (dflt && *dflt) ? dflt : static_cast(""); 40 | interact->len = strlen(static_cast(interact->result)); 41 | interact++; 42 | } 43 | 44 | return LDAP_SUCCESS; 45 | } 46 | 47 | int sasl_bind_digest_md5(LDAP *ds, string binddn, string bindpw) { 48 | int bindresult; 49 | 50 | string sasl_mech = "DIGEST-MD5"; 51 | unsigned sasl_flags = LDAP_SASL_QUIET; 52 | 53 | sasl_defaults_digest_md5 defaults; 54 | defaults.username = binddn; 55 | defaults.password = bindpw; 56 | 57 | bindresult = ldap_sasl_interactive_bind_s(ds, NULL, 58 | sasl_mech.c_str(), 59 | NULL, NULL, 60 | sasl_flags, sasl_interact_digest_md5, &defaults); 61 | return bindresult; 62 | } 63 | 64 | int sasl_bind_simple(LDAP *ds, string binddn, string bindpw) { 65 | int bindresult; 66 | 67 | struct berval cred; 68 | struct berval *servcred; 69 | 70 | cred.bv_val = strdup(bindpw.c_str()); 71 | cred.bv_len = bindpw.size(); 72 | 73 | bindresult = ldap_sasl_bind_s(ds, binddn.c_str(), NULL, &cred, NULL, NULL, &servcred); 74 | 75 | memset(cred.bv_val, 0, cred.bv_len); 76 | free(cred.bv_val); 77 | 78 | return bindresult; 79 | } 80 | 81 | 82 | #ifdef KRB5 83 | struct sasl_defaults_gssapi { 84 | char *mech; 85 | char *realm; 86 | char *authcid; 87 | char *passwd; 88 | char *authzid; 89 | }; 90 | 91 | int sasl_interact_gssapi(LDAP *ds, unsigned flags, void *indefaults, void *in) { 92 | sasl_defaults_gssapi *defaults = static_cast(indefaults); 93 | sasl_interact_t *interact = static_cast(in); 94 | 95 | if (ds == NULL) { 96 | return LDAP_PARAM_ERROR; 97 | } 98 | 99 | while (interact->id != SASL_CB_LIST_END) { 100 | const char *dflt = static_cast(interact->defresult); 101 | 102 | switch (interact->id) { 103 | case SASL_CB_GETREALM: 104 | if (defaults) 105 | dflt = defaults->realm; 106 | break; 107 | case SASL_CB_AUTHNAME: 108 | if (defaults) 109 | dflt = defaults->authcid; 110 | break; 111 | case SASL_CB_PASS: 112 | if (defaults) 113 | dflt = defaults->passwd; 114 | break; 115 | case SASL_CB_USER: 116 | if (defaults) 117 | dflt = defaults->authzid; 118 | break; 119 | case SASL_CB_NOECHOPROMPT: 120 | break; 121 | case SASL_CB_ECHOPROMPT: 122 | break; 123 | } 124 | 125 | if (dflt && !*dflt) { 126 | dflt = NULL; 127 | } 128 | 129 | /* input must be empty */ 130 | interact->result = (dflt && *dflt) ? dflt : static_cast(""); 131 | interact->len = strlen(static_cast(interact->result)); 132 | interact++; 133 | } 134 | 135 | return LDAP_SUCCESS; 136 | } 137 | 138 | int sasl_bind_gssapi(LDAP *ds) { 139 | unsigned sasl_flags = LDAP_SASL_QUIET; 140 | string sasl_mech = "GSSAPI"; 141 | 142 | string sasl_secprops = "maxssf=56"; 143 | int rc = ldap_set_option(ds, LDAP_OPT_X_SASL_SECPROPS, (void *) sasl_secprops.c_str()); 144 | if (rc != LDAP_SUCCESS) { 145 | //cout << "ERROR: Could not set LDAP_OPT_X_SASL_SECPROPS " << sasl_secprops << ":" << ldap_err2string(rc) << endl; 146 | return rc; 147 | } 148 | 149 | sasl_defaults_gssapi defaults; 150 | 151 | defaults.mech = strdup(sasl_mech.c_str()); 152 | ldap_get_option(ds, LDAP_OPT_X_SASL_REALM, &defaults.realm); 153 | ldap_get_option(ds, LDAP_OPT_X_SASL_AUTHCID, &defaults.authcid); 154 | ldap_get_option(ds, LDAP_OPT_X_SASL_AUTHZID, &defaults.authzid); 155 | defaults.passwd = NULL; 156 | 157 | rc = ldap_sasl_interactive_bind_s(ds, NULL, 158 | sasl_mech.c_str(), NULL, NULL, 159 | sasl_flags, sasl_interact_gssapi, &defaults); 160 | 161 | free(defaults.mech); 162 | ldap_memfree(defaults.realm); 163 | ldap_memfree(defaults.authcid); 164 | ldap_memfree(defaults.authzid); 165 | if (rc != LDAP_SUCCESS) { 166 | //cout << "ERROR: ldap_sasl_interactive_bind_s error: " << ldap_err2string(rc) << endl; 167 | } 168 | return rc; 169 | 170 | } 171 | 172 | int sasl_rebind_gssapi(LDAP * ld, 173 | LDAP_CONST char *url, 174 | ber_tag_t request, 175 | ber_int_t msgid, 176 | void *params) { 177 | return sasl_bind_gssapi(ld); 178 | } 179 | #endif 180 | -------------------------------------------------------------------------------- /adclient_test.go: -------------------------------------------------------------------------------- 1 | package adclient 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "reflect" 7 | "sort" 8 | "testing" 9 | ) 10 | 11 | type Group struct { 12 | CommonName string 13 | Container string 14 | ShortName string 15 | } 16 | 17 | type User struct { 18 | CommonName string 19 | Container string 20 | ShortName string 21 | Password string 22 | SN string 23 | Initials string 24 | GivenName string 25 | DisplayName string 26 | RoomNumber string 27 | Address string 28 | Info string 29 | Title string 30 | Department string 31 | Company string 32 | Phone string 33 | Description string 34 | } 35 | 36 | var LDAPServer = []string{"domain.local"} 37 | var LDAPUser = "rwuser" 38 | var LDAPPasswd = "rwuserpassword" 39 | var LDAPSearchBase = "DC=domain,DC=local" 40 | 41 | var TestOU = "OU=GhostBusters," + LDAPSearchBase 42 | var TestUser1 = User{CommonName: "Egon Spengler", Container: TestOU, ShortName: "Spengler.Egon.Dr", Password: "engoSiunah5m", 43 | SN: "Spengler", Initials: "Dr", GivenName: "Egon", DisplayName: "Dr. Egon Spengler, Ph.D.", RoomNumber: "Basement", 44 | Address: "110 N. Moore Street, New York", Info: "Former professor of paranormal studies at the Columbia University", 45 | Title: "Founder", Department: "Science", Company: "GhostBusters", Phone: "555-2368", Description: "Collects spores, molds, and fungus"} 46 | var TestUser2 = User{CommonName: "Peter Venkman", Container: TestOU, ShortName: "Venkman.Peter.Dr"} 47 | var TestGroup1 = Group{"GBGroup1", TestOU, "GBGroup1"} 48 | var TestGroup2 = Group{"GBGroup2", TestOU, "GBGroup2"} 49 | 50 | func TestMain(m *testing.M) { 51 | ret := 1 52 | New() 53 | err := Login(LDAPServer, LDAPUser, LDAPPasswd, LDAPSearchBase, true) 54 | if err != nil { 55 | fmt.Println(err) 56 | } else { 57 | fmt.Printf("Binded to '%+v'\n", BindedUri()) 58 | if dirty_env, err := IfDNExists(TestOU); err != nil { 59 | fmt.Println(err) 60 | } else if dirty_env { 61 | fmt.Printf("'%+v' exists, remove it before testing\n", TestOU) 62 | } else { 63 | ret = m.Run() 64 | } 65 | } 66 | Delete() 67 | os.Exit(ret) 68 | } 69 | 70 | func TestCreateUsers(t *testing.T) { 71 | t.Logf("Creating '%+v'", TestUser1.CommonName) 72 | err1 := CreateUser(TestUser1.CommonName, TestUser1.Container, TestUser1.ShortName) 73 | if err1 != nil { 74 | t.Fatalf("Failed to CreateUser('%+v') - '%+v'", TestUser1.CommonName, err1) 75 | } 76 | t.Logf("Creating '%+v'", TestUser2.CommonName) 77 | err2 := CreateUser(TestUser2.CommonName, TestUser2.Container, TestUser2.ShortName) 78 | if err2 != nil { 79 | t.Fatalf("Failed to CreateUser('%+v') - '%+v'", TestUser2.CommonName, err2) 80 | } 81 | } 82 | 83 | func TestCreateGroups(t *testing.T) { 84 | t.Logf("Creating '%+v'", TestGroup1.CommonName) 85 | err1 := CreateGroup(TestGroup1.CommonName, TestGroup1.Container, TestGroup1.ShortName) 86 | if err1 != nil { 87 | t.Fatalf("Failed to CreateGroup('%+v') - '%+v'", TestGroup1.CommonName, err1) 88 | } 89 | t.Logf("Creating '%+v'", TestGroup2.CommonName) 90 | err2 := CreateGroup(TestGroup2.CommonName, TestGroup2.Container, TestGroup2.ShortName) 91 | if err2 != nil { 92 | t.Fatalf("Failed to CreateGroup('%+v') - '%+v'", TestGroup2.CommonName, err2) 93 | } 94 | } 95 | 96 | func TestUserProps(t *testing.T) { 97 | t.Logf("Setting '%+v' props", TestUser1.CommonName) 98 | // TODO: check err 99 | SetUserPassword(TestUser1.ShortName, TestUser1.Password) 100 | EnableUser(TestUser1.ShortName) 101 | SetUserSN(TestUser1.ShortName, TestUser1.SN) 102 | SetUserInitials(TestUser1.ShortName, TestUser1.Initials) 103 | SetUserGivenName(TestUser1.ShortName, TestUser1.GivenName) 104 | SetUserDisplayName(TestUser1.ShortName, TestUser1.DisplayName) 105 | SetUserRoomNumber(TestUser1.ShortName, TestUser1.RoomNumber) 106 | SetUserAddress(TestUser1.ShortName, TestUser1.Address) 107 | SetUserInfo(TestUser1.ShortName, TestUser1.Info) 108 | SetUserTitle(TestUser1.ShortName, TestUser1.Title) 109 | SetUserDepartment(TestUser1.ShortName, TestUser1.Department) 110 | SetUserCompany(TestUser1.ShortName, TestUser1.Company) 111 | SetUserPhone(TestUser1.ShortName, TestUser1.Phone) 112 | SetUserDescription(TestUser1.ShortName, TestUser1.Description) 113 | 114 | t.Logf("Checking '%+v' props", TestUser1.CommonName) 115 | if ok, err := CheckUserPassword(TestUser1.ShortName, TestUser1.Password); err != nil { 116 | t.Fatalf("Failed to CheckUserPassword('%+v') - '%+v'", TestUser1.ShortName, err) 117 | } else if !ok { 118 | t.Errorf("'%+v' password expected to be '%+v'", TestUser1.CommonName, TestUser1.Password) 119 | } 120 | if props, err := GetObjectAttributes(TestUser1.ShortName); err != nil { 121 | t.Fatalf("Failed to GetObjectAttributes('%+v') - '%+v'", TestUser1.ShortName, err) 122 | } else { 123 | if props["pwdLastSet"][0] == "0" { 124 | t.Errorf("User '%+v' pwdLastSet expected to be set", TestUser1.CommonName) 125 | } 126 | checkmap := map[string]string{ 127 | "name": TestUser1.CommonName, 128 | "company": TestUser1.Company, 129 | "title": TestUser1.Title, 130 | "initials": TestUser1.Initials, 131 | "sn": TestUser1.SN, 132 | "cn": TestUser1.CommonName, 133 | "displayName": TestUser1.DisplayName, 134 | "info": TestUser1.Info, 135 | "streetAddress": TestUser1.Address, 136 | "telephoneNumber": TestUser1.Phone, 137 | "distinguishedName": "CN=" + TestUser1.CommonName + "," + TestOU, 138 | "department": TestUser1.Department, 139 | "givenName": TestUser1.GivenName, 140 | "sAMAccountName": TestUser1.ShortName, 141 | "description": TestUser1.Description, 142 | "physicalDeliveryOfficeName": TestUser1.RoomNumber, 143 | } 144 | for prop, value := range checkmap { 145 | if props[prop][0] != value { 146 | t.Errorf("User '%+v' %+v expected to be '%+v', got '%+v'", TestUser1.CommonName, prop, value, props[prop][0]) 147 | } 148 | } 149 | } 150 | 151 | //controls: map[string]bool{"locked":false, "mustChangePassword":false, "disabled":false, "dontExpirePassword":true, "expired":false} 152 | if controls, err := GetUserControls(TestUser1.ShortName); err != nil { 153 | t.Fatalf("Failed to GetUserControls('%+v') - '%+v'", TestUser1.CommonName, err) 154 | } else { 155 | if controls["disabled"] { 156 | t.Errorf("User '%+v' expected to be enabled", TestUser1.CommonName) 157 | } 158 | } 159 | if controls, err := GetUserControls(TestUser2.ShortName); err != nil { 160 | t.Fatalf("Failed to GetUserControls('%+v') - '%+v'", TestUser2.CommonName, err) 161 | } else { 162 | if !controls["disabled"] { 163 | t.Errorf("User '%+v' expected to be disabled", TestUser2.CommonName) 164 | } 165 | } 166 | } 167 | 168 | func TestUserGroups(t *testing.T) { 169 | t.Logf("Adding '%+v' to '%+v'", TestUser1.CommonName, TestGroup1.CommonName) 170 | if err := GroupAddUser(TestGroup1.ShortName, TestUser1.ShortName); err != nil { 171 | t.Fatalf("Failed to GroupAddUser('%+v', '%+v') - '%+v'", TestGroup1.ShortName, TestUser1.ShortName, err) 172 | } 173 | t.Logf("Adding '%+v' to '%+v'", TestUser1.CommonName, TestGroup2.CommonName) 174 | if err := GroupAddUser(TestGroup2.ShortName, TestUser1.ShortName); err != nil { 175 | t.Fatalf("Failed to GroupAddUser('%+v', '%+v') - '%+v'", TestGroup2.ShortName, TestUser1.ShortName, err) 176 | } 177 | t.Logf("Adding '%+v' to '%+v'", TestUser2.CommonName, TestGroup2.CommonName) 178 | if err := GroupAddUser(TestGroup2.ShortName, TestUser2.ShortName); err != nil { 179 | t.Fatalf("Failed to GroupAddUser('%+v', '%+v') - '%+v'", TestGroup2.ShortName, TestUser2.ShortName, err) 180 | } 181 | 182 | t.Logf("Checking '%+v' memberof", TestUser1.CommonName) 183 | if groups, err := GetUserGroups(TestUser1.ShortName); err != nil { 184 | t.Fatalf("Failed to GetUserGroups('%+v') - '%+v'", TestUser1.ShortName, err) 185 | } else { 186 | expected := []string{TestGroup1.CommonName, TestGroup2.CommonName} 187 | sort.Strings(expected) 188 | sort.Strings(groups) 189 | if !reflect.DeepEqual(groups, expected) { 190 | t.Fatalf("'%+v' groups expected to be '%+v', got '%+v'", TestUser1.CommonName, expected, groups) 191 | } 192 | } 193 | t.Logf("Checking '%+v' memberof", TestUser2.CommonName) 194 | if groups, err := GetUserGroups(TestUser2.ShortName); err != nil { 195 | t.Fatalf("Failed to GetUserGroups('%+v') - '%+v'", TestUser2.ShortName, err) 196 | } else { 197 | expected := []string{TestGroup2.CommonName} 198 | sort.Strings(expected) 199 | sort.Strings(groups) 200 | if !reflect.DeepEqual(groups, expected) { 201 | t.Fatalf("'%+v' groups expected to be '%+v', got '%+v'", TestUser2.CommonName, expected, groups) 202 | } 203 | } 204 | 205 | t.Logf("Checking '%+v' membership", TestGroup1.CommonName) 206 | if users, err := GetUsersInGroup(TestGroup1.CommonName); err != nil { 207 | t.Fatalf("Failed to GetUsersInGroup('%+v') - '%+v'", TestGroup1.ShortName, err) 208 | } else { 209 | expected := []string{TestUser1.ShortName} 210 | sort.Strings(expected) 211 | sort.Strings(users) 212 | if !reflect.DeepEqual(users, expected) { 213 | t.Fatalf("'%+v' users expected to be '%+v', got '%+v'", TestGroup1.CommonName, expected, users) 214 | } 215 | } 216 | t.Logf("Checking '%+v' membership", TestGroup2.CommonName) 217 | if users, err := GetUsersInGroup(TestGroup2.CommonName); err != nil { 218 | t.Fatalf("Failed to GetUsersInGroup('%+v') - '%+v'", TestGroup2.ShortName, err) 219 | } else { 220 | expected := []string{TestUser1.ShortName, TestUser2.ShortName} 221 | sort.Strings(expected) 222 | sort.Strings(users) 223 | if !reflect.DeepEqual(users, expected) { 224 | t.Fatalf("'%+v' users expected to be '%+v', got '%+v'", TestGroup2.CommonName, expected, users) 225 | } 226 | } 227 | 228 | t.Logf("Removing '%+v' from '%+v'", TestUser1.CommonName, TestGroup2.CommonName) 229 | if err := GroupRemoveUser(TestGroup2.ShortName, TestUser1.ShortName); err != nil { 230 | t.Fatalf("Failed to GroupRemoveUser('%+v', '%+v') - '%+v'", TestGroup2.ShortName, TestUser1.ShortName, err) 231 | } 232 | t.Logf("Checking '%+v' membership", TestGroup2.CommonName) 233 | if users, err := GetUsersInGroup(TestGroup2.CommonName); err != nil { 234 | t.Fatalf("Failed to GetUsersInGroup('%+v') - '%+v'", TestGroup2.ShortName, err) 235 | } else { 236 | expected := []string{TestUser2.ShortName} 237 | sort.Strings(expected) 238 | sort.Strings(users) 239 | if !reflect.DeepEqual(users, expected) { 240 | t.Fatalf("'%+v' users expected to be '%+v', got '%+v'", TestGroup2.CommonName, expected, users) 241 | } 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /adclient_wrapper.go: -------------------------------------------------------------------------------- 1 | package adclient 2 | 3 | // #cgo CPPFLAGS: -DOPENLDAP -DKRB5 4 | // #cgo LDFLAGS: -lstdc++ -lldap -lsasl2 -lstdc++ -llber -lresolv -lkrb5 5 | // #include 6 | import "C" 7 | 8 | import "fmt" 9 | import "strings" 10 | import "strconv" 11 | 12 | const ( 13 | AD_SCOPE_BASE = C.LDAP_SCOPE_BASE 14 | AD_SCOPE_BASEOBJECT = C.LDAP_SCOPE_BASE 15 | AD_SCOPE_ONELEVEL = C.LDAP_SCOPE_ONELEVEL 16 | AD_SCOPE_ONE = C.LDAP_SCOPE_ONELEVEL 17 | AD_SCOPE_SUBTREE = C.LDAP_SCOPE_SUBTREE 18 | AD_SCOPE_SUB = C.LDAP_SCOPE_SUBTREE 19 | AD_SCOPE_SUBORDINATE = C.LDAP_SCOPE_SUBORDINATE /* OpenLDAP extension */ 20 | AD_SCOPE_CHILDREN = C.LDAP_SCOPE_SUBORDINATE 21 | AD_SCOPE_DEFAULT = C.LDAP_SCOPE_DEFAULT /* OpenLDAP extension */ 22 | ) 23 | 24 | type ADError struct { 25 | msg string 26 | code int 27 | } 28 | 29 | type ADConnParams struct { 30 | Domain string 31 | Site string 32 | Uries []string 33 | Binddn string 34 | Bindpw string 35 | Search_base string 36 | 37 | Secured bool 38 | UseGSSAPI bool 39 | UseLDAPS bool 40 | UseStartTLS bool 41 | 42 | Nettimeout int 43 | Timelimit int 44 | } 45 | 46 | func DefaultADConnParams() (params ADConnParams) { 47 | params.Nettimeout = -1 48 | params.Timelimit = -1 49 | params.Secured = true 50 | params.UseGSSAPI = false 51 | params.UseLDAPS = false 52 | params.UseStartTLS = false 53 | return 54 | } 55 | 56 | func Ldap_servers(domain string, site string) []string { 57 | vector := AdclientGet_ldap_servers(domain, site) 58 | defer DeleteStringVector(vector) 59 | result := vector2slice(vector) 60 | return result 61 | } 62 | 63 | func Domain2dn(domain string) string { 64 | dn := AdclientDomain2dn(domain) 65 | return dn 66 | } 67 | 68 | func (err ADError) Error() string { 69 | return fmt.Sprintf("%v: %v", err.code, err.msg) 70 | } 71 | 72 | func catch(err *error) { 73 | if r := recover(); r != nil { 74 | err_splitted := strings.SplitN(r.(string), ":", 2) 75 | if len(err_splitted) != 2 { 76 | *err = ADError{ 77 | r.(string), 78 | -1, 79 | } 80 | } else { 81 | code, code_err := strconv.Atoi(err_splitted[0]) 82 | if code_err != nil { 83 | code = -1 84 | } 85 | *err = ADError{ 86 | err_splitted[1], 87 | code, 88 | } 89 | } 90 | } 91 | } 92 | 93 | func vector2slice(vector StringVector) []string { 94 | result := make([]string, vector.Size()) 95 | for i := 0; i < int(vector.Size()); i++ { 96 | result[i] = vector.Get(i) 97 | } 98 | return result 99 | } 100 | 101 | func commonStringToSlice(f func(string) StringVector, thing string) (result []string, err error) { 102 | defer catch(&err) 103 | vector := f(thing) 104 | defer DeleteStringVector(vector) 105 | result = vector2slice(vector) 106 | return 107 | } 108 | 109 | func common2StringsToSlice(f func(string, string) StringVector, thing1 string, thing2 string) (result []string, err error) { 110 | defer catch(&err) 111 | vector := f(thing1, thing2) 112 | defer DeleteStringVector(vector) 113 | result = vector2slice(vector) 114 | return 115 | } 116 | 117 | func commonStringsIntToSlice(f func(string, int) StringVector, thing1 string, thing2 int) (result []string, err error) { 118 | defer catch(&err) 119 | vector := f(thing1, thing2) 120 | defer DeleteStringVector(vector) 121 | result = vector2slice(vector) 122 | return 123 | } 124 | 125 | func commonEmptyToSlice(f func() StringVector) (result []string, err error) { 126 | defer catch(&err) 127 | vector := f() 128 | defer DeleteStringVector(vector) 129 | result = vector2slice(vector) 130 | return 131 | } 132 | 133 | var ad Adclient 134 | 135 | func New() { 136 | ad = NewAdclient() 137 | } 138 | 139 | func Delete() { 140 | DeleteAdclient(ad) 141 | } 142 | 143 | func Login(_params ADConnParams) (err error) { 144 | defer catch(&err) 145 | 146 | params := NewAdConnParams() 147 | defer DeleteAdConnParams(params) 148 | 149 | params.SetDomain(_params.Domain) 150 | params.SetSite(_params.Site) 151 | params.SetBinddn(_params.Binddn) 152 | params.SetBindpw(_params.Bindpw) 153 | params.SetSearch_base(_params.Search_base) 154 | params.SetSecured(_params.Secured) 155 | params.SetUse_gssapi(_params.UseGSSAPI) 156 | params.SetNettimeout(_params.Nettimeout) 157 | params.SetTimelimit(_params.Timelimit) 158 | params.SetUse_tls(_params.UseStartTLS) 159 | params.SetUse_ldaps(_params.UseLDAPS) 160 | 161 | uries := NewStringVector() 162 | defer DeleteStringVector(uries) 163 | for _, uri := range _params.Uries { 164 | uries.Add(uri) 165 | } 166 | params.SetUries(uries) 167 | 168 | ad.Login(params) 169 | return 170 | } 171 | 172 | func LoginOld(uri interface{}, user string, passwd string, sb string, secured bool) (err error) { 173 | defer catch(&err) 174 | 175 | args := DefaultADConnParams() 176 | args.Binddn = user 177 | args.Bindpw = passwd 178 | args.Search_base = sb 179 | args.UseGSSAPI = secured 180 | 181 | switch uri.(type) { 182 | case string: 183 | args.Domain = uri.(string) 184 | case []string: 185 | args.Uries = uri.([]string) 186 | default: 187 | err = ADError{ 188 | fmt.Sprintf("unknown uri type - %#v", uri), 189 | -1, 190 | } 191 | } 192 | Login(args) 193 | return 194 | } 195 | 196 | func BindedUri() (result string) { 197 | return ad.Binded_uri() 198 | } 199 | 200 | func SearchBase() (result string) { 201 | return ad.Search_base() 202 | } 203 | 204 | func LoginMethod() (result string) { 205 | return ad.Login_method() 206 | } 207 | 208 | func BindMethod() (result string) { 209 | return ad.Bind_method() 210 | } 211 | 212 | func GroupAddUser(group string, user string) (err error) { 213 | defer catch(&err) 214 | ad.GroupAddUser(group, user) 215 | return 216 | } 217 | 218 | func GroupRemoveUser(group string, user string) (err error) { 219 | defer catch(&err) 220 | ad.GroupRemoveUser(group, user) 221 | return 222 | } 223 | 224 | func CreateComputer(name string, container string) (err error) { 225 | defer catch(&err) 226 | ad.CreateComputer(name, container) 227 | return 228 | } 229 | 230 | func CreateUser(cn string, container string, user_short string) (err error) { 231 | defer catch(&err) 232 | ad.CreateUser(cn, container, user_short) 233 | return 234 | } 235 | 236 | func CreateGroup(cn string, container string, group_short string) (err error) { 237 | defer catch(&err) 238 | ad.CreateGroup(cn, container, group_short) 239 | return 240 | } 241 | 242 | func DeleteDN(dn string) (err error) { 243 | defer catch(&err) 244 | ad.DeleteDN(dn) 245 | return 246 | } 247 | 248 | func RenameDN(dn string, new_rdn string) (err error) { 249 | defer catch(&err) 250 | ad.RenameDN(dn, new_rdn) 251 | return 252 | } 253 | 254 | func RenameGroup(dn string, new_rdn string) (err error) { 255 | defer catch(&err) 256 | ad.RenameGroup(dn, new_rdn) 257 | return 258 | } 259 | 260 | func CreateOU(ou string) (err error) { 261 | defer catch(&err) 262 | ad.CreateOU(ou) 263 | return 264 | } 265 | 266 | func EnableUser(user string) (err error) { 267 | defer catch(&err) 268 | ad.EnableUser(user) 269 | return 270 | } 271 | 272 | func DisableUser(user string) (err error) { 273 | defer catch(&err) 274 | ad.DisableUser(user) 275 | return 276 | } 277 | 278 | func UnLockUser(user string) (err error) { 279 | defer catch(&err) 280 | ad.UnLockUser(user) 281 | return 282 | } 283 | 284 | func SetUserPassword(user string, password string) (err error) { 285 | defer catch(&err) 286 | ad.SetUserPassword(user, password) 287 | return 288 | } 289 | 290 | func SetUserDialinAllowed(user string) (err error) { 291 | defer catch(&err) 292 | ad.SetUserDialinAllowed(user) 293 | return 294 | } 295 | 296 | func SetUserDialinDisabled(user string) (err error) { 297 | defer catch(&err) 298 | ad.SetUserDialinDisabled(user) 299 | return 300 | } 301 | 302 | func CheckUserPassword(user string, password string) (result bool, err error) { 303 | defer catch(&err) 304 | result = ad.CheckUserPassword(user, password) 305 | return 306 | } 307 | 308 | func SetUserSN(user string, sn string) (err error) { 309 | defer catch(&err) 310 | ad.SetUserSN(user, sn) 311 | return 312 | } 313 | 314 | func SetUserInitials(user string, initials string) (err error) { 315 | defer catch(&err) 316 | ad.SetUserInitials(user, initials) 317 | return 318 | } 319 | 320 | func SetUserGivenName(user string, givenName string) (err error) { 321 | defer catch(&err) 322 | ad.SetUserGivenName(user, givenName) 323 | return 324 | } 325 | 326 | func SetUserDisplayName(user string, displayName string) (err error) { 327 | defer catch(&err) 328 | ad.SetUserDisplayName(user, displayName) 329 | return 330 | } 331 | 332 | func SetUserRoomNumber(user string, roomNum string) (err error) { 333 | defer catch(&err) 334 | ad.SetUserRoomNumber(user, roomNum) 335 | return 336 | } 337 | 338 | func SetUserAddress(user string, streetAddress string) (err error) { 339 | defer catch(&err) 340 | ad.SetUserAddress(user, streetAddress) 341 | return 342 | } 343 | 344 | func SetUserInfo(user string, info string) (err error) { 345 | defer catch(&err) 346 | ad.SetUserInfo(user, info) 347 | return 348 | } 349 | 350 | func SetUserTitle(user string, title string) (err error) { 351 | defer catch(&err) 352 | ad.SetUserTitle(user, title) 353 | return 354 | } 355 | 356 | func SetUserDepartment(user string, department string) (err error) { 357 | defer catch(&err) 358 | ad.SetUserDepartment(user, department) 359 | return 360 | } 361 | 362 | func SetUserCompany(user string, company string) (err error) { 363 | defer catch(&err) 364 | ad.SetUserCompany(user, company) 365 | return 366 | } 367 | 368 | func SetUserPhone(user string, phone string) (err error) { 369 | defer catch(&err) 370 | ad.SetUserPhone(user, phone) 371 | return 372 | } 373 | 374 | func SetUserDescription(user string, descr string) (err error) { 375 | defer catch(&err) 376 | ad.SetUserDescription(user, descr) 377 | return 378 | } 379 | 380 | func GetUserControls(user string) (result map[string]bool, err error) { 381 | result = make(map[string]bool) 382 | defer catch(&err) 383 | cmap := ad.GetUserControls(user) 384 | defer DeleteStringBoolMap(cmap) 385 | keys := cmap.Keys() 386 | for i := 0; i < int(keys.Size()); i++ { 387 | key := keys.Get(i) 388 | result[key] = cmap.Get(key) 389 | } 390 | return 391 | } 392 | 393 | func GetUserControl(user string, control string) (result bool, err error) { 394 | defer catch(&err) 395 | result = ad.GetUserControl(user, control) 396 | return 397 | } 398 | 399 | func IfUserExpired(user string) (result bool, err error) { 400 | defer catch(&err) 401 | result = ad.IfUserExpired(user) 402 | return 403 | } 404 | 405 | func IfUserLocked(user string) (result bool, err error) { 406 | defer catch(&err) 407 | result = ad.IfUserLocked(user) 408 | return 409 | } 410 | 411 | func IfUserDisabled(user string) (result bool, err error) { 412 | defer catch(&err) 413 | result = ad.IfUserDisabled(user) 414 | return 415 | } 416 | 417 | func IfUserMustChangePassword(user string) (result bool, err error) { 418 | defer catch(&err) 419 | result = ad.IfUserMustChangePassword(user) 420 | return 421 | } 422 | 423 | func IfUserDontExpirePassword(user string) (result bool, err error) { 424 | defer catch(&err) 425 | result = ad.IfUserDontExpirePassword(user) 426 | return 427 | } 428 | 429 | func GetObjectDN(object string) (result string, err error) { 430 | defer catch(&err) 431 | result = ad.GetObjectDN(object) 432 | return 433 | } 434 | 435 | func GetUserDisplayName(user string) (result string, err error) { 436 | defer catch(&err) 437 | result = ad.GetUserDisplayName(user) 438 | return 439 | } 440 | 441 | func IfDialinUser(user string) (result bool, err error) { 442 | defer catch(&err) 443 | result = ad.IfDialinUser(user) 444 | return 445 | } 446 | 447 | func IfDNExists(args ...string) (result bool, err error) { 448 | defer catch(&err) 449 | switch len(args) { 450 | case 1: 451 | result = ad.IfDNExists(args[0]) 452 | case 2: 453 | result = ad.IfDNExists(args[0], args[1]) 454 | default: 455 | panic("wrong number of args for IfDNExists") 456 | } 457 | return 458 | } 459 | 460 | func GetGroups() ([]string, error) { 461 | return commonEmptyToSlice(ad.GetGroups) 462 | } 463 | 464 | func GetUsers() ([]string, error) { 465 | return commonEmptyToSlice(ad.GetUsers) 466 | } 467 | 468 | func GetOUs() ([]string, error) { 469 | return commonEmptyToSlice(ad.GetOUs) 470 | } 471 | 472 | func GetDialinUsers() ([]string, error) { 473 | return commonEmptyToSlice(ad.GetDialinUsers) 474 | } 475 | 476 | func GetDisabledUsers() ([]string, error) { 477 | return commonEmptyToSlice(ad.GetDisabledUsers) 478 | } 479 | 480 | func GetUserGroups(user string, nested bool) (result []string, err error) { 481 | defer catch(&err) 482 | vector := ad.GetUserGroups(user, nested) 483 | defer DeleteStringVector(vector) 484 | result = vector2slice(vector) 485 | return 486 | } 487 | 488 | func GetUsersInGroup(group string, nested bool) (result []string, err error) { 489 | defer catch(&err) 490 | vector := ad.GetUsersInGroup(group, nested) 491 | defer DeleteStringVector(vector) 492 | result = vector2slice(vector) 493 | return 494 | } 495 | 496 | func GetGroupsInOU(OU string, scope int) (result []string, err error) { 497 | return commonStringsIntToSlice(ad.GetGroupsInOU, OU, scope) 498 | } 499 | 500 | func GetComputersInOU(OU string, scope int) (result []string, err error) { 501 | return commonStringsIntToSlice(ad.GetComputersInOU, OU, scope) 502 | } 503 | 504 | func GetOUsInOU(OU string, scope int) (result []string, err error) { 505 | return commonStringsIntToSlice(ad.GetOUsInOU, OU, scope) 506 | } 507 | 508 | func GetUsersInOU(OU string, scope int) (result []string, err error) { 509 | return commonStringsIntToSlice(ad.GetUsersInOU, OU, scope) 510 | } 511 | 512 | func GetObjectAttribute(object string, attribute string) (result []string, err error) { 513 | return common2StringsToSlice(ad.GetObjectAttribute, object, attribute) 514 | } 515 | 516 | func SearchDN(search_base string, filter string, scope int) (result []string, err error) { 517 | defer catch(&err) 518 | vector := ad.SearchDN(search_base, filter, scope) 519 | defer DeleteStringVector(vector) 520 | result = vector2slice(vector) 521 | return 522 | } 523 | 524 | func SetObjectAttribute(object string, attr string, values ...string) (err error) { 525 | if len(values) == 0 { 526 | err = ADError{ 527 | fmt.Sprintf("wrong number of arguments"), 528 | -1, 529 | } 530 | } else { 531 | defer catch(&err) 532 | cattrs := NewStringVector() 533 | defer DeleteStringVector(cattrs) 534 | for _, attr := range values { 535 | cattrs.Add(attr) 536 | } 537 | ad.SetObjectAttribute(object, attr, cattrs) 538 | } 539 | return 540 | } 541 | 542 | func ClearObjectAttribute(object string, attr string) (err error) { 543 | defer catch(&err) 544 | ad.ClearObjectAttribute(object, attr) 545 | return 546 | } 547 | 548 | func MoveObject(object string, new_container string) (err error) { 549 | defer catch(&err) 550 | ad.MoveObject(object, new_container) 551 | return 552 | } 553 | 554 | func MoveUser(user string, new_container string) (err error) { 555 | defer catch(&err) 556 | ad.MoveUser(user, new_container) 557 | return 558 | } 559 | 560 | func RenameUser(user string, shortname string, cn_optional ...string) (err error) { 561 | cn := "" 562 | if len(cn_optional) > 0 { 563 | cn = cn_optional[0] 564 | } 565 | defer catch(&err) 566 | ad.RenameUser(user, shortname, cn) 567 | return 568 | } 569 | 570 | /* 571 | map < string, map < string, std::vector > > search(string OU, int scope, string filter, const std::vector &attributes); 572 | */ 573 | 574 | func GetObjectAttributes(object string, attrs ...string) (result map[string][]string, err error) { 575 | cattrs := NewStringVector() 576 | defer DeleteStringVector(cattrs) 577 | if len(attrs) == 0 { 578 | cattrs.Add("*") 579 | } else { 580 | for _, attr := range attrs { 581 | cattrs.Add(attr) 582 | } 583 | } 584 | 585 | result = make(map[string][]string) 586 | defer catch(&err) 587 | cmap := ad.GetObjectAttributes(object, cattrs) 588 | defer DeleteString_VectorString_Map(cmap) 589 | keys := cmap.Keys() 590 | for i := 0; i < int(keys.Size()); i++ { 591 | key := keys.Get(i) 592 | value := cmap.Get(key) 593 | result[key] = vector2slice(value) 594 | } 595 | return 596 | } 597 | 598 | /* 599 | map > GetObjectAttributes(string object, const std::vector &attributes); 600 | */ 601 | -------------------------------------------------------------------------------- /adclient_wrapper_python2.cpp: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | /* 4 | Python wrapper around C++ class. 5 | */ 6 | #include 7 | #include "adclient.h" 8 | 9 | static PyObject *ADBindError; 10 | static PyObject *ADSearchError; 11 | static PyObject *ADOperationalError; 12 | static int error_num; 13 | 14 | PyObject *vector2list(vector vec) { 15 | string st; 16 | PyObject *list = PyList_New(vec.size());; 17 | 18 | for (unsigned int j=0; (j < vec.size()); j++) { 19 | if (PyList_SetItem(list, j, PyString_FromStringAndSize(vec[j].c_str(), vec[j].size())) < 0) 20 | return NULL; 21 | } 22 | return list; 23 | } 24 | 25 | adclient *convert_ad(PyObject *obj) { 26 | void * temp = PyCObject_AsVoidPtr(obj); 27 | return static_cast(temp); 28 | } 29 | 30 | static PyObject *wrapper_get_error_num(PyObject *self, PyObject *args) { 31 | return Py_BuildValue("i", error_num); 32 | } 33 | 34 | static PyObject *wrapper_domain2dn(PyObject *self, PyObject *args) { 35 | char *domain; 36 | if (!PyArg_ParseTuple(args, "s", &domain)) return NULL; 37 | string result = adclient::domain2dn(domain); 38 | return Py_BuildValue("s", result.c_str()); 39 | } 40 | 41 | static PyObject *wrapper_decodeSID(PyObject *self, PyObject *args) { 42 | char *sid; 43 | int len; 44 | if (!PyArg_ParseTuple(args, "s#", &sid, &len)) return NULL; 45 | string result = decodeSID(string(sid, len)); 46 | return Py_BuildValue("s", result.c_str()); 47 | } 48 | 49 | static PyObject *wrapper_FileTimeToPOSIX(PyObject *self, PyObject *args) { 50 | long long filetime; 51 | if (!PyArg_ParseTuple(args, "L", &filetime)) return NULL; 52 | time_t result = FileTimeToPOSIX(filetime); 53 | return Py_BuildValue("i", result); 54 | } 55 | 56 | static PyObject *wrapper_get_ldap_servers(PyObject *self, PyObject *args) { 57 | char *domain, *site; 58 | if (!PyArg_ParseTuple(args, "ss", &domain, &site)) return NULL; 59 | vector result = adclient::get_ldap_servers(domain, site); 60 | return vector2list(result); 61 | } 62 | 63 | static PyObject *wrapper_int2ip(PyObject *self, PyObject *args) { 64 | char *ipstr; 65 | if (!PyArg_ParseTuple(args, "s", &ipstr)) return NULL; 66 | string result = int2ip(ipstr); 67 | return Py_BuildValue("s", result.c_str()); 68 | } 69 | 70 | static PyObject *wrapper_new_adclient(PyObject *self, PyObject *args) { 71 | error_num = 0; 72 | adclient *obj = new adclient(); 73 | return PyCObject_FromVoidPtr(obj, NULL); 74 | } 75 | 76 | string dict_get_string(PyObject *dict, string key_str) { 77 | string result; 78 | 79 | PyObject *key = PyString_FromString(key_str.c_str()); 80 | if (PyDict_Contains(dict, key) == 1) { 81 | PyObject *val = PyDict_GetItem(dict, key); 82 | if (PyString_Check(val)) { 83 | result = PyString_AsString(val); 84 | } 85 | } 86 | Py_DECREF(key); 87 | return result; 88 | } 89 | 90 | bool dict_get_bool(PyObject *dict, string key_str) { 91 | bool result = false; 92 | 93 | PyObject *key = PyString_FromString(key_str.c_str()); 94 | if (PyDict_Contains(dict, key) == 1) { 95 | PyObject *val = PyDict_GetItem(dict, key); 96 | result = PyObject_IsTrue(val); 97 | } 98 | Py_DECREF(key); 99 | return result; 100 | } 101 | 102 | int dict_get_int(PyObject *dict, string key_str) { 103 | int result = -1; 104 | 105 | PyObject *key = PyString_FromString(key_str.c_str()); 106 | if (PyDict_Contains(dict, key) == 1) { 107 | PyObject *val = PyDict_GetItem(dict, key); 108 | result = PyInt_AsLong(val); 109 | } 110 | Py_DECREF(key); 111 | return result; 112 | } 113 | 114 | static PyObject *wrapper_login_adclient(PyObject *self, PyObject *args) { 115 | PyObject *obj; 116 | PyObject *paramsObj; 117 | 118 | if (!PyArg_ParseTuple(args, "OO!", &obj, &PyDict_Type, ¶msObj)) return NULL; 119 | 120 | adConnParams params; 121 | 122 | params.domain = dict_get_string(paramsObj, "domain"); 123 | params.site = dict_get_string(paramsObj, "site"); 124 | params.binddn = dict_get_string(paramsObj, "binddn"); 125 | params.bindpw = dict_get_string(paramsObj, "bindpw"); 126 | params.search_base = dict_get_string(paramsObj, "search_base"); 127 | params.secured = dict_get_bool(paramsObj, "secured"); 128 | params.use_gssapi = dict_get_bool(paramsObj, "use_gssapi"); 129 | params.use_tls = dict_get_bool(paramsObj, "use_tls"); 130 | params.use_ldaps = dict_get_bool(paramsObj, "use_ldaps"); 131 | params.nettimeout = dict_get_int(paramsObj, "nettimeout"); 132 | params.timelimit = dict_get_int(paramsObj, "timelimit"); 133 | 134 | PyObject *key = PyString_FromString("uries"); 135 | if (PyDict_Contains(paramsObj, key) == 1) { 136 | PyObject *val = PyDict_GetItem(paramsObj, key); 137 | if (PyList_Check(val)) { 138 | for (unsigned int i = 0; i < PyList_Size(val); i++) { 139 | PyObject *strObj = PyList_GetItem(val, i); 140 | if (PyString_Check(strObj)) { 141 | string item = PyString_AsString(strObj); 142 | params.uries.push_back(item); 143 | } 144 | } 145 | } 146 | } 147 | Py_DECREF(key); 148 | 149 | adclient *ad = convert_ad(obj); 150 | try { 151 | ad->login(params); 152 | } 153 | catch (ADBindException& ex) { 154 | error_num = ex.code; 155 | PyErr_SetString(ADBindError, ex.msg.c_str()); 156 | return NULL; 157 | } 158 | Py_INCREF(Py_None); 159 | return Py_None; 160 | } 161 | 162 | static PyObject *wrapper_binded_uri_adclient(PyObject *self, PyObject *args) { 163 | PyObject *obj; 164 | 165 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 166 | 167 | adclient *ad = convert_ad(obj); 168 | return Py_BuildValue("s", ad->binded_uri().c_str()); 169 | } 170 | 171 | static PyObject *wrapper_search_base_adclient(PyObject *self, PyObject *args) { 172 | PyObject *obj; 173 | 174 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 175 | 176 | adclient *ad = convert_ad(obj); 177 | return Py_BuildValue("s", ad->search_base().c_str()); 178 | } 179 | 180 | static PyObject *wrapper_login_method_adclient(PyObject *self, PyObject *args) { 181 | PyObject *obj; 182 | 183 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 184 | 185 | adclient *ad = convert_ad(obj); 186 | return Py_BuildValue("s", ad->login_method().c_str()); 187 | } 188 | 189 | static PyObject *wrapper_bind_method_adclient(PyObject *self, PyObject *args) { 190 | PyObject *obj; 191 | 192 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 193 | 194 | adclient *ad = convert_ad(obj); 195 | return Py_BuildValue("s", ad->bind_method().c_str()); 196 | } 197 | 198 | static PyObject *wrapper_search_adclient(PyObject *self, PyObject *args) { 199 | PyObject *obj; 200 | char *ou, *filter; 201 | PyObject * listObj; 202 | int scope; 203 | 204 | map < string, map < string, vector > > res; 205 | 206 | if (!PyArg_ParseTuple(args, "OsisO!", &obj, &ou, &scope, &filter, &PyList_Type, &listObj)) return NULL; 207 | 208 | vector attrs; 209 | 210 | for (unsigned int i = 0; i < PyList_Size(listObj); ++i) { 211 | PyObject *strObj = PyList_GetItem(listObj, i); 212 | string item = PyString_AsString(strObj); 213 | attrs.push_back(item); 214 | } 215 | 216 | adclient *ad = convert_ad(obj); 217 | try { 218 | res = ad->search(ou, scope, filter, attrs); 219 | } 220 | catch(ADSearchException& ex) { 221 | error_num = ex.code; 222 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 223 | return NULL; 224 | } 225 | 226 | PyObject *res_dict = PyDict_New(); 227 | map < string, map < string, vector > >::iterator res_it; 228 | for ( res_it=res.begin() ; res_it != res.end(); ++res_it ) { 229 | PyObject *attrs_dict = PyDict_New(); 230 | string dn = (*res_it).first; 231 | map < string, vector > attrs = (*res_it).second; 232 | map < string, vector >::iterator attrs_it; 233 | for ( attrs_it=attrs.begin() ; attrs_it != attrs.end(); ++attrs_it ) { 234 | string attribute = (*attrs_it).first; 235 | vector values_v = (*attrs_it).second; 236 | PyObject *values_list = vector2list(values_v); 237 | if (PyDict_SetItemString(attrs_dict, attribute.c_str(), values_list) < 0) return NULL; 238 | } 239 | if (PyDict_SetItemString(res_dict, dn.c_str(), attrs_dict) < 0) return NULL; 240 | } 241 | return res_dict; 242 | } 243 | 244 | static PyObject *wrapper_searchDN_adclient(PyObject *self, PyObject *args) { 245 | PyObject *obj; 246 | char *search_base, *filter; 247 | int scope; 248 | 249 | vector result; 250 | if (!PyArg_ParseTuple(args, "Ossi", &obj, &search_base, &filter, &scope)) return NULL; 251 | adclient *ad = convert_ad(obj); 252 | try { 253 | result = ad->searchDN(search_base, filter, scope); 254 | } 255 | catch(ADSearchException& ex) { 256 | error_num = ex.code; 257 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 258 | return NULL; 259 | } 260 | return vector2list(result); 261 | } 262 | 263 | static PyObject *wrapper_getUserGroups_adclient(PyObject *self, PyObject *args) { 264 | PyObject *obj; 265 | char *user; 266 | int nested; 267 | vector result; 268 | if (!PyArg_ParseTuple(args, "Osi", &obj, &user, &nested)) return NULL; 269 | adclient *ad = convert_ad(obj); 270 | try { 271 | result = ad->getUserGroups(user, nested); 272 | } 273 | catch(ADSearchException& ex) { 274 | error_num = ex.code; 275 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 276 | return NULL; 277 | } 278 | return vector2list(result); 279 | } 280 | 281 | static PyObject *wrapper_getUsersInGroup_adclient(PyObject *self, PyObject *args) { 282 | PyObject *obj; 283 | char *group; 284 | int nested; 285 | vector result; 286 | if (!PyArg_ParseTuple(args, "Osi", &obj, &group, &nested)) return NULL; 287 | adclient *ad = convert_ad(obj); 288 | try { 289 | result = ad->getUsersInGroup(group, nested); 290 | } 291 | catch(ADSearchException& ex) { 292 | error_num = ex.code; 293 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 294 | return NULL; 295 | } 296 | return vector2list(result); 297 | } 298 | 299 | static PyObject *wrapper_getUserControls_adclient(PyObject *self, PyObject *args) { 300 | PyObject *obj; 301 | char *user; 302 | map result; 303 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 304 | adclient *ad = convert_ad(obj); 305 | try { 306 | result = ad->getUserControls(user); 307 | } 308 | catch(ADSearchException& ex) { 309 | error_num = ex.code; 310 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 311 | return NULL; 312 | } 313 | PyObject *res_dict = PyDict_New(); 314 | map ::iterator it; 315 | for (it = result.begin(); it != result.end(); ++it) { 316 | if (PyDict_SetItemString(res_dict, (*it).first.c_str(), PyBool_FromLong((*it).second)) < 0) 317 | return NULL; 318 | } 319 | 320 | return res_dict; 321 | } 322 | 323 | static PyObject *wrapper_groupAddUser_adclient(PyObject *self, PyObject *args) { 324 | PyObject *obj; 325 | char *group, *user; 326 | if (!PyArg_ParseTuple(args, "Oss", &obj, &group, &user)) return NULL; 327 | adclient *ad = convert_ad(obj); 328 | try { 329 | ad->groupAddUser(group, user); 330 | } 331 | catch(ADSearchException& ex) { 332 | error_num = ex.code; 333 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 334 | return NULL; 335 | } 336 | catch(ADOperationalException& ex) { 337 | error_num = ex.code; 338 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 339 | return NULL; 340 | } 341 | Py_INCREF(Py_None); 342 | return Py_None; 343 | } 344 | 345 | static PyObject *wrapper_groupRemoveUser_adclient(PyObject *self, PyObject *args) { 346 | PyObject *obj; 347 | char *group, *user; 348 | if (!PyArg_ParseTuple(args, "Oss", &obj, &group, &user)) return NULL; 349 | adclient *ad = convert_ad(obj); 350 | try { 351 | ad->groupRemoveUser(group, user); 352 | } 353 | catch(ADSearchException& ex) { 354 | error_num = ex.code; 355 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 356 | return NULL; 357 | } 358 | catch(ADOperationalException& ex) { 359 | error_num = ex.code; 360 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 361 | return NULL; 362 | } 363 | Py_INCREF(Py_None); 364 | return Py_None; 365 | } 366 | 367 | static PyObject *wrapper_ifDialinUser_adclient(PyObject *self, PyObject *args) { 368 | PyObject *obj; 369 | char *user; 370 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 371 | adclient *ad = convert_ad(obj); 372 | try { 373 | return Py_BuildValue("i", ad->ifDialinUser(user)); 374 | } 375 | catch(ADSearchException& ex) { 376 | error_num = ex.code; 377 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 378 | return NULL; 379 | } 380 | } 381 | 382 | static PyObject *wrapper_getDialinUsers_adclient(PyObject *self, PyObject *args) { 383 | PyObject *obj; 384 | vector result; 385 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 386 | adclient *ad = convert_ad(obj); 387 | try { 388 | result = ad->getDialinUsers(); 389 | } 390 | catch(ADSearchException& ex) { 391 | error_num = ex.code; 392 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 393 | return NULL; 394 | } 395 | return vector2list(result); 396 | } 397 | 398 | static PyObject *wrapper_getDisabledUsers_adclient(PyObject *self, PyObject *args) { 399 | PyObject *obj; 400 | vector result; 401 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 402 | adclient *ad = convert_ad(obj); 403 | try { 404 | result = ad->getDisabledUsers(); 405 | } 406 | catch(ADSearchException& ex) { 407 | error_num = ex.code; 408 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 409 | return NULL; 410 | } 411 | return vector2list(result); 412 | } 413 | 414 | static PyObject *wrapper_getObjectDN_adclient(PyObject *self, PyObject *args) { 415 | PyObject *obj; 416 | char *user; 417 | string result; 418 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 419 | adclient *ad = convert_ad(obj); 420 | try { 421 | result = ad->getObjectDN(user); 422 | } 423 | catch(ADSearchException& ex) { 424 | error_num = ex.code; 425 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 426 | return NULL; 427 | } 428 | return Py_BuildValue("s", result.c_str()); 429 | } 430 | 431 | static PyObject *wrapper_ifUserDisabled_adclient(PyObject *self, PyObject *args) { 432 | PyObject *obj; 433 | char *user; 434 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 435 | adclient *ad = convert_ad(obj); 436 | try { 437 | return Py_BuildValue("N", PyBool_FromLong(ad->ifUserDisabled(user))); 438 | } 439 | catch(ADSearchException& ex) { 440 | error_num = ex.code; 441 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 442 | return NULL; 443 | } 444 | } 445 | 446 | static PyObject *wrapper_ifDNExists_adclient(PyObject *self, PyObject *args) { 447 | PyObject *obj; 448 | char *dn; 449 | char *objectclass; 450 | 451 | if (!PyArg_ParseTuple(args, "Oss", &obj, &dn, &objectclass)) return NULL; 452 | adclient *ad = convert_ad(obj); 453 | try { 454 | return Py_BuildValue("N", PyBool_FromLong(ad->ifDNExists(dn, objectclass))); 455 | } 456 | catch(ADSearchException& ex) { 457 | error_num = ex.code; 458 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 459 | return NULL; 460 | } 461 | } 462 | 463 | static PyObject *wrapper_getOUs_adclient(PyObject *self, PyObject *args) { 464 | PyObject *obj; 465 | vector result; 466 | 467 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 468 | adclient *ad = convert_ad(obj); 469 | try { 470 | result = ad->getOUs(); 471 | } 472 | catch(ADSearchException& ex) { 473 | error_num = ex.code; 474 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 475 | return NULL; 476 | } 477 | return vector2list(result); 478 | } 479 | 480 | static PyObject *wrapper_getOUsInOU_adclient(PyObject *self, PyObject *args) { 481 | PyObject *obj; 482 | char *OU; 483 | int scope; 484 | 485 | vector result; 486 | 487 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 488 | adclient *ad = convert_ad(obj); 489 | try { 490 | result = ad->getOUsInOU(OU, scope); 491 | } 492 | catch(ADSearchException& ex) { 493 | error_num = ex.code; 494 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 495 | return NULL; 496 | } 497 | return vector2list(result); 498 | } 499 | 500 | static PyObject *wrapper_getUsersInOU_adclient(PyObject *self, PyObject *args) { 501 | PyObject *obj; 502 | char *OU; 503 | int scope; 504 | 505 | vector result; 506 | 507 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 508 | adclient *ad = convert_ad(obj); 509 | try { 510 | result = ad->getUsersInOU(OU, scope); 511 | } 512 | catch(ADSearchException& ex) { 513 | error_num = ex.code; 514 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 515 | return NULL; 516 | } 517 | return vector2list(result); 518 | } 519 | 520 | static PyObject *wrapper_getComputersInOU_adclient(PyObject *self, PyObject *args) { 521 | PyObject *obj; 522 | char *OU; 523 | int scope; 524 | 525 | vector result; 526 | 527 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 528 | adclient *ad = convert_ad(obj); 529 | try { 530 | result = ad->getComputersInOU(OU, scope); 531 | } 532 | catch(ADSearchException& ex) { 533 | error_num = ex.code; 534 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 535 | return NULL; 536 | } 537 | return vector2list(result); 538 | } 539 | 540 | static PyObject *wrapper_getGroupsInOU_adclient(PyObject *self, PyObject *args) { 541 | PyObject *obj; 542 | char *OU; 543 | int scope; 544 | 545 | vector result; 546 | 547 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 548 | adclient *ad = convert_ad(obj); 549 | try { 550 | result = ad->getGroupsInOU(OU, scope); 551 | } 552 | catch(ADSearchException& ex) { 553 | error_num = ex.code; 554 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 555 | return NULL; 556 | } 557 | return vector2list(result); 558 | } 559 | 560 | static PyObject *wrapper_getGroups_adclient(PyObject *self, PyObject *args) { 561 | PyObject *obj; 562 | vector result; 563 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 564 | adclient *ad = convert_ad(obj); 565 | try { 566 | result = ad->getGroups(); 567 | } 568 | catch(ADSearchException& ex) { 569 | error_num = ex.code; 570 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 571 | return NULL; 572 | } 573 | return vector2list(result); 574 | } 575 | 576 | static PyObject *wrapper_getUsers_adclient(PyObject *self, PyObject *args) { 577 | PyObject *obj; 578 | vector result; 579 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 580 | adclient *ad = convert_ad(obj); 581 | try { 582 | result = ad->getUsers(); 583 | } 584 | catch(ADSearchException& ex) { 585 | error_num = ex.code; 586 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 587 | return NULL; 588 | } 589 | return vector2list(result); 590 | } 591 | 592 | static PyObject *wrapper_getUserDisplayName_adclient(PyObject *self, PyObject *args) { 593 | PyObject *obj; 594 | char *user_short; 595 | string result; 596 | if (!PyArg_ParseTuple(args, "Os", &obj, &user_short)) return NULL; 597 | adclient *ad = convert_ad(obj); 598 | try { 599 | result = ad->getUserDisplayName(user_short); 600 | } 601 | catch(ADSearchException& ex) { 602 | error_num = ex.code; 603 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 604 | return NULL; 605 | } 606 | return Py_BuildValue("s", result.c_str()); 607 | } 608 | 609 | static PyObject *wrapper_getUserIpAddress_adclient(PyObject *self, PyObject *args) { 610 | PyObject *obj; 611 | char *user_short; 612 | string result; 613 | if (!PyArg_ParseTuple(args, "Os", &obj, &user_short)) return NULL; 614 | adclient *ad = convert_ad(obj); 615 | try { 616 | result = ad->getUserIpAddress(user_short); 617 | } 618 | catch(ADSearchException& ex) { 619 | error_num = ex.code; 620 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 621 | return NULL; 622 | } 623 | return Py_BuildValue("s", result.c_str()); 624 | } 625 | 626 | static PyObject *wrapper_getObjectAttribute_adclient(PyObject *self, PyObject *args) { 627 | PyObject *obj; 628 | char *user_short, *attribute; 629 | vector result; 630 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user_short, &attribute)) return NULL; 631 | adclient *ad = convert_ad(obj); 632 | try { 633 | result = ad->getObjectAttribute(user_short, attribute); 634 | } 635 | catch(ADSearchException& ex) { 636 | error_num = ex.code; 637 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 638 | return NULL; 639 | } 640 | return vector2list(result); 641 | } 642 | 643 | static PyObject *wrapper_getObjectAttributes_adclient(PyObject *self, PyObject *args) { 644 | PyObject *obj; 645 | char *object_short; 646 | map > result; 647 | if (!PyArg_ParseTuple(args, "Os", &obj, &object_short)) return NULL; 648 | adclient *ad = convert_ad(obj); 649 | try { 650 | result = ad->getObjectAttributes(object_short); 651 | } 652 | catch(ADSearchException& ex) { 653 | error_num = ex.code; 654 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 655 | return NULL; 656 | } 657 | 658 | string attr; 659 | vector values; 660 | 661 | PyObject *res_dict = PyDict_New(); 662 | 663 | map >::iterator it; 664 | for (it = result.begin(); it != result.end(); ++it) { 665 | attr = it->first; 666 | values = it->second; 667 | PyObject *temp_list = vector2list(values); 668 | PyDict_SetItemString(res_dict, attr.c_str(), temp_list); 669 | } 670 | return res_dict; 671 | } 672 | 673 | static PyObject *wrapper_CreateComputer_adclient(PyObject *self, PyObject *args) { 674 | PyObject *obj; 675 | char *name, *container; 676 | if (!PyArg_ParseTuple(args, "Oss", &obj, &name, &container)) return NULL; 677 | adclient *ad = convert_ad(obj); 678 | try { 679 | ad->CreateComputer(name, container); 680 | } 681 | catch(ADSearchException& ex) { 682 | error_num = ex.code; 683 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 684 | return NULL; 685 | } 686 | catch(ADOperationalException& ex) { 687 | error_num = ex.code; 688 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 689 | return NULL; 690 | } 691 | Py_INCREF(Py_None); 692 | return Py_None; 693 | } 694 | 695 | static PyObject *wrapper_CreateUser_adclient(PyObject *self, PyObject *args) { 696 | PyObject *obj; 697 | char *cn, *short_name, *container; 698 | if (!PyArg_ParseTuple(args, "Osss", &obj, &cn, &container, &short_name)) return NULL; 699 | adclient *ad = convert_ad(obj); 700 | try { 701 | ad->CreateUser(cn, container, short_name); 702 | } 703 | catch(ADSearchException& ex) { 704 | error_num = ex.code; 705 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 706 | return NULL; 707 | } 708 | catch(ADOperationalException& ex) { 709 | error_num = ex.code; 710 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 711 | return NULL; 712 | } 713 | Py_INCREF(Py_None); 714 | return Py_None; 715 | } 716 | 717 | static PyObject *wrapper_CreateGroup_adclient(PyObject *self, PyObject *args) { 718 | PyObject *obj; 719 | char *cn, *short_name, *container; 720 | if (!PyArg_ParseTuple(args, "Osss", &obj, &cn, &container, &short_name)) return NULL; 721 | adclient *ad = convert_ad(obj); 722 | try { 723 | ad->CreateGroup(cn, container, short_name); 724 | } 725 | catch(ADSearchException& ex) { 726 | error_num = ex.code; 727 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 728 | return NULL; 729 | } 730 | catch(ADOperationalException& ex) { 731 | error_num = ex.code; 732 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 733 | return NULL; 734 | } 735 | Py_INCREF(Py_None); 736 | return Py_None; 737 | } 738 | 739 | static PyObject *wrapper_DeleteDN_adclient(PyObject *self, PyObject *args) { 740 | PyObject *obj; 741 | char *dn; 742 | if (!PyArg_ParseTuple(args, "Os", &obj, &dn)) return NULL; 743 | adclient *ad = convert_ad(obj); 744 | try { 745 | ad->DeleteDN(dn); 746 | } 747 | catch(ADSearchException& ex) { 748 | error_num = ex.code; 749 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 750 | return NULL; 751 | } 752 | catch(ADOperationalException& ex) { 753 | error_num = ex.code; 754 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 755 | return NULL; 756 | } 757 | Py_INCREF(Py_None); 758 | return Py_None; 759 | } 760 | 761 | static PyObject *wrapper_CreateOU_adclient(PyObject *self, PyObject *args) { 762 | PyObject *obj; 763 | char *ou; 764 | if (!PyArg_ParseTuple(args, "Os", &obj, &ou)) return NULL; 765 | adclient *ad = convert_ad(obj); 766 | try { 767 | ad->CreateOU(ou); 768 | } 769 | catch(ADSearchException& ex) { 770 | error_num = ex.code; 771 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 772 | return NULL; 773 | } 774 | catch(ADOperationalException& ex) { 775 | error_num = ex.code; 776 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 777 | return NULL; 778 | } 779 | Py_INCREF(Py_None); 780 | return Py_None; 781 | } 782 | 783 | static PyObject *wrapper_EnableUser_adclient(PyObject *self, PyObject *args) { 784 | PyObject *obj; 785 | char *user; 786 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 787 | adclient *ad = convert_ad(obj); 788 | try { 789 | ad->EnableUser(user); 790 | } 791 | catch(ADSearchException& ex) { 792 | error_num = ex.code; 793 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 794 | return NULL; 795 | } 796 | catch(ADOperationalException& ex) { 797 | error_num = ex.code; 798 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 799 | return NULL; 800 | } 801 | Py_INCREF(Py_None); 802 | return Py_None; 803 | } 804 | 805 | static PyObject *wrapper_DisableUser_adclient(PyObject *self, PyObject *args) { 806 | PyObject *obj; 807 | char *user; 808 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 809 | adclient *ad = convert_ad(obj); 810 | try { 811 | ad->DisableUser(user); 812 | } 813 | catch(ADSearchException& ex) { 814 | error_num = ex.code; 815 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 816 | return NULL; 817 | } 818 | catch(ADOperationalException& ex) { 819 | error_num = ex.code; 820 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 821 | return NULL; 822 | } 823 | Py_INCREF(Py_None); 824 | return Py_None; 825 | } 826 | 827 | static PyObject *wrapper_setUserDescription_adclient(PyObject *self, PyObject *args) { 828 | PyObject *obj; 829 | char *dn, *descr; 830 | if (!PyArg_ParseTuple(args, "Oss", &obj, &dn, &descr)) return NULL; 831 | adclient *ad = convert_ad(obj); 832 | try { 833 | ad->setUserDescription(dn, descr); 834 | } 835 | catch(ADSearchException& ex) { 836 | error_num = ex.code; 837 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 838 | return NULL; 839 | } 840 | catch(ADOperationalException& ex) { 841 | error_num = ex.code; 842 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 843 | return NULL; 844 | } 845 | Py_INCREF(Py_None); 846 | return Py_None; 847 | } 848 | 849 | static PyObject *wrapper_changeUserPassword_adclient(PyObject *self, PyObject *args) { 850 | PyObject *obj; 851 | char *user, *old_password, *new_password; 852 | if (!PyArg_ParseTuple(args, "Osss", &obj, &user, &old_password, &new_password)) return NULL; 853 | adclient *ad = convert_ad(obj); 854 | try { 855 | ad->changeUserPassword(user, old_password, new_password); 856 | } 857 | catch(ADSearchException& ex) { 858 | error_num = ex.code; 859 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 860 | return NULL; 861 | } 862 | catch(ADOperationalException& ex) { 863 | error_num = ex.code; 864 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 865 | return NULL; 866 | } 867 | Py_INCREF(Py_None); 868 | return Py_None; 869 | } 870 | 871 | static PyObject *wrapper_setUserPassword_adclient(PyObject *self, PyObject *args) { 872 | PyObject *obj; 873 | char *user, *password; 874 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &password)) return NULL; 875 | adclient *ad = convert_ad(obj); 876 | try { 877 | ad->setUserPassword(user, password); 878 | } 879 | catch(ADSearchException& ex) { 880 | error_num = ex.code; 881 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 882 | return NULL; 883 | } 884 | catch(ADOperationalException& ex) { 885 | error_num = ex.code; 886 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 887 | return NULL; 888 | } 889 | Py_INCREF(Py_None); 890 | return Py_None; 891 | } 892 | 893 | static PyObject *wrapper_checkUserPassword_adclient(PyObject *self, PyObject *args) { 894 | PyObject *obj; 895 | char *user, *password; 896 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &password)) return NULL; 897 | adclient *ad = convert_ad(obj); 898 | try { 899 | return Py_BuildValue("N", PyBool_FromLong(ad->checkUserPassword(user, password))); 900 | } 901 | catch(ADSearchException& ex) { 902 | error_num = ex.code; 903 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 904 | return NULL; 905 | } 906 | } 907 | 908 | static PyObject *wrapper_setUserDialinAllowed_adclient(PyObject *self, PyObject *args) { 909 | PyObject *obj; 910 | char *user; 911 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 912 | adclient *ad = convert_ad(obj); 913 | try { 914 | ad->setUserDialinAllowed(user); 915 | } 916 | catch(ADSearchException& ex) { 917 | error_num = ex.code; 918 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 919 | return NULL; 920 | } 921 | catch(ADOperationalException& ex) { 922 | error_num = ex.code; 923 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 924 | return NULL; 925 | } 926 | Py_INCREF(Py_None); 927 | return Py_None; 928 | } 929 | 930 | static PyObject *wrapper_setUserDialinDisabled_adclient(PyObject *self, PyObject *args) { 931 | PyObject *obj; 932 | char *user; 933 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 934 | adclient *ad = convert_ad(obj); 935 | try { 936 | ad->setUserDialinDisabled(user); 937 | } 938 | catch(ADSearchException& ex) { 939 | error_num = ex.code; 940 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 941 | return NULL; 942 | } 943 | catch(ADOperationalException& ex) { 944 | error_num = ex.code; 945 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 946 | return NULL; 947 | } 948 | Py_INCREF(Py_None); 949 | return Py_None; 950 | } 951 | 952 | static PyObject *wrapper_setUserSN_adclient(PyObject *self, PyObject *args) { 953 | PyObject *obj; 954 | char *user, *sn; 955 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &sn)) return NULL; 956 | adclient *ad = convert_ad(obj); 957 | try { 958 | ad->setUserSN(user, sn); 959 | } 960 | catch(ADSearchException& ex) { 961 | error_num = ex.code; 962 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 963 | return NULL; 964 | } 965 | catch(ADOperationalException& ex) { 966 | error_num = ex.code; 967 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 968 | return NULL; 969 | } 970 | Py_INCREF(Py_None); 971 | return Py_None; 972 | } 973 | 974 | static PyObject *wrapper_setUserInitials_adclient(PyObject *self, PyObject *args) { 975 | PyObject *obj; 976 | char *user, *initials; 977 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &initials)) return NULL; 978 | adclient *ad = convert_ad(obj); 979 | try { 980 | ad->setUserInitials(user, initials); 981 | } 982 | catch(ADSearchException& ex) { 983 | error_num = ex.code; 984 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 985 | return NULL; 986 | } 987 | catch(ADOperationalException& ex) { 988 | error_num = ex.code; 989 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 990 | return NULL; 991 | } 992 | Py_INCREF(Py_None); 993 | return Py_None; 994 | } 995 | 996 | static PyObject *wrapper_setUserGivenName_adclient(PyObject *self, PyObject *args) { 997 | PyObject *obj; 998 | char *user, *givenName; 999 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &givenName)) return NULL; 1000 | adclient *ad = convert_ad(obj); 1001 | try { 1002 | ad->setUserGivenName(user, givenName); 1003 | } 1004 | catch(ADSearchException& ex) { 1005 | error_num = ex.code; 1006 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1007 | return NULL; 1008 | } 1009 | catch(ADOperationalException& ex) { 1010 | error_num = ex.code; 1011 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1012 | return NULL; 1013 | } 1014 | Py_INCREF(Py_None); 1015 | return Py_None; 1016 | } 1017 | 1018 | static PyObject *wrapper_setUserDisplayName_adclient(PyObject *self, PyObject *args) { 1019 | PyObject *obj; 1020 | char *user, *displayName; 1021 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &displayName)) return NULL; 1022 | adclient *ad = convert_ad(obj); 1023 | try { 1024 | ad->setUserDisplayName(user, displayName); 1025 | } 1026 | catch(ADSearchException& ex) { 1027 | error_num = ex.code; 1028 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1029 | return NULL; 1030 | } 1031 | catch(ADOperationalException& ex) { 1032 | error_num = ex.code; 1033 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1034 | return NULL; 1035 | } 1036 | Py_INCREF(Py_None); 1037 | return Py_None; 1038 | } 1039 | 1040 | static PyObject *wrapper_setUserRoomNumber_adclient(PyObject *self, PyObject *args) { 1041 | PyObject *obj; 1042 | char *user, *roomNum; 1043 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &roomNum)) return NULL; 1044 | adclient *ad = convert_ad(obj); 1045 | try { 1046 | ad->setUserRoomNumber(user, roomNum); 1047 | } 1048 | catch(ADSearchException& ex) { 1049 | error_num = ex.code; 1050 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1051 | return NULL; 1052 | } 1053 | catch(ADOperationalException& ex) { 1054 | error_num = ex.code; 1055 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1056 | return NULL; 1057 | } 1058 | Py_INCREF(Py_None); 1059 | return Py_None; 1060 | } 1061 | 1062 | static PyObject *wrapper_setUserAddress_adclient(PyObject *self, PyObject *args) { 1063 | PyObject *obj; 1064 | char *user, *streetAddress; 1065 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &streetAddress)) return NULL; 1066 | adclient *ad = convert_ad(obj); 1067 | try { 1068 | ad->setUserAddress(user, streetAddress); 1069 | } 1070 | catch(ADSearchException& ex) { 1071 | error_num = ex.code; 1072 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1073 | return NULL; 1074 | } 1075 | catch(ADOperationalException& ex) { 1076 | error_num = ex.code; 1077 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1078 | return NULL; 1079 | } 1080 | Py_INCREF(Py_None); 1081 | return Py_None; 1082 | } 1083 | 1084 | static PyObject *wrapper_setUserInfo_adclient(PyObject *self, PyObject *args) { 1085 | PyObject *obj; 1086 | char *user, *info; 1087 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &info)) return NULL; 1088 | adclient *ad = convert_ad(obj); 1089 | try { 1090 | ad->setUserInfo(user, info); 1091 | } 1092 | catch(ADSearchException& ex) { 1093 | error_num = ex.code; 1094 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1095 | return NULL; 1096 | } 1097 | catch(ADOperationalException& ex) { 1098 | error_num = ex.code; 1099 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1100 | return NULL; 1101 | } 1102 | Py_INCREF(Py_None); 1103 | return Py_None; 1104 | } 1105 | 1106 | static PyObject *wrapper_setUserTitle_adclient(PyObject *self, PyObject *args) { 1107 | PyObject *obj; 1108 | char *user, *title; 1109 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &title)) return NULL; 1110 | adclient *ad = convert_ad(obj); 1111 | try { 1112 | ad->setUserTitle(user, title); 1113 | } 1114 | catch(ADSearchException& ex) { 1115 | error_num = ex.code; 1116 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1117 | return NULL; 1118 | } 1119 | catch(ADOperationalException& ex) { 1120 | error_num = ex.code; 1121 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1122 | return NULL; 1123 | } 1124 | Py_INCREF(Py_None); 1125 | return Py_None; 1126 | } 1127 | 1128 | static PyObject *wrapper_setUserDepartment_adclient(PyObject *self, PyObject *args) { 1129 | PyObject *obj; 1130 | char *user, *department; 1131 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &department)) return NULL; 1132 | adclient *ad = convert_ad(obj); 1133 | try { 1134 | ad->setUserDepartment(user, department); 1135 | } 1136 | catch(ADSearchException& ex) { 1137 | error_num = ex.code; 1138 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1139 | return NULL; 1140 | } 1141 | catch(ADOperationalException& ex) { 1142 | error_num = ex.code; 1143 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1144 | return NULL; 1145 | } 1146 | Py_INCREF(Py_None); 1147 | return Py_None; 1148 | } 1149 | 1150 | static PyObject *wrapper_setUserCompany_adclient(PyObject *self, PyObject *args) { 1151 | PyObject *obj; 1152 | char *user, *company; 1153 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &company)) return NULL; 1154 | adclient *ad = convert_ad(obj); 1155 | try { 1156 | ad->setUserCompany(user, company); 1157 | } 1158 | catch(ADSearchException& ex) { 1159 | error_num = ex.code; 1160 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1161 | return NULL; 1162 | } 1163 | catch(ADOperationalException& ex) { 1164 | error_num = ex.code; 1165 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1166 | return NULL; 1167 | } 1168 | Py_INCREF(Py_None); 1169 | return Py_None; 1170 | } 1171 | 1172 | static PyObject *wrapper_setUserPhone_adclient(PyObject *self, PyObject *args) { 1173 | PyObject *obj; 1174 | char *user, *phone; 1175 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &phone)) return NULL; 1176 | adclient *ad = convert_ad(obj); 1177 | try { 1178 | ad->setUserPhone(user, phone); 1179 | } 1180 | catch(ADSearchException& ex) { 1181 | error_num = ex.code; 1182 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1183 | return NULL; 1184 | } 1185 | catch(ADOperationalException& ex) { 1186 | error_num = ex.code; 1187 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1188 | return NULL; 1189 | } 1190 | Py_INCREF(Py_None); 1191 | return Py_None; 1192 | } 1193 | 1194 | static PyObject *wrapper_setUserIpAddress_adclient(PyObject *self, PyObject *args) { 1195 | PyObject *obj; 1196 | char *user, *ip; 1197 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &ip)) return NULL; 1198 | adclient *ad = convert_ad(obj); 1199 | try { 1200 | ad->setUserIpAddress(user, ip); 1201 | } 1202 | catch(ADSearchException& ex) { 1203 | error_num = ex.code; 1204 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1205 | return NULL; 1206 | } 1207 | catch(ADOperationalException& ex) { 1208 | error_num = ex.code; 1209 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1210 | return NULL; 1211 | } 1212 | Py_INCREF(Py_None); 1213 | return Py_None; 1214 | } 1215 | 1216 | static PyObject *wrapper_setObjectAttribute_adclient(PyObject *self, PyObject *args) { 1217 | PyObject *obj; 1218 | char *object, *attr; 1219 | PyObject *listObj; 1220 | 1221 | if (!PyArg_ParseTuple(args, "OssO!", &obj, &object, &attr, &PyList_Type, &listObj)) return NULL; 1222 | 1223 | vector values; 1224 | for (unsigned int i = 0; i < PyList_Size(listObj); ++i) { 1225 | PyObject *strObj = PyList_GetItem(listObj, i); 1226 | string item = PyString_AsString(strObj); 1227 | values.push_back(item); 1228 | } 1229 | 1230 | adclient *ad = convert_ad(obj); 1231 | try { 1232 | ad->setObjectAttribute(object, attr, values); 1233 | } 1234 | catch(ADSearchException& ex) { 1235 | error_num = ex.code; 1236 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1237 | return NULL; 1238 | } 1239 | catch(ADOperationalException& ex) { 1240 | error_num = ex.code; 1241 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1242 | return NULL; 1243 | } 1244 | Py_INCREF(Py_None); 1245 | return Py_None; 1246 | } 1247 | 1248 | static PyObject *wrapper_clearObjectAttribute_adclient(PyObject *self, PyObject *args) { 1249 | PyObject *obj; 1250 | char *object, *attr; 1251 | if (!PyArg_ParseTuple(args, "Oss", &obj, &object, &attr)) return NULL; 1252 | adclient *ad = convert_ad(obj); 1253 | try { 1254 | ad->clearObjectAttribute(object, attr); 1255 | } 1256 | catch(ADSearchException& ex) { 1257 | error_num = ex.code; 1258 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1259 | return NULL; 1260 | } 1261 | catch(ADOperationalException& ex) { 1262 | error_num = ex.code; 1263 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1264 | return NULL; 1265 | } 1266 | Py_INCREF(Py_None); 1267 | return Py_None; 1268 | } 1269 | 1270 | static PyObject * wrapper_UnLockUser_adclient(PyObject *self, PyObject *args) { 1271 | PyObject *obj; 1272 | char *user; 1273 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 1274 | adclient *ad = convert_ad(obj); 1275 | try { 1276 | ad->UnLockUser(user); 1277 | } 1278 | catch(ADSearchException& ex) { 1279 | error_num = ex.code; 1280 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1281 | return NULL; 1282 | } 1283 | catch(ADOperationalException& ex) { 1284 | error_num = ex.code; 1285 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1286 | return NULL; 1287 | } 1288 | Py_INCREF(Py_None); 1289 | return Py_None; 1290 | } 1291 | 1292 | static PyObject * wrapper_MoveUser_adclient(PyObject *self, PyObject *args) { 1293 | PyObject *obj; 1294 | char *user; 1295 | char *new_container; 1296 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &new_container)) return NULL; 1297 | adclient *ad = convert_ad(obj); 1298 | try { 1299 | ad->MoveUser(user, new_container); 1300 | } 1301 | catch(ADSearchException& ex) { 1302 | error_num = ex.code; 1303 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1304 | return NULL; 1305 | } 1306 | catch(ADOperationalException& ex) { 1307 | error_num = ex.code; 1308 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1309 | return NULL; 1310 | } 1311 | Py_INCREF(Py_None); 1312 | return Py_None; 1313 | } 1314 | 1315 | static PyObject * wrapper_MoveObject_adclient(PyObject *self, PyObject *args) { 1316 | PyObject *obj; 1317 | char *object; 1318 | char *new_container; 1319 | if (!PyArg_ParseTuple(args, "Oss", &obj, &object, &new_container)) return NULL; 1320 | adclient *ad = convert_ad(obj); 1321 | try { 1322 | ad->MoveObject(object, new_container); 1323 | } 1324 | catch(ADSearchException& ex) { 1325 | error_num = ex.code; 1326 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1327 | return NULL; 1328 | } 1329 | catch(ADOperationalException& ex) { 1330 | error_num = ex.code; 1331 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1332 | return NULL; 1333 | } 1334 | Py_INCREF(Py_None); 1335 | return Py_None; 1336 | } 1337 | 1338 | static PyObject * wrapper_RenameUser_adclient(PyObject *self, PyObject *args) { 1339 | PyObject *obj; 1340 | char *user; 1341 | char *shortname; 1342 | char *cn; 1343 | if (!PyArg_ParseTuple(args, "Osss", &obj, &user, &shortname, &cn)) return NULL; 1344 | adclient *ad = convert_ad(obj); 1345 | try { 1346 | ad->RenameUser(user, shortname, cn); 1347 | } 1348 | catch(ADSearchException& ex) { 1349 | error_num = ex.code; 1350 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1351 | return NULL; 1352 | } 1353 | catch(ADOperationalException& ex) { 1354 | error_num = ex.code; 1355 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1356 | return NULL; 1357 | } 1358 | Py_INCREF(Py_None); 1359 | return Py_None; 1360 | } 1361 | 1362 | static PyMethodDef adclient_methods[] = { 1363 | { "new_adclient", wrapper_new_adclient, 1 }, 1364 | { "login_adclient", wrapper_login_adclient, 1 }, 1365 | { "searchDN_adclient", wrapper_searchDN_adclient, 1}, 1366 | { "search_adclient", wrapper_search_adclient, 1}, 1367 | { "getUserGroups_adclient", wrapper_getUserGroups_adclient, 1 }, 1368 | { "getUsersInGroup_adclient", wrapper_getUsersInGroup_adclient, 1}, 1369 | { "getUserControls_adclient", wrapper_getUserControls_adclient, 1 }, 1370 | { "groupAddUser_adclient", wrapper_groupAddUser_adclient, 1 }, 1371 | { "groupRemoveUser_adclient", wrapper_groupRemoveUser_adclient, 1 }, 1372 | { "ifDialinUser_adclient", wrapper_ifDialinUser_adclient, 1 }, 1373 | { "getDialinUsers_adclient", wrapper_getDialinUsers_adclient, 1 }, 1374 | { "getDisabledUsers_adclient", wrapper_getDisabledUsers_adclient, 1 }, 1375 | { "getObjectDN_adclient", wrapper_getObjectDN_adclient, 1 }, 1376 | { "ifUserDisabled_adclient", wrapper_ifUserDisabled_adclient, 1 }, 1377 | { "getOUs_adclient", wrapper_getOUs_adclient, 1 }, 1378 | { "getGroupsInOU_adclient", wrapper_getGroupsInOU_adclient, 1}, 1379 | { "getComputersInOU_adclient", wrapper_getComputersInOU_adclient, 1}, 1380 | { "getOUsInOU_adclient", wrapper_getOUsInOU_adclient, 1}, 1381 | { "getUsersInOU_adclient", wrapper_getUsersInOU_adclient, 1 }, 1382 | { "getGroups_adclient", wrapper_getGroups_adclient, 1 }, 1383 | { "getUsers_adclient", wrapper_getUsers_adclient, 1 }, 1384 | { "getUserDisplayName_adclient", wrapper_getUserDisplayName_adclient, 1 }, 1385 | { "getUserIpAddress_adclient", wrapper_getUserIpAddress_adclient, 1 }, 1386 | { "getObjectAttribute_adclient", wrapper_getObjectAttribute_adclient, 1 }, 1387 | { "getObjectAttributes_adclient", wrapper_getObjectAttributes_adclient, 1 }, 1388 | { "CreateUser_adclient", wrapper_CreateUser_adclient, 1 }, 1389 | { "CreateComputer_adclient", wrapper_CreateComputer_adclient, 1 }, 1390 | { "CreateGroup_adclient", wrapper_CreateGroup_adclient, 1 }, 1391 | { "DeleteDN_adclient", wrapper_DeleteDN_adclient, 1 }, 1392 | { "CreateOU_adclient", wrapper_CreateOU_adclient, 1 }, 1393 | { "EnableUser_adclient", wrapper_EnableUser_adclient, 1 }, 1394 | { "DisableUser_adclient", wrapper_DisableUser_adclient, 1 }, 1395 | { "setUserDescription_adclient", wrapper_setUserDescription_adclient, 1 }, 1396 | { "changeUserPassword_adclient", wrapper_changeUserPassword_adclient, 1 }, 1397 | { "setUserPassword_adclient", wrapper_setUserPassword_adclient, 1 }, 1398 | { "checkUserPassword_adclient", wrapper_checkUserPassword_adclient, 1 }, 1399 | { "setUserDialinAllowed_adclient", wrapper_setUserDialinAllowed_adclient, 1 }, 1400 | { "setUserDialinDisabled_adclient", wrapper_setUserDialinDisabled_adclient, 1 }, 1401 | { "setUserSN_adclient", wrapper_setUserSN_adclient, 1 }, 1402 | { "setUserInitials_adclient", wrapper_setUserInitials_adclient, 1 }, 1403 | { "setUserGivenName_adclient", wrapper_setUserGivenName_adclient, 1 }, 1404 | { "setUserDisplayName_adclient", wrapper_setUserDisplayName_adclient, 1 }, 1405 | { "setUserRoomNumber_adclient", wrapper_setUserRoomNumber_adclient, 1 }, 1406 | { "setUserAddress_adclient", wrapper_setUserAddress_adclient, 1 }, 1407 | { "setUserInfo_adclient", wrapper_setUserInfo_adclient, 1 }, 1408 | { "setUserTitle_adclient", wrapper_setUserTitle_adclient, 1 }, 1409 | { "setUserDepartment_adclient", wrapper_setUserDepartment_adclient, 1 }, 1410 | { "setUserCompany_adclient", wrapper_setUserCompany_adclient, 1 }, 1411 | { "setUserPhone_adclient", wrapper_setUserPhone_adclient, 1 }, 1412 | { "setUserIpAddress_adclient", wrapper_setUserIpAddress_adclient, 1 }, 1413 | { "clearObjectAttribute_adclient", wrapper_clearObjectAttribute_adclient, 1 }, 1414 | { "setObjectAttribute_adclient", wrapper_setObjectAttribute_adclient, 1 }, 1415 | { "UnLockUser_adclient", wrapper_UnLockUser_adclient, 1 }, 1416 | { "MoveUser_adclient", wrapper_MoveUser_adclient, 1 }, 1417 | { "MoveObject_adclient", wrapper_MoveObject_adclient, 1 }, 1418 | { "RenameUser_adclient", wrapper_RenameUser_adclient, 1 }, 1419 | { "ifDNExists_adclient", wrapper_ifDNExists_adclient, 1 }, 1420 | { "binded_uri_adclient", wrapper_binded_uri_adclient, 1}, 1421 | { "search_base_adclient", wrapper_search_base_adclient, 1}, 1422 | { "login_method_adclient", wrapper_login_method_adclient, 1}, 1423 | { "bind_method_adclient", wrapper_bind_method_adclient, 1}, 1424 | { "get_error_num", wrapper_get_error_num, 1 }, 1425 | { "int2ip", wrapper_int2ip, 1 }, 1426 | { "domain2dn", wrapper_domain2dn, 1 }, 1427 | { "decodeSID", wrapper_decodeSID, 1 }, 1428 | { "FileTimeToPOSIX", wrapper_FileTimeToPOSIX, 1 }, 1429 | { "get_ldap_servers", wrapper_get_ldap_servers, 1 }, 1430 | { NULL, NULL } 1431 | }; 1432 | 1433 | PyMODINIT_FUNC 1434 | init_adclient(void) { 1435 | PyObject *m; 1436 | m = Py_InitModule("_adclient", adclient_methods); 1437 | #pragma GCC diagnostic push 1438 | #pragma GCC diagnostic ignored "-Wwrite-strings" 1439 | ADBindError = PyErr_NewException("ADBindError.error", NULL, NULL); 1440 | ADSearchError = PyErr_NewException("ADSearchError.error", NULL, NULL); 1441 | ADOperationalError = PyErr_NewException("ADOperationalError.error", NULL, NULL); 1442 | #pragma GCC diagnostic pop 1443 | Py_INCREF(ADBindError); 1444 | Py_INCREF(ADSearchError); 1445 | Py_INCREF(ADOperationalError); 1446 | PyModule_AddObject(m, "ADBindError", ADBindError); 1447 | PyModule_AddObject(m, "ADSearchError", ADSearchError); 1448 | PyModule_AddObject(m, "ADOperationalError", ADOperationalError); 1449 | 1450 | PyModule_AddIntMacro(m, AD_SUCCESS); 1451 | PyModule_AddIntMacro(m, AD_LDAP_CONNECTION_ERROR); 1452 | PyModule_AddIntMacro(m, AD_PARAMS_ERROR); 1453 | PyModule_AddIntMacro(m, AD_SERVER_CONNECT_FAILURE); 1454 | PyModule_AddIntMacro(m, AD_OBJECT_NOT_FOUND); 1455 | PyModule_AddIntMacro(m, AD_ATTRIBUTE_ENTRY_NOT_FOUND); 1456 | PyModule_AddIntMacro(m, AD_OU_SYNTAX_ERROR); 1457 | 1458 | PyModule_AddIntMacro(m, AD_SCOPE_BASE); 1459 | PyModule_AddIntMacro(m, AD_SCOPE_ONELEVEL); 1460 | PyModule_AddIntMacro(m, AD_SCOPE_SUBTREE); 1461 | } 1462 | -------------------------------------------------------------------------------- /adclient_wrapper_python3.cpp: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | /* 4 | Python wrapper around C++ class. 5 | */ 6 | #include 7 | #include "adclient.h" 8 | 9 | static PyObject *ADBindError; 10 | static PyObject *ADSearchError; 11 | static PyObject *ADOperationalError; 12 | static int error_num; 13 | 14 | string unicode2string(PyObject *pobj) { 15 | return PyBytes_AsString( PyUnicode_AsEncodedString(pobj, "utf-8", "Error ~") ); 16 | } 17 | 18 | PyObject *vector2list(vector vec) { 19 | PyObject *list = PyList_New(0); 20 | 21 | for (unsigned int j=0; j < vec.size(); j++) { 22 | PyObject *unicodeString = PyUnicode_FromStringAndSize(vec[j].c_str(), vec[j].size()); 23 | if (unicodeString != NULL) { 24 | PyList_Append(list, unicodeString); 25 | } else { 26 | // clear error from previous PyUnicode_FromStringAndSize call 27 | PyErr_Clear(); 28 | 29 | // TODO: 30 | // not sure that this will not lead to mixing str & bytes in the same list 31 | // but ATM I don't see other simple way to add support for binary values 32 | PyObject *bytes = PyBytes_FromStringAndSize(vec[j].c_str(), vec[j].size()); 33 | if (bytes != NULL) { 34 | PyList_Append(list, bytes); 35 | } else { 36 | // ignore unconvertable fields 37 | PyErr_Clear(); 38 | } 39 | } 40 | } 41 | return list; 42 | } 43 | 44 | adclient *convert_ad(PyObject *obj) { 45 | void * temp = PyCapsule_GetPointer(obj, "adclient"); 46 | return static_cast(temp); 47 | } 48 | 49 | static PyObject *wrapper_get_error_num(PyObject *self, PyObject *args) { 50 | return Py_BuildValue("i", error_num); 51 | } 52 | 53 | static PyObject *wrapper_domain2dn(PyObject *self, PyObject *args) { 54 | char *domain; 55 | if (!PyArg_ParseTuple(args, "s", &domain)) return NULL; 56 | string result = adclient::domain2dn(domain); 57 | return Py_BuildValue("s", result.c_str()); 58 | } 59 | 60 | static PyObject *wrapper_decodeSID(PyObject *self, PyObject *args) { 61 | char *sid; 62 | int len; 63 | if (!PyArg_ParseTuple(args, "s#", &sid, &len)) return NULL; 64 | string result = decodeSID(string(sid, len)); 65 | return Py_BuildValue("s", result.c_str()); 66 | } 67 | 68 | static PyObject *wrapper_FileTimeToPOSIX(PyObject *self, PyObject *args) { 69 | long long filetime; 70 | if (!PyArg_ParseTuple(args, "L", &filetime)) return NULL; 71 | time_t result = FileTimeToPOSIX(filetime); 72 | return Py_BuildValue("i", result); 73 | } 74 | 75 | static PyObject *wrapper_get_ldap_servers(PyObject *self, PyObject *args) { 76 | char *domain, *site; 77 | if (!PyArg_ParseTuple(args, "ss", &domain, &site)) return NULL; 78 | vector result = adclient::get_ldap_servers(domain, site); 79 | return vector2list(result); 80 | } 81 | 82 | static PyObject *wrapper_int2ip(PyObject *self, PyObject *args) { 83 | char *ipstr; 84 | if (!PyArg_ParseTuple(args, "s", &ipstr)) return NULL; 85 | string result = int2ip(ipstr); 86 | return Py_BuildValue("s", result.c_str()); 87 | } 88 | 89 | void delete_adclient(PyObject *capsule) { 90 | adclient *ad = convert_ad(capsule); 91 | delete ad; 92 | } 93 | 94 | static PyObject *wrapper_new_adclient(PyObject *self, PyObject *args) { 95 | error_num = 0; 96 | adclient *obj = new adclient(); 97 | return PyCapsule_New(obj, "adclient", delete_adclient); 98 | } 99 | 100 | string dict_get_string(PyObject *dict, string key_str) { 101 | string result; 102 | 103 | PyObject *key = PyUnicode_FromString(key_str.c_str()); 104 | if (PyDict_Contains(dict, key) == 1) { 105 | PyObject *val = PyDict_GetItem(dict, key); 106 | if (PyUnicode_Check(val)) { 107 | result = unicode2string(val); 108 | } 109 | } 110 | Py_DECREF(key); 111 | return result; 112 | } 113 | 114 | bool dict_get_bool(PyObject *dict, string key_str) { 115 | bool result = false; 116 | 117 | PyObject *key = PyUnicode_FromString(key_str.c_str()); 118 | if (PyDict_Contains(dict, key) == 1) { 119 | PyObject *val = PyDict_GetItem(dict, key); 120 | result = PyObject_IsTrue(val); 121 | } 122 | Py_DECREF(key); 123 | return result; 124 | } 125 | 126 | int dict_get_int(PyObject *dict, string key_str) { 127 | int result = -1; 128 | 129 | PyObject *key = PyUnicode_FromString(key_str.c_str()); 130 | if (PyDict_Contains(dict, key) == 1) { 131 | PyObject *val = PyDict_GetItem(dict, key); 132 | result = PyLong_AsLong(val); 133 | } 134 | Py_DECREF(key); 135 | return result; 136 | } 137 | 138 | static PyObject *wrapper_login_adclient(PyObject *self, PyObject *args) { 139 | PyObject *obj; 140 | PyObject *paramsObj; 141 | 142 | if (!PyArg_ParseTuple(args, "OO!", &obj, &PyDict_Type, ¶msObj)) return NULL; 143 | 144 | adConnParams params; 145 | 146 | params.domain = dict_get_string(paramsObj, "domain"); 147 | params.site = dict_get_string(paramsObj, "site"); 148 | params.binddn = dict_get_string(paramsObj, "binddn"); 149 | params.bindpw = dict_get_string(paramsObj, "bindpw"); 150 | params.search_base = dict_get_string(paramsObj, "search_base"); 151 | params.secured = dict_get_bool(paramsObj, "secured"); 152 | params.use_gssapi = dict_get_bool(paramsObj, "use_gssapi"); 153 | params.use_tls = dict_get_bool(paramsObj, "use_tls"); 154 | params.use_ldaps = dict_get_bool(paramsObj, "use_ldaps"); 155 | params.nettimeout = dict_get_int(paramsObj, "nettimeout"); 156 | params.timelimit = dict_get_int(paramsObj, "timelimit"); 157 | 158 | PyObject *key = PyUnicode_FromString("uries"); 159 | if (PyDict_Contains(paramsObj, key) == 1) { 160 | PyObject *val = PyDict_GetItem(paramsObj, key); 161 | if (PyList_Check(val)) { 162 | for (unsigned int i = 0; i < PyList_Size(val); i++) { 163 | PyObject *strObj = PyList_GetItem(val, i); 164 | if (PyUnicode_Check(strObj)) { 165 | string item = unicode2string(strObj); 166 | params.uries.push_back(item); 167 | } 168 | } 169 | } 170 | } 171 | Py_DECREF(key); 172 | 173 | adclient *ad = convert_ad(obj); 174 | try { 175 | ad->login(params); 176 | } 177 | catch (ADBindException& ex) { 178 | error_num = ex.code; 179 | PyErr_SetString(ADBindError, ex.msg.c_str()); 180 | return NULL; 181 | } 182 | Py_INCREF(Py_None); 183 | return Py_None; 184 | } 185 | 186 | static PyObject *wrapper_binded_uri_adclient(PyObject *self, PyObject *args) { 187 | PyObject *obj; 188 | 189 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 190 | 191 | adclient *ad = convert_ad(obj); 192 | return Py_BuildValue("s", ad->binded_uri().c_str()); 193 | } 194 | 195 | static PyObject *wrapper_search_base_adclient(PyObject *self, PyObject *args) { 196 | PyObject *obj; 197 | 198 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 199 | 200 | adclient *ad = convert_ad(obj); 201 | return Py_BuildValue("s", ad->search_base().c_str()); 202 | } 203 | 204 | static PyObject *wrapper_login_method_adclient(PyObject *self, PyObject *args) { 205 | PyObject *obj; 206 | 207 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 208 | 209 | adclient *ad = convert_ad(obj); 210 | return Py_BuildValue("s", ad->login_method().c_str()); 211 | } 212 | 213 | static PyObject *wrapper_bind_method_adclient(PyObject *self, PyObject *args) { 214 | PyObject *obj; 215 | 216 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 217 | 218 | adclient *ad = convert_ad(obj); 219 | return Py_BuildValue("s", ad->bind_method().c_str()); 220 | } 221 | 222 | static PyObject *wrapper_search_adclient(PyObject *self, PyObject *args) { 223 | PyObject *obj; 224 | char *ou, *filter; 225 | PyObject * listObj; 226 | int scope; 227 | 228 | map < string, map < string, vector > > res; 229 | 230 | if (!PyArg_ParseTuple(args, "OsisO!", &obj, &ou, &scope, &filter, &PyList_Type, &listObj)) return NULL; 231 | 232 | vector attrs; 233 | 234 | for (unsigned int i = 0; i < PyList_Size(listObj); ++i) { 235 | PyObject *strObj = PyList_GetItem(listObj, i); 236 | string item = unicode2string(strObj); 237 | attrs.push_back(item); 238 | } 239 | 240 | adclient *ad = convert_ad(obj); 241 | try { 242 | res = ad->search(ou, scope, filter, attrs); 243 | } 244 | catch(ADSearchException& ex) { 245 | error_num = ex.code; 246 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 247 | return NULL; 248 | } 249 | 250 | PyObject *res_dict = PyDict_New(); 251 | map < string, map < string, vector > >::iterator res_it; 252 | for ( res_it=res.begin() ; res_it != res.end(); ++res_it ) { 253 | PyObject *attrs_dict = PyDict_New(); 254 | string dn = (*res_it).first; 255 | map < string, vector > attrs = (*res_it).second; 256 | map < string, vector >::iterator attrs_it; 257 | for ( attrs_it=attrs.begin() ; attrs_it != attrs.end(); ++attrs_it ) { 258 | string attribute = (*attrs_it).first; 259 | vector values_v = (*attrs_it).second; 260 | PyObject *values_list = vector2list(values_v); 261 | if (PyDict_SetItemString(attrs_dict, attribute.c_str(), values_list) < 0) return NULL; 262 | } 263 | if (PyDict_SetItemString(res_dict, dn.c_str(), attrs_dict) < 0) return NULL; 264 | } 265 | return res_dict; 266 | } 267 | 268 | static PyObject *wrapper_searchDN_adclient(PyObject *self, PyObject *args) { 269 | PyObject *obj; 270 | char *search_base, *filter; 271 | int scope; 272 | 273 | vector result; 274 | if (!PyArg_ParseTuple(args, "Ossi", &obj, &search_base, &filter, &scope)) return NULL; 275 | adclient *ad = convert_ad(obj); 276 | try { 277 | result = ad->searchDN(search_base, filter, scope); 278 | } 279 | catch(ADSearchException& ex) { 280 | error_num = ex.code; 281 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 282 | return NULL; 283 | } 284 | return vector2list(result); 285 | } 286 | 287 | static PyObject *wrapper_getUserGroups_adclient(PyObject *self, PyObject *args) { 288 | PyObject *obj; 289 | char *user; 290 | int nested; 291 | vector result; 292 | if (!PyArg_ParseTuple(args, "Osi", &obj, &user, &nested)) return NULL; 293 | adclient *ad = convert_ad(obj); 294 | try { 295 | result = ad->getUserGroups(user, nested); 296 | } 297 | catch(ADSearchException& ex) { 298 | error_num = ex.code; 299 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 300 | return NULL; 301 | } 302 | return vector2list(result); 303 | } 304 | 305 | static PyObject *wrapper_getUsersInGroup_adclient(PyObject *self, PyObject *args) { 306 | PyObject *obj; 307 | char *group; 308 | int nested; 309 | vector result; 310 | if (!PyArg_ParseTuple(args, "Osi", &obj, &group, &nested)) return NULL; 311 | adclient *ad = convert_ad(obj); 312 | try { 313 | result = ad->getUsersInGroup(group, nested); 314 | } 315 | catch(ADSearchException& ex) { 316 | error_num = ex.code; 317 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 318 | return NULL; 319 | } 320 | return vector2list(result); 321 | } 322 | 323 | static PyObject *wrapper_getUserControls_adclient(PyObject *self, PyObject *args) { 324 | PyObject *obj; 325 | char *user; 326 | map result; 327 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 328 | adclient *ad = convert_ad(obj); 329 | try { 330 | result = ad->getUserControls(user); 331 | } 332 | catch(ADSearchException& ex) { 333 | error_num = ex.code; 334 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 335 | return NULL; 336 | } 337 | PyObject *res_dict = PyDict_New(); 338 | map ::iterator it; 339 | for (it = result.begin(); it != result.end(); ++it) { 340 | if (PyDict_SetItemString(res_dict, (*it).first.c_str(), PyBool_FromLong((*it).second)) < 0) 341 | return NULL; 342 | } 343 | 344 | return res_dict; 345 | } 346 | 347 | static PyObject *wrapper_groupAddUser_adclient(PyObject *self, PyObject *args) { 348 | PyObject *obj; 349 | char *group, *user; 350 | if (!PyArg_ParseTuple(args, "Oss", &obj, &group, &user)) return NULL; 351 | adclient *ad = convert_ad(obj); 352 | try { 353 | ad->groupAddUser(group, user); 354 | } 355 | catch(ADSearchException& ex) { 356 | error_num = ex.code; 357 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 358 | return NULL; 359 | } 360 | catch(ADOperationalException& ex) { 361 | error_num = ex.code; 362 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 363 | return NULL; 364 | } 365 | Py_INCREF(Py_None); 366 | return Py_None; 367 | } 368 | 369 | static PyObject *wrapper_groupRemoveUser_adclient(PyObject *self, PyObject *args) { 370 | PyObject *obj; 371 | char *group, *user; 372 | if (!PyArg_ParseTuple(args, "Oss", &obj, &group, &user)) return NULL; 373 | adclient *ad = convert_ad(obj); 374 | try { 375 | ad->groupRemoveUser(group, user); 376 | } 377 | catch(ADSearchException& ex) { 378 | error_num = ex.code; 379 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 380 | return NULL; 381 | } 382 | catch(ADOperationalException& ex) { 383 | error_num = ex.code; 384 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 385 | return NULL; 386 | } 387 | Py_INCREF(Py_None); 388 | return Py_None; 389 | } 390 | 391 | static PyObject *wrapper_ifDialinUser_adclient(PyObject *self, PyObject *args) { 392 | PyObject *obj; 393 | char *user; 394 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 395 | adclient *ad = convert_ad(obj); 396 | try { 397 | return Py_BuildValue("i", ad->ifDialinUser(user)); 398 | } 399 | catch(ADSearchException& ex) { 400 | error_num = ex.code; 401 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 402 | return NULL; 403 | } 404 | } 405 | 406 | static PyObject *wrapper_getDialinUsers_adclient(PyObject *self, PyObject *args) { 407 | PyObject *obj; 408 | vector result; 409 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 410 | adclient *ad = convert_ad(obj); 411 | try { 412 | result = ad->getDialinUsers(); 413 | } 414 | catch(ADSearchException& ex) { 415 | error_num = ex.code; 416 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 417 | return NULL; 418 | } 419 | return vector2list(result); 420 | } 421 | 422 | static PyObject *wrapper_getDisabledUsers_adclient(PyObject *self, PyObject *args) { 423 | PyObject *obj; 424 | vector result; 425 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 426 | adclient *ad = convert_ad(obj); 427 | try { 428 | result = ad->getDisabledUsers(); 429 | } 430 | catch(ADSearchException& ex) { 431 | error_num = ex.code; 432 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 433 | return NULL; 434 | } 435 | return vector2list(result); 436 | } 437 | 438 | static PyObject *wrapper_getObjectDN_adclient(PyObject *self, PyObject *args) { 439 | PyObject *obj; 440 | char *user; 441 | string result; 442 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 443 | adclient *ad = convert_ad(obj); 444 | try { 445 | result = ad->getObjectDN(user); 446 | } 447 | catch(ADSearchException& ex) { 448 | error_num = ex.code; 449 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 450 | return NULL; 451 | } 452 | return Py_BuildValue("s", result.c_str()); 453 | } 454 | 455 | static PyObject *wrapper_ifUserDisabled_adclient(PyObject *self, PyObject *args) { 456 | PyObject *obj; 457 | char *user; 458 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 459 | adclient *ad = convert_ad(obj); 460 | try { 461 | return Py_BuildValue("N", PyBool_FromLong(ad->ifUserDisabled(user))); 462 | } 463 | catch(ADSearchException& ex) { 464 | error_num = ex.code; 465 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 466 | return NULL; 467 | } 468 | } 469 | 470 | static PyObject *wrapper_ifDNExists_adclient(PyObject *self, PyObject *args) { 471 | PyObject *obj; 472 | char *dn; 473 | char *objectclass; 474 | if (!PyArg_ParseTuple(args, "Oss", &obj, &dn, &objectclass)) return NULL; 475 | adclient *ad = convert_ad(obj); 476 | try { 477 | return Py_BuildValue("N", PyBool_FromLong(ad->ifDNExists(dn, objectclass))); 478 | } 479 | catch(ADSearchException& ex) { 480 | error_num = ex.code; 481 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 482 | return NULL; 483 | } 484 | } 485 | 486 | static PyObject *wrapper_getOUs_adclient(PyObject *self, PyObject *args) { 487 | PyObject *obj; 488 | vector result; 489 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 490 | adclient *ad = convert_ad(obj); 491 | try { 492 | result = ad->getOUs(); 493 | } 494 | catch(ADSearchException& ex) { 495 | error_num = ex.code; 496 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 497 | return NULL; 498 | } 499 | return vector2list(result); 500 | } 501 | 502 | static PyObject *wrapper_getOUsInOU_adclient(PyObject *self, PyObject *args) { 503 | PyObject *obj; 504 | char *OU; 505 | int scope; 506 | 507 | vector result; 508 | 509 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 510 | adclient *ad = convert_ad(obj); 511 | try { 512 | result = ad->getOUsInOU(OU, scope); 513 | } 514 | catch(ADSearchException& ex) { 515 | error_num = ex.code; 516 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 517 | return NULL; 518 | } 519 | return vector2list(result); 520 | } 521 | 522 | static PyObject *wrapper_getUsersInOU_adclient(PyObject *self, PyObject *args) { 523 | PyObject *obj; 524 | char *OU; 525 | int scope; 526 | 527 | vector result; 528 | 529 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 530 | adclient *ad = convert_ad(obj); 531 | try { 532 | result = ad->getUsersInOU(OU, scope); 533 | } 534 | catch(ADSearchException& ex) { 535 | error_num = ex.code; 536 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 537 | return NULL; 538 | } 539 | return vector2list(result); 540 | } 541 | 542 | static PyObject *wrapper_getComputersInOU_adclient(PyObject *self, PyObject *args) { 543 | PyObject *obj; 544 | char *OU; 545 | int scope; 546 | 547 | vector result; 548 | 549 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 550 | adclient *ad = convert_ad(obj); 551 | try { 552 | result = ad->getComputersInOU(OU, scope); 553 | } 554 | catch(ADSearchException& ex) { 555 | error_num = ex.code; 556 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 557 | return NULL; 558 | } 559 | return vector2list(result); 560 | } 561 | 562 | static PyObject *wrapper_getGroupsInOU_adclient(PyObject *self, PyObject *args) { 563 | PyObject *obj; 564 | char *OU; 565 | int scope; 566 | 567 | vector result; 568 | 569 | if (!PyArg_ParseTuple(args, "Osi", &obj, &OU, &scope)) return NULL; 570 | adclient *ad = convert_ad(obj); 571 | try { 572 | result = ad->getGroupsInOU(OU, scope); 573 | } 574 | catch(ADSearchException& ex) { 575 | error_num = ex.code; 576 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 577 | return NULL; 578 | } 579 | return vector2list(result); 580 | } 581 | 582 | static PyObject *wrapper_getGroups_adclient(PyObject *self, PyObject *args) { 583 | PyObject *obj; 584 | vector result; 585 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 586 | adclient *ad = convert_ad(obj); 587 | try { 588 | result = ad->getGroups(); 589 | } 590 | catch(ADSearchException& ex) { 591 | error_num = ex.code; 592 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 593 | return NULL; 594 | } 595 | return vector2list(result); 596 | } 597 | 598 | static PyObject *wrapper_getUsers_adclient(PyObject *self, PyObject *args) { 599 | PyObject *obj; 600 | vector result; 601 | if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; 602 | adclient *ad = convert_ad(obj); 603 | try { 604 | result = ad->getUsers(); 605 | } 606 | catch(ADSearchException& ex) { 607 | error_num = ex.code; 608 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 609 | return NULL; 610 | } 611 | return vector2list(result); 612 | } 613 | 614 | static PyObject *wrapper_getUserDisplayName_adclient(PyObject *self, PyObject *args) { 615 | PyObject *obj; 616 | char *user_short; 617 | string result; 618 | if (!PyArg_ParseTuple(args, "Os", &obj, &user_short)) return NULL; 619 | adclient *ad = convert_ad(obj); 620 | try { 621 | result = ad->getUserDisplayName(user_short); 622 | } 623 | catch(ADSearchException& ex) { 624 | error_num = ex.code; 625 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 626 | return NULL; 627 | } 628 | return Py_BuildValue("s", result.c_str()); 629 | } 630 | 631 | static PyObject *wrapper_getUserIpAddress_adclient(PyObject *self, PyObject *args) { 632 | PyObject *obj; 633 | char *user_short; 634 | string result; 635 | if (!PyArg_ParseTuple(args, "Os", &obj, &user_short)) return NULL; 636 | adclient *ad = convert_ad(obj); 637 | try { 638 | result = ad->getUserIpAddress(user_short); 639 | } 640 | catch(ADSearchException& ex) { 641 | error_num = ex.code; 642 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 643 | return NULL; 644 | } 645 | return Py_BuildValue("s", result.c_str()); 646 | } 647 | 648 | static PyObject *wrapper_getObjectAttribute_adclient(PyObject *self, PyObject *args) { 649 | PyObject *obj; 650 | char *user_short, *attribute; 651 | vector result; 652 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user_short, &attribute)) return NULL; 653 | adclient *ad = convert_ad(obj); 654 | try { 655 | result = ad->getObjectAttribute(user_short, attribute); 656 | } 657 | catch(ADSearchException& ex) { 658 | error_num = ex.code; 659 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 660 | return NULL; 661 | } 662 | return vector2list(result); 663 | } 664 | 665 | static PyObject *wrapper_getObjectAttributes_adclient(PyObject *self, PyObject *args) { 666 | PyObject *obj; 667 | char *object_short; 668 | map > result; 669 | if (!PyArg_ParseTuple(args, "Os", &obj, &object_short)) return NULL; 670 | adclient *ad = convert_ad(obj); 671 | try { 672 | result = ad->getObjectAttributes(object_short); 673 | } 674 | catch(ADSearchException& ex) { 675 | error_num = ex.code; 676 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 677 | return NULL; 678 | } 679 | 680 | string attr; 681 | vector values; 682 | 683 | PyObject *res_dict = PyDict_New(); 684 | 685 | map >::iterator it; 686 | for (it = result.begin(); it != result.end(); ++it) { 687 | attr = it->first; 688 | values = it->second; 689 | PyDict_SetItem(res_dict, PyUnicode_FromString(attr.c_str()), vector2list(values)); 690 | } 691 | return res_dict; 692 | } 693 | 694 | static PyObject *wrapper_CreateComputer_adclient(PyObject *self, PyObject *args) { 695 | PyObject *obj; 696 | char *name, *container; 697 | if (!PyArg_ParseTuple(args, "Oss", &obj, &name, &container)) return NULL; 698 | adclient *ad = convert_ad(obj); 699 | try { 700 | ad->CreateComputer(name, container); 701 | } 702 | catch(ADSearchException& ex) { 703 | error_num = ex.code; 704 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 705 | return NULL; 706 | } 707 | catch(ADOperationalException& ex) { 708 | error_num = ex.code; 709 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 710 | return NULL; 711 | } 712 | Py_INCREF(Py_None); 713 | return Py_None; 714 | } 715 | 716 | static PyObject *wrapper_CreateUser_adclient(PyObject *self, PyObject *args) { 717 | PyObject *obj; 718 | char *cn, *short_name, *container; 719 | if (!PyArg_ParseTuple(args, "Osss", &obj, &cn, &container, &short_name)) return NULL; 720 | adclient *ad = convert_ad(obj); 721 | try { 722 | ad->CreateUser(cn, container, short_name); 723 | } 724 | catch(ADSearchException& ex) { 725 | error_num = ex.code; 726 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 727 | return NULL; 728 | } 729 | catch(ADOperationalException& ex) { 730 | error_num = ex.code; 731 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 732 | return NULL; 733 | } 734 | Py_INCREF(Py_None); 735 | return Py_None; 736 | } 737 | 738 | static PyObject *wrapper_CreateGroup_adclient(PyObject *self, PyObject *args) { 739 | PyObject *obj; 740 | char *cn, *short_name, *container; 741 | if (!PyArg_ParseTuple(args, "Osss", &obj, &cn, &container, &short_name)) return NULL; 742 | adclient *ad = convert_ad(obj); 743 | try { 744 | ad->CreateGroup(cn, container, short_name); 745 | } 746 | catch(ADSearchException& ex) { 747 | error_num = ex.code; 748 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 749 | return NULL; 750 | } 751 | catch(ADOperationalException& ex) { 752 | error_num = ex.code; 753 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 754 | return NULL; 755 | } 756 | Py_INCREF(Py_None); 757 | return Py_None; 758 | } 759 | 760 | static PyObject *wrapper_DeleteDN_adclient(PyObject *self, PyObject *args) { 761 | PyObject *obj; 762 | char *dn; 763 | if (!PyArg_ParseTuple(args, "Os", &obj, &dn)) return NULL; 764 | adclient *ad = convert_ad(obj); 765 | try { 766 | ad->DeleteDN(dn); 767 | } 768 | catch(ADSearchException& ex) { 769 | error_num = ex.code; 770 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 771 | return NULL; 772 | } 773 | catch(ADOperationalException& ex) { 774 | error_num = ex.code; 775 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 776 | return NULL; 777 | } 778 | Py_INCREF(Py_None); 779 | return Py_None; 780 | } 781 | 782 | static PyObject *wrapper_CreateOU_adclient(PyObject *self, PyObject *args) { 783 | PyObject *obj; 784 | char *ou; 785 | if (!PyArg_ParseTuple(args, "Os", &obj, &ou)) return NULL; 786 | adclient *ad = convert_ad(obj); 787 | try { 788 | ad->CreateOU(ou); 789 | } 790 | catch(ADSearchException& ex) { 791 | error_num = ex.code; 792 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 793 | return NULL; 794 | } 795 | catch(ADOperationalException& ex) { 796 | error_num = ex.code; 797 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 798 | return NULL; 799 | } 800 | Py_INCREF(Py_None); 801 | return Py_None; 802 | } 803 | 804 | static PyObject *wrapper_EnableUser_adclient(PyObject *self, PyObject *args) { 805 | PyObject *obj; 806 | char *user; 807 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 808 | adclient *ad = convert_ad(obj); 809 | try { 810 | ad->EnableUser(user); 811 | } 812 | catch(ADSearchException& ex) { 813 | error_num = ex.code; 814 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 815 | return NULL; 816 | } 817 | catch(ADOperationalException& ex) { 818 | error_num = ex.code; 819 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 820 | return NULL; 821 | } 822 | Py_INCREF(Py_None); 823 | return Py_None; 824 | } 825 | 826 | static PyObject *wrapper_DisableUser_adclient(PyObject *self, PyObject *args) { 827 | PyObject *obj; 828 | char *user; 829 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 830 | adclient *ad = convert_ad(obj); 831 | try { 832 | ad->DisableUser(user); 833 | } 834 | catch(ADSearchException& ex) { 835 | error_num = ex.code; 836 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 837 | return NULL; 838 | } 839 | catch(ADOperationalException& ex) { 840 | error_num = ex.code; 841 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 842 | return NULL; 843 | } 844 | Py_INCREF(Py_None); 845 | return Py_None; 846 | } 847 | 848 | static PyObject *wrapper_setUserDescription_adclient(PyObject *self, PyObject *args) { 849 | PyObject *obj; 850 | char *dn, *descr; 851 | if (!PyArg_ParseTuple(args, "Oss", &obj, &dn, &descr)) return NULL; 852 | adclient *ad = convert_ad(obj); 853 | try { 854 | ad->setUserDescription(dn, descr); 855 | } 856 | catch(ADSearchException& ex) { 857 | error_num = ex.code; 858 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 859 | return NULL; 860 | } 861 | catch(ADOperationalException& ex) { 862 | error_num = ex.code; 863 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 864 | return NULL; 865 | } 866 | Py_INCREF(Py_None); 867 | return Py_None; 868 | } 869 | 870 | static PyObject *wrapper_setUserPassword_adclient(PyObject *self, PyObject *args) { 871 | PyObject *obj; 872 | char *user, *password; 873 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &password)) return NULL; 874 | adclient *ad = convert_ad(obj); 875 | try { 876 | ad->setUserPassword(user, password); 877 | } 878 | catch(ADSearchException& ex) { 879 | error_num = ex.code; 880 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 881 | return NULL; 882 | } 883 | catch(ADOperationalException& ex) { 884 | error_num = ex.code; 885 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 886 | return NULL; 887 | } 888 | Py_INCREF(Py_None); 889 | return Py_None; 890 | } 891 | 892 | static PyObject *wrapper_changeUserPassword_adclient(PyObject *self, PyObject *args) { 893 | PyObject *obj; 894 | char *user, *old_password, *new_password; 895 | if (!PyArg_ParseTuple(args, "Osss", &obj, &user, &old_password, &new_password)) return NULL; 896 | adclient *ad = convert_ad(obj); 897 | try { 898 | ad->changeUserPassword(user, old_password, new_password); 899 | } 900 | catch(ADSearchException& ex) { 901 | error_num = ex.code; 902 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 903 | return NULL; 904 | } 905 | catch(ADOperationalException& ex) { 906 | error_num = ex.code; 907 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 908 | return NULL; 909 | } 910 | Py_INCREF(Py_None); 911 | return Py_None; 912 | } 913 | 914 | static PyObject *wrapper_checkUserPassword_adclient(PyObject *self, PyObject *args) { 915 | PyObject *obj; 916 | char *user, *password; 917 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &password)) return NULL; 918 | adclient *ad = convert_ad(obj); 919 | try { 920 | return Py_BuildValue("N", PyBool_FromLong(ad->checkUserPassword(user, password))); 921 | } 922 | catch(ADSearchException& ex) { 923 | error_num = ex.code; 924 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 925 | return NULL; 926 | } 927 | } 928 | 929 | static PyObject *wrapper_setUserDialinAllowed_adclient(PyObject *self, PyObject *args) { 930 | PyObject *obj; 931 | char *user; 932 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 933 | adclient *ad = convert_ad(obj); 934 | try { 935 | ad->setUserDialinAllowed(user); 936 | } 937 | catch(ADSearchException& ex) { 938 | error_num = ex.code; 939 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 940 | return NULL; 941 | } 942 | catch(ADOperationalException& ex) { 943 | error_num = ex.code; 944 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 945 | return NULL; 946 | } 947 | Py_INCREF(Py_None); 948 | return Py_None; 949 | } 950 | 951 | static PyObject *wrapper_setUserDialinDisabled_adclient(PyObject *self, PyObject *args) { 952 | PyObject *obj; 953 | char *user; 954 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 955 | adclient *ad = convert_ad(obj); 956 | try { 957 | ad->setUserDialinDisabled(user); 958 | } 959 | catch(ADSearchException& ex) { 960 | error_num = ex.code; 961 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 962 | return NULL; 963 | } 964 | catch(ADOperationalException& ex) { 965 | error_num = ex.code; 966 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 967 | return NULL; 968 | } 969 | Py_INCREF(Py_None); 970 | return Py_None; 971 | } 972 | 973 | static PyObject *wrapper_setUserSN_adclient(PyObject *self, PyObject *args) { 974 | PyObject *obj; 975 | char *user, *sn; 976 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &sn)) return NULL; 977 | adclient *ad = convert_ad(obj); 978 | try { 979 | ad->setUserSN(user, sn); 980 | } 981 | catch(ADSearchException& ex) { 982 | error_num = ex.code; 983 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 984 | return NULL; 985 | } 986 | catch(ADOperationalException& ex) { 987 | error_num = ex.code; 988 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 989 | return NULL; 990 | } 991 | Py_INCREF(Py_None); 992 | return Py_None; 993 | } 994 | 995 | static PyObject *wrapper_setUserInitials_adclient(PyObject *self, PyObject *args) { 996 | PyObject *obj; 997 | char *user, *initials; 998 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &initials)) return NULL; 999 | adclient *ad = convert_ad(obj); 1000 | try { 1001 | ad->setUserInitials(user, initials); 1002 | } 1003 | catch(ADSearchException& ex) { 1004 | error_num = ex.code; 1005 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1006 | return NULL; 1007 | } 1008 | catch(ADOperationalException& ex) { 1009 | error_num = ex.code; 1010 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1011 | return NULL; 1012 | } 1013 | Py_INCREF(Py_None); 1014 | return Py_None; 1015 | } 1016 | 1017 | static PyObject *wrapper_setUserGivenName_adclient(PyObject *self, PyObject *args) { 1018 | PyObject *obj; 1019 | char *user, *givenName; 1020 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &givenName)) return NULL; 1021 | adclient *ad = convert_ad(obj); 1022 | try { 1023 | ad->setUserGivenName(user, givenName); 1024 | } 1025 | catch(ADSearchException& ex) { 1026 | error_num = ex.code; 1027 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1028 | return NULL; 1029 | } 1030 | catch(ADOperationalException& ex) { 1031 | error_num = ex.code; 1032 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1033 | return NULL; 1034 | } 1035 | Py_INCREF(Py_None); 1036 | return Py_None; 1037 | } 1038 | 1039 | static PyObject *wrapper_setUserDisplayName_adclient(PyObject *self, PyObject *args) { 1040 | PyObject *obj; 1041 | char *user, *displayName; 1042 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &displayName)) return NULL; 1043 | adclient *ad = convert_ad(obj); 1044 | try { 1045 | ad->setUserDisplayName(user, displayName); 1046 | } 1047 | catch(ADSearchException& ex) { 1048 | error_num = ex.code; 1049 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1050 | return NULL; 1051 | } 1052 | catch(ADOperationalException& ex) { 1053 | error_num = ex.code; 1054 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1055 | return NULL; 1056 | } 1057 | Py_INCREF(Py_None); 1058 | return Py_None; 1059 | } 1060 | 1061 | static PyObject *wrapper_setUserRoomNumber_adclient(PyObject *self, PyObject *args) { 1062 | PyObject *obj; 1063 | char *user, *roomNum; 1064 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &roomNum)) return NULL; 1065 | adclient *ad = convert_ad(obj); 1066 | try { 1067 | ad->setUserRoomNumber(user, roomNum); 1068 | } 1069 | catch(ADSearchException& ex) { 1070 | error_num = ex.code; 1071 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1072 | return NULL; 1073 | } 1074 | catch(ADOperationalException& ex) { 1075 | error_num = ex.code; 1076 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1077 | return NULL; 1078 | } 1079 | Py_INCREF(Py_None); 1080 | return Py_None; 1081 | } 1082 | 1083 | static PyObject *wrapper_setUserAddress_adclient(PyObject *self, PyObject *args) { 1084 | PyObject *obj; 1085 | char *user, *streetAddress; 1086 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &streetAddress)) return NULL; 1087 | adclient *ad = convert_ad(obj); 1088 | try { 1089 | ad->setUserAddress(user, streetAddress); 1090 | } 1091 | catch(ADSearchException& ex) { 1092 | error_num = ex.code; 1093 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1094 | return NULL; 1095 | } 1096 | catch(ADOperationalException& ex) { 1097 | error_num = ex.code; 1098 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1099 | return NULL; 1100 | } 1101 | Py_INCREF(Py_None); 1102 | return Py_None; 1103 | } 1104 | 1105 | static PyObject *wrapper_setUserInfo_adclient(PyObject *self, PyObject *args) { 1106 | PyObject *obj; 1107 | char *user, *info; 1108 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &info)) return NULL; 1109 | adclient *ad = convert_ad(obj); 1110 | try { 1111 | ad->setUserInfo(user, info); 1112 | } 1113 | catch(ADSearchException& ex) { 1114 | error_num = ex.code; 1115 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1116 | return NULL; 1117 | } 1118 | catch(ADOperationalException& ex) { 1119 | error_num = ex.code; 1120 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1121 | return NULL; 1122 | } 1123 | Py_INCREF(Py_None); 1124 | return Py_None; 1125 | } 1126 | 1127 | static PyObject *wrapper_setUserTitle_adclient(PyObject *self, PyObject *args) { 1128 | PyObject *obj; 1129 | char *user, *title; 1130 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &title)) return NULL; 1131 | adclient *ad = convert_ad(obj); 1132 | try { 1133 | ad->setUserTitle(user, title); 1134 | } 1135 | catch(ADSearchException& ex) { 1136 | error_num = ex.code; 1137 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1138 | return NULL; 1139 | } 1140 | catch(ADOperationalException& ex) { 1141 | error_num = ex.code; 1142 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1143 | return NULL; 1144 | } 1145 | Py_INCREF(Py_None); 1146 | return Py_None; 1147 | } 1148 | 1149 | static PyObject *wrapper_setUserDepartment_adclient(PyObject *self, PyObject *args) { 1150 | PyObject *obj; 1151 | char *user, *department; 1152 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &department)) return NULL; 1153 | adclient *ad = convert_ad(obj); 1154 | try { 1155 | ad->setUserDepartment(user, department); 1156 | } 1157 | catch(ADSearchException& ex) { 1158 | error_num = ex.code; 1159 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1160 | return NULL; 1161 | } 1162 | catch(ADOperationalException& ex) { 1163 | error_num = ex.code; 1164 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1165 | return NULL; 1166 | } 1167 | Py_INCREF(Py_None); 1168 | return Py_None; 1169 | } 1170 | 1171 | static PyObject *wrapper_setUserCompany_adclient(PyObject *self, PyObject *args) { 1172 | PyObject *obj; 1173 | char *user, *company; 1174 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &company)) return NULL; 1175 | adclient *ad = convert_ad(obj); 1176 | try { 1177 | ad->setUserCompany(user, company); 1178 | } 1179 | catch(ADSearchException& ex) { 1180 | error_num = ex.code; 1181 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1182 | return NULL; 1183 | } 1184 | catch(ADOperationalException& ex) { 1185 | error_num = ex.code; 1186 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1187 | return NULL; 1188 | } 1189 | Py_INCREF(Py_None); 1190 | return Py_None; 1191 | } 1192 | 1193 | static PyObject *wrapper_setUserPhone_adclient(PyObject *self, PyObject *args) { 1194 | PyObject *obj; 1195 | char *user, *phone; 1196 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &phone)) return NULL; 1197 | adclient *ad = convert_ad(obj); 1198 | try { 1199 | ad->setUserPhone(user, phone); 1200 | } 1201 | catch(ADSearchException& ex) { 1202 | error_num = ex.code; 1203 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1204 | return NULL; 1205 | } 1206 | catch(ADOperationalException& ex) { 1207 | error_num = ex.code; 1208 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1209 | return NULL; 1210 | } 1211 | Py_INCREF(Py_None); 1212 | return Py_None; 1213 | } 1214 | 1215 | static PyObject *wrapper_setUserIpAddress_adclient(PyObject *self, PyObject *args) { 1216 | PyObject *obj; 1217 | char *user, *ip; 1218 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &ip)) return NULL; 1219 | adclient *ad = convert_ad(obj); 1220 | try { 1221 | ad->setUserIpAddress(user, ip); 1222 | } 1223 | catch(ADSearchException& ex) { 1224 | error_num = ex.code; 1225 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1226 | return NULL; 1227 | } 1228 | catch(ADOperationalException& ex) { 1229 | error_num = ex.code; 1230 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1231 | return NULL; 1232 | } 1233 | Py_INCREF(Py_None); 1234 | return Py_None; 1235 | } 1236 | 1237 | static PyObject *wrapper_clearObjectAttribute_adclient(PyObject *self, PyObject *args) { 1238 | PyObject *obj; 1239 | char *object, *attr; 1240 | if (!PyArg_ParseTuple(args, "Oss", &obj, &object, &attr)) return NULL; 1241 | adclient *ad = convert_ad(obj); 1242 | try { 1243 | ad->clearObjectAttribute(object, attr); 1244 | } 1245 | catch(ADSearchException& ex) { 1246 | error_num = ex.code; 1247 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1248 | return NULL; 1249 | } 1250 | catch(ADOperationalException& ex) { 1251 | error_num = ex.code; 1252 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1253 | return NULL; 1254 | } 1255 | Py_INCREF(Py_None); 1256 | return Py_None; 1257 | } 1258 | 1259 | static PyObject *wrapper_setObjectAttribute_adclient(PyObject *self, PyObject *args) { 1260 | PyObject *obj; 1261 | char *object, *attr; 1262 | PyObject *listObj; 1263 | 1264 | if (!PyArg_ParseTuple(args, "OssO!", &obj, &object, &attr, &PyList_Type, &listObj)) return NULL; 1265 | 1266 | vector values; 1267 | for (unsigned int i = 0; i < PyList_Size(listObj); ++i) { 1268 | PyObject *strObj = PyList_GetItem(listObj, i); 1269 | string item = unicode2string(strObj); 1270 | values.push_back(item); 1271 | } 1272 | 1273 | adclient *ad = convert_ad(obj); 1274 | try { 1275 | ad->setObjectAttribute(object, attr, values); 1276 | } 1277 | catch(ADSearchException& ex) { 1278 | error_num = ex.code; 1279 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1280 | return NULL; 1281 | } 1282 | catch(ADOperationalException& ex) { 1283 | error_num = ex.code; 1284 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1285 | return NULL; 1286 | } 1287 | Py_INCREF(Py_None); 1288 | return Py_None; 1289 | } 1290 | 1291 | static PyObject *wrapper_UnLockUser_adclient(PyObject *self, PyObject *args) { 1292 | PyObject *obj; 1293 | char *user; 1294 | if (!PyArg_ParseTuple(args, "Os", &obj, &user)) return NULL; 1295 | adclient *ad = convert_ad(obj); 1296 | try { 1297 | ad->UnLockUser(user); 1298 | } 1299 | catch(ADSearchException& ex) { 1300 | error_num = ex.code; 1301 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1302 | return NULL; 1303 | } 1304 | catch(ADOperationalException& ex) { 1305 | error_num = ex.code; 1306 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1307 | return NULL; 1308 | } 1309 | Py_INCREF(Py_None); 1310 | return Py_None; 1311 | } 1312 | 1313 | static PyObject *wrapper_MoveUser_adclient(PyObject *self, PyObject *args) { 1314 | PyObject *obj; 1315 | char *user; 1316 | char *new_container; 1317 | if (!PyArg_ParseTuple(args, "Oss", &obj, &user, &new_container)) return NULL; 1318 | adclient *ad = convert_ad(obj); 1319 | try { 1320 | ad->MoveUser(user, new_container); 1321 | } 1322 | catch(ADSearchException& ex) { 1323 | error_num = ex.code; 1324 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1325 | return NULL; 1326 | } 1327 | catch(ADOperationalException& ex) { 1328 | error_num = ex.code; 1329 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1330 | return NULL; 1331 | } 1332 | Py_INCREF(Py_None); 1333 | return Py_None; 1334 | } 1335 | 1336 | static PyObject *wrapper_MoveObject_adclient(PyObject *self, PyObject *args) { 1337 | PyObject *obj; 1338 | char *object; 1339 | char *new_container; 1340 | if (!PyArg_ParseTuple(args, "Oss", &obj, &object, &new_container)) return NULL; 1341 | adclient *ad = convert_ad(obj); 1342 | try { 1343 | ad->MoveObject(object, new_container); 1344 | } 1345 | catch(ADSearchException& ex) { 1346 | error_num = ex.code; 1347 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1348 | return NULL; 1349 | } 1350 | catch(ADOperationalException& ex) { 1351 | error_num = ex.code; 1352 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1353 | return NULL; 1354 | } 1355 | Py_INCREF(Py_None); 1356 | return Py_None; 1357 | } 1358 | 1359 | static PyObject *wrapper_RenameUser_adclient(PyObject *self, PyObject *args) { 1360 | PyObject *obj; 1361 | char *user; 1362 | char *shortname; 1363 | char *cn; 1364 | if (!PyArg_ParseTuple(args, "Osss", &obj, &user, &shortname, &cn)) return NULL; 1365 | adclient *ad = convert_ad(obj); 1366 | try { 1367 | ad->RenameUser(user, shortname, cn); 1368 | } 1369 | catch(ADSearchException& ex) { 1370 | error_num = ex.code; 1371 | PyErr_SetString(ADSearchError, ex.msg.c_str()); 1372 | return NULL; 1373 | } 1374 | catch(ADOperationalException& ex) { 1375 | error_num = ex.code; 1376 | PyErr_SetString(ADOperationalError, ex.msg.c_str()); 1377 | return NULL; 1378 | } 1379 | Py_INCREF(Py_None); 1380 | return Py_None; 1381 | } 1382 | 1383 | static PyMethodDef adclient_methods[] = { 1384 | { "new_adclient", (PyCFunction)wrapper_new_adclient, METH_VARARGS, NULL }, 1385 | { "login_adclient", (PyCFunction)wrapper_login_adclient, METH_VARARGS, NULL }, 1386 | { "searchDN_adclient", (PyCFunction)wrapper_searchDN_adclient, METH_VARARGS, NULL }, 1387 | { "search_adclient", (PyCFunction)wrapper_search_adclient, METH_VARARGS, NULL }, 1388 | { "getUserGroups_adclient", (PyCFunction)wrapper_getUserGroups_adclient, METH_VARARGS, NULL }, 1389 | { "getUsersInGroup_adclient", (PyCFunction)wrapper_getUsersInGroup_adclient, METH_VARARGS, NULL }, 1390 | { "getUserControls_adclient", (PyCFunction)wrapper_getUserControls_adclient, METH_VARARGS, NULL }, 1391 | { "groupAddUser_adclient", (PyCFunction)wrapper_groupAddUser_adclient, METH_VARARGS, NULL }, 1392 | { "groupRemoveUser_adclient", (PyCFunction)wrapper_groupRemoveUser_adclient, METH_VARARGS, NULL }, 1393 | { "ifDialinUser_adclient", (PyCFunction)wrapper_ifDialinUser_adclient, METH_VARARGS, NULL }, 1394 | { "getDialinUsers_adclient", (PyCFunction)wrapper_getDialinUsers_adclient, METH_VARARGS, NULL }, 1395 | { "getDisabledUsers_adclient", (PyCFunction)wrapper_getDisabledUsers_adclient, METH_VARARGS, NULL }, 1396 | { "getObjectDN_adclient", (PyCFunction)wrapper_getObjectDN_adclient, METH_VARARGS, NULL }, 1397 | { "ifUserDisabled_adclient", (PyCFunction)wrapper_ifUserDisabled_adclient, METH_VARARGS, NULL }, 1398 | { "getOUs_adclient", (PyCFunction)wrapper_getOUs_adclient, METH_VARARGS, NULL }, 1399 | { "getOUsInOU_adclient", (PyCFunction)wrapper_getOUsInOU_adclient, METH_VARARGS, NULL }, 1400 | { "getUsersInOU_adclient", (PyCFunction)wrapper_getUsersInOU_adclient, METH_VARARGS, NULL }, 1401 | { "getGroupsInOU_adclient", (PyCFunction)wrapper_getGroupsInOU_adclient, METH_VARARGS, NULL }, 1402 | { "getComputersInOU_adclient", (PyCFunction)wrapper_getComputersInOU_adclient, METH_VARARGS, NULL }, 1403 | { "getGroups_adclient", (PyCFunction)wrapper_getGroups_adclient, METH_VARARGS, NULL }, 1404 | { "getUsers_adclient", (PyCFunction)wrapper_getUsers_adclient, METH_VARARGS, NULL }, 1405 | { "getUserDisplayName_adclient", (PyCFunction)wrapper_getUserDisplayName_adclient, METH_VARARGS, NULL }, 1406 | { "getUserIpAddress_adclient", (PyCFunction)wrapper_getUserIpAddress_adclient, METH_VARARGS, NULL }, 1407 | { "getObjectAttribute_adclient", (PyCFunction)wrapper_getObjectAttribute_adclient, METH_VARARGS, NULL }, 1408 | { "getObjectAttributes_adclient", (PyCFunction)wrapper_getObjectAttributes_adclient, METH_VARARGS, NULL }, 1409 | { "CreateUser_adclient", (PyCFunction)wrapper_CreateUser_adclient, METH_VARARGS, NULL }, 1410 | { "CreateComputer_adclient", (PyCFunction)wrapper_CreateComputer_adclient, METH_VARARGS, NULL }, 1411 | { "CreateGroup_adclient", (PyCFunction)wrapper_CreateGroup_adclient, METH_VARARGS, NULL }, 1412 | { "DeleteDN_adclient", (PyCFunction)wrapper_DeleteDN_adclient, METH_VARARGS, NULL }, 1413 | { "CreateOU_adclient", (PyCFunction)wrapper_CreateOU_adclient, METH_VARARGS, NULL }, 1414 | { "EnableUser_adclient", (PyCFunction)wrapper_EnableUser_adclient, METH_VARARGS, NULL }, 1415 | { "DisableUser_adclient", (PyCFunction)wrapper_DisableUser_adclient, METH_VARARGS, NULL }, 1416 | { "setUserDescription_adclient", (PyCFunction)wrapper_setUserDescription_adclient, METH_VARARGS, NULL }, 1417 | { "setUserPassword_adclient", (PyCFunction)wrapper_setUserPassword_adclient, METH_VARARGS, NULL }, 1418 | { "changeUserPassword_adclient", (PyCFunction)wrapper_changeUserPassword_adclient, METH_VARARGS, NULL }, 1419 | { "checkUserPassword_adclient", (PyCFunction)wrapper_checkUserPassword_adclient, METH_VARARGS, NULL }, 1420 | { "setUserDialinAllowed_adclient", (PyCFunction)wrapper_setUserDialinAllowed_adclient, METH_VARARGS, NULL }, 1421 | { "setUserDialinDisabled_adclient", (PyCFunction)wrapper_setUserDialinDisabled_adclient, METH_VARARGS, NULL }, 1422 | { "setUserSN_adclient", (PyCFunction)wrapper_setUserSN_adclient, METH_VARARGS, NULL }, 1423 | { "setUserInitials_adclient", (PyCFunction)wrapper_setUserInitials_adclient, METH_VARARGS, NULL }, 1424 | { "setUserGivenName_adclient", (PyCFunction)wrapper_setUserGivenName_adclient, METH_VARARGS, NULL }, 1425 | { "setUserDisplayName_adclient", (PyCFunction)wrapper_setUserDisplayName_adclient, METH_VARARGS, NULL }, 1426 | { "setUserRoomNumber_adclient", (PyCFunction)wrapper_setUserRoomNumber_adclient, METH_VARARGS, NULL }, 1427 | { "setUserAddress_adclient", (PyCFunction)wrapper_setUserAddress_adclient, METH_VARARGS, NULL }, 1428 | { "setUserInfo_adclient", (PyCFunction)wrapper_setUserInfo_adclient, METH_VARARGS, NULL }, 1429 | { "setUserTitle_adclient", (PyCFunction)wrapper_setUserTitle_adclient, METH_VARARGS, NULL }, 1430 | { "setUserDepartment_adclient", (PyCFunction)wrapper_setUserDepartment_adclient, METH_VARARGS, NULL }, 1431 | { "setUserCompany_adclient", (PyCFunction)wrapper_setUserCompany_adclient, METH_VARARGS, NULL }, 1432 | { "setUserPhone_adclient", (PyCFunction)wrapper_setUserPhone_adclient, METH_VARARGS, NULL }, 1433 | { "setUserIpAddress_adclient", (PyCFunction)wrapper_setUserIpAddress_adclient, METH_VARARGS, NULL }, 1434 | { "clearObjectAttribute_adclient", (PyCFunction)wrapper_clearObjectAttribute_adclient, METH_VARARGS, NULL }, 1435 | { "setObjectAttribute_adclient", (PyCFunction)wrapper_setObjectAttribute_adclient, METH_VARARGS, NULL }, 1436 | { "UnLockUser_adclient", (PyCFunction)wrapper_UnLockUser_adclient, METH_VARARGS, NULL }, 1437 | { "MoveUser_adclient", (PyCFunction)wrapper_MoveUser_adclient, METH_VARARGS, NULL }, 1438 | { "MoveObject_adclient", (PyCFunction)wrapper_MoveObject_adclient, METH_VARARGS, NULL }, 1439 | { "RenameUser_adclient", (PyCFunction)wrapper_RenameUser_adclient, METH_VARARGS, NULL }, 1440 | { "ifDNExists_adclient", (PyCFunction)wrapper_ifDNExists_adclient, METH_VARARGS, NULL }, 1441 | { "binded_uri_adclient", (PyCFunction)wrapper_binded_uri_adclient, METH_VARARGS, NULL }, 1442 | { "search_base_adclient", (PyCFunction)wrapper_search_base_adclient, METH_VARARGS, NULL }, 1443 | { "login_method_adclient", (PyCFunction)wrapper_login_method_adclient, METH_VARARGS, NULL }, 1444 | { "bind_method_adclient", (PyCFunction)wrapper_bind_method_adclient, METH_VARARGS, NULL }, 1445 | { "get_error_num", (PyCFunction)wrapper_get_error_num, METH_VARARGS, NULL }, 1446 | { "int2ip", (PyCFunction)wrapper_int2ip, METH_VARARGS, NULL }, 1447 | { "domain2dn", (PyCFunction)wrapper_domain2dn, METH_VARARGS, NULL }, 1448 | { "decodeSID", (PyCFunction)wrapper_decodeSID, METH_VARARGS, NULL }, 1449 | { "FileTimeToPOSIX", (PyCFunction)wrapper_FileTimeToPOSIX, METH_VARARGS, NULL }, 1450 | { "get_ldap_servers", (PyCFunction)wrapper_get_ldap_servers, METH_VARARGS, NULL }, 1451 | { NULL, NULL } 1452 | }; 1453 | 1454 | static struct PyModuleDef moduledef = { 1455 | PyModuleDef_HEAD_INIT, 1456 | "_adclient", 1457 | NULL, 1458 | -1, 1459 | adclient_methods, 1460 | NULL, 1461 | NULL, 1462 | NULL, 1463 | NULL 1464 | }; 1465 | 1466 | PyMODINIT_FUNC 1467 | PyInit__adclient() { 1468 | PyObject *module = PyModule_Create(&moduledef); 1469 | 1470 | #pragma GCC diagnostic push 1471 | #pragma GCC diagnostic ignored "-Wwrite-strings" 1472 | ADBindError = PyErr_NewException("ADBindError.error", NULL, NULL); 1473 | ADSearchError = PyErr_NewException("ADSearchError.error", NULL, NULL); 1474 | ADOperationalError = PyErr_NewException("ADOperationalError.error", NULL, NULL); 1475 | #pragma GCC diagnostic pop 1476 | Py_INCREF(ADBindError); 1477 | Py_INCREF(ADSearchError); 1478 | Py_INCREF(ADOperationalError); 1479 | PyModule_AddObject(module, "ADBindError", ADBindError); 1480 | PyModule_AddObject(module, "ADSearchError", ADSearchError); 1481 | PyModule_AddObject(module, "ADOperationalError", ADOperationalError); 1482 | 1483 | PyModule_AddIntMacro(module, AD_SUCCESS); 1484 | PyModule_AddIntMacro(module, AD_LDAP_CONNECTION_ERROR); 1485 | PyModule_AddIntMacro(module, AD_PARAMS_ERROR); 1486 | PyModule_AddIntMacro(module, AD_SERVER_CONNECT_FAILURE); 1487 | PyModule_AddIntMacro(module, AD_OBJECT_NOT_FOUND); 1488 | PyModule_AddIntMacro(module, AD_ATTRIBUTE_ENTRY_NOT_FOUND); 1489 | PyModule_AddIntMacro(module, AD_OU_SYNTAX_ERROR); 1490 | 1491 | PyModule_AddIntMacro(module, AD_SCOPE_BASE); 1492 | PyModule_AddIntMacro(module, AD_SCOPE_ONELEVEL); 1493 | PyModule_AddIntMacro(module, AD_SCOPE_SUBTREE); 1494 | 1495 | return module; 1496 | } 1497 | 1498 | // vim: ai ts=4 sts=4 et sw=4 expandtab 1499 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from distutils.core import setup, Extension 3 | import sys 4 | 5 | wrapper = "adclient_wrapper_python{0}.cpp".format(sys.version_info[0]) 6 | 7 | setup(name="adclient", 8 | version="1.0", 9 | description = "Active Directory manipulation tool", 10 | author = "Oleg Palij", 11 | author_email = "o.palij@gmail.com", 12 | py_modules=["adclient"], 13 | ext_modules=[Extension("_adclient", [wrapper], 14 | include_dirs=["/usr/local/include", "/usr/include"], 15 | library_dirs=["/usr/local/lib", "/usr/lib"], 16 | libraries=["ldap", "adclient"], 17 | extra_compile_args=["-g", "-O0", "-Wall"] 18 | ) 19 | ] 20 | ) 21 | --------------------------------------------------------------------------------