2 * Unix SMB/Netbios implementation.
4 * RPC Pipe client / server routines
5 * Copyright (C) Andrew Tridgell 1992-1997,
6 * Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
7 * Copyright (C) Paul Ashton 1997.
8 * Copyright (C) Jeremy Allison 1998-2001.
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.
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.
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.
25 /* This is the implementation of the netlogon pipe. */
29 extern int DEBUGLEVEL;
31 extern BOOL sam_logon_in_ssb;
32 extern pstring samlogon_user;
33 extern pstring global_myname;
34 extern DOM_SID global_sam_sid;
36 /*************************************************************************
38 *************************************************************************/
40 static void init_net_r_req_chal(NET_R_REQ_CHAL *r_c,
41 DOM_CHAL *srv_chal, int status)
43 DEBUG(6,("init_net_r_req_chal: %d\n", __LINE__));
44 memcpy(r_c->srv_chal.data, srv_chal->data, sizeof(srv_chal->data));
48 /*************************************************************************
49 error messages cropping up when using nltest.exe...
50 *************************************************************************/
52 #define ERROR_NO_SUCH_DOMAIN 0x54b
53 #define ERROR_NO_LOGON_SERVERS 0x51f
55 /*************************************************************************
56 net_reply_logon_ctrl2:
57 *************************************************************************/
59 uint32 _net_logon_ctrl2(pipes_struct *p, NET_Q_LOGON_CTRL2 *q_u, NET_R_LOGON_CTRL2 *r_u)
61 /* lkclXXXX - guess what - absolutely no idea what these are! */
63 uint32 pdc_connection_status = 0x0;
64 uint32 logon_attempts = 0x0;
65 uint32 tc_status = ERROR_NO_LOGON_SERVERS;
66 char *trusted_domain = "test_domain";
68 DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
70 /* set up the Logon Control2 response */
71 init_r_logon_ctrl2(r_u, q_u->query_level,
72 flags, pdc_connection_status, logon_attempts,
73 tc_status, trusted_domain);
75 DEBUG(6,("_net_logon_ctrl2: %d\n", __LINE__));
80 /*************************************************************************
81 net_reply_trust_dom_list:
82 *************************************************************************/
84 uint32 _net_trust_dom_list(pipes_struct *p, NET_Q_TRUST_DOM_LIST *q_u, NET_R_TRUST_DOM_LIST *r_u)
86 char *trusted_domain = "test_domain";
87 uint32 num_trust_domains = 1;
89 DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
91 /* set up the Trusted Domain List response */
92 init_r_trust_dom(r_u, num_trust_domains, trusted_domain);
94 DEBUG(6,("_net_trust_dom_list: %d\n", __LINE__));
99 /*************************************************************************
101 *************************************************************************/
103 static void init_net_r_auth_2(NET_R_AUTH_2 *r_a,
104 DOM_CHAL *resp_cred, NEG_FLAGS *flgs, int status)
106 memcpy(r_a->srv_chal.data, resp_cred->data, sizeof(resp_cred->data));
107 memcpy(&r_a->srv_flgs, flgs, sizeof(r_a->srv_flgs));
108 r_a->status = status;
111 /***********************************************************************************
112 init_net_r_srv_pwset:
113 ***********************************************************************************/
115 static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
116 DOM_CRED *srv_cred, int status)
118 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
120 memcpy(&r_s->srv_cred, srv_cred, sizeof(r_s->srv_cred));
121 r_s->status = status;
123 DEBUG(5,("init_net_r_srv_pwset: %d\n", __LINE__));
126 /******************************************************************
127 gets a machine password entry. checks access rights of the host.
128 ******************************************************************/
130 static BOOL get_md4pw(char *md4pw, char *mach_acct)
132 SAM_ACCOUNT *sampass = NULL;
137 * Currently this code is redundent as we already have a filter
138 * by hostname list. What this code really needs to do is to
139 * get a hosts allowed/hosts denied list from the SAM database
140 * on a per user basis, and make the access decision there.
141 * I will leave this code here for now as a reminder to implement
142 * this at a later date. JRA.
145 if (!allow_access(lp_domain_hostsdeny(), lp_domain_hostsallow(),
146 client_name(), client_addr()))
148 DEBUG(0,("get_md4pw: Workstation %s denied access to domain\n", mach_acct));
153 /* JRA. This is ok as it is only used for generating the challenge. */
156 sampass = pdb_getsampwnam(mach_acct);
159 if ((sampass) != NULL && !(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) &&
160 ((pass=pdb_get_nt_passwd(sampass)) != NULL))
162 memcpy(md4pw, pass, 16);
163 dump_data(5, md4pw, 16);
168 DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
172 /*************************************************************************
174 *************************************************************************/
176 uint32 _net_req_chal(pipes_struct *p, NET_Q_REQ_CHAL *q_u, NET_R_REQ_CHAL *r_u)
178 uint32 status = NT_STATUS_NOPROBLEMO;
181 if (!get_valid_user_struct(p->vuid))
182 return NT_STATUS_NO_SUCH_USER;
184 fstrcpy(mach_acct, dos_unistrn2(q_u->uni_logon_clnt.buffer,
185 q_u->uni_logon_clnt.uni_str_len));
188 fstrcat(mach_acct, "$");
190 if (get_md4pw((char *)p->dc.md4pw, mach_acct)) {
191 /* copy the client credentials */
192 memcpy(p->dc.clnt_chal.data , q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
193 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
195 /* create a server challenge for the client */
196 /* Set these to random values. */
197 generate_random_buffer(p->dc.srv_chal.data, 8, False);
199 memcpy(p->dc.srv_cred.challenge.data, p->dc.srv_chal.data, 8);
201 memset((char *)p->dc.sess_key, '\0', sizeof(p->dc.sess_key));
203 /* from client / server challenges and md4 password, generate sess key */
204 cred_session_key(&p->dc.clnt_chal, &p->dc.srv_chal,
205 (char *)p->dc.md4pw, p->dc.sess_key);
207 /* Save the machine account name. */
208 fstrcpy(p->dc.mach_acct, mach_acct);
211 /* lkclXXXX take a guess at a good error message to return :-) */
212 status = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
215 /* set up the LSA REQUEST CHALLENGE response */
216 init_net_r_req_chal(r_u, &p->dc.srv_chal, status);
221 /*************************************************************************
223 *************************************************************************/
225 uint32 _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
227 uint32 status = NT_STATUS_NOPROBLEMO;
232 if (!get_valid_user_struct(p->vuid))
233 return NT_STATUS_NO_SUCH_USER;
237 /* check that the client credentials are valid */
238 if (cred_assert(&q_u->clnt_chal, p->dc.sess_key, &p->dc.clnt_cred.challenge, srv_time)) {
240 /* create server challenge for inclusion in the reply */
241 cred_create(p->dc.sess_key, &p->dc.srv_cred.challenge, srv_time, &srv_cred);
243 /* copy the received client credentials for use next time */
244 memcpy(p->dc.clnt_cred.challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
245 memcpy(p->dc.srv_cred .challenge.data, q_u->clnt_chal.data, sizeof(q_u->clnt_chal.data));
247 status = NT_STATUS_ACCESS_DENIED;
250 srv_flgs.neg_flags = 0x000001ff;
252 /* set up the LSA AUTH 2 response */
253 init_net_r_auth_2(r_u, &srv_cred, &srv_flgs, status);
258 /*************************************************************************
260 *************************************************************************/
262 uint32 _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
264 uint32 status = NT_STATUS_WRONG_PASSWORD;
267 SAM_ACCOUNT *sampass;
269 unsigned char pwd[16];
272 if (!get_valid_user_struct(p->vuid))
273 return NT_STATUS_NO_SUCH_USER;
275 /* checks and updates credentials. creates reply credentials */
276 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->clnt_id.cred, &srv_cred))
277 return NT_STATUS_INVALID_HANDLE;
279 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
281 DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
283 pstrcpy(mach_acct, dos_unistrn2(q_u->clnt_id.login.uni_acct_name.buffer,
284 q_u->clnt_id.login.uni_acct_name.uni_str_len));
286 DEBUG(3,("Server Password Set Wksta:[%s]\n", mach_acct));
289 sampass = pdb_getsampwnam(mach_acct);
292 /* Ensure the account exists and is a machine account. */
294 if (sampass == NULL || !(pdb_get_acct_ctrl(sampass) & ACB_WSTRUST))
295 return NT_STATUS_NO_SUCH_USER;
298 * Check the machine account name we're changing is the same
299 * as the one we've authenticated from. This prevents arbitrary
300 * machines changing other machine account passwords.
303 if (!strequal(mach_acct, p->dc.mach_acct))
304 return NT_STATUS_ACCESS_DENIED;
307 DEBUG(100,("Server password set : new given value was :\n"));
308 for(i = 0; i < 16; i++)
309 DEBUG(100,("%02X ", q_u->pwd[i]));
312 cred_hash3( pwd, q_u->pwd, p->dc.sess_key, 0);
314 /* lies! nt and lm passwords are _not_ the same: don't care */
315 pdb_set_lanman_passwd (sampass, pwd);
316 pdb_set_nt_passwd (sampass, pwd);
317 pdb_set_acct_ctrl (sampass, ACB_WSTRUST);
320 ret = pdb_update_sam_account (sampass,False);
324 status = NT_STATUS_NOPROBLEMO;
326 /* set up the LSA Server Password Set response */
327 init_net_r_srv_pwset(r_u, &srv_cred, status);
333 /*************************************************************************
335 *************************************************************************/
337 uint32 _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
341 if (!get_valid_user_struct(p->vuid))
342 return NT_STATUS_NO_SUCH_USER;
344 /* checks and updates credentials. creates reply credentials */
345 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred,
346 &q_u->sam_id.client.cred, &srv_cred))
347 return NT_STATUS_INVALID_HANDLE;
349 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
351 /* XXXX maybe we want to say 'no', reject the client's credentials */
352 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
353 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
355 r_u->status = NT_STATUS_NOPROBLEMO;
360 /*************************************************************************
361 net_login_interactive:
362 *************************************************************************/
364 static uint32 net_login_interactive(NET_ID_INFO_1 *id1, SAM_ACCOUNT *sampass, pipes_struct *p)
370 unsigned char key[16];
373 memcpy(key, p->dc.sess_key, 8);
375 memcpy(lm_pwd, id1->lm_owf.data, 16);
376 memcpy(nt_pwd, id1->nt_owf.data, 16);
378 #ifdef DEBUG_PASSWORD
380 dump_data(100, (char *)key, 16);
382 DEBUG(100,("lm owf password:"));
383 dump_data(100, lm_pwd, 16);
385 DEBUG(100,("nt owf password:"));
386 dump_data(100, nt_pwd, 16);
389 SamOEMhash((uchar *)lm_pwd, key, False);
390 SamOEMhash((uchar *)nt_pwd, key, False);
392 #ifdef DEBUG_PASSWORD
393 DEBUG(100,("decrypt of lm owf password:"));
394 dump_data(100, lm_pwd, 16);
396 DEBUG(100,("decrypt of nt owf password:"));
397 dump_data(100, nt_pwd, 16);
400 if (memcmp(pdb_get_lanman_passwd(sampass), lm_pwd, 16) != 0 ||
401 memcmp(pdb_get_nt_passwd(sampass), nt_pwd, 16) != 0) {
402 status = NT_STATUS_WRONG_PASSWORD;
408 /*************************************************************************
410 *************************************************************************/
412 static uint32 net_login_network(NET_ID_INFO_2 *id2, SAM_ACCOUNT *sampass)
414 uint8 *nt_pwd, *lanman_pwd;
416 DEBUG(5,("net_login_network: lm_len: %d nt_len: %d\n",
417 id2->hdr_lm_chal_resp.str_str_len,
418 id2->hdr_nt_chal_resp.str_str_len));
420 /* JRA. Check the NT password first if it exists - this is a higher quality
421 password, if it exists and it doesn't match - fail. */
423 nt_pwd = pdb_get_nt_passwd(sampass);
424 lanman_pwd = pdb_get_lanman_passwd(sampass);
426 if (id2->hdr_nt_chal_resp.str_str_len == 24 && nt_pwd) {
427 if(smb_password_check((char *)id2->nt_chal_resp.buffer,
428 nt_pwd, id2->lm_chal))
429 return NT_STATUS_NOPROBLEMO;
431 return NT_STATUS_WRONG_PASSWORD;
434 /* lkclXXXX this is not a good place to put disabling of LM hashes in.
435 if that is to be done, first move this entire function into a
436 library routine that calls the two smb_password_check() functions.
437 if disabling LM hashes (which nt can do for security reasons) then
438 an attempt should be made to disable them everywhere (which nt does
439 not do, for various security-hole reasons).
442 if (id2->hdr_lm_chal_resp.str_str_len == 24 && lanman_pwd &&
443 smb_password_check((char *)id2->lm_chal_resp.buffer,
444 lanman_pwd, id2->lm_chal))
445 return NT_STATUS_NOPROBLEMO;
447 /* oops! neither password check succeeded */
449 return NT_STATUS_WRONG_PASSWORD;
452 /*************************************************************************
454 *************************************************************************/
456 uint32 _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
458 uint32 status = NT_STATUS_NOPROBLEMO;
459 NET_USER_INFO_3 *usr_info = NULL;
461 SAM_ACCOUNT *sampass = NULL;
463 UNISTR2 *uni_samlogon_user = NULL;
466 usr_info = (NET_USER_INFO_3 *)talloc(p->mem_ctx, sizeof(NET_USER_INFO_3));
468 return NT_STATUS_NO_MEMORY;
469 ZERO_STRUCTP(usr_info);
471 if (!get_valid_user_struct(p->vuid))
472 return NT_STATUS_NO_SUCH_USER;
474 /* checks and updates credentials. creates reply credentials */
475 if (!deal_with_creds(p->dc.sess_key, &p->dc.clnt_cred, &q_u->sam_id.client.cred, &srv_cred))
476 return NT_STATUS_INVALID_HANDLE;
478 memcpy(&p->dc.srv_cred, &p->dc.clnt_cred, sizeof(p->dc.clnt_cred));
480 /* find the username */
482 switch (q_u->sam_id.logon_level) {
483 case INTERACTIVE_LOGON_TYPE:
484 uni_samlogon_user = &q_u->sam_id.ctr->auth.id1.uni_user_name;
486 DEBUG(3,("SAM Logon (Interactive). Domain:[%s]. ", lp_workgroup()));
489 uni_samlogon_user = &q_u->sam_id.ctr->auth.id2.uni_user_name;
491 DEBUG(3,("SAM Logon (Network). Domain:[%s]. ", lp_workgroup()));
494 DEBUG(2,("SAM Logon: unsupported switch value\n"));
495 return NT_STATUS_INVALID_INFO_CLASS;
498 /* check username exists */
500 pstrcpy(nt_username, dos_unistrn2(uni_samlogon_user->buffer, uni_samlogon_user->uni_str_len));
502 DEBUG(3,("User:[%s]\n", nt_username));
505 * Convert to a UNIX username.
508 map_username(nt_username);
510 /* get the account information */
512 sampass = pdb_getsampwnam(nt_username);
516 return NT_STATUS_NO_SUCH_USER;
518 acct_ctrl = pdb_get_acct_ctrl(sampass);
520 if (acct_ctrl & ACB_DISABLED)
521 return NT_STATUS_ACCOUNT_DISABLED;
523 /* Validate password - if required. */
525 if (!(acct_ctrl & ACB_PWNOTREQ)) {
526 switch (q_u->sam_id.logon_level) {
527 case INTERACTIVE_LOGON_TYPE:
528 /* interactive login. */
529 status = net_login_interactive(&q_u->sam_id.ctr->auth.id1, sampass, p);
532 /* network login. lm challenge and 24 byte responses */
533 status = net_login_network(&q_u->sam_id.ctr->auth.id2, sampass);
538 if (status != NT_STATUS_NOPROBLEMO)
541 /* lkclXXXX this is the point at which, if the login was
542 successful, that the SAM Local Security Authority should
543 record that the user is logged in to the domain.
547 DOM_GID *gids = NULL;
550 pstring my_workgroup;
551 pstring domain_groups;
553 /* set up pointer indicating user/password failed to be found */
554 usr_info->ptr_user_info = 0;
556 /* XXXX hack to get standard_sub_basic() to use sam logon username */
557 /* possibly a better way would be to do a become_user() call */
558 sam_logon_in_ssb = True;
559 pstrcpy(samlogon_user, nt_username);
561 pstrcpy(my_workgroup, lp_workgroup());
562 pstrcpy(my_name, global_myname);
566 * This is the point at which we get the group
567 * database - we should be getting the gid_t list
568 * from /etc/group and then turning the uids into
569 * rids and then into machine sids for this user.
573 get_domain_user_groups(domain_groups, nt_username);
576 * make_dom_gids allocates the gids array. JRA.
579 num_gids = make_dom_gids(p->mem_ctx, domain_groups, &gids);
581 sam_logon_in_ssb = False;
583 init_net_user_info3(p->mem_ctx, usr_info, sampass,
585 0, /* bad_pw_count */
586 num_gids, /* uint32 num_groups */
587 gids , /* DOM_GID *gids */
588 0x20 , /* uint32 user_flgs (?) */
589 NULL, /* char sess_key[16] */
590 my_name , /* char *logon_srv */
591 my_workgroup, /* char *logon_dom */
592 &global_sam_sid, /* DOM_SID *dom_sid */
593 NULL); /* char *other_sids */
596 /* XXXX maybe we want to say 'no', reject the client's credentials */
597 r_u->buffer_creds = 1; /* yes, we have valid server credentials */
598 memcpy(&r_u->srv_creds, &srv_cred, sizeof(r_u->srv_creds));
600 /* store the user information, if there is any. */
601 r_u->user = usr_info;
602 if (status == NT_STATUS_NOPROBLEMO && usr_info != NULL && usr_info->ptr_user_info != 0)
603 r_u->switch_value = 3; /* indicates type of validation user info */
605 r_u->switch_value = 0; /* indicates no info */
607 r_u->status = status;
608 r_u->auth_resp = 1; /* authoritative response */