| .. | .. | 
|---|
| 31 | 31 | #include <linux/utsname.h> | 
|---|
| 32 | 32 | #include <linux/slab.h> | 
|---|
| 33 | 33 | #include "cifs_spnego.h" | 
|---|
|  | 34 | +#include "smb2proto.h" | 
|---|
|  | 35 | + | 
|---|
|  | 36 | +bool | 
|---|
|  | 37 | +is_server_using_iface(struct TCP_Server_Info *server, | 
|---|
|  | 38 | +		      struct cifs_server_iface *iface) | 
|---|
|  | 39 | +{ | 
|---|
|  | 40 | +	struct sockaddr_in *i4 = (struct sockaddr_in *)&iface->sockaddr; | 
|---|
|  | 41 | +	struct sockaddr_in6 *i6 = (struct sockaddr_in6 *)&iface->sockaddr; | 
|---|
|  | 42 | +	struct sockaddr_in *s4 = (struct sockaddr_in *)&server->dstaddr; | 
|---|
|  | 43 | +	struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&server->dstaddr; | 
|---|
|  | 44 | + | 
|---|
|  | 45 | +	if (server->dstaddr.ss_family != iface->sockaddr.ss_family) | 
|---|
|  | 46 | +		return false; | 
|---|
|  | 47 | +	if (server->dstaddr.ss_family == AF_INET) { | 
|---|
|  | 48 | +		if (s4->sin_addr.s_addr != i4->sin_addr.s_addr) | 
|---|
|  | 49 | +			return false; | 
|---|
|  | 50 | +	} else if (server->dstaddr.ss_family == AF_INET6) { | 
|---|
|  | 51 | +		if (memcmp(&s6->sin6_addr, &i6->sin6_addr, | 
|---|
|  | 52 | +			   sizeof(i6->sin6_addr)) != 0) | 
|---|
|  | 53 | +			return false; | 
|---|
|  | 54 | +	} else { | 
|---|
|  | 55 | +		/* unknown family.. */ | 
|---|
|  | 56 | +		return false; | 
|---|
|  | 57 | +	} | 
|---|
|  | 58 | +	return true; | 
|---|
|  | 59 | +} | 
|---|
|  | 60 | + | 
|---|
|  | 61 | +bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface) | 
|---|
|  | 62 | +{ | 
|---|
|  | 63 | +	int i; | 
|---|
|  | 64 | + | 
|---|
|  | 65 | +	for (i = 0; i < ses->chan_count; i++) { | 
|---|
|  | 66 | +		if (is_server_using_iface(ses->chans[i].server, iface)) | 
|---|
|  | 67 | +			return true; | 
|---|
|  | 68 | +	} | 
|---|
|  | 69 | +	return false; | 
|---|
|  | 70 | +} | 
|---|
|  | 71 | + | 
|---|
|  | 72 | +/* returns number of channels added */ | 
|---|
|  | 73 | +int cifs_try_adding_channels(struct cifs_ses *ses) | 
|---|
|  | 74 | +{ | 
|---|
|  | 75 | +	int old_chan_count = ses->chan_count; | 
|---|
|  | 76 | +	int left = ses->chan_max - ses->chan_count; | 
|---|
|  | 77 | +	int i = 0; | 
|---|
|  | 78 | +	int rc = 0; | 
|---|
|  | 79 | +	int tries = 0; | 
|---|
|  | 80 | +	struct cifs_server_iface *ifaces = NULL; | 
|---|
|  | 81 | +	size_t iface_count; | 
|---|
|  | 82 | + | 
|---|
|  | 83 | +	if (left <= 0) { | 
|---|
|  | 84 | +		cifs_dbg(FYI, | 
|---|
|  | 85 | +			 "ses already at max_channels (%zu), nothing to open\n", | 
|---|
|  | 86 | +			 ses->chan_max); | 
|---|
|  | 87 | +		return 0; | 
|---|
|  | 88 | +	} | 
|---|
|  | 89 | + | 
|---|
|  | 90 | +	if (ses->server->dialect < SMB30_PROT_ID) { | 
|---|
|  | 91 | +		cifs_dbg(VFS, "multichannel is not supported on this protocol version, use 3.0 or above\n"); | 
|---|
|  | 92 | +		return 0; | 
|---|
|  | 93 | +	} | 
|---|
|  | 94 | + | 
|---|
|  | 95 | +	if (!(ses->server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL)) { | 
|---|
|  | 96 | +		cifs_dbg(VFS, "server %s does not support multichannel\n", ses->server->hostname); | 
|---|
|  | 97 | +		ses->chan_max = 1; | 
|---|
|  | 98 | +		return 0; | 
|---|
|  | 99 | +	} | 
|---|
|  | 100 | + | 
|---|
|  | 101 | +	/* | 
|---|
|  | 102 | +	 * Make a copy of the iface list at the time and use that | 
|---|
|  | 103 | +	 * instead so as to not hold the iface spinlock for opening | 
|---|
|  | 104 | +	 * channels | 
|---|
|  | 105 | +	 */ | 
|---|
|  | 106 | +	spin_lock(&ses->iface_lock); | 
|---|
|  | 107 | +	iface_count = ses->iface_count; | 
|---|
|  | 108 | +	if (iface_count <= 0) { | 
|---|
|  | 109 | +		spin_unlock(&ses->iface_lock); | 
|---|
|  | 110 | +		cifs_dbg(VFS, "no iface list available to open channels\n"); | 
|---|
|  | 111 | +		return 0; | 
|---|
|  | 112 | +	} | 
|---|
|  | 113 | +	ifaces = kmemdup(ses->iface_list, iface_count*sizeof(*ifaces), | 
|---|
|  | 114 | +			 GFP_ATOMIC); | 
|---|
|  | 115 | +	if (!ifaces) { | 
|---|
|  | 116 | +		spin_unlock(&ses->iface_lock); | 
|---|
|  | 117 | +		return 0; | 
|---|
|  | 118 | +	} | 
|---|
|  | 119 | +	spin_unlock(&ses->iface_lock); | 
|---|
|  | 120 | + | 
|---|
|  | 121 | +	/* | 
|---|
|  | 122 | +	 * Keep connecting to same, fastest, iface for all channels as | 
|---|
|  | 123 | +	 * long as its RSS. Try next fastest one if not RSS or channel | 
|---|
|  | 124 | +	 * creation fails. | 
|---|
|  | 125 | +	 */ | 
|---|
|  | 126 | +	while (left > 0) { | 
|---|
|  | 127 | +		struct cifs_server_iface *iface; | 
|---|
|  | 128 | + | 
|---|
|  | 129 | +		tries++; | 
|---|
|  | 130 | +		if (tries > 3*ses->chan_max) { | 
|---|
|  | 131 | +			cifs_dbg(FYI, "too many channel open attempts (%d channels left to open)\n", | 
|---|
|  | 132 | +				 left); | 
|---|
|  | 133 | +			break; | 
|---|
|  | 134 | +		} | 
|---|
|  | 135 | + | 
|---|
|  | 136 | +		iface = &ifaces[i]; | 
|---|
|  | 137 | +		if (is_ses_using_iface(ses, iface) && !iface->rss_capable) { | 
|---|
|  | 138 | +			i = (i+1) % iface_count; | 
|---|
|  | 139 | +			continue; | 
|---|
|  | 140 | +		} | 
|---|
|  | 141 | + | 
|---|
|  | 142 | +		rc = cifs_ses_add_channel(ses, iface); | 
|---|
|  | 143 | +		if (rc) { | 
|---|
|  | 144 | +			cifs_dbg(FYI, "failed to open extra channel on iface#%d rc=%d\n", | 
|---|
|  | 145 | +				 i, rc); | 
|---|
|  | 146 | +			i = (i+1) % iface_count; | 
|---|
|  | 147 | +			continue; | 
|---|
|  | 148 | +		} | 
|---|
|  | 149 | + | 
|---|
|  | 150 | +		cifs_dbg(FYI, "successfully opened new channel on iface#%d\n", | 
|---|
|  | 151 | +			 i); | 
|---|
|  | 152 | +		left--; | 
|---|
|  | 153 | +	} | 
|---|
|  | 154 | + | 
|---|
|  | 155 | +	kfree(ifaces); | 
|---|
|  | 156 | +	return ses->chan_count - old_chan_count; | 
|---|
|  | 157 | +} | 
|---|
|  | 158 | + | 
|---|
|  | 159 | +/* | 
|---|
|  | 160 | + * If server is a channel of ses, return the corresponding enclosing | 
|---|
|  | 161 | + * cifs_chan otherwise return NULL. | 
|---|
|  | 162 | + */ | 
|---|
|  | 163 | +struct cifs_chan * | 
|---|
|  | 164 | +cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server) | 
|---|
|  | 165 | +{ | 
|---|
|  | 166 | +	int i; | 
|---|
|  | 167 | + | 
|---|
|  | 168 | +	for (i = 0; i < ses->chan_count; i++) { | 
|---|
|  | 169 | +		if (ses->chans[i].server == server) | 
|---|
|  | 170 | +			return &ses->chans[i]; | 
|---|
|  | 171 | +	} | 
|---|
|  | 172 | +	return NULL; | 
|---|
|  | 173 | +} | 
|---|
|  | 174 | + | 
|---|
|  | 175 | +int | 
|---|
|  | 176 | +cifs_ses_add_channel(struct cifs_ses *ses, struct cifs_server_iface *iface) | 
|---|
|  | 177 | +{ | 
|---|
|  | 178 | +	struct cifs_chan *chan; | 
|---|
|  | 179 | +	struct smb_vol vol = {NULL}; | 
|---|
|  | 180 | +	static const char unc_fmt[] = "\\%s\\foo"; | 
|---|
|  | 181 | +	char unc[sizeof(unc_fmt)+SERVER_NAME_LEN_WITH_NULL] = {0}; | 
|---|
|  | 182 | +	struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr; | 
|---|
|  | 183 | +	struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr; | 
|---|
|  | 184 | +	int rc; | 
|---|
|  | 185 | +	unsigned int xid = get_xid(); | 
|---|
|  | 186 | + | 
|---|
|  | 187 | +	if (iface->sockaddr.ss_family == AF_INET) | 
|---|
|  | 188 | +		cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI4)\n", | 
|---|
|  | 189 | +			 ses, iface->speed, iface->rdma_capable ? "yes" : "no", | 
|---|
|  | 190 | +			 &ipv4->sin_addr); | 
|---|
|  | 191 | +	else | 
|---|
|  | 192 | +		cifs_dbg(FYI, "adding channel to ses %p (speed:%zu bps rdma:%s ip:%pI4)\n", | 
|---|
|  | 193 | +			 ses, iface->speed, iface->rdma_capable ? "yes" : "no", | 
|---|
|  | 194 | +			 &ipv6->sin6_addr); | 
|---|
|  | 195 | + | 
|---|
|  | 196 | +	/* | 
|---|
|  | 197 | +	 * Setup a smb_vol with mostly the same info as the existing | 
|---|
|  | 198 | +	 * session and overwrite it with the requested iface data. | 
|---|
|  | 199 | +	 * | 
|---|
|  | 200 | +	 * We need to setup at least the fields used for negprot and | 
|---|
|  | 201 | +	 * sesssetup. | 
|---|
|  | 202 | +	 * | 
|---|
|  | 203 | +	 * We only need the volume here, so we can reuse memory from | 
|---|
|  | 204 | +	 * the session and server without caring about memory | 
|---|
|  | 205 | +	 * management. | 
|---|
|  | 206 | +	 */ | 
|---|
|  | 207 | + | 
|---|
|  | 208 | +	/* Always make new connection for now (TODO?) */ | 
|---|
|  | 209 | +	vol.nosharesock = true; | 
|---|
|  | 210 | + | 
|---|
|  | 211 | +	/* Auth */ | 
|---|
|  | 212 | +	vol.domainauto = ses->domainAuto; | 
|---|
|  | 213 | +	vol.domainname = ses->domainName; | 
|---|
|  | 214 | +	vol.username = ses->user_name; | 
|---|
|  | 215 | +	vol.password = ses->password; | 
|---|
|  | 216 | +	vol.sectype = ses->sectype; | 
|---|
|  | 217 | +	vol.sign = ses->sign; | 
|---|
|  | 218 | + | 
|---|
|  | 219 | +	/* UNC and paths */ | 
|---|
|  | 220 | +	/* XXX: Use ses->server->hostname? */ | 
|---|
|  | 221 | +	sprintf(unc, unc_fmt, ses->serverName); | 
|---|
|  | 222 | +	vol.UNC = unc; | 
|---|
|  | 223 | +	vol.prepath = ""; | 
|---|
|  | 224 | + | 
|---|
|  | 225 | +	/* Reuse same version as master connection */ | 
|---|
|  | 226 | +	vol.vals = ses->server->vals; | 
|---|
|  | 227 | +	vol.ops = ses->server->ops; | 
|---|
|  | 228 | + | 
|---|
|  | 229 | +	vol.noblocksnd = ses->server->noblocksnd; | 
|---|
|  | 230 | +	vol.noautotune = ses->server->noautotune; | 
|---|
|  | 231 | +	vol.sockopt_tcp_nodelay = ses->server->tcp_nodelay; | 
|---|
|  | 232 | +	vol.echo_interval = ses->server->echo_interval / HZ; | 
|---|
|  | 233 | +	vol.max_credits = ses->server->max_credits; | 
|---|
|  | 234 | + | 
|---|
|  | 235 | +	/* | 
|---|
|  | 236 | +	 * This will be used for encoding/decoding user/domain/pw | 
|---|
|  | 237 | +	 * during sess setup auth. | 
|---|
|  | 238 | +	 * | 
|---|
|  | 239 | +	 * XXX: We use the default for simplicity but the proper way | 
|---|
|  | 240 | +	 * would be to use the one that ses used, which is not | 
|---|
|  | 241 | +	 * stored. This might break when dealing with non-ascii | 
|---|
|  | 242 | +	 * strings. | 
|---|
|  | 243 | +	 */ | 
|---|
|  | 244 | +	vol.local_nls = load_nls_default(); | 
|---|
|  | 245 | + | 
|---|
|  | 246 | +	/* Use RDMA if possible */ | 
|---|
|  | 247 | +	vol.rdma = iface->rdma_capable; | 
|---|
|  | 248 | +	memcpy(&vol.dstaddr, &iface->sockaddr, sizeof(struct sockaddr_storage)); | 
|---|
|  | 249 | + | 
|---|
|  | 250 | +	/* reuse master con client guid */ | 
|---|
|  | 251 | +	memcpy(&vol.client_guid, ses->server->client_guid, | 
|---|
|  | 252 | +	       SMB2_CLIENT_GUID_SIZE); | 
|---|
|  | 253 | +	vol.use_client_guid = true; | 
|---|
|  | 254 | + | 
|---|
|  | 255 | +	mutex_lock(&ses->session_mutex); | 
|---|
|  | 256 | + | 
|---|
|  | 257 | +	chan = ses->binding_chan = &ses->chans[ses->chan_count]; | 
|---|
|  | 258 | +	chan->server = cifs_get_tcp_session(&vol); | 
|---|
|  | 259 | +	if (IS_ERR(chan->server)) { | 
|---|
|  | 260 | +		rc = PTR_ERR(chan->server); | 
|---|
|  | 261 | +		chan->server = NULL; | 
|---|
|  | 262 | +		goto out; | 
|---|
|  | 263 | +	} | 
|---|
|  | 264 | +	spin_lock(&cifs_tcp_ses_lock); | 
|---|
|  | 265 | +	chan->server->is_channel = true; | 
|---|
|  | 266 | +	spin_unlock(&cifs_tcp_ses_lock); | 
|---|
|  | 267 | + | 
|---|
|  | 268 | +	/* | 
|---|
|  | 269 | +	 * We need to allocate the server crypto now as we will need | 
|---|
|  | 270 | +	 * to sign packets before we generate the channel signing key | 
|---|
|  | 271 | +	 * (we sign with the session key) | 
|---|
|  | 272 | +	 */ | 
|---|
|  | 273 | +	rc = smb311_crypto_shash_allocate(chan->server); | 
|---|
|  | 274 | +	if (rc) { | 
|---|
|  | 275 | +		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); | 
|---|
|  | 276 | +		goto out; | 
|---|
|  | 277 | +	} | 
|---|
|  | 278 | + | 
|---|
|  | 279 | +	ses->binding = true; | 
|---|
|  | 280 | +	rc = cifs_negotiate_protocol(xid, ses); | 
|---|
|  | 281 | +	if (rc) | 
|---|
|  | 282 | +		goto out; | 
|---|
|  | 283 | + | 
|---|
|  | 284 | +	rc = cifs_setup_session(xid, ses, vol.local_nls); | 
|---|
|  | 285 | +	if (rc) | 
|---|
|  | 286 | +		goto out; | 
|---|
|  | 287 | + | 
|---|
|  | 288 | +	/* success, put it on the list | 
|---|
|  | 289 | +	 * XXX: sharing ses between 2 tcp servers is not possible, the | 
|---|
|  | 290 | +	 * way "internal" linked lists works in linux makes element | 
|---|
|  | 291 | +	 * only able to belong to one list | 
|---|
|  | 292 | +	 * | 
|---|
|  | 293 | +	 * the binding session is already established so the rest of | 
|---|
|  | 294 | +	 * the code should be able to look it up, no need to add the | 
|---|
|  | 295 | +	 * ses to the new server. | 
|---|
|  | 296 | +	 */ | 
|---|
|  | 297 | + | 
|---|
|  | 298 | +	ses->chan_count++; | 
|---|
|  | 299 | +	atomic_set(&ses->chan_seq, 0); | 
|---|
|  | 300 | +out: | 
|---|
|  | 301 | +	ses->binding = false; | 
|---|
|  | 302 | +	ses->binding_chan = NULL; | 
|---|
|  | 303 | +	mutex_unlock(&ses->session_mutex); | 
|---|
|  | 304 | + | 
|---|
|  | 305 | +	if (rc && chan->server) | 
|---|
|  | 306 | +		cifs_put_tcp_session(chan->server, 0); | 
|---|
|  | 307 | +	unload_nls(vol.local_nls); | 
|---|
|  | 308 | + | 
|---|
|  | 309 | +	free_xid(xid); | 
|---|
|  | 310 | +	return rc; | 
|---|
|  | 311 | +} | 
|---|
| 34 | 312 |  | 
|---|
| 35 | 313 | static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB) | 
|---|
| 36 | 314 | { | 
|---|
| .. | .. | 
|---|
| 159 | 437 | const struct nls_table *nls_cp) | 
|---|
| 160 | 438 | { | 
|---|
| 161 | 439 | char *bcc_ptr = *pbcc_area; | 
|---|
|  | 440 | +	int len; | 
|---|
| 162 | 441 |  | 
|---|
| 163 | 442 | /* copy user */ | 
|---|
| 164 | 443 | /* BB what about null user mounts - check that we do this BB */ | 
|---|
| 165 | 444 | /* copy user */ | 
|---|
| 166 | 445 | if (ses->user_name != NULL) { | 
|---|
| 167 |  | -		strncpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN); | 
|---|
| 168 |  | -		bcc_ptr += strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN); | 
|---|
|  | 446 | +		len = strscpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN); | 
|---|
|  | 447 | +		if (WARN_ON_ONCE(len < 0)) | 
|---|
|  | 448 | +			len = CIFS_MAX_USERNAME_LEN - 1; | 
|---|
|  | 449 | +		bcc_ptr += len; | 
|---|
| 169 | 450 | } | 
|---|
| 170 | 451 | /* else null user mount */ | 
|---|
| 171 | 452 | *bcc_ptr = 0; | 
|---|
| .. | .. | 
|---|
| 173 | 454 |  | 
|---|
| 174 | 455 | /* copy domain */ | 
|---|
| 175 | 456 | if (ses->domainName != NULL) { | 
|---|
| 176 |  | -		strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); | 
|---|
| 177 |  | -		bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN); | 
|---|
|  | 457 | +		len = strscpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN); | 
|---|
|  | 458 | +		if (WARN_ON_ONCE(len < 0)) | 
|---|
|  | 459 | +			len = CIFS_MAX_DOMAINNAME_LEN - 1; | 
|---|
|  | 460 | +		bcc_ptr += len; | 
|---|
| 178 | 461 | } /* else we will send a null domain name | 
|---|
| 179 | 462 | so the server will default to its own domain */ | 
|---|
| 180 | 463 | *bcc_ptr = 0; | 
|---|
| .. | .. | 
|---|
| 242 | 525 |  | 
|---|
| 243 | 526 | kfree(ses->serverOS); | 
|---|
| 244 | 527 |  | 
|---|
| 245 |  | -	ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | 
|---|
|  | 528 | +	ses->serverOS = kmalloc(len + 1, GFP_KERNEL); | 
|---|
| 246 | 529 | if (ses->serverOS) { | 
|---|
| 247 |  | -		strncpy(ses->serverOS, bcc_ptr, len); | 
|---|
|  | 530 | +		memcpy(ses->serverOS, bcc_ptr, len); | 
|---|
|  | 531 | +		ses->serverOS[len] = 0; | 
|---|
| 248 | 532 | if (strncmp(ses->serverOS, "OS/2", 4) == 0) | 
|---|
| 249 | 533 | cifs_dbg(FYI, "OS/2 server\n"); | 
|---|
| 250 | 534 | } | 
|---|
| .. | .. | 
|---|
| 258 | 542 |  | 
|---|
| 259 | 543 | kfree(ses->serverNOS); | 
|---|
| 260 | 544 |  | 
|---|
| 261 |  | -	ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); | 
|---|
| 262 |  | -	if (ses->serverNOS) | 
|---|
| 263 |  | -		strncpy(ses->serverNOS, bcc_ptr, len); | 
|---|
|  | 545 | +	ses->serverNOS = kmalloc(len + 1, GFP_KERNEL); | 
|---|
|  | 546 | +	if (ses->serverNOS) { | 
|---|
|  | 547 | +		memcpy(ses->serverNOS, bcc_ptr, len); | 
|---|
|  | 548 | +		ses->serverNOS[len] = 0; | 
|---|
|  | 549 | +	} | 
|---|
| 264 | 550 |  | 
|---|
| 265 | 551 | bcc_ptr += len + 1; | 
|---|
| 266 | 552 | bleft -= len + 1; | 
|---|
| .. | .. | 
|---|
| 310 | 596 | tioffset = le32_to_cpu(pblob->TargetInfoArray.BufferOffset); | 
|---|
| 311 | 597 | tilen = le16_to_cpu(pblob->TargetInfoArray.Length); | 
|---|
| 312 | 598 | if (tioffset > blob_len || tioffset + tilen > blob_len) { | 
|---|
| 313 |  | -		cifs_dbg(VFS, "tioffset + tilen too high %u + %u", | 
|---|
| 314 |  | -			tioffset, tilen); | 
|---|
|  | 599 | +		cifs_dbg(VFS, "tioffset + tilen too high %u + %u\n", | 
|---|
|  | 600 | +			 tioffset, tilen); | 
|---|
| 315 | 601 | return -EINVAL; | 
|---|
| 316 | 602 | } | 
|---|
| 317 | 603 | if (tilen) { | 
|---|
| 318 | 604 | ses->auth_key.response = kmemdup(bcc_ptr + tioffset, tilen, | 
|---|
| 319 | 605 | GFP_KERNEL); | 
|---|
| 320 | 606 | if (!ses->auth_key.response) { | 
|---|
| 321 |  | -			cifs_dbg(VFS, "Challenge target info alloc failure"); | 
|---|
|  | 607 | +			cifs_dbg(VFS, "Challenge target info alloc failure\n"); | 
|---|
| 322 | 608 | return -ENOMEM; | 
|---|
| 323 | 609 | } | 
|---|
| 324 | 610 | ses->auth_key.len = tilen; | 
|---|
| .. | .. | 
|---|
| 334 | 620 | void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | 
|---|
| 335 | 621 | struct cifs_ses *ses) | 
|---|
| 336 | 622 | { | 
|---|
|  | 623 | +	struct TCP_Server_Info *server = cifs_ses_server(ses); | 
|---|
| 337 | 624 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | 
|---|
| 338 | 625 | __u32 flags; | 
|---|
| 339 | 626 |  | 
|---|
| .. | .. | 
|---|
| 346 | 633 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 
|---|
| 347 | 634 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC | | 
|---|
| 348 | 635 | NTLMSSP_NEGOTIATE_SEAL; | 
|---|
| 349 |  | -	if (ses->server->sign) | 
|---|
|  | 636 | +	if (server->sign) | 
|---|
| 350 | 637 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 
|---|
| 351 |  | -	if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) | 
|---|
|  | 638 | +	if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess) | 
|---|
| 352 | 639 | flags |= NTLMSSP_NEGOTIATE_KEY_XCH; | 
|---|
| 353 | 640 |  | 
|---|
| 354 | 641 | sec_blob->NegotiateFlags = cpu_to_le32(flags); | 
|---|
| .. | .. | 
|---|
| 519 | 806 | if ((server->sec_kerberos || server->sec_mskerberos) && | 
|---|
| 520 | 807 | (global_secflags & CIFSSEC_MAY_KRB5)) | 
|---|
| 521 | 808 | return Kerberos; | 
|---|
| 522 |  | -			/* Fallthrough */ | 
|---|
|  | 809 | +			fallthrough; | 
|---|
| 523 | 810 | default: | 
|---|
| 524 | 811 | return Unspecified; | 
|---|
| 525 | 812 | } | 
|---|
| .. | .. | 
|---|
| 534 | 821 | if (global_secflags & CIFSSEC_MAY_NTLM) | 
|---|
| 535 | 822 | return NTLM; | 
|---|
| 536 | 823 | default: | 
|---|
| 537 |  | -			/* Fallthrough to attempt LANMAN authentication next */ | 
|---|
| 538 | 824 | break; | 
|---|
| 539 | 825 | } | 
|---|
|  | 826 | +		fallthrough;	/* to attempt LANMAN authentication next */ | 
|---|
| 540 | 827 | case CIFS_NEGFLAVOR_LANMAN: | 
|---|
| 541 | 828 | switch (requested) { | 
|---|
| 542 | 829 | case LANMAN: | 
|---|
| .. | .. | 
|---|
| 544 | 831 | case Unspecified: | 
|---|
| 545 | 832 | if (global_secflags & CIFSSEC_MAY_LANMAN) | 
|---|
| 546 | 833 | return LANMAN; | 
|---|
| 547 |  | -			/* Fallthrough */ | 
|---|
|  | 834 | +			fallthrough; | 
|---|
| 548 | 835 | default: | 
|---|
| 549 | 836 | return Unspecified; | 
|---|
| 550 | 837 | } | 
|---|
| .. | .. | 
|---|
| 659 | 946 | struct kvec rsp_iov = { NULL, 0 }; | 
|---|
| 660 | 947 |  | 
|---|
| 661 | 948 | count = sess_data->iov[1].iov_len + sess_data->iov[2].iov_len; | 
|---|
| 662 |  | -	smb_buf->smb_buf_length = | 
|---|
| 663 |  | -		cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count); | 
|---|
|  | 949 | +	be32_add_cpu(&smb_buf->smb_buf_length, count); | 
|---|
| 664 | 950 | put_bcc(count, smb_buf); | 
|---|
| 665 | 951 |  | 
|---|
| 666 | 952 | rc = SendReceive2(sess_data->xid, sess_data->ses, | 
|---|
| .. | .. | 
|---|
| 690 | 976 | char *bcc_ptr; | 
|---|
| 691 | 977 | struct cifs_ses *ses = sess_data->ses; | 
|---|
| 692 | 978 | char lnm_session_key[CIFS_AUTH_RESP_SIZE]; | 
|---|
| 693 |  | -	__u32 capabilities; | 
|---|
| 694 | 979 | __u16 bytes_remaining; | 
|---|
| 695 | 980 |  | 
|---|
| 696 | 981 | /* lanman 2 style sessionsetup */ | 
|---|
| .. | .. | 
|---|
| 701 | 986 |  | 
|---|
| 702 | 987 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | 
|---|
| 703 | 988 | bcc_ptr = sess_data->iov[2].iov_base; | 
|---|
| 704 |  | -	capabilities = cifs_ssetup_hdr(ses, pSMB); | 
|---|
|  | 989 | +	(void)cifs_ssetup_hdr(ses, pSMB); | 
|---|
| 705 | 990 |  | 
|---|
| 706 | 991 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; | 
|---|
| 707 | 992 |  | 
|---|
| .. | .. | 
|---|
| 711 | 996 |  | 
|---|
| 712 | 997 | /* Calculate hash with password and copy into bcc_ptr. | 
|---|
| 713 | 998 | * Encryption Key (stored as in cryptkey) gets used if the | 
|---|
| 714 |  | -		 * security mode bit in Negottiate Protocol response states | 
|---|
|  | 999 | +		 * security mode bit in Negotiate Protocol response states | 
|---|
| 715 | 1000 | * to use challenge/response method (i.e. Password bit is 1). | 
|---|
| 716 | 1001 | */ | 
|---|
| 717 | 1002 | rc = calc_lanman_hash(ses->password, ses->server->cryptkey, | 
|---|
| .. | .. | 
|---|
| 1044 | 1329 | * sending us a response in an expected form | 
|---|
| 1045 | 1330 | */ | 
|---|
| 1046 | 1331 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { | 
|---|
| 1047 |  | -		cifs_dbg(VFS, | 
|---|
| 1048 |  | -		  "incorrect version of cifs.upcall (expected %d but got %d)", | 
|---|
| 1049 |  | -			      CIFS_SPNEGO_UPCALL_VERSION, msg->version); | 
|---|
|  | 1332 | +		cifs_dbg(VFS, "incorrect version of cifs.upcall (expected %d but got %d)\n", | 
|---|
|  | 1333 | +			 CIFS_SPNEGO_UPCALL_VERSION, msg->version); | 
|---|
| 1050 | 1334 | rc = -EKEYREJECTED; | 
|---|
| 1051 | 1335 | goto out_put_spnego_key; | 
|---|
| 1052 | 1336 | } | 
|---|
| .. | .. | 
|---|
| 1054 | 1338 | ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len, | 
|---|
| 1055 | 1339 | GFP_KERNEL); | 
|---|
| 1056 | 1340 | if (!ses->auth_key.response) { | 
|---|
| 1057 |  | -		cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory", | 
|---|
| 1058 |  | -				msg->sesskey_len); | 
|---|
|  | 1341 | +		cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory\n", | 
|---|
|  | 1342 | +			 msg->sesskey_len); | 
|---|
| 1059 | 1343 | rc = -ENOMEM; | 
|---|
| 1060 | 1344 | goto out_put_spnego_key; | 
|---|
| 1061 | 1345 | } | 
|---|
| .. | .. | 
|---|
| 1154 | 1438 | static int | 
|---|
| 1155 | 1439 | _sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data) | 
|---|
| 1156 | 1440 | { | 
|---|
| 1157 |  | -	struct smb_hdr *smb_buf; | 
|---|
| 1158 | 1441 | SESSION_SETUP_ANDX *pSMB; | 
|---|
| 1159 | 1442 | struct cifs_ses *ses = sess_data->ses; | 
|---|
| 1160 | 1443 | __u32 capabilities; | 
|---|
| 1161 | 1444 | char *bcc_ptr; | 
|---|
| 1162 | 1445 |  | 
|---|
| 1163 | 1446 | pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; | 
|---|
| 1164 |  | -	smb_buf = (struct smb_hdr *)pSMB; | 
|---|
| 1165 | 1447 |  | 
|---|
| 1166 | 1448 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 
|---|
| 1167 | 1449 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 
|---|
| .. | .. | 
|---|
| 1400 | 1682 | type = cifs_select_sectype(ses->server, ses->sectype); | 
|---|
| 1401 | 1683 | cifs_dbg(FYI, "sess setup type %d\n", type); | 
|---|
| 1402 | 1684 | if (type == Unspecified) { | 
|---|
| 1403 |  | -		cifs_dbg(VFS, | 
|---|
| 1404 |  | -			"Unable to select appropriate authentication method!"); | 
|---|
|  | 1685 | +		cifs_dbg(VFS, "Unable to select appropriate authentication method!\n"); | 
|---|
| 1405 | 1686 | return -EINVAL; | 
|---|
| 1406 | 1687 | } | 
|---|
| 1407 | 1688 |  | 
|---|
| .. | .. | 
|---|
| 1431 | 1712 | #else | 
|---|
| 1432 | 1713 | cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n"); | 
|---|
| 1433 | 1714 | return -ENOSYS; | 
|---|
| 1434 |  | -		break; | 
|---|
| 1435 | 1715 | #endif /* CONFIG_CIFS_UPCALL */ | 
|---|
| 1436 | 1716 | case RawNTLMSSP: | 
|---|
| 1437 | 1717 | sess_data->func = sess_auth_rawntlmssp_negotiate; | 
|---|