Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: LGPL-2.1
  2/*
  3 *   SPNEGO upcall management for CIFS
  4 *
  5 *   Copyright (c) 2007 Red Hat, Inc.
  6 *   Author(s): Jeff Layton (jlayton@redhat.com)
  7 *
 
 
 
 
 
 
 
 
 
 
 
 
 
  8 */
  9
 10#include <linux/list.h>
 11#include <linux/slab.h>
 12#include <linux/string.h>
 13#include <keys/user-type.h>
 14#include <linux/key-type.h>
 15#include <linux/keyctl.h>
 16#include <linux/inet.h>
 17#include "cifsglob.h"
 18#include "cifs_spnego.h"
 19#include "cifs_debug.h"
 20#include "cifsproto.h"
 21static const struct cred *spnego_cred;
 22
 23/* create a new cifs key */
 24static int
 25cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 26{
 27	char *payload;
 28	int ret;
 29
 30	ret = -ENOMEM;
 31	payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
 32	if (!payload)
 33		goto error;
 34
 35	/* attach the data */
 36	key->payload.data[0] = payload;
 
 37	ret = 0;
 38
 39error:
 40	return ret;
 41}
 42
 43static void
 44cifs_spnego_key_destroy(struct key *key)
 45{
 46	kfree(key->payload.data[0]);
 47}
 48
 49
 50/*
 51 * keytype for CIFS spnego keys
 52 */
 53struct key_type cifs_spnego_key_type = {
 54	.name		= "cifs.spnego",
 55	.instantiate	= cifs_spnego_key_instantiate,
 
 56	.destroy	= cifs_spnego_key_destroy,
 57	.describe	= user_describe,
 58};
 59
 60/* length of longest version string e.g.  strlen("ver=0xFF") */
 61#define MAX_VER_STR_LEN		8
 62
 63/* length of longest security mechanism name, eg in future could have
 64 * strlen(";sec=ntlmsspi") */
 65#define MAX_MECH_STR_LEN	13
 66
 67/* strlen of "host=" */
 68#define HOST_KEY_LEN		5
 69
 70/* strlen of ";ip4=" or ";ip6=" */
 71#define IP_KEY_LEN		5
 72
 73/* strlen of ";uid=0x" */
 74#define UID_KEY_LEN		7
 75
 76/* strlen of ";creduid=0x" */
 77#define CREDUID_KEY_LEN		11
 78
 79/* strlen of ";user=" */
 80#define USER_KEY_LEN		6
 81
 82/* strlen of ";pid=0x" */
 83#define PID_KEY_LEN		7
 84
 85/* get a key struct with a SPNEGO security blob, suitable for session setup */
 86struct key *
 87cifs_get_spnego_key(struct cifs_ses *sesInfo,
 88		    struct TCP_Server_Info *server)
 89{
 
 90	struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
 91	struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
 92	char *description, *dp;
 93	size_t desc_len;
 94	struct key *spnego_key;
 95	const char *hostname = server->hostname;
 96	const struct cred *saved_cred;
 97
 98	/* length of fields (with semicolons): ver=0xyz ip4=ipaddress
 99	   host=hostname sec=mechanism uid=0xFF user=username */
100	desc_len = MAX_VER_STR_LEN +
101		   HOST_KEY_LEN + strlen(hostname) +
102		   IP_KEY_LEN + INET6_ADDRSTRLEN +
103		   MAX_MECH_STR_LEN +
104		   UID_KEY_LEN + (sizeof(uid_t) * 2) +
105		   CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
106		   PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
107
108	if (sesInfo->user_name)
109		desc_len += USER_KEY_LEN + strlen(sesInfo->user_name);
110
111	spnego_key = ERR_PTR(-ENOMEM);
112	description = kzalloc(desc_len, GFP_KERNEL);
113	if (description == NULL)
114		goto out;
115
116	dp = description;
117	/* start with version and hostname portion of UNC string */
118	spnego_key = ERR_PTR(-EINVAL);
119	sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
120		hostname);
121	dp = description + strlen(description);
122
123	/* add the server address */
124	if (server->dstaddr.ss_family == AF_INET)
125		sprintf(dp, "ip4=%pI4", &sa->sin_addr);
126	else if (server->dstaddr.ss_family == AF_INET6)
127		sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
128	else
129		goto out;
130
131	dp = description + strlen(description);
132
133	/* for now, only sec=krb5 and sec=mskrb5 are valid */
134	if (server->sec_kerberos)
135		sprintf(dp, ";sec=krb5");
136	else if (server->sec_mskerberos)
137		sprintf(dp, ";sec=mskrb5");
138	else {
139		cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
140		sprintf(dp, ";sec=krb5");
141	}
142
143	dp = description + strlen(description);
144	sprintf(dp, ";uid=0x%x",
145		from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
146
147	dp = description + strlen(description);
148	sprintf(dp, ";creduid=0x%x",
149		from_kuid_munged(&init_user_ns, sesInfo->cred_uid));
150
151	if (sesInfo->user_name) {
152		dp = description + strlen(description);
153		sprintf(dp, ";user=%s", sesInfo->user_name);
154	}
155
156	dp = description + strlen(description);
157	sprintf(dp, ";pid=0x%x", current->pid);
158
159	cifs_dbg(FYI, "key description = %s\n", description);
160	saved_cred = override_creds(spnego_cred);
161	spnego_key = request_key(&cifs_spnego_key_type, description, "");
162	revert_creds(saved_cred);
163
164#ifdef CONFIG_CIFS_DEBUG2
165	if (cifsFYI && !IS_ERR(spnego_key)) {
166		struct cifs_spnego_msg *msg = spnego_key->payload.data[0];
167		cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
168				msg->secblob_len + msg->sesskey_len));
169	}
170#endif /* CONFIG_CIFS_DEBUG2 */
171
172out:
173	kfree(description);
174	return spnego_key;
175}
176
177int
178init_cifs_spnego(void)
179{
180	struct cred *cred;
181	struct key *keyring;
182	int ret;
183
184	cifs_dbg(FYI, "Registering the %s key type\n",
185		 cifs_spnego_key_type.name);
186
187	/*
188	 * Create an override credential set with special thread keyring for
189	 * spnego upcalls.
190	 */
191
192	cred = prepare_kernel_cred(&init_task);
193	if (!cred)
194		return -ENOMEM;
195
196	keyring = keyring_alloc(".cifs_spnego",
197				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
198				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
199				KEY_USR_VIEW | KEY_USR_READ,
200				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
201	if (IS_ERR(keyring)) {
202		ret = PTR_ERR(keyring);
203		goto failed_put_cred;
204	}
205
206	ret = register_key_type(&cifs_spnego_key_type);
207	if (ret < 0)
208		goto failed_put_key;
209
210	/*
211	 * instruct request_key() to use this special keyring as a cache for
212	 * the results it looks up
213	 */
214	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
215	cred->thread_keyring = keyring;
216	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
217	spnego_cred = cred;
218
219	cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
220	return 0;
221
222failed_put_key:
223	key_put(keyring);
224failed_put_cred:
225	put_cred(cred);
226	return ret;
227}
228
229void
230exit_cifs_spnego(void)
231{
232	key_revoke(spnego_cred->thread_keyring);
233	unregister_key_type(&cifs_spnego_key_type);
234	put_cred(spnego_cred);
235	cifs_dbg(FYI, "Unregistered %s key type\n", cifs_spnego_key_type.name);
236}
v3.5.6
 
  1/*
  2 *   fs/cifs/cifs_spnego.c -- SPNEGO upcall management for CIFS
  3 *
  4 *   Copyright (c) 2007 Red Hat, Inc.
  5 *   Author(s): Jeff Layton (jlayton@redhat.com)
  6 *
  7 *   This library is free software; you can redistribute it and/or modify
  8 *   it under the terms of the GNU Lesser General Public License as published
  9 *   by the Free Software Foundation; either version 2.1 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   This library is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 15 *   the GNU Lesser General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU Lesser General Public License
 18 *   along with this library; if not, write to the Free Software
 19 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 20 */
 21
 22#include <linux/list.h>
 23#include <linux/slab.h>
 24#include <linux/string.h>
 25#include <keys/user-type.h>
 26#include <linux/key-type.h>
 
 27#include <linux/inet.h>
 28#include "cifsglob.h"
 29#include "cifs_spnego.h"
 30#include "cifs_debug.h"
 
 
 31
 32/* create a new cifs key */
 33static int
 34cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
 35{
 36	char *payload;
 37	int ret;
 38
 39	ret = -ENOMEM;
 40	payload = kmalloc(datalen, GFP_KERNEL);
 41	if (!payload)
 42		goto error;
 43
 44	/* attach the data */
 45	memcpy(payload, data, datalen);
 46	key->payload.data = payload;
 47	ret = 0;
 48
 49error:
 50	return ret;
 51}
 52
 53static void
 54cifs_spnego_key_destroy(struct key *key)
 55{
 56	kfree(key->payload.data);
 57}
 58
 59
 60/*
 61 * keytype for CIFS spnego keys
 62 */
 63struct key_type cifs_spnego_key_type = {
 64	.name		= "cifs.spnego",
 65	.instantiate	= cifs_spnego_key_instantiate,
 66	.match		= user_match,
 67	.destroy	= cifs_spnego_key_destroy,
 68	.describe	= user_describe,
 69};
 70
 71/* length of longest version string e.g.  strlen("ver=0xFF") */
 72#define MAX_VER_STR_LEN		8
 73
 74/* length of longest security mechanism name, eg in future could have
 75 * strlen(";sec=ntlmsspi") */
 76#define MAX_MECH_STR_LEN	13
 77
 78/* strlen of "host=" */
 79#define HOST_KEY_LEN		5
 80
 81/* strlen of ";ip4=" or ";ip6=" */
 82#define IP_KEY_LEN		5
 83
 84/* strlen of ";uid=0x" */
 85#define UID_KEY_LEN		7
 86
 87/* strlen of ";creduid=0x" */
 88#define CREDUID_KEY_LEN		11
 89
 90/* strlen of ";user=" */
 91#define USER_KEY_LEN		6
 92
 93/* strlen of ";pid=0x" */
 94#define PID_KEY_LEN		7
 95
 96/* get a key struct with a SPNEGO security blob, suitable for session setup */
 97struct key *
 98cifs_get_spnego_key(struct cifs_ses *sesInfo)
 
 99{
100	struct TCP_Server_Info *server = sesInfo->server;
101	struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
102	struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
103	char *description, *dp;
104	size_t desc_len;
105	struct key *spnego_key;
106	const char *hostname = server->hostname;
 
107
108	/* length of fields (with semicolons): ver=0xyz ip4=ipaddress
109	   host=hostname sec=mechanism uid=0xFF user=username */
110	desc_len = MAX_VER_STR_LEN +
111		   HOST_KEY_LEN + strlen(hostname) +
112		   IP_KEY_LEN + INET6_ADDRSTRLEN +
113		   MAX_MECH_STR_LEN +
114		   UID_KEY_LEN + (sizeof(uid_t) * 2) +
115		   CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
116		   PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
117
118	if (sesInfo->user_name)
119		desc_len += USER_KEY_LEN + strlen(sesInfo->user_name);
120
121	spnego_key = ERR_PTR(-ENOMEM);
122	description = kzalloc(desc_len, GFP_KERNEL);
123	if (description == NULL)
124		goto out;
125
126	dp = description;
127	/* start with version and hostname portion of UNC string */
128	spnego_key = ERR_PTR(-EINVAL);
129	sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
130		hostname);
131	dp = description + strlen(description);
132
133	/* add the server address */
134	if (server->dstaddr.ss_family == AF_INET)
135		sprintf(dp, "ip4=%pI4", &sa->sin_addr);
136	else if (server->dstaddr.ss_family == AF_INET6)
137		sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
138	else
139		goto out;
140
141	dp = description + strlen(description);
142
143	/* for now, only sec=krb5 and sec=mskrb5 are valid */
144	if (server->sec_kerberos)
145		sprintf(dp, ";sec=krb5");
146	else if (server->sec_mskerberos)
147		sprintf(dp, ";sec=mskrb5");
148	else
149		goto out;
 
 
150
151	dp = description + strlen(description);
152	sprintf(dp, ";uid=0x%x", sesInfo->linux_uid);
 
153
154	dp = description + strlen(description);
155	sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid);
 
156
157	if (sesInfo->user_name) {
158		dp = description + strlen(description);
159		sprintf(dp, ";user=%s", sesInfo->user_name);
160	}
161
162	dp = description + strlen(description);
163	sprintf(dp, ";pid=0x%x", current->pid);
164
165	cFYI(1, "key description = %s", description);
 
166	spnego_key = request_key(&cifs_spnego_key_type, description, "");
 
167
168#ifdef CONFIG_CIFS_DEBUG2
169	if (cifsFYI && !IS_ERR(spnego_key)) {
170		struct cifs_spnego_msg *msg = spnego_key->payload.data;
171		cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
172				msg->secblob_len + msg->sesskey_len));
173	}
174#endif /* CONFIG_CIFS_DEBUG2 */
175
176out:
177	kfree(description);
178	return spnego_key;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179}