This commit was generated by cvs2svn to compensate for changes in r30,
[samba.git] / source4 / 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
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         /* Winbind uid/gid range */
263
264         if (lp_winbind_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_winbind_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         fstrcpy(request.data.auth_crap.user, username);
431
432         generate_random_buffer(request.data.auth_crap.chal, 8, False);
433         
434         if (use_lm_hash) {
435                 SMBencrypt((uchar *)password, request.data.auth_crap.chal, 
436                            (uchar *)request.data.auth_crap.lm_resp);
437                 request.data.auth_crap.lm_resp_len = 24;
438         }
439
440         if (use_nt_hash) {
441                 SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
442                              (uchar *)request.data.auth_crap.nt_resp);
443                 request.data.auth_crap.nt_resp_len = 24;
444         }
445
446         if (winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response) 
447             != NSS_STATUS_SUCCESS) {
448                 PyErr_SetString(winbind_error, "lookup failed");
449                 return NULL;            
450         }
451         
452         return PyInt_FromLong(response.data.auth.nt_status);
453 }
454
455 /* Get user info from name */
456
457 static PyObject *py_getpwnam(PyObject *self, PyObject *args)
458 {
459         struct winbindd_request request;
460         struct winbindd_response response;
461         char *username;
462         PyObject *result;
463
464         if (!PyArg_ParseTuple(args, "s", &username))
465                 return NULL;
466
467         ZERO_STRUCT(request);
468         ZERO_STRUCT(response);
469
470         fstrcpy(request.data.username, username);
471
472         if (winbindd_request(WINBINDD_GETPWNAM, &request, &response) 
473             != NSS_STATUS_SUCCESS) {
474                 PyErr_SetString(winbind_error, "lookup failed");
475                 return NULL;            
476         }
477         
478         if (!py_from_winbind_passwd(&result, &response)) {
479                 result = Py_None;
480                 Py_INCREF(result);
481         }
482
483         return result;
484 }
485
486 /* Get user info from uid */
487
488 static PyObject *py_getpwuid(PyObject *self, PyObject *args)
489 {
490         struct winbindd_request request;
491         struct winbindd_response response;
492         uid_t uid;
493         PyObject *result;
494
495         if (!PyArg_ParseTuple(args, "i", &uid))
496                 return NULL;
497
498         ZERO_STRUCT(request);
499         ZERO_STRUCT(response);
500
501         request.data.uid = uid;
502
503         if (winbindd_request(WINBINDD_GETPWUID, &request, &response) 
504             != NSS_STATUS_SUCCESS) {
505                 PyErr_SetString(winbind_error, "lookup failed");
506                 return NULL;            
507         }
508         
509         if (!py_from_winbind_passwd(&result, &response)) {
510                 result = Py_None;
511                 Py_INCREF(result);
512         }
513
514         return result;
515 }
516
517 /*
518  * Method dispatch table
519  */
520
521 static PyMethodDef winbind_methods[] = {
522
523         { "getpwnam", (PyCFunction)py_getpwnam, METH_VARARGS, "getpwnam(3)" },
524         { "getpwuid", (PyCFunction)py_getpwuid, METH_VARARGS, "getpwuid(3)" },
525
526         /* Name <-> SID conversion */
527
528         { "name_to_sid", (PyCFunction)py_name_to_sid, METH_VARARGS,
529           "name_to_sid(s) -> string
530
531 Return the SID for a name.
532
533 Example:
534
535 >>> winbind.name_to_sid('FOO/Administrator')
536 'S-1-5-21-406022937-1377575209-526660263-500' " },
537
538         { "sid_to_name", (PyCFunction)py_sid_to_name, METH_VARARGS,
539           "sid_to_name(s) -> string
540
541 Return the name for a SID.
542
543 Example:
544
545 >>> import winbind
546 >>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')
547 'FOO/Administrator' " },
548
549         /* Enumerate users/groups */
550
551         { "enum_domain_users", (PyCFunction)py_enum_domain_users, METH_VARARGS,
552           "enum_domain_users() -> list of strings
553
554 Return a list of domain users.
555
556 Example:
557
558 >>> winbind.enum_domain_users()
559 ['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build', 
560 'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1', 
561 'FOO/whoops-ptang'] " },
562
563         { "enum_domain_groups", (PyCFunction)py_enum_domain_groups, 
564           METH_VARARGS,
565           "enum_domain_groups() -> list of strings
566
567 Return a list of domain groups.
568
569 Example:
570
571 >>> winbind.enum_domain_groups()
572 ['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests', 
573 'FOO/Domain Users'] " },
574
575         /* ID mapping */
576
577         { "uid_to_sid", (PyCFunction)py_uid_to_sid, METH_VARARGS,
578           "uid_to_sid(int) -> string
579
580 Return the SID for a UNIX uid.
581
582 Example:
583
584 >>> winbind.uid_to_sid(10000)   
585 'S-1-5-21-406022937-1377575209-526660263-500' " },
586
587         { "gid_to_sid", (PyCFunction)py_gid_to_sid, METH_VARARGS,
588           "gid_to_sid(int) -> string
589
590 Return the UNIX gid for a SID.
591
592 Example:
593
594 >>> winbind.gid_to_sid(10001)
595 'S-1-5-21-406022937-1377575209-526660263-512' " },
596
597         { "sid_to_uid", (PyCFunction)py_sid_to_uid, METH_VARARGS,
598           "sid_to_uid(string) -> int
599
600 Return the UNIX uid for a SID.
601
602 Example:
603
604 >>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')
605 10000 " },
606
607         { "sid_to_gid", (PyCFunction)py_sid_to_gid, METH_VARARGS,
608           "sid_to_gid(string) -> int
609
610 Return the UNIX gid corresponding to a SID.
611
612 Example:
613
614 >>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')
615 10001 " },
616
617         /* Miscellaneous */
618
619         { "check_secret", (PyCFunction)py_check_secret, METH_VARARGS,
620           "check_secret() -> int
621
622 Check the machine trust account password.  The NT status is returned
623 with zero indicating success. " },
624
625         { "enum_trust_dom", (PyCFunction)py_enum_trust_dom, METH_VARARGS,
626           "enum_trust_dom() -> list of strings
627
628 Return a list of trusted domains.  The domain the server is a member 
629 of is not included.
630
631 Example:
632
633 >>> winbind.enum_trust_dom()
634 ['NPSD-TEST2', 'SP2NDOM'] " },
635
636         /* PAM authorisation functions */
637
638         { "auth_plaintext", (PyCFunction)py_auth_plaintext, METH_VARARGS,
639           "auth_plaintext(s, s) -> int
640
641 Authenticate a username and password using plaintext authentication.
642 The NT status code is returned with zero indicating success." },
643
644         { "auth_crap", (PyCFunction)py_auth_crap, METH_VARARGS,
645           "auth_crap(s, s) -> int
646
647 Authenticate a username and password using the challenge/response
648 protocol.  The NT status code is returned with zero indicating
649 success." },
650
651         { NULL }
652 };
653
654 static struct const_vals {
655         char *name;
656         uint32 value;
657         char *docstring;
658 } module_const_vals[] = {
659
660         /* Well known RIDs */
661         
662         { "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN, 
663           "Well-known RID for Administrator user" },
664
665         { "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
666           "Well-known RID for Guest user" },
667
668         { "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
669           "Well-known RID for Domain Admins group" },
670
671         { "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
672           "Well-known RID for Domain Users group" },
673
674         { "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
675           "Well-known RID for Domain Guests group" }, 
676         
677         { NULL }
678 };
679
680 static void const_init(PyObject *dict)
681 {
682         struct const_vals *tmp;
683         PyObject *obj;
684
685         for (tmp = module_const_vals; tmp->name; tmp++) {
686                 obj = PyInt_FromLong(tmp->value);
687                 PyDict_SetItemString(dict, tmp->name, obj);
688                 Py_DECREF(obj);
689         }
690 }
691
692 /*
693  * Module initialisation 
694  */
695
696 static char winbind_module__doc__[] =
697 "A python extension to winbind client functions.";
698
699 void initwinbind(void)
700 {
701         PyObject *module, *dict;
702
703         /* Initialise module */
704
705         module = Py_InitModule3("winbind", winbind_methods,
706                                 winbind_module__doc__);
707
708         dict = PyModule_GetDict(module);
709
710         winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
711         PyDict_SetItemString(dict, "error", winbind_error);
712
713         /* Do samba initialisation */
714
715         py_samba_init();
716
717         /* Initialise constants */
718
719         const_init(dict);
720
721         /* Insert configuration dictionary */
722
723         PyDict_SetItemString(dict, "config", py_config_dict());
724 }