zentyal-samba-2.3.12+quantal1ubuntu1/0000775000000000000000000000000012017560227014306 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/ChangeLog0000664000000000000000000003417412017560227016071 0ustar HEAD + Change default fileserver from s3fs to ntvfs to be compatible with the quantal samba version + Remove provision parameter --use-rfc2307, not compatible with the quantal samba version + Add missing use statement on EBox::Samba::User + Fix updating Zentyal LDAP users kerberos keys from samba users + Ensure proper permissions on the samba privileged socket + Check that account names does not exists in the whole domain when adding users and groups from the LdapModuleBase callbacks + Do not notify samba module when deleting Zentyal users and groups through the synchronizer script + Improve netbios name validation (no dots) + Validate netbios domain name as netbios name + Force zentyal-dns dependency version + Fix bug managing the dns domain when enabling/disabling the module + Improvements in daemons management to avoid restarting them twice while saving changes. 2.3.12 + Support additional domain controller mode + Remove user addon to set the user as domain admin. Add it to the domain admins group instead. + Sync domain administrator and domain admins accounts to zentyal + Increase log level from 1 to 3 to trace problems. + Provision database only when saving changes, not in module enable. + Change samba home to /home/samba instead /home/ebox/samba + Use the privileged LDAP socket to connect to samba LDAP. + Provision using bind9 DLZ backend. + Add config key to choose the fileserver to use, 'ntvfs' or 's3fs' + Removed wrong empty string translations + Enable printing daemon. Printers ACLs stored in a model within printers module. 2.3.11 + Added modeldepends to yaml schema + Enable printing daemon. Printers ACLs are now stored in a model within printers module + Removed wrong empty string translations 2.3.10 + Fix exception creating shares + Sync passwords from LDAP to LDB directly from hashes 2.3.9 + Fields in General Settings can be edited now, with the exception of domain and computer names + Added methods to get the paths used by shares, users and groups to generate disk usage reports + User addon to enable/disable the account and set the user as domain administrator + Group addon to create group shares + Added method to give captive portal module firewall rules to allow domain joins 2.3.8 + Recycle Bin feature is now working with samba4 + Remove unnecessary dns enable depend as users already depend on it + Integration with samba 4.0 beta2 which uses samba4 for the Active Directory domain services and the samba3 daemon for the file sharing and printing services + Added LogObserver support + Avoid showing admin password if provision command fails + Add domain name validation, cannot be equal to host name + Fix provision bug caused by passwords containing spaces + Threaded synchronizer script + Roaming profiles implementation + Home drive implementation + Guest access implementation + Delete directories from disk when shares are removed 2.3.7 + Fixed problems with provision in fresh install + Adapted to new Model management framework + Store printers in redis using the new JSON config objects 2.3.6 + Integrate with zentyal DNS + Fix loop over array reference in funcion usesPort 2.3.5 + New samba4 synchronization based on LDB module and LDIF files + Depend on samba-zentyal-modules instead of libldb-perl + Custom build of samba4 is no longer needed 2.3.4 + Packaging fixes for precise + Code typo fix in Samba::Model::GeneralSettings::_checkDomainName 2.3.3 + Validate domain admin password in general settings + Fixed bugs when adding users or groups with spaces 2.3.2 + Ignore mailfilter users in s4sync 2.3.1 + Samba4 integration + Service description is now translatable + Restore samba-vscan dependency 2.3 + Adapted to new MySQL logs backend + Remove samba-vscan dependency as it is not yet available for precise + Replaced autotools with zbuildtools + Use always the same string to refer to the NetBIOS computer name + Validation of maximum length of domain name, validation against reserved words of netbios and domain names 2.1.7 + Allow non-ascii characters in share names and comments 2.1.6 + Added config key to set Zentyal folders and default domain prefix + Removed /zentyal prefix from URLs + Added maximum limits to PDC options + Avoid duplicated restart during postinst 2.1.5 + Removed wrong quotes in smb.conf + Added missing touch and minsize options in /etc/zentyal/samba.conf for Recycle Bin 2.1.4 + Better validation of samba shares paths + Improve smb.conf template: delete use_client_driver and allow include per client + Always depend on samba-vscan + Use quote column option for periodic and report log consolidation 2.1.3 + Now deleted users and groups are removed correctly from printers permissions lists + Show group comment if exists as share description + Fixed SQL in activity report section + Removed redundant code _dumpSharesTree and _loadSharesTree 2.1.2 + Domain names ending in ".local" are no longer allowed 2.1.1 + Quotas are now included in users module + Bugfix: disabled shares are correctly ignored now + Bugfix: fixed bad column name in report consolidation + Renamed internal-backups and quarantine shares from ebox- to zentyal- + Bug fix: default file sharing quota works properly now 2.1 + Remove ebox- prefix from helper scripts names + Use new standard enable-module script + Replace /etc/ebox/80samba.conf with /etc/zentyal/samba.conf + Use new initial-setup in postinst and delete old migrations + Bug fix: Home directory is mapped when accessing from a Windows 7 client + User quotas are now stored in configuration backup and users directory + Bug fix: Share size is estimated although some files cannot be read + Bug fix: Removed permissions are actually removed + Roaming profiles with correct file attribs + The files in a group share can be modified by all the members in the group + Show forbidden paths in the "Path not allowed" exception text + Truncate the resource field to avoid overflow error of log database 2.0.7 + Removed printers are ignored during backup restore + Added backup domain + Added printers as restore dependency 2.0.6 + Check for incompatibility between PDC and PAM on slaves + Improved performance by adding samba LDAP indexes + Only set shares ACL if needed + Set default order for dashboard widgets 2.0.5 + Only ASCII characters are now allowed for share names and comments + Bug fix: guest shares also work if PDC not enabled 2.0.4 + Fixed quarantine folder permissions + Don't ask for password in guest shares 2.0.3 + Bug fix: guest shares now work on Windows clients + Fixed log retrieving for quarantine alerts 2.0.2 + Fixed problems in backup restoration + Bug fix: support users and groups with spaces and so on in ACLs 2.0.1 + Bug fix: cups daemon is now started before samba one + Bug fix: samba can be enabled now if filesystem does not support quotas + Removed warning due to mix numeric and string values in printer hash. + New CUPS printers are also stored in redis when editing groups + Deleted obsolete code regarding external/non-external printers 1.5.9 + Rebranded domain name and description 1.5.8 + Zentyal rebrand + On smb.conf.mas: use client driver = no to allow printer server to give clients the uploaded drivers. 1.5.7 + Avoid antivirus scan on large files to fix read problems + Add a keyconf to Samba listen on external interfaces + Added more report subsections 1.5.6 + Move NSS from ebox-samba to ebox-usersandgroups + Home directories are under /home now + Shares permissions model now states if the ACL is for a user or a group 1.5.5 + Bug fix: set proper permissions on guest shares + Bug fix: avoid parse of non-word characters in vscan log entries 1.5.4 + Added bridged mode support in firewall helper 1.5.3 + Bug fix: do not add acl attribute in /etc/fstab when using xfs 1.5.2 + Enforce uniqueness of 'user/group' filed in shares permissions + Enable full audit feature as it's working again in samba 3.4.6 + Allow guest shares 1.5.1 + Add support for file system ACLs. Modify /etc/fstab accordingly. Add dependency on acl. + Bug fix: check if a group has been deleted when configurer printers, otherwise users end up with a blank screen when granting printer permissions + Use the new upstart scripts that the Ubuntu samba packages ships in Lucid 1.4.2 + Add missing samba_virus_report table 1.4.1 + Restored RecycleBin feature lost when merged breadcrumbs 1.3.15 + Added 'hide files' directive by default in smb.conf.mas + Bug fix: PDC password policy settings are kept after samba restarts 1.3.14 + Add DefaultUser model to be used in users and groups default user template. Admins can select if they wish to enable the file sharing account by default when creating new users. 1.3.13 + Disable full_audit until fixed in a newer samba version 1.3.12 + Add breadcrumbs 1.3.11 + Added report support 1.3.10 + bugfix: ignore case when comparing domain and netbios names + Added support for Recycle Bin in shares + bugfix: restore Domain Users with GID 513 and not 512. as this made Domain Admins not work + Remove unused quota related methods 1.3.7 + Create .V2 profile directories. Windows Vista looks for them. + remove extendedBackup, data files must be backuped using ebackup 1.3.6 + bugfix: do not allow netbios names longer than 15 characters 1.3.4 + bugfix: some samba actions never appeared in the access log 1.3.3 + bugfix: we dont consults users when users is not configured in EBox::Samba::existsShareResource 1.3.1 + bugfix: use right number for Domain Computers group 1.3.0 + bugfix: keep sambaMinPwdLength attribute 1.1.30 + bugfix: add user works if quota is disabled + bugfix: replaced storeElementByName with store to avoid bug when restoring 1.1.20 + samba allows the use of internal virtual ifaces now + bugfix: importFromLdif was calling a maethod that was removed in a previous merge 1.1.10 + Only update sambaPaths on users with sambaSamAccount object class + UI imrpovement: in general setting some fileds are disabled when PDC is not selected 1.1 + Bugfix: issue with codepages on shares + Home drive letter can be changed now from general settings + Added new PDC model with password settings + Use the new row() and ids() API + Windows user's profiles are backed up only in extended backups + Enable quota support again + Bugfix: when importing data from ldiff we assure that the default group is created before any group assignment to avoid 'group not existent' errors 0.12.101 + Bugfix: set force directory mode and force create mode to 0660 in shares 0.12.100 + Admin user method is more robust in face of user's incomplete groups membership + Bugfix: `printers` method returns an empty list when `ebox-printers` package is not installed + Add per-user disk quota 0.12.99 + New release 0.12.6.101 + Bugfix. roaming profiles are not created automatically when they are disabled 0.12.6.100 + Support for external printers configured with CUPS + Bugfix. Set users and groups suffix properly in smb.conf 0.12.5 + Bugfix. Set loginShell when adding users. By default it takes /bin/false but users can change it using /etc/ebox/80samba.conf 0.12.4 + Bugfix. Check and correct if there is a user or group with a wrong SID. It's possible to run into that scenarion depending when the user/group is created + Do not delete some domain attributes that are used to store password attributes such us password length, expiration... 0.12.3 + Add configuration variable to enable/disable quota support as it might be really slow if we have many users 0.12.2 + Restore group share names when restoring a backup 0.12.1 + Leave Logon Home empty, as Logon Home = "" as stated by smb.conf documentation doesn't seem to work + Make sure workgroup and netbios names are different 0.12 + Add help to model fields + Fix typo in defaultEnabledValue. Now shares are enabled by default. + Fix typo in administrator label + Mark shares strings to translate + Use eBox OID number in LDAP schemas + Do not use shares that don't have permission for any user or group + Remove deprecated printer admin configuration key in smb.conf.mas + Enable dns proxy in smb.conf.mas 0.11.103 + Bugfix. Add and use EBox::Samba::Types::Select to avoid issues with the options cache 0.11.102 + Extend functinality to add custom shares and not only one per-group: - Any share within the file system - Any share automatically created under /home/samba/shares - Fine-grained access to the share: read-only, read and write, administrator, per user and per group. + Set editable attribute to 1 in User field. To comply with what the type expects and avoid warnings 0.11.101 + New release 0.11.100 + Change slapd.conf ownership to module users + Fix typos + onInstall() functionality moved to migration script 0.11.99 + Allow others to read contents from users home directory to publish HTML 0.11 + New release 0.10.99 + New release 0.10 + Create directory with 0770 + Add users to Domain Users group 0.9.100 + New release 0.9.99 + New release 0.9.3 + New release 0.9.2 + Add ebox backup directory as a shared resource to download/upload files + Create smbldap_bind.conf which contains password with mask 0600 0.9.1 + New release 0.9 + Added Polish translation + Added German translation + Added Dutch translation 0.8.99 + New release 0.8.1 + bugfix. Do not mess up home directories when upgrading + Minor workaround. Create slapd run directory in case it does not exist 0.8 + New release 0.7.99 + Full backup mode stores shared files + Unlimited i-node quota + Various bug-fixes + Portuguese translation 0.7.1 + Initial support for PDC + GUI improvements + Added update/clean actions to eobx-samba-ldap + Use EBox::LDAP singleton + Debian package fixes + Fetch SID from configuration file + Use of ebox-sudoers-friendly 0.7 + First public release 0.6 + move to client + API documented using naturaldocs + Update install + Update debian scripts + Enable/disable printer sharing and file sharing independentely + Use new syntax to define ACLs in slapd.conf + Implements usesPort + Add full support for printers + Several bugfixes 0.5.2 + Fix some packaging issues 0.5.1 + Convert module to new menu system 0.5 + Initial release zentyal-samba-2.3.12+quantal1ubuntu1/extra/0000775000000000000000000000000012017560227015431 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/extra/files.list0000664000000000000000000000005712017560227017432 0ustar samba-ignore-sids.txt /usr/share/zentyal-samba zentyal-samba-2.3.12+quantal1ubuntu1/extra/samba-ignore-sids.txt0000664000000000000000000000367612017560227021512 0ustar # Group: Allowed RODC Password Replication Group # Members in this group can have their passwords replicated to all # read-only domain controllers in the domain S-1-5-21-\d+-\d+-\d+-571 # Group: Enterprise Read-only Domain Controllers # Members of this group are Read-Only Domain Controllers in the enterprise S-1-5-21-\d+-\d+-\d+-498 # Group: Denied RODC Password Replication Group # Members in this group cannot have their passwords replicated to any # read-only domain controllers in the domain S-1-5-21-\d+-\d+-\d+-572 # Group: Read-only Domain Controllers # Members of this group are Read-Only Domain Controllers in the domain S-1-5-21-\d+-\d+-\d+-521 # Group: Group Policy Creator Owners # Members in this group can modify group policy for the domain S-1-5-21-\d+-\d+-\d+-520 # Group: RAS and IAS Servers # Servers in this group can access remote access properties of users S-1-5-21-\d+-\d+-\d+-553 # Group: Domain Controllers # All domain controllers in the domain S-1-5-21-\d+-\d+-\d+-516 # Group: Enterprise Admins # Designated administrators of the enterprise S-1-5-21-\d+-\d+-\d+-519 # Group: Domain Computers # All workstations and servers joined to the domain S-1-5-21-\d+-\d+-\d+-515 # Group: Cert Publishers # Members of this group are permitted to publish certificates to the directory S-1-5-21-\d+-\d+-\d+-517 # Group: Domain Admins # Designated administrators of the domain #S-1-5-21-\d+-\d+-\d+-512 # Group: Domain Guests # All domain guests S-1-5-21-\d+-\d+-\d+-514 # Group: Schema Admins # Designated administrators of the schema S-1-5-21-\d+-\d+-\d+-518 # Group: Domain Users # All domain users S-1-5-21-\d+-\d+-\d+-513 # Group: Administrator # Built-in account for administering the computer/domain #S-1-5-21-\d+-\d+-\d+-500 # User: krbtgt # Key Distribution Center Service Account S-1-5-21-\d+-\d+-\d+-502 # User: Guest # Built-in account for guest access to the computer/domain S-1-5-21-\d+-\d+-\d+-501 zentyal-samba-2.3.12+quantal1ubuntu1/COPYING0000664000000000000000000004311012017560227015340 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. zentyal-samba-2.3.12+quantal1ubuntu1/stubs/0000775000000000000000000000000012017560227015446 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/stubs/vscan-clamav.conf.mas0000664000000000000000000000457312017560227021460 0ustar [samba-vscan] ; run-time configuration for vscan-samba using ; clamd ; all options are set to default values ; do not scan files larger than X bytes. If set to 0 (default), ; this feature is disable (i.e. all files are scanned) max file size = 104857600 ; log all file access (yes/no). If set to yes, every access will ; be logged. If set to no (default), only access to infected files ; will be logged verbose file logging = no ; if set to yes (default), a file will be scanned while opening scan on open = yes ; if set to yes, a file will be scanned while closing (default is yes) scan on close = yes ; if communication to clamd fails, should access to file denied? ; (default: yes) deny access on error = yes ; if daemon files with a minor error (corruption, etc.), ; should access to file denied? ; (default: yes) deny access on minor error = yes ; send a warning message via Windows Messenger service ; when virus is found? ; (default: yes) send warning message = yes ; what to do with an infected file ; quarantine: try to move to quantine directory ; delete: delete infected file ; nothing: do nothing (default) infected file action = quarantine ; where to put infected files - you really want to change this! quarantine directory = /var/lib/zentyal/quarantine/ ; prefix for files in quarantine quarantine prefix = vir- ; as Windows tries to open a file multiple time in a (very) short time ; of period, samba-vscan use a last recently used file mechanism to avoid ; multiple scans of a file. This setting specified the maximum number of ; elements of the last recently used file list. (default: 100) max lru files entries = 100 ; an entry is invalidad after lru file entry lifetime (in seconds). ; (Default: 5) lru file entry lifetime = 5 ; exclude files from being scanned based on the MIME-type! Semi-colon ; seperated list (default: empty list). Use this with care! exclude file types = ; socket name of clamd (default: /var/run/clamd). Setting will be ignored if ; libclamav is used clamd socket name = /var/run/clamav/clamd.ctl ; limits, if vscan-clamav was build for using the clamav library (libclamav) ; instead of clamd ; maximum number of files in archive (default: 1000) libclamav max files in archive = 1000 ; maximum archived file size, in bytes (default: 10 MB) libclamav max archived file size = 10485760 ; maximum recursion level (default: 5) libclamav max recursion level = 5 zentyal-samba-2.3.12+quantal1ubuntu1/stubs/smb.conf.mas0000664000000000000000000001012412017560227017653 0ustar <%args> $fs => 'ntvfs' $workgroup $netbiosName $description $ifaces $mode $realm @shares $roamingProfiles => 0 $profilesPath $printers => [] $antivirus => 0 $antivirus_exceptions => {} $recycle => 0 $recycle_exceptions => {} $recycle_config => {} $prefix => 'Zentyal' $backup_path => '/tmp' $quarantine_path => '/tmp' <%init> use EBox::Gettext; use EBox::Samba; [global] netbios name = <% $netbiosName %> workgroup = <% $workgroup %> server string = <% $description %> wins support = yes dns proxy = yes name resolve order = wins bcast host interfaces = <% $ifaces %> bind interfaces only = yes server role = <% $mode %> realm = <% $realm %> log level = 3 log file = /var/log/samba/samba.log passdb backend = samba4 idmap_ldb:use rfc2307 = yes % if ($fs eq 's3fs') { rpc_daemon:spoolssd = embedded % } else { dcerpc endpoint servers = epmapper, wkssvc, rpcecho, samr, netlogon, lsarpc, spoolss, drsuapi, dssetup, unixinfo, browser, eventlog6, backupkey, dnsserver, winreg, srvsvc server services = rpc, nbt, wrepl, ldap, cldap, kdc, drepl, winbind, ntp_signd, kcc, dnsupdate, smb % } ldap privileged socket mode = 0770 % if ($mode eq 'dc') { % if ($roamingProfiles) { [profiles] path = <% $profilesPath %> browseable = no read only = no % } [netlogon] path = /var/lib/samba/sysvol/<% $realm %>/scripts browseable = no read only = yes [sysvol] path = /var/lib/samba/sysvol read only = no % } [homes] comment = <% __('Home Directories') %> path = /home/%S read only = no browseable = no create mask = 0611 directory mask = 0711 % my $av = ($antivirus xor defined($antivirus_exceptions->{'users'})); % my $rb = ($recycle xor defined($recycle_exceptions->{'users'})); % my $objects = 'acl_xattr full_audit'; % if ($av) { % $objects .= ' zavs'; % } % if ($rb) { % $objects .= ' recycle'; % } vfs objects = <% $objects %> full_audit:success = connect opendir disconnect unlink mkdir rmdir open rename full_audit:failure = connect opendir disconnect unlink mkdir rmdir open rename % if ($rb) { % foreach my $key (keys %{$recycle_config}) { % next unless $key; recycle: <% $key %> = <% $recycle_config->{$key} %> % } % } % foreach my $share (@shares) { # Shares [<% $share->{share} %>] comment = <% $share->{comment} %> path = <% $share->{path} %> browseable = Yes read only = No force create mode = 0660 force directory mode = 0660 % my $av = ($antivirus xor defined($antivirus_exceptions->{'share'}->{$share->{'share'}})); % my $rb = ($recycle xor defined($recycle_exceptions->{'share'}->{$share->{'share'}})); % my $objects = 'acl_xattr full_audit'; % if ($av) { % $objects .= ' zavs'; % } % if ($rb) { % $objects .= ' recycle'; % } vfs objects = <% $objects %> full_audit:success = connect opendir disconnect unlink mkdir rmdir open rename full_audit:failure = connect opendir disconnect unlink mkdir rmdir open rename % if ($rb) { % foreach my $key (keys %{$recycle_config}) { % next unless $key; recycle: <% $key %> = <% $recycle_config->{$key} %> % } % } % } % foreach my $printer (@{$printers}) { [<% $printer->{name} %>] comment = "<% $printer->{description} %>" path = /var/spool/samba printable = yes read only = yes % if ($printer->{guest}) { guest ok = yes % } else { % my $acl = join (", ", @{$printer->{acl}}); valid users = <% $acl %> % } % } [print$] comment = "Printer Drivers" path = /var/lib/samba/printers browseable = yes read only = yes guest ok = no write list = @"Domain Admins" valid users = @"Domain Users" #[<% $prefix %>-internal-backups] # path = <% $backup_path %> # browseable = yes # read only = yes # valid users = @"Domain Admins" # admin users = @"Domain Admins" # force group = ebox # force user = ebox # #[<% $prefix %>-quarantine] # path = <% $quarantine_path %> # browseable = yes # read only = no # valid users = @"Domain Admins" # admin users = @"Domain Admins" zentyal-samba-2.3.12+quantal1ubuntu1/conf/0000775000000000000000000000000012017560227015233 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/conf/samba.conf0000664000000000000000000000367012017560227017173 0ustar # samba.conf - configuration file for zentyal-samba # # This file contains the most basic settings, most other stuff is configured # using the web interface. # # Everything after a '#' character is ignored # # All whitespace is ignored # # Config keys are set this way: # # key = value # # They may contain comments at the end: # # key = value # this is ignored # -- s4sync settings -- s4sync_debug = yes # -- File server -- # Choose the file server to use. The new 'ntvfs' included # in samba4 or the old 's3fs' from samba3. Printers and # vfs plugins such recycle bin, audit or antivirus will not # work if you choose 'ntvfs'. # values: ntvfs | s3fs samba_fs = ntvfs # -- Recycle Bin settings -- # Name of the recycle bin directory # If a full path like /tmp/foo is entered, # the same Recycle Bin will be used for all the shares repository = RecycleBin # Permissions of the recycle bin directory directory_mode = 0700 # Keep directory structure keeptree = Yes # Keep copies if a file is deleted more than once versions = Yes # Specifies whether a file's access date should be updated # when the file is moved to the repository. #touch = Yes # Files that are smaller than the number of bytes # specified by this parameter will not be put into # the repository. #minsize = 0 # Files that are larger than the number of bytes # specified by this parameter will not be put into # the Recycle Bin. (0 = disabled) maxsize = 0 # List of files that should not be stored when deleted, # but deleted in the regular way. #exclude = *.tmp|*.temp # When files from these directories are deleted, # they are not put into the recycle bin but are deleted # in the regular way. excludedir = /tmp|/var/tmp # Specifies a list of paths # (wildcards such as * and ? are supported) # for which no versioning should be used. # Only useful when versions is enabled. #noversions = *.foo|*.bar # -- End of Recycle Bin settings -- # Listen on external interfaces listen_external = no zentyal-samba-2.3.12+quantal1ubuntu1/src/0000775000000000000000000000000012017560227015075 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/0000775000000000000000000000000012017560227015732 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/0000775000000000000000000000000012017560227016755 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/0000775000000000000000000000000012017560227020015 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/AntivirusExceptions.pm0000664000000000000000000000720212017560227024402 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::Antivirus # # This model is used to configure antivirus settings for Samba shares # use strict; use warnings; package EBox::Samba::Model::AntivirusExceptions; use base 'EBox::Model::DataTable'; use EBox::Gettext; use EBox::Global; use EBox::Types::Select; # Constructor: new # # Create the new Antivirus table # # Overrides: # # # # Returns: # # - the newly created object # instance # sub new { my ($class, %opts) = @_; my $self = $class->SUPER::new(%opts); bless ($self, $class); return $self; } sub shareModel { return EBox::Global->modInstance('samba')->model('SambaShares'); } # Method: _table # # Overrides: # # # sub _table { my ($self) = @_; my @tableDesc = ( new EBox::Types::Union( fieldName => 'user_group_share', printableName => __('User/Group/Share'), subtypes => [ new EBox::Types::Union::Text( fieldName => 'users', unique => '1', printableName => __('User homes')), new EBox::Types::Select( fieldName => 'share', disableCache => 1, unique => 1, printableName => __('Share'), foreignModel => \&shareModel, foreignField => 'share', HTMLViewer => '/samba/ajax/viewer/shareViewer.mas', editable => 1) ] ), ); my $dataTable = { tableName => 'AntivirusExceptions', printableTableName => __('Samba shares antivirus exceptions'), modelDomain => 'Samba', defaultActions => [ 'add', 'del', 'changeView' ], tableDescription => \@tableDesc, class => 'dataTable', help => __('Add exceptions to the default antivirus settings'), printableRowName => __('exception'), }; return $dataTable; } sub syncRows { my ($self, $currentIds) = @_; my $anyChange = undef; my $shareModel = $self->parentModule->model('SambaShares'); for my $id (@{$currentIds}) { my $userGroupShare = $self->row($id)->elementByName('user_group_share'); my $remove; if ($userGroupShare->selectedType() eq 'share') { my $share = $shareModel->find(share => $userGroupShare->value()); unless (defined $share) { $self->removeRow($id, 1); $anyChange = 1; } } } return $anyChange; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/AntivirusDefault.pm0000664000000000000000000000451012017560227023644 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Class: EBox::Samba::Model::AntivirusDefault # # TODO: Document class # use strict; use warnings; package EBox::Samba::Model::AntivirusDefault; use EBox::Gettext; use EBox::Validate qw(:all); use EBox::Types::Port; use base 'EBox::Model::DataForm'; sub new { my $class = shift; my %parms = @_; my $self = $class->SUPER::new(@_); bless($self, $class); return $self; } sub _table { my @tableHead = ( new EBox::Types::Boolean( 'fieldName' => 'scan', 'printableName' => __('Enable virus scanning'), 'editable' => 1, 'defaultValue' => 0, ), ); my $dataTable = { 'tableName' => 'AntivirusDefault', 'printableTableName' => __('Antivirus default settings'), 'pageTitle' => undef, 'modelDomain' => 'Samba', 'defaultActions' => ['add', 'del', 'editField', 'changeView' ], 'tableDescription' => \@tableHead, 'help' => '', # FIXME }; return $dataTable; } sub precondition { my ($self) = @_; my $fs = EBox::Config::configkey('samba_fs'); my $s3fs = (defined $fs and $fs eq 's3fs'); return $s3fs; } sub preconditionFailMsg { my ($self) = @_; return __("You are using the new samba 'ntvfs' file server, " . "which is incompatible with vfs plugins such the " . "antivirus. If you wish to enable this feature, add " . "the Zentyal PPA to your APT sources.list and install " . "our samba4 package, then change the samba config key " . "'samba_fs' to 's3fs' in /etc/zentyal/samba.conf"); } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/RecycleExceptions.pm0000664000000000000000000000741512017560227024012 0ustar # Copyright (C) 2009-2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::RecycleExceptions # # This model is used to set Samba shares for the Recycle Bin # package EBox::Samba::Model::RecycleExceptions; use base 'EBox::Model::DataTable'; use strict; use warnings; use EBox::Gettext; use EBox::Global; use EBox::Types::Select; # Dependencies # Group: Public methods # Constructor: new # # Create the new RecycleExceptions table # # Overrides: # # # # Returns: # # - the newly created object # instance # sub new { my ($class, %opts) = @_; my $self = $class->SUPER::new(%opts); bless ($self, $class); return $self; } sub shareModel { return EBox::Global->modInstance('samba')->model('SambaShares'); } # Group: Protected methods # Method: _table # # Overrides: # # # sub _table { my ($self) = @_; my @tableDesc = ( new EBox::Types::Union( fieldName => 'user_group_share', printableName => __('User/Group/Share'), subtypes => [ new EBox::Types::Union::Text( fieldName => 'users', unique => '1', printableName => __('User homes')), new EBox::Types::Select( fieldName => 'share', disableCache => 1, unique => 1, printableName => __('Share'), foreignModel => \&shareModel, foreignField => 'share', HTMLViewer => '/samba/ajax/viewer/shareViewer.mas', editable => 1) ] ), ); my $dataTable = { tableName => 'RecycleExceptions', printableTableName => __('Samba shares Recycle Bin exceptions'), modelDomain => 'Samba', defaultActions => [ 'add', 'del', 'changeView' ], tableDescription => \@tableDesc, class => 'dataTable', help => __('Add exceptions to the default Recycle Bin settings'), printableRowName => __('exception'), }; return $dataTable; } sub syncRows { my ($self, $currentIds) = @_; my $anyChange = undef; my $shareModel = $self->parentModule->model('SambaShares'); for my $id (@{$currentIds}) { my $userGroupShare = $self->row($id)->elementByName('user_group_share'); my $remove; if ($userGroupShare->selectedType() eq 'share') { my $share = $shareModel->find(share => $userGroupShare->value()); unless (defined $share) { $self->removeRow($id, 1); $anyChange = 1; } } } return $anyChange; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/GeneralSettings.pm0000664000000000000000000003244612017560227023462 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::GeneralSettings # # This model is used to configure file sharing eneral settings. # package EBox::Samba::Model::GeneralSettings; use EBox::Gettext; use EBox::Validate qw(:all); use Error qw(:try); use Encode; use EBox::Samba; use EBox::Types::Union; use EBox::Types::Union::Text; use EBox::Types::Boolean; use EBox::Types::DomainName; use EBox::Types::Text; use EBox::Types::Int; use EBox::Types::Select; use EBox::Config; use EBox::View::Customizer; use EBox::Exceptions::External; use strict; use warnings; use base 'EBox::Model::DataForm'; use constant MAXNETBIOSLENGTH => 15; use constant MAXWORKGROUPLENGTH => 32; use constant MAXDESCRIPTIONLENGTH => 255; use constant MODE_DC => 'dc'; use constant MODE_ADC => 'adc'; # see http://support.microsoft.com/kb/909264 my @reservedNames = ( 'ANONYMOUS', 'AUTHENTICATED USER', 'BATCH', 'BUILTIN', 'CREATOR GROUP', 'CREATOR GROUP SERVER', 'CREATOR OWNER', 'CREATOR OWNER SERVER', 'DIALUP', 'DIGEST AUTH', 'INTERACTIVE', 'INTERNET', 'LOCAL', 'LOCAL SYSTEM', 'NETWORK', 'NETWORK SERVICE', 'NT AUTHORITY', 'NT DOMAIN', 'NTLM AUTH', 'NULL', 'PROXY', 'REMOTE INTERACTIVE', 'RESTRICTED', 'SCHANNEL AUTH', 'SELF', 'SERVER', 'SERVICE', 'SYSTEM', 'TERMINAL SERVER', 'THIS ORGANIZATION', 'USERS', 'WORLD', ); sub new { my $class = shift; my %parms = @_; my $self = $class->SUPER::new(@_); bless ($self, $class); return $self; } # Method: validateTypedRow # # Override method # sub validateTypedRow { my ($self, $action, $oldParams, $newParams) = @_; my $netbios = exists $newParams->{'netbiosName'} ? $newParams->{'netbiosName'}->value() : $oldParams->{'netbiosName'}->value(); my $workgroup = exists $newParams->{'workgroup'} ? $newParams->{'workgroup'}->value() : $oldParams->{'workgroup'}->value(); my $realm = exists $newParams->{'realm'} ? $newParams->{'realm'}->value() : $oldParams->{'realm'}->value(); my $description = exists $newParams->{'description'} ? $newParams->{'description'}->value() : $oldParams->{'description'}->value(); if (uc ($netbios) eq uc ($workgroup)) { throw EBox::Exceptions::External( __('NetBIOS computer name and NetBIOS domain name must be different')); } $self->_checkNetbiosName($netbios); $self->_checkNetbiosName($workgroup); $self->_checkDomainName($realm); $self->_checkDescriptionString($description); # Check if the password meet the policy requirements if (exists $newParams->{password}) { my $password = $newParams->{password}->value(); # Check if the password meet the complexity constraints unless ($password =~ /[a-z]+/ and $password =~ /[A-Z]+/ and $password =~ /[0-9]+/ and length ($password) >=8) { throw EBox::Exceptions::External( __('The password does not meet the password policy requirements. ' . 'It must be at least eight characters long and contain uppercase, ' . 'lowercase and numbers')); } } } sub _checkDomainName { my ($self, $domain) = @_; if (length ($domain) > MAXWORKGROUPLENGTH) { throw EBox::Exceptions::External(__('Domain or workgroup name is too long')); } if (length ($domain) <= 0) { throw EBox::Exceptions::External(__('Domain or workgroup name field is empty')); } if ($domain =~ m/\.local$/) { throw EBox::Exceptions::External(__(q{Domain name cannot end in '.local'})); } $self->_checkWinName($domain, __('Domain name')); my $sysinfo = EBox::Global->modInstance('sysinfo'); if (lc ($domain) eq lc ($sysinfo->hostName())) { throw EBox::Exceptions::External(__('Domain name cannot be equal to host name')); } } sub _checkNetbiosName { my ($self, $netbios) = @_; if (length ($netbios) <= 0) { throw EBox::Exceptions::External(__('NetBIOS name field is empty')); } if (length ($netbios) > MAXNETBIOSLENGTH) { throw EBox::Exceptions::External(__('NetBIOS name is too long')); } if ($netbios =~ m/\./) { throw EBox::Exceptions::External(__('NetBIOS names cannot contain dots')); } $self->_checkWinName($netbios, __('NetBIOS computer name')); } sub _checkDescriptionString { my ($self, $description) = @_; if (length ($description) <= 0) { throw EBox::Exceptions::External(__('Description string is empty')); } if (length ($description) > MAXDESCRIPTIONLENGTH) { throw EBox::Exceptions::Externam(__('Description string is too long')); } } sub _checkWinName { my ($self, $name, $type) = @_; my $length = length $name; if ($length > MAXNETBIOSLENGTH) { throw EBox::Exceptions::External( __x('{type} is limited to a maximum of 15 characters.', type => $type) ); } my @parts = split ('\.', $name); foreach my $part (@parts) { $part = uc $part; foreach my $reserved (@reservedNames) { if ($part eq $reserved) { throw EBox::Exceptions::External( __x(q{{type} cannot contain the reserved name {reserved}}, type => $type, reserved => $reserved) ); } } } } sub _table { my ($self) = @_; my @tableHead = ( new EBox::Types::Select( fieldName => 'mode', printableName => __('Server Role'), populate => \&_server_roles, editable => 1, ), new EBox::Types::DomainName( fieldName => 'realm', printableName => __('Realm'), defaultValue => EBox::Global->modInstance('users')->kerberosRealm(), editable => 0, ), new EBox::Types::DomainName( fieldName => 'dcfqdn', printableName => __('Domain controller FQDN'), editable => 1, ), new EBox::Types::HostIP( fieldName => 'dnsip', printableName => __('Domain DNS server IP'), editable => 1, ), new EBox::Types::Text( # This is the administrator account used to join the zentyal # server to an existent domain fieldName => 'adminAccount', printableName => __('Administrator account'), editable => 1, ), new EBox::Types::Text( fieldName => 'password', printableName => __('Administrator password'), defaultValue => EBox::Samba::defaultAdministratorPassword(), editable => 1, ), new EBox::Types::DomainName( fieldName => 'workgroup', printableName => __('NetBIOS domain name'), defaultValue => EBox::Samba::defaultWorkgroup(), editable => 1, ), new EBox::Types::Text( fieldName => 'netbiosName', printableName => __('NetBIOS computer name'), defaultValue => EBox::Samba::defaultNetbios(), editable => 0, ), new EBox::Types::Text( fieldName => 'description', printableName => __('Server description'), defaultValue => EBox::Samba::defaultDescription(), editable => 1, ), new EBox::Types::Boolean( fieldName => 'roaming', printableName => __('Enable roaming profiles'), defaultValue => 0, editable => 1, ), new EBox::Types::Select( fieldName => 'drive', printableName => __('Drive letter'), populate => \&_drive_letters, editable => 1, ), ); my $dataTable = { tableName => 'GeneralSettings', printableTableName => __('General settings'), modelDomain => 'Samba', defaultActions => [ 'editField', 'changeView' ], tableDescription => \@tableHead, confirmationDialog => { submit => \&confirmReprovision }, help => __('On this page you can set different general settings for Samba'), }; return $dataTable; } sub updatedRowNotify { my ($self, $row, $oldRow, $force) = @_; my $newMode = $row->valueByName('mode'); my $oldMode = defined $oldRow ? $oldRow->valueByName('mode') : $newMode; my $newRealm = $row->valueByName('realm'); my $oldRealm = defined $oldRow ? $oldRow->valueByName('realm') : $newRealm; my $newDomain = $row->valueByName('workgroup'); my $oldDomain = defined $oldRow ? $oldRow->valueByName('workgroup') : $newDomain; if ($newMode ne $oldMode or $newRealm ne $oldRealm or $newDomain ne $oldDomain) { EBox::debug('Domain rename detected, clearing the provisioned flag'); my $sambaMod = $self->parentModule(); $sambaMod->setProvisioned(0); } my $newAdminPwd = $row->valueByName('password'); my $oldAdminPwd = defined $oldRow ? $oldRow->valueByName('password') : $newAdminPwd; if ($newAdminPwd ne $oldAdminPwd) { EBox::debug('Changing samba admin password'); # The DC expect the pwd quoted and UTF16-LE encoded $newAdminPwd = Encode::encode('UTF16-LE', '"' . $newAdminPwd . '"'); $oldAdminPwd = Encode::encode('UTF16-LE', '"' . $oldAdminPwd . '"'); # Get the DN of the administrator account my $ldb = $self->parentModule()->ldb(); my $args = { base => $ldb->dn(), scope => 'sub', filter => '(samAccountName=Administrator)', attrs => [], }; my $msg = $ldb->search($args); return unless ($msg->count() == 1); my $entry = $msg->entry(0); my $dn = $entry->dn(); # And replace the unicodePwd attribute $args = { changes => [ delete => [ unicodePwd => $oldAdminPwd ], add => [ unicodePwd => $newAdminPwd ], ], }; $msg = $ldb->modify($dn, $args); EBox::debug('Samba administrator password changed successfully'); } } sub confirmReprovision { my ($self, $params) = @_; my $newRealm = $params->{realm}; my $oldRealm = $self->value('realm'); my $newDomain = $params->{workgroup}; my $oldDomain = $self->value('workgroup'); my $newMode = $params->{mode}; my $oldMode = $self->value('mode'); return undef if ($newRealm eq $oldRealm and $newDomain eq $oldDomain and $newMode eq $oldMode); if ($newMode eq 'dc') { return __("Changing the domain name will cause to reprovision the samba database.\n\n" . 'The users and groups will be imported from Zentyal LDAP, but you will have to ' . 'rejoin all computers to the new domain.'); } elsif ($newMode eq 'adc') { return __("Joining a domain will delete all your users and groups from Zentyal and import " . "the domain ones."); } return undef; } # Populate the server role select sub _server_roles { my $roles = []; push (@{$roles}, { value => MODE_DC, printableValue => __('Domain controller')}); push (@{$roles}, { value => MODE_ADC, printableValue => __('Additional domain controller')}); # FIXME # These roles are disabled until implemented, we should also use better names #push (@roles, { value => 'standalone', printableValue => __('Standalone')}); return $roles; } sub _drive_letters { my $letters; foreach my $letter ('H'..'Z') { $letter .= ':'; push (@{$letters}, { value => $letter, printableValue => $letter }); } return $letters; } # Method: headTile # # Overrides # sub headTitle { return undef; } # Method: viewCustomizer # # Overrides # sub viewCustomizer { my ($self) = @_; my $actions = { mode => { dc => { hide => ['dcfqdn', 'dnsip','adminAccount'], }, adc => { show => ['dcfqdn','dnsip','adminAccount'], }, }, }; my $customizer = new EBox::View::Customizer(); $customizer->setModel($self); $customizer->setOnChangeActions($actions); $customizer->setHTMLTitle([]); $customizer->setInitHTMLStateOrder(['mode']); return $customizer; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/SambaDeletedShares.pm0000664000000000000000000000650512017560227024041 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::SambaDeletedShares # # This model is used to store the samba shares which are removed by the user. # Zentyal configuration works as follows: # # - User add/remove stuff on the GUI # - Once is done he saves changes and the changes take places # - We need to actually remove the directories at saving changes time, # so we have to write down which directories we must remove # package EBox::Samba::Model::SambaDeletedShares; use base 'EBox::Model::DataTable'; use strict; use warnings; use EBox::Gettext; use EBox::Global; use EBox::Types::Text; use EBox::Sudo; use Error qw(:try); # Dependencies # Group: Public methods # Constructor: new # # Create the new deleted Samba shares table # # Overrides: # # # # Returns: # # - the newly created object # instance # sub new { my ($class, %opts) = @_; my $self = $class->SUPER::new(%opts); bless ( $self, $class); return $self; } # Method: removeDirs # # This method is used to remove the share directories. It must be used # in saving changes time. # sub removeDirs { my ($self) = @_; for my $id ( @{$self->ids()}) { my $row = $self->row($id); my $path = EBox::Samba::SHARES_DIR(); $path .= $row->elementByName('path')->value(); unless ( -d $path ) { $self->removeRow($row->id(), 1); next; } try { EBox::Sudo::root("rm -rf $path"); } otherwise { EBox::warn("Couldn't remove $path"); }; $self->removeRow($id, 1); } } # Group: Protected methods # Method: _table # # Overrides: # # # sub _table { my ($self) = @_; my @tableDesc = ( new EBox::Types::Text( fieldName => 'path', printableName => __('path'), editable => 1, unique => 1, ), ); my $dataTable = { tableName => 'SambaDeletedShares', printableTableName => 'Deleted shares', modelDomain => 'Samba', defaultActions => [ 'add', 'del', 'editField', 'changeView' ], tableDescription => \@tableDesc, class => 'dataTable', help => '', printableRowName => __('share'), }; return $dataTable; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/RecycleDefault.pm0000664000000000000000000000500312017560227023244 0ustar # Copyright (C) 2009-2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Class: EBox::Samba::Model::RecycleDefault # # TODO: Document class # package EBox::Samba::Model::RecycleDefault; use EBox::Gettext; use EBox::Validate qw(:all); use EBox::Types::Port; use strict; use warnings; use base 'EBox::Model::DataForm'; sub new { my $class = shift; my %parms = @_; my $self = $class->SUPER::new(@_); bless($self, $class); return $self; } sub pageTitle { return __('Recycle default settings'); } sub _table { my @tableHead = ( new EBox::Types::Boolean( 'fieldName' => 'enabled', 'printableName' => __('Enable recycle bin'), 'editable' => 1, 'defaultValue' => 0 ), ); my $dataTable = { 'tableName' => 'RecycleDefault', 'printableTableName' => __('Recycle Bin default settings'), 'modelDomain' => 'Samba', 'defaultActions' => ['add', 'del', 'editField', 'changeView' ], 'tableDescription' => \@tableHead, 'help' => 'If Recycle Bin is enabled on a share, the deleted files on the share are stored on it instead of being deleted forever. This is the default setting that can be overrided by adding exceptions.', }; return $dataTable; } sub precondition { my ($self) = @_; my $fs = EBox::Config::configkey('samba_fs'); my $s3fs = (defined $fs and $fs eq 's3fs'); return ($s3fs); } sub preconditionFailMsg { my ($self) = @_; return __("You are using the new samba 'ntvfs' file server, " . "which is incompatible with vfs plugins such the " . "recycle bin. If you wish to enable this feature, add " . "the Zentyal PPA to your APT sources.list and install " . "our samba4 package, then change the samba config key " . "'samba_fs' to 's3fs' in /etc/zentyal/samba.conf"); } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/SambaSharePermissions.pm0000664000000000000000000001661612017560227024627 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::SambaShareConfiguration # # This model is used to configure permissions of each share # created in EBox::Samba::Model::SambaShares # package EBox::Samba::Model::SambaSharePermissions; use base 'EBox::Model::DataTable'; use strict; use warnings; use EBox::Exceptions::DataExists; use EBox::Gettext; use EBox::Global; use EBox::Samba::Types::Select; use EBox::View::Customizer; # Dependencies use Error qw(:try); # Group: Public methods # Constructor: new # # Create the new Samba shares table # # Overrides: # # # # Returns: # # - the newly created object # instance # sub new { my ($class, %opts) = @_; my $self = $class->SUPER::new(%opts); bless ( $self, $class); return $self; } sub populateUser { my $userMod = EBox::Global->modInstance('users'); my @users = (); my $list = $userMod->users(); foreach my $u (@{$list}) { my $gr = {}; $gr->{value} = $u->get('uid'); $gr->{printableValue} = $u->name(); push (@users, $gr); } return \@users; } sub populateGroup { my $userMod = EBox::Global->modInstance('users'); my @groups = (); my $list = $userMod->groups(); foreach my $g (@{$list}) { my $gr = {}; $gr->{value} = $g->get('cn'); $gr->{printableValue} = $g->name(); push (@groups, $gr); } return \@groups; } sub populatePermissions { return [ { value => 'readOnly', printableValue => __('Read only') }, { value => 'readWrite', printableValue => __('Read and write') }, { value => 'administrator', printableValue => __('Administrator') } ]; } sub validateTypedRow { my ($self, $action, $params) = @_; # we check that user_group is unique here bz union does nto seem to work my $user_group = $params->{user_group}; if (not defined $user_group) { return; } my $selected = $user_group->selectedType(); my $value = $user_group->value(); foreach my $id (@{ $self->ids() }) { my $row = $self->row($id); my $rowUserGroup =$row->elementByName('user_group'); if ($value ne $rowUserGroup->value()) { next; } if ($selected eq $rowUserGroup->selectedType()) { throw EBox::Exceptions::DataExists( 'data' => __('User/Group'), 'value' => "$selected/$value", ); } } } sub syncRows { my ($self, $currentIds) = @_; my $anyChange = undef; for my $id (@{$currentIds}) { my $userGroup = $self->row($id)->printableValueByName('user_group'); unless(defined($userGroup) and length ($userGroup) > 0) { $self->removeRow($id, 1); $anyChange = 1; } } return $anyChange; } # Method: viewCustomizer # # Overrides to provide a # custom HTML title with breadcrumbs and to warn the user about the # usage of this is only useful if the share does not allow guest # access # # Overrides: # # # sub viewCustomizer { my ($self) = @_; my $custom = $self->SUPER::viewCustomizer(); $custom->setHTMLTitle([ { title => __('Shares'), link => '/Samba/Composite/General#SambaShares', }, { title => $self->parentRow()->valueByName('share'), link => '' } ]); if ($self->parentRow()->valueByName('guest')) { $custom->setPermanentMessage( __('Any access control is disabled if the guest access is allowed.') ); } else { $custom->setPermanentMessage(''); } return $custom; } # Group: Protected methods # Method: _table # # Overrides: # # # sub _table { my ($self) = @_; my @tableDesc = ( new EBox::Types::Union( fieldName => 'user_group', printableName => __('User/Group'), subtypes => [ new EBox::Samba::Types::Select( fieldName => 'user', printableName => __('User'), populate => \&populateUser, editable => 1), new EBox::Samba::Types::Select( fieldName => 'group', printableName => __('Group'), populate => \&populateGroup, editable => 1) ], unique => 1, filter => \&filterUserGroupPrintableValue, ), new EBox::Types::Select( fieldName => 'permissions', printableName => __('Permissions'), populate => \&populatePermissions, editable => 1, help => _permissionsHelp() ) ); my $dataTable = { tableName => 'SambaSharePermissions', printableTableName => __('Access Control'), modelDomain => 'Samba', menuNamespace => 'Samba/View/SambaShares', defaultActions => [ 'add', 'del', 'editField', 'changeView' ], tableDescription => \@tableDesc, class => 'dataTable', help => '', printableRowName => __('ACL'), insertPosition => 'back', }; return $dataTable; } # Private methods sub _permissionsHelp { return __('Be careful if you grant administrator privileges.' . 'User will be able to read and write any file in the share.'); } sub filterUserGroupPrintableValue { my ($element) = @_; my $selectedType = $element->selectedType(); my $value = $element->value(); if ($selectedType eq 'user') { return $value . __(' (user))') } elsif ($selectedType eq 'group') { return $value . __(' (group))') } return $value; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Model/SambaShares.pm0000664000000000000000000003424612017560227022555 0ustar # Copyright (C) 2008-2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Model::SambaShares # # This model is used to configure shares different to those which are # given by the group share # package EBox::Samba::Model::SambaShares; use base 'EBox::Model::DataTable'; use strict; use warnings; use Cwd 'abs_path'; use String::ShellQuote; use EBox::Gettext; use EBox::Global; use EBox::Types::Text; use EBox::Types::Union; use EBox::Types::Boolean; use EBox::Model::Manager; use EBox::Exceptions::DataInUse; use EBox::Sudo; use Error qw(:try); use constant DEFAULT_MASK => '0700'; use constant DEFAULT_USER => 'root'; use constant DEFAULT_GROUP => 'root'; use constant GUEST_DEFAULT_MASK => '0777'; use constant GUEST_DEFAULT_USER => 'nobody'; use constant GUEST_DEFAULT_GROUP => 'nogroup'; use constant FILTER_PATH => ('/bin', '/boot', '/dev', '/etc', '/lib', '/root', '/proc', '/run', '/sbin', '/sys', '/var', '/usr'); # Dependencies # Group: Public methods # Constructor: new # # Create the new Samba shares table # # Overrides: # # # # Returns: # # - the newly created object # instance # sub new { my ($class, %opts) = @_; my $self = $class->SUPER::new(%opts); bless ($self, $class); return $self; } # Group: Protected methods # Method: _table # # Overrides: # # # sub _table { my ($self) = @_; my @tableDesc = ( new EBox::Types::Text( fieldName => 'share', printableName => __('Share name'), editable => 1, unique => 1, ), new EBox::Types::Union( fieldName => 'path', printableName => __('Share path'), subtypes => [ new EBox::Types::Text( fieldName => 'zentyal', printableName => __('Directory under Zentyal'), editable => 1, unique => 1, ), new EBox::Types::Text( fieldName => 'system', printableName => __('File system path'), editable => 1, unique => 1, ), ], help => _pathHelp($self->parentModule()->SHARES_DIR())), new EBox::Types::Text( fieldName => 'comment', printableName => __('Comment'), editable => 1, ), new EBox::Types::Boolean( fieldName => 'guest', printableName => __('Guest access'), editable => 1, defaultValue => 0, help => __('This share will not require authentication.'), ), new EBox::Types::HasMany( fieldName => 'access', printableName => __('Access control'), foreignModel => 'SambaSharePermissions', view => '/Samba/View/SambaSharePermissions' ), # This hidden field is filled with the group name when the share is configured as # a group share through the group addon new EBox::Types::Text( fieldName => 'groupShare', hidden => 1, optional => 1, ), ); my $dataTable = { tableName => 'SambaShares', printableTableName => __('Shares'), modelDomain => 'Samba', defaultActions => [ 'add', 'del', 'editField', 'changeView' ], tableDescription => \@tableDesc, menuNamespace => 'Samba/View/SambaShares', class => 'dataTable', help => _sharesHelp(), printableRowName => __('share'), enableProperty => 1, defaultEnabledValue => 1, orderedBy => 'share', }; return $dataTable; } # Method: validateTypedRow # # Override method # # Check if the share path is allowed or not sub validateTypedRow { my ($self, $action, $parms) = @_; return unless ($action eq 'add' or $action eq 'update'); if (exists $parms->{'path'}) { my $path = $parms->{'path'}->selectedType(); if ($path eq 'system') { # Check if it is an allowed system path my $normalized = abs_path($parms->{'path'}->value()); foreach my $filterPath (FILTER_PATH) { if ($normalized =~ /^$filterPath/) { throw EBox::Exceptions::External( __x('Path not allowed. It cannot be under {dir}', dir => $normalized ) ); } } EBox::Validate::checkAbsoluteFilePath($parms->{'path'}->value(), __('Samba share absolute path') ); } else { # Check if it is a valid directory my $dir = $parms->{'path'}->value(); EBox::Validate::checkFilePath($dir, __('Samba share directory')); } } } # Method: removeRow # # Override method # # Overriden to warn the user if the directory is not empty # sub removeRow { my ($self, $id, $force) = @_; my $row = $self->row($id); if ($force or $row->elementByName('path')->selectedType() eq 'system') { return $self->SUPER::removeRow($id, $force); } my $path = $self->parentModule()->SHARES_DIR() . '/' . $row->valueByName('path'); unless ( -d $path) { return $self->SUPER::removeRow($id, $force); } opendir (my $dir, $path); while(my $entry = readdir ($dir)) { next if($entry =~ /^\.\.?$/); closedir ($dir); throw EBox::Exceptions::DataInUse( __('The directory is not empty. Are you sure you want to remove it?')); } closedir($dir); return $self->SUPER::removeRow($id, $force); } # Method: deletedRowNotify # # Override method # # Write down shares directories to be removed when saving changes # sub deletedRowNotify { my ($self, $row) = @_; my $path = $row->elementByName('path'); # We are only interested in shares created under /home/samba/shares return unless ($path->selectedType() eq 'zentyal'); my $mgr = EBox::Model::Manager->instance(); my $deletedModel = $mgr->model('SambaDeletedShares'); $deletedModel->addRow('path' => $path->value()); } # Method: createDirs # # This method is used to create the necessary directories for those # shares which must live under /home/samba/shares # We must set here both POSIX ACLs and navite NT ACLs. If we only set # POSIX ACLs, a user can change the permissions in the security tab # of the share. To avoid it we set also navive NT ACLs and set the # owner of the share to 'Domain Admins'. # sub createDirs { my ($self) = @_; my $sambaModule = $self->parentModule(); my $ldb = $sambaModule->ldb(); my $domainSid = $ldb->domainSID(); my $domainAdminsSid = $domainSid . '-512'; my $domainUsersSid = $domainSid . '-513'; for my $id (@{$self->ids()}) { my $row = $self->row($id); my $pathType = $row->elementByName('path'); my $guestAccess = $row->valueByName('guest'); next unless ( $pathType->selectedType() eq 'zentyal'); my $path = $self->parentModule()->SHARES_DIR() . '/' . $pathType->value(); my @cmds = (); push (@cmds, "mkdir -p '$path'"); if ($guestAccess) { push (@cmds, 'chmod ' . GUEST_DEFAULT_MASK . " '$path'"); push (@cmds, 'chown ' . GUEST_DEFAULT_USER . ':' . GUEST_DEFAULT_GROUP . " '$path'"); } else { push (@cmds, 'chmod ' . DEFAULT_MASK . " '$path'"); push (@cmds, 'chown ' . DEFAULT_USER . ':' . DEFAULT_GROUP . " '$path'"); } push (@cmds, "setfacl -b $path"); # Clear POSIX ACLs EBox::Sudo::root(@cmds); if ($guestAccess) { my $ntACL = ''; $ntACL .= "O:$domainAdminsSid"; # Object's owner $ntACL .= "G:$domainUsersSid"; # Object's primary group my $aceString = '(A;OICI;0x001301BF;;;S-1-1-0)'; $ntACL .= "D:$aceString"; my $cmd = EBox::Samba::SAMBATOOL() . " ntacl set '$ntACL' '$path'"; try { EBox::Sudo::root($cmd); } otherwise { my $error = shift; EBox::error("Coundn't enable NT ACLs for $path: $error"); }; next; } # Build the security descriptor string my $ntACL = ''; $ntACL .= "O:$domainAdminsSid"; # Object's owner $ntACL .= "G:$domainUsersSid"; # Object's primary group # Build the ACS strings my @aceStrings = (); push (@aceStrings, '(A;;0x001f01ff;;;SY)'); # SYSTEM account has full access push (@aceStrings, "(A;;0x001f01ff;;;$domainAdminsSid)"); # Domain admins have full access # Posix ACL my @posixACL; push (@posixACL, 'u:root:rwx'); push (@posixACL, 'g::---'); push (@posixACL, 'g:' . DEFAULT_GROUP . ':---'); for my $subId (@{$row->subModel('access')->ids()}) { my $subRow = $row->subModel('access')->row($subId); my $permissions = $subRow->elementByName('permissions'); my $userType = $subRow->elementByName('user_group'); my $perm; if ($userType->selectedType() eq 'group') { $perm = 'g:'; } elsif ($userType->selectedType() eq 'user') { $perm = 'u:'; } my $account = $userType->printableValue(); my $qobject = shell_quote($account); $perm .= $qobject . ':'; my $aceString = '(A;OICI;'; if ($permissions->value() eq 'readOnly') { $aceString .= '0x001200A9;'; $perm .= 'rx'; } elsif ($permissions->value() eq 'readWrite') { $aceString .= '0x001301BF;'; $perm .= 'rwx'; } elsif ($permissions->value() eq 'administrator') { $aceString .= '0x001F01FF;'; $perm .= 'rwx'; } else { my $type = $permissions->value(); EBox::error("Unknown share permission type '$type'"); next; } push (@posixACL, $perm); # Account Sid my $object = new EBox::Samba::LdbObject(samAccountName => $account); if ($object->exists()) { $aceString .= ';;' . $object->sid() . ')'; push (@aceStrings, $aceString); } } if (@posixACL) { try { my $cmd = 'setfacl -R -m ' . join(',', @posixACL) . " $path"; my $defaultCmd = 'setfacl -R -m d:' . join(',d:', @posixACL) ." $path"; EBox::Sudo::root($cmd); EBox::Sudo::root($defaultCmd); } otherwise { my $error = shift; EBox::debug("Couldn't enable POSIX ACLs for $path: $error") }; } if (@aceStrings) { try { my $fullAce = join ('', @aceStrings); $ntACL .= "D:$fullAce"; my $cmd = EBox::Samba::SAMBATOOL() . " ntacl set '$ntACL' '$path'"; EBox::Sudo::root($cmd); } otherwise { my $error = shift; EBox::error("Coundn't enable NT ACLs for $path: $error"); }; } } } # Private methods sub _pathHelp { my ($sharesPath) = @_; return __x( '{openit}Directory under Zentyal{closeit} will ' . 'automatically create the share.' . "directory in {sharesPath} {br}" . '{openit}File system path{closeit} will allow you to share '. 'an existing directory within your file system', sharesPath => $sharesPath, openit => '', closeit => '', br => '
'); } sub _sharesHelp { return __('Here you can create shares with more fine-grained permission ' . 'control. ' . 'You can use an existing directory or pick a name and let Zentyal ' . 'create it for you.'); } # Method: headTile # # Overrides # # sub headTitle { return undef; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Group.pm0000664000000000000000000001574312017560227020421 0ustar #!/usr/bin/perl # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::Group # # Samba group, stored in samba LDAP # package EBox::Samba::Group; use strict; use warnings; use EBox::Global; use EBox::Gettext; use EBox::Exceptions::External; use EBox::Exceptions::InvalidData; use EBox::UsersAndGroups::User; use EBox::UsersAndGroups::Group; use Perl6::Junction qw(any); use Error qw(:try); use constant MAXGROUPLENGTH => 128; use base 'EBox::Samba::LdbObject'; sub new { my $class = shift; my %opts = @_; my $self = $class->SUPER::new(@_); bless ($self, $class); return $self; } # Method: removeAllMembers # # Remove all members in the group # sub removeAllMembers { my ($self, $lazy) = @_; $self->set('member', [], $lazy); } # Method: addMember # # Adds the given user as a member # # Parameters: # # user - User object # sub addMember { my ($self, $user, $lazy) = @_; my @members = $self->get('member'); # return if user already in the group foreach my $dn (@members) { if (lc ($dn) eq lc ($user->dn())) { return; } } push (@members, $user->dn()); $self->set('member', \@members, $lazy); } # Method: removeMember # # Removes the given user as a member # # Parameters: # # user - User object # sub removeMember { my ($self, $user, $lazy) = @_; my @members; foreach my $dn ($self->get('member')) { push (@members, $dn) if (lc ($dn) ne lc ($user->dn())); } $self->set('member', \@members, $lazy); } # Method: users # # Return the list of members for this group # # Returns: # # arrary ref of members (EBox::Samba::User) # sub users { my ($self) = @_; my @members = $self->get('member'); @members = map { new EBox::Samba::User(dn => $_) } @members; return \@members; } # Method: usersNotIn # # Users that don't belong to this group # # Returns: # # array ref of EBox::UsersAndGroups::Group objects # sub usersNotIn { my ($self, $system) = @_; my $dn = $self->dn(); my %attrs = ( base => $self->_ldap->dn(), filter => "(&(objectclass=posixAccount)(!(memberof=$dn)))", scope => 'sub', ); my $result = $self->_ldap->search(\%attrs); my @users; if ($result->count > 0) { foreach my $entry ($result->sorted('uid')) { push (@users, new EBox::Samba::User(entry => $entry)); } } return \@users; } sub setupGidMapping { my ($self, $gidNumber) = @_; # NOTE Samba4 beta2 support rfc2307, reading uidNumber from ldap instead idmap.ldb, but # it is not working when the user init session as DOMAIN/user but user@domain.com # FIXME Remove this when fixed my $type = $self->_ldap->idmap->TYPE_GID(); $self->_ldap->idmap->setupNameMapping($self->sid(), $type, $gidNumber); } # Method: create # # Adds a new group # # Parameters: # # group - group name # comment - comment's group # system - boolan: if true it adds the group as system group, # otherwise as normal group # ignoreMods - ldap modules to be ignored on addUser notify # ignoreSlaves - slaves to be ignored on addUser notify # sub create { my ($self, $samAccountName, $params) = @_; # TODO Is the group added to the default OU? my $baseDn = $self->_ldap->dn(); my $dn = "CN=$samAccountName,CN=Users,$baseDn"; $self->_checkAccountName($samAccountName, MAXGROUPLENGTH); $self->_checkAccountNotExists($samAccountName); my $usersModule = EBox::Global->modInstance('users'); my $realm = $usersModule->kerberosRealm(); my $attr = []; push ($attr, objectClass => ['top', 'group', 'posixGroup']); push ($attr, sAMAccountName => "$samAccountName"); push ($attr, gidNumber => $params->{gidNumber}) if defined $params->{gidNumber}; push ($attr, description => $params->{description}) if defined $params->{description}; # Add the entry my $result = $self->_ldap->add($dn, { attr => $attr }); my $createdGroup = new EBox::Samba::Group(dn => $dn); # Setup the gid mapping $createdGroup->setupGidMapping($params->{gidNumber}) if defined $params->{gidNumber}; return $createdGroup; } sub addToZentyal { my ($self) = @_; my $gid = $self->get('samAccountName'); my $comment = $self->get('description'); my %optParams; $optParams{ignoreMods} = ['samba']; EBox::info("Adding samba group '$gid' to Zentyal"); try { EBox::UsersAndGroups::Group->create($gid, $comment, 0, %optParams); } otherwise {}; } sub updateZentyal { my ($self) = @_; my $gid = $self->get('samAccountName'); EBox::info("Updating zentyal group '$gid'"); my $zentyalGroup = undef; try { my $desc = $self->get('description'); $zentyalGroup = new EBox::UsersAndGroups::Group(gid => $gid); $zentyalGroup->setIgnoredModules(['samba']); return unless $zentyalGroup->exists(); $zentyalGroup->set('description', $desc, 1); $zentyalGroup->save(); } otherwise {}; return unless defined $zentyalGroup; try { $self->_membersToZentyal($zentyalGroup); } otherwise { my $error = shift; EBox::error("Error: $error"); }; } sub _membersToZentyal { my ($self, $zentyalGroup) = @_; return unless (defined $zentyalGroup and $zentyalGroup->exists()); my $gid = $self->get('samAccountName'); my $sambaMembersList = $self->users(); my $zentyalMembersList = $zentyalGroup->users(); my %sambaMembers = map { $_->get('samAccountName') => $_ } @{$sambaMembersList}; my %zentyalMembers = map { $_->get('uid') => $_ } @{$zentyalMembersList}; foreach my $memberName (keys %zentyalMembers) { unless (exists $sambaMembers{$memberName}) { EBox::info("Removing member '$memberName' from Zentyal group '$gid'"); $zentyalGroup->removeMember($zentyalMembers{$memberName}, 1); } } foreach my $memberName (keys %sambaMembers) { unless (exists $zentyalMembers{$memberName}) { EBox::info("Adding member '$memberName' to Zentyal group '$gid'"); my $zentyalUser = new EBox::UsersAndGroups::User(uid => $memberName); next unless $zentyalUser->exists(); $zentyalGroup->addMember($zentyalUser, 1); } } $zentyalGroup->setIgnoredModules(['samba']); $zentyalGroup->save(); } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Composite/0000775000000000000000000000000012017560227020717 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Composite/Antivirus.pm0000664000000000000000000000275612017560227023253 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::Composite::Antivirus; use base 'EBox::Model::Composite'; use strict; use warnings; use EBox::Gettext; use EBox::Global; # Group: Public methods # Constructor: new # # Constructor for the Antivirus composite # # Returns: # # - the recently created model # sub new { my ($class) = @_; my $self = $class->SUPER::new(); return $self; } # Group: Protected methods # Method: _description # # Overrides: # # # sub _description { my $description = { layout => 'top-bottom', name => __PACKAGE__->nameFromClass, printableName => __('Antivirus'), pageTitle => undef, compositeDomain => 'Samba', }; return $description; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Composite/General.pm0000664000000000000000000000301612017560227022632 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::Composite::General; use base 'EBox::Model::Composite'; use strict; use warnings; use EBox::Gettext; # Group: Public methods # Constructor: new # # Constructor for the general events composite # # Returns: # # - a # general events composite # sub new { my ($class, @params) = @_; my $self = $class->SUPER::new(@params); return $self; } # Method: _description # # Overrides: # # # sub _description { my $description = { layout => 'tabbed', name => __PACKAGE__->nameFromClass, pageTitle => __('File Sharing'), printableName => __('File sharing options'), compositeDomain => 'Samba', #help => __(''), # TODO }; return $description; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Composite/RecycleBin.pm0000664000000000000000000000277512017560227023307 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::Composite::RecycleBin; use base 'EBox::Model::Composite'; use strict; use warnings; use EBox::Gettext; # Group: Public methods # Constructor: new # # Constructor for the Recycle composite # # Returns: # # - the recently created model # sub new { my ($class) = @_; my $self = $class->SUPER::new(); return $self; } # Group: Protected methods # Method: _description # # Overrides: # # # sub _description { my $description = { layout => 'top-bottom', name => __PACKAGE__->nameFromClass, pageTitle => undef, printableName => __('Recycle Bin'), compositeDomain => 'Samba', #help => __(''), # TODO }; return $description; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/User.pm0000664000000000000000000003102112017560227020226 0ustar #!/usr/bin/perl # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 # Class: EBox::Samba::User # # Samba user, stored in samba LDAP # package EBox::Samba::User; use strict; use warnings; use EBox::Global; use EBox::Gettext; use EBox::Exceptions::External; use EBox::Exceptions::InvalidData; use EBox::Samba::Credentials; use EBox::UsersAndGroups::User; use EBox::UsersAndGroups::Group; use Perl6::Junction qw(any); use Encode; use Net::LDAP::Control; use Error qw(:try); use Date::Calc; use constant MAXUSERLENGTH => 128; use constant MAXPWDLENGTH => 512; use base 'EBox::Samba::LdbObject'; sub new { my $class = shift; my %opts = @_; my $self = $class->SUPER::new(@_); bless ($self, $class); return $self; } # Method: addGroup # # Add this user to the given group # # Parameters: # # group - Group object # sub addGroup { my ($self, $group) = @_; $group->addMember($self); } # Method: removeGroup # # Removes this user from the given group # # Parameters: # # group - Group object # sub removeGroup { my ($self, $group) = @_; $group->removeMember($self); } # Method: groups # # Groups this user belongs to # # Returns: # # array ref of EBox::Samba::Group objects # sub groups { my ($self) = @_; return $self->_groups(); } # Method: groupsNotIn # # Groups this user does not belong to # # Returns: # # array ref of EBox::UsersAndGroups::Group objects # sub groupsNotIn { my ($self) = @_; return $self->_groups(1); } sub _groups { my ($self, $invert) = @_; my $dn = $self->dn(); my $filter; if ($invert) { $filter = "(&(objectclass=group)(!(member=$dn)))"; } else { $filter = "(&(objectclass=group)(member=$dn))"; } my $attrs = { base => $self->_ldap->dn(), filter => $filter, scope => 'sub', }; my $result = $self->_ldap->search($attrs); my $groups = []; if ($result->count > 0) { foreach my $entry ($result->sorted('cn')) { push (@{$groups}, new EBox::Samba::Group(entry => $entry)); } } return $groups; } # Method: changePassword # # Configure a new password for the user # sub changePassword { my ($self, $passwd, $lazy) = @_; $self->_checkPwdLength($passwd); $passwd = encode('UTF16-LE', "\"$passwd\""); # The password will be changed on save $self->set('unicodePwd', $passwd, 1); $self->save() unless $lazy; } # Method: setCredentials # # Configure user credentials directly from kerberos hashes # # Parameters: # # keys - array ref of krb5keys # sub setCredentials { my ($self, $keys, $lazy) = @_; my $pwdSet = 0; my $credentials = new EBox::Samba::Credentials(krb5Keys => $keys); if ($credentials->supplementalCredentials()) { $self->set('supplementalCredentials', $credentials->supplementalCredentials(), 1); $pwdSet = 1; } if ($credentials->unicodePwd()) { $self->set('unicodePwd', $credentials->unicodePwd(), 1); $pwdSet = 1; } if ($pwdSet) { # This value is stored as a large integer that represents # the number of 100 nanosecond intervals since January 1, 1601 (UTC) my ($sec, $min, $hour, $day, $mon, $year) = gmtime(time); $year = $year + 1900; $mon += 1; my $days = Date::Calc::Delta_Days(1601, 1, 1, $year, $mon, $day); my $secs = $sec + $min * 60 + $hour * 3600 + $days * 86400; my $val = $secs * 10000000; $self->set('pwdLastSet', $val, 1); } my $bypassControl = Net::LDAP::Control->new( type => '1.3.6.1.4.1.7165.4.3.12', critical => 1 ); $self->save($bypassControl) unless $lazy; } # Method: deleteObject # # Delete the user # sub deleteObject { my ($self) = @_; # remove this user from all its grups foreach my $group (@{$self->groups()}) { $self->removeGroup($group); } # Remove the roaming profile directory my $samAccountName = $self->get('samAccountName'); my $path = EBox::Samba::PROFILES_DIR() . "/$samAccountName"; EBox::Sudo::silentRoot("rm -rf '$path'"); # TODO Remove this user from shares ACLs # Call super implementation shift @_; $self->SUPER::deleteObject(@_); } sub setupUidMapping { my ($self, $uidNumber) = @_; # NOTE Samba4 beta2 support rfc2307, reading uidNumber from ldap instead idmap.ldb, but # it is not working when the user init session as DOMAIN/user but user@domain.com # FIXME Remove this when fixed my $type = $self->_ldap->idmap->TYPE_UID(); $self->_ldap->idmap->setupNameMapping($self->sid(), $type, $uidNumber); } # Method: setAccountEnabled # # Enables or disables the user account, setting the userAccountControl # attribute. For a description of this attribute check: # http://support.microsoft.com/kb/305144 # sub setAccountEnabled { my ($self, $enable, $lazy) = @_; my $flags = $self->get('userAccountControl'); if ($enable) { $flags = $flags & ~0x0002; } else { $flags = $flags | 0x0002; } $self->set('userAccountControl', $flags, 1); $self->save() unless $lazy; } # Method: isAccountEnabled # # Check if the account is enabled, reading the userAccountControl # attribute. For a description of this attribute check: # http://support.microsoft.com/kb/305144 # # Returns: # # boolean - 1 if enabled, 0 if disabled # sub isAccountEnabled { my ($self) = @_; return not ($self->get('userAccountControl') & 0x0002); } # Method: addSpn # # Add a service principal name to this account # sub addSpn { my ($self, $spn, $lazy) = @_; my @spns = $self->get('servicePrincipalName'); # return if spn already present foreach my $s (@spns) { return if (lc ($s) eq lc ($spn)); } push (@spns, $spn); $self->set('servicePrincipalName', \@spns, $lazy); } sub createRoamingProfileDirectory { my ($self) = @_; my $samAccountName = $self->get('samAccountName'); my $uidNumber = $self->get('uidNumber'); my $userSID = $self->sid(); my $domainAdminsSID = $self->_ldap->domainSID() . '-512'; my $domainUsersSID = $self->_ldap->domainSID() . '-513'; # Create the directory if it does not exists my $samba = EBox::Global->modInstance('samba'); my $path = EBox::Samba::PROFILES_DIR() . "/$samAccountName"; my $group = EBox::UsersAndGroups::DEFAULTGROUP(); my @cmds = (); # Create the directory if it does not exists push (@cmds, "mkdir -p \'$path\'") unless -d $path; # Set unix permissions on directory push (@cmds, "chown $uidNumber:$group \'$path\'"); push (@cmds, "chmod 0700 \'$path\'"); # Set native NT permissions on directory my @perms; push (@perms, 'u:root:rwx'); push (@perms, 'g::---'); push (@perms, "g:$group:---"); push (@perms, "u:$uidNumber:rwx"); push (@cmds, "setfacl -b \'$path\'"); push (@cmds, 'setfacl -R -m ' . join(',', @perms) . " \'$path\'"); push (@cmds, 'setfacl -R -m d:' . join(',d:', @perms) ." \'$path\'"); EBox::Sudo::root(@cmds); } sub setRoamingProfile { my ($self, $enable, $path, $lazy) = @_; my $userName = $self->get('samAccountName'); if ($enable) { $self->createRoamingProfileDirectory(); $path .= "\\$userName"; $self->set('profilePath', $path); } else { $self->delete('profilePath'); } $self->save() unless $lazy; } sub setHomeDrive { my ($self, $drive, $path, $lazy) = @_; my $userName = $self->get('samAccountName'); $path .= "\\$userName"; $self->set('homeDrive', $drive); $self->set('homeDirectory', $path); $self->save() unless $lazy; } # Method: create # # Adds a new user # # Parameters: # # user - hash ref containing: # 'samAccountName' # # params hash ref (all optional): # clearPassword - Clear text password # uidNumber - user UID numberer # ou - OU where the user will be created # # Returns: # # Returns the new create user object # sub create { my ($self, $samAccountName, $params) = @_; # TODO Is the user added to the default OU? my $baseDn = $self->_ldap->dn(); my $dn = "CN=$samAccountName,CN=Users,$baseDn"; $self->_checkAccountName($samAccountName, MAXUSERLENGTH); $self->_checkAccountNotExists($samAccountName); # Check the password length if specified my $clearPassword = $params->{'clearPassword'}; if (defined $clearPassword) { $self->_checkPwdLength($clearPassword); } my $usersModule = EBox::Global->modInstance('users'); my $realm = $usersModule->kerberosRealm(); my $attr = []; push ($attr, objectClass => [ 'top', 'person', 'organizationalPerson', 'user', 'posixAccount' ]); push ($attr, sAMAccountName => "$samAccountName"); push ($attr, userPrincipalName => "$samAccountName\@$realm"); push ($attr, userAccountControl => '514'); push ($attr, givenName => $params->{givenName}) if defined $params->{givenName}; push ($attr, sn => $params->{sn}) if defined $params->{sn}; push ($attr, uidNumber => $params->{uidNumber}) if defined $params->{uidNumber}; push ($attr, description => $params->{description}) if defined $params->{description}; # Add the entry my $result = $self->_ldap->add($dn, { attr => $attr }); my $createdUser = new EBox::Samba::User(dn => $dn); # Setup the uid mapping $createdUser->setupUidMapping($params->{uidNumber}) if defined $params->{uidNumber}; # Set the password if (defined $params->{clearPassword}) { $createdUser->changePassword($params->{clearPassword}); $createdUser->setAccountEnabled(1); } elsif (defined $params->{kerberosKeys}) { $createdUser->setCredentials($params->{kerberosKeys}); $createdUser->setAccountEnabled(1); } # Return the new created user return $createdUser; } sub _checkPwdLength { my ($self, $pwd) = @_; if (length($pwd) > MAXPWDLENGTH) { throw EBox::Exceptions::External( __x("Password must not be longer than {maxPwdLength} characters", maxPwdLength => MAXPWDLENGTH)); } } sub addToZentyal { my ($self) = @_; my $uid = $self->get('samAccountName'); my $fullname = $self->get('name'); my $givenName = $self->get('givenName'); my $surName = $self->get('sn'); my $comment = $self->get('description'); $givenName = '-' unless defined $givenName; $surName = '-' unless defined $surName; my $params = { user => $uid, fullname => $fullname, givenname => $givenName, surname => $surName, comment => $comment, }; my %optParams; $optParams{ignoreMods} = ['samba']; EBox::info("Adding samba user '$uid' to Zentyal"); try { EBox::UsersAndGroups::User->create($params, 0, %optParams); } otherwise { }; } sub updateZentyal { my ($self) = @_; my $uid = $self->get('samAccountName'); EBox::info("Updating zentyal user '$uid'"); my $zentyalUser = undef; try { my $gn = $self->get('givenName'); my $sn = $self->get('sn'); my $desc = $self->get('description'); $gn = '-' unless defined $gn; $sn = '-' unless defined $sn; my $cn = "$gn $sn"; $zentyalUser = new EBox::UsersAndGroups::User(uid => $uid); $zentyalUser->setIgnoredModules(['samba']); return unless $zentyalUser->exists(); $zentyalUser->set('givenName', $gn, 1); $zentyalUser->set('sn', $sn, 1); $zentyalUser->set('description', $desc, 1); $zentyalUser->set('cn', $cn, 1); $zentyalUser->save(); } otherwise {}; return unless defined $zentyalUser; try { my $sc = $self->get('supplementalCredentials'); my $up = $self->get('unicodePwd'); my $creds = new EBox::Samba::Credentials(supplementalCredentials => $sc, unicodePwd => $up); $zentyalUser->setKerberosKeys($creds->kerberosKeys()); } otherwise {}; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Types/0000775000000000000000000000000012017560227020061 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Types/Select.pm0000664000000000000000000000266212017560227021644 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::Types::Select; use strict; use warnings; use base 'EBox::Types::Select'; sub new { my $class = shift; my %opts = @_; my $self = $class->SUPER::new(%opts); bless($self, $class); return $self; } # Method: options # # Overrides to not cache the options. # # This is needed for the SambaSharePermissions model, as this # options are populated from the users stored in LDAP and they might change. # # It would make more sense to add an attribute to the type, or waiting # until we have a proper user model, and this will be done automatically # # TODO Is this still needed? sub options { my ($self) = @_; my $populateFunc = $self->populate(); return &$populateFunc(); } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/Credentials.pm0000664000000000000000000004422412017560227021556 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::Credentials; use strict; use warnings; use EBox::Exceptions::MissingArgument; use EBox::Exceptions::Internal; use Encode; sub new { my ($class, %params) = @_; my $self = {}; bless ($self, $class); unless ($params{krb5Keys} or $params{unicodePwd} or $params{supplementalCredentials}) { throw EBox::Exceptions::MissingArgument('krb5Keys or unicodePwd or supplementalCredentials'); } if (exists $params{krb5Keys}) { my $encoded = $self->_encodeSambaCredentials($params{krb5Keys}); $self->{krb5Keys} = $params{krb5Keys}; $self->{unicodePwd} = $encoded->{unicodePwd}; $self->{supplementalCredentials} = $encoded->{supplementalCredentials}; } elsif (exists $params{unicodePwd} or exists $params{supplementalCredential}) { my $decoded = $self->_decodeSambaCredentials($params{supplementalCredentials}, $params{unicodePwd}); $self->{unicodePwd} = $params{unicodePwd}; $self->{supplementalCredentials} = $params{supplementalCredentials}; $self->{krb5Keys} = $decoded->{kerberosKeys}; } return $self; } sub kerberosKeys { my ($self) = @_; return $self->{krb5Keys}; } sub supplementalCredentials { my ($self) = @_; return $self->{supplementalCredentials}; } sub unicodePwd { my ($self) = @_; return $self->{unicodePwd}; } ########################################################### ## Encoding Section ## ########################################################### sub _encodeKerberosKeyData { my ($self, $key, $keyOffset) = @_; my $reserved1 = 0; my $reserved2 = 0; my $reserved3 = 0; my $keyType = $key->{type}; my $keyLength = length ($key->{value}); my $blob = pack ('s s l L L l', $reserved1, $reserved2, $reserved3, $keyType, $keyLength, $keyOffset); return $blob; } sub _encodeKerberosProperty { my ($self, $keys, $oldKeys) = @_; my $salt = @{$keys}[0]->{salt}; # FIXME $salt = encode('UTF16-LE', $salt); my $defaultSaltLength = length ($salt); my $defaultSaltMaxLength = length ($salt); my $credentials = []; my $oldCredentials = []; my $keyValues = []; my $keyValueOffset = 16 + 20 + (scalar @{$keys} * 20) + $defaultSaltLength; foreach my $key (@{$keys}) { push ($credentials, $self->_encodeKerberosKeyData($key, $keyValueOffset)); push ($keyValues, $key->{value}); $keyValueOffset += 8; } foreach my $key (@{$oldKeys}) { push ($oldCredentials, $self->_encodeKerberosKeyData($key, $keyValueOffset)); push ($keyValues, $key->{value}); $keyValueOffset += 8; } my $revision = 3; my $flags = 0; my $credentialCount = scalar @{$credentials}; my $oldCredentialCount = scalar @{$oldCredentials}; my $credentialsString = join ('', @{$credentials}); my $oldCredentialsString = join ('', @{$oldCredentials}); my $valuesString = join ('', @{$keyValues}); my $defaultSaltOffset = 16 + 20 + length ($credentialsString) + length ($oldCredentialsString); my $blob = pack ('s s s s s s L a* x20 a* a* a*', $revision, $flags, $credentialCount, $oldCredentialCount, $defaultSaltLength, $defaultSaltMaxLength, $defaultSaltOffset, $credentialsString, $oldCredentialsString, $salt, $valuesString); return $blob; } sub _encodeWDigestProperty { my ($self, $sam, $principal, $netbios, $dns, $pwd) = @_; $sam = encode("iso-8859-1", $sam); $principal = encode("iso-8859-1", $principal); $netbios = encode("iso-8859-1", $netbios); $dns = encode("iso-8859-1", $dns); $pwd = encode("iso-8859-1", $pwd); my $reserved1 = 0; my $reserved2 = 0; my $version = 1; my $numHashes = 29; my $hashes = []; push ($hashes, md5_hex($sam . $netbios . $pwd)); # 1 push ($hashes, md5_hex(uc($sam) . uc($netbios) . $pwd)); # 2 push ($hashes, md5_hex(lc($sam) . lc($netbios) . $pwd)); # 3 push ($hashes, md5_hex($sam . uc($netbios) . $pwd)); # 4 push ($hashes, md5_hex($sam . lc($netbios) . $pwd)); # 5 push ($hashes, md5_hex(uc($sam) . lc($netbios) . $pwd)); # 6 push ($hashes, md5_hex(lc($sam) . uc($netbios) . $pwd)); # 7 push ($hashes, md5_hex($sam . $dns . $pwd)); # 8 push ($hashes, md5_hex(uc($sam) . uc($dns) . $pwd)); # 9 push ($hashes, md5_hex(lc($sam) . lc($dns) . $pwd)); # 10 push ($hashes, md5_hex($sam . uc($dns) . $pwd)); # 11 push ($hashes, md5_hex($sam . lc($dns) . $pwd)); # 12 push ($hashes, md5_hex(uc($sam) . lc($dns) . $pwd)); # 13 push ($hashes, md5_hex(lc($sam) . uc($dns) . $pwd)); # 14 push ($hashes, md5_hex($principal . $pwd)); # 15 push ($hashes, md5_hex(uc($principal) . $pwd)); # 16 push ($hashes, md5_hex(lc($principal) . $pwd)); # 17 push ($hashes, md5_hex($netbios . '\\' . $sam . $pwd)); # 18 push ($hashes, md5_hex(uc($netbios . '\\' . $sam) . $pwd)); # 19 push ($hashes, md5_hex(lc($netbios . '\\' . $sam) . $pwd)); # 20 push ($hashes, md5_hex($sam . 'Digest' . $pwd)); # 21 push ($hashes, md5_hex(uc($sam) . 'DIGEST' . $pwd)); # 22 push ($hashes, md5_hex(lc($sam) . 'digest' . $pwd)); # 23 push ($hashes, md5_hex($principal . 'Digest' . $pwd)); # 24 push ($hashes, md5_hex(uc($principal) . 'DIGEST' . $pwd)); # 25 push ($hashes, md5_hex(lc($principal) . 'digest' . $pwd)); # 26 push ($hashes, md5_hex($netbios . '\\' . $sam . 'Digest' . $pwd)); # 27 push ($hashes, md5_hex(uc($netbios . '\\' . $sam) . 'DIGEST' . $pwd)); # 28 push ($hashes, md5_hex(lc($netbios . '\\' . $sam) . 'digest' . $pwd)); # 29 my $blob = pack ('W W W W x12 a*', $reserved1, $reserved2, $version, $numHashes, join ('', @{$hashes})); return $blob; } sub _encodeUserProperty { my ($self, $name, $value) = @_; my $propertyName = encode('UTF16-LE', $name); my $propertyValue = uc(unpack ('H*', $value)); my $nameLength = length ($propertyName); my $valueLength = length ($propertyValue); my $reserved = 0; my $blob = pack ('s s s a* a*', $nameLength, $valueLength, $reserved, $propertyName, $propertyValue); return $blob; } sub _encodeUserProperties { my ($self, $kerberosKeys, $digest) = @_; my @packages = (); my $userProperties = ''; my $reserved1 = 0; my $reserved2 = 0; my $reserved3 = 0; my $reserved4 = ''; my $reserved5 = 0; my $signature = 0x50; my $propertyCount = (defined $kerberosKeys) + (defined $digest) + 1; # Samba4 expects reserved4 to be an array of '0x2000' for (my $i=0; $i<48; $i++) { $reserved4 .= pack('H*', 2000); } if (defined $kerberosKeys) { my $kerberosProperty = $self->_encodeKerberosProperty($kerberosKeys); $userProperties .= $self->_encodeUserProperty('Primary:Kerberos', $kerberosProperty); push (@packages, encode('UTF16-LE', 'Kerberos')); } if (defined $digest) { my $wdigestProperty = $self->_encodeWDigestProperty( $digest->{sam}, $digest->{principal}, $digest->{netbios}, $digest->{dns}, $digest->{pwd}); $userProperties .= $self->_encodeUserProperty('Primary:WDigest', $wdigestProperty); push (@packages, encode('UTF16-LE', 'WDigest')); } my $packagesStr = join(encode('UTF16-LE', "\0"), @packages); $userProperties .= $self->_encodeUserProperty('Packages', $packagesStr); my $length = 4 + 96 + length ($userProperties); my $blobFormat = 'l L s s a* s s a* W'; my $blob = pack ($blobFormat, $reserved1, $length, $reserved2, $reserved3, $reserved4, $signature, $propertyCount, $userProperties, $reserved5); return $blob; } sub _encodeSambaCredentials { my ($self, $krbKeys) = @_; unless (defined $krbKeys) { throw EBox::Exceptions::MissingArgument('krbKeys'); } my $credentials = {}; # Remove the type 23 from keys because it is the unicodePwd attribute # and make sure type 3 is the first in the array, it must be the first # key or samba will fail to write the supplementalCredentials attribute my $newList = []; foreach my $key (@{$krbKeys}) { if ($key->{type} == 23) { $credentials->{unicodePwd} = $key->{value}; next; } elsif ($key->{type} == 3) { @{$newList}[0] = $key; next; } elsif ($key->{type} == 1) { @{$newList}[1] = $key; next; } } if (scalar @{$krbKeys} >= 2) { $credentials->{supplementalCredentials} = $self->_encodeUserProperties($newList); } return $credentials; } ########################################################### ## Decoding Section ## ########################################################### # Method: _decodeWDigest # # Docode the WDIGEST_CREDENTIALS struct. This struct # contains 29 different hashes produced by combinations # of different elements including the sAMAccountName, # realm, host, etc. The format is documented at: # http://msdn.microsoft.com/en-us/library/cc245502(v=prot.10).aspx # The list of included hashes is documented at: # http://msdn.microsoft.com/en-us/library/cc245680(v=prot.10).aspx # # Returns: # # An array reference containing the hashes # sub _decodeWDigest { my ($self, $data) = @_; my $hashes = (); my $format = 'x4 a2 a2 x24 (a32)29'; if (length ($data) == 960) { my ($version, $nHashes, @hashValues) = unpack($format, $data); $version = hex($version); $nHashes = hex($nHashes); if ($version == 1 and $nHashes == 29) { $hashes = \@hashValues; } } return $hashes; } # Method: _decodeKerberos # # Decode the KERB_STORED_CREDENTIAL struct. This struct # contains the hashes of the kerberos keys. Its format # is documented at: # http://msdn.microsoft.com/en-us/library/cc245503(v=prot.10).aspx # # Returns: # # A hash reference with the kerberos keys # sub _decodeKerberos { my ($self, $data) = @_; my $kerberosKeys = []; $data = pack('H*', $data); # from hex to binary my $format = 's x2 s s s s l a*'; if (length ($data) > 16) { my ($revision, $nCredentials, $nOldCredentials, $saltLength, $maxSaltLength, $saltOffset) = unpack($format, $data); if ($revision == 3) { my ($saltValue) = unpack('@' . $saltOffset . 'a' . $maxSaltLength, $data); my $offset = 16; for (my $i=0; $i<$nCredentials; $i++) { my ($keyType, $keyLength, $keyOffset) = unpack('@' . $offset . 'x8 l l l', $data); # From MS-SAMR Security Account Manager (SAM) Remote Protocol Specification (Client-to-Server) (v20110610) # Section 2.2.10.8: When the current domain functional level is DS_BEHAVIOR_WIN2003 or # less, a Windows Server 2008 or Windows Server 2008 R2 DC includes a KeyType of -140 in each of # KERB_STORED_CREDENTIAL and KERB_STORED_CREDENTIAL_NEW, which is not needed and can # be ignored; it is a dummy type in the supplemental credentials that is not present when the domain # functional level is raised to DS_BEHAVIOR_WIN2008 or greater. The key data is the NT hash of the # password. my ($keyValue) = unpack('@' . $keyOffset . 'a' . $keyLength, $data); $offset += 20; my $key = { type => $keyType, value => $keyValue, salt => decode ('UTF-16LE', $saltValue), }; push (@{$kerberosKeys}, $key) if ($keyType != -140); } } } return $kerberosKeys; } sub _decodeKerberosNewerKeys { my ($self, $data) = @_; my $kerberosKeys = []; $data = pack('H*', $data); # from hex to binary my $format = 's x2 s s s s s s l l a*'; if (length ($data) > 24) { my ($revision, $nCredentials, $nServiceCredentials, $nOldCredentials, $nOlderCredentials, $saltLength, $maxSaltLength, $saltOffset, $defaultIterationCount) = unpack ($format, $data); if ($revision == 4) { my ($saltValue) = unpack('@' . $saltOffset . 'a' . $maxSaltLength, $data); my $offset = 24; for(my $i=0; $i<$nCredentials; $i++) { my ($keyType, $keyLength, $keyOffset) = unpack('@' . $offset . 'x12 l l l', $data); my ($keyValue) = unpack('@' . $keyOffset . 'a' . $keyLength, $data); $offset += 24; my $key = { type => $keyType, value => $keyValue, salt => decode ('UTF-16LE', $saltValue), }; push (@{$kerberosKeys}, $key) if ($keyType != -140); } } } return $kerberosKeys; } # Method: _decodeSupplementalCredentials # # this struct is documented at: # http://msdn.microsoft.com/en-us/library/cc245500(v=prot.10).aspx # The USER_PROPERTIES contains various USER_PROPERTY structs, # documented at: # http://msdn.microsoft.com/en-us/library/cc245501(v=prot.10).aspx # # Returns: # # A hash reference containing the different hashes # of the user credentials in different formats # sub _decodeSupplementalCredentials { my ($self, $blob) = @_; my $credentials = {}; my $blobFormat = 'x4 L< x2 x2 x96 S< S< a*'; if (length ($blob) > 112) { my ($blobLength, $blobSignature, $nProperties, $properties) = unpack ($blobFormat, $blob); # Check the signature. Its value must be 0x50 if ($blobSignature == 0x50) { my $offset = 112; for (my $i=0; $i<$nProperties; $i++) { my ($propertyNameLength) = unpack('@' . $offset . 'S<', $blob); $offset += 2; my ($propertyValueLength) = unpack('@' . $offset . 'S<', $blob); $offset += 4; # 2 bytes + 2 bytes reserved my ($propertyName) = unpack('@' . $offset . 'a' . $propertyNameLength, $blob); $offset += $propertyNameLength; my ($propertyValue) = unpack('@' . $offset . 'a' . $propertyValueLength, $blob); $offset += $propertyValueLength; if($propertyName eq encode('UTF-16LE', 'Primary:Kerberos')) { $credentials->{'Primary:Kerberos'} = $self->_decodeKerberos($propertyValue); } elsif($propertyName eq encode('UTF-16LE', 'Primary:Kerberos-Newer-Keys')) { $credentials->{'Primary:Kerberos-Newer-Keys'} = $self->_decodeKerberosNewerKeys($propertyValue); } elsif($propertyName eq encode('UTF-16LE', 'Primary:WDigest')) { $credentials->{'Primary:WDigest'} = $self->_decodeWDigest($propertyValue); } elsif($propertyName eq encode('UTF-16LE', 'Primary:CLEARTEXT')) { $credentials->{'Primary:CLEARTEXT'} = decode('UTF-16LE', pack ('H*', $propertyValue)); } } } else { throw EBox::Exceptions::Internal("Corrupted supplementalCredentials"); } } else { throw EBox::Exceptions::Internal("Truncated supplementalCredentials"); } return $credentials; } # Method: _decodeSambaCredentials # # This method gets all the credentials stored in the # LDB for the user # # Parameters: # # supplementalCredentialsBlob # unicodePwdBlob # # Returns: # # A hash reference containing all found credentials # sub _decodeSambaCredentials { my ($self, $supplementalCredentialsBlob, $unicodePwdBlob) = @_; my $credentials = {}; if (defined $supplementalCredentialsBlob) { my $properties = $self->_decodeSupplementalCredentials($supplementalCredentialsBlob); if (exists $properties->{'Primary:Kerberos-Newer-Keys'}) { $credentials->{kerberosKeys} = $properties->{'Primary:Kerberos-Newer-Keys'}; } elsif (exists $properties->{'Primary:Kerberos'}) { $credentials->{kerberosKeys} = $properties->{'Primary:Kerberos'}; } if (exists $properties->{'Primary:WDigest'}) { $credentials->{WDigest} = $properties->{'Primary:WDigest'}; } if (exists $properties->{'Primary:CLEARTEXT'}) { $credentials->{clearText} = $properties->{'Primary:CLEARTEXT'}; } } if (defined $unicodePwdBlob) { unless (exists $credentials->{kerberosKeys}) { $credentials->{kerberosKeys} = []; } if (scalar @{$credentials->{kerberosKeys}} > 0) { # Copy salt from previous krb keys my $key = { type => 23, salt => @{$credentials->{kerberosKeys}}[0]->{salt}, value => $unicodePwdBlob, }; push (@{$credentials->{kerberosKeys}}, $key); } else { my $key = { type => 23, value => $unicodePwdBlob, }; push (@{$credentials->{kerberosKeys}}, $key); } } return $credentials; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba/LdbObject.pm0000664000000000000000000002672012017560227021152 0ustar #!/usr/bin/perl # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba::LdbObject; use strict; use warnings; use EBox::Global; use EBox::Gettext; use EBox::Exceptions::External; use EBox::Exceptions::MissingArgument; use Net::LDAP::LDIF; use Net::LDAP::Constant qw(LDAP_LOCAL_ERROR); use Net::LDAP::Control; use Perl6::Junction qw(any); use Error qw(:try); # Method: new # # Instance an object readed from LDB. # # Parameters: # # dn - Full dn for the entry # or # ldif - Net::LDAP::LDIF for the entry # or # entry - Net::LDAP entry # or # samAccountName # or # SID # sub new { my ($class, %params) = @_; my $self = {}; bless ($self, $class); unless ($params{entry} or $params{dn} or $params{ldif} or $params{samAccountName} or $params{sid}) { throw EBox::Exceptions::MissingArgument('entry|dn|ldif|samAccountName|sid'); } if ($params{entry}) { $self->{entry} = $params{entry}; } elsif ($params{ldif}) { my $ldif = Net::LDAP::LDIF->new($params{ldif}, "r"); $self->{entry} = $ldif->read_entry(); } elsif ($params{dn}) { $self->{dn} = $params{dn}; } elsif ($params{samAccountName}) { $self->{samAccountName} = $params{samAccountName}; } elsif ($params{sid}) { $self->{sid} = $params{sid}; } return $self; } # Method: exists # # Returns 1 if the object exist, 0 if not # sub exists { my ($self) = @_; # User exists if we already have its entry return 1 if ($self->{entry}); $self->{entry} = $self->_entry(); return (defined $self->{entry}); } # Method: get # # Read an user attribute # # Parameters: # # attribute - Attribute name to read # sub get { my ($self, $attr) = @_; return $self->_entry->get_value($attr); } # Method: set # # Set an user attribute. # # Parameters: # # attribute - Attribute name to read # value - Value to set (scalar or array ref) # lazy - Do not update the entry in LDAP # sub set { my ($self, $attr, $value, $lazy) = @_; $self->_entry->replace($attr => $value); $self->save() unless $lazy; } # Method: add # # Adds a value to an attribute without removing previous ones (if any) # # Parameters: # # attribute - Attribute name to read # value - Value to set (scalar or array ref) # lazy - Do not update the entry in LDAP # sub add { my ($self, $attr, $value, $lazy) = @_; $self->_entry->add($attr => $value); $self->save() unless $lazy; } # Method: delete # # Deletes an attribute from the object if given # # Parameters (for attribute deletion): # # attribute - Attribute name to read # lazy - Do not update the entry in LDAP # sub delete { my ($self, $attr, $lazy) = @_; if ($attr eq any $self->_entry->attributes) { $self->_entry->delete($attr); $self->save() unless $lazy; } } # Method: deleteObject # # Deletes this object from the LDAP # sub deleteObject { my ($self, $attr, $lazy) = @_; $self->_entry->delete(); $self->save(); } # Method: remove # # Remove a value from the given attribute, or the whole # attribute if no values left # # If an array ref is received as value, all the values will be # deleted at the same time # # Parameters: # # attribute - Attribute name # value(s) - Value(s) to remove (value or array ref to values) # lazy - Do not update the entry in LDAP # sub remove { my ($self, $attr, $value, $lazy) = @_; # Delete attribute only if it exists if ($attr eq any $self->_entry->attributes) { if (ref ($value) ne 'ARRAY') { $value = [ $value ]; } $self->_entry->delete($attr, $value); $self->save() unless $lazy; } } # Method: save # # Store all pending lazy operations (if any) # # This method is only needed if some operation # was used using lazy flag # sub save { my ($self, $control) = @_; $control = [] unless $control; my $result = $self->_entry->update($self->_ldap->ldbCon(), control => $control); if ($result->is_error()) { unless ($result->code == LDAP_LOCAL_ERROR and $result->error eq 'No attributes to update') { throw EBox::Exceptions::External(__('There was an error updating LDAP: ') . $result->error()); } } } # Method: dn # # Return DN for this object # sub dn { my ($self) = @_; return $self->_entry->dn(); } # Method: baseDn # # Return base DN for this object # sub baseDn { my ($self) = @_; my ($trash, $basedn) = split(/,/, $self->dn(), 2); return $basedn; } # Method: _entry # # Return Net::LDAP::Entry entry for the user # sub _entry { my ($self) = @_; unless ($self->{entry}) { my $result = undef; if (defined $self->{dn}) { my ($filter, $basedn) = split(/,/, $self->{dn}, 2); my $attrs = { base => $basedn, filter => $filter, scope => 'one', attrs => ['*', 'unicodePwd', 'supplementalCredentials'], }; $result = $self->_ldap->search($attrs); } elsif (defined $self->{samAccountName}) { my $attrs = { base => $self->_ldap->dn(), filter => "(samAccountName=$self->{samAccountName})", scope => 'sub', attrs => ['*', 'unicodePwd', 'supplementalCredentials'], }; $result = $self->_ldap->search($attrs); } elsif (defined $self->{sid}) { my $attrs = { base => $self->_ldap->dn(), filter => "(objectSid=$self->{sid})", scope => 'sub', attrs => ['*', 'unicodePwd', 'supplementalCredentials'], }; $result = $self->_ldap->search($attrs); } return undef unless defined $result; if ($result->count() > 1) { throw EBox::Exceptions::Internal( __x('Found {count} results for, expected only one.', count => $result->count())); } $self->{entry} = $result->entry(0); } return $self->{entry}; } # Method: _ldap # # Returns the LDAP object # sub _ldap { my ($self) = @_; return EBox::Global->modInstance('samba')->ldb(); } # Method: to_ldif # # Returns a string containing the LDAP entry as LDIF # sub as_ldif { my ($self) = @_; return $self->_entry->ldif(change => 0); } sub sid { my ($self) = @_; my $sid = $self->get('objectSid'); my $sidString = $self->_sidToString($sid); return $sidString; } sub _sidToString { my ($self, $sid) = @_; return undef unless unpack("C", substr($sid, 0, 1)) == 1; return undef unless length($sid) == 8 + 4 * unpack("C", substr($sid, 1, 1)); my $sid_str = "S-1-"; $sid_str .= (unpack("C", substr($sid, 7, 1)) + (unpack("C", substr($sid, 6, 1)) << 8) + (unpack("C", substr($sid, 5, 1)) << 16) + (unpack("C", substr($sid, 4, 1)) << 24)); for my $loop (0 .. unpack("C", substr($sid, 1, 1)) - 1) { $sid_str .= "-" . unpack("I", substr($sid, 4 * $loop + 8, 4)); } return $sid_str; } sub _stringToSid { my ($self, $sidString) = @_; return undef unless uc(substr($sidString, 0, 4)) eq "S-1-"; my ($auth_id, @sub_auth_id) = split(/-/, substr($sidString, 4)); my $sid = pack("C4", 1, $#sub_auth_id + 1, 0, 0); $sid .= pack("C4", ($auth_id & 0xff000000) >> 24, ($auth_id &0x00ff0000) >> 16, ($auth_id & 0x0000ff00) >> 8, $auth_id &0x000000ff); for my $loop (0 .. $#sub_auth_id) { $sid .= pack("I", $sub_auth_id[$loop]); } return $sid; } sub _guidToString { my ($self, $guid) = @_; return sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", unpack("I", $guid), unpack("S", substr($guid, 4, 2)), unpack("S", substr($guid, 6, 2)), unpack("C", substr($guid, 8, 1)), unpack("C", substr($guid, 9, 1)), unpack("C", substr($guid, 10, 1)), unpack("C", substr($guid, 11, 1)), unpack("C", substr($guid, 12, 1)), unpack("C", substr($guid, 13, 1)), unpack("C", substr($guid, 14, 1)), unpack("C", substr($guid, 15, 1)); } sub _stringToGuid { my ($self, $guidString) = @_; return undef unless $guidString =~ /([0-9,a-z]{8})-([0-9,a-z]{4})-([0-9,a-z]{4})-([0-9,a-z]{2})([0-9,a-z]{2})-([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})/i; return pack("I", hex $1) . pack("S", hex $2) . pack("S", hex $3) . pack("C", hex $4) . pack("C", hex $5) . pack("C", hex $6) . pack("C", hex $7) . pack("C", hex $8) . pack("C", hex $9) . pack("C", hex $10) . pack("C", hex $11); } sub _checkAccountName { my ($self, $name, $maxLength) = @_; my $advice = undef; if ($name =~ m/\.$/) { $advice = __('Windows account names cannot end with a period'); } if ($name =~ m/^[[:space:]0-9\.]+$/) { $advice = __('Windows account names cannot be only spaces, numbers and dots'); } unless ($name =~ /^([a-zA-Z\d\s_-]+\.)*[a-zA-Z\d\s_-]+$/) { $advice = __('To avoid problems, the account name should ' . 'consist only of letters, digits, underscores, ' . 'spaces, periods, dashs, not start with a ' . 'dash and not end with dot'); } if (length ($name) > $maxLength) { $advice = __x("Account name must not be longer than {maxLength} characters", maxLength => $maxLength); } if (defined $advice) { throw EBox::Exceptions::InvalidData( 'data' => __('samAccountName'), 'value' => $name, 'advice' => $advice); } } sub _checkAccountNotExists { my ($self, $samAccountName) = @_; my $obj = new EBox::Samba::LdbObject(samAccountName => $samAccountName); if ($obj->exists()) { my $dn = $obj->dn(); throw EBox::Exceptions::DataExists( 'data' => __('Account name'), 'value' => "$samAccountName ($dn)"); } } sub setCritical { my ($self, $critical, $lazy) = @_; if ($critical) { $self->set('isCriticalSystemObject', 'TRUE', 1); } else { $self->delete('isCriticalSystemObject', 1); } my $relaxOidControl = Net::LDAP::Control->new( type => '1.3.6.1.4.1.4203.666.5.12', critical => 0 ); $self->save($relaxOidControl) unless $lazy; } sub setViewInAdvancedOnly { my ($self, $enable, $lazy) = @_; if ($enable) { $self->set('showInAdvancedViewOnly', 'TRUE', 1); } else { $self->delete('showInAdvancedViewOnly', 1); } my $relaxOidControl = Net::LDAP::Control->new( type => '1.3.6.1.4.1.4203.666.5.12', critical => 0 ); $self->save($relaxOidControl) unless $lazy; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/SambaLogHelper.pm0000664000000000000000000001067512017560227021126 0ustar # Copyright (C) 2009-2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::SambaLogHelper; use base 'EBox::LogHelper'; use strict; use warnings; use EBox; use EBox::Config; use EBox::Gettext; use constant SAMBA_LOGFILE => '/var/log/syslog'; use constant RESOURCE_FIELD_MAX_LENGTH => 240; # this must be the same length of # the db samba_Access.resource # field sub new { my $class = shift; my $self = {}; bless($self, $class); return $self; } # Method: logFiles # # This function must return the file or files to be read from. # # Returns: # # array ref - containing the whole paths # sub logFiles { return [SAMBA_LOGFILE]; } # Method: processLine # # This fucntion will be run every time a new line is recieved in # the associated file. You must parse the line, and generate # the messages which will be logged to ebox through an object # implementing EBox::AbstractLogger interface. # # Parameters: # # file - file name # line - string containing the log line # dbengine- An instance of class implemeting AbstractDBEngineinterface # sub processLine # (file, line, logger) { my ($self, $file, $line, $dbengine) = @_; unless ($line =~ /^(\w+\s+\d+ \d\d:\d\d:\d\d) .*smbd.*?: (.+)/) { return; } my $date = $1 . ' ' . (${[localtime(time)]}[5] + 1900); my $message = $2; my %dataToInsert; my $timestamp = $self->_convertTimestamp('%b %e %H:%M:%S %Y', $date); $dataToInsert{timestamp} = $timestamp; if ($message =~ /^ALERT - Scan result: '(.*?)' infected with virus '(.*?)', client: '[^0-9]*(.*?)'$/) { $dataToInsert{event} = 'virus'; $dataToInsert{filename} = $1; $dataToInsert{virus} = $2; $dataToInsert{client} = $3; } elsif ($message =~ /^INFO: quarantining file '(.*?)' to '(.*?)' was successful$/) { $dataToInsert{event} = 'quarantine'; $dataToInsert{filename} = $1; $dataToInsert{qfilename} = $2; } else { my @fields = split(/\|/, $message); unless (@fields > 2) { return; } $dataToInsert{username} = $fields[0]; $dataToInsert{client} = $fields[1]; my $type = $fields[2]; $dataToInsert{event} = $type; if ( ($type eq 'connect') or ($type eq 'opendir') or ($type eq 'disconnect') or ($type eq 'unlink') or ($type eq 'mkdir') or ($type eq 'rmdir') ) { $dataToInsert{resource} = $fields[4]; } elsif ($type eq 'open') { if ($fields[4] eq 'r') { $dataToInsert{event} = 'readfile'; } else { $dataToInsert{event} = 'writefile'; } $dataToInsert{resource} = $fields[5]; } elsif ($type eq 'rename') { my $orig = $fields[4]; my $dest = $fields[5]; $orig =~ s/\s+$//; $dest =~ s/\s+$//; $dataToInsert{resource} = $orig . " -> " . $dest; } } if (exists $dataToInsert{resource} and defined $dataToInsert{resource}) { $dataToInsert{resource} =~ s/\s+$//; if ($dataToInsert{resource} eq 'IPC$') { return; } if (length ($dataToInsert{resource}) > RESOURCE_FIELD_MAX_LENGTH) { my $abbreviateRes = '(..) '; $abbreviateRes .= substr ($dataToInsert{resource}, - (RESOURCE_FIELD_MAX_LENGTH - 5)); $dataToInsert{resource} = $abbreviateRes; } } if ($dataToInsert{event} eq 'virus') { $dbengine->insert('samba_virus', \%dataToInsert); } elsif ($dataToInsert{event} eq 'quarantine') { $dbengine->insert('samba_quarantine', \%dataToInsert); } else { $dbengine->insert('samba_access', \%dataToInsert); } } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/LDB.pm0000664000000000000000000004345112017560227016700 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::LDB; use strict; use warnings; use EBox::Samba::LdbObject; use EBox::Samba::Credentials; use EBox::Samba::User; use EBox::Samba::Group; use EBox::LDB::IdMapDb; use EBox::Exceptions::DataNotFound; use EBox::Exceptions::DataExists; use Net::LDAP; use Net::LDAP::Control; use Net::LDAP::Util qw(ldap_error_name); use Authen::SASL qw(Perl); use IO::Socket::UNIX; use Data::Dumper; use File::Slurp; use Error qw( :try ); use constant LDAPI => "ldapi://%2fvar%2flib%2fsamba%2fprivate%2fldap_priv%2fldapi"; use constant SOCKET_PATH => '/var/run/ldb'; # Singleton variable my $_instance = undef; sub _new_instance { my $class = shift; my $ignoredSidsFile = EBox::Config::scripts('samba') . 'samba-ignore-sids.txt'; my @lines = read_file($ignoredSidsFile); my @sidsTmp = grep(/^\s*S-/, @lines); my @sids = map { s/\n//; $_; } @sidsTmp; my $self = {}; $self->{ldb} = undef; $self->{idamp} = undef; $self->{ignoredSids} = \@sids; bless ($self, $class); return $self; } # Method: instance # # Return a singleton instance of class # # Returns: # # object of class sub instance { my ($self, %opts) = @_; unless (defined ($_instance)) { $_instance = EBox::LDB->_new_instance(); } return $_instance; } # Method: idmap # # Returns an instance of IdMapDb. # sub idmap { my ($self) = @_; unless (defined $self->{idmap}) { $self->{idmap} = EBox::LDB::IdMapDb->new(); } return $self->{idmap}; } # Method: ldbCon # # Returns the Net::LDAP connection used by the module # # Returns: # # An object of class Net::LDAP whose connection has already bound # # Exceptions: # # Internal - If connection can't be created # sub ldbCon { my ($self) = @_; # Workaround to detect if connection is broken and force reconnection my $reconnect = 0; if (defined $self->{ldb}) { my $mesg = $self->{ldb}->search( base => '', scope => 'base', filter => "(cn=*)", ); if (ldap_error_name($mesg) ne 'LDAP_SUCCESS' ) { $self->clearConn(); $reconnect = 1; } } if (not defined $self->{ldb} or $reconnect) { $self->{ldb} = $self->safeConnect(); } return $self->{ldb}; } sub safeConnect { my ($self) = @_; my $retries = 6; my $ldb = undef; local $SIG{PIPE}; $SIG{PIPE} = sub { EBox::warn('SIGPIPE received connecting to samba LDAP'); }; while (not $ldb = Net::LDAP->new(LDAPI) and $retries--) { my $samba = EBox::Global->modInstance('samba'); unless ($samba->isRunning()) { EBox::debug("Samba daemon was stopped, starting it"); $samba->_startService(); sleep (5); next; } EBox::error("Couldn't connect to samba LDAP server: $@, retrying"); sleep (5); } unless ($ldb) { throw EBox::Exceptions::External( "FATAL: Couldn't connect to samba LDAP server"); } return $ldb; } # Method: dn # # Returns the base DN (Distinguished Name) # # Returns: # # string - DN # sub dn { my ($self) = @_; unless (defined ($self->{dn})) { my $params = { base => '', scope => 'base', filter => 'cn=*', attrs => ['defaultNamingContext'], }; my $msg = $self->search($params); if ($msg->count() == 1) { my $entry = $msg->entry(0); $self->{dn} = $entry->get_value('defaultNamingContext'); } } return defined ($self->{dn}) ? $self->{dn} : ''; } # Method: clearConn # # Closes LDAP connection and clears DN cached value # sub clearConn { my ($self) = @_; if (defined $self->{ldb}) { $self->{ldb}->disconnect(); } delete $self->{dn}; delete $self->{ldb}; } # Method: search # # Performs a search in the LDB database using Net::LDAP. # # Parameters: # # args - arguments to pass to Net::LDAP->search() # # Exceptions: # # Internal - If there is an error during the search # sub search { my ($self, $args) = @_; my $ldb = $self->ldbCon(); my $result = $ldb->search(%{$args}); $self->_errorOnLdap($result, $args); return $result; } # Method: modify # # Performs a modification in the LDB database using Net::LDAP. # # Parameters: # # dn - dn where to perform the modification # args - parameters to pass to Net::LDAP->modify() # # Exceptions: # # Internal - If there is an error during the operation # sub modify { my ($self, $dn, $args) = @_; my $ldb = $self->ldbCon(); my $result = $ldb->modify($dn, %{$args}); $self->_errorOnLdap($result, $args); return $result; } # Method: delete # # Performs a deletion in the LDB database using Net::LDAP # # Parameters: # # dn - dn to delete # # Exceptions: # # Internal - If there is an error during the operation # sub delete { my ($self, $dn) = @_; my $ldb = $self->ldbCon(); my $result = $ldb->delete($dn); $self->_errorOnLdap($result, $dn); return $result; } # Method: add # # Adds an object or attributes in the LDB database using Net::LDAP # # Parameters: # # dn - dn to add # args - parameters to pass to Net::LDAP->add() # # Exceptions: # # Internal - If there is an error during the operation # sub add { my ($self, $dn, $args) = @_; my $ldb = $self->ldbCon(); my $result = $ldb->add($dn, %{$args}); $self->_errorOnLdap($result, $args); return $result; } # Method: _errorOnLdap # # Check the result for errors # sub _errorOnLdap { my ($self, $result, $args) = @_; my @frames = caller (2); if ($result->is_error()) { if ($args) { EBox::error( Dumper($args) ); } throw EBox::Exceptions::Internal("Unknown error at " . $frames[3] . " " . $result->error); } } ############################################################################# ## LDB related functions ## ############################################################################# # Method domainSID # # Get the domain SID # # Returns: # # string - The SID string of the domain # sub domainSID { my ($self) = @_; my $base = $self->dn(); my $params = { base => $base, scope => 'base', filter => "(distinguishedName=$base)", attrs => ['objectSid'], }; my $msg = $self->search($params); if ($msg->count() == 1) { my $entry = $msg->entry(0); my $object = new EBox::Samba::LdbObject(entry => $entry); return $object->sid(); } else { throw EBox::Exceptions::DataNotFound(data => 'domain', value => $base); } } sub domainNetBiosName { my ($self) = @_; my $realm = EBox::Global->modInstance('users')->kerberosRealm(); my $params = { base => 'CN=Partitions,CN=Configuration,' . $self->dn(), scope => 'sub', filter => "(&(nETBIOSName=*)(dnsRoot=$realm))", attrs => ['nETBIOSName'], }; my $result = $self->search($params); if ($result->count() == 1) { my $entry = $result->entry(0); my $name = $entry->get_value('nETBIOSName'); return $name; } return undef; } sub ldapUsersToLdb { my ($self) = @_; EBox::info('Loading Zentyal users into samba database'); my $usersModule = EBox::Global->modInstance('users'); my $users = $usersModule->users(); foreach my $user (@{$users}) { my $dn = $user->dn(); EBox::debug("Loading user $dn"); try { my $samAccountName = $user->get('uid'); my $params = { uidNumber => scalar ($user->get('uidNumber')), sn => scalar ($user->get('sn')), givenName => scalar ($user->get('givenName')), description => scalar ($user->get('description')), kerberosKeys => $user->kerberosKeys(), }; EBox::Samba::User->create($samAccountName, $params); } otherwise { my $error = shift; EBox::error("Error loading user '$dn': $error"); }; } } sub ldapGroupsToLdb { my ($self) = @_; EBox::info('Loading Zentyal groups into samba database'); my $usersModule = EBox::Global->modInstance('users'); my $groups = $usersModule->groups(); foreach my $group (@{$groups}) { my $dn = $group->dn(); EBox::debug("Loading group $dn"); my $sambaGroup = undef; try { my $samAccountName = $group->get('cn'); my $params = { gidNumber => scalar ($group->get('gidNumber')), description => scalar ($group->get('description')), }; $sambaGroup = EBox::Samba::Group->create($samAccountName, $params); } otherwise { my $error = shift; EBox::error("Error loading group '$dn': $error"); }; next unless defined $sambaGroup; foreach my $user (@{$group->users()}) { try { my $smbUser = new EBox::Samba::User(samAccountName => $user->get('uid')); next unless defined $smbUser; $sambaGroup->addMember($smbUser, 1); } otherwise { my $error = shift; EBox::error("Error adding member: $error"); }; } $sambaGroup->save(); } } sub ldapServicePrincipalsToLdb { my ($self) = @_; EBox::info('Loading Zentyal service principals into samba database'); my $sysinfo = EBox::Global->modInstance('sysinfo'); my $hostname = $sysinfo->hostName(); my $fqdn = $sysinfo->fqdn(); my $modules = EBox::Global->modInstancesOfType('EBox::KerberosModule'); foreach my $module (@{$modules}) { my $principals = $module->kerberosServicePrincipals(); my $samAccountName = "$principals->{service}-$hostname"; try { my $smbUser = new EBox::Samba::User(samAccountName => $samAccountName); unless ($smbUser->exists()) { # Get the heimdal user to extract the kerberos keys. All service # principals for each module should have the same keys, so take # the first one. my $usersModule = EBox::Global->modInstance('users'); my $p = @{$principals->{principals}}[0]; my $baseDn = $usersModule->ldap->dn(); my $realm = $usersModule->kerberosRealm(); my $dn = "krb5PrincipalName=$p/$fqdn\@$realm,ou=Kerberos,$baseDn"; my $user = new EBox::UsersAndGroups::User(dn => $dn); my $params = { description => scalar ($user->get('description')), kerberosKeys => $user->kerberosKeys(), }; $smbUser = EBox::Samba::User->create($samAccountName, $params); $smbUser->setCritical(1); $smbUser->setViewInAdvancedOnly(1); } foreach my $p (@{$principals->{principals}}) { try { my $spn = "$p/$fqdn"; EBox::debug("Adding SPN '$spn' to user " . $smbUser->dn()); $smbUser->addSpn($spn); } otherwise { my $error = shift; EBox::error("Error adding SPN '$p' to account '$samAccountName': $error"); }; } } otherwise { my $error = shift; EBox::error("Error adding account '$samAccountName': $error"); }; } } sub users { my ($self) = @_; my $params = { base => 'CN=Users,' . $self->dn(), scope => 'sub', filter => '(&(objectclass=user)(!(showInAdvancedViewOnly=*))(!(isDeleted=*)))', attrs => ['*', 'unicodePwd', 'supplementalCredentials'], }; my $result = $self->search($params); my $list = []; foreach my $entry ($result->sorted('samAccountName')) { my $user = new EBox::Samba::User(entry => $entry); my $entrySid = $user->sid(); my $skip = 0; foreach my $ignoredSidMask (@{$self->{ignoredSids}}) { $skip = 1 if ($user->sid() =~ m/$ignoredSidMask/); } next if $skip; push (@{$list}, $user); } return $list; } sub groups { my ($self) = @_; my $params = { base => 'CN=Users,' . $self->dn(), scope => 'sub', filter => '(&(objectclass=group)(!(showInAdvancedViewOnly=*))(!(isDeleted=*)))', attrs => ['*', 'unicodePwd', 'supplementalCredentials'], }; my $result = $self->search($params); my $list = []; foreach my $entry ($result->sorted('samAccountName')) { my $group = new EBox::Samba::Group(entry => $entry); my $skip = 0; foreach my $ignoredSidMask (@{$self->{ignoredSids}}) { $skip = 1 if ($group->sid() =~ m/$ignoredSidMask/); } my $entrySid = $group->sid(); next if $skip; push (@{$list}, $group); } return $list; } sub ldbUsersToLdap { my ($self, $users) = @_; EBox::info('Loading Samba users into Zentyal LDAP'); my $usersModule = EBox::Global->modInstance('users'); $users = $self->users() unless defined ($users); foreach my $sambaUser (@{$users}) { my $dn = $sambaUser->dn(); EBox::info("Adding user '$dn'"); my $user = undef; try { my $params = {}; $params->{user} = $sambaUser->get('samAccountName'); $params->{fullname} = $sambaUser->get('name'); $params->{givenname} = defined (scalar ($sambaUser->get('givenName'))) ? $sambaUser->get('givenName') : $sambaUser->get('samAccountName'); $params->{surname} = defined (scalar ($sambaUser->get('sn'))) ? $sambaUser->get('sn') : $sambaUser->get('samAccountName'); $params->{comment} = defined (scalar ($sambaUser->get('description'))) ? $sambaUser->get('description') : undef; my %optParams; $optParams{ignoreMods} = ['samba']; $user = EBox::UsersAndGroups::User->create($params, 0, %optParams); } catch EBox::Exceptions::DataExists with { $user = $usersModule->user($sambaUser->get('samAccountName')); } otherwise { my $error = shift; EBox::error("Error loading user '$dn': $error"); }; next unless defined $user; try { my $suppCred = $sambaUser->get('supplementalCredentials'); my $unicodePwd = $sambaUser->get('unicodePwd'); my $credentials = new EBox::Samba::Credentials( supplementalCredentials => $suppCred, unicodePwd => $unicodePwd); $user->setKerberosKeys($credentials->kerberosKeys()); } otherwise { my $error = shift; EBox::error("Error setting kerberos keys: $error"); }; try { my $uidNumber = $user->get('uidNumber'); $sambaUser->set('uidNumber', $uidNumber); my $type = $self->idmap->TYPE_UID(); my $sid = $sambaUser->sid(); $self->idmap->setupNameMapping($sid, $type, $uidNumber); } otherwise { my $error = shift; EBox::error("Error setting uid mapping: $error"); }; } } sub ldbGroupsToLdap { my ($self, $groups) = @_; EBox::info('Loading Samba groups into Zentyal LDAP'); my $usersModule = EBox::Global->modInstance('users'); $groups = $self->groups() unless defined ($groups); foreach my $sambaGroup (@{$groups}) { my $dn = $sambaGroup->dn(); my $name = $sambaGroup->get('samAccountName'); my $comment = $sambaGroup->get('description'); my $zentyalGroup = undef; try { my %optParams; $optParams{ignoreMods} = ['samba']; EBox::info("Adding group '$dn'"); $zentyalGroup = EBox::UsersAndGroups::Group->create($name, $comment, 0, %optParams); } catch EBox::Exceptions::DataExists with { $zentyalGroup = $usersModule->group($name); } otherwise { my $error = shift; EBox::error("Error adding group '$dn': $error"); }; next unless defined $zentyalGroup; try { my $gidNumber = $zentyalGroup->get('gidNumber'); $sambaGroup->set('gidNumber', $gidNumber); my $type = $self->idmap->TYPE_GID(); my $sid = $sambaGroup->sid(); $self->idmap->setupNameMapping($sid, $type, $gidNumber); } otherwise { my $error = shift; EBox::error("Error setting up gid mapping: $error"); }; my @members = $sambaGroup->get('member'); foreach my $sambaDN (@members) { try { my $sambaMember = new EBox::Samba::User(dn => $sambaDN); my $zentyalUser = $usersModule->user($sambaMember->get('samAccountName')); $zentyalGroup->addMember($zentyalUser); } otherwise { my $error = shift; EBox::error("Error adding member to group '$dn': $error"); }; } } } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/SambaFirewall.pm0000664000000000000000000000356412017560227021011 0ustar # Copyright (C) 2008-2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::SambaFirewall; use strict; use warnings; use base 'EBox::FirewallHelper'; use EBox::Objects; use EBox::Global; use EBox::Config; use EBox::Firewall; use EBox::Gettext; use constant SAMBAPORTS => qw(137 138 139 445); sub new { my $class = shift; my %opts = @_; my $self = $class->SUPER::new(@_); bless($self, $class); return $self; } sub output { my ($self) = @_; my @rules = (); my $samba = EBox::Global->modInstance('samba'); my @ifaces = @{ $samba->sambaInterfaces() }; foreach my $ifc (@ifaces) { my $output = $self->_outputIface($ifc); foreach my $port (SAMBAPORTS) { my $r = "-m state --state NEW $output ". "-p tcp --sport $port -j ACCEPT"; push(@rules, $r); $r = "-m state --state NEW $output ". "-p udp --sport $port -j ACCEPT"; push(@rules, $r); $r = "-m state --state NEW $output ". "-p tcp --dport $port -j ACCEPT"; push(@rules, $r); $r = "-m state --state NEW $output ". "-p udp --dport $port -j ACCEPT"; push(@rules, $r); } } return \@rules; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/LDB/0000775000000000000000000000000012017560227016333 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/LDB/IdMapDb.pm0000664000000000000000000000301412017560227020127 0ustar package EBox::LDB::IdMapDb; use strict; use warnings; use constant PRIVATE_DIR => '/var/lib/samba/private/'; use constant FILE => 'idmap.ldb'; # Mappings for ID_TYPE_UID, ID_TYPE_GID and ID_TYPE_BOTH use constant TYPE_UID => 'ID_TYPE_UID'; use constant TYPE_GID => 'ID_TYPE_GID'; use constant TYPE_BOTH => 'ID_TYPE_BOTH'; sub new { my $class = shift; my $self = { file => PRIVATE_DIR . FILE }; bless ($self, $class); return $self; } # Method: setupNameMapping # # Setup a mapping between a SID and a uidNumber # sub setupNameMapping { my ($self, $sid, $type, $uidNumber) = @_; $self->deleteMapping($sid, 1); my $file = EBox::Config::tmp() . 'idmap.ldif'; my $ldif = "dn: CN=$sid\n" . "changetype: add\n" . "xidNumber: $uidNumber\n" . "objectSid: $sid\n" . "objectClass: sidMap\n" . "type: $type\n" . "cn: $sid\n"; EBox::debug("Mapping XID '$uidNumber' to '$sid'"); EBox::Sudo::root("echo '$ldif' | ldbmodify -H $self->{file}"); unlink $file; } sub deleteMapping { my ($self, $sid, $silent) = @_; my $file = EBox::Config::tmp() . 'idmap.ldif'; my $ldif = "dn: CN=$sid\n" . "changetype: delete\n"; if ($silent) { EBox::Sudo::silentRoot("echo '$ldif' | ldbmodify -H $self->{file}"); } else { EBox::debug("Unmapping XID '$sid'"); EBox::Sudo::root("echo '$ldif' | ldbmodify -H $self->{file}"); } unlink $file; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/SambaLdapUser.pm0000664000000000000000000002230012017560227020750 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::SambaLdapUser; use strict; use warnings; use MIME::Base64; use Encode; use Error qw(:try); use EBox::Sudo; use EBox::Samba; use EBox::Samba::User; use EBox::Samba::Group; use EBox::UsersAndGroups::User; use EBox::UsersAndGroups::Group; use base qw(EBox::LdapUserBase); sub new { my $class = shift; my $self = {}; $self->{samba} = EBox::Global->modInstance('samba'); $self->{ldb} = $self->{samba}->ldb(); bless($self, $class); return $self; } # Method: _addUser # # This method adds the user to samba LDAP # TODO Support multiples OU # sub _addUser { my ($self, $zentyalUser, $zentyalPassword) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalUser->dn(); EBox::debug("Adding user '$dn' to samba"); my $params = { clearPassword => $zentyalPassword, uidNumber => scalar ($zentyalUser->get('uidNumber')), description => scalar ($zentyalUser->get('description')), givenName => scalar ($zentyalUser->get('givenName')), sn => scalar ($zentyalUser->get('sn')), }; EBox::Samba::User->create($zentyalUser->get('uid'), $params); } sub _modifyUser { my ($self, $zentyalUser, $zentyalPwd) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalUser->dn(); EBox::debug("Updating user '$dn'"); try { my $sambaUser = new EBox::Samba::User(samAccountName => $zentyalUser->get('uid')); return unless $sambaUser->exists(); my $gn = $zentyalUser->get('givenName'); my $sn = $zentyalUser->get('sn'); my $desc = $zentyalUser->get('description'); $sambaUser->set('givenName', $gn, 1); $sambaUser->set('sn', $sn, 1); $sambaUser->set('description', $desc, 1); $sambaUser->changePassword($zentyalPwd, 1) if defined $zentyalPwd; $sambaUser->save(); } otherwise { my ($error) = @_; EBox::error("Error modifying user: $error"); }; } sub _delUser { my ($self, $zentyalUser) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalUser->dn(); EBox::debug("Deleting user '$dn' from samba"); try { my $sambaUser = new EBox::Samba::User(samAccountName => $zentyalUser->get('uid')); return unless $sambaUser->exists(); $sambaUser->deleteObject(); } otherwise { my ($error) = @_; EBox::error("Error deleting user: $error"); }; } # Method: _addGroup # # This method adds the group to samba LDAP # TODO Support multiples OU # sub _addGroup { my ($self, $zentyalGroup) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalGroup->dn(); EBox::debug("Adding group '$dn' to samba"); my $params = { gidNumber => scalar ($zentyalGroup->get('gidNumber')), description => scalar ($zentyalGroup->get('description')), }; EBox::Samba::Group->create($zentyalGroup->get('cn'), $params); } sub _modifyGroup { my ($self, $zentyalGroup) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalGroup->dn(); EBox::debug("Modifying group '$dn'"); try { my $sambaGroup = new EBox::Samba::Group(samAccountName => $zentyalGroup->get('cn')); return unless $sambaGroup->exists(); my $sambaMembersDNs = []; my $zentyalMembers = $zentyalGroup->users(); foreach my $zentyalMember (@{$zentyalMembers}) { my $sambaUser = new EBox::Samba::User(samAccountName => $zentyalMember->get('uid')); push (@{$sambaMembersDNs}, $sambaUser->dn()); } $sambaGroup->set('member', $sambaMembersDNs, 1); $sambaGroup->set('description', scalar ($zentyalGroup->get('description')), 1); $sambaGroup->save(); } otherwise { my ($error) = @_; EBox::error("Error modifying group: $error"); }; } sub _delGroup { my ($self, $zentyalGroup) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $dn = $zentyalGroup->dn(); EBox::debug("Deleting group '$dn' from samba"); try { my $sambaGroup = new EBox::Samba::Group(samAccountName => $zentyalGroup->get('cn')); return unless $sambaGroup->exists(); $sambaGroup->deleteObject(); } otherwise { my ($error) = @_; EBox::error("Error deleting user: $error"); }; } # User and group addons sub _userAddOns { my ($self, $zentyalUser) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $sambaUser = new EBox::Samba::User(samAccountName => $zentyalUser->get('uid')); return undef unless $sambaUser->exists(); my $serviceEnabled = $self->{samba}->isEnabled(); my $accountEnabled = $sambaUser->isAccountEnabled(); my $args = { 'username' => $zentyalUser->dn(), 'accountEnabled' => $accountEnabled, 'service' => $serviceEnabled, }; return { path => '/samba/samba.mas', params => $args }; } # Method: _groupShareEnabled # # Check if there is a share configured for the group # # Returns: # # The share name or undef if it is not configured # sub _groupShareEnabled { my ($self, $zentyalGroup) = @_; my $groupName = $zentyalGroup->get('cn'); my $sharesModel = $self->{samba}->model('SambaShares'); foreach my $id (@{$sharesModel->ids()}) { my $row = $sharesModel->row($id); my $shareName = $row->valueByName('share'); my $groupShare = $row->valueByName('groupShare'); return $shareName if $groupShare eq $groupName; } return undef; } sub setGroupShare { my ($self, $group, $shareName) = @_; if ((not defined $shareName) or ( $shareName =~ /^\s*$/)) { throw EBox::Exceptions::External(__("A name should be provided for the share.")); } my $oldName = $self->_groupShareEnabled($group); return if ($oldName and $oldName eq $shareName); my $groupName = $group->get('cn'); my $sharesModel = $self->{samba}->model('SambaShares'); # Create or rename the share for the group my $row = $sharesModel->findValue(groupShare => $groupName); if ($row) { # Rename the share EBox::debug("Renaming the share for group '$groupName' from '$oldName' to '$shareName'"); $row->elementByName('share')->setValue($shareName); $row->store(); } else { # Add the share my %params = ( share => $shareName, path_selected => 'zentyal', zentyal => $shareName, comment => "Share for group $groupName", guest => 0, groupShare => $groupName ); EBox::debug("Adding share named '$shareName' for group '$groupName'"); my $shareRowId = $sharesModel->addRow(%params, readOnly => 1, enabled => 1); my $shareRow = $sharesModel->row($shareRowId); # And set the access control my $accessModel = $shareRow->subModel('access'); %params = ( user_group_selected => 'group', group => $groupName, permissions => 'readWrite' ); $accessModel->addRow(%params); } } sub removeGroupShare { my ($self, $zentyalGroup) = @_; my $groupName = $zentyalGroup->get('cn'); my $sharesModel = $self->{samba}->model('SambaShares'); my $row = $sharesModel->findValue(groupShare => $groupName); $sharesModel->removeRow($row->id()) if $row; } sub _groupAddOns { my ($self, $zentyalGroup) = @_; return unless ($self->{samba}->configured() and $self->{samba}->isEnabled() and $self->{samba}->isProvisioned()); my $share = $self->_groupShareEnabled($zentyalGroup); my $args = { 'groupname' => $zentyalGroup->dn(), 'share' => $share, 'service' => $self->{samba}->isEnabled(), }; return { path => '/samba/samba.mas', params => $args }; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/Samba.pm0000664000000000000000000015622612017560227017327 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::Samba; use strict; use warnings; use base qw( EBox::Module::Service EBox::FirewallObserver EBox::LdapModule EBox::LogObserver ); use EBox::Global; use EBox::Service; use EBox::Sudo; use EBox::SambaLdapUser; use EBox::Network; use EBox::SambaFirewall; use EBox::SambaLogHelper; use EBox::Dashboard::Widget; use EBox::Dashboard::List; use EBox::Menu::Item; use EBox::Exceptions::Internal; use EBox::Gettext; use EBox::Config; use EBox::DBEngineFactory; use EBox::LDB; use EBox::Util::Random qw( generate ); use Perl6::Junction qw( any ); use Error qw(:try); use File::Slurp; use File::Temp; use constant SAMBA_DIR => '/home/samba/'; use constant SAMBA_PROVISION_FILE => SAMBA_DIR . '.provisioned'; use constant SAMBATOOL => '/usr/bin/samba-tool'; use constant SAMBAPROVISION => '/usr/share/samba/setup/provision'; use constant SAMBACONFFILE => '/etc/samba/smb.conf'; use constant PRIVATE_DIR => '/var/lib/samba/private/'; use constant SAMBA_DNS_ZONE => PRIVATE_DIR . 'named.conf'; use constant SAMBA_DNS_POLICY => PRIVATE_DIR . 'named.conf.update'; use constant SAMBA_DNS_KEYTAB => PRIVATE_DIR . 'dns.keytab'; use constant SAMBA_DNS_DLZ_X86 => '/usr/lib/i386-linux-gnu/samba/bind9/dlz_bind9.so'; use constant SAMBA_DNS_DLZ_X64 => '/usr/lib/x86_64-linux-gnu/samba/bind9/dlz_bind9.so'; use constant SAM_DB => PRIVATE_DIR . 'sam.ldb'; use constant SAMBA_PRIVILEGED_SOCKET => PRIVATE_DIR . '/ldap_priv'; use constant FSTAB_FILE => '/etc/fstab'; use constant SYSVOL_DIR => '/var/lib/samba/sysvol'; use constant SHARES_DIR => SAMBA_DIR . '/shares'; use constant PROFILES_DIR => SAMBA_DIR . '/profiles'; use constant LOGON_SCRIPT => 'logon.bat'; use constant LOGON_DEFAULT_SCRIPT => 'zentyal-logon.bat'; use constant CLAMAVSMBCONFFILE => '/etc/samba/vscan-clamav.conf'; sub _create { my $class = shift; my $self = $class->SUPER::_create( name => 'samba', printableName => __('File Sharing'), @_); bless ($self, $class); return $self; } # Method: bootDepends # # Samba depends on CUPS only if printers module enabled. # # Overrides: # # # sub bootDepends { my ($self) = @_; my $dependsList = $self->depends(); my $module = 'printers'; if (EBox::Global->modExists($module)) { my $printers = EBox::Global->modInstance($module); if ($printers->isEnabled()) { push (@{$dependsList}, $module); } } return $dependsList; } # Method: actions # # Override EBox::Module::Service::actions # sub actions { return [ { 'action' => __('Create Samba home directory for shares and groups'), 'reason' => __('Zentyal will create the directories for Samba ' . 'shares and groups under /home/samba.'), 'module' => 'samba', }, ]; } # Method: usedFiles # # Override EBox::Module::Service::files # sub usedFiles { return [ { 'file' => SAMBACONFFILE, 'reason' => __('To set up Samba according to your configuration.'), 'module' => 'samba', }, { 'file' => FSTAB_FILE, 'reason' => __('To enable extended attributes and acls.'), 'module' => 'samba', }, { 'file' => '/etc/services', 'reason' => __('To add microsoft specific services'), 'module' => 'samba', }, { 'file' => CLAMAVSMBCONFFILE, 'reason' => __('To set the antivirus settings for Samba.'), 'module' => 'samba' }, ]; } # Method: initialSetup # # Overrides: # # EBox::Module::Base::initialSetup # sub initialSetup { my ($self, $version) = @_; # Create default rules and services only if enabling the first time unless ($version) { my $services = EBox::Global->modInstance('services'); my $serviceName = 'samba'; unless($services->serviceExists(name => $serviceName)) { $services->addMultipleService( 'name' => $serviceName, 'printableName' => 'Samba', 'description' => __('File sharing (Samba) protocol'), 'internal' => 1, 'readOnly' => 1, 'services' => $self->_services(), ); } my $firewall = EBox::Global->modInstance('firewall'); $firewall->setInternalService($serviceName, 'accept'); $firewall->saveConfigRecursive(); } } sub enableService { my ($self, $status) = @_; if ($self->isEnabled() and not $status) { $self->setupDNS(0); } elsif (not $self->isEnabled() and $status) { $self->setupDNS(1); } $self->SUPER::enableService($status); } # Method: _startService # # Overrided to ensure proper permissions of the ldap_priv folder, where the # privileged socket that zentyal uses to connect is. This is a special socket # that samba create that allow r/w restricted attributes. # Samba expects the ldap_priv folder to be owned by root and mode 0750, or the # LDAP service won't run. # # Here we set the expected permissions before start the daemon. # sub _startService { my ($self) = @_; my $group = EBox::Config::group(); EBox::Sudo::root("mkdir -p " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chgrp $group " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chmod 0750 " . SAMBA_PRIVILEGED_SOCKET); $self->SUPER::_startService(@_); } # Method: _enforceServiceState # # Start the samba daemon is expensive and takes a while. After writing # smb.conf the daemon is started to make queries to LDB, so it is not # necessary to restart it after that. This method is overrided to avoid # this situation and restart samba twice while saving changes. # sub _enforceServiceState { my ($self) = @_; if ($self->isEnabled() and $self->isProvisioned()) { unless ($self->isRunning()) { $self->_startService(); } } else { $self->_stopService(); } } sub _services { my ($self) = @_; return [ { # kerberos 'protocol' => 'tcp/udp', 'sourcePort' => 'any', 'destinationPort' => '88', 'description' => 'Kerberos authentication', }, { # DCE endpoint resolution 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '135', 'description' => 'DCE endpoint resolution', }, { # netbios-ns 'protocol' => 'udp', 'sourcePort' => 'any', 'destinationPort' => '137', 'description' => 'NETBIOS name service', }, { # netbios-dgm 'protocol' => 'udp', 'sourcePort' => 'any', 'destinationPort' => '138', 'description' => 'NETBIOS datagram service', }, { # netbios-ssn 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '139', 'description' => 'NETBIOS session service', }, { # samba LDAP 'protocol' => 'tcp/udp', 'sourcePort' => 'any', 'destinationPort' => '389', 'description' => 'Lightweight Directory Access Protocol', }, { # microsoft-ds 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '445', 'description' => 'Microsoft directory services', }, { # kerberos change/set password 'protocol' => 'tcp/udp', 'sourcePort' => 'any', 'destinationPort' => '464', 'description' => 'Kerberos set/change password', }, { # LDAP over TLS/SSL 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '636', 'description' => 'LDAP over TLS/SSL', }, { # unknown??? 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '1024', }, { # msft-gc 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '3268', 'description' => 'Microsoft global catalog', }, { # msft-gc-ssl 'protocol' => 'tcp', 'sourcePort' => 'any', 'destinationPort' => '3269', 'description' => 'Microsoft global catalog over SSL', }, ]; } # Method: enableActions # # Override EBox::Module::Service::enableActions # sub enableActions { my ($self) = @_; my $group = EBox::UsersAndGroups::DEFAULTGROUP(); my @cmds = (); push (@cmds, 'invoke-rc.d samba4 stop'); push (@cmds, 'update-rc.d samba4 disable'); push (@cmds, 'mkdir -p ' . SAMBA_DIR); push (@cmds, "chown root:$group " . SAMBA_DIR); push (@cmds, "chmod 770 " . SAMBA_DIR); push (@cmds, 'mkdir -p ' . PROFILES_DIR); push (@cmds, "chown root:$group " . PROFILES_DIR); push (@cmds, "chmod 770 " . PROFILES_DIR); push (@cmds, 'mkdir -p ' . SHARES_DIR); push (@cmds, "chown root:$group " . SHARES_DIR); push (@cmds, "chmod 770 " . SHARES_DIR); EBox::debug('Creating directories'); EBox::Sudo::root(@cmds); # Remount filesystem with user_xattr and acl options EBox::debug('Setting up filesystem options'); EBox::Sudo::root(EBox::Config::scripts('samba') . 'setup-filesystem'); } sub isProvisioned { my ($self) = @_; return EBox::Sudo::fileTest('-f', SAMBA_PROVISION_FILE); } sub setProvisioned { my ($self, $provisioned) = @_; if ($provisioned) { EBox::Sudo::root("touch " . SAMBA_PROVISION_FILE); } else { EBox::Sudo::root("rm -f " . SAMBA_PROVISION_FILE); } } # Method: shares # # It returns the custom shares # # Parameters: # # all - return all shares regardless of their permission # level. Otherwise shares without permssions or guset access are # ignored. Default: false # # Returns: # # Array ref containing hash ref with: # # share - share's name # path - share's path # comment - share's comment # readOnly - string containing users and groups with read-only permissions # readWrite - string containing users and groups with read and write # permissions # administrators - string containing users and groups with admin priviliges # on the share # validUsers - readOnly + readWrite + administrators # sub shares { my ($self, $all) = @_; my $shares = $self->model('SambaShares'); my @shares = (); for my $id (@{$shares->enabledRows()}) { my $row = $shares->row($id); my @readOnly; my @readWrite; my @administrators; my $shareConf = {}; my $path = $row->elementByName('path'); if ($path->selectedType() eq 'zentyal') { $shareConf->{'path'} = SHARES_DIR . '/' . $path->value(); } else { $shareConf->{'path'} = $path->value(); } $shareConf->{'share'} = $row->valueByName('share'); $shareConf->{'comment'} = $row->valueByName('comment'); $shareConf->{'guest'} = $row->valueByName('guest'); $shareConf->{'groupShare'} = $row->valueByName('groupShare'); for my $subId (@{$row->subModel('access')->ids()}) { my $subRow = $row->subModel('access')->row($subId); my $userType = $subRow->elementByName('user_group'); my $preCar = ''; if ($userType->selectedType() eq 'group') { $preCar = '@'; } my $user = $preCar . '"' . $userType->printableValue() . '"'; my $permissions = $subRow->elementByName('permissions'); if ($permissions->value() eq 'readOnly') { push (@readOnly, $user); } elsif ($permissions->value() eq 'readWrite') { push (@readWrite, $user); } elsif ($permissions->value() eq 'administrator') { push (@administrators, $user) } } if (not $all) { next unless (@readOnly or @readWrite or @administrators or $shareConf->{'guest'}); } $shareConf->{'readOnly'} = join (', ', @readOnly); $shareConf->{'readWrite'} = join (', ', @readWrite); $shareConf->{'administrators'} = join (', ', @administrators); $shareConf->{'validUsers'} = join (', ', @readOnly, @readWrite, @administrators); push (@shares, $shareConf); } return \@shares; } sub defaultAntivirusSettings { my ($self) = @_; my $antivirus = $self->model('AntivirusDefault'); return $antivirus->value('scan'); } sub antivirusExceptions { my ($self) = @_; my $model = $self->model('AntivirusExceptions'); my $exceptions = { 'share' => {}, 'group' => {}, }; foreach my $id (@{$model->ids()}) { my $row = $model->row($id); my $element = $row->elementByName('user_group_share'); my $type = $element->selectedType(); if ($type eq 'users') { $exceptions->{'users'} = 1; } else { my $value = $element->printableValue(); $exceptions->{$type}->{$value} = 1; } } return $exceptions; } sub defaultRecycleSettings { my ($self) = @_; my $recycle = $self->model('RecycleDefault'); return $recycle->row()->valueByName('enabled'); } sub recycleExceptions { my ($self) = @_; my $model = $self->model('RecycleExceptions'); my $exceptions = { 'share' => {}, 'group' => {}, }; for my $id (@{$model->ids()}) { my $row = $model->row($id); my $element = $row->elementByName('user_group_share'); my $type = $element->selectedType(); if ($type eq 'users') { $exceptions->{'users'} = 1; } else { my $value = $element->printableValue(); $exceptions->{$type}->{$value} = 1; } } return $exceptions; } sub recycleConfig { my ($self) = @_; my $conf = {}; my @keys = ('repository', 'directory_mode', 'keeptree', 'versions', 'touch', 'minsize', 'maxsize', 'exclude', 'excludedir', 'noversions'); foreach my $key (@keys) { my $value = EBox::Config::configkey($key); if ($value) { $conf->{$key} = $value; } } return $conf; } # Method: provision # # This method provision the database # sub provision { my ($self) = @_; # Stop the service $self->stopService(); # Delete samba config file and private folder EBox::Sudo::root('rm -f ' . SAMBACONFFILE); EBox::Sudo::root('rm -rf ' . PRIVATE_DIR . '/*'); my $mode = $self->mode(); my $fs = EBox::Config::configkey('samba_fs'); if ($mode eq EBox::Samba::Model::GeneralSettings::MODE_DC()) { $self->provisionAsDC($fs); } elsif ($mode eq EBox::Samba::Model::GeneralSettings::MODE_ADC()) { $self->provisionAsADC(); } else { throw EBox::Exceptions::External(__x('The mode {mode} is not supported'), mode => $mode); } } sub provisionAsDC { my ($self, $fs) = @_; my $sysinfo = EBox::Global->modInstance('sysinfo'); my $usersModule = EBox::Global->modInstance('users'); my $cmd = SAMBAPROVISION . ' --domain=' . $self->workgroup() . ' --workgroup=' . $self->workgroup() . ' --realm=' . $usersModule->kerberosRealm() . ' --dns-backend=BIND9_DLZ' . ' --use-xattrs=yes ' . ' --server-role=' . $self->mode() . ' --users=' . $usersModule->DEFAULTGROUP() . ' --host-name=' . $sysinfo->hostName(); $cmd .= ' --use-ntvfs' if (defined $fs and $fs eq 'ntvfs'); EBox::debug("Provisioning database '$cmd'"); $cmd .= " --adminpass='" . $self->administratorPassword() . "'"; # Use silent root to avoid showing the admin pass in the logs if # provision command fails. my $output = EBox::Sudo::silentRoot($cmd); if ($? == 0) { EBox::debug("Provision result: @{$output}"); # Mark the module as provisioned EBox::debug('Setting provisioned flag'); $self->setProvisioned(1); } else { my @error = (); my $stderr = EBox::Config::tmp() . 'stderr'; if (-r $stderr) { @error = read_file($stderr); } throw EBox::Exceptions::Internal("Error provisioning database. Output: @{$output}, error:@error"); }; # Disable password policy # NOTE complexity is disabled because when changing password in # zentyal the command may fail if it do not meet requirements, # ending with different passwords EBox::debug('Setting password policy'); $cmd = SAMBATOOL . " domain passwordsettings set " . " --complexity=off " . " --min-pwd-length=0" . " --min-pwd-age=0" . " --max-pwd-age=365"; EBox::Sudo::root($cmd); # Set DNS. The domain should have been created by the users # module. $self->setupDNS(1); # Write smb.conf to grant rw access to zentyal group on the # privileged socket $self->writeSambaConfig(); my $group = EBox::Config::group(); EBox::Sudo::root("mkdir -p " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chgrp $group " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chmod 0750 " . SAMBA_PRIVILEGED_SOCKET); # Start managed service to let it create the LDAP socket EBox::debug('Starting service'); $self->_startService(); # Load all zentyal users and groups into ldb $self->ldb->ldapUsersToLdb(); $self->ldb->ldapGroupsToLdb(); $self->ldb->ldapServicePrincipalsToLdb(); } sub provisionAsADC { my ($self) = @_; my $model = $self->model('GeneralSettings'); my $domainToJoin = $model->value('realm'); my $dcFQDN = $model->value('dcfqdn'); my $domainDNS = $model->value('dnsip'); my $adminAccount = $model->value('adminAccount'); my $adminAccountPwd = $model->value('password'); my $netbiosDomain = $model->value('workgroup'); # If the host domain or the users kerberos realm does not # match the domain we are trying to join warn the user and # abort my $sysinfo = EBox::Global->modInstance('sysinfo'); my $usersModule = EBox::Global->modInstance('users'); my $hostName = $sysinfo->hostName(); my $ucHostName = uc ($hostName); my $krbRealm = $usersModule->kerberosRealm(); my $fqdn = $sysinfo->fqdn(); if (lc ($sysinfo->hostDomain()) ne lc ($domainToJoin) or lc ($sysinfo->hostDomain() ne lc ($krbRealm))) { throw EBox::Exceptions::External( __('The server domain and kerberos realm must match the domain the ' . 'domain you are trying to join.')); } my $dnsFile = undef; try { EBox::info("Joining to domain '$domainToJoin' as DC"); # Set the domain DNS as the primary resolver. This will also let to get # the kerberos ticket for the admin account. EBox::debug("Setting domain DNS server '$domainDNS' as the primary resolver"); $dnsFile = new File::Temp(TEMPLATE => 'resolvXXXXXX', DIR => EBox::Config::tmp()); EBox::Sudo::root("cp /etc/resolv.conf $dnsFile"); my $array = []; push (@{$array}, searchDomain => $domainToJoin); push (@{$array}, nameservers => [ $domainDNS ]); $self->writeConfFile(EBox::Network::RESOLV_FILE(), 'network/resolv.conf.mas', $array); # Join the domain EBox::debug("Joining to the domain"); my @cmds; push (@cmds, SAMBATOOL . " domain join $domainToJoin DC " . " -U $adminAccount " . " --workgroup='$netbiosDomain' " . " --password='$adminAccountPwd' " . " --server=$dcFQDN"); my $output = EBox::Sudo::silentRoot(@cmds); if ($? == 0) { $self->setProvisioned(1); EBox::debug("Provision result: @{$output}"); } else { my @error = (); my $stderr = EBox::Config::tmp() . 'stderr'; if (-r $stderr) { @error = read_file($stderr); } throw EBox::Exceptions::Internal("Error joining to domain: @error"); } $self->setupDNS(1); # Write smb.conf to grant rw access to zentyal group on the # privileged socket $self->writeSambaConfig(); my $group = EBox::Config::group(); EBox::Sudo::root("mkdir -p " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chgrp $group " . SAMBA_PRIVILEGED_SOCKET); EBox::Sudo::root("chmod 0750 " . SAMBA_PRIVILEGED_SOCKET); # Start managed service to let it create the LDAP socket EBox::debug('Starting service'); $self->_startService(); # Wait for RID allocation my $args = { base => "CN=$hostName,OU=Domain Controllers," . $self->ldb->dn, scope => 'base', filter => '(objectClass=*)', attrs => ['rIDSetReferences'], }; for (my $retries=12; $retries>=0; $retries--) { EBox::debug ("Waiting for RID allocation, $retries"); my $result = $self->ldb->search($args); if ($result->count() == 1) { my $entry = $result->entry(0); my @val = $entry->get_value('rIDSetReferences'); last if @val; } sleep (5); } # Purge users and groups EBox::info("Purging the Zentyal LDAP to import Samba users"); my $usersMod = EBox::Global->modInstance('users'); my $users = $usersMod->users(); my $groups = $usersMod->groups(); foreach my $user (@{$users}) { $user->deleteObject(); } foreach my $group (@{$groups}) { $group->deleteObject(); } # Load samba users and groups into Zentyal ldap $self->ldb->ldbUsersToLdap(); $self->ldb->ldbGroupsToLdap(); # Load Zentyal service principals into samba $self->ldb->ldapServicePrincipalsToLdb(); # Load administrator user and domain admins group to zentyal my $domainSid = $self->ldb->domainSID(); my $adminUser = new EBox::Samba::User(sid => $domainSid . '-500'); my $adminGroup = new EBox::Samba::Group(sid => $domainSid . '-512'); $self->ldb->ldbUsersToLdap([$adminUser]); $self->ldb->ldbGroupsToLdap([$adminGroup]); # FIXME This should not be necessary, it is a samba bug. @cmds = (); push (@cmds, "rm -f " . SAMBA_DNS_KEYTAB); push (@cmds, SAMBATOOL . " spn add DNS/$fqdn $ucHostName\$"); push (@cmds, SAMBATOOL . " domain exportkeytab " . SAMBA_DNS_KEYTAB . " --principal=$ucHostName\$"); push (@cmds, SAMBATOOL . " domain exportkeytab " . SAMBA_DNS_KEYTAB . " --principal=DNS/$fqdn"); push (@cmds, "chgrp bind " . SAMBA_DNS_KEYTAB); push (@cmds, "chmod g+r " . SAMBA_DNS_KEYTAB); EBox::Sudo::root(@cmds); } otherwise { my $error = shift; throw $error; } finally { # Revert primary resolver changes if (defined $dnsFile and -f $dnsFile) { EBox::Sudo::root("cp $dnsFile /etc/resolv.conf"); unlink $dnsFile; } }; } # Method: setupDNS # # Modify the domain setup for samba or for users module # # Parameters: # # dlz - If set to 1, the domain will be set up for samba, else it will be # set up for users module # sub setupDNS { my ($self, $dlz) = @_; my $dnsModule = EBox::Global->modInstance('dns'); my $usersModule = EBox::Global->modInstance('users'); my $sysinfo = EBox::Global->modInstance('sysinfo'); my $domainModel = $dnsModule->model('DomainTable'); my $domainRow = $domainModel->find(domain => $sysinfo->hostDomain()); unless (defined $domainRow) { throw EBox::Exceptions::Internal("Domain named '" . $sysinfo->hostDomain() . "' not found"); } my $DBPath = undef; if (EBox::Sudo::fileTest('-f', SAMBA_DNS_DLZ_X86)) { $DBPath = SAMBA_DNS_DLZ_X86; } elsif (EBox::Sudo::fileTest('-f', SAMBA_DNS_DLZ_X64)) { $DBPath = SAMBA_DNS_DLZ_X64; } unless (defined $DBPath) { throw EBox::Exceptions::Internal( __("Samba DNS DLZ file for bind can't be found")); } if ($dlz) { EBox::debug('Setting up DNS for samba'); $domainRow->elementByName('dlzDbPath')->setValue($DBPath); $domainRow->elementByName('type')->setValue(EBox::DNS::DLZ_ZONE()); $domainRow->store(); } else { EBox::debug('Setting up DNS for users'); $domainRow->elementByName('type')->setValue(EBox::DNS::STATIC_ZONE()); $domainRow->store(); } if (EBox::Sudo::fileTest('-f', SAMBA_DNS_KEYTAB)) { my @cmds; push (@cmds, "chgrp bind " . SAMBA_DNS_KEYTAB); push (@cmds, "chmod g+r " . SAMBA_DNS_KEYTAB); EBox::Sudo::root(@cmds); } } # Method: sambaInterfaces # # Return interfaces upon samba should listen # sub sambaInterfaces { my ($self) = @_; my @ifaces = (); # Always listen on loopback interface push (@ifaces, 'lo'); my $net = EBox::Global->modInstance('network'); my $listen_external = EBox::Config::configkey('listen_external'); my $netIfaces; if ($listen_external eq 'yes') { $netIfaces = $net->allIfaces(); } else { $netIfaces = $net->InternalIfaces(); } foreach my $iface (@{$netIfaces}) { push @ifaces, $iface; if ($net->ifaceMethod($iface) eq 'bridged') { my $br = $net->ifaceBridge($iface); push (@ifaces, "br$br"); next; } my $vifacesNames = $net->vifaceNames($iface); if (defined $vifacesNames) { push @ifaces, @{$vifacesNames}; } } my @moduleGeneratedIfaces = (); push @ifaces, @moduleGeneratedIfaces; return \@ifaces; } sub writeSambaConfig { my ($self) = @_; my $interfaces = join (',', @{$self->sambaInterfaces()}); my $netbiosName = $self->netbiosName(); my $realmName = EBox::Global->modInstance('users')->kerberosRealm(); my $prefix = EBox::Config::configkey('custom_prefix'); $prefix = 'zentyal' unless $prefix; my @array = (); push (@array, 'fs' => EBox::Config::configkey('samba_fs')); push (@array, 'prefix' => $prefix); push (@array, 'workgroup' => $self->workgroup()); push (@array, 'netbiosName' => $netbiosName); push (@array, 'description' => $self->description()); push (@array, 'ifaces' => $interfaces); push (@array, 'mode' => 'dc'); push (@array, 'realm' => $realmName); push (@array, 'roamingProfiles' => $self->roamingProfiles()); push (@array, 'profilesPath' => PROFILES_DIR); push (@array, 'printers' => $self->printersConf()); #push(@array, 'backup_path' => EBox::Config::conf() . 'backups'); #push(@array, 'quarantine_path' => EBox::Config::var() . 'lib/zentyal/quarantine'); my $shares = $self->shares(); push(@array, 'shares' => $shares); push (@array, 'antivirus' => $self->defaultAntivirusSettings()); push (@array, 'antivirus_exceptions' => $self->antivirusExceptions()); push (@array, 'recycle' => $self->defaultRecycleSettings()); push (@array, 'recycle_exceptions' => $self->recycleExceptions()); push (@array, 'recycle_config' => $self->recycleConfig()); #my $netlogonDir = "/var/lib/samba/sysvol/" . $self->realm() . "/scripts"; #if ($self->mode() eq 'dc') { # #my $logonScript = join('/', $netlogonDir, LOGON_SCRIPT); # #if (EBox::Sudo::fileTest('-f', $logonScript)) { # # push(@array, 'logon_script', LOGON_SCRIPT); # #} # $self->writeConfFile(join('/', $netlogonDir, LOGON_DEFAULT_SCRIPT), # 'samba/logon.bat.mas', \@array); #} $self->writeConfFile(SAMBACONFFILE, 'samba/smb.conf.mas', \@array); $self->writeConfFile(CLAMAVSMBCONFFILE, 'samba/vscan-clamav.conf.mas', []); } sub _preSetConf { my ($self) = @_; $self->stopService(); } sub _setConf { my ($self) = @_; return unless $self->configured() and $self->isEnabled(); $self->provision() unless $self->isProvisioned(); $self->writeSambaConfig(); # Remove shares $self->model('SambaDeletedShares')->removeDirs(); # Create shares $self->model('SambaShares')->createDirs(); # Change group ownership of quarantine_dir to __USERS__ my $quarantine_dir = EBox::Config::var() . '/lib/zentyal/quarantine'; EBox::Sudo::silentRoot("chown root:__USERS__ $quarantine_dir"); my $netbiosName = $self->netbiosName(); my $realmName = EBox::Global->modInstance('users')->kerberosRealm(); my $users = $self->ldb->users(); foreach my $user (@{$users}) { # Set roaming profiles if ($self->roamingProfiles()) { my $path = "\\\\$netbiosName.$realmName\\profiles"; $user->setRoamingProfile(1, $path, 1); } else { $user->setRoamingProfile(0); } # Mount user home on network drive my $drivePath = "\\\\$netbiosName.$realmName"; $user->setHomeDrive($self->drive(), $drivePath, 1); $user->save(); } } sub printersConf { my ($self) = @_; my $printers = []; if (EBox::Global->modExists('printers')) { my $printersModule = EBox::Global->modInstance('printers'); if ($printersModule->isEnabled()) { my $printersModel = $printersModule->model('Printers'); my $ids = $printersModel->ids(); foreach my $id (@{$ids}) { my $row = $printersModel->row($id); my $printerName = $row->valueByName('printer'); my $printerGuest = $row->valueByName('guest'); my $printerDescription = $row->valueByName('description'); # Get the allowed users and groups for this printer if guest # access is disabled my $printerAcl = []; for my $subId (@{$row->subModel('access')->ids()}) { my $subRow = $row->subModel('access')->row($subId); my $userType = $subRow->elementByName('user_group'); my $preCar = $userType->selectedType() eq 'group' ? '@' : ''; my $user = $preCar . '"' . $userType->printableValue() . '"'; push (@{$printerAcl}, $user); } push (@{$printers}, { name => $printerName, description => $printerDescription, guest => $printerGuest, acl => $printerAcl, } ); } } } return $printers; } sub _shareUsers { my $state = 0; my $pids = {}; # for my $line (`smbstatus`) { # chomp($line); # if($state == 0) { # if($line =~ '----------------------------') { # $state = 1; # } # } elsif($state == 1) { # if($line eq '') { # $state = 2; # } else { # # 1735 javi javi blackops (192.168.45.48) # $line =~ m/(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+\((\S+)\)/; # my ($pid, $user, $machine) = ($1, $2, $4); # $pids->{$pid} = { 'user' => $user, 'machine' => $machine }; # } # } elsif($state == 2) { # if($line =~ '----------------------------') { # $state = 3; # } # } elsif($state == 3) { # if($line eq '') { # last; # } else { # #administracion 1735 blackops Wed Nov 26 17:27:19 2008 # $line =~ m/(\S+)\s+(\d+)\s+(\S+)\s+(\S.+)/; # my($share, $pid, $date) = ($1, $2, $4); # $pids->{$pid}->{'share'} = $share; # $pids->{$pid}->{'date'} = $date; # } # } # } return [values %{$pids}]; } sub _sharesGroupedBy { my ($group) = @_; my $shareUsers = _shareUsers(); my $groupedInfo = {}; foreach my $info (@{$shareUsers}) { if (not defined ($groupedInfo->{$info->{$group}})) { $groupedInfo->{$info->{$group}} = []; } push (@{$groupedInfo->{$info->{$group}}}, $info); } return $groupedInfo; } sub sharesByUserWidget { my ($widget) = @_; my $sharesByUser = _sharesGroupedBy('user'); foreach my $user (sort keys %{$sharesByUser}) { my $section = new EBox::Dashboard::Section($user, $user); $widget->add($section); my $titles = [__('Share'), __('Source machine'), __('Connected since')]; my $rows = {}; foreach my $share (@{$sharesByUser->{$user}}) { my $id = $share->{'share'} . '_' . $share->{'machine'}; $rows->{$id} = [$share->{'share'}, $share->{'machine'}, $share->{'date'}]; } my $ids = [sort keys %{$rows}]; $section->add(new EBox::Dashboard::List(undef, $titles, $ids, $rows)); } } sub usersByShareWidget { my ($widget) = @_; my $usersByShare = _sharesGroupedBy('share'); for my $share (sort keys %{$usersByShare}) { my $section = new EBox::Dashboard::Section($share, $share); $widget->add($section); my $titles = [__('User'), __('Source machine'), __('Connected since')]; my $rows = {}; foreach my $user (@{$usersByShare->{$share}}) { my $id = $user->{'user'} . '_' . $user->{'machine'}; $rows->{$id} = [$user->{'user'}, $user->{'machine'}, $user->{'date'}]; } my $ids = [sort keys %{$rows}]; $section->add(new EBox::Dashboard::List(undef, $titles, $ids, $rows)); } } # Method: widgets # # Override EBox::Module::widgets # sub widgets { return { 'sharesbyuser' => { 'title' => __('Shares by user'), 'widget' => \&sharesByUserWidget, 'order' => 7, 'default' => 1 }, 'usersbyshare' => { 'title' => __('Users by share'), 'widget' => \&usersByShareWidget, 'order' => 9, 'default' => 1 } }; } # Method: _daemons # # Override EBox::Module::Service::_daemons # sub _daemons { return [ { name => 'samba4', precondition => \&isProvisioned, pidfiles => ['/var/run/samba.pid'], }, { name => 'zentyal.s4sync', precondition => \&isProvisioned, }, ]; } # Function: usesPort # # Implements EBox::FirewallObserver interface # sub usesPort { my ($self, $protocol, $port, $iface) = @_; return undef unless($self->isEnabled()); foreach my $smbport (@{$self->_services()}) { return 1 if ($port eq $smbport->{destinationPort}); } return undef; } sub firewallHelper { my ($self) = @_; if ($self->isEnabled()) { return new EBox::SambaFirewall(); } return undef; } # Method: firewallCaptivePortalExceptions # # this method gives firewall ruels to add to the captive portal module. # They purpose is to allow domain joins without captive portal interference sub firewallCaptivePortalExceptions { my ($self) = @_; my @rules; if (not $self->isEnabled()) { return []; } my @services = @{ $self->_services() }; foreach my $conf (@services) { my $args = ''; my $tcpAndUdp = 0; if ($conf->{protocol} ne 'any') { if ($conf->{protocol} eq 'tcp/udp') { $tcpAndUdp = 1; } else { $args .= '--protocol ' . $conf->{protocol}; } } if ($conf->{sourcePort} ne 'any') { $args .= ' --sport ' . $conf->{sourcePort}; } if ($conf->{destinationPort} ne 'any') { $args .= ' --dport ' . $conf->{destinationPort}; } if ($args) { if ($tcpAndUdp) { push @rules, "--protocol tcp $args -j RETURN"; push @rules, "--protocol udp $args -j RETURN"; } else { push @rules, "$args -j RETURN"; } } } return \@rules; } sub menu { my ($self, $root) = @_; $root->add(new EBox::Menu::Item('url' => 'Samba/Composite/General', 'text' => $self->printableName(), 'separator' => 'Office', 'order' => 540)); } # Method: defaultAdministratorPassword # # Generates a default administrator password # sub defaultAdministratorPassword { return 'Zentyal1234'; } # Method: administratorPassword # # Returns the administrator password sub administratorPassword { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->passwordValue(); } # Method: defaultNetbios # # Generates the default netbios server name # sub defaultNetbios { my ($self) = @_; my $sysinfo = EBox::Global->modInstance('sysinfo'); my $hostName = $sysinfo->hostName(); return $hostName; } # Method: netbiosName # # Returns the configured netbios name # sub netbiosName { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->netbiosNameValue(); } # Method: defaultRealm # # Generates the default realm # sub defaultRealm { my ($self) = @_; my $sysinfo = EBox::Global->modInstance('sysinfo'); my $domainName = $sysinfo->hostDomain(); return $domainName; } # Method: defaultWorkgroup # # Generates the default workgroup # sub defaultWorkgroup { my $prefix = EBox::Config::configkey('custom_prefix'); $prefix = 'zentyal' unless $prefix; return uc($prefix) . '-DOMAIN'; } # Method: workgroup # # Returns the configured workgroup name # sub workgroup { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->workgroupValue(); } # Method: defaultDescription # # Generates the default server string # sub defaultDescription { my $prefix = EBox::Config::configkey('custom_prefix'); $prefix = 'zentyal' unless $prefix; return ucfirst($prefix) . ' File Server'; } # Method: description # # Returns the configured description string # sub description { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->descriptionValue(); } # Method: roamingProfiles # # Returns if roaming profiles are enabled # sub roamingProfiles { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->roamingValue(); } # Method: mode # # Returns the configured server mode # sub mode { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->modeValue(); } # Method: drive # # Returns the configured drive letter # sub drive { my ($self) = @_; my $model = $self->model('GeneralSettings'); return $model->driveValue(); } # Method: _ldapModImplementation # # LdapModule implmentation # sub _ldapModImplementation { my $self; return new EBox::SambaLdapUser(); } sub restoreConfig { my ($self, $dir) = @_; # try { # TODO: Provision database and export LDAP to LDB # my $sambaLdapUser = new EBox::SambaLdapUser; # $sambaLdapUser->migrateUsers(); # } otherwise { # } finally { # }; } sub restoreDependencies { my @depends = (); push (@depends, 'users'); if (EBox::Global->modExists('printers')) { push (@depends, 'printers'); } return \@depends; } # backup domains #sub backupDomains #{ # my $name = 'shares'; # my %attrs = ( # printableName => __('File Sharing'), # description => __(q{Shares, users and groups homes and profiles}), # ); # # return ($name, \%attrs); #} #sub backupDomainsFileSelection #{ # my ($self, %enabled) = @_; # if ($enabled{shares}) { # my $sambaLdapUser = new EBox::SambaLdapUser(); # my @dirs = @{ $sambaLdapUser->sharedDirectories() }; # push @dirs, map { # $_->{path} # } @{ $self->shares(1) }; # # my $selection = { # includes => \@dirs, # }; # return $selection; # } # # return {}; #} # Overrides: # EBox::Report::DiskUsageProvider::_facilitiesForDiskUsage #sub _facilitiesForDiskUsage #{ # my ($self) = @_; # # my $usersPrintableName = __(q{Users files}); # my $usersPath = EBox::SambaLdapUser::usersPath(); # my $groupsPrintableName = __(q{Groups files}); # my $groupsPath = EBox::SambaLdapUser::groupsPath(); # # return { # $usersPrintableName => [ $usersPath ], # $groupsPrintableName => [ $groupsPath ], # }; #} # Implement LogHelper interface sub tableInfo { my ($self) = @_; my $access_titles = { 'timestamp' => __('Date'), 'client' => __('Client address'), 'username' => __('User'), 'event' => __('Action'), 'resource' => __('Resource'), }; my @access_order = qw(timestamp client username event resource); my $access_events = { 'connect' => __('Connect'), 'opendir' => __('Access to directory'), 'readfile' => __('Read file'), 'writefile' => __('Write file'), 'disconnect' => __('Disconnect'), 'unlink' => __('Remove'), 'mkdir' => __('Create directory'), 'rmdir' => __('Remove directory'), 'rename' => __('Rename'), }; my $virus_titles = { 'timestamp' => __('Date'), 'client' => __('Client address'), 'filename' => __('File name'), 'virus' => __('Virus'), 'event' => __('Type'), }; my @virus_order = qw(timestamp client filename virus event);; my $virus_events = { 'virus' => __('Virus') }; my $quarantine_titles = { 'timestamp' => __('Date'), 'filename' => __('File name'), 'qfilename' => __('Quarantined file name'), 'event' => __('Quarantine'), }; my @quarantine_order = qw(timestamp filename qfilename event); my $quarantine_events = { 'quarantine' => __('Quarantine') }; return [{ 'name' => __('Samba access'), 'tablename' => 'samba_access', 'titles' => $access_titles, 'order' => \@access_order, 'timecol' => 'timestamp', 'filter' => ['client', 'username', 'resource'], 'types' => { 'client' => 'IPAddr' }, 'events' => $access_events, 'eventcol' => 'event' }, { 'name' => __('Samba virus'), 'tablename' => 'samba_virus', 'titles' => $virus_titles, 'order' => \@virus_order, 'timecol' => 'timestamp', 'filter' => ['client', 'filename', 'virus'], 'types' => { 'client' => 'IPAddr' }, 'events' => $virus_events, 'eventcol' => 'event' }, { 'name' => __('Samba quarantine'), 'tablename' => 'samba_quarantine', 'titles' => $quarantine_titles, 'order' => \@quarantine_order, 'timecol' => 'timestamp', 'filter' => ['filename'], 'events' => $quarantine_events, 'eventcol' => 'event' }]; } sub logHelper { my ($self) = @_; return (new EBox::SambaLogHelper); } #sub report #{ # my ($self, $beg, $end, $options) = @_; # my $maxTopActivityUsers = $options->{'max_top_activity_users'}; # my $maxTopActivityGroups = $options->{'max_top_activity_groups'}; # my $maxTopSizeShares = $options->{'max_top_size_shares'}; # my $maxTopVirusShares = $options->{'max_top_virus_shares'}; # # my $report = {}; # # $report->{'activity'} = $self->runMonthlyQuery($beg, $end, { # 'select' => 'COALESCE(SUM(operations), 0) AS OPERATIONS', # 'from' => 'samba_access_report' # }); # # $report->{'top_activity_users'} = $self->runQuery($beg, $end, { # 'select' => 'username, SUM(operations) AS operations', # 'from' => 'samba_access_report', # 'group' => 'username', # 'limit' => $maxTopActivityUsers, # 'order' => 'operations DESC' # }); # # # $report->{top_activity_groups} = _topActivityGroups($self, $beg, $end, $maxTopActivityGroups); # # $report->{'top_size_shares'} = $self->runQuery($beg, $end, { # 'select' => 'share, type, AVG(size) AS size', # 'from' => 'samba_disk_usage_report', # 'group' => 'share, type', # 'limit' => $maxTopSizeShares, # 'order' => 'size DESC', # }); # # $report->{'top_size_user_shares'} = $self->runQuery($beg, $end, { # 'select' => 'share, AVG(size) AS size', # 'from' => 'samba_disk_usage_report', # 'group' => 'share', # 'limit' => $maxTopSizeShares, # 'order' => 'size DESC', # 'where' => q{type = 'user'} # }); # # $report->{'top_size_group_shares'} = $self->runQuery($beg, $end, { # 'select' => 'share, AVG(size) AS size', # 'from' => 'samba_disk_usage_report', # 'group' => 'share, type', # 'limit' => $maxTopSizeShares, # 'order' => 'size DESC', # 'where' => q{type = 'group'} # }); # # $report->{'top_size_custom_shares'} = $self->runQuery($beg, $end, { # 'select' => 'share, AVG(size) AS size', # 'from' => 'samba_disk_usage_report', # 'group' => 'share, type', # 'limit' => $maxTopSizeShares, # 'order' => 'size DESC', # 'where' => q{type = 'custom'} # }); # # $report->{'top_virus_shares'} = $self->runQuery($beg, $end, { # 'select' => 'share, SUM(virus) as virus', # 'from' => 'samba_virus_share_report', # 'group' => 'share', # 'limit' => $maxTopVirusShares, # 'order' => 'virus DESC', # }); # # # return $report; #} # #sub _topActivityGroups #{ # my ($self, $beg, $end, $maxTopActivityGroups) = @_; # my $usersMod = EBox::Global->modInstance('users'); # # my $sqlResult = $self->runQuery($beg, $end, { # 'select' => 'username, SUM(operations) AS operations', # 'from' => 'samba_access_report', # 'group' => 'username', # }); # my %operationsByUser; # foreach my $i (0 .. $#{ $sqlResult->{username} } ) { # $operationsByUser{ $sqlResult->{username}->[$i] } = $sqlResult->{operations}->[$i]; # } # # delete $sqlResult->{username}; # delete $sqlResult->{operations}; # # # my $min = -1; # my @groupsAndOperations; # foreach my $group_r ($usersMod->groups()) { # my $groupname = $group_r->{account}; # my $operations = 0; # # my @users = @{ $usersMod->usersInGroup($groupname) }; # foreach my $user (@users) { # $operations += $operationsByUser{$user}; # } # # # if (@groupsAndOperations < $maxTopActivityGroups ) { # push @groupsAndOperations, [$groupname => $operations]; # } elsif ($operations > $min) { # pop @groupsAndOperations; # push @groupsAndOperations, [$groupname => $operations]; # } else { # next; # } # # @groupsAndOperations = sort { $b->[1] <=> $a->[1] } @groupsAndOperations; # $min = $groupsAndOperations[-1]->[1]; # } # # my @topGroups = map { $_->[0] } @groupsAndOperations; # my @topOperations = map { $_->[1] } @groupsAndOperations; # return { # 'groupname' => \@topGroups, # 'operations' => \@topOperations, # }; #} # #sub consolidateReportQueries #{ # return [ # { # 'target_table' => 'samba_access_report', # 'query' => { # 'select' => 'username, COUNT(event) AS operations', # 'from' => 'samba_access', # 'group' => 'username' # }, # quote => { username => 1 }, # }, # { # 'target_table' => 'samba_virus_report', # 'query' => { # 'select' => 'client, COUNT(event) AS virus', # 'from' => 'samba_virus', # 'group' => 'client' # }, # quote => { client => 1 }, # }, # { # 'target_table' => 'samba_disk_usage_report', # 'query' => { # 'select' => 'share, type, CAST (AVG(size) AS int) AS size', # 'from' => 'samba_disk_usage', # 'group' => 'share, type' # # }, # quote => { share => 1 }, # }, # { # 'target_table' => 'samba_virus_share_report', # 'query' => { # 'select' => 'share, count(*) as virus', # 'from' => 'samba_quarantine', # 'where' => q{event='quarantine'}, # 'group' => 'filename' # }, # 'rowConversor' => \&_virusShareReportRowConversor, # 'targetGroupFields' => ['share'], # quote => { share => 1 }, # }, # ]; #} # #my @sharesSortedByPathLen; # #sub _updatePathsByLen #{ # my ($self) = @_; # # my $ldapInfo = EBox::SambaLdapUser->new(); # @sharesSortedByPathLen = map { # { path => $_->{path}, # share => $_->{sharename} } # } ( @{ $ldapInfo->userShareDirectories }, # @{ $ldapInfo->groupShareDirectories } # ); # # foreach my $sh_r (@{ $self->shares(1) }) { # push @sharesSortedByPathLen, {path => $sh_r->{path}, # share => $sh_r->{share} }; # } # # # add regexes # foreach my $share (@sharesSortedByPathLen) { # my $path = $share->{path}; # $share->{pathRegex} = qr{^$path/}; # } # # @sharesSortedByPathLen = sort { # length($b->{path}) <=> length($a->{path}) # } @sharesSortedByPathLen; #} # #sub _shareByFilename #{ # my ($filename) = @_; # # if (not @sharesSortedByPathLen) { # my $samba =EBox::Global->modInstance('samba'); # $samba->_updatePathsByLen(); # } # # # foreach my $shareAndPath (@sharesSortedByPathLen) { # if ($filename =~ m/$shareAndPath->{pathRegex}/) { # return $shareAndPath->{share}; # } # } # # # return undef; #} # #sub _virusShareReportRowConversor #{ # my ($row) = @_; # my $filename = delete $row->{filename}; # my $share = _shareByFilename($filename); # EBox::debug("COBV $filename -> $share"); # if ($share) { # $row->{share} = $share; # } else { # return undef; # } # # # return $row; #} # #sub logReportInfo #{ # my ($self) = @_; # # if ($self->_diskUsageAlreadyCheckedToday) { # return []; # } # # my @reportData; # # my %shareByPath; # # my @shares = @{ $self->_sharesAndSizes() }; # # # foreach my $share (@shares) { # # add info about disk usage by share # my $entry = { # table => 'samba_disk_usage', # values => { # share => $share->{share}, # size => $share->{size}, # type => $share->{type}, # } # }; # push @reportData, $entry; # } # # return \@reportData; #} # #sub _diskUsageAlreadyCheckedToday #{ # my ($self) = @_; # # my $db = EBox::DBEngineFactory::DBEngine(); # my $query = q{SELECT share FROM samba_disk_usage WHERE (timestamp >= (current_date + interval '0 day')) AND (timestamp < (current_date + interval '1 day'))}; # my $results = $db->query($query); # return @{ $results } > 0; #} # #sub _sharesAndSizes #{ # my ($self) = @_; # # my $ldapInfo = EBox::SambaLdapUser->new(); # my @shares; # # foreach my $sh_r ( @{ $ldapInfo->userShareDirectories }) { # my $share = { # share => $sh_r->{sharename}, # path => $sh_r->{path}, # type => 'user', # }; # push @shares, $share; # } # # foreach my $sh_r ( @{ $ldapInfo->groupShareDirectories }) { # my $share = { # share => $sh_r->{sharename}, # path => $sh_r->{path}, # type => 'group', # }; # push @shares, $share; # } # # # add no-account shares to share list # foreach my $sh_r (@{ $self->shares(1) }) { # my $share = { # share => $sh_r->{share}, # path => $sh_r->{path}, # type => 'custom', # }; # push @shares, $share; # } # # # foreach my $share (@shares) { # my $path = $share->{path}; # if (EBox::Sudo::fileTest('-d', $path)) { # my $output = EBox::Sudo::rootWithoutException("du -ms '$path'"); # # my ($size) = $output->[0] =~ m{^(\d+)}; # if (not defined $size) { # EBox::error("Problem getting $path size: @{$output}"); # $size = 0; # } # # $share->{size} = $size; # } # } # # return \@shares; #} # Method: ldb # # Provides an EBox::LDB object with the proper settings # sub ldb { my ($self) = @_; unless (defined ($self->{ldb})) { $self->{ldb} = EBox::LDB->instance(); } return $self->{ldb}; } # Method: sharesPaths # # This function is used to generate disk usage reports. It # returns the shares paths, excluding the group shares. # sub sharesPaths { my ($self) = @_; my $shares = $self->shares(1); my $paths = []; foreach my $share (@{$shares}) { push (@{$paths}, $share->{path}) unless defined $share->{groupShare}; } return $paths; } # Method: userPaths # # This function is used to generate disk usage reports. It # returns all the paths where a user store data # sub userPaths { my ($self, $user) = @_; my $userProfilePath = PROFILES_DIR; $userProfilePath .= "/" . $user->get('uid'); my $paths = []; push (@{$paths}, $user->get('homeDirectory')); push (@{$paths}, $userProfilePath); return $paths; } # Method: groupPaths # # This function is used to generate disk usage reports. It # returns the group share path if it is configured. # sub groupPaths { my ($self, $group) = @_; my $groupName = $group->get('cn'); my $shares = $self->shares(1); my $paths = []; foreach my $share (@{$shares}) { if (defined $groupName and defined $share->{groupShare} and $groupName eq $share->{groupShare}) { push (@{$paths}, $share->{path}); last; } } return $paths; } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/CGI/0000775000000000000000000000000012017560227016334 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/EBox/CGI/ActiveSharing.pm0000664000000000000000000000502612017560227021424 0ustar # Copyright (C) 2012 eBox Technologies S.L. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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 package EBox::CGI::Samba::ActiveSharing; use strict; use warnings; use base 'EBox::CGI::ClientBase'; use EBox::Global; use EBox::SambaLdapUser; use EBox::UsersAndGroups; use EBox::Gettext; use EBox::Exceptions::External; use EBox::Samba::User; sub new { my $class = shift; my $self = $class->SUPER::new('title' => 'Users and Groups', @_); bless ($self, $class); return $self; } sub _group { my ($self) = @_; my $smbldap = new EBox::SambaLdapUser; $self->_requireParam('group', __('group')); my $group = $self->unsafeParam('group'); $self->{redirect} = "UsersAndGroups/Group?group=$group"; $self->{errorchain} = "UsersAndGroups/Group"; $self->keepParam('group'); $group = new EBox::UsersAndGroups::Group(dn => $group); $self->_requireParamAllowEmpty('sharename', __('share name')); my $name = $self->param('sharename'); if ($self->param('namechange') or $self->param('add')) { $smbldap->setGroupShare($group, $name); } elsif ($self->param('remove')) { $smbldap->removeGroupShare($group); } } sub _user { my ($self) = @_; my $smbldap = new EBox::SambaLdapUser; $self->_requireParam('user', __('user')); my $user = $self->unsafeParam('user'); $self->{redirect} = "UsersAndGroups/User?user=$user"; $self->{errorchain} = "UsersAndGroups/User"; $self->keepParam('user'); my $zentyalUser = new EBox::UsersAndGroups::User(dn => $user); my $sambaUser = new EBox::Samba::User(samAccountName => $zentyalUser->get('uid')); my $accountEnabled = $self->param('accountEnabled'); if ($accountEnabled eq 'yes') { $sambaUser->setAccountEnabled(1); } else { $sambaUser->setAccountEnabled(0); } } sub _process { my ($self) = @_; if ($self->unsafeParam('user')) { $self->_user(); } else { $self->_group(); } } 1; zentyal-samba-2.3.12+quantal1ubuntu1/src/templates/0000775000000000000000000000000012017560227017073 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/templates/samba.mas0000664000000000000000000000532712017560227020667 0ustar <%args> $params <%init> use EBox::Gettext; % if ($params->{'username'}) {

<% __('Active Directory/File sharing account') %>

<& .sambaDisabled, $params &>
<% __('User account') %>:
% } else {

<% __('Sharing directory for this group') %>

<% __("You can set a share directory for this group, but you should keep in mind that Microsoft Windows 98 and Millenium will not be able to see names longer than 12 characters") %>
<& .sambaDisabled, $params &> % if (length($params->{'sharename'}) > 12) {
<% __("This resource name is longer than 12 characters.") %>
% } <% __('Directory name')%>: % if (defined $params->{'share'}) { % } else { % }
% } <%def .sambaDisabled> <%init> my ($params) = @_; return if $params->{service}; my $mod = __('file sharing module'); <& .modWarn, mod => $mod &> <%def .modWarn> <%args> $mod
<% __x( q{The following settings will take effect only when the {mod} is enabled}, mod => $mod, ) %>
zentyal-samba-2.3.12+quantal1ubuntu1/src/templates/ajax/0000775000000000000000000000000012017560227020016 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/templates/ajax/viewer/0000775000000000000000000000000012017560227021317 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/templates/ajax/viewer/shareViewer.mas0000664000000000000000000000065412017560227024312 0ustar <%args> $data <%init> % my $type; % if ($data->selectedType() eq 'user') { % $type = __('User'); % } elsif ($data->selectedType() eq 'group') { % $type = __('Group'); % } elsif ($data->selectedType() eq 'share') { % $type = __('Share'); % } % if (defined($data->printableValue())) { <% $type %>: <% $data->printableValue() %> <% $data->trailingText() %> % } % else { -- % } zentyal-samba-2.3.12+quantal1ubuntu1/src/scripts/0000775000000000000000000000000012017560227016564 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/src/scripts/setup-filesystem0000775000000000000000000000201712017560227022034 0ustar #!/usr/bin/perl use File::Slurp; use constant FSTAB_FILE => '/etc/fstab'; my @fstab = read_file(FSTAB_FILE) or die ('Could not open ' . FSTAB_FILE . ": $!"); my @modifiedLines = (); my @newFstab = (); for my $line (@fstab) { next if ($fields[0] =~ /^#.*/); my $modified = 0; my @fields = split (/[\t\s]+/, $line); if ($fields[2] =~ /^(ext3|ext4)$/) { unless ($fields[3] =~ /acl/) { $fields[3] .= ',acl'; $modified = 1; } unless ($fields[3] =~ /user_xattr/) { $fields[3] .= ',user_xattr'; $modified = 1; } } my $newLine = join ("\t", @fields) . "\n"; push (@newFstab, $newLine); if ($modified) { push (@modifiedLines, $newLine); } } write_file(FSTAB_FILE, @newFstab) or die ('Could not write on ' . FSTAB_FILE . ": $!"); foreach my $line (@modifiedLines) { my @fields = split(/[\t\s]+/, $line); system ("/bin/mount -o remount " . $fields[1]) == 0 or die ('Could not write on ' . FSTAB_FILE . ": $!"); } zentyal-samba-2.3.12+quantal1ubuntu1/src/scripts/s4sync0000775000000000000000000000601112017560227017733 0ustar #!/usr/bin/perl use strict; use warnings; use EBox; use EBox::Global; use Time::gmtime; use File::Slurp; sub getTimestamp { my $time = gmtime(); my $timestamp = sprintf("%04d%02d%02d%02d%02d%02d", $time->year + 1900, $time->mon + 1, $time->mday, $time->hour, $time->min, $time->sec); return $timestamp; } EBox::init(); my $sambaTimestampFile = EBox::Config::home() . '.s4sync_ts'; unless (-f $sambaTimestampFile) { write_file($sambaTimestampFile, '0'); } my $sambaModule = EBox::Global->modInstance('samba'); my $usersModule = EBox::Global->modInstance('users'); while (1) { my $sambaTimestamp = read_file($sambaTimestampFile); my $sambaUserList = $sambaModule->ldb->users(); my $sambaGroupList = $sambaModule->ldb->groups(); write_file($sambaTimestampFile, getTimestamp()); my %sambaUsers = map { $_->get('samAccountName') => $_ } @{$sambaUserList}; my %sambaGroups = map { $_->get('samAccountName') => $_ } @{$sambaGroupList}; my $zentyalUserList = $usersModule->users(); my $zentyalGroupList = $usersModule->groups(); my %zentyalUsers = map { $_->get('uid') => $_ } @{$zentyalUserList}; my %zentyalGroups = map { $_->get('cn') => $_ } @{$zentyalGroupList}; ################################################# #### Sync users ################################################# # Add users that exists in samba but not in Zentyal foreach my $sambaUserName (sort keys %sambaUsers) { if (exists $zentyalUsers{$sambaUserName}) { my $changed = $sambaUsers{$sambaUserName}->get('whenChanged'); $changed =~ s/\.\d+Z//; if ($changed > $sambaTimestamp) { $sambaUsers{$sambaUserName}->updateZentyal(); } delete $zentyalUsers{$sambaUserName}; } else { $sambaUsers{$sambaUserName}->addToZentyal(); } } foreach my $zentyalUserName (sort keys %zentyalUsers) { EBox::debug("Deleting Zentyal user '$zentyalUserName'"); $zentyalUsers{$zentyalUserName}->setIgnoredModules(['samba']); $zentyalUsers{$zentyalUserName}->deleteObject(); } ################################################# #### Sync groups ################################################# foreach my $sambaGroupName (sort keys %sambaGroups) { if (exists $zentyalGroups{$sambaGroupName}) { my $changed = $sambaGroups{$sambaGroupName}->get('whenChanged'); $changed =~ s/\.\d+Z//; if ($changed > $sambaTimestamp) { $sambaGroups{$sambaGroupName}->updateZentyal(); } delete $zentyalGroups{$sambaGroupName}; } else { $sambaGroups{$sambaGroupName}->addToZentyal(); } } foreach my $zentyalGroupName (sort keys %zentyalGroups) { EBox::debug("Deleting Zentyal group '$zentyalGroupName'"); $zentyalGroups{$zentyalGroupName}->setIgnoredModules(['samba']); $zentyalGroups{$zentyalGroupName}->deleteObject(); } sleep (30); } zentyal-samba-2.3.12+quantal1ubuntu1/src/scripts/initial-setup0000775000000000000000000000024512017560227021302 0ustar #!/bin/bash set -e QUARANTINE_DIR=/var/lib/zentyal/quarantine/ if [ ! -d $QUARANTINE_DIR ]; then mkdir -p $QUARANTINE_DIR fi chmod 730 $QUARANTINE_DIR exit 0 zentyal-samba-2.3.12+quantal1ubuntu1/schemas/0000775000000000000000000000000012017560227015731 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/0000775000000000000000000000000012017560227016530 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_virus_report.sql0000664000000000000000000000017612017560227023163 0ustar CREATE TABLE IF NOT EXISTS samba_virus_report ( `date` DATE, client INT UNSIGNED, virus BIGINT ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_disk_usage_report.sql0000664000000000000000000000026612017560227024131 0ustar CREATE TABLE IF NOT EXISTS samba_disk_usage_report ( date DATE NOT NULL, share VARCHAR(24) NOT NULL, type VARCHAR(10) NOT NULL, size INT DEFAULT 0 ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_virus.sql0000664000000000000000000000031512017560227021563 0ustar CREATE TABLE IF NOT EXISTS samba_virus ( client INT UNSIGNED, virus VARCHAR(120), filename VARCHAR(120), event VARCHAR(16), timestamp TIMESTAMP, INDEX(timestamp) ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_access_report.sql0000664000000000000000000000020312017560227023243 0ustar CREATE TABLE IF NOT EXISTS samba_access_report ( date DATE, username VARCHAR(24), operations BIGINT ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_virus_share_report.sql0000664000000000000000000000021112017560227024333 0ustar CREATE TABLE IF NOT EXISTS samba_virus_share_report ( date DATE, share VARCHAR(24) NOT NULL, virus BIGINT ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_access.sql0000664000000000000000000000032012017560227021650 0ustar CREATE TABLE IF NOT EXISTS samba_access ( client INT UNSIGNED, username VARCHAR(24), resource VARCHAR(240), event VARCHAR(16), timestamp TIMESTAMP, INDEX(timestamp) ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_quarantine.sql0000664000000000000000000000027512017560227022567 0ustar CREATE TABLE IF NOT EXISTS samba_quarantine ( filename VARCHAR(120), qfilename VARCHAR(120), event VARCHAR(16), timestamp TIMESTAMP, INDEX(timestamp) ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/sql/samba_disk_usage.sql0000664000000000000000000000027112017560227022532 0ustar CREATE TABLE IF NOT EXISTS samba_disk_usage ( timestamp TIMESTAMP NOT NULL, share VARCHAR(24) NOT NULL, type VARCHAR(10) NOT NULL, size INT DEFAULT 0 ) ENGINE = MyISAM; zentyal-samba-2.3.12+quantal1ubuntu1/schemas/samba.yaml0000664000000000000000000000124712017560227017704 0ustar class: 'EBox::Samba' depends: - network - printers enabledepends: - network - users - dns models: - GeneralSettings - SambaShares - SambaSharePermissions - SambaDeletedShares - AntivirusDefault - AntivirusExceptions - RecycleDefault - RecycleExceptions composites: RecycleBin: [RecycleDefault, RecycleExceptions] Antivirus: [AntivirusDefault, AntivirusExceptions] General: [GeneralSettings, SambaShares, RecycleBin, Antivirus] modeldepends: AntivirusExceptions: samba/SambaShares: [share] RecycleExceptions: samba/SambaShares: [share] foreign: SambaShares: [SambaSharePermissions] zentyal-samba-2.3.12+quantal1ubuntu1/AUTHORS0000664000000000000000000000023312017560227015354 0ustar Copyright (C) 2012 eBox Technologies S.L. For an updated list of the current and past developers please visit: http://trac.zentyal.org/wiki/Contributors zentyal-samba-2.3.12+quantal1ubuntu1/debian/0000775000000000000000000000000012244275156015536 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/debian/source/0000775000000000000000000000000012017560227017030 5ustar zentyal-samba-2.3.12+quantal1ubuntu1/debian/source/format0000664000000000000000000000001512017560227020237 0ustar 3.0 (native) zentyal-samba-2.3.12+quantal1ubuntu1/debian/copyright0000664000000000000000000000214112017560227017461 0ustar This package was debianized by Zentyal Packaging Maintainers Fri, 20 Feb 2005 15:13:22 +0100. It was downloaded from http://www.zentyal.org/ Files: * Upstream Author: eBox Technologies S.L. Copyright (C) 2004-2012 eBox Technologies S.L. License: 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. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-2 file. The Debian packaging is: (C) 2004-2011, Zentyal Packaging Maintainers and is licensed under the GPL, see `/usr/share/common-licenses/GPL-2'. zentyal-samba-2.3.12+quantal1ubuntu1/debian/zentyal-samba.dirs0000664000000000000000000000003412017560227021157 0ustar var/lib/zentyal/quarantine/ zentyal-samba-2.3.12+quantal1ubuntu1/debian/changelog0000664000000000000000000002607112244275156017416 0ustar zentyal-samba (2.3.12+quantal1ubuntu1) trusty; urgency=low * Add alternate dependency on samba >= 4 | samba4. -- Dmitrijs Ledkovs Sun, 24 Nov 2013 04:02:10 +0000 zentyal-samba (2.3.12+quantal1) quantal; urgency=low * New upstream release for Quantal -- Jorge Salamero Sanz Tue, 28 Aug 2012 19:06:17 +0200 zentyal-samba (2.3.12) precise; urgency=low * New upstream release -- José A. Calvo Thu, 23 Aug 2012 19:10:41 +0200 zentyal-samba (2.3.11) precise; urgency=low * New upstream release -- José A. Calvo Mon, 13 Aug 2012 11:03:34 +0200 zentyal-samba (2.3.10) precise; urgency=low * New upstream release -- José A. Calvo Mon, 23 Jul 2012 12:54:02 +0200 zentyal-samba (2.3.9) precise; urgency=low * New upstream release -- José A. Calvo Thu, 19 Jul 2012 06:50:26 +0200 zentyal-samba (2.3.8) precise; urgency=low * New upstream release -- José A. Calvo Thu, 12 Jul 2012 02:47:12 +0200 zentyal-samba (2.3.7) precise; urgency=low * New upstream release -- José A. Calvo Fri, 15 Jun 2012 16:02:46 +0200 zentyal-samba (2.3.6) precise; urgency=low * New upstream release -- José A. Calvo Mon, 11 Jun 2012 01:49:40 +0200 zentyal-samba (2.3.5) precise; urgency=low * New upstream release -- José A. Calvo Mon, 16 Apr 2012 02:50:50 +0200 zentyal-samba (2.3.4) precise; urgency=low * New upstream release -- José A. Calvo Mon, 26 Mar 2012 09:46:03 +0200 zentyal-samba (2.3.3) precise; urgency=low * New upstream release -- José A. Calvo Sat, 10 Mar 2012 00:51:21 +0100 zentyal-samba (2.3.2) precise; urgency=low * New upstream release -- José A. Calvo Thu, 08 Mar 2012 11:33:55 +0100 zentyal-samba (2.3.1) precise; urgency=low * New upstream release -- José A. Calvo Wed, 07 Mar 2012 02:17:18 +0100 zentyal-samba (2.3) precise; urgency=low * New upstream release -- José A. Calvo Mon, 30 Jan 2012 01:45:13 +0100 zentyal-samba (2.2) lucid; urgency=low * New upstream release -- José A. Calvo Tue, 13 Sep 2011 16:16:06 +0200 zentyal-samba (2.1.7) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 07 Sep 2011 18:19:40 +0200 zentyal-samba (2.1.6) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 24 Aug 2011 11:52:16 +0200 zentyal-samba (2.1.5) lucid; urgency=low * New upstream release -- José A. Calvo Tue, 26 Jul 2011 17:25:35 +0200 zentyal-samba (2.1.4) lucid; urgency=low * New upstream release -- José A. Calvo Thu, 14 Jul 2011 22:30:26 +0200 zentyal-samba (2.1.3) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 29 Jun 2011 19:35:59 +0200 zentyal-samba (2.1.2) lucid; urgency=low * New upstream release -- José A. Calvo Tue, 10 May 2011 22:37:25 +0200 zentyal-samba (2.1.1) lucid; urgency=low * New upstream release -- José A. Calvo Thu, 17 Mar 2011 00:46:39 +0100 zentyal-samba (2.1) lucid; urgency=low * New upstream release -- José A. Calvo Tue, 22 Feb 2011 03:26:50 +0100 ebox-samba (2.0.7) lucid; urgency=low * New upstream release -- José A. Calvo Sat, 18 Dec 2010 02:09:23 +0100 ebox-samba (2.0.6) lucid; urgency=low * New upstream release -- José A. Calvo Sat, 11 Dec 2010 15:27:40 +0100 ebox-samba (2.0.5) lucid; urgency=low * New upstream release -- José A. Calvo Mon, 08 Nov 2010 19:21:14 +0100 ebox-samba (2.0.4) lucid; urgency=low * New upstream release -- José A. Calvo Fri, 29 Oct 2010 03:01:14 +0200 ebox-samba (2.0.3) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 27 Oct 2010 13:27:51 +0200 ebox-samba (2.0.2) lucid; urgency=low * New upstream release -- José A. Calvo Sun, 24 Oct 2010 19:44:22 +0200 ebox-samba (2.0.1) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 06 Oct 2010 15:26:39 +0200 ebox-samba (2.0) lucid; urgency=low * New upstream release -- José A. Calvo Mon, 30 Aug 2010 22:06:29 +0200 ebox-samba (1.5.9-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Thu, 26 Aug 2010 16:04:26 +0200 ebox-samba (1.5.8-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Mon, 23 Aug 2010 02:19:02 +0200 ebox-samba (1.5.7-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Wed, 18 Aug 2010 17:23:51 +0200 ebox-samba (1.5.6-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Mon, 19 Jul 2010 12:07:33 +0200 ebox-samba (1.5.5-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Sun, 27 Jun 2010 00:51:26 +0200 ebox-samba (1.5.4-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Sun, 20 Jun 2010 20:39:51 +0200 ebox-samba (1.5.3-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Thu, 10 Jun 2010 16:34:20 +0200 ebox-samba (1.5.2-0ubuntu1~ppa1~lucid1) lucid; urgency=low * New upstream release -- José A. Calvo Thu, 13 May 2010 01:33:08 +0200 ebox-samba (1.5.1-0ubuntu) lucid; urgency=low * debian/control: add dependency on acl -- Javier Uruen Val Mon, 22 Feb 2010 22:11:53 +0100 ebox-samba (1.5-0ubuntu1) lucid; urgency=low [Javier Uruen Val] * New upstream release (LP: #521812) * debian/control - Bump eBox dependency - Update description -- Javier Uruen Val Sun, 07 Feb 2010 18:51:11 +0100 ebox-samba (1.3.5-0ubuntu1) karmic; urgency=low [Javier Uruen Val] * New upstream release [LP: 411554] * cdbs/ebox.mk - GConf schemas are not used anymore - Remove SCHEMASPATH variable - Remove schemadir variable - Fix the script that copy upstart scripts - Use new upstart directory and file naming convention * debian/control - Bump standards version - Bump eBox depenency - Remove dependency on dpatch * debian/ebox.nmbd.upstart removed (upstream uses init.d) * debian/ebox.smbd.upstart removed (upstream uses init.d) * debian/ebox-samba.postinst - Fix indentation - Do not pkill gconfd as it's not necessary anymore - Run ebox trigger - Create quarantine directory for anti-virus - Create log tables for anti-virus - Add set -e * removed unused debian/ebox-samba.prerm * debian/ebox-samba.postrm - Run ebox trigger - Add set -e * debian/patches - Drop dpatch system + Drop 01_disable_tls_unix_socket.dpatch (Already shipped by upstream) * debian/rules - Do not include debian/cdbs/gnome.mk * debian/watch - Change URL -- Javier Uruen Val Wed, 05 Aug 2009 12:29:43 +0200 ebox-samba (0.12.6.101-0ubuntu2) jaunty; urgency=low * debian/patches/01_disable_tls_unix_socket. Closes (LP: #354150) - Disable TLS on unix socket connecting to openLDAP * Enable dpatch system -- Javier Uruen Val Thu, 02 Apr 2009 23:51:56 +0200 ebox-samba (0.12.6.101-0ubuntu1) jaunty; urgency=low [ Javier Uruen Val ] * New upstream release. Closes (LP: #318829) * debian/watch: - add watch file. -- Mathias Gug Mon, 26 Jan 2009 22:07:17 -0500 ebox-samba (0.11.99-0ubuntu3) hardy; urgency=low * debian/patches/02_configure_roaming_profiles.dpatch - Enable/disable roaming profiles. * debian/patches/03_output_firewall_rules.dpatch - Fix to add output firewall rules. -- Chuck Short Mon, 07 Apr 2008 10:22:10 -0400 ebox-samba (0.11.99-0ubuntu2) hardy; urgency=low * debian/patches/01_adjust_group_share - Do not use sticky bit. - Remove leading underscore. - Add comment to share. -- Chuck Short Mon, 24 Mar 2008 09:16:29 -0400 ebox-samba (0.11.99-0ubuntu1) hardy; urgency=low * New upstream release. -- Chuck Short Wed, 27 Feb 2008 13:39:41 -0500 ebox-samba (0.11.99-0ubuntu1~ppa1) hardy; urgency=low * New upstream release -- Javier Uruen Val Mon, 25 Feb 2008 15:11:58 +0100 ebox-samba (0.11.99) unstable; urgency=low * New upstream release -- Enrique José Hernández Blasco Tue, 8 Jan 2008 16:14:40 +0100 ebox-samba (0.11-0ubuntu1~ppa1) hardy; urgency=low * New upstream release -- Javier Uruen Val Wed, 28 Nov 2007 15:23:34 +0100 ebox-samba (0.10.99) unstable; urgency=low * New upstream release -- Javier Uruen Val Thu, 01 Nov 2007 21:38:15 +0100 ebox-samba (0.10) unstable; urgency=low * New upstream release -- Javier Uruen Val Wed, 10 Oct 2007 21:53:51 +0200 ebox-samba (0.9.100) unstable; urgency=low * New upstream release -- Javier Uruen Val Tue, 04 Sep 2007 14:20:48 +0200 ebox-samba (0.9.99) unstable; urgency=low * New upstream release -- Javier Amor Garcia Tue, 24 Jul 2007 12:57:38 +0200 ebox-samba (0.9.3) unstable; urgency=low * New upstream release -- Javier Uruen Val Sun, 24 Jun 2007 16:38:49 +0200 ebox-samba (0.9.2) unstable; urgency=low * New upstream release -- Javier Uruen Val Tue, 12 Jun 2007 18:59:28 +0200 ebox-samba (0.9.1) unstable; urgency=low * New upstream release -- Javier Uruen Val Tue, 15 May 2007 13:02:27 +0200 ebox-samba (0.9) unstable; urgency=low * New upstream release -- Javier Amor Garcia Tue, 27 Mar 2007 12:07:55 +0200 ebox-samba (0.7.99) unstable; urgency=low * New upstream release -- Javier Amor Garcia Mon, 20 Nov 2006 11:03:07 +0100 ebox-samba (0.7.1) unstable; urgency=low * New upstream release -- Daniel Baeyens Sicilia Wed, 22 Mar 2006 16:07:14 +0100 ebox-samba (0.7.0.99-rc1+0.7.1-rc1) unstable; urgency=low * New upstream release -- Javier Uruen Val Tue, 17 Jan 2006 11:45:28 +0100 ebox-samba (0.5.1) unstable; urgency=low * New upstream release -- Guillermo Ontañón Mon, 14 Mar 2005 14:33:06 +0100 ebox-samba (0.5) unstable; urgency=low * New upstream release -- Isaac Clerencia Thu, 3 Mar 2005 19:55:47 +0100 ebox-samba (0.4-2) unstable; urgency=low * New upstream release -- Isaac Clerencia Sat, 4 Dec 2004 16:36:45 +0100 zentyal-samba-2.3.12+quantal1ubuntu1/debian/control0000664000000000000000000000236312244275160017140 0ustar Source: zentyal-samba Section: web Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Zentyal Packaging Maintainers Uploaders: Jorge Salamero Sanz Build-Depends: zbuildtools Standards-Version: 3.9.2 Homepage: http://www.zentyal.org/ Vcs-Browser: http://git.zentyal.org/zentyal.git/tree/quantal:/main/samba Vcs-Git: git://git.zentyal.org/zentyal.git Package: zentyal-samba Architecture: all Replaces: ebox-samba (<< 2.0.100) Breaks: ebox-samba (<< 2.0.100) Depends: zentyal-core (>= 2.3), zentyal-core (<< 2.3.100), zentyal-network, ldb-tools, zentyal-firewall, zentyal-users, zentyal-dns, acl, samba (>= 2:4.0) | samba4 (>= 4.0.0~beta2+dfsg1-3), samba-dsdb-modules (>= 4.0.0~beta2+dfsg1-3), libdate-calc-perl, ${misc:Depends} Description: Zentyal - File Sharing and Domain Services Zentyal is a Linux small business server that can act as a Gateway, Unified Threat Manager, Office Server, Infrastructure Manager, Unified Communications Server or a combination of them. One single, easy-to-use platform to manage all your network services. . This module adds a Samba4 server to your Zentyal installation. zentyal-samba-2.3.12+quantal1ubuntu1/debian/zentyal-samba.postinst0000664000000000000000000000044312017560227022105 0ustar #!/bin/bash set -e #DEBHELPER# case "$1" in configure) # initial setup /usr/share/zentyal/initial-setup --no-restart samba $2 # restart module invoke-rc.d zentyal samba restart || true dpkg-trigger --no-await zentyal-core ;; esac exit 0 zentyal-samba-2.3.12+quantal1ubuntu1/debian/rules0000775000000000000000000000010612017560227016605 0ustar #!/usr/bin/make -f include /usr/share/zbuildtools/1/rules/zentyal.mk zentyal-samba-2.3.12+quantal1ubuntu1/debian/zentyal-samba.postrm0000664000000000000000000000033212017560227021543 0ustar #!/bin/bash set -e #DEBHELPER# case "$1" in purge) # purge configuration /usr/share/zentyal/purge-module samba ;; remove) dpkg-trigger --no-await zentyal-core ;; esac exit 0 zentyal-samba-2.3.12+quantal1ubuntu1/debian/compat0000664000000000000000000000000212017560227016726 0ustar 5 zentyal-samba-2.3.12+quantal1ubuntu1/debian/zentyal.s4sync.upstart0000664000000000000000000000005512017560227022064 0ustar exec /usr/share/zentyal-samba/s4sync respawn