~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/auth/ntlmssp/ntlmssp.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/Netbios implementation.
 
3
   Version 3.0
 
4
   handle NLTMSSP, client server side parsing
 
5
 
 
6
   Copyright (C) Andrew Tridgell      2001
 
7
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005
 
8
   Copyright (C) Stefan Metzmacher 2005
 
9
 
 
10
   This program is free software; you can redistribute it and/or modify
 
11
   it under the terms of the GNU General Public License as published by
 
12
   the Free Software Foundation; either version 3 of the License, or
 
13
   (at your option) any later version.
 
14
   
 
15
   This program is distributed in the hope that it will be useful,
 
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
   GNU General Public License for more details.
 
19
   
 
20
   You should have received a copy of the GNU General Public License
 
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
#include "includes.h"
 
25
#include "auth/ntlmssp/ntlmssp.h"
 
26
#include "auth/ntlmssp/msrpc_parse.h"
 
27
#include "librpc/gen_ndr/ndr_dcerpc.h"
 
28
#include "auth/credentials/credentials.h"
 
29
#include "auth/gensec/gensec.h"
 
30
#include "auth/gensec/gensec_proto.h"
 
31
#include "auth/auth.h"
 
32
#include "auth/ntlm/auth_proto.h"
 
33
#include "param/param.h"
 
34
 
 
35
/**
 
36
 * Callbacks for NTLMSSP - for both client and server operating modes
 
37
 * 
 
38
 */
 
39
 
 
40
static const struct ntlmssp_callbacks {
 
41
        enum ntlmssp_role role;
 
42
        enum ntlmssp_message_type command;
 
43
        NTSTATUS (*sync_fn)(struct gensec_security *gensec_security,
 
44
                            TALLOC_CTX *out_mem_ctx,
 
45
                            DATA_BLOB in, DATA_BLOB *out);
 
46
} ntlmssp_callbacks[] = {
 
47
        {
 
48
                .role           = NTLMSSP_CLIENT,
 
49
                .command        = NTLMSSP_INITIAL,
 
50
                .sync_fn        = ntlmssp_client_initial,
 
51
        },{
 
52
                .role           = NTLMSSP_SERVER,
 
53
                .command        = NTLMSSP_NEGOTIATE,
 
54
                .sync_fn        = ntlmssp_server_negotiate,
 
55
        },{
 
56
                .role           = NTLMSSP_CLIENT,
 
57
                .command        = NTLMSSP_CHALLENGE,
 
58
                .sync_fn        = ntlmssp_client_challenge,
 
59
        },{
 
60
                .role           = NTLMSSP_SERVER,
 
61
                .command        = NTLMSSP_AUTH,
 
62
                .sync_fn        = ntlmssp_server_auth,
 
63
        }
 
64
};
 
65
 
 
66
 
 
67
/**
 
68
 * Print out the NTLMSSP flags for debugging 
 
69
 * @param neg_flags The flags from the packet
 
70
 */
 
71
 
 
72
void debug_ntlmssp_flags(uint32_t neg_flags)
 
73
{
 
74
        DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
 
75
        
 
76
        if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) 
 
77
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_UNICODE\n"));
 
78
        if (neg_flags & NTLMSSP_NEGOTIATE_OEM) 
 
79
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_OEM\n"));
 
80
        if (neg_flags & NTLMSSP_REQUEST_TARGET) 
 
81
                DEBUGADD(4, ("  NTLMSSP_REQUEST_TARGET\n"));
 
82
        if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) 
 
83
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SIGN\n"));
 
84
        if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) 
 
85
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SEAL\n"));
 
86
        if (neg_flags & NTLMSSP_NEGOTIATE_DATAGRAM_STYLE) 
 
87
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_DATAGRAM_STYLE\n"));
 
88
        if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
 
89
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_LM_KEY\n"));
 
90
        if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) 
 
91
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NETWARE\n"));
 
92
        if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) 
 
93
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM\n"));
 
94
        if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) 
 
95
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
 
96
        if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) 
 
97
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
 
98
        if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) 
 
99
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
 
100
        if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) 
 
101
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
 
102
        if (neg_flags & NTLMSSP_CHAL_ACCEPT_RESPONSE) 
 
103
                DEBUGADD(4, ("  NTLMSSP_CHAL_ACCEPT_RESPONSE\n"));
 
104
        if (neg_flags & NTLMSSP_CHAL_NON_NT_SESSION_KEY) 
 
105
                DEBUGADD(4, ("  NTLMSSP_CHAL_NON_NT_SESSION_KEY\n"));
 
106
        if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) 
 
107
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM2\n"));
 
108
        if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) 
 
109
                DEBUGADD(4, ("  NTLMSSP_CHAL_TARGET_INFO\n"));
 
110
        if (neg_flags & NTLMSSP_NEGOTIATE_128) 
 
111
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_128\n"));
 
112
        if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) 
 
113
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
 
114
        if (neg_flags & NTLMSSP_NEGOTIATE_56) 
 
115
                DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_56\n"));
 
116
}
 
117
 
 
118
static NTSTATUS gensec_ntlmssp_magic(struct gensec_security *gensec_security, 
 
119
                                     const DATA_BLOB *first_packet) 
 
120
{
 
121
        if (first_packet->length > 8 && memcmp("NTLMSSP\0", first_packet->data, 8) == 0) {
 
122
                return NT_STATUS_OK;
 
123
        } else {
 
124
                return NT_STATUS_INVALID_PARAMETER;
 
125
        }
 
126
}
 
127
 
 
128
static NTSTATUS gensec_ntlmssp_update_find(struct gensec_ntlmssp_state *gensec_ntlmssp_state,
 
129
                                           const DATA_BLOB input, uint32_t *idx)
 
130
{
 
131
        struct gensec_security *gensec_security = gensec_ntlmssp_state->gensec_security;
 
132
        uint32_t ntlmssp_command;
 
133
        uint32_t i;
 
134
 
 
135
        if (gensec_ntlmssp_state->expected_state == NTLMSSP_DONE) {
 
136
                /* We are strict here because other modules, which we
 
137
                 * don't fully control (such as GSSAPI) are also
 
138
                 * strict, but are tested less often */
 
139
 
 
140
                DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
 
141
                return NT_STATUS_INVALID_PARAMETER;
 
142
        }
 
143
 
 
144
        if (!input.length) {
 
145
                switch (gensec_ntlmssp_state->role) {
 
146
                case NTLMSSP_CLIENT:
 
147
                        ntlmssp_command = NTLMSSP_INITIAL;
 
148
                        break;
 
149
                case NTLMSSP_SERVER:
 
150
                        if (gensec_security->want_features & GENSEC_FEATURE_DATAGRAM_MODE) {
 
151
                                /* 'datagram' mode - no neg packet */
 
152
                                ntlmssp_command = NTLMSSP_NEGOTIATE;
 
153
                        } else {
 
154
                                /* This is normal in SPNEGO mech negotiation fallback */
 
155
                                DEBUG(2, ("Failed to parse NTLMSSP packet: zero length\n"));
 
156
                                return NT_STATUS_INVALID_PARAMETER;
 
157
                        }
 
158
                        break;
 
159
                }
 
160
        } else {
 
161
                if (!msrpc_parse(gensec_ntlmssp_state, 
 
162
                                 &input, "Cd",
 
163
                                 "NTLMSSP",
 
164
                                 &ntlmssp_command)) {
 
165
                        DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
 
166
                        dump_data(2, input.data, input.length);
 
167
                        return NT_STATUS_INVALID_PARAMETER;
 
168
                }
 
169
        }
 
170
 
 
171
        if (ntlmssp_command != gensec_ntlmssp_state->expected_state) {
 
172
                DEBUG(2, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, gensec_ntlmssp_state->expected_state));
 
173
                return NT_STATUS_INVALID_PARAMETER;
 
174
        }
 
175
 
 
176
        for (i=0; i < ARRAY_SIZE(ntlmssp_callbacks); i++) {
 
177
                if (ntlmssp_callbacks[i].role == gensec_ntlmssp_state->role &&
 
178
                    ntlmssp_callbacks[i].command == ntlmssp_command) {
 
179
                        *idx = i;
 
180
                        return NT_STATUS_OK;
 
181
                }
 
182
        }
 
183
 
 
184
        DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", 
 
185
                  gensec_ntlmssp_state->role, ntlmssp_command)); 
 
186
                
 
187
        return NT_STATUS_INVALID_PARAMETER;
 
188
}
 
189
 
 
190
/**
 
191
 * Next state function for the wrapped NTLMSSP state machine
 
192
 * 
 
193
 * @param gensec_security GENSEC state, initialised to NTLMSSP
 
194
 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
 
195
 * @param in The request, as a DATA_BLOB
 
196
 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
 
197
 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
 
198
 *                or NT_STATUS_OK if the user is authenticated. 
 
199
 */
 
200
 
 
201
static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, 
 
202
                                      TALLOC_CTX *out_mem_ctx, 
 
203
                                      const DATA_BLOB input, DATA_BLOB *out)
 
204
{
 
205
        struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
 
206
        NTSTATUS status;
 
207
        uint32_t i;
 
208
 
 
209
        *out = data_blob(NULL, 0);
 
210
 
 
211
        if (!out_mem_ctx) {
 
212
                /* if the caller doesn't want to manage/own the memory, 
 
213
                   we can put it on our context */
 
214
                out_mem_ctx = gensec_ntlmssp_state;
 
215
        }
 
216
 
 
217
        status = gensec_ntlmssp_update_find(gensec_ntlmssp_state, input, &i);
 
218
        NT_STATUS_NOT_OK_RETURN(status);
 
219
 
 
220
        status = ntlmssp_callbacks[i].sync_fn(gensec_security, out_mem_ctx, input, out);
 
221
        NT_STATUS_NOT_OK_RETURN(status);
 
222
        
 
223
        return NT_STATUS_OK;
 
224
}
 
225
 
 
226
/**
 
227
 * Return the NTLMSSP master session key
 
228
 * 
 
229
 * @param gensec_ntlmssp_state NTLMSSP State
 
230
 */
 
231
 
 
232
NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security, 
 
233
                                    DATA_BLOB *session_key)
 
234
{
 
235
        struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
 
236
 
 
237
        if (gensec_ntlmssp_state->expected_state != NTLMSSP_DONE) {
 
238
                return NT_STATUS_NO_USER_SESSION_KEY;
 
239
        }
 
240
 
 
241
        if (!gensec_ntlmssp_state->session_key.data) {
 
242
                return NT_STATUS_NO_USER_SESSION_KEY;
 
243
        }
 
244
        *session_key = gensec_ntlmssp_state->session_key;
 
245
 
 
246
        return NT_STATUS_OK;
 
247
}
 
248
 
 
249
void ntlmssp_handle_neg_flags(struct gensec_ntlmssp_state *gensec_ntlmssp_state,
 
250
                              uint32_t neg_flags, bool allow_lm)
 
251
{
 
252
        if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
 
253
                gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
 
254
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
 
255
                gensec_ntlmssp_state->unicode = true;
 
256
        } else {
 
257
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
 
258
                gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
 
259
                gensec_ntlmssp_state->unicode = false;
 
260
        }
 
261
 
 
262
        if ((neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && allow_lm && !gensec_ntlmssp_state->use_ntlmv2) {
 
263
                /* other end forcing us to use LM */
 
264
                gensec_ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
 
265
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
 
266
        } else {
 
267
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
 
268
        }
 
269
 
 
270
        if (!(neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) {
 
271
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
 
272
        }
 
273
 
 
274
        if (!(neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
 
275
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
 
276
        }
 
277
 
 
278
        if (!(neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
 
279
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SEAL;
 
280
        }
 
281
 
 
282
        if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
 
283
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
 
284
        }
 
285
 
 
286
        if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
 
287
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
 
288
        }
 
289
 
 
290
        if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) {
 
291
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
 
292
        }
 
293
 
 
294
        if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
 
295
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
 
296
        }
 
297
 
 
298
        /* Woop Woop - unknown flag for Windows compatibility...
 
299
           What does this really do ? JRA. */
 
300
        if (!(neg_flags & NTLMSSP_UNKNOWN_02000000)) {
 
301
                gensec_ntlmssp_state->neg_flags &= ~NTLMSSP_UNKNOWN_02000000;
 
302
        }
 
303
 
 
304
        if ((neg_flags & NTLMSSP_REQUEST_TARGET)) {
 
305
                gensec_ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
 
306
        }
 
307
        
 
308
}
 
309
 
 
310
/**
 
311
   Weaken NTLMSSP keys to cope with down-level clients and servers.
 
312
 
 
313
   We probably should have some parameters to control this, but as
 
314
   it only occours for LM_KEY connections, and this is controlled
 
315
   by the client lanman auth/lanman auth parameters, it isn't too bad.
 
316
*/
 
317
 
 
318
DATA_BLOB ntlmssp_weakend_key(struct gensec_ntlmssp_state *gensec_ntlmssp_state, 
 
319
                              TALLOC_CTX *mem_ctx) 
 
320
{
 
321
        DATA_BLOB weakened_key = data_blob_talloc(mem_ctx, 
 
322
                                                  gensec_ntlmssp_state->session_key.data, 
 
323
                                                  gensec_ntlmssp_state->session_key.length);
 
324
        /* Nothing to weaken.  We certainly don't want to 'extend' the length... */
 
325
        if (weakened_key.length < 16) {
 
326
                /* perhaps there was no key? */
 
327
                return weakened_key;
 
328
        }
 
329
 
 
330
        /* Key weakening not performed on the master key for NTLM2
 
331
           and does not occour for NTLM1.  Therefore we only need
 
332
           to do this for the LM_KEY.  
 
333
        */
 
334
        if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
 
335
                /* LM key doesn't support 128 bit crypto, so this is
 
336
                 * the best we can do.  If you negotiate 128 bit, but
 
337
                 * not 56, you end up with 40 bit... */
 
338
                if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
 
339
                        weakened_key.data[7] = 0xa0;
 
340
                        weakened_key.length = 8;
 
341
                } else { /* forty bits */
 
342
                        weakened_key.data[5] = 0xe5;
 
343
                        weakened_key.data[6] = 0x38;
 
344
                        weakened_key.data[7] = 0xb0;
 
345
                        weakened_key.length = 8;
 
346
                }
 
347
        }
 
348
        return weakened_key;
 
349
}
 
350
 
 
351
static bool gensec_ntlmssp_have_feature(struct gensec_security *gensec_security,
 
352
                                        uint32_t feature)
 
353
{
 
354
        struct gensec_ntlmssp_state *gensec_ntlmssp_state = (struct gensec_ntlmssp_state *)gensec_security->private_data;
 
355
        if (feature & GENSEC_FEATURE_SIGN) {
 
356
                if (!gensec_ntlmssp_state->session_key.length) {
 
357
                        return false;
 
358
                }
 
359
                if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
 
360
                        return true;
 
361
                }
 
362
        }
 
363
        if (feature & GENSEC_FEATURE_SEAL) {
 
364
                if (!gensec_ntlmssp_state->session_key.length) {
 
365
                        return false;
 
366
                }
 
367
                if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
 
368
                        return true;
 
369
                }
 
370
        }
 
371
        if (feature & GENSEC_FEATURE_SESSION_KEY) {
 
372
                if (gensec_ntlmssp_state->session_key.length) {
 
373
                        return true;
 
374
                }
 
375
        }
 
376
        if (feature & GENSEC_FEATURE_DCE_STYLE) {
 
377
                return true;
 
378
        }
 
379
        if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
 
380
                if (gensec_ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
 
381
                        return true;
 
382
                }
 
383
        }
 
384
        return false;
 
385
}
 
386
 
 
387
NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
 
388
{
 
389
        struct gensec_ntlmssp_state *gensec_ntlmssp_state;
 
390
        
 
391
        gensec_ntlmssp_state = talloc_zero(gensec_security, struct gensec_ntlmssp_state);
 
392
        if (!gensec_ntlmssp_state) {
 
393
                return NT_STATUS_NO_MEMORY;
 
394
        }
 
395
 
 
396
        gensec_ntlmssp_state->gensec_security = gensec_security;
 
397
        gensec_ntlmssp_state->auth_context = NULL;
 
398
        gensec_ntlmssp_state->server_info = NULL;
 
399
 
 
400
        gensec_security->private_data = gensec_ntlmssp_state;
 
401
        return NT_STATUS_OK;
 
402
}
 
403
 
 
404
static const char *gensec_ntlmssp_oids[] = { 
 
405
        GENSEC_OID_NTLMSSP, 
 
406
        NULL
 
407
};
 
408
 
 
409
static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
 
410
        .name           = "ntlmssp",
 
411
        .sasl_name      = "NTLM",
 
412
        .auth_type      = DCERPC_AUTH_TYPE_NTLMSSP,
 
413
        .oid            = gensec_ntlmssp_oids,
 
414
        .client_start   = gensec_ntlmssp_client_start,
 
415
        .server_start   = gensec_ntlmssp_server_start,
 
416
        .magic          = gensec_ntlmssp_magic,
 
417
        .update         = gensec_ntlmssp_update,
 
418
        .sig_size       = gensec_ntlmssp_sig_size,
 
419
        .sign_packet    = gensec_ntlmssp_sign_packet,
 
420
        .check_packet   = gensec_ntlmssp_check_packet,
 
421
        .seal_packet    = gensec_ntlmssp_seal_packet,
 
422
        .unseal_packet  = gensec_ntlmssp_unseal_packet,
 
423
        .wrap           = gensec_ntlmssp_wrap,
 
424
        .unwrap         = gensec_ntlmssp_unwrap,
 
425
        .session_key    = gensec_ntlmssp_session_key,
 
426
        .session_info   = gensec_ntlmssp_session_info,
 
427
        .have_feature   = gensec_ntlmssp_have_feature,
 
428
        .enabled        = true,
 
429
        .priority       = GENSEC_NTLMSSP
 
430
};
 
431
 
 
432
 
 
433
_PUBLIC_ NTSTATUS gensec_ntlmssp_init(void)
 
434
{
 
435
        NTSTATUS ret;
 
436
 
 
437
        ret = gensec_register(&gensec_ntlmssp_security_ops);
 
438
        if (!NT_STATUS_IS_OK(ret)) {
 
439
                DEBUG(0,("Failed to register '%s' gensec backend!\n",
 
440
                        gensec_ntlmssp_security_ops.name));
 
441
                return ret;
 
442
        }
 
443
 
 
444
        return ret;
 
445
}