Old 6th April 2007, 12:12   #1
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Create folder share using system plugin

I am trying to create a network share with NSIS using the system plugin.
I do not want to call net share from a command prompt since I want to give access only to a specific user for the share.
I am trying to implement this idea in nsis:
code:
...
!define NO_MULTIPLE_TRUSTEE 0
!define TRUSTEE_IS_SID 0
!define TRUSTEE_IS_USER 1
!define GENERIC_READ 8
!define GENERIC_EXECUTE 2
!define SET_ACCESS 2
!define STYPE_DISKTREE 0
!define SECURITY_DESCRIPTOR_REVISION 0
!define NO_INHERITANCE 0
!define ACCESS_READ 0x1
!define ACCESS_EXEC 0x8
!define strEXPLICIT_ACCESS '(i,i,i,i)i'
!define strTRUSTEE '(i,i,i,i,t)i'
!define strSHARE_INFO_502 '(w,i,w,i,i,i,w,w,i,i)i'
...
System::Call '*${strTRUSTEE}(0,${NO_MULTIPLE_TRUSTEE},${TRUSTEE_IS_SID},${TRUSTEE_IS_USER},$R8).R7'
System::Call '*${strEXPLICIT_ACCESS}(${GENERIC_READ}|${GENERIC_EXECUTE},${SET_ACCESS},${NO_INHERITANCE},R7).R6'
System::Call 'advapi32::SetEntriesInAclA(i 1,i R6,i n,*i .R5)i.r1'
System::Call 'advapi32::InitializeSecurityDescriptor(*i.R4,i ${SECURITY_DESCRIPTOR_REVISION})i.r1'
System::Call 'advapi32::SetSecurityDescriptorDacl(i R4,i 1,i R5,i 0)i.r1'
System::Call '*${strSHARE_INFO_502}("Some Name",${STYPE_DISKTREE},"Comment",${ACCESS_READ}|${ACCESS_EXEC},-1,0,"F:\NewShare","",0,R4).R0'
System::Call 'netapi32::NetShareAdd(,i 502,i R0,*i .R1)i.r1'

The code breaks at the SetEntriesInAclA call with error 87 (invalid parameter). I tried to define the EXPLICIT_ACCESS structure as:
code:
System::Call '*${strEXPLICIT_ACCESS}(${GENERIC_READ}|${GENERIC_EXECUTE},${SET_ACCESS},${NO_INHERITANCE},0,${NO_MULTIPLE_TRUSTEE},${TRUSTEE_IS_SID},${TRUSTEE_IS_USER},$R8).R6'
including the TRUSTEE information as well, where $R8 is a valid user SID which I get using the LookupAccountName and ConvertSidToStringSid calls of advapi32.dll, but I am still getting error 87.

Any insights?


CF
CancerFace is offline   Reply With Quote
Old 8th April 2007, 16:31   #2
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
strEXPLICIT_ACCESS is not defined properly. In your definition it contains four integers, but there's no mention of the TRUSTEE structure.

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 8th April 2007, 19:00   #3
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Hi kichik,
thanks for the input!

I realize that the second example I used actually is wrong (blame it on copy/paste) as I redefined the strEXPLICIT_ACCESS in order to contain also the TRUSTEE structure.

Here is the correct 2nd part of the post:
code:
...
!define strEXPLICIT_ACCESS '(i,i,i,i,i,i,i,t)i
System::Call '*${strEXPLICIT_ACCESS}(${GENERIC_READ}|${GENERIC_EXECUTE},${SET_ACCESS},${NO_INHERITANCE},0,${NO_MULTIPLE_TRUSTEE},${TRUSTEE_IS_SID},${TRUSTEE_IS_USER},$R8).R6'
System::Call 'advapi32::SetEntriesInAclA(i 1,i R6,i n,*i .R5)i.r1'

I am still getting error 87 and I am not sure why ...

CF
CancerFace is offline   Reply With Quote
Old 8th April 2007, 19:06   #4
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
Can you attach a complete example I can test?

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 8th April 2007, 19:26   #5
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Hi kichik,
I am attaching the nsi file that I am working on.
Thanks for taking the time to look at this
CF
Attached Files
File Type: nsi createshare.nsi (5.0 KB, 494 views)
CancerFace is offline   Reply With Quote
Old 8th April 2007, 20:00   #6
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
When passing TRUSTEE_IS_SID, you must pass a real SID, not a string representation of the SID or a string representation of a pointer to it. Use `i R9` instead of `t R8`.

BTW, it crashes right away if the provided user name doesn't exist. A little error handling won't hurt

Also, $R5 should be freed using LocalFree as documented by MSDN and not by System::Free.

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 8th April 2007, 20:21   #7
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Hmmm ...
I tried it with the SID buffer (R9) but it still gives me error 87 ...

This is a test build hence the lack of error checking ... A good idea nonetheless

Thanks for the help as always!

CF
CancerFace is offline   Reply With Quote
Old 8th April 2007, 20:27   #8
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
Did you change `t` to `i` in the definition of strEXPLICIT_ACCESS?

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 8th April 2007, 20:33   #9
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace


Yes (I get error 87 with 'i R9' or 't R8')
CancerFace is offline   Reply With Quote
Old 8th April 2007, 20:40   #10
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
Weird, it worked fine for me as attached... Make sure the SID came out right. Though I don't get 87 even with an invalid user (but the SID pointer still points somewhere).
Attached Files
File Type: nsi createshare.nsi (5.0 KB, 491 views)

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 8th April 2007, 20:47   #11
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Hmmm...

Both the SID buffer (R9) and the string SID (R8) look OK and I still get error 87 ($1 on the message box) ...



Even worse, if I pass an invalid username then it works ($1 is 0 and $R5 gets an address)

?

CancerFace is offline   Reply With Quote
Old 9th April 2007, 01:09   #12
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,216
87=The parameter is incorrect
and
0x87=An attempt was made to use a JOIN or SUBST command on a drive that has already been substituted.

not sure if its in hex or not, but i would guess the parameter is incorrect

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 24th April 2007, 12:48   #13
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Finally got it!

I was freeing the SID buffer ($R4) inside the LookupAccountName macro and as such the SetEntriesInAcl call would fail with error 87 (where did you find the 0x87 error Anders? It is not hex, it is a standard error code after all).

So for anyone who is interested here is a macro that will create a share giving read permission to a specified user. I am including more definitions in case someone wants to modify this in any way:
code:
!include "LogicLib.nsh"
# Definitions and user flags
!define STYPE_DISKTREE 0
!define ACCESS_READ 0x01
!define ACCESS_WRITE 0x02
!define ACCESS_CREATE 0x04
!define ACCESS_EXEC 0x08
!define ACCESS_DELETE 0x10
!define ACCESS_ATRIB 0x20
!define ACCESS_PERM 0x40
!define ACCESS_ALL 0x7F
# Permissions
!define GENERIC_READ 0x80000000
!define GENERIC_WRITE 0x40000000
!define GENERIC_EXECUTE 0x20000000
!define GENERIC_ALL 0x10000000
!define NO_INHERITANCE 0x0
!define SECURITY_DESCRIPTOR_REVISION 1
# ACCESS_MODE values
!define NOT_USED_ACCESS 0
!define GRANT_ACCESS 1
!define SET_ACCESS 2
!define DENY_ACCESS 3
!define REVOKE_ACCESS 4
!define SET_AUDIT_SUCCESS 5
!define SET_AUDIT_FAILURE 6
# MULTIPLE_TRUSTEE_OPERATION values
!define NO_MULTIPLE_TRUSTEE 0
!define TRUSTEE_IS_IMPERSONATE 1
# TRUSTEE_FORM values
!define TRUSTEE_IS_SID 0
!define TRUSTEE_IS_NAME 1
!define TRUSTEE_BAD_FORM 2
!define TRUSTEE_IS_OBJECTS_AND_SID 3
!define TRUSTEE_IS_OBJECTS_AND_NAME 4
# TRUSTEE_TYPE values
!define TRUSTEE_IS_UNKNOWN 0
!define TRUSTEE_IS_USER 1
!define TRUSTEE_IS_GROUP 2
!define TRUSTEE_IS_DOMAIN 3
!define TRUSTEE_IS_ALIAS 4
!define TRUSTEE_IS_WELL_KNOWN_GROUP 5
!define TRUSTEE_IS_DELETED 6
!define TRUSTEE_IS_INVALID 7
!define TRUSTEE_IS_COMPUTER 8
# Structure Definitions
!define strSHARE_INFO_2 '(w,i,w,i,i,i,w,w)i'
!define strSHARE_INFO_502 '(w,i,w,i,i,i,w,w,i,i)i'
!define strEXPLICIT_ACCESS '(i,i,i,i,i,i,i,i)i'


!macro CreateNewShare USERNAME SHARENAME SHARE_TYPE SHARE_COMMENT SHARE_PERMISSIONS ACL_ACCESS MAX_USERS CURRENT_USES SHARE_PATH SHARE_PASS
# Get the user's SID from the username
System::Call /NOUNLOAD '*(&w${NSIS_MAX_STRLEN})i.R9'
System::Call /NOUNLOAD 'advapi32::LookupAccountNameA(,t "${USERNAME}",i R9,*i ${NSIS_MAX_STRLEN},w .R8,*i ${NSIS_MAX_STRLEN},*i .r4)i.r5'
System::Call /NOUNLOAD 'advapi32::ConvertSidToStringSid(i R9,*t .R8)i.r5'
${If} $R8 == ''
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'User "${USERNAME}" does not exist!$\nAborting...'
System::Free $R9
Quit
${EndIf}
# Create an EXPLICIT_ACCESS structure and place it on $R6
System::Call /NOUNLOAD '*${strEXPLICIT_ACCESS}(${ACL_ACCESS},${SET_ACCESS},${NO_INHERITANCE},0, ${NO_MULTIPLE_TRUSTEE},${TRUSTEE_IS_SID},${TRUSTEE_IS_USER},$R9).R6'
System::Call /NOUNLOAD 'advapi32::SetEntriesInAclA(i 1,i R6,,*i .R5)i.r1'
${If} $1 <> 0
System::Free $R9
System::Free $R6
Quit
${EndIf}
# Create an empty security descriptor and place it in R4.
System::Alloc ${NSIS_MAX_STRLEN}
Pop $R4
System::Call /NOUNLOAD 'advapi32::InitializeSecurityDescriptor(i R4,i ${SECURITY_DESCRIPTOR_REVISION})i.r1'
${If} $1 == 0
System::Free $R9
System::Free $R6
System::Call 'kernel32::LocalFree(i R5)i.r0'
Quit
${EndIf}
# Add the ACL to the security descriptor
System::Call /NOUNLOAD 'advapi32::SetSecurityDescriptorDacl(i R4,i 1,i R5,i 0)i.r1'
${If} $1 == 0
System::Free $R9
System::Free $R6
System::Call 'kernel32::LocalFree(i R5)i.r0'
Quit
${EndIf}
# Generate the structure that holds the share info and place it on $R0
System::Call /NOUNLOAD '*${strSHARE_INFO_502}("${SHARENAME}",${SHARE_TYPE},"${SHARE_COMMENT}",${SHARE_PERMISSIONS},${MAX_USERS},${CURRENT_USES},"${SHARE_PATH}","${SHARE_PASS}",0,R4).R0'
System::Call /NOUNLOAD 'netapi32::NetShareAdd(, i 502, i R0, *i .R1) i .r1'
${If} $1 <> 0
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'There was an error creating the share!'
${EndIf}
# Cleanup
System::Free $R9
System::Free $R6
System::Call 'kernel32::LocalFree(i R5)i.r0'
System::Free $R0
!macroend

In order to create a share and give it read access to the user jdoe call the macro like this:
code:
!insertmacro CreateNewShare "jdoe" "Name for the share" ${STYPE_DISKTREE} "share description" ${ACCESS_ALL} ${GENERIC_READ}|${GENERIC_EXECUTE} -1 0 "C:\<some_folder_to_share>" ""
In order to create a share with full access for the user jdoe call the macro like this:
code:
!insertmacro CreateNewShare "jdoe" "Name for the share" ${STYPE_DISKTREE} "share description" ${ACCESS_ALL} ${GENERIC_ALL} -1 0 "C:\<some_folder_to_share>" ""
and so on.

Thanks for the help guys!

CF
CancerFace is offline   Reply With Quote
Old 24th April 2007, 14:36   #14
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
Sometimes we may want to create a share with full access for everyone, without specifying extra permissions.
This can be done with the above code by using the SHARE_INFO_2 structure. Here it is in a macro:
code:
!define strSHARE_INFO_2 '(w,i,w,i,i,i,w,w)i'
!macro CreateNewFullShare SHARENAME SHARE_TYPE SHARE_COMMENT SHARE_PERMISSIONS MAX_USERS CURRENT_USES SHARE_PATH SHARE_PASS
System::Call /NOUNLOAD '*${strSHARE_INFO_2}("${SHARENAME}",${SHARE_TYPE},"${SHARE_COMMENT}",${SHARE_PERMISSIONS},${MAX_USERS},${CURRENT_USES},"${SHARE_PATH}","${SHARE_PASS}")i.R0'
System::Call /NOUNLOAD 'netapi32::NetShareAdd(, i 2, i R0, *i .R1) i .r1'
${If} $1 <> 0
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'There was an error creating the share!'
${EndIf}
System::Free $R0
!macroend


To use it call it from within your code:
code:
!insertmacro CreateNewFullShare "Share Name" ${STYPE_DISKTREE} "Share Description" 0 -1 0 "X:\<folder_to_share>" ""


Also added a wiki page for all the above

CF
CancerFace is offline   Reply With Quote
Old 2nd April 2008, 08:54   #15
fantrs91
Junior Member
 
Join Date: Apr 2008
Posts: 5
Hi,
Your macros are very useful :-)

Does any one have another one which allows to unshare a directory ? I need this for my uninstaller script.

Thanks
fantrs91 is offline   Reply With Quote
Old 3rd April 2008, 00:46   #16
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
You can use NetShareDel to remove a share from a computer, assuming that you have admin/power user rights. Note however that this will also close any active connections to the share ...

Here is a very simple macro version of the above without any error checking:
code:
!macro RemoveShare SHARENAME
System::Call /NOUNLOAD 'netapi32::NetShareDel(, *t ${SHARENAME}, i 0) i .r1'
${If} $1 <> 0
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'There was an error removing the share!'
${EndIf}
!macroend


To use it call it from within your code:
code:
!insertmacro RemoveShare "ShareName"


Let me know if this works (untested)
CF
CancerFace is offline   Reply With Quote
Old 14th April 2008, 12:58   #17
fantrs91
Junior Member
 
Join Date: Apr 2008
Posts: 5
Hi,
thanks for your reply !
I just tried your RemoveShare macro, and it does not work :'-(

Let me explain:
In my installation procedure I use the following:

!insertmacro CreateNewFullShare "MY_SHARE" ${STYPE_DISKTREE} "blablabla" 0 -1 0 "$INSTDIR" ""

And in my uninstaller:

!insertmacro RemoveShare "MY_SHARE"

But while uninstallation I get the message from the macro: 'There was an error removing the share!'


I will try to investigate.
fantrs91 is offline   Reply With Quote
Old 15th April 2008, 21:21   #18
CancerFace
Senior Member
 
Join Date: Apr 2006
Posts: 289
Send a message via ICQ to CancerFace
My bad, it should be a unicode string ...
This one works:
code:
!macro RemoveShare SHARENAME
System::Call /NOUNLOAD 'netapi32::NetShareDel(, w "${SHARENAME}",i 0) i .r1'
${If} $1 <> 0
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'There was an error removing the share!"'
${EndIf}
!macroend



CF
CancerFace is offline   Reply With Quote
Old 25th April 2008, 15:43   #19
fantrs91
Junior Member
 
Join Date: Apr 2008
Posts: 5
This one works flawlessly.
Thanks a lot!
fantrs91 is offline   Reply With Quote
Old 21st April 2011, 10:47   #20
deinename
Junior Member
 
Join Date: Jul 2007
Location: Poland
Posts: 6
I don't know why but none of above scripts worked for me.
I managed to share a folder using standard windows command line like this:
code:
nsExec::ExecToStack 'net share "name"="dir_to_share" /remark:"share description"'
pop $NET_SHARE_RETURN_CODE
${If} $NET_SHARE_RETURN_CODE = 0
MessageBox MB_OK|MB_ICONSTOP|MB_TOPMOST 'Share created'
${EndIf}


if return code is "2" than a share with this name already exists
deinename is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump