1 // SPDX-License-Identifier: GPL-2.0-or-later 1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 2 /* 3 * The ASB.1/BER parsing code is derived from 3 * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in 4 * turn derived from the gxsnmp package by Gre 4 * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich 5 * 5 * 6 * Copyright (c) 2000 RP Internet (www.rpi.net 6 * Copyright (c) 2000 RP Internet (www.rpi.net.au). 7 */ 7 */ 8 8 9 #include <linux/module.h> 9 #include <linux/module.h> 10 #include <linux/types.h> 10 #include <linux/types.h> 11 #include <linux/kernel.h> 11 #include <linux/kernel.h> 12 #include <linux/mm.h> 12 #include <linux/mm.h> 13 #include <linux/slab.h> 13 #include <linux/slab.h> 14 #include <linux/oid_registry.h> 14 #include <linux/oid_registry.h> 15 15 16 #include "glob.h" 16 #include "glob.h" 17 17 18 #include "asn1.h" 18 #include "asn1.h" 19 #include "connection.h" 19 #include "connection.h" 20 #include "auth.h" 20 #include "auth.h" 21 #include "ksmbd_spnego_negtokeninit.asn1.h" 21 #include "ksmbd_spnego_negtokeninit.asn1.h" 22 #include "ksmbd_spnego_negtokentarg.asn1.h" 22 #include "ksmbd_spnego_negtokentarg.asn1.h" 23 23 24 #define NTLMSSP_OID_LEN 10 24 #define NTLMSSP_OID_LEN 10 25 25 26 static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = 26 static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01, 27 0x82, 0x37, 0x02, 0x02, 0x0a }; 27 0x82, 0x37, 0x02, 0x02, 0x0a }; 28 28 29 int 29 int 30 ksmbd_decode_negTokenInit(unsigned char *secur 30 ksmbd_decode_negTokenInit(unsigned char *security_blob, int length, 31 struct ksmbd_conn *c 31 struct ksmbd_conn *conn) 32 { 32 { 33 return asn1_ber_decoder(&ksmbd_spnego_ 33 return asn1_ber_decoder(&ksmbd_spnego_negtokeninit_decoder, conn, 34 security_blob, 34 security_blob, length); 35 } 35 } 36 36 37 int 37 int 38 ksmbd_decode_negTokenTarg(unsigned char *secur 38 ksmbd_decode_negTokenTarg(unsigned char *security_blob, int length, 39 struct ksmbd_conn *c 39 struct ksmbd_conn *conn) 40 { 40 { 41 return asn1_ber_decoder(&ksmbd_spnego_ 41 return asn1_ber_decoder(&ksmbd_spnego_negtokentarg_decoder, conn, 42 security_blob, 42 security_blob, length); 43 } 43 } 44 44 45 static int compute_asn_hdr_len_bytes(int len) 45 static int compute_asn_hdr_len_bytes(int len) 46 { 46 { 47 if (len > 0xFFFFFF) 47 if (len > 0xFFFFFF) 48 return 4; 48 return 4; 49 else if (len > 0xFFFF) 49 else if (len > 0xFFFF) 50 return 3; 50 return 3; 51 else if (len > 0xFF) 51 else if (len > 0xFF) 52 return 2; 52 return 2; 53 else if (len > 0x7F) 53 else if (len > 0x7F) 54 return 1; 54 return 1; 55 else 55 else 56 return 0; 56 return 0; 57 } 57 } 58 58 59 static void encode_asn_tag(char *buf, unsigned 59 static void encode_asn_tag(char *buf, unsigned int *ofs, char tag, char seq, 60 int length) 60 int length) 61 { 61 { 62 int i; 62 int i; 63 int index = *ofs; 63 int index = *ofs; 64 char hdr_len = compute_asn_hdr_len_byt 64 char hdr_len = compute_asn_hdr_len_bytes(length); 65 int len = length + 2 + hdr_len; 65 int len = length + 2 + hdr_len; 66 66 67 /* insert tag */ 67 /* insert tag */ 68 buf[index++] = tag; 68 buf[index++] = tag; 69 69 70 if (!hdr_len) { 70 if (!hdr_len) { 71 buf[index++] = len; 71 buf[index++] = len; 72 } else { 72 } else { 73 buf[index++] = 0x80 | hdr_len; 73 buf[index++] = 0x80 | hdr_len; 74 for (i = hdr_len - 1; i >= 0; 74 for (i = hdr_len - 1; i >= 0; i--) 75 buf[index++] = (len >> 75 buf[index++] = (len >> (i * 8)) & 0xFF; 76 } 76 } 77 77 78 /* insert seq */ 78 /* insert seq */ 79 len = len - (index - *ofs); 79 len = len - (index - *ofs); 80 buf[index++] = seq; 80 buf[index++] = seq; 81 81 82 if (!hdr_len) { 82 if (!hdr_len) { 83 buf[index++] = len; 83 buf[index++] = len; 84 } else { 84 } else { 85 buf[index++] = 0x80 | hdr_len; 85 buf[index++] = 0x80 | hdr_len; 86 for (i = hdr_len - 1; i >= 0; 86 for (i = hdr_len - 1; i >= 0; i--) 87 buf[index++] = (len >> 87 buf[index++] = (len >> (i * 8)) & 0xFF; 88 } 88 } 89 89 90 *ofs += (index - *ofs); 90 *ofs += (index - *ofs); 91 } 91 } 92 92 93 int build_spnego_ntlmssp_neg_blob(unsigned cha 93 int build_spnego_ntlmssp_neg_blob(unsigned char **pbuffer, u16 *buflen, 94 char *ntlm_b 94 char *ntlm_blob, int ntlm_blob_len) 95 { 95 { 96 char *buf; 96 char *buf; 97 unsigned int ofs = 0; 97 unsigned int ofs = 0; 98 int neg_result_len = 4 + compute_asn_h 98 int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; 99 int oid_len = 4 + compute_asn_hdr_len_ 99 int oid_len = 4 + compute_asn_hdr_len_bytes(NTLMSSP_OID_LEN) * 2 + 100 NTLMSSP_OID_LEN; 100 NTLMSSP_OID_LEN; 101 int ntlmssp_len = 4 + compute_asn_hdr_ 101 int ntlmssp_len = 4 + compute_asn_hdr_len_bytes(ntlm_blob_len) * 2 + 102 ntlm_blob_len; 102 ntlm_blob_len; 103 int total_len = 4 + compute_asn_hdr_le 103 int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len + 104 oid_len + ntlmssp_len) 104 oid_len + ntlmssp_len) * 2 + 105 neg_result_len + oid_l 105 neg_result_len + oid_len + ntlmssp_len; 106 106 107 buf = kmalloc(total_len, GFP_KERNEL); 107 buf = kmalloc(total_len, GFP_KERNEL); 108 if (!buf) 108 if (!buf) 109 return -ENOMEM; 109 return -ENOMEM; 110 110 111 /* insert main gss header */ 111 /* insert main gss header */ 112 encode_asn_tag(buf, &ofs, 0xa1, 0x30, 112 encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len + oid_len + 113 ntlmssp_len); 113 ntlmssp_len); 114 114 115 /* insert neg result */ 115 /* insert neg result */ 116 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 116 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); 117 buf[ofs++] = 1; 117 buf[ofs++] = 1; 118 118 119 /* insert oid */ 119 /* insert oid */ 120 encode_asn_tag(buf, &ofs, 0xa1, 0x06, 120 encode_asn_tag(buf, &ofs, 0xa1, 0x06, NTLMSSP_OID_LEN); 121 memcpy(buf + ofs, NTLMSSP_OID_STR, NTL 121 memcpy(buf + ofs, NTLMSSP_OID_STR, NTLMSSP_OID_LEN); 122 ofs += NTLMSSP_OID_LEN; 122 ofs += NTLMSSP_OID_LEN; 123 123 124 /* insert response token - ntlmssp blo 124 /* insert response token - ntlmssp blob */ 125 encode_asn_tag(buf, &ofs, 0xa2, 0x04, 125 encode_asn_tag(buf, &ofs, 0xa2, 0x04, ntlm_blob_len); 126 memcpy(buf + ofs, ntlm_blob, ntlm_blob 126 memcpy(buf + ofs, ntlm_blob, ntlm_blob_len); 127 ofs += ntlm_blob_len; 127 ofs += ntlm_blob_len; 128 128 129 *pbuffer = buf; 129 *pbuffer = buf; 130 *buflen = total_len; 130 *buflen = total_len; 131 return 0; 131 return 0; 132 } 132 } 133 133 134 int build_spnego_ntlmssp_auth_blob(unsigned ch 134 int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, 135 int neg_res 135 int neg_result) 136 { 136 { 137 char *buf; 137 char *buf; 138 unsigned int ofs = 0; 138 unsigned int ofs = 0; 139 int neg_result_len = 4 + compute_asn_h 139 int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1; 140 int total_len = 4 + compute_asn_hdr_le 140 int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len) * 2 + 141 neg_result_len; 141 neg_result_len; 142 142 143 buf = kmalloc(total_len, GFP_KERNEL); 143 buf = kmalloc(total_len, GFP_KERNEL); 144 if (!buf) 144 if (!buf) 145 return -ENOMEM; 145 return -ENOMEM; 146 146 147 /* insert main gss header */ 147 /* insert main gss header */ 148 encode_asn_tag(buf, &ofs, 0xa1, 0x30, 148 encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len); 149 149 150 /* insert neg result */ 150 /* insert neg result */ 151 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 151 encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1); 152 if (neg_result) 152 if (neg_result) 153 buf[ofs++] = 2; 153 buf[ofs++] = 2; 154 else 154 else 155 buf[ofs++] = 0; 155 buf[ofs++] = 0; 156 156 157 *pbuffer = buf; 157 *pbuffer = buf; 158 *buflen = total_len; 158 *buflen = total_len; 159 return 0; 159 return 0; 160 } 160 } 161 161 162 int ksmbd_gssapi_this_mech(void *context, size 162 int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag, 163 const void *value, 163 const void *value, size_t vlen) 164 { 164 { 165 enum OID oid; 165 enum OID oid; 166 166 167 oid = look_up_OID(value, vlen); 167 oid = look_up_OID(value, vlen); 168 if (oid != OID_spnego) { 168 if (oid != OID_spnego) { 169 char buf[50]; 169 char buf[50]; 170 170 171 sprint_oid(value, vlen, buf, s 171 sprint_oid(value, vlen, buf, sizeof(buf)); 172 ksmbd_debug(AUTH, "Unexpected 172 ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); 173 return -EBADMSG; 173 return -EBADMSG; 174 } 174 } 175 175 176 return 0; 176 return 0; 177 } 177 } 178 178 179 int ksmbd_neg_token_init_mech_type(void *conte 179 int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen, 180 unsigned ch 180 unsigned char tag, const void *value, 181 size_t vlen 181 size_t vlen) 182 { 182 { 183 struct ksmbd_conn *conn = context; 183 struct ksmbd_conn *conn = context; 184 enum OID oid; 184 enum OID oid; 185 int mech_type; 185 int mech_type; 186 186 187 oid = look_up_OID(value, vlen); 187 oid = look_up_OID(value, vlen); 188 if (oid == OID_ntlmssp) { 188 if (oid == OID_ntlmssp) { 189 mech_type = KSMBD_AUTH_NTLMSSP 189 mech_type = KSMBD_AUTH_NTLMSSP; 190 } else if (oid == OID_mskrb5) { 190 } else if (oid == OID_mskrb5) { 191 mech_type = KSMBD_AUTH_MSKRB5; 191 mech_type = KSMBD_AUTH_MSKRB5; 192 } else if (oid == OID_krb5) { 192 } else if (oid == OID_krb5) { 193 mech_type = KSMBD_AUTH_KRB5; 193 mech_type = KSMBD_AUTH_KRB5; 194 } else if (oid == OID_krb5u2u) { 194 } else if (oid == OID_krb5u2u) { 195 mech_type = KSMBD_AUTH_KRB5U2U 195 mech_type = KSMBD_AUTH_KRB5U2U; 196 } else { 196 } else { 197 char buf[50]; 197 char buf[50]; 198 198 199 sprint_oid(value, vlen, buf, s 199 sprint_oid(value, vlen, buf, sizeof(buf)); 200 ksmbd_debug(AUTH, "Unexpected 200 ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf); 201 return -EBADMSG; 201 return -EBADMSG; 202 } 202 } 203 203 204 conn->auth_mechs |= mech_type; 204 conn->auth_mechs |= mech_type; 205 if (conn->preferred_auth_mech == 0) 205 if (conn->preferred_auth_mech == 0) 206 conn->preferred_auth_mech = me 206 conn->preferred_auth_mech = mech_type; 207 207 208 return 0; 208 return 0; 209 } 209 } 210 210 211 static int ksmbd_neg_token_alloc(void *context 211 static int ksmbd_neg_token_alloc(void *context, size_t hdrlen, 212 unsigned char 212 unsigned char tag, const void *value, 213 size_t vlen) 213 size_t vlen) 214 { 214 { 215 struct ksmbd_conn *conn = context; 215 struct ksmbd_conn *conn = context; 216 216 217 if (!vlen) !! 217 conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL); 218 return -EINVAL; << 219 << 220 conn->mechToken = kmemdup_nul(value, v << 221 if (!conn->mechToken) 218 if (!conn->mechToken) 222 return -ENOMEM; 219 return -ENOMEM; 223 220 224 conn->mechTokenLen = (unsigned int)vle !! 221 memcpy(conn->mechToken, value, vlen); 225 !! 222 conn->mechToken[vlen] = '\0'; 226 return 0; 223 return 0; 227 } 224 } 228 225 229 int ksmbd_neg_token_init_mech_token(void *cont 226 int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen, 230 unsigned c 227 unsigned char tag, const void *value, 231 size_t vle 228 size_t vlen) 232 { 229 { 233 return ksmbd_neg_token_alloc(context, 230 return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); 234 } 231 } 235 232 236 int ksmbd_neg_token_targ_resp_token(void *cont 233 int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen, 237 unsigned c 234 unsigned char tag, const void *value, 238 size_t vle 235 size_t vlen) 239 { 236 { 240 return ksmbd_neg_token_alloc(context, 237 return ksmbd_neg_token_alloc(context, hdrlen, tag, value, vlen); 241 } 238 } 242 239
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.