Tims' little fix.
[tprouty/samba.git] / source / 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 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
29 PyObject *winbind_error;        /* A winbind call returned WINBINDD_ERROR */
30
31 /* Prototypes from common.h */
32
33 NSS_STATUS winbindd_request(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
43 static 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(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
82 static 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(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
119 static 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(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) {
138                 const char *extra_data = response.extra_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
150 static 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(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) {
169                 const char *extra_data = response.extra_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
185 static 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(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) {
204                 const char *extra_data = response.extra_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
216 static 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(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
239 static 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
283 static 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(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
308 static 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(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
333 static 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(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
358 static 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(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
387 static 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(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
413 static 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, False);
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(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
462 static 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, False);
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(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
522 static 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(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
553 static 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(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
586 static 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,
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
730 static 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
756 static 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
772 static char winbind_module__doc__[] =
773 "A python extension to winbind client functions.";
774
775 void 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 }