0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/list.h>
0011 #include <linux/slab.h>
0012 #include <linux/string.h>
0013 #include <keys/user-type.h>
0014 #include <linux/key-type.h>
0015 #include <linux/keyctl.h>
0016 #include <linux/inet.h>
0017 #include "cifsglob.h"
0018 #include "cifs_spnego.h"
0019 #include "cifs_debug.h"
0020 #include "cifsproto.h"
0021 static const struct cred *spnego_cred;
0022
0023
0024 static int
0025 cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
0026 {
0027 char *payload;
0028 int ret;
0029
0030 ret = -ENOMEM;
0031 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
0032 if (!payload)
0033 goto error;
0034
0035
0036 key->payload.data[0] = payload;
0037 ret = 0;
0038
0039 error:
0040 return ret;
0041 }
0042
0043 static void
0044 cifs_spnego_key_destroy(struct key *key)
0045 {
0046 kfree(key->payload.data[0]);
0047 }
0048
0049
0050
0051
0052
0053 struct key_type cifs_spnego_key_type = {
0054 .name = "cifs.spnego",
0055 .instantiate = cifs_spnego_key_instantiate,
0056 .destroy = cifs_spnego_key_destroy,
0057 .describe = user_describe,
0058 };
0059
0060
0061 #define MAX_VER_STR_LEN 8
0062
0063
0064
0065 #define MAX_MECH_STR_LEN 13
0066
0067
0068 #define HOST_KEY_LEN 5
0069
0070
0071 #define IP_KEY_LEN 5
0072
0073
0074 #define UID_KEY_LEN 7
0075
0076
0077 #define CREDUID_KEY_LEN 11
0078
0079
0080 #define USER_KEY_LEN 6
0081
0082
0083 #define PID_KEY_LEN 7
0084
0085
0086 struct key *
0087 cifs_get_spnego_key(struct cifs_ses *sesInfo,
0088 struct TCP_Server_Info *server)
0089 {
0090 struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr;
0091 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr;
0092 char *description, *dp;
0093 size_t desc_len;
0094 struct key *spnego_key;
0095 const char *hostname = server->hostname;
0096 const struct cred *saved_cred;
0097
0098
0099
0100 desc_len = MAX_VER_STR_LEN +
0101 HOST_KEY_LEN + strlen(hostname) +
0102 IP_KEY_LEN + INET6_ADDRSTRLEN +
0103 MAX_MECH_STR_LEN +
0104 UID_KEY_LEN + (sizeof(uid_t) * 2) +
0105 CREDUID_KEY_LEN + (sizeof(uid_t) * 2) +
0106 PID_KEY_LEN + (sizeof(pid_t) * 2) + 1;
0107
0108 if (sesInfo->user_name)
0109 desc_len += USER_KEY_LEN + strlen(sesInfo->user_name);
0110
0111 spnego_key = ERR_PTR(-ENOMEM);
0112 description = kzalloc(desc_len, GFP_KERNEL);
0113 if (description == NULL)
0114 goto out;
0115
0116 dp = description;
0117
0118 spnego_key = ERR_PTR(-EINVAL);
0119 sprintf(dp, "ver=0x%x;host=%s;", CIFS_SPNEGO_UPCALL_VERSION,
0120 hostname);
0121 dp = description + strlen(description);
0122
0123
0124 if (server->dstaddr.ss_family == AF_INET)
0125 sprintf(dp, "ip4=%pI4", &sa->sin_addr);
0126 else if (server->dstaddr.ss_family == AF_INET6)
0127 sprintf(dp, "ip6=%pI6", &sa6->sin6_addr);
0128 else
0129 goto out;
0130
0131 dp = description + strlen(description);
0132
0133
0134 if (server->sec_kerberos)
0135 sprintf(dp, ";sec=krb5");
0136 else if (server->sec_mskerberos)
0137 sprintf(dp, ";sec=mskrb5");
0138 else {
0139 cifs_dbg(VFS, "unknown or missing server auth type, use krb5\n");
0140 sprintf(dp, ";sec=krb5");
0141 }
0142
0143 dp = description + strlen(description);
0144 sprintf(dp, ";uid=0x%x",
0145 from_kuid_munged(&init_user_ns, sesInfo->linux_uid));
0146
0147 dp = description + strlen(description);
0148 sprintf(dp, ";creduid=0x%x",
0149 from_kuid_munged(&init_user_ns, sesInfo->cred_uid));
0150
0151 if (sesInfo->user_name) {
0152 dp = description + strlen(description);
0153 sprintf(dp, ";user=%s", sesInfo->user_name);
0154 }
0155
0156 dp = description + strlen(description);
0157 sprintf(dp, ";pid=0x%x", current->pid);
0158
0159 cifs_dbg(FYI, "key description = %s\n", description);
0160 saved_cred = override_creds(spnego_cred);
0161 spnego_key = request_key(&cifs_spnego_key_type, description, "");
0162 revert_creds(saved_cred);
0163
0164 #ifdef CONFIG_CIFS_DEBUG2
0165 if (cifsFYI && !IS_ERR(spnego_key)) {
0166 struct cifs_spnego_msg *msg = spnego_key->payload.data[0];
0167 cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U,
0168 msg->secblob_len + msg->sesskey_len));
0169 }
0170 #endif
0171
0172 out:
0173 kfree(description);
0174 return spnego_key;
0175 }
0176
0177 int
0178 init_cifs_spnego(void)
0179 {
0180 struct cred *cred;
0181 struct key *keyring;
0182 int ret;
0183
0184 cifs_dbg(FYI, "Registering the %s key type\n",
0185 cifs_spnego_key_type.name);
0186
0187
0188
0189
0190
0191
0192 cred = prepare_kernel_cred(NULL);
0193 if (!cred)
0194 return -ENOMEM;
0195
0196 keyring = keyring_alloc(".cifs_spnego",
0197 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
0198 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
0199 KEY_USR_VIEW | KEY_USR_READ,
0200 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
0201 if (IS_ERR(keyring)) {
0202 ret = PTR_ERR(keyring);
0203 goto failed_put_cred;
0204 }
0205
0206 ret = register_key_type(&cifs_spnego_key_type);
0207 if (ret < 0)
0208 goto failed_put_key;
0209
0210
0211
0212
0213
0214 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
0215 cred->thread_keyring = keyring;
0216 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
0217 spnego_cred = cred;
0218
0219 cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring));
0220 return 0;
0221
0222 failed_put_key:
0223 key_put(keyring);
0224 failed_put_cred:
0225 put_cred(cred);
0226 return ret;
0227 }
0228
0229 void
0230 exit_cifs_spnego(void)
0231 {
0232 key_revoke(spnego_cred->thread_keyring);
0233 unregister_key_type(&cifs_spnego_key_type);
0234 put_cred(spnego_cred);
0235 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_spnego_key_type.name);
0236 }