• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.0.25b/source/python/
1/*
2   Unix SMB/CIFS implementation.
3
4   Python wrapper for winbind client functions.
5
6   Copyright (C) Tim Potter      2002-2003
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#include "py_winbind.h"
24
25/*
26 * Exceptions raised by this module
27 */
28
29PyObject *winbind_error;	/* A winbind call returned WINBINDD_ERROR */
30
31/* Prototypes from common.h */
32
33NSS_STATUS winbindd_request_response(int req_type,
34			    struct winbindd_request *request,
35			    struct winbindd_response *response);
36
37/*
38 * Name <-> SID conversion
39 */
40
41/* Convert a name to a sid */
42
43static PyObject *py_name_to_sid(PyObject *self, PyObject *args)
44
45{
46	struct winbindd_request request;
47	struct winbindd_response response;
48	PyObject *result;
49	char *name, *p;
50	const char *sep;
51
52	if (!PyArg_ParseTuple(args, "s", &name))
53		return NULL;
54
55	ZERO_STRUCT(request);
56	ZERO_STRUCT(response);
57
58	sep = lp_winbind_separator();
59
60	if ((p = strchr(name, sep[0]))) {
61		*p = 0;
62		fstrcpy(request.data.name.dom_name, name);
63		fstrcpy(request.data.name.name, p + 1);
64	} else {
65		fstrcpy(request.data.name.dom_name, lp_workgroup());
66		fstrcpy(request.data.name.name, name);
67	}
68
69	if (winbindd_request_response(WINBINDD_LOOKUPNAME, &request, &response)
70	    != NSS_STATUS_SUCCESS) {
71		PyErr_SetString(winbind_error, "lookup failed");
72		return NULL;
73	}
74
75	result = PyString_FromString(response.data.sid.sid);
76
77	return result;
78}
79
80/* Convert a sid to a name */
81
82static PyObject *py_sid_to_name(PyObject *self, PyObject *args)
83{
84	struct winbindd_request request;
85	struct winbindd_response response;
86	PyObject *result;
87	char *sid, *name;
88
89	if (!PyArg_ParseTuple(args, "s", &sid))
90		return NULL;
91
92	ZERO_STRUCT(request);
93	ZERO_STRUCT(response);
94
95	fstrcpy(request.data.sid, sid);
96
97	if (winbindd_request_response(WINBINDD_LOOKUPSID, &request, &response)
98	    != NSS_STATUS_SUCCESS) {
99		PyErr_SetString(winbind_error, "lookup failed");
100		return NULL;
101	}
102
103	asprintf(&name, "%s%s%s", response.data.name.dom_name,
104		 lp_winbind_separator(), response.data.name.name);
105
106	result = PyString_FromString(name);
107
108	free(name);
109
110	return result;
111}
112
113/*
114 * Enumerate users/groups
115 */
116
117/* Enumerate domain users */
118
119static PyObject *py_enum_domain_users(PyObject *self, PyObject *args)
120{
121	struct winbindd_response response;
122	PyObject *result;
123
124	if (!PyArg_ParseTuple(args, ""))
125		return NULL;
126
127	ZERO_STRUCT(response);
128
129	if (winbindd_request_response(WINBINDD_LIST_USERS, NULL, &response)
130	    != NSS_STATUS_SUCCESS) {
131		PyErr_SetString(winbind_error, "lookup failed");
132		return NULL;
133	}
134
135	result = PyList_New(0);
136
137	if (response.extra_data.data) {
138		const char *extra_data = response.extra_data.data;
139		fstring name;
140
141		while (next_token(&extra_data, name, ",", sizeof(fstring)))
142			PyList_Append(result, PyString_FromString(name));
143	}
144
145	return result;
146}
147
148/* Enumerate domain groups */
149
150static PyObject *py_enum_domain_groups(PyObject *self, PyObject *args)
151{
152	struct winbindd_response response;
153	PyObject *result = NULL;
154
155	if (!PyArg_ParseTuple(args, ""))
156		return NULL;
157
158	ZERO_STRUCT(response);
159
160	if (winbindd_request_response(WINBINDD_LIST_GROUPS, NULL, &response)
161	    != NSS_STATUS_SUCCESS) {
162		PyErr_SetString(winbind_error, "lookup failed");
163		return NULL;
164	}
165
166	result = PyList_New(0);
167
168	if (response.extra_data.data) {
169		const char *extra_data = response.extra_data.data;
170		fstring name;
171
172		while (next_token(&extra_data, name, ",", sizeof(fstring)))
173			PyList_Append(result, PyString_FromString(name));
174	}
175
176	return result;
177}
178
179/*
180 * Miscellaneous domain related
181 */
182
183/* Enumerate domain groups */
184
185static PyObject *py_enum_trust_dom(PyObject *self, PyObject *args)
186{
187	struct winbindd_response response;
188	PyObject *result = NULL;
189
190	if (!PyArg_ParseTuple(args, ""))
191		return NULL;
192
193	ZERO_STRUCT(response);
194
195	if (winbindd_request_response(WINBINDD_LIST_TRUSTDOM, NULL, &response)
196	    != NSS_STATUS_SUCCESS) {
197		PyErr_SetString(winbind_error, "lookup failed");
198		return NULL;
199	}
200
201	result = PyList_New(0);
202
203	if (response.extra_data.data) {
204		const char *extra_data = response.extra_data.data;
205		fstring name;
206
207		while (next_token(&extra_data, name, ",", sizeof(fstring)))
208			PyList_Append(result, PyString_FromString(name));
209	}
210
211	return result;
212}
213
214/* Check machine account password */
215
216static PyObject *py_check_secret(PyObject *self, PyObject *args)
217{
218	struct winbindd_response response;
219
220	if (!PyArg_ParseTuple(args, ""))
221		return NULL;
222
223	ZERO_STRUCT(response);
224
225	if (winbindd_request_response(WINBINDD_CHECK_MACHACC, NULL, &response)
226	    != NSS_STATUS_SUCCESS) {
227		PyErr_SetString(winbind_error, "lookup failed");
228		return NULL;
229	}
230
231	return PyInt_FromLong(response.data.num_entries);
232}
233
234/*
235 * Return a dictionary consisting of all the winbind related smb.conf
236 * parameters.  This is stored in the module object.
237 */
238
239static PyObject *py_config_dict(void)
240{
241	PyObject *result;
242	uid_t ulow, uhi;
243	gid_t glow, ghi;
244
245	if (!(result = PyDict_New()))
246		return NULL;
247
248	/* Various string parameters */
249
250	PyDict_SetItemString(result, "workgroup",
251			     PyString_FromString(lp_workgroup()));
252
253	PyDict_SetItemString(result, "separator",
254			     PyString_FromString(lp_winbind_separator()));
255
256	PyDict_SetItemString(result, "template_homedir",
257			     PyString_FromString(lp_template_homedir()));
258
259	PyDict_SetItemString(result, "template_shell",
260			     PyString_FromString(lp_template_shell()));
261
262	/* idmap uid/gid range */
263
264	if (lp_idmap_uid(&ulow, &uhi)) {
265		PyDict_SetItemString(result, "uid_low", PyInt_FromLong(ulow));
266		PyDict_SetItemString(result, "uid_high", PyInt_FromLong(uhi));
267	}
268
269	if (lp_idmap_gid(&glow, &ghi)) {
270		PyDict_SetItemString(result, "gid_low", PyInt_FromLong(glow));
271		PyDict_SetItemString(result, "gid_high", PyInt_FromLong(ghi));
272	}
273
274	return result;
275}
276
277/*
278 * ID mapping
279 */
280
281/* Convert a uid to a SID */
282
283static PyObject *py_uid_to_sid(PyObject *self, PyObject *args)
284{
285	struct winbindd_request request;
286	struct winbindd_response response;
287	int id;
288
289	if (!PyArg_ParseTuple(args, "i", &id))
290		return NULL;
291
292	ZERO_STRUCT(request);
293	ZERO_STRUCT(response);
294
295	request.data.uid = id;
296
297	if (winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response)
298	    != NSS_STATUS_SUCCESS) {
299		PyErr_SetString(winbind_error, "lookup failed");
300		return NULL;
301	}
302
303	return PyString_FromString(response.data.sid.sid);
304}
305
306/* Convert a gid to a SID */
307
308static PyObject *py_gid_to_sid(PyObject *self, PyObject *args)
309{
310	struct winbindd_request request;
311	struct winbindd_response response;
312	int id;
313
314	if (!PyArg_ParseTuple(args, "i", &id))
315		return NULL;
316
317	ZERO_STRUCT(request);
318	ZERO_STRUCT(response);
319
320	request.data.gid = id;
321
322	if (winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response)
323	    != NSS_STATUS_SUCCESS) {
324		PyErr_SetString(winbind_error, "lookup failed");
325		return NULL;
326	}
327
328	return PyString_FromString(response.data.sid.sid);
329}
330
331/* Convert a sid to a uid */
332
333static PyObject *py_sid_to_uid(PyObject *self, PyObject *args)
334{
335	struct winbindd_request request;
336	struct winbindd_response response;
337	char *sid;
338
339	if (!PyArg_ParseTuple(args, "s", &sid))
340		return NULL;
341
342	ZERO_STRUCT(request);
343	ZERO_STRUCT(response);
344
345	fstrcpy(request.data.sid, sid);
346
347	if (winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response)
348	    != NSS_STATUS_SUCCESS) {
349		PyErr_SetString(winbind_error, "lookup failed");
350		return NULL;
351	}
352
353	return PyInt_FromLong(response.data.uid);
354}
355
356/* Convert a sid to a gid */
357
358static PyObject *py_sid_to_gid(PyObject *self, PyObject *args)
359{
360	struct winbindd_request request;
361	struct winbindd_response response;
362	char *sid;
363
364	if (!PyArg_ParseTuple(args, "s", &sid))
365		return NULL;
366
367	ZERO_STRUCT(request);
368	ZERO_STRUCT(response);
369
370	fstrcpy(request.data.sid, sid);
371
372	if (winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response)
373	    != NSS_STATUS_SUCCESS) {
374		PyErr_SetString(winbind_error, "lookup failed");
375		return NULL;
376	}
377
378	return PyInt_FromLong(response.data.gid);
379}
380
381/*
382 * PAM authentication functions
383 */
384
385/* Plaintext authentication */
386
387static PyObject *py_auth_plaintext(PyObject *self, PyObject *args)
388{
389	struct winbindd_request request;
390	struct winbindd_response response;
391	char *username, *password;
392
393	if (!PyArg_ParseTuple(args, "ss", &username, &password))
394		return NULL;
395
396	ZERO_STRUCT(request);
397	ZERO_STRUCT(response);
398
399	fstrcpy(request.data.auth.user, username);
400	fstrcpy(request.data.auth.pass, password);
401
402	if (winbindd_request_response(WINBINDD_PAM_AUTH, &request, &response)
403	    != NSS_STATUS_SUCCESS) {
404		PyErr_SetString(winbind_error, "lookup failed");
405		return NULL;
406	}
407
408	return PyInt_FromLong(response.data.auth.nt_status);
409}
410
411/* Challenge/response authentication */
412
413static PyObject *py_auth_crap(PyObject *self, PyObject *args, PyObject *kw)
414{
415	static char *kwlist[] =
416		{"username", "password", "use_lm_hash", "use_nt_hash", NULL };
417	struct winbindd_request request;
418	struct winbindd_response response;
419	char *username, *password;
420	int use_lm_hash = 1, use_nt_hash = 1;
421
422	if (!PyArg_ParseTupleAndKeywords(
423		    args, kw, "ss|ii", kwlist, &username, &password,
424		    &use_lm_hash, &use_nt_hash))
425		return NULL;
426
427	ZERO_STRUCT(request);
428	ZERO_STRUCT(response);
429
430	if (push_utf8_fstring(request.data.auth_crap.user, username) == -1) {
431		PyErr_SetString(winbind_error, "unable to create utf8 string");
432		return NULL;
433	}
434
435	generate_random_buffer(request.data.auth_crap.chal, 8);
436
437	if (use_lm_hash) {
438		SMBencrypt((uchar *)password, request.data.auth_crap.chal,
439			   (uchar *)request.data.auth_crap.lm_resp);
440		request.data.auth_crap.lm_resp_len = 24;
441	}
442
443	if (use_nt_hash) {
444		SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
445			     (uchar *)request.data.auth_crap.nt_resp);
446		request.data.auth_crap.nt_resp_len = 24;
447	}
448
449	if (winbindd_request_response(WINBINDD_PAM_AUTH_CRAP, &request, &response)
450	    != NSS_STATUS_SUCCESS) {
451		PyErr_SetString(winbind_error, "lookup failed");
452		return NULL;
453	}
454
455	return PyInt_FromLong(response.data.auth.nt_status);
456}
457
458#if 0				/* Include when auth_smbd merged to HEAD */
459
460/* Challenge/response authentication, with secret */
461
462static PyObject *py_auth_smbd(PyObject *self, PyObject *args, PyObject *kw)
463{
464	static char *kwlist[] =
465		{"username", "password", "use_lm_hash", "use_nt_hash", NULL };
466	struct winbindd_request request;
467	struct winbindd_response response;
468	char *username, *password;
469	int use_lm_hash = 1, use_nt_hash = 1;
470
471	if (!PyArg_ParseTupleAndKeywords(
472		    args, kw, "ss|ii", kwlist, &username, &password,
473		    &use_lm_hash, &use_nt_hash))
474		return NULL;
475
476	ZERO_STRUCT(request);
477	ZERO_STRUCT(response);
478
479	if (push_utf8_fstring(request.data.auth_crap.user, username) == -1) {
480		PyErr_SetString("unable to create utf8 string");
481		return NULL;
482	}
483
484	generate_random_buffer(request.data.smbd_auth_crap.chal, 8);
485
486	if (use_lm_hash) {
487		SMBencrypt((uchar *)password,
488			   request.data.smbd_auth_crap.chal,
489			   (uchar *)request.data.smbd_auth_crap.lm_resp);
490		request.data.smbd_auth_crap.lm_resp_len = 24;
491	}
492
493	if (use_nt_hash) {
494		SMBNTencrypt((uchar *)password,
495			     request.data.smbd_auth_crap.chal,
496			     (uchar *)request.data.smbd_auth_crap.nt_resp);
497		request.data.smbd_auth_crap.nt_resp_len = 24;
498	}
499
500	if (!secrets_fetch_trust_account_password(
501		    lp_workgroup(), request.data.smbd_auth_crap.proof, NULL)) {
502		PyErr_SetString(
503			winbind_error, "unable to fetch domain secret");
504		return NULL;
505	}
506
507
508
509	if (winbindd_request_response(WINBINDD_SMBD_AUTH_CRAP, &request, &response)
510	    != NSS_STATUS_SUCCESS) {
511		PyErr_SetString(winbind_error, "lookup failed");
512		return NULL;
513	}
514
515	return PyInt_FromLong(response.data.auth.nt_status);
516}
517
518#endif /* 0 */
519
520/* Get user info from name */
521
522static PyObject *py_getpwnam(PyObject *self, PyObject *args)
523{
524	struct winbindd_request request;
525	struct winbindd_response response;
526	char *username;
527	PyObject *result;
528
529	if (!PyArg_ParseTuple(args, "s", &username))
530		return NULL;
531
532	ZERO_STRUCT(request);
533	ZERO_STRUCT(response);
534
535	fstrcpy(request.data.username, username);
536
537	if (winbindd_request_response(WINBINDD_GETPWNAM, &request, &response)
538	    != NSS_STATUS_SUCCESS) {
539		PyErr_SetString(winbind_error, "lookup failed");
540		return NULL;
541	}
542
543	if (!py_from_winbind_passwd(&result, &response)) {
544		result = Py_None;
545		Py_INCREF(result);
546	}
547
548	return result;
549}
550
551/* Get user info from uid */
552
553static PyObject *py_getpwuid(PyObject *self, PyObject *args)
554{
555	struct winbindd_request request;
556	struct winbindd_response response;
557	uid_t uid;
558	PyObject *result;
559
560	if (!PyArg_ParseTuple(args, "i", &uid))
561		return NULL;
562
563	ZERO_STRUCT(request);
564	ZERO_STRUCT(response);
565
566	request.data.uid = uid;
567
568	if (winbindd_request_response(WINBINDD_GETPWUID, &request, &response)
569	    != NSS_STATUS_SUCCESS) {
570		PyErr_SetString(winbind_error, "lookup failed");
571		return NULL;
572	}
573
574	if (!py_from_winbind_passwd(&result, &response)) {
575		result = Py_None;
576		Py_INCREF(result);
577	}
578
579	return result;
580}
581
582/*
583 * Method dispatch table
584 */
585
586static PyMethodDef winbind_methods[] = {
587
588	{ "getpwnam", (PyCFunction)py_getpwnam, METH_VARARGS, "getpwnam(3)" },
589	{ "getpwuid", (PyCFunction)py_getpwuid, METH_VARARGS, "getpwuid(3)" },
590
591	/* Name <-> SID conversion */
592
593	{ "name_to_sid", (PyCFunction)py_name_to_sid, METH_VARARGS,
594	  "name_to_sid(s) -> string\n"
595"\n"
596"Return the SID for a name.\n"
597"\n"
598"Example:\n"
599"\n"
600">>> winbind.name_to_sid('FOO/Administrator')\n"
601"'S-1-5-21-406022937-1377575209-526660263-500' " },
602
603	{ "sid_to_name", (PyCFunction)py_sid_to_name, METH_VARARGS,
604	  "sid_to_name(s) -> string\n"
605"\n"
606"Return the name for a SID.\n"
607"\n"
608"Example:\n"
609"\n"
610">>> import winbind\n"
611">>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')\n"
612"'FOO/Administrator' " },
613
614	/* Enumerate users/groups */
615
616	{ "enum_domain_users", (PyCFunction)py_enum_domain_users, METH_VARARGS,
617	  "enum_domain_users() -> list of strings\n"
618"\n"
619"Return a list of domain users.\n"
620"\n"
621"Example:\n"
622"\n"
623">>> winbind.enum_domain_users()\n"
624"['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build', \n"
625"'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1', \n"
626"'FOO/whoops-ptang'] " },
627
628	{ "enum_domain_groups", (PyCFunction)py_enum_domain_groups,
629	  METH_VARARGS,
630	  "enum_domain_groups() -> list of strings\n"
631"\n"
632"Return a list of domain groups.\n"
633"\n"
634"Example:\n"
635"\n"
636">>> winbind.enum_domain_groups()\n"
637"['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests', \n"
638"'FOO/Domain Users'] " },
639
640	/* ID mapping */
641
642	{ "uid_to_sid", (PyCFunction)py_uid_to_sid, METH_VARARGS,
643	  "uid_to_sid(int) -> string\n"
644"\n"
645"Return the SID for a UNIX uid.\n"
646"\n"
647"Example:\n"
648"\n"
649">>> winbind.uid_to_sid(10000)   \n"
650"'S-1-5-21-406022937-1377575209-526660263-500' " },
651
652	{ "gid_to_sid", (PyCFunction)py_gid_to_sid, METH_VARARGS,
653	  "gid_to_sid(int) -> string\n"
654"\n"
655"Return the UNIX gid for a SID.\n"
656"\n"
657"Example:\n"
658"\n"
659">>> winbind.gid_to_sid(10001)\n"
660"'S-1-5-21-406022937-1377575209-526660263-512' " },
661
662	{ "sid_to_uid", (PyCFunction)py_sid_to_uid, METH_VARARGS,
663	  "sid_to_uid(string) -> int\n"
664"\n"
665"Return the UNIX uid for a SID.\n"
666"\n"
667"Example:\n"
668"\n"
669">>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')\n"
670"10000 " },
671
672	{ "sid_to_gid", (PyCFunction)py_sid_to_gid, METH_VARARGS,
673	  "sid_to_gid(string) -> int\n"
674"\n"
675"Return the UNIX gid corresponding to a SID.\n"
676"\n"
677"Example:\n"
678"\n"
679">>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')\n"
680"10001 " },
681
682	/* Miscellaneous */
683
684	{ "check_secret", (PyCFunction)py_check_secret, METH_VARARGS,
685	  "check_secret() -> int\n"
686"\n"
687"Check the machine trust account password.  The NT status is returned\n"
688"with zero indicating success. " },
689
690	{ "enum_trust_dom", (PyCFunction)py_enum_trust_dom, METH_VARARGS,
691	  "enum_trust_dom() -> list of strings\n"
692"\n"
693"Return a list of trusted domains.  The domain the server is a member \n"
694"of is not included.\n"
695"\n"
696"Example:\n"
697"\n"
698">>> winbind.enum_trust_dom()\n"
699"['NPSD-TEST2', 'SP2NDOM'] " },
700
701	/* PAM authorisation functions */
702
703	{ "auth_plaintext", (PyCFunction)py_auth_plaintext, METH_VARARGS,
704	  "auth_plaintext(s, s) -> int\n"
705"\n"
706"Authenticate a username and password using plaintext authentication.\n"
707"The NT status code is returned with zero indicating success." },
708
709	{ "auth_crap", (PyCFunction)py_auth_crap, METH_VARARGS | METH_KEYWORDS,
710	  "auth_crap(s, s) -> int\n"
711"\n"
712"Authenticate a username and password using the challenge/response\n"
713"protocol.  The NT status code is returned with zero indicating\n"
714"success." },
715
716#if 0				/* Include when smbd_auth merged to HEAD */
717
718	{ "auth_smbd", (PyCFunction)py_auth_crap, METH_VARARGS,
719	  "auth_smbd(s, s) -> int\n"
720"\n"
721"Authenticate a username and password using the challenge/response\n"
722"protocol but using the domain secret to prove we are root.  The NT \n"
723"status code is returned with zero indicating success." },
724
725#endif
726
727	{ NULL }
728};
729
730static struct const_vals {
731	char *name;
732	uint32 value;
733	char *docstring;
734} module_const_vals[] = {
735
736	/* Well known RIDs */
737
738	{ "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN,
739	  "Well-known RID for Administrator user" },
740
741	{ "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
742	  "Well-known RID for Guest user" },
743
744	{ "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
745	  "Well-known RID for Domain Admins group" },
746
747	{ "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
748	  "Well-known RID for Domain Users group" },
749
750	{ "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
751	  "Well-known RID for Domain Guests group" },
752
753	{ NULL }
754};
755
756static void const_init(PyObject *dict)
757{
758	struct const_vals *tmp;
759	PyObject *obj;
760
761	for (tmp = module_const_vals; tmp->name; tmp++) {
762		obj = PyInt_FromLong(tmp->value);
763		PyDict_SetItemString(dict, tmp->name, obj);
764		Py_DECREF(obj);
765	}
766}
767
768/*
769 * Module initialisation
770 */
771
772static char winbind_module__doc__[] =
773"A python extension to winbind client functions.";
774
775void initwinbind(void)
776{
777	PyObject *module, *dict;
778
779	/* Initialise module */
780
781        module = Py_InitModule3("winbind", winbind_methods,
782				winbind_module__doc__);
783
784	dict = PyModule_GetDict(module);
785
786	winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
787	PyDict_SetItemString(dict, "error", winbind_error);
788
789	/* Do samba initialisation */
790
791	py_samba_init();
792
793	/* Initialise constants */
794
795	const_init(dict);
796
797	/* Insert configuration dictionary */
798
799	PyDict_SetItemString(dict, "config", py_config_dict());
800}
801