1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
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
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
72#define MAX_VER_STR_LEN 8
73
74
75
76#define MAX_MECH_STR_LEN 13
77
78
79#define HOST_KEY_LEN 5
80
81
82#define IP_KEY_LEN 5
83
84
85#define UID_KEY_LEN 7
86
87
88#define CREDUID_KEY_LEN 11
89
90
91#define USER_KEY_LEN 6
92
93
94#define PID_KEY_LEN 7
95
96
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
109
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
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
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
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
175
176out:
177 kfree(description);
178 return spnego_key;
179}
180