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