| 1 | /*
|
|---|
| 2 | * Unix SMB/CIFS implementation.
|
|---|
| 3 | * RPC Pipe client / server routines
|
|---|
| 4 | * Copyright (C) Andrew Tridgell 1992-1997,
|
|---|
| 5 | * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
|
|---|
| 6 | * Copyright (C) Paul Ashton 1997.
|
|---|
| 7 | * Copyright (C) Jeremy Allison 1998-2001.
|
|---|
| 8 | * Copyright (C) Andrew Bartlett 2001.
|
|---|
| 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 2 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, write to the Free Software
|
|---|
| 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|---|
| 23 | */
|
|---|
| 24 |
|
|---|
| 25 | /* This is the implementation of the netlogon pipe. */
|
|---|
| 26 |
|
|---|
| 27 | #include "includes.h"
|
|---|
| 28 |
|
|---|
| 29 | extern userdom_struct current_user_info;
|
|---|
| 30 |
|
|---|
| 31 | #undef DBGC_CLASS
|
|---|
| 32 | #define DBGC_CLASS DBGC_RPC_SRV
|
|---|
| 33 |
|
|---|
| 34 | /*************************************************************************
|
|---|
| 35 | init_net_r_req_chal:
|
|---|
| 36 | *************************************************************************/
|
|---|
| 37 |
|
|---|
| 38 | static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
|
|---|
| 39 | DOM_CHAL *srv_chal, NTSTATUS status)
|
|---|
| 40 | {
|
|---|
| 41 | DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
|
|---|
| 42 | memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
|
|---|
| 43 | r_c->status = status;
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | /*************************************************************************
|
|---|
| 47 | error messages cropping up when using nltest.exe...
|
|---|
| 48 | *************************************************************************/
|
|---|
| 49 |
|
|---|
| 50 | #define ERROR_NO_SUCH_DOMAIN 0x54b
|
|---|
| 51 | #define ERROR_NO_LOGON_SERVERS 0x51f
|
|---|
| 52 | #define NO_ERROR 0x0
|
|---|
| 53 |
|
|---|
| 54 | /*************************************************************************
|
|---|
| 55 | net_reply_logon_ctrl:
|
|---|
| 56 | *************************************************************************/
|
|---|
| 57 |
|
|---|
| 58 | NTSTATUS _net_logon_ctrl(pipes_struct *p, NET_Q_LOGON_CTRL *q_u,
|
|---|
| 59 | NET_R_LOGON_CTRL *r_u)
|
|---|
| 60 | {
|
|---|
| 61 | uint32 flags = 0x0;
|
|---|
| 62 | uint32 pdc_connection_status = 0x00; /* Maybe a win32 error code? */
|
|---|
| 63 |
|
|---|
| 64 | /* Setup the Logon Control response */
|
|---|
| 65 |
|
|---|
| 66 | init_net_r_logon_ctrl(r_u, q_u->query_level, flags,
|
|---|
| 67 | pdc_connection_status);
|
|---|
| 68 |
|
|---|
| 69 | return r_u->status;
|
|---|
| 70 | }
|
|---|
| 71 |
|
|---|
| 72 | /****************************************************************************
|
|---|
| 73 | Send a message to smbd to do a sam synchronisation
|
|---|
| 74 | **************************************************************************/
|
|---|
| 75 |
|
|---|
| 76 | static void send_sync_message(void)
|
|---|
| 77 | {
|
|---|
| 78 | TDB_CONTEXT *tdb;
|
|---|
| 79 |
|
|---|
| 80 | tdb = tdb_open_log(lock_path("connections.tdb"), 0,
|
|---|
| 81 | TDB_DEFAULT, O_RDONLY, 0);
|
|---|
| 82 |
|
|---|
| 83 | if (!tdb) {
|
|---|
| 84 | DEBUG(3, ("send_sync_message(): failed to open connections "
|
|---|
| 85 | "database\n"));
|
|---|
| 86 | return;
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | DEBUG(3, ("sending sam synchronisation message\n"));
|
|---|
| 90 |
|
|---|
| 91 | message_send_all(tdb, MSG_SMB_SAM_SYNC, NULL, 0, False, NULL);
|
|---|
| 92 |
|
|---|
| 93 | tdb_close(tdb);
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | /*************************************************************************
|
|---|
| 97 | net_reply_logon_ctrl2:
|
|---|
| 98 | *************************************************************************/
|
|---|
| 99 |
|
|---|
| 100 | NTSTATUS _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
|
|---|
| 101 | {
|
|---|
| 102 | uint32 flags = 0x0;
|
|---|
| 103 | uint32 pdc_connection_status = 0x0;
|
|---|
| 104 | uint32 logon_attempts = 0x0;
|
|---|
| 105 | uint32 tc_status;
|
|---|
| 106 | fstring servername, domain, dc_name, dc_name2;
|
|---|
| 107 | struct in_addr dc_ip;
|
|---|
| 108 |
|
|---|
| 109 | /* this should be \\global_myname() */
|
|---|
| 110 | unistr2_to_ascii(servername, &q_u->uni_server_name, sizeof(servername));
|
|---|
| 111 |
|
|---|
| 112 | r_u->status = NT_STATUS_OK;
|
|---|
| 113 |
|
|---|
| 114 | tc_status = ERROR_NO_SUCH_DOMAIN;
|
|---|
| 115 | fstrcpy( dc_name, "" );
|
|---|
| 116 |
|
|---|
| 117 | switch ( q_u->function_code ) {
|
|---|
| 118 | case NETLOGON_CONTROL_TC_QUERY:
|
|---|
| 119 | unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
|
|---|
| 120 |
|
|---|
| 121 | if ( !is_trusted_domain( domain ) )
|
|---|
| 122 | break;
|
|---|
| 123 |
|
|---|
| 124 | if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
|
|---|
| 125 | tc_status = ERROR_NO_LOGON_SERVERS;
|
|---|
| 126 | break;
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
|
|---|
| 130 |
|
|---|
| 131 | tc_status = NO_ERROR;
|
|---|
| 132 |
|
|---|
| 133 | break;
|
|---|
| 134 |
|
|---|
| 135 | case NETLOGON_CONTROL_REDISCOVER:
|
|---|
| 136 | unistr2_to_ascii(domain, &q_u->info.info6.domain, sizeof(domain));
|
|---|
| 137 |
|
|---|
| 138 | if ( !is_trusted_domain( domain ) )
|
|---|
| 139 | break;
|
|---|
| 140 |
|
|---|
| 141 | if ( !get_dc_name( domain, NULL, dc_name2, &dc_ip ) ) {
|
|---|
| 142 | tc_status = ERROR_NO_LOGON_SERVERS;
|
|---|
| 143 | break;
|
|---|
| 144 | }
|
|---|
| 145 |
|
|---|
| 146 | fstr_sprintf( dc_name, "\\\\%s", dc_name2 );
|
|---|
| 147 |
|
|---|
| 148 | tc_status = NO_ERROR;
|
|---|
| 149 |
|
|---|
| 150 | break;
|
|---|
| 151 |
|
|---|
| 152 | default:
|
|---|
| 153 | /* no idea what this should be */
|
|---|
| 154 | DEBUG(0,("_net_logon_ctrl2: unimplemented function level [%d]\n",
|
|---|
| 155 | q_u->function_code));
|
|---|
| 156 | }
|
|---|
| 157 |
|
|---|
| 158 | /* prepare the response */
|
|---|
| 159 |
|
|---|
| 160 | init_net_r_logon_ctrl2( r_u, q_u->query_level, flags,
|
|---|
| 161 | pdc_connection_status, logon_attempts, tc_status, dc_name );
|
|---|
| 162 |
|
|---|
| 163 | if (lp_server_role() == ROLE_DOMAIN_BDC)
|
|---|
| 164 | send_sync_message();
|
|---|
| 165 |
|
|---|
| 166 | return r_u->status;
|
|---|
| 167 | }
|
|---|
| 168 |
|
|---|
| 169 | /*************************************************************************
|
|---|
| 170 | net_reply_trust_dom_list:
|
|---|
| 171 | *************************************************************************/
|
|---|
| 172 |
|
|---|
| 173 | NTSTATUS _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
|
|---|
| 174 | {
|
|---|
| 175 | const char *trusted_domain = "test_domain";
|
|---|
| 176 | uint32 num_trust_domains = 1;
|
|---|
| 177 |
|
|---|
| 178 | DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
|
|---|
| 179 |
|
|---|
| 180 | /* set up the Trusted Domain List response */
|
|---|
| 181 | init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
|
|---|
| 182 |
|
|---|
| 183 | DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
|
|---|
| 184 |
|
|---|
| 185 | return r_u->status;
|
|---|
| 186 | }
|
|---|
| 187 |
|
|---|
| 188 | /***********************************************************************************
|
|---|
| 189 | init_net_r_srv_pwset:
|
|---|
| 190 | ***********************************************************************************/
|
|---|
| 191 |
|
|---|
| 192 | static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
|
|---|
| 193 | DOM_CRED *srv_cred, NTSTATUS status)
|
|---|
| 194 | {
|
|---|
| 195 | DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
|
|---|
| 196 |
|
|---|
| 197 | memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
|
|---|
| 198 | r_s->status = status;
|
|---|
| 199 |
|
|---|
| 200 | DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
|
|---|
| 201 | }
|
|---|
| 202 |
|
|---|
| 203 | /******************************************************************
|
|---|
| 204 | gets a machine password entry. checks access rights of the host.
|
|---|
| 205 | ******************************************************************/
|
|---|
| 206 |
|
|---|
| 207 | static NTSTATUS get_md4pw(char *md4pw, char *mach_acct, uint16 sec_chan_type)
|
|---|
| 208 | {
|
|---|
| 209 | struct samu *sampass = NULL;
|
|---|
| 210 | const uint8 *pass;
|
|---|
| 211 | BOOL ret;
|
|---|
| 212 | uint32 acct_ctrl;
|
|---|
| 213 |
|
|---|
| 214 | #if 0
|
|---|
| 215 | /*
|
|---|
| 216 | * Currently this code is redundent as we already have a filter
|
|---|
| 217 | * by hostname list. What this code really needs to do is to
|
|---|
| 218 | * get a hosts allowed/hosts denied list from the SAM database
|
|---|
| 219 | * on a per user basis, and make the access decision there.
|
|---|
| 220 | * I will leave this code here for now as a reminder to implement
|
|---|
| 221 | * this at a later date. JRA.
|
|---|
| 222 | */
|
|---|
| 223 |
|
|---|
| 224 | if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
|
|---|
| 225 | client_name(), client_addr()))
|
|---|
| 226 | {
|
|---|
| 227 | DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
|
|---|
| 228 | return False;
|
|---|
| 229 | }
|
|---|
| 230 | #endif /* 0 */
|
|---|
| 231 |
|
|---|
| 232 | if ( !(sampass = samu_new( NULL )) ) {
|
|---|
| 233 | return NT_STATUS_NO_MEMORY;
|
|---|
| 234 | }
|
|---|
| 235 |
|
|---|
| 236 | /* JRA. This is ok as it is only used for generating the challenge. */
|
|---|
| 237 | become_root();
|
|---|
| 238 | ret = pdb_getsampwnam(sampass, mach_acct);
|
|---|
| 239 | unbecome_root();
|
|---|
| 240 |
|
|---|
| 241 | if (!ret) {
|
|---|
| 242 | DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
|
|---|
| 243 | TALLOC_FREE(sampass);
|
|---|
| 244 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 245 | }
|
|---|
| 246 |
|
|---|
| 247 | acct_ctrl = pdb_get_acct_ctrl(sampass);
|
|---|
| 248 | if (acct_ctrl & ACB_DISABLED) {
|
|---|
| 249 | DEBUG(0,("get_md4pw: Workstation %s: account is disabled\n", mach_acct));
|
|---|
| 250 | TALLOC_FREE(sampass);
|
|---|
| 251 | return NT_STATUS_ACCOUNT_DISABLED;
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 | if (!(acct_ctrl & ACB_SVRTRUST) &&
|
|---|
| 255 | !(acct_ctrl & ACB_WSTRUST) &&
|
|---|
| 256 | !(acct_ctrl & ACB_DOMTRUST))
|
|---|
| 257 | {
|
|---|
| 258 | DEBUG(0,("get_md4pw: Workstation %s: account is not a trust account\n", mach_acct));
|
|---|
| 259 | TALLOC_FREE(sampass);
|
|---|
| 260 | return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
|
|---|
| 261 | }
|
|---|
| 262 |
|
|---|
| 263 | switch (sec_chan_type) {
|
|---|
| 264 | case SEC_CHAN_BDC:
|
|---|
| 265 | if (!(acct_ctrl & ACB_SVRTRUST)) {
|
|---|
| 266 | DEBUG(0,("get_md4pw: Workstation %s: BDC secure channel requested "
|
|---|
| 267 | "but not a server trust account\n", mach_acct));
|
|---|
| 268 | TALLOC_FREE(sampass);
|
|---|
| 269 | return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
|
|---|
| 270 | }
|
|---|
| 271 | break;
|
|---|
| 272 | case SEC_CHAN_WKSTA:
|
|---|
| 273 | if (!(acct_ctrl & ACB_WSTRUST)) {
|
|---|
| 274 | DEBUG(0,("get_md4pw: Workstation %s: WORKSTATION secure channel requested "
|
|---|
| 275 | "but not a workstation trust account\n", mach_acct));
|
|---|
| 276 | TALLOC_FREE(sampass);
|
|---|
| 277 | return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
|
|---|
| 278 | }
|
|---|
| 279 | break;
|
|---|
| 280 | case SEC_CHAN_DOMAIN:
|
|---|
| 281 | if (!(acct_ctrl & ACB_DOMTRUST)) {
|
|---|
| 282 | DEBUG(0,("get_md4pw: Workstation %s: DOMAIN secure channel requested "
|
|---|
| 283 | "but not a interdomain trust account\n", mach_acct));
|
|---|
| 284 | TALLOC_FREE(sampass);
|
|---|
| 285 | return NT_STATUS_NO_TRUST_SAM_ACCOUNT;
|
|---|
| 286 | }
|
|---|
| 287 | break;
|
|---|
| 288 | default:
|
|---|
| 289 | break;
|
|---|
| 290 | }
|
|---|
| 291 |
|
|---|
| 292 | if ((pass = pdb_get_nt_passwd(sampass)) == NULL) {
|
|---|
| 293 | DEBUG(0,("get_md4pw: Workstation %s: account does not have a password\n", mach_acct));
|
|---|
| 294 | TALLOC_FREE(sampass);
|
|---|
| 295 | return NT_STATUS_LOGON_FAILURE;
|
|---|
| 296 | }
|
|---|
| 297 |
|
|---|
| 298 | memcpy(md4pw, pass, 16);
|
|---|
| 299 | dump_data(5, md4pw, 16);
|
|---|
| 300 |
|
|---|
| 301 | TALLOC_FREE(sampass);
|
|---|
| 302 |
|
|---|
| 303 | return NT_STATUS_OK;
|
|---|
| 304 |
|
|---|
| 305 |
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | /*************************************************************************
|
|---|
| 309 | _net_req_chal
|
|---|
| 310 | *************************************************************************/
|
|---|
| 311 |
|
|---|
| 312 | NTSTATUS _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
|
|---|
| 313 | {
|
|---|
| 314 | if (!p->dc) {
|
|---|
| 315 | p->dc = TALLOC_ZERO_P(p->pipe_state_mem_ctx, struct dcinfo);
|
|---|
| 316 | if (!p->dc) {
|
|---|
| 317 | return NT_STATUS_NO_MEMORY;
|
|---|
| 318 | }
|
|---|
| 319 | } else {
|
|---|
| 320 | DEBUG(10,("_net_req_chal: new challenge requested. Clearing old state.\n"));
|
|---|
| 321 | ZERO_STRUCTP(p->dc);
|
|---|
| 322 | }
|
|---|
| 323 |
|
|---|
| 324 | rpcstr_pull(p->dc->remote_machine,
|
|---|
| 325 | q_u->uni_logon_clnt.buffer,
|
|---|
| 326 | sizeof(fstring),q_u->uni_logon_clnt.uni_str_len*2,0);
|
|---|
| 327 |
|
|---|
| 328 | /* Save the client challenge to the server. */
|
|---|
| 329 | memcpy(p->dc->clnt_chal.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
|
|---|
| 330 |
|
|---|
| 331 | /* Create a server challenge for the client */
|
|---|
| 332 | /* Set this to a random value. */
|
|---|
| 333 | generate_random_buffer(p->dc->srv_chal.data, 8);
|
|---|
| 334 |
|
|---|
| 335 | /* set up the LSA REQUEST CHALLENGE response */
|
|---|
| 336 | init_net_r_req_chal(r_u, &p->dc->srv_chal, NT_STATUS_OK);
|
|---|
| 337 |
|
|---|
| 338 | p->dc->challenge_sent = True;
|
|---|
| 339 |
|
|---|
| 340 | return NT_STATUS_OK;
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | /*************************************************************************
|
|---|
| 344 | init_net_r_auth:
|
|---|
| 345 | *************************************************************************/
|
|---|
| 346 |
|
|---|
| 347 | static void init_net_r_auth(NET_R_AUTH *r_a, DOM_CHAL *resp_cred, NTSTATUS status)
|
|---|
| 348 | {
|
|---|
| 349 | memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
|
|---|
| 350 | r_a->status = status;
|
|---|
| 351 | }
|
|---|
| 352 |
|
|---|
| 353 | /*************************************************************************
|
|---|
| 354 | _net_auth. Create the initial credentials.
|
|---|
| 355 | *************************************************************************/
|
|---|
| 356 |
|
|---|
| 357 | NTSTATUS _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
|
|---|
| 358 | {
|
|---|
| 359 | NTSTATUS status;
|
|---|
| 360 | fstring mach_acct;
|
|---|
| 361 | fstring remote_machine;
|
|---|
| 362 | DOM_CHAL srv_chal_out;
|
|---|
| 363 |
|
|---|
| 364 | if (!p->dc || !p->dc->challenge_sent) {
|
|---|
| 365 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 366 | }
|
|---|
| 367 |
|
|---|
| 368 | rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
|
|---|
| 369 | q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
|
|---|
| 370 | rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
|
|---|
| 371 | q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
|
|---|
| 372 |
|
|---|
| 373 | status = get_md4pw((char *)p->dc->mach_pw, mach_acct, q_u->clnt_id.sec_chan);
|
|---|
| 374 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 375 | DEBUG(0,("_net_auth: creds_server_check failed. Failed to "
|
|---|
| 376 | "get password for machine account %s "
|
|---|
| 377 | "from client %s: %s\n",
|
|---|
| 378 | mach_acct, remote_machine, nt_errstr(status) ));
|
|---|
| 379 | /* always return NT_STATUS_ACCESS_DENIED */
|
|---|
| 380 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 381 | }
|
|---|
| 382 |
|
|---|
| 383 | /* From the client / server challenges and md4 password, generate sess key */
|
|---|
| 384 | creds_server_init(0, /* No neg flags. */
|
|---|
| 385 | p->dc,
|
|---|
| 386 | &p->dc->clnt_chal, /* Stored client chal. */
|
|---|
| 387 | &p->dc->srv_chal, /* Stored server chal. */
|
|---|
| 388 | p->dc->mach_pw,
|
|---|
| 389 | &srv_chal_out);
|
|---|
| 390 |
|
|---|
| 391 | /* Check client credentials are valid. */
|
|---|
| 392 | if (!creds_server_check(p->dc, &q_u->clnt_chal)) {
|
|---|
| 393 | DEBUG(0,("_net_auth: creds_server_check failed. Rejecting auth "
|
|---|
| 394 | "request from client %s machine account %s\n",
|
|---|
| 395 | remote_machine, mach_acct ));
|
|---|
| 396 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 397 | }
|
|---|
| 398 |
|
|---|
| 399 | fstrcpy(p->dc->mach_acct, mach_acct);
|
|---|
| 400 | fstrcpy(p->dc->remote_machine, remote_machine);
|
|---|
| 401 | p->dc->authenticated = True;
|
|---|
| 402 |
|
|---|
| 403 | /* set up the LSA AUTH response */
|
|---|
| 404 | /* Return the server credentials. */
|
|---|
| 405 | init_net_r_auth(r_u, &srv_chal_out, NT_STATUS_OK);
|
|---|
| 406 |
|
|---|
| 407 | return r_u->status;
|
|---|
| 408 | }
|
|---|
| 409 |
|
|---|
| 410 | /*************************************************************************
|
|---|
| 411 | init_net_r_auth_2:
|
|---|
| 412 | *************************************************************************/
|
|---|
| 413 |
|
|---|
| 414 | static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
|
|---|
| 415 | DOM_CHAL *resp_cred, NEG_FLAGS *flgs, NTSTATUS status)
|
|---|
| 416 | {
|
|---|
| 417 | memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
|
|---|
| 418 | memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
|
|---|
| 419 | r_a->status = status;
|
|---|
| 420 | }
|
|---|
| 421 |
|
|---|
| 422 | /*************************************************************************
|
|---|
| 423 | _net_auth_2
|
|---|
| 424 | *************************************************************************/
|
|---|
| 425 |
|
|---|
| 426 | NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
|
|---|
| 427 | {
|
|---|
| 428 | NTSTATUS status;
|
|---|
| 429 | NEG_FLAGS srv_flgs;
|
|---|
| 430 | fstring mach_acct;
|
|---|
| 431 | fstring remote_machine;
|
|---|
| 432 | DOM_CHAL srv_chal_out;
|
|---|
| 433 |
|
|---|
| 434 | rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
|
|---|
| 435 | q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
|
|---|
| 436 |
|
|---|
| 437 | /* We use this as the key to store the creds. */
|
|---|
| 438 | rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
|
|---|
| 439 | q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
|
|---|
| 440 |
|
|---|
| 441 | if (!p->dc || !p->dc->challenge_sent) {
|
|---|
| 442 | DEBUG(0,("_net_auth2: no challenge sent to client %s\n",
|
|---|
| 443 | remote_machine ));
|
|---|
| 444 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 | if ( (lp_server_schannel() == True) &&
|
|---|
| 448 | ((q_u->clnt_flgs.neg_flags & NETLOGON_NEG_SCHANNEL) == 0) ) {
|
|---|
| 449 |
|
|---|
| 450 | /* schannel must be used, but client did not offer it. */
|
|---|
| 451 | DEBUG(0,("_net_auth2: schannel required but client failed "
|
|---|
| 452 | "to offer it. Client was %s\n",
|
|---|
| 453 | mach_acct ));
|
|---|
| 454 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 455 | }
|
|---|
| 456 |
|
|---|
| 457 | status = get_md4pw((char *)p->dc->mach_pw, mach_acct, q_u->clnt_id.sec_chan);
|
|---|
| 458 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 459 | DEBUG(0,("_net_auth2: failed to get machine password for "
|
|---|
| 460 | "account %s: %s\n",
|
|---|
| 461 | mach_acct, nt_errstr(status) ));
|
|---|
| 462 | /* always return NT_STATUS_ACCESS_DENIED */
|
|---|
| 463 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 464 | }
|
|---|
| 465 |
|
|---|
| 466 | /* From the client / server challenges and md4 password, generate sess key */
|
|---|
| 467 | creds_server_init(q_u->clnt_flgs.neg_flags,
|
|---|
| 468 | p->dc,
|
|---|
| 469 | &p->dc->clnt_chal, /* Stored client chal. */
|
|---|
| 470 | &p->dc->srv_chal, /* Stored server chal. */
|
|---|
| 471 | p->dc->mach_pw,
|
|---|
| 472 | &srv_chal_out);
|
|---|
| 473 |
|
|---|
| 474 | /* Check client credentials are valid. */
|
|---|
| 475 | if (!creds_server_check(p->dc, &q_u->clnt_chal)) {
|
|---|
| 476 | DEBUG(0,("_net_auth2: creds_server_check failed. Rejecting auth "
|
|---|
| 477 | "request from client %s machine account %s\n",
|
|---|
| 478 | remote_machine, mach_acct ));
|
|---|
| 479 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 480 | }
|
|---|
| 481 |
|
|---|
| 482 | srv_flgs.neg_flags = 0x000001ff;
|
|---|
| 483 |
|
|---|
| 484 | if (lp_server_schannel() != False) {
|
|---|
| 485 | srv_flgs.neg_flags |= NETLOGON_NEG_SCHANNEL;
|
|---|
| 486 | }
|
|---|
| 487 |
|
|---|
| 488 | /* set up the LSA AUTH 2 response */
|
|---|
| 489 | init_net_r_auth_2(r_u, &srv_chal_out, &srv_flgs, NT_STATUS_OK);
|
|---|
| 490 |
|
|---|
| 491 | fstrcpy(p->dc->mach_acct, mach_acct);
|
|---|
| 492 | fstrcpy(p->dc->remote_machine, remote_machine);
|
|---|
| 493 | fstrcpy(p->dc->domain, lp_workgroup() );
|
|---|
| 494 |
|
|---|
| 495 | p->dc->authenticated = True;
|
|---|
| 496 |
|
|---|
| 497 | /* Store off the state so we can continue after client disconnect. */
|
|---|
| 498 | become_root();
|
|---|
| 499 | secrets_store_schannel_session_info(p->mem_ctx,
|
|---|
| 500 | remote_machine,
|
|---|
| 501 | p->dc);
|
|---|
| 502 | unbecome_root();
|
|---|
| 503 |
|
|---|
| 504 | return r_u->status;
|
|---|
| 505 | }
|
|---|
| 506 |
|
|---|
| 507 | /*************************************************************************
|
|---|
| 508 | _net_srv_pwset
|
|---|
| 509 | *************************************************************************/
|
|---|
| 510 |
|
|---|
| 511 | NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
|
|---|
| 512 | {
|
|---|
| 513 | fstring remote_machine;
|
|---|
| 514 | struct samu *sampass=NULL;
|
|---|
| 515 | BOOL ret = False;
|
|---|
| 516 | unsigned char pwd[16];
|
|---|
| 517 | int i;
|
|---|
| 518 | uint32 acct_ctrl;
|
|---|
| 519 | DOM_CRED cred_out;
|
|---|
| 520 | const uchar *old_pw;
|
|---|
| 521 |
|
|---|
| 522 | DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
|
|---|
| 523 |
|
|---|
| 524 | /* We need the remote machine name for the creds lookup. */
|
|---|
| 525 | rpcstr_pull(remote_machine,q_u->clnt_id.login.uni_comp_name.buffer,
|
|---|
| 526 | sizeof(remote_machine),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
|
|---|
| 527 |
|
|---|
| 528 | if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
|
|---|
| 529 | /* 'server schannel = yes' should enforce use of
|
|---|
| 530 | schannel, the client did offer it in auth2, but
|
|---|
| 531 | obviously did not use it. */
|
|---|
| 532 | DEBUG(0,("_net_srv_pwset: client %s not using schannel for netlogon\n",
|
|---|
| 533 | remote_machine ));
|
|---|
| 534 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 535 | }
|
|---|
| 536 |
|
|---|
| 537 | if (!p->dc) {
|
|---|
| 538 | /* Restore the saved state of the netlogon creds. */
|
|---|
| 539 | become_root();
|
|---|
| 540 | ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 541 | remote_machine,
|
|---|
| 542 | &p->dc);
|
|---|
| 543 | unbecome_root();
|
|---|
| 544 | if (!ret) {
|
|---|
| 545 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 546 | }
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | if (!p->dc || !p->dc->authenticated) {
|
|---|
| 550 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | DEBUG(3,("_net_srv_pwset: Server Password Set by remote machine:[%s] on account [%s]\n",
|
|---|
| 554 | remote_machine, p->dc->mach_acct));
|
|---|
| 555 |
|
|---|
| 556 | /* Step the creds chain forward. */
|
|---|
| 557 | if (!creds_server_step(p->dc, &q_u->clnt_id.cred, &cred_out)) {
|
|---|
| 558 | DEBUG(2,("_net_srv_pwset: creds_server_step failed. Rejecting auth "
|
|---|
| 559 | "request from client %s machine account %s\n",
|
|---|
| 560 | remote_machine, p->dc->mach_acct ));
|
|---|
| 561 | return NT_STATUS_INVALID_PARAMETER;
|
|---|
| 562 | }
|
|---|
| 563 |
|
|---|
| 564 | /* We must store the creds state after an update. */
|
|---|
| 565 | sampass = samu_new( NULL );
|
|---|
| 566 | if (!sampass) {
|
|---|
| 567 | return NT_STATUS_NO_MEMORY;
|
|---|
| 568 | }
|
|---|
| 569 |
|
|---|
| 570 | become_root();
|
|---|
| 571 | secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 572 | remote_machine,
|
|---|
| 573 | p->dc);
|
|---|
| 574 | ret = pdb_getsampwnam(sampass, p->dc->mach_acct);
|
|---|
| 575 | unbecome_root();
|
|---|
| 576 |
|
|---|
| 577 | if (!ret) {
|
|---|
| 578 | TALLOC_FREE(sampass);
|
|---|
| 579 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 580 | }
|
|---|
| 581 |
|
|---|
| 582 | /* Ensure the account exists and is a machine account. */
|
|---|
| 583 |
|
|---|
| 584 | acct_ctrl = pdb_get_acct_ctrl(sampass);
|
|---|
| 585 |
|
|---|
| 586 | if (!(acct_ctrl & ACB_WSTRUST ||
|
|---|
| 587 | acct_ctrl & ACB_SVRTRUST ||
|
|---|
| 588 | acct_ctrl & ACB_DOMTRUST)) {
|
|---|
| 589 | TALLOC_FREE(sampass);
|
|---|
| 590 | return NT_STATUS_NO_SUCH_USER;
|
|---|
| 591 | }
|
|---|
| 592 |
|
|---|
| 593 | if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
|
|---|
| 594 | TALLOC_FREE(sampass);
|
|---|
| 595 | return NT_STATUS_ACCOUNT_DISABLED;
|
|---|
| 596 | }
|
|---|
| 597 |
|
|---|
| 598 | /* Woah - what does this to to the credential chain ? JRA */
|
|---|
| 599 | cred_hash3( pwd, q_u->pwd, p->dc->sess_key, 0);
|
|---|
| 600 |
|
|---|
| 601 | DEBUG(100,("Server password set : new given value was :\n"));
|
|---|
| 602 | for(i = 0; i < sizeof(pwd); i++)
|
|---|
| 603 | DEBUG(100,("%02X ", pwd[i]));
|
|---|
| 604 | DEBUG(100,("\n"));
|
|---|
| 605 |
|
|---|
| 606 | old_pw = pdb_get_nt_passwd(sampass);
|
|---|
| 607 |
|
|---|
| 608 | if (old_pw && memcmp(pwd, old_pw, 16) == 0) {
|
|---|
| 609 | /* Avoid backend modificiations and other fun if the
|
|---|
| 610 | client changed the password to the *same thing* */
|
|---|
| 611 |
|
|---|
| 612 | ret = True;
|
|---|
| 613 | } else {
|
|---|
| 614 |
|
|---|
| 615 | /* LM password should be NULL for machines */
|
|---|
| 616 | if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
|
|---|
| 617 | TALLOC_FREE(sampass);
|
|---|
| 618 | return NT_STATUS_NO_MEMORY;
|
|---|
| 619 | }
|
|---|
| 620 |
|
|---|
| 621 | if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
|
|---|
| 622 | TALLOC_FREE(sampass);
|
|---|
| 623 | return NT_STATUS_NO_MEMORY;
|
|---|
| 624 | }
|
|---|
| 625 |
|
|---|
| 626 | if (!pdb_set_pass_last_set_time(sampass, time(NULL), PDB_CHANGED)) {
|
|---|
| 627 | TALLOC_FREE(sampass);
|
|---|
| 628 | /* Not quite sure what this one qualifies as, but this will do */
|
|---|
| 629 | return NT_STATUS_UNSUCCESSFUL;
|
|---|
| 630 | }
|
|---|
| 631 |
|
|---|
| 632 | become_root();
|
|---|
| 633 | r_u->status = pdb_update_sam_account(sampass);
|
|---|
| 634 | unbecome_root();
|
|---|
| 635 | }
|
|---|
| 636 |
|
|---|
| 637 | /* set up the LSA Server Password Set response */
|
|---|
| 638 | init_net_r_srv_pwset(r_u, &cred_out, r_u->status);
|
|---|
| 639 |
|
|---|
| 640 | TALLOC_FREE(sampass);
|
|---|
| 641 | return r_u->status;
|
|---|
| 642 | }
|
|---|
| 643 |
|
|---|
| 644 | /*************************************************************************
|
|---|
| 645 | _net_sam_logoff:
|
|---|
| 646 | *************************************************************************/
|
|---|
| 647 |
|
|---|
| 648 | NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
|
|---|
| 649 | {
|
|---|
| 650 | fstring remote_machine;
|
|---|
| 651 |
|
|---|
| 652 | if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
|
|---|
| 653 | /* 'server schannel = yes' should enforce use of
|
|---|
| 654 | schannel, the client did offer it in auth2, but
|
|---|
| 655 | obviously did not use it. */
|
|---|
| 656 | DEBUG(0,("_net_sam_logoff: client %s not using schannel for netlogon\n",
|
|---|
| 657 | get_remote_machine_name() ));
|
|---|
| 658 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 659 | }
|
|---|
| 660 |
|
|---|
| 661 |
|
|---|
| 662 | if (!get_valid_user_struct(p->vuid))
|
|---|
| 663 | return NT_STATUS_NO_SUCH_USER;
|
|---|
| 664 |
|
|---|
| 665 | /* Get the remote machine name for the creds store. */
|
|---|
| 666 | rpcstr_pull(remote_machine,q_u->sam_id.client.login.uni_comp_name.buffer,
|
|---|
| 667 | sizeof(remote_machine),q_u->sam_id.client.login.uni_comp_name.uni_str_len*2,0);
|
|---|
| 668 |
|
|---|
| 669 | if (!p->dc) {
|
|---|
| 670 | /* Restore the saved state of the netlogon creds. */
|
|---|
| 671 | BOOL ret;
|
|---|
| 672 |
|
|---|
| 673 | become_root();
|
|---|
| 674 | ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 675 | remote_machine,
|
|---|
| 676 | &p->dc);
|
|---|
| 677 | unbecome_root();
|
|---|
| 678 | if (!ret) {
|
|---|
| 679 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 680 | }
|
|---|
| 681 | }
|
|---|
| 682 |
|
|---|
| 683 | if (!p->dc || !p->dc->authenticated) {
|
|---|
| 684 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 685 | }
|
|---|
| 686 |
|
|---|
| 687 | r_u->buffer_creds = 1; /* yes, we have valid server credentials */
|
|---|
| 688 |
|
|---|
| 689 | /* checks and updates credentials. creates reply credentials */
|
|---|
| 690 | if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
|
|---|
| 691 | DEBUG(2,("_net_sam_logoff: creds_server_step failed. Rejecting auth "
|
|---|
| 692 | "request from client %s machine account %s\n",
|
|---|
| 693 | remote_machine, p->dc->mach_acct ));
|
|---|
| 694 | return NT_STATUS_INVALID_PARAMETER;
|
|---|
| 695 | }
|
|---|
| 696 |
|
|---|
| 697 | /* We must store the creds state after an update. */
|
|---|
| 698 | become_root();
|
|---|
| 699 | secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 700 | remote_machine,
|
|---|
| 701 | p->dc);
|
|---|
| 702 | unbecome_root();
|
|---|
| 703 |
|
|---|
| 704 | r_u->status = NT_STATUS_OK;
|
|---|
| 705 | return r_u->status;
|
|---|
| 706 | }
|
|---|
| 707 |
|
|---|
| 708 | /*******************************************************************
|
|---|
| 709 | gets a domain user's groups from their already-calculated NT_USER_TOKEN
|
|---|
| 710 | ********************************************************************/
|
|---|
| 711 |
|
|---|
| 712 | static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx,
|
|---|
| 713 | const DOM_SID *domain_sid,
|
|---|
| 714 | size_t num_sids,
|
|---|
| 715 | const DOM_SID *sids,
|
|---|
| 716 | int *numgroups, DOM_GID **pgids)
|
|---|
| 717 | {
|
|---|
| 718 | int i;
|
|---|
| 719 |
|
|---|
| 720 | *numgroups=0;
|
|---|
| 721 | *pgids = NULL;
|
|---|
| 722 |
|
|---|
| 723 | for (i=0; i<num_sids; i++) {
|
|---|
| 724 | DOM_GID gid;
|
|---|
| 725 | if (!sid_peek_check_rid(domain_sid, &sids[i], &gid.g_rid)) {
|
|---|
| 726 | continue;
|
|---|
| 727 | }
|
|---|
| 728 | gid.attr = (SE_GROUP_MANDATORY|SE_GROUP_ENABLED_BY_DEFAULT|
|
|---|
| 729 | SE_GROUP_ENABLED);
|
|---|
| 730 | ADD_TO_ARRAY(mem_ctx, DOM_GID, gid, pgids, numgroups);
|
|---|
| 731 | if (*pgids == NULL) {
|
|---|
| 732 | return NT_STATUS_NO_MEMORY;
|
|---|
| 733 | }
|
|---|
| 734 | }
|
|---|
| 735 | return NT_STATUS_OK;
|
|---|
| 736 | }
|
|---|
| 737 |
|
|---|
| 738 | /*************************************************************************
|
|---|
| 739 | _net_sam_logon
|
|---|
| 740 | *************************************************************************/
|
|---|
| 741 |
|
|---|
| 742 | static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
|
|---|
| 743 | NET_Q_SAM_LOGON *q_u,
|
|---|
| 744 | NET_R_SAM_LOGON *r_u,
|
|---|
| 745 | BOOL process_creds)
|
|---|
| 746 | {
|
|---|
| 747 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 748 | NET_USER_INFO_3 *usr_info = NULL;
|
|---|
| 749 | NET_ID_INFO_CTR *ctr = q_u->sam_id.ctr;
|
|---|
| 750 | UNISTR2 *uni_samlogon_user = NULL;
|
|---|
| 751 | UNISTR2 *uni_samlogon_domain = NULL;
|
|---|
| 752 | UNISTR2 *uni_samlogon_workstation = NULL;
|
|---|
| 753 | fstring nt_username, nt_domain, nt_workstation;
|
|---|
| 754 | auth_usersupplied_info *user_info = NULL;
|
|---|
| 755 | auth_serversupplied_info *server_info = NULL;
|
|---|
| 756 | struct samu *sampw;
|
|---|
| 757 | struct auth_context *auth_context = NULL;
|
|---|
| 758 |
|
|---|
| 759 | if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
|
|---|
| 760 | /* 'server schannel = yes' should enforce use of
|
|---|
| 761 | schannel, the client did offer it in auth2, but
|
|---|
| 762 | obviously did not use it. */
|
|---|
| 763 | DEBUG(0,("_net_sam_logon_internal: client %s not using schannel for netlogon\n",
|
|---|
| 764 | get_remote_machine_name() ));
|
|---|
| 765 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 766 | }
|
|---|
| 767 |
|
|---|
| 768 | usr_info = TALLOC_P(p->mem_ctx, NET_USER_INFO_3);
|
|---|
| 769 | if (!usr_info) {
|
|---|
| 770 | return NT_STATUS_NO_MEMORY;
|
|---|
| 771 | }
|
|---|
| 772 |
|
|---|
| 773 | ZERO_STRUCTP(usr_info);
|
|---|
| 774 |
|
|---|
| 775 | /* store the user information, if there is any. */
|
|---|
| 776 | r_u->user = usr_info;
|
|---|
| 777 | r_u->auth_resp = 1; /* authoritative response */
|
|---|
| 778 | if (q_u->validation_level != 2 && q_u->validation_level != 3) {
|
|---|
| 779 | DEBUG(0,("_net_sam_logon: bad validation_level value %d.\n", (int)q_u->validation_level ));
|
|---|
| 780 | return NT_STATUS_ACCESS_DENIED;
|
|---|
| 781 | }
|
|---|
| 782 | /* We handle the return of USER_INFO_2 instead of 3 in the parse return. Sucks, I know... */
|
|---|
| 783 | r_u->switch_value = q_u->validation_level; /* indicates type of validation user info */
|
|---|
| 784 | r_u->buffer_creds = 1; /* Ensure we always return server creds. */
|
|---|
| 785 |
|
|---|
| 786 | if (!get_valid_user_struct(p->vuid))
|
|---|
| 787 | return NT_STATUS_NO_SUCH_USER;
|
|---|
| 788 |
|
|---|
| 789 | if (process_creds) {
|
|---|
| 790 | fstring remote_machine;
|
|---|
| 791 |
|
|---|
| 792 | /* Get the remote machine name for the creds store. */
|
|---|
| 793 | /* Note this is the remote machine this request is coming from (member server),
|
|---|
| 794 | not neccessarily the workstation name the user is logging onto.
|
|---|
| 795 | */
|
|---|
| 796 | rpcstr_pull(remote_machine,q_u->sam_id.client.login.uni_comp_name.buffer,
|
|---|
| 797 | sizeof(remote_machine),q_u->sam_id.client.login.uni_comp_name.uni_str_len*2,0);
|
|---|
| 798 |
|
|---|
| 799 | if (!p->dc) {
|
|---|
| 800 | /* Restore the saved state of the netlogon creds. */
|
|---|
| 801 | BOOL ret;
|
|---|
| 802 |
|
|---|
| 803 | become_root();
|
|---|
| 804 | ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 805 | remote_machine,
|
|---|
| 806 | &p->dc);
|
|---|
| 807 | unbecome_root();
|
|---|
| 808 | if (!ret) {
|
|---|
| 809 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 810 | }
|
|---|
| 811 | }
|
|---|
| 812 |
|
|---|
| 813 | if (!p->dc || !p->dc->authenticated) {
|
|---|
| 814 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 815 | }
|
|---|
| 816 |
|
|---|
| 817 | /* checks and updates credentials. creates reply credentials */
|
|---|
| 818 | if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
|
|---|
| 819 | DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth "
|
|---|
| 820 | "request from client %s machine account %s\n",
|
|---|
| 821 | remote_machine, p->dc->mach_acct ));
|
|---|
| 822 | return NT_STATUS_INVALID_PARAMETER;
|
|---|
| 823 | }
|
|---|
| 824 |
|
|---|
| 825 | /* We must store the creds state after an update. */
|
|---|
| 826 | become_root();
|
|---|
| 827 | secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
|
|---|
| 828 | remote_machine,
|
|---|
| 829 | p->dc);
|
|---|
| 830 | unbecome_root();
|
|---|
| 831 | }
|
|---|
| 832 |
|
|---|
| 833 | switch (q_u->sam_id.logon_level) {
|
|---|
| 834 | case INTERACTIVE_LOGON_TYPE:
|
|---|
| 835 | uni_samlogon_user = &ctr->auth.id1.uni_user_name;
|
|---|
| 836 | uni_samlogon_domain = &ctr->auth.id1.uni_domain_name;
|
|---|
| 837 |
|
|---|
| 838 | uni_samlogon_workstation = &ctr->auth.id1.uni_wksta_name;
|
|---|
| 839 |
|
|---|
| 840 | DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
|
|---|
| 841 | break;
|
|---|
| 842 | case NET_LOGON_TYPE:
|
|---|
| 843 | uni_samlogon_user = &ctr->auth.id2.uni_user_name;
|
|---|
| 844 | uni_samlogon_domain = &ctr->auth.id2.uni_domain_name;
|
|---|
| 845 | uni_samlogon_workstation = &ctr->auth.id2.uni_wksta_name;
|
|---|
| 846 |
|
|---|
| 847 | DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
|
|---|
| 848 | break;
|
|---|
| 849 | default:
|
|---|
| 850 | DEBUG(2,("SAM Logon: unsupported switch value\n"));
|
|---|
| 851 | return NT_STATUS_INVALID_INFO_CLASS;
|
|---|
| 852 | } /* end switch */
|
|---|
| 853 |
|
|---|
| 854 | rpcstr_pull(nt_username,uni_samlogon_user->buffer,sizeof(nt_username),uni_samlogon_user->uni_str_len*2,0);
|
|---|
| 855 | rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
|
|---|
| 856 | rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);
|
|---|
| 857 |
|
|---|
| 858 | DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain));
|
|---|
| 859 | fstrcpy(current_user_info.smb_name, nt_username);
|
|---|
| 860 | sub_set_smb_name(nt_username);
|
|---|
| 861 |
|
|---|
| 862 | DEBUG(5,("Attempting validation level %d for unmapped username %s.\n", q_u->sam_id.ctr->switch_value, nt_username));
|
|---|
| 863 |
|
|---|
| 864 | status = NT_STATUS_OK;
|
|---|
| 865 |
|
|---|
| 866 | switch (ctr->switch_value) {
|
|---|
| 867 | case NET_LOGON_TYPE:
|
|---|
| 868 | {
|
|---|
| 869 | const char *wksname = nt_workstation;
|
|---|
| 870 |
|
|---|
| 871 | if (!NT_STATUS_IS_OK(status = make_auth_context_fixed(&auth_context, ctr->auth.id2.lm_chal))) {
|
|---|
| 872 | return status;
|
|---|
| 873 | }
|
|---|
| 874 |
|
|---|
| 875 | /* For a network logon, the workstation name comes in with two
|
|---|
| 876 | * backslashes in the front. Strip them if they are there. */
|
|---|
| 877 |
|
|---|
| 878 | if (*wksname == '\\') wksname++;
|
|---|
| 879 | if (*wksname == '\\') wksname++;
|
|---|
| 880 |
|
|---|
| 881 | /* Standard challenge/response authenticaion */
|
|---|
| 882 | if (!make_user_info_netlogon_network(&user_info,
|
|---|
| 883 | nt_username, nt_domain,
|
|---|
| 884 | wksname,
|
|---|
| 885 | ctr->auth.id2.param_ctrl,
|
|---|
| 886 | ctr->auth.id2.lm_chal_resp.buffer,
|
|---|
| 887 | ctr->auth.id2.lm_chal_resp.str_str_len,
|
|---|
| 888 | ctr->auth.id2.nt_chal_resp.buffer,
|
|---|
| 889 | ctr->auth.id2.nt_chal_resp.str_str_len)) {
|
|---|
| 890 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 891 | }
|
|---|
| 892 | break;
|
|---|
| 893 | }
|
|---|
| 894 | case INTERACTIVE_LOGON_TYPE:
|
|---|
| 895 | /* 'Interactive' authentication, supplies the password in its
|
|---|
| 896 | MD4 form, encrypted with the session key. We will convert
|
|---|
| 897 | this to challenge/response for the auth subsystem to chew
|
|---|
| 898 | on */
|
|---|
| 899 | {
|
|---|
| 900 | const uint8 *chal;
|
|---|
| 901 |
|
|---|
| 902 | if (!NT_STATUS_IS_OK(status = make_auth_context_subsystem(&auth_context))) {
|
|---|
| 903 | return status;
|
|---|
| 904 | }
|
|---|
| 905 |
|
|---|
| 906 | chal = auth_context->get_ntlm_challenge(auth_context);
|
|---|
| 907 |
|
|---|
| 908 | if (!make_user_info_netlogon_interactive(&user_info,
|
|---|
| 909 | nt_username, nt_domain,
|
|---|
| 910 | nt_workstation,
|
|---|
| 911 | ctr->auth.id1.param_ctrl,
|
|---|
| 912 | chal,
|
|---|
| 913 | ctr->auth.id1.lm_owf.data,
|
|---|
| 914 | ctr->auth.id1.nt_owf.data,
|
|---|
| 915 | p->dc->sess_key)) {
|
|---|
| 916 | status = NT_STATUS_NO_MEMORY;
|
|---|
| 917 | }
|
|---|
| 918 | break;
|
|---|
| 919 | }
|
|---|
| 920 | default:
|
|---|
| 921 | DEBUG(2,("SAM Logon: unsupported switch value\n"));
|
|---|
| 922 | return NT_STATUS_INVALID_INFO_CLASS;
|
|---|
| 923 | } /* end switch */
|
|---|
| 924 |
|
|---|
| 925 | if ( NT_STATUS_IS_OK(status) ) {
|
|---|
| 926 | status = auth_context->check_ntlm_password(auth_context,
|
|---|
| 927 | user_info, &server_info);
|
|---|
| 928 | }
|
|---|
| 929 |
|
|---|
| 930 | (auth_context->free)(&auth_context);
|
|---|
| 931 | free_user_info(&user_info);
|
|---|
| 932 |
|
|---|
| 933 | DEBUG(5, ("_net_sam_logon: check_password returned status %s\n",
|
|---|
| 934 | nt_errstr(status)));
|
|---|
| 935 |
|
|---|
| 936 | /* Check account and password */
|
|---|
| 937 |
|
|---|
| 938 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 939 | /* If we don't know what this domain is, we need to
|
|---|
| 940 | indicate that we are not authoritative. This
|
|---|
| 941 | allows the client to decide if it needs to try
|
|---|
| 942 | a local user. Fix by [email protected], #2976 */
|
|---|
| 943 | if ( NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
|
|---|
| 944 | && !strequal(nt_domain, get_global_sam_name())
|
|---|
| 945 | && !is_trusted_domain(nt_domain) )
|
|---|
| 946 | r_u->auth_resp = 0; /* We are not authoritative */
|
|---|
| 947 |
|
|---|
| 948 | TALLOC_FREE(server_info);
|
|---|
| 949 | return status;
|
|---|
| 950 | }
|
|---|
| 951 |
|
|---|
| 952 | if (server_info->guest) {
|
|---|
| 953 | /* We don't like guest domain logons... */
|
|---|
| 954 | DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST "
|
|---|
| 955 | "denied.\n"));
|
|---|
| 956 | TALLOC_FREE(server_info);
|
|---|
| 957 | return NT_STATUS_LOGON_FAILURE;
|
|---|
| 958 | }
|
|---|
| 959 |
|
|---|
| 960 | /* This is the point at which, if the login was successful, that
|
|---|
| 961 | the SAM Local Security Authority should record that the user is
|
|---|
| 962 | logged in to the domain. */
|
|---|
| 963 |
|
|---|
| 964 | {
|
|---|
| 965 | DOM_GID *gids = NULL;
|
|---|
| 966 | const DOM_SID *user_sid = NULL;
|
|---|
| 967 | const DOM_SID *group_sid = NULL;
|
|---|
| 968 | DOM_SID domain_sid;
|
|---|
| 969 | uint32 user_rid, group_rid;
|
|---|
| 970 |
|
|---|
| 971 | int num_gids = 0;
|
|---|
| 972 | pstring my_name;
|
|---|
| 973 | fstring user_sid_string;
|
|---|
| 974 | fstring group_sid_string;
|
|---|
| 975 | unsigned char user_session_key[16];
|
|---|
| 976 | unsigned char lm_session_key[16];
|
|---|
| 977 | unsigned char pipe_session_key[16];
|
|---|
| 978 |
|
|---|
| 979 | sampw = server_info->sam_account;
|
|---|
| 980 |
|
|---|
| 981 | /* set up pointer indicating user/password failed to be
|
|---|
| 982 | * found */
|
|---|
| 983 | usr_info->ptr_user_info = 0;
|
|---|
| 984 |
|
|---|
| 985 | user_sid = pdb_get_user_sid(sampw);
|
|---|
| 986 | group_sid = pdb_get_group_sid(sampw);
|
|---|
| 987 |
|
|---|
| 988 | if ((user_sid == NULL) || (group_sid == NULL)) {
|
|---|
| 989 | DEBUG(1, ("_net_sam_logon: User without group or user SID\n"));
|
|---|
| 990 | return NT_STATUS_UNSUCCESSFUL;
|
|---|
| 991 | }
|
|---|
| 992 |
|
|---|
| 993 | sid_copy(&domain_sid, user_sid);
|
|---|
| 994 | sid_split_rid(&domain_sid, &user_rid);
|
|---|
| 995 |
|
|---|
| 996 | if (!sid_peek_check_rid(&domain_sid, group_sid, &group_rid)) {
|
|---|
| 997 | DEBUG(1, ("_net_sam_logon: user %s\\%s has user sid "
|
|---|
| 998 | "%s\n but group sid %s.\n"
|
|---|
| 999 | "The conflicting domain portions are not "
|
|---|
| 1000 | "supported for NETLOGON calls\n",
|
|---|
| 1001 | pdb_get_domain(sampw),
|
|---|
| 1002 | pdb_get_username(sampw),
|
|---|
| 1003 | sid_to_string(user_sid_string, user_sid),
|
|---|
| 1004 | sid_to_string(group_sid_string, group_sid)));
|
|---|
| 1005 | return NT_STATUS_UNSUCCESSFUL;
|
|---|
| 1006 | }
|
|---|
| 1007 |
|
|---|
| 1008 |
|
|---|
| 1009 | if(server_info->login_server) {
|
|---|
| 1010 | pstrcpy(my_name, server_info->login_server);
|
|---|
| 1011 | } else {
|
|---|
| 1012 | pstrcpy(my_name, global_myname());
|
|---|
| 1013 | }
|
|---|
| 1014 |
|
|---|
| 1015 | status = nt_token_to_group_list(p->mem_ctx, &domain_sid,
|
|---|
| 1016 | server_info->num_sids,
|
|---|
| 1017 | server_info->sids,
|
|---|
| 1018 | &num_gids, &gids);
|
|---|
| 1019 |
|
|---|
| 1020 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 1021 | return status;
|
|---|
| 1022 | }
|
|---|
| 1023 |
|
|---|
| 1024 | if (server_info->user_session_key.length) {
|
|---|
| 1025 | memcpy(user_session_key,
|
|---|
| 1026 | server_info->user_session_key.data,
|
|---|
| 1027 | MIN(sizeof(user_session_key),
|
|---|
| 1028 | server_info->user_session_key.length));
|
|---|
| 1029 | if (process_creds) {
|
|---|
| 1030 | /* Get the pipe session key from the creds. */
|
|---|
| 1031 | memcpy(pipe_session_key, p->dc->sess_key, 16);
|
|---|
| 1032 | } else {
|
|---|
| 1033 | /* Get the pipe session key from the schannel. */
|
|---|
| 1034 | if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
|
|---|
| 1035 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 1036 | }
|
|---|
| 1037 | memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
|
|---|
| 1038 | }
|
|---|
| 1039 | SamOEMhash(user_session_key, pipe_session_key, 16);
|
|---|
| 1040 | memset(pipe_session_key, '\0', 16);
|
|---|
| 1041 | }
|
|---|
| 1042 | if (server_info->lm_session_key.length) {
|
|---|
| 1043 | memcpy(lm_session_key,
|
|---|
| 1044 | server_info->lm_session_key.data,
|
|---|
| 1045 | MIN(sizeof(lm_session_key),
|
|---|
| 1046 | server_info->lm_session_key.length));
|
|---|
| 1047 | if (process_creds) {
|
|---|
| 1048 | /* Get the pipe session key from the creds. */
|
|---|
| 1049 | memcpy(pipe_session_key, p->dc->sess_key, 16);
|
|---|
| 1050 | } else {
|
|---|
| 1051 | /* Get the pipe session key from the schannel. */
|
|---|
| 1052 | if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
|
|---|
| 1053 | return NT_STATUS_INVALID_HANDLE;
|
|---|
| 1054 | }
|
|---|
| 1055 | memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
|
|---|
| 1056 | }
|
|---|
| 1057 | SamOEMhash(lm_session_key, pipe_session_key, 16);
|
|---|
| 1058 | memset(pipe_session_key, '\0', 16);
|
|---|
| 1059 | }
|
|---|
| 1060 |
|
|---|
| 1061 | init_net_user_info3(p->mem_ctx, usr_info,
|
|---|
| 1062 | user_rid,
|
|---|
| 1063 | group_rid,
|
|---|
| 1064 | pdb_get_username(sampw),
|
|---|
| 1065 | pdb_get_fullname(sampw),
|
|---|
| 1066 | pdb_get_homedir(sampw),
|
|---|
| 1067 | pdb_get_dir_drive(sampw),
|
|---|
| 1068 | pdb_get_logon_script(sampw),
|
|---|
| 1069 | pdb_get_profile_path(sampw),
|
|---|
| 1070 | pdb_get_logon_time(sampw),
|
|---|
| 1071 | get_time_t_max(),
|
|---|
| 1072 | get_time_t_max(),
|
|---|
| 1073 | pdb_get_pass_last_set_time(sampw),
|
|---|
| 1074 | pdb_get_pass_can_change_time(sampw),
|
|---|
| 1075 | pdb_get_pass_must_change_time(sampw),
|
|---|
| 1076 | 0, /* logon_count */
|
|---|
| 1077 | 0, /* bad_pw_count */
|
|---|
| 1078 | num_gids, /* uint32 num_groups */
|
|---|
| 1079 | gids , /* DOM_GID *gids */
|
|---|
| 1080 | LOGON_EXTRA_SIDS, /* uint32 user_flgs (?) */
|
|---|
| 1081 | pdb_get_acct_ctrl(sampw),
|
|---|
| 1082 | server_info->user_session_key.length ? user_session_key : NULL,
|
|---|
| 1083 | server_info->lm_session_key.length ? lm_session_key : NULL,
|
|---|
| 1084 | my_name , /* char *logon_srv */
|
|---|
| 1085 | pdb_get_domain(sampw),
|
|---|
| 1086 | &domain_sid); /* DOM_SID *dom_sid */
|
|---|
| 1087 | ZERO_STRUCT(user_session_key);
|
|---|
| 1088 | ZERO_STRUCT(lm_session_key);
|
|---|
| 1089 | }
|
|---|
| 1090 | TALLOC_FREE(server_info);
|
|---|
| 1091 | return status;
|
|---|
| 1092 | }
|
|---|
| 1093 |
|
|---|
| 1094 | /*************************************************************************
|
|---|
| 1095 | _net_sam_logon
|
|---|
| 1096 | *************************************************************************/
|
|---|
| 1097 |
|
|---|
| 1098 | NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
|
|---|
| 1099 | {
|
|---|
| 1100 | return _net_sam_logon_internal(p, q_u, r_u, True);
|
|---|
| 1101 | }
|
|---|
| 1102 |
|
|---|
| 1103 | /*************************************************************************
|
|---|
| 1104 | _net_sam_logon_ex - no credential chaining. Map into net sam logon.
|
|---|
| 1105 | *************************************************************************/
|
|---|
| 1106 |
|
|---|
| 1107 | NTSTATUS _net_sam_logon_ex(pipes_struct *p, NET_Q_SAM_LOGON_EX *q_u, NET_R_SAM_LOGON_EX *r_u)
|
|---|
| 1108 | {
|
|---|
| 1109 | NET_Q_SAM_LOGON q;
|
|---|
| 1110 | NET_R_SAM_LOGON r;
|
|---|
| 1111 |
|
|---|
| 1112 | ZERO_STRUCT(q);
|
|---|
| 1113 | ZERO_STRUCT(r);
|
|---|
| 1114 |
|
|---|
| 1115 | /* Only allow this if the pipe is protected. */
|
|---|
| 1116 | if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
|
|---|
| 1117 | DEBUG(0,("_net_sam_logon_ex: client %s not using schannel for netlogon\n",
|
|---|
| 1118 | get_remote_machine_name() ));
|
|---|
| 1119 | return NT_STATUS_INVALID_PARAMETER;
|
|---|
| 1120 | }
|
|---|
| 1121 |
|
|---|
| 1122 | /* Map a NET_Q_SAM_LOGON_EX to NET_Q_SAM_LOGON. */
|
|---|
| 1123 | q.validation_level = q_u->validation_level;
|
|---|
| 1124 |
|
|---|
| 1125 | /* Map a DOM_SAM_INFO_EX into a DOM_SAM_INFO with no creds. */
|
|---|
| 1126 | q.sam_id.client.login = q_u->sam_id.client;
|
|---|
| 1127 | q.sam_id.logon_level = q_u->sam_id.logon_level;
|
|---|
| 1128 | q.sam_id.ctr = q_u->sam_id.ctr;
|
|---|
| 1129 |
|
|---|
| 1130 | r_u->status = _net_sam_logon_internal(p, &q, &r, False);
|
|---|
| 1131 |
|
|---|
| 1132 | if (!NT_STATUS_IS_OK(r_u->status)) {
|
|---|
| 1133 | return r_u->status;
|
|---|
| 1134 | }
|
|---|
| 1135 |
|
|---|
| 1136 | /* Map the NET_R_SAM_LOGON to NET_R_SAM_LOGON_EX. */
|
|---|
| 1137 | r_u->switch_value = r.switch_value;
|
|---|
| 1138 | r_u->user = r.user;
|
|---|
| 1139 | r_u->auth_resp = r.auth_resp;
|
|---|
| 1140 | r_u->flags = 0; /* FIXME ! */
|
|---|
| 1141 | return r_u->status;
|
|---|
| 1142 | }
|
|---|
| 1143 |
|
|---|
| 1144 | /*************************************************************************
|
|---|
| 1145 | _ds_enum_dom_trusts
|
|---|
| 1146 | *************************************************************************/
|
|---|
| 1147 | #if 0 /* JERRY -- not correct */
|
|---|
| 1148 | NTSTATUS _ds_enum_dom_trusts(pipes_struct *p, DS_Q_ENUM_DOM_TRUSTS *q_u,
|
|---|
| 1149 | DS_R_ENUM_DOM_TRUSTS *r_u)
|
|---|
| 1150 | {
|
|---|
| 1151 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 1152 |
|
|---|
| 1153 | /* TODO: According to MSDN, the can only be executed against a
|
|---|
| 1154 | DC or domain member running Windows 2000 or later. Need
|
|---|
| 1155 | to test against a standalone 2k server and see what it
|
|---|
| 1156 | does. A windows 2000 DC includes its own domain in the
|
|---|
| 1157 | list. --jerry */
|
|---|
| 1158 |
|
|---|
| 1159 | return status;
|
|---|
| 1160 | }
|
|---|
| 1161 | #endif /* JERRY */
|
|---|