~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/libcli/auth/session.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
void sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
 
33
                     bool forward)
 
34
{
 
35
        int i, k;
 
36
 
 
37
        for (i=0,k=0;
 
38
             i<in->length;
 
39
             i += 8, k += 7) {
 
40
                uint8_t bin[8], bout[8], key[7];
 
41
 
 
42
                memset(bin, 0, 8);
 
43
                memcpy(bin,  &in->data[i], MIN(8, in->length-i));
 
44
 
 
45
                if (k + 7 > session_key->length) {
 
46
                        k = (session_key->length - k);
 
47
                }
 
48
                memcpy(key, &session_key->data[k], 7);
 
49
 
 
50
                des_crypt56(bout, bin, key, forward?1:0);
 
51
 
 
52
                memcpy(&out->data[i], bout, MIN(8, in->length-i));
 
53
        }
 
54
}
 
55
 
 
56
 
 
57
/*
 
58
  a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
 
59
 
 
60
  note that we round the length to a multiple of 8. This seems to be needed for 
 
61
  compatibility with windows
 
62
 
 
63
  caller should free using data_blob_free()
 
64
*/
 
65
DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
 
66
{
 
67
        DATA_BLOB ret, src;
 
68
        int slen = strlen(str);
 
69
        int dlen = (slen+7) & ~7;
 
70
 
 
71
        src = data_blob(NULL, 8+dlen);
 
72
        if (!src.data) {
 
73
                return data_blob(NULL, 0);
 
74
        }
 
75
 
 
76
        ret = data_blob(NULL, 8+dlen);
 
77
        if (!ret.data) {
 
78
                data_blob_free(&src);
 
79
                return data_blob(NULL, 0);
 
80
        }
 
81
 
 
82
        SIVAL(src.data, 0, slen);
 
83
        SIVAL(src.data, 4, 1);
 
84
        memset(src.data+8, 0,   dlen);
 
85
        memcpy(src.data+8, str, slen);
 
86
 
 
87
        sess_crypt_blob(&ret, &src, session_key, true);
 
88
        
 
89
        data_blob_free(&src);
 
90
 
 
91
        return ret;
 
92
}
 
93
 
 
94
/*
 
95
  a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
 
96
 
 
97
  caller should free the returned string
 
98
*/
 
99
char *sess_decrypt_string(TALLOC_CTX *mem_ctx, 
 
100
                          DATA_BLOB *blob, const DATA_BLOB *session_key)
 
101
{
 
102
        DATA_BLOB out;
 
103
        int slen;
 
104
        char *ret;
 
105
 
 
106
        if (blob->length < 8) {
 
107
                return NULL;
 
108
        }
 
109
        
 
110
        out = data_blob_talloc(mem_ctx, NULL, blob->length);
 
111
        if (!out.data) {
 
112
                return NULL;
 
113
        }
 
114
 
 
115
        sess_crypt_blob(&out, blob, session_key, false);
 
116
 
 
117
        if (IVAL(out.data, 4) != 1) {
 
118
                DEBUG(0,("Unexpected revision number %d in session crypted string\n",
 
119
                         IVAL(out.data, 4)));
 
120
                data_blob_free(&out);
 
121
                return NULL;
 
122
        }
 
123
 
 
124
        slen = IVAL(out.data, 0);
 
125
        if (slen > blob->length - 8) {
 
126
                DEBUG(0,("Invalid crypt length %d\n", slen));
 
127
                data_blob_free(&out);
 
128
                return NULL;
 
129
        }
 
130
 
 
131
        ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
 
132
 
 
133
        data_blob_free(&out);
 
134
 
 
135
        DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
 
136
 
 
137
        return ret;
 
138
}
 
139
 
 
140
/*
 
141
  a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
 
142
 
 
143
  note that we round the length to a multiple of 8. This seems to be needed for 
 
144
  compatibility with windows
 
145
 
 
146
  caller should free using data_blob_free()
 
147
*/
 
148
DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
 
149
{
 
150
        DATA_BLOB ret, src;
 
151
        int dlen = (blob_in->length+7) & ~7;
 
152
 
 
153
        src = data_blob_talloc(mem_ctx, NULL, 8+dlen);
 
154
        if (!src.data) {
 
155
                return data_blob(NULL, 0);
 
156
        }
 
157
 
 
158
        ret = data_blob_talloc(mem_ctx, NULL, 8+dlen);
 
159
        if (!ret.data) {
 
160
                data_blob_free(&src);
 
161
                return data_blob(NULL, 0);
 
162
        }
 
163
 
 
164
        SIVAL(src.data, 0, blob_in->length);
 
165
        SIVAL(src.data, 4, 1);
 
166
        memset(src.data+8, 0, dlen);
 
167
        memcpy(src.data+8, blob_in->data, blob_in->length);
 
168
 
 
169
        sess_crypt_blob(&ret, &src, session_key, true);
 
170
        
 
171
        data_blob_free(&src);
 
172
 
 
173
        return ret;
 
174
}
 
175
 
 
176
/*
 
177
  Decrypt a DATA_BLOB using the LSA convention
 
178
*/
 
179
NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key, 
 
180
                           DATA_BLOB *ret)
 
181
{
 
182
        DATA_BLOB out;
 
183
        int slen;
 
184
 
 
185
        if (blob->length < 8) {
 
186
                DEBUG(0, ("Unexpected length %d in session crypted secret (BLOB)\n",
 
187
                          (int)blob->length));
 
188
                return NT_STATUS_INVALID_PARAMETER;
 
189
        }
 
190
        
 
191
        out = data_blob_talloc(mem_ctx, NULL, blob->length);
 
192
        if (!out.data) {
 
193
                return NT_STATUS_NO_MEMORY;
 
194
        }
 
195
 
 
196
        sess_crypt_blob(&out, blob, session_key, false);
 
197
 
 
198
        if (IVAL(out.data, 4) != 1) {
 
199
                DEBUG(2,("Unexpected revision number %d in session crypted secret (BLOB)\n",
 
200
                         IVAL(out.data, 4)));
 
201
                return NT_STATUS_UNKNOWN_REVISION;
 
202
        }
 
203
                
 
204
        slen = IVAL(out.data, 0);
 
205
        if (slen > blob->length - 8) {
 
206
                DEBUG(0,("Invalid crypt length %d in session crypted secret (BLOB)\n", slen));
 
207
                return NT_STATUS_WRONG_PASSWORD;
 
208
        }
 
209
 
 
210
        *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
 
211
        if (slen && !ret->data) {
 
212
                return NT_STATUS_NO_MEMORY;
 
213
        }
 
214
 
 
215
        data_blob_free(&out);
 
216
 
 
217
        return NT_STATUS_OK;
 
218
}