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