r25598: Add missing become_root/unbecome_root around calls of add_aliases.
[samba.git] / source / python / py_winbind.c
index 5b0d3306ec3213761d4a105c620e415596482611..7d3a9cdf087dea9c85d7b346616810c9f386dd44 100644 (file)
@@ -3,11 +3,11 @@
 
    Python wrapper for winbind client functions.
 
-   Copyright (C) Tim Potter      2002
+   Copyright (C) Tim Potter      2002-2003
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-#include "includes.h"
-#include "Python.h"
+#include "py_winbind.h"
 
 /* 
  * Exceptions raised by this module 
@@ -31,7 +29,7 @@ PyObject *winbind_error;      /* A winbind call returned WINBINDD_ERROR */
 
 /* Prototypes from common.h */
 
-NSS_STATUS winbindd_request(int req_type, 
+NSS_STATUS winbindd_request_response(int req_type, 
                            struct winbindd_request *request,
                            struct winbindd_response *response);
 
@@ -41,13 +39,14 @@ NSS_STATUS winbindd_request(int req_type,
 
 /* Convert a name to a sid */
 
-static PyObject *winbind_name_to_sid(PyObject *self, PyObject *args)
+static PyObject *py_name_to_sid(PyObject *self, PyObject *args)
 
 {
        struct winbindd_request request;
        struct winbindd_response response;
        PyObject *result;
        char *name, *p;
+       const char *sep;
 
        if (!PyArg_ParseTuple(args, "s", &name))
                return NULL;
@@ -55,9 +54,9 @@ static PyObject *winbind_name_to_sid(PyObject *self, PyObject *args)
        ZERO_STRUCT(request);
        ZERO_STRUCT(response);
 
-       /* FIXME: use winbind separator */
+       sep = lp_winbind_separator();
 
-       if ((p = strchr(name, '\\'))) {
+       if ((p = strchr(name, sep[0]))) {
                *p = 0;
                fstrcpy(request.data.name.dom_name, name);
                fstrcpy(request.data.name.name, p + 1);
@@ -66,7 +65,7 @@ static PyObject *winbind_name_to_sid(PyObject *self, PyObject *args)
                fstrcpy(request.data.name.name, name);
        }
 
-       if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response)  
+       if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response)  
            != NSS_STATUS_SUCCESS) {
                PyErr_SetString(winbind_error, "lookup failed");
                return NULL;
@@ -79,7 +78,7 @@ static PyObject *winbind_name_to_sid(PyObject *self, PyObject *args)
 
 /* Convert a sid to a name */
 
-static PyObject *winbind_sid_to_name(PyObject *self, PyObject *args)
+static PyObject *py_sid_to_name(PyObject *self, PyObject *args)
 {
        struct winbindd_request request;
        struct winbindd_response response;
@@ -94,16 +93,14 @@ static PyObject *winbind_sid_to_name(PyObject *self, PyObject *args)
 
        fstrcpy(request.data.sid, sid);
 
-       if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response)  
+       if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response)  
            != NSS_STATUS_SUCCESS) {
                PyErr_SetString(winbind_error, "lookup failed");
                return NULL;
        }
 
-       /* FIXME: use actual winbind separator */
-
-       asprintf(&name, "%s%c%s", response.data.name.dom_name,
-                '\\', response.data.name.name);
+       asprintf(&name, "%s%s%s", response.data.name.dom_name,
+                lp_winbind_separator(), response.data.name.name);
 
        result = PyString_FromString(name);
 
@@ -118,7 +115,7 @@ static PyObject *winbind_sid_to_name(PyObject *self, PyObject *args)
 
 /* Enumerate domain users */
 
-static PyObject *winbind_enum_domain_users(PyObject *self, PyObject *args)
+static PyObject *py_enum_domain_users(PyObject *self, PyObject *args)
 {
        struct winbindd_response response;
        PyObject *result;
@@ -128,7 +125,7 @@ static PyObject *winbind_enum_domain_users(PyObject *self, PyObject *args)
 
        ZERO_STRUCT(response);
 
-       if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response) 
+       if (winbindd_request_response(WINBINDD_LIST_USERS, NULL, &response) 
            != NSS_STATUS_SUCCESS) {
                PyErr_SetString(winbind_error, "lookup failed");
                return NULL;            
@@ -136,8 +133,8 @@ static PyObject *winbind_enum_domain_users(PyObject *self, PyObject *args)
 
        result = PyList_New(0);
 
-       if (response.extra_data) {
-               char *extra_data = response.extra_data;
+       if (response.extra_data.data) {
+               const char *extra_data = response.extra_data.data;
                fstring name;
 
                while (next_token(&extra_data, name, ",", sizeof(fstring)))
@@ -149,9 +146,43 @@ static PyObject *winbind_enum_domain_users(PyObject *self, PyObject *args)
 
 /* Enumerate domain groups */
 
-static PyObject *winbind_enum_domain_groups(PyObject *self, PyObject *args)
+static PyObject *py_enum_domain_groups(PyObject *self, PyObject *args)
+{
+       struct winbindd_response response;
+       PyObject *result = NULL;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+
+       ZERO_STRUCT(response);
+
+       if (winbindd_request_response(WINBINDD_LIST_GROUPS, NULL, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+
+       result = PyList_New(0);
+
+       if (response.extra_data.data) {
+               const char *extra_data = response.extra_data.data;
+               fstring name;
+
+               while (next_token(&extra_data, name, ",", sizeof(fstring)))
+                       PyList_Append(result, PyString_FromString(name));
+       }
+
+       return result;
+}
+
+/*
+ * Miscellaneous domain related
+ */
+
+/* Enumerate domain groups */
+
+static PyObject *py_enum_trust_dom(PyObject *self, PyObject *args)
 {
-       struct winbindd_request request;
        struct winbindd_response response;
        PyObject *result = NULL;
 
@@ -160,7 +191,7 @@ static PyObject *winbind_enum_domain_groups(PyObject *self, PyObject *args)
 
        ZERO_STRUCT(response);
 
-       if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response) 
+       if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, NULL, &response) 
            != NSS_STATUS_SUCCESS) {
                PyErr_SetString(winbind_error, "lookup failed");
                return NULL;            
@@ -168,8 +199,8 @@ static PyObject *winbind_enum_domain_groups(PyObject *self, PyObject *args)
 
        result = PyList_New(0);
 
-       if (response.extra_data) {
-               char *extra_data = response.extra_data;
+       if (response.extra_data.data) {
+               const char *extra_data = response.extra_data.data;
                fstring name;
 
                while (next_token(&extra_data, name, ",", sizeof(fstring)))
@@ -179,46 +210,590 @@ static PyObject *winbind_enum_domain_groups(PyObject *self, PyObject *args)
        return result;
 }
 
+/* Check machine account password */
+
+static PyObject *py_check_secret(PyObject *self, PyObject *args)
+{
+       struct winbindd_response response;
+
+       if (!PyArg_ParseTuple(args, ""))
+               return NULL;
+
+       ZERO_STRUCT(response);
+
+       if (winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+
+       return PyInt_FromLong(response.data.num_entries);
+}
+
+/*
+ * Return a dictionary consisting of all the winbind related smb.conf
+ * parameters.  This is stored in the module object.
+ */
+
+static PyObject *py_config_dict(void)
+{
+       PyObject *result;
+       uid_t ulow, uhi;
+       gid_t glow, ghi;
+       
+       if (!(result = PyDict_New()))
+               return NULL;
+
+       /* Various string parameters */
+
+       PyDict_SetItemString(result, "workgroup", 
+                            PyString_FromString(lp_workgroup()));
+
+       PyDict_SetItemString(result, "separator", 
+                            PyString_FromString(lp_winbind_separator()));
+
+       PyDict_SetItemString(result, "template_homedir", 
+                            PyString_FromString(lp_template_homedir()));
+
+       PyDict_SetItemString(result, "template_shell", 
+                            PyString_FromString(lp_template_shell()));
+
+       /* idmap uid/gid range */
+
+       if (lp_idmap_uid(&ulow, &uhi)) {
+               PyDict_SetItemString(result, "uid_low", PyInt_FromLong(ulow));
+               PyDict_SetItemString(result, "uid_high", PyInt_FromLong(uhi));
+       }
+
+       if (lp_idmap_gid(&glow, &ghi)) {
+               PyDict_SetItemString(result, "gid_low", PyInt_FromLong(glow));
+               PyDict_SetItemString(result, "gid_high", PyInt_FromLong(ghi));
+       }
+
+       return result;
+}
+
+/*
+ * ID mapping
+ */
+
+/* Convert a uid to a SID */
+
+static PyObject *py_uid_to_sid(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int id;
+
+       if (!PyArg_ParseTuple(args, "i", &id))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       request.data.uid = id;
+
+       if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+
+       return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a gid to a SID */
+
+static PyObject *py_gid_to_sid(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       int id;
+
+       if (!PyArg_ParseTuple(args, "i", &id))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       request.data.gid = id;
+
+       if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+
+       return PyString_FromString(response.data.sid.sid);
+}
+
+/* Convert a sid to a uid */
+
+static PyObject *py_sid_to_uid(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *sid;
+
+       if (!PyArg_ParseTuple(args, "s", &sid))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.sid, sid);
+
+       if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+
+       return PyInt_FromLong(response.data.uid);
+}
+
+/* Convert a sid to a gid */
+
+static PyObject *py_sid_to_gid(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *sid;
+
+       if (!PyArg_ParseTuple(args, "s", &sid))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.sid, sid);
+
+       if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       return PyInt_FromLong(response.data.gid);
+}
+
+/*
+ * PAM authentication functions
+ */
+
+/* Plaintext authentication */
+
+static PyObject *py_auth_plaintext(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *username, *password;
+
+       if (!PyArg_ParseTuple(args, "ss", &username, &password))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.auth.user, username);
+       fstrcpy(request.data.auth.pass, password);
+
+       if (winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+/* Challenge/response authentication */
+
+static PyObject *py_auth_crap(PyObject *self, PyObject *args, PyObject *kw)
+{
+       static char *kwlist[] = 
+               {"username", "password", "use_lm_hash", "use_nt_hash", NULL };
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *username, *password;
+       int use_lm_hash = 1, use_nt_hash = 1;
+
+       if (!PyArg_ParseTupleAndKeywords(
+                   args, kw, "ss|ii", kwlist, &username, &password, 
+                   &use_lm_hash, &use_nt_hash))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if (push_utf8_fstring(request.data.auth_crap.user, username) == -1) {
+               PyErr_SetString(winbind_error, "unable to create utf8 string");
+               return NULL;
+       }
+
+       generate_random_buffer(request.data.auth_crap.chal, 8);
+        
+       if (use_lm_hash) {
+               SMBencrypt((uchar *)password, request.data.auth_crap.chal, 
+                          (uchar *)request.data.auth_crap.lm_resp);
+               request.data.auth_crap.lm_resp_len = 24;
+       }
+
+       if (use_nt_hash) {
+               SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
+                            (uchar *)request.data.auth_crap.nt_resp);
+               request.data.auth_crap.nt_resp_len = 24;
+       }
+
+       if (winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+#if 0                          /* Include when auth_smbd merged to HEAD */
+
+/* Challenge/response authentication, with secret */
+
+static PyObject *py_auth_smbd(PyObject *self, PyObject *args, PyObject *kw)
+{
+       static char *kwlist[] = 
+               {"username", "password", "use_lm_hash", "use_nt_hash", NULL };
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *username, *password;
+       int use_lm_hash = 1, use_nt_hash = 1;
+
+       if (!PyArg_ParseTupleAndKeywords(
+                   args, kw, "ss|ii", kwlist, &username, &password, 
+                   &use_lm_hash, &use_nt_hash))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       if (push_utf8_fstring(request.data.auth_crap.user, username) == -1) {
+               PyErr_SetString("unable to create utf8 string");
+               return NULL;
+       }
+
+       generate_random_buffer(request.data.smbd_auth_crap.chal, 8);
+        
+       if (use_lm_hash) {
+               SMBencrypt((uchar *)password, 
+                          request.data.smbd_auth_crap.chal, 
+                          (uchar *)request.data.smbd_auth_crap.lm_resp);
+               request.data.smbd_auth_crap.lm_resp_len = 24;
+       }
+
+       if (use_nt_hash) {
+               SMBNTencrypt((uchar *)password, 
+                            request.data.smbd_auth_crap.chal,
+                            (uchar *)request.data.smbd_auth_crap.nt_resp);
+               request.data.smbd_auth_crap.nt_resp_len = 24;
+       }
+
+       if (!secrets_fetch_trust_account_password(
+                   lp_workgroup(), request.data.smbd_auth_crap.proof, NULL)) {
+               PyErr_SetString(
+                       winbind_error, "unable to fetch domain secret");
+               return NULL;
+       }
+
+
+
+       if (winbindd_request_response(WINBINDD_SMBD_AUTH_CRAP, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       return PyInt_FromLong(response.data.auth.nt_status);
+}
+
+#endif /* 0 */
+
+/* Get user info from name */
+
+static PyObject *py_getpwnam(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       char *username;
+       PyObject *result;
+
+       if (!PyArg_ParseTuple(args, "s", &username))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       fstrcpy(request.data.username, username);
+
+       if (winbindd_request_response(WINBINDD_GETPWNAM, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       if (!py_from_winbind_passwd(&result, &response)) {
+               result = Py_None;
+               Py_INCREF(result);
+       }
+
+       return result;
+}
+
+/* Get user info from uid */
+
+static PyObject *py_getpwuid(PyObject *self, PyObject *args)
+{
+       struct winbindd_request request;
+       struct winbindd_response response;
+       uid_t uid;
+       PyObject *result;
+
+       if (!PyArg_ParseTuple(args, "i", &uid))
+               return NULL;
+
+       ZERO_STRUCT(request);
+       ZERO_STRUCT(response);
+
+       request.data.uid = uid;
+
+       if (winbindd_request_response(WINBINDD_GETPWUID, &request, &response) 
+           != NSS_STATUS_SUCCESS) {
+               PyErr_SetString(winbind_error, "lookup failed");
+               return NULL;            
+       }
+       
+       if (!py_from_winbind_passwd(&result, &response)) {
+               result = Py_None;
+               Py_INCREF(result);
+       }
+
+       return result;
+}
+
 /*
  * Method dispatch table
  */
 
 static PyMethodDef winbind_methods[] = {
 
-       /* Name <-> SID conversion */
+       { "getpwnam", (PyCFunction)py_getpwnam, METH_VARARGS, "getpwnam(3)" },
+       { "getpwuid", (PyCFunction)py_getpwuid, METH_VARARGS, "getpwuid(3)" },
 
-       { "name_to_sid", winbind_name_to_sid, METH_VARARGS,
-         "Convert a name to a sid" },
+       /* Name <-> SID conversion */
 
-       { "sid_to_name", winbind_sid_to_name, METH_VARARGS,
-         "Convert a sid to a name" },
+       { "name_to_sid", (PyCFunction)py_name_to_sid, METH_VARARGS,
+         "name_to_sid(s) -> string\n"
+"\n"
+"Return the SID for a name.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.name_to_sid('FOO/Administrator')\n"
+"'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+       { "sid_to_name", (PyCFunction)py_sid_to_name, METH_VARARGS,
+         "sid_to_name(s) -> string\n"
+"\n"
+"Return the name for a SID.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> import winbind\n"
+">>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')\n"
+"'FOO/Administrator' " },
 
        /* Enumerate users/groups */
 
-       { "enum_domain_users", winbind_enum_domain_users, METH_VARARGS,
-         "Enumerate domain users" },
+       { "enum_domain_users", (PyCFunction)py_enum_domain_users, METH_VARARGS,
+         "enum_domain_users() -> list of strings\n"
+"\n"
+"Return a list of domain users.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.enum_domain_users()\n"
+"['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build', \n"
+"'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1', \n"
+"'FOO/whoops-ptang'] " },
+
+       { "enum_domain_groups", (PyCFunction)py_enum_domain_groups, 
+         METH_VARARGS,
+         "enum_domain_groups() -> list of strings\n"
+"\n"
+"Return a list of domain groups.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.enum_domain_groups()\n"
+"['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests', \n"
+"'FOO/Domain Users'] " },
+
+       /* ID mapping */
+
+       { "uid_to_sid", (PyCFunction)py_uid_to_sid, METH_VARARGS,
+         "uid_to_sid(int) -> string\n"
+"\n"
+"Return the SID for a UNIX uid.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.uid_to_sid(10000)   \n"
+"'S-1-5-21-406022937-1377575209-526660263-500' " },
+
+       { "gid_to_sid", (PyCFunction)py_gid_to_sid, METH_VARARGS,
+         "gid_to_sid(int) -> string\n"
+"\n"
+"Return the UNIX gid for a SID.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.gid_to_sid(10001)\n"
+"'S-1-5-21-406022937-1377575209-526660263-512' " },
+
+       { "sid_to_uid", (PyCFunction)py_sid_to_uid, METH_VARARGS,
+         "sid_to_uid(string) -> int\n"
+"\n"
+"Return the UNIX uid for a SID.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')\n"
+"10000 " },
+
+       { "sid_to_gid", (PyCFunction)py_sid_to_gid, METH_VARARGS,
+         "sid_to_gid(string) -> int\n"
+"\n"
+"Return the UNIX gid corresponding to a SID.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')\n"
+"10001 " },
+
+       /* Miscellaneous */
+
+       { "check_secret", (PyCFunction)py_check_secret, METH_VARARGS,
+         "check_secret() -> int\n"
+"\n"
+"Check the machine trust account password.  The NT status is returned\n"
+"with zero indicating success. " },
+
+       { "enum_trust_dom", (PyCFunction)py_enum_trust_dom, METH_VARARGS,
+         "enum_trust_dom() -> list of strings\n"
+"\n"
+"Return a list of trusted domains.  The domain the server is a member \n"
+"of is not included.\n"
+"\n"
+"Example:\n"
+"\n"
+">>> winbind.enum_trust_dom()\n"
+"['NPSD-TEST2', 'SP2NDOM'] " },
+
+       /* PAM authorisation functions */
+
+       { "auth_plaintext", (PyCFunction)py_auth_plaintext, METH_VARARGS,
+         "auth_plaintext(s, s) -> int\n"
+"\n"
+"Authenticate a username and password using plaintext authentication.\n"
+"The NT status code is returned with zero indicating success." },
+
+       { "auth_crap", (PyCFunction)py_auth_crap, METH_VARARGS | METH_KEYWORDS,
+         "auth_crap(s, s) -> int\n"
+"\n"
+"Authenticate a username and password using the challenge/response\n"
+"protocol.  The NT status code is returned with zero indicating\n"
+"success." },
+
+#if 0                          /* Include when smbd_auth merged to HEAD */
+
+       { "auth_smbd", (PyCFunction)py_auth_crap, METH_VARARGS,
+         "auth_smbd(s, s) -> int\n"
+"\n"
+"Authenticate a username and password using the challenge/response\n"
+"protocol but using the domain secret to prove we are root.  The NT \n"
+"status code is returned with zero indicating success." },
+
+#endif
 
-       { "enum_domain_groups", winbind_enum_domain_groups, METH_VARARGS,
-         "Enumerate domain groups" },
+       { NULL }
+};
 
+static struct const_vals {
+       char *name;
+       uint32 value;
+       char *docstring;
+} module_const_vals[] = {
+
+       /* Well known RIDs */
+       
+       { "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN, 
+         "Well-known RID for Administrator user" },
+
+       { "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
+         "Well-known RID for Guest user" },
+
+       { "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
+         "Well-known RID for Domain Admins group" },
+
+       { "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
+         "Well-known RID for Domain Users group" },
+
+       { "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
+         "Well-known RID for Domain Guests group" }, 
+       
        { NULL }
 };
 
+static void const_init(PyObject *dict)
+{
+       struct const_vals *tmp;
+       PyObject *obj;
+
+       for (tmp = module_const_vals; tmp->name; tmp++) {
+               obj = PyInt_FromLong(tmp->value);
+               PyDict_SetItemString(dict, tmp->name, obj);
+               Py_DECREF(obj);
+       }
+}
+
 /*
  * Module initialisation 
  */
 
+static char winbind_module__doc__[] =
+"A python extension to winbind client functions.";
+
 void initwinbind(void)
 {
        PyObject *module, *dict;
 
        /* Initialise module */
 
-       module = Py_InitModule("winbind", winbind_methods);
+        module = Py_InitModule3("winbind", winbind_methods,
+                               winbind_module__doc__);
+
        dict = PyModule_GetDict(module);
 
        winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
        PyDict_SetItemString(dict, "error", winbind_error);
 
+       /* Do samba initialisation */
+
        py_samba_init();
+
+       /* Initialise constants */
+
+       const_init(dict);
+
+       /* Insert configuration dictionary */
+
+       PyDict_SetItemString(dict, "config", py_config_dict());
 }