Autor Beitrag
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 08.12.03 22:34 
Unit zum Verwalten von Benutzerkonten auf NT Maschinen

Version: 2.5
Datum: 2005-10-12
Download: MpuNTUser.pas [25 KB]
zusätzlich benötigte Units: MpuWinNT.pas [15 KB]; MpuRegistry.pas [7 KB]

ausblenden volle Höhe Delphi-Quelltext
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:
(*======================================================================*
 | Project  :                                                           |
 | Unit     : MpuNTUser.pas                                             |
 |                                                                      |
 | Notes    : Unit for administrating user-accounts on a NT machines.   |
 |            Requires: MpuWinNT, MpuRegistry                           |
 |                                                                      |
 |                                                                      |
 | Copyright (c) 2005 Michael Puff (MPu)                                |
 | Url      : http://www.luckie-online.de                               |
 | Mail     : mpuff@luckie-online.de                                    |
 |                                                                      |
 | Version  Date        By    Description                               |
 | -------  ----------  ----  ------------------------------------------|
 | 1.0      2003-12-08  MPu                                             |
 | 2.0      2004-10-01  MPu   Bugs fixed. Own header translations       |
 | 2.1      2004-10-20  MPu   Bugs fixed.                               |
 | 2.2      2004-10-24  Mpu   even more bugs fixed                      |
 | 2.3      2004-10-30  MPu   added GetMembersInGroup                   |
 | 2.4      2005-02-16  MPu   Fixed password bug                        |
 | 2.5      2005-10-12  MPu   added UserModalsGet                       |
 |                                                                      |
 *======================================================================*)


(*======================================================================*
 |                                                                      |
 |                        COPYRIGHT NOTICE                              |
 |                                                                      |
 | Copyright (c) 2001-2005, Michael Puff ["copyright holder(s)"]        |
 | All rights reserved.                                                 |
 |                                                                      |
 | Redistribution and use in source and binary forms, with or without   |
 | modification, are permitted provided that the following conditions   |
 | are met:                                                             |
 |                                                                      |
 | 1. Redistributions of source code must retain the above copyright    |
 |    notice, this list of conditions and the following disclaimer.     |
 | 2. Redistributions in binary form must reproduce the above copyright |
 |    notice, this list of conditions and the following disclaimer in   |
 |    the documentation and/or other materials provided with the        |
 |    distribution.                                                     |
 | 3. The name(s) of the copyright holder(s) may not be used to endorse |
 |    or promote products derived from this software without specific   |
 |    prior written permission.                                         |
 |                                                                      |
 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
 | FORA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE        |
 | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;     |
 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER     |
 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT   |
 | LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY |
 | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
 | POSSIBILITY OF SUCH DAMAGE.                                          |
 |                                                                      |
 *======================================================================*)


unit MPuNTUser;

interface

uses
  windows, MpuWinNT, MpuRegistry, ActiveX;

type
  TStringArray = array of WideString;

type
  TUserInfo3 = record
    usri3_name: LPWSTR;
    usri3_password: LPWSTR;
    usri3_password_age: DWORD;
    usri3_priv: DWORD;
    usri3_home_dir: LPWSTR;
    usri3_comment: LPWSTR;
    usri3_flags: DWORD;
    usri3_script_path: LPWSTR;
    usri3_auth_flags: DWORD;
    usri3_full_name: LPWSTR;
    usri3_usr_comment: LPWSTR;
    usri3_parms: LPWSTR;
    usri3_workstations: LPWSTR;
    usri3_last_logon: DWORD;
    usri3_last_logoff: DWORD;
    usri3_acct_expires: DWORD;
    usri3_max_storage: DWORD;
    usri3_units_per_week: DWORD;
    usri3_logon_hours: PBYTE;
    usri3_bad_pw_count: DWORD;
    usri3_num_logons: DWORD;
    usri3_logon_server: LPWSTR;
    usri3_country_code: DWORD;
    usri3_code_page: DWORD;
    usri3_user_id: DWORD;
    usri3_primary_group_id: DWORD;
    usri3_profile: LPWSTR;
    usri3_home_dir_drive: LPWSTR;
    usri3_password_expired: DWORD;
  end;
  PUserInfo3 = ^TUserInfo3;

  TUSER_MODALS_INFO_0 = record
    usrmod0_min_passwd_len: DWORD;
    usrmod0_max_passwd_age: DWORD;
    usrmod0_min_passwd_age: DWORD;
    usrmod0_force_logoff: DWORD;
    usrmod0_password_hist_len: DWORD;
  end;
  PUser_Modals_Info_0 = ^TUser_Modals_Info_0;

const
  FILTER_TEMP_DUPLICATE_ACCOUNT = $0001;
  FILTER_NORMAL_ACCOUNT = $0002;
  FILTER_PROXY_ACCOUNT = $0004;
  FILTER_INTERDOMAIN_TRUST_ACCOUNT = $0008;
  FILTER_WORKSTATION_TRUST_ACCOUNT = $0010;
  FILTER_SERVER_TRUST_ACCOUNT = $0020;

  UF_PASSWD_CANT_CHANGE = $0040;
  UF_DONT_EXPIRE_PASSWD = $10000;
  UF_ACCOUNTDISABLE = $0002;

  TIMEQ_FOREVER     = DWord(-1);

function GetUserGroups(const Server, User: WideString): TStringArray;
function EnumGroups(const Server: WideString): TStringArray;
function GetMembersInGroup(const Server: WideString; Group: WideString):
  TStringArray;
function GetUserInfo(const Server, User: WideString; var ret: TUserInfo3):
  NET_API_STATUS;
function SetUserInfo(const Server, User: WideString; const UserInfo:
  TUserInfo3; PasswordHasChanged: Boolean): NET_API_STATUS;
function EnumUsers(const Server: WideString; filter: DWORD): TStringArray;
function AddUser(const Server, User, Password: WideString): NET_API_STATUS;
function DelUser(const Server, User: WideString): NET_API_STATUS;
function RemoveFromGroup(const Server, User, Group: WideString):
  NET_API_STATUS;
function AddToGroup(const Server, User, Group: WideString): NET_API_STATUS;
function IsAccountDisabled(const Server, User: WideString): Boolean;
function UserModalsGet(const Server: WideString): TUSER_MODALS_INFO_0;

function NetErrorStr(dwNetError: DWORD): string;
// Registry Settings
function AutoLogIn(Computer, User: String): Boolean;
function SetAutoLogin(const Machine, User, PW: string): LongInt;
function RemoveAutoLogin(const Machine: string): LongInt;
function HideAccount(const Computer, User: string; Hide: Boolean): LongInt;
function IsAccountHidden(const Machine, User: string): Boolean;

implementation

function IntToStr(Int: integer): string;
begin
  Str(Int, Result);
end;

function SysErrorMessage(ErrorCode: Integer): string;
var
  Len               : Integer;
  Buffer            : array[0..255of Char;
begin
  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
    FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, ErrorCode, 0, Buffer,
    SizeOf(Buffer), nil);
  while (Len > 0and (Buffer[Len - 1in [#0..#32'.']) do
    Dec(Len);
  SetString(Result, Buffer, Len);
end;

function NetErrorStr(dwNetError: DWORD): string;
var
  s                 : string;
resourcestring
  rsERROR_ACCESS_DENIED = 'Zugriff verweigert';
  rsERROR_INVALID_PARAMETER = 'Ungültiger Parameter';
  rsNERR_InvalidComputer = 'Ungültiger Computer';
  rsNERR_NotPrimary =
    'Operation darf nur auf dem Domain-Controller ausgeführt werden';
  rsNERR_SpeGroupOp =
    'Operation darf nicht auf diese Gruppe angewandt werden';
  rsNERR_LastAdmin  =
    'Der letzte Administrator Account kann nicht gelöscht werden';
  rsNERR_BadPassword = 'Ungültiges Passwort';
  rsNERR_PasswordTooShort = 'Passwort zu kurz';
  rsNERR_UserNotFound = 'Ungültiger Benutzer';
  rsNERR_GroupNotFound = 'Gruppe nicht gefunden';
  rsERROR_NO_SUCH_MEMBER = 'Benutzer existiert nicht';
  rsERROR_INVALID_MEMBER = 'Ungültiges Konto';
  rsERROR_MEMBER_IN_ALIAS = 'Benutzer ist schon Mitglied dieser Gruppe';
  rsUnknownError    = 'unbekannter Fehler: ';
  rsErrorCode       = 'Fehlercode ';
begin
  case dwNetError of
    ERROR_ACCESS_DENIED: s := rsERROR_ACCESS_DENIED;
    ERROR_INVALID_PARAMETER: s := rsERROR_INVALID_PARAMETER;
    NERR_InvalidComputer: s := rsNERR_InvalidComputer;
    NERR_NotPrimary: s := rsNERR_NotPrimary;
    NERR_SpeGroupOp: s := rsNERR_SpeGroupOp;
    NERR_LastAdmin: s := rsNERR_LastAdmin;
    NERR_BadPassword: s := rsNERR_BadPassword;
    NERR_PasswordTooShort: s := rsNERR_BadPassword;
    NERR_UserNotFound: s := rsNERR_PasswordTooShort;
    NERR_GroupNotFound: s := rsNERR_GroupNotFound;
    ERROR_NO_SUCH_MEMBER: s := rsERROR_NO_SUCH_MEMBER;
    ERROR_INVALID_MEMBER: s := rsERROR_INVALID_MEMBER;
    ERROR_MEMBER_IN_ALIAS: s := rsERROR_MEMBER_IN_ALIAS;
  else
    s := SysErrorMessage(dwNetError);
  end;
  result := rsErrorCode + IntToStr(dwNetError) + ': ' + s;
end;

function GetAccountSid(const Server, User: WideString; var Sid: PSID): DWORD;
var
  dwDomainSize, dwSidSize: DWord;
  R                 : LongBool;
  wDomain           : WideString;
  Use               : DWord;
begin
  Result := 0;
  SetLastError(0);
  dwSidSize := 0;
  dwDomainSize := 0;
  R := LookupAccountNameW(PWideChar(Server), PWideChar(User), nil, dwSidSize,
    nil, dwDomainSize, Use);
  if (not R) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then
  begin
    SetLength(wDomain, dwDomainSize);
    Sid := GetMemory(dwSidSize);
    R := LookupAccountNameW(PWideChar(Server), PWideChar(User), Sid,
      dwSidSize, PWideChar(wDomain), dwDomainSize, Use);
    if not R then
    begin
      FreeMemory(Sid);
      Sid := nil;
    end;
  end
  else
    Result := GetLastError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : GetUserGroups
// Comment   : Enumerates the groups a user belongs to

function GetUserGroups(const Server, User: WideString): TStringArray;
var
  gui0, pWork       : Pointer;
  Loop              : Integer;
  NetError          : DWORD;
  EntriesRead, EntriesTotal: DWORD;
begin
  gui0 := nil;
  pWork := nil;
  if User <> '' then
  begin
    try
      NetError := NetUserGetLocalGroups(PWideChar(Server), PWideChar(User),
        00, gui0, MAX_PREFERRED_LENGTH, EntriesRead, EntriesTotal);
      if (NetError = NERR_SUCCESS) and (EntriesRead > 0then
      begin
        pwork := gui0;
        SetLength(Result, EntriesRead);
        for Loop := 0 to EntriesRead - 1 do
        begin
          Result[Loop] := PGroupInfo0(gui0)^.grpi0_name;
          Inc(Integer(gui0), sizeof(Pointer));
        end;
      end;
    finally
      NetApiBufferFree(pWork);
    end;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : EnumGroups
// Comment   : Enumerates the existing groups on a local machine

function EnumGroups(const Server: WideString): TStringArray;
var
  lgi01, pWork      : Pointer;
  EntriesRead, EntriesTotal: DWORD;
  NetError          : DWORD;
  Loop              : Integer;
begin
  lgi01 := nil;
  pWork := nil;
  if Server <> '' then
  begin
    try
      NetError := NetLocalGroupEnum(PWideChar(Server), 0, lgi01,
        MAX_PREFERRED_LENGTH, EntriesRead, EntriesTotal, nil);
      if (NetError = NERR_SUCCESS) and (EntriesRead > 0then
      begin
        pWork := lgi01;
        SetLength(Result, EntriesRead);
        for Loop := 0 to EntriesRead - 1 do
        begin
          Result[Loop] := PLocalGroupInfo0(lgi01)^.lgrpi0_name;
          Inc(Integer(lgi01), sizeof(Pointer));
        end;
      end;
    finally
      NetApiBufferFree(pWork)
    end;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : GetUserInfo
// Comment   : Gathers information about the user
//             Incomplete!!!

function GetUserInfo(const Server, User: WideString; var ret: TUserInfo3):
  NET_API_STATUS;
var
  ui3               : PUserInfo3;
  NetError          : DWORD;
begin
  ui3 := nil;
  NetError := 0;
  if User <> '' then
  begin
    try
      NetError := NetUserGetInfo(PWideChar(Server), PWideChar(User), 3,
        Pointer(ui3));
      if NetError = NERR_SUCCESS then
      begin
        with ret do
        begin
          usri3_flags := 0;
          usri3_name := SysAllocString(ui3^.usri3_name);
          usri3_full_name := SysAllocString(ui3^.usri3_full_name);
          usri3_comment := SysAllocString(ui3^.usri3_comment);
          usri3_home_dir := SysAllocString(ui3^.usri3_home_dir);
          usri3_script_path := SysAllocString(ui3^.usri3_script_path);

          usri3_password_age := ui3^.usri3_password_age;
          usri3_last_logon := ui3^.usri3_last_logon;
          usri3_num_logons := ui3^.usri3_num_logons;
          usri3_acct_expires := ui3^.usri3_acct_expires;
          usri3_max_storage := ui3^.usri3_max_storage;
          usri3_user_id := ui3^.usri3_user_id;
          usri3_bad_pw_count := ui3^.usri3_bad_pw_count;
          usri3_password_expired := ui3^.usri3_password_expired;

          if (DWORD(ui3^.usri3_flags and UF_PASSWD_CANT_CHANGE) =
            UF_PASSWD_CANT_CHANGE) then
            usri3_flags := usri3_flags or UF_PASSWD_CANT_CHANGE;
          if (DWORD(ui3^.usri3_flags and UF_DONT_EXPIRE_PASSWD) =
            UF_DONT_EXPIRE_PASSWD) then
            usri3_flags := usri3_flags or UF_DONT_EXPIRE_PASSWD;
          if (DWORD(ui3^.usri3_flags and UF_ACCOUNTDISABLE) =
            UF_ACCOUNTDISABLE) then
            usri3_flags := usri3_flags or UF_ACCOUNTDISABLE;
        end;
      end;
    finally
      NetApiBufferFree(ui3);
    end;
  end;
  result := NetError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : SetUserInfo
// Comment   : Sets account properties

function SetUserInfo(const Server, User: WideString; const UserInfo:
  TUserInfo3; PasswordHasChanged: Boolean): NET_API_STATUS;
var
  ui3               : PUserInfo3;
  NetError          : DWORD;
begin
  ui3 := nil;
  NetError := 0;
  if User <> '' then
  begin
    try
      if NetUserGetInfo(PWideChar(Server), PWideChar(User), 3,
        Pointer(ui3)) = NERR_SUCCESS then
      begin
        with ui3^ do
        begin
          usri3_name := UserInfo.usri3_name;
          usri3_full_name := UserInfo.usri3_full_name;
          if PasswordHasChanged then
            usri3_password := UserInfo.usri3_password;
          usri3_home_dir := UserInfo.usri3_home_dir;
          usri3_comment := UserInfo.usri3_comment;
          usri3_usr_comment := UserInfo.usri3_usr_comment;
          usri3_priv := UserInfo.usri3_priv;
          usri3_script_path := UserInfo.usri3_script_path;
          usri3_auth_flags := UserInfo.usri3_auth_flags;
          usri3_parms := UserInfo.usri3_parms;
          usri3_workstations := UserInfo.usri3_workstations;
          usri3_acct_expires := UserInfo.usri3_acct_expires;
          usri3_max_storage := UserInfo.usri3_max_storage;
          usri3_home_dir_drive := UserInfo.usri3_home_dir_drive;
          usri3_profile := UserInfo.usri3_profile;
          usri3_password_expired := UserInfo.usri3_password_expired;
          usri3_flags := UserInfo.usri3_flags;
        end;
        NetError := NetUserSetInfo(PWideChar(Server), PWideChar(User), 3, ui3, nil);
      end;
    finally
      NetApiBufferFree(ui3);
    end;
  end;
  Result := NetError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : EnumUsers
// Comment   : Enumerates all users on the local machine

function EnumUsers(const Server: WideString; filter: DWORD): TStringArray;
var
  ui1, pWork        : Pointer;
  EntriesRead, EntriesTotal: DWORD;
  NetError          : DWORD;
  Loop              : Integer;
begin
  ui1 := nil;
  pWork := nil;
  if Server <> '' then
  begin
    try
      NetError := NetUserEnum(PWideChar(Server), 0, filter, ui1,
        MAX_PREFERRED_LENGTH, EntriesRead, EntriesTotal, nil);
      if (NetError = NERR_SUCCESS) and (EntriesRead > 0then
      begin
        pWork := ui1;
        SetLength(Result, EntriesRead);
        for Loop := 0 to EntriesRead - 1 do
        begin
          Result[Loop] := PUserInfo1(ui1)^.usri1_name;
          Inc(Integer(ui1), sizeof(Pointer));
        end;
      end;
    finally
      NetApiBufferFree(pWork);
    end;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
//
//  GetMembersInGroup
//
//    Enumerates mebers of a group
//

function GetMembersInGroup(const Server: WideString; Group: WideString): TStringArray;
var
  Member            : Pointer;
  pWork             : Pointer;
  EntriesRead, EntriesTotal: DWORD;
  NetError          : NET_API_STATUS;
  Loop              : Integer;
begin
  Member := nil;
  pWork := nil;
  if (Server <> ''and (Group <> ''then
  begin
    try
      NetError := NetLocalGroupGetMembers(PWideChar(Server), PWideChar(Group), 3, Member, MAX_PREFERRED_LENGTH,
        EntriesRead, EntriesTotal, nil);
      if (NetError = NERR_SUCCESS) and (EntriesRead > 0then
      begin
        pWork := Member;
        SetLength(result, EntriesRead);
        for Loop := 0 to EntriesRead - 1 do
        begin
          Result[Loop] :=
            PLocalGroupMembersInfo3(Member)^.lgrmi3_domainandname;
          Inc(Integer(Member), sizeof(Pointer));
        end;
      end;
    finally
      NetApiBufferFree(pWork);
    end;
  end;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : AddUser
// Comment   : Adds an account on a machine

function AddUser(const Server, User, Password: WideString): NET_API_STATUS;
const
  DOMAIN_GROUP_RID_USERS = $00000201;
var
  ui3                    : TUserInfo3;
  NetError               : DWORD;
begin
//  ui3 := nil;
  NetError := 0;
  if User <> '' then
  begin
    ZeroMemory(@ui3, sizeof(TUserInfo3));
    ui3.usri3_name := PWideChar(User);
    ui3.usri3_password := PWideChar(Password);
    ui3.usri3_primary_group_id := DOMAIN_GROUP_RID_USERS;
    NetError := NetUserAdd(PWideChar(Server), 3, @ui3, nil);
  end;
  result := NetError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : DelUser
// Comment   : Deletes a user on a machine . Returns NET_ERROR Code.

function DelUser(const Server, User: WideString): NET_API_STATUS;
var
  NetError          : DWORD;
begin
  NetError := 0;
  if (Server <> ''and (User <> ''then
  begin
    NetError := NetUserDel(PWideChar(Server), PWideChar(User));
  end;
  result := NetError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : RemoveFromGroup
// Comment   : Removes a user form a group

function RemoveFromGroup(const Server, User, Group: WideString):
  NET_API_STATUS;
var
  Member            : PLocalGroupMembersInfo3;
  NetError          : DWORD;
begin
  NetError := 0;
  if (User <> ''and (Group <> ''and (Server <> ''then
  begin
    GetMem(Member, sizeof(TLocalGroupMembersInfo3));
    try
      Member.lgrmi3_domainandname := PWideChar(copy(Server, 3, length(Server)) + '\' + User);
      NetError := NetLocalGroupDelMembers(PWideChar(Server), PWideChar(Group), 3, Member, 1);
    finally
      FreeMem(Member, sizeof(TLocalGroupMembersInfo3));
    end;
  end;
  result := NetError;
end;

////////////////////////////////////////////////////////////////////////////////
// Procedure : AddToGroup
// Comment   : Adds a user to a group

function AddToGroup(const Server, User, Group: WideString): NET_API_STATUS;
var
  pSID              : Pointer;
  NetError          : DWORD;
begin
  pSID := nil;
  NetError := 0;
  if (User <> ''and (Group <> ''and (Server <> ''then
  begin
    if (GetAccountSid(Server, User, pSID) = 0and Assigned(pSID) then
    begin
      NetError := NetLocalGroupAddMembers(PWideChar(Server), PWideChar(Group), 0, @pSID, 1);
      FreeMemory(pSID);
    end;
  end;
  result := NetError;
end;

function IsAccountDisabled(const Server, User: WideString): Boolean;
var
  ui3               : PUserInfo3;
  NetError          : DWORD;
begin
  result := True;
  ui3 := nil;
  if User <> '' then
  begin
    try
      NetError := NetUserGetInfo(PWideChar(Server), PWideChar(User), 3,
        Pointer(ui3));
      if NetError = NERR_SUCCESS then
        result := (DWORD(ui3^.usri3_flags and UF_ACCOUNTDISABLE) =
          UF_ACCOUNTDISABLE);
    finally
      NetApiBufferFree(ui3);
    end;
  end;
end;

function UserModalsGet(const Server: WideString): TUSER_MODALS_INFO_0;
var
  UserModalsInfo    : PUSER_MODALS_INFO_0;
  dwRet             : DWORD;
begin
  UserModalsInfo := nil;
  dwRet := NetUserModalsGet(nil0, Pointer(UserModalsInfo));
  if ((dwRet = NERR_Success) and Assigned(UserModalsInfo)) then
  begin
    result.usrmod0_min_passwd_len := UserModalsInfo.usrmod0_min_passwd_len;
    result.usrmod0_max_passwd_age := UserModalsInfo.usrmod0_max_passwd_age;
    result.usrmod0_min_passwd_age := UserModalsInfo.usrmod0_min_passwd_age;
    result.usrmod0_force_logoff := UserModalsInfo.usrmod0_force_logoff;
    result.usrmod0_password_hist_len := UserModalsInfo.usrmod0_password_hist_len;
    NetApiBufferFree(UserModalsInfo);
  end;
end;

function AutoLogIn(Computer, User: String): Boolean;
var
  MyReg : TMpuRegistry;
  AutoLogon: string;
  DefaultUsername: string;
begin
  MyReg := TMpuRegistry.Create(Computer, HKEY_LOCAL_MACHINE);
  try
    with MyReg do
    begin
      Connect;
      if OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon', KEY_READ) = 0 then
      begin
        ReadString('AutoAdminLogon', AutoLogon);
        ReadString('DefaultUsername', DefaultUsername);
      end;
    end;
  finally
    MyReg.Free;
  end;
  result := (AutoLogon = '1'and (DefaultUsername = User);
end;

function SetAutoLogin(const Machine, User, PW: string): LongInt;
var
  MyReg             : TMpuRegistry;
  ret               : LongInt;
begin
  MyReg := TMpuRegistry.Create(Machine, HKEY_LOCAL_MACHINE);
  try
    with MyReg do
    begin
      ret := Connect;
      if ret = 0 then
      begin
        ret :=
          OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
          KEY_WRITE);
        if ret = 0 then
        begin
          WriteStringW('DefaultUsername', User);
          WriteStringW('DefaultPassword', PW);
          WriteStringW('AutoAdminLogon''1');
        end;
      end;
    end;
  finally
    MyReg.Free;
  end;
  result := ret;
end;

function RemoveAutoLogin(const Machine: string): LongInt;
var
  MyReg             : TMpuRegistry;
  ret               : LongInt;
begin
  MyReg := TMpuRegistry.Create(Machine, HKEY_LOCAL_MACHINE);
  try
    with MyReg do
    begin
      ret := Connect;
      if ret = 0 then
      begin
        ret :=
          OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
          KEY_WRITE);
        if ret = 0 then
        begin
          ret := DeleteValueName('DefaultPassword');
          ret := WriteString('AutoAdminLogon''0');
        end;
      end;
    end;
  finally
    MyReg.Free;
  end;
  result := ret;
end;

function IsAccountHidden(const Machine, User: string): Boolean;
var
  MyReg             : TMpuRegistry;
  ret               : Integer;
  Hidden            : LongInt;
begin
  result := False;
  MyReg := TMpuRegistry.Create(Machine, HKEY_LOCAL_MACHINE);
  try
    with MyReg do
    begin
      ret := Connect;
      if ret = 0 then
      begin
        ret :=
          OpenKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList', KEY_READ);
        if ret = 0 then
        begin
          ReadInt(User, Hidden);
          result := Hidden = 0;
        end
        else
          result := False;
      end;
    end;
  finally
    MyReg.Free;
  end;
end;

function HideAccount(const Computer, User: string; Hide: Boolean): LongInt;
var
  MyReg             : TMpuRegistry;
  ret               : LongInt;
begin
  MyReg := TMpuRegistry.Create(Computer, HKEY_LOCAL_MACHINE);
  try
    with MyReg do
    begin
      ret := Connect;
      if ret = 0 then
      begin
        ret := CreateKey(HKEY_LOCAL_MACHINE,
          'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList');
        if ret = 0 then
        begin
          if Hide then
            ret := WriteInt(User, 0)
          else
            ret := WriteInt(User, 1);
        end;
      end;
    end;
  finally
    MyReg.Free;
  end;
  result := ret;
end;

end.


Zuletzt bearbeitet von Luckie am Mi 02.11.05 13:59, insgesamt 4-mal bearbeitet
G-man
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 258

Win 2000, Win ME, SuSE 8.2
D5 Standard, D6 Professional
BeitragVerfasst: Di 09.12.03 18:10 
Ist eine nützliche Unit (vor allem für Netzwerkadministratoren).

_________________
...To err is human, but to really foul things up requires a computer.
focus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 187

XP, 2k, 98, Me
D6 Prof
BeitragVerfasst: Fr 12.12.03 11:32 
nutzbar ist AddUser aber nur wenn man adminrechte hat oder?

Gruss
Michael

_________________
Wer im Leben kein Ziel hat, verläuft sich.
Chatfix
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 1583
Erhaltene Danke: 10

Win 10, Win 8, Win 7, Win Vista, Win XP
VB.net (VS 2015), MsSQL (T-SQL), HTML, CSS, PHP, MySQL
BeitragVerfasst: Fr 12.12.03 12:08 
Alle funktionen sollte man nur machen können wenn man Adminrechte hat ;-)

_________________
Gehirn: ein Organ, mit dem wir denken, daß wir denken. - Ambrose Bierce
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 12.12.03 12:31 
Nun ja, etwas muss musst du schon selber machen. Und sicherstellen, dass man Admin-Rechte hat, bleibt eben dir überlassen.
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: Di 15.03.05 01:14 
aus gegebenem anlass ;) könntest du noch eine setFolderPerm funktion einbauen - das wäre dann der overkill

_________________
es gibt leute, die sind genetisch nicht zum programmieren geschaffen.
in der regel haben diese leute die regel...
Holgerwa
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 325

WIN XP Pro, Vista Business
Delphi 7 Pro, BDS 2006 Pro
BeitragVerfasst: Di 15.03.05 08:59 
Hallo,

sieht super aus, vielen Dank :)
Kann man eigentlich davon ausgehen, daß solche Funktionen, die also ab NT laufen, 100% auch auf Win-2000 und XP funktionieren?
Oder gibts da etwas zu beachten?

Holger
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 15.03.05 12:59 
Es gibt eine neue Version! Siehe oben.

Also getestet sind diese Unit nur unter 2000 und XP. Man kann aber im PSDK nachschlagen und gucken, ob Anmerkungen zu NT oder so dabei stehen.
Pepe
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 107

Win 98, Win 2000 Prof., Win XP Prof.
Delphi 2005 Prof.
BeitragVerfasst: Sa 29.10.05 11:30 
Hoi, wie sieht das aus bei nem ADS-Domänencontroller, ist die UNIT dort auch einsetzbar?

so long
Pepe
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 29.10.05 14:52 
Nein. Bisher kann man damit nir lokale Konten auf Rechnern verwalten.
Pepe
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 107

Win 98, Win 2000 Prof., Win XP Prof.
Delphi 2005 Prof.
BeitragVerfasst: Sa 29.10.05 20:30 
nicht ganz, habs ausprobiert, wenn man die flags richtig setzt, funktioniert es erste sahne unter active directory :D

Muss man schon sagen, die Units sind TOP!


Nur wie man die User in Container Packt hab ich noch nicht rausgefunden, is aber nicht so wild, dafür kann man ja ne neue gruppe erstellen, die alle da eintragen lassen und diese dann in einen container schieben :)
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 31.10.05 00:29 
Welche Flags richtig setzen? Und dann geht auch ADS? Das Problem ist, da ich keinen Server hier zur Verfügung habe, konnte ich das nie testen.
Pepe
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 107

Win 98, Win 2000 Prof., Win XP Prof.
Delphi 2005 Prof.
BeitragVerfasst: Di 01.11.05 06:01 
Du musst eigentlich nur beachten, das du die lifetime des accounts, sowie pw etc. richtig setzt!
Desweiteren kann man mit den Units nur die Gruppen des Typs "Lokale Domäne | Sicherheit" verwalten, wobei man auch auf Gruppen des Typs Global ohne Probleme zugreifen kann, wenn man die Units um die NetGroup*-Funktionen erweitert. Bei den Usern ist es Recht wurscht, da diese so oder so nur für die Lokale-Domäne gelten. Um den Usern Admin-Rechte etc. zu geben, ist es allerdings nicht notwendig die NetGroup*-Funktionen einzubinden, da die standart gruppen eh alle vom Typ "Lokale Domäne" sind.
Ab Server 2003 und XP Clients kann man auch mit GROUP_INFO_3 arbeiten, habe ich aber nicht ausprobiert, da ich diese nicht brauchte und man dafür die funktionen zu verwaltung von SID's auch noch hätte einbinden müssen.

Soweit meine Erfahrungen bis jetzt.

Wenn man sich die Api-funktionen bei MSDN anguckt, steht in der Regel eigentlich auch immer noch dabei, wie Sich die einzelnen Funktionen unter ADS verhalten bzw. das Sie sich eigentlich genauso verhalten. Wie man die Gruppen dann allerdings in Container verschiebt und Policies bearbeitet habe ich noch nicht herausgefunden, weiß jemand dort evtl. wo ich die entsprechenden API funktionen finde? bei MSDN bin ich nicht wirklich weiter gekommen bis jetzt...

so long,
Pepe
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 01.11.05 13:07 
user profile iconPepe hat folgendes geschrieben:
wenn man die Units um die NetGroup*-Funktionen erweitert.

Das habe ich im PSDK natürlich auch gesehen, als ich den Usermanager angefangen habe. Aber da ich hier keinen PDC und ein entsprechendes Netzwerk zur Verfügung habe, konnte ich das nie probieren und so ins Blaue programmieren ist immer schlecht. ;)
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: Di 01.11.05 13:19 
user profile iconLuckie hat folgendes geschrieben:
user profile iconPepe hat folgendes geschrieben:
wenn man die Units um die NetGroup*-Funktionen erweitert.

Das habe ich im PSDK natürlich auch gesehen, als ich den Usermanager angefangen habe. Aber da ich hier keinen PDC und ein entsprechendes Netzwerk zur Verfügung habe, konnte ich das nie probieren und so ins Blaue programmieren ist immer schlecht. ;)

nimm einfach VMWare...

_________________
es gibt leute, die sind genetisch nicht zum programmieren geschaffen.
in der regel haben diese leute die regel...
Pepe
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 107

Win 98, Win 2000 Prof., Win XP Prof.
Delphi 2005 Prof.
BeitragVerfasst: Di 01.11.05 13:19 
hehe, das ist wohl wahr...

ich hab allerdings die Funktion NetLocalGroupAdd und NetLocalGroupDel vermisst warum haste die nicht mit reingenommen?
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 02.11.05 13:51 
Weil ich bisher noch nicht rausgefunden habe, wie ich Gruppen Rechte nehme bzw. gebe. Also Richtlinien zuweise oder wie man das nennt.
Pepe
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 107

Win 98, Win 2000 Prof., Win XP Prof.
Delphi 2005 Prof.
BeitragVerfasst: Fr 04.11.05 15:57 
was meinst du damit genau? den gruppen admin status oder ähnliches geben?
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 04.11.05 19:18 
Genau das meine ich, ansonsten hat es ja keinen Sinn.