// // Sharing.cpp // // Utility functions to help with file and printer sharing. // // To use these functions, you need to add SvrApi.cpp to your project, // and call its InitSvrApiThunk() function at startup. // // History: // // 5/17/1999 KenSh Created for JetNet // 10/05/1999 KenSh Adapted for Home Networking Wizard // 10/19/1999 KenSh Added AreAdvancedFoldersShared // #include "stdafx.h" #include "Sharing.h" #include "MySvrApi.h" #include "MyDocs.h" #include "Util.h" #include #include #include "theapp.h" #include "newapi.h" #include // SetFolderPermissionsForSharing #define NET_API_STATUS DWORD #define API_RET_TYPE NET_API_STATUS // Allocates array of shares using malloc(), returns number of shares int EnumLocalShares(SHARE_INFO** pprgShares) { SHARE_INFO_502* prgShares = NULL; DWORD dwShares; DWORD dwTotalShares; if (NERR_Success == NetShareEnum(NULL, 502, (LPBYTE*)&prgShares, MAX_PREFERRED_LENGTH, &dwShares, &dwTotalShares, NULL)) { // We defined SHARE_INFO to mimic SHARE_INFO_502, even though we ignore // all but four fields of it. *pprgShares = (SHARE_INFO*)prgShares; return (int)dwShares; } else { *pprgShares = NULL; return 0; } } // EnumSharedDrives // // Use this version if you've already enumerated shares via EnumLocalShares(). // // pbDriveArray is an array of 26 bytes, one for each possible shared drive. // Each entry is filled with a NETACCESS flag (defined in Sharing.h): 0 if not // shared, 1 if read-only, 2 if read-write, 3 if depends-on-password. // // Return value is number of drives shared. // int EnumSharedDrives(LPBYTE pbDriveArray, int cShares, const SHARE_INFO* prgShares) { ZeroMemory(pbDriveArray, 26); int cDrives = 0; for (int i = 0; i < cShares; i++) { LPCTSTR pszPath = prgShares[i].pszPath; if (pszPath[1] == _T(':') && pszPath[2] == _T('\\')) // is it a folder { if (pszPath[3] == _T('\0')) // is it a whole drive { TCHAR ch = (TCHAR)CharUpper((LPTSTR)(prgShares[i].pszPath[0])); ASSERT (ch >= _T('A') && ch <= _T('Z')); pbDriveArray[ch - _T('A')] = (BYTE)(prgShares[i].uFlags & NETACCESS_MASK); cDrives += 1; } } } return cDrives; } // Use this version of EnumSharedDrives if you haven't called EnumLocalShares() int EnumSharedDrives(LPBYTE pbDriveArray) { SHARE_INFO* prgShares; int cShares = EnumLocalShares(&prgShares); int cDrives = EnumSharedDrives(pbDriveArray, cShares, prgShares); NetApiBufferFree(prgShares); return cDrives; } // Helper function for ShareFolder() (and SharePrinter on 9x) BOOL ShareHelper(LPCTSTR pszPath, LPCTSTR pszShareName, DWORD dwAccess, BYTE bShareType, LPCTSTR pszReadOnlyPassword, LPCTSTR pszFullAccessPassword) { ASSERTMSG(pszReadOnlyPassword==NULL, "ShareHelper doesn't support roPassword"); SHARE_INFO_502 si; si.shi502_netname = (LPTSTR)pszShareName; //CharUpperA(si.shi50_netname); si.shi502_type = bShareType; si.shi502_remark = NULL; si.shi502_permissions = ACCESS_ALL; si.shi502_max_uses = -1; si.shi502_current_uses = -1; TCHAR szPath[MAX_PATH]; if (bShareType == STYPE_DISKTREE) { StrCpyN(szPath, pszPath, ARRAYSIZE(szPath)); CharUpper(szPath); si.shi502_path = szPath; } else { si.shi502_path = (LPWSTR)pszPath; } si.shi502_passwd = (pszFullAccessPassword) ? (LPTSTR)pszFullAccessPassword : L""; si.shi502_reserved = NULL; si.shi502_security_descriptor = NULL; if (NO_ERROR != NetShareAdd(NULL, 502, (LPBYTE)&si)) { return FALSE; } MakeSharePersistent(pszShareName); return TRUE; } // dwAccess is NETACCESS_READONLY, NETACCESS_FULL, or NETACCESS_DEPENDSON // Either or both passwords may be NULL. For simplicity, you can pass the // same password for both, even if you're only sharing read-only or full-access. BOOL ShareFolder(LPCTSTR pszPath, LPCTSTR pszShareName, DWORD dwAccess, LPCTSTR pszReadOnlyPassword, LPCTSTR pszFullAccessPassword) { ASSERT(pszPath != NULL); ASSERT(pszShareName != NULL); ASSERT(dwAccess == NETACCESS_READONLY || dwAccess == NETACCESS_FULL || dwAccess == NETACCESS_DEPENDSON); BOOL bResult = ShareHelper(pszPath, pszShareName, dwAccess, STYPE_DISKTREE, pszReadOnlyPassword, pszFullAccessPassword); if (bResult) { SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, pszPath, NULL); // On NT, make sure the folder permissions are set correctly HINSTANCE hInstNtShrUI = LoadLibrary(TEXT("ntshrui.dll")); if (hInstNtShrUI != NULL) { PFNSETFOLDERPERMISSIONSFORSHARING pfn = (PFNSETFOLDERPERMISSIONSFORSHARING)GetProcAddress(hInstNtShrUI, "SetFolderPermissionsForSharing"); if (pfn != NULL) { // level 3 means "shared read/write" // level 2 means "shared read-only" (*pfn)(pszPath, NULL, dwAccess == NETACCESS_FULL ? 3 : 2, NULL); } FreeLibrary(hInstNtShrUI); } } return bResult; } BOOL UnshareFolder(LPCTSTR pszPath) { TCHAR szShareName[SHARE_NAME_LENGTH+1]; BOOL bResult = FALSE; if (ShareNameFromPath(pszPath, szShareName, ARRAYSIZE(szShareName))) { if (NO_ERROR == NetShareDel(NULL, szShareName, 0)) { SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, pszPath, NULL); bResult = TRUE; // On NT, make sure the folder permissions are set correctly HINSTANCE hInstNtShrUI = LoadLibrary(TEXT("ntshrui.dll")); if (hInstNtShrUI != NULL) { PFNSETFOLDERPERMISSIONSFORSHARING pfn = (PFNSETFOLDERPERMISSIONSFORSHARING)GetProcAddress(hInstNtShrUI, "SetFolderPermissionsForSharing"); if (pfn != NULL) { // level 1 means "not shared" (*pfn)(pszPath, NULL, 1, NULL); } FreeLibrary(hInstNtShrUI); } } } return bResult; } BOOL ShareNameFromPath(LPCTSTR pszPath, LPTSTR pszShareName, UINT cchShareName) { BOOL bResult = FALSE; *pszShareName = _T('\0'); SHARE_INFO* prgShares; int cShares = EnumLocalShares(&prgShares); for (int i = 0; i < cShares; i++) { if (0 == StrCmpI(prgShares[i].pszPath, pszPath)) { StrCpyN(pszShareName, prgShares[i].szShareName, cchShareName); bResult = TRUE; break; } } NetApiBufferFree(prgShares); return bResult; } BOOL IsVisibleFolderShare(const SHARE_INFO* pShare) { return (pShare->bShareType == STYPE_DISKTREE && pShare->szShareName[lstrlen(pShare->szShareName) - 1] != _T('$')); } BOOL IsShareNameInUse(LPCTSTR pszShareName) { LPBYTE pbuf; BOOL bResult = (NERR_Success == NetShareGetInfo(NULL, pszShareName, 502, &pbuf)); if (bResult) NetApiBufferFree(pbuf); return bResult; } // Note: this function works for printers too BOOL IsFolderSharedEx(LPCTSTR pszPath, BOOL bDetectHidden, BOOL bPrinter, int cShares, const SHARE_INFO* prgShares) { BYTE bShareType = (bPrinter ? STYPE_PRINTQ : STYPE_DISKTREE); for (int i = 0; i < cShares; i++) { const SHARE_INFO* pShare = &prgShares[i]; if (pShare->bShareType == bShareType && (bDetectHidden || IsVisibleFolderShare(pShare)) && 0 == StrCmpI(pShare->pszPath, pszPath)) { return TRUE; } } return FALSE; } BOOL IsFolderShared(LPCTSTR pszPath, BOOL bDetectHidden) { SHARE_INFO* prgShares; int cShares = EnumLocalShares(&prgShares); BOOL bShared = IsFolderSharedEx(pszPath, bDetectHidden, FALSE, cShares, prgShares); NetApiBufferFree(prgShares); return bShared; } void MakeSharePersistent(LPCTSTR pszShareName) { SHARE_INFO_502* pShare2; if (GetShareInfo502(pszShareName, &pShare2)) { SetShareInfo502(pShare2->shi502_netname, pShare2); // Need to manually add the Path to the registry CRegistry reg; if (reg.OpenKey(HKEY_LOCAL_MACHINE, REGSTR_KEY_SHARES)) { if (reg.OpenSubKey(pShare2->shi502_netname)) { reg.SetStringValue(REGSTR_VAL_SHARES_PATH, pShare2->shi502_path); } else if (reg.OpenKey(HKEY_LOCAL_MACHINE, REGSTR_KEY_SHARES) && reg.CreateSubKey(pShare2->shi502_netname)) { // On older downlevel platforms we need to persist this manually. DWORD dwFlags = (pShare2->shi502_permissions & (ACCESS_ALL ^ ACCESS_READ)) ? SHI50F_FULL : SHI50F_RDONLY; dwFlags |= SHI50F_PERSIST; if (pShare2->shi502_type == STYPE_PRINTQ) dwFlags |= 0x0090; // REVIEW: what does this number mean? else dwFlags |= 0x0080; // REVIEW: what does this number mean? reg.SetDwordValue(REGSTR_VAL_SHARES_FLAGS, dwFlags); reg.SetDwordValue(REGSTR_VAL_SHARES_TYPE, (DWORD)pShare2->shi502_type); reg.SetStringValue(REGSTR_VAL_SHARES_PATH, pShare2->shi502_path); reg.SetStringValue(REGSTR_VAL_SHARES_REMARK, pShare2->shi502_remark); } } NetApiBufferFree(pShare2); } #ifdef OLD_WAY // Hack: add the new share to the registry, or else it won't be persisted! // REVIEW: surely there must be an API that does this?? CRegistry reg; if (reg.OpenKey(HKEY_LOCAL_MACHINE, REGSTR_KEY_SHARES)) { if (reg.CreateSubKey(pShare->szShareName) || reg.OpenSubKey(pShare->szShareName)) { DWORD dwFlags = pShare->uFlags | SHI50F_PERSIST; if (pShare->bShareType == STYPE_PRINTQ) dwFlags |= 0x0090; // REVIEW: what does this number mean? else dwFlags |= 0x0080; // REVIEW: what does this number mean? reg.SetDwordValue(REGSTR_VAL_SHARES_FLAGS, dwFlags); reg.SetDwordValue(REGSTR_VAL_SHARES_TYPE, (DWORD)pShare->bShareType); reg.SetStringValue(REGSTR_VAL_SHARES_PATH, pShare->pszPath); reg.SetStringValue(REGSTR_VAL_SHARES_REMARK, pShare->pszComment); reg.SetStringValue(REGSTR_VAL_SHARES_RW_PASS, pShare->szPassword_rw); reg.SetStringValue(REGSTR_VAL_SHARES_RO_PASS, pShare->szPassword_ro); // reg.SetBinaryValue("Parm1enc", "", 0); // reg.SetBinaryValue("Parm2enc", "", 0); // Note: passwords are encrypted next time the user reboots. } } #endif // OLD_WAY } BOOL SetShareInfo502(LPCTSTR pszShareName, SHARE_INFO_502* pShare) { BOOL bResult; if (StrCmpI(pszShareName, pShare->shi502_netname) != 0) { // Can't rename an existing share. Unshare and re-share instead. bResult = (NO_ERROR == NetShareDel(NULL, pszShareName, 0) && NO_ERROR == NetShareAdd(NULL, 502, (LPBYTE)pShare)); if (bResult) { MakeSharePersistent(pShare->shi502_netname); } } else { // Change parameters of existing share. bResult = (NO_ERROR == NetShareSetInfo(NULL, pszShareName, 502, (LPBYTE)pShare)); } return bResult; } BOOL GetShareInfo502(LPCTSTR pszShareName, SHARE_INFO_502** ppShare) { NET_API_STATUS ret = NetShareGetInfo(NULL, pszShareName, 502, (LPBYTE*)ppShare); return (NERR_Success == ret); } BOOL SharePrinter(LPCTSTR pszPrinterName, LPCTSTR pszShareName, LPCTSTR pszPassword) { ASSERT(pszPrinterName != NULL); ASSERT(pszShareName != NULL); BOOL fResult = FALSE; if (g_fRunningOnNT) { HANDLE hPrinter; PRINTER_DEFAULTS pd = {0}; pd.DesiredAccess = PRINTER_ALL_ACCESS; if (OpenPrinter_NT((LPWSTR) pszPrinterName, &hPrinter, &pd)) { DWORD cbBuffer = 0; // Get buffer size if (!GetPrinter_NT(hPrinter, 2, NULL, 0, &cbBuffer) && cbBuffer) { PRINTER_INFO_2* pInfo2 = (PRINTER_INFO_2*) LocalAlloc(LPTR, cbBuffer); if (pInfo2) { if (GetPrinter_NT(hPrinter, 2, (LPBYTE) pInfo2, cbBuffer, &cbBuffer)) { if (pInfo2->Attributes & PRINTER_ATTRIBUTE_SHARED) { // Printer is already shared - we're good to go fResult = TRUE; } else { // Share printer pInfo2->Attributes |= PRINTER_ATTRIBUTE_SHARED; if((!pInfo2->pShareName) || (!pInfo2->pShareName[0])) { pInfo2->pShareName = (LPWSTR) pszShareName; } fResult = SetPrinter_NT(hPrinter, 2, (LPBYTE) pInfo2, 0); } } LocalFree(pInfo2); } } ClosePrinter_NT(hPrinter); } } else { fResult = ShareHelper(pszPrinterName, pszShareName, NETACCESS_FULL, STYPE_PRINTQ, NULL, pszPassword); if (fResult) { Sleep(500); // need to wait for VSERVER to register the changes, same as msprint2 SHChangeNotify(SHCNE_NETSHARE, SHCNF_PRINTER, pszPrinterName, NULL); } } return fResult; } BOOL IsPrinterShared(LPCTSTR pszPrinterName) { SHARE_INFO* prgShares; int cShares = EnumLocalShares(&prgShares); BOOL bShared = IsFolderSharedEx(pszPrinterName, TRUE, TRUE, cShares, prgShares); NetApiBufferFree(prgShares); return bShared; } BOOL SetSharePassword(LPCTSTR pszShareName, LPCTSTR pszReadOnlyPassword, LPCTSTR pszFullAccessPassword) { SHARE_INFO_502* pShare; BOOL bResult = FALSE; if (GetShareInfo502(pszShareName, &pShare)) { ASSERTMSG(NULL == pszReadOnlyPassword, "SetSharePassword can't store roPassword"); if (pszFullAccessPassword == NULL) pszFullAccessPassword = TEXT(""); pShare->shi502_passwd = (LPTSTR)pszFullAccessPassword; bResult = SetShareInfo502(pszShareName, pShare); NetApiBufferFree(pShare); } return bResult; } BOOL GetSharePassword(LPCTSTR pszShareName, LPTSTR pszReadOnlyPassword, DWORD cchRO, LPTSTR pszFullAccessPassword, DWORD cchFA) { SHARE_INFO_502* pShare; BOOL bResult = GetShareInfo502(pszShareName, &pShare); if (bResult) { ASSERTMSG(NULL==pszReadOnlyPassword, "GetSharePassword can't support roPassword"); if (pszFullAccessPassword != NULL) StrCpyN(pszFullAccessPassword, pShare->shi502_passwd, cchFA); NetApiBufferFree(pShare); } return bResult; }