aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs
blob: a6ad59fb1aec13bbb1145aea13462688fe222877 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
// This code is derived from jcifs smb client library <jcifs at samba dot org>
// Ported by J. Arturo <webmaster at komodosoft dot net>
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using SharpCifs.Dcerpc;
using SharpCifs.Dcerpc.Msrpc;
using SharpCifs.Util;
using SharpCifs.Util.Sharpen;
using Hashtable = SharpCifs.Util.Sharpen.Hashtable; //not System.Collections.Hashtable

namespace SharpCifs.Smb
{
	/// <summary>
	/// A Windows SID is a numeric identifier used to represent Windows
	/// accounts.
	/// </summary>
	/// <remarks>
	/// A Windows SID is a numeric identifier used to represent Windows
	/// accounts. SIDs are commonly represented using a textual format such as
	/// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt> but they may
	/// also be resolved to yield the name of the associated Windows account
	/// such as <tt>Administrators</tt> or <tt>MYDOM\alice</tt>.
	/// <p>
	/// Consider the following output of <tt>examples/SidLookup.java</tt>:
	/// <pre>
	/// toString: S-1-5-21-4133388617-793952518-2001621813-512
	/// toDisplayString: WNET\Domain Admins
	/// getType: 2
	/// getTypeText: Domain group
	/// getDomainName: WNET
	/// getAccountName: Domain Admins
	/// </pre>
	/// </remarks>
	public class Sid : Rpc.SidT
	{
		public const int SidTypeUseNone = Lsarpc.SidNameUseNone;

		public const int SidTypeUser = Lsarpc.SidNameUser;

		public const int SidTypeDomGrp = Lsarpc.SidNameDomGrp;

		public const int SidTypeDomain = Lsarpc.SidNameDomain;

		public const int SidTypeAlias = Lsarpc.SidNameAlias;

		public const int SidTypeWknGrp = Lsarpc.SidNameWknGrp;

		public const int SidTypeDeleted = Lsarpc.SidNameDeleted;

		public const int SidTypeInvalid = Lsarpc.SidNameInvalid;

		public const int SidTypeUnknown = Lsarpc.SidNameUnknown;

		internal static readonly string[] SidTypeNames = { "0", "User", "Domain group"
			, "Domain", "Local group", "Builtin group", "Deleted", "Invalid", "Unknown" };

		public const int SidFlagResolveSids = unchecked(0x0001);

		public static Sid Everyone;

		public static Sid CreatorOwner;

		public static Sid SYSTEM;

		static Sid()
		{
			try
			{
				Everyone = new Sid("S-1-1-0");
				CreatorOwner = new Sid("S-1-3-0");
				SYSTEM = new Sid("S-1-5-18");
			}
			catch (SmbException)
			{
			}
		}

		internal static Hashtable SidCache = new Hashtable();

		/// <exception cref="System.IO.IOException"></exception>
		internal static void ResolveSids(DcerpcHandle handle, LsaPolicyHandle policyHandle
			, Sid[] sids)
		{
			MsrpcLookupSids rpc = new MsrpcLookupSids(policyHandle, sids);
			handle.Sendrecv(rpc);
			switch (rpc.Retval)
			{
				case 0:
				case NtStatus.NtStatusNoneMapped:
				case unchecked(0x00000107):
				{
					// NT_STATUS_SOME_NOT_MAPPED
					break;
				}

				default:
				{
					throw new SmbException(rpc.Retval, false);
				}
			}
			for (int si = 0; si < sids.Length; si++)
			{
				sids[si].Type = rpc.Names.Names[si].SidType;
				sids[si].DomainName = null;
				switch (sids[si].Type)
				{
					case SidTypeUser:
					case SidTypeDomGrp:
					case SidTypeDomain:
					case SidTypeAlias:
					case SidTypeWknGrp:
					{
						int sidIndex = rpc.Names.Names[si].SidIndex;
						Rpc.Unicode_string ustr = rpc.Domains.Domains[sidIndex].Name;
						sids[si].DomainName = (new UnicodeString(ustr, false)).ToString();
						break;
					}
				}
				sids[si].AcctName = (new UnicodeString(rpc.Names.Names[si].Name, false)).ToString
					();
				sids[si].OriginServer = null;
				sids[si].OriginAuth = null;
			}
		}

		/// <exception cref="System.IO.IOException"></exception>
		internal static void ResolveSids0(string authorityServerName, NtlmPasswordAuthentication
			 auth, Sid[] sids)
		{
			DcerpcHandle handle = null;
			LsaPolicyHandle policyHandle = null;
			lock (SidCache)
			{
				try
				{
					handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\lsarpc]"
						, auth);
					string server = authorityServerName;
					int dot = server.IndexOf('.');
					if (dot > 0 && char.IsDigit(server[0]) == false)
					{
						server = Runtime.Substring(server, 0, dot);
					}
					policyHandle = new LsaPolicyHandle(handle, "\\\\" + server, unchecked(0x00000800));
					ResolveSids(handle, policyHandle, sids);
				}
				finally
				{
					if (handle != null)
					{
						if (policyHandle != null)
						{
							policyHandle.Close();
						}
						handle.Close();
					}
				}
			}
		}

		/// <exception cref="System.IO.IOException"></exception>
		public static void ResolveSids(string authorityServerName, NtlmPasswordAuthentication
			 auth, Sid[] sids, int offset, int length)
		{
            List<object> list = new List<object>();//new List<object>(sids.Length);
			int si;
			lock (SidCache)
			{
				for (si = 0; si < length; si++)
				{
					Sid sid = (Sid)SidCache.Get(sids[offset + si]);
					if (sid != null)
					{
						sids[offset + si].Type = sid.Type;
						sids[offset + si].DomainName = sid.DomainName;
						sids[offset + si].AcctName = sid.AcctName;
					}
					else
					{
						list.Add(sids[offset + si]);
					}
				}
				if (list.Count > 0)
				{
					//sids = (Jcifs.Smb.SID[])Sharpen.Collections.ToArray(list, new Jcifs.Smb.SID[0]);
                    sids = (Sid[])list.ToArray();
					ResolveSids0(authorityServerName, auth, sids);
					for (si = 0; si < sids.Length; si++)
					{
						SidCache.Put(sids[si], sids[si]);
					}
				}
			}
		}

		/// <summary>Resolve an array of SIDs using a cache and at most one MSRPC request.</summary>
		/// <remarks>
		/// Resolve an array of SIDs using a cache and at most one MSRPC request.
		/// <p>
		/// This method will attempt
		/// to resolve SIDs using a cache and cache the results of any SIDs that
		/// required resolving with the authority. SID cache entries are currently not
		/// expired because under normal circumstances SID information never changes.
		/// </remarks>
		/// <param name="authorityServerName">The hostname of the server that should be queried. For maximum efficiency this should be the hostname of a domain controller however a member server will work as well and a domain controller may not return names for SIDs corresponding to local accounts for which the domain controller is not an authority.
		/// 	</param>
		/// <param name="auth">The credentials that should be used to communicate with the named server. As usual, <tt>null</tt> indicates that default credentials should be used.
		/// 	</param>
		/// <param name="sids">The SIDs that should be resolved. After this function is called, the names associated with the SIDs may be queried with the <tt>toDisplayString</tt>, <tt>getDomainName</tt>, and <tt>getAccountName</tt> methods.
		/// 	</param>
		/// <exception cref="System.IO.IOException"></exception>
		public static void ResolveSids(string authorityServerName, NtlmPasswordAuthentication
			 auth, Sid[] sids)
		{
            List<object> list = new List<object>();//new List<object>(sids.Length);
			int si;
			lock (SidCache)
			{
				for (si = 0; si < sids.Length; si++)
				{
					Sid sid = (Sid)SidCache.Get(sids[si]);
					if (sid != null)
					{
						sids[si].Type = sid.Type;
						sids[si].DomainName = sid.DomainName;
						sids[si].AcctName = sid.AcctName;
					}
					else
					{
						list.Add(sids[si]);
					}
				}
				if (list.Count > 0)
				{
					//sids = (Jcifs.Smb.SID[])Sharpen.Collections.ToArray(list, new Jcifs.Smb.SID[0]);
				    sids = (Sid[]) list.ToArray();
					ResolveSids0(authorityServerName, auth, sids);
					for (si = 0; si < sids.Length; si++)
					{
						SidCache.Put(sids[si], sids[si]);
					}
				}
			}
		}

		/// <exception cref="System.IO.IOException"></exception>
		public static Sid GetServerSid(string server, NtlmPasswordAuthentication
			 auth)
		{
			DcerpcHandle handle = null;
			LsaPolicyHandle policyHandle = null;
			Lsarpc.LsarDomainInfo info = new Lsarpc.LsarDomainInfo();
			MsrpcQueryInformationPolicy rpc;
			lock (SidCache)
			{
				try
				{
					handle = DcerpcHandle.GetHandle("ncacn_np:" + server + "[\\PIPE\\lsarpc]", auth);
					// NetApp doesn't like the 'generic' access mask values
					policyHandle = new LsaPolicyHandle(handle, null, unchecked(0x00000001));
					rpc = new MsrpcQueryInformationPolicy(policyHandle, Lsarpc.PolicyInfoAccountDomain
						, info);
					handle.Sendrecv(rpc);
					if (rpc.Retval != 0)
					{
						throw new SmbException(rpc.Retval, false);
					}
					return new Sid(info.Sid, SidTypeDomain, (new UnicodeString
						(info.Name, false)).ToString(), null, false);
				}
				finally
				{
					if (handle != null)
					{
						if (policyHandle != null)
						{
							policyHandle.Close();
						}
						handle.Close();
					}
				}
			}
		}

		public static byte[] ToByteArray(Rpc.SidT sid)
		{
			byte[] dst = new byte[1 + 1 + 6 + sid.SubAuthorityCount * 4];
			int di = 0;
			dst[di++] = sid.Revision;
			dst[di++] = sid.SubAuthorityCount;
			Array.Copy(sid.IdentifierAuthority, 0, dst, di, 6);
			di += 6;
			for (int ii = 0; ii < sid.SubAuthorityCount; ii++)
			{
				Encdec.Enc_uint32le(sid.SubAuthority[ii], dst, di);
				di += 4;
			}
			return dst;
		}

		internal int Type;

		internal string DomainName;

		internal string AcctName;

		internal string OriginServer;

		internal NtlmPasswordAuthentication OriginAuth;

		public Sid(byte[] src, int si)
		{
			Revision = src[si++];
			SubAuthorityCount = src[si++];
			IdentifierAuthority = new byte[6];
			Array.Copy(src, si, IdentifierAuthority, 0, 6);
			si += 6;
			if (SubAuthorityCount > 100)
			{
				throw new RuntimeException("Invalid SID sub_authority_count");
			}
			SubAuthority = new int[SubAuthorityCount];
			for (int i = 0; i < SubAuthorityCount; i++)
			{
				SubAuthority[i] = ServerMessageBlock.ReadInt4(src, si);
				si += 4;
			}
		}

		/// <summary>
		/// Construct a SID from it's textual representation such as
		/// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
		/// </summary>
		/// <remarks>
		/// Construct a SID from it's textual representation such as
		/// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
		/// </remarks>
		/// <exception cref="SharpCifs.Smb.SmbException"></exception>
		public Sid(string textual)
		{
			StringTokenizer st = new StringTokenizer(textual, "-");
			if (st.CountTokens() < 3 || !st.NextToken().Equals("S"))
			{
				// need S-N-M
				throw new SmbException("Bad textual SID format: " + textual);
			}
			Revision = byte.Parse(st.NextToken());
			string tmp = st.NextToken();
			long id = 0;
			if (tmp.StartsWith("0x"))
			{
				//id = long.Parse(Sharpen.Runtime.Substring(tmp, 2), 16);
                id = long.Parse(Runtime.Substring(tmp, 2));
			}
			else
			{
				id = long.Parse(tmp);
			}
			IdentifierAuthority = new byte[6];
			for (int i = 5; id > 0; i--)
			{
				IdentifierAuthority[i] = unchecked((byte)(id % 256));
				id >>= 8;
			}
			SubAuthorityCount = unchecked((byte)st.CountTokens());
			if (SubAuthorityCount > 0)
			{
				SubAuthority = new int[SubAuthorityCount];
				for (int i1 = 0; i1 < SubAuthorityCount; i1++)
				{
					SubAuthority[i1] = (int)(long.Parse(st.NextToken()) & unchecked(0xFFFFFFFFL));
				}
			}
		}

		/// <summary>
		/// Construct a SID from a domain SID and an RID
		/// (relative identifier).
		/// </summary>
		/// <remarks>
		/// Construct a SID from a domain SID and an RID
		/// (relative identifier). For example, a domain SID
		/// <tt>S-1-5-21-1496946806-2192648263-3843101252</tt> and RID <tt>1029</tt> would
		/// yield the SID <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
		/// </remarks>
		public Sid(Sid domsid, int rid)
		{
			Revision = domsid.Revision;
			IdentifierAuthority = domsid.IdentifierAuthority;
			SubAuthorityCount = unchecked((byte)(domsid.SubAuthorityCount + 1));
			SubAuthority = new int[SubAuthorityCount];
			int i;
			for (i = 0; i < domsid.SubAuthorityCount; i++)
			{
				SubAuthority[i] = domsid.SubAuthority[i];
			}
			SubAuthority[i] = rid;
		}

		public Sid(Rpc.SidT sid, int type, string domainName, string acctName, bool decrementAuthority
			)
		{
			Revision = sid.Revision;
			SubAuthorityCount = sid.SubAuthorityCount;
			IdentifierAuthority = sid.IdentifierAuthority;
			SubAuthority = sid.SubAuthority;
			this.Type = type;
			this.DomainName = domainName;
			this.AcctName = acctName;
			if (decrementAuthority)
			{
				SubAuthorityCount--;
				SubAuthority = new int[SubAuthorityCount];
				for (int i = 0; i < SubAuthorityCount; i++)
				{
					SubAuthority[i] = sid.SubAuthority[i];
				}
			}
		}

		public virtual Sid GetDomainSid()
		{
			return new Sid(this, SidTypeDomain, DomainName, null, GetType() 
				!= SidTypeDomain);
		}

		public virtual int GetRid()
		{
			if (GetType() == SidTypeDomain)
			{
				throw new ArgumentException("This SID is a domain sid");
			}
			return SubAuthority[SubAuthorityCount - 1];
		}

		/// <summary>Returns the type of this SID indicating the state or type of account.</summary>
		/// <remarks>
		/// Returns the type of this SID indicating the state or type of account.
		/// <p>
		/// SID types are described in the following table.
		/// <tt>
		/// <table>
		/// <tr><th>Type</th><th>Name</th></tr>
		/// <tr><td>SID_TYPE_USE_NONE</td><td>0</td></tr>
		/// <tr><td>SID_TYPE_USER</td><td>User</td></tr>
		/// <tr><td>SID_TYPE_DOM_GRP</td><td>Domain group</td></tr>
		/// <tr><td>SID_TYPE_DOMAIN</td><td>Domain</td></tr>
		/// <tr><td>SID_TYPE_ALIAS</td><td>Local group</td></tr>
		/// <tr><td>SID_TYPE_WKN_GRP</td><td>Builtin group</td></tr>
		/// <tr><td>SID_TYPE_DELETED</td><td>Deleted</td></tr>
		/// <tr><td>SID_TYPE_INVALID</td><td>Invalid</td></tr>
		/// <tr><td>SID_TYPE_UNKNOWN</td><td>Unknown</td></tr>
		/// </table>
		/// </tt>
		/// </remarks>
		public virtual int GetType()
		{
			if (OriginServer != null)
			{
				ResolveWeak();
			}
			return Type;
		}

		/// <summary>
		/// Return text represeting the SID type suitable for display to
		/// users.
		/// </summary>
		/// <remarks>
		/// Return text represeting the SID type suitable for display to
		/// users. Text includes 'User', 'Domain group', 'Local group', etc.
		/// </remarks>
		public virtual string GetTypeText()
		{
			if (OriginServer != null)
			{
				ResolveWeak();
			}
			return SidTypeNames[Type];
		}

		/// <summary>
		/// Return the domain name of this SID unless it could not be
		/// resolved in which case the numeric representation is returned.
		/// </summary>
		/// <remarks>
		/// Return the domain name of this SID unless it could not be
		/// resolved in which case the numeric representation is returned.
		/// </remarks>
		public virtual string GetDomainName()
		{
			if (OriginServer != null)
			{
				ResolveWeak();
			}
			if (Type == SidTypeUnknown)
			{
				string full = ToString();
				return Runtime.Substring(full, 0, full.Length - GetAccountName().Length -
					 1);
			}
			return DomainName;
		}

		/// <summary>
		/// Return the sAMAccountName of this SID unless it could not
		/// be resolved in which case the numeric RID is returned.
		/// </summary>
		/// <remarks>
		/// Return the sAMAccountName of this SID unless it could not
		/// be resolved in which case the numeric RID is returned. If this
		/// SID is a domain SID, this method will return an empty String.
		/// </remarks>
		public virtual string GetAccountName()
		{
			if (OriginServer != null)
			{
				ResolveWeak();
			}
			if (Type == SidTypeUnknown)
			{
				return string.Empty + SubAuthority[SubAuthorityCount - 1];
			}
			if (Type == SidTypeDomain)
			{
				return string.Empty;
			}
			return AcctName;
		}

		public override int GetHashCode()
		{
			int hcode = IdentifierAuthority[5];
			for (int i = 0; i < SubAuthorityCount; i++)
			{
				hcode += 65599 * SubAuthority[i];
			}
			return hcode;
		}

		public override bool Equals(object obj)
		{
			if (obj is Sid)
			{
				Sid sid = (Sid)obj;
				if (sid == this)
				{
					return true;
				}
				if (sid.SubAuthorityCount == SubAuthorityCount)
				{
					int i = SubAuthorityCount;
					while (i-- > 0)
					{
						if (sid.SubAuthority[i] != SubAuthority[i])
						{
							return false;
						}
					}
					for (i = 0; i < 6; i++)
					{
						if (sid.IdentifierAuthority[i] != IdentifierAuthority[i])
						{
							return false;
						}
					}
					return sid.Revision == Revision;
				}
			}
			return false;
		}

		/// <summary>
		/// Return the numeric representation of this sid such as
		/// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
		/// </summary>
		/// <remarks>
		/// Return the numeric representation of this sid such as
		/// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
		/// </remarks>
		public override string ToString()
		{
			string ret = "S-" + (Revision & unchecked(0xFF)) + "-";
			if (IdentifierAuthority[0] != unchecked(0) || IdentifierAuthority[1] != unchecked(
				0))
			{
				ret += "0x";
				ret += Hexdump.ToHexString(IdentifierAuthority, 0, 6);
			}
			else
			{
				int shift = 0;
				long id = 0;
				for (int i = 5; i > 1; i--)
				{
					id += (IdentifierAuthority[i] & unchecked(0xFFL)) << shift;
					shift += 8;
				}
				ret += id;
			}
			for (int i1 = 0; i1 < SubAuthorityCount; i1++)
			{
				ret += "-" + (SubAuthority[i1] & unchecked(0xFFFFFFFFL));
			}
			return ret;
		}

		/// <summary>
		/// Return a String representing this SID ideal for display to
		/// users.
		/// </summary>
		/// <remarks>
		/// Return a String representing this SID ideal for display to
		/// users. This method should return the same text that the ACL
		/// editor in Windows would display.
		/// <p>
		/// Specifically, if the SID has
		/// been resolved and it is not a domain SID or builtin account,
		/// the full DOMAIN\name form of the account will be
		/// returned (e.g. MYDOM\alice or MYDOM\Domain Users).
		/// If the SID has been resolved but it is is a domain SID,
		/// only the domain name will be returned (e.g. MYDOM).
		/// If the SID has been resolved but it is a builtin account,
		/// only the name component will be returned (e.g. SYSTEM).
		/// If the sid cannot be resolved the numeric representation from
		/// toString() is returned.
		/// </remarks>
		public virtual string ToDisplayString()
		{
			if (OriginServer != null)
			{
				ResolveWeak();
			}
			if (DomainName != null)
			{
				string str;
				if (Type == SidTypeDomain)
				{
					str = DomainName;
				}
				else
				{
					if (Type == SidTypeWknGrp || DomainName.Equals("BUILTIN"))
					{
						if (Type == SidTypeUnknown)
						{
							str = ToString();
						}
						else
						{
							str = AcctName;
						}
					}
					else
					{
						str = DomainName + "\\" + AcctName;
					}
				}
				return str;
			}
			return ToString();
		}

		/// <summary>Manually resolve this SID.</summary>
		/// <remarks>
		/// Manually resolve this SID. Normally SIDs are automatically
		/// resolved. However, if a SID is constructed explicitly using a SID
		/// constructor, JCIFS will have no knowledge of the server that created the
		/// SID and therefore cannot possibly resolve it automatically. In this case,
		/// this method will be necessary.
		/// </remarks>
		/// <param name="authorityServerName">The FQDN of the server that is an authority for the SID.
		/// 	</param>
		/// <param name="auth">Credentials suitable for accessing the SID's information.</param>
		/// <exception cref="System.IO.IOException"></exception>
		public virtual void Resolve(string authorityServerName, NtlmPasswordAuthentication
			 auth)
		{
			Sid[] sids = new Sid[1];
			sids[0] = this;
			ResolveSids(authorityServerName, auth, sids);
		}

		internal virtual void ResolveWeak()
		{
			if (OriginServer != null)
			{
				try
				{
					Resolve(OriginServer, OriginAuth);
				}
				catch (IOException)
				{
				}
				finally
				{
					OriginServer = null;
					OriginAuth = null;
				}
			}
		}

		/// <exception cref="System.IO.IOException"></exception>
		internal static Sid[] GetGroupMemberSids0(DcerpcHandle handle, SamrDomainHandle
			 domainHandle, Sid domsid, int rid, int flags)
		{
			SamrAliasHandle aliasHandle = null;
			Lsarpc.LsarSidArray sidarray = new Lsarpc.LsarSidArray();
			MsrpcGetMembersInAlias rpc = null;
			try
			{
				aliasHandle = new SamrAliasHandle(handle, domainHandle, unchecked(0x0002000c), rid);
				rpc = new MsrpcGetMembersInAlias(aliasHandle, sidarray);
				handle.Sendrecv(rpc);
				if (rpc.Retval != 0)
				{
					throw new SmbException(rpc.Retval, false);
				}
				Sid[] sids = new Sid[rpc.Sids.NumSids];
				string originServer = handle.GetServer();
				NtlmPasswordAuthentication originAuth = (NtlmPasswordAuthentication)handle.GetPrincipal
					();
				for (int i = 0; i < sids.Length; i++)
				{
					sids[i] = new Sid(rpc.Sids.Sids[i].Sid, 0, null, null, false);
					sids[i].OriginServer = originServer;
					sids[i].OriginAuth = originAuth;
				}
				if (sids.Length > 0 && (flags & SidFlagResolveSids) != 0)
				{
					ResolveSids(originServer, originAuth, sids);
				}
				return sids;
			}
			finally
			{
				if (aliasHandle != null)
				{
					aliasHandle.Close();
				}
			}
		}

		/// <exception cref="System.IO.IOException"></exception>
		public virtual Sid[] GetGroupMemberSids(string authorityServerName, NtlmPasswordAuthentication
			 auth, int flags)
		{
			if (Type != SidTypeDomGrp && Type != SidTypeAlias)
			{
				return new Sid[0];
			}
			DcerpcHandle handle = null;
			SamrPolicyHandle policyHandle = null;
			SamrDomainHandle domainHandle = null;
			Sid domsid = GetDomainSid();
			lock (SidCache)
			{
				try
				{
					handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\samr]"
						, auth);
					policyHandle = new SamrPolicyHandle(handle, authorityServerName, unchecked(0x00000030));
					domainHandle = new SamrDomainHandle(handle, policyHandle, unchecked(0x00000200), domsid);
					return GetGroupMemberSids0(handle, domainHandle, domsid, GetRid(), 
						flags);
				}
				finally
				{
					if (handle != null)
					{
						if (policyHandle != null)
						{
							if (domainHandle != null)
							{
								domainHandle.Close();
							}
							policyHandle.Close();
						}
						handle.Close();
					}
				}
			}
		}

		/// <summary>
		/// This specialized method returns a Map of users and local groups for the
		/// target server where keys are SIDs representing an account and each value
		/// is an List<object> of SIDs represents the local groups that the account is
		/// a member of.
		/// </summary>
		/// <remarks>
		/// This specialized method returns a Map of users and local groups for the
		/// target server where keys are SIDs representing an account and each value
		/// is an List<object> of SIDs represents the local groups that the account is
		/// a member of.
		/// <p/>
		/// This method is designed to assist with computing access control for a
		/// given user when the target object's ACL has local groups. Local groups
		/// are not listed in a user's group membership (e.g. as represented by the
		/// tokenGroups constructed attribute retrived via LDAP).
		/// <p/>
		/// Domain groups nested inside a local group are currently not expanded. In
		/// this case the key (SID) type will be SID_TYPE_DOM_GRP rather than
		/// SID_TYPE_USER.
		/// </remarks>
		/// <param name="authorityServerName">The server from which the local groups will be queried.
		/// 	</param>
		/// <param name="auth">The credentials required to query groups and group members.</param>
		/// <param name="flags">
		/// Flags that control the behavior of the operation. When all
		/// name associated with SIDs will be required, the SID_FLAG_RESOLVE_SIDS
		/// flag should be used which causes all group member SIDs to be resolved
		/// together in a single more efficient operation.
		/// </param>
		/// <exception cref="System.IO.IOException"></exception>
		internal static Hashtable GetLocalGroupsMap(string authorityServerName, NtlmPasswordAuthentication
			 auth, int flags)
		{
			Sid domsid = GetServerSid(authorityServerName, auth);
			DcerpcHandle handle = null;
			SamrPolicyHandle policyHandle = null;
			SamrDomainHandle domainHandle = null;
			Samr.SamrSamArray sam = new Samr.SamrSamArray();
			MsrpcEnumerateAliasesInDomain rpc;
			lock (SidCache)
			{
				try
				{
					handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\samr]"
						, auth);
					policyHandle = new SamrPolicyHandle(handle, authorityServerName, unchecked(0x02000000));
					domainHandle = new SamrDomainHandle(handle, policyHandle, unchecked(0x02000000), domsid);
					rpc = new MsrpcEnumerateAliasesInDomain(domainHandle, unchecked(0xFFFF), sam
						);
					handle.Sendrecv(rpc);
					if (rpc.Retval != 0)
					{
						throw new SmbException(rpc.Retval, false);
					}
                    Hashtable map = new Hashtable();
					for (int ei = 0; ei < rpc.Sam.Count; ei++)
					{
						Samr.SamrSamEntry entry = rpc.Sam.Entries[ei];
						Sid[] mems = GetGroupMemberSids0(handle, domainHandle, domsid
							, entry.Idx, flags);
						Sid groupSid = new Sid(domsid, entry.Idx);
						groupSid.Type = SidTypeAlias;
						groupSid.DomainName = domsid.GetDomainName();
						groupSid.AcctName = (new UnicodeString(entry.Name, false)).ToString();
						for (int mi = 0; mi < mems.Length; mi++)
						{
							List<object> groups = (List<object>)map.Get(mems[mi]);
							if (groups == null)
							{
								groups = new List<object>();
								map.Put(mems[mi], groups);
							}
							if (!groups.Contains(groupSid))
							{
								groups.Add(groupSid);
							}
						}
					}
					return map;
				}
				finally
				{
					if (handle != null)
					{
						if (policyHandle != null)
						{
							if (domainHandle != null)
							{
								domainHandle.Close();
							}
							policyHandle.Close();
						}
						handle.Close();
					}
				}
			}
		}
	}
}