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