c254acd11b7271037259297a88d0cc7dd12f9a5e
[samba.git] / source4 / scripting / swig / samr.py
1 import dcerpc
2
3 def sid_to_string(sid):
4     """Convert a Python dictionary SID to a string SID."""
5
6     result = 'S-%d' % sid.sid_rev_num
7
8     result = result + '-%u' % \
9              (dcerpc.uint8_array_getitem(sid.id_auth, 5) +
10               (dcerpc.uint8_array_getitem(sid.id_auth, 4) << 8) + 
11               (dcerpc.uint8_array_getitem(sid.id_auth, 3) << 16) +
12               (dcerpc.uint8_array_getitem(sid.id_auth, 2) << 24))
13     
14     for i in range(0, sid.num_auths):
15         result = result + '-%u' % \
16                  dcerpc.uint32_array_getitem(sid.sub_auths, i)
17
18     return result
19
20
21 def string_to_sid(string):
22     """Convert a string SID to a Python dictionary SID.  Throws a
23     ValueError if the SID string was badly formed."""
24
25     if string[0] != 'S':
26         raise ValueError('Bad SID format')
27
28     string = string[1:]
29
30     import re
31
32     match = re.match('-\d+', string)
33
34     if not match:
35         raise ValueError('Bad SID format')
36
37     try:
38         sid_rev_num = int(string[match.start()+1:match.end()])
39     except ValueError:
40         raise ValueError('Bad SID format')
41
42     string = string[match.end():]
43
44     match = re.match('-\d+', string)
45
46     if not match:
47         raise ValueError('Bad SID format')
48
49     try:
50         ia = int(string[match.start()+1:match.end()])
51     except ValueError:
52         raise ValueError('Bad SID format')
53
54     string = string[match.end():]
55
56     id_auth = [0, 0, (ia >> 24) & 0xff, (ia >> 16) & 0xff,
57                (ia >> 8) & 0xff, ia & 0xff]
58
59     num_auths = 0
60     sub_auths = []
61     
62     while len(string):
63
64         match = re.match('-\d+', string)
65
66         if not match:
67             raise ValueError('Bad SID format')
68
69         try:
70             sa = int(string[match.start() + 1 : match.end()])
71         except ValueError:
72             raise ValueError('Bad SID format')
73
74         num_auths = num_auths + 1
75         sub_auths.append(int(sa))
76
77         string = string[match.end():]
78
79     sid = dcerpc.dom_sid()
80     sid.sid_rev_num = sid_rev_num
81     sid.id_auth = dcerpc.new_uint8_array(6)
82     for i in range(6):
83         dcerpc.uint8_array_setitem(sid.id_auth, i, id_auth[i])
84     sid.num_auths = num_auths
85     sid.sub_auths = dcerpc.new_uint32_array(num_auths)
86     for i in range(num_auths):
87         dcerpc.uint32_array_setitem(sid.sub_auths, i, sub_auths[i])
88
89     return sid
90
91
92 def call_fn(fn, pipe, args):
93     """Wrap up a RPC call and throw an exception is an error was returned."""
94     
95     result = fn(pipe, args);
96
97     if result & 0xc0000000L:
98         raise dcerpc.NTSTATUS(result, dcerpc.nt_errstr(result));
99
100     return result;
101
102     
103 class SamrHandle:
104
105     def __init__(self, pipe, handle):
106
107         self.pipe = pipe
108         self.handle = handle
109
110     def __del__(self):
111
112         if self.handle is not None:
113             self.Close()
114
115     def Close(self):
116                     
117         r = dcerpc.samr_Close()
118         r.data_in.handle = self.handle
119
120         call_fn(dcerpc.dcerpc_samr_Close, self.pipe, r)
121
122         self.handle = None
123
124     def QuerySecurity(self, sec_info = 7):
125
126         r = dcerpc.samr_QuerySecurity()
127         r.data_in.handle = self.handle
128         r.data_in.sec_info = sec_info
129
130         call_fn(dcerpc.dcerpc_samr_QuerySecurity, self.pipe, r)
131
132         return r.data_out.sdbuf
133
134     def SetSecurity(self, sdbuf, sec_info = 7):
135
136         r = dcerpc.samr_SetSecurity()
137         r.data_in.handle = self.handle
138         r.data_in.sec_info = sec_info
139         r.data_in.sdbuf = sdbuf
140
141         call_fn(dcerpc.dcerpc_samr_SetSecurity, self.pipe, r)
142
143         
144 class ConnectHandle(SamrHandle):
145
146     def EnumDomains(self):
147
148         r = dcerpc.samr_EnumDomains()
149         r.data_in.connect_handle = self.handle
150         r.data_in.resume_handle = 0
151         r.data_in.buf_size = -1
152
153         domains = []
154
155         while 1:
156
157             call_fn(dcerpc.dcerpc_samr_EnumDomains, self.pipe, r)
158
159             for i in range(r.data_out.sam.count):
160                 domains.append(dcerpc.samr_SamEntry_array_getitem(
161                     r.data_out.sam.entries, i).name.string)
162
163             # TODO: Handle more entries here
164
165             break
166
167         return domains
168
169     def LookupDomain(self, domain_name):
170
171         r = dcerpc.samr_LookupDomain()
172         r.data_in.connect_handle = self.handle
173         r.data_in.domain_name = dcerpc.samr_String()
174         r.data_in.domain_name.string = domain_name
175
176         call_fn(dcerpc.dcerpc_samr_LookupDomain, self.pipe, r)
177
178         return sid_to_string(r.data_out.sid);
179
180     def OpenDomain(self, domain_sid, access_mask = 0x02000000):
181
182         r = dcerpc.samr_OpenDomain()
183         r.data_in.connect_handle = self.handle
184         r.data_in.access_mask = access_mask
185         r.data_in.sid = string_to_sid(domain_sid)
186
187         call_fn(dcerpc.dcerpc_samr_OpenDomain, self.pipe, r)
188
189         return DomainHandle(self.pipe, r.data_out.domain_handle)
190
191     def Shutdown(self):
192
193         r = dcerpc.samr_Shutdown()
194         r.data_in.connect_handle = self.handle
195
196         call_fn(dcerpc.dcerpc_samr_Shutdown, self.pipe, r)
197
198     def GetDomPwInfo(self, domain_name):
199
200         r = dcerpc.samr_GetDomPwInfo()
201         r.data_in.domain_name = dcerpc.samr_String()
202         r.data_in.domain_name.string = domain_name
203
204         call_fn(dcerpc.dcerpc_samr_GetDomPwInfo, self.pipe, r)
205
206         return r.data_out.info
207
208
209 class DomainHandle(SamrHandle):
210
211     def QueryDomainInfo(self, level = 2):
212
213         r = dcerpc.samr_QueryDomainInfo()
214         r.data_in.domain_handle = self.handle
215         r.data_in.level = level
216
217         call_fn(dcerpc.dcerpc_samr_QueryDomainInfo, self.pipe, r)
218
219         return getattr(r.data_out.info, 'info%d' % level)
220
221     def QueryDomainInfo2(self, level = 2):
222
223         r = dcerpc.samr_QueryDomainInfo2()
224         r.data_in.domain_handle = self.handle
225         r.data_in.level = level
226
227         call_fn(dcerpc.dcerpc_samr_QueryDomainInfo2, self.pipe, r)
228
229         return getattr(r.data_out.info, 'info%d' % level)       
230
231     def SetDomainInfo(self, level, info):
232
233         r = dcerpc.samr_SetDomainInfo()
234         r.data_in.domain_handle = self.handle
235         r.data_in.level = level
236         r.data_in.info = dcerpc.samr_DomainInfo()
237         setattr(r.data_in.info, 'info%d' % level, info)
238
239         call_fn(dcerpc.dcerpc_samr_SetDomainInfo, self.pipe, r)
240
241     def EnumDomainGroups(self):
242
243         r = dcerpc.samr_EnumDomainGroups()
244         r.data_in.domain_handle = self.handle
245         r.data_in.resume_handle = 0
246         r.data_in.max_size = 1000
247
248         call_fn(dcerpc.dcerpc_samr_EnumDomainGroups, self.pipe, r)
249
250         groups = []
251
252         if r.data_out.sam.entries:
253             for i in range(r.data_out.sam.count):
254                 groups.append(dcerpc.samr_SamEntry_array_getitem(
255                     r.data_out.sam.entries, i).name.string)
256
257         return groups
258
259     def EnumDomainAliases(self):
260
261         r = dcerpc.samr_EnumDomainAliases()
262         r.data_in.domain_handle = self.handle
263         r.data_in.resume_handle = 0
264         # acct_flags in SamrEnumerateAliasesInDomain has probably
265         # no meaning so use 0xffffffff like W2K
266         r.data_in.acct_flags = 0xffffffffL
267
268         call_fn(dcerpc.dcerpc_samr_EnumDomainAliases, self.pipe, r)
269
270         aliases = []
271
272         if r.data_out.sam.entries:
273             for i in range(r.data_out.sam.count):
274                 aliases.append(dcerpc.samr_SamEntry_array_getitem(
275                     r.data_out.sam.entries, i).name.string)
276
277         return aliases
278
279     def EnumDomainUsers(self, user_account_flags = 16):
280
281         r = dcerpc.samr_EnumDomainUsers()
282         r.data_in.domain_handle = self.handle
283         r.data_in.resume_handle = 0
284         r.data_in.acct_flags = user_account_flags
285         r.data_in.max_size = 1000
286
287         call_fn(dcerpc.dcerpc_samr_EnumDomainUsers, self.pipe, r)
288
289         users = []
290
291         if r.data_out.sam.entries:
292             for i in range(r.data_out.sam.count):
293                 users.append(dcerpc.samr_SamEntry_array_getitem(
294                     r.data_out.sam.entries, i).name.string)
295
296         return users
297
298     def CreateUser(self, account_name, access_mask = 0x02000000):
299
300         r = dcerpc.samr_CreateUser()
301         r.data_in.domain_handle = self.handle
302         r.data_in.account_name = dcerpc.samr_String()
303         r.data_in.account_name.string = account_name
304         r.data_in.access_mask = access_mask
305
306         call_fn(dcerpc.dcerpc_samr_CreateUser, self.pipe, r)
307
308         return (r.data_out.user_handle,
309                 dcerpc.uint32_array_getitem(r.data_out.rid, 0))
310
311     def CreateUser2(self, account_name, acct_flags = 0x00000010,
312                     access_mask = 0x02000000):
313
314         r = dcerpc.samr_CreateUser2()
315         r.data_in.domain_handle = self.handle
316         r.data_in.account_name = dcerpc.samr_String()
317         r.data_in.account_name.string = account_name
318         r.data_in.acct_flags = acct_flags
319         r.data_in.access_mask = access_mask
320
321         call_fn(dcerpc.dcerpc_samr_CreateUser2, self.pipe, r)
322
323         return (r.data_out.user_handle,
324                 dcerpc.uint32_array_getitem(r.data_out.access_granted, 0),
325                 dcerpc.uint32_array_getitem(r.data_out.rid, 0))
326
327     def OpenUser(self, rid, access_mask = 0x02000000):
328
329         r = dcerpc.samr_OpenUser()
330         r.data_in.domain_handle = self.handle
331         r.data_in.access_mask = access_mask
332         r.data_in.rid = rid
333
334         call_fn(dcerpc.dcerpc_samr_OpenUser, self.pipe, r)
335
336         return UserHandle(self.pipe, r.data_out.user_handle)
337
338     def OpenGroup(self, rid, access_mask = 0x02000000):
339
340         r = dcerpc.samr_OpenGroup()
341         r.data_in.domain_handle = self.handle
342         r.data_in.access_mask = access_mask
343         r.data_in.rid = rid
344
345         call_fn(dcerpc.dcerpc_samr_OpenGroup, self.pipe, r)
346
347         return GroupHandle(self.pipe, r.data_out.group_handle)
348
349     def OpenAlias(self, rid, access_mask = 0x02000000):
350
351         r = dcerpc.samr_OpenAlias()
352         r.data_in.domain_handle = self.handle
353         r.data_in.access_mask = access_mask
354         r.data_in.rid = rid
355
356         call_fn(dcerpc.dcerpc_samr_OpenAlias, self.pipe, r)
357
358         return AliasHandle(self.pipe, r.data_out.alias_handle)
359
360     def CreateDomAlias(self, alias_name, access_mask = 0x02000000):
361
362         r = dcerpc.samr_CreateDomAlias()
363         r.data_in.domain_handle = self.handle
364         r.data_in.alias_name = dcerpc.samr_String()
365         r.data_in.alias_name.string = alias_name
366         r.data_in.access_mask = access_mask
367
368         call_fn(dcerpc.dcerpc_samr_CreateDomAlias, self.pipe, r)
369
370         return (AliasHandle(self.pipe, r.data_out.alias_handle),
371                 r.data_out.rid)    
372
373     def RidToSid(self, rid):
374
375         r = dcerpc.samr_RidToSid()
376         r.data_in.domain_handle = self.handle
377         r.data_in.rid = rid
378
379         call_fn(dcerpc.dcerpc_samr_RidToSid, self.pipe, r)
380
381         return sid_to_string(r.data_out.sid)
382
383     def RemoveMemberFromForeignDomain(self, sid):
384
385         r = dcerpc.samr_RemoveMemberFromForeignDomain()
386         r.data_in.domain_handle = self.handle
387         r.data_in.sid = sid
388
389         call_fn(dcerpc.dcerpc_samr_RemoveMemberFromForeignDomain, self.pipe, r)
390
391     def LookupNames(self, names):
392
393         r = dcerpc.samr_LookupNames()
394         r.data_in.domain_handle = self.handle
395         r.data_in.num_names = len(names)
396         r.data_in.names = dcerpc.new_samr_String_array(len(names))
397
398         for i in range(len(names)):
399             s = dcerpc.samr_String()
400             s.string = names[i]
401             dcerpc.samr_String_array_setitem(r.data_in.names, i, s)
402
403         call_fn(dcerpc.dcerpc_samr_LookupNames, self.pipe, r)
404
405         return ([dcerpc.uint32_array_getitem(r.data_out.rids.ids, i) for i in range(r.data_out.rids.count)],
406                 [dcerpc.uint32_array_getitem(r.data_out.types.ids, i) for i in range(r.data_out.types.count)])
407
408     def CreateDomainGroup(self, domain_name, access_mask = 0x02000000):
409
410         r = dcerpc.samr_CreateDomainGroup()
411         r.data_in.domain_handle = self.handle
412         r.data_in.name = dcerpc.samr_String()
413         r.data_in.name.string = domain_name
414         r.data_in.access_mask = access_mask
415
416         call_fn(dcerpc.dcerpc_samr_CreateDomainGroup, self.pipe, r)
417
418     def GetAliasMembership(self, sids):
419
420         r = dcerpc.samr_GetAliasMembership()
421         r.data_in.domain_handle = self.handle
422         r.data_in.sids = dcerpc.lsa_SidArray()
423         r.data_in.sids.num_sids = len(sids)
424         r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids))
425
426         for i in range(len(sids)):
427             s = dcerpc.lsa_SidPtr()
428             s.sid = string_to_sid(sids[i])
429             dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s)
430
431         call_fn(dcerpc.dcerpc_samr_GetAliasMembership, self.pipe, r)
432
433         return [r.ids[x] for x in range(r.count)]
434
435     def QueryDisplayInfo(self, level):
436
437         # TODO: Handle more data returns
438
439         r = dcerpc.samr_QueryDisplayInfo()
440         r.data_in.domain_handle = self.handle
441         r.data_in.level = level
442         r.data_in.start_idx = 0
443         r.data_in.max_entries = 1000
444         r.data_in.buf_size = -1
445
446         call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo, self.pipe, r)
447
448         # TODO: Return a mapping of the various samr_DispInfo
449         # structures here.
450
451         return getattr(r.data_out.info, 'info%d' % level)
452     
453     def QueryDisplayInfo2(self, level):
454
455         # TODO: Handle more data returns
456
457         r = dcerpc.samr_QueryDisplayInfo2()
458         r.data_in.domain_handle = self.handle
459         r.data_in.level = level
460         r.data_in.start_idx = 0
461         r.data_in.max_entries = 1000
462         r.data_in.buf_size = -1
463
464         call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo2, self.pipe, r)
465
466         # TODO: Return a mapping of the various samr_DispInfo
467         # structures here.
468
469         return getattr(r.data_out.info, 'info%d' % level)
470
471     def QueryDisplayInfo3(self, level):
472
473         # TODO: Handle more data returns
474
475         r = dcerpc.samr_QueryDisplayInfo3()
476         r.data_in.domain_handle = self.handle
477         r.data_in.level = level
478         r.data_in.start_idx = 0
479         r.data_in.max_entries = 1000
480         r.data_in.buf_size = -1
481
482         call_fn(dcerpc.dcerpc_samr_QueryDisplayInfo3, self.pipe, r)
483
484         # TODO: Return a mapping of the various samr_DispInfo
485         # structures here.
486
487         return getattr(r.data_out.info, 'info%d' % level)
488
489
490 class UserHandle(SamrHandle):
491
492     def DeleteUser(self):
493
494         r = dcerpc.samr_DeleteUser()
495         r.data_in.user_handle = self.handle
496         
497         call_fn(dcerpc.dcerpc_samr_DeleteUser, self.pipe, r)
498
499         self.handle = None
500
501     def GetUserPwInfo(self):
502
503         r = dcerpc.samr_GetUserPwInfo()
504         r.data_in.user_handle = self.handle
505
506         call_fn(dcerpc.dcerpc_samr_GetUserPwInfo, self.pipe, r)
507
508         return r.data_out.info
509
510     def QueryUserInfo(self, level):
511
512         r = dcerpc.samr_QueryUserInfo()
513         r.data_in.user_handle = self.handle
514         r.data_in.level = level
515
516         call_fn(dcerpc.dcerpc_samr_QueryUserInfo, self.pipe, r)
517
518         return r.data_out.info
519
520     def QueryUserInfo2(self, level):
521
522         r = dcerpc.samr_QueryUserInfo2()
523         r.data_in.user_handle = self.handle
524         r.data_in.level = level
525
526         call_fn(dcerpc.dcerpc_samr_QueryUserInfo2, self.pipe, r)
527
528         return r.data_out.info
529
530 class GroupHandle(SamrHandle):
531     pass
532     
533
534 class AliasHandle(SamrHandle):
535
536     def DeleteDomAlias(self):
537
538         r = dcerpc.samr_DeleteDomAlias()
539         r.data_in.alias_handle = self.handle
540
541         call_fn(dcerpc.dcerpc_samr_DeleteDomAlias, self.pipe, r)
542
543         self.handle = None
544
545     def QueryAliasInfo(self, level = 1):
546
547         r = dcerpc.samr_QueryAliasInfo()
548         r.data_in.alias_handle = self.handle
549         r.data_in.level = level
550
551         call_fn(dcerpc.dcerpc_samr_QueryAliasInfo, self.pipe, r)
552
553         return r.data_out.info
554
555     def SetAliasInfo(self, level, info):
556
557         r = dcerpc.samr_SetAliasInfo()
558         r.data_in.alias_handle = self.handle
559         r.data_in.level = level
560         r.data_in.info = info
561
562         call_fn(dcerpc.dcerpc_samr_SetAliasInfo, self.pipe, r)
563
564     def AddAliasMember(self, sid):
565
566         r = dcerpc.samr_AddAliasMember()
567         r.data_in.alias_handle = self.handle
568         r.data_in.sid = string_to_sid(sid)
569
570         call_fn(dcerpc.dcerpc_samr_AddAliasMember, self.pipe, r)
571
572     def AddMultipleMembersToAlias(self, sids):
573
574         r = dcerpc.samr_AddMultipleMembersToAlias()
575         r.data_in.alias_handle = self.handle
576         r.data_in.sids = dcerpc.lsa_SidArray()
577         r.data_in.sids.num_sids = len(sids)
578         r.data_in.sids.sids = dcerpc.new_lsa_SidPtr_array(len(sids))
579
580         for i in range(len(sids)):
581             s = dcerpc.lsa_SidPtr()
582             s.sid = string_to_sid(sids[i])
583             dcerpc.lsa_SidPtr_array_setitem(r.data_in.sids.sids, i, s)
584
585         call_fn(dcerpc.dcerpc_samr_AddMultipleMembersToAlias, self.pipe, r)
586
587 def Connect(pipe, access_mask = 0x02000000):
588
589     r = dcerpc.samr_Connect()
590     r.data_in.system_name = dcerpc.new_uint16_array(1)
591     dcerpc.uint16_array_setitem(r.data_in.system_name, 0, ord('\\'))
592     r.data_in.access_mask = access_mask
593
594     call_fn(dcerpc.dcerpc_samr_Connect, pipe, r)
595
596     return ConnectHandle(pipe, r.data_out.connect_handle)
597
598
599 def Connect2(pipe, system_name = '', access_mask = 0x02000000):
600     """Connect to the SAMR pipe."""
601
602     r = dcerpc.samr_Connect2()
603     r.data_in.system_name = system_name
604     r.data_in.access_mask = access_mask
605
606     call_fn(dcerpc.dcerpc_samr_Connect2, pipe, r)
607
608     return ConnectHandle(pipe, r.data_out.connect_handle)
609
610
611 def Connect3(pipe, system_name = '', access_mask = 0x02000000):
612
613     r = dcerpc.samr_Connect3()
614     r.data_in.system_name = system_name
615     r.data_in.unknown = 0
616     r.data_in.access_mask = access_mask
617
618     call_fn(dcerpc.dcerpc_samr_Connect3, pipe, r)
619
620     return ConnectHandle(pipe, r.data_out.connect_handle)
621
622
623 def Connect4(pipe, system_name = '', access_mask = 0x02000000):
624
625     r = dcerpc.samr_Connect4()
626     r.data_in.system_name = system_name
627     r.data_in.unknown = 0
628     r.data_in.access_mask = access_mask
629
630     call_fn(dcerpc.dcerpc_samr_Connect4, pipe, r)
631
632     return ConnectHandle(pipe, r.data_out.connect_handle)
633
634 def Connect5(pipe, system_name = '', access_mask = 0x02000000):
635
636     r = dcerpc.samr_Connect5()
637     r.data_in.system_name = system_name
638     r.data_in.access_mask = access_mask
639     r.data_in.level = 1
640     r.data_in.info = dcerpc.new_samr_ConnectInfo_array(1)
641     r.data_in.info.unknown1 = 0
642     r.data_in.info.unknown2 = 0
643
644     call_fn(dcerpc.dcerpc_samr_Connect5, pipe, r)
645
646     return ConnectHandle(pipe, r.data_out.connect_handle)
647     
648 # QueryGroupInfo
649 # SetGroupInfo
650 # AddGroupMember
651 # DeleteDomainGroup
652 # DeleteGroupMember
653 # QueryGroupMember
654 # SetMemberAttributesofGroup
655 # AddAliasMember
656 # DeleteAliasMember
657 # GetMembersinAlias
658 # SetUserInfo
659 # ChangePasswordUser
660 # GetGroupsForUser
661 # GetDisplayEnumerationIndex
662 # TestPrivateFunctionsDomain
663 # TestPrivateFunctionsUser
664 # RemoveMemberFromForeignDomain
665 # GetDisplayEnumerationIndex2
666 # RemoveMultipleMembersFromAlias
667 # OemChangePasswordUser2
668 # ChangePasswordUser2
669 # SetUserInfo2
670 # SetBootKeyInformation
671 # GetBootKeyInformation
672 # ChangePasswordUser3
673 # SetDsrmPassword
674 # ValidatePassword