aboutsummaryrefslogtreecommitdiff
path: root/net-mgmt/adcli
diff options
context:
space:
mode:
authorMikhail Teterin <mi@FreeBSD.org>2016-06-16 15:35:31 +0000
committerMikhail Teterin <mi@FreeBSD.org>2016-06-16 15:35:31 +0000
commitda863ad4d4799b66bd183bcae92a1424c5face2c (patch)
tree0b1b963cc6c0ded11404d37deccb85d1ee721389 /net-mgmt/adcli
parent6c31093b12b9f0f06364c414da1b1ede2d9a1caa (diff)
downloadports-da863ad4d4799b66bd183bcae92a1424c5face2c.tar.gz
ports-da863ad4d4799b66bd183bcae92a1424c5face2c.zip
Notes
Diffstat (limited to 'net-mgmt/adcli')
-rw-r--r--net-mgmt/adcli/Makefile51
-rw-r--r--net-mgmt/adcli/distinfo3
-rw-r--r--net-mgmt/adcli/files/patch-configure10
-rw-r--r--net-mgmt/adcli/files/patch-heimdal522
-rw-r--r--net-mgmt/adcli/pkg-descr10
5 files changed, 596 insertions, 0 deletions
diff --git a/net-mgmt/adcli/Makefile b/net-mgmt/adcli/Makefile
new file mode 100644
index 000000000000..e7e7f5fabb92
--- /dev/null
+++ b/net-mgmt/adcli/Makefile
@@ -0,0 +1,51 @@
+# Created by: Mikhail T. <mi@aldan.algebra.com>
+# $FreeBSD$
+
+PORTNAME= adcli
+PORTVERSION= 0.8.1
+CATEGORIES= net-mgmt net security
+MASTER_SITES= https://www.freedesktop.org/software/realmd/releases/
+
+MAINTAINER= mi@aldan.algebra.com
+COMMENT= Tool for performing actions on an Active Directory domain
+
+LICENSE= LGPL21
+
+LIB_DEPENDS= libldap.so:net/openldap24-sasl-client
+BUILD_DEPENDS= xsltproc:textproc/libxslt
+
+PLIST_FILES= sbin/adcli man/man8/adcli.8.gz
+GNU_CONFIGURE= yes
+TEST_TARGET= check
+
+OPTIONS_SINGLE= GSSAPI
+OPTIONS_SINGLE_GSSAPI= GSSAPI_BASE GSSAPI_HEIMDAL GSSAPI_MIT
+OPTIONS_DEFAULT= GSSAPI_BASE
+
+CONFIGURE_ENV+= ac_cv_path_KRB5_CONFIG=${KRB5CONFIG} \
+ ac_cv_path_XMLTO=${TRUE}
+CONFIGURE_ARGS+=--disable-silent-rules --sysconfdir=/etc
+
+# Kerberos may or may not be there, but LDAP always is:
+CFLAGS+= -I${LOCALBASE}/include -DLDAP_DEPRECATED=0
+LDFLAGS+= -L${LOCALBASE}/lib
+
+GSSAPI_BASE_USES= gssapi
+GSSAPI_MIT_USES= gssapi:mit,flags
+GSSAPI_HEIMDAL_USES= gssapi:heimdal,flags
+
+GSSAPI_BASE_CONFIGURE_ARGS= --sysconfdir=/etc
+GSSAPI_BASE_CONFIGURE_ENV= KRB5_CFLAGS="-I${GSSAPIINCDIR}" \
+ KRB5_LIBS="${GSSAPILIBS}"
+GSSAPI_HEIMDAL_CONFIGURE_ARGS= --sysconfdir=${LOCALBASE}/etc
+GSSAPI_HEIMDAL_CONFIGURE_ENV= KRB5_CFLAGS="-I${GSSAPIINCDIR}/heimdal" \
+ KRB5_LIBS="${GSSAPILDFLAGS} ${GSSAPILIBS}"
+GSSAPI_MIT_CONFIGURE_ARGS= --sysconfdir=${LOCALBASE}/etc
+GSSAPI_MIT_CONFIGURE_ENV= KRB5_CFLAGS="-I${GSSAPIINCDIR}/gssapi" \
+ KRB5_LIBS="${GSSAPILDFLAGS} ${GSSAPILIBS} -lk5crypto"
+# Quiets down warnings inside MIT's headers:
+GSSAPI_BASE_CFLAGS+= -DHEIMDAL
+GSSAPI_HEIMDAL_CFLAGS+= -DHEIMDAL
+GSSAPI_MIT_CFLAGS+= -DTARGET_OS_MAC=0
+
+.include <bsd.port.mk>
diff --git a/net-mgmt/adcli/distinfo b/net-mgmt/adcli/distinfo
new file mode 100644
index 000000000000..9a7406a82d96
--- /dev/null
+++ b/net-mgmt/adcli/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1466020300
+SHA256 (adcli-0.8.1.tar.gz) = 5a611bfc55e563d94b526e975aac7c069304fe305f86076800bf7aae71bec7b5
+SIZE (adcli-0.8.1.tar.gz) = 466440
diff --git a/net-mgmt/adcli/files/patch-configure b/net-mgmt/adcli/files/patch-configure
new file mode 100644
index 000000000000..af9a311dd1dd
--- /dev/null
+++ b/net-mgmt/adcli/files/patch-configure
@@ -0,0 +1,10 @@
+--- configure 2016-01-19 15:01:43.000000000 -0500
++++ configure 2016-06-15 16:55:50.354029000 -0400
+@@ -13209,4 +13209,7 @@
+ /* end confdefs.h. */
+
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <arpa/nameser.h>
+ #include <resolv.h>
+ int
diff --git a/net-mgmt/adcli/files/patch-heimdal b/net-mgmt/adcli/files/patch-heimdal
new file mode 100644
index 000000000000..1b8605ab8632
--- /dev/null
+++ b/net-mgmt/adcli/files/patch-heimdal
@@ -0,0 +1,522 @@
+Submitted upstream:
+
+ https://bugs.freedesktop.org/show_bug.cgi?id=96558
+
+--- library/adprivate.h 2015-12-11 05:29:24.000000000 -0500
++++ library/adprivate.h 2016-06-15 19:21:07.357447000 -0400
+@@ -39,4 +39,12 @@
+ #endif
+
++#ifdef HEIMDAL
++#define MAX_KEYTAB_NAME_LEN 1100 /* This is, what Samba does */
++#define krb5_free_string(ctx, string) krb5_xfree(string)
++#define krb5_free_keytab_entry_contents krb5_kt_free_entry /* Samba as well */
++#else
++typedef krb5_data krb5_salt; /* MIT Kerberos does not have this */
++#endif
++
+ /* Utilities */
+
+@@ -133,5 +141,5 @@ int _adcli_str_has_suffix
+ const char *suffix);
+
+-char * _adcli_str_dupn (void *data,
++char * _adcli_str_dupn (const void *data,
+ size_t len);
+
+@@ -248,5 +256,5 @@ krb5_error_code _adcli_krb5_keytab_add_
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salt);
++ const krb5_salt *salt);
+
+ krb5_error_code _adcli_krb5_keytab_test_salt (krb5_context k5,
+@@ -256,5 +264,5 @@ krb5_error_code _adcli_krb5_keytab_test
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salt);
++ const krb5_salt *salt);
+
+ krb5_error_code _adcli_krb5_keytab_discover_salt (krb5_context k5,
+@@ -263,5 +271,5 @@ krb5_error_code _adcli_krb5_keytab_disc
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salts,
++ const krb5_salt *salts,
+ int *discovered);
+
+@@ -269,5 +277,5 @@ krb5_error_code _adcli_krb5_w2k3_salt
+ krb5_principal principal,
+ const char *host_netbios,
+- krb5_data *salt);
++ krb5_salt *salt);
+
+ krb5_enctype * _adcli_krb5_parse_enctypes (const char *value);
+--- library/adconn.h 2015-12-07 03:59:59.000000000 -0500
++++ library/adconn.h 2016-06-15 17:34:40.511127000 -0400
+@@ -27,5 +27,9 @@
+ #include "adutil.h"
+
+-#include <krb5/krb5.h>
++#ifdef HEIMDAL
++# include <krb5.h>
++#else
++# include <krb5/krb5.h>
++#endif
+ #include <ldap.h>
+
+--- library/adenroll.c 2015-12-11 05:37:01.000000000 -0500
++++ library/adenroll.c 2016-06-15 19:46:42.925270000 -0400
+@@ -29,5 +29,10 @@
+
+ #include <gssapi/gssapi_krb5.h>
+-#include <krb5/krb5.h>
++#ifdef HEIMDAL
++# include <krb5.h>
++# define krb5_free_data_contents(ctx, data) krb5_data_free(data)
++#else
++# include <krb5/krb5.h>
++#endif
+ #include <ldap.h>
+ #include <sasl/sasl.h>
+@@ -228,5 +233,9 @@ generate_host_password (adcli_enroll *e
+ buffer.data = password + at;
+
++#ifdef HEIMDAL
++ krb5_generate_random_block(buffer.data, buffer.length);
++#else
+ code = krb5_c_random_make_octets (k5, &buffer);
+ return_val_if_fail (code == 0, NULL);
++#endif
+
+@@ -895,5 +904,6 @@ set_password_with_computer_creds (adcli_
+ }
+
+- code = krb5_change_password (k5, &creds, enroll->computer_password,
++ /* Use new krb5_set_password instead of deprecated krb5_change_password */
++ code = krb5_set_password (k5, &creds, enroll->computer_password, NULL,
+ &result_code, &result_code_string, &result_string);
+
+@@ -1252,5 +1262,5 @@ ensure_host_keytab (adcli_result res,
+ return_unexpected_if_fail (code == 0);
+
+- enroll->keytab_name = name;
++ enroll->keytab_name = realloc(name, strlen(name) + 1);
+ enroll->keytab_name_is_krb5 = 1;
+ }
+@@ -1268,6 +1278,6 @@ load_keytab_entry (krb5_context k5,
+ krb5_error_code code;
+ krb5_principal principal;
+- const char *realm;
+- size_t len;
++ const char *realm, *entry_realm;
++ size_t len, entry_realm_len;
+ char *value;
+ char *name;
+@@ -1275,11 +1285,22 @@ load_keytab_entry (krb5_context k5,
+ /* Skip over any entry without a principal or realm */
+ principal = entry->principal;
+- if (!principal || !principal->realm.length)
++ if (principal == NULL)
+ return TRUE;
++#ifdef HEIMDAL
++ entry_realm = krb5_principal_get_realm(k5, principal);
++ if (entry_realm == NULL || entry_realm[0] == '\0')
++ return TRUE;
++ entry_realm_len = strlen(entry_realm);
++#else
++ if (!principal->realm.length)
++ return TRUE;
++ entry_realm = principal->realm.data;
++ entry_realm_len = principal->realm.length;
++#endif
+
+ /* Use the first keytab entry as realm */
+ realm = adcli_conn_get_domain_realm (enroll->conn);
+ if (!realm) {
+- value = _adcli_str_dupn (principal->realm.data, principal->realm.length);
++ value = _adcli_str_dupn (entry_realm, entry_realm_len);
+ adcli_conn_set_domain_realm (enroll->conn, value);
+ _adcli_info ("Found realm in keytab: %s", value);
+@@ -1290,5 +1311,5 @@ load_keytab_entry (krb5_context k5,
+ /* Only look at entries that match the realm */
+ len = strlen (realm);
+- if (principal->realm.length != len && strncmp (realm, principal->realm.data, len) != 0)
++ if (entry_realm_len != len && strncmp (realm, entry_realm, len) != 0)
+ return TRUE;
+
+@@ -1388,7 +1409,13 @@ match_principal_and_kvno (krb5_context k
+ }
+
+-#define DEFAULT_SALT 1
++enum SALTS {
++ STANDARD_SALT,
++ W2K3_SALT,
++ NULL_SALT,
++ _NUM_SALTS
++};
++#define DEFAULT_SALT W2K3_SALT
+
+-static krb5_data *
++static krb5_salt *
+ build_principal_salts (adcli_enroll *enroll,
+ krb5_context k5,
+@@ -1396,23 +1423,29 @@ build_principal_salts (adcli_enroll *enr
+ {
+ krb5_error_code code;
+- krb5_data *salts;
+- const int count = 3;
+- int i = 0;
++ krb5_salt *salts;
+
+- salts = calloc (count, sizeof (krb5_data));
++ salts = calloc (_NUM_SALTS, sizeof (*salts));
+ return_val_if_fail (salts != NULL, NULL);
+
+ /* Build up the salts, first a standard kerberos salt */
+- code = krb5_principal2salt (k5, principal, &salts[i++]);
++#ifdef HEIMDAL
++ code = krb5_get_pw_salt(k5, principal, &salts[STANDARD_SALT]);
++#else
++ code = krb5_principal2salt(k5, principal, &salts[STANDARD_SALT]);
++#endif
+ return_val_if_fail (code == 0, NULL);
+
+ /* Then a Windows 2003 computer account salt */
+- code = _adcli_krb5_w2k3_salt (k5, principal, enroll->computer_name, &salts[i++]);
++ code = _adcli_krb5_w2k3_salt (k5, principal, enroll->computer_name, &salts[W2K3_SALT]);
+ return_val_if_fail (code == 0, NULL);
+
+ /* And lastly a null salt */
+- salts[i++].data = NULL;
++#ifdef HEIMDAL
++ salts[NULL_SALT].salttype = KRB5_PW_SALT;
++ salts[NULL_SALT].saltvalue.data = NULL;
++#else
++ salts[NULL_SALT].data = NULL;
++#endif
+
+- assert (count == i);
+ return salts;
+ }
+@@ -1420,10 +1453,15 @@ build_principal_salts (adcli_enroll *enr
+ static void
+ free_principal_salts (krb5_context k5,
+- krb5_data *salts)
++ krb5_salt *salts)
+ {
+ int i;
+
++#ifdef HEIMDAL
++ for (i = 0; i < _NUM_SALTS; i++)
++ krb5_free_salt(k5, salts[i]);
++#else
+ for (i = 0; salts[i].data != NULL; i++)
+ krb5_free_data_contents (k5, salts + i);
++#endif
+
+ free (salts);
+@@ -1440,5 +1478,5 @@ add_principal_to_keytab (adcli_enroll *e
+ krb5_data password;
+ krb5_error_code code;
+- krb5_data *salts;
++ krb5_salt *salts;
+ krb5_enctype *enctypes;
+
+@@ -1525,5 +1563,9 @@ update_keytab_for_principals (adcli_enro
+ res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i],
+ name, &which_salt);
++#ifdef HEIMDAL
++ krb5_xfree(name);
++#else
+ krb5_free_unparsed_name (k5, name);
++#endif
+
+ if (res != ADCLI_SUCCESS)
+--- library/adkrb5.c 2015-12-07 03:59:59.000000000 -0500
++++ library/adkrb5.c 2016-06-15 19:41:21.641988000 -0400
+@@ -28,5 +28,9 @@
+
+ #include <gssapi/gssapi_krb5.h>
+-#include <krb5/krb5.h>
++#ifdef HEIMDAL
++# include <krb5.h>
++#else
++# include <krb5/krb5.h>
++#endif
+
+ #include <assert.h>
+@@ -79,5 +83,9 @@
+ /* See if we should remove this entry */
+ if (!match_func (k5, &entry, match_data)) {
++#ifdef HEIMDAL
++ krb5_kt_free_entry(k5, &entry);
++#else
+ krb5_free_keytab_entry_contents (k5, &entry);
++#endif
+ continue;
+ }
+@@ -92,5 +100,9 @@
+
+ code = krb5_kt_remove_entry (k5, keytab, &entry);
++#ifdef HEIMDAL
++ krb5_kt_free_entry(k5, &entry);
++#else
+ krb5_free_keytab_entry_contents (k5, &entry);
++#endif
+
+ if (code != 0)
+@@ -213,5 +225,5 @@
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salt)
++ const krb5_salt *salt)
+ {
+ krb5_keytab_entry entry;
+@@ -222,5 +234,10 @@
+ memset (&entry, 0, sizeof(entry));
+
++#ifdef HEIMDAL
++ code = krb5_string_to_key_salt(k5, enctypes[i], password->data,
++ *salt, &entry.keyblock);
++#else
+ code = krb5_c_string_to_key (k5, enctypes[i], password, salt, &entry.key);
++#endif
+ if (code != 0)
+ return code;
+@@ -248,5 +265,5 @@
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salt)
++ const krb5_salt *salt)
+ {
+ krb5_error_code code;
+@@ -274,5 +291,5 @@
+ krb5_data *password,
+ krb5_enctype *enctypes,
+- krb5_data *salts,
++ const krb5_salt *salts,
+ int *discovered)
+ {
+@@ -286,5 +303,11 @@
+ return_val_if_fail (code == 0, code);
+
+- for (i = 0; salts[i].data != NULL; i++) {
++ for (i = 0;
++#ifdef HEIMDAL
++ salts[i].saltvalue.data != NULL;
++#else
++ salts[i].data != NULL;
++#endif
++ i++) {
+ code = _adcli_krb5_keytab_test_salt (k5, scratch, principal, kvno,
+ password, enctypes, &salts[i]);
+@@ -305,11 +328,15 @@
+ krb5_principal principal,
+ const char *host_netbios,
+- krb5_data *salt)
++ krb5_salt *salt)
+ {
+- krb5_data *realm;
+- size_t size = 0;
+- size_t host_length = 0;
++ const char *realm;
++#ifndef HEIMDAL
++ const krb5_data *krealm;
++#endif
++ size_t size = 0, realm_len;
++ size_t host_length;
+ size_t at = 0;
+ int i;
++ char *data;
+
+ /*
+@@ -318,41 +345,55 @@
+ */
+
+- realm = krb5_princ_realm (k5, principal);
++#ifdef HEIMDAL
++ salt->salttype = KRB5_PW_SALT;
++ realm = krb5_principal_get_realm(k5, principal);
++ realm_len = strlen(realm);
++#else
++ krealm = krb5_princ_realm (k5, principal);
++ realm = krealm->data;
++ realm_len = krealm->length;
++#endif
+ host_length = strlen (host_netbios);
+
+- size += realm->length;
++ size += realm_len;
+ size += 4; /* "host" */
+ size += host_length;
+ size += 1; /* "." */
+- size += realm->length;
++ size += realm_len;
+
+- salt->data = malloc (size);
+- return_val_if_fail (salt->data != NULL, ENOMEM);
++ data = malloc (size);
++ return_val_if_fail (data != NULL, ENOMEM);
+
+ /* Upper case realm */
+- for (i = 0; i < realm->length; i++)
+- salt->data[at + i] = toupper (realm->data[i]);
+- at += realm->length;
++ for (i = 0; i < realm_len; i++)
++ data[at + i] = toupper (realm[i]);
++ at += realm_len;
+
+ /* The string "host" */
+- memcpy (salt->data + at, "host", 4);
++ memcpy (data + at, "host", 4);
+ at += 4;
+
+ /* The netbios name in lower case */
+ for (i = 0; i < host_length; i++)
+- salt->data[at + i] = tolower (host_netbios[i]);
++ data[at + i] = tolower (host_netbios[i]);
+ at += host_length;
+
+ /* The dot */
+- memcpy (salt->data + at, ".", 1);
++ memcpy (data + at, ".", 1);
+ at += 1;
+
+ /* Lower case realm */
+- for (i = 0; i < realm->length; i++)
+- salt->data[at + i] = tolower (realm->data[i]);
+- at += realm->length;
++ for (i = 0; i < realm_len; i++)
++ data[at + i] = tolower (realm[i]);
++ at += realm_len;
+
+ assert (at == size);
++#ifdef HEIMDAL
++ salt->saltvalue.data = data;
++ salt->saltvalue.length = size;
++#else
++ salt->data = data;
+ salt->length = size;
++#endif
+ return 0;
+ }
+--- library/adldap.c 2015-12-07 04:18:09.000000000 -0500
++++ library/adldap.c 2016-06-15 17:36:22.374212000 -0400
+@@ -28,5 +28,9 @@
+
+ #include <gssapi/gssapi_krb5.h>
+-#include <krb5/krb5.h>
++#ifdef HEIMDAL
++# include <krb5.h>
++#else
++# include <krb5/krb5.h>
++#endif
+ #include <ldap.h>
+ #include <sasl/sasl.h>
+--- library/adutil.c 2016-01-19 14:56:21.000000000 -0500
++++ library/adutil.c 2016-06-15 18:34:42.841301000 -0400
+@@ -295,5 +295,5 @@ _adcli_strv_set (char ***field,
+
+ char *
+-_adcli_str_dupn (void *data,
++_adcli_str_dupn (const void *data,
+ size_t len)
+ {
+--- library/addisco.c 2015-12-07 04:18:09.000000000 -0500
++++ library/addisco.c 2016-06-15 17:06:34.197797000 -0400
+@@ -32,4 +32,5 @@
+
+ #include <arpa/inet.h>
++#include <netinet/in.h>
+ #include <arpa/nameser.h>
+
+--- library/adconn.c 2015-12-16 04:33:30.000000000 -0500
++++ library/adconn.c 2016-06-16 01:19:09.031863000 -0400
+@@ -27,10 +27,11 @@
+ #include "adprivate.h"
+ #include "addisco.h"
++#include "adconn.h"
+
+ #include <gssapi/gssapi_krb5.h>
+-#include <krb5/krb5.h>
+-#include <ldap.h>
+ #include <sasl/sasl.h>
+
++#include <netinet/in.h>
++
+ #include <sys/types.h>
+ #include <sys/socket.h>
+@@ -386,5 +387,7 @@
+ " %s = {\n"
+ " kdc = %s:88\n"
++#ifndef HEIMDAL
+ " master_kdc = %s:88\n"
++#endif
+ " kpasswd_server = %s\n"
+ " }\n"
+@@ -392,5 +395,9 @@
+ " %s = %s\n"
+ " %s = %s\n",
+- conn->domain_realm, controller, controller, controller,
++ conn->domain_realm, controller,
++#ifndef HEIMDAL
++ controller,
++#endif
++ controller,
+ conn->canonical_host, conn->domain_realm,
+ conn->domain_controller, conn->domain_realm) < 0)
+@@ -481,8 +488,10 @@
+ return_val_if_fail (code == 0, code);
+
++#ifndef HEIMDAL /* No such call in Heimdal -- not needed */
+ if (ccache) {
+ code = krb5_get_init_creds_opt_set_out_ccache (k5, opt, ccache);
+ return_val_if_fail (code == 0, code);
+ }
++#endif
+
+ memset (&dummy, 0, sizeof (dummy));
+@@ -554,8 +563,10 @@
+ return_val_if_fail (code == 0, code);
+
++#ifndef HEIMDAL /* No such call in Heimdal -- not needed */
+ if (ccache) {
+ code = krb5_get_init_creds_opt_set_out_ccache (k5, opt, ccache);
+ return_val_if_fail (code == 0, code);
+ }
++#endif
+
+ memset (&dummy, 0, sizeof (dummy));
+@@ -565,5 +576,5 @@
+ code = krb5_get_init_creds_password (k5, creds, principal,
+ conn->user_password, null_prompter, NULL,
+- 0, (char *)in_tkt_service, opt);
++ 0, in_tkt_service, opt);
+
+ krb5_free_principal (k5, principal);
+@@ -1014,5 +1025,9 @@
+
+ /* Clear the credential cache GSSAPI to use (for this thread) */
++#ifdef HEIMDAL
++ status = gss_krb5_ccache_name (&minor, "", NULL);
++#else
+ status = gss_krb5_ccache_name (&minor, NULL, NULL);
++#endif
+ return_unexpected_if_fail (status == 0);
+
+--- tools/tools.c 2015-12-16 04:35:03.000000000 -0500
++++ tools/tools.c 2016-06-16 02:53:00.103111000 -0400
+@@ -504,5 +504,12 @@
+ errx (-1, "unexpected memory problems");
+ adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL);
++#ifndef HEIMDAL
++ /*
++ * Only do this with MIT Kerberos. Heimdal does not support
++ * includedir and include directives and seems to work
++ * without this anyway.
++ */
+ setup_krb5_conf_directory (conn);
++#endif
+ }
+
diff --git a/net-mgmt/adcli/pkg-descr b/net-mgmt/adcli/pkg-descr
new file mode 100644
index 000000000000..965b6e02d386
--- /dev/null
+++ b/net-mgmt/adcli/pkg-descr
@@ -0,0 +1,10 @@
+adcli is a command line tool that can perform actions in an Active Directory
+domain:
+
+ . "join" a computer (not necessarily the current one) into AD-domain
+ . output information about the domain -- in human- and computer-readable
+ form
+ . create user- and group-accounts in the domain
+ . delete and reset accounts
+
+WWW: https://www.freedesktop.org/software/realmd/adcli/adcli.html