/*++ Copyright (c) 1992-1993 Microsoft Corporation Module Name: ExpAdd.c Abstract: This file contains NetrReplExportDirAdd. Author: John Rogers (JohnRo) 08-Jan-1992 Environment: Runs under Windows NT. Requires ANSI C extensions: slash-slash comments, long external names. Revision History: 08-Jan-1992 JohnRo Created. 20-Jan-1992 JohnRo Avoid possible duplicate entry. 20-Jan-1992 JohnRo Changed prototype to match MIDL requirements. Netr prototypes are now generated by MIDL and put in repl.h. 20-Jan-1992 JohnRo Call ExportDirIsApiRecordValid() to do some checking. 24-Jan-1992 JohnRo Changed to use LPTSTR etc. 15-Mar-1992 JohnRo Update registry with new values. 22-Mar-1992 JohnRo Fixed bug handling union in debug output. 08-May-1992 JohnRo Fixed link problem in free (nondebug) build. 22-Jul-1992 JohnRo RAID 2274: repl svc should impersonate caller. 02-Nov-1992 JohnRo RAID 7962: Repl APIs in wrong role kill svc. 02-Apr-1993 JohnRo Use NetpKdPrint() where possible. --*/ // These must be included first: #include // IN, VOID, LPTSTR, etc. #include // NET_API_STATUS, PARM equates, etc. #include // IF_DEBUG(), etc. #include // PMASTER_LIST_REC, RMGlobalListLock. #include // Needed by . // These can be in any order: #include // ExportDirIsApiRecordValid(), etc. #include // LPREPL_EDIR_INFO_1, REPL_EXTENT_ stuff, etc. #include // GetMasterRecord(), NewMasterRecord(). #include // NetpAssert(), NetpKdPrint(), etc. #include // NetpSetParmError(). #include // ACQUIRE_LOCK(), etc. #include // My prototype (in MIDL-generated .h file). #include // ReplConfigLock, ReplConfigRole. #include // NetpImpersonateClient(), NetpRevertToSelf(). #include // ERROR_ equates, NO_ERROR. NET_API_STATUS NetrReplExportDirAdd ( IN LPTSTR UncServerName OPTIONAL, IN DWORD Level, IN LPEXPORT_CONTAINER Buf, // RPC container (union) OUT LPDWORD ParmError OPTIONAL // name used by NetpSetParmError() macro. ) /*++ Routine Description: Same as NetReplExportDirAdd. Arguments: Same as NetReplExportDirAdd. Return Value: Same as NetReplExportDirAdd. --*/ { LPREPL_EDIR_INFO_1 ApiRecord; NET_API_STATUS ApiStatus; BOOL ConfigLocked = FALSE; BOOL Impersonated = FALSE; PMASTER_LIST_REC InternalRecord; BOOL ListLocked = FALSE; // // Check for caller errors. // NetpSetParmError( PARM_ERROR_UNKNOWN ); // Assume error until proven... if (Buf == NULL) { return (ERROR_INVALID_PARAMETER); } if (Level != 1) { return (ERROR_INVALID_LEVEL); } if ( ! ExportDirIsApiRecordValid ( Level, Buf->Info1, ParmError) ) { return (ERROR_INVALID_PARAMETER); } ApiRecord = Buf->Info1; NetpAssert( ApiRecord != NULL ); IF_DEBUG(EXPAPI) { NetpKdPrint(( "NetrReplExportDirAdd: adding API record...\n" )); NetpDbgDisplayReplExportDir( Level, Buf->Info1 ); } // // Impersonate caller, so security check (write to registry) reflects // the client's process, not the repl service process. // ApiStatus = NetpImpersonateClient(); if (ApiStatus != NO_ERROR) { goto Cleanup; } Impersonated = TRUE; // // Get a shared lock on config data so we can see if role includes export. // ACQUIRE_LOCK_SHARED( ReplConfigLock ); ConfigLocked = TRUE; // // Check for duplicate record, one way or the other. // if (ReplRoleIncludesExport( ReplConfigRole ) ) { // // Get a lock on the global list which we want to add to. // if (ReplRoleIncludesExport( ReplConfigRole ) ) { ACQUIRE_LOCK( RMGlobalListLock ); // Get excl lock. ListLocked = TRUE; } // We're exporting, so just use export half's global data. if (GetMasterRec( ApiRecord->rped1_dirname ) != NULL) { // Oops, we got a duplicate. ApiStatus = ERROR_ALREADY_EXISTS; goto Cleanup; // Don't forget to release lock... } } else { // Service is running but not exporting, so we can only use registry. if (ExportDirConfigDataExists( NULL, // no server name ApiRecord->rped1_dirname) ) { ApiStatus = ERROR_ALREADY_EXISTS; goto Cleanup; // Don't forget to release lock... } } // // Write config data for this export directory. // This has the side-effect of doing a security check. // ApiStatus = ExportDirWriteConfigData ( UncServerName, ApiRecord->rped1_dirname, ApiRecord->rped1_integrity, ApiRecord->rped1_extent, 0, // lock count 0 ); // lock time (none) Seconds since 1970. if (ApiStatus != NO_ERROR) { goto Cleanup; // Don't forget to release lock... } if ( !ReplRoleIncludesExport( ReplConfigRole ) ) { goto CleanupOK; } // // Create a new master record and add it to the appropriate list(s). // NewMasterRecord() will do any necessary locking and unlocking. // InternalRecord = NewMasterRecord( ApiRecord->rped1_dirname, ApiRecord->rped1_integrity, ApiRecord->rped1_extent); IF_DEBUG(EXPAPI) { NetpKdPrint(( "NetrReplExportDirAdd: done adding API record, " "got master record at " FORMAT_LPVOID ".\n", (LPVOID) InternalRecord )); } // // Assumption: NewMasterRecord can only fail if it can't allocate memory. // if (InternalRecord == NULL) { // BUGBUG: Registry updated but not service? Oh well, we tried. ApiStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; // Don't forget to release lock... } // // I (JohnRo) was thinking about putting some assertion checking on // InternalRecord here. However, I'm not sure we can depend on the // pointer. What if some other process just did a ReplExportDirDel // on the same name? We have a pointer to a record that's gone. // So, never mind the assertion check. // CleanupOK: // // Everything went OK. Tell caller. // NetpSetParmError( PARM_ERROR_NONE ); ApiStatus = NO_ERROR; Cleanup: if (ListLocked) { RELEASE_LOCK( RMGlobalListLock ); } if (ConfigLocked) { RELEASE_LOCK( ReplConfigLock ); } if (Impersonated) { (VOID) NetpRevertToSelf(); } return (ApiStatus); }