Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2269 lines
63 KiB

/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1991 **/
/********************************************************************/
/***
* use.c
* Functions for displaying and manipulating network uses
* Redirected device can only be: disks a: to z:;
* comm devs com1[:] to com9[:]; and lpt1[:] to lpt9[:].
* NOTE: even though it uses the WNet*** calls, it is not
* intended to be used for networks other than LM.
* we use WNet purely to leverage off the persistent
* connections.
*
* History:
* mm/dd/yy, who, comment
* 06/09/87, andyh, new code
* 07/02/87, andyh, del with ucond = 1
* 10/31/88, erichn, uses OS2.H instead of DOSCALLS
* 01/04/89, erichn, filenames now MAX_PATH LONG
* 05/02/89, erichn, NLS conversion
* 05/09/89, erichn, local security mods
* 05/19/89, erichn, NETCMD output sorting
* 06/08/89, erichn, canonicalization sweep
* 06/23/89, erichn, replaced old NetI canon calls with new I_Net
* 03/03/90, thomaspa, INTERNAL retry with mixed case for
* password errors from down-level servers
* 03/06/90, thomaspa, integrate INTERNAL to shipped product
* 02/09/91, danhi, change to use lm 16/32 mapping layer
* 02/20/91, robdu, added profile update code
* 02/18/92, chuckc, use WNet*** to handle sticky connections (part I)
* 04/25/92, jonn, removed two cases for build fix
* 09/21/92 keithmo, use unicode versions of WNet*** API.
*/
/* Include files */
#define INCL_NOCOMMON
#define INCL_DOSFILEMGR
#define INCL_ERRORS
#define INCL_ERROR_H
#include <os2.h>
#include <search.h>
#include <lmcons.h>
#include <lmerr.h>
#include <lmapibuf.h>
#include <lmaccess.h>
#include <lmuse.h>
#include <apperr.h>
#include <apperr2.h>
#include <icanon.h>
#include <lui.h>
#include <wincred.h>
#include <dlwksta.h>
#include "mwksta.h"
#include "netcmds.h"
#include "nettext.h"
#include "msystem.h"
// pull in the win32 headers
#include <mpr.h> // for MPR_* manifests
//
// structure for combines LM and WNet info
//
typedef struct _NET_USE_INFO {
LPWSTR lpLocalName ;
LPWSTR lpRemoteName ;
LPWSTR lpProviderName ;
DWORD dwType ;
DWORD dwStatus ;
DWORD dwRefCount ;
DWORD dwUseCount ;
BOOL fIsLanman ;
} NET_USE_INFO ;
/* Static variables */
TCHAR *LanmanProviderName = NULL ;
/* Forward declarations */
VOID LanmanDisplayUse(LPUSE_INFO_1);
BOOL is_admin_dollar(LPWSTR);
int __cdecl CmpUseInfo(const VOID FAR *, const VOID FAR *);
VOID NEAR UseInit(VOID);
USHORT QueryDefaultPersistence(BOOL *pfRemember) ;
DWORD SetDefaultPersistence(BOOL fRemember) ;
BOOL CheckIfWantUpdate(TCHAR *dev, TCHAR *resource) ;
VOID WNetErrorExit(ULONG err);
WCHAR *GetLanmanProviderName(void) ;
TCHAR *MapWildCard(TCHAR *dev, TCHAR *startdev) ;
DWORD MprUseEnum(PDWORD num_read,
NET_USE_INFO **NetUseInfoBuffer,
PDWORD NetUseInfoCount);
DWORD LanmanUseAugment(DWORD num_read,
NET_USE_INFO *NetUseInfoBuffer) ;
DWORD UnavailUseAugment(PDWORD num_read,
NET_USE_INFO **NetUseInfoBuffer,
PDWORD NetUseInfoCount);
VOID MprUseDisplay(TCHAR *dev) ;
VOID use_del_all() ;
/* Externs */
extern int YorN_Switch;
/* Message related definitions */
#define USE_STATUS_OK 0
#define USE_STATUS_PAUSED ( USE_STATUS_OK + 1 )
#define USE_STATUS_SESSION_LOST ( USE_STATUS_PAUSED + 1 )
#define USE_STATUS_NET_ERROR ( USE_STATUS_SESSION_LOST + 1 )
#define USE_STATUS_CONNECTING ( USE_STATUS_NET_ERROR + 1 )
#define USE_STATUS_RECONNECTING ( USE_STATUS_CONNECTING + 1 )
#define USE_STATUS_UNAVAIL ( USE_STATUS_RECONNECTING + 1 )
#ifdef DEBUG
#define USE_STATUS_UNKNOWN ( USE_STATUS_UNAVAIL + 1 )
#endif
#define USE_REMEMBERED 0xFFFE
static MESSAGE UseStatusList[] =
{
{ APE2_USE_STATUS_OK, NULL },
{ APE2_USE_STATUS_PAUSED, NULL },
{ APE2_USE_STATUS_SESSION_LOST, NULL },
{ APE2_USE_STATUS_NET_ERROR, NULL },
{ APE2_USE_STATUS_CONNECTING, NULL },
{ APE2_USE_STATUS_RECONNECTING, NULL },
{ APE2_USE_STATUS_UNAVAIL, NULL }
#ifdef DEBUG
,
{ APE2_GEN_UNKNOWN, NULL }
#endif
};
#define NUM_STATUS_MSGS (sizeof(UseStatusList)/sizeof(UseStatusList[0]))
#define USE_MSG_LOCAL 0
#define USE_MSG_REMOTE ( USE_MSG_LOCAL + 1 )
#define USE_MSG_TYPE ( USE_MSG_REMOTE + 1 )
#define USE_TYPE_TBD ( USE_MSG_TYPE + 1 )
#define USE_MSG_STATUS ( USE_TYPE_TBD + 1 )
#define USE_STATUS_TBD ( USE_MSG_STATUS + 1 )
#define USE_MSG_OPEN_COUNT ( USE_STATUS_TBD + 1 )
#define USE_MSG_USE_COUNT ( USE_MSG_OPEN_COUNT + 1 )
static MESSAGE UseMsgList[] =
{
{ APE2_USE_MSG_LOCAL, NULL },
{ APE2_USE_MSG_REMOTE, NULL },
{ APE2_USE_MSG_TYPE, NULL },
{ APE2_GEN_UNKNOWN /* ie, TBD */, NULL },
{ APE2_USE_MSG_STATUS, NULL },
{ APE2_GEN_UNKNOWN /* ie, TBD */, NULL },
{ APE2_USE_MSG_OPEN_COUNT, NULL },
{ APE2_USE_MSG_USE_COUNT, NULL }
};
#define NUM_USE_MSGS (sizeof(UseMsgList)/sizeof(UseMsgList[0]))
/***
* use_display_all()
* Display all network uses
*
* Args:
* none
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID
use_display_all(
VOID
)
{
DWORD err; /* API return status */
DWORD num_read; /* num entries read by API */
DWORD maxLen; /* max message length */
DWORD i;
int msgno;
BOOL fRemember ;
DWORD NetUseInfoCount = 0 ;
NET_USE_INFO *NetUseInfoBuffer = NULL ;
NET_USE_INFO *pNetUseInfo ;
UseInit();
if (err = MprUseEnum(&num_read, &NetUseInfoBuffer, &NetUseInfoCount))
ErrorExit(err);
if (err = UnavailUseAugment(&num_read, &NetUseInfoBuffer, &NetUseInfoCount))
ErrorExit(err);
if (err = LanmanUseAugment(num_read, NetUseInfoBuffer))
ErrorExit(err);
if (QueryDefaultPersistence(&fRemember) == NERR_Success)
InfoPrint(fRemember ? APE_ConnectionsAreRemembered :
APE_ConnectionsAreNotRemembered);
else
InfoPrint(APE_ProfileReadError);
if (num_read == 0)
EmptyExit();
for (i = 0, pNetUseInfo = NetUseInfoBuffer;
i < num_read; i++, pNetUseInfo++)
{
//
// if we find at least one entry we will display, break
//
if (!(pNetUseInfo->fIsLanman)
|| (pNetUseInfo->dwStatus != USE_OK)
|| (pNetUseInfo->dwUseCount != 0)
|| (pNetUseInfo->dwRefCount != 0))
break;
}
if (i == num_read)
EmptyExit(); // loop reached limit, so no entries to display
qsort(NetUseInfoBuffer,
num_read,
sizeof(NET_USE_INFO), CmpUseInfo);
GetMessageList(NUM_STATUS_MSGS, UseStatusList, &maxLen);
PrintNL();
InfoPrint(APE2_USE_HEADER);
PrintLine();
for (i = 0, pNetUseInfo = NetUseInfoBuffer;
i < num_read;
i++, pNetUseInfo++)
{
TCHAR *status_string ;
switch(pNetUseInfo->dwStatus)
{
case USE_OK:
if ((pNetUseInfo->dwUseCount == 0)
&& (pNetUseInfo->dwRefCount == 0)
&& pNetUseInfo->fIsLanman)
continue;
else
msgno = USE_STATUS_OK;
break;
case USE_PAUSED:
msgno = USE_STATUS_PAUSED;
break;
case USE_SESSLOST:
msgno = USE_STATUS_SESSION_LOST;
break;
case USE_NETERR:
msgno = USE_STATUS_NET_ERROR;
break;
case USE_CONN:
msgno = USE_STATUS_CONNECTING;
break;
case USE_REMEMBERED:
msgno = USE_STATUS_UNAVAIL;
break;
case USE_RECONN:
msgno = USE_STATUS_RECONNECTING;
break;
default:
msgno = -1;
break;
}
if (msgno != -1)
status_string = UseStatusList[msgno].msg_text ;
else
status_string = TEXT("") ;
{
TCHAR Buffer1[13],Buffer2[10],Buffer3[MAX_PATH + 1];
if( wcslen( pNetUseInfo->lpRemoteName ) <= 25 ) {
WriteToCon(TEXT("%Fs %Fs %Fs %Fs\r\n"),
PaddedString(12,status_string,Buffer1),
PaddedString( 9,pNetUseInfo->lpLocalName,Buffer2),
PaddedString(25,pNetUseInfo->lpRemoteName,Buffer3),
pNetUseInfo->lpProviderName);
}
else
{
TCHAR Buffer4[13],Buffer5[10],Buffer6[25];
WriteToCon(TEXT("%Fs %Fs %Fs \r\n%Fs %Fs %Fs %Fs\r\n"),
PaddedString(12,status_string,Buffer1),
PaddedString( 9,pNetUseInfo->lpLocalName,Buffer2),
PaddedString(wcslen(pNetUseInfo->lpRemoteName),
pNetUseInfo->lpRemoteName,
Buffer3),
PaddedString(12,TEXT(""),Buffer4),
PaddedString(9,TEXT(""),Buffer5),
PaddedString(25,TEXT(""),Buffer6),
pNetUseInfo->lpProviderName);
}
}
}
FreeMem((LPBYTE)NetUseInfoBuffer);
InfoSuccess();
}
/***
* LanmanUseAugment()
* Enumerate uses from Lanman
*
* Args:
* none
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
DWORD
LanmanUseAugment(
DWORD num_read,
NET_USE_INFO *NetUseInfoBuffer
)
{
DWORD dwErr;
DWORD cTotalAvail;
LPSTR pBuffer;
DWORD numLMread; /* num entries read by API */
DWORD j;
DWORD i;
LPUSE_INFO_1 use_entry;
NET_USE_INFO *pNetUseInfo = NetUseInfoBuffer ;
dwErr = NetUseEnum(NULL, 1, &pBuffer, MAX_PREFERRED_LENGTH,
&numLMread, &cTotalAvail, NULL);
if (dwErr != NERR_Success)
{
// consider as success (ie. there are no Lanman ones)
return NERR_Success;
}
if (numLMread == 0)
{
return NERR_Success;
}
//
// for all MPR returned entries that are Lanman uses,
// augment with extra info if we have it.
//
for (i = 0; i < num_read; i++, pNetUseInfo++)
{
//
// not LM, skip it
//
if (!(pNetUseInfo->fIsLanman))
continue ;
//
// lets find it in the NetUseEnum return data
//
for (j = 0, use_entry = (LPUSE_INFO_1) pBuffer;
j < numLMread; j++, use_entry++)
{
//
// look for match. if device names are present & match, we've found
// one. else we match only if remote names match *and* both device
// names are not present.
//
TCHAR *local = use_entry->ui1_local ;
TCHAR *remote = use_entry->ui1_remote ;
if ( (local && *local && !_tcsicmp(pNetUseInfo->lpLocalName,local))
||
( (!local || !*local) &&
!*(pNetUseInfo->lpLocalName) &&
!_tcsicmp(pNetUseInfo->lpRemoteName,remote)
)
)
{
//
// found the device in the LM list or
// found as deviceless connection
//
pNetUseInfo->dwUseCount = use_entry->ui1_usecount ;
pNetUseInfo->dwRefCount = use_entry->ui1_refcount ;
pNetUseInfo->dwStatus = use_entry->ui1_status ;
break ;
}
}
}
NetApiBufferFree(pBuffer);
return NERR_Success;
}
/***
* MprUseEnum()
* Enumerates uses returned by WNET
*
* Args:
* none
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
DWORD
MprUseEnum(
LPDWORD num_read,
NET_USE_INFO **NetUseInfoBuffer,
LPDWORD NetUseInfoCount
)
{
DWORD EntriesRead = 0;
LPBYTE Buffer;
DWORD dwErr;
DWORD dwAllocErr;
HANDLE EnumHandle;
DWORD BufferSize, Count;
static TCHAR *NullString = TEXT("");
//
// initialize
//
*num_read = 0;
*NetUseInfoCount = 64; // assume 64 entries initially. realloc if need
if (dwAllocErr = AllocMem( *NetUseInfoCount * sizeof(NET_USE_INFO),
(LPBYTE *) NetUseInfoBuffer ))
{
ErrorExit(dwAllocErr);
}
//
// allocate memory and open the enumeration
//
if (dwAllocErr = AllocMem(BufferSize = 4096, &Buffer))
{
ErrorExit(dwAllocErr);
}
dwErr = WNetOpenEnum(RESOURCE_CONNECTED, 0, 0, NULL, &EnumHandle) ;
if (dwErr != WN_SUCCESS)
{
return dwErr;
}
do
{
Count = 0xFFFFFFFF ;
dwErr = WNetEnumResource(EnumHandle, &Count, Buffer, &BufferSize) ;
if (dwErr == WN_SUCCESS || dwErr == WN_NO_MORE_ENTRIES)
{
LPNETRESOURCE lpNetResource ;
NET_USE_INFO *lpNetUseInfo ;
DWORD i ;
//
// grow the buffer if need. note there are no
// pointers that point back to the buffer, so we
// should be fine with the realloc.
//
if (EntriesRead + Count >= *NetUseInfoCount)
{
//
// make sure it can hold all the new data, and add 64
// to reduce the number of reallocs
//
*NetUseInfoCount = EntriesRead + Count + 64;
dwAllocErr = ReallocMem(*NetUseInfoCount * sizeof(NET_USE_INFO),
(LPBYTE *)NetUseInfoBuffer) ;
if (dwAllocErr != NERR_Success)
return dwAllocErr;
}
lpNetResource = (LPNETRESOURCE) Buffer ;
lpNetUseInfo = *NetUseInfoBuffer + EntriesRead ;
//
// stick the entries into the NetUseInfoBuffer
//
for ( i = 0;
i < Count;
i++,EntriesRead++,lpNetUseInfo++,lpNetResource++ )
{
lpNetUseInfo->lpLocalName = lpNetResource->lpLocalName ?
lpNetResource->lpLocalName : NullString ;
lpNetUseInfo->lpRemoteName = lpNetResource->lpRemoteName ?
lpNetResource->lpRemoteName : NullString ;
lpNetUseInfo->lpProviderName = lpNetResource->lpProvider ?
lpNetResource->lpProvider : NullString ;
lpNetUseInfo->dwType = lpNetResource->dwType ;
lpNetUseInfo->fIsLanman =
(_tcscmp(lpNetResource->lpProvider,LanmanProviderName)==0) ;
lpNetUseInfo->dwStatus = 0xFFFFFFFF ;
lpNetUseInfo->dwRefCount =
lpNetUseInfo->dwUseCount = 0 ;
}
//
// allocate a new buffer for next set, since we still need
// data in the old one, we dont free it. Netcmd lets the
// system clean up when it exits.
//
if (dwErr == WN_SUCCESS)
{
if (dwAllocErr = AllocMem(BufferSize = 4096, &Buffer))
{
ErrorExit(dwAllocErr);
}
}
}
else
{
return dwErr;
}
}
while (dwErr == WN_SUCCESS);
dwErr = WNetCloseEnum(EnumHandle) ; // we dont report any errors here
*num_read = EntriesRead ;
return NERR_Success ;
}
/***
* UnavailUseAugment()
* Enumerate unavail uses & tags them on.
*
* Args:
* none
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
DWORD
UnavailUseAugment(
LPDWORD NumRead,
NET_USE_INFO **NetUseInfoBuffer,
LPDWORD NetUseInfoCount
)
{
LPBYTE Buffer ;
DWORD dwErr ;
HANDLE EnumHandle ;
DWORD BufferSize, Count, InitialUseInfoCount ;
DWORD err ;
static TCHAR *NullString = TEXT("") ;
InitialUseInfoCount = *NumRead ;
//
// allocate memory and open the enumeration
//
if (err = AllocMem(BufferSize = 4096, &Buffer))
{
ErrorExit(err);
}
dwErr = WNetOpenEnum(RESOURCE_REMEMBERED, 0, 0, NULL, &EnumHandle) ;
if (dwErr != WN_SUCCESS)
{
return dwErr;
}
do
{
Count = 0xFFFFFFFF ;
dwErr = WNetEnumResource(EnumHandle, &Count, Buffer, &BufferSize) ;
if (dwErr == WN_SUCCESS || dwErr == WN_NO_MORE_ENTRIES)
{
LPNETRESOURCE lpNetResource ;
NET_USE_INFO *lpNetUseInfo ;
DWORD i,j ;
if (Count == 0xFFFFFFFF || Count == 0)
break ;
lpNetResource = (LPNETRESOURCE) Buffer ;
//
// for each entry, see if it is an unavail one
//
for ( i = 0;
i < Count;
i++,lpNetResource++ )
{
lpNetUseInfo = *NetUseInfoBuffer ;
//
// search thru the ones we already have
//
for (j = 0;
j < InitialUseInfoCount;
j++, ++lpNetUseInfo)
{
if (lpNetUseInfo->lpLocalName &&
lpNetResource->lpLocalName)
{
if ( *lpNetUseInfo->lpLocalName != 0 )
{
// Use _tcsnicmp because the Net api returns an LPTX
// redirection without the ':' whereas the WNet api
// includes the ':'.
if (_tcsnicmp(lpNetResource->lpLocalName,
lpNetUseInfo->lpLocalName,
_tcslen(lpNetUseInfo->lpLocalName))==0)
{
break;
}
}
else if (*lpNetResource->lpLocalName == 0)
{
break ;
}
}
}
//
// if we broke out early, this is already connected, so
// we dont bother add an 'unavailable' entry.
//
if (j < InitialUseInfoCount)
continue ;
//
// grow the buffer if need. note there are no
// pointers that point back to the buffer, so we
// should be fine with the realloc.
//
if (*NumRead >= *NetUseInfoCount)
{
//
// make sure it can hold all the new data, and add 64
// to reduce the number of reallocs
//
*NetUseInfoCount += 64 ;
err = ReallocMem(*NetUseInfoCount * sizeof(NET_USE_INFO),
(LPBYTE *) NetUseInfoBuffer);
if (err != NERR_Success)
{
return err;
}
}
lpNetUseInfo = *NetUseInfoBuffer + *NumRead ;
lpNetUseInfo->lpLocalName = lpNetResource->lpLocalName ?
lpNetResource->lpLocalName : NullString ;
lpNetUseInfo->lpRemoteName = lpNetResource->lpRemoteName ?
lpNetResource->lpRemoteName : NullString ;
lpNetUseInfo->lpProviderName = lpNetResource->lpProvider ?
lpNetResource->lpProvider : NullString ;
lpNetUseInfo->dwType = lpNetResource->dwType ;
lpNetUseInfo->fIsLanman = FALSE ; // no more info of interest
lpNetUseInfo->dwStatus = USE_REMEMBERED ;
lpNetUseInfo->dwRefCount =
lpNetUseInfo->dwUseCount = 0 ;
_tcsupr(lpNetUseInfo->lpLocalName) ;
*NumRead += 1 ;
}
//
// allocate a new buffer for next set, since we still need
// data in the old one, we dont free it. Netcmd lets the
// system clean up when it exits.
//
if (dwErr == WN_SUCCESS)
{
if (err = AllocMem(BufferSize = 4096, &Buffer))
{
ErrorExit(err);
}
}
}
else
{
return dwErr;
}
}
while (dwErr == WN_SUCCESS) ;
dwErr = WNetCloseEnum(EnumHandle) ; // we dont report any errors here
return NERR_Success ;
}
/***
* CmpUseInfo(use1,use2)
*
* Compares two USE_INFO_1 structures and returns a relative
* lexical value, suitable for using in qsort.
*
*/
int __cdecl CmpUseInfo(const VOID FAR * use1, const VOID FAR * use2)
{
register USHORT localDev1, localDev2;
register DWORD devType1, devType2;
/* first sort by whether use has local device name */
localDev1 = ((NET_USE_INFO *) use1)->lpLocalName[0];
localDev2 = ((NET_USE_INFO *) use2)->lpLocalName[0];
if (localDev1 && !localDev2)
return -1;
if (localDev2 && !localDev1)
return +1;
/* then sort by device type */
devType1 = ((NET_USE_INFO *) use1)->dwType;
devType2 = ((NET_USE_INFO *) use2)->dwType;
if (devType1 != devType2)
return( (devType1 < devType2) ? -1 : 1 );
/* if local device, sort by local name */
if (localDev1)
return _tcsicmp ( ((NET_USE_INFO *) use1)->lpLocalName,
((NET_USE_INFO *) use2)->lpLocalName);
else
/* sort by remote name */
return _tcsicmp ( ((NET_USE_INFO *) use1)->lpRemoteName,
((NET_USE_INFO *) use2)->lpRemoteName);
}
/***
* use_unc()
* Process "NET USE unc-name" command line (display or add)
*
* Args:
* name - the unc name
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID use_unc(TCHAR * name)
{
DWORD dwErr;
LPUSE_INFO_1 use_entry;
UseInit();
if (dwErr = NetUseGetInfo(NULL,
name,
1,
(LPBYTE *) &use_entry))
{
//
// hit an error, so just add it
//
NetApiBufferFree((LPBYTE) use_entry);
use_add(NULL, name, NULL, FALSE, TRUE);
}
else
{
//
// it is Lanman. treat it as we have in the past
//
if ((use_entry->ui1_usecount == 0) && (use_entry->ui1_refcount == 0))
use_add(NULL, name, NULL, FALSE, FALSE);
else
LanmanDisplayUse(use_entry);
NetApiBufferFree((CHAR FAR *) use_entry);
InfoSuccess();
}
}
/***
* use_display_dev()
* Display status of redirected device.
*
* Args:
* dev - redirected device
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID use_display_dev(TCHAR * dev)
{
DWORD dwErr;
LPUSE_INFO_1 use_entry = NULL;
if (IsWildCard(dev))
help_help(0, USAGE_ONLY) ;
UseInit();
if (dwErr = NetUseGetInfo(NULL,
dev,
1,
(LPBYTE *) &use_entry))
{
//
// Lanman failed, so try MPR
//
NetApiBufferFree((LPBYTE) use_entry);
MprUseDisplay(dev) ;
InfoSuccess();
}
else
{
LanmanDisplayUse(use_entry);
NetApiBufferFree((CHAR FAR *) use_entry);
InfoSuccess();
}
}
VOID
MprUseDisplay(
TCHAR *dev
)
{
DWORD dwErr;
DWORD dwLength = 0;
LPTSTR lpRemoteName;
DWORD maxLen;
//
// Figure out how large a buffer we need
//
dwErr = WNetGetConnection(dev, NULL, &dwLength);
if (dwErr != WN_MORE_DATA)
{
ErrorExit(dwErr);
}
dwErr = AllocMem(dwLength * sizeof(TCHAR), &lpRemoteName);
if (dwErr != NERR_Success)
{
ErrorExit(dwErr);
}
dwErr = WNetGetConnection(dev, lpRemoteName, &dwLength);
if (dwErr != WN_SUCCESS && dwErr != WN_CONNECTION_CLOSED)
{
ErrorExit(dwErr);
}
dwLength = _tcslen(dev);
if (dwLength == 2 && _istalpha(dev[0]) && dev[1] == TEXT(':'))
{
UseMsgList[USE_TYPE_TBD].msg_number = APE2_USE_TYPE_DISK;
}
else if (dwLength >= 3 && _tcsnicmp(dev, TEXT("LPT"), 3) == 0)
{
UseMsgList[USE_TYPE_TBD].msg_number = APE2_USE_TYPE_PRINT;
}
else
{
UseMsgList[USE_TYPE_TBD].msg_number = APE2_GEN_UNKNOWN;
}
GetMessageList(NUM_USE_MSGS, UseMsgList, &maxLen);
maxLen += 5;
WriteToCon(fmtPSZ,0,maxLen,
PaddedString(maxLen,UseMsgList[USE_MSG_LOCAL].msg_text,NULL),
dev);
WriteToCon(fmtPSZ,0,maxLen,
PaddedString(maxLen,UseMsgList[USE_MSG_REMOTE].msg_text,NULL),
lpRemoteName);
WriteToCon(fmtNPSZ,0,maxLen,
PaddedString(maxLen,UseMsgList[USE_MSG_TYPE].msg_text,NULL),
UseMsgList[USE_TYPE_TBD].msg_text);
FreeMem(lpRemoteName);
return;
}
/***
* use_add()
* Add a redirection
*
* Args:
* dev - local device to redirect
* name - remote name to redirect to
* pass - password to use when validating the use
* comm - TRUE --> use as a char dev
* print_ok - should a message be printed on success?
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID use_add(TCHAR * dev, TCHAR * name, TCHAR * pass, int comm, int print_ok)
{
//
// pbuf should be sized to whichever one is larger
//
C_ASSERT(PWLEN <= CREDUI_MAX_PASSWORD_LENGTH);
static TCHAR pbuf[CREDUI_MAX_PASSWORD_LENGTH + 1];
static TCHAR UserBuffer[CREDUI_MAX_USERNAME_LENGTH + 1];
static TCHAR ServerNameBuffer[MAX_PATH + 1] = {0};
USHORT err; /* short return status */
ULONG ulErr ; /* long return status */
ULONG longtype; /* type field for I_NetPath */
NETRESOURCEW netresource ;
BOOL fRememberSwitch = FALSE ;
BOOL fRemember = FALSE ;
BOOL fSmartCard = FALSE;
ULONG bConnectFlags = 0L ;
LPWSTR pw_username = NULL;
LPWSTR pw_pass = NULL;
TCHAR *devicename = dev ;
BOOL fExitCodeIsDrive = FALSE ;
BOOL fSaveCred = FALSE;
// unreferenced
(void) comm ;
UseInit();
//
// Build a non-UNC version of name to connect to.
//
if ( name != NULL ) {
TCHAR *SlashPointer;
//
// Lob off the leading backslashes
//
if ( name[0] == '\\' && name[1] == '\\' ) {
_tcsncpy( ServerNameBuffer, &name[2], MAX_PATH );
} else {
_tcsncpy( ServerNameBuffer, name, MAX_PATH );
}
//
// Lob off the share name
//
SlashPointer = _tcschr( ServerNameBuffer, '\\');
if ( SlashPointer != NULL ) {
*SlashPointer = '\0';
}
} else {
ServerNameBuffer[0] = '\0';
}
// make sure we clean this up
AddToMemClearList(pbuf, sizeof(pbuf), FALSE) ;
// deal with any wild card Device specification
if (devicename)
{
// If the devicname is a '?', then the exit code should be the ASCII
// value of the drive that we connect.
if (IsQuestionMark(devicename))
{
fExitCodeIsDrive = TRUE;
}
devicename = MapWildCard(devicename, NULL) ;
if (!devicename)
{
// this can omly happen if no drives left
ErrorExit(APE_UseWildCardNoneLeft) ;
}
}
/* Initialize netresource structure */
netresource.lpProvider = NULL ;
netresource.lpLocalName = NULL ;
netresource.lpRemoteName = NULL ;
netresource.dwType = 0L ;
if (devicename)
{
if (I_NetPathType(NULL, devicename, &longtype, 0L))
ErrorExit(APE_UnknDevType);
/*
* NOTE: I would haved LOVED to have used a switch statement here.
* But since types are now LONGS, and the compiler doesn't support
* long switch statements, we're stuck with multiple if's. Sorry.
*/
if (longtype == ITYPE_DEVICE_DISK)
netresource.dwType = RESOURCETYPE_DISK;
else if (longtype == ITYPE_DEVICE_LPT)
netresource.dwType = RESOURCETYPE_PRINT;
else if (longtype == ITYPE_DEVICE_COM)
netresource.dwType = RESOURCETYPE_PRINT;
else
ErrorExit(APE_UnknDevType);
netresource.lpLocalName = devicename ;
}
else
{
netresource.dwType = RESOURCETYPE_ANY;
netresource.lpLocalName = L"" ;
}
if( name != NULL )
{
netresource.lpRemoteName = name ;
}
{
USHORT i;
// Find out if the /USER or /PERSISTENT switches are used
for (i = 0; SwitchList[i]; i++)
{
//
// Handle the /PERSISTENT switch
//
if ( !(_tcsncmp(SwitchList[i],
swtxt_SW_USE_PERSISTENT,
_tcslen(swtxt_SW_USE_PERSISTENT))) )
{
LPTSTR ptr;
DWORD res;
DWORD answer;
fRememberSwitch = TRUE;
// find the colon separator
if ((ptr = FindColon(SwitchList[i])) == NULL)
{
ErrorExit(APE_InvalidSwitchArg);
}
// parse string after colon for YES or NO
if ((res = LUI_ParseYesNo(ptr,&answer)) != 0)
{
ErrorExitInsTxt(APE_CmdArgIllegal,SwitchList[i]);
}
fRemember = (answer == LUI_YES_VAL) ;
//
// Handle the /USER switch
//
}
else if ( !(_tcsncmp(SwitchList[i],
swtxt_SW_USE_USER,
_tcslen(swtxt_SW_USE_USER))) )
{
PTCHAR ptr;
// find the colon separator
if ((ptr = FindColon(SwitchList[i])) == NULL)
ErrorExit(APE_InvalidSwitchArg);
pw_username = ptr;
//
// Handle the /SMARTCARD switch
//
} else if ( !(_tcscmp(SwitchList[i], swtxt_SW_USE_SMARTCARD ))) {
fSmartCard = TRUE;
//
// Handle the /SAVECRED switch
//
} else if ( !(_tcscmp(SwitchList[i], swtxt_SW_USE_SAVECRED ))) {
fSaveCred = TRUE;
//
// Handle the /Delete switch
// (The parser really doesn't let this through.)
//
}
else if ( !(_tcscmp(SwitchList[i], swtxt_SW_DELETE)) )
{
// what the heck? adding and deleting?
ErrorExit(APE_ConflictingSwitches) ;
}
// ignore other switches
}
}
// remember switch was not specified
if (!fRememberSwitch)
{
if (QueryDefaultPersistence(&fRemember)!=NERR_Success)
InfoPrint(APE_ProfileReadError);
}
//
// /user and /savecred are mutually exclusive.
// This is because the auth packages don't call cred man if the user name
// is specified. Therefore, the auth package didn't pass the target info to cred man.
// If there is no target info, the UI will save a server specific cred.
//
if ( pw_username != NULL && fSaveCred ) {
ErrorExit(APE_ConflictingSwitches) ;
}
//
// Handle /SMARTCARD switch.
// Prompt for smart card credentials.
//
if ( fSmartCard ) {
//
// We don't know how to save smartcard creds
//
if ( fSaveCred ) {
ErrorExit(APE_ConflictingSwitches) ;
}
//
// If a user name was specified,
// use it to select which smart card to use.
//
if ( pw_username != NULL ) {
_tcsncpy( UserBuffer, pw_username, CREDUI_MAX_USERNAME_LENGTH );
} else {
UserBuffer[0] = '\0';
}
//
// If password is specified,
// use it as the default PIN
if ( pass != NULL ) {
// Consider "*" to be the same as "not specified"
if (! _tcscmp(pass, TEXT("*"))) {
pbuf[0] = '\0';
} else {
if (err = LUI_CanonPassword(pass)) {
ErrorExit(err);
}
_tcsncpy( pbuf, pass, CREDUI_MAX_PASSWORD_LENGTH );
}
} else {
pbuf[0] = '\0';
}
//
// Call the common UI.
//
// RtlZeroMemory( &UiInfo, sizeof(UiInfo) );
// UiInfo.dwVersion = 1;
ulErr = CredUICmdLinePromptForCredentialsW(
ServerNameBuffer, // Target name
NULL, // No context
NO_ERROR, // No authentication error
UserBuffer,
CREDUI_MAX_USERNAME_LENGTH,
pbuf,
CREDUI_MAX_PASSWORD_LENGTH,
NULL, // SaveFlag not allowed unless flag is specified
CREDUI_FLAGS_REQUIRE_SMARTCARD |
CREDUI_FLAGS_DO_NOT_PERSIST );
if ( ulErr != NO_ERROR ) {
ErrorExit(ulErr);
}
pw_username = UserBuffer;
pw_pass = pbuf;
//
// Handle cases where the password is specified on the command line.
//
} else if (pass) {
//
// We don't know how to save creds we don't prompt for
//
if ( fSaveCred ) {
ErrorExit(APE_ConflictingSwitches) ;
}
if (! _tcscmp(pass, TEXT("*")))
{
pass = pbuf;
IStrings[0] = name;
ReadPass(pass, PWLEN, 0, APE_UsePassPrompt, 1, FALSE);
if (err = LUI_CanonPassword(pass))
ErrorExit(err);
}
else
{
if (err = LUI_CanonPassword(pass))
ErrorExit(err);
}
pw_pass = pass;
}
//
// Loop handling assigning to the next drive letter
//
do {
//if persistent, the check for clash with existing remembered connection
bConnectFlags = 0 ;
if (fRemember)
{
if (CheckIfWantUpdate(devicename, name))
bConnectFlags |= CONNECT_UPDATE_PROFILE ;
}
//
// Allow it to prompt for us if the credential aren't on the command line
//
if ( !pass && !fSmartCard) {
bConnectFlags |= CONNECT_INTERACTIVE | CONNECT_COMMANDLINE;
//
// If the caller wants to save both username and password,
// create an enterprise peristed cred.
//
if ( fSaveCred ) {
bConnectFlags |= CONNECT_CMD_SAVECRED;
}
}
ulErr = WNetAddConnection2(&netresource,
pw_pass,
pw_username,
bConnectFlags) ;
switch(ulErr)
{
case WN_SUCCESS:
if (fRememberSwitch)
{
DWORD dwErr = SetDefaultPersistence(fRemember);
if (dwErr != NERR_Success)
{
ErrorExit(dwErr);
}
}
if (print_ok)
{
if (IsWildCard(dev)) // if originally a wildcard
{
IStrings[0] = devicename;
IStrings[1] = name;
InfoPrintIns(APE_UseWildCardSuccess, 2) ;
}
InfoSuccess();
}
if (fExitCodeIsDrive)
{
MyExit((int)devicename[0]);
}
return;
case WN_BAD_PASSWORD:
case WN_ACCESS_DENIED:
case ERROR_LOGON_FAILURE:
WNetErrorExit(ulErr);
case ERROR_ALREADY_ASSIGNED:
if (!IsWildCard(dev))
{
ErrorExit(ERROR_ALREADY_ASSIGNED);
}
// Get another drive letter
(devicename[0])++;
devicename = MapWildCard(TEXT("*"), devicename) ;
if (!devicename)
{
// this can only happen if no drives left
ErrorExit(APE_UseWildCardNoneLeft) ;
}
netresource.lpLocalName = devicename ;
break;
case WN_BAD_NETNAME:
if (is_admin_dollar(name))
{
ErrorExit(APE_BadAdminConfig);
}
// else drop thru
default:
WNetErrorExit(ulErr);
}
} while ( ulErr == ERROR_ALREADY_ASSIGNED );
}
VOID
use_set_remembered(
VOID
)
{
PTCHAR ptr;
BOOL fRemember ;
// Find the /persistent switch
if ((ptr = FindColon(SwitchList[0])) == NULL)
ErrorExit(APE_InvalidSwitchArg);
if ( !(_tcscmp(SwitchList[0], swtxt_SW_USE_PERSISTENT) ) )
{
DWORD res;
DWORD answer;
if ((res = LUI_ParseYesNo(ptr,&answer)) != 0)
{
ErrorExitInsTxt(APE_CmdArgIllegal,SwitchList[0]) ;
}
fRemember = (answer == LUI_YES_VAL) ;
res = SetDefaultPersistence(fRemember);
if (res != NERR_Success)
{
ErrorExit(res);
}
}
else
{
ErrorExit(APE_InvalidSwitch);
}
InfoSuccess();
}
/***
* use_del()
* Delete a redirection
*
* Args:
* dev - device OR unc-name to delete
* print_ok - print success message?
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID use_del(TCHAR * dev, BOOL deviceless, int print_ok)
{
ULONG ulErr; /* API return status */
BOOL fRememberSwitch = FALSE ;
ULONG bConnectFlags = 0L ;
USHORT i;
UseInit();
// Find out if the /PERSISTENT switch is used
for (i = 0; SwitchList[i]; i++)
{
if ( !(_tcscmp(SwitchList[i], swtxt_SW_USE_PERSISTENT)) )
ErrorExit(APE_InvalidSwitch);
}
if (IsWildCard(dev))
{
use_del_all() ;
goto gone;
}
bConnectFlags = CONNECT_UPDATE_PROFILE ; // deletes always update
if ((ulErr = WNetCancelConnection2( dev,
bConnectFlags,
FALSE)) != WN_SUCCESS)
{
if (ulErr != WN_OPEN_FILES)
WNetErrorExit(ulErr);
}
else
goto gone;
InfoPrintInsTxt(APE_OpenHandles, dev);
if (!YorN(APE_UseBlowAway, 0))
NetcmdExit(2);
if ((ulErr = WNetCancelConnection2( (LPWSTR)dev,
bConnectFlags,
TRUE )) != WN_SUCCESS)
WNetErrorExit(ulErr);
gone:
if (print_ok)
if ( IsWildCard( dev ) )
InfoSuccess();
else
InfoPrintInsTxt(APE_DelSuccess, dev);
}
/***
* use_del_all()
* Delete all redirections
*
* Args:
* none
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
VOID use_del_all()
{
DWORD err = 0; /* API return status */
ULONG ulErr = 0; /* WNet error */
ULONG ulFirstErr = 0; /* WNet error */
DWORD num_read = 0; /* num entries read by API */
DWORD i = 0,j = 0;
DWORD NetUseInfoCount = 0 ;
NET_USE_INFO *NetUseInfoBuffer = NULL ;
NET_USE_INFO *pNetUseInfo = NULL;
ULONG bConnectFlags = 0L ;
UseInit();
if (err = MprUseEnum(&num_read, &NetUseInfoBuffer, &NetUseInfoCount))
ErrorExit(err);
if (err = UnavailUseAugment(&num_read, &NetUseInfoBuffer, &NetUseInfoCount))
ErrorExit(err);
if (err = LanmanUseAugment(num_read, NetUseInfoBuffer))
ErrorExit(err);
if (num_read == 0)
EmptyExit();
for (i = 0, pNetUseInfo = NetUseInfoBuffer;
i < num_read; i++, pNetUseInfo++)
{
//
// if we find at least one entry we will display, break
//
if (!(pNetUseInfo->fIsLanman)
|| (pNetUseInfo->dwStatus != USE_OK)
|| (pNetUseInfo->dwUseCount != 0)
|| (pNetUseInfo->dwRefCount != 0))
break;
}
qsort(NetUseInfoBuffer,
num_read,
sizeof(NET_USE_INFO), CmpUseInfo);
if (i != num_read)
{
InfoPrint(APE_KillDevList);
for (i = 0, pNetUseInfo = NetUseInfoBuffer;
i < num_read;
i++, pNetUseInfo++)
{
if (pNetUseInfo->lpLocalName[0] != NULLC)
WriteToCon(TEXT(" %Fws %Fws\r\n"),
PaddedString(15,pNetUseInfo->lpLocalName,NULL),
pNetUseInfo->lpRemoteName);
else
WriteToCon(TEXT(" %Fws %Fws\r\n"),
PaddedString(15,pNetUseInfo->lpLocalName,NULL),
pNetUseInfo->lpRemoteName);
}
InfoPrint(APE_KillCancel);
if (!YorN(APE_ProceedWOp, 0))
NetcmdExit(2);
}
bConnectFlags = CONNECT_UPDATE_PROFILE ; // deletes always update
ulErr = NO_ERROR;
ulFirstErr = NO_ERROR;
for (i = 0, pNetUseInfo = NetUseInfoBuffer;
i < num_read;
i++, pNetUseInfo++)
{
/* delete both local and UNC uses */
if (pNetUseInfo->lpLocalName[0] != NULLC)
{
ulErr = WNetCancelConnection2( pNetUseInfo->lpLocalName,
bConnectFlags,
FALSE);
}
else
{
/*
* Delete All UNC uses to use_entry->ui1_remote
*/
if ( pNetUseInfo->dwUseCount == 0 )
{
pNetUseInfo->dwUseCount = 1;
}
for( j = 0; j < pNetUseInfo->dwUseCount; j++ )
{
ulErr = WNetCancelConnection2( pNetUseInfo->lpRemoteName,
bConnectFlags,
FALSE );
if ( ulErr != NO_ERROR )
break;
}
}
switch(ulErr)
{
case NO_ERROR:
/* The use was returned by Enum, but is already gone */
case WN_BAD_NETNAME:
case WN_NOT_CONNECTED:
break;
case WN_OPEN_FILES:
if (pNetUseInfo->lpLocalName[0] != NULLC)
IStrings[0] = pNetUseInfo->lpLocalName;
else
IStrings[0] = pNetUseInfo->lpRemoteName;
InfoPrintIns(APE_OpenHandles, 1);
if (!YorN(APE_UseBlowAway, 0))
continue;
if (pNetUseInfo->lpLocalName[0] != NULLC)
{
ulErr = WNetCancelConnection2( pNetUseInfo->lpLocalName,
bConnectFlags,
TRUE ) ;
}
else
{
/*
* Delete All UNC uses to use_entry->ui1_remote
*/
for( j = 0; j < pNetUseInfo->dwUseCount; j++ )
{
ulErr = WNetCancelConnection2( pNetUseInfo->lpRemoteName,
bConnectFlags,
TRUE );
if ( ulErr != NO_ERROR )
break;
}
}
if (ulErr == NO_ERROR)
break;
// fall through
default:
ulFirstErr = ulErr;
}
}
FreeMem((LPBYTE)NetUseInfoBuffer);
if (ulFirstErr != NO_ERROR)
WNetErrorExit( ulErr );
}
/***
* LanmanDisplayUse()
* Display info from a USE_INFO_1 struct
*
* Args:
* use_entry - pointer to a USE_INFO_1 struct
*
* Returns:
* 0
*/
VOID
LanmanDisplayUse(
LPUSE_INFO_1 use_entry
)
{
DWORD maxLen;
USHORT status = APE2_GEN_UNKNOWN;
USHORT type = APE2_GEN_UNKNOWN;
switch(use_entry->ui1_asg_type)
{
case USE_DISKDEV:
type = APE2_USE_TYPE_DISK;
break;
case USE_SPOOLDEV:
type = APE2_USE_TYPE_PRINT;
break;
case USE_CHARDEV:
type = APE2_USE_TYPE_COMM;
break;
case USE_IPC:
type = APE2_USE_TYPE_IPC;
break;
}
UseMsgList[USE_TYPE_TBD].msg_number = type;
switch(use_entry->ui1_status)
{
case USE_OK:
status = APE2_USE_STATUS_OK;
break;
case USE_PAUSED:
status = APE2_USE_STATUS_PAUSED;
break;
case USE_SESSLOST:
status = APE2_USE_STATUS_SESSION_LOST;
break;
case USE_NETERR:
status = APE2_USE_STATUS_NET_ERROR;
break;
case USE_CONN:
status = APE2_USE_STATUS_CONNECTING;
break;
case USE_RECONN:
status = APE2_USE_STATUS_RECONNECTING;
break;
}
UseMsgList[USE_STATUS_TBD].msg_number = status;
GetMessageList(NUM_USE_MSGS, UseMsgList, &maxLen);
maxLen += 5;
WriteToCon(fmtPSZ,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_LOCAL].msg_text, NULL),
use_entry->ui1_local);
WriteToCon(fmtPSZ,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_REMOTE].msg_text, NULL),
use_entry->ui1_remote);
WriteToCon(fmtNPSZ,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_TYPE].msg_text, NULL),
UseMsgList[USE_TYPE_TBD].msg_text);
WriteToCon(fmtNPSZ,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_STATUS].msg_text, NULL),
UseMsgList[USE_STATUS_TBD].msg_text);
WriteToCon(fmtUSHORT,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_OPEN_COUNT].msg_text, NULL),
use_entry->ui1_refcount);
WriteToCon(fmtUSHORT,0,maxLen,
PaddedString(maxLen, UseMsgList[USE_MSG_USE_COUNT].msg_text, NULL),
use_entry->ui1_usecount);
}
/***
* use_add_home()
* Add a use for the user's home directory
*
* Args:
* Dev - device to be used as the home directory
* Pass - password, or NULL if none supplied
*
* Returns:
* 0 - success
* exit(2) - command failed
*/
void
use_add_home(
LPTSTR Dev,
LPTSTR Pass
)
{
DWORD dwErr;
TCHAR HomeDir[PATHLEN];
TCHAR Server[MAX_PATH + 1];
TCHAR FAR *SubPath;
ULONG Type;
TCHAR User[UNLEN + 1];
TCHAR *DeviceName = Dev ;
LPWKSTA_INFO_1 info_entry_w;
LPUSER_INFO_11 user_entry;
//
// If necessary, start the workstation and logon.
//
UseInit();
//
// Get the user name and the name of the server that logged the user on.
//
dwErr = MNetWkstaGetInfo(1, (LPBYTE*) &info_entry_w) ;
if (dwErr)
{
ErrorExit(dwErr);
}
_tcscpy(User, info_entry_w->wki1_username);
_tcscpy(Server, TEXT("\\\\")) ;
_tcscat(Server, info_entry_w->wki1_logon_server);
NetApiBufferFree((TCHAR FAR *) info_entry_w);
/* Now get user information (ie. the home directory). If you were */
/* logged on STANDALONE, and the local machine is a STANDALONE */
/* server, this will still work. Otherwise (eg., you are logged on */
/* STANDALONE on a DOS workstation), it will fail because there is */
/* no local UAS. */
dwErr = NetUserGetInfo(Server, User, 11, (LPBYTE *) &user_entry);
if (dwErr)
{
ErrorExit(APE_UseHomeDirNotDetermined);
}
_tcscpy(HomeDir, user_entry->usri11_home_dir);
NetApiBufferFree((TCHAR FAR *) user_entry);
/* If it is null string, return a "not set" error msg. */
if (HomeDir[0] == NULLC)
ErrorExit(APE_UseHomeDirNotSet);
/* Make sure the home directory is a UNC name. This does not */
/* insure that the sharename is usable under DOS, but the */
/* general policy on this issue is to make it the admin's */
/* responsibility to be aware of non-8.3 sharename implications, */
/* and "net share" does issue a warning. */
dwErr = I_NetPathType(NULL, HomeDir, &Type, 0L);
if (dwErr || Type != ITYPE_UNC)
ErrorExitInsTxt(APE_UseHomeDirNotUNC, HomeDir);
/* Split the home directory into a remote name and a subpath. */
/* After doing this, HomeDir points to the remote name, and */
/* SubPath points to a subpath, or a null string if there is */
/* no subpath. */
/* Find the backslash between the computername and the sharename. */
SubPath = _tcschr(HomeDir + 2, '\\');
/* Find the next backslash, if there is one. */
SubPath = _tcschr(SubPath + 1, '\\');
if (SubPath)
{
*SubPath = NULLC;
SubPath++;
}
else
SubPath = NULL_STRING;
/* Map the wild cards as need */
if (DeviceName)
{
DeviceName = MapWildCard(DeviceName, NULL) ;
if (!DeviceName)
{
// this can only happen if no drives left
ErrorExit(APE_UseWildCardNoneLeft) ;
}
}
/* Do the use. If we return, we succeeded. */
use_add(DeviceName, HomeDir, Pass, FALSE, FALSE);
IStrings[0] = DeviceName;
IStrings[1] = HomeDir;
IStrings[2] = DeviceName;
IStrings[3] = SubPath;
InfoPrintIns(APE_UseHomeDirSuccess, 4);
return;
}
BOOL
is_admin_dollar(
LPWSTR name
)
{
LPWSTR tfpC;
if (name[0] == L'\0' || name[1] == L'\0')
{
return FALSE;
}
tfpC = _tcspbrk(name + 2, TEXT("\\/"));
if (tfpC == NULL)
{
return FALSE;
}
tfpC += 1;
return (!_tcsicmp(ADMIN_DOLLAR, tfpC));
}
/***
* UseInit()
* Common initialization processing for all the use.c module entry
* points.
*
* Args: None.
*
* Returns: None.
*/
VOID NEAR
UseInit(VOID)
{
LanmanProviderName = GetLanmanProviderName() ;
if (LanmanProviderName == NULL)
{
LanmanProviderName = TEXT("") ;
}
}
/*
* query the user profile to see if connections are currently being remembered
*/
USHORT QueryDefaultPersistence(BOOL *pfRemember)
{
// by adding the two, we are guaranteed to have enough
TCHAR szAnswer[(sizeof(MPR_YES_VALUE)+sizeof(MPR_NO_VALUE))/sizeof(TCHAR)] ;
ULONG iRes, len ;
len = DIMENSION(szAnswer) ;
iRes = GetProfileString(MPR_NETWORK_SECTION,
MPR_SAVECONNECTION_KEY,
MPR_YES_VALUE, // default is yes
szAnswer,
len) ;
if (iRes == len) // error
return(APE_ProfileReadError) ;
*pfRemember = (_tcsicmp(szAnswer,MPR_YES_VALUE)==0) ;
return (NERR_Success) ;
}
/*
* set if connections are currently being remembered
*/
DWORD
SetDefaultPersistence(
BOOL fRemember
)
{
BOOL fSuccess ;
fSuccess = (WriteProfileString(MPR_NETWORK_SECTION,
MPR_SAVECONNECTION_KEY,
fRemember ? MPR_YES_VALUE : MPR_NO_VALUE ) != 0);
return (fSuccess ? NERR_Success : APE_ProfileWriteError) ;
}
/*
* WNetErrorExit()
* maps the Winnet error to NERR and error exits
*
* arguments: ULONG win32 error code.
* return value: none. this baby dont return
*/
VOID
WNetErrorExit(
ULONG ulWNetErr
)
{
WCHAR w_ErrorText[256];
WCHAR w_ProviderText[64];
LONG ulExtendedError ;
DWORD err ;
switch (ulWNetErr)
{
case WN_SUCCESS :
return ;
case WN_BAD_POINTER :
case WN_BAD_VALUE :
err = ERROR_INVALID_PARAMETER ;
break ;
case WN_BAD_USER :
err = APE_BadUserContext ;
break ;
case WN_NO_NET_OR_BAD_PATH :
err = ERROR_BAD_NET_NAME ;
break ;
case WN_NO_NETWORK :
err = NERR_WkstaNotStarted ;
break ;
case WN_NOT_CONNECTED :
err = NERR_UseNotFound ;
break ;
case WN_DEVICE_IN_USE :
err = NERR_DevInUse ;
break ;
case WN_BAD_PROFILE :
case WN_CANNOT_OPEN_PROFILE :
err = APE_ProfileReadError ;
break ;
/*
* these should not happen under the calls we currently make,
* but for completeness, they are there.
*/
case WN_BAD_PROVIDER :
case WN_CONNECTION_CLOSED :
case WN_NOT_CONTAINER :
case WN_FUNCTION_BUSY :
case WN_DEVICE_ERROR :
err = ERROR_UNEXP_NET_ERR ;
break ;
/*
* special case this one
*/
case WN_EXTENDED_ERROR :
// get the extended error
ulWNetErr = WNetGetLastError(&ulExtendedError,
(LPWSTR)w_ErrorText,
DIMENSION(w_ErrorText),
(LPWSTR)w_ProviderText,
DIMENSION(w_ProviderText));
// if we got it, print it out
if (ulWNetErr == WN_SUCCESS)
{
TCHAR buf[40];
IStrings[0] = _ultow(ulExtendedError, buf, 10);
ErrorPrint(APE_OS2Error,1) ;
WriteToCon(TEXT("%ws\r\n"), w_ErrorText) ;
MyExit(2) ;
}
// otherwise report it as unexpected error
err = ERROR_UNEXP_NET_ERR ;
break ;
default:
// the the remainder dont need to be mapped.
err = ulWNetErr ;
break ;
}
ErrorExit(err) ;
}
/*
* code to handle the situation where the user has a remembered
* connection that is currently not used, and we need to figure out
* if we need to delete it first.
*
* returns whether we need update profile.
*/
BOOL CheckIfWantUpdate(TCHAR *dev, TCHAR *resource)
{
WCHAR w_RemoteName[MAX_PATH];
ULONG ulErr, cchRemoteName = DIMENSION(w_RemoteName);
// if deviceless, no problem since never remembered anyway.
if (dev == NULL)
return FALSE ;
// check out the device
ulErr = WNetGetConnection( (LPWSTR)dev,
(LPWSTR)w_RemoteName,
&cchRemoteName );
// device is really connected, bag out
if (ulErr == WN_SUCCESS)
ErrorExit(ERROR_ALREADY_ASSIGNED) ;
// it is an unavail remembered device, so prompt as need
if (ulErr == WN_CONNECTION_CLOSED)
{
// if the new and old are the same we just return FALSE
// since the user effectively does not change his profile
if (!_tcsicmp(w_RemoteName, resource))
{
return FALSE ;
}
// check if YES/NO switch is specified.
if (YorN_Switch == 2)
{
// he specified /NO, so we tell him why we bag out
IStrings[0] = dev ;
IStrings[1] = w_RemoteName ;
ErrorExitIns(APE_DeviceIsRemembered,2) ;
}
// nothing specified, so ask user
if (YorN_Switch == 0)
{
IStrings[0] = dev ;
IStrings[1] = w_RemoteName ;
if (!LUI_YorNIns(IStrings,2,APE_OverwriteRemembered,1))
{
// he said no, so quit
NetcmdExit(2) ;
}
}
// remove the persistent connection,
// we get here if the user specifies /YES, or didnt
// specify anything but consented,
if (WNetCancelConnection2( dev,
CONNECT_UPDATE_PROFILE,
FALSE) != WN_SUCCESS)
ErrorExit(APE_ProfileWriteError) ;
}
// if we get here then all is cool, let the caller carry on.
return TRUE ;
}
#define PROVIDER_NAME_LEN 256
#define PROVIDER_NAME_VALUE L"Name"
#define PROVIDER_NAME_KEY L"System\\CurrentControlSet\\Services\\LanmanWorkstation\\NetworkProvider"
/***
* GetLanmanProviderName()
* Reads the Lanman provider name from the registry.
* This is to make sure we only use the LM provider even
* if someone else supports UNC.
*
* Args:
* none
*
* Returns:
* pointer to provider name if success
* NULL if cannot read registry
* ErrorExit() for other errors.
*/
WCHAR *GetLanmanProviderName(void)
{
LONG Nerr;
LPBYTE buffer ;
HKEY hKey ;
DWORD buffersize, datatype ;
buffersize = PROVIDER_NAME_LEN * sizeof(WCHAR) ;
datatype = REG_SZ ;
if (Nerr = AllocMem(buffersize, &buffer))
{
ErrorExit(Nerr);
}
Nerr = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
PROVIDER_NAME_KEY,
0L,
KEY_QUERY_VALUE,
&hKey) ;
if (Nerr != ERROR_SUCCESS)
{
//
// if cannot read, we use NULL. this is more generous
// than normal, but at least the command will still work if
// we cannot get to this.
//
FreeMem(buffer);
return NULL;
}
Nerr = RegQueryValueExW(hKey,
PROVIDER_NAME_VALUE,
0L,
&datatype,
(LPBYTE)buffer,
&buffersize) ;
if (Nerr == ERROR_MORE_DATA)
{
if (Nerr = ReallocMem(buffersize, &buffer))
{
RegCloseKey(hKey);
ErrorExit(Nerr);
}
Nerr = RegQueryValueExW(hKey,
PROVIDER_NAME_VALUE,
0L,
&datatype,
(LPBYTE)buffer,
&buffersize) ;
}
RegCloseKey(hKey);
if (Nerr != ERROR_SUCCESS)
{
FreeMem(buffer);
return(NULL) ; // treat as cannot read
}
return ((WCHAR *) buffer);
}
/***
* MapWildCard()
* Maps the wildcard ASTERISK to next avail drive.
*
* Args:
* dev - the input string. Must NOT be NULL.
*
* Returns:
* dev unchanged if it is not the wildcard
* pointer to next avail drive id dev is wildcard
* NULL if there are no avail drives left
*/
LPTSTR
MapWildCard(
LPTSTR dev,
LPTSTR startdev
)
{
static TCHAR new_dev[DEVLEN+1] ;
//
// if not the wold card char, just return it unchanged
//
if (!IsWildCard(dev))
{
return dev ;
}
//
// need find the next avail drive letter
// note: the char advance does not need to be DBCS safe,
// since we are only dealing with drive letters.
//
if ( startdev != NULL )
{
_tcscpy(new_dev, startdev);
}
else
{
_tcscpy(new_dev,TEXT("Z:\\")) ;
}
while ( TRUE )
{
if (GetDriveType(new_dev) == 1) // 1 means root not found
{
//
// check if it's a remembered connection
//
DWORD status;
TCHAR remote_name[40]; // length doesn't matter since we
// check for WN_MORE_DATA
DWORD length = sizeof(remote_name)/sizeof(TCHAR);
new_dev[2] = 0 ;
status = WNetGetConnection(new_dev, remote_name, &length);
if (status == WN_CONNECTION_CLOSED ||
status == WN_MORE_DATA ||
status == WN_SUCCESS)
{
//
// it's a remembered connection; try the next drive
//
new_dev[2] = TEXT('\\');
}
else
{
return (new_dev) ;
}
}
if ( new_dev[0] == 'c' || new_dev[0] == 'C' )
{
break;
}
--new_dev[0] ;
}
//
// if we got here, there were no drives left
//
return NULL ;
}