CTC++ Coverage Report - Execution Profile    #856/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: fs/cifs/cifssmb.c
Instrumentation mode: function-decision-multicondition
TER: 0 % ( 0/1478)

Start/ End/    
True False - Line Source

  1 /*
  2  *   fs/cifs/cifssmb.c
  3  *
  4  *   Copyright (C) International Business Machines  Corp., 2002,2005
  5  *   Author(s): Steve French (sfrench@us.ibm.com)
  6  *
  7  *   Contains the routines for constructing the SMB PDUs themselves
  8  *
  9  *   This library is free software; you can redistribute it and/or modify
  10  *   it under the terms of the GNU Lesser General Public License as published
  11  *   by the Free Software Foundation; either version 2.1 of the License, or
  12  *   (at your option) any later version.
  13  *
  14  *   This library is distributed in the hope that it will be useful,
  15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  17  *   the GNU Lesser General Public License for more details.
  18  *
  19  *   You should have received a copy of the GNU Lesser General Public License
  20  *   along with this library; if not, write to the Free Software
  21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22  */
  23 
  24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
  25  /* These are mostly routines that operate on a pathname, or on a tree id     */
  26  /* (mounted volume), but there are eight handle based routines which must be */
  27  /* treated slightly different for reconnection purposes since we never want  */
  28  /* to reuse a stale file handle and the caller knows the file handle */
  29 
  30 #include <linux/fs.h>
  31 #include <linux/kernel.h>
  32 #include <linux/vfs.h>
  33 #include <linux/posix_acl_xattr.h>
  34 #include <asm/uaccess.h>
  35 #include "cifspdu.h"
  36 #include "cifsglob.h"
  37 #include "cifsproto.h"
  38 #include "cifs_unicode.h"
  39 #include "cifs_debug.h"
  40 #include "cifsacl.h"
  41 
  42 #ifdef CONFIG_CIFS_POSIX
  43 static struct {
  44    int index;
  45    char *name;
  46 } protocols[] = {
  47    {CIFS_PROT, "\2NT LM 0.12"}, 
  48    {CIFS_PROT, "\2POSIX 2"},
  49    {BAD_PROT, "\2"}
  50 };
  51 #else
  52 static struct {
  53    int index;
  54    char *name;
  55 } protocols[] = {
  56    {CIFS_PROT, "\2NT LM 0.12"}, 
  57    {BAD_PROT, "\2"}
  58 };
  59 #endif
  60 
  61 
  62 /* Mark as invalid, all open files on tree connections since they
  63    were closed when session to server was lost */
 
- 64 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
  65 {
  66    struct cifsFileInfo *open_file = NULL;
  67    struct list_head * tmp;
  68    struct list_head * tmp1;
  69 
  70 /* list all files open on tree connection and mark them invalid */
    71    write_lock(&GlobalSMBSeslock);
    71   do
- 71   do-while (0)
- 71 do-while (0)
- 72    list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
  73       open_file = list_entry(tmp,struct cifsFileInfo, tlist);
- 74       if(open_file) {
  75          open_file->invalidHandle = TRUE;
  76       }
  77    }
    78    write_unlock(&GlobalSMBSeslock);
    78   do
- 78   do-while (0)
- 78 do-while (0)
  79    /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
  80       to this tcon */
  81 }
  82 
  83 /* If the return code is zero, this function must fill in request_buf pointer */
  84 static int
 
- 85 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
  86     void **request_buf /* returned */)
  87 {
  88    int rc = 0;
  89 
  90    /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
  91       check for tcp and smb session status done differently
  92       for those three - in the calling routine */
- 93    if(tcon) {
- 94       if(tcon->tidStatus == CifsExiting) {
  95          /* only tree disconnect, open, and write,
  96          (and ulogoff which does not have tcon)
  97          are allowed as we start force umount */
  98          if((smb_command != SMB_COM_WRITE_ANDX) && 
  99             (smb_command != SMB_COM_OPEN_ANDX) && 
- 100             (smb_command != SMB_COM_TREE_DISCONNECT)) {
 - 100       (T) && (T) && (T)
 - 100       (T) && (T) && (F)
 - 100       (T) && (F) && (_)
 - 100       (F) && (_) && (_)
- 101             cFYI(1,("can not send cmd %d while umounting",
- 101         if (cifsFYI & 0x01)
  102                smb_command));
 - 103             return -ENODEV;
  104          }
  105       }
  106       if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
- 107               (tcon->ses->server)){
 - 107     (T) && (T) && (T)
 - 107     (T) && (T) && (F)
 - 107     (T) && (F) && (_)
 - 107     (F) && (_) && (_)
  108          struct nls_table *nls_codepage;
  109             /* Give Demultiplex thread up to 10 seconds to 
  110                reconnect, should be greater than cifs socket
  111                timeout which is 7 seconds */
- 112          while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
  113             wait_event_interruptible_timeout(tcon->ses->server->response_q,
  114                (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- 115             if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
  116                /* on "soft" mounts we wait once */
  117                if((tcon->retry == FALSE) || 
- 118                   (tcon->ses->status == CifsExiting)) {
 - 118           (T) || (_)
 - 118           (F) || (T)
 - 118           (F) || (F)
- 119                   cFYI(1,("gave up waiting on reconnect in smb_init"));
- 119             if (cifsFYI & 0x01)
 - 120                   return -EHOSTDOWN;
  121                } /* else "hard" mount - keep retrying
  122                     until process is killed or server
  123                     comes back on-line */
    124             } else /* TCP session is reestablished now */
 - 125                break;
  126              
  127          }
  128          
  129          nls_codepage = load_nls_default();
  130       /* need to prevent multiple threads trying to
  131       simultaneously reconnect the same SMB session */
  132          down(&tcon->ses->sesSem);
- 133          if(tcon->ses->status == CifsNeedReconnect)
  134             rc = cifs_setup_session(0, tcon->ses, 
  135                      nls_codepage);
- 136          if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 - 136       T && (T)
 - 136       T && (F)
 - 136       F && (_)
  137             mark_open_files_invalid(tcon);
  138             rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
  139                , nls_codepage);
  140             up(&tcon->ses->sesSem);
  141             /* BB FIXME add code to check if wsize needs
  142                update due to negotiated smb buffer size
  143                shrinking */
- 144             if(rc == 0)
  145                atomic_inc(&tconInfoReconnectCount);
  146 
- 147             cFYI(1, ("reconnect tcon rc = %d", rc));
- 147         if (cifsFYI & 0x01)
  148             /* Removed call to reopen open files here - 
  149                it is safer (and faster) to reopen files
  150                one at a time as needed in read and write */
  151 
  152             /* Check if handle based operation so we 
  153                know whether we can continue or not without
  154                returning to caller to reset file handle */
    155             switch(smb_command) {
 - 156                case SMB_COM_READ_ANDX:
 - 157                case SMB_COM_WRITE_ANDX:
 - 158                case SMB_COM_CLOSE:
 - 159                case SMB_COM_FIND_CLOSE2:
 - 160                case SMB_COM_LOCKING_ANDX: {
  161                   unload_nls(nls_codepage);
 - 162                   return -EAGAIN;
  163                }
  164             }
    165          } else {
  166             up(&tcon->ses->sesSem);
  167          }
  168          unload_nls(nls_codepage);
  169 
    170       } else {
 - 171          return -EIO;
  172       }
  173    }
- 174    if(rc)
 - 175       return rc;
  176 
  177    *request_buf = cifs_small_buf_get();
- 178    if (*request_buf == NULL) {
  179       /* BB should we add a retry in here if not a writepage? */
 - 180       return -ENOMEM;
  181    }
  182 
  183    header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
  184 
- 185         if(tcon != NULL)
    186                 cifs_stats_inc(&tcon->num_smbs_sent);
- 186   do-while (0)
  187 
 - 188    return rc;
  189 }  
  190 
  191 /* If the return code is zero, this function must fill in request_buf pointer */
  192 static int
 
- 193 smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
  194     void **request_buf /* returned */ ,
  195     void **response_buf /* returned */ )
  196 {
  197    int rc = 0;
  198 
  199    /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
  200       check for tcp and smb session status done differently
  201       for those three - in the calling routine */
- 202    if(tcon) {
- 203       if(tcon->tidStatus == CifsExiting) {
  204          /* only tree disconnect, open, and write,
  205            (and ulogoff which does not have tcon)
  206            are allowed as we start force umount */
  207          if((smb_command != SMB_COM_WRITE_ANDX) &&
  208             (smb_command != SMB_COM_OPEN_ANDX) &&
- 209             (smb_command != SMB_COM_TREE_DISCONNECT)) {
 - 209       (T) && (T) && (T)
 - 209       (T) && (T) && (F)
 - 209       (T) && (F) && (_)
 - 209       (F) && (_) && (_)
- 210             cFYI(1,("can not send cmd %d while umounting",
- 210         if (cifsFYI & 0x01)
  211                smb_command));
 - 212             return -ENODEV;
  213          }
  214       }
  215 
  216       if((tcon->ses) && (tcon->ses->status != CifsExiting) && 
- 217               (tcon->ses->server)){
 - 217     (T) && (T) && (T)
 - 217     (T) && (T) && (F)
 - 217     (T) && (F) && (_)
 - 217     (F) && (_) && (_)
  218          struct nls_table *nls_codepage;
  219             /* Give Demultiplex thread up to 10 seconds to
  220                reconnect, should be greater than cifs socket
  221                timeout which is 7 seconds */
- 222          while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
  223             wait_event_interruptible_timeout(tcon->ses->server->response_q,
  224                (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
  225             if(tcon->ses->server->tcpStatus == 
- 226                   CifsNeedReconnect) {
  227                /* on "soft" mounts we wait once */
  228                if((tcon->retry == FALSE) || 
- 229                   (tcon->ses->status == CifsExiting)) {
 - 229           (T) || (_)
 - 229           (F) || (T)
 - 229           (F) || (F)
- 230                   cFYI(1,("gave up waiting on reconnect in smb_init"));
- 230             if (cifsFYI & 0x01)
 - 231                   return -EHOSTDOWN;
  232                } /* else "hard" mount - keep retrying
  233                     until process is killed or server
  234                     comes on-line */
    235             } else /* TCP session is reestablished now */
 - 236                break;
  237              
  238          }
  239          
  240          nls_codepage = load_nls_default();
  241       /* need to prevent multiple threads trying to
  242       simultaneously reconnect the same SMB session */
  243          down(&tcon->ses->sesSem);
- 244          if(tcon->ses->status == CifsNeedReconnect)
  245             rc = cifs_setup_session(0, tcon->ses, 
  246                      nls_codepage);
- 247          if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 - 247       T && (T)
 - 247       T && (F)
 - 247       F && (_)
  248             mark_open_files_invalid(tcon);
  249             rc = CIFSTCon(0, tcon->ses, tcon->treeName,
  250                      tcon, nls_codepage);
  251             up(&tcon->ses->sesSem);
  252             /* BB FIXME add code to check if wsize needs
  253             update due to negotiated smb buffer size
  254             shrinking */
- 255             if(rc == 0)
  256                atomic_inc(&tconInfoReconnectCount);
  257 
- 258             cFYI(1, ("reconnect tcon rc = %d", rc));
- 258         if (cifsFYI & 0x01)
  259             /* Removed call to reopen open files here - 
  260                it is safer (and faster) to reopen files
  261                one at a time as needed in read and write */
  262 
  263             /* Check if handle based operation so we 
  264                know whether we can continue or not without
  265                returning to caller to reset file handle */
    266             switch(smb_command) {
 - 267                case SMB_COM_READ_ANDX:
 - 268                case SMB_COM_WRITE_ANDX:
 - 269                case SMB_COM_CLOSE:
 - 270                case SMB_COM_FIND_CLOSE2:
 - 271                case SMB_COM_LOCKING_ANDX: {
  272                   unload_nls(nls_codepage);
 - 273                   return -EAGAIN;
  274                }
  275             }
    276          } else {
  277             up(&tcon->ses->sesSem);
  278          }
  279          unload_nls(nls_codepage);
  280 
    281       } else {
 - 282          return -EIO;
  283       }
  284    }
- 285    if(rc)
 - 286       return rc;
  287 
  288    *request_buf = cifs_buf_get();
- 289    if (*request_buf == NULL) {
  290       /* BB should we add a retry in here if not a writepage? */
 - 291       return -ENOMEM;
  292    }
  293     /* Although the original thought was we needed the response buf for  */
  294     /* potential retries of smb operations it turns out we can determine */
  295     /* from the mid flags when the request buffer can be resent without  */
  296     /* having to use a second distinct buffer for the response */
  297    *response_buf = *request_buf; 
  298 
  299    header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
  300          wct /*wct */ );
  301 
- 302         if(tcon != NULL)
    303                 cifs_stats_inc(&tcon->num_smbs_sent);
- 303   do-while (0)
  304 
 - 305    return rc;
  306 }
  307 
 
- 308 static int validate_t2(struct smb_t2_rsp * pSMB) 
  309 {
  310    int rc = -EINVAL;
  311    int total_size;
  312    char * pBCC;
  313 
  314    /* check for plausible wct, bcc and t2 data and parm sizes */
  315    /* check for parm and data offset going beyond end of smb */
- 316    if(pSMB->hdr.WordCount >= 10) {
  317       if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
- 318          (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
 - 318     (T) && (T)
 - 318     (T) && (F)
 - 318     (F) && (_)
  319          /* check that bcc is at least as big as parms + data */
  320          /* check that bcc is less than negotiated smb buffer */
  321          total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
- 322          if(total_size < 512) {
  323             total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
  324             /* BCC le converted in SendReceive */
  325             pBCC = (pSMB->hdr.WordCount * 2) + 
  326                sizeof(struct smb_hdr) +
  327                (char *)pSMB;
  328             if((total_size <= (*(u16 *)pBCC)) && 
  329                (total_size < 
- 330                CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
 - 330         (T) && (T)
 - 330         (T) && (F)
 - 330         (F) && (_)
 - 331                return 0;
  332             }
  333             
  334          }
  335       }
  336    }
  337    cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
  338       sizeof(struct smb_t2_rsp) + 16);
 - 339    return rc;
  340 }
  341 int
 
- 342 CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
  343 {
  344    NEGOTIATE_REQ *pSMB;
  345    NEGOTIATE_RSP *pSMBr;
  346    int rc = 0;
  347    int bytes_returned;
  348    struct TCP_Server_Info * server;
  349    u16 count;
  350 
- 351    if(ses->server)
  352       server = ses->server;
    353    else {
  354       rc = -EIO;
 - 355       return rc;
  356    }
  357    rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
  358             (void **) &pSMB, (void **) &pSMBr);
- 359    if (rc)
 - 360       return rc;
  361    pSMB->hdr.Mid = GetNextMid(server);
  362    pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
- 363    if (extended_security)
  364       pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
  365 
  366    count = strlen(protocols[0].name) + 1;
  367    strncpy(pSMB->DialectsArray, protocols[0].name, 30);   
  368     /* null guaranteed to be at end of source and target buffers anyway */
  369 
  370    pSMB->hdr.smb_buf_length += count;
  371    pSMB->ByteCount = cpu_to_le16(count);
  372 
  373    rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
  374           (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- 375    if (rc == 0) {
  376       server->secMode = pSMBr->SecurityMode;
- 377       if((server->secMode & SECMODE_USER) == 0)
- 378          cFYI(1,("share mode security"));
- 378       if (cifsFYI & 0x01)
  379       server->secType = NTLM; /* BB override default for
  380                   NTLMv2 or kerberos v5 */
  381       /* one byte - no need to convert this or EncryptionKeyLen
  382          from little endian */
  383       server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
  384       /* probably no need to store and check maxvcs */
  385       server->maxBuf =
  386          min(le32_to_cpu(pSMBr->MaxBufferSize),
  387          (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
  388       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
- 389       cFYI(0, ("Max buf = %d", ses->server->maxBuf));
- 389     if (cifsFYI & 0x01)
  390       GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
  391       server->capabilities = le32_to_cpu(pSMBr->Capabilities);
  392       server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);   
  393         /* BB with UTC do we ever need to be using srvr timezone? */
- 394       if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
  395          memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
  396                 CIFS_CRYPTO_KEY_SIZE);
  397       } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
- 398             && (pSMBr->EncryptionKeyLength == 0)) {
 - 398     (T) && (T)
 - 398     (T) && (F)
 - 398     (F) && (_)
  399          /* decode security blob */
    400       } else
  401          rc = -EIO;
  402 
  403       /* BB might be helpful to save off the domain of server here */
  404 
  405       if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
- 406          (server->capabilities & CAP_EXTENDED_SECURITY)) {
 - 406     (T) && (T)
 -