diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 181 |
1 files changed, 131 insertions, 50 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2208f06e4c45..95c2ea67edfb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "nterr.h" | 48 | #include "nterr.h" |
49 | #include "rfc1002pdu.h" | 49 | #include "rfc1002pdu.h" |
50 | #include "cn_cifs.h" | 50 | #include "cn_cifs.h" |
51 | #include "fscache.h" | ||
51 | 52 | ||
52 | #define CIFS_PORT 445 | 53 | #define CIFS_PORT 445 |
53 | #define RFC1001_PORT 139 | 54 | #define RFC1001_PORT 139 |
@@ -66,6 +67,7 @@ struct smb_vol { | |||
66 | char *iocharset; /* local code page for mapping to and from Unicode */ | 67 | char *iocharset; /* local code page for mapping to and from Unicode */ |
67 | char source_rfc1001_name[16]; /* netbios name of client */ | 68 | char source_rfc1001_name[16]; /* netbios name of client */ |
68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 69 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ |
70 | uid_t cred_uid; | ||
69 | uid_t linux_uid; | 71 | uid_t linux_uid; |
70 | gid_t linux_gid; | 72 | gid_t linux_gid; |
71 | mode_t file_mode; | 73 | mode_t file_mode; |
@@ -97,6 +99,7 @@ struct smb_vol { | |||
97 | bool noblocksnd:1; | 99 | bool noblocksnd:1; |
98 | bool noautotune:1; | 100 | bool noautotune:1; |
99 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ | 101 | bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ |
102 | bool fsc:1; /* enable fscache */ | ||
100 | unsigned int rsize; | 103 | unsigned int rsize; |
101 | unsigned int wsize; | 104 | unsigned int wsize; |
102 | bool sockopt_tcp_nodelay:1; | 105 | bool sockopt_tcp_nodelay:1; |
@@ -830,7 +833,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
830 | /* null target name indicates to use *SMBSERVR default called name | 833 | /* null target name indicates to use *SMBSERVR default called name |
831 | if we end up sending RFC1001 session initialize */ | 834 | if we end up sending RFC1001 session initialize */ |
832 | vol->target_rfc1001_name[0] = 0; | 835 | vol->target_rfc1001_name[0] = 0; |
833 | vol->linux_uid = current_uid(); /* use current_euid() instead? */ | 836 | vol->cred_uid = current_uid(); |
837 | vol->linux_uid = current_uid(); | ||
834 | vol->linux_gid = current_gid(); | 838 | vol->linux_gid = current_gid(); |
835 | 839 | ||
836 | /* default to only allowing write access to owner of the mount */ | 840 | /* default to only allowing write access to owner of the mount */ |
@@ -1257,6 +1261,12 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1257 | } else if ((strnicmp(data, "nocase", 6) == 0) || | 1261 | } else if ((strnicmp(data, "nocase", 6) == 0) || |
1258 | (strnicmp(data, "ignorecase", 10) == 0)) { | 1262 | (strnicmp(data, "ignorecase", 10) == 0)) { |
1259 | vol->nocase = 1; | 1263 | vol->nocase = 1; |
1264 | } else if (strnicmp(data, "mand", 4) == 0) { | ||
1265 | /* ignore */ | ||
1266 | } else if (strnicmp(data, "nomand", 6) == 0) { | ||
1267 | /* ignore */ | ||
1268 | } else if (strnicmp(data, "_netdev", 7) == 0) { | ||
1269 | /* ignore */ | ||
1260 | } else if (strnicmp(data, "brl", 3) == 0) { | 1270 | } else if (strnicmp(data, "brl", 3) == 0) { |
1261 | vol->nobrl = 0; | 1271 | vol->nobrl = 0; |
1262 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | 1272 | } else if ((strnicmp(data, "nobrl", 5) == 0) || |
@@ -1331,6 +1341,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1331 | printk(KERN_WARNING "CIFS: Mount option noac not " | 1341 | printk(KERN_WARNING "CIFS: Mount option noac not " |
1332 | "supported. Instead set " | 1342 | "supported. Instead set " |
1333 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1343 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); |
1344 | } else if (strnicmp(data, "fsc", 3) == 0) { | ||
1345 | vol->fsc = true; | ||
1334 | } else | 1346 | } else |
1335 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1347 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1336 | data); | 1348 | data); |
@@ -1380,18 +1392,92 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1380 | return 0; | 1392 | return 0; |
1381 | } | 1393 | } |
1382 | 1394 | ||
1395 | static bool | ||
1396 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
1397 | { | ||
1398 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1399 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1400 | |||
1401 | switch (addr->sa_family) { | ||
1402 | case AF_INET: | ||
1403 | if (addr4->sin_addr.s_addr != | ||
1404 | server->addr.sockAddr.sin_addr.s_addr) | ||
1405 | return false; | ||
1406 | if (addr4->sin_port && | ||
1407 | addr4->sin_port != server->addr.sockAddr.sin_port) | ||
1408 | return false; | ||
1409 | break; | ||
1410 | case AF_INET6: | ||
1411 | if (!ipv6_addr_equal(&addr6->sin6_addr, | ||
1412 | &server->addr.sockAddr6.sin6_addr)) | ||
1413 | return false; | ||
1414 | if (addr6->sin6_scope_id != | ||
1415 | server->addr.sockAddr6.sin6_scope_id) | ||
1416 | return false; | ||
1417 | if (addr6->sin6_port && | ||
1418 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
1419 | return false; | ||
1420 | break; | ||
1421 | } | ||
1422 | |||
1423 | return true; | ||
1424 | } | ||
1425 | |||
1426 | static bool | ||
1427 | match_security(struct TCP_Server_Info *server, struct smb_vol *vol) | ||
1428 | { | ||
1429 | unsigned int secFlags; | ||
1430 | |||
1431 | if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
1432 | secFlags = vol->secFlg; | ||
1433 | else | ||
1434 | secFlags = global_secflags | vol->secFlg; | ||
1435 | |||
1436 | switch (server->secType) { | ||
1437 | case LANMAN: | ||
1438 | if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT))) | ||
1439 | return false; | ||
1440 | break; | ||
1441 | case NTLMv2: | ||
1442 | if (!(secFlags & CIFSSEC_MAY_NTLMV2)) | ||
1443 | return false; | ||
1444 | break; | ||
1445 | case NTLM: | ||
1446 | if (!(secFlags & CIFSSEC_MAY_NTLM)) | ||
1447 | return false; | ||
1448 | break; | ||
1449 | case Kerberos: | ||
1450 | if (!(secFlags & CIFSSEC_MAY_KRB5)) | ||
1451 | return false; | ||
1452 | break; | ||
1453 | case RawNTLMSSP: | ||
1454 | if (!(secFlags & CIFSSEC_MAY_NTLMSSP)) | ||
1455 | return false; | ||
1456 | break; | ||
1457 | default: | ||
1458 | /* shouldn't happen */ | ||
1459 | return false; | ||
1460 | } | ||
1461 | |||
1462 | /* now check if signing mode is acceptible */ | ||
1463 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0 && | ||
1464 | (server->secMode & SECMODE_SIGN_REQUIRED)) | ||
1465 | return false; | ||
1466 | else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) && | ||
1467 | (server->secMode & | ||
1468 | (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0) | ||
1469 | return false; | ||
1470 | |||
1471 | return true; | ||
1472 | } | ||
1473 | |||
1383 | static struct TCP_Server_Info * | 1474 | static struct TCP_Server_Info * |
1384 | cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | 1475 | cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) |
1385 | { | 1476 | { |
1386 | struct list_head *tmp; | ||
1387 | struct TCP_Server_Info *server; | 1477 | struct TCP_Server_Info *server; |
1388 | struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; | ||
1389 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; | ||
1390 | 1478 | ||
1391 | write_lock(&cifs_tcp_ses_lock); | 1479 | write_lock(&cifs_tcp_ses_lock); |
1392 | list_for_each(tmp, &cifs_tcp_ses_list) { | 1480 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
1393 | server = list_entry(tmp, struct TCP_Server_Info, | ||
1394 | tcp_ses_list); | ||
1395 | /* | 1481 | /* |
1396 | * the demux thread can exit on its own while still in CifsNew | 1482 | * the demux thread can exit on its own while still in CifsNew |
1397 | * so don't accept any sockets in that state. Since the | 1483 | * so don't accept any sockets in that state. Since the |
@@ -1401,37 +1487,11 @@ cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) | |||
1401 | if (server->tcpStatus == CifsNew) | 1487 | if (server->tcpStatus == CifsNew) |
1402 | continue; | 1488 | continue; |
1403 | 1489 | ||
1404 | switch (addr->ss_family) { | 1490 | if (!match_address(server, addr)) |
1405 | case AF_INET: | 1491 | continue; |
1406 | if (addr4->sin_addr.s_addr == | ||
1407 | server->addr.sockAddr.sin_addr.s_addr) { | ||
1408 | addr4->sin_port = htons(port); | ||
1409 | /* user overrode default port? */ | ||
1410 | if (addr4->sin_port) { | ||
1411 | if (addr4->sin_port != | ||
1412 | server->addr.sockAddr.sin_port) | ||
1413 | continue; | ||
1414 | } | ||
1415 | break; | ||
1416 | } else | ||
1417 | continue; | ||
1418 | 1492 | ||
1419 | case AF_INET6: | 1493 | if (!match_security(server, vol)) |
1420 | if (ipv6_addr_equal(&addr6->sin6_addr, | 1494 | continue; |
1421 | &server->addr.sockAddr6.sin6_addr) && | ||
1422 | (addr6->sin6_scope_id == | ||
1423 | server->addr.sockAddr6.sin6_scope_id)) { | ||
1424 | addr6->sin6_port = htons(port); | ||
1425 | /* user overrode default port? */ | ||
1426 | if (addr6->sin6_port) { | ||
1427 | if (addr6->sin6_port != | ||
1428 | server->addr.sockAddr6.sin6_port) | ||
1429 | continue; | ||
1430 | } | ||
1431 | break; | ||
1432 | } else | ||
1433 | continue; | ||
1434 | } | ||
1435 | 1495 | ||
1436 | ++server->srv_count; | 1496 | ++server->srv_count; |
1437 | write_unlock(&cifs_tcp_ses_lock); | 1497 | write_unlock(&cifs_tcp_ses_lock); |
@@ -1460,6 +1520,8 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1460 | server->tcpStatus = CifsExiting; | 1520 | server->tcpStatus = CifsExiting; |
1461 | spin_unlock(&GlobalMid_Lock); | 1521 | spin_unlock(&GlobalMid_Lock); |
1462 | 1522 | ||
1523 | cifs_fscache_release_client_cookie(server); | ||
1524 | |||
1463 | task = xchg(&server->tsk, NULL); | 1525 | task = xchg(&server->tsk, NULL); |
1464 | if (task) | 1526 | if (task) |
1465 | force_sig(SIGKILL, task); | 1527 | force_sig(SIGKILL, task); |
@@ -1479,7 +1541,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1479 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); | 1541 | cFYI(1, "UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip); |
1480 | 1542 | ||
1481 | if (volume_info->UNCip && volume_info->UNC) { | 1543 | if (volume_info->UNCip && volume_info->UNC) { |
1482 | rc = cifs_convert_address(volume_info->UNCip, &addr); | 1544 | rc = cifs_fill_sockaddr((struct sockaddr *)&addr, |
1545 | volume_info->UNCip, | ||
1546 | strlen(volume_info->UNCip), | ||
1547 | volume_info->port); | ||
1483 | if (!rc) { | 1548 | if (!rc) { |
1484 | /* we failed translating address */ | 1549 | /* we failed translating address */ |
1485 | rc = -EINVAL; | 1550 | rc = -EINVAL; |
@@ -1499,7 +1564,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1499 | } | 1564 | } |
1500 | 1565 | ||
1501 | /* see if we already have a matching tcp_ses */ | 1566 | /* see if we already have a matching tcp_ses */ |
1502 | tcp_ses = cifs_find_tcp_session(&addr, volume_info->port); | 1567 | tcp_ses = cifs_find_tcp_session((struct sockaddr *)&addr, volume_info); |
1503 | if (tcp_ses) | 1568 | if (tcp_ses) |
1504 | return tcp_ses; | 1569 | return tcp_ses; |
1505 | 1570 | ||
@@ -1543,12 +1608,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1543 | cFYI(1, "attempting ipv6 connect"); | 1608 | cFYI(1, "attempting ipv6 connect"); |
1544 | /* BB should we allow ipv6 on port 139? */ | 1609 | /* BB should we allow ipv6 on port 139? */ |
1545 | /* other OS never observed in Wild doing 139 with v6 */ | 1610 | /* other OS never observed in Wild doing 139 with v6 */ |
1546 | sin_server6->sin6_port = htons(volume_info->port); | ||
1547 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1611 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, |
1548 | sizeof(struct sockaddr_in6)); | 1612 | sizeof(struct sockaddr_in6)); |
1549 | rc = ipv6_connect(tcp_ses); | 1613 | rc = ipv6_connect(tcp_ses); |
1550 | } else { | 1614 | } else { |
1551 | sin_server->sin_port = htons(volume_info->port); | ||
1552 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1615 | memcpy(&tcp_ses->addr.sockAddr, sin_server, |
1553 | sizeof(struct sockaddr_in)); | 1616 | sizeof(struct sockaddr_in)); |
1554 | rc = ipv4_connect(tcp_ses); | 1617 | rc = ipv4_connect(tcp_ses); |
@@ -1577,6 +1640,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1577 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1640 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
1578 | write_unlock(&cifs_tcp_ses_lock); | 1641 | write_unlock(&cifs_tcp_ses_lock); |
1579 | 1642 | ||
1643 | cifs_fscache_get_client_cookie(tcp_ses); | ||
1644 | |||
1580 | return tcp_ses; | 1645 | return tcp_ses; |
1581 | 1646 | ||
1582 | out_err: | 1647 | out_err: |
@@ -1591,17 +1656,27 @@ out_err: | |||
1591 | } | 1656 | } |
1592 | 1657 | ||
1593 | static struct cifsSesInfo * | 1658 | static struct cifsSesInfo * |
1594 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) | 1659 | cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) |
1595 | { | 1660 | { |
1596 | struct list_head *tmp; | ||
1597 | struct cifsSesInfo *ses; | 1661 | struct cifsSesInfo *ses; |
1598 | 1662 | ||
1599 | write_lock(&cifs_tcp_ses_lock); | 1663 | write_lock(&cifs_tcp_ses_lock); |
1600 | list_for_each(tmp, &server->smb_ses_list) { | 1664 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
1601 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 1665 | switch (server->secType) { |
1602 | if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) | 1666 | case Kerberos: |
1603 | continue; | 1667 | if (vol->cred_uid != ses->cred_uid) |
1604 | 1668 | continue; | |
1669 | break; | ||
1670 | default: | ||
1671 | /* anything else takes username/password */ | ||
1672 | if (strncmp(ses->userName, vol->username, | ||
1673 | MAX_USERNAME_SIZE)) | ||
1674 | continue; | ||
1675 | if (strlen(vol->username) != 0 && | ||
1676 | strncmp(ses->password, vol->password, | ||
1677 | MAX_PASSWORD_SIZE)) | ||
1678 | continue; | ||
1679 | } | ||
1605 | ++ses->ses_count; | 1680 | ++ses->ses_count; |
1606 | write_unlock(&cifs_tcp_ses_lock); | 1681 | write_unlock(&cifs_tcp_ses_lock); |
1607 | return ses; | 1682 | return ses; |
@@ -1643,7 +1718,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1643 | 1718 | ||
1644 | xid = GetXid(); | 1719 | xid = GetXid(); |
1645 | 1720 | ||
1646 | ses = cifs_find_smb_ses(server, volume_info->username); | 1721 | ses = cifs_find_smb_ses(server, volume_info); |
1647 | if (ses) { | 1722 | if (ses) { |
1648 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); | 1723 | cFYI(1, "Existing smb sess found (status=%d)", ses->status); |
1649 | 1724 | ||
@@ -1706,6 +1781,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1706 | if (ses->domainName) | 1781 | if (ses->domainName) |
1707 | strcpy(ses->domainName, volume_info->domainname); | 1782 | strcpy(ses->domainName, volume_info->domainname); |
1708 | } | 1783 | } |
1784 | ses->cred_uid = volume_info->cred_uid; | ||
1709 | ses->linux_uid = volume_info->linux_uid; | 1785 | ses->linux_uid = volume_info->linux_uid; |
1710 | ses->overrideSecFlg = volume_info->secFlg; | 1786 | ses->overrideSecFlg = volume_info->secFlg; |
1711 | 1787 | ||
@@ -1773,6 +1849,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1773 | CIFSSMBTDis(xid, tcon); | 1849 | CIFSSMBTDis(xid, tcon); |
1774 | _FreeXid(xid); | 1850 | _FreeXid(xid); |
1775 | 1851 | ||
1852 | cifs_fscache_release_super_cookie(tcon); | ||
1776 | tconInfoFree(tcon); | 1853 | tconInfoFree(tcon); |
1777 | cifs_put_smb_ses(ses); | 1854 | cifs_put_smb_ses(ses); |
1778 | } | 1855 | } |
@@ -1843,6 +1920,8 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
1843 | list_add(&tcon->tcon_list, &ses->tcon_list); | 1920 | list_add(&tcon->tcon_list, &ses->tcon_list); |
1844 | write_unlock(&cifs_tcp_ses_lock); | 1921 | write_unlock(&cifs_tcp_ses_lock); |
1845 | 1922 | ||
1923 | cifs_fscache_get_super_cookie(tcon); | ||
1924 | |||
1846 | return tcon; | 1925 | return tcon; |
1847 | 1926 | ||
1848 | out_fail: | 1927 | out_fail: |
@@ -2397,6 +2476,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2397 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | 2476 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; |
2398 | if (pvolume_info->dynperm) | 2477 | if (pvolume_info->dynperm) |
2399 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2478 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; |
2479 | if (pvolume_info->fsc) | ||
2480 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | ||
2400 | if (pvolume_info->direct_io) { | 2481 | if (pvolume_info->direct_io) { |
2401 | cFYI(1, "mounting share using direct i/o"); | 2482 | cFYI(1, "mounting share using direct i/o"); |
2402 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2483 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |