root/source3/auth/auth_netlogond.c

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

DEFINITIONS

This source file includes following definitions.
  1. netlogond_validate
  2. mymachinepw
  3. check_netlogond_security
  4. auth_init_netlogond
  5. auth_netlogond_init

   1 /*
   2    Unix SMB/CIFS implementation.
   3    Authenticate against a netlogon pipe listening on a unix domain socket
   4    Copyright (C) Volker Lendecke 2008
   5 
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10 
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15 
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 
  22 #undef DBGC_CLASS
  23 #define DBGC_CLASS DBGC_AUTH
  24 
  25 static NTSTATUS netlogond_validate(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  26                                    const struct auth_context *auth_context,
  27                                    const char *ncalrpc_sockname,
  28                                    uint8_t schannel_key[16],
  29                                    const auth_usersupplied_info *user_info,
  30                                    struct netr_SamInfo3 **pinfo3,
  31                                    NTSTATUS *schannel_bind_result)
  32 {
  33         struct rpc_pipe_client *p;
  34         struct cli_pipe_auth_data *auth;
  35         struct netr_SamInfo3 *info3 = NULL;
  36         NTSTATUS status;
  37 
  38         *schannel_bind_result = NT_STATUS_OK;
  39 
  40         status = rpc_pipe_open_ncalrpc(talloc_tos(), ncalrpc_sockname,
  41                                        &ndr_table_netlogon.syntax_id, &p);
  42         if (!NT_STATUS_IS_OK(status)) {
  43                 DEBUG(10, ("rpc_pipe_open_ncalrpc failed: %s\n",
  44                            nt_errstr(status)));
  45                 return status;
  46         }
  47 
  48         status = rpccli_schannel_bind_data(p, lp_workgroup(),
  49                                            PIPE_AUTH_LEVEL_PRIVACY,
  50                                            schannel_key, &auth);
  51         if (!NT_STATUS_IS_OK(status)) {
  52                 DEBUG(10, ("rpccli_schannel_bind_data failed: %s\n",
  53                            nt_errstr(status)));
  54                 TALLOC_FREE(p);
  55                 return status;
  56         }
  57 
  58         status = rpc_pipe_bind(p, auth);
  59         if (!NT_STATUS_IS_OK(status)) {
  60                 DEBUG(10, ("rpc_pipe_bind failed: %s\n", nt_errstr(status)));
  61                 TALLOC_FREE(p);
  62                 *schannel_bind_result = status;
  63                 return status;
  64         }
  65 
  66         /*
  67          * We have to fake a struct dcinfo, so that
  68          * rpccli_netlogon_sam_network_logon_ex can decrypt the session keys.
  69          */
  70 
  71         p->dc = talloc(p, struct dcinfo);
  72         if (p->dc == NULL) {
  73                 DEBUG(0, ("talloc failed\n"));
  74                 TALLOC_FREE(p);
  75                 return NT_STATUS_NO_MEMORY;
  76         }
  77 
  78         memcpy(p->dc->sess_key, schannel_key, 16);
  79 
  80         status = rpccli_netlogon_sam_network_logon_ex(
  81                 p, p,
  82                 user_info->logon_parameters,/* flags such as 'allow
  83                                              * workstation logon' */
  84                 global_myname(),            /* server name */
  85                 user_info->smb_name,        /* user name logging on. */
  86                 user_info->client_domain,   /* domain name */
  87                 user_info->wksta_name,      /* workstation name */
  88                 (uchar *)auth_context->challenge.data, /* 8 byte challenge. */
  89                 user_info->lm_resp,         /* lanman 24 byte response */
  90                 user_info->nt_resp,         /* nt 24 byte response */
  91                 &info3);                    /* info3 out */
  92 
  93         DEBUG(10, ("rpccli_netlogon_sam_network_logon_ex returned %s\n",
  94                    nt_errstr(status)));
  95 
  96         if (!NT_STATUS_IS_OK(status)) {
  97                 TALLOC_FREE(p);
  98                 return status;
  99         }
 100 
 101         *pinfo3 = talloc_move(mem_ctx, &info3);
 102 
 103         TALLOC_FREE(p);
 104         return NT_STATUS_OK;
 105 }
 106 
 107 static char *mymachinepw(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 108 {
 109         fstring pwd;
 110         const char *script;
 111         char *to_free = NULL;
 112         ssize_t nread;
 113         int ret, fd;
 114 
 115         script = lp_parm_const_string(
 116                 GLOBAL_SECTION_SNUM, "auth_netlogond", "machinepwscript",
 117                 NULL);
 118 
 119         if (script == NULL) {
 120                 to_free = talloc_asprintf(talloc_tos(), "%s/%s",
 121                                           get_dyn_SBINDIR(), "mymachinepw");
 122                 script = to_free;
 123         }
 124         if (script == NULL) {
 125                 return NULL;
 126         }
 127 
 128         ret = smbrun(script, &fd);
 129         DEBUG(ret ? 0 : 3, ("mymachinepw: Running the command `%s' gave %d\n",
 130                             script, ret));
 131         TALLOC_FREE(to_free);
 132 
 133         if (ret != 0) {
 134                 return NULL;
 135         }
 136 
 137         nread = read(fd, pwd, sizeof(pwd)-1);
 138         close(fd);
 139 
 140         if (nread <= 0) {
 141                 DEBUG(3, ("mymachinepwd: Could not read password\n"));
 142                 return NULL;
 143         }
 144 
 145         pwd[nread] = '\0';
 146 
 147         if (pwd[nread-1] == '\n') {
 148                 pwd[nread-1] = '\0';
 149         }
 150 
 151         return talloc_strdup(mem_ctx, pwd);
 152 }
 153 
 154 static NTSTATUS check_netlogond_security(const struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
 155                                          void *my_private_data,
 156                                          TALLOC_CTX *mem_ctx,
 157                                          const auth_usersupplied_info *user_info,
 158                                          auth_serversupplied_info **server_info)
 159 {
 160         TALLOC_CTX *frame = talloc_stackframe();
 161         struct netr_SamInfo3 *info3 = NULL;
 162         struct rpc_pipe_client *p;
 163         struct cli_pipe_auth_data *auth;
 164         uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
 165         char *plaintext_machinepw;
 166         uint8_t machine_password[16];
 167         uint8_t schannel_key[16];
 168         NTSTATUS schannel_bind_result, status;
 169         struct named_mutex *mutex;
 170         const char *ncalrpcsock;
 171 
 172         ncalrpcsock = lp_parm_const_string(
 173                 GLOBAL_SECTION_SNUM, "auth_netlogond", "socket", NULL);
 174 
 175         if (ncalrpcsock == NULL) {
 176                 ncalrpcsock = talloc_asprintf(talloc_tos(), "%s/%s",
 177                                               get_dyn_NCALRPCDIR(), "DEFAULT");
 178         }
 179 
 180         if (ncalrpcsock == NULL) {
 181                 status = NT_STATUS_NO_MEMORY;
 182                 goto done;
 183         }
 184 
 185         if (!secrets_fetch_local_schannel_key(schannel_key)) {
 186                 goto new_key;
 187         }
 188 
 189         status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
 190                                     schannel_key, user_info, &info3,
 191                                     &schannel_bind_result);
 192 
 193         DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
 194 
 195         if (NT_STATUS_IS_OK(status)) {
 196                 goto okay;
 197         }
 198 
 199         if (NT_STATUS_IS_OK(schannel_bind_result)) {
 200                 /*
 201                  * This is a real failure from the DC
 202                  */
 203                 goto done;
 204         }
 205 
 206  new_key:
 207 
 208         mutex = grab_named_mutex(talloc_tos(), "LOCAL_SCHANNEL_KEY", 60);
 209         if (mutex == NULL) {
 210                 DEBUG(10, ("Could not get mutex LOCAL_SCHANNEL_KEY\n"));
 211                 status = NT_STATUS_ACCESS_DENIED;
 212                 goto done;
 213         }
 214 
 215         DEBUG(10, ("schannel bind failed, setting up new key\n"));
 216 
 217         status = rpc_pipe_open_ncalrpc(talloc_tos(), ncalrpcsock,
 218                                        &ndr_table_netlogon.syntax_id, &p);
 219 
 220         if (!NT_STATUS_IS_OK(status)) {
 221                 DEBUG(10, ("rpc_pipe_open_ncalrpc failed: %s\n",
 222                            nt_errstr(status)));
 223                 goto done;
 224         }
 225 
 226         status = rpccli_anon_bind_data(p, &auth);
 227         if (!NT_STATUS_IS_OK(status)) {
 228                 DEBUG(10, ("rpccli_anon_bind_data failed: %s\n",
 229                            nt_errstr(status)));
 230                 goto done;
 231         }
 232 
 233         status = rpc_pipe_bind(p, auth);
 234         if (!NT_STATUS_IS_OK(status)) {
 235                 DEBUG(10, ("rpc_pipe_bind failed: %s\n", nt_errstr(status)));
 236                 goto done;
 237         }
 238 
 239         plaintext_machinepw = mymachinepw(talloc_tos());
 240         if (plaintext_machinepw == NULL) {
 241                 status = NT_STATUS_NO_MEMORY;
 242                 goto done;
 243         }
 244 
 245         E_md4hash(plaintext_machinepw, machine_password);
 246 
 247         TALLOC_FREE(plaintext_machinepw);
 248 
 249         status = rpccli_netlogon_setup_creds(
 250                 p, global_myname(), lp_workgroup(), global_myname(),
 251                 global_myname(), machine_password, SEC_CHAN_BDC, &neg_flags);
 252 
 253         if (!NT_STATUS_IS_OK(status)) {
 254                 DEBUG(10, ("rpccli_netlogon_setup_creds failed: %s\n",
 255                            nt_errstr(status)));
 256                 goto done;
 257         }
 258 
 259         memcpy(schannel_key, p->dc->sess_key, 16);
 260         secrets_store_local_schannel_key(schannel_key);
 261 
 262         TALLOC_FREE(p);
 263 
 264         /*
 265          * Retry the authentication with the mutex held. This way nobody else
 266          * can step on our toes.
 267          */
 268 
 269         status = netlogond_validate(talloc_tos(), auth_context, ncalrpcsock,
 270                                     schannel_key, user_info, &info3,
 271                                     &schannel_bind_result);
 272 
 273         DEBUG(10, ("netlogond_validate returned %s\n", nt_errstr(status)));
 274 
 275         if (!NT_STATUS_IS_OK(status)) {
 276                 goto done;
 277         }
 278 
 279  okay:
 280 
 281         status = make_server_info_info3(mem_ctx, user_info->smb_name,
 282                                         user_info->domain, server_info,
 283                                         info3);
 284         if (!NT_STATUS_IS_OK(status)) {
 285                 DEBUG(10, ("make_server_info_info3 failed: %s\n",
 286                            nt_errstr(status)));
 287                 TALLOC_FREE(frame);
 288                 return status;
 289         }
 290 
 291         status = NT_STATUS_OK;
 292 
 293  done:
 294         TALLOC_FREE(frame);
 295         return status;
 296 }
 297 
 298 /* module initialisation */
 299 static NTSTATUS auth_init_netlogond(struct auth_context *auth_context,
     /* [<][>][^][v][top][bottom][index][help] */
 300                                     const char *param,
 301                                     auth_methods **auth_method)
 302 {
 303         if (!make_auth_methods(auth_context, auth_method)) {
 304                 return NT_STATUS_NO_MEMORY;
 305         }
 306 
 307         (*auth_method)->name = "netlogond";
 308         (*auth_method)->auth = check_netlogond_security;
 309         return NT_STATUS_OK;
 310 }
 311 
 312 NTSTATUS auth_netlogond_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 313 {
 314         smb_register_auth(AUTH_INTERFACE_VERSION, "netlogond",
 315                           auth_init_netlogond);
 316         return NT_STATUS_OK;
 317 }

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