Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/auth/session.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   code to encrypt/decrypt data using the user session key
5
6
   Copyright (C) Andrew Tridgell 2004
7
   
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
   
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
   
18
   You should have received a copy of the GNU General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
*/
21
22
#include "includes.h"
23
#include "libcli/auth/libcli_auth.h"
24
25
/*
26
  encrypt or decrypt a blob of data using the user session key
27
  as used in lsa_SetSecret
28
29
  before calling, the out blob must be initialised to be the same size
30
  as the in blob
31
*/
32
int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
33
        enum samba_gnutls_direction encrypt)
34
406
{
35
406
  int i, k, rc;
36
37
406
  if (in->length % 8 != 0) {
38
102
    return GNUTLS_E_INVALID_REQUEST;
39
102
  }
40
41
304
  if (session_key->length < 7) {
42
70
    return GNUTLS_E_INVALID_REQUEST;
43
70
  }
44
45
234
  for (i=0,k=0;
46
1.84M
       i<in->length;
47
1.84M
       i += 8, k += 7) {
48
1.84M
    uint8_t bin[8], bout[8], key[7];
49
50
1.84M
    memcpy(bin,  &in->data[i], 8);
51
52
1.84M
    if (k + 7 > session_key->length) {
53
1.13M
      k = (session_key->length - k);
54
1.13M
    }
55
1.84M
    memcpy(key, &session_key->data[k], 7);
56
57
1.84M
    rc = des_crypt56_gnutls(bout, bin, key, encrypt);
58
1.84M
    if (rc != 0) {
59
0
      ZERO_ARRAY(bin);
60
0
      ZERO_ARRAY(bout);
61
0
      ZERO_ARRAY(key);
62
0
      return rc;
63
0
    }
64
65
1.84M
    memcpy(&out->data[i], bout, 8);
66
67
1.84M
    ZERO_ARRAY(bin);
68
1.84M
    ZERO_ARRAY(bout);
69
1.84M
    ZERO_ARRAY(key);
70
1.84M
  }
71
234
  return 0;
72
234
}
73
74
75
/*
76
  a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
77
78
  note that we round the length to a multiple of 8. This seems to be needed for 
79
  compatibility with windows
80
81
  caller should free using data_blob_free()
82
*/
83
DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
84
0
{
85
0
  DATA_BLOB ret, src;
86
0
  int slen = strlen(str);
87
0
  int dlen = (slen+7) & ~7;
88
0
  int rc;
89
90
0
  src = data_blob(NULL, 8+dlen);
91
0
  if (!src.data) {
92
0
    return data_blob(NULL, 0);
93
0
  }
94
95
0
  ret = data_blob(NULL, 8+dlen);
96
0
  if (!ret.data) {
97
0
    data_blob_free(&src);
98
0
    return data_blob(NULL, 0);
99
0
  }
100
101
0
  SIVAL(src.data, 0, slen);
102
0
  SIVAL(src.data, 4, 1);
103
0
  memset(src.data+8, 0,   dlen);
104
0
  memcpy(src.data+8, str, slen);
105
106
0
  rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
107
  
108
0
  data_blob_free(&src);
109
0
  if (rc != 0) {
110
0
    data_blob_free(&ret);
111
0
    return data_blob(NULL, 0);
112
0
  }
113
114
0
  return ret;
115
0
}
116
117
/*
118
  a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
119
120
  caller should free the returned string
121
*/
122
char *sess_decrypt_string(TALLOC_CTX *mem_ctx, 
123
        DATA_BLOB *blob, const DATA_BLOB *session_key)
124
0
{
125
0
  DATA_BLOB out;
126
0
  int rc, slen;
127
0
  char *ret;
128
129
0
  if (blob->length < 8) {
130
0
    return NULL;
131
0
  }
132
133
0
  out = data_blob_talloc_s(mem_ctx, NULL, blob->length);
134
0
  if (!out.data) {
135
0
    return NULL;
136
0
  }
137
138
0
  rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
139
0
  if (rc != 0) {
140
0
    data_blob_free(&out);
141
0
    return NULL;
142
0
  }
143
144
0
  if (IVAL(out.data, 4) != 1) {
145
0
    DEBUG(0,("Unexpected revision number %d in session encrypted string\n",
146
0
       IVAL(out.data, 4)));
147
0
    data_blob_free(&out);
148
0
    return NULL;
149
0
  }
150
151
0
  slen = IVAL(out.data, 0);
152
0
  if (slen > blob->length - 8) {
153
0
    DEBUG(0,("Invalid crypt length %d\n", slen));
154
0
    data_blob_free(&out);
155
0
    return NULL;
156
0
  }
157
158
0
  ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
159
160
0
  data_blob_free(&out);
161
162
0
  DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
163
164
0
  return ret;
165
0
}
166
167
/*
168
  a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
169
170
  note that we round the length to a multiple of 8. This seems to be needed for 
171
  compatibility with windows
172
173
  caller should free using data_blob_free()
174
*/
175
DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
176
218
{
177
218
  DATA_BLOB ret, src;
178
218
  int dlen = (blob_in->length+7) & ~7;
179
218
  int rc;
180
181
218
  src = data_blob_talloc_s(mem_ctx, NULL, 8 + dlen);
182
218
  if (!src.data) {
183
0
    return data_blob(NULL, 0);
184
0
  }
185
186
218
  ret = data_blob_talloc_s(mem_ctx, NULL, 8 + dlen);
187
218
  if (!ret.data) {
188
0
    data_blob_free(&src);
189
0
    return data_blob(NULL, 0);
190
0
  }
191
192
218
  SIVAL(src.data, 0, blob_in->length);
193
218
  SIVAL(src.data, 4, 1);
194
218
  memset(src.data+8, 0, dlen);
195
218
  memcpy(src.data+8, blob_in->data, blob_in->length);
196
197
218
  rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
198
  
199
218
  data_blob_free(&src);
200
218
  if (rc != 0) {
201
69
    data_blob_free(&ret);
202
69
    return data_blob(NULL, 0);
203
69
  }
204
205
149
  return ret;
206
218
}
207
208
/*
209
  Decrypt a DATA_BLOB using the LSA convention
210
*/
211
NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key, 
212
         DATA_BLOB *ret)
213
218
{
214
218
  DATA_BLOB out;
215
218
  int rc, slen;
216
217
218
  if (blob->length < 8) {
218
30
    DEBUG(0, ("Unexpected length %d in session encrypted secret (BLOB)\n",
219
30
        (int)blob->length));
220
30
    return NT_STATUS_INVALID_PARAMETER;
221
30
  }
222
223
188
  out = data_blob_talloc_s(mem_ctx, NULL, blob->length);
224
188
  if (!out.data) {
225
0
    return NT_STATUS_NO_MEMORY;
226
0
  }
227
228
188
  rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
229
188
  if (rc != 0) {
230
103
    data_blob_free(&out);
231
103
    return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
232
103
  }
233
234
85
  if (IVAL(out.data, 4) != 1) {
235
63
    DEBUG(2,("Unexpected revision number %d in session encrypted secret (BLOB)\n",
236
63
       IVAL(out.data, 4)));
237
63
    return NT_STATUS_UNKNOWN_REVISION;
238
63
  }
239
    
240
22
  slen = IVAL(out.data, 0);
241
22
  if (slen > blob->length - 8) {
242
22
    DEBUG(0,("Invalid crypt length %d in session encrypted secret (BLOB)\n", slen));
243
22
    return NT_STATUS_WRONG_PASSWORD;
244
22
  }
245
246
0
  *ret = data_blob_talloc_s(mem_ctx, out.data + 8, slen);
247
0
  if (slen && !ret->data) {
248
0
    return NT_STATUS_NO_MEMORY;
249
0
  }
250
251
0
  data_blob_free(&out);
252
253
0
  return NT_STATUS_OK;
254
0
}