Question

  1. How does one programmatically create a UNC share from a known directory?
  2. 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)

Was it helpful?

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
scroll top