windows-volume-status-plugin-20070705
[openafs.git] / src / WINNT / afsd / smb.c
index d90f0fc..fddacf1 100644 (file)
@@ -31,7 +31,8 @@
 /* These characters are illegal in Windows filenames */
 static char *illegalChars = "\\/:*?\"<>|";
 
-int smbShutdownFlag = 0;
+static int smbShutdownFlag = 0;
+static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
 
 int smb_LogoffTokenTransfer;
 time_t smb_LogoffTransferTimeout;
@@ -46,6 +47,7 @@ unsigned int sessionGen = 0;
 
 extern void afsi_log(char *pattern, ...);
 extern HANDLE afsi_file;
+extern int powerStateSuspended;
 
 osi_hyper_t hzero = {0, 0};
 osi_hyper_t hones = {0xFFFFFFFF, -1};
@@ -58,6 +60,8 @@ osi_mutex_t  smb_ListenerLock;
 char smb_LANadapter;
 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
 
+BOOL isGateway = FALSE;
+
 /* for debugging */
 long smb_maxObsConcurrentCalls=0;
 long smb_concurrentCalls=0;
@@ -156,7 +160,7 @@ DWORD smb_TlsRequestSlot = -1;
 /* forward decl */
 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
                        NCB *ncbp, raw_write_cont_t *rwcp);
-void smb_NetbiosInit();
+int smb_NetbiosInit(void);
 
 #ifdef LOG_PACKET
 void smb_LogPacket(smb_packet_t *packet);
@@ -1451,6 +1455,9 @@ void smb_HoldFIDNoLock(smb_fid_t *fidp)
     fidp->refCount++;
 }
 
+
+/* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
+/* the sm_fid_t->mx and smb_rctLock must not be held */
 void smb_ReleaseFID(smb_fid_t *fidp)
 {
     cm_scache_t *scp = NULL;
@@ -1465,7 +1472,13 @@ void smb_ReleaseFID(smb_fid_t *fidp)
         vcp = fidp->vcp;
         fidp->vcp = NULL;
         scp = fidp->scp;    /* release after lock is released */
-        fidp->scp = NULL;
+       if (scp) {
+           lock_ObtainMutex(&scp->mx);
+           scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+           lock_ReleaseMutex(&scp->mx);
+           osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
+           fidp->scp = NULL;
+       }
         userp = fidp->userp;
         fidp->userp = NULL;
 
@@ -1621,6 +1634,36 @@ int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
         return 0;
     }
 
+    /* Check for volume references
+     * 
+     * They look like <cell>{%,#}<volume>
+     */
+    if (strchr(shareName, '%') != NULL ||
+        strchr(shareName, '#') != NULL) {
+        char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
+                                /* make room for '/@vol:' + mountchar + NULL terminator*/
+
+        osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
+                 osi_LogSaveString(smb_logp, shareName));
+
+        snprintf(pathstr, sizeof(pathstr)/sizeof(char),
+                 "/" CM_PREFIX_VOL "%s", shareName);
+        pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
+        len = strlen(pathstr) + 1;
+
+        *pathNamep = malloc(len);
+        if (*pathNamep) {
+            strcpy(*pathNamep, pathstr);
+            strlwr(*pathNamep);
+            osi_Log1(smb_logp, "   returning pathname [%s]",
+                     osi_LogSaveString(smb_logp, *pathNamep));
+
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
                          0, KEY_QUERY_VALUE, &parmKey);
     if (code == ERROR_SUCCESS) {
@@ -1824,6 +1867,8 @@ void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
 {
     lock_ObtainWrite(&smb_globalLock);
     lock_ObtainMutex(&dsp->mx);
+    osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
+             dsp->cookie, dsp, dsp->scp);
     dsp->flags |= SMB_DIRSEARCH_DELETE;
     if (dsp->scp != NULL) {
         lock_ObtainMutex(&dsp->scp->mx);
@@ -1852,6 +1897,8 @@ void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
         lock_ReleaseMutex(&dsp->mx);
         lock_FinalizeMutex(&dsp->mx);
         scp = dsp->scp;
+       osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
+                dsp->cookie, dsp, scp);
         free(dsp);
     } else {
         lock_ReleaseMutex(&dsp->mx);
@@ -1939,6 +1986,8 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
     counter = 0;
 
     /* what's the biggest ID allowed in this version of the protocol */
+    /* TODO: do we really want a non v3 dir search request to wrap
+       smb_dirSearchCounter? */
     maxAllowed = isV3 ? 65535 : 255;
     if (smb_dirSearchCounter > maxAllowed)
         smb_dirSearchCounter = 1;
@@ -1982,7 +2031,10 @@ smb_dirSearch_t *smb_NewDirSearch(int isV3)
         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
         if (!smb_lastDirSearchp) 
             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
-        break;
+    
+       osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
+                dsp->cookie, dsp);
+       break;
     }  
     lock_ReleaseWrite(&smb_globalLock);
     return dsp;
@@ -2124,7 +2176,7 @@ void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
 }       
 
 /* return the parm'th parameter in the smbp packet */
-unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
+unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
 {
     int parmCount;
     unsigned char *parmDatap;
@@ -2148,6 +2200,30 @@ unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
 }
 
 /* return the parm'th parameter in the smbp packet */
+unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
+{
+    int parmCount;
+    unsigned char *parmDatap;
+
+    parmCount = *smbp->wctp;
+
+    if (parm >= parmCount) {
+       char s[100];
+
+       sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
+                parm, parmCount, smbp->ncb_length);
+       osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
+                 parm, parmCount, smbp->ncb_length);
+       LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
+                __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
+        osi_panic(s, __FILE__, __LINE__);
+    }
+    parmDatap = smbp->wctp + (2*parm) + 1;
+        
+    return parmDatap[0];
+}
+
+/* return the parm'th parameter in the smbp packet */
 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
 {
     int parmCount;
@@ -2554,6 +2630,9 @@ void smb_MapNTError(long code, unsigned long *NTStatusp)
 #endif
     else if (code == RXKADUNKNOWNKEY) {
        NTStatus = 0xC0000322L; /* Bad Kerberos key */
+    } 
+    else if (code == CM_ERROR_BAD_LEVEL) {
+       NTStatus = 0xC0000148L; /* Invalid Level */
     } else {
         NTStatus = 0xC0982001L;        /* SMB non-specific error */
     }
@@ -3338,6 +3417,7 @@ void smb_WaitingLocksDaemon()
                          wlRequest);
 
                 scp = wlRequest->scp;
+               osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
 
                 cm_InitReq(&req);
 
@@ -3874,6 +3954,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     lock_ObtainMutex(&dsp->mx);
     if (dsp->scp) {
         scp = dsp->scp;
+       osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
         cm_HoldSCache(scp);
         code = 0;
     } else {
@@ -3905,6 +3986,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
 #endif /* DFS_SUPPORT */
 
             dsp->scp = scp;
+           osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
             /* we need one hold for the entry we just stored into,
              * and one for our own processing.  When we're done with this
              * function, we'll drop the one for our own processing.
@@ -4155,6 +4237,7 @@ long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
                           fileType);
                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
+                    fileType == CM_SCACHETYPE_MOUNTPOINT ||
                     fileType == CM_SCACHETYPE_DFSLINK ||
                     fileType == CM_SCACHETYPE_INVALID)
                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
@@ -4770,17 +4853,22 @@ long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+
     /* and the user */
     cm_HoldUser(userp);
     fidp->userp = userp;
 
     lock_ObtainMutex(&fidp->mx);
     if ((share & 0xf) == 0)
-        fidp->flags |= SMB_FID_OPENREAD;
+        fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
     else if ((share & 0xf) == 1)
         fidp->flags |= SMB_FID_OPENWRITE;
     else 
-        fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
+        fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
     lock_ReleaseMutex(&fidp->mx);
 
     lock_ObtainMutex(&scp->mx);
@@ -4974,6 +5062,7 @@ typedef struct smb_renameRock {
     char *maskp;               /* pointer to star pattern of old file name */
     int flags;             /* tilde, casefold, etc */
     char *newNamep;            /* ptr to the new file's name */
+    int any;
 } smb_renameRock_t;
 
 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
@@ -4982,7 +5071,7 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
     smb_renameRock_t *rockp;
     int caseFold;
     int match;
-    char shortName[13];
+    char shortName[13]="";
 
     rockp = (smb_renameRock_t *) vrockp;
 
@@ -4998,16 +5087,20 @@ int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hype
         match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
     }
     if (match) {
-        code = cm_Rename(rockp->odscp, dep->name,
+       rockp->any = 1;
+
+       code = cm_Rename(rockp->odscp, dep->name,
                          rockp->ndscp, rockp->newNamep, rockp->userp,
                          rockp->reqp); 
         /* if the call worked, stop doing the search now, since we
          * really only want to rename one file.
          */
+       osi_Log1(smb_logp, "cm_Rename returns %ld", code);
         if (code == 0) 
             code = CM_ERROR_STOPNOW;
     }       
-    else code = 0;
+    else 
+       code = 0;
 
     return code;
 }
@@ -5112,12 +5205,13 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     rock.maskp = oldLastNamep;
     rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
     rock.newNamep = newLastNamep;
+    rock.any = 0;
 
     /* Check if the file already exists; if so return error */
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+                 osi_LogSaveString(smb_logp, newLastNamep));
 
         /* Check if the old and the new names differ only in case. If so return
          * success, else return CM_ERROR_EXISTS 
@@ -5155,6 +5249,12 @@ smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, i
     thyper.HighPart = 0;
 
     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
+    if (code == 0 && !rock.any) {
+       thyper.LowPart = 0;
+       thyper.HighPart = 0;
+        rock.flags |= SMB_MASKFLAG_CASEFOLD;
+       code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
+    }
     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
 
     if (code == CM_ERROR_STOPNOW)
@@ -5300,7 +5400,7 @@ smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
         osi_Log2(smb_logp, "  lookup returns %ld for [%s]", code,
-                 osi_LogSaveString(afsd_logp, newLastNamep));
+                 osi_LogSaveString(smb_logp, newLastNamep));
 
         /* if the existing link is to the same file, then we return success */
         if (!code) {
@@ -5350,6 +5450,7 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
     char *oldPathp;
     char *newPathp;
     char *tp;
+    long code;
 
     tp = smb_GetSMBData(inp, NULL);
     oldPathp = smb_ParseASCIIBlock(tp, &tp);
@@ -5360,10 +5461,13 @@ smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
         OemToChar(newPathp,newPathp);
 
     osi_Log2(smb_logp, "smb rename [%s] to [%s]",
-              osi_LogSaveString(smb_logp, oldPathp),
-              osi_LogSaveString(smb_logp, newPathp));
+             osi_LogSaveString(smb_logp, oldPathp),
+             osi_LogSaveString(smb_logp, newPathp));
+
+    code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
 
-    return smb_Rename(vcp,inp,oldPathp,newPathp,0);
+    osi_Log1(smb_logp, "smb rename returns 0x%x", code);
+    return code;
 }
 
 
@@ -5483,6 +5587,7 @@ long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *ou
     rock.userp = userp;
     rock.reqp = &req;
     rock.dscp = dscp;
+
     /* First do a case sensitive match, and if that fails, do a case insensitive match */
     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
     if (code == 0 && !rock.any) {
@@ -5600,14 +5705,14 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                   afs_uint32 dosTime) {
     long code = 0;
     cm_req_t req;
-    cm_scache_t *dscp = fidp->NTopen_dscp;
-    char *pathp = fidp->NTopen_pathp;
-    cm_scache_t * scp = fidp->scp;
+    cm_scache_t *dscp = NULL;
+    char *pathp = NULL;
+    cm_scache_t * scp = NULL;
     int deleted = 0;
     int nullcreator = 0;
 
-    osi_Log3(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d vcp=0x%x)",
-             fidp, fidp->fid, vcp);
+    osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
+             fidp, fidp->fid, scp, vcp);
 
     if (!userp) {
        lock_ObtainMutex(&fidp->mx);
@@ -5634,6 +5739,20 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     lock_ReleaseWrite(&smb_rctLock);
 
     lock_ObtainMutex(&fidp->mx);
+    if (fidp->NTopen_dscp) {
+       dscp = fidp->NTopen_dscp;
+       cm_HoldSCache(dscp);
+    }
+
+    if (fidp->NTopen_pathp) {
+       pathp = strdup(fidp->NTopen_pathp);
+    }
+
+    if (fidp->scp) {
+       scp = fidp->scp;
+       cm_HoldSCache(scp);
+    }
+
     /* Don't jump the gun on an async raw write */
     while (fidp->raw_writers) {
         lock_ReleaseMutex(&fidp->mx);
@@ -5729,15 +5848,25 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
     }
 
     if (fidp->flags & SMB_FID_NTOPEN) {
+       cm_ReleaseSCache(fidp->NTopen_dscp);
        fidp->NTopen_dscp = NULL;
+       free(fidp->NTopen_pathp);
         fidp->NTopen_pathp = NULL;
        fidp->flags &= ~SMB_FID_NTOPEN;
+    } else {
+       osi_assert(fidp->NTopen_dscp == NULL);
+       osi_assert(fidp->NTopen_pathp == NULL);
     }
+
     if (fidp->NTopen_wholepathp) {
-        free(fidp->NTopen_wholepathp);
-        fidp->NTopen_wholepathp = NULL;
+       free(fidp->NTopen_wholepathp);
+       fidp->NTopen_wholepathp = NULL;
+    }
+
+    if (fidp->scp) {
+       cm_ReleaseSCache(fidp->scp);
+       fidp->scp = NULL;
     }
-    fidp->scp = NULL;
     lock_ReleaseMutex(&fidp->mx);
 
     if (dscp)
@@ -5752,6 +5881,9 @@ long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
                scp->flags |= CM_SCACHEFLAG_DELETED;
            lock_ReleaseMutex(&scp->mx);
        }
+       lock_ObtainMutex(&scp->mx);
+       scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+       lock_ReleaseMutex(&scp->mx);
        cm_ReleaseSCache(scp);
     }
 
@@ -5815,6 +5947,7 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
 
     lock_ObtainMutex(&fidp->mx);
     scp = fidp->scp;
+    cm_HoldSCache(scp);
     lock_ObtainMutex(&scp->mx);
 
     if (offset.HighPart == 0) {
@@ -5936,6 +6069,8 @@ long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
     if (code == 0 && sequential)
         cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
 
+    cm_ReleaseSCache(scp);
+
     return code;
 }
 
@@ -6307,7 +6442,7 @@ long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
         offset = LargeIntegerAdd(offset,
                                  ConvertLongToLargeInteger(written));
-        count -= written;
+        count -= (unsigned short)written;
         total_written += written;
         written = 0;
     }
@@ -6933,14 +7068,20 @@ long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
 
     lock_ObtainMutex(&fidp->mx);
     /* always create it open for read/write */
-    fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
+    fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
 
     /* remember that the file was newly created */
     if (created)
        fidp->flags |= SMB_FID_CREATED;
 
+    osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
+
     /* save a pointer to the vnode */
     fidp->scp = scp;
+    lock_ObtainMutex(&scp->mx);
+    scp->flags |= CM_SCACHEFLAG_SMB_FID;
+    lock_ReleaseMutex(&scp->mx);
+    
     /* and the user */
     fidp->userp = userp;
     lock_ReleaseMutex(&fidp->mx);
@@ -7787,7 +7928,7 @@ void smb_Listener(void *parmp)
     GetComputerName(cname, &cnamelen);
     _strupr(cname);
 
-    while (1) {
+    while (smb_ListenerState == SMB_LISTENER_STARTED) {
         memset(ncbp, 0, sizeof(NCB));
         flags = 0;
 
@@ -7807,12 +7948,43 @@ void smb_Listener(void *parmp)
 
         code = Netbios(ncbp);
 
-        if (code != 0)
-        {
+       if (code == NRC_BRIDGE) {
+           int lanaRemaining = 0;
+
+           if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
+               ExitThread(1);
+           }
+
+           osi_Log2(smb_logp,
+                     "NCBLISTEN lana=%d failed with NRC_BRIDGE.  Listener thread exiting.",
+                     ncbp->ncb_lana_num, code);
+
+           for (i = 0; i < lana_list.length; i++) {
+               if (lana_list.lana[i] == ncbp->ncb_lana_num) {
+                   smb_StopListener(ncbp, lana_list.lana[i]);
+                   lana_list.lana[i] = 255;
+               }
+               if (lana_list.lana[i] != 255)
+                   lanaRemaining++;
+           }
+
+           if (lanaRemaining == 0) {
+                cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                             ,cm_NetbiosName
+#endif
+                                              );
+               smb_ListenerState = SMB_LISTENER_STOPPED;
+               smb_LANadapter = -1;
+               lana_list.length = 0;
+           }
+           FreeNCB(ncbp);
+           return;
+       } else if (code != 0) {
             char tbuffer[256];
 
             /* terminate silently if shutdown flag is set */
-            if (smbShutdownFlag == 1) {
+            if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
                 ExitThread(1);
             }
 
@@ -8009,10 +8181,12 @@ void smb_Listener(void *parmp)
         /* unlock */
         lock_ReleaseMutex(&smb_ListenerLock);
     }  /* dispatch while loop */
+
+    FreeNCB(ncbp);
 }
 
 /* initialize Netbios */
-void smb_NetbiosInit()
+int smb_NetbiosInit(void)
 {
     NCB *ncbp;
     int i, lana, code, l;
@@ -8020,16 +8194,40 @@ void smb_NetbiosInit()
     int delname_tried=0;
     int len;
     int lana_found = 0;
-    OSVERSIONINFO Version;
-
-    /* Get the version of Windows */
-    memset(&Version, 0x00, sizeof(Version));
-    Version.dwOSVersionInfoSize = sizeof(Version);
-    GetVersionEx(&Version);
+    lana_number_t lanaNum;
 
     /* setup the NCB system */
     ncbp = GetNCB();
 
+    /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
+    if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
+        smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
+
+        if (smb_LANadapter != -1)
+           afsi_log("LAN adapter number %d", smb_LANadapter);
+        else
+           afsi_log("LAN adapter number not determined");
+
+        if (isGateway)
+           afsi_log("Set for gateway service");
+
+        afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
+    } else {
+        /* something went horribly wrong.  We can't proceed without a netbios name */
+        char buf[128];
+        StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
+        osi_panic(buf, __FILE__, __LINE__);
+    }
+
+    /* remember the name */
+    len = (int)strlen(cm_NetbiosName);
+    if (smb_localNamep)
+        free(smb_localNamep);
+    smb_localNamep = malloc(len+1);
+    strcpy(smb_localNamep, cm_NetbiosName);
+    afsi_log("smb_localNamep is >%s<", smb_localNamep);
+
+
     if (smb_LANadapter == -1) {
         ncbp->ncb_command = NCBENUM;
         ncbp->ncb_buffer = (PUCHAR)&lana_list;
@@ -8089,7 +8287,9 @@ void smb_NetbiosInit()
             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
         }
 
-        if (code == 0) code = ncbp->ncb_retcode;
+        if (code == 0) 
+           code = ncbp->ncb_retcode;
+
         if (code == 0) {
             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
         }
@@ -8125,7 +8325,6 @@ void smb_NetbiosInit()
             else {
                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
                 lana_list.lana[l] = 255;  /* invalid lana */
-                osi_panic(s, __FILE__, __LINE__);
             }
         }
         if (code == 0) {
@@ -8135,14 +8334,122 @@ void smb_NetbiosInit()
 
     osi_assert(lana_list.length >= 0);
     if (!lana_found) {
-        osi_panic("No valid LANA numbers found!", __FILE__, __LINE__);
+        afsi_log("No valid LANA numbers found!");
+       lana_list.length = 0;
+       smb_LANadapter = -1;
+       smb_ListenerState = SMB_LISTENER_STOPPED;
+        cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                      ,cm_NetbiosName
+#endif
+                                      );
     }
         
     /* we're done with the NCB now */
     FreeNCB(ncbp);
+
+    return (lana_list.length > 0 ? 1 : 0);
+}
+
+void smb_StartListeners()
+{
+    int i;
+    int lpid;
+    thread_t phandle;
+
+    if (smb_ListenerState == SMB_LISTENER_STARTED)
+       return;
+    
+    smb_ListenerState = SMB_LISTENER_STARTED;
+    cm_VolStatus_Network_Started(cm_NetbiosName
+#ifdef _WIN64
+                                  , cm_NetbiosName
+#endif
+                                  );
+
+    for (i = 0; i < lana_list.length; i++) {
+        if (lana_list.lana[i] == 255) 
+            continue;
+        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
+                               (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
+        osi_assert(phandle != NULL);
+        thrd_CloseHandle(phandle);
+    }
+}
+
+void smb_RestartListeners()
+{
+    if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
+       if (smb_NetbiosInit())
+           smb_StartListeners();
+    }
+}
+
+void smb_StopListener(NCB *ncbp, int lana)
+{
+    long code;
+
+    memset(ncbp, 0, sizeof(*ncbp));
+    ncbp->ncb_command = NCBDELNAME;
+    ncbp->ncb_lana_num = lana;
+    memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
+    code = Netbios(ncbp);
+          
+    afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
+             lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
+
+    /* and then reset the LANA; this will cause the listener threads to exit */
+    ncbp->ncb_command = NCBRESET;
+    ncbp->ncb_callname[0] = 100;
+    ncbp->ncb_callname[2] = 100;
+    ncbp->ncb_lana_num = lana;
+    code = Netbios(ncbp);
+    if (code == 0) 
+       code = ncbp->ncb_retcode;
+    if (code != 0) {
+       afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
+    } else {
+       afsi_log("Netbios NCBRESET lana %d succeeded", lana);
+    }
 }
 
-void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
+void smb_StopListeners(void)
+{
+    NCB *ncbp;
+    int lana, l;
+
+    if (smb_ListenerState == SMB_LISTENER_STOPPED)
+       return;
+
+    smb_ListenerState = SMB_LISTENER_STOPPED;
+    cm_VolStatus_Network_Stopped(cm_NetbiosName
+#ifdef _WIN64
+                                  , cm_NetbiosName
+#endif
+                                  );
+
+    ncbp = GetNCB();
+
+    /* Unregister the SMB name */
+    for (l = 0; l < lana_list.length; l++) {
+        lana = lana_list.lana[l];
+
+       if (lana != 255) {
+           smb_StopListener(ncbp, lana);
+
+           /* mark the adapter invalid */
+           lana_list.lana[l] = 255;  /* invalid lana */
+       }
+    }
+
+    /* force a re-evaluation of the network adapters */
+    lana_list.length = 0;
+    smb_LANadapter = -1;
+    FreeNCB(ncbp);
+    Sleep(1000);       /* give the listener threads a chance to exit */
+}
+
+void smb_Init(osi_log_t *logp, int useV3,
               int nThreads
               , void *aMBfunc
   )
@@ -8151,7 +8458,6 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     thread_t phandle;
     int lpid;
     INT_PTR i;
-    int len;
     struct tm myTime;
     EVENT_HANDLE retHandle;
     char eventName[MAX_PATH];
@@ -8161,7 +8467,6 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     smb_MBfunc = aMBfunc;
 
     smb_useV3 = useV3;
-    smb_LANadapter = LANadapt;
 
     /* Initialize smb_localZero */
     myTime.tm_isdst = -1;              /* compute whether on DST or not */
@@ -8185,12 +8490,6 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
     /* initialize the remote debugging log */
     smb_logp = logp;
         
-    /* remember the name */
-    len = (int)strlen(snamep);
-    smb_localNamep = malloc(len+1);
-    strcpy(smb_localNamep, snamep);
-    afsi_log("smb_localNamep is >%s<", smb_localNamep);
-
     /* and the global lock */
     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
@@ -8390,6 +8689,7 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
                  * performance by removing the network access and works around a bug
                  * seen at sites which are using a MIT Kerberos principal to login
                  * to machines joined to a non-root domain in a multi-domain forest.
+                * MsV1_0SetProcessOption was added in Windows XP.
                  */
                 PVOID pResponse = NULL;
                 ULONG cbResponse = 0;
@@ -8480,14 +8780,7 @@ void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
 
     /* Start listeners, waiters, servers, and daemons */
 
-    for (i = 0; i < lana_list.length; i++) {
-        if (lana_list.lana[i] == 255) 
-            continue;
-        phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
-                               (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
-        osi_assert(phandle != NULL);
-        thrd_CloseHandle(phandle);
-    }
+    smb_StartListeners();
 
     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
                           NULL, 0, &lpid, "smb_ClientWaiter");
@@ -8609,6 +8902,10 @@ void smb_Shutdown(void)
                 if (fidp->scp != NULL) {
                     scp = fidp->scp;
                     fidp->scp = NULL;
+                   lock_ObtainMutex(&scp->mx);
+                   scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
+                   lock_ReleaseMutex(&scp->mx);
+                   osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
                     cm_ReleaseSCache(scp);
                 }
                 lock_ReleaseMutex(&fidp->mx);
@@ -8628,7 +8925,7 @@ void smb_Shutdown(void)
         }
     }
     lock_ReleaseWrite(&smb_rctLock);
-
+    FreeNCB(ncbp);
     TlsFree(smb_TlsRequestSlot);
 }
 
@@ -8723,97 +9020,72 @@ int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
     if (lock)
         lock_ObtainRead(&smb_rctLock);
   
-    sprintf(output, "begin dumping smb_vc_t\n");
+    sprintf(output, "begin dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
     {
         smb_fid_t *fidp;
       
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
       
-        sprintf(output, "begin dumping smb_fid_t\n");
+        sprintf(output, "begin dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
+            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
       
-        sprintf(output, "done dumping smb_fid_t\n");
+        sprintf(output, "done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
-    sprintf(output, "done dumping smb_vc_t\n");
+    sprintf(output, "done dumping smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
-    sprintf(output, "begin dumping DEAD smb_vc_t\n");
+    sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
     {
         smb_fid_t *fidp;
       
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
+        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
       
-        sprintf(output, "begin dumping smb_fid_t\n");
+        sprintf(output, "begin dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
 
         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
         {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
+            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n", 
                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
         }
       
-        sprintf(output, "done dumping smb_fid_t\n");
+        sprintf(output, "done dumping smb_fid_t\r\n");
         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
     }
 
-    sprintf(output, "done dumping DEAD smb_vc_t\n");
-    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-  
-    sprintf(output, "begin dumping DEAD smb_vc_t\n");
-    WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-
-    for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp) 
-    {
-        smb_fid_t *fidp;
-      
-        sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
-                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-      
-        sprintf(output, "begin dumping smb_fid_t\n");
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-
-        for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
-        {
-            sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
-                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
-                     fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
-                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
-            WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-        }
-      
-        sprintf(output, "done dumping smb_fid_t\n");
-        WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
-    }
-
-    sprintf(output, "done dumping DEAD smb_vc_t\n");
+    sprintf(output, "done dumping DEAD smb_vc_t\r\n");
     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
   
     if (lock)
         lock_ReleaseRead(&smb_rctLock);
     return 0;
 }
+
+long smb_IsNetworkStarted(void)
+{
+    return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
+}