root/source4/auth/ntlm/auth.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. auth_context_set_challenge
  2. auth_challenge_may_be_modified
  3. auth_get_challenge
  4. auth_get_server_info_principal
  5. auth_check_password_sync_callback
  6. auth_check_password
  7. auth_check_password_async_timed_handler
  8. auth_check_password_send
  9. auth_check_password_recv
  10. auth_context_create_methods
  11. auth_context_create
  12. auth_register
  13. auth_backend_byname
  14. auth_interface_version
  15. auth_init
  16. server_service_auth_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Password and authentication handling
   4    Copyright (C) Andrew Bartlett         2001-2002
   5    Copyright (C) Stefan Metzmacher       2005
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "../lib/util/dlinklist.h"
  23 #include "auth/auth.h"
  24 #include "auth/ntlm/auth_proto.h"
  25 #include "lib/events/events.h"
  26 #include "param/param.h"
  27 
  28 /***************************************************************************
  29  Set a fixed challenge
  30 ***************************************************************************/
  31 _PUBLIC_ NTSTATUS auth_context_set_challenge(struct auth_context *auth_ctx, const uint8_t chal[8], const char *set_by) 
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         auth_ctx->challenge.set_by = talloc_strdup(auth_ctx, set_by);
  34         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.set_by);
  35 
  36         auth_ctx->challenge.data = data_blob_talloc(auth_ctx, chal, 8);
  37         NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
  38 
  39         return NT_STATUS_OK;
  40 }
  41 
  42 /***************************************************************************
  43  Set a fixed challenge
  44 ***************************************************************************/
  45 bool auth_challenge_may_be_modified(struct auth_context *auth_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
  46 {
  47         return auth_ctx->challenge.may_be_modified;
  48 }
  49 
  50 /****************************************************************************
  51  Try to get a challenge out of the various authentication modules.
  52  Returns a const char of length 8 bytes.
  53 ****************************************************************************/
  54 _PUBLIC_ NTSTATUS auth_get_challenge(struct auth_context *auth_ctx, const uint8_t **_chal)
     /* [<][>][^][v][top][bottom][index][help] */
  55 {
  56         NTSTATUS nt_status;
  57         struct auth_method_context *method;
  58 
  59         if (auth_ctx->challenge.data.length) {
  60                 DEBUG(5, ("auth_get_challenge: returning previous challenge by module %s (normal)\n", 
  61                           auth_ctx->challenge.set_by));
  62                 *_chal = auth_ctx->challenge.data.data;
  63                 return NT_STATUS_OK;
  64         }
  65 
  66         for (method = auth_ctx->methods; method; method = method->next) {
  67                 DATA_BLOB challenge = data_blob(NULL,0);
  68 
  69                 nt_status = method->ops->get_challenge(method, auth_ctx, &challenge);
  70                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
  71                         continue;
  72                 }
  73 
  74                 NT_STATUS_NOT_OK_RETURN(nt_status);
  75 
  76                 if (challenge.length != 8) {
  77                         DEBUG(0, ("auth_get_challenge: invalid challenge (length %u) by mothod [%s]\n",
  78                                 (unsigned)challenge.length, method->ops->name));
  79                         return NT_STATUS_INTERNAL_ERROR;
  80                 }
  81 
  82                 auth_ctx->challenge.data        = challenge;
  83                 auth_ctx->challenge.set_by      = method->ops->name;
  84 
  85                 break;
  86         }
  87 
  88         if (!auth_ctx->challenge.set_by) {
  89                 uint8_t chal[8];
  90                 generate_random_buffer(chal, 8);
  91 
  92                 auth_ctx->challenge.data                = data_blob_talloc(auth_ctx, chal, 8);
  93                 NT_STATUS_HAVE_NO_MEMORY(auth_ctx->challenge.data.data);
  94                 auth_ctx->challenge.set_by              = "random";
  95 
  96                 auth_ctx->challenge.may_be_modified     = true;
  97         }
  98 
  99         DEBUG(10,("auth_get_challenge: challenge set by %s\n",
 100                  auth_ctx->challenge.set_by));
 101 
 102         *_chal = auth_ctx->challenge.data.data;
 103         return NT_STATUS_OK;
 104 }
 105 
 106 /****************************************************************************
 107  Try to get a challenge out of the various authentication modules.
 108  Returns a const char of length 8 bytes.
 109 ****************************************************************************/
 110 _PUBLIC_ NTSTATUS auth_get_server_info_principal(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 111                                                   struct auth_context *auth_ctx,
 112                                                   const char *principal,
 113                                                   struct auth_serversupplied_info **server_info)
 114 {
 115         NTSTATUS nt_status;
 116         struct auth_method_context *method;
 117 
 118         for (method = auth_ctx->methods; method; method = method->next) {
 119                 if (!method->ops->get_server_info_principal) {
 120                         continue;
 121                 }
 122 
 123                 nt_status = method->ops->get_server_info_principal(mem_ctx, auth_ctx, principal, server_info);
 124                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
 125                         continue;
 126                 }
 127 
 128                 NT_STATUS_NOT_OK_RETURN(nt_status);
 129 
 130                 break;
 131         }
 132 
 133         return NT_STATUS_OK;
 134 }
 135 
 136 struct auth_check_password_sync_state {
 137         bool finished;
 138         NTSTATUS status;
 139         struct auth_serversupplied_info *server_info;
 140 };
 141 
 142 static void auth_check_password_sync_callback(struct auth_check_password_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 143                                               void *private_data)
 144 {
 145         struct auth_check_password_sync_state *s = talloc_get_type(private_data,
 146                                                    struct auth_check_password_sync_state);
 147 
 148         s->finished = true;
 149         s->status = auth_check_password_recv(req, s, &s->server_info);
 150 }
 151 
 152 /**
 153  * Check a user's Plaintext, LM or NTLM password.
 154  * (sync version)
 155  *
 156  * Check a user's password, as given in the user_info struct and return various
 157  * interesting details in the server_info struct.
 158  *
 159  * The return value takes precedence over the contents of the server_info 
 160  * struct.  When the return is other than NT_STATUS_OK the contents 
 161  * of that structure is undefined.
 162  *
 163  * @param auth_ctx Supplies the challenges and some other data. 
 164  *                  Must be created with auth_context_create(), and the challenges should be 
 165  *                  filled in, either at creation or by calling the challenge geneation 
 166  *                  function auth_get_challenge().  
 167  *
 168  * @param user_info Contains the user supplied components, including the passwords.
 169  *
 170  * @param mem_ctx The parent memory context for the server_info structure
 171  *
 172  * @param server_info If successful, contains information about the authentication, 
 173  *                    including a SAM_ACCOUNT struct describing the user.
 174  *
 175  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
 176  *
 177  **/
 178 
 179 _PUBLIC_ NTSTATUS auth_check_password(struct auth_context *auth_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 180                              TALLOC_CTX *mem_ctx,
 181                              const struct auth_usersupplied_info *user_info, 
 182                              struct auth_serversupplied_info **server_info)
 183 {
 184         struct auth_check_password_sync_state *sync_state;
 185         NTSTATUS status;
 186 
 187         sync_state = talloc_zero(auth_ctx, struct auth_check_password_sync_state);
 188         NT_STATUS_HAVE_NO_MEMORY(sync_state);
 189 
 190         auth_check_password_send(auth_ctx, user_info, auth_check_password_sync_callback, sync_state);
 191 
 192         while (!sync_state->finished) {
 193                 event_loop_once(auth_ctx->event_ctx);
 194         }
 195 
 196         status = sync_state->status;
 197 
 198         if (NT_STATUS_IS_OK(status)) {
 199                 *server_info = talloc_steal(mem_ctx, sync_state->server_info);
 200         }
 201 
 202         talloc_free(sync_state);
 203         return status;
 204 }
 205 
 206 struct auth_check_password_request {
 207         struct auth_context *auth_ctx;
 208         const struct auth_usersupplied_info *user_info;
 209         struct auth_serversupplied_info *server_info;
 210         struct auth_method_context *method;
 211         NTSTATUS status;
 212         struct {
 213                 void (*fn)(struct auth_check_password_request *req, void *private_data);
 214                 void *private_data;
 215         } callback;
 216 };
 217 
 218 static void auth_check_password_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
     /* [<][>][^][v][top][bottom][index][help] */
 219                                                     struct timeval t, void *ptr)
 220 {
 221         struct auth_check_password_request *req = talloc_get_type(ptr, struct auth_check_password_request);
 222         req->status = req->method->ops->check_password(req->method, req, req->user_info, &req->server_info);
 223         req->callback.fn(req, req->callback.private_data);
 224 }
 225 
 226 /**
 227  * Check a user's Plaintext, LM or NTLM password.
 228  * async send hook
 229  *
 230  * Check a user's password, as given in the user_info struct and return various
 231  * interesting details in the server_info struct.
 232  *
 233  * The return value takes precedence over the contents of the server_info 
 234  * struct.  When the return is other than NT_STATUS_OK the contents 
 235  * of that structure is undefined.
 236  *
 237  * @param auth_ctx Supplies the challenges and some other data. 
 238  *                  Must be created with make_auth_context(), and the challenges should be 
 239  *                  filled in, either at creation or by calling the challenge geneation 
 240  *                  function auth_get_challenge().  
 241  *
 242  * @param user_info Contains the user supplied components, including the passwords.
 243  *
 244  * @param callback A callback function which will be called when the operation is finished.
 245  *                 The callback function needs to call auth_check_password_recv() to get the return values
 246  *
 247  * @param private_data A private pointer which will ba passed to the callback function
 248  *
 249  **/
 250 
 251 _PUBLIC_ void auth_check_password_send(struct auth_context *auth_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 252                               const struct auth_usersupplied_info *user_info,
 253                               void (*callback)(struct auth_check_password_request *req, void *private_data),
 254                               void *private_data)
 255 {
 256         /* if all the modules say 'not for me' this is reasonable */
 257         NTSTATUS nt_status;
 258         struct auth_method_context *method;
 259         const uint8_t *challenge;
 260         struct auth_usersupplied_info *user_info_tmp;
 261         struct auth_check_password_request *req = NULL;
 262 
 263         DEBUG(3,   ("auth_check_password_send:  Checking password for unmapped user [%s]\\[%s]@[%s]\n", 
 264                     user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));
 265 
 266         req = talloc_zero(auth_ctx, struct auth_check_password_request);
 267         if (!req) {
 268                 callback(NULL, private_data);
 269                 return;
 270         }
 271         req->auth_ctx                   = auth_ctx;
 272         req->user_info                  = user_info;
 273         req->callback.fn                = callback;
 274         req->callback.private_data      = private_data;
 275 
 276         if (!user_info->mapped_state) {
 277                 nt_status = map_user_info(req, lp_workgroup(auth_ctx->lp_ctx), user_info, &user_info_tmp);
 278                 if (!NT_STATUS_IS_OK(nt_status)) goto failed;
 279                 user_info = user_info_tmp;
 280                 req->user_info  = user_info_tmp;
 281         }
 282 
 283         DEBUGADD(3,("auth_check_password_send:  mapped user is: [%s]\\[%s]@[%s]\n", 
 284                     user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));
 285 
 286         nt_status = auth_get_challenge(auth_ctx, &challenge);
 287         if (!NT_STATUS_IS_OK(nt_status)) {
 288                 DEBUG(0, ("auth_check_password_send:  Invalid challenge (length %u) stored for this auth context set_by %s - cannot continue: %s\n",
 289                         (unsigned)auth_ctx->challenge.data.length, auth_ctx->challenge.set_by, nt_errstr(nt_status)));
 290                 goto failed;
 291         }
 292 
 293         if (auth_ctx->challenge.set_by) {
 294                 DEBUG(10, ("auth_check_password_send: auth_context challenge created by %s\n",
 295                                         auth_ctx->challenge.set_by));
 296         }
 297 
 298         DEBUG(10, ("auth_check_password_send: challenge is: \n"));
 299         dump_data(5, auth_ctx->challenge.data.data, auth_ctx->challenge.data.length);
 300 
 301         nt_status = NT_STATUS_NO_SUCH_USER; /* If all the modules say 'not for me', then this is reasonable */
 302         for (method = auth_ctx->methods; method; method = method->next) {
 303                 NTSTATUS result;
 304                 struct tevent_timer *te = NULL;
 305 
 306                 /* check if the module wants to chek the password */
 307                 result = method->ops->want_check(method, req, user_info);
 308                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
 309                         DEBUG(11,("auth_check_password_send: %s had nothing to say\n", method->ops->name));
 310                         continue;
 311                 }
 312 
 313                 nt_status = result;
 314                 req->method     = method;
 315 
 316                 if (!NT_STATUS_IS_OK(nt_status)) break;
 317 
 318                 te = event_add_timed(auth_ctx->event_ctx, req,
 319                                      timeval_zero(),
 320                                      auth_check_password_async_timed_handler, req);
 321                 if (!te) {
 322                         nt_status = NT_STATUS_NO_MEMORY;
 323                         goto failed;
 324                 }
 325                 return;
 326         }
 327 
 328 failed:
 329         req->status = nt_status;
 330         req->callback.fn(req, req->callback.private_data);
 331 }
 332 
 333 /**
 334  * Check a user's Plaintext, LM or NTLM password.
 335  * async receive function
 336  *
 337  * The return value takes precedence over the contents of the server_info 
 338  * struct.  When the return is other than NT_STATUS_OK the contents 
 339  * of that structure is undefined.
 340  *
 341  *
 342  * @param req The async auth_check_password state, passes to the callers callback function
 343  *
 344  * @param mem_ctx The parent memory context for the server_info structure
 345  *
 346  * @param server_info If successful, contains information about the authentication, 
 347  *                    including a SAM_ACCOUNT struct describing the user.
 348  *
 349  * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
 350  *
 351  **/
 352 
 353 _PUBLIC_ NTSTATUS auth_check_password_recv(struct auth_check_password_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 354                                   TALLOC_CTX *mem_ctx,
 355                                   struct auth_serversupplied_info **server_info)
 356 {
 357         NTSTATUS status;
 358 
 359         NT_STATUS_HAVE_NO_MEMORY(req);
 360 
 361         if (NT_STATUS_IS_OK(req->status)) {
 362                 DEBUG(5,("auth_check_password_recv: %s authentication for user [%s\\%s] succeeded\n",
 363                          req->method->ops->name, req->server_info->domain_name, req->server_info->account_name));
 364 
 365                 *server_info = talloc_steal(mem_ctx, req->server_info);
 366         } else {
 367                 DEBUG(2,("auth_check_password_recv: %s authentication for user [%s\\%s] FAILED with error %s\n", 
 368                          (req->method ? req->method->ops->name : "NO_METHOD"),
 369                          req->user_info->mapped.domain_name,
 370                          req->user_info->mapped.account_name, 
 371                          nt_errstr(req->status)));
 372         }
 373 
 374         status = req->status;
 375         talloc_free(req);
 376         return status;
 377 }
 378 
 379 /***************************************************************************
 380  Make a auth_info struct for the auth subsystem
 381  - Allow the caller to specify the methods to use
 382 ***************************************************************************/
 383 _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char **methods, 
     /* [<][>][^][v][top][bottom][index][help] */
 384                                      struct tevent_context *ev,
 385                                      struct messaging_context *msg,
 386                                      struct loadparm_context *lp_ctx,
 387                                      struct auth_context **auth_ctx)
 388 {
 389         int i;
 390         struct auth_context *ctx;
 391 
 392         auth_init();
 393 
 394         if (!methods) {
 395                 DEBUG(0,("auth_context_create: No auth method list!?\n"));
 396                 return NT_STATUS_INTERNAL_ERROR;
 397         }
 398 
 399         if (!ev) {
 400                 DEBUG(0,("auth_context_create: called with out event context\n"));
 401                 return NT_STATUS_INTERNAL_ERROR;
 402         }
 403 
 404         if (!msg) {
 405                 DEBUG(0,("auth_context_create: called with out messaging context\n"));
 406                 return NT_STATUS_INTERNAL_ERROR;
 407         }
 408 
 409         ctx = talloc(mem_ctx, struct auth_context);
 410         NT_STATUS_HAVE_NO_MEMORY(ctx);
 411         ctx->challenge.set_by           = NULL;
 412         ctx->challenge.may_be_modified  = false;
 413         ctx->challenge.data             = data_blob(NULL, 0);
 414         ctx->methods                    = NULL;
 415         ctx->event_ctx                  = ev;
 416         ctx->msg_ctx                    = msg;
 417         ctx->lp_ctx                     = lp_ctx;
 418 
 419         for (i=0; methods[i] ; i++) {
 420                 struct auth_method_context *method;
 421 
 422                 method = talloc(ctx, struct auth_method_context);
 423                 NT_STATUS_HAVE_NO_MEMORY(method);
 424 
 425                 method->ops = auth_backend_byname(methods[i]);
 426                 if (!method->ops) {
 427                         DEBUG(1,("auth_context_create: failed to find method=%s\n",
 428                                 methods[i]));
 429                         return NT_STATUS_INTERNAL_ERROR;
 430                 }
 431                 method->auth_ctx        = ctx;
 432                 method->depth           = i;
 433                 DLIST_ADD_END(ctx->methods, method, struct auth_method_context *);
 434         }
 435 
 436         if (!ctx->methods) {
 437                 return NT_STATUS_INTERNAL_ERROR;
 438         }
 439 
 440         ctx->check_password = auth_check_password;
 441         ctx->get_challenge = auth_get_challenge;
 442         ctx->set_challenge = auth_context_set_challenge;
 443         ctx->challenge_may_be_modified = auth_challenge_may_be_modified;
 444         ctx->get_server_info_principal = auth_get_server_info_principal;
 445 
 446         *auth_ctx = ctx;
 447 
 448         return NT_STATUS_OK;
 449 }
 450 /***************************************************************************
 451  Make a auth_info struct for the auth subsystem
 452  - Uses default auth_methods, depending on server role and smb.conf settings
 453 ***************************************************************************/
 454 _PUBLIC_ NTSTATUS auth_context_create(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 455                              struct tevent_context *ev,
 456                              struct messaging_context *msg,
 457                              struct loadparm_context *lp_ctx,
 458                              struct auth_context **auth_ctx)
 459 {
 460         const char **auth_methods = NULL;
 461         switch (lp_server_role(lp_ctx)) {
 462         case ROLE_STANDALONE:
 463                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "standalone", NULL);
 464                 break;
 465         case ROLE_DOMAIN_MEMBER:
 466                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "member server", NULL);
 467                 break;
 468         case ROLE_DOMAIN_CONTROLLER:
 469                 auth_methods = lp_parm_string_list(mem_ctx, lp_ctx, NULL, "auth methods", "domain controller", NULL);
 470                 break;
 471         }
 472         return auth_context_create_methods(mem_ctx, auth_methods, ev, msg, lp_ctx, auth_ctx);
 473 }
 474 
 475 
 476 /* the list of currently registered AUTH backends */
 477 static struct auth_backend {
 478         const struct auth_operations *ops;
 479 } *backends = NULL;
 480 static int num_backends;
 481 
 482 /*
 483   register a AUTH backend. 
 484 
 485   The 'name' can be later used by other backends to find the operations
 486   structure for this backend.
 487 */
 488 _PUBLIC_ NTSTATUS auth_register(const struct auth_operations *ops)
     /* [<][>][^][v][top][bottom][index][help] */
 489 {
 490         struct auth_operations *new_ops;
 491         
 492         if (auth_backend_byname(ops->name) != NULL) {
 493                 /* its already registered! */
 494                 DEBUG(0,("AUTH backend '%s' already registered\n", 
 495                          ops->name));
 496                 return NT_STATUS_OBJECT_NAME_COLLISION;
 497         }
 498 
 499         backends = talloc_realloc(talloc_autofree_context(), backends, 
 500                                   struct auth_backend, num_backends+1);
 501         NT_STATUS_HAVE_NO_MEMORY(backends);
 502 
 503         new_ops = (struct auth_operations *)talloc_memdup(backends, ops, sizeof(*ops));
 504         NT_STATUS_HAVE_NO_MEMORY(new_ops);
 505         new_ops->name = talloc_strdup(new_ops, ops->name);
 506         NT_STATUS_HAVE_NO_MEMORY(new_ops->name);
 507 
 508         backends[num_backends].ops = new_ops;
 509 
 510         num_backends++;
 511 
 512         DEBUG(3,("AUTH backend '%s' registered\n", 
 513                  ops->name));
 514 
 515         return NT_STATUS_OK;
 516 }
 517 
 518 /*
 519   return the operations structure for a named backend of the specified type
 520 */
 521 const struct auth_operations *auth_backend_byname(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 522 {
 523         int i;
 524 
 525         for (i=0;i<num_backends;i++) {
 526                 if (strcmp(backends[i].ops->name, name) == 0) {
 527                         return backends[i].ops;
 528                 }
 529         }
 530 
 531         return NULL;
 532 }
 533 
 534 /*
 535   return the AUTH interface version, and the size of some critical types
 536   This can be used by backends to either detect compilation errors, or provide
 537   multiple implementations for different smbd compilation options in one module
 538 */
 539 const struct auth_critical_sizes *auth_interface_version(void)
     /* [<][>][^][v][top][bottom][index][help] */
 540 {
 541         static const struct auth_critical_sizes critical_sizes = {
 542                 AUTH_INTERFACE_VERSION,
 543                 sizeof(struct auth_operations),
 544                 sizeof(struct auth_method_context),
 545                 sizeof(struct auth_context),
 546                 sizeof(struct auth_usersupplied_info),
 547                 sizeof(struct auth_serversupplied_info)
 548         };
 549 
 550         return &critical_sizes;
 551 }
 552 
 553 _PUBLIC_ NTSTATUS auth_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 554 {
 555         static bool initialized = false;
 556         extern NTSTATUS auth_developer_init(void);
 557         extern NTSTATUS auth_winbind_init(void);
 558         extern NTSTATUS auth_anonymous_init(void);
 559         extern NTSTATUS auth_unix_init(void);
 560         extern NTSTATUS auth_sam_init(void);
 561         extern NTSTATUS auth_server_init(void);
 562 
 563         init_module_fn static_init[] = { STATIC_auth_MODULES };
 564         
 565         if (initialized) return NT_STATUS_OK;
 566         initialized = true;
 567         
 568         run_init_functions(static_init);
 569         
 570         return NT_STATUS_OK;    
 571 }
 572 
 573 NTSTATUS server_service_auth_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 574 {
 575         return auth_init();
 576 }

/* [<][>][^][v][top][bottom][index][help] */