Since 1.3.70:
+ * A new Windows authorization group "AFS Client Admins" is now
+ created and populated with the members of the "Administrators"
+ group. The group is used to determine which accounts on the
+ machine may be used to modify the AFS Client Configuration via
+ the UI and command line tools. afs_config.exe, fs.exe,
+
+ * Modify the WinLogon Logoff Event Handler to query NT4 domain
+ controllers for the remote profile path if Active Directory
+ services are not available.
+
* Fix aklog.exe to not add the AFS ID to the username
* PTS registration of new users to foreign cells has been added to
-OpenAFS for Windows 1.3.70 Installation Notes
+OpenAFS for Windows 1.3.71 Installation Notes
---------------------------------------------
The OpenAFS for Windows product was very poorly maintained throughout the
(\Program Files\OpenAFS\Client\CellServDB).
-5. OpenAFS for Windows 1.3.70 only supports Windows 2000, Windows XP, and
+5. OpenAFS for Windows 1.3.71 only supports Windows 2000, Windows XP, and
Windows 2003. Windows NT 4.0 and the entire Windows 9x/Me line are no
longer supported. Older releases of OpenAFS are available for download
if those operating systems must be supported. The last version with support
No commandline arguments means authenticate to the local cell.
-11. The AFS Server functionality provided with OpenAFS 1.3.70 might work but
+11. The AFS Server functionality provided with OpenAFS 1.3.71 might work but
should be considered highly experimental. It has not been thoroughly tested.
-Any data which would cause pain if lost should be stored in an OpenAFS
+Any data which would cause pain if lost should not be stored in an OpenAFS
Server on Windows.
A few notes on the usage of the AFS Client Service if it is going to be
is often referred to as "fcrypt" mode.
-18. OpenAFS 1.3.70 adds support for authenticated SMB connections using
+18. OpenAFS 1.3.71 adds support for authenticated SMB connections using
either NTLM or GSS SPNEGO (NTLM, Kerberos 5, ...). In previous versions
of OpenAFS the SMB connections were unauthenticated which left open the
door for several security holes which could be used to obtain access to
will result in AFS not running properly. The AFS Server should not
be installed on a machine with Terminal Server installed.
+
24. AFS is a Unix native file system. As such the OpenAFS client attempts
to treat the files stored in AFS as they would be on Unix. File and directory
names beginning with a "." are automatically given the Hidden attribute so
they will not normally be displayed.
+
+25. As of 1.3.71, the OpenAFS for Windows client supports a local Windows
+authorization group called "AFS Client Admins". This group is used in
+place of the "Administrators" group to determine which users are allowed
+to modify the AFS Client Service configuration via either afs_config.exe
+or fs.exe. During installation this group is created and the current
+contents of the Administrators group is copied.
+
+
------------------------------------------------------------------------
Reporting Bugs:
12. miscellaneous
13. need to add support for all of the new registry values since 1.2.8
11. Identify why 16-bit DOS applications executed out of AFS fail
- 12. Create new Windows Security Group to which users can be added for them to become AFS
- Client Administrators
- 13. Add support for configurable Icon file representing AFS folders within the Explorer Shell
- 14. Documentation Documentation Documentation
- 15. Large File support (> 2GB)
- 16. Integrate KFW installation into the NSIS installer
- 17. Add support for record locking to AFS (requires changes to the servers)
- 18. Unicode enable the SMB/CIFS server. OEM Code Pages:
+ 12. Add support for configurable Icon file representing AFS folders within the Explorer Shell
+ 13. Documentation Documentation Documentation
+ 14. Large File support (> 2GB)
+ 15. Integrate KFW installation into the NSIS installer
+ 16. Add support for record locking to AFS (requires changes to the servers)
+ 17. Unicode enable the SMB/CIFS server. OEM Code Pages:
1. prevent the use of interoperable file names
2. force the use of paths no longer than 256 characters
3. force share names to be no longer than 13 characters
4. restrict authentication to ASCII only names and passwords
- 19. Complete implementation of CIFS Remote Administration Protocol
- 20. Correct the problems with overlapped writes which adversely affect
+ 18. Complete implementation of CIFS Remote Administration Protocol
+ 19. Correct the problems with overlapped writes which adversely affect
Microsoft Office applications storing documents and temporary files
within AFS volumes
- 21. Add support for SMB/CIFS Digital Signatures
- 22. Development of afsmap.exe tool to provide AFS aware NET USE functionality
+ 20. Add support for SMB/CIFS Digital Signatures
+ 21. Development of afsmap.exe tool to provide AFS aware NET USE functionality
afsmap.exe <drive> <afs-path> [/PERSISTENT]
afsmap.exe <drive> <unc-path> [/PERSISTENT]
afsmap.exe <drive> /DELETE
- 23. Write-through caching appears to be unsupported. Files copied to AFS
+ 22. Write-through caching appears to be unsupported. Files copied to AFS
do not end up in the local cache.
return mydata;
}
+#define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
+
BOOL IsAdmin (void)
{
static BOOL fAdmin = FALSE;
if (!fTested)
{
- /* Obtain the SID for BUILTIN\Administrators. If this is Windows NT,
- * expect this call to succeed; if it does not, we can presume that
- * it's not NT and therefore the user always has administrative
- * privileges.
+ /* Obtain the SID for the AFS client admin group. If the group does
+ * not exist, then assume we have AFS client admin privileges.
*/
PSID psidAdmin = NULL;
- SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
+ DWORD dwSize, dwSize2;
+ char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
+ char *pszRefDomain = NULL;
+ SID_NAME_USE snu = SidTypeGroup;
+
+ dwSize = sizeof(pszAdminGroup);
+
+ if (!GetComputerName(pszAdminGroup, &dwSize)) {
+ /* Can't get computer name. We return false in this case.
+ Retain fAdmin and fTested. This shouldn't happen.*/
+ return FALSE;
+ }
fTested = TRUE;
- if (!AllocateAndInitializeSid (&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin))
+ dwSize = 0;
+ dwSize2 = 0;
+
+ strcat(pszAdminGroup,"\\");
+ strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
+
+ LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
+ /* that should always fail. */
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ /* if we can't find the group, then we allow the operation */
fAdmin = TRUE;
- else
- {
+ return TRUE;
+ }
+
+ if (dwSize == 0 || dwSize2 == 0) {
+ /* Paranoia */
+ fAdmin = TRUE;
+ return TRUE;
+ }
+
+ psidAdmin = (PSID)malloc(dwSize); memset(psidAdmin,0,dwSize);
+ pszRefDomain = (char *)malloc(dwSize2);
+
+ if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
+ /* We can't lookup the group now even though we looked it up earlier.
+ Could this happen? */
+ fAdmin = TRUE;
+ } else {
/* Then open our current ProcessToken */
HANDLE hToken;
if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
{
/* Look through the list of group SIDs and see if any of them
- * matches the Administrator group SID.
+ * matches the AFS Client Admin group SID.
*/
size_t iGroup = 0;
for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
{
- if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid))
+ if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
fAdmin = TRUE;
+ }
}
}
}
}
- if (psidAdmin)
- FreeSid (psidAdmin);
+ free(psidAdmin);
+ free(pszRefDomain);
}
return fAdmin;
if ( checkserv.tinterval != 0 ) {
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
if (ti) {
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
#ifdef WIN32
if ( !IsAdmin() ) {
- fprintf (stderr,"Permission denied: requires Administrator access.\n");
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
return EACCES;
}
#else /* WIN32 */
static CSCPolicyCmd(struct cmd_syndesc *asp)
{
- struct cmd_item *ti;
- char *share = NULL;
+ struct cmd_item *ti;
+ char *share = NULL;
HKEY hkCSCPolicy;
- for(ti=asp->parms[0].items; ti;ti=ti->next) {
- share = ti->data;
- if (share)
- {
- break;
- }
- }
+ for(ti=asp->parms[0].items; ti;ti=ti->next) {
+ share = ti->data;
+ if (share)
+ {
+ break;
+ }
+ }
- if (share)
- {
+ if (share)
+ {
char *policy;
RegCreateKeyEx( HKEY_LOCAL_MACHINE,
&hkCSCPolicy,
NULL );
- if ( !IsAdmin() || hkCSCPolicy == NULL ) {
+ if ( hkCSCPolicy == NULL ) {
fprintf (stderr,"Permission denied: requires Administrator access.\n");
- if ( hkCSCPolicy )
- RegCloseKey(hkCSCPolicy);
+ return EACCES;
+ }
+
+ if ( !IsAdmin() ) {
+ fprintf (stderr,"Permission denied: requires AFS Client Administrator access.\n");
+ RegCloseKey(hkCSCPolicy);
return EACCES;
}
policy = "manual";
- if (asp->parms[1].items)
- policy = "manual";
- if (asp->parms[2].items)
- policy = "programs";
- if (asp->parms[3].items)
- policy = "documents";
- if (asp->parms[4].items)
- policy = "disable";
+ if (asp->parms[1].items)
+ policy = "manual";
+ if (asp->parms[2].items)
+ policy = "programs";
+ if (asp->parms[3].items)
+ policy = "documents";
+ if (asp->parms[4].items)
+ policy = "disable";
RegSetValueEx( hkCSCPolicy, share, 0, REG_SZ, policy, strlen(policy)+1);
- printf("CSC policy on share \"%s\" changed to \"%s\".\n\n", share, policy);
- printf("Close all applications that accessed files on this share or restart AFS Client for the change to take effect.\n");
- }
- else
- {
+ printf("CSC policy on share \"%s\" changed to \"%s\".\n\n", share, policy);
+ printf("Close all applications that accessed files on this share or restart AFS Client for the change to take effect.\n");
+ }
+ else
+ {
DWORD dwIndex, dwPolicies;
- char policyName[256];
- DWORD policyNameLen;
+ char policyName[256];
+ DWORD policyNameLen;
char policy[256];
DWORD policyLen;
DWORD dwType;
- /* list current csc policies */
-
+ /* list current csc policies */
+
RegCreateKeyEx( HKEY_LOCAL_MACHINE,
"SOFTWARE\\OpenAFS\\Client\\CSCPolicy",
0,
NULL /* lpftLastWriteTime */
);
- printf("Current CSC policies:\n");
+ printf("Current CSC policies:\n");
for ( dwIndex = 0; dwIndex < dwPolicies; dwIndex ++ ) {
policyNameLen = sizeof(policyName);
RegEnumValue( hkCSCPolicy, dwIndex, policyName, &policyNameLen, NULL,
&dwType, policy, &policyLen);
- printf(" %s = %s\n", policyName, policy);
- }
- }
+ printf(" %s = %s\n", policyName, policy);
+ }
+ }
RegCloseKey(hkCSCPolicy);
- return (0);
+ return (0);
}
cm_scache_t *dscp, char *filename, char *otherFilename,
BOOL isDirectParent)
{
- smb_packet_t *watch, *lastWatch, *nextWatch;
- ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
- char *outData, *oldOutData;
- ULONG filter;
- USHORT fid, wtree;
- ULONG maxLen;
- BOOL twoEntries = FALSE;
- ULONG otherNameLen, oldParmCount = 0;
- DWORD otherAction;
- smb_vc_t *vcp;
- smb_fid_t *fidp;
+ smb_packet_t *watch, *lastWatch, *nextWatch;
+ ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
+ char *outData, *oldOutData;
+ ULONG filter;
+ USHORT fid, wtree;
+ ULONG maxLen;
+ BOOL twoEntries = FALSE;
+ ULONG otherNameLen, oldParmCount = 0;
+ DWORD otherAction;
+ smb_vc_t *vcp;
+ smb_fid_t *fidp;
- /* Get ready for rename within directory */
- if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
- twoEntries = TRUE;
- otherAction = FILE_ACTION_RENAMED_NEW_NAME;
- }
+ /* Get ready for rename within directory */
+ if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
+ twoEntries = TRUE;
+ otherAction = FILE_ACTION_RENAMED_NEW_NAME;
+ }
osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
- osi_LogSaveString(smb_logp,filename),dscp);
-
- lock_ObtainMutex(&smb_Dir_Watch_Lock);
- watch = smb_Directory_Watches;
- while (watch) {
- filter = smb_GetSMBParm(watch, 19)
- | (smb_GetSMBParm(watch, 20) << 16);
- fid = smb_GetSMBParm(watch, 21);
- wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
- maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
- | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
- vcp = watch->vcp;
-
- /*
- * Strange hack - bug in NT Client and NT Server that we
- * must emulate?
- */
- if (filter == 3 && wtree)
- filter = 0x17;
+ osi_LogSaveString(smb_logp,filename),dscp);
+
+ lock_ObtainMutex(&smb_Dir_Watch_Lock);
+ watch = smb_Directory_Watches;
+ while (watch) {
+ filter = smb_GetSMBParm(watch, 19)
+ | (smb_GetSMBParm(watch, 20) << 16);
+ fid = smb_GetSMBParm(watch, 21);
+ wtree = smb_GetSMBParm(watch, 22) & 0xffff; /* TODO: should this be 0xff ? */
+ maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
+ | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
+ vcp = watch->vcp;
+
+ /*
+ * Strange hack - bug in NT Client and NT Server that we
+ * must emulate?
+ */
+ if (filter == 3 && wtree)
+ filter = 0x17;
- fidp = smb_FindFID(vcp, fid, 0);
+ fidp = smb_FindFID(vcp, fid, 0);
if (!fidp) {
osi_Log1(smb_logp," no fidp for fid[%d]",fid);
- lastWatch = watch;
- watch = watch->nextp;
- continue;
- }
- if (fidp->scp != dscp
- || (filter & notifyFilter) == 0
- || (!isDirectParent && !wtree)) {
+ lastWatch = watch;
+ watch = watch->nextp;
+ continue;
+ }
+ if (fidp->scp != dscp
+ || (filter & notifyFilter) == 0
+ || (!isDirectParent && !wtree)) {
osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
smb_ReleaseFID(fidp);
- lastWatch = watch;
- watch = watch->nextp;
- continue;
- }
- smb_ReleaseFID(fidp);
+ lastWatch = watch;
+ watch = watch->nextp;
+ continue;
+ }
+ smb_ReleaseFID(fidp);
- osi_Log4(smb_logp,
- "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
- fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
+ osi_Log4(smb_logp,
+ "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
+ fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
- nextWatch = watch->nextp;
- if (watch == smb_Directory_Watches)
- smb_Directory_Watches = nextWatch;
- else
- lastWatch->nextp = nextWatch;
+ nextWatch = watch->nextp;
+ if (watch == smb_Directory_Watches)
+ smb_Directory_Watches = nextWatch;
+ else
+ lastWatch->nextp = nextWatch;
- /* Turn off WATCHED flag in dscp */
- lock_ObtainMutex(&dscp->mx);
- if (wtree)
- dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
- else
- dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
- lock_ReleaseMutex(&dscp->mx);
+ /* Turn off WATCHED flag in dscp */
+ lock_ObtainMutex(&dscp->mx);
+ if (wtree)
+ dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
+ else
+ dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
+ lock_ReleaseMutex(&dscp->mx);
- /* Convert to response packet */
- ((smb_t *) watch)->reb = 0x80;
- ((smb_t *) watch)->wct = 0;
+ /* Convert to response packet */
+ ((smb_t *) watch)->reb = 0x80;
+ ((smb_t *) watch)->wct = 0;
- /* out parms */
- if (filename == NULL)
- parmCount = 0;
- else {
- nameLen = strlen(filename);
- parmCount = 3*4 + nameLen*2;
- parmCount = (parmCount + 3) & ~3; /* pad to 4 */
- if (twoEntries) {
- otherNameLen = strlen(otherFilename);
- oldParmCount = parmCount;
- parmCount += 3*4 + otherNameLen*2;
- parmCount = (parmCount + 3) & ~3; /* pad to 4 */
- }
- if (maxLen < parmCount)
- parmCount = 0; /* not enough room */
- }
- parmOffset = 8*4 + 39;
- parmOffset += 1; /* pad to 4 */
- dataOffset = parmOffset + parmCount;
-
- parmSlot = 1;
- watch->oddByte = 1;
- /* Total Parameter Count */
- smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
- /* Total Data Count */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Parameter Count */
- smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
- /* Parameter Offset */
- smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
- /* Parameter Displacement */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Data Count */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- /* Data Offset */
- smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
- /* Data Displacement */
- smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
- smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
- smb_SetSMBDataLength(watch, parmCount + 1);
-
- if (parmCount != 0) {
- outData = smb_GetSMBData(watch, NULL);
- outData++; /* round to get to parmOffset */
- oldOutData = outData;
- *((DWORD *)outData) = oldParmCount; outData += 4;
- /* Next Entry Offset */
- *((DWORD *)outData) = action; outData += 4;
- /* Action */
- *((DWORD *)outData) = nameLen*2; outData += 4;
- /* File Name Length */
- mbstowcs((WCHAR *)outData, filename, nameLen);
- /* File Name */
- if (twoEntries) {
- outData = oldOutData + oldParmCount;
- *((DWORD *)outData) = 0; outData += 4;
- /* Next Entry Offset */
- *((DWORD *)outData) = otherAction; outData += 4;
- /* Action */
- *((DWORD *)outData) = otherNameLen*2;
- outData += 4; /* File Name Length */
- mbstowcs((WCHAR *)outData, otherFilename,
- otherNameLen); /* File Name */
- }
- }
+ /* out parms */
+ if (filename == NULL)
+ parmCount = 0;
+ else {
+ nameLen = strlen(filename);
+ parmCount = 3*4 + nameLen*2;
+ parmCount = (parmCount + 3) & ~3; /* pad to 4 */
+ if (twoEntries) {
+ otherNameLen = strlen(otherFilename);
+ oldParmCount = parmCount;
+ parmCount += 3*4 + otherNameLen*2;
+ parmCount = (parmCount + 3) & ~3; /* pad to 4 */
+ }
+ if (maxLen < parmCount)
+ parmCount = 0; /* not enough room */
+ }
+ parmOffset = 8*4 + 39;
+ parmOffset += 1; /* pad to 4 */
+ dataOffset = parmOffset + parmCount;
- /*
- * If filename is null, we don't know the cause of the
- * change notification. We return zero data (see above),
- * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
- * (= 0x010C). We set the error code here by hand, without
- * modifying wct and bcc.
- */
- if (filename == NULL) {
- ((smb_t *) watch)->rcls = 0x0C;
- ((smb_t *) watch)->reh = 0x01;
- ((smb_t *) watch)->errLow = 0;
- ((smb_t *) watch)->errHigh = 0;
- /* Set NT Status codes flag */
- ((smb_t *) watch)->flg2 |= 0x4000;
- }
+ parmSlot = 1;
+ watch->oddByte = 1;
+ /* Total Parameter Count */
+ smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
+ /* Total Data Count */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Parameter Count */
+ smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
+ /* Parameter Offset */
+ smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
+ /* Parameter Displacement */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Data Count */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ /* Data Offset */
+ smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
+ /* Data Displacement */
+ smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
+ smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
+ smb_SetSMBDataLength(watch, parmCount + 1);
+
+ if (parmCount != 0) {
+ outData = smb_GetSMBData(watch, NULL);
+ outData++; /* round to get to parmOffset */
+ oldOutData = outData;
+ *((DWORD *)outData) = oldParmCount; outData += 4;
+ /* Next Entry Offset */
+ *((DWORD *)outData) = action; outData += 4;
+ /* Action */
+ *((DWORD *)outData) = nameLen*2; outData += 4;
+ /* File Name Length */
+ mbstowcs((WCHAR *)outData, filename, nameLen);
+ /* File Name */
+ if (twoEntries) {
+ outData = oldOutData + oldParmCount;
+ *((DWORD *)outData) = 0; outData += 4;
+ /* Next Entry Offset */
+ *((DWORD *)outData) = otherAction; outData += 4;
+ /* Action */
+ *((DWORD *)outData) = otherNameLen*2;
+ outData += 4; /* File Name Length */
+ mbstowcs((WCHAR *)outData, otherFilename,
+ otherNameLen); /* File Name */
+ }
+ }
+
+ /*
+ * If filename is null, we don't know the cause of the
+ * change notification. We return zero data (see above),
+ * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
+ * (= 0x010C). We set the error code here by hand, without
+ * modifying wct and bcc.
+ */
+ if (filename == NULL) {
+ ((smb_t *) watch)->rcls = 0x0C;
+ ((smb_t *) watch)->reh = 0x01;
+ ((smb_t *) watch)->errLow = 0;
+ ((smb_t *) watch)->errHigh = 0;
+ /* Set NT Status codes flag */
+ ((smb_t *) watch)->flg2 |= 0x4000;
+ }
- smb_SendPacket(vcp, watch);
+ smb_SendPacket(vcp, watch);
smb_ReleaseVC(vcp);
- smb_FreePacket(watch);
- watch = nextWatch;
- }
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
-}
+ smb_FreePacket(watch);
+ watch = nextWatch;
+ }
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+}
long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
{
- unsigned char *replyWctp;
- smb_packet_t *watch, *lastWatch;
- USHORT fid, watchtree;
- smb_fid_t *fidp;
- cm_scache_t *scp;
-
- osi_Log0(smb_logp, "SMB3 receive NT cancel");
+ unsigned char *replyWctp;
+ smb_packet_t *watch, *lastWatch;
+ USHORT fid, watchtree;
+ smb_fid_t *fidp;
+ cm_scache_t *scp;
- lock_ObtainMutex(&smb_Dir_Watch_Lock);
- watch = smb_Directory_Watches;
- while (watch) {
- if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
- && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
- && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
- && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
- if (watch == smb_Directory_Watches)
- smb_Directory_Watches = watch->nextp;
- else
- lastWatch->nextp = watch->nextp;
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+ osi_Log0(smb_logp, "SMB3 receive NT cancel");
+
+ lock_ObtainMutex(&smb_Dir_Watch_Lock);
+ watch = smb_Directory_Watches;
+ while (watch) {
+ if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
+ && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
+ && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
+ && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
+ if (watch == smb_Directory_Watches)
+ smb_Directory_Watches = watch->nextp;
+ else
+ lastWatch->nextp = watch->nextp;
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
- /* Turn off WATCHED flag in scp */
- fid = smb_GetSMBParm(watch, 21);
- watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
+ /* Turn off WATCHED flag in scp */
+ fid = smb_GetSMBParm(watch, 21);
+ watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
if (vcp != watch->vcp)
osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
- vcp, watch->vcp);
+ vcp, watch->vcp);
- fidp = smb_FindFID(vcp, fid, 0);
+ fidp = smb_FindFID(vcp, fid, 0);
if (fidp) {
osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s",
- fid, watchtree,
- osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
+ fid, watchtree,
+ osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
scp = fidp->scp;
lock_ObtainMutex(&scp->mx);
osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
}
- /* assume STATUS32; return 0xC0000120 (CANCELED) */
- replyWctp = watch->wctp;
- *replyWctp++ = 0;
- *replyWctp++ = 0;
- *replyWctp++ = 0;
- ((smb_t *)watch)->rcls = 0x20;
- ((smb_t *)watch)->reh = 0x1;
- ((smb_t *)watch)->errLow = 0;
- ((smb_t *)watch)->errHigh = 0xC0;
- ((smb_t *)watch)->flg2 |= 0x4000;
- smb_SendPacket(vcp, watch);
+ /* assume STATUS32; return 0xC0000120 (CANCELED) */
+ replyWctp = watch->wctp;
+ *replyWctp++ = 0;
+ *replyWctp++ = 0;
+ *replyWctp++ = 0;
+ ((smb_t *)watch)->rcls = 0x20;
+ ((smb_t *)watch)->reh = 0x1;
+ ((smb_t *)watch)->errLow = 0;
+ ((smb_t *)watch)->errHigh = 0xC0;
+ ((smb_t *)watch)->flg2 |= 0x4000;
+ smb_SendPacket(vcp, watch);
if (watch->vcp)
smb_ReleaseVC(watch->vcp);
- smb_FreePacket(watch);
- return 0;
- }
- lastWatch = watch;
- watch = watch->nextp;
- }
- lock_ReleaseMutex(&smb_Dir_Watch_Lock);
+ smb_FreePacket(watch);
+ return 0;
+ }
+ lastWatch = watch;
+ watch = watch->nextp;
+ }
+ lock_ReleaseMutex(&smb_Dir_Watch_Lock);
- return 0;
+ return 0;
}
void smb3_Init()
*
*/
+#define AFSCLIENT_ADMIN_GROUPNAME "AFS Client Admins"
+
BOOL IsAdmin (void)
{
- static BOOL fAdmin = FALSE;
- static BOOL fTested = FALSE;
- if (!fTested)
- {
- fTested = TRUE;
-
- // Obtain the SID for BUILTIN\Administrators. If this is Windows NT,
- // expect this call to succeed; if it does not, we can presume that
- // it's not NT and therefore the user always has administrative
- // privileges.
- //
- PSID psidAdmin = NULL;
- SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
- if (!AllocateAndInitializeSid (&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin))
- fAdmin = TRUE;
- else
- {
-
- // Then open our current ProcessToken
- //
- HANDLE hToken;
- if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
+ static BOOL fAdmin = FALSE;
+ static BOOL fTested = FALSE;
+
+ if (!fTested)
+ {
+ /* Obtain the SID for the AFS client admin group. If the group does
+ * not exist, then assume we have AFS client admin privileges.
+ */
+ PSID psidAdmin = NULL;
+ DWORD dwSize, dwSize2;
+ char pszAdminGroup[ MAX_COMPUTERNAME_LENGTH + sizeof(AFSCLIENT_ADMIN_GROUPNAME) + 2 ];
+ char *pszRefDomain = NULL;
+ SID_NAME_USE snu = SidTypeGroup;
+
+ dwSize = sizeof(pszAdminGroup);
+
+ if (!GetComputerName(pszAdminGroup, &dwSize)) {
+ /* Can't get computer name. We return false in this case.
+ Retain fAdmin and fTested. This shouldn't happen.*/
+ return FALSE;
+ }
+
+ fTested = TRUE;
+
+ dwSize = 0;
+ dwSize2 = 0;
+
+ strcat(pszAdminGroup,"\\");
+ strcat(pszAdminGroup, AFSCLIENT_ADMIN_GROUPNAME);
+
+ LookupAccountName(NULL, pszAdminGroup, NULL, &dwSize, NULL, &dwSize2, &snu);
+ /* that should always fail. */
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ /* if we can't find the group, then we allow the operation */
+ fAdmin = TRUE;
+ return TRUE;
+ }
+
+ if (dwSize == 0 || dwSize2 == 0) {
+ /* Paranoia */
+ fAdmin = TRUE;
+ return TRUE;
+ }
+
+ psidAdmin = (PSID) malloc(dwSize); memset(psidAdmin,0,dwSize);
+ pszRefDomain = (char *)malloc(dwSize2);
+
+ if (!LookupAccountName(NULL, pszAdminGroup, psidAdmin, &dwSize, pszRefDomain, &dwSize2, &snu)) {
+ /* We can't lookup the group now even though we looked it up earlier.
+ Could this happen? */
+ fAdmin = TRUE;
+ } else {
+ /* Then open our current ProcessToken */
+ HANDLE hToken;
+
+ if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
-
- // We'll have to allocate a chunk of memory to store the list of
- // groups to which this user belongs; find out how much memory
- // we'll need.
- //
- DWORD dwSize = 0;
- GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
+ /* We'll have to allocate a chunk of memory to store the list of
+ * groups to which this user belongs; find out how much memory
+ * we'll need.
+ */
+ DWORD dwSize = 0;
+ PTOKEN_GROUPS pGroups;
+
+ GetTokenInformation (hToken, TokenGroups, NULL, dwSize, &dwSize);
- // Allocate that buffer, and read in the list of groups.
- //
- PTOKEN_GROUPS pGroups = (PTOKEN_GROUPS)Allocate (dwSize);
- if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
- {
- // Look through the list of group SIDs and see if any of them
- // matches the Administrator group SID.
- //
- for (size_t iGroup = 0; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
- {
- if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid))
- fAdmin = TRUE;
- }
- }
-
- if (pGroups)
- Free (pGroups);
+ pGroups = (PTOKEN_GROUPS)malloc(dwSize);
+
+ /* Allocate that buffer, and read in the list of groups. */
+ if (GetTokenInformation (hToken, TokenGroups, pGroups, dwSize, &dwSize))
+ {
+ /* Look through the list of group SIDs and see if any of them
+ * matches the AFS Client Admin group SID.
+ */
+ size_t iGroup = 0;
+ for (; (!fAdmin) && (iGroup < pGroups->GroupCount); ++iGroup)
+ {
+ if (EqualSid (psidAdmin, pGroups->Groups[ iGroup ].Sid)) {
+ fAdmin = TRUE;
+ }
+ }
+ }
+
+ if (pGroups)
+ free(pGroups);
}
- }
+ }
- if (psidAdmin)
- FreeSid (psidAdmin);
- }
+ free(psidAdmin);
+ free(pszRefDomain);
+ }
- return fAdmin;
+ return fAdmin;
}
--- /dev/null
+#include<windows.h>
+#include<string.h>
+#include<stdio.h>
+#include<lm.h>
+
+#pragma comment(lib,"netapi32.lib")
+
+#define AFSCLIENT_ADMIN_GROUPNAMEW L"AFS Client Admins"
+#define AFSCLIENT_ADMIN_COMMENTW L"AFS Client Administrators"
+
+UINT createAfsAdminGroup(void) {
+ LOCALGROUP_INFO_1 gInfo;
+ DWORD dwError;
+ NET_API_STATUS status;
+
+ gInfo.lgrpi1_name = AFSCLIENT_ADMIN_GROUPNAMEW;
+ gInfo.lgrpi1_comment = AFSCLIENT_ADMIN_COMMENTW;
+ status = NetLocalGroupAdd(NULL, 1, (LPBYTE) &gInfo, &dwError);
+
+ return status;
+}
+
+UINT initializeAfsAdminGroup(void) {
+ PSID psidAdmin = NULL;
+ SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
+ NET_API_STATUS status;
+ LOCALGROUP_MEMBERS_INFO_0 *gmAdmins = NULL;
+ DWORD dwNEntries, dwTEntries;
+
+ status = NetLocalGroupGetMembers(NULL, L"Administrators", 0, (LPBYTE *) &gmAdmins, MAX_PREFERRED_LENGTH, &dwNEntries, &dwTEntries, NULL);
+ if(status)
+ return status;
+
+ status = NetLocalGroupAddMembers(NULL, AFSCLIENT_ADMIN_GROUPNAMEW, 0, (LPBYTE) gmAdmins, dwNEntries);
+
+ NetApiBufferFree( gmAdmins );
+
+ return status;
+}
+
+UINT removeAfsAdminGroup(void) {
+ NET_API_STATUS status;
+ status = NetLocalGroupDel(NULL, AFSCLIENT_ADMIN_GROUPNAMEW);
+ return status;
+}
+
+void showUsage(char * progname) {
+ printf(
+ "Usage: %s [-create | -remove]\n"
+ " -create : Create AFS Client Admins group and populate it with\n"
+ " the members of the Administrators group\n"
+ " -remove : Remove the AFS Client Admins group\n"
+ , progname);
+}
+
+int main(int argc, char ** argv) {
+
+ UINT rv = 0;
+
+ if(argc < 2) {
+ showUsage(argv[0]);
+ return 1;
+ }
+
+ if(stricmp(argv[1], "-create")) {
+ rv = createAfsAdminGroup();
+ if(rv) {
+ if(rv != ERROR_ALIAS_EXISTS) {
+ fprintf(stderr, "%s: Can't create AFS Client Admin group. NetApi error %u\n", rv);
+ } else {
+ /* The group already exists. (Preserved config from a
+ prior install). */
+ rv = 0;
+ }
+ } else {
+ rv = initializeAfsAdminGroup();
+ if(rv)
+ fprintf(stderr, "%s: Can't populate AFS Client Admin group. NetApi error %u\n", rv);
+ }
+ } else if(stricmp(argv[1], "-remove")) {
+ removeAfsAdminGroup();
+ rv = 0;
+ } else {
+ showUsage(argv[0]);
+ rv = 0;
+ }
+
+ return rv;
+}
\ No newline at end of file
$(EXEDIR)\Killer.exe: $(OUT)\Killer.obj
$(EXECONLINK) $(OUT)\Killer.obj
+$(OUT)\AdminGroup.obj: AdminGroup.cpp
+ $(C2OBJ) AdminGroup.cpp
+
+$(EXEDIR)\AdminGroup.exe: $(OUT)\AdminGroup.obj
+ $(EXECONLINK) $(OUT)\AdminGroup.obj
+
prebuild:
!IF ("$(AFSDEV_BUILDTYPE)" == "FREE")
!IF ("$(AFSVER_CL)"=="1310")
build: prebuild
"C:\Program Files\NSIS\makensis.exe" /DINCLUDEDIR=$(OUT) OpenAFS.nsi
-install: $(OUT)\Service.obj $(EXEDIR)\Service.exe $(OUT)\Killer.obj $(EXEDIR)\Killer.exe build
+install: $(OUT)\Service.obj $(EXEDIR)\Service.exe $(OUT)\Killer.obj $(EXEDIR)\Killer.exe $(EXEDIR)\AdminGroup.exe build
#clean:
# $(DEL) $(OUT)\Service.obj
; Get AFS CellServDB file
Call afs.GetCellServDB
+ GetTempFileName $R0
+ File /oname=$R0 "${AFS_WININSTALL_DIR}\AdminGroup.exe"
+ nsExec::Exec '$R0 -create'
+
!ifdef INSTALL_KFW
; Include Kerberos for Windows files in the installer...
SetOutPath "$INSTDIR\kfw\bin\"
ReadINIStr $R1 $2 "Field 13" "State"
StrCmp $R1 "1" +1 +2
StrCpy $R2 "$R2-S"
-
+
WriteRegStr HKLM "SOFTWARE\OpenAFS\Client" "AfscredsShortcutParams" "$R2"
CreateShortCut "$SMPROGRAMS\OpenAFS\Client\Authentication.lnk" "$INSTDIR\Client\Program\afscreds.exe" "$R2"
!ENDIF
Delete "$INSTDIR\Client\afsdns.ini"
+ GetTempFileName $R0
+ File /oname=$R0 "${AFS_WININSTALL_DIR}\AdminGroup.exe"
+ nsExec::Exec '$R0 -remove'
+
SkipDel:
Delete "$WINDIR\afsd_init.log"
Delete "$INSTDIR\Uninstall.exe"
-EXPORT:ConfigureClientService \
-EXPORT:ConfigureServerService \
-EXPORT:AbortMsiImmediate \
- -EXPORT:UninstallNsisInstallation
+ -EXPORT:UninstallNsisInstallation \
+ -EXPORT:CreateAFSClientAdminGroup \
+ -EXPORT:RemoveAFSClientAdminGroup
DLLLIBFILES=\
- msi.lib advapi32.lib
+ msi.lib advapi32.lib netapi32.lib
LINK=link
}
return rv;
}
+
+/* Create or remove the 'AFS Client Admins' group. Initially
+ it will hold members of the Administrator group. */
+
+MSIDLLEXPORT CreateAFSClientAdminGroup( MSIHANDLE hInstall ) {
+ UINT rv;
+ rv = createAfsAdminGroup();
+ if(rv) {
+ if(rv == ERROR_ALIAS_EXISTS) {
+ /* The group already exists, probably from a previous
+ installation. We let things be. */
+ return ERROR_SUCCESS;
+ }
+
+ ShowMsiError( hInstall, ERR_GROUP_CREATE_FAILED, rv );
+ return rv;
+ }
+
+ rv = initializeAfsAdminGroup();
+ if(rv)
+ ShowMsiError( hInstall, ERR_GROUP_MEMBER_FAILED, rv );
+ return rv;
+}
+
+MSIDLLEXPORT RemoveAFSClientAdminGroup( MSIHANDLE hInstall ) {
+ removeAfsAdminGroup();
+ return ERROR_SUCCESS;
+}
+
+#define AFSCLIENT_ADMIN_GROUPNAMEW L"AFS Client Admins"
+#define AFSCLIENT_ADMIN_COMMENTW L"AFS Client Administrators"
+
+UINT createAfsAdminGroup(void) {
+ LOCALGROUP_INFO_1 gInfo;
+ DWORD dwError;
+ NET_API_STATUS status;
+
+ gInfo.lgrpi1_name = AFSCLIENT_ADMIN_GROUPNAMEW;
+ gInfo.lgrpi1_comment = AFSCLIENT_ADMIN_COMMENTW;
+ status = NetLocalGroupAdd(NULL, 1, (LPBYTE) &gInfo, &dwError);
+
+ return status;
+}
+
+UINT initializeAfsAdminGroup(void) {
+ PSID psidAdmin = NULL;
+ SID_IDENTIFIER_AUTHORITY auth = SECURITY_NT_AUTHORITY;
+ NET_API_STATUS status;
+ LOCALGROUP_MEMBERS_INFO_0 *gmAdmins = NULL;
+ DWORD dwNEntries, dwTEntries;
+
+ status = NetLocalGroupGetMembers(NULL, L"Administrators", 0, (LPBYTE *) &gmAdmins, MAX_PREFERRED_LENGTH, &dwNEntries, &dwTEntries, NULL);
+ if(status)
+ return status;
+
+ status = NetLocalGroupAddMembers(NULL, AFSCLIENT_ADMIN_GROUPNAMEW, 0, (LPBYTE) gmAdmins, dwNEntries);
+
+ NetApiBufferFree( gmAdmins );
+
+ return status;
+}
+
+UINT removeAfsAdminGroup(void) {
+ NET_API_STATUS status;
+ status = NetLocalGroupDel(NULL, AFSCLIENT_ADMIN_GROUPNAMEW);
+ return status;
+}
+
#include<msiquery.h>
#include<stdio.h>
#include<string.h>
+#include<lm.h>
#define MSIDLLEXPORT UINT __stdcall
#define ERR_SCS_FAILED 4003
#define ERR_ABORT 4004
#define ERR_NSS_FAILED 4005
+#define ERR_GROUP_CREATE_FAILED 4006
+#define ERR_GROUP_MEMBER_FAILED 4007
/* non-exported */
int npi_CheckAndAddRemove( LPTSTR, LPTSTR, int );
DWORD InstNetProvider(MSIHANDLE, int);
void ShowMsiError(MSIHANDLE, DWORD, DWORD);
DWORD ConfigService(int);
+UINT createAfsAdminGroup(void);
+UINT initializeAfsAdminGroup(void);
+UINT removeAfsAdminGroup(void);
/* exported */
MSIDLLEXPORT InstallNetProvider( MSIHANDLE );
MSIDLLEXPORT ConfigureServerService( MSIHANDLE );
MSIDLLEXPORT AbortMsiImmediate( MSIHANDLE );
MSIDLLEXPORT UninstallNsisInstallation( MSIHANDLE hInstall );
+MSIDLLEXPORT CreateAFSClientAdminGroup( MSIHANDLE hInstall );
+MSIDLLEXPORT RemoveAFSClientAdminGroup( MSIHANDLE hInstall );
#endif /*__afsMsiTools_H__*/
<String Id="ErrSCSFailed">Configuration of server service failed. System error [2]</String>
<String Id="ErrAbort">Installation aborted : [2]</String>
<String Id="ErrNsisFailed">Uninstallation of the NSIS installation of OpenAFS failed with code [2]</String>
+ <String Id="ErrCantCreateGroup">Can't create AFS Client Admin group. NET_API_Error [2]</String>
+ <String Id="ErrCantAddMembers">Can't add members to AFS Client Admin group. NET_API_Error [2]</String>
<String Id="ActInstallLoopback">Installing loopback adapter</String>
<String Id="ActRemoveLoopback">Removing existing loopback adapter</String>
<Error Id="4003">$(loc.ErrSCSFailed)</Error>
<Error Id="4004">$(loc.ErrAbort)</Error>
<Error Id="4005">$(loc.ErrNsisFailed)</Error>
+ <Error Id="4006">$(loc.ErrCantCreateGroup)</Error>
+ <Error Id="4007">$(loc.ErrCantAddMembers)</Error>
<ProgressText Action="RemoveLoopback" Template="[1]:([2])([3])([4])">$(loc.ActRemoveLoopback)</ProgressText>
<ProgressText Action="InstallLoopback" Template="[1]:([2])([3])([4])">$(loc.ActInstallLoopback)</ProgressText>
<ProgressText Action="RemoveNetProvider">$(loc.ActRemoveNetProvider)</ProgressText>
BinaryKey="BIN_afsCustom"
DllEntry="UninstallNsisInstallation"
Execute="immediate" />
+ <CustomAction
+ Id="CreateAFSAdminGroup"
+ BinaryKey="BIN_afsCustom"
+ DllEntry="CreateAFSClientAdminGroup"
+ Impersonate="no"
+ Execute="deferred" />
+ <CustomAction
+ Id="RemoveAFSAdminGroup"
+ BinaryKey="BIN_afsCustom"
+ DllEntry="RemoveAFSClientAdminGroup"
+ Impersonate="no"
+ Execute="deferred" />
+ <CustomAction
+ Id="RollbackAFSAdminGroup"
+ BinaryKey="BIN_afsCustom"
+ DllEntry="RemoveAFSClientAdminGroup"
+ Impersonate="no"
+ Execute="rollback" />
<CustomAction
Id="AbortInstallationA"
BinaryKey="BIN_afsCustom"
<Custom Action="RemoveNetProvider" After="InstallNetProvider">&feaClient=2</Custom>
<Custom Action="ConfigureClient" After="InstallServices">&feaClient=3</Custom>
<Custom Action="ConfigureServer" After="ConfigureClient">&feaServer=3</Custom>
+ <!-- <Custom Action="RemoveAFSAdminGroup" Before="">&feaClient=2</Custom> -->
+ <Custom Action="RollbackAFSAdminGroup" Before="CreateAFSAdminGroup">&feaClient=3</Custom>
+ <Custom Action="CreateAFSAdminGroup" Before="CreateFolders">&feaClient=3</Custom>
<ScheduleReboot After="PublishProduct">&feaClient=3 OR &feaServer=3 OR &feaClient=2 OR &feaServer=2</ScheduleReboot>
</InstallExecuteSequence>
#
####### Special optional defines
-!IFNDEF NO_CRTDBG #don't set _CRTDBG_MAP_ALLOC flag for some module compliations
+!IFNDEF NO_CRTDBG
+#don't set _CRTDBG_MAP_ALLOC flag for some module compliations
#_CRTDBG_MAP_ALLOC=1
!ENDIF
#define used in WinNT/2000 installation and program version display
AFSPRODUCT_VER_MAJOR=1
AFSPRODUCT_VER_MINOR=3
-AFSPRODUCT_VER_PATCH=7001
+AFSPRODUCT_VER_PATCH=7004
AFSPRODUCT_VER_BUILD=0
# For MSI installer, each major release should have a different GUID
+# http://msdn.microsoft.com/library/en-us/msi/setup/changing_the_product_code.asp
AFSPRODUCT_VER_GUID=CCAF9E14-976E-46C0-8A1B-A218EAB7ADC5
AFSPRODUCT_VERSION=$(AFSPRODUCT_VER_MAJOR).$(AFSPRODUCT_VER_MINOR).$(AFSPRODUCT_VER_PATCH)
CELLSERVDB_WEB=http://grand.central.org/dl/cellservdb/CellServDB
TARGETOS = WINNT
-# Define defaults folder locations
+# Define defaults folder locations
DEST=dest
SRC=src
OBJ=obj