diff options
author | Gerald Carter <jerry@samba.org> | 2003-08-20 21:52:52 +0000 |
---|---|---|
committer | Gerald Carter <jerry@samba.org> | 2003-08-20 21:52:52 +0000 |
commit | a750624f4d005e2bc415e86a38947a7fa10d0cb9 (patch) | |
tree | 206472fd4bc1af26969b85e2ac19dafe82774eff /examples/LDAP/smbldap-tools | |
parent | 8bfe26b62db2e671b143d93a5428f8fb64a9df05 (diff) | |
download | samba-a750624f4d005e2bc415e86a38947a7fa10d0cb9.tar.gz samba-a750624f4d005e2bc415e86a38947a7fa10d0cb9.tar.bz2 samba-a750624f4d005e2bc415e86a38947a7fa10d0cb9.zip |
checlking in initial version of 2.2 scripts so I can start updating them
(This used to be commit 766a5070d58ada7a871a7fab45b5f7e203264952)
Diffstat (limited to 'examples/LDAP/smbldap-tools')
35 files changed, 6143 insertions, 0 deletions
diff --git a/examples/LDAP/smbldap-tools/AUTHORS b/examples/LDAP/smbldap-tools/AUTHORS new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/examples/LDAP/smbldap-tools/AUTHORS diff --git a/examples/LDAP/smbldap-tools/CONTRIBUTORS b/examples/LDAP/smbldap-tools/CONTRIBUTORS new file mode 100644 index 0000000000..9765a57e60 --- /dev/null +++ b/examples/LDAP/smbldap-tools/CONTRIBUTORS @@ -0,0 +1,29 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/CONTRIBUTORS,v $ +# +## Authors and actives contributors to SMBLDAP-TOOLS + +Have contributed directly to this tools, or are always in charge of +some aspects of it developments (alphabetical order): + . Terry Davis <tdavis@approbation.org> + . David Le Corfec <dlc@freesurf.fr> + . Olivier Lemaire <olivier.lemaire@IDEALX.com> + . Jérôme Tournier <jerome.tournier@IDEALX.com> + +Many thanks to contributors for bug report and patches: + . Gert-Jan Braas <braas@wyldebeast-wunderliebe.com> + bug report for 2.2.3 samba.schema + . Jody Haynes <Jody.Haynes@isunnetworks.com> + originaly passwd.pl + . Brad Langhorst <brad@langhorst.com> + package relocatability + . Mirko Manea <mami@arena.sci.univr.it> + originaly useradd.pl + . Alain Richard <alain.richard@equation.fr> + bug report and Perl tips + . Roland Schulz <mail@r2s2.de> + bug report for smbldap-passwd + . Xavier Boschian <Xavier.Boschian@rtlgroup.net> + bug report for smbldap-populate + + +# - The End diff --git a/examples/LDAP/smbldap-tools/COPYING b/examples/LDAP/smbldap-tools/COPYING new file mode 100644 index 0000000000..32d0e6014a --- /dev/null +++ b/examples/LDAP/smbldap-tools/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/examples/LDAP/smbldap-tools/ChangeLog b/examples/LDAP/smbldap-tools/ChangeLog new file mode 100644 index 0000000000..9a0bc744e1 --- /dev/null +++ b/examples/LDAP/smbldap-tools/ChangeLog @@ -0,0 +1,29 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/ChangeLog,v $ +# +## ChangeLog for SMBLDAP-TOOLS + +* 2002-06-03: notes to webmin.idealx.org (idxldapaccounts) +* 2002-06-01: release 0.7. tested with 2.2.4 +* 2002-05-31: fixed smbldap-populate compliance to smbldap_conf + cleaned up smbldap_conf to be more readable + some more documentation + bugfixes on smbldap-passwd and smbldap-populate +* 2002-05-16: modified default mode on homes: now 700 +* 2002-05-13: fixed spec (relocation and reqs) +* 2002-03-02: fixed 2.2.3 sambaAccount bug with smbldap-useradd.pl + (rid is now mandatory in the sambaAccount objectClass) +* 2002-02-14: just modified default populate for Administrator +* 2002-02-05: release 0.6. enable/disable user in usermod +* 2002-02-04: release 0.5. added smbldap-migrate-groups to migrate NT groups + from a net group dump. added samba parameters to smbldap-useradd + and smbldap-usermod. +* 2002-01-12: added smbldap-migrate-accounts to migrate users/machines + accounts from a PWDUMP dump +* 2001-12-13: added smbldap-populate to create the initial base +* 2001-12-13: initial release 0.1 +* 2001-12-12: fixed the SPEC file for RedHat +* 2001-12-03: cleaned the code and use strict; +* 2001-11-20: initial needs (for testing purpose on Samba-2.2.2 an Samba-TNG) + + +# - The End diff --git a/examples/LDAP/smbldap-tools/FILES b/examples/LDAP/smbldap-tools/FILES new file mode 100644 index 0000000000..48ee571b29 --- /dev/null +++ b/examples/LDAP/smbldap-tools/FILES @@ -0,0 +1,43 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/FILES,v $ +# +## File listing for SMBLDAP-TOOLS + +CONTRIBUTORS : authors and contributors +COPYING : licence +FILES : this file listing +README : introduction and usage +TODO : feature request and bug report list +ChangeLog : changelog + +Core: +=-=-= +smbldap-groupadd.pl : to add a new group + (objectclass: posixGroup) +smbldap-groupdel.pl : to delete a group + (objectclass: posixGroup) +smbldap-groupmod.pl : to modify a group (mostly used to add user to a group) + (objectclass: posixGroup) +smbldap-groupshow.pl : to view a group + (objectclass: posixGroup) +smbldap_conf.pm : global configuration datas +smbldap_tools.pm : functions +smbldap-useradd.pl : to add a new user + (objectclass: posixAccount and/or sambaAccount) +smbldap-userdel.pl : to delete a user + (objectclass: posixAccount and/or sambaAccount) +smbldap-usermod.pl : to modify an user datas + (objectclass: posixAccount and/or sambaAccount) +smbldap-usershow.pl : to view an user datas + (objectclass: posixAccount and/or sambaAccount) +smbldap-passwd.pl : to sync passwd (Unix and Samba) + (a replacement for the system passwd utility) +smbldap-populate.pl : to add a builtin ldif to initialize your LDAP master for + smbldap use, or to add a specified ldif +smbldap-tools.spec : SPEC file for RedHat RPM package format + +Migration: +=-=-=-=-=- +smbldap-migrate-accounts.pl : add NT sam entries from pwdump to ldap +smbldap-migrate-groups.pl : add any LDAP posixGroups from the output of the 'net group' NT command + +# - The End diff --git a/examples/LDAP/smbldap-tools/INFRASTRUCTURE b/examples/LDAP/smbldap-tools/INFRASTRUCTURE new file mode 100644 index 0000000000..75b80bb4c8 --- /dev/null +++ b/examples/LDAP/smbldap-tools/INFRASTRUCTURE @@ -0,0 +1,84 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/INFRASTRUCTURE,v $ +# +## Some notes about the architecture + + +Global Architecture for smbdlap-tools +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +smbldap-tools help you manage users and groups for Unix and Samba, +using LDAP. They may be used in any context, and are kept relatively +simplier enought to let you customize them to you needs. + +They need the following objectClasses to work: + . sambaAccount: from samba.schema for Samba 2.2 branch + . posixAccount and posixGroup : from nis.schema + . organizationalUnit and dcObject: from core.schema + +They will probably use in a near future some additional objectClasses +to support : + . mail features (sendmail/postfix/qmail/courier). + . conform to RFC2307 best practices (and so some maps too like merging + Netbios computers (sambaAccounts) with ipHosts + +For ease of visualization of the LDAP objects by human standards, we +used a DIT like this one : + . dc=IDEALX,dc=org : the company/organization suffix + . ou=Users : to store users accounts + . ou=Computers : to store computers accounts + . ou=Groups : to store system groups +Of course, you're free to use a different naming scheme and DIT (see +smbldap_conf.pm). + + +Built in groups initial population +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +smbldap-populate.pl populate the LDAP directory with some built in groups +using gidNumber according to Well Know RID of Windows NT4 Srv. In fact, As +far a Samba 2.2.x is concerned, only the 'Domain Admins' (gidNumber 512) have +real inpact on the Samba and Windows population. To activate this group as +the Domain Administrators Group, use the following smb.conf directive (see +man smb.conf for more): + + domain admin group = " @"Domain Admins" " + +Other built in groups are really cosmetic ones with Samba 2.2.x. We did not +removed them because one of these days, we whish to use Samba 3.0 where +Windows Group Support should be operational. + +Why these specific gidNumbers ? +It's about unix/windows mapping of numerical ids with Samba. Ids below 1024 +are NT special ids. In fact, 512 is the RID (Windows uid/gid) for the +"Domain Administrators" NT group. The magic number is found in Samba sources +and possibly other Samba/Windows documentations. + +The goal is to have a set of Unix users who are Domain Administrators and can +modify Samba datas (eg. LDAP content), with commandline tools or within +Windows via Samba. + +Say you want to add a NT4 ws to an NT domain (controlled by a samba/ldap +server). You give the domain administrator's login and password in the +appropriate ws settings, then the ws contacts the samba server, which checks +the credentials and use them as unix user to run the smbldap-tools (if I +remember). Giving 512 as a RID to a LDAP entry marks it as a domain admin +for Samba (thus Windows). Using nss_ldap, you also have an account with +gid 512. + + +Known BUGS and WORKAROUND used +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +The 2.2.2 has at least a bug : rid/primaryGroupID are read as hex in LDAP, +but written as decimal. Fixed in CVS by reading as decimal. By default +smbldap-useradd.pl writes decimal to LDAP. Use -x to support the odd +behaviour. + +The samba-2.2.4-ldapbindnotuid0.patch is not a perfect solution however +as the check is there because Samba store admin credentials to establish the +LDAP connection. The uid == 0 check was to ensure that a normal user could +not get write access to the LDAP backend. A more logical situation should be +done for 2.2.5 by checking if the user is a member of the domain admin group +(reported to Jerremy and Gerald 2002-05-28). + +# - The End diff --git a/examples/LDAP/smbldap-tools/INSTALL b/examples/LDAP/smbldap-tools/INSTALL new file mode 100644 index 0000000000..f4c72751a7 --- /dev/null +++ b/examples/LDAP/smbldap-tools/INSTALL @@ -0,0 +1,28 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/INSTALL,v $ +# +## How To Install SMBLDAP-TOOLS + +Quick & Dirty: +=-=-=-=-=-=-=- + . Copy all those scripts in /usr/local/sbin/ + . Modify smbldap_conf.pm to match your configuration + . If not already done : "smbpasswd -w secret" to set up + the ldap admin password in secrets.tdb + . Either add /usr/local/sbin in $PERLLIB or run the scripts + from this directory, or make a symlink from /usr/local/sbin/*.pm + to /usr/lib/perl5/. + . to allow a domain admin to add user using "add user script" in smb.conf : + chmod 753 smbldap_conf.pm + chmod 750 smbldap-useradd.pl + chgrp 512 smbldap_conf.pm smbldap-useradd.pl (512 = 0x200 = Domain Admins) + Have your admin belong to this group + In smb.conf : domain admin group = " @"Domain Admins" " + +RedHat RPM: +=-=-=-=-=-= +Install smbldap-tools-0.7-1.i386.rpm +Modify /usr/local/sbin/smbldap_conf.pm to match you configuration +If not already done : "smbpasswd -w secret" to set up +the ldap admin password in secrets.tdb + +# - The End diff --git a/examples/LDAP/smbldap-tools/Makefile b/examples/LDAP/smbldap-tools/Makefile new file mode 100644 index 0000000000..3e5eac427d --- /dev/null +++ b/examples/LDAP/smbldap-tools/Makefile @@ -0,0 +1,35 @@ +PACKAGE=smbldap-tools +RELEASE=0.7 +DESTDIR = $(PACKAGE)-$(RELEASE) + +dist: distclean $(DESTDIR).tgz + +$(DESTDIR).tgz: .diststamp + rm -rf $(DESTDIR) + mkdir $(DESTDIR) + # copy files + cp CONTRIBUTORS $(DESTDIR) + cp COPYING $(DESTDIR) + cp ChangeLog $(DESTDIR) + cp FILES $(DESTDIR) + cp INSTALL $(DESTDIR) + cp README $(DESTDIR) + cp TODO $(DESTDIR) + cp INFRASTRUCTURE $(DESTDIR) + tar cf mkntpwd.tar mkntpwd + gzip mkntpwd.tar + cp mkntpwd.tar.gz $(DESTDIR) + cp smbldap-*.pl $(DESTDIR) + cp smbldap_*.pm $(DESTDIR) + # copy directories + tar cvzf $(DESTDIR).tgz $(DESTDIR) + rm -rf $(DESTDIR) + touch .diststamp + +.diststamp: + +distclean: + rm -f *~ + rm -f $(DESTDIR).tgz + rm -f mkntpwd.tar.gz + diff --git a/examples/LDAP/smbldap-tools/NEWS b/examples/LDAP/smbldap-tools/NEWS new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/examples/LDAP/smbldap-tools/NEWS diff --git a/examples/LDAP/smbldap-tools/README b/examples/LDAP/smbldap-tools/README new file mode 100644 index 0000000000..add0175c0c --- /dev/null +++ b/examples/LDAP/smbldap-tools/README @@ -0,0 +1,87 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/README,v $ +# + +Latest version may be found at http://samba.idealx.org/ + + +What those tools are for? +=-=-=-=-=-=-=-=-=-=-=-=-= + +A collection of scripts, «over» user{add,del,mod} and group{add,del,mod} +system tools to manipulate users and groups stored in LDAP directory, +for DEN system like SAMBA-LDAP and pam/nss_ldap systems. + +Additionnaly, some scripts are designed to ease your migration from +a Windows NT 4.0 PDC Server to a Samba-LDAP PDC Server (Killer?;-): +smbldap-populate, smbldap-migrate-groups, smbldap-migrate-accounts. + +They are currently used with Samba 2.2.4, therefore you may (will) have +to make some fixes for Samba TNG and Samba 3.0. Hint: contribs welcome :) + +In the future, some other function may come (like backup and restore, +Novell migration tools, samba system activity report, dealing with +mail functions, compliance to RFC2307...): consult TODO. + + +What do SMBLDAP-TOOLS provide? +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Those tools provide the following functions : + . populate LDAP database with a basic LDIF + . add a user or group + . delete a user or group + . modify all users or groups data (all attributes types stored in + posixAccount and sambaAccount object class) +Taking care of : + . staying compatible with all standard system tools options + (user/group{add,del,mod}) + . be extensible for future developments + (manipulation of shadow account options, for example) + . error management, in the way system tools do +Constraints : + . usage of PERL (portability) + . all options must be placed in an external configuration file + . english localization + +The current release uses the "mkntpwd" program, in mkntpwd.tar.gz +in the current directory. It comes from +http://www.demog.berkeley.edu/~aperrin/tips/src/mkntpwd.tar.gz +It allows to not use smbpasswd (if $with_smbpasswd == 0 in smbldap_conf.pm) + +What do SMBLDAP-TOOLS deliver? +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +Contents : + . scripts (see FILES) + . user documentation in pod format, included in the sources + (or just use the -? option) + +These tools aim at delivering the same functionality as the corresponding +system tools. However they may not be all implemented yet. +Current limitations : + . no shadow support + . cannot change uid with usermod + . no UTF-8 support (thus ASCII-7 only) + + +How to generate documentation? +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Just issue the following command: + perldoc name_of_script.pl (ex: perldoc smbldap-useradd.pl) + +Where can I find the latest release of those scripts? +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +Just fire any web browser to http://samba.IDEALX.org/ +and/or contact samba@IDEALX.org + +Additionnaly, you will find an useful Webmin module +at http://webmin.IDEALX.org/ if interested in a graphical +user interface to manager user and groups accounts via Webmin +for your Samba+LDAP PDC. + +Let us know if these tools helped you, or if we should enhance +them with some functions you want them to support. + +Sincerly, + LEM + +# - The End diff --git a/examples/LDAP/smbldap-tools/TODO b/examples/LDAP/smbldap-tools/TODO new file mode 100644 index 0000000000..57424d462a --- /dev/null +++ b/examples/LDAP/smbldap-tools/TODO @@ -0,0 +1,27 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/TODO,v $ +# +## TODO list - First In, Last in the list... +## (BF: Bug Report / FR: Feature Request) + + +FR * use RFC2307 best practices (Luke, next time you visit Paris, have a + beer at IDEALX'cantina ;-) +FR * add mail (sendmail/postfix/qmail/courier) support +FR * bugfix, really : allow non-root users to change passwd + (currently the config must be unreadable because of bindpasswd) +FR * make smbldap-tools to use system configuration files + (/etc/login.defs and /etc/ldap.conf for example) +FR * rewrite smbldap-tools using perl-ldap. In fact, this 0.x + release use ldap system tools (ldapadd,ldapdelete,ldapmodify) +FR * add shadowAccounts manipulation support +FR * internationalize the SMBLDAP-TOOLS +FR * add smbldap-sar : Samba System Activity Report to help + supporting Samba/LDAP sysadmin activity +FR * add smbldap-backup/smbldap-restore to backup and restore + a SAM (in LDAP) database. No sorcery, just LDIF, but usefull + for non-LDAP gurus +FR * adding migration tools from migration from W2K and NetWare to Samba-LDAP +FR * adapt smbldap-tools to use Samba 3.0 + + +# - The End diff --git a/examples/LDAP/smbldap-tools/cgi/README b/examples/LDAP/smbldap-tools/cgi/README new file mode 100644 index 0000000000..7a4fc0c02b --- /dev/null +++ b/examples/LDAP/smbldap-tools/cgi/README @@ -0,0 +1,27 @@ +Description: + A cgi to allow users to change their passwords via a web browser. + +Installation: + Drop this into a cgi-enabled directory on your webserver. + Edit it and change the CONFIGURATION section to suit your environment. + READ THE NOTES SECTION. + +Notes: This script will run as the user who runs your web server. So, to invoke the smbpasswd call, you must implement sudo. + Example of /etc/sudoers: + + # Host alias specification + # User alias specification + User_Alias PASSWD = apache + # Cmnd alias specification + Cmnd_Alias PASSWD = /usr/bin/smbpasswd + # User privilege specification + root ALL=(ALL) ALL + PASSWD ALL= NOPASSWD: PASSWD + + This concept is probably very insecure and broken. That is why this is a 0.1 release. :) + + +Feel free to drop me suggestions. I am a perl learner so I am always open to suggestions. + +Terry Davis +tdavis@approbation.org diff --git a/examples/LDAP/smbldap-tools/cgi/ldappass.cgi b/examples/LDAP/smbldap-tools/cgi/ldappass.cgi new file mode 100755 index 0000000000..4a5ecb8f3a --- /dev/null +++ b/examples/LDAP/smbldap-tools/cgi/ldappass.cgi @@ -0,0 +1,202 @@ +#!/usr/bin/perl + +################################################################################ +# +# changepass.pl - A program to allow users to change their passwords +# via a web browser. +# Terry Davis +# +# URLs +# Net::LDAP - http:// +# usermod and this file - http://www.cloudamster.com/cloudmaster/projects +# +# Release History: +# Version 0.1 - initial write +# +# ToDo: +# ... the ToDo section is on the ToDo list... +# +# Limitations: +# The password cannot contain single and double quotes.....welcome to quoting hell.... +# +# Notes: +# This code is largely based on work done by Danny Sauer - http://www.cloudamster.com/cloudmaster/projects +# His work is not licensed and is marked as 'freely distributable'. +# Thank you to Danny for his hard work on the initial work. +# +################################################################################ + +use CGI qw(:standard); +use Net::LDAP; + +# CONFIGURATION SECTION +$masterLDAP = "ldap.idealx.org"; +$basedn = "dc=IDEALX,dc=org"; +$masterPw = ""; +$masterDN = "cn=manager,$basedn"; +$ldap_path = "/usr/bin"; +$ldap_opts = "-x"; +$ldappasswd = "$ldap_path/ldappasswd $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; +$usersdn = "ou=Users,$basedn"; +# END CONFIGURATION + + + +# DONT EDIT ANYTHING BELOW THIS LINE +$logtag = "Login:"; +$passtag = "Current password:"; +$npasstag1 = "New password:"; +$npasstag2 = "Retype new pasword:"; +$error = ""; +$color = "<FONT color='red'>"; +$stopcolor = "</FONT>"; + +if(param()){ + nologin() unless ($username = param('login')); + nopass() unless ($oldpass = param('oldpass')); + nonewpass(1) unless ($newpass1 = param('newpass')); + nonewpass(2) unless ($newpass2 = param('newpass2')); + verifyuser($username) or die "bad user"; + verifypass($username, $oldpass) or die "bad pass"; + testnewpass($newpass1, $newpass2) or die "bad new pass"; + changepass($username, $newpass1) or die "couldn't change pass"; + printsuccess(); +}else{ + printpage(); +} +exit(0); + +sub verifyuser{ + local $user = shift; + $ldap = Net::LDAP->new($masterLDAP) or die "can't make new LDAP object: $@"; + $ldap->bind(); + if (0 < $ldap->search(base => $basedn, filter => "(uid=$user)")->count){ + return 1; + } + $logtag = $color . $logtag . $color; + $error = "No such user"; + printpage(); + return 0; +} + +sub verifypass{ + $uid = shift; + $pass = shift; + $ldap = Net::LDAP->new($masterLDAP) or die "can't make new LDAP object: $@"; + $binddn = "uid=$uid,ou=People,$basedn"; + return 1 if($ldap->bind( $binddn, password => $pass)->code == 0); + if($ldap->bind()){ + $passtag = $color . $passtag . $color; + $error = "Incorrect password"; + printpage(); + return 0; + }else{ + print header, start_html(-title=>"LDAP dead"); + print h2("<CENTER>The LDAP server is temporarily unavailable."), + p,"Please try again later</CENTER>"; + return 0; + }die "Something (or someone) is defective, contact your friendly Systems Administrator"; +} + +sub testnewpass{ + $p1 = shift; $p2 = shift; + if ($p1 ne $p2){ + $npasstag1 = $color . $npasstag1 . $color; + $npasstag2 = $color . $npasstag2 . $color; + $error = "Passwords don't match ($p1 vs $p2)"; + printpage(); + return 0; + } + if ($p1 =~ /"/ ){ + $npasstag1 = $color . $npasstag1 . $color; + $npasstag2 = $color . $npasstag2 . $color; + $error = "Passwords cannot contain double quotes. Sorry"; + printpage(); + return 0; + } + if ($p1 =~ /'/ ){ + $npasstag1 = $color . $npasstag1 . $color; + $npasstag2 = $color . $npasstag2 . $color; + $error = "Passwords cannot contain single quotes. Sorry"; + printpage(); + return 0; + } + return 1; +} + +sub changepass{ + local $user = shift; + local $newpass = shift; + local $dn = "uid=$user,$usersdn"; + system "$ldappasswd $dn -s '$newpass' > /dev/null"; + `/usr/bin/sudo /usr/bin/smbpasswd $user "$newpass"`; + exit(1); +} + +sub nologin{ + $logtag = $color . $logtag . $color; + $error = "You need to enter a Login Name"; + printpage(); + exit(1); +} + +sub nopass{ + $passtag = $color . $passtag . $color; + $error = "Please enter your old password"; + printpage(); + exit(1); +} + +sub nonewpass{ + $f=shift; + $npasstag1 = $color . $npasstag1 . $color if($f==1); + $npasstag2 = $color . $npasstag2 . $color if($f==2); + $error = "You need to enter your new password"; + $error .= " twice" if($f==2); + printpage(); + exit(1); +} + +sub printpage{ + print header, + start_html(-title=> "Password Change Page", + -author=> 'tdavis@birddog.com', + -BGCOLOR=> 'WHITE'), + h3('Password Change Page'), + startform(-method=>'POST'), + "<TABLE BORDER=0 WIDTH=50%>", + "<font size=2>", + "<TR><TD>", + $logtag, + "</TD><TD>", + textfield(-name=>'login', -default=>$login, + -size=>15, -maxlength=>20), + "</TD><TR><TD>", + $passtag, + "</TD><TD>", + password_field(-name=>'oldpass', -size=>15, -maxlength=>25), + "</TD><TR><TD>", + $npasstag1, + "</TD><TD>", + password_field(-name=>'newpass', -size=>15, -maxlength=>25), + "</TD><TR><TD>", + $npasstag2, + "</TD><TD>", + password_field(-name=>'newpass2', -size=>15, -maxlength=>25), + "</TD><TR><TD></TD><TD>", + submit(-name=>"change"),reset(), + "</TD></TR></TABLE>", + "</font>", + endform(), + "<FONT color='red'>$error</FONT>", + end_html; +} + +sub printsuccess(){ + print header, + start_html(-title=> "Success", + -BGCOLOR=> 'WHITE'), + h1("Password Succesfully Changed"), + "<br>", + end_html; +} diff --git a/examples/LDAP/smbldap-tools/mkntpwd/Makefile b/examples/LDAP/smbldap-tools/mkntpwd/Makefile new file mode 100644 index 0000000000..23c9d471b0 --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/Makefile @@ -0,0 +1,62 @@ +# Makefile for l0phtcrack - mudge@l0pht.com 11/1/96 + +# C compiler +#CC=cc +CC=gcc + +# Uncomment the following to add symbols to the code for debugging +#DEBUG=-g -Wall -D_DEBUG +#DEBUG=-D_DEBUG + +# Optimization for the compiler +#OPTIMIZE= +OPTIMIZE=-O2 + +# Choose your architecture +# note that if you are on a big-endian machine like SUN's +# I haven't tweaked the mem-cmp's and md4 stuff to be in +# the correct order yet. You're on your own right now. +# +# FreeBSD +ARCH=-DMPU8086 +STATIC= +XLIBS= +# +# SUNOS +#ARCH=-DBIGENDIAN +#STATIC= +#OPTIMIZE=-O2 +#XLIBS= +# +# ULTRA_SPARC w/ native compiler +#ARCH=-DBIGENDIAN +#STATIC= +#OPTIMIZE=-fast -xO4 -xdepend -xchip=ultra -xarch=v8plus +#XLIBS= +# +# SunOS/Solaris w/gcc +#ARCH=-DBIGENDIAN -DTEST +#STATIC= +#OPTIMIZE=-O2 +#XLIBS= +# +# NeXTStep 3.2 +#CC=cc +#ARCH=-DBIGENDIAN +#STATIC=-Bstatic +#OPTIMIZE= +#XLIBS= + +CFLAGS= $(DEBUG) $(OPTIMIZE) $(ARCH) $(VISUAL) $(PERMUTE) $(STATIC) + +OBJS = getopt.o md4.o mkntpwd.o smbdes.o + +mkntpwd: $(OBJS) + $(CC) $(CFLAGS) $(XLIBS) -o mkntpwd $(OBJS) + +clean: + rm -f core *.o mkntpwd + +install: mkntpwd + install -m 555 mkntpwd $(PREFIX)/sbin/mkntpwd + diff --git a/examples/LDAP/smbldap-tools/mkntpwd/getopt.c b/examples/LDAP/smbldap-tools/mkntpwd/getopt.c new file mode 100644 index 0000000000..5b2e7a9100 --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/getopt.c @@ -0,0 +1,756 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 + Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +#ifdef WIN32 +#include <string.h> +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include <stdlib.h> +#endif /* GNU C library. */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include <string.h> +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + optstring = _getopt_initialize (optstring); + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; /* set to zero by Anton */ + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int)(nameend - nextchar) == (unsigned int)strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + else + fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/examples/LDAP/smbldap-tools/mkntpwd/getopt.h b/examples/LDAP/smbldap-tools/mkntpwd/getopt.h new file mode 100644 index 0000000000..f3696d955d --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/getopt.h @@ -0,0 +1,133 @@ +/* Declarations for getopt. + Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/examples/LDAP/smbldap-tools/mkntpwd/md4.c b/examples/LDAP/smbldap-tools/mkntpwd/md4.c new file mode 100644 index 0000000000..1c9c2e6ecd --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/md4.c @@ -0,0 +1,171 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + a implementation of MD4 designed for use in the SMB authentication protocol + Copyright (C) Andrew Tridgell 1997 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* NOTE: This code makes no attempt to be fast! + + It assumes that a int is at least 32 bits long +*/ + +typedef unsigned int uint32; + +static uint32 A, B, C, D; + +static uint32 F(uint32 X, uint32 Y, uint32 Z) +{ + return (X&Y) | ((~X)&Z); +} + +static uint32 G(uint32 X, uint32 Y, uint32 Z) +{ + return (X&Y) | (X&Z) | (Y&Z); +} + +static uint32 H(uint32 X, uint32 Y, uint32 Z) +{ + return X^Y^Z; +} + +static uint32 lshift(uint32 x, int s) +{ + x &= 0xFFFFFFFF; + return ((x<<s)&0xFFFFFFFF) | (x>>(32-s)); +} + +#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void mdfour64(uint32 *M) +{ + int j; + uint32 AA, BB, CC, DD; + uint32 X[16]; + + for (j=0;j<16;j++) + X[j] = M[j]; + + AA = A; BB = B; CC = C; DD = D; + + ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); + ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); + ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); + ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); + ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); + ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); + ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); + ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); + + ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); + ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); + ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); + ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); + ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); + ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); + ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); + ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); + + ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); + ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); + ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); + ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); + ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); + ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); + ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); + ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); + + A += AA; B += BB; C += CC; D += DD; + + A &= 0xFFFFFFFF; B &= 0xFFFFFFFF; + C &= 0xFFFFFFFF; D &= 0xFFFFFFFF; + + for (j=0;j<16;j++) + X[j] = 0; +} + +static void copy64(uint32 *M, unsigned char *in) +{ + int i; + + for (i=0;i<16;i++) + M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | + (in[i*4+1]<<8) | (in[i*4+0]<<0); +} + +static void copy4(unsigned char *out,uint32 x) +{ + out[0] = x&0xFF; + out[1] = (x>>8)&0xFF; + out[2] = (x>>16)&0xFF; + out[3] = (x>>24)&0xFF; +} + +/* produce a md4 message digest from data of length n bytes */ +void mdfour(unsigned char *out, unsigned char *in, int n) +{ + unsigned char buf[128]; + uint32 M[16]; + uint32 b = n * 8; + int i; + + A = 0x67452301; + B = 0xefcdab89; + C = 0x98badcfe; + D = 0x10325476; + + while (n > 64) { + copy64(M, in); + mdfour64(M); + in += 64; + n -= 64; + } + + for (i=0;i<128;i++) + buf[i] = 0; + memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf+56, b); + copy64(M, buf); + mdfour64(M); + } else { + copy4(buf+120, b); + copy64(M, buf); + mdfour64(M); + copy64(M, buf+64); + mdfour64(M); + } + + for (i=0;i<128;i++) + buf[i] = 0; + copy64(M, buf); + + copy4(out, A); + copy4(out+4, B); + copy4(out+8, C); + copy4(out+12, D); + + A = B = C = D = 0; +} + + diff --git a/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.c b/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.c new file mode 100644 index 0000000000..0c7d61e134 --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.c @@ -0,0 +1,253 @@ +/* + This code is based on work from + L0phtcrack 1.5 06.02.97 mudge@l0pht.com + + The code also contains sources from: + . routines from the samba code source + md4.c smbdes.c + + Anton Roeckseisen (anton@genua.de) + +*/ + +/* + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "mkntpwd.h" + +void str_to_key(unsigned char *,unsigned char *); +void usage(char *); +int PutUniCode(char *dst,char *src); +void printlanhash(char *tmp); +void mdfour(unsigned char *out, unsigned char *in, int n); +void E_P16(unsigned char *p14,unsigned char *p16); + + +void main(int argc, char **argv) { + extern char *optarg; + int c; + + int printlan = 0; + char lanpwd[LMPASSWDLEN+1]; + int printnt = 0; + char inputfile[FILENAMEBUFFER+1] = ""; + FILE* InputFilePtr; + int just_pwd = 0; + int i; + char hashout[17]; + + char ntpasswd[NTPASSWDLEN+1]; + char *hold; + unsigned char *p16; + int uni_len; + char passwd[NTPASSWDLEN+1]; + + if (argc==1) + usage(argv[0]); + + if (argc==2) + just_pwd=1; + else + just_pwd=0; + + lanpwd[0] = '\0'; + ntpasswd[0] = '\0'; + + while ( (c = getopt(argc, argv, "L:N:f:")) != EOF){ + switch(c) { + case 'L': + printlan++; + strncpy(lanpwd,optarg,LMPASSWDLEN); + lanpwd[LMPASSWDLEN]='\0'; + for (i=0;i<LMPASSWDLEN;i++) + lanpwd[i]=toupper(lanpwd[i]); + break; + case 'N': + printnt++; + strncpy(passwd,optarg,NTPASSWDLEN); + passwd[NTPASSWDLEN]='\0'; + break; + case 'f': + strncpy(inputfile,optarg,FILENAMEBUFFER); + inputfile[FILENAMEBUFFER]='\0'; + break; + default: + usage(argv[0]); + } + } + + /* Get password from file or STDIN */ + if (inputfile[0]!='\0') { + + just_pwd=0; /* make sure no shit is happening... */ + + /* get NT-password (longer) */ + if (strcmp(inputfile,"-")==0) { + fgets(passwd,NTPASSWDLEN,stdin); + } else { + if ((InputFilePtr=fopen(inputfile,"r")) == NULL) + fprintf(stderr,"Couldn't open passwordfile: %s",inputfile) ; + fgets(passwd,NTPASSWDLEN,InputFilePtr); + fclose(InputFilePtr); + } + while (strlen(passwd)>0 && passwd[strlen(passwd)-1]=='\n') + passwd[strlen(passwd)-1]='\0'; + + /* create LANMAN-password (shorter) */ + strncpy(lanpwd,passwd,LMPASSWDLEN); + lanpwd[LMPASSWDLEN]='\0'; + for (i=0;i<LMPASSWDLEN;i++) + lanpwd[i]=toupper(lanpwd[i]); + printlan++; + printnt++; + + } + + + /* Assume the one and only Arg is the new password! */ + + if (argc>1 && just_pwd==1) { + strncpy(lanpwd,argv[1],LMPASSWDLEN); + lanpwd[LMPASSWDLEN]='\0'; + for (i=0;i<LMPASSWDLEN;i++) + lanpwd[i]=toupper(lanpwd[i]); + printlan++; + + strncpy(passwd,argv[1],NTPASSWDLEN); + passwd[NTPASSWDLEN]='\0'; + printnt++; + } + + if (printlan >0) { + memset(hashout,'\0',17); + E_P16((uchar *)lanpwd,hashout); + printlanhash(hashout); + } + + if (printnt >0) { + + if (printlan>0) printf(":"); + + memset(ntpasswd, '\0', sizeof(ntpasswd)); + + if (passwd[strlen(passwd)-1] == '\n') /* strip the \n - this + is done in LowerString for the case sensitive + check */ + passwd[strlen(passwd)-1] = '\0'; + + hold = (char *)malloc(NTPASSWDLEN * 2); /* grab space for + unicode */ + if (hold == NULL){ + fprintf(stderr, "out of memory...crackntdialog hold\n"); + exit(1); + } + + uni_len = PutUniCode(hold, passwd); /* convert to + unicode and return correct + unicode length for md4 */ + + p16 = (unsigned char*)malloc(17); /* grab space for md4 hash */ + if (p16 == NULL){ + fprintf(stderr, "out of memory...crackntdialect p16\n"); + exit(1); + } + + memset(p16,'\0',17); + mdfour(p16,hold, uni_len); + + printlanhash(p16); + + free(p16); + free(hold); + } + + printf("\n"); + + exit(0); + +} + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ + +void usage(char *progname){ + char *p; + + p = strrchr(progname, '\\'); + if (p == NULL) + p = progname; + else + p++; + + fprintf(stderr, "Usage: %s [-L lanmgrpwd] [-N ntpasswd]\n",p); + fprintf(stderr, " %s password\n",p); + fprintf(stderr, " %s -f [-] [filename]\n\n",p); + fprintf(stderr, " -L lanmgrpasswd LanManager cleartextpwd <= 14 chars\n"); + fprintf(stderr, " -N ntpasswd NT cleartextpwd <=128 chars (usually <=14)\n\n"); + fprintf(stderr, " with both options present the encrypted LanManager-Pwd is \n"); + fprintf(stderr, " printed first, followed by a ':' and the encrypted NT-Pwd.\n\n"); + fprintf(stderr, " The second usage behaves like %s -L pwd -N pwd\n\n",p); + fprintf(stderr, " The third usage reads the password from STDIN or a File. Printout\n"); + fprintf(stderr, " is the same as second.\n\n"); + fprintf(stderr, "anton@genua.de\n\n"); + exit(1); +} + + +/******************************************************************* +write a string in unicoode format +********************************************************************/ +int PutUniCode(char *dst,char *src) +{ + int ret = 0; + while (*src) { + dst[ret++] = src[0]; + dst[ret++] = 0; + src++; + } + dst[ret++]=0; + dst[ret++]=0; + return(ret-2); /* the way they do the md4 hash they don't represent + the last null. ie 'A' becomes just 0x41 0x00 - not + 0x41 0x00 0x00 0x00 */ +} + +/* + print binary buffer as hex-string +*/ +void printlanhash(char *tmp) { + + int i; + unsigned char c; + char outbuffer[33]; + + + /* build string from binary hash */ + for(i=0;i<16;i++) { + c=tmp[i]; + sprintf(outbuffer+2*i,"%x",(c>>4) & 0x0f); + sprintf(outbuffer+2*i+1,"%x",c & 0x0f); + } + + /* convert to uppercase */ + for(i=0;i<32;i++) + outbuffer[i] = toupper(outbuffer[i]); + outbuffer[32]='\0'; + + /* print out hex-string */ + printf("%s",outbuffer); +} + + diff --git a/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.h b/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.h new file mode 100644 index 0000000000..9a020b8d28 --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/mkntpwd.h @@ -0,0 +1,17 @@ +#include <memory.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +typedef short int16; +typedef int int32; +typedef unsigned short uint16; +typedef unsigned int uint32; +typedef unsigned char uchar; + +#define MAX_STRING 255 +#define MAX_WORD 128 +#define LMPASSWDLEN 14 +#define NTPASSWDLEN 128 +#define FILENAMEBUFFER 128 diff --git a/examples/LDAP/smbldap-tools/mkntpwd/smbdes.c b/examples/LDAP/smbldap-tools/mkntpwd/smbdes.c new file mode 100644 index 0000000000..e4f8280f9b --- /dev/null +++ b/examples/LDAP/smbldap-tools/mkntpwd/smbdes.c @@ -0,0 +1,337 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + + a partial implementation of DES designed for use in the + SMB authentication protocol + + Copyright (C) Andrew Tridgell 1997 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* NOTES: + + This code makes no attempt to be fast! In fact, it is a very + slow implementation + + This code is NOT a complete DES implementation. It implements only + the minimum necessary for SMB authentication, as used by all SMB + products (including every copy of Microsoft Windows95 ever sold) + + In particular, it can only do a unchained forward DES pass. This + means it is not possible to use this code for encryption/decryption + of data, instead it is only useful as a "hash" algorithm. + + There is no entry point into this code that allows normal DES operation. + + I believe this means that this code does not come under ITAR + regulations but this is NOT a legal opinion. If you are concerned + about the applicability of ITAR regulations to this code then you + should confirm it for yourself (and maybe let me know if you come + up with a different answer to the one above) +*/ + + + +static int perm1[56] = {57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4}; + +static int perm2[48] = {14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32}; + +static int perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7}; + +static int perm4[48] = { 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1}; + +static int perm5[32] = { 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25}; + + +static int perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25}; + + +static int sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}; + +static int sbox[8][4][16] = { + {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, + {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, + {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, + {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, + + {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, + {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, + {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, + {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, + + {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, + {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, + {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, + {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, + + {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, + {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, + {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, + {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, + + {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, + {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, + {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, + {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, + + {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, + {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, + {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, + {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, + + {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, + {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, + {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, + {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, + + {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, + {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, + {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, + {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}}; + +static void permute(char *out, char *in, int *p, int n) +{ + int i; + for (i=0;i<n;i++) + out[i] = in[p[i]-1]; +} + +static void lshift(char *d, int count, int n) +{ + char out[64]; + int i; + for (i=0;i<n;i++) + out[i] = d[(i+count)%n]; + for (i=0;i<n;i++) + d[i] = out[i]; +} + +static void concat(char *out, char *in1, char *in2, int l1, int l2) +{ + while (l1--) + *out++ = *in1++; + while (l2--) + *out++ = *in2++; +} + +static void xor(char *out, char *in1, char *in2, int n) +{ + int i; + for (i=0;i<n;i++) + out[i] = in1[i] ^ in2[i]; +} + +static void dohash(char *out, char *in, char *key) +{ + int i, j, k; + char pk1[56]; + char c[28]; + char d[28]; + char cd[56]; + char ki[16][48]; + char pd1[64]; + char l[32], r[32]; + char rl[64]; + + permute(pk1, key, perm1, 56); + + for (i=0;i<28;i++) + c[i] = pk1[i]; + for (i=0;i<28;i++) + d[i] = pk1[i+28]; + + for (i=0;i<16;i++) { + lshift(c, sc[i], 28); + lshift(d, sc[i], 28); + + concat(cd, c, d, 28, 28); + permute(ki[i], cd, perm2, 48); + } + + permute(pd1, in, perm3, 64); + + for (j=0;j<32;j++) { + l[j] = pd1[j]; + r[j] = pd1[j+32]; + } + + for (i=0;i<16;i++) { + char er[48]; + char erk[48]; + char b[8][6]; + char cb[32]; + char pcb[32]; + char r2[32]; + + permute(er, r, perm4, 48); + + xor(erk, er, ki[i], 48); + + for (j=0;j<8;j++) + for (k=0;k<6;k++) + b[j][k] = erk[j*6 + k]; + + for (j=0;j<8;j++) { + int m, n; + m = (b[j][0]<<1) | b[j][5]; + + n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4]; + + for (k=0;k<4;k++) + b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0; + } + + for (j=0;j<8;j++) + for (k=0;k<4;k++) + cb[j*4+k] = b[j][k]; + permute(pcb, cb, perm5, 32); + + xor(r2, l, pcb, 32); + + for (j=0;j<32;j++) + l[j] = r[j]; + + for (j=0;j<32;j++) + r[j] = r2[j]; + } + + concat(rl, r, l, 32, 32); + + permute(out, rl, perm6, 64); +} + +static void str_to_key(unsigned char *str,unsigned char *key) +{ + int i; + + key[0] = str[0]>>1; + key[1] = ((str[0]&0x01)<<6) | (str[1]>>2); + key[2] = ((str[1]&0x03)<<5) | (str[2]>>3); + key[3] = ((str[2]&0x07)<<4) | (str[3]>>4); + key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5); + key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6); + key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7); + key[7] = str[6]&0x7F; + for (i=0;i<8;i++) { + key[i] = (key[i]<<1); + } +} + + +static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key) +{ + int i; + char outb[64]; + char inb[64]; + char keyb[64]; + unsigned char key2[8]; + + str_to_key(key, key2); + + for (i=0;i<64;i++) { + inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0; + keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0; + outb[i] = 0; + } + + dohash(outb, inb, keyb); + + for (i=0;i<8;i++) { + out[i] = 0; + } + + for (i=0;i<64;i++) { + if (outb[i]) + out[i/8] |= (1<<(7-(i%8))); + } +} + +void E_P16(unsigned char *p14,unsigned char *p16) +{ + unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; + smbhash(p16, sp8, p14); + smbhash(p16+8, sp8, p14+7); +} + +void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) +{ + smbhash(p24, c8, p21); + smbhash(p24+8, c8, p21+7); + smbhash(p24+16, c8, p21+14); +} + +void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key) +{ + unsigned char buf[8]; + + smbhash(buf, in, key); + smbhash(out, buf, key+9); +} + +void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key) +{ + unsigned char buf[8]; + static unsigned char key2[8]; + + smbhash(buf, in, key); + key2[0] = key[7]; + smbhash(out, buf, key2); +} + diff --git a/examples/LDAP/smbldap-tools/smbldap-groupadd.pl b/examples/LDAP/smbldap-tools/smbldap-groupadd.pl new file mode 100755 index 0000000000..ee804b34d3 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-groupadd.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-groupadd : group (posix) add + +use strict; +use smbldap_tools; + +use Getopt::Std; +my %Options; + +my $ok = getopts('og:?', \%Options); +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-go?] groupname\n"; + print " -g gid\n"; + print " -o gid is not unique\n"; + print " -? show this help message\n"; + exit (1); +} + +my $_groupName = $ARGV[0]; + +if (defined(get_group_dn($_groupName))) { + print "$0: group $_groupName exists\n"; + exit (6); +} + +my $_groupGidNumber = $Options{'g'}; + +if (!group_add($_groupName, $_groupGidNumber, $Options{'o'})) { + print "$0: error adding group $_groupName\n"; + exit (6); +} + +exit(0); + +######################################## + +=head1 NAME + + smbldap-groupadd.pl - Create a new group + +=head1 SYNOPSIS + + smbldap-groupadd.pl [-g gid [-o]] group + +=head1 DESCRIPTION + The smbldap-groupadd.pl command creates a new group account using + the values specified on the command line and the default values + from the system. The new group will be entered into the system + files as needed. The options which apply to the groupadd command are + + -g gid The numerical value of the group's ID. This value must be + unique, unless the -o option is used. The value must be non- + negative. The default is to use the smallest ID value greater + than 1000 and greater than every other group. + +=head1 SEE ALSO + + groupadd(1) + +=cut + +#' + diff --git a/examples/LDAP/smbldap-tools/smbldap-groupdel.pl b/examples/LDAP/smbldap-tools/smbldap-groupdel.pl new file mode 100755 index 0000000000..3d072585b2 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-groupdel.pl @@ -0,0 +1,93 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-groupdel : group (posix) deletion + +use strict; +use smbldap_tools; +use smbldap_conf; + +##################### + +use Getopt::Std; +my %Options; + +my $ok = getopts('?', \%Options); +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 groupname\n"; + print " -? show this help message\n"; + exit (1); +} + +my $_groupName = $ARGV[0]; + +my $dn_line; +if (!defined($dn_line = get_group_dn($_groupName))) { + print "$0: group $_groupName doesn't exist\n"; + exit (6); +} + +my $dn = get_dn_from_line($dn_line); + +my $rc = system "$ldapdelete $dn >/dev/null"; +die "$0: error while deleting group $_groupName\n" + unless ($rc == 0); + +my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd restart > /dev/null 2>&1"; +} + +#if (defined($dn_line = get_group_dn($_groupName))) { +# print "$0: failed to delete group\n"; +# exit (7); +#} + + +exit (0); + +############################################################ + +=head1 NAME + + smbldap-groupdel.pl - Delete a group + +=head1 SYNOPSIS + + smbldap-groupdel.pl group + +=head1 DESCRIPTION + + The smbldap-groupdel.pl command modifies the system account files, + deleting all entries that refer to group. The named group must exist. + + You must manually check all filesystems to insure that no files remain + with the named group as the file group ID. + +=head1 SEE ALSO + + groupdel(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-groupmod.pl b/examples/LDAP/smbldap-tools/smbldap-groupmod.pl new file mode 100755 index 0000000000..f9b42f95b4 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-groupmod.pl @@ -0,0 +1,211 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-groupmod : group (posix) modification + + +use strict; +use smbldap_tools; +use smbldap_conf; + + +##################### + +use Getopt::Std; +my %Options; + +my $ok = getopts('og:n:m:x:?', \%Options); +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-g gid [-o]] [-n name] [-m members(,)] [-x members (,)] groupname\n"; + print " -g new gid\n"; + print " -o gid is not unique\n"; + print " -n new group name\n"; + print " -m add members (comma delimited)\n"; + print " -x delete members (comma delimted)\n"; + print " -? show this help message\n"; + exit (1); +} + +my $groupName = $ARGV[0]; + +if (!defined(get_group_dn($groupName))) { + print "$0: group $groupName doesn't exist\n"; + exit (6); +} + +my $newname = $Options{'n'}; + +my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd restart > /dev/null 2>&1"; +} + +my $gid = getgrnam($groupName); + +my $tmp; +if (defined($tmp = $Options{'g'}) and $tmp =~ /\d+/) { + if (!defined($Options{'o'})) { + if (defined(getgrgid($tmp))) { + print "$0: gid $tmp exists\n"; + exit (6); + } + } + if (!($gid == $tmp)) { + my $tmpldif = +"dn: cn=$groupName,$groupsdn +changetype: modify +replace: gidNumber +gidNumber: $tmp + +"; + die "$0: error while modifying group $groupName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + + } +} + +if (defined($newname)) { + my $FILE="|$ldapmodrdn >/dev/null"; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +cn=$groupName,$groupsdn +cn=$newname + +EOF + ; + close FILE; + die "$0: error while modifying group $groupName\n" if ($?); + + my $tmpldif = +"dn: cn=$newname,$groupsdn +changetype: modify +delete: cn +- +add: cn +cn: $newname + +"; + die "$0: error while modifying group $groupName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + +} + +# Add members +if (defined($Options{'m'})) { + my $members = $Options{'m'}; + my @members = split( /,/, $members ); + my $member; + foreach $member ( @members ) { + my $tmpldif = +"dn: cn=$groupName,$groupsdn +changetype: modify +add: memberUid +memberUid: $member + +"; + die "$0: error while modifying group $groupName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + } +} + +# Delete members +if (defined($Options{'x'})) { + my $members = $Options{'x'}; + my @members = split( /,/, $members ); + my $member; + foreach $member ( @members ) { + my $tmpldif = +"dn: cn=$groupName,$groupsdn +changetype: modify +delete: memberUid +memberUid: $member + +"; + die "$0: error while modifying group $groupName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + } +} + +$nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd restart > /dev/null 2>&1"; +} + +exit (0); + +############################################################ + +=head1 NAME + + smbldap-groupmod.pl - Modify a group + +=head1 SYNOPSIS + + smbldap-groupmod.pl [-g gid [-o]] [-n group_name ] group + +=head1 DESCRIPTION + + The smbldap-groupmod.pl command modifies the system account files to + reflect the changes that are specified on the command line. + The options which apply to the smbldap-groupmod command are + + -g gid The numerical value of the group's ID. This value must be + unique, unless the -o option is used. The value must be non- + negative. Any files which the old group ID is the file + group ID must have the file group ID changed manually. + + -n group_name + The name of the group will be changed from group to group_name. + + -m members + The members to be added to the group in comma-delimeted form. + + -x members + The members to be removed from the group in comma-delimted form. + +=head1 EXAMPLES + + smbldap-groupmod.pl -g 253 development + This will change the GID of the 'development' group to '253'. + + smbldap-groupmod.pl -n Idiots Managers + This will change the name of the 'Managers' group to 'Idiots'. + + smbldap-groupmod.pl -m "jdoe,jsmith" "Domain Admins" + This will add 'jdoe' and 'jsmith' to the 'Domain Admins' group. + + smbldap-groupmod.pl -x "jdoe,jsmith" "Domain Admins" + This will remove 'jdoe' and 'jsmith' from the 'Domain Admins' group. + +=head1 SEE ALSO + + groupmod(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-groupshow.pl b/examples/LDAP/smbldap-tools/smbldap-groupshow.pl new file mode 100755 index 0000000000..bc5b4d98fb --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-groupshow.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-groupshow : user (posix,shadow,samba) display +# +# History : +# . originally by David Le Corfec <david.le-corfec@IDEALX.com> + +use strict; +use smbldap_tools; + +use Getopt::Std; +my %Options; + +my $ok = getopts('?', \%Options); + +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-?] group\n"; + print " -? show this help message\n"; + exit (1); +} + +# Read only first @ARGV +my $group = $ARGV[0]; + +my $lines = read_group($group); +if (!defined($lines)) { + print "$0: group $group doesn't exist\n"; + exit (1); +} + +print "$lines\n"; + +exit(0); + +############################################################ + +=head1 NAME + + smbldap-groupshow.pl - Display group informations + +=head1 SYNOPSIS + + smbldap-groupshow.pl groupname + +=head1 DESCRIPTION + + The smbldap-groupshow.pl command displays informations + associated with the given group. + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-migrate-accounts.pl b/examples/LDAP/smbldap-tools/smbldap-migrate-accounts.pl new file mode 100755 index 0000000000..b1780dec61 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-migrate-accounts.pl @@ -0,0 +1,234 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-migrate-accounts : add NT sam entries from pwdump +# to ldap + +use strict; +use Getopt::Std; +use smbldap_tools; +use smbldap_conf; + +# smbldap-migrate.pl (-? for help) +# +# Read pwdump entries on stdin, and add them to the ldap server. +# Output uncreated/unmodified entries (see parameters -C -U) +# in pwdump format to stdout. +# Errors, debug and stats are output to stderr. + +sub modify_account +{ + my ($login, $basedn, $lmpwd, $ntpwd, $gecos, $homedir) = @_; + + my $tmpldif = +"dn: uid=$login,$basedn +changetype: modify +lmpassword: $lmpwd +ntpassword: $ntpwd +gecos: $gecos +smbHome: $homedir + +"; + + die "$0: error while modifying user $login\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; +} + +##################### + + +my %Options; + +my $ok = getopts('awA:CUW:?', \%Options); + +if ( (!$ok) || ($Options{'?'}) ) { + print "Usage: $0 [-awAWCU?]\n"; + print " -a process only people, ignore computers\n"; + print " -w process only computers, ignore persons\n"; + print " -A <opts> option string passed verbatim to smbldap-useradd for persons\n"; + print " -W <opts> option string passed verbatim to smbldap-useradd for computers\n"; + print " -C if entry not found, don't create it and log it to stdout (default: create it)\n"; + print " -U if entry found, don't update it and log it to stdout (default: update it)\n"; + print " -? show this help message\n"; + exit (1); +} + +my %processed = ( 'user' => 0, 'machine' => 0); +my %created = ( 'user' => 0, 'machine' => 0); +my %updated = ( 'user' => 0, 'machine' => 0); +my %logged = ( 'user' => 0, 'machine' => 0); +my %errors = ( 'user' => 0, 'machine' => 0); +my %existing = ( 'user' => 0, 'machine' => 0); +my $specialskipped = 0; + +while (<>) +{ + my ($login, $rid, $lmpwd, $ntpwd, $gecos, $homedir, $b) = split(/:/, $_); + my $usertype; + my $userbasedn; + + my $entry_type = 'user'; + + if ($login =~ m/.*\$$/ ) { # computer + $processed{'machine'}++; + $entry_type = 'machine'; + if (defined($Options{'a'})) { + print STDERR "ignoring $login\n"; + next; + } + + $usertype = "-w $Options{'W'}"; + $userbasedn = $computersdn; + } + else { # people + $processed{'user'}++; + if (defined($Options{'w'})) { + print STDERR "ignoring $login\n"; + next; + } + if ($rid < 1000) { + $specialskipped++; + print STDERR "$login seems to be a special Win account (rid=$rid), skipping\n"; + next; + } + + $usertype = "-a $Options{'A'}"; + $userbasedn = $usersdn; + } + + # normalize homedir +# uncomment to replace configured share with share from pwdump +# if ($homedir eq "") { + $homedir = $_userSmbHome; +# } + + # normalize gecos + if (!($gecos eq "")) { + $gecos =~ tr/ÁÀÂÄáàâäÇçÉÈÊËÆéèêëæÍÌÏÎíìîÏÑñÓÒÔÖóòôöÚÙÜÛúùüûÝýÿ/AAAAaaaaCcEEEEEeeeeeIIIIiiiiNnOOOOooooUUUUuuuuYyy/; + } else { + $gecos = $_userGecos; + } + + my $user_exists = is_samba_user($login); + + if (!$user_exists) { + if (!defined($Options{'C'})) { + # uid doesn't exist and we want to create it + my $addcmd = "/usr/local/sbin/smbldap-useradd.pl $usertype $login > /dev/null"; + print STDERR "$addcmd\n"; + my $r = system "$addcmd"; + if ($r != 0) { + print STDERR "error adding $login, skipping\n"; + next; + } + # lem modif... a retirer si pb + if ($entry_type eq "user") + { + modify_account($login, $userbasedn, $lmpwd, $ntpwd, $gecos, $homedir); + } + + $created{$entry_type}++; + } + else { # uid doesn't exist and no create => log + print "$_"; + $logged{$entry_type}++; + } + } + else { # account exists + $existing{$entry_type}++; + if (!defined($Options{'U'})) { # exists and modify + modify_account($login, $userbasedn, $lmpwd, $ntpwd, $gecos, $homedir); + $updated{$entry_type}++; + } + else { # exists and log + print "$_"; + $logged{$entry_type}++; + } + } +} + +my $sum; + +$sum = $processed{'user'} + $processed{'machine'}; +print STDERR "processed: all=$sum user=$processed{'user'} machine=$processed{'machine'}\n"; + +$sum = $existing{'user'} + $existing{'machine'}; +print STDERR "existing: all=$sum user=$existing{'user'} machine=$existing{'machine'}\n"; + +$sum = $created{'user'} + $created{'machine'}; +print STDERR "created: all=$sum user=$created{'user'} machine=$created{'machine'}\n"; + +$sum = $updated{'user'} + $updated{'machine'}; +print STDERR "updated: all=$sum user=$updated{'user'} machine=$updated{'machine'}\n"; + +$sum = $logged{'user'} + $logged{'machine'}; +print STDERR "logged: all=$sum user=$logged{'user'} machine=$logged{'machine'}\n"; + +print STDERR "special users skipped: $specialskipped\n"; + + +######################################## + +=head1 NAME + + smbldap-migrate.pl - Migrate NT accounts to LDAP + +=head1 SYNOPSIS + + smbldap-migrate.pl [-a] [-w] [-A opts] [-W opts] [-C] [-U] [-?] + +=head1 DESCRIPTION + + This command reads from stdin account entries as created by pwdump, + a tool to dump an user database on NT. + Depending of the options, some account entries may be output on + stdout. All errors and informations are sent to stderr. + + -a process only people, ignore computers + + -w process only computers, ignore persons + + -A opts + a string containing arguments to pass verbatim to + smbldap-useradd when adding users, eg "-m -x". + You don't have to specify -a in this string. + + -W opts + a string containing arguments to pass verbatim to + smbldap-useradd when adding computers, eg "-m -x". + You don't have to specify -w in this string. + + -C if NT account not found in LDAP, don't create it and log it to stdout + (default: create it) + + -U if NT account found in LDAP, don't update it and log it to stdout + (default: update it) + + -? show the help message + +=cut + +#' + +# The End + diff --git a/examples/LDAP/smbldap-tools/smbldap-migrate-groups.pl b/examples/LDAP/smbldap-tools/smbldap-migrate-groups.pl new file mode 100644 index 0000000000..0d3dd07d50 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-migrate-groups.pl @@ -0,0 +1,225 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-migrate-groups : to parse a Windows +# group dump and populate Unix groups +# Reads group dump on stdin + + +use strict; +use smbldap_tools; +use smbldap_conf; +use Getopt::Std; + + + +sub process_rec_group +{ + my ($group, $mb) = @_; + my @members; + + if (!(@members = group_get_members($group))) { + return 0; + } + + foreach my $m (@members) { + if ( !($m =~ m/^\*/) ) { + push @{$mb}, $m; + } else { + my $gname = $m; + $gname =~ s/^.//; + if (!process_rec_group($gname, $mb)) { + print "recursive group not added : $gname\n"; + } + } + } +} + + +# given a group dn and a list of members, update the group +sub modify_group +{ + my ($group, $dn_line, @members, $recgroup) = @_; + my $m; + my @new_mb; + + foreach $m (@members) { + if ( ($m =~ m/^\*/) ) { + my $gname = $m; + $gname =~ s/^.//; + if (!$recgroup) { + print "recursive group not added : $gname\n"; + } else { + if (!process_rec_group($gname, \@new_mb)) { + print "recursive group not added : $gname\n"; + } + } + } else { + push @new_mb, $m; + } + } + + # new_mb contains flat members from group dump + # now append them to existing members + push @new_mb, group_get_members($group); + # uniq them + my %saw; + @saw{@new_mb} = (); + @new_mb = keys %saw; + + my $nmb = $#new_mb + 1; + print STDERR "Group $group now has $nmb member(s)\n"; + + my $mbs; + foreach $m (@new_mb) { + $mbs .= "memberUid: $m\n"; + } + + my $mods="$dn_line +changetype: modify +replace: memberUid +$mbs +"; + + #print "$mods\n"; + my $tmpldif = +"$mods +"; + + die "$0: error while modifying group $group\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; +} + +sub display_group +{ + my ($group, @members) = @_; + + print "Group name $group\n"; + print "Members\n"; + my $m; + my $i = 0; + foreach $m (@members) { + print "$m "; + if ($i % 5 == 0) { + print "\n"; + } + $i++; + } +} + +sub process_group +{ + my ($group, @members, $nocreate, $noupdate, $recgroup) = @_; + + my $dn_line; + if (!defined($dn_line = get_group_dn($group))) { + # group not found, create it ? + if (!$nocreate) { + system "/usr/local/sbin/smbldap-groupadd.pl \"$group\"; sleep 5"; + if (!defined($dn_line = get_group_dn($group))) { + return 1; + } + modify_group($group, $dn_line, @members, $recgroup); + } else { + # don't create + print "not created:\n"; + display_group($group, @members); + } + } else { + # group found, update it ? + if (!$noupdate) { + modify_group($group, $dn_line, @members, $recgroup); + } else { + # don't update + print "not updated:\n"; + display_group($group, @members); + } + } +} + +################################################### + +my %Options; + +my $ok = getopts('CUr?', \%Options); +if ( (!$ok) || ($Options{'?'}) ) { + print "Usage: $0 [-CUr?] < group_dump\n"; + print " -C don't create group if it doesn't exist\n"; + print " -U don't update group if it exists\n"; + print " -r recursively process groups\n"; + exit(1); +} + +my $group_name; +my $group_desc; +my $has_members = 0; +my @members = (); + +while (<>) +{ + my $line = $_; + chomp($line); + next if ( $line =~ m/^\s*$/ ); + + if ($group_name eq "") { + if ( $line =~ m/^Group name\s+(.+).$/ ) { + $group_name = $1; + next; + } + } + if ($group_desc eq "") { + if ( $line =~ m/^Comment\s+(.*)$/ ) { + $group_desc = $1; + next; + } + } + next if ( $line =~ m/^-+.$/ ); + if (!$has_members) { + if ( $line =~ m/^Members/ ) { + $has_members = 1; + next; + } + } else { + if ( $line =~ m/^The command completed successfully/ ) { + last; + } else { + push(@members, split(/\s+/, $line)); + next; + } + } + + #print; +} + +if ( $#members > -1) { + process_group($group_name, @members, $Options{'C'}, $Options{'U'}, $Options{'r'}); +} + +#print "gn=$group_name\n"; +#print "gd=$group_desc\n"; +#my $m; +#foreach $m (@members) +#{ +# print "$m "; +#} +#print "\n"; diff --git a/examples/LDAP/smbldap-tools/smbldap-passwd.pl b/examples/LDAP/smbldap-tools/smbldap-passwd.pl new file mode 100755 index 0000000000..ef7687a49e --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-passwd.pl @@ -0,0 +1,215 @@ +#!/usr/bin/perl + +# LDAP to unix password sync script for samba +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose : +# . ldap-unix passwd sync for SAMBA-2.2.2 + LDAP +# . may also replace /bin/passwd + +use strict; +use smbldap_tools; +use smbldap_conf; + +my $user; +my $oldpass; +my $ret; + +my $arg; + +foreach $arg (@ARGV) { + if ($< != 0) { + die "Only root can specify parameters\n"; + } else { + if ( ($arg eq '-?') || ($arg eq '--help') ) { + print "Usage: $0 [username]\n"; + print " -?, --help show this help message\n"; + exit (6); + } elsif (substr($arg,0) ne '-') { + $user = $arg; + } + $oldpass = 1; + } +} + +if (!defined($user)) { + $user=$ENV{"USER"}; +} + +# test existence of user in LDAP +my $dn_line; +if (!defined($dn_line = get_user_dn($user))) { + print "$0: user $user doesn't exist\n"; + exit (10); +} + +my $dn = get_dn_from_line($dn_line); + +my $samba = is_samba_user($user); + +print "Changing password for $user\n"; + +# non-root user +if (!defined($oldpass)) { + # prompt for current password + system "stty -echo"; + print "(current) UNIX password: "; + chomp($oldpass=<STDIN>); + print "\n"; + system "stty echo"; + + if (!is_user_valid($user, $dn, $oldpass)) { + print "Authentication failure\n"; + exit (10); + } +} + +# prompt for new password + +my $pass; +my $pass2; + +system "stty -echo"; +print "New password : "; +chomp($pass=<STDIN>); +print "\n"; +system "stty echo"; + +system "stty -echo"; +print "Retype new password : "; +chomp($pass2=<STDIN>); +print "\n"; +system "stty echo"; + +if ($pass ne $pass2) { + print "New passwords don't match!\n"; + exit (10); +} + +# only modify smb passwords if smb user +if ($samba == 1) { + if (!$with_smbpasswd) { +# generate LanManager and NT clear text passwords + if ($mk_ntpasswd eq '') { + print "Either set \$with_smbpasswd = 1 or specify \$mk_ntpasswd\n"; + exit(1); + } + my $ntpwd = `$mk_ntpasswd '$pass'`; + chomp(my $lmpassword = substr($ntpwd, 0, index($ntpwd, ':'))); + chomp(my $ntpassword = substr($ntpwd, index($ntpwd, ':')+1)); + +# change nt/lm passwords + my $tmpldif = +"$dn_line +changetype: modify +replace: lmpassword +lmpassword: $lmpassword +- +changetype: modify +replace: ntpassword +ntpassword: $ntpassword +- + +"; + die "$0: error while modifying password for $user\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + } + else { + if ($< != 0) { + my $FILE="|$smbpasswd -s >/dev/null"; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +'$oldpass' +'$pass' +'$pass' +EOF + ; + close FILE; + } else { + my $FILE="|$smbpasswd $user -s >/dev/null"; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +'$pass' +'$pass' +EOF + ; + close FILE; + } + } +} +# change unix password +$ret = system "$ldappasswd $dn -s '$pass' > /dev/null"; +if ($ret == 0) { + print "all authentication tokens updated successfully\n"; +} else { + return $ret; +} + +exit 0; + + +# - The End + +=head1 NAME + +smbldap-passwd.pl - change user password + +=head1 SYNOPSIS + + smbldap-passwd.pl [name] + +=head1 DESCRIPTION + + smbldap-passwd.pl changes passwords for user accounts. A normal user + may only change the password for their own account, the super user may + change the password for any account. + + Password Changes + The user is first prompted for their old password, if one is present. + This password is then tested against the stored password by binding + to the server. The user has only one chance to enter the correct pass- + word. The super user is permitted to bypass this step so that forgot- + ten passwords may be changed. + + The user is then prompted for a replacement password. As a general + guideline, passwords should consist of 6 to 8 characters including + one or more from each of following sets: + + Lower case alphabetics + + Upper case alphabetics + + Digits 0 thru 9 + + Punctuation marks + + passwd will prompt again and compare the second entry against the first. + Both entries are require to match in order for the password to be + changed. + +=head1 SEE ALSO + + passwd(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-populate.pl b/examples/LDAP/smbldap-tools/smbldap-populate.pl new file mode 100755 index 0000000000..5be9ca4262 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-populate.pl @@ -0,0 +1,294 @@ +#!/usr/bin/perl + +# Populate a LDAP base for Samba-LDAP usage +# +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose : +# . Create an initial LDAP database suitable for Samba 2.2 +# . For lazy people, replace ldapadd (with only an ldif parameter) + +use strict; +use smbldap_tools; +use smbldap_conf; + +use Getopt::Std; + +use vars qw(%oc); + +# objectclass of the suffix +%oc = ( + "ou" => "organizationalUnit", + "o" => "organization", + "dc" => "dcObject", +); + + +my %Options; + +my $ok = getopts('a:b:?', \%Options); +if ( (!$ok) || ($Options{'?'}) ) { + print "Usage: $0 [-ab?] [ldif]\n"; + print " -a administrator login name (default: Administrator)\n"; + print " -b guest login name (default: nobody)\n"; + print " -? show this help message\n"; + print " ldif file to add to ldap (default: suffix, Groups,"; + print " Users, Computers and builtin users )\n"; + exit (1); +} + +my $_ldifName; + +if (@ARGV >= 1) { + $_ldifName = $ARGV[0]; +} + +my $adminName = $Options{'a'}; +if (!defined($adminName)) { + $adminName = "Administrator"; +} + +my $guestName = $Options{'b'}; +if (!defined($guestName)) { + $guestName = "nobody"; +} + +if (!defined($_ldifName)) { + my $attr; + my $val; + my $objcl; + + if ($suffix =~ m/([^=]+)=([^,]+)/) { + $attr = $1; + $val = $2; + $objcl = $oc{$attr} if (exists $oc{$attr}); + if (!defined($objcl)) { + $objcl = "myhardcodedobjectclass"; + } + } else { + die "can't extract first attr and value from suffix $suffix"; + } + #print "$attr=$val\n"; + + #my $FILE="|cat"; + my $FILE="|$ldapadd -c"; + open (FILE, $FILE) || die "$!\n"; + + print FILE <<EOF; +dn: $suffix +objectClass: $objcl +$attr: $val + +dn: $usersdn +objectClass: organizationalUnit +ou: $usersou + +dn: $groupsdn +objectClass: organizationalUnit +ou: $groupsou + +dn: $computersdn +objectClass: organizationalUnit +ou: $computersou + +dn: uid=$adminName,$usersdn +cn: $adminName +objectClass: sambaAccount +objectClass: posixAccount +gidNumber: 512 +uid: $adminName +uidNumber: 998 +homeDirectory: $_userHomePrefix +pwdLastSet: 0 +logonTime: 0 +logoffTime: 2147483647 +kickoffTime: 2147483647 +pwdCanChange: 0 +pwdMustChange: 2147483647 +smbHome: $_userSmbHome +homeDrive: $_userHomeDrive +profilePath: $_userProfile +rid: 500 +primaryGroupID: 512 +lmPassword: XXX +ntPassword: XXX +acctFlags: [U ] +loginShell: /bin/false +gecos: Netbios Domain Administrator + +dn: uid=$guestName,$usersdn +cn: $guestName +objectClass: sambaAccount +objectClass: posixAccount +gidNumber: 514 +uid: $guestName +uidNumber: 999 +homeDirectory: /dev/null +pwdLastSet: 0 +logonTime: 0 +logoffTime: 2147483647 +kickoffTime: 2147483647 +pwdCanChange: 0 +pwdMustChange: 2147483647 +smbHome: $_userSmbHome +homeDrive: $_userHomeDrive +profilePath: $_userProfile +rid: 501 +primaryGroupID: 514 +lmPassword: NO PASSWORDXXXXXXXXXXXXXXXXXXXXX +ntPassword: NO PASSWORDXXXXXXXXXXXXXXXXXXXXX +acctFlags: [NU ] +loginShell: /bin/false + +dn: cn=Domain Admins,$groupsdn +objectClass: posixGroup +gidNumber: 512 +cn: Domain Admins +memberUid: $adminName +description: Netbios Domain Administrators (need smb.conf configuration) + +dn: cn=Domain Users,$groupsdn +objectClass: posixGroup +gidNumber: 513 +cn: Domain Users +description: Netbios Domain Users (not implemented yet) + +dn: cn=Domain Guests,$groupsdn +objectClass: posixGroup +gidNumber: 514 +cn: Domain Guests +description: Netbios Domain Guests Users (not implemented yet) + +dn: cn=Administrators,$groupsdn +objectClass: posixGroup +gidNumber: 544 +cn: Administrators +description: Netbios Domain Members can fully administer the computer/domain (not implemented yet) + +dn: cn=Users,$groupsdn +objectClass: posixGroup +gidNumber: 545 +cn: Users +description: Netbios Domain Ordinary users (not implemented yet) + +dn: cn=Guests,$groupsdn +objectClass: posixGroup +gidNumber: 546 +cn: Guests +memberUid: $guestName +description: Netbios Domain Users granted guest access to the computer/domain (not implemented yet) + + +dn: cn=Power Users,$groupsdn +objectClass: posixGroup +gidNumber: 547 +cn: Power Users +description: Netbios Domain Members can share directories and printers (not implemented yet) + +dn: cn=Account Operators,$groupsdn +objectClass: posixGroup +gidNumber: 548 +cn: Account Operators +description: Netbios Domain Users to manipulate users accounts (not implemented yet) + +dn: cn=Server Operators,$groupsdn +objectClass: posixGroup +gidNumber: 549 +cn: Server Operators +description: Netbios Domain Server Operators (need smb.conf configuration) + +dn: cn=Print Operators,$groupsdn +objectClass: posixGroup +gidNumber: 550 +cn: Print Operators +description: Netbios Domain Print Operators (need smb.conf configuration) + +dn: cn=Backup Operators,$groupsdn +objectClass: posixGroup +gidNumber: 551 +cn: Backup Operators +description: Netbios Domain Members can bypass file security to back up files (not implemented yet) + +dn: cn=Replicator,$groupsdn +objectClass: posixGroup +gidNumber: 552 +cn: Replicator +description: Netbios Domain Supports file replication in a domain (not implemented yet) + +dn: cn=Domain Computers,$groupsdn +objectClass: posixGroup +gidNumber: 553 +cn: Domain Computers +description: Netbios Domain Computers accounts + +EOF + close FILE; + exit($?) + +} else { + exec "$ldapadd < $_ldifName"; +} + +exit(0); + + +######################################## + +=head1 NAME + + smbldap-populate.pl - Populate your LDAP database + +=head1 SYNOPSIS + + smbldap-populate.pl [ldif-file] + +=head1 DESCRIPTION + + The smbldap-populate.pl command helps to populate an LDAP server + by adding the necessary entries : base suffix (doesn't abort + if already there), organizational units for users, groups and + computers, builtin users : Administrator and guest, builtin + groups (though posixAccount only, no SambaTNG support). + + -a name Your local administrator login name (default: Administrator) + -b name Your local guest login name (default: nobody) + + If you give an extra parameter, it is assumed to be the ldif + file to use instead of the builtin one. Options -a and -b + will be ignored. This usage mode makes the command behave + like ldapadd(1) with extra parameters taken from the smbldap-tools + config (smbldap_conf.pm). + +=head1 FILES + + /usr/lib/perl5/site-perl/smbldap_conf.pm : Global parameters. + +=head1 SEE ALSO + + smp(1) + +=cut + +#' + + + +# - The End diff --git a/examples/LDAP/smbldap-tools/smbldap-tools.spec b/examples/LDAP/smbldap-tools/smbldap-tools.spec new file mode 100755 index 0000000000..7bb438cb32 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-tools.spec @@ -0,0 +1,169 @@ +# $Source: /data/src/mirror/cvs/samba/examples/LDAP/smbldap-tools/smbldap-tools.spec,v $ +%define version 0.7 +%define release 1 +%define name smbldap-tools +%define realname smbldap-tools + +Summary: User & Group administration tools for Samba-OpenLDAP +Name: %{name} +version: %{version} +Release: %{release} +Group: System Environment/Base +License: GPL + +Vendor: IDEALX S.A.S. +URL: http://samba.IDEALX.org/ +Packager: Olivier Lemaire <olivier.lemaire@IDEALX.com> +Source0: smbldap-groupadd.pl +Source1: smbldap-groupdel.pl +Source2: smbldap-groupmod.pl +Source3: smbldap-groupshow.pl +Source4: smbldap-passwd.pl +Source5: smbldap-useradd.pl +Source6: smbldap-userdel.pl +Source7: smbldap-usermod.pl +Source8: smbldap-usershow.pl +Source9: smbldap_conf.pm +Source10: smbldap_tools.pm +Source11: CONTRIBUTORS +Source12: COPYING +Source13: ChangeLog +Source14: FILES +Source15: README +Source16: TODO +Source17: mkntpwd.tar.gz +Source18: smbldap-populate.pl +Source19: smbldap-migrate-accounts.pl +Source20: smbldap-migrate-groups.pl +Source21: INFRA +BuildRoot: /%{_tmppath}/%{name} +Prefix: /usr/local +BuildRequires: perl >= 5.6 +Requires: perl >= 5.6, openldap, openldap-clients, samba + +%description +In settings with OpenLDAP and Samba-LDAP servers, this collection is +useful to add, modify and delete users and groups, and to change +Unix and Samba passwords. In those context they replace the system +tools to manage users, groups and passwords. + +%prep + +%setup -c -T + +%build +tar zxvf %{SOURCE17} +cd mkntpwd +make + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/%{prefix}/sbin +mkdir -p $RPM_BUILD_ROOT/%{prefix}/share +mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/doc +mkdir -p $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools + +cd mkntpwd ; make PREFIX=$RPM_BUILD_ROOT/%{prefix} install + +install -m 550 %{SOURCE0} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-groupadd.pl +install -m 550 %{SOURCE1} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-groupdel.pl +install -m 550 %{SOURCE2} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-groupmod.pl +install -m 555 %{SOURCE3} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-groupshow.pl +install -m 555 %{SOURCE4} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-passwd.pl +install -m 550 %{SOURCE5} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-useradd.pl +install -m 550 %{SOURCE6} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-userdel.pl +install -m 550 %{SOURCE7} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-usermod.pl +install -m 555 %{SOURCE8} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-usershow.pl +install -m 550 %{SOURCE18} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-populate.pl +install -m 751 %{SOURCE9} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap_conf.pm +install -m 555 %{SOURCE10} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap_tools.pm +install -m 550 %{SOURCE19} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-migrate-accounts.pl +install -m 550 %{SOURCE20} $RPM_BUILD_ROOT/%{prefix}/sbin/smbldap-migrate-groups.pl + +install -m 644 %{SOURCE11} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/CONTRIBUTORS +install -m 644 %{SOURCE12} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/COPYING +install -m 644 %{SOURCE13} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/ChangeLog +install -m 644 %{SOURCE14} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/FILES +install -m 644 %{SOURCE15} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/README +install -m 644 %{SOURCE16} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/TODO +install -m 644 %{SOURCE21} $RPM_BUILD_ROOT/%{prefix}/share/doc/smbldap-tools/INFRA + +%clean +rm -rf $RPM_BUILD_ROOT + +%post +ln -sf %{prefix}/sbin/smbldap_tools.pm /usr/lib/perl5/site_perl/smbldap_tools.pm +ln -sf %{prefix}/sbin/smbldap_conf.pm /usr/lib/perl5/site_perl/smbldap_conf.pm +chgrp 512 %{prefix}/sbin/smbldap-useradd.pl %{prefix}/sbin/smbldap_conf.pm || echo "An error occured while changing groups of smbldap-useradd.pl and smbldap_conf.pm in /usr/local/sbin. For proper operations, please ensure that they have the same posix group as the Samba domain administrator if there's a local Samba PDC." +perl -i -pe 's/_SLAVELDAP_/localhost/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_MASTERLDAP_/localhost/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_SUFFIX_/dc=IDEALX,dc=org/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_USERS_/Users/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_COMPUTERS_/Computers/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_GROUPS_/Groups/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_LOGINSHELL_/\/bin\/bash/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_USERHOMEPREFIX_/\/home\//' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_BINDDN_/cn=Manager,\$suffix/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_BINDPW_/secret/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_PDCNAME_/PDC-SRV/' %{prefix}/sbin/smbldap_conf.pm +perl -i -pe 's/_HOMEDRIVE_/D/' %{prefix}/sbin/smbldap_conf.pm + +# FIXME: links should not be removed on upgrade +#%postun +#if [ $1 = 0 ] ; then +# rm -f /usr/lib/perl5/site_perl/smbldap_tools.pm +# rm -f /usr/lib/perl5/site_perl/smbldap_conf.pm +#fi + +%files +%defattr(-,root,root) +%{prefix}/sbin/*.pl +%{prefix}/sbin/smbldap_tools.pm +%config %{prefix}/sbin/smbldap_conf.pm +%{prefix}/sbin/mkntpwd +%doc %{prefix}/share/doc/%{name}/TODO +%doc %{prefix}/share/doc/%{name}/README +%doc %{prefix}/share/doc/%{name}/CONTRIBUTORS +%doc %{prefix}/share/doc/%{name}/FILES +%doc %{prefix}/share/doc/%{name}/COPYING + + +%changelog +* Sat Jun 1 2002 Olivier Lemaire <olem@IDEALX.com> 0.7-1 +- some bugfixes about smbldap-populate +- bugfixed the smbpasswd call in smbldap-useradd +- cleaned up the smbldap_conf +- more documentation + +* Tue Apr 30 2002 Brad Langhorst <brad@langhorst.com> 0.6-2 +- changed requires samba-common to samba +- replaced /usr/local with %{prefix} to allow relocation + +* Tue Feb 5 2002 David Le Corfec <dlc@IDEALX.com> 0.6-1 +- v0.6 + +* Mon Feb 4 2002 David Le Corfec <dlc@IDEALX.com> 0.5-1 +- v0.5 + +* Mon Jan 14 2002 David Le Corfec <dlc@IDEALX.com> 0.3-4 +- internal changes +- should upgrade smoothly from now on + +* Mon Jan 14 2002 David Le Corfec <dlc@IDEALX.com> 0.2-1 +- added migration scripts + +* Fri Dec 28 2001 David Le Corfec <dlc@IDEALX.com> 0.1-5 +- numeric group for chmod + +* Thu Dec 27 2001 David Le Corfec <dlc@IDEALX.com> 0.1-4 +- misc bugfixes + +* Mon Dec 18 2001 David Le Corfec <dlc@IDEALX.com> 0.1-3 +- changed files attrs for domain admins to add users +- added smbldap-populate.pl + +* Fri Dec 14 2001 David Le Corfec <dlc@IDEALX.com> +- added mkntpwd + +* Wed Dec 12 2001 Olivier Lemaire <olivier.lemaire@IDEALX.com> +- Spec file was generated, and tested atomically. diff --git a/examples/LDAP/smbldap-tools/smbldap-useradd.pl b/examples/LDAP/smbldap-tools/smbldap-useradd.pl new file mode 100755 index 0000000000..508487af93 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-useradd.pl @@ -0,0 +1,460 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-useradd : user (posix,shadow,samba) add + +use strict; +use smbldap_tools; +use smbldap_conf; + + +##################### + +use Getopt::Std; +my %Options; + +my $ok = getopts('axnmwPG:u:g:d:s:c:k:A:B:C:D:E:F:H:?', \%Options); + +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-awmugdsckGPABCDEFH?] username\n"; + print " -a is a Windows User (otherwise, Posix stuff only)\n"; + print " -w is a Windows Workstation (otherwise, Posix stuff only)\n"; + print " -x creates rid and primaryGroupID in hex instead of decimal\n"; + print " -u uid\n"; + print " -g gid\n"; + print " -G supplementary comma-separated groups\n"; + print " -n do not create a group\n"; + print " -d home\n"; + print " -s shell\n"; + print " -c gecos\n"; + print " -m creates home directory and copies /etc/skel\n"; + print " -k skeleton dir (with -m)\n"; + print " -P ends by invoking smbldap-passwd.pl\n"; + print " -A can change password ? 0 if no, 1 if yes\n"; + print " -B must change password ? 0 if no, 1 if yes\n"; + print " -C smbHome (SMB home share, like '\\\\PDC-SRV\\homes')\n"; + print " -D homeDrive (letter associated with home share, like 'H:')\n"; + print " -E scriptPath (DOS script to execute on login)\n"; + print " -F profilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')\n"; + print " -H acctFlags (samba account control bits like '[NDHTUMWSLKI]')\n"; + print " -? show this help message\n"; + exit (1); +} + +# cause problems when dealing with getpwuid because of the +# negative ttl and ldap modification +my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd stop > /dev/null 2>&1"; +} + +# Read options +my $userUidNumber = $Options{'u'}; +if (!defined($userUidNumber)) { + # find first unused uid starting from $UID_START + while (defined(getpwuid($UID_START))) { + $UID_START++; + } + $userUidNumber = $UID_START; +} elsif (getpwuid($userUidNumber)) { die "Uid already exists.\n"; } + +if ($nscd_status == 0) { + system "/etc/init.d/nscd start > /dev/null 2>&1"; +} + + +# as rid we use 2 * uid + 1000 +my $userRid = 2 * $userUidNumber + 1000; +if (defined($Options{'x'})) { + $userRid= sprint("%x", $userRid); +} + +my $createGroup = 0; +my $userGidNumber = $Options{'g'}; +# gid not specified ? +if (!defined($userGidNumber)) { + # windows machine => $_defaultComputerGid + if (defined($Options{'w'})) { + $userGidNumber = $_defaultComputerGid; +# } elsif (!defined($Options{'n'})) { + # create new group (redhat style) + # find first unused gid starting from $GID_START +# while (defined(getgrgid($GID_START))) { +# $GID_START++; +# } +# $userGidNumber = $GID_START; + +# $createGroup = 1; + + } else { + # user will have gid = $_defaultUserGid + $userGidNumber = $_defaultUserGid; + } +} else { + my $gid; + if (($gid = parse_group($userGidNumber)) < 0) { + print "$0: unknown group $userGidNumber\n"; + exit (6); + } + $userGidNumber = $gid; +} + +# as grouprid we use 2 * gid + 1001 +my $userGroupRid = 2 * $userGidNumber + 1001; +if (defined($Options{'x'})) { + $userGroupRid = sprint("%x", $userGroupRid); +} +# Read only first @ARGV +my $userName = $ARGV[0]; + +# user must not exist in LDAP (should it be nss-wide ?) +my ($rc, $dn) = get_user_dn2($userName); +if ($rc and defined($dn)) { + print "$0: user $userName exists\n"; + exit (9); +} elsif (!$rc) { + print "$0: error in get_user_dn2\n"; + exit(10); +} + +my $userHomeDirectory; +my $tmp; +if (!defined($userHomeDirectory = $Options{'d'})) +{ + $userHomeDirectory = $_userHomePrefix.$userName; +} +$_userLoginShell = $tmp if (defined($tmp = $Options{'s'})); +$_userGecos = $tmp if (defined($tmp = $Options{'c'})); +$_skeletonDir = $tmp if (defined($tmp = $Options{'k'})); + +######################## + +# MACHINE ACCOUNT +if (defined($tmp = $Options{'w'})) { + + # add a trailing dollar if missing + if ($userName =~ /[^\$]$/s) { + $userName .= "\$"; + } + + #print "About to create machine $userName:\n"; + + if (!add_posix_machine ($userName, $userUidNumber, $userGidNumber)) { + die "$0: error while adding posix account\n"; + } + + if (!$with_smbpasswd) { + if (!add_samba_machine_mkntpwd($userName, $userUidNumber)) { + die "$0: error while adding samba account\n"; + } + } else { + if (!add_samba_machine($userName)) { + die "$0: error while adding samba account\n"; + } + + my $tmpldif = +"dn: uid=$userName,$computersdn +changetype: modify +acctFlags: [W ] + +"; + die "$0: error while modifying accountflags of $userName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + } + + exit 0; +} + +####################### + +# USER ACCOUNT + +# add posix account first + +my $tmpldif = +"dn: uid=$userName,$usersdn +objectclass: top +objectclass: account +objectclass: posixAccount +cn: $userName +uid: $userName +uidNumber: $userUidNumber +gidNumber: $userGidNumber +homeDirectory: $userHomeDirectory +loginShell: $_userLoginShell +gecos: $_userGecos +description: $_userGecos +userPassword: {crypt}x + +"; + +die "$0: error while adding posix user $userName\n" + unless (do_ldapadd($tmpldif) == 0); + +undef $tmpldif; + +#if ($createGroup) { +# group_add($userName, $userGidNumber); +#} + +group_add_user($userGidNumber, $userName); + +my $grouplist; +# adds to supplementary groups +if (defined($grouplist = $Options{'G'})) { + add_grouplist_user($grouplist, $userName); +} + +# If user was created successfully then we should create his/her home dir +if (defined($tmp = $Options{'m'})) { + if ( !(-e $userHomeDirectory) ) { + system "mkdir $userHomeDirectory 2>/dev/null"; + system "cp -a $_skeletonDir/.[a-z,A-Z]* $_skeletonDir/* $userHomeDirectory 2>/dev/null"; + system "chown -R $userUidNumber:$userGidNumber $userHomeDirectory 2>/dev/null"; + system "chmod 700 $userHomeDirectory 2>/dev/null"; + } +} + + +# Add Samba user infos +if (defined($Options{'a'})) { + if (!$with_smbpasswd) { + + my $winmagic = 2147483647; + my $valpwdcanchange = 0; + my $valpwdmustchange = $winmagic; + my $valacctflags = "[UX]"; + + if (defined($tmp = $Options{'A'})) { + if ($tmp != 0) { + $valpwdcanchange = "0"; + } else { + $valpwdcanchange = "$winmagic"; + } + } + + if (defined($tmp = $Options{'B'})) { + if ($tmp != 0) { + $valpwdmustchange = "0"; + } else { + $valpwdmustchange = "$winmagic"; + } + } + + if (defined($tmp = $Options{'H'})) { + $valacctflags = "$tmp"; + } + + my $tmpldif = +"dn: uid=$userName,$usersdn +changetype: modify +objectclass: top +objectclass: account +objectclass: posixAccount +objectClass: sambaAccount +pwdLastSet: 0 +logonTime: 0 +logoffTime: 2147483647 +kickoffTime: 2147483647 +pwdCanChange: $valpwdcanchange +pwdMustChange: $valpwdmustchange +displayName: $_userGecos +acctFlags: $valacctflags +rid: $userRid + +"; + + die "$0: error while adding samba account to posix user $userName\n" + unless (do_ldapmodify($tmpldif) == 0); + + undef $tmpldif; + } else { + my $FILE="|smbpasswd -s -a $userName >/dev/null" ; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +x +x +EOF + ; + close FILE; + if ($?) { + print "$0: error adding samba account\n"; + exit (10); + } + } # with_smbpasswd + + my $valscriptpath = "$userName.cmd"; + my $valprofilepath = "$_userProfile$userName"; + my $valsmbhome = "$_userSmbHome"; + my $valhomedrive = "$_userHomeDrive"; + +if (defined($tmp = $Options{'C'})) { + $valsmbhome = "$tmp"; +} + +if (defined($tmp = $Options{'D'})) { + $tmp = $tmp.":" unless ($tmp =~ /:/); + $valhomedrive = "$tmp"; +} + +if (defined($tmp = $Options{'E'})) { + $valscriptpath = "$tmp"; +} + +if (defined($tmp = $Options{'F'})) { + $valprofilepath = "$tmp"; +} + + my $tmpldif = +"dn: uid=$userName,$usersdn +changetype: modify +rid: $userRid +primaryGroupID: $userGroupRid +homeDrive: $valhomedrive +smbHome: $valsmbhome +profilePath: $valprofilepath +scriptPath: $valscriptpath +lmPassword: XXX +ntPassword: XXX + +"; + + die "$0: error while modifying samba account of user $userName\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; +} + +if (defined($Options{'P'})) { + exec "/usr/local/sbin/smbldap-passwd.pl $userName" +} + +exit 0; + +######################################## + +=head1 NAME + + smbldap-useradd.pl - Create a new user or update default new + user information + +=head1 SYNOPSIS + + smbldap-useradd.pl [-c comment] [-d home_dir] + [-g initial_group] [-G group[,...]] + [-m [-k skeleton_dir]] + [-s shell] [-u uid [ -o]] [-P] + [-A canchange] [-B mustchange] [-C smbhome] + [-D homedrive] [-E scriptpath] [-F profilepath] + [-H acctflags] login + +=head1 DESCRIPTION + + Creating New Users + The smbldap-useradd.pl command creates a new user account using + the values specified on the command line and the default + values from the system. + The new user account will be entered into the system + files as needed, the home directory will be created, and + initial files copied, depending on the command line options. + + You have to use smbldap-passwd to set the user password. + For Samba users, rid is 2*uidNumber+1000, and primaryGroupID + is 2*gidNumber+1001. Thus you may want to use + smbldap-useradd.pl -a -g "Domain Admins" -u 500 Administrator + to create a domain administrator (admin rid is 0x1F4 = 500 and + grouprid is 0x200 = 512) + + Without any option, the account created will be an Unix (Posix) + account. The following options may be used to add information: + + -a The user will have a Samba account (and Unix). + + -w Creates an account for a Samba machine (Workstation), so that + it can join a domain. + + -x Creates rid and primaryGroupID in hex (for Samba 2.2.2 bug). Else + decimal (2.2.2 patched from cvs or 2.2.x, x > 2) + + -c comment + The new user's comment field (gecos). + + -d home_dir + The new user will be created using home_dir as the value for the + user's login directory. The default is to append the login name + to default_home and use that as the login directory name. + + -g initial_group + The group name or number of the user's initial login group. The + group name must exist. A group number must refer to an already + existing group. The default group number is 1. + + -G group,[...] + A list of supplementary groups which the user is also a member + of. Each group is separated from the next by a comma, with no + intervening whitespace. The groups are subject to the same + restrictions as the group given with the -g option. The default + is for the user to belong only to the initial group. + + -m The user's home directory will be created if it does not exist. + The files contained in skeleton_dir will be copied to the home + directory if the -k option is used, otherwise the files con + tained in /etc/skel will be used instead. Any directories con + tained in skeleton_dir or /etc/skel will be created in the + user's home directory as well. The -k option is only valid in + conjunction with the -m option. The default is to not create + the directory and to not copy any files. + + -s shell + The name of the user's login shell. The default is to leave + this field blank, which causes the system to select the default + login shell. + + -u uid The numerical value of the user's ID. This value must be + unique, unless the -o option is used. The value must be non- + negative. The default is to use the smallest ID value greater + than 1000 and greater than every other user. + + -P ends by invoking smbldap-passwd.pl + + -A can change password ? 0 if no, 1 if yes + + -B must change password ? 0 if no, 1 if yes + + -C smbHome (SMB home share, like '\\\\PDC-SRV\\homes') + + -D homeDrive (letter associated with home share, like 'H:') + + -E scriptPath, relative to the [netlogon] share (DOS script to execute on login, like 'foo.bat') + + -F profilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo') + + -H acctFlags, spaces and trailing bracket are ignored (samba account control bits like '[NDHTUMWSLKI]') + +=head1 SEE ALSO + + useradd(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-userdel.pl b/examples/LDAP/smbldap-tools/smbldap-userdel.pl new file mode 100755 index 0000000000..54309fa5db --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-userdel.pl @@ -0,0 +1,122 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-userdel : user (posix,shadow,samba) deletion + +use strict; +use smbldap_tools; + + +##################### + +use Getopt::Std; +my %Options; + +my $ok = getopts('r?', \%Options); + +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-r?] username\n"; + print " -r remove home directory\n"; + exit (1); +} + +# Read only first @ARGV +my $user = $ARGV[0]; + +my $dn; +# user must not exist in LDAP +if (!defined($dn=get_user_dn($user))) { + print "$0: user $user does not exist\n"; + exit (6); +} + +if ($< != 0) { + print "You must be root to delete an user\n"; + exit (1); +} + +my $homedir; +if (defined($Options{'r'})) { + $homedir=get_homedir($user); +} + +# remove user from groups +my $groups = find_groups_of $user; +my @grplines = split(/\n/, $groups); + +my $grp; +foreach $grp (@grplines) { + my $gname = ""; + if ( $grp =~ /dn: cn=([^,]+),/) { + $gname = $1; + #print "xx $gname\n"; + } + if ($gname ne "") { + group_remove_member($gname, $user); + } +} + +# XXX +delete_user($user); + +# delete dir -- be sure that homeDir is not a strange value +if (defined($Options{'r'})) { + if ($homedir !~ /^\/dev/ and $homedir !~ /^\/$/) { + system "rm -rf $homedir"; + } +} + +my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd restart > /dev/null 2>&1"; +} + +exit (0); + +############################################################ + +=head1 NAME + + smbldap-userdel.pl - Delete a user account and related files + +=head1 SYNOPSIS + + smbldap-userdel.pl [-r] login + +=head1 DESCRIPTION + + The smbldap-userdel.pl command modifies the system + account files, deleting all entries that refer to login. + The named user must exist. + + -r Files in the user's home directory will be removed along with + the home directory itself. Files located in other file + systems will have to be searched for and deleted manually. + +=head1 SEE ALSO + + userdel(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-usermod.pl b/examples/LDAP/smbldap-tools/smbldap-usermod.pl new file mode 100755 index 0000000000..016d7b5422 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-usermod.pl @@ -0,0 +1,403 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-usermod : user (posix,shadow,samba) modification + +use strict; +use smbldap_tools; +use smbldap_conf; + + +##################### + +use Getopt::Std; +my %Options; +my $nscd_status; + +my $ok = getopts('A:B:C:D:E:F:H:IJxme:f:u:g:G:d:l:s:c:ok:?', \%Options); +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-awmugdsckxABCDEFGHI?] username\n"; + print " -c gecos\n"; + print " -d home directory\n"; + #print " -m move home directory\n"; + #print " -e expire date (YYYY-MM-DD)\n"; + #print " -f inactive days\n"; + print " -u uid\n"; + print " -o uid can be non unique\n"; + print " -g gid\n"; + print " -G supplementary groups (comma separated)\n"; + print " -l login name\n"; + print " -s shell\n"; + print " -x creates rid and primaryGroupID in hex instead of decimal (for Samba 2.2.2 unpatched only)\n"; + print " -A can change password ? 0 if no, 1 if yes\n"; + print " -B must change password ? 0 if no, 1 if yes\n"; + print " -C smbHome (SMB home share, like '\\\\PDC-SRV\\homes')\n"; + print " -D homeDrive (letter associated with home share, like 'H:')\n"; + print " -E scriptPath (DOS script to execute on login)\n"; + print " -F profilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')\n"; + print " -H acctFlags (samba account control bits like '[NDHTUMWSLKI]')\n"; + print " -I disable an user. Can't be used with -H or -J\n"; + print " -J enable an user. Can't be used with -H or -I\n"; + print " -? show this help message\n"; + exit (1); +} + +if ($< != 0) { + print "You must be root to modify an user\n"; + exit (1); +} + +# Read only first @ARGV +my $user = $ARGV[0]; + +# Read user datas +my $lines = read_user($user); +if (!defined($lines)) { + print "$0: user $user doesn't exist\n"; + exit (1); +} + +#print "$lines\n"; +my $dn_line; +if ( $lines =~ /(^dn: .*)/ ) { + $dn_line = $1; +} + +chomp($dn_line); + +my $samba = 0; +if ($lines =~ m/objectClass: sambaAccount/) { + $samba = 1; +} + +############ + +my $tmp; +my $mods; + +# Process options +my $changed_uid; +my $_userUidNumber; +my $_userRid; +if (defined($tmp = $Options{'u'})) { + if (defined($Options{'o'})) { + $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + + if ($nscd_status == 0) { + system "/etc/init.d/nscd stop > /dev/null 2>&1"; + } + + if (getpwuid($tmp)) { + if ($nscd_status == 0) { + system "/etc/init.d/nscd start > /dev/null 2>&1"; + } + + print "$0: uid number $tmp exists\n"; + exit (6); + } + if ($nscd_status == 0) { + system "/etc/init.d/nscd start > /dev/null 2>&1"; + } + + } + $_userUidNumber = $tmp; + # as rid we use 2 * uid + 1000 + my $_userRid = 2 * $_userUidNumber + 1000; + if (defined($Options{'x'})) { + $_userRid= sprint("%x", $_userRid); + } + $mods .= "uidNumber: $_userUidNumber\n"; + if ($samba) { + $mods .= "rid: $_userRid\n"; + } + $changed_uid = 1; +} + +my $changed_gid; +my $_userGidNumber; +my $_userGroupRid; +if (defined($tmp = $Options{'g'})) { + $_userGidNumber = parse_group($tmp); + if ($_userGidNumber < 0) { + print "$0: group $tmp doesn't exist\n"; + exit (6); + } +# as grouprid we use 2 * gid + 1001 + my $_userGroupRid = 2 * $_userGidNumber + 1001; + if (defined($Options{'x'})) { + $_userGroupRid = sprint("%x", $_userGroupRid); + } + $mods .= "gidNumber: $_userGidNumber\n"; + if ($samba) { + $mods .= "primaryGroupID: $_userGroupRid\n"; + } + $changed_gid = 1; +} + +my $changed_shell; +my $_userLoginShell; +if (defined($tmp = $Options{'s'})) { + $_userLoginShell = $tmp; + $mods .= "loginShell: $_userLoginShell\n"; + $changed_shell = 1; +} + +my $changed_gecos; +my $_userGecos; +if (defined($tmp = $Options{'c'})) { + $_userGecos = $tmp; + $mods .= "gecos: $_userGecos\n"; + $changed_gecos = 1; +} + +my $changed_homedir; +my $newhomedir; +if (defined($tmp = $Options{'d'})) { + $newhomedir = $tmp; + $mods .= "homeDirectory: $newhomedir\n"; + $changed_homedir = 1; +} + + +if (defined($tmp = $Options{'G'})) { + + # remove user from old groups + my $groups = find_groups_of $user; + my @grplines = split(/\n/, $groups); + + my $grp; + foreach $grp (@grplines) { + my $gname = ""; + if ( $grp =~ /dn: cn=([^,]+),/) { + $gname = $1; + #print "xx $gname\n"; + } + if ($gname ne "") { + group_remove_member($gname, $user); + } + } + + # add user to new groups + add_grouplist_user($tmp, $user); +} + +# +# A : pwdCanChange +# B : pwdMustChange +# C : smbHome +# D : homeDrive +# E : scriptPath +# F : profilePath +# H : acctFlags + +my $attr; +my $winmagic = 2147483647; + +if (defined($tmp = $Options{'A'})) { + $attr = "pwdCanChange"; + if ($tmp != 0) { + $mods .= "$attr: 0\n"; + } else { + $mods .= "$attr: $winmagic\n"; + } +} + +if (defined($tmp = $Options{'B'})) { + $attr = "pwdMustChange"; + if ($tmp != 0) { + $mods .= "$attr: 0\n"; + } else { + $mods .= "$attr: $winmagic\n"; + } +} + +if (defined($tmp = $Options{'C'})) { + $attr = "smbHome"; + #$tmp =~ s/\\/\\\\/g; + $mods .= "$attr: $tmp\n"; +} + +if (defined($tmp = $Options{'D'})) { + $attr = "homeDrive"; + $tmp = $tmp.":" unless ($tmp =~ /:/); + $mods .= "$attr: $tmp\n"; +} + +if (defined($tmp = $Options{'E'})) { + $attr = "scriptPath"; + #$tmp =~ s/\\/\\\\/g; + $mods .= "$attr: $tmp\n"; +} + +if (defined($tmp = $Options{'F'})) { + $attr = "profilePath"; + #$tmp =~ s/\\/\\\\/g; + $mods .= "$attr: $tmp\n"; +} + +if (defined($tmp = $Options{'H'})) { + $attr = "acctFlags"; + #$tmp =~ s/\\/\\\\/g; + $mods .= "$attr: $tmp\n"; +} elsif (defined($tmp = $Options{'I'})) { + my $flags; + + if ( $lines =~ /^acctFlags: (.*)/m ) { + $flags = $1; + } + + chomp($flags); + + if ( !($flags =~ /D/) ) { + my $letters; + if ($flags =~ /(\w+)/) { + $letters = $1; + } + $mods .= "acctFlags: \[D$letters\]\n"; + } +} elsif (defined($tmp = $Options{'J'})) { + my $flags; + + if ( $lines =~ /^acctFlags: (.*)/m ) { + $flags = $1; + } + + chomp($flags); + + if ( $flags =~ /D/ ) { + my $letters; + if ($flags =~ /(\w+)/) { + $letters = $1; + } + $letters =~ s/D//; + $mods .= "acctFlags: \[$letters\]\n"; + } +} + +if ($mods ne '') { + #print "----\n$dn_line\n$mods\n----\n"; + + my $tmpldif = +"$dn_line +changetype: modify +$mods +"; + + die "$0: error while modifying user $user\n" + unless (do_ldapmodify($tmpldif) == 0); + + undef $tmpldif; +} + +$nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + +if ($nscd_status == 0) { + system "/etc/init.d/nscd restart > /dev/null 2>&1"; +} + + +############################################################ + +=head1 NAME + + smbldap-usermod.pl - Modify a user account + +=head1 SYNOPSIS + + smbldap-usermod.pl [-c comment] [-d home_dir] + [-g initial_group] [-G group[,...]] + [-l login_name] [-p passwd] + [-s shell] [-u uid [ -o]] [-x] + [-A canchange] [-B mustchange] [-C smbhome] + [-D homedrive] [-E scriptpath] [-F profilepath] + [-H acctflags] login + +=head1 DESCRIPTION + + The smbldap-usermod.pl command modifies the system account files + to reflect the changes that are specified on the command line. + The options which apply to the usermod command are + + -c comment + The new value of the user's comment field (gecos). + + -d home_dir + The user's new login directory. + + -g initial_group + The group name or number of the user's new initial login group. + The group name must exist. A group number must refer to an + already existing group. The default group number is 1. + + -G group,[...] + A list of supplementary groups which the user is also a member + of. Each group is separated from the next by a comma, with no + intervening whitespace. The groups are subject to the same + restrictions as the group given with the -g option. If the user + is currently a member of a group which is not listed, the user + will be removed from the group + + -l login_name + The name of the user will be changed from login to login_name. + Nothing else is changed. In particular, the user's home direc + tory name should probably be changed to reflect the new login + name. + + -s shell + The name of the user's new login shell. Setting this field to + blank causes the system to select the default login shell. + + -u uid The numerical value of the user's ID. This value must be + unique, unless the -o option is used. The value must be non- + negative. Any files which the user owns and which are + located in the directory tree rooted at the user's home direc + tory will have the file user ID changed automatically. Files + outside of the user's home directory must be altered manually. + + -x Creates rid and primaryGroupID in hex instead of decimal (for + Samba 2.2.2 unpatched only - higher versions always use decimal) + + -A can change password ? 0 if no, 1 if yes + + -B must change password ? 0 if no, 1 if yes + + -C smbHome (SMB home share, like '\\\\PDC-SRV\\homes') + + -D homeDrive (letter associated with home share, like 'H:') + + -E scriptPath, relative to the [netlogon] share (DOS script to execute on login, like 'foo.bat') + + -F profilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo') + + -H acctFlags, spaces and trailing bracket are ignored (samba account control bits like '[NDHTUMWSLKI]') + + -I disable user. Can't be used with -H or -J + + -J enable user. Can't be used with -H or -I + +=head1 SEE ALSO + + usermod(1) + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap-usershow.pl b/examples/LDAP/smbldap-tools/smbldap-usershow.pl new file mode 100755 index 0000000000..b05f087620 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap-usershow.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose of smbldap-userdisplay : user (posix,shadow,samba) display + +use strict; +use smbldap_tools; + +use Getopt::Std; +my %Options; + +my $ok = getopts('?', \%Options); + +if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) { + print "Usage: $0 [-?] username\n"; + print " -? show this help message\n"; + exit (1); +} + +# Read only first @ARGV +my $user = $ARGV[0]; + +my $lines = read_user($user); +if (!defined($lines)) { + print "$0: user $user doesn't exist\n"; + exit (1); +} + +print "$lines\n"; + +exit(0); + +############################################################ + +=head1 NAME + + smbldap-usershow.pl - Show a user account informations + +=head1 SYNOPSIS + + smbldap-usershow.pl login + +=head1 DESCRIPTION + + The smbldap-usershow.pl command displays the informations + associated with the login. The named user must exist. + +=cut + +#' diff --git a/examples/LDAP/smbldap-tools/smbldap_conf.pm b/examples/LDAP/smbldap-tools/smbldap_conf.pm new file mode 100644 index 0000000000..9a5a116b98 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap_conf.pm @@ -0,0 +1,249 @@ +#!/usr/bin/perl +use strict; +package smbldap_conf; + +# smbldap-tools.conf : Q & D configuration file for smbldap-tools + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + +# Purpose : +# . be the configuration file for all smbldap-tools scripts + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS +$UID_START $GID_START $smbpasswd $slaveLDAP $masterLDAP +$with_smbpasswd $mk_ntpasswd +$ldap_path $ldap_opts $ldapsearch $ldapsearchnobind +$ldapmodify $ldappasswd $ldapadd $ldapdelete $ldapmodrdn +$suffix $usersdn $computersdn +$groupsdn $scope $binddn $bindpasswd +$slaveDN $slavePw $masterDN $masterPw +$_userLoginShell $_userHomePrefix $_userGecos +$_defaultUserGid $_defaultComputerGid +$_skeletonDir $_userSmbHome +$_userProfile $_userHomeDrive +$_userScript $usersou $computersou $groupsou +); + +use Exporter; +$VERSION = 1.00; +@ISA = qw(Exporter); + +@EXPORT = qw( +$UID_START $GID_START $smbpasswd $slaveLDAP $masterLDAP +$with_smbpasswd $mk_ntpasswd +$ldap_path $ldap_opts $ldapsearch $ldapsearchnobind $ldapmodify $ldappasswd +$ldapadd $ldapdelete $ldapmodrdn $suffix $usersdn +$computersdn $groupsdn $scope $binddn $bindpasswd +$slaveDN $slavePw $masterDN $masterPw +$_userLoginShell $_userHomePrefix $_userGecos +$_defaultUserGid $_defaultComputerGid $_skeletonDir +$_userSmbHome $_userProfile $_userHomeDrive $_userScript +$usersou $computersou $groupsou +); + + +############################################################################## +# +# General Configuration +# +############################################################################## + +# +# UID and GID starting at... +# + +$UID_START = 1000; +$GID_START = 1000; + +############################################################################## +# +# LDAP Configuration +# +############################################################################## + +# Notes: to use to dual ldap servers backend for Samba, you must patch +# Samba with the dual-head patch from IDEALX. If not using this patch +# just use the same server for slaveLDAP and masterLDAP. +# +# Slave LDAP : needed for read operations +# +# Ex: $slaveLDAP = "127.0.0.1"; +$slaveLDAP = "_SLAVELDAP_"; + +# +# Master LDAP : needed for write operations +# +# Ex: $masterLDAP = "127.0.0.1"; +$masterLDAP = "_MASTERLDAP_"; + +# +# LDAP Suffix +# +# Ex: $suffix = "dc=IDEALX,dc=ORG"; +$suffix = "_SUFFIX_"; + +# +# Where are stored Users +# +# Ex: $usersdn = "ou=Users,$suffix"; for ou=Users,dc=IDEALX,dc=ORG +$usersou = q(_USERS_); + +$usersdn = "ou=$usersou,$suffix"; + +# +# Where are stored Computers +# +# Ex: $computersdn = "ou=Computers,$suffix"; for ou=Computers,dc=IDEALX,dc=ORG +$computersou = q(_COMPUTERS_); + +$computersdn = "ou=$computersou,$suffix"; + +# +# Where are stored Groups +# +# Ex $groupsdn = "ou=Groups,$suffix"; for ou=Groups,dc=IDEALX,dc=ORG +$groupsou = q(_GROUPS_); + +$groupsdn = "ou=$groupsou,$suffix"; + +# +# Default scope Used +# +$scope = "sub"; + +# +# Credential Configuration +# +# Bind DN used +# Ex: $binddn = "cn=Manager,$suffix"; for cn=Manager,dc=IDEALX,dc=org +$binddn = "_BINDDN_"; +# +# Bind DN passwd used +# Ex: $bindpasswd = 'secret'; for 'secret' +$bindpasswd = "_BINDPW_"; + +# +# Notes: if using dual ldap patch, you can specify to different configuration +# By default, we will use the same DN (so it will work for standard Samba +# release) +# +$slaveDN = $binddn; +$slavePw = $bindpasswd; +$masterDN = $binddn; +$masterPw = $bindpasswd; + +############################################################################## +# +# Unix Accounts Configuration +# +############################################################################## + +# Login defs +# +# Default Login Shell +# +# Ex: $_userLoginShell = q(/bin/bash); +$_userLoginShell = q(_LOGINSHELL_); + +# +# Home directory prefix (without username) +# +#Ex: $_userHomePrefix = q(/home/); +$_userHomePrefix = q(_USERHOMEPREFIX_); + +# +# Gecos +# +$_userGecos = q(System User); + +# +# Default User (POSIX and Samba) GID +# +$_defaultUserGid = 100; + +# +# Default Computer (Samba) GID +# +$_defaultComputerGid = 553; + +# +# Skel dir +# +$_skeletonDir = q(/etc/skel); + +############################################################################## +# +# SAMBA Configuration +# +############################################################################## + +# +# The UNC path to home drives location without the username last extension +# (will be dynamically prepended) +# Ex: q(\\\\My-PDC-netbios-name\\homes) for \\My-PDC-netbios-name\homes +$_userSmbHome = q(\\\\_PDCNAME_\\homes); + +# +# The UNC path to profiles locations without the username last extension +# (will be dynamically prepended) +# Ex: q(\\\\My-PDC-netbios-name\\profiles) for \\My-PDC-netbios-name\profiles +$_userProfile = q(\\\\_PDCNAME_\\profiles\\); + +# +# The default Home Drive Letter mapping +# (will be automatically mapped at logon time if home directory exist) +# Ex: q(U:) for U: +$_userHomeDrive = q(_HOMEDRIVE_:); + +# +# The default user netlogon script name +# if not used, will be automatically username.cmd +# +#$_userScript = q(startup.cmd); # make sure script file is edited under dos + + +############################################################################## +# +# SMBLDAP-TOOLS Configuration (default are ok for a RedHat) +# +############################################################################## + +# Allows not to use smbpasswd (if $with_smbpasswd == 0 in smbldap_conf.pm) but +# prefer mkntpwd... most of the time, it's a wise choice :-) +$with_smbpasswd = 0; +$smbpasswd = "/usr/bin/smbpasswd"; +$mk_ntpasswd = "/usr/local/sbin/mkntpwd"; + +$ldap_path = "/usr/bin"; +$ldap_opts = "-x"; +$ldapsearch = "$ldap_path/ldapsearch $ldap_opts -h $slaveLDAP -D '$slaveDN' -w '$slavePw'"; +$ldapsearchnobind = "$ldap_path/ldapsearch $ldap_opts -h $slaveLDAP"; +$ldapmodify = "$ldap_path/ldapmodify $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; +$ldappasswd = "$ldap_path/ldappasswd $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; +$ldapadd = "$ldap_path/ldapadd $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; +$ldapdelete = "$ldap_path/ldapdelete $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; +$ldapmodrdn = "$ldap_path/ldapmodrdn $ldap_opts -h $masterLDAP -D '$masterDN' -w '$masterPw'"; + + + +1; + +# - The End diff --git a/examples/LDAP/smbldap-tools/smbldap_tools.pm b/examples/LDAP/smbldap-tools/smbldap_tools.pm new file mode 100755 index 0000000000..0a451210f3 --- /dev/null +++ b/examples/LDAP/smbldap-tools/smbldap_tools.pm @@ -0,0 +1,583 @@ +#! /usr/bin/perl +use strict; +package smbldap_tools; +use smbldap_conf; + +# This code was developped by IDEALX (http://IDEALX.org/) and +# contributors (their names can be found in the CONTRIBUTORS file). +# +# Copyright (C) 2001-2002 IDEALX +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +# USA. + + +# ugly funcs using global variables and spawning openldap clients + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); +use Exporter; +$VERSION = 1.00; +@ISA = qw(Exporter); + +@EXPORT = qw( +get_user_dn +get_group_dn +is_samba_user +is_user_valid +get_dn_from_line +add_posix_machine +add_samba_machine +add_samba_machine_mkntpwd +group_add_user +add_grouplist_user +disable_user +delete_user +group_add +get_homedir +read_user +read_group +find_groups_of +parse_group +group_remove_member +group_get_members +do_ldapadd +do_ldapmodify +get_user_dn2 +); + +# dn_line = get_user_dn($username) +# where dn_line is like "dn: a=b,c=d" +sub get_user_dn +{ + my $user = shift; + my $dn=`$ldapsearch -b '$suffix' -s '$scope' '(&(objectclass=posixAccount)(uid=$user))' | grep "^dn:"`; + chomp $dn; + if ($dn eq '') { + return undef; + } + + return $dn; +} + +# return (success, dn) +sub get_user_dn2 +{ + my $user = shift; + + my $sr = `$ldapsearch -b '$suffix' -s '$scope' '(&(objectclass=posixAccount)(uid=$user))'`; + if ($sr eq "") { + print "get_user_dn2: error in ldapsearch : +$ldapsearch -b '$suffix' -s '$scope' '(&(objectclass=posixAccount)(uid=$user))'\n"; + return (0, undef); + } + + my @lines = split(/\n/, $sr); + + my @matches = grep(/^dn:/, @lines); + + my $dn = $matches[0]; + chomp $dn; + if ($dn eq '') { + return (1, undef); + } + + return (1, $dn); +} + +# dn_line = get_group_dn($groupname) +# where dn_line is like "dn: a=b,c=d" +sub get_group_dn +{ + my $group = shift; + my $dn=`$ldapsearch -b '$groupsdn' -s '$scope' '(&(objectclass=posixGroup)(|(cn=$group)(gidNumber=$group)))' | grep "^dn:"`; + chomp $dn; + if ($dn eq '') { + return undef; + } + + return $dn; +} + +# bool = is_samba_user($username) +sub is_samba_user +{ + my $user = shift; + my $cmd = "$ldapsearch -b '$suffix' -s '$scope' '(&(objectClass=sambaAccount)(uid=$user))' | grep '^dn:\'"; + my $res=`$cmd`; + chomp $res; + if ($res ne '') { + return 1; + } + return 0; +} + +# bool = is_user_valid($username) +# try to bind with user dn and password to validate current password +sub is_user_valid +{ + my ($user, $dn, $pass) = @_; + my $res=`$ldapsearchnobind -b '$usersdn' -s '$scope' -D '$dn' -w '$pass' '(&(objectclass=posixAccount)(uid=$user))' 2>/dev/null | grep "^dn:"`; + chomp $res; + if ($res eq '') { + return 0; + } + return 1; +} + +# dn = get_dn_from_line ($dn_line) +# helper to get "a=b,c=d" from "dn: a=b,c=d" +sub get_dn_from_line +{ + my $dn = shift; + $dn =~ s/^dn: //; + return $dn; +} + +# success = add_posix_machine($user, $uid, $gid) +sub add_posix_machine +{ + my ($user, $uid, $gid) = @_; + +my $tmpldif = +"dn: uid=$user,$computersdn +objectclass: top +objectclass: posixAccount +cn: $user +uid: $user +uidNumber: $uid +gidNumber: $gid +homeDirectory: /dev/null +loginShell: /bin/false +description: Computer + +"; + + die "$0: error while adding posix account to machine $user\n" + unless (do_ldapadd($tmpldif) == 0); + + undef $tmpldif; + + return 1; +} + +# success = add_samba_machine($computername) +sub add_samba_machine +{ + my $user = shift; + system "smbpasswd -a -m $user"; + + return 1; +} + +sub add_samba_machine_mkntpwd +{ + my ($user, $uid) = @_; + my $rid = 2 * $uid + 1000; # Samba 2.2.2 stuff + + my $name = $user; + $name =~ s/.$//s; + + if ($mk_ntpasswd eq '') { + print "Either set \$with_smbpasswd = 1 or specify \$mk_ntpasswd\n"; + return 0; + } + + my $ntpwd = `$mk_ntpasswd '$name'`; + chomp(my $lmpassword = substr($ntpwd, 0, index($ntpwd, ':'))); + chomp(my $ntpassword = substr($ntpwd, index($ntpwd, ':')+1)); + + my $tmpldif = +"dn: uid=$user,$computersdn +changetype: modify +objectclass: top +objectclass: posixAccount +objectClass: sambaAccount +pwdLastSet: 0 +logonTime: 0 +logoffTime: 2147483647 +kickoffTime: 2147483647 +pwdCanChange: 0 +pwdMustChange: 2147483647 +acctFlags: [W ] +lmpassword: $lmpassword +ntpassword: $ntpassword +rid: $rid +primaryGroupID: 0 + +"; + + die "$0: error while adding samba account to $user\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + + return 1; +} + + + +sub group_add_user +{ + my ($group, $userid) = @_; + my $dn_line; + + if (!defined($dn_line = get_group_dn($group))) { + return 1; + } + my $dn = get_dn_from_line($dn_line); + my $members = `$ldapsearch -b '$dn' -s base | grep -i "^memberUid:"`; + chomp($members); + # user already member ? + if ($members =~ m/^memberUid: $userid/) { + return 2; + } + my $mods = ""; + if ($members ne '') { + $mods="$dn_line +changetype: modify +replace: memberUid +$members +memberUid: $userid +"; + } else { + $mods="$dn_line +changetype: modify +add: memberUid +memberUid: $userid +"; + } + + #print "$mods\n"; + + my $tmpldif = +"$mods +"; + + die "$0: error while modifying group $group\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + return 0; +} + +sub add_grouplist_user +{ + my ($grouplist, $user) = @_; + my @array = split(/,/, $grouplist); + foreach my $group (@array) { + group_add_user($group, $user); + } +} + +# XXX FIXME : acctFlags |= D, and not acctFlags = D +sub disable_user +{ + my $user = shift; + my $dn_line; + + if (!defined($dn_line = get_user_dn($user))) { + print "$0: user $user doesn't exist\n"; + exit (10); + } + + my $tmpldif = +"dn: $dn_line +changetype: modify +replace: userPassword +userPassword: {crypt}!x + +"; + + die "$0: error while modifying user $user\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + + if (is_samba_user($user)) { + + my $tmpldif = +"dn: $dn_line +changetype: modify +replace: acctFlags +acctFlags: [D ] + +"; + + die "$0: error while modifying user $user\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + + } + +} + +# delete_user($user) +sub delete_user +{ + my $user = shift; + my $dn_line; + + if (!defined($dn_line = get_user_dn($user))) { + print "$0: user $user doesn't exist\n"; + exit (10); + } + + my $dn = get_dn_from_line($dn_line); + system "$ldapdelete $dn >/dev/null"; +} + +# $success = group_add($groupname, $group_gid, $force_using_existing_gid) +sub group_add +{ + my ($gname, $gid, $force) = @_; + + my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1"; + + if ($nscd_status == 0) { + system "/etc/init.d/nscd stop > /dev/null 2>&1"; + } + + if (!defined($gid)) { + while (defined(getgrgid($GID_START))) { + $GID_START++; + } + $gid = $GID_START; + } else { + if (!defined($force)) { + if (defined(getgrgid($gid))) { + return 0; + } + } + } + + if ($nscd_status == 0) { + system "/etc/init.d/nscd start > /dev/null 2>&1"; + } + + my $tmpldif = +"dn: cn=$gname,$groupsdn +objectclass: posixGroup +cn: $gname +gidNumber: $gid + +"; + + die "$0: error while adding posix group $gname\n" + unless (do_ldapadd($tmpldif) == 0); + + undef $tmpldif; + + return 1; +} + +# $homedir = get_homedir ($user) +sub get_homedir +{ + my $user = shift; + my $homeDir=`$ldapsearch -b '$suffix' -s '$scope' '(&(objectclass=posixAccount)(uid=$user))' | grep "^homeDirectory:"`; + chomp $homeDir; + if ($homeDir eq '') { + return undef; + } + $homeDir =~ s/^homeDirectory: //; + + return $homeDir; +} + +# search for an user +sub read_user +{ + my $user = shift; + my $lines=`$ldapsearch -b '$suffix' -s '$scope' '(&(objectclass=posixAccount)(uid=$user))' -LLL`; + chomp $lines; + if ($lines eq '') { + return undef; + } + + return $lines; +} + +# search for a group +sub read_group +{ + my $user = shift; + my $lines=`$ldapsearch -b '$groupsdn' -s '$scope' '(&(objectclass=posixGroup)(cn=$user))' -LLL`; + chomp $lines; + if ($lines eq '') { + return undef; + } + + return $lines; +} + +# find groups of a given user +sub find_groups_of +{ + my $user = shift; + my $lines=`$ldapsearch -b '$groupsdn' -s '$scope' '(&(objectclass=posixGroup)(memberuid=$user))' -LLL | grep "^dn: "`; + chomp $lines; + if ($lines eq '') { + return undef; + } + + return $lines; +} + +# return the gidnumber for a group given as name or gid +# -1 : bad group name +# -2 : bad gidnumber +sub parse_group +{ + my $userGidNumber = shift; + + if ($userGidNumber =~ /[^\d]/ ) { + my $gname = $userGidNumber; + my $gidnum = getgrnam($gname); + if ($gidnum !~ /\d+/) { + return -1; + } else { + $userGidNumber = $gidnum; + } + } elsif (!defined(getgrgid($userGidNumber))) { + return -2; + } + return $userGidNumber; +} + +# remove $user from $group +sub group_remove_member +{ + my ($group, $user) = @_; + + my $grp_line = get_group_dn($group); + if (!defined($grp_line)) { + return 0; + } + my $members = `$ldapsearch -b '$groupsdn' -s '$scope' '(&(objectclass=posixgroup)(cn=$group))' | grep -i "^memberUid:"`; + + #print "avant ---\n$members\n"; + $members =~ s/memberUid: $user\n//; + #print "----\n$members\n---\n"; + + chomp($members); + + my $header; + if ($members eq '') { + $header = "changetype: modify\n"; + $header .= "delete: memberUid"; + } else { + $header = "changetype: modify\n"; + $header .= "replace: memberUid"; + } + + my $tmpldif = +"$grp_line +$header +$members +"; + die "$0: error while modifying group $group\n" + unless (do_ldapmodify($tmpldif) == 0); + undef $tmpldif; + + return 1; +} + +sub group_get_members +{ + my ($group) = @_; + my @members; + + my $grp_line = get_group_dn($group); + if (!defined($grp_line)) { + return 0; + } + my $members = `$ldapsearch -b '$groupsdn' -s '$scope' '(&(objectclass=posixgroup)(cn=$group))' memberUid | grep -i "^memberUid:"`; + + my @lines = split (/\n/, $members); + foreach my $line (@lines) { + $line =~ s/^memberUid: //; + push(@members, $line); + } + + return @members; +} + +sub file_write { + my ($filename, $filecontent) = @_; + local *FILE; + open (FILE, "> $filename") || + die "Cannot open «$filename» for writing: $!\n"; + print FILE $filecontent; + close FILE; +} + +# wrapper for ldapadd +sub do_ldapadd2 +{ + my $ldif = shift; + + my $tempfile = "/tmp/smbldapadd.$$"; + file_write($tempfile, $ldif); + + my $rc = system "$ldapadd < $tempfile >/dev/null"; + unlink($tempfile); + return $rc; +} + +sub do_ldapadd +{ + my $ldif = shift; + + my $FILE = "|$ldapadd >/dev/null"; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +$ldif +EOF + ; + close FILE; + my $rc = $?; + return $rc; +} + +# wrapper for ldapmodify +sub do_ldapmodify2 +{ + my $ldif = shift; + + my $tempfile = "/tmp/smbldapmod.$$"; + file_write($tempfile, $ldif); + + my $rc = system "$ldapmodify -r < $tempfile >/dev/null"; + unlink($tempfile); + return $rc; +} + +sub do_ldapmodify +{ + my $ldif = shift; + + my $FILE = "|$ldapmodify -r >/dev/null"; + open (FILE, $FILE) || die "$!\n"; + print FILE <<EOF; +$ldif +EOF + ; + close FILE; + my $rc = $?; + + return $rc; +} + + + +1; + |