DAViCal-cli

What is Davical-cli? 

Davical-cli is a console tool for managing DAViCal instances (each DAViCal installation, for each mail domain in this case, with its own database) from the command line. It’s very useful when you want to handle DAViCal from the Shell (cron scripts, whatever…) for whatever reason.

The final goal is basically to provide unattended management of DAViCal from different kinds of interfaces.

Why was it created? 

Basically I created Davical-cli because we wanted to offer collaborative features to our mail service (Saremail) and I didn’t see any tool for managing multiple DAViCal instances from the Shell that properly handled permissions configurations for principals and collections when, for instance, they become shared between different users. And of course, that later return the permissions to a proper configuration, without disallowing you from seeing something else that you are allowed to but without permitting you to see what you shouldn’t in that user's principal.

CalDAV and CardDAV are nice and mature protocols for handling organizational and collaborative aspects for everyone (for any company) mainly when you don’t see Exchange as an option because it is mainly closed code and you prefer having some control on the software you run.

Important code aspects, features and working mode 

- I wrote this code for Sarenet, so it has some of Sarenet’s customizations, like some config file path, file names, URL, etc… that you can very easily adapt to your environment, to be able to start using it. In future versions I will make all these customizations a customizable element instead of being something written into the code (although hugely easy to adapt to your environment and, in fact, I explain later how you can do it easily).

- It does not handle any kind of user's (principal finally) password modifications, because we authenticate DAViCal against our IMAP service.

- As we use a wildcard cert for all domains in (https sessions), all our DAViCal instances are accessed like: .organizer.sarenet.es. Organizer is the name of this subservice integrated in our mail service, and of course sarenet.es (our Internet domain). Obviously, this is a customization you will have to change in the code for suiting your DAViCal instance's URL names. Only note that  should be as described between '<' and '>'. Let's show some examples:


 * + Example 1: For the domain davical.org the https URL would be : https://davicalorg.organizer.sarenet.es/...
 * + Example 2: For the domain davical.nom.es the https URL would be : https://davicalnomes.organizer.sarenet.es/...
 * + Example 3: For the domain dav-ical.com the https URL would be : https://davicalcom.organizer.sarenet.es/...

- In order for the code of this project to work, DAViCal instance configuration files should be found in /usr/local/etc/davical/ with as file name the following pattern: .organizer.sarenet.es-conf.php. So similar to URL hostname part and "-conf.php".

- With these last two points I'm trying to explain that I recommend to use  a dot and later the whatever subdomain you plan to use. We have used as said "organizer.sarenet.es" because is what it's now being used with and because it serves perfectly as an example for understanding how should or at how it was planned to be used.

- When I write code I try to write it with security in mind. So there's no admin user what can access to all databases. Instead of that the own script collects database access credentials for connecting to DAViCal instance database from the own instance's config files to which it needs to handle a request for. So a connect line, that matches with the following regexp, should exist as database connecting line in the DAViCal instance's config file :


 * /(\w+)=(\w+\.{1}\w+\.{1}\w+\.{1}\w+ )(\w+)=(\w+ )(\w+)=(\w+ )(\w+)=(\w+ )(\w+)=(\w+)/

For example:


 * $c->pg_connect[] = "host=1.2.3.4 port=5432 dbname=xxxxxxx user=yyyyyyy password=zzzzzzzzzz";

- This code assumes default collections “calendar” and “addresses” should never be removed because they are the default ones and are needed to keep the same default content in all accounts. Really this is a rule I have created personally and can be discussed but I think it’s helpful and contributes having content in a more homogeneous way.

- Another customizable aspect in the code is that it logs to syslog local2 facility and info priority. It can be easily be changed in “## SYSLOG STAFF “ section of the code.

- At present, this tool does only contemplate read-only or read-write permissions for collections. For this purpose, davical-cli autoadjusts principal’s and other collections’ permissions, in order to prevent unwanted and erroneously occurred accesses.

- DAViCal and Davical-cli grant scheduling permission by default, and it’s not possible to remove this privilege from any authenticated user from davical-cli. Even being totally possible from DAViCal admin interface, I don’t recommend removing this privilege because when you later would need to change again from Davical-cli the users permissions (wherever they changed) scheduling privilege will be restored. I consider removing scheduling privilege in a scheduling and collaborative system it’s pretty uncommon.

- 9987982389 (number seen in the code) is nothing but an invented error code which is pretty difficult to any time be owned by any id of any kind.

- The DAViCal instances managed by this code have the username and email of each account sharing the same value. By the way, DAViCal users are and correspond to an email account in our mail service. So DAViCal usernames are the users' own emails and this helps us (Sarenet) too with the IMAP auth. So when we refer to the a@b.com user, we are referring to that user in bcom.organizer.sarenet.es DAViCal instance.

- Groups can never contain “@” character. It’s a rule required by davical-cli for managing groups properly. Davical-cli was designed with the idea that each group belongs to a concrete user. I know in DAViCal Admin web interface this is not a requirement because in fact are two different and totally independent concepts, but joining group concept with the user it creates, allows us to manage properly the fact that different users could have created the same group name without having any kind of problem. How? Because davical-cli creates groupnames as userid+groupname and internally always refers to groups this way. Later when showing to a user his groups, or managing them, it "translates" that internal group name to the name given by the user to the group. Knowing this working mode, groups can obviously be used for assigning permissions to several users just one time in an ordered way as always.

- This script has too some possible security measures, in function comprobar_permiso_ejecutar. It does some checks that could help you for instance, at least delaying an attack (with the example implemented function) for example, when someone tries to use davical-cli in an illegal way. Obviously, you have to properly build the function for your env (or just leave it empty), in order to use this code (I mean davical-cli and important!!, before!!) comprobar_permiso_ejecutar or it will fail to work. Customizing it properly could improve your security. If you don't customize it and just leave empty, it won't harm but obviously won't help in improving security.

Special combined operations 

The following operations (possibilities given by Davical-cli) are slightly special, because they should be launched both one after the other one, in order to get the desired operation to be applied.

- Allow all authenticated users with READ or READ-WRITE privilege in a collection, would require this two davical-cli invocations :


 * davical-cli -r  -o 14 -w user -p READWRITE –v
 * davical-cli -r   -o 12 -u user  -p READ or READWRITE -c colection –v

- Give some user(s) (not to all authenticated ones) permissions on some collection (and handle properly all elements permission):


 * davical-cli -r  -o 5 -u $usuario_implicado -w $usuario -p READWRITE -v
 * davical-cli -r  -o 7 -u $usuario_implicado -w $usuario -c $coleccion -p permisos -v

IMPORTANT


 * In this last permission assigning operation if assigning/unassigning permissions to groups you should include "–z groupowner" option. So in this last options -u, or -w are the groupname (the own user seeing group name) but as explained before and in order to handle it properly we need to pass to davical-cli which one is the group owner with "-z" option.
 *  Remember when launching any davical-cli operation, the -r option should always have the own mail domain as is. I mean, with dots, dashes... let's say like we would use when wanted to use the domain name for email purposes. For instance, sare-net.net, sarenet.es...

Summarizing all process steps in order to have davical-cli working 

1-> Copy the script to a place outside scope of the web server.

2-> Create the config files for each Davical instance in the directory /usr/local/etc/davical and with the following name format : .organizer.sarenet.es-conf.php.

3-> Ensure you have all required Perl modules :

## REQUIRED PERL MODULES

use DBI;

use strict;

use warnings;

use Getopt::Long;

use Switch;

use Sys::Syslog qw(:DEFAULT setlogsock);

4-> Reset (empty) or adjust the comprobar_permiso_ejecutar function suitting it to your needs.

5-> Ensure each DAViCal instance configuration file contains a database connection line like :

pg_connect[] = "host=11.22.33.44 port=5432 dbname=ramattacknet user=usernamedatabase password=passworddatabase";

.

.

.

.

?>

6-> Finally, launch davical-cli –r <real-domain-with-dot-and-dash> -v

If you see a menu with all options and syntax, you have installed the script properly and you can now start working with it.

Please enter with -o the number of the request you need to carry out by looking at the example requests below. 1 -> CREATE COLLECTION. 2 -> REMOVE COLLECTION. 3 -> APPEND USER TO A GROUP OF AN OWNER (OWNERS ARE THE WAY OF UNIQUELY IDENTIFY A GROUP FROM A CONCRETE PRINCIPAL OR USER) 4 -> REMOVE USER TO A GROUP OF AN OWNER (OWNERS ARE THE WAY OF UNIQUELY IDENTIFY A GROUP FROM A CONCRETE PRINCIPAL OR USER) 5 -> GRANT CONCRETE PERMISSIONS TO A PRINCIPAL IN ANOTHER PRINCIPAL (PRINCIPALS ARE FINALLY JUST USERS) 6 -> REVOKE PERMISSIONS TO A PRINCIPAL IN PRINCIPAL (PRINCIPALS ARE FINALLY JUST USERS) 7 -> GRANT PERMISSIONS TO A PRINCIPAL (A USER FINALLY) IN A COLLECTION OF ANOTHER PRINCIPAL (ANOTHER USER FINALLY) 8 -> REVOKE PERMISSIONS TO A PRINCIPAL (A USER FINALLY) IN A COLLECTION OF ANOTHER PRINCIPAL (ANOTHER USER FINALLY) 9 -> CREATE GROUP OWNED BY USER (BY A PRINCIPAL FINALLY) 10 -> REMOVE GROUP OWNED BY USER (BY A PRINCIPAL FINALLY) 11 -> REMOVE PRINCIPAL/USER (AN ACCOUNT FINALLY WITH ALL THE COLLECTIONS) 12 -> SET DEFAULT PERMISSIONS IN A COLLECTION OF A PRINCIPAL 13 -> UNSET DEFAULT PERMISSIONS IN A COLLECTION OF A PRINCIPAL 14 -> SET DEFAULT PERMISSIONS IN A PRINCIPAL 15 -> UNSET DEFAULT PERMISSIONS IN A PRINCIPAL 16 -> OBTAIN PRINCIPAL GRANTS FOR DISPLAYING THEM FOR EXAMPLE IN THE WEBMAIL.... 17 -> OBTAIN GROUP MEMBERS FROM A GROUP OWNED BY AN USER (A PRINCIPAL) 18 -> OBTAIN GROUPS OWNED BY AN USER (OR PRINCIPAL) 19 -> SET A COLLECTION'S (FROM A PRINCIPAL) DISPLAY NAME 20 -> OBTAIN PERMISSIONS GRANTED TO OTHER USERS IN MY COLLECTIONS 21 -> OBTAIN A LIST OF ALL CREATED USERS IN THE DAVICAL INSTANCE 22 -> OBTAIN A LISTING WHICH DISPLAYS FROM A CONCRETE OWNER, GROUP:MEMBERS 23 -> COMBINED LISTING OF 16,20,21,22



Example syntax for all operations : 1 -> davical-interface-r11.pl -r domain -o 1 -c collection_name -u user_principal_to_create_inside -t 0 for calendar or 1 for addressbook -v 2 -> davical-interface-r11.pl -r domain -o 2 -c collection_name -u user_principal_to_create_inside -v 3 -> davical-interface-r11.pl -r domain -o 3 -u user_to_add -z owner_of_the_group_of_this_request -g groupname -v 4 -> davical-interface-r11.pl -r domain -o 4 -u user_to_add -z owner_of_the_group_of_this_request -g groupname -v 5 -> davical-interface-r11.pl -r domain -o 5 -u permissions_granted_to_user -w permissions_granted_in_principal -p READ OR READWRITE -v 6 -> davical-interface-r11.pl -r domain -o 6 -u permissions_revoked_to_user -w permissions_revoked_in_principal -v 7 -> davical-interface-r11.pl -r domain -o 7 -u permissions_granted_to_user -w permissions_granted_in_collection_of_principal -c collection -p READ or READWRITE -v 8 -> davical-interface-r11.pl -r domain -o 8 -u permissions_granted_to_user -w permissions_granted_in_collection_of_principal -c collection -v 9 -> davical-interface-r11.pl -r domain -o 9 -z user_owner_of_group -g groupname -v 10 -> davical-interface-r11.pl -r domain -o 10 -z user_owner_of_group -g groupname -v 11 -> davical-interface-r11.pl -r domain -o 11 -u user_principal_to_be_removed -v 12 -> davical-interface-r11.pl -r domain -o 12 -u user_owning_the_collection_overwhich -p READ or READWRITE -c collection -v 13 -> davical-interface-r11.pl -r domain -o 13 -w user_owning_the_collection_overwhich -c collection -v 14 -> davical-interface-r11.pl -r domain -o 14 -w destination_principal -p READ OR READWRITE -v 15 -> davical-interface-r11.pl -r domain -o 15 -w destination_principal -v 16 -> davical-interface-r11.pl -r domain -o 16 -u user_principal_to_answer_for -v 17 -> davical-interface-r11.pl -r domain -o 17 -z principal_user_owner_of_the_group -g the_own_group_of_the_query_for_obtain_members -v 18 -> davical-interface-r11.pl -r domain -o 18 -z principal_user_owner_of_the_groups -v 19 -> davical-interface-r11.pl -r domain -o 19 -u principal_with_collection_inside -c collection_name -d "NEW DISPLAY NAME" -v 20 -> davical-interface-r11.pl -r domain -o 20 -u user_principal_to_query_for -v 21 -> davical-interface-r11.pl -r domain -o 21 -v 22 -> davical-interface-r11.pl -r domain -o 22 -z owner_to_query_for_the_listing -v 22 -> davical-interface-r11.pl -r domain -o 23 -v

If you don't see this, you have to check step what you did wrongly. Also check or adjust the comprobar_permiso_ejecutar function.

<font size="+2">If something becomes messy or suffering issues... 

If you are suffering issues or having doubts of its working mode, please contact me by [mailto:egoitz@sarenet.es email address] and I'll help you happily :)

<font size="+2">Special thanks 

I personally would like to express my gratitude to Sarenet for allowing me doing sharing this code with all you and I'm very proud of doing it.

Egoitz Aurrekoetxea  Sysadmin at Sarenet S.A.U.