Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
0004  * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
0005  *
0006  * Copyright (c) 2000 RP Internet (www.rpi.net.au).
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/mm.h>
0013 #include <linux/slab.h>
0014 #include <linux/oid_registry.h>
0015 
0016 #include "glob.h"
0017 
0018 #include "asn1.h"
0019 #include "connection.h"
0020 #include "auth.h"
0021 #include "ksmbd_spnego_negtokeninit.asn1.h"
0022 #include "ksmbd_spnego_negtokentarg.asn1.h"
0023 
0024 #define NTLMSSP_OID_LEN  10
0025 
0026 static char NTLMSSP_OID_STR[NTLMSSP_OID_LEN] = { 0x2b, 0x06, 0x01, 0x04, 0x01,
0027     0x82, 0x37, 0x02, 0x02, 0x0a };
0028 
0029 int
0030 ksmbd_decode_negTokenInit(unsigned char *security_blob, int length,
0031               struct ksmbd_conn *conn)
0032 {
0033     return asn1_ber_decoder(&ksmbd_spnego_negtokeninit_decoder, conn,
0034                 security_blob, length);
0035 }
0036 
0037 int
0038 ksmbd_decode_negTokenTarg(unsigned char *security_blob, int length,
0039               struct ksmbd_conn *conn)
0040 {
0041     return asn1_ber_decoder(&ksmbd_spnego_negtokentarg_decoder, conn,
0042                 security_blob, length);
0043 }
0044 
0045 static int compute_asn_hdr_len_bytes(int len)
0046 {
0047     if (len > 0xFFFFFF)
0048         return 4;
0049     else if (len > 0xFFFF)
0050         return 3;
0051     else if (len > 0xFF)
0052         return 2;
0053     else if (len > 0x7F)
0054         return 1;
0055     else
0056         return 0;
0057 }
0058 
0059 static void encode_asn_tag(char *buf, unsigned int *ofs, char tag, char seq,
0060                int length)
0061 {
0062     int i;
0063     int index = *ofs;
0064     char hdr_len = compute_asn_hdr_len_bytes(length);
0065     int len = length + 2 + hdr_len;
0066 
0067     /* insert tag */
0068     buf[index++] = tag;
0069 
0070     if (!hdr_len) {
0071         buf[index++] = len;
0072     } else {
0073         buf[index++] = 0x80 | hdr_len;
0074         for (i = hdr_len - 1; i >= 0; i--)
0075             buf[index++] = (len >> (i * 8)) & 0xFF;
0076     }
0077 
0078     /* insert seq */
0079     len = len - (index - *ofs);
0080     buf[index++] = seq;
0081 
0082     if (!hdr_len) {
0083         buf[index++] = len;
0084     } else {
0085         buf[index++] = 0x80 | hdr_len;
0086         for (i = hdr_len - 1; i >= 0; i--)
0087             buf[index++] = (len >> (i * 8)) & 0xFF;
0088     }
0089 
0090     *ofs += (index - *ofs);
0091 }
0092 
0093 int build_spnego_ntlmssp_neg_blob(unsigned char **pbuffer, u16 *buflen,
0094                   char *ntlm_blob, int ntlm_blob_len)
0095 {
0096     char *buf;
0097     unsigned int ofs = 0;
0098     int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1;
0099     int oid_len = 4 + compute_asn_hdr_len_bytes(NTLMSSP_OID_LEN) * 2 +
0100         NTLMSSP_OID_LEN;
0101     int ntlmssp_len = 4 + compute_asn_hdr_len_bytes(ntlm_blob_len) * 2 +
0102         ntlm_blob_len;
0103     int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len +
0104             oid_len + ntlmssp_len) * 2 +
0105             neg_result_len + oid_len + ntlmssp_len;
0106 
0107     buf = kmalloc(total_len, GFP_KERNEL);
0108     if (!buf)
0109         return -ENOMEM;
0110 
0111     /* insert main gss header */
0112     encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len + oid_len +
0113             ntlmssp_len);
0114 
0115     /* insert neg result */
0116     encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1);
0117     buf[ofs++] = 1;
0118 
0119     /* insert oid */
0120     encode_asn_tag(buf, &ofs, 0xa1, 0x06, NTLMSSP_OID_LEN);
0121     memcpy(buf + ofs, NTLMSSP_OID_STR, NTLMSSP_OID_LEN);
0122     ofs += NTLMSSP_OID_LEN;
0123 
0124     /* insert response token - ntlmssp blob */
0125     encode_asn_tag(buf, &ofs, 0xa2, 0x04, ntlm_blob_len);
0126     memcpy(buf + ofs, ntlm_blob, ntlm_blob_len);
0127     ofs += ntlm_blob_len;
0128 
0129     *pbuffer = buf;
0130     *buflen = total_len;
0131     return 0;
0132 }
0133 
0134 int build_spnego_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
0135                    int neg_result)
0136 {
0137     char *buf;
0138     unsigned int ofs = 0;
0139     int neg_result_len = 4 + compute_asn_hdr_len_bytes(1) * 2 + 1;
0140     int total_len = 4 + compute_asn_hdr_len_bytes(neg_result_len) * 2 +
0141         neg_result_len;
0142 
0143     buf = kmalloc(total_len, GFP_KERNEL);
0144     if (!buf)
0145         return -ENOMEM;
0146 
0147     /* insert main gss header */
0148     encode_asn_tag(buf, &ofs, 0xa1, 0x30, neg_result_len);
0149 
0150     /* insert neg result */
0151     encode_asn_tag(buf, &ofs, 0xa0, 0x0a, 1);
0152     if (neg_result)
0153         buf[ofs++] = 2;
0154     else
0155         buf[ofs++] = 0;
0156 
0157     *pbuffer = buf;
0158     *buflen = total_len;
0159     return 0;
0160 }
0161 
0162 int ksmbd_gssapi_this_mech(void *context, size_t hdrlen, unsigned char tag,
0163                const void *value, size_t vlen)
0164 {
0165     enum OID oid;
0166 
0167     oid = look_up_OID(value, vlen);
0168     if (oid != OID_spnego) {
0169         char buf[50];
0170 
0171         sprint_oid(value, vlen, buf, sizeof(buf));
0172         ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
0173         return -EBADMSG;
0174     }
0175 
0176     return 0;
0177 }
0178 
0179 int ksmbd_neg_token_init_mech_type(void *context, size_t hdrlen,
0180                    unsigned char tag, const void *value,
0181                    size_t vlen)
0182 {
0183     struct ksmbd_conn *conn = context;
0184     enum OID oid;
0185     int mech_type;
0186 
0187     oid = look_up_OID(value, vlen);
0188     if (oid == OID_ntlmssp) {
0189         mech_type = KSMBD_AUTH_NTLMSSP;
0190     } else if (oid == OID_mskrb5) {
0191         mech_type = KSMBD_AUTH_MSKRB5;
0192     } else if (oid == OID_krb5) {
0193         mech_type = KSMBD_AUTH_KRB5;
0194     } else if (oid == OID_krb5u2u) {
0195         mech_type = KSMBD_AUTH_KRB5U2U;
0196     } else {
0197         char buf[50];
0198 
0199         sprint_oid(value, vlen, buf, sizeof(buf));
0200         ksmbd_debug(AUTH, "Unexpected OID: %s\n", buf);
0201         return -EBADMSG;
0202     }
0203 
0204     conn->auth_mechs |= mech_type;
0205     if (conn->preferred_auth_mech == 0)
0206         conn->preferred_auth_mech = mech_type;
0207 
0208     return 0;
0209 }
0210 
0211 int ksmbd_neg_token_init_mech_token(void *context, size_t hdrlen,
0212                     unsigned char tag, const void *value,
0213                     size_t vlen)
0214 {
0215     struct ksmbd_conn *conn = context;
0216 
0217     conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL);
0218     if (!conn->mechToken)
0219         return -ENOMEM;
0220 
0221     memcpy(conn->mechToken, value, vlen);
0222     conn->mechToken[vlen] = '\0';
0223     return 0;
0224 }
0225 
0226 int ksmbd_neg_token_targ_resp_token(void *context, size_t hdrlen,
0227                     unsigned char tag, const void *value,
0228                     size_t vlen)
0229 {
0230     struct ksmbd_conn *conn = context;
0231 
0232     conn->mechToken = kmalloc(vlen + 1, GFP_KERNEL);
0233     if (!conn->mechToken)
0234         return -ENOMEM;
0235 
0236     memcpy(conn->mechToken, value, vlen);
0237     conn->mechToken[vlen] = '\0';
0238     return 0;
0239 }