fs/smb/client/cifsencrypt.c

Source file repositories/reference/linux-study-clean/fs/smb/client/cifsencrypt.c

File Facts

System
Linux kernel
Corpus path
fs/smb/client/cifsencrypt.c
Extension
.c
Size
13439 bytes
Lines
515
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!IS_ALIGNED(len, sizeof(__le16))) {
			cifs_dbg(VFS | ONCE, "%s: bad length(%u) for type %u\n",
				 __func__, len, type);
			continue;
		}
		nlen = len / sizeof(__le16);
		if (nlen <= maxlen) {
			++nlen;
			*name = kmalloc(nlen, GFP_KERNEL);
			if (!*name)
				return -ENOMEM;
			cifs_from_utf16(*name, AV_DATA_PTR(av), nlen,
					len, nlsc, NO_MAP_UNI_RSVD);
			break;
		}
	}
	return 0;
}

/* Server has provided av pairs/target info in the type 2 challenge
 * packet and we have plucked it and stored within smb session.
 * We parse that blob here to find the server given timestamp
 * as part of ntlmv2 authentication (or local current time as
 * default in case of failure)
 */
static __le64 find_timestamp(struct cifs_ses *ses)
{
	struct ntlmssp2_name *av;
	struct timespec64 ts;

	av_for_each_entry(ses, av) {
		if (AV_TYPE(av) == NTLMSSP_AV_TIMESTAMP &&
		    AV_LEN(av) == sizeof(u64))
			return *((__le64 *)AV_DATA_PTR(av));
	}
	ktime_get_real_ts64(&ts);
	return cpu_to_le64(cifs_UnixTimeToNT(ts));
}

static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
			    const struct nls_table *nls_cp)
{
	int len;
	char nt_hash[CIFS_NTHASH_SIZE];
	struct hmac_md5_ctx hmac_ctx;
	__le16 *user;
	wchar_t *domain;
	wchar_t *server;

	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash, nls_cp);

	hmac_md5_init_usingrawkey(&hmac_ctx, nt_hash, CIFS_NTHASH_SIZE);

	/* convert ses->user_name to unicode */
	len = ses->user_name ? strlen(ses->user_name) : 0;
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
	if (user == NULL)
		return -ENOMEM;

	if (len) {
		len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
		UniStrupr(user);
	} else {
		*(u16 *)user = 0;
	}

	hmac_md5_update(&hmac_ctx, (const u8 *)user, 2 * len);
	kfree(user);

	/* convert ses->domainName to unicode and uppercase */
	if (ses->domainName) {
		len = strlen(ses->domainName);

		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (domain == NULL)
			return -ENOMEM;

		len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len,
				      nls_cp);
		hmac_md5_update(&hmac_ctx, (const u8 *)domain, 2 * len);
		kfree(domain);
	} else {
		/* We use ses->ip_addr if no domain name available */
		len = strlen(ses->ip_addr);

		server = kmalloc(2 + (len * 2), GFP_KERNEL);
		if (server == NULL)
			return -ENOMEM;

Annotation

Implementation Notes