diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 681 |
1 files changed, 370 insertions, 311 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 683dee4d2f76..d2ea95bef1c1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -89,6 +89,7 @@ struct smb_vol { | |||
89 | bool nullauth:1; /* attempt to authenticate with null user */ | 89 | bool nullauth:1; /* attempt to authenticate with null user */ |
90 | bool nocase:1; /* request case insensitive filenames */ | 90 | bool nocase:1; /* request case insensitive filenames */ |
91 | bool nobrl:1; /* disable sending byte range locks to srv */ | 91 | bool nobrl:1; /* disable sending byte range locks to srv */ |
92 | bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ | ||
92 | bool seal:1; /* request transport encryption on share */ | 93 | bool seal:1; /* request transport encryption on share */ |
93 | bool nodfs:1; /* Do not request DFS, even if available */ | 94 | bool nodfs:1; /* Do not request DFS, even if available */ |
94 | bool local_lease:1; /* check leases only on local system, not remote */ | 95 | bool local_lease:1; /* check leases only on local system, not remote */ |
@@ -101,25 +102,17 @@ struct smb_vol { | |||
101 | char *prepath; | 102 | char *prepath; |
102 | }; | 103 | }; |
103 | 104 | ||
104 | static int ipv4_connect(struct sockaddr_in *psin_server, | 105 | static int ipv4_connect(struct TCP_Server_Info *server); |
105 | struct socket **csocket, | 106 | static int ipv6_connect(struct TCP_Server_Info *server); |
106 | char *netb_name, | ||
107 | char *server_netb_name, | ||
108 | bool noblocksnd, | ||
109 | bool nosndbuf); /* ipv6 never set sndbuf size */ | ||
110 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | ||
111 | struct socket **csocket, bool noblocksnd); | ||
112 | |||
113 | |||
114 | /* | ||
115 | * cifs tcp session reconnection | ||
116 | * | ||
117 | * mark tcp session as reconnecting so temporarily locked | ||
118 | * mark all smb sessions as reconnecting for tcp session | ||
119 | * reconnect tcp session | ||
120 | * wake up waiters on reconnection? - (not needed currently) | ||
121 | */ | ||
122 | 107 | ||
108 | /* | ||
109 | * cifs tcp session reconnection | ||
110 | * | ||
111 | * mark tcp session as reconnecting so temporarily locked | ||
112 | * mark all smb sessions as reconnecting for tcp session | ||
113 | * reconnect tcp session | ||
114 | * wake up waiters on reconnection? - (not needed currently) | ||
115 | */ | ||
123 | static int | 116 | static int |
124 | cifs_reconnect(struct TCP_Server_Info *server) | 117 | cifs_reconnect(struct TCP_Server_Info *server) |
125 | { | 118 | { |
@@ -156,7 +149,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
156 | } | 149 | } |
157 | read_unlock(&cifs_tcp_ses_lock); | 150 | read_unlock(&cifs_tcp_ses_lock); |
158 | /* do not want to be sending data on a socket we are freeing */ | 151 | /* do not want to be sending data on a socket we are freeing */ |
159 | down(&server->tcpSem); | 152 | mutex_lock(&server->srv_mutex); |
160 | if (server->ssocket) { | 153 | if (server->ssocket) { |
161 | cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state, | 154 | cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state, |
162 | server->ssocket->flags)); | 155 | server->ssocket->flags)); |
@@ -182,21 +175,15 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
182 | } | 175 | } |
183 | } | 176 | } |
184 | spin_unlock(&GlobalMid_Lock); | 177 | spin_unlock(&GlobalMid_Lock); |
185 | up(&server->tcpSem); | 178 | mutex_unlock(&server->srv_mutex); |
186 | 179 | ||
187 | while ((server->tcpStatus != CifsExiting) && | 180 | while ((server->tcpStatus != CifsExiting) && |
188 | (server->tcpStatus != CifsGood)) { | 181 | (server->tcpStatus != CifsGood)) { |
189 | try_to_freeze(); | 182 | try_to_freeze(); |
190 | if (server->addr.sockAddr6.sin6_family == AF_INET6) { | 183 | if (server->addr.sockAddr6.sin6_family == AF_INET6) |
191 | rc = ipv6_connect(&server->addr.sockAddr6, | 184 | rc = ipv6_connect(server); |
192 | &server->ssocket, server->noautotune); | 185 | else |
193 | } else { | 186 | rc = ipv4_connect(server); |
194 | rc = ipv4_connect(&server->addr.sockAddr, | ||
195 | &server->ssocket, | ||
196 | server->workstation_RFC1001_name, | ||
197 | server->server_RFC1001_name, | ||
198 | server->noblocksnd, server->noautotune); | ||
199 | } | ||
200 | if (rc) { | 187 | if (rc) { |
201 | cFYI(1, ("reconnect error %d", rc)); | 188 | cFYI(1, ("reconnect error %d", rc)); |
202 | msleep(3000); | 189 | msleep(3000); |
@@ -776,7 +763,7 @@ multi_t2_fnd: | |||
776 | set_current_state(TASK_RUNNING); | 763 | set_current_state(TASK_RUNNING); |
777 | } | 764 | } |
778 | 765 | ||
779 | return 0; | 766 | module_put_and_exit(0); |
780 | } | 767 | } |
781 | 768 | ||
782 | /* extract the host portion of the UNC string */ | 769 | /* extract the host portion of the UNC string */ |
@@ -1260,6 +1247,17 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1260 | if (vol->file_mode == | 1247 | if (vol->file_mode == |
1261 | (S_IALLUGO & ~(S_ISUID | S_IXGRP))) | 1248 | (S_IALLUGO & ~(S_ISUID | S_IXGRP))) |
1262 | vol->file_mode = S_IALLUGO; | 1249 | vol->file_mode = S_IALLUGO; |
1250 | } else if (strnicmp(data, "forcemandatorylock", 9) == 0) { | ||
1251 | /* will take the shorter form "forcemand" as well */ | ||
1252 | /* This mount option will force use of mandatory | ||
1253 | (DOS/Windows style) byte range locks, instead of | ||
1254 | using posix advisory byte range locks, even if the | ||
1255 | Unix extensions are available and posix locks would | ||
1256 | be supported otherwise. If Unix extensions are not | ||
1257 | negotiated this has no effect since mandatory locks | ||
1258 | would be used (mandatory locks is all that those | ||
1259 | those servers support) */ | ||
1260 | vol->mand_lock = 1; | ||
1263 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1261 | } else if (strnicmp(data, "setuids", 7) == 0) { |
1264 | vol->setuids = 1; | 1262 | vol->setuids = 1; |
1265 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1263 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
@@ -1417,6 +1415,143 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1417 | force_sig(SIGKILL, task); | 1415 | force_sig(SIGKILL, task); |
1418 | } | 1416 | } |
1419 | 1417 | ||
1418 | static struct TCP_Server_Info * | ||
1419 | cifs_get_tcp_session(struct smb_vol *volume_info) | ||
1420 | { | ||
1421 | struct TCP_Server_Info *tcp_ses = NULL; | ||
1422 | struct sockaddr addr; | ||
1423 | struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; | ||
1424 | struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; | ||
1425 | int rc; | ||
1426 | |||
1427 | memset(&addr, 0, sizeof(struct sockaddr)); | ||
1428 | |||
1429 | if (volume_info->UNCip && volume_info->UNC) { | ||
1430 | rc = cifs_inet_pton(AF_INET, volume_info->UNCip, | ||
1431 | &sin_server->sin_addr.s_addr); | ||
1432 | |||
1433 | if (rc <= 0) { | ||
1434 | /* not ipv4 address, try ipv6 */ | ||
1435 | rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, | ||
1436 | &sin_server6->sin6_addr.in6_u); | ||
1437 | if (rc > 0) | ||
1438 | addr.sa_family = AF_INET6; | ||
1439 | } else { | ||
1440 | addr.sa_family = AF_INET; | ||
1441 | } | ||
1442 | |||
1443 | if (rc <= 0) { | ||
1444 | /* we failed translating address */ | ||
1445 | rc = -EINVAL; | ||
1446 | goto out_err; | ||
1447 | } | ||
1448 | |||
1449 | cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, | ||
1450 | volume_info->UNCip)); | ||
1451 | } else if (volume_info->UNCip) { | ||
1452 | /* BB using ip addr as tcp_ses name to connect to the | ||
1453 | DFS root below */ | ||
1454 | cERROR(1, ("Connecting to DFS root not implemented yet")); | ||
1455 | rc = -EINVAL; | ||
1456 | goto out_err; | ||
1457 | } else /* which tcp_sess DFS root would we conect to */ { | ||
1458 | cERROR(1, | ||
1459 | ("CIFS mount error: No UNC path (e.g. -o " | ||
1460 | "unc=//192.168.1.100/public) specified")); | ||
1461 | rc = -EINVAL; | ||
1462 | goto out_err; | ||
1463 | } | ||
1464 | |||
1465 | /* see if we already have a matching tcp_ses */ | ||
1466 | tcp_ses = cifs_find_tcp_session(&addr); | ||
1467 | if (tcp_ses) | ||
1468 | return tcp_ses; | ||
1469 | |||
1470 | tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); | ||
1471 | if (!tcp_ses) { | ||
1472 | rc = -ENOMEM; | ||
1473 | goto out_err; | ||
1474 | } | ||
1475 | |||
1476 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | ||
1477 | if (IS_ERR(tcp_ses->hostname)) { | ||
1478 | rc = PTR_ERR(tcp_ses->hostname); | ||
1479 | goto out_err; | ||
1480 | } | ||
1481 | |||
1482 | tcp_ses->noblocksnd = volume_info->noblocksnd; | ||
1483 | tcp_ses->noautotune = volume_info->noautotune; | ||
1484 | atomic_set(&tcp_ses->inFlight, 0); | ||
1485 | init_waitqueue_head(&tcp_ses->response_q); | ||
1486 | init_waitqueue_head(&tcp_ses->request_q); | ||
1487 | INIT_LIST_HEAD(&tcp_ses->pending_mid_q); | ||
1488 | mutex_init(&tcp_ses->srv_mutex); | ||
1489 | memcpy(tcp_ses->workstation_RFC1001_name, | ||
1490 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | ||
1491 | memcpy(tcp_ses->server_RFC1001_name, | ||
1492 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | ||
1493 | tcp_ses->sequence_number = 0; | ||
1494 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | ||
1495 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | ||
1496 | |||
1497 | /* | ||
1498 | * at this point we are the only ones with the pointer | ||
1499 | * to the struct since the kernel thread not created yet | ||
1500 | * no need to spinlock this init of tcpStatus or srv_count | ||
1501 | */ | ||
1502 | tcp_ses->tcpStatus = CifsNew; | ||
1503 | ++tcp_ses->srv_count; | ||
1504 | |||
1505 | if (addr.sa_family == AF_INET6) { | ||
1506 | cFYI(1, ("attempting ipv6 connect")); | ||
1507 | /* BB should we allow ipv6 on port 139? */ | ||
1508 | /* other OS never observed in Wild doing 139 with v6 */ | ||
1509 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | ||
1510 | sizeof(struct sockaddr_in6)); | ||
1511 | sin_server6->sin6_port = htons(volume_info->port); | ||
1512 | rc = ipv6_connect(tcp_ses); | ||
1513 | } else { | ||
1514 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | ||
1515 | sizeof(struct sockaddr_in)); | ||
1516 | sin_server->sin_port = htons(volume_info->port); | ||
1517 | rc = ipv4_connect(tcp_ses); | ||
1518 | } | ||
1519 | if (rc < 0) { | ||
1520 | cERROR(1, ("Error connecting to socket. Aborting operation")); | ||
1521 | goto out_err; | ||
1522 | } | ||
1523 | |||
1524 | /* | ||
1525 | * since we're in a cifs function already, we know that | ||
1526 | * this will succeed. No need for try_module_get(). | ||
1527 | */ | ||
1528 | __module_get(THIS_MODULE); | ||
1529 | tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, | ||
1530 | tcp_ses, "cifsd"); | ||
1531 | if (IS_ERR(tcp_ses->tsk)) { | ||
1532 | rc = PTR_ERR(tcp_ses->tsk); | ||
1533 | cERROR(1, ("error %d create cifsd thread", rc)); | ||
1534 | module_put(THIS_MODULE); | ||
1535 | goto out_err; | ||
1536 | } | ||
1537 | |||
1538 | /* thread spawned, put it on the list */ | ||
1539 | write_lock(&cifs_tcp_ses_lock); | ||
1540 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | ||
1541 | write_unlock(&cifs_tcp_ses_lock); | ||
1542 | |||
1543 | return tcp_ses; | ||
1544 | |||
1545 | out_err: | ||
1546 | if (tcp_ses) { | ||
1547 | kfree(tcp_ses->hostname); | ||
1548 | if (tcp_ses->ssocket) | ||
1549 | sock_release(tcp_ses->ssocket); | ||
1550 | kfree(tcp_ses); | ||
1551 | } | ||
1552 | return ERR_PTR(rc); | ||
1553 | } | ||
1554 | |||
1420 | static struct cifsSesInfo * | 1555 | static struct cifsSesInfo * |
1421 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) | 1556 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) |
1422 | { | 1557 | { |
@@ -1593,93 +1728,96 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) | |||
1593 | 1728 | ||
1594 | 1729 | ||
1595 | static int | 1730 | static int |
1596 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | 1731 | ipv4_connect(struct TCP_Server_Info *server) |
1597 | char *netbios_name, char *target_name, | ||
1598 | bool noblocksnd, bool noautotune) | ||
1599 | { | 1732 | { |
1600 | int rc = 0; | 1733 | int rc = 0; |
1601 | int connected = 0; | 1734 | bool connected = false; |
1602 | __be16 orig_port = 0; | 1735 | __be16 orig_port = 0; |
1736 | struct socket *socket = server->ssocket; | ||
1603 | 1737 | ||
1604 | if (*csocket == NULL) { | 1738 | if (socket == NULL) { |
1605 | rc = sock_create_kern(PF_INET, SOCK_STREAM, | 1739 | rc = sock_create_kern(PF_INET, SOCK_STREAM, |
1606 | IPPROTO_TCP, csocket); | 1740 | IPPROTO_TCP, &socket); |
1607 | if (rc < 0) { | 1741 | if (rc < 0) { |
1608 | cERROR(1, ("Error %d creating socket", rc)); | 1742 | cERROR(1, ("Error %d creating socket", rc)); |
1609 | *csocket = NULL; | ||
1610 | return rc; | 1743 | return rc; |
1611 | } else { | ||
1612 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | ||
1613 | cFYI(1, ("Socket created")); | ||
1614 | (*csocket)->sk->sk_allocation = GFP_NOFS; | ||
1615 | cifs_reclassify_socket4(*csocket); | ||
1616 | } | 1744 | } |
1745 | |||
1746 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | ||
1747 | cFYI(1, ("Socket created")); | ||
1748 | server->ssocket = socket; | ||
1749 | socket->sk->sk_allocation = GFP_NOFS; | ||
1750 | cifs_reclassify_socket4(socket); | ||
1617 | } | 1751 | } |
1618 | 1752 | ||
1619 | psin_server->sin_family = AF_INET; | 1753 | /* user overrode default port */ |
1620 | if (psin_server->sin_port) { /* user overrode default port */ | 1754 | if (server->addr.sockAddr.sin_port) { |
1621 | rc = (*csocket)->ops->connect(*csocket, | 1755 | rc = socket->ops->connect(socket, (struct sockaddr *) |
1622 | (struct sockaddr *) psin_server, | 1756 | &server->addr.sockAddr, |
1623 | sizeof(struct sockaddr_in), 0); | 1757 | sizeof(struct sockaddr_in), 0); |
1624 | if (rc >= 0) | 1758 | if (rc >= 0) |
1625 | connected = 1; | 1759 | connected = true; |
1626 | } | 1760 | } |
1627 | 1761 | ||
1628 | if (!connected) { | 1762 | if (!connected) { |
1629 | /* save original port so we can retry user specified port | 1763 | /* save original port so we can retry user specified port |
1630 | later if fall back ports fail this time */ | 1764 | later if fall back ports fail this time */ |
1631 | orig_port = psin_server->sin_port; | 1765 | orig_port = server->addr.sockAddr.sin_port; |
1632 | 1766 | ||
1633 | /* do not retry on the same port we just failed on */ | 1767 | /* do not retry on the same port we just failed on */ |
1634 | if (psin_server->sin_port != htons(CIFS_PORT)) { | 1768 | if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { |
1635 | psin_server->sin_port = htons(CIFS_PORT); | 1769 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); |
1636 | 1770 | rc = socket->ops->connect(socket, | |
1637 | rc = (*csocket)->ops->connect(*csocket, | 1771 | (struct sockaddr *) |
1638 | (struct sockaddr *) psin_server, | 1772 | &server->addr.sockAddr, |
1639 | sizeof(struct sockaddr_in), 0); | 1773 | sizeof(struct sockaddr_in), 0); |
1640 | if (rc >= 0) | 1774 | if (rc >= 0) |
1641 | connected = 1; | 1775 | connected = true; |
1642 | } | 1776 | } |
1643 | } | 1777 | } |
1644 | if (!connected) { | 1778 | if (!connected) { |
1645 | psin_server->sin_port = htons(RFC1001_PORT); | 1779 | server->addr.sockAddr.sin_port = htons(RFC1001_PORT); |
1646 | rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) | 1780 | rc = socket->ops->connect(socket, (struct sockaddr *) |
1647 | psin_server, | 1781 | &server->addr.sockAddr, |
1648 | sizeof(struct sockaddr_in), 0); | 1782 | sizeof(struct sockaddr_in), 0); |
1649 | if (rc >= 0) | 1783 | if (rc >= 0) |
1650 | connected = 1; | 1784 | connected = true; |
1651 | } | 1785 | } |
1652 | 1786 | ||
1653 | /* give up here - unless we want to retry on different | 1787 | /* give up here - unless we want to retry on different |
1654 | protocol families some day */ | 1788 | protocol families some day */ |
1655 | if (!connected) { | 1789 | if (!connected) { |
1656 | if (orig_port) | 1790 | if (orig_port) |
1657 | psin_server->sin_port = orig_port; | 1791 | server->addr.sockAddr.sin_port = orig_port; |
1658 | cFYI(1, ("Error %d connecting to server via ipv4", rc)); | 1792 | cFYI(1, ("Error %d connecting to server via ipv4", rc)); |
1659 | sock_release(*csocket); | 1793 | sock_release(socket); |
1660 | *csocket = NULL; | 1794 | server->ssocket = NULL; |
1661 | return rc; | 1795 | return rc; |
1662 | } | 1796 | } |
1663 | /* Eventually check for other socket options to change from | 1797 | |
1664 | the default. sock_setsockopt not used because it expects | 1798 | |
1665 | user space buffer */ | 1799 | /* |
1666 | cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", | 1800 | * Eventually check for other socket options to change from |
1667 | (*csocket)->sk->sk_sndbuf, | 1801 | * the default. sock_setsockopt not used because it expects |
1668 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); | 1802 | * user space buffer |
1669 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1803 | */ |
1670 | if (!noblocksnd) | 1804 | socket->sk->sk_rcvtimeo = 7 * HZ; |
1671 | (*csocket)->sk->sk_sndtimeo = 3 * HZ; | 1805 | socket->sk->sk_sndtimeo = 3 * HZ; |
1672 | 1806 | ||
1673 | /* make the bufsizes depend on wsize/rsize and max requests */ | 1807 | /* make the bufsizes depend on wsize/rsize and max requests */ |
1674 | if (noautotune) { | 1808 | if (server->noautotune) { |
1675 | if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) | 1809 | if (socket->sk->sk_sndbuf < (200 * 1024)) |
1676 | (*csocket)->sk->sk_sndbuf = 200 * 1024; | 1810 | socket->sk->sk_sndbuf = 200 * 1024; |
1677 | if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) | 1811 | if (socket->sk->sk_rcvbuf < (140 * 1024)) |
1678 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | 1812 | socket->sk->sk_rcvbuf = 140 * 1024; |
1679 | } | 1813 | } |
1680 | 1814 | ||
1815 | cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx", | ||
1816 | socket->sk->sk_sndbuf, | ||
1817 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo)); | ||
1818 | |||
1681 | /* send RFC1001 sessinit */ | 1819 | /* send RFC1001 sessinit */ |
1682 | if (psin_server->sin_port == htons(RFC1001_PORT)) { | 1820 | if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { |
1683 | /* some servers require RFC1001 sessinit before sending | 1821 | /* some servers require RFC1001 sessinit before sending |
1684 | negprot - BB check reconnection in case where second | 1822 | negprot - BB check reconnection in case where second |
1685 | sessinit is sent but no second negprot */ | 1823 | sessinit is sent but no second negprot */ |
@@ -1689,31 +1827,42 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1689 | GFP_KERNEL); | 1827 | GFP_KERNEL); |
1690 | if (ses_init_buf) { | 1828 | if (ses_init_buf) { |
1691 | ses_init_buf->trailer.session_req.called_len = 32; | 1829 | ses_init_buf->trailer.session_req.called_len = 32; |
1692 | if (target_name && (target_name[0] != 0)) { | 1830 | if (server->server_RFC1001_name && |
1693 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1831 | server->server_RFC1001_name[0] != 0) |
1694 | target_name, 16); | 1832 | rfc1002mangle(ses_init_buf->trailer. |
1695 | } else { | 1833 | session_req.called_name, |
1696 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1834 | server->server_RFC1001_name, |
1697 | DEFAULT_CIFS_CALLED_NAME, 16); | 1835 | RFC1001_NAME_LEN_WITH_NULL); |
1698 | } | 1836 | else |
1837 | rfc1002mangle(ses_init_buf->trailer. | ||
1838 | session_req.called_name, | ||
1839 | DEFAULT_CIFS_CALLED_NAME, | ||
1840 | RFC1001_NAME_LEN_WITH_NULL); | ||
1699 | 1841 | ||
1700 | ses_init_buf->trailer.session_req.calling_len = 32; | 1842 | ses_init_buf->trailer.session_req.calling_len = 32; |
1843 | |||
1701 | /* calling name ends in null (byte 16) from old smb | 1844 | /* calling name ends in null (byte 16) from old smb |
1702 | convention. */ | 1845 | convention. */ |
1703 | if (netbios_name && (netbios_name[0] != 0)) { | 1846 | if (server->workstation_RFC1001_name && |
1704 | rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, | 1847 | server->workstation_RFC1001_name[0] != 0) |
1705 | netbios_name, 16); | 1848 | rfc1002mangle(ses_init_buf->trailer. |
1706 | } else { | 1849 | session_req.calling_name, |
1707 | rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, | 1850 | server->workstation_RFC1001_name, |
1708 | "LINUX_CIFS_CLNT", 16); | 1851 | RFC1001_NAME_LEN_WITH_NULL); |
1709 | } | 1852 | else |
1853 | rfc1002mangle(ses_init_buf->trailer. | ||
1854 | session_req.calling_name, | ||
1855 | "LINUX_CIFS_CLNT", | ||
1856 | RFC1001_NAME_LEN_WITH_NULL); | ||
1857 | |||
1710 | ses_init_buf->trailer.session_req.scope1 = 0; | 1858 | ses_init_buf->trailer.session_req.scope1 = 0; |
1711 | ses_init_buf->trailer.session_req.scope2 = 0; | 1859 | ses_init_buf->trailer.session_req.scope2 = 0; |
1712 | smb_buf = (struct smb_hdr *)ses_init_buf; | 1860 | smb_buf = (struct smb_hdr *)ses_init_buf; |
1713 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | 1861 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ |
1714 | smb_buf->smb_buf_length = 0x81000044; | 1862 | smb_buf->smb_buf_length = 0x81000044; |
1715 | rc = smb_send(*csocket, smb_buf, 0x44, | 1863 | rc = smb_send(socket, smb_buf, 0x44, |
1716 | (struct sockaddr *)psin_server, noblocksnd); | 1864 | (struct sockaddr *) &server->addr.sockAddr, |
1865 | server->noblocksnd); | ||
1717 | kfree(ses_init_buf); | 1866 | kfree(ses_init_buf); |
1718 | msleep(1); /* RFC1001 layer in at least one server | 1867 | msleep(1); /* RFC1001 layer in at least one server |
1719 | requires very short break before negprot | 1868 | requires very short break before negprot |
@@ -1733,79 +1882,81 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1733 | } | 1882 | } |
1734 | 1883 | ||
1735 | static int | 1884 | static int |
1736 | ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket, | 1885 | ipv6_connect(struct TCP_Server_Info *server) |
1737 | bool noblocksnd) | ||
1738 | { | 1886 | { |
1739 | int rc = 0; | 1887 | int rc = 0; |
1740 | int connected = 0; | 1888 | bool connected = false; |
1741 | __be16 orig_port = 0; | 1889 | __be16 orig_port = 0; |
1890 | struct socket *socket = server->ssocket; | ||
1742 | 1891 | ||
1743 | if (*csocket == NULL) { | 1892 | if (socket == NULL) { |
1744 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, | 1893 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, |
1745 | IPPROTO_TCP, csocket); | 1894 | IPPROTO_TCP, &socket); |
1746 | if (rc < 0) { | 1895 | if (rc < 0) { |
1747 | cERROR(1, ("Error %d creating ipv6 socket", rc)); | 1896 | cERROR(1, ("Error %d creating ipv6 socket", rc)); |
1748 | *csocket = NULL; | 1897 | socket = NULL; |
1749 | return rc; | 1898 | return rc; |
1750 | } else { | ||
1751 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | ||
1752 | cFYI(1, ("ipv6 Socket created")); | ||
1753 | (*csocket)->sk->sk_allocation = GFP_NOFS; | ||
1754 | cifs_reclassify_socket6(*csocket); | ||
1755 | } | 1899 | } |
1756 | } | ||
1757 | 1900 | ||
1758 | psin_server->sin6_family = AF_INET6; | 1901 | /* BB other socket options to set KEEPALIVE, NODELAY? */ |
1902 | cFYI(1, ("ipv6 Socket created")); | ||
1903 | server->ssocket = socket; | ||
1904 | socket->sk->sk_allocation = GFP_NOFS; | ||
1905 | cifs_reclassify_socket6(socket); | ||
1906 | } | ||
1759 | 1907 | ||
1760 | if (psin_server->sin6_port) { /* user overrode default port */ | 1908 | /* user overrode default port */ |
1761 | rc = (*csocket)->ops->connect(*csocket, | 1909 | if (server->addr.sockAddr6.sin6_port) { |
1762 | (struct sockaddr *) psin_server, | 1910 | rc = socket->ops->connect(socket, |
1911 | (struct sockaddr *) &server->addr.sockAddr6, | ||
1763 | sizeof(struct sockaddr_in6), 0); | 1912 | sizeof(struct sockaddr_in6), 0); |
1764 | if (rc >= 0) | 1913 | if (rc >= 0) |
1765 | connected = 1; | 1914 | connected = true; |
1766 | } | 1915 | } |
1767 | 1916 | ||
1768 | if (!connected) { | 1917 | if (!connected) { |
1769 | /* save original port so we can retry user specified port | 1918 | /* save original port so we can retry user specified port |
1770 | later if fall back ports fail this time */ | 1919 | later if fall back ports fail this time */ |
1771 | 1920 | ||
1772 | orig_port = psin_server->sin6_port; | 1921 | orig_port = server->addr.sockAddr6.sin6_port; |
1773 | /* do not retry on the same port we just failed on */ | 1922 | /* do not retry on the same port we just failed on */ |
1774 | if (psin_server->sin6_port != htons(CIFS_PORT)) { | 1923 | if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { |
1775 | psin_server->sin6_port = htons(CIFS_PORT); | 1924 | server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); |
1776 | 1925 | rc = socket->ops->connect(socket, (struct sockaddr *) | |
1777 | rc = (*csocket)->ops->connect(*csocket, | 1926 | &server->addr.sockAddr6, |
1778 | (struct sockaddr *) psin_server, | ||
1779 | sizeof(struct sockaddr_in6), 0); | 1927 | sizeof(struct sockaddr_in6), 0); |
1780 | if (rc >= 0) | 1928 | if (rc >= 0) |
1781 | connected = 1; | 1929 | connected = true; |
1782 | } | 1930 | } |
1783 | } | 1931 | } |
1784 | if (!connected) { | 1932 | if (!connected) { |
1785 | psin_server->sin6_port = htons(RFC1001_PORT); | 1933 | server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); |
1786 | rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) | 1934 | rc = socket->ops->connect(socket, (struct sockaddr *) |
1787 | psin_server, sizeof(struct sockaddr_in6), 0); | 1935 | &server->addr.sockAddr6, |
1936 | sizeof(struct sockaddr_in6), 0); | ||
1788 | if (rc >= 0) | 1937 | if (rc >= 0) |
1789 | connected = 1; | 1938 | connected = true; |
1790 | } | 1939 | } |
1791 | 1940 | ||
1792 | /* give up here - unless we want to retry on different | 1941 | /* give up here - unless we want to retry on different |
1793 | protocol families some day */ | 1942 | protocol families some day */ |
1794 | if (!connected) { | 1943 | if (!connected) { |
1795 | if (orig_port) | 1944 | if (orig_port) |
1796 | psin_server->sin6_port = orig_port; | 1945 | server->addr.sockAddr6.sin6_port = orig_port; |
1797 | cFYI(1, ("Error %d connecting to server via ipv6", rc)); | 1946 | cFYI(1, ("Error %d connecting to server via ipv6", rc)); |
1798 | sock_release(*csocket); | 1947 | sock_release(socket); |
1799 | *csocket = NULL; | 1948 | server->ssocket = NULL; |
1800 | return rc; | 1949 | return rc; |
1801 | } | 1950 | } |
1802 | /* Eventually check for other socket options to change from | ||
1803 | the default. sock_setsockopt not used because it expects | ||
1804 | user space buffer */ | ||
1805 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | ||
1806 | if (!noblocksnd) | ||
1807 | (*csocket)->sk->sk_sndtimeo = 3 * HZ; | ||
1808 | 1951 | ||
1952 | /* | ||
1953 | * Eventually check for other socket options to change from | ||
1954 | * the default. sock_setsockopt not used because it expects | ||
1955 | * user space buffer | ||
1956 | */ | ||
1957 | socket->sk->sk_rcvtimeo = 7 * HZ; | ||
1958 | socket->sk->sk_sndtimeo = 3 * HZ; | ||
1959 | server->ssocket = socket; | ||
1809 | 1960 | ||
1810 | return rc; | 1961 | return rc; |
1811 | } | 1962 | } |
@@ -2011,6 +2162,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2011 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | 2162 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; |
2012 | if (pvolume_info->nobrl) | 2163 | if (pvolume_info->nobrl) |
2013 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | 2164 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; |
2165 | if (pvolume_info->mand_lock) | ||
2166 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL; | ||
2014 | if (pvolume_info->cifs_acl) | 2167 | if (pvolume_info->cifs_acl) |
2015 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | 2168 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; |
2016 | if (pvolume_info->override_uid) | 2169 | if (pvolume_info->override_uid) |
@@ -2035,32 +2188,30 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2035 | { | 2188 | { |
2036 | int rc = 0; | 2189 | int rc = 0; |
2037 | int xid; | 2190 | int xid; |
2038 | struct socket *csocket = NULL; | 2191 | struct smb_vol *volume_info; |
2039 | struct sockaddr addr; | ||
2040 | struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; | ||
2041 | struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; | ||
2042 | struct smb_vol volume_info; | ||
2043 | struct cifsSesInfo *pSesInfo = NULL; | 2192 | struct cifsSesInfo *pSesInfo = NULL; |
2044 | struct cifsTconInfo *tcon = NULL; | 2193 | struct cifsTconInfo *tcon = NULL; |
2045 | struct TCP_Server_Info *srvTcp = NULL; | 2194 | struct TCP_Server_Info *srvTcp = NULL; |
2046 | 2195 | ||
2047 | xid = GetXid(); | 2196 | xid = GetXid(); |
2048 | 2197 | ||
2049 | /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ | 2198 | volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL); |
2199 | if (!volume_info) { | ||
2200 | rc = -ENOMEM; | ||
2201 | goto out; | ||
2202 | } | ||
2050 | 2203 | ||
2051 | memset(&addr, 0, sizeof(struct sockaddr)); | 2204 | if (cifs_parse_mount_options(mount_data, devname, volume_info)) { |
2052 | memset(&volume_info, 0, sizeof(struct smb_vol)); | ||
2053 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { | ||
2054 | rc = -EINVAL; | 2205 | rc = -EINVAL; |
2055 | goto out; | 2206 | goto out; |
2056 | } | 2207 | } |
2057 | 2208 | ||
2058 | if (volume_info.nullauth) { | 2209 | if (volume_info->nullauth) { |
2059 | cFYI(1, ("null user")); | 2210 | cFYI(1, ("null user")); |
2060 | volume_info.username = ""; | 2211 | volume_info->username = ""; |
2061 | } else if (volume_info.username) { | 2212 | } else if (volume_info->username) { |
2062 | /* BB fixme parse for domain name here */ | 2213 | /* BB fixme parse for domain name here */ |
2063 | cFYI(1, ("Username: %s", volume_info.username)); | 2214 | cFYI(1, ("Username: %s", volume_info->username)); |
2064 | } else { | 2215 | } else { |
2065 | cifserror("No username specified"); | 2216 | cifserror("No username specified"); |
2066 | /* In userspace mount helper we can get user name from alternate | 2217 | /* In userspace mount helper we can get user name from alternate |
@@ -2069,139 +2220,29 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2069 | goto out; | 2220 | goto out; |
2070 | } | 2221 | } |
2071 | 2222 | ||
2072 | if (volume_info.UNCip && volume_info.UNC) { | ||
2073 | rc = cifs_inet_pton(AF_INET, volume_info.UNCip, | ||
2074 | &sin_server->sin_addr.s_addr); | ||
2075 | |||
2076 | if (rc <= 0) { | ||
2077 | /* not ipv4 address, try ipv6 */ | ||
2078 | rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, | ||
2079 | &sin_server6->sin6_addr.in6_u); | ||
2080 | if (rc > 0) | ||
2081 | addr.sa_family = AF_INET6; | ||
2082 | } else { | ||
2083 | addr.sa_family = AF_INET; | ||
2084 | } | ||
2085 | |||
2086 | if (rc <= 0) { | ||
2087 | /* we failed translating address */ | ||
2088 | rc = -EINVAL; | ||
2089 | goto out; | ||
2090 | } | ||
2091 | |||
2092 | cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); | ||
2093 | /* success */ | ||
2094 | rc = 0; | ||
2095 | } else if (volume_info.UNCip) { | ||
2096 | /* BB using ip addr as server name to connect to the | ||
2097 | DFS root below */ | ||
2098 | cERROR(1, ("Connecting to DFS root not implemented yet")); | ||
2099 | rc = -EINVAL; | ||
2100 | goto out; | ||
2101 | } else /* which servers DFS root would we conect to */ { | ||
2102 | cERROR(1, | ||
2103 | ("CIFS mount error: No UNC path (e.g. -o " | ||
2104 | "unc=//192.168.1.100/public) specified")); | ||
2105 | rc = -EINVAL; | ||
2106 | goto out; | ||
2107 | } | ||
2108 | 2223 | ||
2109 | /* this is needed for ASCII cp to Unicode converts */ | 2224 | /* this is needed for ASCII cp to Unicode converts */ |
2110 | if (volume_info.iocharset == NULL) { | 2225 | if (volume_info->iocharset == NULL) { |
2111 | cifs_sb->local_nls = load_nls_default(); | 2226 | cifs_sb->local_nls = load_nls_default(); |
2112 | /* load_nls_default can not return null */ | 2227 | /* load_nls_default can not return null */ |
2113 | } else { | 2228 | } else { |
2114 | cifs_sb->local_nls = load_nls(volume_info.iocharset); | 2229 | cifs_sb->local_nls = load_nls(volume_info->iocharset); |
2115 | if (cifs_sb->local_nls == NULL) { | 2230 | if (cifs_sb->local_nls == NULL) { |
2116 | cERROR(1, ("CIFS mount error: iocharset %s not found", | 2231 | cERROR(1, ("CIFS mount error: iocharset %s not found", |
2117 | volume_info.iocharset)); | 2232 | volume_info->iocharset)); |
2118 | rc = -ELIBACC; | 2233 | rc = -ELIBACC; |
2119 | goto out; | 2234 | goto out; |
2120 | } | 2235 | } |
2121 | } | 2236 | } |
2122 | 2237 | ||
2123 | srvTcp = cifs_find_tcp_session(&addr); | 2238 | /* get a reference to a tcp session */ |
2124 | if (!srvTcp) { /* create socket */ | 2239 | srvTcp = cifs_get_tcp_session(volume_info); |
2125 | if (addr.sa_family == AF_INET6) { | 2240 | if (IS_ERR(srvTcp)) { |
2126 | cFYI(1, ("attempting ipv6 connect")); | 2241 | rc = PTR_ERR(srvTcp); |
2127 | /* BB should we allow ipv6 on port 139? */ | 2242 | goto out; |
2128 | /* other OS never observed in Wild doing 139 with v6 */ | ||
2129 | sin_server6->sin6_port = htons(volume_info.port); | ||
2130 | rc = ipv6_connect(sin_server6, &csocket, | ||
2131 | volume_info.noblocksnd); | ||
2132 | } else { | ||
2133 | sin_server->sin_port = htons(volume_info.port); | ||
2134 | rc = ipv4_connect(sin_server, &csocket, | ||
2135 | volume_info.source_rfc1001_name, | ||
2136 | volume_info.target_rfc1001_name, | ||
2137 | volume_info.noblocksnd, | ||
2138 | volume_info.noautotune); | ||
2139 | } | ||
2140 | if (rc < 0) { | ||
2141 | cERROR(1, ("Error connecting to socket. " | ||
2142 | "Aborting operation")); | ||
2143 | if (csocket != NULL) | ||
2144 | sock_release(csocket); | ||
2145 | goto out; | ||
2146 | } | ||
2147 | |||
2148 | srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); | ||
2149 | if (!srvTcp) { | ||
2150 | rc = -ENOMEM; | ||
2151 | sock_release(csocket); | ||
2152 | goto out; | ||
2153 | } else { | ||
2154 | srvTcp->noblocksnd = volume_info.noblocksnd; | ||
2155 | srvTcp->noautotune = volume_info.noautotune; | ||
2156 | if (addr.sa_family == AF_INET6) | ||
2157 | memcpy(&srvTcp->addr.sockAddr6, sin_server6, | ||
2158 | sizeof(struct sockaddr_in6)); | ||
2159 | else | ||
2160 | memcpy(&srvTcp->addr.sockAddr, sin_server, | ||
2161 | sizeof(struct sockaddr_in)); | ||
2162 | atomic_set(&srvTcp->inFlight, 0); | ||
2163 | /* BB Add code for ipv6 case too */ | ||
2164 | srvTcp->ssocket = csocket; | ||
2165 | srvTcp->hostname = extract_hostname(volume_info.UNC); | ||
2166 | if (IS_ERR(srvTcp->hostname)) { | ||
2167 | rc = PTR_ERR(srvTcp->hostname); | ||
2168 | sock_release(csocket); | ||
2169 | goto out; | ||
2170 | } | ||
2171 | init_waitqueue_head(&srvTcp->response_q); | ||
2172 | init_waitqueue_head(&srvTcp->request_q); | ||
2173 | INIT_LIST_HEAD(&srvTcp->pending_mid_q); | ||
2174 | /* at this point we are the only ones with the pointer | ||
2175 | to the struct since the kernel thread not created yet | ||
2176 | so no need to spinlock this init of tcpStatus */ | ||
2177 | srvTcp->tcpStatus = CifsNew; | ||
2178 | init_MUTEX(&srvTcp->tcpSem); | ||
2179 | srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd"); | ||
2180 | if (IS_ERR(srvTcp->tsk)) { | ||
2181 | rc = PTR_ERR(srvTcp->tsk); | ||
2182 | cERROR(1, ("error %d create cifsd thread", rc)); | ||
2183 | srvTcp->tsk = NULL; | ||
2184 | sock_release(csocket); | ||
2185 | kfree(srvTcp->hostname); | ||
2186 | goto out; | ||
2187 | } | ||
2188 | rc = 0; | ||
2189 | memcpy(srvTcp->workstation_RFC1001_name, | ||
2190 | volume_info.source_rfc1001_name, 16); | ||
2191 | memcpy(srvTcp->server_RFC1001_name, | ||
2192 | volume_info.target_rfc1001_name, 16); | ||
2193 | srvTcp->sequence_number = 0; | ||
2194 | INIT_LIST_HEAD(&srvTcp->tcp_ses_list); | ||
2195 | INIT_LIST_HEAD(&srvTcp->smb_ses_list); | ||
2196 | ++srvTcp->srv_count; | ||
2197 | write_lock(&cifs_tcp_ses_lock); | ||
2198 | list_add(&srvTcp->tcp_ses_list, | ||
2199 | &cifs_tcp_ses_list); | ||
2200 | write_unlock(&cifs_tcp_ses_lock); | ||
2201 | } | ||
2202 | } | 2243 | } |
2203 | 2244 | ||
2204 | pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); | 2245 | pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username); |
2205 | if (pSesInfo) { | 2246 | if (pSesInfo) { |
2206 | cFYI(1, ("Existing smb sess found (status=%d)", | 2247 | cFYI(1, ("Existing smb sess found (status=%d)", |
2207 | pSesInfo->status)); | 2248 | pSesInfo->status)); |
@@ -2228,31 +2269,38 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2228 | 2269 | ||
2229 | /* new SMB session uses our srvTcp ref */ | 2270 | /* new SMB session uses our srvTcp ref */ |
2230 | pSesInfo->server = srvTcp; | 2271 | pSesInfo->server = srvTcp; |
2231 | sprintf(pSesInfo->serverName, "%u.%u.%u.%u", | 2272 | if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6) |
2232 | NIPQUAD(sin_server->sin_addr.s_addr)); | 2273 | sprintf(pSesInfo->serverName, NIP6_FMT, |
2274 | NIP6(srvTcp->addr.sockAddr6.sin6_addr)); | ||
2275 | else | ||
2276 | sprintf(pSesInfo->serverName, NIPQUAD_FMT, | ||
2277 | NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr)); | ||
2233 | 2278 | ||
2234 | write_lock(&cifs_tcp_ses_lock); | 2279 | write_lock(&cifs_tcp_ses_lock); |
2235 | list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); | 2280 | list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); |
2236 | write_unlock(&cifs_tcp_ses_lock); | 2281 | write_unlock(&cifs_tcp_ses_lock); |
2237 | 2282 | ||
2238 | /* volume_info.password freed at unmount */ | 2283 | /* volume_info->password freed at unmount */ |
2239 | if (volume_info.password) { | 2284 | if (volume_info->password) { |
2240 | pSesInfo->password = volume_info.password; | 2285 | pSesInfo->password = kstrdup(volume_info->password, |
2241 | /* set to NULL to prevent freeing on exit */ | 2286 | GFP_KERNEL); |
2242 | volume_info.password = NULL; | 2287 | if (!pSesInfo->password) { |
2288 | rc = -ENOMEM; | ||
2289 | goto mount_fail_check; | ||
2290 | } | ||
2243 | } | 2291 | } |
2244 | if (volume_info.username) | 2292 | if (volume_info->username) |
2245 | strncpy(pSesInfo->userName, volume_info.username, | 2293 | strncpy(pSesInfo->userName, volume_info->username, |
2246 | MAX_USERNAME_SIZE); | 2294 | MAX_USERNAME_SIZE); |
2247 | if (volume_info.domainname) { | 2295 | if (volume_info->domainname) { |
2248 | int len = strlen(volume_info.domainname); | 2296 | int len = strlen(volume_info->domainname); |
2249 | pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); | 2297 | pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); |
2250 | if (pSesInfo->domainName) | 2298 | if (pSesInfo->domainName) |
2251 | strcpy(pSesInfo->domainName, | 2299 | strcpy(pSesInfo->domainName, |
2252 | volume_info.domainname); | 2300 | volume_info->domainname); |
2253 | } | 2301 | } |
2254 | pSesInfo->linux_uid = volume_info.linux_uid; | 2302 | pSesInfo->linux_uid = volume_info->linux_uid; |
2255 | pSesInfo->overrideSecFlg = volume_info.secFlg; | 2303 | pSesInfo->overrideSecFlg = volume_info->secFlg; |
2256 | down(&pSesInfo->sesSem); | 2304 | down(&pSesInfo->sesSem); |
2257 | 2305 | ||
2258 | /* BB FIXME need to pass vol->secFlgs BB */ | 2306 | /* BB FIXME need to pass vol->secFlgs BB */ |
@@ -2263,14 +2311,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2263 | 2311 | ||
2264 | /* search for existing tcon to this server share */ | 2312 | /* search for existing tcon to this server share */ |
2265 | if (!rc) { | 2313 | if (!rc) { |
2266 | setup_cifs_sb(&volume_info, cifs_sb); | 2314 | setup_cifs_sb(volume_info, cifs_sb); |
2267 | 2315 | ||
2268 | tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); | 2316 | tcon = cifs_find_tcon(pSesInfo, volume_info->UNC); |
2269 | if (tcon) { | 2317 | if (tcon) { |
2270 | cFYI(1, ("Found match on UNC path")); | 2318 | cFYI(1, ("Found match on UNC path")); |
2271 | /* existing tcon already has a reference */ | 2319 | /* existing tcon already has a reference */ |
2272 | cifs_put_smb_ses(pSesInfo); | 2320 | cifs_put_smb_ses(pSesInfo); |
2273 | if (tcon->seal != volume_info.seal) | 2321 | if (tcon->seal != volume_info->seal) |
2274 | cERROR(1, ("transport encryption setting " | 2322 | cERROR(1, ("transport encryption setting " |
2275 | "conflicts with existing tid")); | 2323 | "conflicts with existing tid")); |
2276 | } else { | 2324 | } else { |
@@ -2279,11 +2327,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2279 | rc = -ENOMEM; | 2327 | rc = -ENOMEM; |
2280 | goto mount_fail_check; | 2328 | goto mount_fail_check; |
2281 | } | 2329 | } |
2330 | |||
2282 | tcon->ses = pSesInfo; | 2331 | tcon->ses = pSesInfo; |
2332 | if (volume_info->password) { | ||
2333 | tcon->password = kstrdup(volume_info->password, | ||
2334 | GFP_KERNEL); | ||
2335 | if (!tcon->password) { | ||
2336 | rc = -ENOMEM; | ||
2337 | goto mount_fail_check; | ||
2338 | } | ||
2339 | } | ||
2283 | 2340 | ||
2284 | /* check for null share name ie connect to dfs root */ | 2341 | /* check for null share name ie connect to dfs root */ |
2285 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | 2342 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) |
2286 | && (strchr(volume_info.UNC + 3, '/') == NULL)) { | 2343 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { |
2287 | /* rc = connect_to_dfs_path(...) */ | 2344 | /* rc = connect_to_dfs_path(...) */ |
2288 | cFYI(1, ("DFS root not supported")); | 2345 | cFYI(1, ("DFS root not supported")); |
2289 | rc = -ENODEV; | 2346 | rc = -ENODEV; |
@@ -2292,10 +2349,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2292 | /* BB Do we need to wrap sesSem around | 2349 | /* BB Do we need to wrap sesSem around |
2293 | * this TCon call and Unix SetFS as | 2350 | * this TCon call and Unix SetFS as |
2294 | * we do on SessSetup and reconnect? */ | 2351 | * we do on SessSetup and reconnect? */ |
2295 | rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, | 2352 | rc = CIFSTCon(xid, pSesInfo, volume_info->UNC, |
2296 | tcon, cifs_sb->local_nls); | 2353 | tcon, cifs_sb->local_nls); |
2297 | cFYI(1, ("CIFS Tcon rc = %d", rc)); | 2354 | cFYI(1, ("CIFS Tcon rc = %d", rc)); |
2298 | if (volume_info.nodfs) { | 2355 | if (volume_info->nodfs) { |
2299 | tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; | 2356 | tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; |
2300 | cFYI(1, ("DFS disabled (%d)", | 2357 | cFYI(1, ("DFS disabled (%d)", |
2301 | tcon->Flags)); | 2358 | tcon->Flags)); |
@@ -2303,7 +2360,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2303 | } | 2360 | } |
2304 | if (rc) | 2361 | if (rc) |
2305 | goto mount_fail_check; | 2362 | goto mount_fail_check; |
2306 | tcon->seal = volume_info.seal; | 2363 | tcon->seal = volume_info->seal; |
2307 | write_lock(&cifs_tcp_ses_lock); | 2364 | write_lock(&cifs_tcp_ses_lock); |
2308 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | 2365 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); |
2309 | write_unlock(&cifs_tcp_ses_lock); | 2366 | write_unlock(&cifs_tcp_ses_lock); |
@@ -2313,9 +2370,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2313 | to a share so for resources mounted more than once | 2370 | to a share so for resources mounted more than once |
2314 | to the same server share the last value passed in | 2371 | to the same server share the last value passed in |
2315 | for the retry flag is used */ | 2372 | for the retry flag is used */ |
2316 | tcon->retry = volume_info.retry; | 2373 | tcon->retry = volume_info->retry; |
2317 | tcon->nocase = volume_info.nocase; | 2374 | tcon->nocase = volume_info->nocase; |
2318 | tcon->local_lease = volume_info.local_lease; | 2375 | tcon->local_lease = volume_info->local_lease; |
2319 | } | 2376 | } |
2320 | if (pSesInfo) { | 2377 | if (pSesInfo) { |
2321 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { | 2378 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { |
@@ -2352,7 +2409,7 @@ mount_fail_check: | |||
2352 | if (tcon->ses->capabilities & CAP_UNIX) | 2409 | if (tcon->ses->capabilities & CAP_UNIX) |
2353 | /* reset of caps checks mount to see if unix extensions | 2410 | /* reset of caps checks mount to see if unix extensions |
2354 | disabled for just this mount */ | 2411 | disabled for just this mount */ |
2355 | reset_cifs_unix_caps(xid, tcon, sb, &volume_info); | 2412 | reset_cifs_unix_caps(xid, tcon, sb, volume_info); |
2356 | else | 2413 | else |
2357 | tcon->unix_ext = 0; /* server does not support them */ | 2414 | tcon->unix_ext = 0; /* server does not support them */ |
2358 | 2415 | ||
@@ -2371,18 +2428,22 @@ mount_fail_check: | |||
2371 | cifs_sb->rsize = min(cifs_sb->rsize, | 2428 | cifs_sb->rsize = min(cifs_sb->rsize, |
2372 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2429 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2373 | 2430 | ||
2374 | /* volume_info.password is freed above when existing session found | 2431 | /* volume_info->password is freed above when existing session found |
2375 | (in which case it is not needed anymore) but when new sesion is created | 2432 | (in which case it is not needed anymore) but when new sesion is created |
2376 | the password ptr is put in the new session structure (in which case the | 2433 | the password ptr is put in the new session structure (in which case the |
2377 | password will be freed at unmount time) */ | 2434 | password will be freed at unmount time) */ |
2378 | out: | 2435 | out: |
2379 | /* zero out password before freeing */ | 2436 | /* zero out password before freeing */ |
2380 | if (volume_info.password != NULL) { | 2437 | if (volume_info) { |
2381 | memset(volume_info.password, 0, strlen(volume_info.password)); | 2438 | if (volume_info->password != NULL) { |
2382 | kfree(volume_info.password); | 2439 | memset(volume_info->password, 0, |
2440 | strlen(volume_info->password)); | ||
2441 | kfree(volume_info->password); | ||
2442 | } | ||
2443 | kfree(volume_info->UNC); | ||
2444 | kfree(volume_info->prepath); | ||
2445 | kfree(volume_info); | ||
2383 | } | 2446 | } |
2384 | kfree(volume_info.UNC); | ||
2385 | kfree(volume_info.prepath); | ||
2386 | FreeXid(xid); | 2447 | FreeXid(xid); |
2387 | return rc; | 2448 | return rc; |
2388 | } | 2449 | } |
@@ -2533,7 +2594,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2533 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | 2594 | __u16 action = le16_to_cpu(pSMBr->resp.Action); |
2534 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | 2595 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); |
2535 | if (action & GUEST_LOGIN) | 2596 | if (action & GUEST_LOGIN) |
2536 | cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ | 2597 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ |
2537 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | 2598 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format |
2538 | (little endian) */ | 2599 | (little endian) */ |
2539 | cFYI(1, ("UID = %d ", ses->Suid)); | 2600 | cFYI(1, ("UID = %d ", ses->Suid)); |
@@ -2679,13 +2740,11 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
2679 | len)); | 2740 | len)); |
2680 | } | 2741 | } |
2681 | } else { | 2742 | } else { |
2682 | cERROR(1, | 2743 | cERROR(1, ("Security Blob Length extends beyond " |
2683 | (" Security Blob Length extends beyond " | ||
2684 | "end of SMB")); | 2744 | "end of SMB")); |
2685 | } | 2745 | } |
2686 | } else { | 2746 | } else { |
2687 | cERROR(1, | 2747 | cERROR(1, ("Invalid Word count %d: ", |
2688 | (" Invalid Word count %d: ", | ||
2689 | smb_buffer_response->WordCount)); | 2748 | smb_buffer_response->WordCount)); |
2690 | rc = -EIO; | 2749 | rc = -EIO; |
2691 | } | 2750 | } |
@@ -2843,7 +2902,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
2843 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | 2902 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); |
2844 | 2903 | ||
2845 | if (action & GUEST_LOGIN) | 2904 | if (action & GUEST_LOGIN) |
2846 | cFYI(1, (" Guest login")); | 2905 | cFYI(1, ("Guest login")); |
2847 | /* Do we want to set anything in SesInfo struct when guest login? */ | 2906 | /* Do we want to set anything in SesInfo struct when guest login? */ |
2848 | 2907 | ||
2849 | bcc_ptr = pByteArea(smb_buffer_response); | 2908 | bcc_ptr = pByteArea(smb_buffer_response); |
@@ -2851,8 +2910,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
2851 | 2910 | ||
2852 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | 2911 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; |
2853 | if (SecurityBlob2->MessageType != NtLmChallenge) { | 2912 | if (SecurityBlob2->MessageType != NtLmChallenge) { |
2854 | cFYI(1, | 2913 | cFYI(1, ("Unexpected NTLMSSP message type received %d", |
2855 | ("Unexpected NTLMSSP message type received %d", | ||
2856 | SecurityBlob2->MessageType)); | 2914 | SecurityBlob2->MessageType)); |
2857 | } else if (ses) { | 2915 | } else if (ses) { |
2858 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | 2916 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ |
@@ -3024,8 +3082,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
3024 | cERROR(1, ("No session structure passed in.")); | 3082 | cERROR(1, ("No session structure passed in.")); |
3025 | } | 3083 | } |
3026 | } else { | 3084 | } else { |
3027 | cERROR(1, | 3085 | cERROR(1, ("Invalid Word count %d:", |
3028 | (" Invalid Word count %d:", | ||
3029 | smb_buffer_response->WordCount)); | 3086 | smb_buffer_response->WordCount)); |
3030 | rc = -EIO; | 3087 | rc = -EIO; |
3031 | } | 3088 | } |
@@ -3264,7 +3321,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
3264 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | 3321 | __u16 action = le16_to_cpu(pSMBr->resp.Action); |
3265 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | 3322 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); |
3266 | if (action & GUEST_LOGIN) | 3323 | if (action & GUEST_LOGIN) |
3267 | cFYI(1, (" Guest login")); /* BB Should we set anything | 3324 | cFYI(1, ("Guest login")); /* BB Should we set anything |
3268 | in SesInfo struct ? */ | 3325 | in SesInfo struct ? */ |
3269 | /* if (SecurityBlob2->MessageType != NtLm??) { | 3326 | /* if (SecurityBlob2->MessageType != NtLm??) { |
3270 | cFYI("Unexpected message type on auth response is %d")); | 3327 | cFYI("Unexpected message type on auth response is %d")); |
@@ -3487,12 +3544,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3487 | NTLMv2 password here) */ | 3544 | NTLMv2 password here) */ |
3488 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 3545 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
3489 | if ((extended_security & CIFSSEC_MAY_LANMAN) && | 3546 | if ((extended_security & CIFSSEC_MAY_LANMAN) && |
3490 | (ses->server->secType == LANMAN)) | 3547 | (ses->server->secType == LANMAN)) |
3491 | calc_lanman_hash(ses, bcc_ptr); | 3548 | calc_lanman_hash(tcon->password, ses->server->cryptKey, |
3549 | ses->server->secMode & | ||
3550 | SECMODE_PW_ENCRYPT ? true : false, | ||
3551 | bcc_ptr); | ||
3492 | else | 3552 | else |
3493 | #endif /* CIFS_WEAK_PW_HASH */ | 3553 | #endif /* CIFS_WEAK_PW_HASH */ |
3494 | SMBNTencrypt(ses->password, | 3554 | SMBNTencrypt(tcon->password, ses->server->cryptKey, |
3495 | ses->server->cryptKey, | ||
3496 | bcc_ptr); | 3555 | bcc_ptr); |
3497 | 3556 | ||
3498 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 3557 | bcc_ptr += CIFS_SESS_KEY_SIZE; |