Sharing a folder programmatically and revoking it. (Delphi 7)
Question
- How does one programmatically create a UNC share from a known directory?
- How does one revoke it programmatically?
I don't want the user to fiddle with the Share dialog. Additional info such as changing the share name, comment, user limit is also welcomed.
Thanks SoulBlade (Using Delphi 7)
Solution
Create the share with NetShareAdd. This will share the directory with a null ACL, which is equavalent to allowing everyone full access.
Delete the share with NetShareDel.
Madshi's MadSecurity package has a helper which simplifies this down to:
NewShare(path, shareName, remark);
Share(shareName).Delete;
OTHER TIPS
Here's a snippet of code I use with Delphi 2007:
uses
AclApi, AccCtrl;
type
PShareInfo2 = ^TShareInfo2;
TShareInfo2 = packed record
shi2_netname: PWideChar;
shi2_type: DWORD;
shi2_remark: PWideChar;
shi2_permissions: DWORD;
shi2_max_uses: DWORD;
shi2_current_uses: DWORD;
shi2_path: PWideChar;
shi2_passwd: PWideChar;
end;
const
SECURITY_WORLD_SID_AUTHORITY: TSidIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 1));
SECURITY_WORLD_RID = ($00000000);
NERR_Success = 0;
advapi = 'advapi32.dll';
netapi = 'netapi32.dll';
procedure BuildExplicitAccessWithNameW(pExplicitAccess: PEXPLICIT_ACCESS_W; pTrusteeName: PWideChar;
AccessPermissions: DWORD; AccessMode: ACCESS_MODE; Ineritance: DWORD); stdcall;
external advapi name 'BuildExplicitAccessWithNameW';
function GetNamedSecurityInfoW(pObjectName: PWideChar; ObjectType: SE_OBJECT_TYPE; SecurityInfo: SECURITY_INFORMATION;
ppsidOwner, ppsidGroup: PPSID; ppDacl, ppSacl: PACL; var ppSecurityDescriptor: PSECURITY_DESCRIPTOR): DWORD; stdcall;
external advapi name 'GetNamedSecurityInfoW';
function NetShareAdd(servername: PWideChar; level: DWORD; buf: Pointer; parm_err: LPDWORD): DWORD; stdcall;
external netapi;
function NetShareDel(servername, netname: PWideChar; reserved: DWORD): DWORD; stdcall; external netapi;
function SetNamedSecurityInfoW(pObjectName: PWideChar; ObjectType: SE_OBJECT_TYPE; SecurityInfo: SECURITY_INFORMATION;
ppsidOwner, ppsidGroup: PPSID; ppDacl, ppSacl: PACL): DWORD; stdcall; external advapi name 'SetNamedSecurityInfoW';
procedure NetApiCheck(RetValue: Cardinal);
begin
if RetValue <> ERROR_SUCCESS then
RaiseLastOSError(RetValue);
end;
function WideGetEveryoneName: WideString;
var
psid: PSECURITY_DESCRIPTOR;
Dummy: WideString;
NameLen, DomainNameLen: Cardinal;
Use: SID_NAME_USE;
begin
Result := '';
if not AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, psid) then
Exit;
try
NameLen := 0;
DomainNameLen := 0;
Use := 0;
if LookupAccountSidW(nil, psid, nil, NameLen, nil, DomainNameLen, Use) or
(GetLastError <> ERROR_INSUFFICIENT_BUFFER) then
Exit;
if NameLen = 1 then
Exit;
SetLength(Result, NameLen - 1);
SetLength(Dummy, DomainNameLen);
if not LookupAccountSidW(nil, psid, PWideChar(Result), NameLen, PWideChar(Dummy), DomainNameLen, Use) then
Result := '';
finally
FreeSid(psid);
end;
end;
function WideDeleteShare(const ShareName: WideString): Boolean;
begin
Result := NetShareDel(nil, PWideChar(ShareName), 0) = NERR_Success;
end;
procedure WideShareDirectory(const Directory, ShareName, Description: WideString; ReadOnly: Boolean);
var
ShareInfo: TShareInfo2;
OldAcl, NewAcl: PACL;
psid: PSECURITY_DESCRIPTOR;
ExplicitAccess: EXPLICIT_ACCESS_W;
begin
FillChar(ShareInfo, SizeOf(ShareInfo), 0);
ShareInfo.shi2_netname := PWideChar(ShareName);
ShareInfo.shi2_type := STYPE_DISKTREE;
ShareInfo.shi2_remark := PWideChar(Description);
ShareInfo.shi2_max_uses := SHI_USES_UNLIMITED;
ShareInfo.shi2_path := PWideChar(Directory);
NetApiCheck(NetShareAdd(nil, 2, @ShareInfo, nil));
// Full Control to Everyone is granted by default
if not ReadOnly then
Exit;
NetApiCheck(GetNamedSecurityInfoW(PWideChar(ShareName), SE_LMSHARE, DACL_SECURITY_INFORMATION, nil, nil, @OldAcl, nil,
psid));
try
FillChar(ExplicitAccess, SizeOf(ExplicitAccess), 0);
BuildExplicitAccessWithNameW(@ExplicitAccess, PWideChar(WideGetEveryoneName),
GENERIC_READ or STANDARD_RIGHTS_READ or SPECIFIC_RIGHTS_ALL, SET_ACCESS, NO_INHERITANCE);
NetApiCheck(SetEntriesInAclW(1, @ExplicitAccess, OldAcl, NewAcl));
try
NetApiCheck(SetNamedSecurityInfoW(PWideChar(ShareName), SE_LMSHARE, DACL_SECURITY_INFORMATION, nil, nil, NewAcl,
nil));
finally
LocalFree(HLOCAL(NewAcl));
end;
finally
LocalFree(HLOCAL(psid));
end;
end;
You can specify the user limit in TShareInfo2.shi2_max_uses
(my procedure always creates an unlimited share).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow