lists.arthurdejong.org
RSS feed

nss-pam-ldapd branch master updated. 0.8.12-74-g91440f7

[Date Prev][Date Next] [Thread Prev][Thread Next]

nss-pam-ldapd branch master updated. 0.8.12-74-g91440f7



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "nss-pam-ldapd".

The branch, master has been updated
       via  91440f7af1b78526555c8539cb3219b72390328a (commit)
       via  ded7bd226b51975544cd5bf4f8799787948ffccb (commit)
       via  3117668c15cf88f877a538035875cd0f75ce821c (commit)
      from  7c01898fd02c0f71d4632cca27d3fb92554caa18 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://arthurdejong.org/git/nss-pam-ldapd/commit/?id=91440f7af1b78526555c8539cb3219b72390328a

commit 91440f7af1b78526555c8539cb3219b72390328a
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Mon Jan 28 23:49:24 2013 +0100

    add getent.ldap(1) manual page

diff --git a/.gitignore b/.gitignore
index e979417..8133947 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,8 @@ stamp-*
 /splint.txt
 
 # /man/
+/man/getent.ldap.1
+/man/getent.ldap.1.html
 /man/nslcd.8
 /man/nslcd.8.html
 /man/nslcd.conf.5
diff --git a/man/Makefile.am b/man/Makefile.am
index 19199e9..8975eec 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -18,15 +18,19 @@
 # 02110-1301 USA
 
 PAM_MANS = pam_ldap.8
+UTILS_MANS = getent.ldap.1
 NSLCD_MANS = nslcd.conf.5 nslcd.8
 PYNSLCD_MANS = nslcd.conf.5 pynslcd.8
-ALL_MANS = $(PAM_MANS) $(NSLCD_MANS) $(PYNSLCD_MANS)
+ALL_MANS = $(PAM_MANS) $(UTILS_MANS) $(NSLCD_MANS) $(PYNSLCD_MANS)
 
 # figure out which manual pages to install
 INST_MANS =
 if ENABLE_PAM
   INST_MANS += $(PAM_MANS)
 endif
+if ENABLE_UTILS
+  INST_MANS += $(UTILS_MANS)
+endif
 if ENABLE_NSLCD
   INST_MANS += $(NSLCD_MANS)
 endif
diff --git a/man/getent.ldap.1.xml b/man/getent.ldap.1.xml
new file mode 100644
index 0000000..0dccbbc
--- /dev/null
+++ b/man/getent.ldap.1.xml
@@ -0,0 +1,334 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+                   "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+
+<!--
+   getent.ldap.1.xml - docbook manual page for chsh.ldap
+
+   Copyright (C) 2013 Arthur de Jong
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA
+-->
+
+<refentry id="getentldap1">
+
+ <refentryinfo>
+  <author>
+   <firstname>Arthur</firstname>
+   <surname>de Jong</surname>
+  </author>
+ </refentryinfo>
+
+ <refmeta>
+  <refentrytitle>getent.ldap</refentrytitle>
+  <manvolnum>1</manvolnum>
+  <refmiscinfo class="version">Version 0.8.11</refmiscinfo>
+  <refmiscinfo class="manual">User Commands</refmiscinfo>
+  <refmiscinfo class="date">Oct 2012</refmiscinfo>
+ </refmeta>
+
+ <refnamediv id="name">
+  <refname>getent.ldap</refname>
+  <refpurpose>query information from LDAP</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id="synopsis">
+  <cmdsynopsis>
+   <command>getent.ldap</command>
+   <arg choice="opt"><replaceable>options</replaceable></arg>
+   <arg><replaceable>DATABASE</replaceable></arg>
+   <arg choice="opt"><replaceable>KEY</replaceable></arg>
+  </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+  <title>Description</title>
+  <para>
+   The <command>getent.ldap</command> command can be used to lookup or
+   enumerate information from <acronym>LDAP</acronym>.
+   Unlike the
+   
<citerefentry><refentrytitle>getent</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+   command, this command completely bypasses the lookups configured in
+   <file>/etc/nsswitch.conf</file> and queries the
+   
<citerefentry><refentrytitle>nslcd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+   daemon directly.
+  </para>
+  <para>
+   <command>getent.ldap</command> tries to match the behaviour and output of
+   <command>getent</command> and the format in the corresponding flat files
+   as much as possible, however there are a number of differences.
+   If multiple entries are found in <acronym>LDAP</acronym> that match a
+   specific query, multiple values are printed (e.g. ethernet addresses that
+   have multiple names, services that support multiple protocols, etc.).
+   Also, some databases have extra options as described below.
+  </para>
+ </refsect1>
+
+ <refsect1 id="options">
+  <title>Options</title>
+  <para>
+   The options that may be specified to the <command>getent.ldap</command>
+   command are:
+  </para>
+  <variablelist remap="TP">
+
+   <varlistentry id="help">
+    <term>
+     <option>-h</option>, <option>--help</option>
+    </term>
+    <listitem>
+     <para>Display short help and exit.</para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="version">
+    <term>
+     <option>-V, --version</option>
+    </term>
+    <listitem>
+     <para>Output version information and exit.</para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+ </refsect1>
+
+ <refsect1 id="databases">
+  <title>Databases</title>
+  <para>
+   The <replaceable>DATABASE</replaceable> argument may be any of the
+   supported databases below:
+  </para>
+  <variablelist remap="TP">
+
+   <varlistentry id="aliases">
+    <term><option>aliases</option></term>
+    <listitem>
+     <para>
+      Lists or queries email aliases.
+      If <replaceable>KEY</replaceable> is given it searches for the alias
+      by name, otherwise it returns all aliases from
+      <acronym>LDAP</acronym>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="ethers">
+    <term><option>ethers</option></term>
+    <listitem>
+     <para>
+      Lists or queries ethernet addresses.
+      If <replaceable>KEY</replaceable> matches the format of an ethernet
+      address a search by address is performed, otherwise a search by name
+      is performed or all entries are returned if
+      <replaceable>KEY</replaceable> is omitted.
+      Unlike <command>getent</command>, <command>getent.ldapd</command>
+      does support enumerating all ethernet addresses.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="group">
+    <term><option>group</option></term>
+    <listitem>
+     <para>
+      Lists or queries groups.
+      If <replaceable>KEY</replaceable> is numeric, it searches for the
+      group by group id.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="group.bymember">
+    <term><option>group.bymember</option></term>
+    <listitem>
+     <para>
+      The <replaceable>KEY</replaceable> is a user name and groups are
+      returned for which this user is a member.
+      The format is similar to the <option>group</option> output but the
+      group members are left out for performance reasons.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="hosts">
+    <term><option>hosts</option></term>
+    <listitem>
+     <para>
+      List or search host names and addresses by either host name,
+      IPv4 or IPv6 address. This returns both IPv4 and IPv6 addresses
+      (if available).
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="hostsv4">
+    <term><option>hostsv4</option></term>
+    <listitem>
+     <para>
+      Similar to <option>hosts</option> but any supplied IPv6 addresses are
+      treated as host names and only IPv4 addresses are returned.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="hostsv6">
+    <term><option>hostsv6</option></term>
+    <listitem>
+     <para>
+      Similar to <option>hosts</option> but <replaceable>KEY</replaceable>
+      is treated as an IPv6 address or a host name and only IPv6 addresses
+      are returned.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="netgroup">
+    <term><option>netgroup</option></term>
+    <listitem>
+     <para>
+      List or query netgroups and netgroup triples (host, user, domain) that
+      are a member of the netgroup.
+      Unlike <command>getent</command>, <command>getent.ldapd</command>
+      does support enumerating all ethernet addresses.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="netgroup.norec">
+    <term><option>netgroup.norec</option></term>
+    <listitem>
+     <para>
+      Similar to <option>netgroup</option> except that no subsequent
+      lookups are done to expand netgroups which are member of the
+      supplied netgroup and the output may contain both other netgroup
+      names and netgroup triples.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="networks">
+    <term><option>networks</option></term>
+    <listitem>
+     <para>
+      List or query network names and addresses.
+      <replaceable>KEY</replaceable> may be a network name or address.
+      This map can return both IPv4 and IPv6 network addresses.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="networksv4">
+    <term><option>networksv4</option></term>
+    <listitem>
+     <para>
+      Only return IPv4 network addresses.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="networksv6">
+    <term><option>networksv6</option></term>
+    <listitem>
+     <para>
+      Only return IPv6 network addresses.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="passwd">
+    <term><option>passwd</option></term>
+    <listitem>
+     <para>
+      Enumerate or search the user account database.
+      <replaceable>KEY</replaceable> may be a user name or numeric user id
+      or be omitted to list all users.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="protocols">
+    <term><option>protocols</option></term>
+    <listitem>
+     <para>
+      Enumerate the internet protocols database.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="rpc">
+    <term><option>rpc</option></term>
+    <listitem>
+     <para>
+      List or search user readable names that map to RPC program numbers.
+      Searching by <replaceable>KEY</replaceable> can be done on name or
+      rpc program number.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="services">
+    <term><option>services</option></term>
+    <listitem>
+     <para>
+      List or search the mapping between names for internet services and
+      their corresponding port numbers and protocol types.
+      The <replaceable>KEY</replaceable> can be either a service name or
+      number, followed by an optional slash and protocol name to restrict
+      the search to only entries for the specified protocol.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry id="shadow">
+    <term><option>shadow</option></term>
+    <listitem>
+     <para>
+      Enumerate or search extended user account information.
+      Note that shadow information is likely only exposed to the root user
+      and by default <command>nslcd</command> does not expose password
+      hashes, even to root.
+     </para>
+    </listitem>
+   </varlistentry>
+
+  </variablelist>
+ </refsect1>
+
+
+ <refsect1 id="see_also">
+  <title>See Also</title>
+  <para>
+   
<citerefentry><refentrytitle>getent</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+   
<citerefentry><refentrytitle>nslcd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+  </para>
+ </refsect1>
+
+ <refsect1 id="author">
+  <title>Author</title>
+  <para>This manual was written by Arthur de Jong 
&lt;arthur@arthurdejong.org&gt;.</para>
+ </refsect1>
+
+ <refsect1 id="bugs">
+  <title>Bugs</title>
+  <para>
+   Currently, <command>getent.ldapd</command> does not correctly set an
+   exit code. It should return the same kind of exit codes as
+   <command>getent</command> does (e.g. for missing entries).
+  </para>
+ </refsect1>
+
+</refentry>

http://arthurdejong.org/git/test/commit/?id=ded7bd226b51975544cd5bf4f8799787948ffccb

commit ded7bd226b51975544cd5bf4f8799787948ffccb
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Mon Jan 28 23:13:22 2013 +0100

    implement a getent command to query nslcd while bypassing NSS stack

diff --git a/utils/Makefile.am b/utils/Makefile.am
index e39d7da..e9233d8 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -19,6 +19,7 @@
 
 utilsdir = $(datadir)/nslcdutils
 
+utils_PYTHON = cmdline.py getent.py nslcd.py
 nodist_utils_PYTHON = constants.py
 CLEANFILES = $(nodist_utils_PYTHON)
 
@@ -31,3 +32,11 @@ clean-local:
 # copy constants module
 constants.py: ../pynslcd/constants.py
        cp ../pynslcd/constants.py .
+
+# create symbolic links to the commands and fix permissions
+install-data-hook:
+       $(MKDIR_P) $(DESTDIR)$(bindir)
+       set -ex; for cmd in getent ; do \
+         chmod a+rx $(DESTDIR)$(utilsdir)/$$cmd.py ; \
+         [ -L $(DESTDIR)$(bindir)/$$cmd.ldap ] || $(LN_S) $(utilsdir)/$$cmd.py 
$(DESTDIR)$(bindir)/$$cmd.ldap ; \
+       done
diff --git a/utils/cmdline.py b/utils/cmdline.py
new file mode 100644
index 0000000..eb84fe3
--- /dev/null
+++ b/utils/cmdline.py
@@ -0,0 +1,50 @@
+# coding: utf-8
+
+# cmdline.py - functions for handling command-line options
+#
+# Copyright (C) 2013 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import argparse
+
+import constants
+
+
+version_string = '''
+%s
+Written by Arthur de Jong.
+
+Copyright (C) 2013 Arthur de Jong
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+'''.strip() % constants.PACKAGE_STRING
+
+
+class VersionAction(argparse.Action):
+
+    def __init__(self, option_strings, dest,
+                 help='output version information and exit'):
+        super(VersionAction, self).__init__(
+            option_strings=option_strings,
+            dest=argparse.SUPPRESS,
+            default=argparse.SUPPRESS,
+            nargs=0,
+            help=help)
+
+    def __call__(self, parser, namespace, values, option_string=None):
+        print version_string
+        parser.exit()
diff --git a/utils/getent.py b/utils/getent.py
new file mode 100755
index 0000000..3279249
--- /dev/null
+++ b/utils/getent.py
@@ -0,0 +1,346 @@
+#!/usr/bin/env python
+# coding: utf-8
+
+# getent.py - program for querying nslcd
+#
+# Copyright (C) 2013 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import argparse
+import re
+import socket
+import struct
+import sys
+
+from cmdline import VersionAction
+import constants
+from nslcd import NslcdClient
+
+
+# set up command line parser
+parser = argparse.ArgumentParser(
+        description='Query information in LDAP.',
+        epilog='Report bugs to <%s>.' % constants.PACKAGE_BUGREPORT
+    )
+parser.add_argument('-V', '--version', action=VersionAction)
+parser.add_argument('database', metavar='DATABASE',
+    help='any of those supported by nslcd')
+parser.add_argument('key', metavar='KEY', nargs='?',
+    help='information to lookup')
+
+
+# parse arguments
+args = parser.parse_args()
+
+
+def getent_aliases(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_ALIAS_ALL)
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_ALIAS_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        print '%-16s%s' % (
+                con.read_string() + ': ',
+                ', '.join(con.read_stringlist()),
+            )
+
+
+def getent_ethers(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_ETHER_ALL)
+    elif re.match('^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$', key):
+        con = NslcdClient(constants.NSLCD_ACTION_ETHER_BYETHER)
+        con.write_ether(key)
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_ETHER_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        name = con.read_string()
+        ether = con.read_ether()
+        print '%s %s' % (ether, name)
+
+
+def getent_group(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_GROUP_ALL)
+    elif database == 'group.bymember':
+        con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYMEMBER)
+        con.write_string(key)
+    elif re.match('^\d+$', key):
+        con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYGID)
+        con.write_int32(int(key))
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_GROUP_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        print '%s:%s:%d:%s' % (
+                con.read_string(),
+                con.read_string(),
+                con.read_int32(),
+                ','.join(con.read_stringlist()),
+            )
+
+
+def _get_ipv4(value):
+    try:
+        return socket.inet_pton(socket.AF_INET, value)
+    except socket.error:
+        return None
+
+
+def _get_ipv6(value):
+    try:
+        return socket.inet_pton(socket.AF_INET6, value)
+    except socket.error:
+        return None
+
+
+def _get_af(database):
+    if database.endswith('v4'):
+        return socket.AF_INET
+    elif database.endswith('v6'):
+        return socket.AF_INET6
+    else:
+        return None
+
+
+def getent_hosts(database, key=None):
+    db_af = _get_af(database)
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_HOST_ALL)
+    else:
+        ipv4_addr = _get_ipv4(key)
+        ipv6_addr = _get_ipv6(key)
+        if ipv4_addr and db_af in (socket.AF_INET, None):
+            con = NslcdClient(constants.NSLCD_ACTION_HOST_BYADDR)
+            con.write_address(socket.AF_INET, ipv4_addr)
+        elif ipv6_addr and db_af in (socket.AF_INET, None):
+            con = NslcdClient(constants.NSLCD_ACTION_HOST_BYADDR)
+            con.write_address(socket.AF_INET6, ipv6_addr)
+        else:
+            con = NslcdClient(constants.NSLCD_ACTION_HOST_BYNAME)
+            con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        names = ' '.join([con.read_string()] + con.read_stringlist())
+        for af, address in con.read_addresslist():
+            if db_af in (af, None):
+                print '%-15s %s' % (address, names)
+
+
+def _read_netgroup(con):
+    """Read netgroup name, members and tripples from stream."""
+    name = con.read_string()
+    members = []
+    tripples = []
+    while True:
+        member_type = con.read_int32()
+        if member_type == constants.NSLCD_NETGROUP_TYPE_NETGROUP:
+            members.append(con.read_string())
+        elif member_type == constants.NSLCD_NETGROUP_TYPE_TRIPLE:
+            tripples.append((
+                    con.read_string(), con.read_string(),
+                    con.read_string()
+                ))
+        else:
+            break
+    return name, members, tripples
+
+
+def _get_getgroups(con, recurse, netgroups=None):
+    if netgroups is None:
+        netgroups = {}
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        name, members, tripples = _read_netgroup(con)
+        if not recurse:
+            yield (name, members, tripples)
+        else:
+            netgroups[name] = None
+            for netgroup in members:
+                if netgroup not in netgroups:
+                    con2 = NslcdClient(constants.NSLCD_ACTION_NETGROUP_BYNAME)
+                    con2.write_string(netgroup)
+                    all(_get_getgroups(con2, recurse, netgroups))
+                if netgroups.get(netgroup, None) is not None:
+                    tripples += netgroups[netgroup][1]
+            netgroups[name] = (members, tripples)
+            yield (name, [], tripples)
+
+
+def getent_netgroup(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_NETGROUP_ALL)
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_NETGROUP_BYNAME)
+        con.write_string(key)
+    for name, members, tripples in _get_getgroups(con, database == 'netgroup'):
+        print '%-15s %s' % (name, ' '.join(
+                members +
+                ['(%s, %s, %s)' % (host, user, domain)
+                 for host, user, domain in tripples]
+            ))
+
+
+def getent_networks(database, key=None):
+    db_af = _get_af(database)
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_NETWORK_ALL)
+    else:
+        ipv4_addr = _get_ipv4(key)
+        ipv6_addr = _get_ipv6(key)
+        if ipv4_addr and db_af in (socket.AF_INET, None):
+            con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYADDR)
+            con.write_address(socket.AF_INET, ipv4_addr)
+        elif ipv6_addr and db_af in (socket.AF_INET, None):
+            con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYADDR)
+            con.write_address(socket.AF_INET6, ipv6_addr)
+        else:
+            con = NslcdClient(constants.NSLCD_ACTION_NETWORK_BYNAME)
+            con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        names = ' '.join([con.read_string()] + con.read_stringlist())
+        for af, address in con.read_addresslist():
+            if db_af in (af, None):
+                print '%-15s %s' % (address, names)
+
+
+def getent_passwd(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_PASSWD_ALL)
+    elif re.match('^\d+$', key):
+        con = NslcdClient(constants.NSLCD_ACTION_PASSWD_BYUID)
+        con.write_int32(int(key))
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_PASSWD_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        print '%s:%s:%d:%d:%s:%s:%s' % (
+                con.read_string(),
+                con.read_string(),
+                con.read_int32(),
+                con.read_int32(),
+                con.read_string(),
+                con.read_string(),
+                con.read_string(),
+            )
+
+
+def getent_protocols(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_PROTOCOL_ALL)
+    elif re.match('^\d+$', key):
+        con = NslcdClient(constants.NSLCD_ACTION_PROTOCOL_BYNUMBER)
+        con.write_int32(int(key))
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_PROTOCOL_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        name = con.read_string()
+        aliases = con.read_stringlist()
+        number = con.read_int32()
+        print '%-21s %d %s' % (name, number, ' '.join(aliases))
+
+
+def getent_rpc(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_RPC_ALL)
+    elif re.match('^\d+$', key):
+        con = NslcdClient(constants.NSLCD_ACTION_RPC_BYNUMBER)
+        con.write_int32(int(key))
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_RPC_BYNAME)
+        con.write_string(key)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        name = con.read_string()
+        aliases = con.read_stringlist()
+        number = con.read_int32()
+        print '%-15s %d  %s' % (name, number, ' '.join(aliases))
+
+
+def getent_services(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_SERVICE_ALL)
+    else:
+        value = key
+        protocol = ''
+        if '/' in value:
+            value, protocol = value.split('/', 1)
+        if re.match('^\d+$', value):
+            con = NslcdClient(constants.NSLCD_ACTION_SERVICE_BYNUMBER)
+            con.write_int32(int(value))
+            con.write_string(protocol)
+        else:
+            con = NslcdClient(constants.NSLCD_ACTION_SERVICE_BYNAME)
+            con.write_string(value)
+            con.write_string(protocol)
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        name = con.read_string()
+        aliases = con.read_stringlist()
+        number = con.read_int32()
+        protocol = con.read_string()
+        print '%-21s %d/%s %s' % (name, number, protocol, ' '.join(aliases))
+
+
+def getent_shadow(database, key=None):
+    if not key:
+        con = NslcdClient(constants.NSLCD_ACTION_SHADOW_ALL)
+    else:
+        con = NslcdClient(constants.NSLCD_ACTION_SHADOW_BYNAME)
+        con.write_string(key)
+    value2str = lambda x: str(x) if x != -1 else ''
+    while con.get_response() == constants.NSLCD_RESULT_BEGIN:
+        print '%s:%s:%s:%s:%s:%s:%s:%s:%s' % (
+                con.read_string(),
+                con.read_string(),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+                value2str(con.read_int32()),
+            )
+
+
+try:
+    if args.database == 'aliases':
+        getent_aliases(args.database, args.key)
+    elif args.database == 'ethers':
+        getent_ethers(args.database, args.key)
+    elif args.database in ('group', 'group.bymember'):
+        getent_group(args.database, args.key)
+    elif args.database in ('hosts', 'hostsv4', 'hostsv6'):
+        getent_hosts(args.database, args.key)
+    elif args.database in ('netgroup', 'netgroup.norec'):
+        getent_netgroup(args.database, args.key)
+    elif args.database in ('networks', 'networksv4', 'networksv6'):
+        getent_networks(args.database, args.key)
+    elif args.database == 'passwd':
+        getent_passwd(args.database, args.key)
+    elif args.database == 'protocols':
+        getent_protocols(args.database, args.key)
+    elif args.database == 'rpc':
+        getent_rpc(args.database, args.key)
+    elif args.database == 'services':
+        getent_services(args.database, args.key)
+    elif args.database == 'shadow':
+        getent_shadow(args.database, args.key)
+    else:
+        parser.error('Unknown database: %s' % args.database)
+except struct.error:
+    print 'Problem contacting nslcd'
+    sys.exit(1)
diff --git a/utils/nslcd.py b/utils/nslcd.py
new file mode 100644
index 0000000..06165cc
--- /dev/null
+++ b/utils/nslcd.py
@@ -0,0 +1,113 @@
+# coding: utf-8
+
+# nslcd.py - functions for doing nslcd requests
+#
+# Copyright (C) 2013 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import os
+import socket
+import struct
+import fcntl
+
+import constants
+
+
+# definition for reading and writing INT32 values
+_int32 = struct.Struct('!i')
+
+
+class NslcdClient(object):
+
+    def __init__(self, action):
+        # set up the socket (store in class to avoid closing it)
+        self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        #fcntl.fcntl(sock, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
+        # connect to nslcd
+        self.sock.connect(constants.NSLCD_SOCKET)
+        #self.sock.setblocking(1)
+        self.fp = os.fdopen(self.sock.fileno(), 'r+b', 1024 * 1024)
+        # write a request header with a request code
+        self.action = action
+        self.write_int32(constants.NSLCD_VERSION)
+        self.write_int32(action)
+
+    def write(self, value):
+        self.fp.write(value)
+
+    def write_int32(self, value):
+        self.write(_int32.pack(value))
+
+    def write_string(self, value):
+        self.write_int32(len(value))
+        self.write(value)
+
+    def write_ether(self, value):
+        value = struct.pack('BBBBBB', *(int(x, 16) for x in value.split(':')))
+        self.write(value)
+
+    def write_address(self, af, value):
+        self.write_int32(af)
+        self.write_string(value)
+
+    def read(self, size):
+        return self.fp.read(size)
+
+    def read_int32(self):
+        return _int32.unpack(self.read(_int32.size))[0]
+
+    def read_string(self):
+        len = self.read_int32()
+        return self.read(len)
+
+    def read_stringlist(self):
+        len = self.read_int32()
+        return [self.read_string() for x in xrange(len)]
+
+    def read_ether(self):
+        value = self.fp.read(6)
+        return ':'.join('%x' % x for x in struct.unpack('6B', value))
+
+    def read_address(self):
+        af = self.read_int32()
+        return af, socket.inet_ntop(af, self.read_string())
+
+    def read_addresslist(self):
+        len = self.read_int32()
+        return [self.read_address() for x in xrange(len)]
+
+    def get_response(self):
+        # complete the request if required and check response header
+        if self.action:
+            # flush the stream
+            self.fp.flush()
+            # read and check response version number
+            assert self.read_int32() == constants.NSLCD_VERSION
+            assert self.read_int32() == self.action
+            self.action = None
+        # get the NSLCD_RESULT_* marker and return it
+        return self.read_int32()
+
+    def close(self):
+        if hasattr(self, 'fp'):
+            try:
+                self.fp.close()
+            except IOError:
+                pass
+
+    def __del__(self):
+        self.close()

http://arthurdejong.org/git/test/commit/?id=3117668c15cf88f877a538035875cd0f75ce821c

commit 3117668c15cf88f877a538035875cd0f75ce821c
Author: Arthur de Jong <arthur@arthurdejong.org>
Date:   Sat Jan 26 22:53:02 2013 +0100

    add an --enable-utils option to configure to build command-line utilities

diff --git a/.gitignore b/.gitignore
index 06a9533..e979417 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,6 @@ stamp-*
 /tests/test_pamcmds.log
 /tests/test_set
 /tests/test_tio
+
+# /utils/
+/utils/constants.py
diff --git a/Makefile.am b/Makefile.am
index 2a52417..fe668a1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
 #
 # Copyright (C) 2006 Luke Howard
 # Copyright (C) 2006 West Consulting
-# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Arthur de Jong
+# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arthur de Jong
 #
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -32,12 +32,15 @@ endif
 if ENABLE_PYNSLCD
   SUBDIRS += pynslcd
 endif
+if ENABLE_UTILS
+  SUBDIRS += utils
+endif
 SUBDIRS += man tests
 
 EXTRA_DIST = nslcd.conf nslcd.h $(wildcard ChangeLog-20??) \
              $(wildcard m4/*.m4) HACKING ldapns.schema ldapns.ldif
 
-DISTCHECK_CONFIGURE_FLAGS = --enable-warnings --enable-pynslcd \
+DISTCHECK_CONFIGURE_FLAGS = --enable-warnings --enable-pynslcd --enable-utils \
                             --with-pam-seclib-dir="\$${libdir}/security" \
                             --with-ldap-conf-file="\$${prefix}/nslcd.conf" \
                             CPPFLAGS=$(CPPFLAGS) LDFLAGS=$(LDFLAGS)
diff --git a/configure.ac b/configure.ac
index a25e9a4..483c0ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -126,6 +126,15 @@ AC_ARG_ENABLE(pam,
 AC_MSG_RESULT($enable_pam)
 AM_CONDITIONAL([ENABLE_PAM], [test "x$enable_pam" = "xyes"])
 
+# check whether command-line utilities should be built
+AC_MSG_CHECKING([whether to build the command-line utilities])
+AC_ARG_ENABLE(utils,
+              AS_HELP_STRING([--enable-utils],
+                             [build the the command-line utilities 
[[default=disabled]]]),,
+              [enable_util="no"])
+AC_MSG_RESULT($enable_utils)
+AM_CONDITIONAL([ENABLE_UTILS], [test "x$enable_utils" = "xyes"])
+
 # check whether the nslcd daemon should be built
 AC_MSG_CHECKING([whether to build the nslcd daemon])
 AC_ARG_ENABLE(nslcd,
@@ -762,8 +771,8 @@ then
   AC_SUBST(nslcd_LIBS)
 fi
 
-# pynslcd daemon-specific tests
-if test "x$enable_pynslcd" = "xyes"
+# Python-specific tests
+if test "x$enable_pynslcd" = "xyes" || test "x$enable_utils" = "xyes"
 then
   # check Python interpreter
   AM_PATH_PYTHON(2.5)
@@ -775,7 +784,7 @@ AM_CONDITIONAL([NSS_FLAVOUR_FREEBSD], [test 
"x${with_nss_flavour}" = xfreebsd])
 
 # generate files
 AC_CONFIG_FILES([Makefile compat/Makefile common/Makefile nss/Makefile
-                 pam/Makefile nslcd/Makefile pynslcd/Makefile
+                 pam/Makefile utils/Makefile nslcd/Makefile pynslcd/Makefile
                  man/Makefile tests/Makefile])
 AC_CONFIG_FILES([pynslcd/constants.py], [[
 (
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644
index 0000000..e39d7da
--- /dev/null
+++ b/utils/Makefile.am
@@ -0,0 +1,33 @@
+# Makefile.am - use automake to generate Makefile.in
+#
+# Copyright (C) 2013 Arthur de Jong
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+utilsdir = $(datadir)/nslcdutils
+
+nodist_utils_PYTHON = constants.py
+CLEANFILES = $(nodist_utils_PYTHON)
+
+all-local: $(nodist_utils_PYTHON)
+
+# clean up locally created compiled Python files
+clean-local:
+       rm -f *.pyc *.pyo
+
+# copy constants module
+constants.py: ../pynslcd/constants.py
+       cp ../pynslcd/constants.py .

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                     |    5 +
 Makefile.am                    |    7 +-
 configure.ac                   |   15 ++-
 man/Makefile.am                |    6 +-
 man/getent.ldap.1.xml          |  334 ++++++++++++++++++++++++++++++++++++++
 {pynslcd => utils}/Makefile.am |   29 ++--
 utils/cmdline.py               |   50 ++++++
 utils/getent.py                |  346 ++++++++++++++++++++++++++++++++++++++++
 utils/nslcd.py                 |  113 +++++++++++++
 9 files changed, 885 insertions(+), 20 deletions(-)
 create mode 100644 man/getent.ldap.1.xml
 copy {pynslcd => utils}/Makefile.am (54%)
 create mode 100644 utils/cmdline.py
 create mode 100755 utils/getent.py
 create mode 100644 utils/nslcd.py


hooks/post-receive
-- 
nss-pam-ldapd

-- 
To unsubscribe send an email to
nss-pam-ldapd-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/nss-pam-ldapd-commits/